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