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