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