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