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