1*03f9172cSAndroid Build Coastguard Worker /*
2*03f9172cSAndroid Build Coastguard Worker * X.509v3 certificate parsing and processing (RFC 3280 profile)
3*03f9172cSAndroid Build Coastguard Worker * Copyright (c) 2006-2015, Jouni Malinen <[email protected]>
4*03f9172cSAndroid Build Coastguard Worker *
5*03f9172cSAndroid Build Coastguard Worker * This software may be distributed under the terms of the BSD license.
6*03f9172cSAndroid Build Coastguard Worker * See README for more details.
7*03f9172cSAndroid Build Coastguard Worker */
8*03f9172cSAndroid Build Coastguard Worker
9*03f9172cSAndroid Build Coastguard Worker #include "includes.h"
10*03f9172cSAndroid Build Coastguard Worker
11*03f9172cSAndroid Build Coastguard Worker #include "common.h"
12*03f9172cSAndroid Build Coastguard Worker #include "crypto/crypto.h"
13*03f9172cSAndroid Build Coastguard Worker #include "asn1.h"
14*03f9172cSAndroid Build Coastguard Worker #include "x509v3.h"
15*03f9172cSAndroid Build Coastguard Worker
16*03f9172cSAndroid Build Coastguard Worker
x509_free_name(struct x509_name * name)17*03f9172cSAndroid Build Coastguard Worker void x509_free_name(struct x509_name *name)
18*03f9172cSAndroid Build Coastguard Worker {
19*03f9172cSAndroid Build Coastguard Worker size_t i;
20*03f9172cSAndroid Build Coastguard Worker
21*03f9172cSAndroid Build Coastguard Worker for (i = 0; i < name->num_attr; i++) {
22*03f9172cSAndroid Build Coastguard Worker os_free(name->attr[i].value);
23*03f9172cSAndroid Build Coastguard Worker name->attr[i].value = NULL;
24*03f9172cSAndroid Build Coastguard Worker name->attr[i].type = X509_NAME_ATTR_NOT_USED;
25*03f9172cSAndroid Build Coastguard Worker }
26*03f9172cSAndroid Build Coastguard Worker name->num_attr = 0;
27*03f9172cSAndroid Build Coastguard Worker os_free(name->email);
28*03f9172cSAndroid Build Coastguard Worker name->email = NULL;
29*03f9172cSAndroid Build Coastguard Worker
30*03f9172cSAndroid Build Coastguard Worker os_free(name->alt_email);
31*03f9172cSAndroid Build Coastguard Worker os_free(name->dns);
32*03f9172cSAndroid Build Coastguard Worker os_free(name->uri);
33*03f9172cSAndroid Build Coastguard Worker os_free(name->ip);
34*03f9172cSAndroid Build Coastguard Worker name->alt_email = name->dns = name->uri = NULL;
35*03f9172cSAndroid Build Coastguard Worker name->ip = NULL;
36*03f9172cSAndroid Build Coastguard Worker name->ip_len = 0;
37*03f9172cSAndroid Build Coastguard Worker os_memset(&name->rid, 0, sizeof(name->rid));
38*03f9172cSAndroid Build Coastguard Worker }
39*03f9172cSAndroid Build Coastguard Worker
40*03f9172cSAndroid Build Coastguard Worker
41*03f9172cSAndroid Build Coastguard Worker /**
42*03f9172cSAndroid Build Coastguard Worker * x509_certificate_free - Free an X.509 certificate
43*03f9172cSAndroid Build Coastguard Worker * @cert: Certificate to be freed
44*03f9172cSAndroid Build Coastguard Worker */
x509_certificate_free(struct x509_certificate * cert)45*03f9172cSAndroid Build Coastguard Worker void x509_certificate_free(struct x509_certificate *cert)
46*03f9172cSAndroid Build Coastguard Worker {
47*03f9172cSAndroid Build Coastguard Worker if (cert == NULL)
48*03f9172cSAndroid Build Coastguard Worker return;
49*03f9172cSAndroid Build Coastguard Worker if (cert->next) {
50*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: x509_certificate_free: cer=%p "
51*03f9172cSAndroid Build Coastguard Worker "was still on a list (next=%p)\n",
52*03f9172cSAndroid Build Coastguard Worker cert, cert->next);
53*03f9172cSAndroid Build Coastguard Worker }
54*03f9172cSAndroid Build Coastguard Worker x509_free_name(&cert->issuer);
55*03f9172cSAndroid Build Coastguard Worker x509_free_name(&cert->subject);
56*03f9172cSAndroid Build Coastguard Worker os_free(cert->public_key);
57*03f9172cSAndroid Build Coastguard Worker os_free(cert->sign_value);
58*03f9172cSAndroid Build Coastguard Worker os_free(cert->subject_dn);
59*03f9172cSAndroid Build Coastguard Worker os_free(cert);
60*03f9172cSAndroid Build Coastguard Worker }
61*03f9172cSAndroid Build Coastguard Worker
62*03f9172cSAndroid Build Coastguard Worker
63*03f9172cSAndroid Build Coastguard Worker /**
64*03f9172cSAndroid Build Coastguard Worker * x509_certificate_free - Free an X.509 certificate chain
65*03f9172cSAndroid Build Coastguard Worker * @cert: Pointer to the first certificate in the chain
66*03f9172cSAndroid Build Coastguard Worker */
x509_certificate_chain_free(struct x509_certificate * cert)67*03f9172cSAndroid Build Coastguard Worker void x509_certificate_chain_free(struct x509_certificate *cert)
68*03f9172cSAndroid Build Coastguard Worker {
69*03f9172cSAndroid Build Coastguard Worker struct x509_certificate *next;
70*03f9172cSAndroid Build Coastguard Worker
71*03f9172cSAndroid Build Coastguard Worker while (cert) {
72*03f9172cSAndroid Build Coastguard Worker next = cert->next;
73*03f9172cSAndroid Build Coastguard Worker cert->next = NULL;
74*03f9172cSAndroid Build Coastguard Worker x509_certificate_free(cert);
75*03f9172cSAndroid Build Coastguard Worker cert = next;
76*03f9172cSAndroid Build Coastguard Worker }
77*03f9172cSAndroid Build Coastguard Worker }
78*03f9172cSAndroid Build Coastguard Worker
79*03f9172cSAndroid Build Coastguard Worker
x509_whitespace(char c)80*03f9172cSAndroid Build Coastguard Worker static int x509_whitespace(char c)
81*03f9172cSAndroid Build Coastguard Worker {
82*03f9172cSAndroid Build Coastguard Worker return c == ' ' || c == '\t';
83*03f9172cSAndroid Build Coastguard Worker }
84*03f9172cSAndroid Build Coastguard Worker
85*03f9172cSAndroid Build Coastguard Worker
x509_str_strip_whitespace(char * a)86*03f9172cSAndroid Build Coastguard Worker static void x509_str_strip_whitespace(char *a)
87*03f9172cSAndroid Build Coastguard Worker {
88*03f9172cSAndroid Build Coastguard Worker char *ipos, *opos;
89*03f9172cSAndroid Build Coastguard Worker int remove_whitespace = 1;
90*03f9172cSAndroid Build Coastguard Worker
91*03f9172cSAndroid Build Coastguard Worker ipos = opos = a;
92*03f9172cSAndroid Build Coastguard Worker
93*03f9172cSAndroid Build Coastguard Worker while (*ipos) {
94*03f9172cSAndroid Build Coastguard Worker if (remove_whitespace && x509_whitespace(*ipos))
95*03f9172cSAndroid Build Coastguard Worker ipos++;
96*03f9172cSAndroid Build Coastguard Worker else {
97*03f9172cSAndroid Build Coastguard Worker remove_whitespace = x509_whitespace(*ipos);
98*03f9172cSAndroid Build Coastguard Worker *opos++ = *ipos++;
99*03f9172cSAndroid Build Coastguard Worker }
100*03f9172cSAndroid Build Coastguard Worker }
101*03f9172cSAndroid Build Coastguard Worker
102*03f9172cSAndroid Build Coastguard Worker *opos-- = '\0';
103*03f9172cSAndroid Build Coastguard Worker if (opos > a && x509_whitespace(*opos))
104*03f9172cSAndroid Build Coastguard Worker *opos = '\0';
105*03f9172cSAndroid Build Coastguard Worker }
106*03f9172cSAndroid Build Coastguard Worker
107*03f9172cSAndroid Build Coastguard Worker
x509_str_compare(const char * a,const char * b)108*03f9172cSAndroid Build Coastguard Worker static int x509_str_compare(const char *a, const char *b)
109*03f9172cSAndroid Build Coastguard Worker {
110*03f9172cSAndroid Build Coastguard Worker char *aa, *bb;
111*03f9172cSAndroid Build Coastguard Worker int ret;
112*03f9172cSAndroid Build Coastguard Worker
113*03f9172cSAndroid Build Coastguard Worker if (!a && b)
114*03f9172cSAndroid Build Coastguard Worker return -1;
115*03f9172cSAndroid Build Coastguard Worker if (a && !b)
116*03f9172cSAndroid Build Coastguard Worker return 1;
117*03f9172cSAndroid Build Coastguard Worker if (!a && !b)
118*03f9172cSAndroid Build Coastguard Worker return 0;
119*03f9172cSAndroid Build Coastguard Worker
120*03f9172cSAndroid Build Coastguard Worker aa = os_strdup(a);
121*03f9172cSAndroid Build Coastguard Worker bb = os_strdup(b);
122*03f9172cSAndroid Build Coastguard Worker
123*03f9172cSAndroid Build Coastguard Worker if (aa == NULL || bb == NULL) {
124*03f9172cSAndroid Build Coastguard Worker os_free(aa);
125*03f9172cSAndroid Build Coastguard Worker os_free(bb);
126*03f9172cSAndroid Build Coastguard Worker return os_strcasecmp(a, b);
127*03f9172cSAndroid Build Coastguard Worker }
128*03f9172cSAndroid Build Coastguard Worker
129*03f9172cSAndroid Build Coastguard Worker x509_str_strip_whitespace(aa);
130*03f9172cSAndroid Build Coastguard Worker x509_str_strip_whitespace(bb);
131*03f9172cSAndroid Build Coastguard Worker
132*03f9172cSAndroid Build Coastguard Worker ret = os_strcasecmp(aa, bb);
133*03f9172cSAndroid Build Coastguard Worker
134*03f9172cSAndroid Build Coastguard Worker os_free(aa);
135*03f9172cSAndroid Build Coastguard Worker os_free(bb);
136*03f9172cSAndroid Build Coastguard Worker
137*03f9172cSAndroid Build Coastguard Worker return ret;
138*03f9172cSAndroid Build Coastguard Worker }
139*03f9172cSAndroid Build Coastguard Worker
140*03f9172cSAndroid Build Coastguard Worker
141*03f9172cSAndroid Build Coastguard Worker /**
142*03f9172cSAndroid Build Coastguard Worker * x509_name_compare - Compare X.509 certificate names
143*03f9172cSAndroid Build Coastguard Worker * @a: Certificate name
144*03f9172cSAndroid Build Coastguard Worker * @b: Certificate name
145*03f9172cSAndroid Build Coastguard Worker * Returns: <0, 0, or >0 based on whether a is less than, equal to, or
146*03f9172cSAndroid Build Coastguard Worker * greater than b
147*03f9172cSAndroid Build Coastguard Worker */
x509_name_compare(struct x509_name * a,struct x509_name * b)148*03f9172cSAndroid Build Coastguard Worker int x509_name_compare(struct x509_name *a, struct x509_name *b)
149*03f9172cSAndroid Build Coastguard Worker {
150*03f9172cSAndroid Build Coastguard Worker int res;
151*03f9172cSAndroid Build Coastguard Worker size_t i;
152*03f9172cSAndroid Build Coastguard Worker
153*03f9172cSAndroid Build Coastguard Worker if (!a && b)
154*03f9172cSAndroid Build Coastguard Worker return -1;
155*03f9172cSAndroid Build Coastguard Worker if (a && !b)
156*03f9172cSAndroid Build Coastguard Worker return 1;
157*03f9172cSAndroid Build Coastguard Worker if (!a && !b)
158*03f9172cSAndroid Build Coastguard Worker return 0;
159*03f9172cSAndroid Build Coastguard Worker if (a->num_attr < b->num_attr)
160*03f9172cSAndroid Build Coastguard Worker return -1;
161*03f9172cSAndroid Build Coastguard Worker if (a->num_attr > b->num_attr)
162*03f9172cSAndroid Build Coastguard Worker return 1;
163*03f9172cSAndroid Build Coastguard Worker
164*03f9172cSAndroid Build Coastguard Worker for (i = 0; i < a->num_attr; i++) {
165*03f9172cSAndroid Build Coastguard Worker if (a->attr[i].type < b->attr[i].type)
166*03f9172cSAndroid Build Coastguard Worker return -1;
167*03f9172cSAndroid Build Coastguard Worker if (a->attr[i].type > b->attr[i].type)
168*03f9172cSAndroid Build Coastguard Worker return -1;
169*03f9172cSAndroid Build Coastguard Worker res = x509_str_compare(a->attr[i].value, b->attr[i].value);
170*03f9172cSAndroid Build Coastguard Worker if (res)
171*03f9172cSAndroid Build Coastguard Worker return res;
172*03f9172cSAndroid Build Coastguard Worker }
173*03f9172cSAndroid Build Coastguard Worker res = x509_str_compare(a->email, b->email);
174*03f9172cSAndroid Build Coastguard Worker if (res)
175*03f9172cSAndroid Build Coastguard Worker return res;
176*03f9172cSAndroid Build Coastguard Worker
177*03f9172cSAndroid Build Coastguard Worker return 0;
178*03f9172cSAndroid Build Coastguard Worker }
179*03f9172cSAndroid Build Coastguard Worker
180*03f9172cSAndroid Build Coastguard Worker
x509_parse_algorithm_identifier(const u8 * buf,size_t len,struct x509_algorithm_identifier * id,const u8 ** next)181*03f9172cSAndroid Build Coastguard Worker int x509_parse_algorithm_identifier(const u8 *buf, size_t len,
182*03f9172cSAndroid Build Coastguard Worker struct x509_algorithm_identifier *id,
183*03f9172cSAndroid Build Coastguard Worker const u8 **next)
184*03f9172cSAndroid Build Coastguard Worker {
185*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
186*03f9172cSAndroid Build Coastguard Worker const u8 *pos, *end;
187*03f9172cSAndroid Build Coastguard Worker
188*03f9172cSAndroid Build Coastguard Worker /*
189*03f9172cSAndroid Build Coastguard Worker * AlgorithmIdentifier ::= SEQUENCE {
190*03f9172cSAndroid Build Coastguard Worker * algorithm OBJECT IDENTIFIER,
191*03f9172cSAndroid Build Coastguard Worker * parameters ANY DEFINED BY algorithm OPTIONAL
192*03f9172cSAndroid Build Coastguard Worker * }
193*03f9172cSAndroid Build Coastguard Worker */
194*03f9172cSAndroid Build Coastguard Worker
195*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
196*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
197*03f9172cSAndroid Build Coastguard Worker "X509: Expected SEQUENCE (AlgorithmIdentifier)");
198*03f9172cSAndroid Build Coastguard Worker return -1;
199*03f9172cSAndroid Build Coastguard Worker }
200*03f9172cSAndroid Build Coastguard Worker if (hdr.length > buf + len - hdr.payload)
201*03f9172cSAndroid Build Coastguard Worker return -1;
202*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
203*03f9172cSAndroid Build Coastguard Worker end = pos + hdr.length;
204*03f9172cSAndroid Build Coastguard Worker
205*03f9172cSAndroid Build Coastguard Worker *next = end;
206*03f9172cSAndroid Build Coastguard Worker
207*03f9172cSAndroid Build Coastguard Worker if (asn1_get_oid(pos, end - pos, &id->oid, &pos))
208*03f9172cSAndroid Build Coastguard Worker return -1;
209*03f9172cSAndroid Build Coastguard Worker
210*03f9172cSAndroid Build Coastguard Worker /* TODO: optional parameters */
211*03f9172cSAndroid Build Coastguard Worker
212*03f9172cSAndroid Build Coastguard Worker return 0;
213*03f9172cSAndroid Build Coastguard Worker }
214*03f9172cSAndroid Build Coastguard Worker
215*03f9172cSAndroid Build Coastguard Worker
x509_parse_public_key(const u8 * buf,size_t len,struct x509_certificate * cert,const u8 ** next)216*03f9172cSAndroid Build Coastguard Worker static int x509_parse_public_key(const u8 *buf, size_t len,
217*03f9172cSAndroid Build Coastguard Worker struct x509_certificate *cert,
218*03f9172cSAndroid Build Coastguard Worker const u8 **next)
219*03f9172cSAndroid Build Coastguard Worker {
220*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
221*03f9172cSAndroid Build Coastguard Worker const u8 *pos, *end;
222*03f9172cSAndroid Build Coastguard Worker
223*03f9172cSAndroid Build Coastguard Worker /*
224*03f9172cSAndroid Build Coastguard Worker * SubjectPublicKeyInfo ::= SEQUENCE {
225*03f9172cSAndroid Build Coastguard Worker * algorithm AlgorithmIdentifier,
226*03f9172cSAndroid Build Coastguard Worker * subjectPublicKey BIT STRING
227*03f9172cSAndroid Build Coastguard Worker * }
228*03f9172cSAndroid Build Coastguard Worker */
229*03f9172cSAndroid Build Coastguard Worker
230*03f9172cSAndroid Build Coastguard Worker pos = buf;
231*03f9172cSAndroid Build Coastguard Worker end = buf + len;
232*03f9172cSAndroid Build Coastguard Worker
233*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
234*03f9172cSAndroid Build Coastguard Worker !asn1_is_sequence(&hdr)) {
235*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
236*03f9172cSAndroid Build Coastguard Worker "X509: Expected SEQUENCE (SubjectPublicKeyInfo)");
237*03f9172cSAndroid Build Coastguard Worker return -1;
238*03f9172cSAndroid Build Coastguard Worker }
239*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
240*03f9172cSAndroid Build Coastguard Worker
241*03f9172cSAndroid Build Coastguard Worker if (hdr.length > end - pos)
242*03f9172cSAndroid Build Coastguard Worker return -1;
243*03f9172cSAndroid Build Coastguard Worker end = pos + hdr.length;
244*03f9172cSAndroid Build Coastguard Worker *next = end;
245*03f9172cSAndroid Build Coastguard Worker
246*03f9172cSAndroid Build Coastguard Worker if (x509_parse_algorithm_identifier(pos, end - pos,
247*03f9172cSAndroid Build Coastguard Worker &cert->public_key_alg, &pos))
248*03f9172cSAndroid Build Coastguard Worker return -1;
249*03f9172cSAndroid Build Coastguard Worker
250*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
251*03f9172cSAndroid Build Coastguard Worker !asn1_is_bitstring(&hdr)) {
252*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
253*03f9172cSAndroid Build Coastguard Worker "X509: Expected BITSTRING (subjectPublicKey)");
254*03f9172cSAndroid Build Coastguard Worker return -1;
255*03f9172cSAndroid Build Coastguard Worker }
256*03f9172cSAndroid Build Coastguard Worker if (hdr.length < 1)
257*03f9172cSAndroid Build Coastguard Worker return -1;
258*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
259*03f9172cSAndroid Build Coastguard Worker if (*pos) {
260*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
261*03f9172cSAndroid Build Coastguard Worker "X509: BITSTRING (subjectPublicKey) - %d unused bits",
262*03f9172cSAndroid Build Coastguard Worker *pos);
263*03f9172cSAndroid Build Coastguard Worker /*
264*03f9172cSAndroid Build Coastguard Worker * TODO: should this be rejected? X.509 certificates are
265*03f9172cSAndroid Build Coastguard Worker * unlikely to use such a construction. Now we would end up
266*03f9172cSAndroid Build Coastguard Worker * including the extra bits in the buffer which may also be
267*03f9172cSAndroid Build Coastguard Worker * ok.
268*03f9172cSAndroid Build Coastguard Worker */
269*03f9172cSAndroid Build Coastguard Worker }
270*03f9172cSAndroid Build Coastguard Worker os_free(cert->public_key);
271*03f9172cSAndroid Build Coastguard Worker cert->public_key = os_memdup(pos + 1, hdr.length - 1);
272*03f9172cSAndroid Build Coastguard Worker if (cert->public_key == NULL) {
273*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
274*03f9172cSAndroid Build Coastguard Worker "public key");
275*03f9172cSAndroid Build Coastguard Worker return -1;
276*03f9172cSAndroid Build Coastguard Worker }
277*03f9172cSAndroid Build Coastguard Worker cert->public_key_len = hdr.length - 1;
278*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: subjectPublicKey",
279*03f9172cSAndroid Build Coastguard Worker cert->public_key, cert->public_key_len);
280*03f9172cSAndroid Build Coastguard Worker
281*03f9172cSAndroid Build Coastguard Worker return 0;
282*03f9172cSAndroid Build Coastguard Worker }
283*03f9172cSAndroid Build Coastguard Worker
284*03f9172cSAndroid Build Coastguard Worker
x509_parse_name(const u8 * buf,size_t len,struct x509_name * name,const u8 ** next)285*03f9172cSAndroid Build Coastguard Worker int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
286*03f9172cSAndroid Build Coastguard Worker const u8 **next)
287*03f9172cSAndroid Build Coastguard Worker {
288*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
289*03f9172cSAndroid Build Coastguard Worker const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end;
290*03f9172cSAndroid Build Coastguard Worker struct asn1_oid oid;
291*03f9172cSAndroid Build Coastguard Worker char *val;
292*03f9172cSAndroid Build Coastguard Worker
293*03f9172cSAndroid Build Coastguard Worker /*
294*03f9172cSAndroid Build Coastguard Worker * Name ::= CHOICE { RDNSequence }
295*03f9172cSAndroid Build Coastguard Worker * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
296*03f9172cSAndroid Build Coastguard Worker * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
297*03f9172cSAndroid Build Coastguard Worker * AttributeTypeAndValue ::= SEQUENCE {
298*03f9172cSAndroid Build Coastguard Worker * type AttributeType,
299*03f9172cSAndroid Build Coastguard Worker * value AttributeValue
300*03f9172cSAndroid Build Coastguard Worker * }
301*03f9172cSAndroid Build Coastguard Worker * AttributeType ::= OBJECT IDENTIFIER
302*03f9172cSAndroid Build Coastguard Worker * AttributeValue ::= ANY DEFINED BY AttributeType
303*03f9172cSAndroid Build Coastguard Worker */
304*03f9172cSAndroid Build Coastguard Worker
305*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
306*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
307*03f9172cSAndroid Build Coastguard Worker "X509: Expected SEQUENCE (Name / RDNSequencer)");
308*03f9172cSAndroid Build Coastguard Worker return -1;
309*03f9172cSAndroid Build Coastguard Worker }
310*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
311*03f9172cSAndroid Build Coastguard Worker
312*03f9172cSAndroid Build Coastguard Worker if (hdr.length > buf + len - pos)
313*03f9172cSAndroid Build Coastguard Worker return -1;
314*03f9172cSAndroid Build Coastguard Worker
315*03f9172cSAndroid Build Coastguard Worker end = *next = pos + hdr.length;
316*03f9172cSAndroid Build Coastguard Worker
317*03f9172cSAndroid Build Coastguard Worker while (pos < end) {
318*03f9172cSAndroid Build Coastguard Worker enum x509_name_attr_type type;
319*03f9172cSAndroid Build Coastguard Worker
320*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
321*03f9172cSAndroid Build Coastguard Worker !asn1_is_set(&hdr)) {
322*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
323*03f9172cSAndroid Build Coastguard Worker "X509: Expected SET (RelativeDistinguishedName)");
324*03f9172cSAndroid Build Coastguard Worker x509_free_name(name);
325*03f9172cSAndroid Build Coastguard Worker return -1;
326*03f9172cSAndroid Build Coastguard Worker }
327*03f9172cSAndroid Build Coastguard Worker
328*03f9172cSAndroid Build Coastguard Worker set_pos = hdr.payload;
329*03f9172cSAndroid Build Coastguard Worker pos = set_end = hdr.payload + hdr.length;
330*03f9172cSAndroid Build Coastguard Worker
331*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(set_pos, set_end - set_pos, &hdr) < 0 ||
332*03f9172cSAndroid Build Coastguard Worker !asn1_is_sequence(&hdr)) {
333*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
334*03f9172cSAndroid Build Coastguard Worker "X509: Expected SEQUENCE (AttributeTypeAndValue)");
335*03f9172cSAndroid Build Coastguard Worker x509_free_name(name);
336*03f9172cSAndroid Build Coastguard Worker return -1;
337*03f9172cSAndroid Build Coastguard Worker }
338*03f9172cSAndroid Build Coastguard Worker
339*03f9172cSAndroid Build Coastguard Worker seq_pos = hdr.payload;
340*03f9172cSAndroid Build Coastguard Worker seq_end = hdr.payload + hdr.length;
341*03f9172cSAndroid Build Coastguard Worker
342*03f9172cSAndroid Build Coastguard Worker if (asn1_get_oid(seq_pos, seq_end - seq_pos, &oid, &seq_pos)) {
343*03f9172cSAndroid Build Coastguard Worker x509_free_name(name);
344*03f9172cSAndroid Build Coastguard Worker return -1;
345*03f9172cSAndroid Build Coastguard Worker }
346*03f9172cSAndroid Build Coastguard Worker
347*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(seq_pos, seq_end - seq_pos, &hdr) < 0 ||
348*03f9172cSAndroid Build Coastguard Worker hdr.class != ASN1_CLASS_UNIVERSAL) {
349*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Failed to parse "
350*03f9172cSAndroid Build Coastguard Worker "AttributeValue");
351*03f9172cSAndroid Build Coastguard Worker x509_free_name(name);
352*03f9172cSAndroid Build Coastguard Worker return -1;
353*03f9172cSAndroid Build Coastguard Worker }
354*03f9172cSAndroid Build Coastguard Worker
355*03f9172cSAndroid Build Coastguard Worker if (!asn1_is_string_type(&hdr)) {
356*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
357*03f9172cSAndroid Build Coastguard Worker "X509: Ignore non-string type attribute (tag 0x%x)",
358*03f9172cSAndroid Build Coastguard Worker hdr.tag);
359*03f9172cSAndroid Build Coastguard Worker continue;
360*03f9172cSAndroid Build Coastguard Worker }
361*03f9172cSAndroid Build Coastguard Worker
362*03f9172cSAndroid Build Coastguard Worker /* RFC 3280:
363*03f9172cSAndroid Build Coastguard Worker * MUST: country, organization, organizational-unit,
364*03f9172cSAndroid Build Coastguard Worker * distinguished name qualifier, state or province name,
365*03f9172cSAndroid Build Coastguard Worker * common name, serial number.
366*03f9172cSAndroid Build Coastguard Worker * SHOULD: locality, title, surname, given name, initials,
367*03f9172cSAndroid Build Coastguard Worker * pseudonym, generation qualifier.
368*03f9172cSAndroid Build Coastguard Worker * MUST: domainComponent (RFC 2247).
369*03f9172cSAndroid Build Coastguard Worker */
370*03f9172cSAndroid Build Coastguard Worker type = X509_NAME_ATTR_NOT_USED;
371*03f9172cSAndroid Build Coastguard Worker if (oid.len == 4 &&
372*03f9172cSAndroid Build Coastguard Worker oid.oid[0] == 2 && oid.oid[1] == 5 && oid.oid[2] == 4) {
373*03f9172cSAndroid Build Coastguard Worker /* id-at ::= 2.5.4 */
374*03f9172cSAndroid Build Coastguard Worker switch (oid.oid[3]) {
375*03f9172cSAndroid Build Coastguard Worker case 3:
376*03f9172cSAndroid Build Coastguard Worker /* commonName */
377*03f9172cSAndroid Build Coastguard Worker type = X509_NAME_ATTR_CN;
378*03f9172cSAndroid Build Coastguard Worker break;
379*03f9172cSAndroid Build Coastguard Worker case 6:
380*03f9172cSAndroid Build Coastguard Worker /* countryName */
381*03f9172cSAndroid Build Coastguard Worker type = X509_NAME_ATTR_C;
382*03f9172cSAndroid Build Coastguard Worker break;
383*03f9172cSAndroid Build Coastguard Worker case 7:
384*03f9172cSAndroid Build Coastguard Worker /* localityName */
385*03f9172cSAndroid Build Coastguard Worker type = X509_NAME_ATTR_L;
386*03f9172cSAndroid Build Coastguard Worker break;
387*03f9172cSAndroid Build Coastguard Worker case 8:
388*03f9172cSAndroid Build Coastguard Worker /* stateOrProvinceName */
389*03f9172cSAndroid Build Coastguard Worker type = X509_NAME_ATTR_ST;
390*03f9172cSAndroid Build Coastguard Worker break;
391*03f9172cSAndroid Build Coastguard Worker case 10:
392*03f9172cSAndroid Build Coastguard Worker /* organizationName */
393*03f9172cSAndroid Build Coastguard Worker type = X509_NAME_ATTR_O;
394*03f9172cSAndroid Build Coastguard Worker break;
395*03f9172cSAndroid Build Coastguard Worker case 11:
396*03f9172cSAndroid Build Coastguard Worker /* organizationalUnitName */
397*03f9172cSAndroid Build Coastguard Worker type = X509_NAME_ATTR_OU;
398*03f9172cSAndroid Build Coastguard Worker break;
399*03f9172cSAndroid Build Coastguard Worker }
400*03f9172cSAndroid Build Coastguard Worker } else if (oid.len == 7 &&
401*03f9172cSAndroid Build Coastguard Worker oid.oid[0] == 1 && oid.oid[1] == 2 &&
402*03f9172cSAndroid Build Coastguard Worker oid.oid[2] == 840 && oid.oid[3] == 113549 &&
403*03f9172cSAndroid Build Coastguard Worker oid.oid[4] == 1 && oid.oid[5] == 9 &&
404*03f9172cSAndroid Build Coastguard Worker oid.oid[6] == 1) {
405*03f9172cSAndroid Build Coastguard Worker /* 1.2.840.113549.1.9.1 - e-mailAddress */
406*03f9172cSAndroid Build Coastguard Worker os_free(name->email);
407*03f9172cSAndroid Build Coastguard Worker name->email = os_malloc(hdr.length + 1);
408*03f9172cSAndroid Build Coastguard Worker if (name->email == NULL) {
409*03f9172cSAndroid Build Coastguard Worker x509_free_name(name);
410*03f9172cSAndroid Build Coastguard Worker return -1;
411*03f9172cSAndroid Build Coastguard Worker }
412*03f9172cSAndroid Build Coastguard Worker os_memcpy(name->email, hdr.payload, hdr.length);
413*03f9172cSAndroid Build Coastguard Worker name->email[hdr.length] = '\0';
414*03f9172cSAndroid Build Coastguard Worker continue;
415*03f9172cSAndroid Build Coastguard Worker } else if (oid.len == 7 &&
416*03f9172cSAndroid Build Coastguard Worker oid.oid[0] == 0 && oid.oid[1] == 9 &&
417*03f9172cSAndroid Build Coastguard Worker oid.oid[2] == 2342 && oid.oid[3] == 19200300 &&
418*03f9172cSAndroid Build Coastguard Worker oid.oid[4] == 100 && oid.oid[5] == 1 &&
419*03f9172cSAndroid Build Coastguard Worker oid.oid[6] == 25) {
420*03f9172cSAndroid Build Coastguard Worker /* 0.9.2342.19200300.100.1.25 - domainComponent */
421*03f9172cSAndroid Build Coastguard Worker type = X509_NAME_ATTR_DC;
422*03f9172cSAndroid Build Coastguard Worker }
423*03f9172cSAndroid Build Coastguard Worker
424*03f9172cSAndroid Build Coastguard Worker if (type == X509_NAME_ATTR_NOT_USED) {
425*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_DEBUG, "X509: Unrecognized OID",
426*03f9172cSAndroid Build Coastguard Worker (u8 *) oid.oid,
427*03f9172cSAndroid Build Coastguard Worker oid.len * sizeof(oid.oid[0]));
428*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_MSGDUMP, "X509: Attribute Data",
429*03f9172cSAndroid Build Coastguard Worker hdr.payload, hdr.length);
430*03f9172cSAndroid Build Coastguard Worker continue;
431*03f9172cSAndroid Build Coastguard Worker }
432*03f9172cSAndroid Build Coastguard Worker
433*03f9172cSAndroid Build Coastguard Worker if (name->num_attr == X509_MAX_NAME_ATTRIBUTES) {
434*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_INFO, "X509: Too many Name attributes");
435*03f9172cSAndroid Build Coastguard Worker x509_free_name(name);
436*03f9172cSAndroid Build Coastguard Worker return -1;
437*03f9172cSAndroid Build Coastguard Worker }
438*03f9172cSAndroid Build Coastguard Worker
439*03f9172cSAndroid Build Coastguard Worker val = dup_binstr(hdr.payload, hdr.length);
440*03f9172cSAndroid Build Coastguard Worker if (val == NULL) {
441*03f9172cSAndroid Build Coastguard Worker x509_free_name(name);
442*03f9172cSAndroid Build Coastguard Worker return -1;
443*03f9172cSAndroid Build Coastguard Worker }
444*03f9172cSAndroid Build Coastguard Worker if (os_strlen(val) != hdr.length) {
445*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_INFO, "X509: Reject certificate with "
446*03f9172cSAndroid Build Coastguard Worker "embedded NUL byte in a string (%s[NUL])",
447*03f9172cSAndroid Build Coastguard Worker val);
448*03f9172cSAndroid Build Coastguard Worker os_free(val);
449*03f9172cSAndroid Build Coastguard Worker x509_free_name(name);
450*03f9172cSAndroid Build Coastguard Worker return -1;
451*03f9172cSAndroid Build Coastguard Worker }
452*03f9172cSAndroid Build Coastguard Worker
453*03f9172cSAndroid Build Coastguard Worker name->attr[name->num_attr].type = type;
454*03f9172cSAndroid Build Coastguard Worker name->attr[name->num_attr].value = val;
455*03f9172cSAndroid Build Coastguard Worker name->num_attr++;
456*03f9172cSAndroid Build Coastguard Worker }
457*03f9172cSAndroid Build Coastguard Worker
458*03f9172cSAndroid Build Coastguard Worker return 0;
459*03f9172cSAndroid Build Coastguard Worker }
460*03f9172cSAndroid Build Coastguard Worker
461*03f9172cSAndroid Build Coastguard Worker
x509_name_attr_str(enum x509_name_attr_type type)462*03f9172cSAndroid Build Coastguard Worker static char * x509_name_attr_str(enum x509_name_attr_type type)
463*03f9172cSAndroid Build Coastguard Worker {
464*03f9172cSAndroid Build Coastguard Worker switch (type) {
465*03f9172cSAndroid Build Coastguard Worker case X509_NAME_ATTR_NOT_USED:
466*03f9172cSAndroid Build Coastguard Worker return "[N/A]";
467*03f9172cSAndroid Build Coastguard Worker case X509_NAME_ATTR_DC:
468*03f9172cSAndroid Build Coastguard Worker return "DC";
469*03f9172cSAndroid Build Coastguard Worker case X509_NAME_ATTR_CN:
470*03f9172cSAndroid Build Coastguard Worker return "CN";
471*03f9172cSAndroid Build Coastguard Worker case X509_NAME_ATTR_C:
472*03f9172cSAndroid Build Coastguard Worker return "C";
473*03f9172cSAndroid Build Coastguard Worker case X509_NAME_ATTR_L:
474*03f9172cSAndroid Build Coastguard Worker return "L";
475*03f9172cSAndroid Build Coastguard Worker case X509_NAME_ATTR_ST:
476*03f9172cSAndroid Build Coastguard Worker return "ST";
477*03f9172cSAndroid Build Coastguard Worker case X509_NAME_ATTR_O:
478*03f9172cSAndroid Build Coastguard Worker return "O";
479*03f9172cSAndroid Build Coastguard Worker case X509_NAME_ATTR_OU:
480*03f9172cSAndroid Build Coastguard Worker return "OU";
481*03f9172cSAndroid Build Coastguard Worker }
482*03f9172cSAndroid Build Coastguard Worker return "?";
483*03f9172cSAndroid Build Coastguard Worker }
484*03f9172cSAndroid Build Coastguard Worker
485*03f9172cSAndroid Build Coastguard Worker
486*03f9172cSAndroid Build Coastguard Worker /**
487*03f9172cSAndroid Build Coastguard Worker * x509_name_string - Convert an X.509 certificate name into a string
488*03f9172cSAndroid Build Coastguard Worker * @name: Name to convert
489*03f9172cSAndroid Build Coastguard Worker * @buf: Buffer for the string
490*03f9172cSAndroid Build Coastguard Worker * @len: Maximum buffer length
491*03f9172cSAndroid Build Coastguard Worker */
x509_name_string(struct x509_name * name,char * buf,size_t len)492*03f9172cSAndroid Build Coastguard Worker void x509_name_string(struct x509_name *name, char *buf, size_t len)
493*03f9172cSAndroid Build Coastguard Worker {
494*03f9172cSAndroid Build Coastguard Worker char *pos, *end;
495*03f9172cSAndroid Build Coastguard Worker int ret;
496*03f9172cSAndroid Build Coastguard Worker size_t i;
497*03f9172cSAndroid Build Coastguard Worker
498*03f9172cSAndroid Build Coastguard Worker if (len == 0)
499*03f9172cSAndroid Build Coastguard Worker return;
500*03f9172cSAndroid Build Coastguard Worker
501*03f9172cSAndroid Build Coastguard Worker pos = buf;
502*03f9172cSAndroid Build Coastguard Worker end = buf + len;
503*03f9172cSAndroid Build Coastguard Worker
504*03f9172cSAndroid Build Coastguard Worker for (i = 0; i < name->num_attr; i++) {
505*03f9172cSAndroid Build Coastguard Worker ret = os_snprintf(pos, end - pos, "%s=%s, ",
506*03f9172cSAndroid Build Coastguard Worker x509_name_attr_str(name->attr[i].type),
507*03f9172cSAndroid Build Coastguard Worker name->attr[i].value);
508*03f9172cSAndroid Build Coastguard Worker if (os_snprintf_error(end - pos, ret))
509*03f9172cSAndroid Build Coastguard Worker goto done;
510*03f9172cSAndroid Build Coastguard Worker pos += ret;
511*03f9172cSAndroid Build Coastguard Worker }
512*03f9172cSAndroid Build Coastguard Worker
513*03f9172cSAndroid Build Coastguard Worker if (pos > buf + 1 && pos[-1] == ' ' && pos[-2] == ',') {
514*03f9172cSAndroid Build Coastguard Worker pos--;
515*03f9172cSAndroid Build Coastguard Worker *pos = '\0';
516*03f9172cSAndroid Build Coastguard Worker pos--;
517*03f9172cSAndroid Build Coastguard Worker *pos = '\0';
518*03f9172cSAndroid Build Coastguard Worker }
519*03f9172cSAndroid Build Coastguard Worker
520*03f9172cSAndroid Build Coastguard Worker if (name->email) {
521*03f9172cSAndroid Build Coastguard Worker ret = os_snprintf(pos, end - pos, "/emailAddress=%s",
522*03f9172cSAndroid Build Coastguard Worker name->email);
523*03f9172cSAndroid Build Coastguard Worker if (os_snprintf_error(end - pos, ret))
524*03f9172cSAndroid Build Coastguard Worker goto done;
525*03f9172cSAndroid Build Coastguard Worker pos += ret;
526*03f9172cSAndroid Build Coastguard Worker }
527*03f9172cSAndroid Build Coastguard Worker
528*03f9172cSAndroid Build Coastguard Worker done:
529*03f9172cSAndroid Build Coastguard Worker if (pos < end)
530*03f9172cSAndroid Build Coastguard Worker *pos = '\0';
531*03f9172cSAndroid Build Coastguard Worker end[-1] = '\0';
532*03f9172cSAndroid Build Coastguard Worker }
533*03f9172cSAndroid Build Coastguard Worker
534*03f9172cSAndroid Build Coastguard Worker
parse_uint2(const char * pos,size_t len)535*03f9172cSAndroid Build Coastguard Worker static int parse_uint2(const char *pos, size_t len)
536*03f9172cSAndroid Build Coastguard Worker {
537*03f9172cSAndroid Build Coastguard Worker char buf[3];
538*03f9172cSAndroid Build Coastguard Worker int ret;
539*03f9172cSAndroid Build Coastguard Worker
540*03f9172cSAndroid Build Coastguard Worker if (len < 2)
541*03f9172cSAndroid Build Coastguard Worker return -1;
542*03f9172cSAndroid Build Coastguard Worker buf[0] = pos[0];
543*03f9172cSAndroid Build Coastguard Worker buf[1] = pos[1];
544*03f9172cSAndroid Build Coastguard Worker buf[2] = 0x00;
545*03f9172cSAndroid Build Coastguard Worker if (sscanf(buf, "%2d", &ret) != 1)
546*03f9172cSAndroid Build Coastguard Worker return -1;
547*03f9172cSAndroid Build Coastguard Worker return ret;
548*03f9172cSAndroid Build Coastguard Worker }
549*03f9172cSAndroid Build Coastguard Worker
550*03f9172cSAndroid Build Coastguard Worker
parse_uint4(const char * pos,size_t len)551*03f9172cSAndroid Build Coastguard Worker static int parse_uint4(const char *pos, size_t len)
552*03f9172cSAndroid Build Coastguard Worker {
553*03f9172cSAndroid Build Coastguard Worker char buf[5];
554*03f9172cSAndroid Build Coastguard Worker int ret;
555*03f9172cSAndroid Build Coastguard Worker
556*03f9172cSAndroid Build Coastguard Worker if (len < 4)
557*03f9172cSAndroid Build Coastguard Worker return -1;
558*03f9172cSAndroid Build Coastguard Worker buf[0] = pos[0];
559*03f9172cSAndroid Build Coastguard Worker buf[1] = pos[1];
560*03f9172cSAndroid Build Coastguard Worker buf[2] = pos[2];
561*03f9172cSAndroid Build Coastguard Worker buf[3] = pos[3];
562*03f9172cSAndroid Build Coastguard Worker buf[4] = 0x00;
563*03f9172cSAndroid Build Coastguard Worker if (sscanf(buf, "%4d", &ret) != 1)
564*03f9172cSAndroid Build Coastguard Worker return -1;
565*03f9172cSAndroid Build Coastguard Worker return ret;
566*03f9172cSAndroid Build Coastguard Worker }
567*03f9172cSAndroid Build Coastguard Worker
568*03f9172cSAndroid Build Coastguard Worker
x509_parse_time(const u8 * buf,size_t len,u8 asn1_tag,os_time_t * val)569*03f9172cSAndroid Build Coastguard Worker int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, os_time_t *val)
570*03f9172cSAndroid Build Coastguard Worker {
571*03f9172cSAndroid Build Coastguard Worker const char *pos, *end;
572*03f9172cSAndroid Build Coastguard Worker int year, month, day, hour, min, sec;
573*03f9172cSAndroid Build Coastguard Worker
574*03f9172cSAndroid Build Coastguard Worker /*
575*03f9172cSAndroid Build Coastguard Worker * Time ::= CHOICE {
576*03f9172cSAndroid Build Coastguard Worker * utcTime UTCTime,
577*03f9172cSAndroid Build Coastguard Worker * generalTime GeneralizedTime
578*03f9172cSAndroid Build Coastguard Worker * }
579*03f9172cSAndroid Build Coastguard Worker *
580*03f9172cSAndroid Build Coastguard Worker * UTCTime: YYMMDDHHMMSSZ
581*03f9172cSAndroid Build Coastguard Worker * GeneralizedTime: YYYYMMDDHHMMSSZ
582*03f9172cSAndroid Build Coastguard Worker */
583*03f9172cSAndroid Build Coastguard Worker
584*03f9172cSAndroid Build Coastguard Worker pos = (const char *) buf;
585*03f9172cSAndroid Build Coastguard Worker end = pos + len;
586*03f9172cSAndroid Build Coastguard Worker
587*03f9172cSAndroid Build Coastguard Worker switch (asn1_tag) {
588*03f9172cSAndroid Build Coastguard Worker case ASN1_TAG_UTCTIME:
589*03f9172cSAndroid Build Coastguard Worker if (len != 13 || buf[12] != 'Z') {
590*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized "
591*03f9172cSAndroid Build Coastguard Worker "UTCTime format", buf, len);
592*03f9172cSAndroid Build Coastguard Worker return -1;
593*03f9172cSAndroid Build Coastguard Worker }
594*03f9172cSAndroid Build Coastguard Worker year = parse_uint2(pos, end - pos);
595*03f9172cSAndroid Build Coastguard Worker if (year < 0) {
596*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
597*03f9172cSAndroid Build Coastguard Worker "UTCTime year", buf, len);
598*03f9172cSAndroid Build Coastguard Worker return -1;
599*03f9172cSAndroid Build Coastguard Worker }
600*03f9172cSAndroid Build Coastguard Worker if (year < 50)
601*03f9172cSAndroid Build Coastguard Worker year += 2000;
602*03f9172cSAndroid Build Coastguard Worker else
603*03f9172cSAndroid Build Coastguard Worker year += 1900;
604*03f9172cSAndroid Build Coastguard Worker pos += 2;
605*03f9172cSAndroid Build Coastguard Worker break;
606*03f9172cSAndroid Build Coastguard Worker case ASN1_TAG_GENERALIZEDTIME:
607*03f9172cSAndroid Build Coastguard Worker if (len != 15 || buf[14] != 'Z') {
608*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized "
609*03f9172cSAndroid Build Coastguard Worker "GeneralizedTime format", buf, len);
610*03f9172cSAndroid Build Coastguard Worker return -1;
611*03f9172cSAndroid Build Coastguard Worker }
612*03f9172cSAndroid Build Coastguard Worker year = parse_uint4(pos, end - pos);
613*03f9172cSAndroid Build Coastguard Worker if (year < 0) {
614*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
615*03f9172cSAndroid Build Coastguard Worker "GeneralizedTime year", buf, len);
616*03f9172cSAndroid Build Coastguard Worker return -1;
617*03f9172cSAndroid Build Coastguard Worker }
618*03f9172cSAndroid Build Coastguard Worker pos += 4;
619*03f9172cSAndroid Build Coastguard Worker break;
620*03f9172cSAndroid Build Coastguard Worker default:
621*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Expected UTCTime or "
622*03f9172cSAndroid Build Coastguard Worker "GeneralizedTime - found tag 0x%x", asn1_tag);
623*03f9172cSAndroid Build Coastguard Worker return -1;
624*03f9172cSAndroid Build Coastguard Worker }
625*03f9172cSAndroid Build Coastguard Worker
626*03f9172cSAndroid Build Coastguard Worker month = parse_uint2(pos, end - pos);
627*03f9172cSAndroid Build Coastguard Worker if (month < 0) {
628*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
629*03f9172cSAndroid Build Coastguard Worker "(month)", buf, len);
630*03f9172cSAndroid Build Coastguard Worker return -1;
631*03f9172cSAndroid Build Coastguard Worker }
632*03f9172cSAndroid Build Coastguard Worker pos += 2;
633*03f9172cSAndroid Build Coastguard Worker
634*03f9172cSAndroid Build Coastguard Worker day = parse_uint2(pos, end - pos);
635*03f9172cSAndroid Build Coastguard Worker if (day < 0) {
636*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
637*03f9172cSAndroid Build Coastguard Worker "(day)", buf, len);
638*03f9172cSAndroid Build Coastguard Worker return -1;
639*03f9172cSAndroid Build Coastguard Worker }
640*03f9172cSAndroid Build Coastguard Worker pos += 2;
641*03f9172cSAndroid Build Coastguard Worker
642*03f9172cSAndroid Build Coastguard Worker hour = parse_uint2(pos, end - pos);
643*03f9172cSAndroid Build Coastguard Worker if (hour < 0) {
644*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
645*03f9172cSAndroid Build Coastguard Worker "(hour)", buf, len);
646*03f9172cSAndroid Build Coastguard Worker return -1;
647*03f9172cSAndroid Build Coastguard Worker }
648*03f9172cSAndroid Build Coastguard Worker pos += 2;
649*03f9172cSAndroid Build Coastguard Worker
650*03f9172cSAndroid Build Coastguard Worker min = parse_uint2(pos, end - pos);
651*03f9172cSAndroid Build Coastguard Worker if (min < 0) {
652*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
653*03f9172cSAndroid Build Coastguard Worker "(min)", buf, len);
654*03f9172cSAndroid Build Coastguard Worker return -1;
655*03f9172cSAndroid Build Coastguard Worker }
656*03f9172cSAndroid Build Coastguard Worker pos += 2;
657*03f9172cSAndroid Build Coastguard Worker
658*03f9172cSAndroid Build Coastguard Worker sec = parse_uint2(pos, end - pos);
659*03f9172cSAndroid Build Coastguard Worker if (sec < 0) {
660*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
661*03f9172cSAndroid Build Coastguard Worker "(sec)", buf, len);
662*03f9172cSAndroid Build Coastguard Worker return -1;
663*03f9172cSAndroid Build Coastguard Worker }
664*03f9172cSAndroid Build Coastguard Worker
665*03f9172cSAndroid Build Coastguard Worker if (os_mktime(year, month, day, hour, min, sec, val) < 0) {
666*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to convert Time",
667*03f9172cSAndroid Build Coastguard Worker buf, len);
668*03f9172cSAndroid Build Coastguard Worker if (year < 1970) {
669*03f9172cSAndroid Build Coastguard Worker /*
670*03f9172cSAndroid Build Coastguard Worker * At least some test certificates have been configured
671*03f9172cSAndroid Build Coastguard Worker * to use dates prior to 1970. Set the date to
672*03f9172cSAndroid Build Coastguard Worker * beginning of 1970 to handle these case.
673*03f9172cSAndroid Build Coastguard Worker */
674*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Year=%d before epoch - "
675*03f9172cSAndroid Build Coastguard Worker "assume epoch as the time", year);
676*03f9172cSAndroid Build Coastguard Worker *val = 0;
677*03f9172cSAndroid Build Coastguard Worker return 0;
678*03f9172cSAndroid Build Coastguard Worker }
679*03f9172cSAndroid Build Coastguard Worker return -1;
680*03f9172cSAndroid Build Coastguard Worker }
681*03f9172cSAndroid Build Coastguard Worker
682*03f9172cSAndroid Build Coastguard Worker return 0;
683*03f9172cSAndroid Build Coastguard Worker }
684*03f9172cSAndroid Build Coastguard Worker
685*03f9172cSAndroid Build Coastguard Worker
x509_parse_validity(const u8 * buf,size_t len,struct x509_certificate * cert,const u8 ** next)686*03f9172cSAndroid Build Coastguard Worker static int x509_parse_validity(const u8 *buf, size_t len,
687*03f9172cSAndroid Build Coastguard Worker struct x509_certificate *cert, const u8 **next)
688*03f9172cSAndroid Build Coastguard Worker {
689*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
690*03f9172cSAndroid Build Coastguard Worker const u8 *pos;
691*03f9172cSAndroid Build Coastguard Worker size_t plen;
692*03f9172cSAndroid Build Coastguard Worker
693*03f9172cSAndroid Build Coastguard Worker /*
694*03f9172cSAndroid Build Coastguard Worker * Validity ::= SEQUENCE {
695*03f9172cSAndroid Build Coastguard Worker * notBefore Time,
696*03f9172cSAndroid Build Coastguard Worker * notAfter Time
697*03f9172cSAndroid Build Coastguard Worker * }
698*03f9172cSAndroid Build Coastguard Worker *
699*03f9172cSAndroid Build Coastguard Worker * RFC 3280, 4.1.2.5:
700*03f9172cSAndroid Build Coastguard Worker * CAs conforming to this profile MUST always encode certificate
701*03f9172cSAndroid Build Coastguard Worker * validity dates through the year 2049 as UTCTime; certificate
702*03f9172cSAndroid Build Coastguard Worker * validity dates in 2050 or later MUST be encoded as GeneralizedTime.
703*03f9172cSAndroid Build Coastguard Worker */
704*03f9172cSAndroid Build Coastguard Worker
705*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
706*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr, "X509: Expected SEQUENCE (Validity)");
707*03f9172cSAndroid Build Coastguard Worker return -1;
708*03f9172cSAndroid Build Coastguard Worker }
709*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
710*03f9172cSAndroid Build Coastguard Worker plen = hdr.length;
711*03f9172cSAndroid Build Coastguard Worker
712*03f9172cSAndroid Build Coastguard Worker if (plen > (size_t) (buf + len - pos))
713*03f9172cSAndroid Build Coastguard Worker return -1;
714*03f9172cSAndroid Build Coastguard Worker
715*03f9172cSAndroid Build Coastguard Worker *next = pos + plen;
716*03f9172cSAndroid Build Coastguard Worker
717*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, plen, &hdr) < 0 ||
718*03f9172cSAndroid Build Coastguard Worker (!asn1_is_utctime(&hdr) && !asn1_is_generalizedtime(&hdr)) ||
719*03f9172cSAndroid Build Coastguard Worker x509_parse_time(hdr.payload, hdr.length, hdr.tag,
720*03f9172cSAndroid Build Coastguard Worker &cert->not_before) < 0) {
721*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notBefore "
722*03f9172cSAndroid Build Coastguard Worker "Time", hdr.payload, hdr.length);
723*03f9172cSAndroid Build Coastguard Worker return -1;
724*03f9172cSAndroid Build Coastguard Worker }
725*03f9172cSAndroid Build Coastguard Worker
726*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload + hdr.length;
727*03f9172cSAndroid Build Coastguard Worker plen = *next - pos;
728*03f9172cSAndroid Build Coastguard Worker
729*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, plen, &hdr) < 0 ||
730*03f9172cSAndroid Build Coastguard Worker (!asn1_is_utctime(&hdr) && !asn1_is_generalizedtime(&hdr)) ||
731*03f9172cSAndroid Build Coastguard Worker x509_parse_time(hdr.payload, hdr.length, hdr.tag,
732*03f9172cSAndroid Build Coastguard Worker &cert->not_after) < 0) {
733*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notAfter "
734*03f9172cSAndroid Build Coastguard Worker "Time", hdr.payload, hdr.length);
735*03f9172cSAndroid Build Coastguard Worker return -1;
736*03f9172cSAndroid Build Coastguard Worker }
737*03f9172cSAndroid Build Coastguard Worker
738*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_MSGDUMP, "X509: Validity: notBefore: %lu notAfter: %lu",
739*03f9172cSAndroid Build Coastguard Worker (unsigned long) cert->not_before,
740*03f9172cSAndroid Build Coastguard Worker (unsigned long) cert->not_after);
741*03f9172cSAndroid Build Coastguard Worker
742*03f9172cSAndroid Build Coastguard Worker return 0;
743*03f9172cSAndroid Build Coastguard Worker }
744*03f9172cSAndroid Build Coastguard Worker
745*03f9172cSAndroid Build Coastguard Worker
x509_id_ce_oid(struct asn1_oid * oid)746*03f9172cSAndroid Build Coastguard Worker static int x509_id_ce_oid(struct asn1_oid *oid)
747*03f9172cSAndroid Build Coastguard Worker {
748*03f9172cSAndroid Build Coastguard Worker /* id-ce arc from X.509 for standard X.509v3 extensions */
749*03f9172cSAndroid Build Coastguard Worker return oid->len >= 4 &&
750*03f9172cSAndroid Build Coastguard Worker oid->oid[0] == 2 /* joint-iso-ccitt */ &&
751*03f9172cSAndroid Build Coastguard Worker oid->oid[1] == 5 /* ds */ &&
752*03f9172cSAndroid Build Coastguard Worker oid->oid[2] == 29 /* id-ce */;
753*03f9172cSAndroid Build Coastguard Worker }
754*03f9172cSAndroid Build Coastguard Worker
755*03f9172cSAndroid Build Coastguard Worker
x509_any_ext_key_usage_oid(struct asn1_oid * oid)756*03f9172cSAndroid Build Coastguard Worker static int x509_any_ext_key_usage_oid(struct asn1_oid *oid)
757*03f9172cSAndroid Build Coastguard Worker {
758*03f9172cSAndroid Build Coastguard Worker return oid->len == 6 &&
759*03f9172cSAndroid Build Coastguard Worker x509_id_ce_oid(oid) &&
760*03f9172cSAndroid Build Coastguard Worker oid->oid[3] == 37 /* extKeyUsage */ &&
761*03f9172cSAndroid Build Coastguard Worker oid->oid[4] == 0 /* anyExtendedKeyUsage */;
762*03f9172cSAndroid Build Coastguard Worker }
763*03f9172cSAndroid Build Coastguard Worker
764*03f9172cSAndroid Build Coastguard Worker
x509_parse_ext_key_usage(struct x509_certificate * cert,const u8 * pos,size_t len)765*03f9172cSAndroid Build Coastguard Worker static int x509_parse_ext_key_usage(struct x509_certificate *cert,
766*03f9172cSAndroid Build Coastguard Worker const u8 *pos, size_t len)
767*03f9172cSAndroid Build Coastguard Worker {
768*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
769*03f9172cSAndroid Build Coastguard Worker
770*03f9172cSAndroid Build Coastguard Worker /*
771*03f9172cSAndroid Build Coastguard Worker * KeyUsage ::= BIT STRING {
772*03f9172cSAndroid Build Coastguard Worker * digitalSignature (0),
773*03f9172cSAndroid Build Coastguard Worker * nonRepudiation (1),
774*03f9172cSAndroid Build Coastguard Worker * keyEncipherment (2),
775*03f9172cSAndroid Build Coastguard Worker * dataEncipherment (3),
776*03f9172cSAndroid Build Coastguard Worker * keyAgreement (4),
777*03f9172cSAndroid Build Coastguard Worker * keyCertSign (5),
778*03f9172cSAndroid Build Coastguard Worker * cRLSign (6),
779*03f9172cSAndroid Build Coastguard Worker * encipherOnly (7),
780*03f9172cSAndroid Build Coastguard Worker * decipherOnly (8) }
781*03f9172cSAndroid Build Coastguard Worker */
782*03f9172cSAndroid Build Coastguard Worker
783*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_bitstring(&hdr) ||
784*03f9172cSAndroid Build Coastguard Worker hdr.length < 1) {
785*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr, "X509: Expected BIT STRING in KeyUsage");
786*03f9172cSAndroid Build Coastguard Worker return -1;
787*03f9172cSAndroid Build Coastguard Worker }
788*03f9172cSAndroid Build Coastguard Worker
789*03f9172cSAndroid Build Coastguard Worker cert->extensions_present |= X509_EXT_KEY_USAGE;
790*03f9172cSAndroid Build Coastguard Worker cert->key_usage = asn1_bit_string_to_long(hdr.payload, hdr.length);
791*03f9172cSAndroid Build Coastguard Worker
792*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: KeyUsage 0x%lx", cert->key_usage);
793*03f9172cSAndroid Build Coastguard Worker
794*03f9172cSAndroid Build Coastguard Worker return 0;
795*03f9172cSAndroid Build Coastguard Worker }
796*03f9172cSAndroid Build Coastguard Worker
797*03f9172cSAndroid Build Coastguard Worker
x509_parse_ext_basic_constraints(struct x509_certificate * cert,const u8 * pos,size_t len)798*03f9172cSAndroid Build Coastguard Worker static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,
799*03f9172cSAndroid Build Coastguard Worker const u8 *pos, size_t len)
800*03f9172cSAndroid Build Coastguard Worker {
801*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
802*03f9172cSAndroid Build Coastguard Worker unsigned long value;
803*03f9172cSAndroid Build Coastguard Worker size_t left;
804*03f9172cSAndroid Build Coastguard Worker const u8 *end_seq;
805*03f9172cSAndroid Build Coastguard Worker
806*03f9172cSAndroid Build Coastguard Worker /*
807*03f9172cSAndroid Build Coastguard Worker * BasicConstraints ::= SEQUENCE {
808*03f9172cSAndroid Build Coastguard Worker * cA BOOLEAN DEFAULT FALSE,
809*03f9172cSAndroid Build Coastguard Worker * pathLenConstraint INTEGER (0..MAX) OPTIONAL }
810*03f9172cSAndroid Build Coastguard Worker */
811*03f9172cSAndroid Build Coastguard Worker
812*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
813*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
814*03f9172cSAndroid Build Coastguard Worker "X509: Expected SEQUENCE in BasicConstraints");
815*03f9172cSAndroid Build Coastguard Worker return -1;
816*03f9172cSAndroid Build Coastguard Worker }
817*03f9172cSAndroid Build Coastguard Worker
818*03f9172cSAndroid Build Coastguard Worker cert->extensions_present |= X509_EXT_BASIC_CONSTRAINTS;
819*03f9172cSAndroid Build Coastguard Worker
820*03f9172cSAndroid Build Coastguard Worker if (hdr.length == 0)
821*03f9172cSAndroid Build Coastguard Worker return 0;
822*03f9172cSAndroid Build Coastguard Worker
823*03f9172cSAndroid Build Coastguard Worker end_seq = hdr.payload + hdr.length;
824*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0) {
825*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Failed to parse "
826*03f9172cSAndroid Build Coastguard Worker "BasicConstraints");
827*03f9172cSAndroid Build Coastguard Worker return -1;
828*03f9172cSAndroid Build Coastguard Worker }
829*03f9172cSAndroid Build Coastguard Worker
830*03f9172cSAndroid Build Coastguard Worker if (asn1_is_boolean(&hdr)) {
831*03f9172cSAndroid Build Coastguard Worker cert->ca = hdr.payload[0];
832*03f9172cSAndroid Build Coastguard Worker
833*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload + hdr.length;
834*03f9172cSAndroid Build Coastguard Worker if (pos >= end_seq) {
835*03f9172cSAndroid Build Coastguard Worker /* No optional pathLenConstraint */
836*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d",
837*03f9172cSAndroid Build Coastguard Worker cert->ca);
838*03f9172cSAndroid Build Coastguard Worker return 0;
839*03f9172cSAndroid Build Coastguard Worker }
840*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end_seq - pos, &hdr) < 0) {
841*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Failed to parse "
842*03f9172cSAndroid Build Coastguard Worker "BasicConstraints");
843*03f9172cSAndroid Build Coastguard Worker return -1;
844*03f9172cSAndroid Build Coastguard Worker }
845*03f9172cSAndroid Build Coastguard Worker }
846*03f9172cSAndroid Build Coastguard Worker
847*03f9172cSAndroid Build Coastguard Worker if (!asn1_is_integer(&hdr)) {
848*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
849*03f9172cSAndroid Build Coastguard Worker "X509: Expected INTEGER in BasicConstraints");
850*03f9172cSAndroid Build Coastguard Worker return -1;
851*03f9172cSAndroid Build Coastguard Worker }
852*03f9172cSAndroid Build Coastguard Worker
853*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
854*03f9172cSAndroid Build Coastguard Worker left = hdr.length;
855*03f9172cSAndroid Build Coastguard Worker value = 0;
856*03f9172cSAndroid Build Coastguard Worker while (left) {
857*03f9172cSAndroid Build Coastguard Worker value <<= 8;
858*03f9172cSAndroid Build Coastguard Worker value |= *pos++;
859*03f9172cSAndroid Build Coastguard Worker left--;
860*03f9172cSAndroid Build Coastguard Worker }
861*03f9172cSAndroid Build Coastguard Worker
862*03f9172cSAndroid Build Coastguard Worker cert->path_len_constraint = value;
863*03f9172cSAndroid Build Coastguard Worker cert->extensions_present |= X509_EXT_PATH_LEN_CONSTRAINT;
864*03f9172cSAndroid Build Coastguard Worker
865*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d "
866*03f9172cSAndroid Build Coastguard Worker "pathLenConstraint=%lu",
867*03f9172cSAndroid Build Coastguard Worker cert->ca, cert->path_len_constraint);
868*03f9172cSAndroid Build Coastguard Worker
869*03f9172cSAndroid Build Coastguard Worker return 0;
870*03f9172cSAndroid Build Coastguard Worker }
871*03f9172cSAndroid Build Coastguard Worker
872*03f9172cSAndroid Build Coastguard Worker
x509_parse_alt_name_rfc8222(struct x509_name * name,const u8 * pos,size_t len)873*03f9172cSAndroid Build Coastguard Worker static int x509_parse_alt_name_rfc8222(struct x509_name *name,
874*03f9172cSAndroid Build Coastguard Worker const u8 *pos, size_t len)
875*03f9172cSAndroid Build Coastguard Worker {
876*03f9172cSAndroid Build Coastguard Worker /* rfc822Name IA5String */
877*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - rfc822Name", pos, len);
878*03f9172cSAndroid Build Coastguard Worker os_free(name->alt_email);
879*03f9172cSAndroid Build Coastguard Worker name->alt_email = os_zalloc(len + 1);
880*03f9172cSAndroid Build Coastguard Worker if (name->alt_email == NULL)
881*03f9172cSAndroid Build Coastguard Worker return -1;
882*03f9172cSAndroid Build Coastguard Worker os_memcpy(name->alt_email, pos, len);
883*03f9172cSAndroid Build Coastguard Worker if (os_strlen(name->alt_email) != len) {
884*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_INFO, "X509: Reject certificate with "
885*03f9172cSAndroid Build Coastguard Worker "embedded NUL byte in rfc822Name (%s[NUL])",
886*03f9172cSAndroid Build Coastguard Worker name->alt_email);
887*03f9172cSAndroid Build Coastguard Worker os_free(name->alt_email);
888*03f9172cSAndroid Build Coastguard Worker name->alt_email = NULL;
889*03f9172cSAndroid Build Coastguard Worker return -1;
890*03f9172cSAndroid Build Coastguard Worker }
891*03f9172cSAndroid Build Coastguard Worker return 0;
892*03f9172cSAndroid Build Coastguard Worker }
893*03f9172cSAndroid Build Coastguard Worker
894*03f9172cSAndroid Build Coastguard Worker
x509_parse_alt_name_dns(struct x509_name * name,const u8 * pos,size_t len)895*03f9172cSAndroid Build Coastguard Worker static int x509_parse_alt_name_dns(struct x509_name *name,
896*03f9172cSAndroid Build Coastguard Worker const u8 *pos, size_t len)
897*03f9172cSAndroid Build Coastguard Worker {
898*03f9172cSAndroid Build Coastguard Worker /* dNSName IA5String */
899*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - dNSName", pos, len);
900*03f9172cSAndroid Build Coastguard Worker os_free(name->dns);
901*03f9172cSAndroid Build Coastguard Worker name->dns = os_zalloc(len + 1);
902*03f9172cSAndroid Build Coastguard Worker if (name->dns == NULL)
903*03f9172cSAndroid Build Coastguard Worker return -1;
904*03f9172cSAndroid Build Coastguard Worker os_memcpy(name->dns, pos, len);
905*03f9172cSAndroid Build Coastguard Worker if (os_strlen(name->dns) != len) {
906*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_INFO, "X509: Reject certificate with "
907*03f9172cSAndroid Build Coastguard Worker "embedded NUL byte in dNSName (%s[NUL])",
908*03f9172cSAndroid Build Coastguard Worker name->dns);
909*03f9172cSAndroid Build Coastguard Worker os_free(name->dns);
910*03f9172cSAndroid Build Coastguard Worker name->dns = NULL;
911*03f9172cSAndroid Build Coastguard Worker return -1;
912*03f9172cSAndroid Build Coastguard Worker }
913*03f9172cSAndroid Build Coastguard Worker return 0;
914*03f9172cSAndroid Build Coastguard Worker }
915*03f9172cSAndroid Build Coastguard Worker
916*03f9172cSAndroid Build Coastguard Worker
x509_parse_alt_name_uri(struct x509_name * name,const u8 * pos,size_t len)917*03f9172cSAndroid Build Coastguard Worker static int x509_parse_alt_name_uri(struct x509_name *name,
918*03f9172cSAndroid Build Coastguard Worker const u8 *pos, size_t len)
919*03f9172cSAndroid Build Coastguard Worker {
920*03f9172cSAndroid Build Coastguard Worker /* uniformResourceIdentifier IA5String */
921*03f9172cSAndroid Build Coastguard Worker wpa_hexdump_ascii(MSG_MSGDUMP,
922*03f9172cSAndroid Build Coastguard Worker "X509: altName - uniformResourceIdentifier",
923*03f9172cSAndroid Build Coastguard Worker pos, len);
924*03f9172cSAndroid Build Coastguard Worker os_free(name->uri);
925*03f9172cSAndroid Build Coastguard Worker name->uri = os_zalloc(len + 1);
926*03f9172cSAndroid Build Coastguard Worker if (name->uri == NULL)
927*03f9172cSAndroid Build Coastguard Worker return -1;
928*03f9172cSAndroid Build Coastguard Worker os_memcpy(name->uri, pos, len);
929*03f9172cSAndroid Build Coastguard Worker if (os_strlen(name->uri) != len) {
930*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_INFO, "X509: Reject certificate with "
931*03f9172cSAndroid Build Coastguard Worker "embedded NUL byte in uniformResourceIdentifier "
932*03f9172cSAndroid Build Coastguard Worker "(%s[NUL])", name->uri);
933*03f9172cSAndroid Build Coastguard Worker os_free(name->uri);
934*03f9172cSAndroid Build Coastguard Worker name->uri = NULL;
935*03f9172cSAndroid Build Coastguard Worker return -1;
936*03f9172cSAndroid Build Coastguard Worker }
937*03f9172cSAndroid Build Coastguard Worker return 0;
938*03f9172cSAndroid Build Coastguard Worker }
939*03f9172cSAndroid Build Coastguard Worker
940*03f9172cSAndroid Build Coastguard Worker
x509_parse_alt_name_ip(struct x509_name * name,const u8 * pos,size_t len)941*03f9172cSAndroid Build Coastguard Worker static int x509_parse_alt_name_ip(struct x509_name *name,
942*03f9172cSAndroid Build Coastguard Worker const u8 *pos, size_t len)
943*03f9172cSAndroid Build Coastguard Worker {
944*03f9172cSAndroid Build Coastguard Worker /* iPAddress OCTET STRING */
945*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: altName - iPAddress", pos, len);
946*03f9172cSAndroid Build Coastguard Worker os_free(name->ip);
947*03f9172cSAndroid Build Coastguard Worker name->ip = os_memdup(pos, len);
948*03f9172cSAndroid Build Coastguard Worker if (name->ip == NULL)
949*03f9172cSAndroid Build Coastguard Worker return -1;
950*03f9172cSAndroid Build Coastguard Worker name->ip_len = len;
951*03f9172cSAndroid Build Coastguard Worker return 0;
952*03f9172cSAndroid Build Coastguard Worker }
953*03f9172cSAndroid Build Coastguard Worker
954*03f9172cSAndroid Build Coastguard Worker
x509_parse_alt_name_rid(struct x509_name * name,const u8 * pos,size_t len)955*03f9172cSAndroid Build Coastguard Worker static int x509_parse_alt_name_rid(struct x509_name *name,
956*03f9172cSAndroid Build Coastguard Worker const u8 *pos, size_t len)
957*03f9172cSAndroid Build Coastguard Worker {
958*03f9172cSAndroid Build Coastguard Worker char buf[80];
959*03f9172cSAndroid Build Coastguard Worker
960*03f9172cSAndroid Build Coastguard Worker /* registeredID OBJECT IDENTIFIER */
961*03f9172cSAndroid Build Coastguard Worker if (asn1_parse_oid(pos, len, &name->rid) < 0)
962*03f9172cSAndroid Build Coastguard Worker return -1;
963*03f9172cSAndroid Build Coastguard Worker
964*03f9172cSAndroid Build Coastguard Worker asn1_oid_to_str(&name->rid, buf, sizeof(buf));
965*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_MSGDUMP, "X509: altName - registeredID: %s", buf);
966*03f9172cSAndroid Build Coastguard Worker
967*03f9172cSAndroid Build Coastguard Worker return 0;
968*03f9172cSAndroid Build Coastguard Worker }
969*03f9172cSAndroid Build Coastguard Worker
970*03f9172cSAndroid Build Coastguard Worker
x509_parse_ext_alt_name(struct x509_name * name,const u8 * pos,size_t len)971*03f9172cSAndroid Build Coastguard Worker static int x509_parse_ext_alt_name(struct x509_name *name,
972*03f9172cSAndroid Build Coastguard Worker const u8 *pos, size_t len)
973*03f9172cSAndroid Build Coastguard Worker {
974*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
975*03f9172cSAndroid Build Coastguard Worker const u8 *p, *end;
976*03f9172cSAndroid Build Coastguard Worker
977*03f9172cSAndroid Build Coastguard Worker /*
978*03f9172cSAndroid Build Coastguard Worker * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
979*03f9172cSAndroid Build Coastguard Worker *
980*03f9172cSAndroid Build Coastguard Worker * GeneralName ::= CHOICE {
981*03f9172cSAndroid Build Coastguard Worker * otherName [0] OtherName,
982*03f9172cSAndroid Build Coastguard Worker * rfc822Name [1] IA5String,
983*03f9172cSAndroid Build Coastguard Worker * dNSName [2] IA5String,
984*03f9172cSAndroid Build Coastguard Worker * x400Address [3] ORAddress,
985*03f9172cSAndroid Build Coastguard Worker * directoryName [4] Name,
986*03f9172cSAndroid Build Coastguard Worker * ediPartyName [5] EDIPartyName,
987*03f9172cSAndroid Build Coastguard Worker * uniformResourceIdentifier [6] IA5String,
988*03f9172cSAndroid Build Coastguard Worker * iPAddress [7] OCTET STRING,
989*03f9172cSAndroid Build Coastguard Worker * registeredID [8] OBJECT IDENTIFIER }
990*03f9172cSAndroid Build Coastguard Worker *
991*03f9172cSAndroid Build Coastguard Worker * OtherName ::= SEQUENCE {
992*03f9172cSAndroid Build Coastguard Worker * type-id OBJECT IDENTIFIER,
993*03f9172cSAndroid Build Coastguard Worker * value [0] EXPLICIT ANY DEFINED BY type-id }
994*03f9172cSAndroid Build Coastguard Worker *
995*03f9172cSAndroid Build Coastguard Worker * EDIPartyName ::= SEQUENCE {
996*03f9172cSAndroid Build Coastguard Worker * nameAssigner [0] DirectoryString OPTIONAL,
997*03f9172cSAndroid Build Coastguard Worker * partyName [1] DirectoryString }
998*03f9172cSAndroid Build Coastguard Worker */
999*03f9172cSAndroid Build Coastguard Worker
1000*03f9172cSAndroid Build Coastguard Worker for (p = pos, end = pos + len; p < end; p = hdr.payload + hdr.length) {
1001*03f9172cSAndroid Build Coastguard Worker int res;
1002*03f9172cSAndroid Build Coastguard Worker
1003*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(p, end - p, &hdr) < 0) {
1004*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Failed to parse "
1005*03f9172cSAndroid Build Coastguard Worker "SubjectAltName item");
1006*03f9172cSAndroid Build Coastguard Worker return -1;
1007*03f9172cSAndroid Build Coastguard Worker }
1008*03f9172cSAndroid Build Coastguard Worker
1009*03f9172cSAndroid Build Coastguard Worker if (hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC)
1010*03f9172cSAndroid Build Coastguard Worker continue;
1011*03f9172cSAndroid Build Coastguard Worker
1012*03f9172cSAndroid Build Coastguard Worker switch (hdr.tag) {
1013*03f9172cSAndroid Build Coastguard Worker case 1:
1014*03f9172cSAndroid Build Coastguard Worker res = x509_parse_alt_name_rfc8222(name, hdr.payload,
1015*03f9172cSAndroid Build Coastguard Worker hdr.length);
1016*03f9172cSAndroid Build Coastguard Worker break;
1017*03f9172cSAndroid Build Coastguard Worker case 2:
1018*03f9172cSAndroid Build Coastguard Worker res = x509_parse_alt_name_dns(name, hdr.payload,
1019*03f9172cSAndroid Build Coastguard Worker hdr.length);
1020*03f9172cSAndroid Build Coastguard Worker break;
1021*03f9172cSAndroid Build Coastguard Worker case 6:
1022*03f9172cSAndroid Build Coastguard Worker res = x509_parse_alt_name_uri(name, hdr.payload,
1023*03f9172cSAndroid Build Coastguard Worker hdr.length);
1024*03f9172cSAndroid Build Coastguard Worker break;
1025*03f9172cSAndroid Build Coastguard Worker case 7:
1026*03f9172cSAndroid Build Coastguard Worker res = x509_parse_alt_name_ip(name, hdr.payload,
1027*03f9172cSAndroid Build Coastguard Worker hdr.length);
1028*03f9172cSAndroid Build Coastguard Worker break;
1029*03f9172cSAndroid Build Coastguard Worker case 8:
1030*03f9172cSAndroid Build Coastguard Worker res = x509_parse_alt_name_rid(name, hdr.payload,
1031*03f9172cSAndroid Build Coastguard Worker hdr.length);
1032*03f9172cSAndroid Build Coastguard Worker break;
1033*03f9172cSAndroid Build Coastguard Worker case 0: /* TODO: otherName */
1034*03f9172cSAndroid Build Coastguard Worker case 3: /* TODO: x500Address */
1035*03f9172cSAndroid Build Coastguard Worker case 4: /* TODO: directoryName */
1036*03f9172cSAndroid Build Coastguard Worker case 5: /* TODO: ediPartyName */
1037*03f9172cSAndroid Build Coastguard Worker default:
1038*03f9172cSAndroid Build Coastguard Worker res = 0;
1039*03f9172cSAndroid Build Coastguard Worker break;
1040*03f9172cSAndroid Build Coastguard Worker }
1041*03f9172cSAndroid Build Coastguard Worker if (res < 0)
1042*03f9172cSAndroid Build Coastguard Worker return res;
1043*03f9172cSAndroid Build Coastguard Worker }
1044*03f9172cSAndroid Build Coastguard Worker
1045*03f9172cSAndroid Build Coastguard Worker return 0;
1046*03f9172cSAndroid Build Coastguard Worker }
1047*03f9172cSAndroid Build Coastguard Worker
1048*03f9172cSAndroid Build Coastguard Worker
x509_parse_ext_subject_alt_name(struct x509_certificate * cert,const u8 * pos,size_t len)1049*03f9172cSAndroid Build Coastguard Worker static int x509_parse_ext_subject_alt_name(struct x509_certificate *cert,
1050*03f9172cSAndroid Build Coastguard Worker const u8 *pos, size_t len)
1051*03f9172cSAndroid Build Coastguard Worker {
1052*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
1053*03f9172cSAndroid Build Coastguard Worker
1054*03f9172cSAndroid Build Coastguard Worker /* SubjectAltName ::= GeneralNames */
1055*03f9172cSAndroid Build Coastguard Worker
1056*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
1057*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1058*03f9172cSAndroid Build Coastguard Worker "X509: Expected SEQUENCE in SubjectAltName");
1059*03f9172cSAndroid Build Coastguard Worker return -1;
1060*03f9172cSAndroid Build Coastguard Worker }
1061*03f9172cSAndroid Build Coastguard Worker
1062*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: SubjectAltName");
1063*03f9172cSAndroid Build Coastguard Worker cert->extensions_present |= X509_EXT_SUBJECT_ALT_NAME;
1064*03f9172cSAndroid Build Coastguard Worker
1065*03f9172cSAndroid Build Coastguard Worker if (hdr.length == 0)
1066*03f9172cSAndroid Build Coastguard Worker return 0;
1067*03f9172cSAndroid Build Coastguard Worker
1068*03f9172cSAndroid Build Coastguard Worker return x509_parse_ext_alt_name(&cert->subject, hdr.payload,
1069*03f9172cSAndroid Build Coastguard Worker hdr.length);
1070*03f9172cSAndroid Build Coastguard Worker }
1071*03f9172cSAndroid Build Coastguard Worker
1072*03f9172cSAndroid Build Coastguard Worker
x509_parse_ext_issuer_alt_name(struct x509_certificate * cert,const u8 * pos,size_t len)1073*03f9172cSAndroid Build Coastguard Worker static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,
1074*03f9172cSAndroid Build Coastguard Worker const u8 *pos, size_t len)
1075*03f9172cSAndroid Build Coastguard Worker {
1076*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
1077*03f9172cSAndroid Build Coastguard Worker
1078*03f9172cSAndroid Build Coastguard Worker /* IssuerAltName ::= GeneralNames */
1079*03f9172cSAndroid Build Coastguard Worker
1080*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
1081*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1082*03f9172cSAndroid Build Coastguard Worker "X509: Expected SEQUENCE in IssuerAltName");
1083*03f9172cSAndroid Build Coastguard Worker return -1;
1084*03f9172cSAndroid Build Coastguard Worker }
1085*03f9172cSAndroid Build Coastguard Worker
1086*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: IssuerAltName");
1087*03f9172cSAndroid Build Coastguard Worker cert->extensions_present |= X509_EXT_ISSUER_ALT_NAME;
1088*03f9172cSAndroid Build Coastguard Worker
1089*03f9172cSAndroid Build Coastguard Worker if (hdr.length == 0)
1090*03f9172cSAndroid Build Coastguard Worker return 0;
1091*03f9172cSAndroid Build Coastguard Worker
1092*03f9172cSAndroid Build Coastguard Worker return x509_parse_ext_alt_name(&cert->issuer, hdr.payload,
1093*03f9172cSAndroid Build Coastguard Worker hdr.length);
1094*03f9172cSAndroid Build Coastguard Worker }
1095*03f9172cSAndroid Build Coastguard Worker
1096*03f9172cSAndroid Build Coastguard Worker
x509_id_cert_policy_any_oid(struct asn1_oid * oid)1097*03f9172cSAndroid Build Coastguard Worker static int x509_id_cert_policy_any_oid(struct asn1_oid *oid)
1098*03f9172cSAndroid Build Coastguard Worker {
1099*03f9172cSAndroid Build Coastguard Worker return oid->len == 5 &&
1100*03f9172cSAndroid Build Coastguard Worker oid->oid[0] == 2 /* iso/itu-t */ &&
1101*03f9172cSAndroid Build Coastguard Worker oid->oid[1] == 5 /* X.500 Directory Services */ &&
1102*03f9172cSAndroid Build Coastguard Worker oid->oid[2] == 29 /* id-ce */ &&
1103*03f9172cSAndroid Build Coastguard Worker oid->oid[3] == 32 /* id-ce-certificate-policies */ &&
1104*03f9172cSAndroid Build Coastguard Worker oid->oid[4] == 0 /* anyPolicy */;
1105*03f9172cSAndroid Build Coastguard Worker }
1106*03f9172cSAndroid Build Coastguard Worker
1107*03f9172cSAndroid Build Coastguard Worker
x509_id_wfa_oid(struct asn1_oid * oid)1108*03f9172cSAndroid Build Coastguard Worker static int x509_id_wfa_oid(struct asn1_oid *oid)
1109*03f9172cSAndroid Build Coastguard Worker {
1110*03f9172cSAndroid Build Coastguard Worker return oid->len >= 7 &&
1111*03f9172cSAndroid Build Coastguard Worker oid->oid[0] == 1 /* iso */ &&
1112*03f9172cSAndroid Build Coastguard Worker oid->oid[1] == 3 /* identified-organization */ &&
1113*03f9172cSAndroid Build Coastguard Worker oid->oid[2] == 6 /* dod */ &&
1114*03f9172cSAndroid Build Coastguard Worker oid->oid[3] == 1 /* internet */ &&
1115*03f9172cSAndroid Build Coastguard Worker oid->oid[4] == 4 /* private */ &&
1116*03f9172cSAndroid Build Coastguard Worker oid->oid[5] == 1 /* enterprise */ &&
1117*03f9172cSAndroid Build Coastguard Worker oid->oid[6] == 40808 /* WFA */;
1118*03f9172cSAndroid Build Coastguard Worker }
1119*03f9172cSAndroid Build Coastguard Worker
1120*03f9172cSAndroid Build Coastguard Worker
x509_id_wfa_tod_oid(struct asn1_oid * oid)1121*03f9172cSAndroid Build Coastguard Worker static int x509_id_wfa_tod_oid(struct asn1_oid *oid)
1122*03f9172cSAndroid Build Coastguard Worker {
1123*03f9172cSAndroid Build Coastguard Worker return oid->len >= 9 &&
1124*03f9172cSAndroid Build Coastguard Worker x509_id_wfa_oid(oid) &&
1125*03f9172cSAndroid Build Coastguard Worker oid->oid[7] == 1 &&
1126*03f9172cSAndroid Build Coastguard Worker oid->oid[8] == 3;
1127*03f9172cSAndroid Build Coastguard Worker }
1128*03f9172cSAndroid Build Coastguard Worker
1129*03f9172cSAndroid Build Coastguard Worker
x509_id_wfa_tod_strict_oid(struct asn1_oid * oid)1130*03f9172cSAndroid Build Coastguard Worker static int x509_id_wfa_tod_strict_oid(struct asn1_oid *oid)
1131*03f9172cSAndroid Build Coastguard Worker {
1132*03f9172cSAndroid Build Coastguard Worker return oid->len == 10 &&
1133*03f9172cSAndroid Build Coastguard Worker x509_id_wfa_tod_oid(oid) &&
1134*03f9172cSAndroid Build Coastguard Worker oid->oid[9] == 1;
1135*03f9172cSAndroid Build Coastguard Worker }
1136*03f9172cSAndroid Build Coastguard Worker
1137*03f9172cSAndroid Build Coastguard Worker
x509_id_wfa_tod_tofu_oid(struct asn1_oid * oid)1138*03f9172cSAndroid Build Coastguard Worker static int x509_id_wfa_tod_tofu_oid(struct asn1_oid *oid)
1139*03f9172cSAndroid Build Coastguard Worker {
1140*03f9172cSAndroid Build Coastguard Worker return oid->len == 10 &&
1141*03f9172cSAndroid Build Coastguard Worker x509_id_wfa_tod_oid(oid) &&
1142*03f9172cSAndroid Build Coastguard Worker oid->oid[9] == 2;
1143*03f9172cSAndroid Build Coastguard Worker }
1144*03f9172cSAndroid Build Coastguard Worker
1145*03f9172cSAndroid Build Coastguard Worker
x509_parse_ext_certificate_policies(struct x509_certificate * cert,const u8 * pos,size_t len)1146*03f9172cSAndroid Build Coastguard Worker static int x509_parse_ext_certificate_policies(struct x509_certificate *cert,
1147*03f9172cSAndroid Build Coastguard Worker const u8 *pos, size_t len)
1148*03f9172cSAndroid Build Coastguard Worker {
1149*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
1150*03f9172cSAndroid Build Coastguard Worker const u8 *end;
1151*03f9172cSAndroid Build Coastguard Worker
1152*03f9172cSAndroid Build Coastguard Worker /*
1153*03f9172cSAndroid Build Coastguard Worker * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
1154*03f9172cSAndroid Build Coastguard Worker *
1155*03f9172cSAndroid Build Coastguard Worker * PolicyInformation ::= SEQUENCE {
1156*03f9172cSAndroid Build Coastguard Worker * policyIdentifier CertPolicyId,
1157*03f9172cSAndroid Build Coastguard Worker * policyQualifiers SEQUENCE SIZE (1..MAX) OF
1158*03f9172cSAndroid Build Coastguard Worker * PolicyQualifierInfo OPTIONAL }
1159*03f9172cSAndroid Build Coastguard Worker *
1160*03f9172cSAndroid Build Coastguard Worker * CertPolicyId ::= OBJECT IDENTIFIER
1161*03f9172cSAndroid Build Coastguard Worker */
1162*03f9172cSAndroid Build Coastguard Worker
1163*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
1164*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1165*03f9172cSAndroid Build Coastguard Worker "X509: Expected SEQUENCE (certificatePolicies)");
1166*03f9172cSAndroid Build Coastguard Worker return -1;
1167*03f9172cSAndroid Build Coastguard Worker }
1168*03f9172cSAndroid Build Coastguard Worker if (hdr.length > pos + len - hdr.payload)
1169*03f9172cSAndroid Build Coastguard Worker return -1;
1170*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
1171*03f9172cSAndroid Build Coastguard Worker end = pos + hdr.length;
1172*03f9172cSAndroid Build Coastguard Worker
1173*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: certificatePolicies", pos, end - pos);
1174*03f9172cSAndroid Build Coastguard Worker
1175*03f9172cSAndroid Build Coastguard Worker while (pos < end) {
1176*03f9172cSAndroid Build Coastguard Worker const u8 *pol_end;
1177*03f9172cSAndroid Build Coastguard Worker struct asn1_oid oid;
1178*03f9172cSAndroid Build Coastguard Worker char buf[80];
1179*03f9172cSAndroid Build Coastguard Worker
1180*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1181*03f9172cSAndroid Build Coastguard Worker !asn1_is_sequence(&hdr)) {
1182*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1183*03f9172cSAndroid Build Coastguard Worker "X509: Expected SEQUENCE (PolicyInformation)");
1184*03f9172cSAndroid Build Coastguard Worker return -1;
1185*03f9172cSAndroid Build Coastguard Worker }
1186*03f9172cSAndroid Build Coastguard Worker if (hdr.length > end - hdr.payload)
1187*03f9172cSAndroid Build Coastguard Worker return -1;
1188*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
1189*03f9172cSAndroid Build Coastguard Worker pol_end = pos + hdr.length;
1190*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: PolicyInformation",
1191*03f9172cSAndroid Build Coastguard Worker pos, pol_end - pos);
1192*03f9172cSAndroid Build Coastguard Worker
1193*03f9172cSAndroid Build Coastguard Worker if (asn1_get_oid(pos, pol_end - pos, &oid, &pos))
1194*03f9172cSAndroid Build Coastguard Worker return -1;
1195*03f9172cSAndroid Build Coastguard Worker if (x509_id_cert_policy_any_oid(&oid)) {
1196*03f9172cSAndroid Build Coastguard Worker os_strlcpy(buf, "anyPolicy-STRICT", sizeof(buf));
1197*03f9172cSAndroid Build Coastguard Worker cert->certificate_policy |=
1198*03f9172cSAndroid Build Coastguard Worker X509_EXT_CERT_POLICY_ANY;
1199*03f9172cSAndroid Build Coastguard Worker } else if (x509_id_wfa_tod_strict_oid(&oid)) {
1200*03f9172cSAndroid Build Coastguard Worker os_strlcpy(buf, "TOD-STRICT", sizeof(buf));
1201*03f9172cSAndroid Build Coastguard Worker cert->certificate_policy |=
1202*03f9172cSAndroid Build Coastguard Worker X509_EXT_CERT_POLICY_TOD_STRICT;
1203*03f9172cSAndroid Build Coastguard Worker } else if (x509_id_wfa_tod_tofu_oid(&oid)) {
1204*03f9172cSAndroid Build Coastguard Worker os_strlcpy(buf, "TOD-TOFU", sizeof(buf));
1205*03f9172cSAndroid Build Coastguard Worker cert->certificate_policy |=
1206*03f9172cSAndroid Build Coastguard Worker X509_EXT_CERT_POLICY_TOD_TOFU;
1207*03f9172cSAndroid Build Coastguard Worker } else {
1208*03f9172cSAndroid Build Coastguard Worker asn1_oid_to_str(&oid, buf, sizeof(buf));
1209*03f9172cSAndroid Build Coastguard Worker }
1210*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "policyIdentifier: %s", buf);
1211*03f9172cSAndroid Build Coastguard Worker
1212*03f9172cSAndroid Build Coastguard Worker pos = pol_end;
1213*03f9172cSAndroid Build Coastguard Worker }
1214*03f9172cSAndroid Build Coastguard Worker
1215*03f9172cSAndroid Build Coastguard Worker cert->extensions_present |= X509_EXT_CERTIFICATE_POLICY;
1216*03f9172cSAndroid Build Coastguard Worker
1217*03f9172cSAndroid Build Coastguard Worker return 0;
1218*03f9172cSAndroid Build Coastguard Worker }
1219*03f9172cSAndroid Build Coastguard Worker
1220*03f9172cSAndroid Build Coastguard Worker
x509_id_pkix_oid(struct asn1_oid * oid)1221*03f9172cSAndroid Build Coastguard Worker static int x509_id_pkix_oid(struct asn1_oid *oid)
1222*03f9172cSAndroid Build Coastguard Worker {
1223*03f9172cSAndroid Build Coastguard Worker return oid->len >= 7 &&
1224*03f9172cSAndroid Build Coastguard Worker oid->oid[0] == 1 /* iso */ &&
1225*03f9172cSAndroid Build Coastguard Worker oid->oid[1] == 3 /* identified-organization */ &&
1226*03f9172cSAndroid Build Coastguard Worker oid->oid[2] == 6 /* dod */ &&
1227*03f9172cSAndroid Build Coastguard Worker oid->oid[3] == 1 /* internet */ &&
1228*03f9172cSAndroid Build Coastguard Worker oid->oid[4] == 5 /* security */ &&
1229*03f9172cSAndroid Build Coastguard Worker oid->oid[5] == 5 /* mechanisms */ &&
1230*03f9172cSAndroid Build Coastguard Worker oid->oid[6] == 7 /* id-pkix */;
1231*03f9172cSAndroid Build Coastguard Worker }
1232*03f9172cSAndroid Build Coastguard Worker
1233*03f9172cSAndroid Build Coastguard Worker
x509_id_kp_oid(struct asn1_oid * oid)1234*03f9172cSAndroid Build Coastguard Worker static int x509_id_kp_oid(struct asn1_oid *oid)
1235*03f9172cSAndroid Build Coastguard Worker {
1236*03f9172cSAndroid Build Coastguard Worker /* id-kp */
1237*03f9172cSAndroid Build Coastguard Worker return oid->len >= 8 &&
1238*03f9172cSAndroid Build Coastguard Worker x509_id_pkix_oid(oid) &&
1239*03f9172cSAndroid Build Coastguard Worker oid->oid[7] == 3 /* id-kp */;
1240*03f9172cSAndroid Build Coastguard Worker }
1241*03f9172cSAndroid Build Coastguard Worker
1242*03f9172cSAndroid Build Coastguard Worker
x509_id_kp_server_auth_oid(struct asn1_oid * oid)1243*03f9172cSAndroid Build Coastguard Worker static int x509_id_kp_server_auth_oid(struct asn1_oid *oid)
1244*03f9172cSAndroid Build Coastguard Worker {
1245*03f9172cSAndroid Build Coastguard Worker /* id-kp */
1246*03f9172cSAndroid Build Coastguard Worker return oid->len == 9 &&
1247*03f9172cSAndroid Build Coastguard Worker x509_id_kp_oid(oid) &&
1248*03f9172cSAndroid Build Coastguard Worker oid->oid[8] == 1 /* id-kp-serverAuth */;
1249*03f9172cSAndroid Build Coastguard Worker }
1250*03f9172cSAndroid Build Coastguard Worker
1251*03f9172cSAndroid Build Coastguard Worker
x509_id_kp_client_auth_oid(struct asn1_oid * oid)1252*03f9172cSAndroid Build Coastguard Worker static int x509_id_kp_client_auth_oid(struct asn1_oid *oid)
1253*03f9172cSAndroid Build Coastguard Worker {
1254*03f9172cSAndroid Build Coastguard Worker /* id-kp */
1255*03f9172cSAndroid Build Coastguard Worker return oid->len == 9 &&
1256*03f9172cSAndroid Build Coastguard Worker x509_id_kp_oid(oid) &&
1257*03f9172cSAndroid Build Coastguard Worker oid->oid[8] == 2 /* id-kp-clientAuth */;
1258*03f9172cSAndroid Build Coastguard Worker }
1259*03f9172cSAndroid Build Coastguard Worker
1260*03f9172cSAndroid Build Coastguard Worker
x509_id_kp_ocsp_oid(struct asn1_oid * oid)1261*03f9172cSAndroid Build Coastguard Worker static int x509_id_kp_ocsp_oid(struct asn1_oid *oid)
1262*03f9172cSAndroid Build Coastguard Worker {
1263*03f9172cSAndroid Build Coastguard Worker /* id-kp */
1264*03f9172cSAndroid Build Coastguard Worker return oid->len == 9 &&
1265*03f9172cSAndroid Build Coastguard Worker x509_id_kp_oid(oid) &&
1266*03f9172cSAndroid Build Coastguard Worker oid->oid[8] == 9 /* id-kp-OCSPSigning */;
1267*03f9172cSAndroid Build Coastguard Worker }
1268*03f9172cSAndroid Build Coastguard Worker
1269*03f9172cSAndroid Build Coastguard Worker
x509_parse_ext_ext_key_usage(struct x509_certificate * cert,const u8 * pos,size_t len)1270*03f9172cSAndroid Build Coastguard Worker static int x509_parse_ext_ext_key_usage(struct x509_certificate *cert,
1271*03f9172cSAndroid Build Coastguard Worker const u8 *pos, size_t len)
1272*03f9172cSAndroid Build Coastguard Worker {
1273*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
1274*03f9172cSAndroid Build Coastguard Worker const u8 *end;
1275*03f9172cSAndroid Build Coastguard Worker struct asn1_oid oid;
1276*03f9172cSAndroid Build Coastguard Worker
1277*03f9172cSAndroid Build Coastguard Worker /*
1278*03f9172cSAndroid Build Coastguard Worker * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
1279*03f9172cSAndroid Build Coastguard Worker *
1280*03f9172cSAndroid Build Coastguard Worker * KeyPurposeId ::= OBJECT IDENTIFIER
1281*03f9172cSAndroid Build Coastguard Worker */
1282*03f9172cSAndroid Build Coastguard Worker
1283*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
1284*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1285*03f9172cSAndroid Build Coastguard Worker "X509: Expected SEQUENCE (ExtKeyUsageSyntax)");
1286*03f9172cSAndroid Build Coastguard Worker return -1;
1287*03f9172cSAndroid Build Coastguard Worker }
1288*03f9172cSAndroid Build Coastguard Worker if (hdr.length > pos + len - hdr.payload)
1289*03f9172cSAndroid Build Coastguard Worker return -1;
1290*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
1291*03f9172cSAndroid Build Coastguard Worker end = pos + hdr.length;
1292*03f9172cSAndroid Build Coastguard Worker
1293*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: ExtKeyUsageSyntax", pos, end - pos);
1294*03f9172cSAndroid Build Coastguard Worker
1295*03f9172cSAndroid Build Coastguard Worker while (pos < end) {
1296*03f9172cSAndroid Build Coastguard Worker char buf[80];
1297*03f9172cSAndroid Build Coastguard Worker
1298*03f9172cSAndroid Build Coastguard Worker if (asn1_get_oid(pos, end - pos, &oid, &pos))
1299*03f9172cSAndroid Build Coastguard Worker return -1;
1300*03f9172cSAndroid Build Coastguard Worker if (x509_any_ext_key_usage_oid(&oid)) {
1301*03f9172cSAndroid Build Coastguard Worker os_strlcpy(buf, "anyExtendedKeyUsage", sizeof(buf));
1302*03f9172cSAndroid Build Coastguard Worker cert->ext_key_usage |= X509_EXT_KEY_USAGE_ANY;
1303*03f9172cSAndroid Build Coastguard Worker } else if (x509_id_kp_server_auth_oid(&oid)) {
1304*03f9172cSAndroid Build Coastguard Worker os_strlcpy(buf, "id-kp-serverAuth", sizeof(buf));
1305*03f9172cSAndroid Build Coastguard Worker cert->ext_key_usage |= X509_EXT_KEY_USAGE_SERVER_AUTH;
1306*03f9172cSAndroid Build Coastguard Worker } else if (x509_id_kp_client_auth_oid(&oid)) {
1307*03f9172cSAndroid Build Coastguard Worker os_strlcpy(buf, "id-kp-clientAuth", sizeof(buf));
1308*03f9172cSAndroid Build Coastguard Worker cert->ext_key_usage |= X509_EXT_KEY_USAGE_CLIENT_AUTH;
1309*03f9172cSAndroid Build Coastguard Worker } else if (x509_id_kp_ocsp_oid(&oid)) {
1310*03f9172cSAndroid Build Coastguard Worker os_strlcpy(buf, "id-kp-OCSPSigning", sizeof(buf));
1311*03f9172cSAndroid Build Coastguard Worker cert->ext_key_usage |= X509_EXT_KEY_USAGE_OCSP;
1312*03f9172cSAndroid Build Coastguard Worker } else {
1313*03f9172cSAndroid Build Coastguard Worker asn1_oid_to_str(&oid, buf, sizeof(buf));
1314*03f9172cSAndroid Build Coastguard Worker }
1315*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "ExtKeyUsage KeyPurposeId: %s", buf);
1316*03f9172cSAndroid Build Coastguard Worker }
1317*03f9172cSAndroid Build Coastguard Worker
1318*03f9172cSAndroid Build Coastguard Worker cert->extensions_present |= X509_EXT_EXT_KEY_USAGE;
1319*03f9172cSAndroid Build Coastguard Worker
1320*03f9172cSAndroid Build Coastguard Worker return 0;
1321*03f9172cSAndroid Build Coastguard Worker }
1322*03f9172cSAndroid Build Coastguard Worker
1323*03f9172cSAndroid Build Coastguard Worker
x509_parse_extension_data(struct x509_certificate * cert,struct asn1_oid * oid,const u8 * pos,size_t len)1324*03f9172cSAndroid Build Coastguard Worker static int x509_parse_extension_data(struct x509_certificate *cert,
1325*03f9172cSAndroid Build Coastguard Worker struct asn1_oid *oid,
1326*03f9172cSAndroid Build Coastguard Worker const u8 *pos, size_t len)
1327*03f9172cSAndroid Build Coastguard Worker {
1328*03f9172cSAndroid Build Coastguard Worker if (!x509_id_ce_oid(oid))
1329*03f9172cSAndroid Build Coastguard Worker return 1;
1330*03f9172cSAndroid Build Coastguard Worker
1331*03f9172cSAndroid Build Coastguard Worker /* TODO: add other extensions required by RFC 3280, Ch 4.2:
1332*03f9172cSAndroid Build Coastguard Worker * name constraints (section 4.2.1.11)
1333*03f9172cSAndroid Build Coastguard Worker * policy constraints (section 4.2.1.12)
1334*03f9172cSAndroid Build Coastguard Worker * inhibit any-policy (section 4.2.1.15)
1335*03f9172cSAndroid Build Coastguard Worker */
1336*03f9172cSAndroid Build Coastguard Worker switch (oid->oid[3]) {
1337*03f9172cSAndroid Build Coastguard Worker case 15: /* id-ce-keyUsage */
1338*03f9172cSAndroid Build Coastguard Worker return x509_parse_ext_key_usage(cert, pos, len);
1339*03f9172cSAndroid Build Coastguard Worker case 17: /* id-ce-subjectAltName */
1340*03f9172cSAndroid Build Coastguard Worker return x509_parse_ext_subject_alt_name(cert, pos, len);
1341*03f9172cSAndroid Build Coastguard Worker case 18: /* id-ce-issuerAltName */
1342*03f9172cSAndroid Build Coastguard Worker return x509_parse_ext_issuer_alt_name(cert, pos, len);
1343*03f9172cSAndroid Build Coastguard Worker case 19: /* id-ce-basicConstraints */
1344*03f9172cSAndroid Build Coastguard Worker return x509_parse_ext_basic_constraints(cert, pos, len);
1345*03f9172cSAndroid Build Coastguard Worker case 32: /* id-ce-certificatePolicies */
1346*03f9172cSAndroid Build Coastguard Worker return x509_parse_ext_certificate_policies(cert, pos, len);
1347*03f9172cSAndroid Build Coastguard Worker case 37: /* id-ce-extKeyUsage */
1348*03f9172cSAndroid Build Coastguard Worker return x509_parse_ext_ext_key_usage(cert, pos, len);
1349*03f9172cSAndroid Build Coastguard Worker default:
1350*03f9172cSAndroid Build Coastguard Worker return 1;
1351*03f9172cSAndroid Build Coastguard Worker }
1352*03f9172cSAndroid Build Coastguard Worker }
1353*03f9172cSAndroid Build Coastguard Worker
1354*03f9172cSAndroid Build Coastguard Worker
x509_parse_extension(struct x509_certificate * cert,const u8 * pos,size_t len,const u8 ** next)1355*03f9172cSAndroid Build Coastguard Worker static int x509_parse_extension(struct x509_certificate *cert,
1356*03f9172cSAndroid Build Coastguard Worker const u8 *pos, size_t len, const u8 **next)
1357*03f9172cSAndroid Build Coastguard Worker {
1358*03f9172cSAndroid Build Coastguard Worker const u8 *end;
1359*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
1360*03f9172cSAndroid Build Coastguard Worker struct asn1_oid oid;
1361*03f9172cSAndroid Build Coastguard Worker int critical_ext = 0, res;
1362*03f9172cSAndroid Build Coastguard Worker char buf[80];
1363*03f9172cSAndroid Build Coastguard Worker
1364*03f9172cSAndroid Build Coastguard Worker /*
1365*03f9172cSAndroid Build Coastguard Worker * Extension ::= SEQUENCE {
1366*03f9172cSAndroid Build Coastguard Worker * extnID OBJECT IDENTIFIER,
1367*03f9172cSAndroid Build Coastguard Worker * critical BOOLEAN DEFAULT FALSE,
1368*03f9172cSAndroid Build Coastguard Worker * extnValue OCTET STRING
1369*03f9172cSAndroid Build Coastguard Worker * }
1370*03f9172cSAndroid Build Coastguard Worker */
1371*03f9172cSAndroid Build Coastguard Worker
1372*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
1373*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr, "X509: Expected SEQUENCE in Extensions");
1374*03f9172cSAndroid Build Coastguard Worker return -1;
1375*03f9172cSAndroid Build Coastguard Worker }
1376*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
1377*03f9172cSAndroid Build Coastguard Worker *next = end = pos + hdr.length;
1378*03f9172cSAndroid Build Coastguard Worker
1379*03f9172cSAndroid Build Coastguard Worker if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
1380*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data for "
1381*03f9172cSAndroid Build Coastguard Worker "Extension (expected OID)");
1382*03f9172cSAndroid Build Coastguard Worker return -1;
1383*03f9172cSAndroid Build Coastguard Worker }
1384*03f9172cSAndroid Build Coastguard Worker
1385*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1386*03f9172cSAndroid Build Coastguard Worker (!asn1_is_boolean(&hdr) && !asn1_is_octetstring(&hdr))) {
1387*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1388*03f9172cSAndroid Build Coastguard Worker "X509: Expected BOOLEAN or OCTETSTRING in Extensions");
1389*03f9172cSAndroid Build Coastguard Worker return -1;
1390*03f9172cSAndroid Build Coastguard Worker }
1391*03f9172cSAndroid Build Coastguard Worker
1392*03f9172cSAndroid Build Coastguard Worker if (hdr.tag == ASN1_TAG_BOOLEAN) {
1393*03f9172cSAndroid Build Coastguard Worker critical_ext = hdr.payload[0];
1394*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
1395*03f9172cSAndroid Build Coastguard Worker /*
1396*03f9172cSAndroid Build Coastguard Worker * Number of CA certificates seem to be using Private class in
1397*03f9172cSAndroid Build Coastguard Worker * one of the X.509v3 extensions, so let's accept that instead
1398*03f9172cSAndroid Build Coastguard Worker * of rejecting the certificate. asn1_is_octetstring() covers
1399*03f9172cSAndroid Build Coastguard Worker * the more common case.
1400*03f9172cSAndroid Build Coastguard Worker */
1401*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1402*03f9172cSAndroid Build Coastguard Worker (!asn1_is_octetstring(&hdr) &&
1403*03f9172cSAndroid Build Coastguard Worker !(hdr.class == ASN1_CLASS_PRIVATE &&
1404*03f9172cSAndroid Build Coastguard Worker hdr.tag == ASN1_TAG_OCTETSTRING))) {
1405*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1406*03f9172cSAndroid Build Coastguard Worker "X509: Expected OCTETSTRING in Extensions");
1407*03f9172cSAndroid Build Coastguard Worker return -1;
1408*03f9172cSAndroid Build Coastguard Worker }
1409*03f9172cSAndroid Build Coastguard Worker }
1410*03f9172cSAndroid Build Coastguard Worker
1411*03f9172cSAndroid Build Coastguard Worker asn1_oid_to_str(&oid, buf, sizeof(buf));
1412*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Extension: extnID=%s critical=%d",
1413*03f9172cSAndroid Build Coastguard Worker buf, critical_ext);
1414*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: extnValue", hdr.payload, hdr.length);
1415*03f9172cSAndroid Build Coastguard Worker
1416*03f9172cSAndroid Build Coastguard Worker res = x509_parse_extension_data(cert, &oid, hdr.payload, hdr.length);
1417*03f9172cSAndroid Build Coastguard Worker if (res < 0)
1418*03f9172cSAndroid Build Coastguard Worker return res;
1419*03f9172cSAndroid Build Coastguard Worker if (res == 1 && critical_ext) {
1420*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_INFO, "X509: Unknown critical extension %s",
1421*03f9172cSAndroid Build Coastguard Worker buf);
1422*03f9172cSAndroid Build Coastguard Worker return -1;
1423*03f9172cSAndroid Build Coastguard Worker }
1424*03f9172cSAndroid Build Coastguard Worker
1425*03f9172cSAndroid Build Coastguard Worker return 0;
1426*03f9172cSAndroid Build Coastguard Worker }
1427*03f9172cSAndroid Build Coastguard Worker
1428*03f9172cSAndroid Build Coastguard Worker
x509_parse_extensions(struct x509_certificate * cert,const u8 * pos,size_t len)1429*03f9172cSAndroid Build Coastguard Worker static int x509_parse_extensions(struct x509_certificate *cert,
1430*03f9172cSAndroid Build Coastguard Worker const u8 *pos, size_t len)
1431*03f9172cSAndroid Build Coastguard Worker {
1432*03f9172cSAndroid Build Coastguard Worker const u8 *end;
1433*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
1434*03f9172cSAndroid Build Coastguard Worker
1435*03f9172cSAndroid Build Coastguard Worker /* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension */
1436*03f9172cSAndroid Build Coastguard Worker
1437*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
1438*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr, "X509: Expected SEQUENCE for Extensions");
1439*03f9172cSAndroid Build Coastguard Worker return -1;
1440*03f9172cSAndroid Build Coastguard Worker }
1441*03f9172cSAndroid Build Coastguard Worker
1442*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
1443*03f9172cSAndroid Build Coastguard Worker end = pos + hdr.length;
1444*03f9172cSAndroid Build Coastguard Worker
1445*03f9172cSAndroid Build Coastguard Worker while (pos < end) {
1446*03f9172cSAndroid Build Coastguard Worker if (x509_parse_extension(cert, pos, end - pos, &pos)
1447*03f9172cSAndroid Build Coastguard Worker < 0)
1448*03f9172cSAndroid Build Coastguard Worker return -1;
1449*03f9172cSAndroid Build Coastguard Worker }
1450*03f9172cSAndroid Build Coastguard Worker
1451*03f9172cSAndroid Build Coastguard Worker return 0;
1452*03f9172cSAndroid Build Coastguard Worker }
1453*03f9172cSAndroid Build Coastguard Worker
1454*03f9172cSAndroid Build Coastguard Worker
x509_parse_tbs_certificate(const u8 * buf,size_t len,struct x509_certificate * cert,const u8 ** next)1455*03f9172cSAndroid Build Coastguard Worker static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
1456*03f9172cSAndroid Build Coastguard Worker struct x509_certificate *cert,
1457*03f9172cSAndroid Build Coastguard Worker const u8 **next)
1458*03f9172cSAndroid Build Coastguard Worker {
1459*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
1460*03f9172cSAndroid Build Coastguard Worker const u8 *pos, *end;
1461*03f9172cSAndroid Build Coastguard Worker size_t left;
1462*03f9172cSAndroid Build Coastguard Worker char sbuf[128];
1463*03f9172cSAndroid Build Coastguard Worker unsigned long value;
1464*03f9172cSAndroid Build Coastguard Worker const u8 *subject_dn;
1465*03f9172cSAndroid Build Coastguard Worker
1466*03f9172cSAndroid Build Coastguard Worker /* tbsCertificate TBSCertificate ::= SEQUENCE */
1467*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
1468*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1469*03f9172cSAndroid Build Coastguard Worker "X509: tbsCertificate did not start with a valid SEQUENCE");
1470*03f9172cSAndroid Build Coastguard Worker return -1;
1471*03f9172cSAndroid Build Coastguard Worker }
1472*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
1473*03f9172cSAndroid Build Coastguard Worker end = *next = pos + hdr.length;
1474*03f9172cSAndroid Build Coastguard Worker
1475*03f9172cSAndroid Build Coastguard Worker /*
1476*03f9172cSAndroid Build Coastguard Worker * version [0] EXPLICIT Version DEFAULT v1
1477*03f9172cSAndroid Build Coastguard Worker * Version ::= INTEGER { v1(0), v2(1), v3(2) }
1478*03f9172cSAndroid Build Coastguard Worker */
1479*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end - pos, &hdr) < 0)
1480*03f9172cSAndroid Build Coastguard Worker return -1;
1481*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
1482*03f9172cSAndroid Build Coastguard Worker
1483*03f9172cSAndroid Build Coastguard Worker if (asn1_is_cs_tag(&hdr, 0) && hdr.constructed) {
1484*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1485*03f9172cSAndroid Build Coastguard Worker !asn1_is_integer(&hdr)) {
1486*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1487*03f9172cSAndroid Build Coastguard Worker "X509: No INTEGER tag found for version field");
1488*03f9172cSAndroid Build Coastguard Worker return -1;
1489*03f9172cSAndroid Build Coastguard Worker }
1490*03f9172cSAndroid Build Coastguard Worker if (hdr.length != 1) {
1491*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Unexpected version field "
1492*03f9172cSAndroid Build Coastguard Worker "length %u (expected 1)", hdr.length);
1493*03f9172cSAndroid Build Coastguard Worker return -1;
1494*03f9172cSAndroid Build Coastguard Worker }
1495*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
1496*03f9172cSAndroid Build Coastguard Worker left = hdr.length;
1497*03f9172cSAndroid Build Coastguard Worker value = 0;
1498*03f9172cSAndroid Build Coastguard Worker while (left) {
1499*03f9172cSAndroid Build Coastguard Worker value <<= 8;
1500*03f9172cSAndroid Build Coastguard Worker value |= *pos++;
1501*03f9172cSAndroid Build Coastguard Worker left--;
1502*03f9172cSAndroid Build Coastguard Worker }
1503*03f9172cSAndroid Build Coastguard Worker
1504*03f9172cSAndroid Build Coastguard Worker cert->version = value;
1505*03f9172cSAndroid Build Coastguard Worker if (cert->version != X509_CERT_V1 &&
1506*03f9172cSAndroid Build Coastguard Worker cert->version != X509_CERT_V2 &&
1507*03f9172cSAndroid Build Coastguard Worker cert->version != X509_CERT_V3) {
1508*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Unsupported version %d",
1509*03f9172cSAndroid Build Coastguard Worker cert->version + 1);
1510*03f9172cSAndroid Build Coastguard Worker return -1;
1511*03f9172cSAndroid Build Coastguard Worker }
1512*03f9172cSAndroid Build Coastguard Worker
1513*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end - pos, &hdr) < 0)
1514*03f9172cSAndroid Build Coastguard Worker return -1;
1515*03f9172cSAndroid Build Coastguard Worker } else
1516*03f9172cSAndroid Build Coastguard Worker cert->version = X509_CERT_V1;
1517*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_MSGDUMP, "X509: Version X.509v%d", cert->version + 1);
1518*03f9172cSAndroid Build Coastguard Worker
1519*03f9172cSAndroid Build Coastguard Worker /* serialNumber CertificateSerialNumber ::= INTEGER */
1520*03f9172cSAndroid Build Coastguard Worker if (!asn1_is_integer(&hdr) ||
1521*03f9172cSAndroid Build Coastguard Worker hdr.length < 1 || hdr.length > X509_MAX_SERIAL_NUM_LEN) {
1522*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1523*03f9172cSAndroid Build Coastguard Worker "X509: No INTEGER tag found for serialNumber");
1524*03f9172cSAndroid Build Coastguard Worker return -1;
1525*03f9172cSAndroid Build Coastguard Worker }
1526*03f9172cSAndroid Build Coastguard Worker
1527*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload + hdr.length;
1528*03f9172cSAndroid Build Coastguard Worker while (hdr.length > 0 && hdr.payload[0] == 0) {
1529*03f9172cSAndroid Build Coastguard Worker hdr.payload++;
1530*03f9172cSAndroid Build Coastguard Worker hdr.length--;
1531*03f9172cSAndroid Build Coastguard Worker }
1532*03f9172cSAndroid Build Coastguard Worker os_memcpy(cert->serial_number, hdr.payload, hdr.length);
1533*03f9172cSAndroid Build Coastguard Worker cert->serial_number_len = hdr.length;
1534*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: serialNumber", cert->serial_number,
1535*03f9172cSAndroid Build Coastguard Worker cert->serial_number_len);
1536*03f9172cSAndroid Build Coastguard Worker
1537*03f9172cSAndroid Build Coastguard Worker /* signature AlgorithmIdentifier */
1538*03f9172cSAndroid Build Coastguard Worker if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature,
1539*03f9172cSAndroid Build Coastguard Worker &pos))
1540*03f9172cSAndroid Build Coastguard Worker return -1;
1541*03f9172cSAndroid Build Coastguard Worker
1542*03f9172cSAndroid Build Coastguard Worker /* issuer Name */
1543*03f9172cSAndroid Build Coastguard Worker if (x509_parse_name(pos, end - pos, &cert->issuer, &pos))
1544*03f9172cSAndroid Build Coastguard Worker return -1;
1545*03f9172cSAndroid Build Coastguard Worker x509_name_string(&cert->issuer, sbuf, sizeof(sbuf));
1546*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_MSGDUMP, "X509: issuer %s", sbuf);
1547*03f9172cSAndroid Build Coastguard Worker
1548*03f9172cSAndroid Build Coastguard Worker /* validity Validity */
1549*03f9172cSAndroid Build Coastguard Worker if (x509_parse_validity(pos, end - pos, cert, &pos))
1550*03f9172cSAndroid Build Coastguard Worker return -1;
1551*03f9172cSAndroid Build Coastguard Worker
1552*03f9172cSAndroid Build Coastguard Worker /* subject Name */
1553*03f9172cSAndroid Build Coastguard Worker subject_dn = pos;
1554*03f9172cSAndroid Build Coastguard Worker if (x509_parse_name(pos, end - pos, &cert->subject, &pos))
1555*03f9172cSAndroid Build Coastguard Worker return -1;
1556*03f9172cSAndroid Build Coastguard Worker cert->subject_dn = os_malloc(pos - subject_dn);
1557*03f9172cSAndroid Build Coastguard Worker if (!cert->subject_dn)
1558*03f9172cSAndroid Build Coastguard Worker return -1;
1559*03f9172cSAndroid Build Coastguard Worker cert->subject_dn_len = pos - subject_dn;
1560*03f9172cSAndroid Build Coastguard Worker os_memcpy(cert->subject_dn, subject_dn, cert->subject_dn_len);
1561*03f9172cSAndroid Build Coastguard Worker x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
1562*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf);
1563*03f9172cSAndroid Build Coastguard Worker
1564*03f9172cSAndroid Build Coastguard Worker /* subjectPublicKeyInfo SubjectPublicKeyInfo */
1565*03f9172cSAndroid Build Coastguard Worker if (x509_parse_public_key(pos, end - pos, cert, &pos))
1566*03f9172cSAndroid Build Coastguard Worker return -1;
1567*03f9172cSAndroid Build Coastguard Worker
1568*03f9172cSAndroid Build Coastguard Worker if (pos == end)
1569*03f9172cSAndroid Build Coastguard Worker return 0;
1570*03f9172cSAndroid Build Coastguard Worker
1571*03f9172cSAndroid Build Coastguard Worker if (cert->version == X509_CERT_V1)
1572*03f9172cSAndroid Build Coastguard Worker return 0;
1573*03f9172cSAndroid Build Coastguard Worker
1574*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1575*03f9172cSAndroid Build Coastguard Worker hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
1576*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1577*03f9172cSAndroid Build Coastguard Worker "X509: Expected Context-Specific tag to parse optional tbsCertificate field(s)");
1578*03f9172cSAndroid Build Coastguard Worker return -1;
1579*03f9172cSAndroid Build Coastguard Worker }
1580*03f9172cSAndroid Build Coastguard Worker
1581*03f9172cSAndroid Build Coastguard Worker if (hdr.tag == 1) {
1582*03f9172cSAndroid Build Coastguard Worker /* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL */
1583*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: issuerUniqueID");
1584*03f9172cSAndroid Build Coastguard Worker /* TODO: parse UniqueIdentifier ::= BIT STRING */
1585*03f9172cSAndroid Build Coastguard Worker
1586*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload + hdr.length;
1587*03f9172cSAndroid Build Coastguard Worker if (pos == end)
1588*03f9172cSAndroid Build Coastguard Worker return 0;
1589*03f9172cSAndroid Build Coastguard Worker
1590*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1591*03f9172cSAndroid Build Coastguard Worker hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
1592*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1593*03f9172cSAndroid Build Coastguard Worker "X509: Expected Context-Specific tag to parse optional tbsCertificate field(s)");
1594*03f9172cSAndroid Build Coastguard Worker return -1;
1595*03f9172cSAndroid Build Coastguard Worker }
1596*03f9172cSAndroid Build Coastguard Worker }
1597*03f9172cSAndroid Build Coastguard Worker
1598*03f9172cSAndroid Build Coastguard Worker if (hdr.tag == 2) {
1599*03f9172cSAndroid Build Coastguard Worker /* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL */
1600*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: subjectUniqueID");
1601*03f9172cSAndroid Build Coastguard Worker /* TODO: parse UniqueIdentifier ::= BIT STRING */
1602*03f9172cSAndroid Build Coastguard Worker
1603*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload + hdr.length;
1604*03f9172cSAndroid Build Coastguard Worker if (pos == end)
1605*03f9172cSAndroid Build Coastguard Worker return 0;
1606*03f9172cSAndroid Build Coastguard Worker
1607*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1608*03f9172cSAndroid Build Coastguard Worker hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
1609*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1610*03f9172cSAndroid Build Coastguard Worker "X509: Expected Context-Specific tag to parse optional tbsCertificate field(s)");
1611*03f9172cSAndroid Build Coastguard Worker return -1;
1612*03f9172cSAndroid Build Coastguard Worker }
1613*03f9172cSAndroid Build Coastguard Worker }
1614*03f9172cSAndroid Build Coastguard Worker
1615*03f9172cSAndroid Build Coastguard Worker if (hdr.tag != 3) {
1616*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
1617*03f9172cSAndroid Build Coastguard Worker "X509: Ignored unexpected Context-Specific constructed %d tag %d in optional tbsCertificate fields",
1618*03f9172cSAndroid Build Coastguard Worker hdr.constructed, hdr.tag);
1619*03f9172cSAndroid Build Coastguard Worker return 0;
1620*03f9172cSAndroid Build Coastguard Worker }
1621*03f9172cSAndroid Build Coastguard Worker
1622*03f9172cSAndroid Build Coastguard Worker /* extensions [3] EXPLICIT Extensions OPTIONAL */
1623*03f9172cSAndroid Build Coastguard Worker
1624*03f9172cSAndroid Build Coastguard Worker if (cert->version != X509_CERT_V3) {
1625*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: X.509%d certificate and "
1626*03f9172cSAndroid Build Coastguard Worker "Extensions data which are only allowed for "
1627*03f9172cSAndroid Build Coastguard Worker "version 3", cert->version + 1);
1628*03f9172cSAndroid Build Coastguard Worker return -1;
1629*03f9172cSAndroid Build Coastguard Worker }
1630*03f9172cSAndroid Build Coastguard Worker
1631*03f9172cSAndroid Build Coastguard Worker if (x509_parse_extensions(cert, hdr.payload, hdr.length) < 0)
1632*03f9172cSAndroid Build Coastguard Worker return -1;
1633*03f9172cSAndroid Build Coastguard Worker
1634*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload + hdr.length;
1635*03f9172cSAndroid Build Coastguard Worker if (pos < end) {
1636*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_DEBUG,
1637*03f9172cSAndroid Build Coastguard Worker "X509: Ignored extra tbsCertificate data",
1638*03f9172cSAndroid Build Coastguard Worker pos, end - pos);
1639*03f9172cSAndroid Build Coastguard Worker }
1640*03f9172cSAndroid Build Coastguard Worker
1641*03f9172cSAndroid Build Coastguard Worker return 0;
1642*03f9172cSAndroid Build Coastguard Worker }
1643*03f9172cSAndroid Build Coastguard Worker
1644*03f9172cSAndroid Build Coastguard Worker
x509_rsadsi_oid(struct asn1_oid * oid)1645*03f9172cSAndroid Build Coastguard Worker static int x509_rsadsi_oid(struct asn1_oid *oid)
1646*03f9172cSAndroid Build Coastguard Worker {
1647*03f9172cSAndroid Build Coastguard Worker return oid->len >= 4 &&
1648*03f9172cSAndroid Build Coastguard Worker oid->oid[0] == 1 /* iso */ &&
1649*03f9172cSAndroid Build Coastguard Worker oid->oid[1] == 2 /* member-body */ &&
1650*03f9172cSAndroid Build Coastguard Worker oid->oid[2] == 840 /* us */ &&
1651*03f9172cSAndroid Build Coastguard Worker oid->oid[3] == 113549 /* rsadsi */;
1652*03f9172cSAndroid Build Coastguard Worker }
1653*03f9172cSAndroid Build Coastguard Worker
1654*03f9172cSAndroid Build Coastguard Worker
x509_pkcs_oid(struct asn1_oid * oid)1655*03f9172cSAndroid Build Coastguard Worker static int x509_pkcs_oid(struct asn1_oid *oid)
1656*03f9172cSAndroid Build Coastguard Worker {
1657*03f9172cSAndroid Build Coastguard Worker return oid->len >= 5 &&
1658*03f9172cSAndroid Build Coastguard Worker x509_rsadsi_oid(oid) &&
1659*03f9172cSAndroid Build Coastguard Worker oid->oid[4] == 1 /* pkcs */;
1660*03f9172cSAndroid Build Coastguard Worker }
1661*03f9172cSAndroid Build Coastguard Worker
1662*03f9172cSAndroid Build Coastguard Worker
x509_digest_oid(struct asn1_oid * oid)1663*03f9172cSAndroid Build Coastguard Worker static int x509_digest_oid(struct asn1_oid *oid)
1664*03f9172cSAndroid Build Coastguard Worker {
1665*03f9172cSAndroid Build Coastguard Worker return oid->len >= 5 &&
1666*03f9172cSAndroid Build Coastguard Worker x509_rsadsi_oid(oid) &&
1667*03f9172cSAndroid Build Coastguard Worker oid->oid[4] == 2 /* digestAlgorithm */;
1668*03f9172cSAndroid Build Coastguard Worker }
1669*03f9172cSAndroid Build Coastguard Worker
1670*03f9172cSAndroid Build Coastguard Worker
x509_sha1_oid(struct asn1_oid * oid)1671*03f9172cSAndroid Build Coastguard Worker int x509_sha1_oid(struct asn1_oid *oid)
1672*03f9172cSAndroid Build Coastguard Worker {
1673*03f9172cSAndroid Build Coastguard Worker return oid->len == 6 &&
1674*03f9172cSAndroid Build Coastguard Worker oid->oid[0] == 1 /* iso */ &&
1675*03f9172cSAndroid Build Coastguard Worker oid->oid[1] == 3 /* identified-organization */ &&
1676*03f9172cSAndroid Build Coastguard Worker oid->oid[2] == 14 /* oiw */ &&
1677*03f9172cSAndroid Build Coastguard Worker oid->oid[3] == 3 /* secsig */ &&
1678*03f9172cSAndroid Build Coastguard Worker oid->oid[4] == 2 /* algorithms */ &&
1679*03f9172cSAndroid Build Coastguard Worker oid->oid[5] == 26 /* id-sha1 */;
1680*03f9172cSAndroid Build Coastguard Worker }
1681*03f9172cSAndroid Build Coastguard Worker
1682*03f9172cSAndroid Build Coastguard Worker
x509_sha2_oid(struct asn1_oid * oid)1683*03f9172cSAndroid Build Coastguard Worker static int x509_sha2_oid(struct asn1_oid *oid)
1684*03f9172cSAndroid Build Coastguard Worker {
1685*03f9172cSAndroid Build Coastguard Worker return oid->len == 9 &&
1686*03f9172cSAndroid Build Coastguard Worker oid->oid[0] == 2 /* joint-iso-itu-t */ &&
1687*03f9172cSAndroid Build Coastguard Worker oid->oid[1] == 16 /* country */ &&
1688*03f9172cSAndroid Build Coastguard Worker oid->oid[2] == 840 /* us */ &&
1689*03f9172cSAndroid Build Coastguard Worker oid->oid[3] == 1 /* organization */ &&
1690*03f9172cSAndroid Build Coastguard Worker oid->oid[4] == 101 /* gov */ &&
1691*03f9172cSAndroid Build Coastguard Worker oid->oid[5] == 3 /* csor */ &&
1692*03f9172cSAndroid Build Coastguard Worker oid->oid[6] == 4 /* nistAlgorithm */ &&
1693*03f9172cSAndroid Build Coastguard Worker oid->oid[7] == 2 /* hashAlgs */;
1694*03f9172cSAndroid Build Coastguard Worker }
1695*03f9172cSAndroid Build Coastguard Worker
1696*03f9172cSAndroid Build Coastguard Worker
x509_sha256_oid(struct asn1_oid * oid)1697*03f9172cSAndroid Build Coastguard Worker int x509_sha256_oid(struct asn1_oid *oid)
1698*03f9172cSAndroid Build Coastguard Worker {
1699*03f9172cSAndroid Build Coastguard Worker return x509_sha2_oid(oid) &&
1700*03f9172cSAndroid Build Coastguard Worker oid->oid[8] == 1 /* sha256 */;
1701*03f9172cSAndroid Build Coastguard Worker }
1702*03f9172cSAndroid Build Coastguard Worker
1703*03f9172cSAndroid Build Coastguard Worker
x509_sha384_oid(struct asn1_oid * oid)1704*03f9172cSAndroid Build Coastguard Worker int x509_sha384_oid(struct asn1_oid *oid)
1705*03f9172cSAndroid Build Coastguard Worker {
1706*03f9172cSAndroid Build Coastguard Worker return x509_sha2_oid(oid) &&
1707*03f9172cSAndroid Build Coastguard Worker oid->oid[8] == 2 /* sha384 */;
1708*03f9172cSAndroid Build Coastguard Worker }
1709*03f9172cSAndroid Build Coastguard Worker
1710*03f9172cSAndroid Build Coastguard Worker
x509_sha512_oid(struct asn1_oid * oid)1711*03f9172cSAndroid Build Coastguard Worker int x509_sha512_oid(struct asn1_oid *oid)
1712*03f9172cSAndroid Build Coastguard Worker {
1713*03f9172cSAndroid Build Coastguard Worker return x509_sha2_oid(oid) &&
1714*03f9172cSAndroid Build Coastguard Worker oid->oid[8] == 3 /* sha512 */;
1715*03f9172cSAndroid Build Coastguard Worker }
1716*03f9172cSAndroid Build Coastguard Worker
1717*03f9172cSAndroid Build Coastguard Worker
1718*03f9172cSAndroid Build Coastguard Worker /**
1719*03f9172cSAndroid Build Coastguard Worker * x509_certificate_parse - Parse a X.509 certificate in DER format
1720*03f9172cSAndroid Build Coastguard Worker * @buf: Pointer to the X.509 certificate in DER format
1721*03f9172cSAndroid Build Coastguard Worker * @len: Buffer length
1722*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the parsed certificate or %NULL on failure
1723*03f9172cSAndroid Build Coastguard Worker *
1724*03f9172cSAndroid Build Coastguard Worker * Caller is responsible for freeing the returned certificate by calling
1725*03f9172cSAndroid Build Coastguard Worker * x509_certificate_free().
1726*03f9172cSAndroid Build Coastguard Worker */
x509_certificate_parse(const u8 * buf,size_t len)1727*03f9172cSAndroid Build Coastguard Worker struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
1728*03f9172cSAndroid Build Coastguard Worker {
1729*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
1730*03f9172cSAndroid Build Coastguard Worker const u8 *pos, *end, *hash_start;
1731*03f9172cSAndroid Build Coastguard Worker struct x509_certificate *cert;
1732*03f9172cSAndroid Build Coastguard Worker
1733*03f9172cSAndroid Build Coastguard Worker cert = os_zalloc(sizeof(*cert) + len);
1734*03f9172cSAndroid Build Coastguard Worker if (cert == NULL)
1735*03f9172cSAndroid Build Coastguard Worker return NULL;
1736*03f9172cSAndroid Build Coastguard Worker os_memcpy(cert + 1, buf, len);
1737*03f9172cSAndroid Build Coastguard Worker cert->cert_start = (u8 *) (cert + 1);
1738*03f9172cSAndroid Build Coastguard Worker cert->cert_len = len;
1739*03f9172cSAndroid Build Coastguard Worker
1740*03f9172cSAndroid Build Coastguard Worker pos = buf;
1741*03f9172cSAndroid Build Coastguard Worker end = buf + len;
1742*03f9172cSAndroid Build Coastguard Worker
1743*03f9172cSAndroid Build Coastguard Worker /* RFC 3280 - X.509 v3 certificate / ASN.1 DER */
1744*03f9172cSAndroid Build Coastguard Worker
1745*03f9172cSAndroid Build Coastguard Worker /* Certificate ::= SEQUENCE */
1746*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
1747*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1748*03f9172cSAndroid Build Coastguard Worker "X509: Certificate did not start with a valid SEQUENCE");
1749*03f9172cSAndroid Build Coastguard Worker x509_certificate_free(cert);
1750*03f9172cSAndroid Build Coastguard Worker return NULL;
1751*03f9172cSAndroid Build Coastguard Worker }
1752*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
1753*03f9172cSAndroid Build Coastguard Worker
1754*03f9172cSAndroid Build Coastguard Worker if (hdr.length > end - pos) {
1755*03f9172cSAndroid Build Coastguard Worker x509_certificate_free(cert);
1756*03f9172cSAndroid Build Coastguard Worker return NULL;
1757*03f9172cSAndroid Build Coastguard Worker }
1758*03f9172cSAndroid Build Coastguard Worker
1759*03f9172cSAndroid Build Coastguard Worker if (hdr.length < end - pos) {
1760*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: Ignoring extra data after DER "
1761*03f9172cSAndroid Build Coastguard Worker "encoded certificate",
1762*03f9172cSAndroid Build Coastguard Worker pos + hdr.length, end - (pos + hdr.length));
1763*03f9172cSAndroid Build Coastguard Worker end = pos + hdr.length;
1764*03f9172cSAndroid Build Coastguard Worker }
1765*03f9172cSAndroid Build Coastguard Worker
1766*03f9172cSAndroid Build Coastguard Worker hash_start = pos;
1767*03f9172cSAndroid Build Coastguard Worker cert->tbs_cert_start = cert->cert_start + (hash_start - buf);
1768*03f9172cSAndroid Build Coastguard Worker if (x509_parse_tbs_certificate(pos, end - pos, cert, &pos)) {
1769*03f9172cSAndroid Build Coastguard Worker x509_certificate_free(cert);
1770*03f9172cSAndroid Build Coastguard Worker return NULL;
1771*03f9172cSAndroid Build Coastguard Worker }
1772*03f9172cSAndroid Build Coastguard Worker cert->tbs_cert_len = pos - hash_start;
1773*03f9172cSAndroid Build Coastguard Worker
1774*03f9172cSAndroid Build Coastguard Worker /* signatureAlgorithm AlgorithmIdentifier */
1775*03f9172cSAndroid Build Coastguard Worker if (x509_parse_algorithm_identifier(pos, end - pos,
1776*03f9172cSAndroid Build Coastguard Worker &cert->signature_alg, &pos)) {
1777*03f9172cSAndroid Build Coastguard Worker x509_certificate_free(cert);
1778*03f9172cSAndroid Build Coastguard Worker return NULL;
1779*03f9172cSAndroid Build Coastguard Worker }
1780*03f9172cSAndroid Build Coastguard Worker
1781*03f9172cSAndroid Build Coastguard Worker /* signatureValue BIT STRING */
1782*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1783*03f9172cSAndroid Build Coastguard Worker !asn1_is_bitstring(&hdr)) {
1784*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1785*03f9172cSAndroid Build Coastguard Worker "X509: Expected BITSTRING (signatureValue)");
1786*03f9172cSAndroid Build Coastguard Worker x509_certificate_free(cert);
1787*03f9172cSAndroid Build Coastguard Worker return NULL;
1788*03f9172cSAndroid Build Coastguard Worker }
1789*03f9172cSAndroid Build Coastguard Worker if (hdr.length < 1) {
1790*03f9172cSAndroid Build Coastguard Worker x509_certificate_free(cert);
1791*03f9172cSAndroid Build Coastguard Worker return NULL;
1792*03f9172cSAndroid Build Coastguard Worker }
1793*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
1794*03f9172cSAndroid Build Coastguard Worker if (*pos) {
1795*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
1796*03f9172cSAndroid Build Coastguard Worker "X509: BITSTRING (signatureValue) - %d unused bits",
1797*03f9172cSAndroid Build Coastguard Worker *pos);
1798*03f9172cSAndroid Build Coastguard Worker /* PKCS #1 v1.5 10.2.1:
1799*03f9172cSAndroid Build Coastguard Worker * It is an error if the length in bits of the signature S is
1800*03f9172cSAndroid Build Coastguard Worker * not a multiple of eight.
1801*03f9172cSAndroid Build Coastguard Worker */
1802*03f9172cSAndroid Build Coastguard Worker x509_certificate_free(cert);
1803*03f9172cSAndroid Build Coastguard Worker return NULL;
1804*03f9172cSAndroid Build Coastguard Worker }
1805*03f9172cSAndroid Build Coastguard Worker os_free(cert->sign_value);
1806*03f9172cSAndroid Build Coastguard Worker cert->sign_value = os_memdup(pos + 1, hdr.length - 1);
1807*03f9172cSAndroid Build Coastguard Worker if (cert->sign_value == NULL) {
1808*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
1809*03f9172cSAndroid Build Coastguard Worker "signatureValue");
1810*03f9172cSAndroid Build Coastguard Worker x509_certificate_free(cert);
1811*03f9172cSAndroid Build Coastguard Worker return NULL;
1812*03f9172cSAndroid Build Coastguard Worker }
1813*03f9172cSAndroid Build Coastguard Worker cert->sign_value_len = hdr.length - 1;
1814*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: signature",
1815*03f9172cSAndroid Build Coastguard Worker cert->sign_value, cert->sign_value_len);
1816*03f9172cSAndroid Build Coastguard Worker
1817*03f9172cSAndroid Build Coastguard Worker return cert;
1818*03f9172cSAndroid Build Coastguard Worker }
1819*03f9172cSAndroid Build Coastguard Worker
1820*03f9172cSAndroid Build Coastguard Worker
1821*03f9172cSAndroid Build Coastguard Worker /**
1822*03f9172cSAndroid Build Coastguard Worker * x509_certificate_check_signature - Verify certificate signature
1823*03f9172cSAndroid Build Coastguard Worker * @issuer: Issuer certificate
1824*03f9172cSAndroid Build Coastguard Worker * @cert: Certificate to be verified
1825*03f9172cSAndroid Build Coastguard Worker * Returns: 0 if cert has a valid signature that was signed by the issuer,
1826*03f9172cSAndroid Build Coastguard Worker * -1 if not
1827*03f9172cSAndroid Build Coastguard Worker */
x509_certificate_check_signature(struct x509_certificate * issuer,struct x509_certificate * cert)1828*03f9172cSAndroid Build Coastguard Worker int x509_certificate_check_signature(struct x509_certificate *issuer,
1829*03f9172cSAndroid Build Coastguard Worker struct x509_certificate *cert)
1830*03f9172cSAndroid Build Coastguard Worker {
1831*03f9172cSAndroid Build Coastguard Worker return x509_check_signature(issuer, &cert->signature,
1832*03f9172cSAndroid Build Coastguard Worker cert->sign_value, cert->sign_value_len,
1833*03f9172cSAndroid Build Coastguard Worker cert->tbs_cert_start, cert->tbs_cert_len);
1834*03f9172cSAndroid Build Coastguard Worker }
1835*03f9172cSAndroid Build Coastguard Worker
1836*03f9172cSAndroid Build Coastguard Worker
x509_check_signature(struct x509_certificate * issuer,struct x509_algorithm_identifier * signature,const u8 * sign_value,size_t sign_value_len,const u8 * signed_data,size_t signed_data_len)1837*03f9172cSAndroid Build Coastguard Worker int x509_check_signature(struct x509_certificate *issuer,
1838*03f9172cSAndroid Build Coastguard Worker struct x509_algorithm_identifier *signature,
1839*03f9172cSAndroid Build Coastguard Worker const u8 *sign_value, size_t sign_value_len,
1840*03f9172cSAndroid Build Coastguard Worker const u8 *signed_data, size_t signed_data_len)
1841*03f9172cSAndroid Build Coastguard Worker {
1842*03f9172cSAndroid Build Coastguard Worker struct crypto_public_key *pk;
1843*03f9172cSAndroid Build Coastguard Worker u8 *data;
1844*03f9172cSAndroid Build Coastguard Worker const u8 *pos, *end, *next, *da_end;
1845*03f9172cSAndroid Build Coastguard Worker size_t data_len;
1846*03f9172cSAndroid Build Coastguard Worker struct asn1_hdr hdr;
1847*03f9172cSAndroid Build Coastguard Worker struct asn1_oid oid;
1848*03f9172cSAndroid Build Coastguard Worker u8 hash[64];
1849*03f9172cSAndroid Build Coastguard Worker size_t hash_len;
1850*03f9172cSAndroid Build Coastguard Worker const u8 *addr[1] = { signed_data };
1851*03f9172cSAndroid Build Coastguard Worker size_t len[1] = { signed_data_len };
1852*03f9172cSAndroid Build Coastguard Worker
1853*03f9172cSAndroid Build Coastguard Worker if (!x509_pkcs_oid(&signature->oid) ||
1854*03f9172cSAndroid Build Coastguard Worker signature->oid.len != 7 ||
1855*03f9172cSAndroid Build Coastguard Worker signature->oid.oid[5] != 1 /* pkcs-1 */) {
1856*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Unrecognized signature "
1857*03f9172cSAndroid Build Coastguard Worker "algorithm");
1858*03f9172cSAndroid Build Coastguard Worker return -1;
1859*03f9172cSAndroid Build Coastguard Worker }
1860*03f9172cSAndroid Build Coastguard Worker
1861*03f9172cSAndroid Build Coastguard Worker pk = crypto_public_key_import(issuer->public_key,
1862*03f9172cSAndroid Build Coastguard Worker issuer->public_key_len);
1863*03f9172cSAndroid Build Coastguard Worker if (pk == NULL)
1864*03f9172cSAndroid Build Coastguard Worker return -1;
1865*03f9172cSAndroid Build Coastguard Worker
1866*03f9172cSAndroid Build Coastguard Worker data_len = sign_value_len;
1867*03f9172cSAndroid Build Coastguard Worker data = os_malloc(data_len);
1868*03f9172cSAndroid Build Coastguard Worker if (data == NULL) {
1869*03f9172cSAndroid Build Coastguard Worker crypto_public_key_free(pk);
1870*03f9172cSAndroid Build Coastguard Worker return -1;
1871*03f9172cSAndroid Build Coastguard Worker }
1872*03f9172cSAndroid Build Coastguard Worker
1873*03f9172cSAndroid Build Coastguard Worker if (crypto_public_key_decrypt_pkcs1(pk, sign_value,
1874*03f9172cSAndroid Build Coastguard Worker sign_value_len, data,
1875*03f9172cSAndroid Build Coastguard Worker &data_len) < 0) {
1876*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature");
1877*03f9172cSAndroid Build Coastguard Worker crypto_public_key_free(pk);
1878*03f9172cSAndroid Build Coastguard Worker os_free(data);
1879*03f9172cSAndroid Build Coastguard Worker return -1;
1880*03f9172cSAndroid Build Coastguard Worker }
1881*03f9172cSAndroid Build Coastguard Worker crypto_public_key_free(pk);
1882*03f9172cSAndroid Build Coastguard Worker
1883*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: Signature data D", data, data_len);
1884*03f9172cSAndroid Build Coastguard Worker
1885*03f9172cSAndroid Build Coastguard Worker /*
1886*03f9172cSAndroid Build Coastguard Worker * PKCS #1 v1.5, 10.1.2:
1887*03f9172cSAndroid Build Coastguard Worker *
1888*03f9172cSAndroid Build Coastguard Worker * DigestInfo ::= SEQUENCE {
1889*03f9172cSAndroid Build Coastguard Worker * digestAlgorithm DigestAlgorithmIdentifier,
1890*03f9172cSAndroid Build Coastguard Worker * digest Digest
1891*03f9172cSAndroid Build Coastguard Worker * }
1892*03f9172cSAndroid Build Coastguard Worker *
1893*03f9172cSAndroid Build Coastguard Worker * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
1894*03f9172cSAndroid Build Coastguard Worker *
1895*03f9172cSAndroid Build Coastguard Worker * Digest ::= OCTET STRING
1896*03f9172cSAndroid Build Coastguard Worker *
1897*03f9172cSAndroid Build Coastguard Worker */
1898*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(data, data_len, &hdr) < 0 ||
1899*03f9172cSAndroid Build Coastguard Worker !asn1_is_sequence(&hdr)) {
1900*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr, "X509: Expected SEQUENCE (DigestInfo)");
1901*03f9172cSAndroid Build Coastguard Worker os_free(data);
1902*03f9172cSAndroid Build Coastguard Worker return -1;
1903*03f9172cSAndroid Build Coastguard Worker }
1904*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: DigestInfo", hdr.payload, hdr.length);
1905*03f9172cSAndroid Build Coastguard Worker
1906*03f9172cSAndroid Build Coastguard Worker pos = hdr.payload;
1907*03f9172cSAndroid Build Coastguard Worker end = pos + hdr.length;
1908*03f9172cSAndroid Build Coastguard Worker
1909*03f9172cSAndroid Build Coastguard Worker /*
1910*03f9172cSAndroid Build Coastguard Worker * X.509:
1911*03f9172cSAndroid Build Coastguard Worker * AlgorithmIdentifier ::= SEQUENCE {
1912*03f9172cSAndroid Build Coastguard Worker * algorithm OBJECT IDENTIFIER,
1913*03f9172cSAndroid Build Coastguard Worker * parameters ANY DEFINED BY algorithm OPTIONAL
1914*03f9172cSAndroid Build Coastguard Worker * }
1915*03f9172cSAndroid Build Coastguard Worker */
1916*03f9172cSAndroid Build Coastguard Worker
1917*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1918*03f9172cSAndroid Build Coastguard Worker !asn1_is_sequence(&hdr)) {
1919*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr,
1920*03f9172cSAndroid Build Coastguard Worker "X509: Expected SEQUENCE (AlgorithmIdentifier)");
1921*03f9172cSAndroid Build Coastguard Worker os_free(data);
1922*03f9172cSAndroid Build Coastguard Worker return -1;
1923*03f9172cSAndroid Build Coastguard Worker }
1924*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: DigestAlgorithmIdentifier",
1925*03f9172cSAndroid Build Coastguard Worker hdr.payload, hdr.length);
1926*03f9172cSAndroid Build Coastguard Worker da_end = hdr.payload + hdr.length;
1927*03f9172cSAndroid Build Coastguard Worker
1928*03f9172cSAndroid Build Coastguard Worker if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) {
1929*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Failed to parse digestAlgorithm");
1930*03f9172cSAndroid Build Coastguard Worker os_free(data);
1931*03f9172cSAndroid Build Coastguard Worker return -1;
1932*03f9172cSAndroid Build Coastguard Worker }
1933*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: Digest algorithm parameters",
1934*03f9172cSAndroid Build Coastguard Worker next, da_end - next);
1935*03f9172cSAndroid Build Coastguard Worker
1936*03f9172cSAndroid Build Coastguard Worker /*
1937*03f9172cSAndroid Build Coastguard Worker * RFC 5754: The correct encoding for the SHA2 algorithms would be to
1938*03f9172cSAndroid Build Coastguard Worker * omit the parameters, but there are implementation that encode these
1939*03f9172cSAndroid Build Coastguard Worker * as a NULL element. Allow these two cases and reject anything else.
1940*03f9172cSAndroid Build Coastguard Worker */
1941*03f9172cSAndroid Build Coastguard Worker if (da_end > next &&
1942*03f9172cSAndroid Build Coastguard Worker (asn1_get_next(next, da_end - next, &hdr) < 0 ||
1943*03f9172cSAndroid Build Coastguard Worker !asn1_is_null(&hdr) ||
1944*03f9172cSAndroid Build Coastguard Worker hdr.payload + hdr.length != da_end)) {
1945*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
1946*03f9172cSAndroid Build Coastguard Worker "X509: Unexpected digest algorithm parameters");
1947*03f9172cSAndroid Build Coastguard Worker os_free(data);
1948*03f9172cSAndroid Build Coastguard Worker return -1;
1949*03f9172cSAndroid Build Coastguard Worker }
1950*03f9172cSAndroid Build Coastguard Worker
1951*03f9172cSAndroid Build Coastguard Worker if (x509_sha1_oid(&oid)) {
1952*03f9172cSAndroid Build Coastguard Worker if (signature->oid.oid[6] != 5 /* sha-1WithRSAEncryption */) {
1953*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA1 "
1954*03f9172cSAndroid Build Coastguard Worker "does not match with certificate "
1955*03f9172cSAndroid Build Coastguard Worker "signatureAlgorithm (%lu)",
1956*03f9172cSAndroid Build Coastguard Worker signature->oid.oid[6]);
1957*03f9172cSAndroid Build Coastguard Worker os_free(data);
1958*03f9172cSAndroid Build Coastguard Worker return -1;
1959*03f9172cSAndroid Build Coastguard Worker }
1960*03f9172cSAndroid Build Coastguard Worker goto skip_digest_oid;
1961*03f9172cSAndroid Build Coastguard Worker }
1962*03f9172cSAndroid Build Coastguard Worker
1963*03f9172cSAndroid Build Coastguard Worker if (x509_sha256_oid(&oid)) {
1964*03f9172cSAndroid Build Coastguard Worker if (signature->oid.oid[6] !=
1965*03f9172cSAndroid Build Coastguard Worker 11 /* sha2561WithRSAEncryption */) {
1966*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA256 "
1967*03f9172cSAndroid Build Coastguard Worker "does not match with certificate "
1968*03f9172cSAndroid Build Coastguard Worker "signatureAlgorithm (%lu)",
1969*03f9172cSAndroid Build Coastguard Worker signature->oid.oid[6]);
1970*03f9172cSAndroid Build Coastguard Worker os_free(data);
1971*03f9172cSAndroid Build Coastguard Worker return -1;
1972*03f9172cSAndroid Build Coastguard Worker }
1973*03f9172cSAndroid Build Coastguard Worker goto skip_digest_oid;
1974*03f9172cSAndroid Build Coastguard Worker }
1975*03f9172cSAndroid Build Coastguard Worker
1976*03f9172cSAndroid Build Coastguard Worker if (x509_sha384_oid(&oid)) {
1977*03f9172cSAndroid Build Coastguard Worker if (signature->oid.oid[6] != 12 /* sha384WithRSAEncryption */) {
1978*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA384 "
1979*03f9172cSAndroid Build Coastguard Worker "does not match with certificate "
1980*03f9172cSAndroid Build Coastguard Worker "signatureAlgorithm (%lu)",
1981*03f9172cSAndroid Build Coastguard Worker signature->oid.oid[6]);
1982*03f9172cSAndroid Build Coastguard Worker os_free(data);
1983*03f9172cSAndroid Build Coastguard Worker return -1;
1984*03f9172cSAndroid Build Coastguard Worker }
1985*03f9172cSAndroid Build Coastguard Worker goto skip_digest_oid;
1986*03f9172cSAndroid Build Coastguard Worker }
1987*03f9172cSAndroid Build Coastguard Worker
1988*03f9172cSAndroid Build Coastguard Worker if (x509_sha512_oid(&oid)) {
1989*03f9172cSAndroid Build Coastguard Worker if (signature->oid.oid[6] != 13 /* sha512WithRSAEncryption */) {
1990*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA512 "
1991*03f9172cSAndroid Build Coastguard Worker "does not match with certificate "
1992*03f9172cSAndroid Build Coastguard Worker "signatureAlgorithm (%lu)",
1993*03f9172cSAndroid Build Coastguard Worker signature->oid.oid[6]);
1994*03f9172cSAndroid Build Coastguard Worker os_free(data);
1995*03f9172cSAndroid Build Coastguard Worker return -1;
1996*03f9172cSAndroid Build Coastguard Worker }
1997*03f9172cSAndroid Build Coastguard Worker goto skip_digest_oid;
1998*03f9172cSAndroid Build Coastguard Worker }
1999*03f9172cSAndroid Build Coastguard Worker
2000*03f9172cSAndroid Build Coastguard Worker if (!x509_digest_oid(&oid)) {
2001*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Unrecognized digestAlgorithm");
2002*03f9172cSAndroid Build Coastguard Worker os_free(data);
2003*03f9172cSAndroid Build Coastguard Worker return -1;
2004*03f9172cSAndroid Build Coastguard Worker }
2005*03f9172cSAndroid Build Coastguard Worker switch (oid.oid[5]) {
2006*03f9172cSAndroid Build Coastguard Worker case 5: /* md5 */
2007*03f9172cSAndroid Build Coastguard Worker if (signature->oid.oid[6] != 4 /* md5WithRSAEncryption */) {
2008*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: digestAlgorithm MD5 does "
2009*03f9172cSAndroid Build Coastguard Worker "not match with certificate "
2010*03f9172cSAndroid Build Coastguard Worker "signatureAlgorithm (%lu)",
2011*03f9172cSAndroid Build Coastguard Worker signature->oid.oid[6]);
2012*03f9172cSAndroid Build Coastguard Worker os_free(data);
2013*03f9172cSAndroid Build Coastguard Worker return -1;
2014*03f9172cSAndroid Build Coastguard Worker }
2015*03f9172cSAndroid Build Coastguard Worker break;
2016*03f9172cSAndroid Build Coastguard Worker case 2: /* md2 */
2017*03f9172cSAndroid Build Coastguard Worker case 4: /* md4 */
2018*03f9172cSAndroid Build Coastguard Worker default:
2019*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Unsupported digestAlgorithm "
2020*03f9172cSAndroid Build Coastguard Worker "(%lu)", oid.oid[5]);
2021*03f9172cSAndroid Build Coastguard Worker os_free(data);
2022*03f9172cSAndroid Build Coastguard Worker return -1;
2023*03f9172cSAndroid Build Coastguard Worker }
2024*03f9172cSAndroid Build Coastguard Worker
2025*03f9172cSAndroid Build Coastguard Worker skip_digest_oid:
2026*03f9172cSAndroid Build Coastguard Worker /* Digest ::= OCTET STRING */
2027*03f9172cSAndroid Build Coastguard Worker pos = da_end;
2028*03f9172cSAndroid Build Coastguard Worker
2029*03f9172cSAndroid Build Coastguard Worker if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
2030*03f9172cSAndroid Build Coastguard Worker !asn1_is_octetstring(&hdr)) {
2031*03f9172cSAndroid Build Coastguard Worker asn1_unexpected(&hdr, "X509: Expected OCTETSTRING (Digest)");
2032*03f9172cSAndroid Build Coastguard Worker os_free(data);
2033*03f9172cSAndroid Build Coastguard Worker return -1;
2034*03f9172cSAndroid Build Coastguard Worker }
2035*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest",
2036*03f9172cSAndroid Build Coastguard Worker hdr.payload, hdr.length);
2037*03f9172cSAndroid Build Coastguard Worker
2038*03f9172cSAndroid Build Coastguard Worker switch (signature->oid.oid[6]) {
2039*03f9172cSAndroid Build Coastguard Worker case 4: /* md5WithRSAEncryption */
2040*03f9172cSAndroid Build Coastguard Worker md5_vector(1, addr, len, hash);
2041*03f9172cSAndroid Build Coastguard Worker hash_len = 16;
2042*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (MD5)",
2043*03f9172cSAndroid Build Coastguard Worker hash, hash_len);
2044*03f9172cSAndroid Build Coastguard Worker break;
2045*03f9172cSAndroid Build Coastguard Worker case 5: /* sha-1WithRSAEncryption */
2046*03f9172cSAndroid Build Coastguard Worker sha1_vector(1, addr, len, hash);
2047*03f9172cSAndroid Build Coastguard Worker hash_len = 20;
2048*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA1)",
2049*03f9172cSAndroid Build Coastguard Worker hash, hash_len);
2050*03f9172cSAndroid Build Coastguard Worker break;
2051*03f9172cSAndroid Build Coastguard Worker case 11: /* sha256WithRSAEncryption */
2052*03f9172cSAndroid Build Coastguard Worker sha256_vector(1, addr, len, hash);
2053*03f9172cSAndroid Build Coastguard Worker hash_len = 32;
2054*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)",
2055*03f9172cSAndroid Build Coastguard Worker hash, hash_len);
2056*03f9172cSAndroid Build Coastguard Worker break;
2057*03f9172cSAndroid Build Coastguard Worker case 12: /* sha384WithRSAEncryption */
2058*03f9172cSAndroid Build Coastguard Worker sha384_vector(1, addr, len, hash);
2059*03f9172cSAndroid Build Coastguard Worker hash_len = 48;
2060*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA384)",
2061*03f9172cSAndroid Build Coastguard Worker hash, hash_len);
2062*03f9172cSAndroid Build Coastguard Worker break;
2063*03f9172cSAndroid Build Coastguard Worker case 13: /* sha512WithRSAEncryption */
2064*03f9172cSAndroid Build Coastguard Worker sha512_vector(1, addr, len, hash);
2065*03f9172cSAndroid Build Coastguard Worker hash_len = 64;
2066*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA512)",
2067*03f9172cSAndroid Build Coastguard Worker hash, hash_len);
2068*03f9172cSAndroid Build Coastguard Worker break;
2069*03f9172cSAndroid Build Coastguard Worker case 2: /* md2WithRSAEncryption */
2070*03f9172cSAndroid Build Coastguard Worker default:
2071*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_INFO, "X509: Unsupported certificate signature "
2072*03f9172cSAndroid Build Coastguard Worker "algorithm (%lu)", signature->oid.oid[6]);
2073*03f9172cSAndroid Build Coastguard Worker os_free(data);
2074*03f9172cSAndroid Build Coastguard Worker return -1;
2075*03f9172cSAndroid Build Coastguard Worker }
2076*03f9172cSAndroid Build Coastguard Worker
2077*03f9172cSAndroid Build Coastguard Worker if (hdr.length != hash_len ||
2078*03f9172cSAndroid Build Coastguard Worker os_memcmp_const(hdr.payload, hash, hdr.length) != 0) {
2079*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_INFO, "X509: Certificate Digest does not match "
2080*03f9172cSAndroid Build Coastguard Worker "with calculated tbsCertificate hash");
2081*03f9172cSAndroid Build Coastguard Worker os_free(data);
2082*03f9172cSAndroid Build Coastguard Worker return -1;
2083*03f9172cSAndroid Build Coastguard Worker }
2084*03f9172cSAndroid Build Coastguard Worker
2085*03f9172cSAndroid Build Coastguard Worker if (hdr.payload + hdr.length < data + data_len) {
2086*03f9172cSAndroid Build Coastguard Worker wpa_hexdump(MSG_INFO,
2087*03f9172cSAndroid Build Coastguard Worker "X509: Extra data after certificate signature hash",
2088*03f9172cSAndroid Build Coastguard Worker hdr.payload + hdr.length,
2089*03f9172cSAndroid Build Coastguard Worker data + data_len - hdr.payload - hdr.length);
2090*03f9172cSAndroid Build Coastguard Worker os_free(data);
2091*03f9172cSAndroid Build Coastguard Worker return -1;
2092*03f9172cSAndroid Build Coastguard Worker }
2093*03f9172cSAndroid Build Coastguard Worker
2094*03f9172cSAndroid Build Coastguard Worker os_free(data);
2095*03f9172cSAndroid Build Coastguard Worker
2096*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with "
2097*03f9172cSAndroid Build Coastguard Worker "calculated tbsCertificate hash");
2098*03f9172cSAndroid Build Coastguard Worker
2099*03f9172cSAndroid Build Coastguard Worker return 0;
2100*03f9172cSAndroid Build Coastguard Worker }
2101*03f9172cSAndroid Build Coastguard Worker
2102*03f9172cSAndroid Build Coastguard Worker
x509_valid_issuer(const struct x509_certificate * cert)2103*03f9172cSAndroid Build Coastguard Worker static int x509_valid_issuer(const struct x509_certificate *cert)
2104*03f9172cSAndroid Build Coastguard Worker {
2105*03f9172cSAndroid Build Coastguard Worker if ((cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS) &&
2106*03f9172cSAndroid Build Coastguard Worker !cert->ca) {
2107*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Non-CA certificate used as an "
2108*03f9172cSAndroid Build Coastguard Worker "issuer");
2109*03f9172cSAndroid Build Coastguard Worker return -1;
2110*03f9172cSAndroid Build Coastguard Worker }
2111*03f9172cSAndroid Build Coastguard Worker
2112*03f9172cSAndroid Build Coastguard Worker if (cert->version == X509_CERT_V3 &&
2113*03f9172cSAndroid Build Coastguard Worker !(cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS)) {
2114*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: v3 CA certificate did not "
2115*03f9172cSAndroid Build Coastguard Worker "include BasicConstraints extension");
2116*03f9172cSAndroid Build Coastguard Worker return -1;
2117*03f9172cSAndroid Build Coastguard Worker }
2118*03f9172cSAndroid Build Coastguard Worker
2119*03f9172cSAndroid Build Coastguard Worker if ((cert->extensions_present & X509_EXT_KEY_USAGE) &&
2120*03f9172cSAndroid Build Coastguard Worker !(cert->key_usage & X509_KEY_USAGE_KEY_CERT_SIGN)) {
2121*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Issuer certificate did not have "
2122*03f9172cSAndroid Build Coastguard Worker "keyCertSign bit in Key Usage");
2123*03f9172cSAndroid Build Coastguard Worker return -1;
2124*03f9172cSAndroid Build Coastguard Worker }
2125*03f9172cSAndroid Build Coastguard Worker
2126*03f9172cSAndroid Build Coastguard Worker return 0;
2127*03f9172cSAndroid Build Coastguard Worker }
2128*03f9172cSAndroid Build Coastguard Worker
2129*03f9172cSAndroid Build Coastguard Worker
2130*03f9172cSAndroid Build Coastguard Worker /**
2131*03f9172cSAndroid Build Coastguard Worker * x509_certificate_chain_validate - Validate X.509 certificate chain
2132*03f9172cSAndroid Build Coastguard Worker * @trusted: List of trusted certificates
2133*03f9172cSAndroid Build Coastguard Worker * @chain: Certificate chain to be validated (first chain must be issued by
2134*03f9172cSAndroid Build Coastguard Worker * signed by the second certificate in the chain and so on)
2135*03f9172cSAndroid Build Coastguard Worker * @reason: Buffer for returning failure reason (X509_VALIDATE_*)
2136*03f9172cSAndroid Build Coastguard Worker * Returns: 0 if chain is valid, -1 if not
2137*03f9172cSAndroid Build Coastguard Worker */
x509_certificate_chain_validate(struct x509_certificate * trusted,struct x509_certificate * chain,int * reason,int disable_time_checks)2138*03f9172cSAndroid Build Coastguard Worker int x509_certificate_chain_validate(struct x509_certificate *trusted,
2139*03f9172cSAndroid Build Coastguard Worker struct x509_certificate *chain,
2140*03f9172cSAndroid Build Coastguard Worker int *reason, int disable_time_checks)
2141*03f9172cSAndroid Build Coastguard Worker {
2142*03f9172cSAndroid Build Coastguard Worker long unsigned idx;
2143*03f9172cSAndroid Build Coastguard Worker int chain_trusted = 0;
2144*03f9172cSAndroid Build Coastguard Worker struct x509_certificate *cert, *trust;
2145*03f9172cSAndroid Build Coastguard Worker char buf[128];
2146*03f9172cSAndroid Build Coastguard Worker struct os_time now;
2147*03f9172cSAndroid Build Coastguard Worker
2148*03f9172cSAndroid Build Coastguard Worker *reason = X509_VALIDATE_OK;
2149*03f9172cSAndroid Build Coastguard Worker
2150*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Validate certificate chain");
2151*03f9172cSAndroid Build Coastguard Worker os_get_time(&now);
2152*03f9172cSAndroid Build Coastguard Worker
2153*03f9172cSAndroid Build Coastguard Worker for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
2154*03f9172cSAndroid Build Coastguard Worker cert->issuer_trusted = 0;
2155*03f9172cSAndroid Build Coastguard Worker x509_name_string(&cert->subject, buf, sizeof(buf));
2156*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
2157*03f9172cSAndroid Build Coastguard Worker
2158*03f9172cSAndroid Build Coastguard Worker if (chain_trusted)
2159*03f9172cSAndroid Build Coastguard Worker continue;
2160*03f9172cSAndroid Build Coastguard Worker
2161*03f9172cSAndroid Build Coastguard Worker if (!disable_time_checks &&
2162*03f9172cSAndroid Build Coastguard Worker ((unsigned long) now.sec <
2163*03f9172cSAndroid Build Coastguard Worker (unsigned long) cert->not_before ||
2164*03f9172cSAndroid Build Coastguard Worker (unsigned long) now.sec >
2165*03f9172cSAndroid Build Coastguard Worker (unsigned long) cert->not_after)) {
2166*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_INFO, "X509: Certificate not valid "
2167*03f9172cSAndroid Build Coastguard Worker "(now=%lu not_before=%lu not_after=%lu)",
2168*03f9172cSAndroid Build Coastguard Worker now.sec, cert->not_before, cert->not_after);
2169*03f9172cSAndroid Build Coastguard Worker *reason = X509_VALIDATE_CERTIFICATE_EXPIRED;
2170*03f9172cSAndroid Build Coastguard Worker return -1;
2171*03f9172cSAndroid Build Coastguard Worker }
2172*03f9172cSAndroid Build Coastguard Worker
2173*03f9172cSAndroid Build Coastguard Worker if (cert->next) {
2174*03f9172cSAndroid Build Coastguard Worker if (x509_name_compare(&cert->issuer,
2175*03f9172cSAndroid Build Coastguard Worker &cert->next->subject) != 0) {
2176*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Certificate "
2177*03f9172cSAndroid Build Coastguard Worker "chain issuer name mismatch");
2178*03f9172cSAndroid Build Coastguard Worker x509_name_string(&cert->issuer, buf,
2179*03f9172cSAndroid Build Coastguard Worker sizeof(buf));
2180*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: cert issuer: %s",
2181*03f9172cSAndroid Build Coastguard Worker buf);
2182*03f9172cSAndroid Build Coastguard Worker x509_name_string(&cert->next->subject, buf,
2183*03f9172cSAndroid Build Coastguard Worker sizeof(buf));
2184*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: next cert "
2185*03f9172cSAndroid Build Coastguard Worker "subject: %s", buf);
2186*03f9172cSAndroid Build Coastguard Worker *reason = X509_VALIDATE_CERTIFICATE_UNKNOWN;
2187*03f9172cSAndroid Build Coastguard Worker return -1;
2188*03f9172cSAndroid Build Coastguard Worker }
2189*03f9172cSAndroid Build Coastguard Worker
2190*03f9172cSAndroid Build Coastguard Worker if (x509_valid_issuer(cert->next) < 0) {
2191*03f9172cSAndroid Build Coastguard Worker *reason = X509_VALIDATE_BAD_CERTIFICATE;
2192*03f9172cSAndroid Build Coastguard Worker return -1;
2193*03f9172cSAndroid Build Coastguard Worker }
2194*03f9172cSAndroid Build Coastguard Worker
2195*03f9172cSAndroid Build Coastguard Worker if ((cert->next->extensions_present &
2196*03f9172cSAndroid Build Coastguard Worker X509_EXT_PATH_LEN_CONSTRAINT) &&
2197*03f9172cSAndroid Build Coastguard Worker idx > cert->next->path_len_constraint) {
2198*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: pathLenConstraint"
2199*03f9172cSAndroid Build Coastguard Worker " not met (idx=%lu issuer "
2200*03f9172cSAndroid Build Coastguard Worker "pathLenConstraint=%lu)", idx,
2201*03f9172cSAndroid Build Coastguard Worker cert->next->path_len_constraint);
2202*03f9172cSAndroid Build Coastguard Worker *reason = X509_VALIDATE_BAD_CERTIFICATE;
2203*03f9172cSAndroid Build Coastguard Worker return -1;
2204*03f9172cSAndroid Build Coastguard Worker }
2205*03f9172cSAndroid Build Coastguard Worker
2206*03f9172cSAndroid Build Coastguard Worker if (x509_certificate_check_signature(cert->next, cert)
2207*03f9172cSAndroid Build Coastguard Worker < 0) {
2208*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Invalid "
2209*03f9172cSAndroid Build Coastguard Worker "certificate signature within "
2210*03f9172cSAndroid Build Coastguard Worker "chain");
2211*03f9172cSAndroid Build Coastguard Worker *reason = X509_VALIDATE_BAD_CERTIFICATE;
2212*03f9172cSAndroid Build Coastguard Worker return -1;
2213*03f9172cSAndroid Build Coastguard Worker }
2214*03f9172cSAndroid Build Coastguard Worker }
2215*03f9172cSAndroid Build Coastguard Worker
2216*03f9172cSAndroid Build Coastguard Worker for (trust = trusted; trust; trust = trust->next) {
2217*03f9172cSAndroid Build Coastguard Worker if (x509_name_compare(&cert->issuer, &trust->subject)
2218*03f9172cSAndroid Build Coastguard Worker == 0)
2219*03f9172cSAndroid Build Coastguard Worker break;
2220*03f9172cSAndroid Build Coastguard Worker }
2221*03f9172cSAndroid Build Coastguard Worker
2222*03f9172cSAndroid Build Coastguard Worker if (trust) {
2223*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Found issuer from the "
2224*03f9172cSAndroid Build Coastguard Worker "list of trusted certificates");
2225*03f9172cSAndroid Build Coastguard Worker if (x509_valid_issuer(trust) < 0) {
2226*03f9172cSAndroid Build Coastguard Worker *reason = X509_VALIDATE_BAD_CERTIFICATE;
2227*03f9172cSAndroid Build Coastguard Worker return -1;
2228*03f9172cSAndroid Build Coastguard Worker }
2229*03f9172cSAndroid Build Coastguard Worker
2230*03f9172cSAndroid Build Coastguard Worker if (x509_certificate_check_signature(trust, cert) < 0)
2231*03f9172cSAndroid Build Coastguard Worker {
2232*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Invalid "
2233*03f9172cSAndroid Build Coastguard Worker "certificate signature");
2234*03f9172cSAndroid Build Coastguard Worker *reason = X509_VALIDATE_BAD_CERTIFICATE;
2235*03f9172cSAndroid Build Coastguard Worker return -1;
2236*03f9172cSAndroid Build Coastguard Worker }
2237*03f9172cSAndroid Build Coastguard Worker
2238*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
2239*03f9172cSAndroid Build Coastguard Worker "found to complete the chain");
2240*03f9172cSAndroid Build Coastguard Worker cert->issuer_trusted = 1;
2241*03f9172cSAndroid Build Coastguard Worker chain_trusted = 1;
2242*03f9172cSAndroid Build Coastguard Worker }
2243*03f9172cSAndroid Build Coastguard Worker }
2244*03f9172cSAndroid Build Coastguard Worker
2245*03f9172cSAndroid Build Coastguard Worker if (!chain_trusted) {
2246*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Did not find any of the issuers "
2247*03f9172cSAndroid Build Coastguard Worker "from the list of trusted certificates");
2248*03f9172cSAndroid Build Coastguard Worker if (trusted) {
2249*03f9172cSAndroid Build Coastguard Worker *reason = X509_VALIDATE_UNKNOWN_CA;
2250*03f9172cSAndroid Build Coastguard Worker return -1;
2251*03f9172cSAndroid Build Coastguard Worker }
2252*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Certificate chain validation "
2253*03f9172cSAndroid Build Coastguard Worker "disabled - ignore unknown CA issue");
2254*03f9172cSAndroid Build Coastguard Worker }
2255*03f9172cSAndroid Build Coastguard Worker
2256*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "X509: Certificate chain valid");
2257*03f9172cSAndroid Build Coastguard Worker
2258*03f9172cSAndroid Build Coastguard Worker return 0;
2259*03f9172cSAndroid Build Coastguard Worker }
2260*03f9172cSAndroid Build Coastguard Worker
2261*03f9172cSAndroid Build Coastguard Worker
2262*03f9172cSAndroid Build Coastguard Worker /**
2263*03f9172cSAndroid Build Coastguard Worker * x509_certificate_get_subject - Get a certificate based on Subject name
2264*03f9172cSAndroid Build Coastguard Worker * @chain: Certificate chain to search through
2265*03f9172cSAndroid Build Coastguard Worker * @name: Subject name to search for
2266*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the certificate with the given Subject name or
2267*03f9172cSAndroid Build Coastguard Worker * %NULL on failure
2268*03f9172cSAndroid Build Coastguard Worker */
2269*03f9172cSAndroid Build Coastguard Worker struct x509_certificate *
x509_certificate_get_subject(struct x509_certificate * chain,struct x509_name * name)2270*03f9172cSAndroid Build Coastguard Worker x509_certificate_get_subject(struct x509_certificate *chain,
2271*03f9172cSAndroid Build Coastguard Worker struct x509_name *name)
2272*03f9172cSAndroid Build Coastguard Worker {
2273*03f9172cSAndroid Build Coastguard Worker struct x509_certificate *cert;
2274*03f9172cSAndroid Build Coastguard Worker
2275*03f9172cSAndroid Build Coastguard Worker for (cert = chain; cert; cert = cert->next) {
2276*03f9172cSAndroid Build Coastguard Worker if (x509_name_compare(&cert->subject, name) == 0)
2277*03f9172cSAndroid Build Coastguard Worker return cert;
2278*03f9172cSAndroid Build Coastguard Worker }
2279*03f9172cSAndroid Build Coastguard Worker return NULL;
2280*03f9172cSAndroid Build Coastguard Worker }
2281*03f9172cSAndroid Build Coastguard Worker
2282*03f9172cSAndroid Build Coastguard Worker
2283*03f9172cSAndroid Build Coastguard Worker /**
2284*03f9172cSAndroid Build Coastguard Worker * x509_certificate_self_signed - Is the certificate self-signed?
2285*03f9172cSAndroid Build Coastguard Worker * @cert: Certificate
2286*03f9172cSAndroid Build Coastguard Worker * Returns: 1 if certificate is self-signed, 0 if not
2287*03f9172cSAndroid Build Coastguard Worker */
x509_certificate_self_signed(struct x509_certificate * cert)2288*03f9172cSAndroid Build Coastguard Worker int x509_certificate_self_signed(struct x509_certificate *cert)
2289*03f9172cSAndroid Build Coastguard Worker {
2290*03f9172cSAndroid Build Coastguard Worker return x509_name_compare(&cert->issuer, &cert->subject) == 0;
2291*03f9172cSAndroid Build Coastguard Worker }
2292