xref: /freebsd/contrib/wpa/hs20/client/est.c (revision 7899f917b1c0ea178f1d2be0cfb452086d079d23)
1 /*
2  * Hotspot 2.0 OSU client - EST client
3  * Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 #include <openssl/err.h>
11 #include <openssl/evp.h>
12 #include <openssl/pem.h>
13 #include <openssl/pkcs7.h>
14 #include <openssl/asn1.h>
15 #include <openssl/asn1t.h>
16 #include <openssl/x509.h>
17 #include <openssl/x509v3.h>
18 #include <openssl/opensslv.h>
19 #include <openssl/buffer.h>
20 
21 #include "common.h"
22 #include "utils/base64.h"
23 #include "utils/xml-utils.h"
24 #include "utils/http-utils.h"
25 #include "osu_client.h"
26 
27 
28 static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
29 			 size_t len, char *pem_file, char *der_file)
30 {
31 #ifdef OPENSSL_IS_BORINGSSL
32 	CBS pkcs7_cbs;
33 #else /* OPENSSL_IS_BORINGSSL */
34 	PKCS7 *p7 = NULL;
35 	const unsigned char *p = pkcs7;
36 #endif /* OPENSSL_IS_BORINGSSL */
37 	STACK_OF(X509) *certs;
38 	int i, num, ret = -1;
39 	BIO *out = NULL;
40 
41 #ifdef OPENSSL_IS_BORINGSSL
42 	certs = sk_X509_new_null();
43 	if (!certs)
44 		goto fail;
45 	CBS_init(&pkcs7_cbs, pkcs7, len);
46 	if (!PKCS7_get_certificates(certs, &pkcs7_cbs)) {
47 		wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s",
48 			   ERR_error_string(ERR_get_error(), NULL));
49 		write_result(ctx, "Could not parse PKCS#7 object from EST");
50 		goto fail;
51 	}
52 #else /* OPENSSL_IS_BORINGSSL */
53 	p7 = d2i_PKCS7(NULL, &p, len);
54 	if (p7 == NULL) {
55 		wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s",
56 			   ERR_error_string(ERR_get_error(), NULL));
57 		write_result(ctx, "Could not parse PKCS#7 object from EST");
58 		goto fail;
59 	}
60 
61 	switch (OBJ_obj2nid(p7->type)) {
62 	case NID_pkcs7_signed:
63 		certs = p7->d.sign->cert;
64 		break;
65 	case NID_pkcs7_signedAndEnveloped:
66 		certs = p7->d.signed_and_enveloped->cert;
67 		break;
68 	default:
69 		certs = NULL;
70 		break;
71 	}
72 #endif /* OPENSSL_IS_BORINGSSL */
73 
74 	if (!certs || ((num = sk_X509_num(certs)) == 0)) {
75 		wpa_printf(MSG_INFO, "No certificates found in PKCS#7 object");
76 		write_result(ctx, "No certificates found in PKCS#7 object");
77 		goto fail;
78 	}
79 
80 	if (der_file) {
81 		FILE *f = fopen(der_file, "wb");
82 		if (f == NULL)
83 			goto fail;
84 		i2d_X509_fp(f, sk_X509_value(certs, 0));
85 		fclose(f);
86 	}
87 
88 	if (pem_file) {
89 		out = BIO_new(BIO_s_file());
90 		if (out == NULL ||
91 		    BIO_write_filename(out, pem_file) <= 0)
92 			goto fail;
93 
94 		for (i = 0; i < num; i++) {
95 			X509 *cert = sk_X509_value(certs, i);
96 			X509_print(out, cert);
97 			PEM_write_bio_X509(out, cert);
98 			BIO_puts(out, "\n");
99 		}
100 	}
101 
102 	ret = 0;
103 
104 fail:
105 #ifdef OPENSSL_IS_BORINGSSL
106 	if (certs)
107 		sk_X509_pop_free(certs, X509_free);
108 #else /* OPENSSL_IS_BORINGSSL */
109 	PKCS7_free(p7);
110 #endif /* OPENSSL_IS_BORINGSSL */
111 	if (out)
112 		BIO_free_all(out);
113 
114 	return ret;
115 }
116 
117 
118 int est_load_cacerts(struct hs20_osu_client *ctx, const char *url)
119 {
120 	char *buf, *resp;
121 	size_t buflen;
122 	unsigned char *pkcs7;
123 	size_t pkcs7_len, resp_len;
124 	int res;
125 
126 	buflen = os_strlen(url) + 100;
127 	buf = os_malloc(buflen);
128 	if (buf == NULL)
129 		return -1;
130 
131 	os_snprintf(buf, buflen, "%s/cacerts", url);
132 	wpa_printf(MSG_INFO, "Download EST cacerts from %s", buf);
133 	write_summary(ctx, "Download EST cacerts from %s", buf);
134 	ctx->no_osu_cert_validation = 1;
135 	http_ocsp_set(ctx->http, 1);
136 	res = http_download_file(ctx->http, buf, "Cert/est-cacerts.txt",
137 				 ctx->ca_fname);
138 	http_ocsp_set(ctx->http,
139 		      (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
140 	ctx->no_osu_cert_validation = 0;
141 	if (res < 0) {
142 		wpa_printf(MSG_INFO, "Failed to download EST cacerts from %s",
143 			   buf);
144 		write_result(ctx, "Failed to download EST cacerts from %s",
145 			     buf);
146 		os_free(buf);
147 		return -1;
148 	}
149 	os_free(buf);
150 
151 	resp = os_readfile("Cert/est-cacerts.txt", &resp_len);
152 	if (resp == NULL) {
153 		wpa_printf(MSG_INFO, "Could not read Cert/est-cacerts.txt");
154 		write_result(ctx, "Could not read EST cacerts");
155 		return -1;
156 	}
157 
158 	pkcs7 = base64_decode(resp, resp_len, &pkcs7_len);
159 	if (pkcs7 && pkcs7_len < resp_len / 2) {
160 		wpa_printf(MSG_INFO, "Too short base64 decode (%u bytes; downloaded %u bytes) - assume this was binary",
161 			   (unsigned int) pkcs7_len, (unsigned int) resp_len);
162 		os_free(pkcs7);
163 		pkcs7 = NULL;
164 	}
165 	if (pkcs7 == NULL) {
166 		wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7");
167 		pkcs7 = os_malloc(resp_len);
168 		if (pkcs7) {
169 			os_memcpy(pkcs7, resp, resp_len);
170 			pkcs7_len = resp_len;
171 		}
172 	}
173 	os_free(resp);
174 
175 	if (pkcs7 == NULL) {
176 		wpa_printf(MSG_INFO, "Could not fetch PKCS7 cacerts");
177 		write_result(ctx, "Could not fetch EST PKCS#7 cacerts");
178 		return -1;
179 	}
180 
181 	res = pkcs7_to_cert(ctx, pkcs7, pkcs7_len, "Cert/est-cacerts.pem",
182 			    NULL);
183 	os_free(pkcs7);
184 	if (res < 0) {
185 		wpa_printf(MSG_INFO, "Could not parse CA certs from PKCS#7 cacerts response");
186 		write_result(ctx, "Could not parse CA certs from EST PKCS#7 cacerts response");
187 		return -1;
188 	}
189 	unlink("Cert/est-cacerts.txt");
190 
191 	return 0;
192 }
193 
194 
195 /*
196  * CsrAttrs ::= SEQUENCE SIZE (0..MAX) OF AttrOrOID
197  *
198  * AttrOrOID ::= CHOICE {
199  *   oid OBJECT IDENTIFIER,
200  *   attribute Attribute }
201  *
202  * Attribute ::= SEQUENCE {
203  *   type OBJECT IDENTIFIER,
204  *   values SET SIZE(1..MAX) OF OBJECT IDENTIFIER }
205  */
206 
207 typedef struct {
208 	ASN1_OBJECT *type;
209 	STACK_OF(ASN1_OBJECT) *values;
210 } Attribute;
211 
212 typedef struct {
213 	int type;
214 	union {
215 		ASN1_OBJECT *oid;
216 		Attribute *attribute;
217 	} d;
218 } AttrOrOID;
219 
220 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
221 DEFINE_STACK_OF(AttrOrOID)
222 #endif
223 
224 typedef struct {
225 	int type;
226 	STACK_OF(AttrOrOID) *attrs;
227 } CsrAttrs;
228 
229 ASN1_SEQUENCE(Attribute) = {
230 	ASN1_SIMPLE(Attribute, type, ASN1_OBJECT),
231 	ASN1_SET_OF(Attribute, values, ASN1_OBJECT)
232 } ASN1_SEQUENCE_END(Attribute);
233 
234 ASN1_CHOICE(AttrOrOID) = {
235 	ASN1_SIMPLE(AttrOrOID, d.oid, ASN1_OBJECT),
236 	ASN1_SIMPLE(AttrOrOID, d.attribute, Attribute)
237 } ASN1_CHOICE_END(AttrOrOID);
238 
239 ASN1_CHOICE(CsrAttrs) = {
240 	ASN1_SEQUENCE_OF(CsrAttrs, attrs, AttrOrOID)
241 } ASN1_CHOICE_END(CsrAttrs);
242 
243 IMPLEMENT_ASN1_FUNCTIONS(CsrAttrs);
244 
245 
246 static void add_csrattrs_oid(struct hs20_osu_client *ctx, ASN1_OBJECT *oid,
247 			     STACK_OF(X509_EXTENSION) *exts)
248 {
249 	char txt[100];
250 	int res;
251 
252 	if (!oid)
253 		return;
254 
255 	res = OBJ_obj2txt(txt, sizeof(txt), oid, 1);
256 	if (res < 0 || res >= (int) sizeof(txt))
257 		return;
258 
259 	if (os_strcmp(txt, "1.2.840.113549.1.9.7") == 0) {
260 		wpa_printf(MSG_INFO, "TODO: csrattr challengePassword");
261 	} else if (os_strcmp(txt, "1.2.840.113549.1.1.11") == 0) {
262 		wpa_printf(MSG_INFO, "csrattr sha256WithRSAEncryption");
263 	} else {
264 		wpa_printf(MSG_INFO, "Ignore unsupported csrattr oid %s", txt);
265 	}
266 }
267 
268 
269 static void add_csrattrs_ext_req(struct hs20_osu_client *ctx,
270 				 STACK_OF(ASN1_OBJECT) *values,
271 				 STACK_OF(X509_EXTENSION) *exts)
272 {
273 	char txt[100];
274 	int i, num, res;
275 
276 	num = sk_ASN1_OBJECT_num(values);
277 	for (i = 0; i < num; i++) {
278 		ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(values, i);
279 
280 		res = OBJ_obj2txt(txt, sizeof(txt), oid, 1);
281 		if (res < 0 || res >= (int) sizeof(txt))
282 			continue;
283 
284 		if (os_strcmp(txt, "1.3.6.1.1.1.1.22") == 0) {
285 			wpa_printf(MSG_INFO, "TODO: extReq macAddress");
286 		} else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.3") == 0) {
287 			wpa_printf(MSG_INFO, "TODO: extReq imei");
288 		} else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.4") == 0) {
289 			wpa_printf(MSG_INFO, "TODO: extReq meid");
290 		} else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.5") == 0) {
291 			wpa_printf(MSG_INFO, "TODO: extReq DevId");
292 		} else {
293 			wpa_printf(MSG_INFO, "Ignore unsupported cstattr extensionsRequest %s",
294 				   txt);
295 		}
296 	}
297 }
298 
299 
300 static void add_csrattrs_attr(struct hs20_osu_client *ctx, Attribute *attr,
301 			      STACK_OF(X509_EXTENSION) *exts)
302 {
303 	char txt[100], txt2[100];
304 	int i, num, res;
305 
306 	if (!attr || !attr->type || !attr->values)
307 		return;
308 
309 	res = OBJ_obj2txt(txt, sizeof(txt), attr->type, 1);
310 	if (res < 0 || res >= (int) sizeof(txt))
311 		return;
312 
313 	if (os_strcmp(txt, "1.2.840.113549.1.9.14") == 0) {
314 		add_csrattrs_ext_req(ctx, attr->values, exts);
315 		return;
316 	}
317 
318 	num = sk_ASN1_OBJECT_num(attr->values);
319 	for (i = 0; i < num; i++) {
320 		ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(attr->values, i);
321 
322 		res = OBJ_obj2txt(txt2, sizeof(txt2), oid, 1);
323 		if (res < 0 || res >= (int) sizeof(txt2))
324 			continue;
325 
326 		wpa_printf(MSG_INFO, "Ignore unsupported cstattr::attr %s oid %s",
327 			   txt, txt2);
328 	}
329 }
330 
331 
332 static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
333 			 STACK_OF(X509_EXTENSION) *exts)
334 {
335 	int i, num;
336 
337 	if (!csrattrs || ! csrattrs->attrs)
338 		return;
339 
340 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
341 	num = sk_AttrOrOID_num(csrattrs->attrs);
342 #else
343 	num = SKM_sk_num(AttrOrOID, csrattrs->attrs);
344 #endif
345 	for (i = 0; i < num; i++) {
346 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
347 		AttrOrOID *ao = sk_AttrOrOID_value(csrattrs->attrs, i);
348 #else
349 		AttrOrOID *ao = SKM_sk_value(AttrOrOID, csrattrs->attrs, i);
350 #endif
351 		switch (ao->type) {
352 		case 0:
353 			add_csrattrs_oid(ctx, ao->d.oid, exts);
354 			break;
355 		case 1:
356 			add_csrattrs_attr(ctx, ao->d.attribute, exts);
357 			break;
358 		}
359 	}
360 }
361 
362 
363 static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
364 			char *csr_pem, char *est_req, char *old_cert,
365 			CsrAttrs *csrattrs)
366 {
367 	EVP_PKEY_CTX *pctx = NULL;
368 	EVP_PKEY *pkey = NULL;
369 	X509_REQ *req = NULL;
370 	int ret = -1;
371 	unsigned int val;
372 	X509_NAME *subj = NULL;
373 	char name[100];
374 	STACK_OF(X509_EXTENSION) *exts = NULL;
375 	X509_EXTENSION *ex;
376 	BIO *out;
377 	CONF *ctmp = NULL;
378 
379 	wpa_printf(MSG_INFO, "Generate RSA private key");
380 	write_summary(ctx, "Generate RSA private key");
381 	pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
382 	if (!pctx)
383 		return -1;
384 
385 	if (EVP_PKEY_keygen_init(pctx) <= 0)
386 		goto fail;
387 
388 	if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, 2048) <= 0)
389 		goto fail;
390 
391 	if (EVP_PKEY_keygen(pctx, &pkey) <= 0)
392 		goto fail;
393 	EVP_PKEY_CTX_free(pctx);
394 	pctx = NULL;
395 
396 	if (key_pem) {
397 		FILE *f = fopen(key_pem, "wb");
398 		if (f == NULL)
399 			goto fail;
400 		if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
401 			wpa_printf(MSG_INFO, "Could not write private key: %s",
402 				   ERR_error_string(ERR_get_error(), NULL));
403 			fclose(f);
404 			goto fail;
405 		}
406 		fclose(f);
407 	}
408 
409 	wpa_printf(MSG_INFO, "Generate CSR");
410 	write_summary(ctx, "Generate CSR");
411 	req = X509_REQ_new();
412 	if (req == NULL)
413 		goto fail;
414 
415 	if (old_cert) {
416 		FILE *f;
417 		X509 *cert;
418 		int res;
419 
420 		f = fopen(old_cert, "r");
421 		if (f == NULL)
422 			goto fail;
423 		cert = PEM_read_X509(f, NULL, NULL, NULL);
424 		fclose(f);
425 
426 		if (cert == NULL)
427 			goto fail;
428 		res = X509_REQ_set_subject_name(req,
429 						X509_get_subject_name(cert));
430 		X509_free(cert);
431 		if (!res)
432 			goto fail;
433 	} else {
434 		os_get_random((u8 *) &val, sizeof(val));
435 		os_snprintf(name, sizeof(name), "cert-user-%u", val);
436 		subj = X509_NAME_new();
437 		if (subj == NULL ||
438 		    !X509_NAME_add_entry_by_txt(subj, "CN", MBSTRING_ASC,
439 						(unsigned char *) name,
440 						-1, -1, 0) ||
441 		    !X509_REQ_set_subject_name(req, subj))
442 			goto fail;
443 		X509_NAME_free(subj);
444 		subj = NULL;
445 	}
446 
447 	if (!X509_REQ_set_pubkey(req, pkey))
448 		goto fail;
449 
450 	exts = sk_X509_EXTENSION_new_null();
451 	if (!exts)
452 		goto fail;
453 
454 	ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_basic_constraints,
455 				  "CA:FALSE");
456 	if (ex == NULL ||
457 	    !sk_X509_EXTENSION_push(exts, ex))
458 		goto fail;
459 
460 	ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_key_usage,
461 				  "nonRepudiation,digitalSignature,keyEncipherment");
462 	if (ex == NULL ||
463 	    !sk_X509_EXTENSION_push(exts, ex))
464 		goto fail;
465 
466 	ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_ext_key_usage,
467 				  "1.3.6.1.4.1.40808.1.1.2");
468 	if (ex == NULL ||
469 	    !sk_X509_EXTENSION_push(exts, ex))
470 		goto fail;
471 
472 	add_csrattrs(ctx, csrattrs, exts);
473 
474 	if (!X509_REQ_add_extensions(req, exts))
475 		goto fail;
476 	sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
477 	exts = NULL;
478 
479 	if (!X509_REQ_sign(req, pkey, EVP_sha256()))
480 		goto fail;
481 
482 	out = BIO_new(BIO_s_mem());
483 	if (out) {
484 		char *txt;
485 		size_t rlen;
486 
487 #if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL)
488 		X509_REQ_print(out, req);
489 #endif
490 		rlen = BIO_ctrl_pending(out);
491 		txt = os_malloc(rlen + 1);
492 		if (txt) {
493 			int res = BIO_read(out, txt, rlen);
494 			if (res > 0) {
495 				txt[res] = '\0';
496 				wpa_printf(MSG_MSGDUMP, "OpenSSL: Certificate request:\n%s",
497 					   txt);
498 			}
499 			os_free(txt);
500 		}
501 		BIO_free(out);
502 	}
503 
504 	if (csr_pem) {
505 		FILE *f = fopen(csr_pem, "w");
506 		if (f == NULL)
507 			goto fail;
508 #if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL)
509 		X509_REQ_print_fp(f, req);
510 #endif
511 		if (!PEM_write_X509_REQ(f, req)) {
512 			fclose(f);
513 			goto fail;
514 		}
515 		fclose(f);
516 	}
517 
518 	if (est_req) {
519 		BIO *mem = BIO_new(BIO_s_mem());
520 		BUF_MEM *ptr;
521 		char *pos, *end, *buf_end;
522 		FILE *f;
523 
524 		if (mem == NULL)
525 			goto fail;
526 		if (!PEM_write_bio_X509_REQ(mem, req)) {
527 			BIO_free(mem);
528 			goto fail;
529 		}
530 
531 		BIO_get_mem_ptr(mem, &ptr);
532 		pos = ptr->data;
533 		buf_end = pos + ptr->length;
534 
535 		/* Remove START/END lines */
536 		while (pos < buf_end && *pos != '\n')
537 			pos++;
538 		if (pos == buf_end) {
539 			BIO_free(mem);
540 			goto fail;
541 		}
542 		pos++;
543 
544 		end = pos;
545 		while (end < buf_end && *end != '-')
546 			end++;
547 
548 		f = fopen(est_req, "w");
549 		if (f == NULL) {
550 			BIO_free(mem);
551 			goto fail;
552 		}
553 		fwrite(pos, end - pos, 1, f);
554 		fclose(f);
555 
556 		BIO_free(mem);
557 	}
558 
559 	ret = 0;
560 fail:
561 	if (exts)
562 		sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
563 	if (subj)
564 		X509_NAME_free(subj);
565 	if (req)
566 		X509_REQ_free(req);
567 	if (pkey)
568 		EVP_PKEY_free(pkey);
569 	if (pctx)
570 		EVP_PKEY_CTX_free(pctx);
571 	return ret;
572 }
573 
574 
575 int est_build_csr(struct hs20_osu_client *ctx, const char *url)
576 {
577 	char *buf;
578 	size_t buflen;
579 	int res;
580 	char old_cert_buf[200];
581 	char *old_cert = NULL;
582 	CsrAttrs *csrattrs = NULL;
583 
584 	buflen = os_strlen(url) + 100;
585 	buf = os_malloc(buflen);
586 	if (buf == NULL)
587 		return -1;
588 
589 	os_snprintf(buf, buflen, "%s/csrattrs", url);
590 	wpa_printf(MSG_INFO, "Download csrattrs from %s", buf);
591 	write_summary(ctx, "Download EST csrattrs from %s", buf);
592 	ctx->no_osu_cert_validation = 1;
593 	http_ocsp_set(ctx->http, 1);
594 	res = http_download_file(ctx->http, buf, "Cert/est-csrattrs.txt",
595 				 ctx->ca_fname);
596 	http_ocsp_set(ctx->http,
597 		      (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
598 	ctx->no_osu_cert_validation = 0;
599 	os_free(buf);
600 	if (res < 0) {
601 		wpa_printf(MSG_INFO, "Failed to download EST csrattrs - assume no extra attributes are needed");
602 	} else {
603 		size_t resp_len;
604 		char *resp;
605 		unsigned char *attrs;
606 		const unsigned char *pos;
607 		size_t attrs_len;
608 
609 		resp = os_readfile("Cert/est-csrattrs.txt", &resp_len);
610 		if (resp == NULL) {
611 			wpa_printf(MSG_INFO, "Could not read csrattrs");
612 			return -1;
613 		}
614 
615 		attrs = base64_decode(resp, resp_len, &attrs_len);
616 		os_free(resp);
617 
618 		if (attrs == NULL) {
619 			wpa_printf(MSG_INFO, "Could not base64 decode csrattrs");
620 			return -1;
621 		}
622 		unlink("Cert/est-csrattrs.txt");
623 
624 		pos = attrs;
625 		csrattrs = d2i_CsrAttrs(NULL, &pos, attrs_len);
626 		os_free(attrs);
627 		if (csrattrs == NULL) {
628 			wpa_printf(MSG_INFO, "Failed to parse csrattrs ASN.1");
629 			/* Continue assuming no additional requirements */
630 		}
631 	}
632 
633 	if (ctx->client_cert_present) {
634 		os_snprintf(old_cert_buf, sizeof(old_cert_buf),
635 			    "SP/%s/client-cert.pem", ctx->fqdn);
636 		old_cert = old_cert_buf;
637 	}
638 
639 	res = generate_csr(ctx, "Cert/privkey-plain.pem", "Cert/est-req.pem",
640 			   "Cert/est-req.b64", old_cert, csrattrs);
641 	if (csrattrs)
642 		CsrAttrs_free(csrattrs);
643 
644 	return res;
645 }
646 
647 
648 int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
649 		      const char *user, const char *pw)
650 {
651 	char *buf, *resp, *req, *req2;
652 	size_t buflen, resp_len, len, pkcs7_len;
653 	unsigned char *pkcs7;
654 	char client_cert_buf[200];
655 	char client_key_buf[200];
656 	const char *client_cert = NULL, *client_key = NULL;
657 	int res;
658 
659 	req = os_readfile("Cert/est-req.b64", &len);
660 	if (req == NULL) {
661 		wpa_printf(MSG_INFO, "Could not read Cert/req.b64");
662 		return -1;
663 	}
664 	req2 = os_realloc(req, len + 1);
665 	if (req2 == NULL) {
666 		os_free(req);
667 		return -1;
668 	}
669 	req2[len] = '\0';
670 	req = req2;
671 	wpa_printf(MSG_DEBUG, "EST simpleenroll request: %s", req);
672 
673 	buflen = os_strlen(url) + 100;
674 	buf = os_malloc(buflen);
675 	if (buf == NULL) {
676 		os_free(req);
677 		return -1;
678 	}
679 
680 	if (ctx->client_cert_present) {
681 		os_snprintf(buf, buflen, "%s/simplereenroll", url);
682 		os_snprintf(client_cert_buf, sizeof(client_cert_buf),
683 			    "SP/%s/client-cert.pem", ctx->fqdn);
684 		client_cert = client_cert_buf;
685 		os_snprintf(client_key_buf, sizeof(client_key_buf),
686 			    "SP/%s/client-key.pem", ctx->fqdn);
687 		client_key = client_key_buf;
688 	} else
689 		os_snprintf(buf, buflen, "%s/simpleenroll", url);
690 	wpa_printf(MSG_INFO, "EST simpleenroll URL: %s", buf);
691 	write_summary(ctx, "EST simpleenroll URL: %s", buf);
692 	ctx->no_osu_cert_validation = 1;
693 	http_ocsp_set(ctx->http, 1);
694 	resp = http_post(ctx->http, buf, req, "application/pkcs10",
695 			 "Content-Transfer-Encoding: base64",
696 			 ctx->ca_fname, user, pw, client_cert, client_key,
697 			 &resp_len);
698 	http_ocsp_set(ctx->http,
699 		      (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
700 	ctx->no_osu_cert_validation = 0;
701 	os_free(buf);
702 	if (resp == NULL) {
703 		wpa_printf(MSG_INFO, "EST certificate enrollment failed");
704 		write_result(ctx, "EST certificate enrollment failed");
705 		return -1;
706 	}
707 	wpa_printf(MSG_DEBUG, "EST simpleenroll response: %s", resp);
708 
709 	pkcs7 = base64_decode(resp, resp_len, &pkcs7_len);
710 	if (pkcs7 == NULL) {
711 		wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7");
712 		pkcs7 = os_malloc(resp_len);
713 		if (pkcs7) {
714 			os_memcpy(pkcs7, resp, resp_len);
715 			pkcs7_len = resp_len;
716 		}
717 	}
718 	os_free(resp);
719 
720 	if (pkcs7 == NULL) {
721 		wpa_printf(MSG_INFO, "Failed to parse simpleenroll base64 response");
722 		write_result(ctx, "Failed to parse EST simpleenroll base64 response");
723 		return -1;
724 	}
725 
726 	res = pkcs7_to_cert(ctx, pkcs7, pkcs7_len, "Cert/est_cert.pem",
727 			    "Cert/est_cert.der");
728 	os_free(pkcs7);
729 
730 	if (res < 0) {
731 		wpa_printf(MSG_INFO, "EST: Failed to extract certificate from PKCS7 file");
732 		write_result(ctx, "EST: Failed to extract certificate from EST PKCS7 file");
733 		return -1;
734 	}
735 
736 	wpa_printf(MSG_INFO, "EST simple%senroll completed successfully",
737 		   ctx->client_cert_present ? "re" : "");
738 	write_summary(ctx, "EST simple%senroll completed successfully",
739 		      ctx->client_cert_present ? "re" : "");
740 
741 	return 0;
742 }
743