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