http_curl.c revision d80a401aed31d06f261efd19223cf55d1a2a8228
1/* 2 * HTTP wrapper for libcurl 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 <curl/curl.h> 11#ifdef EAP_TLS_OPENSSL 12#include <openssl/ssl.h> 13#include <openssl/asn1.h> 14#include <openssl/asn1t.h> 15#include <openssl/x509v3.h> 16 17#ifdef SSL_set_tlsext_status_type 18#ifndef OPENSSL_NO_TLSEXT 19#define HAVE_OCSP 20#include <openssl/err.h> 21#include <openssl/ocsp.h> 22#endif /* OPENSSL_NO_TLSEXT */ 23#endif /* SSL_set_tlsext_status_type */ 24#endif /* EAP_TLS_OPENSSL */ 25 26#include "common.h" 27#include "xml-utils.h" 28#include "http-utils.h" 29 30 31struct http_ctx { 32 void *ctx; 33 struct xml_node_ctx *xml; 34 CURL *curl; 35 struct curl_slist *curl_hdr; 36 char *svc_address; 37 char *svc_ca_fname; 38 char *svc_username; 39 char *svc_password; 40 char *svc_client_cert; 41 char *svc_client_key; 42 char *curl_buf; 43 size_t curl_buf_len; 44 45 int (*cert_cb)(void *ctx, struct http_cert *cert); 46 void *cert_cb_ctx; 47 48 enum { 49 NO_OCSP, OPTIONAL_OCSP, MANDATORY_OCSP 50 } ocsp; 51 X509 *peer_cert; 52 X509 *peer_issuer; 53 X509 *peer_issuer_issuer; 54 55 const char *last_err; 56}; 57 58 59static void clear_curl(struct http_ctx *ctx) 60{ 61 if (ctx->curl) { 62 curl_easy_cleanup(ctx->curl); 63 ctx->curl = NULL; 64 } 65 if (ctx->curl_hdr) { 66 curl_slist_free_all(ctx->curl_hdr); 67 ctx->curl_hdr = NULL; 68 } 69} 70 71 72static void clone_str(char **dst, const char *src) 73{ 74 os_free(*dst); 75 if (src) 76 *dst = os_strdup(src); 77 else 78 *dst = NULL; 79} 80 81 82static void debug_dump(struct http_ctx *ctx, const char *title, 83 const char *buf, size_t len) 84{ 85 char *txt; 86 size_t i; 87 88 for (i = 0; i < len; i++) { 89 if (buf[i] < 32 && buf[i] != '\t' && buf[i] != '\n' && 90 buf[i] != '\r') { 91 wpa_hexdump_ascii(MSG_MSGDUMP, title, buf, len); 92 return; 93 } 94 } 95 96 txt = os_malloc(len + 1); 97 if (txt == NULL) 98 return; 99 os_memcpy(txt, buf, len); 100 txt[len] = '\0'; 101 while (len > 0) { 102 len--; 103 if (txt[len] == '\n' || txt[len] == '\r') 104 txt[len] = '\0'; 105 else 106 break; 107 } 108 wpa_printf(MSG_MSGDUMP, "%s[%s]", title, txt); 109 os_free(txt); 110} 111 112 113static int curl_cb_debug(CURL *curl, curl_infotype info, char *buf, size_t len, 114 void *userdata) 115{ 116 struct http_ctx *ctx = userdata; 117 switch (info) { 118 case CURLINFO_TEXT: 119 debug_dump(ctx, "CURLINFO_TEXT", buf, len); 120 break; 121 case CURLINFO_HEADER_IN: 122 debug_dump(ctx, "CURLINFO_HEADER_IN", buf, len); 123 break; 124 case CURLINFO_HEADER_OUT: 125 debug_dump(ctx, "CURLINFO_HEADER_OUT", buf, len); 126 break; 127 case CURLINFO_DATA_IN: 128 debug_dump(ctx, "CURLINFO_DATA_IN", buf, len); 129 break; 130 case CURLINFO_DATA_OUT: 131 debug_dump(ctx, "CURLINFO_DATA_OUT", buf, len); 132 break; 133 case CURLINFO_SSL_DATA_IN: 134 wpa_printf(MSG_DEBUG, "debug - CURLINFO_SSL_DATA_IN - %d", 135 (int) len); 136 break; 137 case CURLINFO_SSL_DATA_OUT: 138 wpa_printf(MSG_DEBUG, "debug - CURLINFO_SSL_DATA_OUT - %d", 139 (int) len); 140 break; 141 case CURLINFO_END: 142 wpa_printf(MSG_DEBUG, "debug - CURLINFO_END - %d", 143 (int) len); 144 break; 145 } 146 return 0; 147} 148 149 150static size_t curl_cb_write(void *ptr, size_t size, size_t nmemb, 151 void *userdata) 152{ 153 struct http_ctx *ctx = userdata; 154 char *n; 155 n = os_realloc(ctx->curl_buf, ctx->curl_buf_len + size * nmemb + 1); 156 if (n == NULL) 157 return 0; 158 ctx->curl_buf = n; 159 os_memcpy(n + ctx->curl_buf_len, ptr, size * nmemb); 160 n[ctx->curl_buf_len + size * nmemb] = '\0'; 161 ctx->curl_buf_len += size * nmemb; 162 return size * nmemb; 163} 164 165 166#ifdef EAP_TLS_OPENSSL 167 168static void debug_dump_cert(const char *title, X509 *cert) 169{ 170 BIO *out; 171 char *txt; 172 size_t rlen; 173 174 out = BIO_new(BIO_s_mem()); 175 if (!out) 176 return; 177 178 X509_print_ex(out, cert, XN_FLAG_COMPAT, X509_FLAG_COMPAT); 179 rlen = BIO_ctrl_pending(out); 180 txt = os_malloc(rlen + 1); 181 if (txt) { 182 int res = BIO_read(out, txt, rlen); 183 if (res > 0) { 184 txt[res] = '\0'; 185 wpa_printf(MSG_MSGDUMP, "%s:\n%s", title, txt); 186 } 187 os_free(txt); 188 } 189 BIO_free(out); 190} 191 192 193static void add_alt_name_othername(struct http_ctx *ctx, struct http_cert *cert, 194 OTHERNAME *o) 195{ 196 char txt[100]; 197 int res; 198 struct http_othername *on; 199 ASN1_TYPE *val; 200 201 on = os_realloc_array(cert->othername, cert->num_othername + 1, 202 sizeof(struct http_othername)); 203 if (on == NULL) 204 return; 205 cert->othername = on; 206 on = &on[cert->num_othername]; 207 os_memset(on, 0, sizeof(*on)); 208 209 res = OBJ_obj2txt(txt, sizeof(txt), o->type_id, 1); 210 if (res < 0 || res >= (int) sizeof(txt)) 211 return; 212 213 on->oid = os_strdup(txt); 214 if (on->oid == NULL) 215 return; 216 217 val = o->value; 218 on->data = val->value.octet_string->data; 219 on->len = val->value.octet_string->length; 220 221 cert->num_othername++; 222} 223 224 225static void add_alt_name_dns(struct http_ctx *ctx, struct http_cert *cert, 226 ASN1_STRING *name) 227{ 228 char *buf; 229 char **n; 230 231 buf = NULL; 232 if (ASN1_STRING_to_UTF8((unsigned char **) &buf, name) < 0) 233 return; 234 235 n = os_realloc_array(cert->dnsname, cert->num_dnsname + 1, 236 sizeof(char *)); 237 if (n == NULL) 238 return; 239 240 cert->dnsname = n; 241 n[cert->num_dnsname] = buf; 242 cert->num_dnsname++; 243} 244 245 246static void add_alt_name(struct http_ctx *ctx, struct http_cert *cert, 247 const GENERAL_NAME *name) 248{ 249 switch (name->type) { 250 case GEN_OTHERNAME: 251 add_alt_name_othername(ctx, cert, name->d.otherName); 252 break; 253 case GEN_DNS: 254 add_alt_name_dns(ctx, cert, name->d.dNSName); 255 break; 256 } 257} 258 259 260static void add_alt_names(struct http_ctx *ctx, struct http_cert *cert, 261 GENERAL_NAMES *names) 262{ 263 int num, i; 264 265 num = sk_GENERAL_NAME_num(names); 266 for (i = 0; i < num; i++) { 267 const GENERAL_NAME *name; 268 name = sk_GENERAL_NAME_value(names, i); 269 add_alt_name(ctx, cert, name); 270 } 271} 272 273 274/* RFC 3709 */ 275 276typedef struct { 277 X509_ALGOR *hashAlg; 278 ASN1_OCTET_STRING *hashValue; 279} HashAlgAndValue; 280 281typedef struct { 282 STACK_OF(HashAlgAndValue) *refStructHash; 283 STACK_OF(ASN1_IA5STRING) *refStructURI; 284} LogotypeReference; 285 286typedef struct { 287 ASN1_IA5STRING *mediaType; 288 STACK_OF(HashAlgAndValue) *logotypeHash; 289 STACK_OF(ASN1_IA5STRING) *logotypeURI; 290} LogotypeDetails; 291 292typedef struct { 293 int type; 294 union { 295 ASN1_INTEGER *numBits; 296 ASN1_INTEGER *tableSize; 297 } d; 298} LogotypeImageResolution; 299 300typedef struct { 301 ASN1_INTEGER *type; /* LogotypeImageType ::= INTEGER */ 302 ASN1_INTEGER *fileSize; 303 ASN1_INTEGER *xSize; 304 ASN1_INTEGER *ySize; 305 LogotypeImageResolution *resolution; 306 ASN1_IA5STRING *language; 307} LogotypeImageInfo; 308 309typedef struct { 310 LogotypeDetails *imageDetails; 311 LogotypeImageInfo *imageInfo; 312} LogotypeImage; 313 314typedef struct { 315 ASN1_INTEGER *fileSize; 316 ASN1_INTEGER *playTime; 317 ASN1_INTEGER *channels; 318 ASN1_INTEGER *sampleRate; 319 ASN1_IA5STRING *language; 320} LogotypeAudioInfo; 321 322typedef struct { 323 LogotypeDetails *audioDetails; 324 LogotypeAudioInfo *audioInfo; 325} LogotypeAudio; 326 327typedef struct { 328 STACK_OF(LogotypeImage) *image; 329 STACK_OF(LogotypeAudio) *audio; 330} LogotypeData; 331 332typedef struct { 333 int type; 334 union { 335 LogotypeData *direct; 336 LogotypeReference *indirect; 337 } d; 338} LogotypeInfo; 339 340typedef struct { 341 ASN1_OBJECT *logotypeType; 342 LogotypeInfo *info; 343} OtherLogotypeInfo; 344 345typedef struct { 346 STACK_OF(LogotypeInfo) *communityLogos; 347 LogotypeInfo *issuerLogo; 348 LogotypeInfo *subjectLogo; 349 STACK_OF(OtherLogotypeInfo) *otherLogos; 350} LogotypeExtn; 351 352ASN1_SEQUENCE(HashAlgAndValue) = { 353 ASN1_SIMPLE(HashAlgAndValue, hashAlg, X509_ALGOR), 354 ASN1_SIMPLE(HashAlgAndValue, hashValue, ASN1_OCTET_STRING) 355} ASN1_SEQUENCE_END(HashAlgAndValue); 356 357ASN1_SEQUENCE(LogotypeReference) = { 358 ASN1_SEQUENCE_OF(LogotypeReference, refStructHash, HashAlgAndValue), 359 ASN1_SEQUENCE_OF(LogotypeReference, refStructURI, ASN1_IA5STRING) 360} ASN1_SEQUENCE_END(LogotypeReference); 361 362ASN1_SEQUENCE(LogotypeDetails) = { 363 ASN1_SIMPLE(LogotypeDetails, mediaType, ASN1_IA5STRING), 364 ASN1_SEQUENCE_OF(LogotypeDetails, logotypeHash, HashAlgAndValue), 365 ASN1_SEQUENCE_OF(LogotypeDetails, logotypeURI, ASN1_IA5STRING) 366} ASN1_SEQUENCE_END(LogotypeDetails); 367 368ASN1_CHOICE(LogotypeImageResolution) = { 369 ASN1_IMP(LogotypeImageResolution, d.numBits, ASN1_INTEGER, 1), 370 ASN1_IMP(LogotypeImageResolution, d.tableSize, ASN1_INTEGER, 2) 371} ASN1_CHOICE_END(LogotypeImageResolution); 372 373ASN1_SEQUENCE(LogotypeImageInfo) = { 374 ASN1_IMP_OPT(LogotypeImageInfo, type, ASN1_INTEGER, 0), 375 ASN1_SIMPLE(LogotypeImageInfo, fileSize, ASN1_INTEGER), 376 ASN1_SIMPLE(LogotypeImageInfo, xSize, ASN1_INTEGER), 377 ASN1_SIMPLE(LogotypeImageInfo, ySize, ASN1_INTEGER), 378 ASN1_OPT(LogotypeImageInfo, resolution, LogotypeImageResolution), 379 ASN1_IMP_OPT(LogotypeImageInfo, language, ASN1_IA5STRING, 4), 380} ASN1_SEQUENCE_END(LogotypeImageInfo); 381 382ASN1_SEQUENCE(LogotypeImage) = { 383 ASN1_SIMPLE(LogotypeImage, imageDetails, LogotypeDetails), 384 ASN1_OPT(LogotypeImage, imageInfo, LogotypeImageInfo) 385} ASN1_SEQUENCE_END(LogotypeImage); 386 387ASN1_SEQUENCE(LogotypeAudioInfo) = { 388 ASN1_SIMPLE(LogotypeAudioInfo, fileSize, ASN1_INTEGER), 389 ASN1_SIMPLE(LogotypeAudioInfo, playTime, ASN1_INTEGER), 390 ASN1_SIMPLE(LogotypeAudioInfo, channels, ASN1_INTEGER), 391 ASN1_IMP_OPT(LogotypeAudioInfo, sampleRate, ASN1_INTEGER, 3), 392 ASN1_IMP_OPT(LogotypeAudioInfo, language, ASN1_IA5STRING, 4) 393} ASN1_SEQUENCE_END(LogotypeAudioInfo); 394 395ASN1_SEQUENCE(LogotypeAudio) = { 396 ASN1_SIMPLE(LogotypeAudio, audioDetails, LogotypeDetails), 397 ASN1_OPT(LogotypeAudio, audioInfo, LogotypeAudioInfo) 398} ASN1_SEQUENCE_END(LogotypeAudio); 399 400ASN1_SEQUENCE(LogotypeData) = { 401 ASN1_SEQUENCE_OF_OPT(LogotypeData, image, LogotypeImage), 402 ASN1_IMP_SEQUENCE_OF_OPT(LogotypeData, audio, LogotypeAudio, 1) 403} ASN1_SEQUENCE_END(LogotypeData); 404 405ASN1_CHOICE(LogotypeInfo) = { 406 ASN1_IMP(LogotypeInfo, d.direct, LogotypeData, 0), 407 ASN1_IMP(LogotypeInfo, d.indirect, LogotypeReference, 1) 408} ASN1_CHOICE_END(LogotypeInfo); 409 410ASN1_SEQUENCE(OtherLogotypeInfo) = { 411 ASN1_SIMPLE(OtherLogotypeInfo, logotypeType, ASN1_OBJECT), 412 ASN1_SIMPLE(OtherLogotypeInfo, info, LogotypeInfo) 413} ASN1_SEQUENCE_END(OtherLogotypeInfo); 414 415ASN1_SEQUENCE(LogotypeExtn) = { 416 ASN1_EXP_SEQUENCE_OF_OPT(LogotypeExtn, communityLogos, LogotypeInfo, 0), 417 ASN1_EXP_OPT(LogotypeExtn, issuerLogo, LogotypeInfo, 1), 418 ASN1_EXP_OPT(LogotypeExtn, issuerLogo, LogotypeInfo, 2), 419 ASN1_EXP_SEQUENCE_OF_OPT(LogotypeExtn, otherLogos, OtherLogotypeInfo, 3) 420} ASN1_SEQUENCE_END(LogotypeExtn); 421 422IMPLEMENT_ASN1_FUNCTIONS(LogotypeExtn); 423 424#ifdef OPENSSL_IS_BORINGSSL 425#define sk_LogotypeInfo_num(st) \ 426sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeInfo) *, (st))) 427#define sk_LogotypeInfo_value(st, i) (LogotypeInfo *) \ 428sk_value(CHECKED_CAST(_STACK *, const STACK_OF(LogotypeInfo) *, (st)), (i)) 429#define sk_LogotypeImage_num(st) \ 430sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeImage) *, (st))) 431#define sk_LogotypeImage_value(st, i) (LogotypeImage *) \ 432sk_value(CHECKED_CAST(_STACK *, const STACK_OF(LogotypeImage) *, (st)), (i)) 433#define sk_LogotypeAudio_num(st) \ 434sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeAudio) *, (st))) 435#define sk_LogotypeAudio_value(st, i) (LogotypeAudio *) \ 436sk_value(CHECK_CAST(_STACK *, const STACK_OF(LogotypeAudio) *, (st)), (i)) 437#define sk_HashAlgAndValue_num(st) \ 438sk_num(CHECKED_CAST(_STACK *, STACK_OF(HashAlgAndValue) *, (st))) 439#define sk_HashAlgAndValue_value(st, i) (HashAlgAndValue *) \ 440sk_value(CHECKED_CAST(_STACK *, const STACK_OF(HashAlgAndValue) *, (st)), (i)) 441#define sk_ASN1_IA5STRING_num(st) \ 442sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_IA5STRING) *, (st))) 443#define sk_ASN1_IA5STRING_value(st, i) (ASN1_IA5STRING *) \ 444sk_value(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_IA5STRING) *, (st)), (i)) 445#else /* OPENSSL_IS_BORINGSSL */ 446#define sk_LogotypeInfo_num(st) SKM_sk_num(LogotypeInfo, (st)) 447#define sk_LogotypeInfo_value(st, i) SKM_sk_value(LogotypeInfo, (st), (i)) 448#define sk_LogotypeImage_num(st) SKM_sk_num(LogotypeImage, (st)) 449#define sk_LogotypeImage_value(st, i) SKM_sk_value(LogotypeImage, (st), (i)) 450#define sk_LogotypeAudio_num(st) SKM_sk_num(LogotypeAudio, (st)) 451#define sk_LogotypeAudio_value(st, i) SKM_sk_value(LogotypeAudio, (st), (i)) 452#define sk_HashAlgAndValue_num(st) SKM_sk_num(HashAlgAndValue, (st)) 453#define sk_HashAlgAndValue_value(st, i) SKM_sk_value(HashAlgAndValue, (st), (i)) 454#define sk_ASN1_IA5STRING_num(st) SKM_sk_num(ASN1_IA5STRING, (st)) 455#define sk_ASN1_IA5STRING_value(st, i) SKM_sk_value(ASN1_IA5STRING, (st), (i)) 456#endif /* OPENSSL_IS_BORINGSSL */ 457 458 459static void add_logo(struct http_ctx *ctx, struct http_cert *hcert, 460 HashAlgAndValue *hash, ASN1_IA5STRING *uri) 461{ 462 char txt[100]; 463 int res, len; 464 struct http_logo *n; 465 466 if (hash == NULL || uri == NULL) 467 return; 468 469 res = OBJ_obj2txt(txt, sizeof(txt), hash->hashAlg->algorithm, 1); 470 if (res < 0 || res >= (int) sizeof(txt)) 471 return; 472 473 n = os_realloc_array(hcert->logo, hcert->num_logo + 1, 474 sizeof(struct http_logo)); 475 if (n == NULL) 476 return; 477 hcert->logo = n; 478 n = &hcert->logo[hcert->num_logo]; 479 os_memset(n, 0, sizeof(*n)); 480 481 n->alg_oid = os_strdup(txt); 482 if (n->alg_oid == NULL) 483 return; 484 485 n->hash_len = ASN1_STRING_length(hash->hashValue); 486 n->hash = os_malloc(n->hash_len); 487 if (n->hash == NULL) { 488 os_free(n->alg_oid); 489 return; 490 } 491 os_memcpy(n->hash, ASN1_STRING_data(hash->hashValue), n->hash_len); 492 493 len = ASN1_STRING_length(uri); 494 n->uri = os_malloc(len + 1); 495 if (n->uri == NULL) { 496 os_free(n->alg_oid); 497 os_free(n->hash); 498 return; 499 } 500 os_memcpy(n->uri, ASN1_STRING_data(uri), len); 501 n->uri[len] = '\0'; 502 503 hcert->num_logo++; 504} 505 506 507static void add_logo_direct(struct http_ctx *ctx, struct http_cert *hcert, 508 LogotypeData *data) 509{ 510 int i, num; 511 512 if (data->image == NULL) 513 return; 514 515 num = sk_LogotypeImage_num(data->image); 516 for (i = 0; i < num; i++) { 517 LogotypeImage *image; 518 LogotypeDetails *details; 519 int j, hash_num, uri_num; 520 HashAlgAndValue *found_hash = NULL; 521 522 image = sk_LogotypeImage_value(data->image, i); 523 if (image == NULL) 524 continue; 525 526 details = image->imageDetails; 527 if (details == NULL) 528 continue; 529 530 hash_num = sk_HashAlgAndValue_num(details->logotypeHash); 531 for (j = 0; j < hash_num; j++) { 532 HashAlgAndValue *hash; 533 char txt[100]; 534 int res; 535 hash = sk_HashAlgAndValue_value(details->logotypeHash, 536 j); 537 if (hash == NULL) 538 continue; 539 res = OBJ_obj2txt(txt, sizeof(txt), 540 hash->hashAlg->algorithm, 1); 541 if (res < 0 || res >= (int) sizeof(txt)) 542 continue; 543 if (os_strcmp(txt, "2.16.840.1.101.3.4.2.1") == 0) { 544 found_hash = hash; 545 break; 546 } 547 } 548 549 if (!found_hash) { 550 wpa_printf(MSG_DEBUG, "OpenSSL: No SHA256 hash found for the logo"); 551 continue; 552 } 553 554 uri_num = sk_ASN1_IA5STRING_num(details->logotypeURI); 555 for (j = 0; j < uri_num; j++) { 556 ASN1_IA5STRING *uri; 557 uri = sk_ASN1_IA5STRING_value(details->logotypeURI, j); 558 add_logo(ctx, hcert, found_hash, uri); 559 } 560 } 561} 562 563 564static void add_logo_indirect(struct http_ctx *ctx, struct http_cert *hcert, 565 LogotypeReference *ref) 566{ 567 int j, hash_num, uri_num; 568 569 hash_num = sk_HashAlgAndValue_num(ref->refStructHash); 570 uri_num = sk_ASN1_IA5STRING_num(ref->refStructURI); 571 if (hash_num != uri_num) { 572 wpa_printf(MSG_INFO, "Unexpected LogotypeReference array size difference %d != %d", 573 hash_num, uri_num); 574 return; 575 } 576 577 for (j = 0; j < hash_num; j++) { 578 HashAlgAndValue *hash; 579 ASN1_IA5STRING *uri; 580 hash = sk_HashAlgAndValue_value(ref->refStructHash, j); 581 uri = sk_ASN1_IA5STRING_value(ref->refStructURI, j); 582 add_logo(ctx, hcert, hash, uri); 583 } 584} 585 586 587static void i2r_HashAlgAndValue(HashAlgAndValue *hash, BIO *out, int indent) 588{ 589 int i; 590 const unsigned char *data; 591 592 BIO_printf(out, "%*shashAlg: ", indent, ""); 593 i2a_ASN1_OBJECT(out, hash->hashAlg->algorithm); 594 BIO_printf(out, "\n"); 595 596 BIO_printf(out, "%*shashValue: ", indent, ""); 597 data = hash->hashValue->data; 598 for (i = 0; i < hash->hashValue->length; i++) 599 BIO_printf(out, "%s%02x", i > 0 ? ":" : "", data[i]); 600 BIO_printf(out, "\n"); 601} 602 603static void i2r_LogotypeDetails(LogotypeDetails *details, BIO *out, int indent) 604{ 605 int i, num; 606 607 BIO_printf(out, "%*sLogotypeDetails\n", indent, ""); 608 if (details->mediaType) { 609 BIO_printf(out, "%*smediaType: ", indent, ""); 610 ASN1_STRING_print(out, details->mediaType); 611 BIO_printf(out, "\n"); 612 } 613 614 num = details->logotypeHash ? 615 sk_HashAlgAndValue_num(details->logotypeHash) : 0; 616 for (i = 0; i < num; i++) { 617 HashAlgAndValue *hash; 618 hash = sk_HashAlgAndValue_value(details->logotypeHash, i); 619 i2r_HashAlgAndValue(hash, out, indent); 620 } 621 622 num = details->logotypeURI ? 623 sk_ASN1_IA5STRING_num(details->logotypeURI) : 0; 624 for (i = 0; i < num; i++) { 625 ASN1_IA5STRING *uri; 626 uri = sk_ASN1_IA5STRING_value(details->logotypeURI, i); 627 BIO_printf(out, "%*slogotypeURI: ", indent, ""); 628 ASN1_STRING_print(out, uri); 629 BIO_printf(out, "\n"); 630 } 631} 632 633static void i2r_LogotypeImageInfo(LogotypeImageInfo *info, BIO *out, int indent) 634{ 635 long val; 636 637 BIO_printf(out, "%*sLogotypeImageInfo\n", indent, ""); 638 if (info->type) { 639 val = ASN1_INTEGER_get(info->type); 640 BIO_printf(out, "%*stype: %ld\n", indent, "", val); 641 } else { 642 BIO_printf(out, "%*stype: default (1)\n", indent, ""); 643 } 644 val = ASN1_INTEGER_get(info->xSize); 645 BIO_printf(out, "%*sxSize: %ld\n", indent, "", val); 646 val = ASN1_INTEGER_get(info->ySize); 647 BIO_printf(out, "%*sySize: %ld\n", indent, "", val); 648 if (info->resolution) { 649 BIO_printf(out, "%*sresolution\n", indent, ""); 650 /* TODO */ 651 } 652 if (info->language) { 653 BIO_printf(out, "%*slanguage: ", indent, ""); 654 ASN1_STRING_print(out, info->language); 655 BIO_printf(out, "\n"); 656 } 657} 658 659static void i2r_LogotypeImage(LogotypeImage *image, BIO *out, int indent) 660{ 661 BIO_printf(out, "%*sLogotypeImage\n", indent, ""); 662 if (image->imageDetails) { 663 i2r_LogotypeDetails(image->imageDetails, out, indent + 4); 664 } 665 if (image->imageInfo) { 666 i2r_LogotypeImageInfo(image->imageInfo, out, indent + 4); 667 } 668} 669 670static void i2r_LogotypeData(LogotypeData *data, const char *title, BIO *out, 671 int indent) 672{ 673 int i, num; 674 675 BIO_printf(out, "%*s%s - LogotypeData\n", indent, "", title); 676 677 num = data->image ? sk_LogotypeImage_num(data->image) : 0; 678 for (i = 0; i < num; i++) { 679 LogotypeImage *image = sk_LogotypeImage_value(data->image, i); 680 i2r_LogotypeImage(image, out, indent + 4); 681 } 682 683 num = data->audio ? sk_LogotypeAudio_num(data->audio) : 0; 684 for (i = 0; i < num; i++) { 685 BIO_printf(out, "%*saudio: TODO\n", indent, ""); 686 } 687} 688 689static void i2r_LogotypeReference(LogotypeReference *ref, const char *title, 690 BIO *out, int indent) 691{ 692 int i, hash_num, uri_num; 693 694 BIO_printf(out, "%*s%s - LogotypeReference\n", indent, "", title); 695 696 hash_num = ref->refStructHash ? 697 sk_HashAlgAndValue_num(ref->refStructHash) : 0; 698 uri_num = ref->refStructURI ? 699 sk_ASN1_IA5STRING_num(ref->refStructURI) : 0; 700 if (hash_num != uri_num) { 701 BIO_printf(out, "%*sUnexpected LogotypeReference array size difference %d != %d\n", 702 indent, "", hash_num, uri_num); 703 return; 704 } 705 706 for (i = 0; i < hash_num; i++) { 707 HashAlgAndValue *hash; 708 ASN1_IA5STRING *uri; 709 710 hash = sk_HashAlgAndValue_value(ref->refStructHash, i); 711 i2r_HashAlgAndValue(hash, out, indent); 712 713 uri = sk_ASN1_IA5STRING_value(ref->refStructURI, i); 714 BIO_printf(out, "%*srefStructURI: ", indent, ""); 715 ASN1_STRING_print(out, uri); 716 BIO_printf(out, "\n"); 717 } 718} 719 720static void i2r_LogotypeInfo(LogotypeInfo *info, const char *title, BIO *out, 721 int indent) 722{ 723 switch (info->type) { 724 case 0: 725 i2r_LogotypeData(info->d.direct, title, out, indent); 726 break; 727 case 1: 728 i2r_LogotypeReference(info->d.indirect, title, out, indent); 729 break; 730 } 731} 732 733static void debug_print_logotypeext(LogotypeExtn *logo) 734{ 735 BIO *out; 736 int i, num; 737 int indent = 0; 738 739 out = BIO_new_fp(stdout, BIO_NOCLOSE); 740 if (out == NULL) 741 return; 742 743 if (logo->communityLogos) { 744 num = sk_LogotypeInfo_num(logo->communityLogos); 745 for (i = 0; i < num; i++) { 746 LogotypeInfo *info; 747 info = sk_LogotypeInfo_value(logo->communityLogos, i); 748 i2r_LogotypeInfo(info, "communityLogo", out, indent); 749 } 750 } 751 752 if (logo->issuerLogo) { 753 i2r_LogotypeInfo(logo->issuerLogo, "issuerLogo", out, indent ); 754 } 755 756 if (logo->subjectLogo) { 757 i2r_LogotypeInfo(logo->subjectLogo, "subjectLogo", out, indent); 758 } 759 760 if (logo->otherLogos) { 761 BIO_printf(out, "%*sotherLogos - TODO\n", indent, ""); 762 } 763 764 BIO_free(out); 765} 766 767 768static void add_logotype_ext(struct http_ctx *ctx, struct http_cert *hcert, 769 X509 *cert) 770{ 771 ASN1_OBJECT *obj; 772 int pos; 773 X509_EXTENSION *ext; 774 ASN1_OCTET_STRING *os; 775 LogotypeExtn *logo; 776 const unsigned char *data; 777 int i, num; 778 779 obj = OBJ_txt2obj("1.3.6.1.5.5.7.1.12", 0); 780 if (obj == NULL) 781 return; 782 783 pos = X509_get_ext_by_OBJ(cert, obj, -1); 784 if (pos < 0) { 785 wpa_printf(MSG_INFO, "No logotype extension included"); 786 return; 787 } 788 789 wpa_printf(MSG_INFO, "Parsing logotype extension"); 790 ext = X509_get_ext(cert, pos); 791 if (!ext) { 792 wpa_printf(MSG_INFO, "Could not get logotype extension"); 793 return; 794 } 795 796 os = X509_EXTENSION_get_data(ext); 797 if (os == NULL) { 798 wpa_printf(MSG_INFO, "Could not get logotype extension data"); 799 return; 800 } 801 802 wpa_hexdump(MSG_DEBUG, "logotypeExtn", 803 ASN1_STRING_data(os), ASN1_STRING_length(os)); 804 805 data = ASN1_STRING_data(os); 806 logo = d2i_LogotypeExtn(NULL, &data, ASN1_STRING_length(os)); 807 if (logo == NULL) { 808 wpa_printf(MSG_INFO, "Failed to parse logotypeExtn"); 809 return; 810 } 811 812 if (wpa_debug_level < MSG_INFO) 813 debug_print_logotypeext(logo); 814 815 if (!logo->communityLogos) { 816 wpa_printf(MSG_INFO, "No communityLogos included"); 817 LogotypeExtn_free(logo); 818 return; 819 } 820 821 num = sk_LogotypeInfo_num(logo->communityLogos); 822 for (i = 0; i < num; i++) { 823 LogotypeInfo *info; 824 info = sk_LogotypeInfo_value(logo->communityLogos, i); 825 switch (info->type) { 826 case 0: 827 add_logo_direct(ctx, hcert, info->d.direct); 828 break; 829 case 1: 830 add_logo_indirect(ctx, hcert, info->d.indirect); 831 break; 832 } 833 } 834 835 LogotypeExtn_free(logo); 836} 837 838 839static void parse_cert(struct http_ctx *ctx, struct http_cert *hcert, 840 X509 *cert, GENERAL_NAMES **names) 841{ 842 os_memset(hcert, 0, sizeof(*hcert)); 843 844 *names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); 845 if (*names) 846 add_alt_names(ctx, hcert, *names); 847 848 add_logotype_ext(ctx, hcert, cert); 849} 850 851 852static void parse_cert_free(struct http_cert *hcert, GENERAL_NAMES *names) 853{ 854 unsigned int i; 855 856 for (i = 0; i < hcert->num_dnsname; i++) 857 OPENSSL_free(hcert->dnsname[i]); 858 os_free(hcert->dnsname); 859 860 for (i = 0; i < hcert->num_othername; i++) 861 os_free(hcert->othername[i].oid); 862 os_free(hcert->othername); 863 864 for (i = 0; i < hcert->num_logo; i++) { 865 os_free(hcert->logo[i].alg_oid); 866 os_free(hcert->logo[i].hash); 867 os_free(hcert->logo[i].uri); 868 } 869 os_free(hcert->logo); 870 871 sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); 872} 873 874 875static int validate_server_cert(struct http_ctx *ctx, X509 *cert) 876{ 877 GENERAL_NAMES *names; 878 struct http_cert hcert; 879 int ret; 880 881 if (ctx->cert_cb == NULL) { 882 wpa_printf(MSG_DEBUG, "%s: no cert_cb configured", __func__); 883 return 0; 884 } 885 886 if (0) { 887 BIO *out; 888 out = BIO_new_fp(stdout, BIO_NOCLOSE); 889 X509_print_ex(out, cert, XN_FLAG_COMPAT, X509_FLAG_COMPAT); 890 BIO_free(out); 891 } 892 893 parse_cert(ctx, &hcert, cert, &names); 894 ret = ctx->cert_cb(ctx->cert_cb_ctx, &hcert); 895 parse_cert_free(&hcert, names); 896 897 return ret; 898} 899 900 901void http_parse_x509_certificate(struct http_ctx *ctx, const char *fname) 902{ 903 BIO *in, *out; 904 X509 *cert; 905 GENERAL_NAMES *names; 906 struct http_cert hcert; 907 unsigned int i; 908 909 in = BIO_new_file(fname, "r"); 910 if (in == NULL) { 911 wpa_printf(MSG_ERROR, "Could not read '%s'", fname); 912 return; 913 } 914 915 cert = d2i_X509_bio(in, NULL); 916 BIO_free(in); 917 918 if (cert == NULL) { 919 wpa_printf(MSG_ERROR, "Could not parse certificate"); 920 return; 921 } 922 923 out = BIO_new_fp(stdout, BIO_NOCLOSE); 924 if (out) { 925 X509_print_ex(out, cert, XN_FLAG_COMPAT, 926 X509_FLAG_COMPAT); 927 BIO_free(out); 928 } 929 930 wpa_printf(MSG_INFO, "Additional parsing information:"); 931 parse_cert(ctx, &hcert, cert, &names); 932 for (i = 0; i < hcert.num_othername; i++) { 933 if (os_strcmp(hcert.othername[i].oid, 934 "1.3.6.1.4.1.40808.1.1.1") == 0) { 935 char *name = os_zalloc(hcert.othername[i].len + 1); 936 if (name) { 937 os_memcpy(name, hcert.othername[i].data, 938 hcert.othername[i].len); 939 wpa_printf(MSG_INFO, 940 "id-wfa-hotspot-friendlyName: %s", 941 name); 942 os_free(name); 943 } 944 wpa_hexdump_ascii(MSG_INFO, 945 "id-wfa-hotspot-friendlyName", 946 hcert.othername[i].data, 947 hcert.othername[i].len); 948 } else { 949 wpa_printf(MSG_INFO, "subjAltName[othername]: oid=%s", 950 hcert.othername[i].oid); 951 wpa_hexdump_ascii(MSG_INFO, "unknown othername", 952 hcert.othername[i].data, 953 hcert.othername[i].len); 954 } 955 } 956 parse_cert_free(&hcert, names); 957 958 X509_free(cert); 959} 960 961 962static int curl_cb_ssl_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) 963{ 964 struct http_ctx *ctx; 965 X509 *cert; 966 int err, depth; 967 char buf[256]; 968 X509_NAME *name; 969 const char *err_str; 970 SSL *ssl; 971 SSL_CTX *ssl_ctx; 972 973 ssl = X509_STORE_CTX_get_ex_data(x509_ctx, 974 SSL_get_ex_data_X509_STORE_CTX_idx()); 975 ssl_ctx = ssl->ctx; 976 ctx = SSL_CTX_get_app_data(ssl_ctx); 977 978 wpa_printf(MSG_DEBUG, "curl_cb_ssl_verify, preverify_ok: %d", 979 preverify_ok); 980 981 err = X509_STORE_CTX_get_error(x509_ctx); 982 err_str = X509_verify_cert_error_string(err); 983 depth = X509_STORE_CTX_get_error_depth(x509_ctx); 984 cert = X509_STORE_CTX_get_current_cert(x509_ctx); 985 if (!cert) { 986 wpa_printf(MSG_INFO, "No server certificate available"); 987 ctx->last_err = "No server certificate available"; 988 return 0; 989 } 990 991 if (depth == 0) 992 ctx->peer_cert = cert; 993 else if (depth == 1) 994 ctx->peer_issuer = cert; 995 else if (depth == 2) 996 ctx->peer_issuer_issuer = cert; 997 998 name = X509_get_subject_name(cert); 999 X509_NAME_oneline(name, buf, sizeof(buf)); 1000 wpa_printf(MSG_INFO, "Server certificate chain - depth=%d err=%d (%s) subject=%s", 1001 depth, err, err_str, buf); 1002 debug_dump_cert("Server certificate chain - certificate", cert); 1003 1004 if (depth == 0 && preverify_ok && validate_server_cert(ctx, cert) < 0) 1005 return 0; 1006 1007 if (!preverify_ok) 1008 ctx->last_err = "TLS validation failed"; 1009 1010 return preverify_ok; 1011} 1012 1013 1014#ifdef HAVE_OCSP 1015 1016static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp) 1017{ 1018 BIO *out; 1019 size_t rlen; 1020 char *txt; 1021 int res; 1022 1023 out = BIO_new(BIO_s_mem()); 1024 if (!out) 1025 return; 1026 1027 OCSP_RESPONSE_print(out, rsp, 0); 1028 rlen = BIO_ctrl_pending(out); 1029 txt = os_malloc(rlen + 1); 1030 if (!txt) { 1031 BIO_free(out); 1032 return; 1033 } 1034 1035 res = BIO_read(out, txt, rlen); 1036 if (res > 0) { 1037 txt[res] = '\0'; 1038 wpa_printf(MSG_MSGDUMP, "OpenSSL: OCSP Response\n%s", txt); 1039 } 1040 os_free(txt); 1041 BIO_free(out); 1042} 1043 1044 1045static void tls_show_errors(const char *func, const char *txt) 1046{ 1047 unsigned long err; 1048 1049 wpa_printf(MSG_DEBUG, "OpenSSL: %s - %s %s", 1050 func, txt, ERR_error_string(ERR_get_error(), NULL)); 1051 1052 while ((err = ERR_get_error())) { 1053 wpa_printf(MSG_DEBUG, "OpenSSL: pending error: %s", 1054 ERR_error_string(err, NULL)); 1055 } 1056} 1057 1058 1059static int ocsp_resp_cb(SSL *s, void *arg) 1060{ 1061 struct http_ctx *ctx = arg; 1062 const unsigned char *p; 1063 int len, status, reason; 1064 OCSP_RESPONSE *rsp; 1065 OCSP_BASICRESP *basic; 1066 OCSP_CERTID *id; 1067 ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update; 1068 X509_STORE *store; 1069 STACK_OF(X509) *certs = NULL; 1070 1071 len = SSL_get_tlsext_status_ocsp_resp(s, &p); 1072 if (!p) { 1073 wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received"); 1074 if (ctx->ocsp == MANDATORY_OCSP) 1075 ctx->last_err = "No OCSP response received"; 1076 return (ctx->ocsp == MANDATORY_OCSP) ? 0 : 1; 1077 } 1078 1079 wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len); 1080 1081 rsp = d2i_OCSP_RESPONSE(NULL, &p, len); 1082 if (!rsp) { 1083 wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response"); 1084 ctx->last_err = "Failed to parse OCSP response"; 1085 return 0; 1086 } 1087 1088 ocsp_debug_print_resp(rsp); 1089 1090 status = OCSP_response_status(rsp); 1091 if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { 1092 wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)", 1093 status, OCSP_response_status_str(status)); 1094 ctx->last_err = "OCSP responder error"; 1095 return 0; 1096 } 1097 1098 basic = OCSP_response_get1_basic(rsp); 1099 if (!basic) { 1100 wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse"); 1101 ctx->last_err = "Could not find BasicOCSPResponse"; 1102 return 0; 1103 } 1104 1105 store = SSL_CTX_get_cert_store(s->ctx); 1106 if (ctx->peer_issuer) { 1107 wpa_printf(MSG_DEBUG, "OpenSSL: Add issuer"); 1108 debug_dump_cert("OpenSSL: Issuer certificate", 1109 ctx->peer_issuer); 1110 1111 if (X509_STORE_add_cert(store, ctx->peer_issuer) != 1) { 1112 tls_show_errors(__func__, 1113 "OpenSSL: Could not add issuer to certificate store"); 1114 } 1115 certs = sk_X509_new_null(); 1116 if (certs) { 1117 X509 *cert; 1118 cert = X509_dup(ctx->peer_issuer); 1119 if (cert && !sk_X509_push(certs, cert)) { 1120 tls_show_errors( 1121 __func__, 1122 "OpenSSL: Could not add issuer to OCSP responder trust store"); 1123 X509_free(cert); 1124 sk_X509_free(certs); 1125 certs = NULL; 1126 } 1127 if (certs && ctx->peer_issuer_issuer) { 1128 cert = X509_dup(ctx->peer_issuer_issuer); 1129 if (cert && !sk_X509_push(certs, cert)) { 1130 tls_show_errors( 1131 __func__, 1132 "OpenSSL: Could not add issuer's issuer to OCSP responder trust store"); 1133 X509_free(cert); 1134 } 1135 } 1136 } 1137 } 1138 1139 status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER); 1140 sk_X509_pop_free(certs, X509_free); 1141 if (status <= 0) { 1142 tls_show_errors(__func__, 1143 "OpenSSL: OCSP response failed verification"); 1144 OCSP_BASICRESP_free(basic); 1145 OCSP_RESPONSE_free(rsp); 1146 ctx->last_err = "OCSP response failed verification"; 1147 return 0; 1148 } 1149 1150 wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded"); 1151 1152 if (!ctx->peer_cert) { 1153 wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check"); 1154 OCSP_BASICRESP_free(basic); 1155 OCSP_RESPONSE_free(rsp); 1156 ctx->last_err = "Peer certificate not available for OCSP status check"; 1157 return 0; 1158 } 1159 1160 if (!ctx->peer_issuer) { 1161 wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check"); 1162 OCSP_BASICRESP_free(basic); 1163 OCSP_RESPONSE_free(rsp); 1164 ctx->last_err = "Peer issuer certificate not available for OCSP status check"; 1165 return 0; 1166 } 1167 1168 id = OCSP_cert_to_id(NULL, ctx->peer_cert, ctx->peer_issuer); 1169 if (!id) { 1170 wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier"); 1171 OCSP_BASICRESP_free(basic); 1172 OCSP_RESPONSE_free(rsp); 1173 ctx->last_err = "Could not create OCSP certificate identifier"; 1174 return 0; 1175 } 1176 1177 if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at, 1178 &this_update, &next_update)) { 1179 wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s", 1180 (ctx->ocsp == MANDATORY_OCSP) ? "" : 1181 " (OCSP not required)"); 1182 OCSP_BASICRESP_free(basic); 1183 OCSP_RESPONSE_free(rsp); 1184 if (ctx->ocsp == MANDATORY_OCSP) 1185 1186 ctx->last_err = "Could not find current server certificate from OCSP response"; 1187 return (ctx->ocsp == MANDATORY_OCSP) ? 0 : 1; 1188 } 1189 1190 if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) { 1191 tls_show_errors(__func__, "OpenSSL: OCSP status times invalid"); 1192 OCSP_BASICRESP_free(basic); 1193 OCSP_RESPONSE_free(rsp); 1194 ctx->last_err = "OCSP status times invalid"; 1195 return 0; 1196 } 1197 1198 OCSP_BASICRESP_free(basic); 1199 OCSP_RESPONSE_free(rsp); 1200 1201 wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s", 1202 OCSP_cert_status_str(status)); 1203 1204 if (status == V_OCSP_CERTSTATUS_GOOD) 1205 return 1; 1206 if (status == V_OCSP_CERTSTATUS_REVOKED) { 1207 ctx->last_err = "Server certificate has been revoked"; 1208 return 0; 1209 } 1210 if (ctx->ocsp == MANDATORY_OCSP) { 1211 wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required"); 1212 ctx->last_err = "OCSP status unknown"; 1213 return 0; 1214 } 1215 wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue"); 1216 return 1; 1217} 1218 1219 1220static SSL_METHOD patch_ssl_method; 1221static const SSL_METHOD *real_ssl_method; 1222 1223static int curl_patch_ssl_new(SSL *s) 1224{ 1225 SSL_CTX *ssl = s->ctx; 1226 int ret; 1227 1228 ssl->method = real_ssl_method; 1229 s->method = real_ssl_method; 1230 1231 ret = s->method->ssl_new(s); 1232 SSL_set_tlsext_status_type(s, TLSEXT_STATUSTYPE_ocsp); 1233 1234 return ret; 1235} 1236 1237#endif /* HAVE_OCSP */ 1238 1239 1240static CURLcode curl_cb_ssl(CURL *curl, void *sslctx, void *parm) 1241{ 1242 struct http_ctx *ctx = parm; 1243 SSL_CTX *ssl = sslctx; 1244 1245 wpa_printf(MSG_DEBUG, "curl_cb_ssl"); 1246 SSL_CTX_set_app_data(ssl, ctx); 1247 SSL_CTX_set_verify(ssl, SSL_VERIFY_PEER, curl_cb_ssl_verify); 1248 1249#ifdef HAVE_OCSP 1250 if (ctx->ocsp != NO_OCSP) { 1251 SSL_CTX_set_tlsext_status_cb(ssl, ocsp_resp_cb); 1252 SSL_CTX_set_tlsext_status_arg(ssl, ctx); 1253 1254 /* 1255 * Use a temporary SSL_METHOD to get a callback on SSL_new() 1256 * from libcurl since there is no proper callback registration 1257 * available for this. 1258 */ 1259 os_memset(&patch_ssl_method, 0, sizeof(patch_ssl_method)); 1260 patch_ssl_method.ssl_new = curl_patch_ssl_new; 1261 real_ssl_method = ssl->method; 1262 ssl->method = &patch_ssl_method; 1263 } 1264#endif /* HAVE_OCSP */ 1265 1266 return CURLE_OK; 1267} 1268 1269#endif /* EAP_TLS_OPENSSL */ 1270 1271 1272static CURL * setup_curl_post(struct http_ctx *ctx, const char *address, 1273 const char *ca_fname, const char *username, 1274 const char *password, const char *client_cert, 1275 const char *client_key) 1276{ 1277 CURL *curl; 1278#ifdef EAP_TLS_OPENSSL 1279 const char *extra = " tls=openssl"; 1280#else /* EAP_TLS_OPENSSL */ 1281 const char *extra = ""; 1282#endif /* EAP_TLS_OPENSSL */ 1283 1284 wpa_printf(MSG_DEBUG, "Start HTTP client: address=%s ca_fname=%s " 1285 "username=%s%s", address, ca_fname, username, extra); 1286 1287 curl = curl_easy_init(); 1288 if (curl == NULL) 1289 return NULL; 1290 1291 curl_easy_setopt(curl, CURLOPT_URL, address); 1292 curl_easy_setopt(curl, CURLOPT_POST, 1L); 1293 if (ca_fname) { 1294 curl_easy_setopt(curl, CURLOPT_CAINFO, ca_fname); 1295 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); 1296#ifdef EAP_TLS_OPENSSL 1297 curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, curl_cb_ssl); 1298 curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, ctx); 1299#endif /* EAP_TLS_OPENSSL */ 1300 } else { 1301 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 1302 } 1303 if (client_cert && client_key) { 1304 curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert); 1305 curl_easy_setopt(curl, CURLOPT_SSLKEY, client_key); 1306 } 1307 /* TODO: use curl_easy_getinfo() with CURLINFO_CERTINFO to fetch 1308 * information about the server certificate */ 1309 curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L); 1310 curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curl_cb_debug); 1311 curl_easy_setopt(curl, CURLOPT_DEBUGDATA, ctx); 1312 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_cb_write); 1313 curl_easy_setopt(curl, CURLOPT_WRITEDATA, ctx); 1314 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 1315 if (username) { 1316 curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE); 1317 curl_easy_setopt(curl, CURLOPT_USERNAME, username); 1318 curl_easy_setopt(curl, CURLOPT_PASSWORD, password); 1319 } 1320 1321 return curl; 1322} 1323 1324 1325static int post_init_client(struct http_ctx *ctx, const char *address, 1326 const char *ca_fname, const char *username, 1327 const char *password, const char *client_cert, 1328 const char *client_key) 1329{ 1330 char *pos; 1331 int count; 1332 1333 clone_str(&ctx->svc_address, address); 1334 clone_str(&ctx->svc_ca_fname, ca_fname); 1335 clone_str(&ctx->svc_username, username); 1336 clone_str(&ctx->svc_password, password); 1337 clone_str(&ctx->svc_client_cert, client_cert); 1338 clone_str(&ctx->svc_client_key, client_key); 1339 1340 /* 1341 * Workaround for Apache "Hostname 'FOO' provided via SNI and hostname 1342 * 'foo' provided via HTTP are different. 1343 */ 1344 for (count = 0, pos = ctx->svc_address; count < 3 && pos && *pos; 1345 pos++) { 1346 if (*pos == '/') 1347 count++; 1348 *pos = tolower(*pos); 1349 } 1350 1351 ctx->curl = setup_curl_post(ctx, ctx->svc_address, ca_fname, username, 1352 password, client_cert, client_key); 1353 if (ctx->curl == NULL) 1354 return -1; 1355 1356 return 0; 1357} 1358 1359 1360int soap_init_client(struct http_ctx *ctx, const char *address, 1361 const char *ca_fname, const char *username, 1362 const char *password, const char *client_cert, 1363 const char *client_key) 1364{ 1365 if (post_init_client(ctx, address, ca_fname, username, password, 1366 client_cert, client_key) < 0) 1367 return -1; 1368 1369 ctx->curl_hdr = curl_slist_append(ctx->curl_hdr, 1370 "Content-Type: application/soap+xml"); 1371 ctx->curl_hdr = curl_slist_append(ctx->curl_hdr, "SOAPAction: "); 1372 ctx->curl_hdr = curl_slist_append(ctx->curl_hdr, "Expect:"); 1373 curl_easy_setopt(ctx->curl, CURLOPT_HTTPHEADER, ctx->curl_hdr); 1374 1375 return 0; 1376} 1377 1378 1379int soap_reinit_client(struct http_ctx *ctx) 1380{ 1381 char *address = NULL; 1382 char *ca_fname = NULL; 1383 char *username = NULL; 1384 char *password = NULL; 1385 char *client_cert = NULL; 1386 char *client_key = NULL; 1387 int ret; 1388 1389 clear_curl(ctx); 1390 1391 clone_str(&address, ctx->svc_address); 1392 clone_str(&ca_fname, ctx->svc_ca_fname); 1393 clone_str(&username, ctx->svc_username); 1394 clone_str(&password, ctx->svc_password); 1395 clone_str(&client_cert, ctx->svc_client_cert); 1396 clone_str(&client_key, ctx->svc_client_key); 1397 1398 ret = soap_init_client(ctx, address, ca_fname, username, password, 1399 client_cert, client_key); 1400 os_free(address); 1401 os_free(ca_fname); 1402 str_clear_free(username); 1403 str_clear_free(password); 1404 os_free(client_cert); 1405 os_free(client_key); 1406 return ret; 1407} 1408 1409 1410static void free_curl_buf(struct http_ctx *ctx) 1411{ 1412 os_free(ctx->curl_buf); 1413 ctx->curl_buf = NULL; 1414 ctx->curl_buf_len = 0; 1415} 1416 1417 1418xml_node_t * soap_send_receive(struct http_ctx *ctx, xml_node_t *node) 1419{ 1420 char *str; 1421 xml_node_t *envelope, *ret, *resp, *n; 1422 CURLcode res; 1423 long http = 0; 1424 1425 ctx->last_err = NULL; 1426 1427 wpa_printf(MSG_DEBUG, "SOAP: Sending message"); 1428 envelope = soap_build_envelope(ctx->xml, node); 1429 str = xml_node_to_str(ctx->xml, envelope); 1430 xml_node_free(ctx->xml, envelope); 1431 wpa_printf(MSG_MSGDUMP, "SOAP[%s]", str); 1432 1433 curl_easy_setopt(ctx->curl, CURLOPT_POSTFIELDS, str); 1434 free_curl_buf(ctx); 1435 1436 res = curl_easy_perform(ctx->curl); 1437 if (res != CURLE_OK) { 1438 if (!ctx->last_err) 1439 ctx->last_err = curl_easy_strerror(res); 1440 wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s", 1441 ctx->last_err); 1442 os_free(str); 1443 free_curl_buf(ctx); 1444 return NULL; 1445 } 1446 os_free(str); 1447 1448 curl_easy_getinfo(ctx->curl, CURLINFO_RESPONSE_CODE, &http); 1449 wpa_printf(MSG_DEBUG, "SOAP: Server response code %ld", http); 1450 if (http != 200) { 1451 ctx->last_err = "HTTP download failed"; 1452 wpa_printf(MSG_INFO, "HTTP download failed - code %ld", http); 1453 free_curl_buf(ctx); 1454 return NULL; 1455 } 1456 1457 if (ctx->curl_buf == NULL) 1458 return NULL; 1459 1460 wpa_printf(MSG_MSGDUMP, "Server response:\n%s", ctx->curl_buf); 1461 resp = xml_node_from_buf(ctx->xml, ctx->curl_buf); 1462 free_curl_buf(ctx); 1463 if (resp == NULL) { 1464 wpa_printf(MSG_INFO, "Could not parse SOAP response"); 1465 ctx->last_err = "Could not parse SOAP response"; 1466 return NULL; 1467 } 1468 1469 ret = soap_get_body(ctx->xml, resp); 1470 if (ret == NULL) { 1471 wpa_printf(MSG_INFO, "Could not get SOAP body"); 1472 ctx->last_err = "Could not get SOAP body"; 1473 return NULL; 1474 } 1475 1476 wpa_printf(MSG_DEBUG, "SOAP body localname: '%s'", 1477 xml_node_get_localname(ctx->xml, ret)); 1478 n = xml_node_copy(ctx->xml, ret); 1479 xml_node_free(ctx->xml, resp); 1480 1481 return n; 1482} 1483 1484 1485struct http_ctx * http_init_ctx(void *upper_ctx, struct xml_node_ctx *xml_ctx) 1486{ 1487 struct http_ctx *ctx; 1488 1489 ctx = os_zalloc(sizeof(*ctx)); 1490 if (ctx == NULL) 1491 return NULL; 1492 ctx->ctx = upper_ctx; 1493 ctx->xml = xml_ctx; 1494 ctx->ocsp = OPTIONAL_OCSP; 1495 1496 curl_global_init(CURL_GLOBAL_ALL); 1497 1498 return ctx; 1499} 1500 1501 1502void http_ocsp_set(struct http_ctx *ctx, int val) 1503{ 1504 if (val == 0) 1505 ctx->ocsp = NO_OCSP; 1506 else if (val == 1) 1507 ctx->ocsp = OPTIONAL_OCSP; 1508 if (val == 2) 1509 ctx->ocsp = MANDATORY_OCSP; 1510} 1511 1512 1513void http_deinit_ctx(struct http_ctx *ctx) 1514{ 1515 clear_curl(ctx); 1516 os_free(ctx->curl_buf); 1517 curl_global_cleanup(); 1518 1519 os_free(ctx->svc_address); 1520 os_free(ctx->svc_ca_fname); 1521 str_clear_free(ctx->svc_username); 1522 str_clear_free(ctx->svc_password); 1523 os_free(ctx->svc_client_cert); 1524 os_free(ctx->svc_client_key); 1525 1526 os_free(ctx); 1527} 1528 1529 1530int http_download_file(struct http_ctx *ctx, const char *url, 1531 const char *fname, const char *ca_fname) 1532{ 1533 CURL *curl; 1534 FILE *f; 1535 CURLcode res; 1536 long http = 0; 1537 1538 ctx->last_err = NULL; 1539 1540 wpa_printf(MSG_DEBUG, "curl: Download file from %s to %s (ca=%s)", 1541 url, fname, ca_fname); 1542 curl = curl_easy_init(); 1543 if (curl == NULL) 1544 return -1; 1545 1546 f = fopen(fname, "wb"); 1547 if (f == NULL) { 1548 curl_easy_cleanup(curl); 1549 return -1; 1550 } 1551 1552 curl_easy_setopt(curl, CURLOPT_URL, url); 1553 if (ca_fname) { 1554 curl_easy_setopt(curl, CURLOPT_CAINFO, ca_fname); 1555 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); 1556 curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L); 1557 } else { 1558 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 1559 } 1560 curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curl_cb_debug); 1561 curl_easy_setopt(curl, CURLOPT_DEBUGDATA, ctx); 1562 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite); 1563 curl_easy_setopt(curl, CURLOPT_WRITEDATA, f); 1564 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 1565 1566 res = curl_easy_perform(curl); 1567 if (res != CURLE_OK) { 1568 if (!ctx->last_err) 1569 ctx->last_err = curl_easy_strerror(res); 1570 wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s", 1571 ctx->last_err); 1572 curl_easy_cleanup(curl); 1573 fclose(f); 1574 return -1; 1575 } 1576 1577 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http); 1578 wpa_printf(MSG_DEBUG, "curl: Server response code %ld", http); 1579 if (http != 200) { 1580 ctx->last_err = "HTTP download failed"; 1581 wpa_printf(MSG_INFO, "HTTP download failed - code %ld", http); 1582 curl_easy_cleanup(curl); 1583 fclose(f); 1584 return -1; 1585 } 1586 1587 curl_easy_cleanup(curl); 1588 fclose(f); 1589 1590 return 0; 1591} 1592 1593 1594char * http_post(struct http_ctx *ctx, const char *url, const char *data, 1595 const char *content_type, const char *ext_hdr, 1596 const char *ca_fname, 1597 const char *username, const char *password, 1598 const char *client_cert, const char *client_key, 1599 size_t *resp_len) 1600{ 1601 long http = 0; 1602 CURLcode res; 1603 char *ret; 1604 CURL *curl; 1605 struct curl_slist *curl_hdr = NULL; 1606 1607 ctx->last_err = NULL; 1608 wpa_printf(MSG_DEBUG, "curl: HTTP POST to %s", url); 1609 curl = setup_curl_post(ctx, url, ca_fname, username, password, 1610 client_cert, client_key); 1611 if (curl == NULL) 1612 return NULL; 1613 1614 if (content_type) { 1615 char ct[200]; 1616 snprintf(ct, sizeof(ct), "Content-Type: %s", content_type); 1617 curl_hdr = curl_slist_append(curl_hdr, ct); 1618 } 1619 if (ext_hdr) 1620 curl_hdr = curl_slist_append(curl_hdr, ext_hdr); 1621 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_hdr); 1622 1623 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); 1624 free_curl_buf(ctx); 1625 1626 res = curl_easy_perform(curl); 1627 if (res != CURLE_OK) { 1628 if (!ctx->last_err) 1629 ctx->last_err = curl_easy_strerror(res); 1630 wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s", 1631 ctx->last_err); 1632 free_curl_buf(ctx); 1633 return NULL; 1634 } 1635 1636 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http); 1637 wpa_printf(MSG_DEBUG, "curl: Server response code %ld", http); 1638 if (http != 200) { 1639 ctx->last_err = "HTTP POST failed"; 1640 wpa_printf(MSG_INFO, "HTTP POST failed - code %ld", http); 1641 free_curl_buf(ctx); 1642 return NULL; 1643 } 1644 1645 if (ctx->curl_buf == NULL) 1646 return NULL; 1647 1648 ret = ctx->curl_buf; 1649 if (resp_len) 1650 *resp_len = ctx->curl_buf_len; 1651 ctx->curl_buf = NULL; 1652 ctx->curl_buf_len = 0; 1653 1654 wpa_printf(MSG_MSGDUMP, "Server response:\n%s", ret); 1655 1656 return ret; 1657} 1658 1659 1660void http_set_cert_cb(struct http_ctx *ctx, 1661 int (*cb)(void *ctx, struct http_cert *cert), 1662 void *cb_ctx) 1663{ 1664 ctx->cert_cb = cb; 1665 ctx->cert_cb_ctx = cb_ctx; 1666} 1667 1668 1669const char * http_get_err(struct http_ctx *ctx) 1670{ 1671 return ctx->last_err; 1672} 1673