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