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