13c260e60Schristos /* 23c260e60Schristos * HTTP wrapper for libcurl 33c260e60Schristos * Copyright (c) 2012-2014, Qualcomm Atheros, Inc. 43c260e60Schristos * 53c260e60Schristos * This software may be distributed under the terms of the BSD license. 63c260e60Schristos * See README for more details. 73c260e60Schristos */ 83c260e60Schristos 93c260e60Schristos #include "includes.h" 103c260e60Schristos #include <curl/curl.h> 113c260e60Schristos #ifdef EAP_TLS_OPENSSL 123c260e60Schristos #include <openssl/ssl.h> 133c260e60Schristos #include <openssl/asn1.h> 143c260e60Schristos #include <openssl/asn1t.h> 153c260e60Schristos #include <openssl/x509v3.h> 163c260e60Schristos 173c260e60Schristos #ifdef SSL_set_tlsext_status_type 183c260e60Schristos #ifndef OPENSSL_NO_TLSEXT 193c260e60Schristos #define HAVE_OCSP 203c260e60Schristos #include <openssl/err.h> 213c260e60Schristos #include <openssl/ocsp.h> 223c260e60Schristos #endif /* OPENSSL_NO_TLSEXT */ 233c260e60Schristos #endif /* SSL_set_tlsext_status_type */ 243c260e60Schristos #endif /* EAP_TLS_OPENSSL */ 253c260e60Schristos 263c260e60Schristos #include "common.h" 273c260e60Schristos #include "xml-utils.h" 283c260e60Schristos #include "http-utils.h" 2936ebd06eSchristos #ifdef EAP_TLS_OPENSSL 3036ebd06eSchristos #include "crypto/tls_openssl.h" 3136ebd06eSchristos #endif /* EAP_TLS_OPENSSL */ 323c260e60Schristos 333c260e60Schristos 343d6c0713Schristos #if OPENSSL_VERSION_NUMBER < 0x10100000L 353d6c0713Schristos static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x) 363d6c0713Schristos { 373d6c0713Schristos return ASN1_STRING_data((ASN1_STRING *) x); 383d6c0713Schristos } 393d6c0713Schristos #endif /* OpenSSL < 1.1.0 */ 403d6c0713Schristos 413d6c0713Schristos 423c260e60Schristos struct http_ctx { 433c260e60Schristos void *ctx; 443c260e60Schristos struct xml_node_ctx *xml; 453c260e60Schristos CURL *curl; 463c260e60Schristos struct curl_slist *curl_hdr; 473c260e60Schristos char *svc_address; 483c260e60Schristos char *svc_ca_fname; 493c260e60Schristos char *svc_username; 503c260e60Schristos char *svc_password; 513c260e60Schristos char *svc_client_cert; 523c260e60Schristos char *svc_client_key; 533c260e60Schristos char *curl_buf; 543c260e60Schristos size_t curl_buf_len; 553c260e60Schristos 563c260e60Schristos int (*cert_cb)(void *ctx, struct http_cert *cert); 573c260e60Schristos void *cert_cb_ctx; 583c260e60Schristos 593c260e60Schristos enum { 603c260e60Schristos NO_OCSP, OPTIONAL_OCSP, MANDATORY_OCSP 613c260e60Schristos } ocsp; 623c260e60Schristos X509 *peer_cert; 633c260e60Schristos X509 *peer_issuer; 643c260e60Schristos X509 *peer_issuer_issuer; 653c260e60Schristos 663c260e60Schristos const char *last_err; 67*bb618362Schristos const char *url; 683c260e60Schristos }; 693c260e60Schristos 703c260e60Schristos 713c260e60Schristos static void clear_curl(struct http_ctx *ctx) 723c260e60Schristos { 733c260e60Schristos if (ctx->curl) { 743c260e60Schristos curl_easy_cleanup(ctx->curl); 753c260e60Schristos ctx->curl = NULL; 763c260e60Schristos } 773c260e60Schristos if (ctx->curl_hdr) { 783c260e60Schristos curl_slist_free_all(ctx->curl_hdr); 793c260e60Schristos ctx->curl_hdr = NULL; 803c260e60Schristos } 813c260e60Schristos } 823c260e60Schristos 833c260e60Schristos 843c260e60Schristos static void clone_str(char **dst, const char *src) 853c260e60Schristos { 863c260e60Schristos os_free(*dst); 873c260e60Schristos if (src) 883c260e60Schristos *dst = os_strdup(src); 893c260e60Schristos else 903c260e60Schristos *dst = NULL; 913c260e60Schristos } 923c260e60Schristos 933c260e60Schristos 943c260e60Schristos static void debug_dump(struct http_ctx *ctx, const char *title, 953c260e60Schristos const char *buf, size_t len) 963c260e60Schristos { 973c260e60Schristos char *txt; 983c260e60Schristos size_t i; 993c260e60Schristos 1003c260e60Schristos for (i = 0; i < len; i++) { 1013c260e60Schristos if (buf[i] < 32 && buf[i] != '\t' && buf[i] != '\n' && 1023c260e60Schristos buf[i] != '\r') { 1033c260e60Schristos wpa_hexdump_ascii(MSG_MSGDUMP, title, buf, len); 1043c260e60Schristos return; 1053c260e60Schristos } 1063c260e60Schristos } 1073c260e60Schristos 1083c260e60Schristos txt = os_malloc(len + 1); 1093c260e60Schristos if (txt == NULL) 1103c260e60Schristos return; 1113c260e60Schristos os_memcpy(txt, buf, len); 1123c260e60Schristos txt[len] = '\0'; 1133c260e60Schristos while (len > 0) { 1143c260e60Schristos len--; 1153c260e60Schristos if (txt[len] == '\n' || txt[len] == '\r') 1163c260e60Schristos txt[len] = '\0'; 1173c260e60Schristos else 1183c260e60Schristos break; 1193c260e60Schristos } 1203c260e60Schristos wpa_printf(MSG_MSGDUMP, "%s[%s]", title, txt); 1213c260e60Schristos os_free(txt); 1223c260e60Schristos } 1233c260e60Schristos 1243c260e60Schristos 1253c260e60Schristos static int curl_cb_debug(CURL *curl, curl_infotype info, char *buf, size_t len, 1263c260e60Schristos void *userdata) 1273c260e60Schristos { 1283c260e60Schristos struct http_ctx *ctx = userdata; 1293c260e60Schristos switch (info) { 1303c260e60Schristos case CURLINFO_TEXT: 1313c260e60Schristos debug_dump(ctx, "CURLINFO_TEXT", buf, len); 1323c260e60Schristos break; 1333c260e60Schristos case CURLINFO_HEADER_IN: 1343c260e60Schristos debug_dump(ctx, "CURLINFO_HEADER_IN", buf, len); 1353c260e60Schristos break; 1363c260e60Schristos case CURLINFO_HEADER_OUT: 1373c260e60Schristos debug_dump(ctx, "CURLINFO_HEADER_OUT", buf, len); 1383c260e60Schristos break; 1393c260e60Schristos case CURLINFO_DATA_IN: 1403c260e60Schristos debug_dump(ctx, "CURLINFO_DATA_IN", buf, len); 1413c260e60Schristos break; 1423c260e60Schristos case CURLINFO_DATA_OUT: 1433c260e60Schristos debug_dump(ctx, "CURLINFO_DATA_OUT", buf, len); 1443c260e60Schristos break; 1453c260e60Schristos case CURLINFO_SSL_DATA_IN: 1463c260e60Schristos wpa_printf(MSG_DEBUG, "debug - CURLINFO_SSL_DATA_IN - %d", 1473c260e60Schristos (int) len); 1483c260e60Schristos break; 1493c260e60Schristos case CURLINFO_SSL_DATA_OUT: 1503c260e60Schristos wpa_printf(MSG_DEBUG, "debug - CURLINFO_SSL_DATA_OUT - %d", 1513c260e60Schristos (int) len); 1523c260e60Schristos break; 1533c260e60Schristos case CURLINFO_END: 1543c260e60Schristos wpa_printf(MSG_DEBUG, "debug - CURLINFO_END - %d", 1553c260e60Schristos (int) len); 1563c260e60Schristos break; 1573c260e60Schristos } 1583c260e60Schristos return 0; 1593c260e60Schristos } 1603c260e60Schristos 1613c260e60Schristos 1623c260e60Schristos static size_t curl_cb_write(void *ptr, size_t size, size_t nmemb, 1633c260e60Schristos void *userdata) 1643c260e60Schristos { 1653c260e60Schristos struct http_ctx *ctx = userdata; 1663c260e60Schristos char *n; 1673c260e60Schristos n = os_realloc(ctx->curl_buf, ctx->curl_buf_len + size * nmemb + 1); 1683c260e60Schristos if (n == NULL) 1693c260e60Schristos return 0; 1703c260e60Schristos ctx->curl_buf = n; 1713c260e60Schristos os_memcpy(n + ctx->curl_buf_len, ptr, size * nmemb); 1723c260e60Schristos n[ctx->curl_buf_len + size * nmemb] = '\0'; 1733c260e60Schristos ctx->curl_buf_len += size * nmemb; 1743c260e60Schristos return size * nmemb; 1753c260e60Schristos } 1763c260e60Schristos 1773c260e60Schristos 1783c260e60Schristos #ifdef EAP_TLS_OPENSSL 1793c260e60Schristos 1803c260e60Schristos static void debug_dump_cert(const char *title, X509 *cert) 1813c260e60Schristos { 1823c260e60Schristos BIO *out; 1833c260e60Schristos char *txt; 1843c260e60Schristos size_t rlen; 1853c260e60Schristos 1863c260e60Schristos out = BIO_new(BIO_s_mem()); 1873c260e60Schristos if (!out) 1883c260e60Schristos return; 1893c260e60Schristos 1903c260e60Schristos X509_print_ex(out, cert, XN_FLAG_COMPAT, X509_FLAG_COMPAT); 1913c260e60Schristos rlen = BIO_ctrl_pending(out); 1923c260e60Schristos txt = os_malloc(rlen + 1); 1933c260e60Schristos if (txt) { 1943c260e60Schristos int res = BIO_read(out, txt, rlen); 1953c260e60Schristos if (res > 0) { 1963c260e60Schristos txt[res] = '\0'; 1973c260e60Schristos wpa_printf(MSG_MSGDUMP, "%s:\n%s", title, txt); 1983c260e60Schristos } 1993c260e60Schristos os_free(txt); 2003c260e60Schristos } 2013c260e60Schristos BIO_free(out); 2023c260e60Schristos } 2033c260e60Schristos 2043c260e60Schristos 2053c260e60Schristos static void add_alt_name_othername(struct http_ctx *ctx, struct http_cert *cert, 2063c260e60Schristos OTHERNAME *o) 2073c260e60Schristos { 2083c260e60Schristos char txt[100]; 2093c260e60Schristos int res; 2103c260e60Schristos struct http_othername *on; 2113c260e60Schristos ASN1_TYPE *val; 2123c260e60Schristos 2133c260e60Schristos on = os_realloc_array(cert->othername, cert->num_othername + 1, 2143c260e60Schristos sizeof(struct http_othername)); 2153c260e60Schristos if (on == NULL) 2163c260e60Schristos return; 2173c260e60Schristos cert->othername = on; 2183c260e60Schristos on = &on[cert->num_othername]; 2193c260e60Schristos os_memset(on, 0, sizeof(*on)); 2203c260e60Schristos 2213c260e60Schristos res = OBJ_obj2txt(txt, sizeof(txt), o->type_id, 1); 2223c260e60Schristos if (res < 0 || res >= (int) sizeof(txt)) 2233c260e60Schristos return; 2243c260e60Schristos 2253c260e60Schristos on->oid = os_strdup(txt); 2263c260e60Schristos if (on->oid == NULL) 2273c260e60Schristos return; 2283c260e60Schristos 2293c260e60Schristos val = o->value; 2303c260e60Schristos on->data = val->value.octet_string->data; 2313c260e60Schristos on->len = val->value.octet_string->length; 2323c260e60Schristos 2333c260e60Schristos cert->num_othername++; 2343c260e60Schristos } 2353c260e60Schristos 2363c260e60Schristos 2373c260e60Schristos static void add_alt_name_dns(struct http_ctx *ctx, struct http_cert *cert, 2383c260e60Schristos ASN1_STRING *name) 2393c260e60Schristos { 2403c260e60Schristos char *buf; 2413c260e60Schristos char **n; 2423c260e60Schristos 2433c260e60Schristos buf = NULL; 2443c260e60Schristos if (ASN1_STRING_to_UTF8((unsigned char **) &buf, name) < 0) 2453c260e60Schristos return; 2463c260e60Schristos 2473c260e60Schristos n = os_realloc_array(cert->dnsname, cert->num_dnsname + 1, 2483c260e60Schristos sizeof(char *)); 2493c260e60Schristos if (n == NULL) 2503c260e60Schristos return; 2513c260e60Schristos 2523c260e60Schristos cert->dnsname = n; 2533c260e60Schristos n[cert->num_dnsname] = buf; 2543c260e60Schristos cert->num_dnsname++; 2553c260e60Schristos } 2563c260e60Schristos 2573c260e60Schristos 2583c260e60Schristos static void add_alt_name(struct http_ctx *ctx, struct http_cert *cert, 2593c260e60Schristos const GENERAL_NAME *name) 2603c260e60Schristos { 2613c260e60Schristos switch (name->type) { 2623c260e60Schristos case GEN_OTHERNAME: 2633c260e60Schristos add_alt_name_othername(ctx, cert, name->d.otherName); 2643c260e60Schristos break; 2653c260e60Schristos case GEN_DNS: 2663c260e60Schristos add_alt_name_dns(ctx, cert, name->d.dNSName); 2673c260e60Schristos break; 2683c260e60Schristos } 2693c260e60Schristos } 2703c260e60Schristos 2713c260e60Schristos 2723c260e60Schristos static void add_alt_names(struct http_ctx *ctx, struct http_cert *cert, 2733c260e60Schristos GENERAL_NAMES *names) 2743c260e60Schristos { 2753c260e60Schristos int num, i; 2763c260e60Schristos 2773c260e60Schristos num = sk_GENERAL_NAME_num(names); 2783c260e60Schristos for (i = 0; i < num; i++) { 2793c260e60Schristos const GENERAL_NAME *name; 2803c260e60Schristos name = sk_GENERAL_NAME_value(names, i); 2813c260e60Schristos add_alt_name(ctx, cert, name); 2823c260e60Schristos } 2833c260e60Schristos } 2843c260e60Schristos 2853c260e60Schristos 2863c260e60Schristos /* RFC 3709 */ 2873c260e60Schristos 2883c260e60Schristos typedef struct { 2893c260e60Schristos X509_ALGOR *hashAlg; 2903c260e60Schristos ASN1_OCTET_STRING *hashValue; 2913c260e60Schristos } HashAlgAndValue; 2923c260e60Schristos 2933c260e60Schristos typedef struct { 2943c260e60Schristos STACK_OF(HashAlgAndValue) *refStructHash; 2953c260e60Schristos STACK_OF(ASN1_IA5STRING) *refStructURI; 2963c260e60Schristos } LogotypeReference; 2973c260e60Schristos 2983c260e60Schristos typedef struct { 2993c260e60Schristos ASN1_IA5STRING *mediaType; 3003c260e60Schristos STACK_OF(HashAlgAndValue) *logotypeHash; 3013c260e60Schristos STACK_OF(ASN1_IA5STRING) *logotypeURI; 3023c260e60Schristos } LogotypeDetails; 3033c260e60Schristos 3043c260e60Schristos typedef struct { 3053c260e60Schristos int type; 3063c260e60Schristos union { 3073c260e60Schristos ASN1_INTEGER *numBits; 3083c260e60Schristos ASN1_INTEGER *tableSize; 3093c260e60Schristos } d; 3103c260e60Schristos } LogotypeImageResolution; 3113c260e60Schristos 3123c260e60Schristos typedef struct { 3133c260e60Schristos ASN1_INTEGER *type; /* LogotypeImageType ::= INTEGER */ 3143c260e60Schristos ASN1_INTEGER *fileSize; 3153c260e60Schristos ASN1_INTEGER *xSize; 3163c260e60Schristos ASN1_INTEGER *ySize; 3173c260e60Schristos LogotypeImageResolution *resolution; 3183c260e60Schristos ASN1_IA5STRING *language; 3193c260e60Schristos } LogotypeImageInfo; 3203c260e60Schristos 3213c260e60Schristos typedef struct { 3223c260e60Schristos LogotypeDetails *imageDetails; 3233c260e60Schristos LogotypeImageInfo *imageInfo; 3243c260e60Schristos } LogotypeImage; 3253c260e60Schristos 3263c260e60Schristos typedef struct { 3273c260e60Schristos ASN1_INTEGER *fileSize; 3283c260e60Schristos ASN1_INTEGER *playTime; 3293c260e60Schristos ASN1_INTEGER *channels; 3303c260e60Schristos ASN1_INTEGER *sampleRate; 3313c260e60Schristos ASN1_IA5STRING *language; 3323c260e60Schristos } LogotypeAudioInfo; 3333c260e60Schristos 3343c260e60Schristos typedef struct { 3353c260e60Schristos LogotypeDetails *audioDetails; 3363c260e60Schristos LogotypeAudioInfo *audioInfo; 3373c260e60Schristos } LogotypeAudio; 3383c260e60Schristos 3393c260e60Schristos typedef struct { 3403c260e60Schristos STACK_OF(LogotypeImage) *image; 3413c260e60Schristos STACK_OF(LogotypeAudio) *audio; 3423c260e60Schristos } LogotypeData; 3433c260e60Schristos 3443c260e60Schristos typedef struct { 3453c260e60Schristos int type; 3463c260e60Schristos union { 3473c260e60Schristos LogotypeData *direct; 3483c260e60Schristos LogotypeReference *indirect; 3493c260e60Schristos } d; 3503c260e60Schristos } LogotypeInfo; 3513c260e60Schristos 3523c260e60Schristos typedef struct { 3533c260e60Schristos ASN1_OBJECT *logotypeType; 3543c260e60Schristos LogotypeInfo *info; 3553c260e60Schristos } OtherLogotypeInfo; 3563c260e60Schristos 3573c260e60Schristos typedef struct { 3583c260e60Schristos STACK_OF(LogotypeInfo) *communityLogos; 3593c260e60Schristos LogotypeInfo *issuerLogo; 3603c260e60Schristos LogotypeInfo *subjectLogo; 3613c260e60Schristos STACK_OF(OtherLogotypeInfo) *otherLogos; 3623c260e60Schristos } LogotypeExtn; 3633c260e60Schristos 3643c260e60Schristos ASN1_SEQUENCE(HashAlgAndValue) = { 3653c260e60Schristos ASN1_SIMPLE(HashAlgAndValue, hashAlg, X509_ALGOR), 3663c260e60Schristos ASN1_SIMPLE(HashAlgAndValue, hashValue, ASN1_OCTET_STRING) 3673c260e60Schristos } ASN1_SEQUENCE_END(HashAlgAndValue); 3683c260e60Schristos 3693c260e60Schristos ASN1_SEQUENCE(LogotypeReference) = { 3703c260e60Schristos ASN1_SEQUENCE_OF(LogotypeReference, refStructHash, HashAlgAndValue), 3713c260e60Schristos ASN1_SEQUENCE_OF(LogotypeReference, refStructURI, ASN1_IA5STRING) 3723c260e60Schristos } ASN1_SEQUENCE_END(LogotypeReference); 3733c260e60Schristos 3743c260e60Schristos ASN1_SEQUENCE(LogotypeDetails) = { 3753c260e60Schristos ASN1_SIMPLE(LogotypeDetails, mediaType, ASN1_IA5STRING), 3763c260e60Schristos ASN1_SEQUENCE_OF(LogotypeDetails, logotypeHash, HashAlgAndValue), 3773c260e60Schristos ASN1_SEQUENCE_OF(LogotypeDetails, logotypeURI, ASN1_IA5STRING) 3783c260e60Schristos } ASN1_SEQUENCE_END(LogotypeDetails); 3793c260e60Schristos 3803c260e60Schristos ASN1_CHOICE(LogotypeImageResolution) = { 3813c260e60Schristos ASN1_IMP(LogotypeImageResolution, d.numBits, ASN1_INTEGER, 1), 3823c260e60Schristos ASN1_IMP(LogotypeImageResolution, d.tableSize, ASN1_INTEGER, 2) 3833c260e60Schristos } ASN1_CHOICE_END(LogotypeImageResolution); 3843c260e60Schristos 3853c260e60Schristos ASN1_SEQUENCE(LogotypeImageInfo) = { 3863c260e60Schristos ASN1_IMP_OPT(LogotypeImageInfo, type, ASN1_INTEGER, 0), 3873c260e60Schristos ASN1_SIMPLE(LogotypeImageInfo, fileSize, ASN1_INTEGER), 3883c260e60Schristos ASN1_SIMPLE(LogotypeImageInfo, xSize, ASN1_INTEGER), 3893c260e60Schristos ASN1_SIMPLE(LogotypeImageInfo, ySize, ASN1_INTEGER), 3903c260e60Schristos ASN1_OPT(LogotypeImageInfo, resolution, LogotypeImageResolution), 3913c260e60Schristos ASN1_IMP_OPT(LogotypeImageInfo, language, ASN1_IA5STRING, 4), 3923c260e60Schristos } ASN1_SEQUENCE_END(LogotypeImageInfo); 3933c260e60Schristos 3943c260e60Schristos ASN1_SEQUENCE(LogotypeImage) = { 3953c260e60Schristos ASN1_SIMPLE(LogotypeImage, imageDetails, LogotypeDetails), 3963c260e60Schristos ASN1_OPT(LogotypeImage, imageInfo, LogotypeImageInfo) 3973c260e60Schristos } ASN1_SEQUENCE_END(LogotypeImage); 3983c260e60Schristos 3993c260e60Schristos ASN1_SEQUENCE(LogotypeAudioInfo) = { 4003c260e60Schristos ASN1_SIMPLE(LogotypeAudioInfo, fileSize, ASN1_INTEGER), 4013c260e60Schristos ASN1_SIMPLE(LogotypeAudioInfo, playTime, ASN1_INTEGER), 4023c260e60Schristos ASN1_SIMPLE(LogotypeAudioInfo, channels, ASN1_INTEGER), 4033c260e60Schristos ASN1_IMP_OPT(LogotypeAudioInfo, sampleRate, ASN1_INTEGER, 3), 4043c260e60Schristos ASN1_IMP_OPT(LogotypeAudioInfo, language, ASN1_IA5STRING, 4) 4053c260e60Schristos } ASN1_SEQUENCE_END(LogotypeAudioInfo); 4063c260e60Schristos 4073c260e60Schristos ASN1_SEQUENCE(LogotypeAudio) = { 4083c260e60Schristos ASN1_SIMPLE(LogotypeAudio, audioDetails, LogotypeDetails), 4093c260e60Schristos ASN1_OPT(LogotypeAudio, audioInfo, LogotypeAudioInfo) 4103c260e60Schristos } ASN1_SEQUENCE_END(LogotypeAudio); 4113c260e60Schristos 4123c260e60Schristos ASN1_SEQUENCE(LogotypeData) = { 4133c260e60Schristos ASN1_SEQUENCE_OF_OPT(LogotypeData, image, LogotypeImage), 4143c260e60Schristos ASN1_IMP_SEQUENCE_OF_OPT(LogotypeData, audio, LogotypeAudio, 1) 4153c260e60Schristos } ASN1_SEQUENCE_END(LogotypeData); 4163c260e60Schristos 4173c260e60Schristos ASN1_CHOICE(LogotypeInfo) = { 4183c260e60Schristos ASN1_IMP(LogotypeInfo, d.direct, LogotypeData, 0), 4193c260e60Schristos ASN1_IMP(LogotypeInfo, d.indirect, LogotypeReference, 1) 4203c260e60Schristos } ASN1_CHOICE_END(LogotypeInfo); 4213c260e60Schristos 4223c260e60Schristos ASN1_SEQUENCE(OtherLogotypeInfo) = { 4233c260e60Schristos ASN1_SIMPLE(OtherLogotypeInfo, logotypeType, ASN1_OBJECT), 4243c260e60Schristos ASN1_SIMPLE(OtherLogotypeInfo, info, LogotypeInfo) 4253c260e60Schristos } ASN1_SEQUENCE_END(OtherLogotypeInfo); 4263c260e60Schristos 4273c260e60Schristos ASN1_SEQUENCE(LogotypeExtn) = { 4283c260e60Schristos ASN1_EXP_SEQUENCE_OF_OPT(LogotypeExtn, communityLogos, LogotypeInfo, 0), 4293c260e60Schristos ASN1_EXP_OPT(LogotypeExtn, issuerLogo, LogotypeInfo, 1), 4303c260e60Schristos ASN1_EXP_OPT(LogotypeExtn, issuerLogo, LogotypeInfo, 2), 4313c260e60Schristos ASN1_EXP_SEQUENCE_OF_OPT(LogotypeExtn, otherLogos, OtherLogotypeInfo, 3) 4323c260e60Schristos } ASN1_SEQUENCE_END(LogotypeExtn); 4333c260e60Schristos 4343c260e60Schristos IMPLEMENT_ASN1_FUNCTIONS(LogotypeExtn); 4353c260e60Schristos 4363d6c0713Schristos #if OPENSSL_VERSION_NUMBER < 0x10100000L 4373c260e60Schristos #define sk_LogotypeInfo_num(st) SKM_sk_num(LogotypeInfo, (st)) 4383c260e60Schristos #define sk_LogotypeInfo_value(st, i) SKM_sk_value(LogotypeInfo, (st), (i)) 4393c260e60Schristos #define sk_LogotypeImage_num(st) SKM_sk_num(LogotypeImage, (st)) 4403c260e60Schristos #define sk_LogotypeImage_value(st, i) SKM_sk_value(LogotypeImage, (st), (i)) 4413c260e60Schristos #define sk_LogotypeAudio_num(st) SKM_sk_num(LogotypeAudio, (st)) 4423c260e60Schristos #define sk_LogotypeAudio_value(st, i) SKM_sk_value(LogotypeAudio, (st), (i)) 4433c260e60Schristos #define sk_HashAlgAndValue_num(st) SKM_sk_num(HashAlgAndValue, (st)) 4443c260e60Schristos #define sk_HashAlgAndValue_value(st, i) SKM_sk_value(HashAlgAndValue, (st), (i)) 4453c260e60Schristos #define sk_ASN1_IA5STRING_num(st) SKM_sk_num(ASN1_IA5STRING, (st)) 4463c260e60Schristos #define sk_ASN1_IA5STRING_value(st, i) SKM_sk_value(ASN1_IA5STRING, (st), (i)) 4473d6c0713Schristos #else 4483d6c0713Schristos DEFINE_STACK_OF(LogotypeInfo) 4493d6c0713Schristos DEFINE_STACK_OF(LogotypeImage) 4503d6c0713Schristos DEFINE_STACK_OF(LogotypeAudio) 4513d6c0713Schristos DEFINE_STACK_OF(HashAlgAndValue) 4523d6c0713Schristos DEFINE_STACK_OF(ASN1_IA5STRING) 4533d6c0713Schristos #endif 4543c260e60Schristos 4553c260e60Schristos 4563c260e60Schristos static void add_logo(struct http_ctx *ctx, struct http_cert *hcert, 4573c260e60Schristos HashAlgAndValue *hash, ASN1_IA5STRING *uri) 4583c260e60Schristos { 4593c260e60Schristos char txt[100]; 4603c260e60Schristos int res, len; 4613c260e60Schristos struct http_logo *n; 4623c260e60Schristos 4633c260e60Schristos if (hash == NULL || uri == NULL) 4643c260e60Schristos return; 4653c260e60Schristos 4663c260e60Schristos res = OBJ_obj2txt(txt, sizeof(txt), hash->hashAlg->algorithm, 1); 4673c260e60Schristos if (res < 0 || res >= (int) sizeof(txt)) 4683c260e60Schristos return; 4693c260e60Schristos 4703c260e60Schristos n = os_realloc_array(hcert->logo, hcert->num_logo + 1, 4713c260e60Schristos sizeof(struct http_logo)); 4723c260e60Schristos if (n == NULL) 4733c260e60Schristos return; 4743c260e60Schristos hcert->logo = n; 4753c260e60Schristos n = &hcert->logo[hcert->num_logo]; 4763c260e60Schristos os_memset(n, 0, sizeof(*n)); 4773c260e60Schristos 4783c260e60Schristos n->alg_oid = os_strdup(txt); 4793c260e60Schristos if (n->alg_oid == NULL) 4803c260e60Schristos return; 4813c260e60Schristos 4823c260e60Schristos n->hash_len = ASN1_STRING_length(hash->hashValue); 4833d6c0713Schristos n->hash = os_memdup(ASN1_STRING_get0_data(hash->hashValue), 4843d6c0713Schristos n->hash_len); 4853c260e60Schristos if (n->hash == NULL) { 4863c260e60Schristos os_free(n->alg_oid); 4873c260e60Schristos return; 4883c260e60Schristos } 4893c260e60Schristos 4903c260e60Schristos len = ASN1_STRING_length(uri); 4913c260e60Schristos n->uri = os_malloc(len + 1); 4923c260e60Schristos if (n->uri == NULL) { 4933c260e60Schristos os_free(n->alg_oid); 4943c260e60Schristos os_free(n->hash); 4953c260e60Schristos return; 4963c260e60Schristos } 4973d6c0713Schristos os_memcpy(n->uri, ASN1_STRING_get0_data(uri), len); 4983c260e60Schristos n->uri[len] = '\0'; 4993c260e60Schristos 5003c260e60Schristos hcert->num_logo++; 5013c260e60Schristos } 5023c260e60Schristos 5033c260e60Schristos 5043c260e60Schristos static void add_logo_direct(struct http_ctx *ctx, struct http_cert *hcert, 5053c260e60Schristos LogotypeData *data) 5063c260e60Schristos { 5073c260e60Schristos int i, num; 5083c260e60Schristos 5093c260e60Schristos if (data->image == NULL) 5103c260e60Schristos return; 5113c260e60Schristos 5123c260e60Schristos num = sk_LogotypeImage_num(data->image); 5133c260e60Schristos for (i = 0; i < num; i++) { 5143c260e60Schristos LogotypeImage *image; 5153c260e60Schristos LogotypeDetails *details; 5163c260e60Schristos int j, hash_num, uri_num; 5173c260e60Schristos HashAlgAndValue *found_hash = NULL; 5183c260e60Schristos 5193c260e60Schristos image = sk_LogotypeImage_value(data->image, i); 5203c260e60Schristos if (image == NULL) 5213c260e60Schristos continue; 5223c260e60Schristos 5233c260e60Schristos details = image->imageDetails; 5243c260e60Schristos if (details == NULL) 5253c260e60Schristos continue; 5263c260e60Schristos 5273c260e60Schristos hash_num = sk_HashAlgAndValue_num(details->logotypeHash); 5283c260e60Schristos for (j = 0; j < hash_num; j++) { 5293c260e60Schristos HashAlgAndValue *hash; 5303c260e60Schristos char txt[100]; 5313c260e60Schristos int res; 5323c260e60Schristos hash = sk_HashAlgAndValue_value(details->logotypeHash, 5333c260e60Schristos j); 5343c260e60Schristos if (hash == NULL) 5353c260e60Schristos continue; 5363c260e60Schristos res = OBJ_obj2txt(txt, sizeof(txt), 5373c260e60Schristos hash->hashAlg->algorithm, 1); 5383c260e60Schristos if (res < 0 || res >= (int) sizeof(txt)) 5393c260e60Schristos continue; 5403c260e60Schristos if (os_strcmp(txt, "2.16.840.1.101.3.4.2.1") == 0) { 5413c260e60Schristos found_hash = hash; 5423c260e60Schristos break; 5433c260e60Schristos } 5443c260e60Schristos } 5453c260e60Schristos 5463c260e60Schristos if (!found_hash) { 5473c260e60Schristos wpa_printf(MSG_DEBUG, "OpenSSL: No SHA256 hash found for the logo"); 5483c260e60Schristos continue; 5493c260e60Schristos } 5503c260e60Schristos 5513c260e60Schristos uri_num = sk_ASN1_IA5STRING_num(details->logotypeURI); 5523c260e60Schristos for (j = 0; j < uri_num; j++) { 5533c260e60Schristos ASN1_IA5STRING *uri; 5543c260e60Schristos uri = sk_ASN1_IA5STRING_value(details->logotypeURI, j); 5553c260e60Schristos add_logo(ctx, hcert, found_hash, uri); 5563c260e60Schristos } 5573c260e60Schristos } 5583c260e60Schristos } 5593c260e60Schristos 5603c260e60Schristos 5613c260e60Schristos static void add_logo_indirect(struct http_ctx *ctx, struct http_cert *hcert, 5623c260e60Schristos LogotypeReference *ref) 5633c260e60Schristos { 5643c260e60Schristos int j, hash_num, uri_num; 5653c260e60Schristos 5663c260e60Schristos hash_num = sk_HashAlgAndValue_num(ref->refStructHash); 5673c260e60Schristos uri_num = sk_ASN1_IA5STRING_num(ref->refStructURI); 5683c260e60Schristos if (hash_num != uri_num) { 5693c260e60Schristos wpa_printf(MSG_INFO, "Unexpected LogotypeReference array size difference %d != %d", 5703c260e60Schristos hash_num, uri_num); 5713c260e60Schristos return; 5723c260e60Schristos } 5733c260e60Schristos 5743c260e60Schristos for (j = 0; j < hash_num; j++) { 5753c260e60Schristos HashAlgAndValue *hash; 5763c260e60Schristos ASN1_IA5STRING *uri; 5773c260e60Schristos hash = sk_HashAlgAndValue_value(ref->refStructHash, j); 5783c260e60Schristos uri = sk_ASN1_IA5STRING_value(ref->refStructURI, j); 5793c260e60Schristos add_logo(ctx, hcert, hash, uri); 5803c260e60Schristos } 5813c260e60Schristos } 5823c260e60Schristos 5833c260e60Schristos 5843c260e60Schristos static void i2r_HashAlgAndValue(HashAlgAndValue *hash, BIO *out, int indent) 5853c260e60Schristos { 5863c260e60Schristos int i; 5873c260e60Schristos const unsigned char *data; 5883c260e60Schristos 5893c260e60Schristos BIO_printf(out, "%*shashAlg: ", indent, ""); 5903c260e60Schristos i2a_ASN1_OBJECT(out, hash->hashAlg->algorithm); 5913c260e60Schristos BIO_printf(out, "\n"); 5923c260e60Schristos 5933c260e60Schristos BIO_printf(out, "%*shashValue: ", indent, ""); 5943c260e60Schristos data = hash->hashValue->data; 5953c260e60Schristos for (i = 0; i < hash->hashValue->length; i++) 5963c260e60Schristos BIO_printf(out, "%s%02x", i > 0 ? ":" : "", data[i]); 5973c260e60Schristos BIO_printf(out, "\n"); 5983c260e60Schristos } 5993c260e60Schristos 6003c260e60Schristos static void i2r_LogotypeDetails(LogotypeDetails *details, BIO *out, int indent) 6013c260e60Schristos { 6023c260e60Schristos int i, num; 6033c260e60Schristos 6043c260e60Schristos BIO_printf(out, "%*sLogotypeDetails\n", indent, ""); 6053c260e60Schristos if (details->mediaType) { 6063c260e60Schristos BIO_printf(out, "%*smediaType: ", indent, ""); 6073c260e60Schristos ASN1_STRING_print(out, details->mediaType); 6083c260e60Schristos BIO_printf(out, "\n"); 6093c260e60Schristos } 6103c260e60Schristos 6113c260e60Schristos num = details->logotypeHash ? 6123c260e60Schristos sk_HashAlgAndValue_num(details->logotypeHash) : 0; 6133c260e60Schristos for (i = 0; i < num; i++) { 6143c260e60Schristos HashAlgAndValue *hash; 6153c260e60Schristos hash = sk_HashAlgAndValue_value(details->logotypeHash, i); 6163c260e60Schristos i2r_HashAlgAndValue(hash, out, indent); 6173c260e60Schristos } 6183c260e60Schristos 6193c260e60Schristos num = details->logotypeURI ? 6203c260e60Schristos sk_ASN1_IA5STRING_num(details->logotypeURI) : 0; 6213c260e60Schristos for (i = 0; i < num; i++) { 6223c260e60Schristos ASN1_IA5STRING *uri; 6233c260e60Schristos uri = sk_ASN1_IA5STRING_value(details->logotypeURI, i); 6243c260e60Schristos BIO_printf(out, "%*slogotypeURI: ", indent, ""); 6253c260e60Schristos ASN1_STRING_print(out, uri); 6263c260e60Schristos BIO_printf(out, "\n"); 6273c260e60Schristos } 6283c260e60Schristos } 6293c260e60Schristos 6303c260e60Schristos static void i2r_LogotypeImageInfo(LogotypeImageInfo *info, BIO *out, int indent) 6313c260e60Schristos { 6323c260e60Schristos long val; 6333c260e60Schristos 6343c260e60Schristos BIO_printf(out, "%*sLogotypeImageInfo\n", indent, ""); 6353c260e60Schristos if (info->type) { 6363c260e60Schristos val = ASN1_INTEGER_get(info->type); 6373c260e60Schristos BIO_printf(out, "%*stype: %ld\n", indent, "", val); 6383c260e60Schristos } else { 6393c260e60Schristos BIO_printf(out, "%*stype: default (1)\n", indent, ""); 6403c260e60Schristos } 64136ebd06eSchristos val = ASN1_INTEGER_get(info->fileSize); 64236ebd06eSchristos BIO_printf(out, "%*sfileSize: %ld\n", indent, "", val); 6433c260e60Schristos val = ASN1_INTEGER_get(info->xSize); 6443c260e60Schristos BIO_printf(out, "%*sxSize: %ld\n", indent, "", val); 6453c260e60Schristos val = ASN1_INTEGER_get(info->ySize); 6463c260e60Schristos BIO_printf(out, "%*sySize: %ld\n", indent, "", val); 6473c260e60Schristos if (info->resolution) { 64836ebd06eSchristos BIO_printf(out, "%*sresolution [%d]\n", indent, "", 64936ebd06eSchristos info->resolution->type); 65036ebd06eSchristos switch (info->resolution->type) { 65136ebd06eSchristos case 0: 65236ebd06eSchristos val = ASN1_INTEGER_get(info->resolution->d.numBits); 65336ebd06eSchristos BIO_printf(out, "%*snumBits: %ld\n", indent, "", val); 65436ebd06eSchristos break; 65536ebd06eSchristos case 1: 65636ebd06eSchristos val = ASN1_INTEGER_get(info->resolution->d.tableSize); 65736ebd06eSchristos BIO_printf(out, "%*stableSize: %ld\n", indent, "", val); 65836ebd06eSchristos break; 65936ebd06eSchristos } 6603c260e60Schristos } 6613c260e60Schristos if (info->language) { 6623c260e60Schristos BIO_printf(out, "%*slanguage: ", indent, ""); 6633c260e60Schristos ASN1_STRING_print(out, info->language); 6643c260e60Schristos BIO_printf(out, "\n"); 6653c260e60Schristos } 6663c260e60Schristos } 6673c260e60Schristos 6683c260e60Schristos static void i2r_LogotypeImage(LogotypeImage *image, BIO *out, int indent) 6693c260e60Schristos { 6703c260e60Schristos BIO_printf(out, "%*sLogotypeImage\n", indent, ""); 6713c260e60Schristos if (image->imageDetails) { 6723c260e60Schristos i2r_LogotypeDetails(image->imageDetails, out, indent + 4); 6733c260e60Schristos } 6743c260e60Schristos if (image->imageInfo) { 6753c260e60Schristos i2r_LogotypeImageInfo(image->imageInfo, out, indent + 4); 6763c260e60Schristos } 6773c260e60Schristos } 6783c260e60Schristos 6793c260e60Schristos static void i2r_LogotypeData(LogotypeData *data, const char *title, BIO *out, 6803c260e60Schristos int indent) 6813c260e60Schristos { 6823c260e60Schristos int i, num; 6833c260e60Schristos 6843c260e60Schristos BIO_printf(out, "%*s%s - LogotypeData\n", indent, "", title); 6853c260e60Schristos 6863c260e60Schristos num = data->image ? sk_LogotypeImage_num(data->image) : 0; 6873c260e60Schristos for (i = 0; i < num; i++) { 6883c260e60Schristos LogotypeImage *image = sk_LogotypeImage_value(data->image, i); 6893c260e60Schristos i2r_LogotypeImage(image, out, indent + 4); 6903c260e60Schristos } 6913c260e60Schristos 6923c260e60Schristos num = data->audio ? sk_LogotypeAudio_num(data->audio) : 0; 6933c260e60Schristos for (i = 0; i < num; i++) { 6943c260e60Schristos BIO_printf(out, "%*saudio: TODO\n", indent, ""); 6953c260e60Schristos } 6963c260e60Schristos } 6973c260e60Schristos 6983c260e60Schristos static void i2r_LogotypeReference(LogotypeReference *ref, const char *title, 6993c260e60Schristos BIO *out, int indent) 7003c260e60Schristos { 7013c260e60Schristos int i, hash_num, uri_num; 7023c260e60Schristos 7033c260e60Schristos BIO_printf(out, "%*s%s - LogotypeReference\n", indent, "", title); 7043c260e60Schristos 7053c260e60Schristos hash_num = ref->refStructHash ? 7063c260e60Schristos sk_HashAlgAndValue_num(ref->refStructHash) : 0; 7073c260e60Schristos uri_num = ref->refStructURI ? 7083c260e60Schristos sk_ASN1_IA5STRING_num(ref->refStructURI) : 0; 7093c260e60Schristos if (hash_num != uri_num) { 7103c260e60Schristos BIO_printf(out, "%*sUnexpected LogotypeReference array size difference %d != %d\n", 7113c260e60Schristos indent, "", hash_num, uri_num); 7123c260e60Schristos return; 7133c260e60Schristos } 7143c260e60Schristos 7153c260e60Schristos for (i = 0; i < hash_num; i++) { 7163c260e60Schristos HashAlgAndValue *hash; 7173c260e60Schristos ASN1_IA5STRING *uri; 7183c260e60Schristos 7193c260e60Schristos hash = sk_HashAlgAndValue_value(ref->refStructHash, i); 7203c260e60Schristos i2r_HashAlgAndValue(hash, out, indent); 7213c260e60Schristos 7223c260e60Schristos uri = sk_ASN1_IA5STRING_value(ref->refStructURI, i); 7233c260e60Schristos BIO_printf(out, "%*srefStructURI: ", indent, ""); 7243c260e60Schristos ASN1_STRING_print(out, uri); 7253c260e60Schristos BIO_printf(out, "\n"); 7263c260e60Schristos } 7273c260e60Schristos } 7283c260e60Schristos 7293c260e60Schristos static void i2r_LogotypeInfo(LogotypeInfo *info, const char *title, BIO *out, 7303c260e60Schristos int indent) 7313c260e60Schristos { 7323c260e60Schristos switch (info->type) { 7333c260e60Schristos case 0: 7343c260e60Schristos i2r_LogotypeData(info->d.direct, title, out, indent); 7353c260e60Schristos break; 7363c260e60Schristos case 1: 7373c260e60Schristos i2r_LogotypeReference(info->d.indirect, title, out, indent); 7383c260e60Schristos break; 7393c260e60Schristos } 7403c260e60Schristos } 7413c260e60Schristos 7423c260e60Schristos static void debug_print_logotypeext(LogotypeExtn *logo) 7433c260e60Schristos { 7443c260e60Schristos BIO *out; 7453c260e60Schristos int i, num; 7463c260e60Schristos int indent = 0; 7473c260e60Schristos 7483c260e60Schristos out = BIO_new_fp(stdout, BIO_NOCLOSE); 7493c260e60Schristos if (out == NULL) 7503c260e60Schristos return; 7513c260e60Schristos 7523c260e60Schristos if (logo->communityLogos) { 7533c260e60Schristos num = sk_LogotypeInfo_num(logo->communityLogos); 7543c260e60Schristos for (i = 0; i < num; i++) { 7553c260e60Schristos LogotypeInfo *info; 7563c260e60Schristos info = sk_LogotypeInfo_value(logo->communityLogos, i); 7573c260e60Schristos i2r_LogotypeInfo(info, "communityLogo", out, indent); 7583c260e60Schristos } 7593c260e60Schristos } 7603c260e60Schristos 7613c260e60Schristos if (logo->issuerLogo) { 7623c260e60Schristos i2r_LogotypeInfo(logo->issuerLogo, "issuerLogo", out, indent ); 7633c260e60Schristos } 7643c260e60Schristos 7653c260e60Schristos if (logo->subjectLogo) { 7663c260e60Schristos i2r_LogotypeInfo(logo->subjectLogo, "subjectLogo", out, indent); 7673c260e60Schristos } 7683c260e60Schristos 7693c260e60Schristos if (logo->otherLogos) { 7703c260e60Schristos BIO_printf(out, "%*sotherLogos - TODO\n", indent, ""); 7713c260e60Schristos } 7723c260e60Schristos 7733c260e60Schristos BIO_free(out); 7743c260e60Schristos } 7753c260e60Schristos 7763c260e60Schristos 7773c260e60Schristos static void add_logotype_ext(struct http_ctx *ctx, struct http_cert *hcert, 7783c260e60Schristos X509 *cert) 7793c260e60Schristos { 7803c260e60Schristos ASN1_OBJECT *obj; 7813c260e60Schristos int pos; 7823c260e60Schristos X509_EXTENSION *ext; 7833c260e60Schristos ASN1_OCTET_STRING *os; 7843c260e60Schristos LogotypeExtn *logo; 7853c260e60Schristos const unsigned char *data; 7863c260e60Schristos int i, num; 7873c260e60Schristos 7883c260e60Schristos obj = OBJ_txt2obj("1.3.6.1.5.5.7.1.12", 0); 7893c260e60Schristos if (obj == NULL) 7903c260e60Schristos return; 7913c260e60Schristos 7923c260e60Schristos pos = X509_get_ext_by_OBJ(cert, obj, -1); 7933c260e60Schristos if (pos < 0) { 7943c260e60Schristos wpa_printf(MSG_INFO, "No logotype extension included"); 7953c260e60Schristos return; 7963c260e60Schristos } 7973c260e60Schristos 7983c260e60Schristos wpa_printf(MSG_INFO, "Parsing logotype extension"); 7993c260e60Schristos ext = X509_get_ext(cert, pos); 8003c260e60Schristos if (!ext) { 8013c260e60Schristos wpa_printf(MSG_INFO, "Could not get logotype extension"); 8023c260e60Schristos return; 8033c260e60Schristos } 8043c260e60Schristos 8053c260e60Schristos os = X509_EXTENSION_get_data(ext); 8063c260e60Schristos if (os == NULL) { 8073c260e60Schristos wpa_printf(MSG_INFO, "Could not get logotype extension data"); 8083c260e60Schristos return; 8093c260e60Schristos } 8103c260e60Schristos 8113c260e60Schristos wpa_hexdump(MSG_DEBUG, "logotypeExtn", 8123d6c0713Schristos ASN1_STRING_get0_data(os), ASN1_STRING_length(os)); 8133c260e60Schristos 8143d6c0713Schristos data = ASN1_STRING_get0_data(os); 8153c260e60Schristos logo = d2i_LogotypeExtn(NULL, &data, ASN1_STRING_length(os)); 8163c260e60Schristos if (logo == NULL) { 8173c260e60Schristos wpa_printf(MSG_INFO, "Failed to parse logotypeExtn"); 8183c260e60Schristos return; 8193c260e60Schristos } 8203c260e60Schristos 8213c260e60Schristos if (wpa_debug_level < MSG_INFO) 8223c260e60Schristos debug_print_logotypeext(logo); 8233c260e60Schristos 8243c260e60Schristos if (!logo->communityLogos) { 8253c260e60Schristos wpa_printf(MSG_INFO, "No communityLogos included"); 8263c260e60Schristos LogotypeExtn_free(logo); 8273c260e60Schristos return; 8283c260e60Schristos } 8293c260e60Schristos 8303c260e60Schristos num = sk_LogotypeInfo_num(logo->communityLogos); 8313c260e60Schristos for (i = 0; i < num; i++) { 8323c260e60Schristos LogotypeInfo *info; 8333c260e60Schristos info = sk_LogotypeInfo_value(logo->communityLogos, i); 8343c260e60Schristos switch (info->type) { 8353c260e60Schristos case 0: 8363c260e60Schristos add_logo_direct(ctx, hcert, info->d.direct); 8373c260e60Schristos break; 8383c260e60Schristos case 1: 8393c260e60Schristos add_logo_indirect(ctx, hcert, info->d.indirect); 8403c260e60Schristos break; 8413c260e60Schristos } 8423c260e60Schristos } 8433c260e60Schristos 8443c260e60Schristos LogotypeExtn_free(logo); 8453c260e60Schristos } 8463c260e60Schristos 8473c260e60Schristos 8483c260e60Schristos static void parse_cert(struct http_ctx *ctx, struct http_cert *hcert, 8493c260e60Schristos X509 *cert, GENERAL_NAMES **names) 8503c260e60Schristos { 8513c260e60Schristos os_memset(hcert, 0, sizeof(*hcert)); 852*bb618362Schristos hcert->url = ctx->url ? ctx->url : ctx->svc_address; 8533c260e60Schristos 8543c260e60Schristos *names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); 8553c260e60Schristos if (*names) 8563c260e60Schristos add_alt_names(ctx, hcert, *names); 8573c260e60Schristos 8583c260e60Schristos add_logotype_ext(ctx, hcert, cert); 8593c260e60Schristos } 8603c260e60Schristos 8613c260e60Schristos 8623c260e60Schristos static void parse_cert_free(struct http_cert *hcert, GENERAL_NAMES *names) 8633c260e60Schristos { 8643c260e60Schristos unsigned int i; 8653c260e60Schristos 8663c260e60Schristos for (i = 0; i < hcert->num_dnsname; i++) 8673c260e60Schristos OPENSSL_free(hcert->dnsname[i]); 8683c260e60Schristos os_free(hcert->dnsname); 8693c260e60Schristos 8703c260e60Schristos for (i = 0; i < hcert->num_othername; i++) 8713c260e60Schristos os_free(hcert->othername[i].oid); 8723c260e60Schristos os_free(hcert->othername); 8733c260e60Schristos 8743c260e60Schristos for (i = 0; i < hcert->num_logo; i++) { 8753c260e60Schristos os_free(hcert->logo[i].alg_oid); 8763c260e60Schristos os_free(hcert->logo[i].hash); 8773c260e60Schristos os_free(hcert->logo[i].uri); 8783c260e60Schristos } 8793c260e60Schristos os_free(hcert->logo); 8803c260e60Schristos 8813c260e60Schristos sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); 8823c260e60Schristos } 8833c260e60Schristos 8843c260e60Schristos 8853c260e60Schristos static int validate_server_cert(struct http_ctx *ctx, X509 *cert) 8863c260e60Schristos { 8873c260e60Schristos GENERAL_NAMES *names; 8883c260e60Schristos struct http_cert hcert; 8893c260e60Schristos int ret; 8903c260e60Schristos 89136ebd06eSchristos if (ctx->cert_cb == NULL) { 89236ebd06eSchristos wpa_printf(MSG_DEBUG, "%s: no cert_cb configured", __func__); 8933c260e60Schristos return 0; 89436ebd06eSchristos } 8953c260e60Schristos 8963c260e60Schristos if (0) { 8973c260e60Schristos BIO *out; 8983c260e60Schristos out = BIO_new_fp(stdout, BIO_NOCLOSE); 8993c260e60Schristos X509_print_ex(out, cert, XN_FLAG_COMPAT, X509_FLAG_COMPAT); 9003c260e60Schristos BIO_free(out); 9013c260e60Schristos } 9023c260e60Schristos 9033c260e60Schristos parse_cert(ctx, &hcert, cert, &names); 9043c260e60Schristos ret = ctx->cert_cb(ctx->cert_cb_ctx, &hcert); 9053c260e60Schristos parse_cert_free(&hcert, names); 9063c260e60Schristos 9073c260e60Schristos return ret; 9083c260e60Schristos } 9093c260e60Schristos 9103c260e60Schristos 9113c260e60Schristos void http_parse_x509_certificate(struct http_ctx *ctx, const char *fname) 9123c260e60Schristos { 9133c260e60Schristos BIO *in, *out; 9143c260e60Schristos X509 *cert; 9153c260e60Schristos GENERAL_NAMES *names; 9163c260e60Schristos struct http_cert hcert; 9173c260e60Schristos unsigned int i; 9183c260e60Schristos 9193c260e60Schristos in = BIO_new_file(fname, "r"); 9203c260e60Schristos if (in == NULL) { 9213c260e60Schristos wpa_printf(MSG_ERROR, "Could not read '%s'", fname); 9223c260e60Schristos return; 9233c260e60Schristos } 9243c260e60Schristos 9253c260e60Schristos cert = d2i_X509_bio(in, NULL); 9263c260e60Schristos BIO_free(in); 9273c260e60Schristos 9283c260e60Schristos if (cert == NULL) { 9293c260e60Schristos wpa_printf(MSG_ERROR, "Could not parse certificate"); 9303c260e60Schristos return; 9313c260e60Schristos } 9323c260e60Schristos 9333c260e60Schristos out = BIO_new_fp(stdout, BIO_NOCLOSE); 9343c260e60Schristos if (out) { 9353c260e60Schristos X509_print_ex(out, cert, XN_FLAG_COMPAT, 9363c260e60Schristos X509_FLAG_COMPAT); 9373c260e60Schristos BIO_free(out); 9383c260e60Schristos } 9393c260e60Schristos 9403c260e60Schristos wpa_printf(MSG_INFO, "Additional parsing information:"); 9413c260e60Schristos parse_cert(ctx, &hcert, cert, &names); 9423c260e60Schristos for (i = 0; i < hcert.num_othername; i++) { 9433c260e60Schristos if (os_strcmp(hcert.othername[i].oid, 9443c260e60Schristos "1.3.6.1.4.1.40808.1.1.1") == 0) { 9453c260e60Schristos char *name = os_zalloc(hcert.othername[i].len + 1); 9463c260e60Schristos if (name) { 9473c260e60Schristos os_memcpy(name, hcert.othername[i].data, 9483c260e60Schristos hcert.othername[i].len); 9493c260e60Schristos wpa_printf(MSG_INFO, 9503c260e60Schristos "id-wfa-hotspot-friendlyName: %s", 9513c260e60Schristos name); 9523c260e60Schristos os_free(name); 9533c260e60Schristos } 9543c260e60Schristos wpa_hexdump_ascii(MSG_INFO, 9553c260e60Schristos "id-wfa-hotspot-friendlyName", 9563c260e60Schristos hcert.othername[i].data, 9573c260e60Schristos hcert.othername[i].len); 9583c260e60Schristos } else { 9593c260e60Schristos wpa_printf(MSG_INFO, "subjAltName[othername]: oid=%s", 9603c260e60Schristos hcert.othername[i].oid); 9613c260e60Schristos wpa_hexdump_ascii(MSG_INFO, "unknown othername", 9623c260e60Schristos hcert.othername[i].data, 9633c260e60Schristos hcert.othername[i].len); 9643c260e60Schristos } 9653c260e60Schristos } 9663c260e60Schristos parse_cert_free(&hcert, names); 9673c260e60Schristos 9683c260e60Schristos X509_free(cert); 9693c260e60Schristos } 9703c260e60Schristos 9713c260e60Schristos 9723c260e60Schristos static int curl_cb_ssl_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) 9733c260e60Schristos { 9743c260e60Schristos struct http_ctx *ctx; 9753c260e60Schristos X509 *cert; 9763c260e60Schristos int err, depth; 9773c260e60Schristos char buf[256]; 9783c260e60Schristos X509_NAME *name; 9793c260e60Schristos const char *err_str; 9803c260e60Schristos SSL *ssl; 9813c260e60Schristos SSL_CTX *ssl_ctx; 9823c260e60Schristos 9833c260e60Schristos ssl = X509_STORE_CTX_get_ex_data(x509_ctx, 9843c260e60Schristos SSL_get_ex_data_X509_STORE_CTX_idx()); 9850a73ee0aSchristos ssl_ctx = SSL_get_SSL_CTX(ssl); 9863c260e60Schristos ctx = SSL_CTX_get_app_data(ssl_ctx); 9873c260e60Schristos 98836ebd06eSchristos wpa_printf(MSG_DEBUG, "curl_cb_ssl_verify, preverify_ok: %d", 98936ebd06eSchristos preverify_ok); 9903c260e60Schristos 9913c260e60Schristos err = X509_STORE_CTX_get_error(x509_ctx); 9923c260e60Schristos err_str = X509_verify_cert_error_string(err); 9933c260e60Schristos depth = X509_STORE_CTX_get_error_depth(x509_ctx); 9943c260e60Schristos cert = X509_STORE_CTX_get_current_cert(x509_ctx); 9953c260e60Schristos if (!cert) { 9963c260e60Schristos wpa_printf(MSG_INFO, "No server certificate available"); 9973c260e60Schristos ctx->last_err = "No server certificate available"; 9983c260e60Schristos return 0; 9993c260e60Schristos } 10003c260e60Schristos 10013c260e60Schristos if (depth == 0) 10023c260e60Schristos ctx->peer_cert = cert; 10033c260e60Schristos else if (depth == 1) 10043c260e60Schristos ctx->peer_issuer = cert; 10053c260e60Schristos else if (depth == 2) 10063c260e60Schristos ctx->peer_issuer_issuer = cert; 10073c260e60Schristos 10083c260e60Schristos name = X509_get_subject_name(cert); 10093c260e60Schristos X509_NAME_oneline(name, buf, sizeof(buf)); 10103c260e60Schristos wpa_printf(MSG_INFO, "Server certificate chain - depth=%d err=%d (%s) subject=%s", 10113c260e60Schristos depth, err, err_str, buf); 10123c260e60Schristos debug_dump_cert("Server certificate chain - certificate", cert); 10133c260e60Schristos 10143c260e60Schristos if (depth == 0 && preverify_ok && validate_server_cert(ctx, cert) < 0) 10153c260e60Schristos return 0; 10163c260e60Schristos 101736ebd06eSchristos #ifdef OPENSSL_IS_BORINGSSL 101836ebd06eSchristos if (depth == 0 && ctx->ocsp != NO_OCSP && preverify_ok) { 101936ebd06eSchristos enum ocsp_result res; 102036ebd06eSchristos 102136ebd06eSchristos res = check_ocsp_resp(ssl_ctx, ssl, cert, ctx->peer_issuer, 102236ebd06eSchristos ctx->peer_issuer_issuer); 102336ebd06eSchristos if (res == OCSP_REVOKED) { 102436ebd06eSchristos preverify_ok = 0; 102536ebd06eSchristos wpa_printf(MSG_INFO, "OCSP: certificate revoked"); 102636ebd06eSchristos if (err == X509_V_OK) 102736ebd06eSchristos X509_STORE_CTX_set_error( 102836ebd06eSchristos x509_ctx, X509_V_ERR_CERT_REVOKED); 102936ebd06eSchristos } else if (res != OCSP_GOOD && (ctx->ocsp == MANDATORY_OCSP)) { 103036ebd06eSchristos preverify_ok = 0; 103136ebd06eSchristos wpa_printf(MSG_INFO, 103236ebd06eSchristos "OCSP: bad certificate status response"); 103336ebd06eSchristos } 103436ebd06eSchristos } 103536ebd06eSchristos #endif /* OPENSSL_IS_BORINGSSL */ 103636ebd06eSchristos 10373c260e60Schristos if (!preverify_ok) 10383c260e60Schristos ctx->last_err = "TLS validation failed"; 10393c260e60Schristos 10403c260e60Schristos return preverify_ok; 10413c260e60Schristos } 10423c260e60Schristos 10433c260e60Schristos 10443c260e60Schristos #ifdef HAVE_OCSP 10453c260e60Schristos 10463c260e60Schristos static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp) 10473c260e60Schristos { 10483c260e60Schristos BIO *out; 10493c260e60Schristos size_t rlen; 10503c260e60Schristos char *txt; 10513c260e60Schristos int res; 10523c260e60Schristos 10533c260e60Schristos out = BIO_new(BIO_s_mem()); 10543c260e60Schristos if (!out) 10553c260e60Schristos return; 10563c260e60Schristos 10573c260e60Schristos OCSP_RESPONSE_print(out, rsp, 0); 10583c260e60Schristos rlen = BIO_ctrl_pending(out); 10593c260e60Schristos txt = os_malloc(rlen + 1); 10603c260e60Schristos if (!txt) { 10613c260e60Schristos BIO_free(out); 10623c260e60Schristos return; 10633c260e60Schristos } 10643c260e60Schristos 10653c260e60Schristos res = BIO_read(out, txt, rlen); 10663c260e60Schristos if (res > 0) { 10673c260e60Schristos txt[res] = '\0'; 10683c260e60Schristos wpa_printf(MSG_MSGDUMP, "OpenSSL: OCSP Response\n%s", txt); 10693c260e60Schristos } 10703c260e60Schristos os_free(txt); 10713c260e60Schristos BIO_free(out); 10723c260e60Schristos } 10733c260e60Schristos 10743c260e60Schristos 10753c260e60Schristos static void tls_show_errors(const char *func, const char *txt) 10763c260e60Schristos { 10773c260e60Schristos unsigned long err; 10783c260e60Schristos 10793c260e60Schristos wpa_printf(MSG_DEBUG, "OpenSSL: %s - %s %s", 10803c260e60Schristos func, txt, ERR_error_string(ERR_get_error(), NULL)); 10813c260e60Schristos 10823c260e60Schristos while ((err = ERR_get_error())) { 10833c260e60Schristos wpa_printf(MSG_DEBUG, "OpenSSL: pending error: %s", 10843c260e60Schristos ERR_error_string(err, NULL)); 10853c260e60Schristos } 10863c260e60Schristos } 10873c260e60Schristos 10883c260e60Schristos 10893c260e60Schristos static int ocsp_resp_cb(SSL *s, void *arg) 10903c260e60Schristos { 10913c260e60Schristos struct http_ctx *ctx = arg; 10923c260e60Schristos const unsigned char *p; 10930a73ee0aSchristos int len, status, reason, res; 10943c260e60Schristos OCSP_RESPONSE *rsp; 10953c260e60Schristos OCSP_BASICRESP *basic; 10963c260e60Schristos OCSP_CERTID *id; 10973c260e60Schristos ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update; 10983c260e60Schristos X509_STORE *store; 10993c260e60Schristos STACK_OF(X509) *certs = NULL; 11003c260e60Schristos 11013c260e60Schristos len = SSL_get_tlsext_status_ocsp_resp(s, &p); 11023c260e60Schristos if (!p) { 11033c260e60Schristos wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received"); 11043c260e60Schristos if (ctx->ocsp == MANDATORY_OCSP) 11053c260e60Schristos ctx->last_err = "No OCSP response received"; 11063c260e60Schristos return (ctx->ocsp == MANDATORY_OCSP) ? 0 : 1; 11073c260e60Schristos } 11083c260e60Schristos 11093c260e60Schristos wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len); 11103c260e60Schristos 11113c260e60Schristos rsp = d2i_OCSP_RESPONSE(NULL, &p, len); 11123c260e60Schristos if (!rsp) { 11133c260e60Schristos wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response"); 11143c260e60Schristos ctx->last_err = "Failed to parse OCSP response"; 11153c260e60Schristos return 0; 11163c260e60Schristos } 11173c260e60Schristos 11183c260e60Schristos ocsp_debug_print_resp(rsp); 11193c260e60Schristos 11203c260e60Schristos status = OCSP_response_status(rsp); 11213c260e60Schristos if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { 11223c260e60Schristos wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)", 11233c260e60Schristos status, OCSP_response_status_str(status)); 11243c260e60Schristos ctx->last_err = "OCSP responder error"; 11253c260e60Schristos return 0; 11263c260e60Schristos } 11273c260e60Schristos 11283c260e60Schristos basic = OCSP_response_get1_basic(rsp); 11293c260e60Schristos if (!basic) { 11303c260e60Schristos wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse"); 11313c260e60Schristos ctx->last_err = "Could not find BasicOCSPResponse"; 11323c260e60Schristos return 0; 11333c260e60Schristos } 11343c260e60Schristos 11353d6c0713Schristos store = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(s)); 11363c260e60Schristos if (ctx->peer_issuer) { 11373c260e60Schristos wpa_printf(MSG_DEBUG, "OpenSSL: Add issuer"); 11383c260e60Schristos debug_dump_cert("OpenSSL: Issuer certificate", 11393c260e60Schristos ctx->peer_issuer); 11403c260e60Schristos 11413c260e60Schristos if (X509_STORE_add_cert(store, ctx->peer_issuer) != 1) { 11423c260e60Schristos tls_show_errors(__func__, 1143bb610346Schristos "OpenSSL: Could not add issuer to certificate store"); 11443c260e60Schristos } 11453c260e60Schristos certs = sk_X509_new_null(); 11463c260e60Schristos if (certs) { 11473c260e60Schristos X509 *cert; 11483c260e60Schristos cert = X509_dup(ctx->peer_issuer); 11493c260e60Schristos if (cert && !sk_X509_push(certs, cert)) { 11503c260e60Schristos tls_show_errors( 11513c260e60Schristos __func__, 1152bb610346Schristos "OpenSSL: Could not add issuer to OCSP responder trust store"); 11533c260e60Schristos X509_free(cert); 11543c260e60Schristos sk_X509_free(certs); 11553c260e60Schristos certs = NULL; 11563c260e60Schristos } 1157bb610346Schristos if (certs && ctx->peer_issuer_issuer) { 11583c260e60Schristos cert = X509_dup(ctx->peer_issuer_issuer); 11593c260e60Schristos if (cert && !sk_X509_push(certs, cert)) { 11603c260e60Schristos tls_show_errors( 11613c260e60Schristos __func__, 1162bb610346Schristos "OpenSSL: Could not add issuer's issuer to OCSP responder trust store"); 11633c260e60Schristos X509_free(cert); 11643c260e60Schristos } 11653c260e60Schristos } 11663c260e60Schristos } 11673c260e60Schristos } 11683c260e60Schristos 11693c260e60Schristos status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER); 11703c260e60Schristos sk_X509_pop_free(certs, X509_free); 11713c260e60Schristos if (status <= 0) { 11723c260e60Schristos tls_show_errors(__func__, 11733c260e60Schristos "OpenSSL: OCSP response failed verification"); 11743c260e60Schristos OCSP_BASICRESP_free(basic); 11753c260e60Schristos OCSP_RESPONSE_free(rsp); 11763c260e60Schristos ctx->last_err = "OCSP response failed verification"; 11773c260e60Schristos return 0; 11783c260e60Schristos } 11793c260e60Schristos 11803c260e60Schristos wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded"); 11813c260e60Schristos 11823c260e60Schristos if (!ctx->peer_cert) { 11833c260e60Schristos wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check"); 11843c260e60Schristos OCSP_BASICRESP_free(basic); 11853c260e60Schristos OCSP_RESPONSE_free(rsp); 11863c260e60Schristos ctx->last_err = "Peer certificate not available for OCSP status check"; 11873c260e60Schristos return 0; 11883c260e60Schristos } 11893c260e60Schristos 11903c260e60Schristos if (!ctx->peer_issuer) { 11913c260e60Schristos wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check"); 11923c260e60Schristos OCSP_BASICRESP_free(basic); 11933c260e60Schristos OCSP_RESPONSE_free(rsp); 11943c260e60Schristos ctx->last_err = "Peer issuer certificate not available for OCSP status check"; 11953c260e60Schristos return 0; 11963c260e60Schristos } 11973c260e60Schristos 11980a73ee0aSchristos id = OCSP_cert_to_id(EVP_sha256(), ctx->peer_cert, ctx->peer_issuer); 11993c260e60Schristos if (!id) { 12000a73ee0aSchristos wpa_printf(MSG_DEBUG, 12010a73ee0aSchristos "OpenSSL: Could not create OCSP certificate identifier (SHA256)"); 12023c260e60Schristos OCSP_BASICRESP_free(basic); 12033c260e60Schristos OCSP_RESPONSE_free(rsp); 12043c260e60Schristos ctx->last_err = "Could not create OCSP certificate identifier"; 12053c260e60Schristos return 0; 12063c260e60Schristos } 12073c260e60Schristos 12080a73ee0aSchristos res = OCSP_resp_find_status(basic, id, &status, &reason, &produced_at, 12090a73ee0aSchristos &this_update, &next_update); 12100a73ee0aSchristos if (!res) { 12110a73ee0aSchristos id = OCSP_cert_to_id(NULL, ctx->peer_cert, ctx->peer_issuer); 12120a73ee0aSchristos if (!id) { 12130a73ee0aSchristos wpa_printf(MSG_DEBUG, 12140a73ee0aSchristos "OpenSSL: Could not create OCSP certificate identifier (SHA1)"); 12150a73ee0aSchristos OCSP_BASICRESP_free(basic); 12160a73ee0aSchristos OCSP_RESPONSE_free(rsp); 12170a73ee0aSchristos ctx->last_err = 12180a73ee0aSchristos "Could not create OCSP certificate identifier"; 12190a73ee0aSchristos return 0; 12200a73ee0aSchristos } 12210a73ee0aSchristos 12220a73ee0aSchristos res = OCSP_resp_find_status(basic, id, &status, &reason, 12230a73ee0aSchristos &produced_at, &this_update, 12240a73ee0aSchristos &next_update); 12250a73ee0aSchristos } 12260a73ee0aSchristos 12270a73ee0aSchristos if (!res) { 12283c260e60Schristos wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s", 12293c260e60Schristos (ctx->ocsp == MANDATORY_OCSP) ? "" : 12303c260e60Schristos " (OCSP not required)"); 123136ebd06eSchristos OCSP_CERTID_free(id); 12323c260e60Schristos OCSP_BASICRESP_free(basic); 12333c260e60Schristos OCSP_RESPONSE_free(rsp); 12343c260e60Schristos if (ctx->ocsp == MANDATORY_OCSP) 12353c260e60Schristos 12363c260e60Schristos ctx->last_err = "Could not find current server certificate from OCSP response"; 12373c260e60Schristos return (ctx->ocsp == MANDATORY_OCSP) ? 0 : 1; 12383c260e60Schristos } 123936ebd06eSchristos OCSP_CERTID_free(id); 12403c260e60Schristos 12413c260e60Schristos if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) { 12423c260e60Schristos tls_show_errors(__func__, "OpenSSL: OCSP status times invalid"); 12433c260e60Schristos OCSP_BASICRESP_free(basic); 12443c260e60Schristos OCSP_RESPONSE_free(rsp); 12453c260e60Schristos ctx->last_err = "OCSP status times invalid"; 12463c260e60Schristos return 0; 12473c260e60Schristos } 12483c260e60Schristos 12493c260e60Schristos OCSP_BASICRESP_free(basic); 12503c260e60Schristos OCSP_RESPONSE_free(rsp); 12513c260e60Schristos 12523c260e60Schristos wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s", 12533c260e60Schristos OCSP_cert_status_str(status)); 12543c260e60Schristos 12553c260e60Schristos if (status == V_OCSP_CERTSTATUS_GOOD) 12563c260e60Schristos return 1; 12573c260e60Schristos if (status == V_OCSP_CERTSTATUS_REVOKED) { 12583c260e60Schristos ctx->last_err = "Server certificate has been revoked"; 12593c260e60Schristos return 0; 12603c260e60Schristos } 12613c260e60Schristos if (ctx->ocsp == MANDATORY_OCSP) { 12623c260e60Schristos wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required"); 12633c260e60Schristos ctx->last_err = "OCSP status unknown"; 12643c260e60Schristos return 0; 12653c260e60Schristos } 12663c260e60Schristos wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue"); 12673c260e60Schristos return 1; 12683c260e60Schristos } 12693c260e60Schristos 12703c260e60Schristos 12713d6c0713Schristos #if OPENSSL_VERSION_NUMBER < 0x10100000L 12723c260e60Schristos static SSL_METHOD patch_ssl_method; 12733c260e60Schristos static const SSL_METHOD *real_ssl_method; 12743c260e60Schristos 12753c260e60Schristos static int curl_patch_ssl_new(SSL *s) 12763c260e60Schristos { 12773d6c0713Schristos SSL_CTX *ssl = SSL_get_SSL_CTX(s); 12783c260e60Schristos int ret; 12793c260e60Schristos 12803c260e60Schristos ssl->method = real_ssl_method; 12813c260e60Schristos s->method = real_ssl_method; 12823c260e60Schristos 12833c260e60Schristos ret = s->method->ssl_new(s); 12843c260e60Schristos SSL_set_tlsext_status_type(s, TLSEXT_STATUSTYPE_ocsp); 12853c260e60Schristos 12863c260e60Schristos return ret; 12873c260e60Schristos } 12883d6c0713Schristos #endif /* OpenSSL < 1.1.0 */ 12893c260e60Schristos 12903c260e60Schristos #endif /* HAVE_OCSP */ 12913c260e60Schristos 12923c260e60Schristos 12933c260e60Schristos static CURLcode curl_cb_ssl(CURL *curl, void *sslctx, void *parm) 12943c260e60Schristos { 12953c260e60Schristos struct http_ctx *ctx = parm; 12963c260e60Schristos SSL_CTX *ssl = sslctx; 12973c260e60Schristos 12983c260e60Schristos wpa_printf(MSG_DEBUG, "curl_cb_ssl"); 12993c260e60Schristos SSL_CTX_set_app_data(ssl, ctx); 13003c260e60Schristos SSL_CTX_set_verify(ssl, SSL_VERIFY_PEER, curl_cb_ssl_verify); 13013c260e60Schristos 13023c260e60Schristos #ifdef HAVE_OCSP 13033c260e60Schristos if (ctx->ocsp != NO_OCSP) { 13043c260e60Schristos SSL_CTX_set_tlsext_status_cb(ssl, ocsp_resp_cb); 13053c260e60Schristos SSL_CTX_set_tlsext_status_arg(ssl, ctx); 13063c260e60Schristos 13073d6c0713Schristos #if OPENSSL_VERSION_NUMBER < 0x10100000L 13083c260e60Schristos /* 13093c260e60Schristos * Use a temporary SSL_METHOD to get a callback on SSL_new() 13103c260e60Schristos * from libcurl since there is no proper callback registration 13113c260e60Schristos * available for this. 13123c260e60Schristos */ 13133c260e60Schristos os_memset(&patch_ssl_method, 0, sizeof(patch_ssl_method)); 13143c260e60Schristos patch_ssl_method.ssl_new = curl_patch_ssl_new; 13153c260e60Schristos real_ssl_method = ssl->method; 13163c260e60Schristos ssl->method = &patch_ssl_method; 13173d6c0713Schristos #endif /* OpenSSL < 1.1.0 */ 13183c260e60Schristos } 13193c260e60Schristos #endif /* HAVE_OCSP */ 13203c260e60Schristos 13213c260e60Schristos return CURLE_OK; 13223c260e60Schristos } 13233c260e60Schristos 13243c260e60Schristos #endif /* EAP_TLS_OPENSSL */ 13253c260e60Schristos 13263c260e60Schristos 13273c260e60Schristos static CURL * setup_curl_post(struct http_ctx *ctx, const char *address, 13283c260e60Schristos const char *ca_fname, const char *username, 13293c260e60Schristos const char *password, const char *client_cert, 13303c260e60Schristos const char *client_key) 13313c260e60Schristos { 13323c260e60Schristos CURL *curl; 133336ebd06eSchristos #ifdef EAP_TLS_OPENSSL 133436ebd06eSchristos const char *extra = " tls=openssl"; 133536ebd06eSchristos #else /* EAP_TLS_OPENSSL */ 133636ebd06eSchristos const char *extra = ""; 133736ebd06eSchristos #endif /* EAP_TLS_OPENSSL */ 13383c260e60Schristos 13393c260e60Schristos wpa_printf(MSG_DEBUG, "Start HTTP client: address=%s ca_fname=%s " 134036ebd06eSchristos "username=%s%s", address, ca_fname, username, extra); 13413c260e60Schristos 13423c260e60Schristos curl = curl_easy_init(); 13433c260e60Schristos if (curl == NULL) 13443c260e60Schristos return NULL; 13453c260e60Schristos 13463c260e60Schristos curl_easy_setopt(curl, CURLOPT_URL, address); 13473c260e60Schristos curl_easy_setopt(curl, CURLOPT_POST, 1L); 13483c260e60Schristos if (ca_fname) { 13493c260e60Schristos curl_easy_setopt(curl, CURLOPT_CAINFO, ca_fname); 13503c260e60Schristos curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); 13513c260e60Schristos #ifdef EAP_TLS_OPENSSL 13523c260e60Schristos curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, curl_cb_ssl); 13533c260e60Schristos curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, ctx); 13543d6c0713Schristos #if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER >= 0x10100000L) 135536ebd06eSchristos /* For now, using the CURLOPT_SSL_VERIFYSTATUS option only 135636ebd06eSchristos * with BoringSSL since the OpenSSL specific callback hack to 135736ebd06eSchristos * enable OCSP is not available with BoringSSL. The OCSP 135836ebd06eSchristos * implementation within libcurl is not sufficient for the 135936ebd06eSchristos * Hotspot 2.0 OSU needs, so cannot use this with OpenSSL. 136036ebd06eSchristos */ 136136ebd06eSchristos if (ctx->ocsp != NO_OCSP) 136236ebd06eSchristos curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L); 136336ebd06eSchristos #endif /* OPENSSL_IS_BORINGSSL */ 13643c260e60Schristos #endif /* EAP_TLS_OPENSSL */ 13653c260e60Schristos } else { 13663c260e60Schristos curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 13673c260e60Schristos } 13683c260e60Schristos if (client_cert && client_key) { 13693c260e60Schristos curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert); 13703c260e60Schristos curl_easy_setopt(curl, CURLOPT_SSLKEY, client_key); 13713c260e60Schristos } 13723c260e60Schristos /* TODO: use curl_easy_getinfo() with CURLINFO_CERTINFO to fetch 13733c260e60Schristos * information about the server certificate */ 13743c260e60Schristos curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L); 13753c260e60Schristos curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curl_cb_debug); 13763c260e60Schristos curl_easy_setopt(curl, CURLOPT_DEBUGDATA, ctx); 13773c260e60Schristos curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_cb_write); 13783c260e60Schristos curl_easy_setopt(curl, CURLOPT_WRITEDATA, ctx); 13793c260e60Schristos curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 13803c260e60Schristos if (username) { 13813c260e60Schristos curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE); 13823c260e60Schristos curl_easy_setopt(curl, CURLOPT_USERNAME, username); 13833c260e60Schristos curl_easy_setopt(curl, CURLOPT_PASSWORD, password); 13843c260e60Schristos } 13853c260e60Schristos 13863c260e60Schristos return curl; 13873c260e60Schristos } 13883c260e60Schristos 13893c260e60Schristos 13903c260e60Schristos static int post_init_client(struct http_ctx *ctx, const char *address, 13913c260e60Schristos const char *ca_fname, const char *username, 13923c260e60Schristos const char *password, const char *client_cert, 13933c260e60Schristos const char *client_key) 13943c260e60Schristos { 13953c260e60Schristos char *pos; 13963c260e60Schristos int count; 13973c260e60Schristos 13983c260e60Schristos clone_str(&ctx->svc_address, address); 13993c260e60Schristos clone_str(&ctx->svc_ca_fname, ca_fname); 14003c260e60Schristos clone_str(&ctx->svc_username, username); 14013c260e60Schristos clone_str(&ctx->svc_password, password); 14023c260e60Schristos clone_str(&ctx->svc_client_cert, client_cert); 14033c260e60Schristos clone_str(&ctx->svc_client_key, client_key); 14043c260e60Schristos 14053c260e60Schristos /* 14063c260e60Schristos * Workaround for Apache "Hostname 'FOO' provided via SNI and hostname 14073c260e60Schristos * 'foo' provided via HTTP are different. 14083c260e60Schristos */ 14093c260e60Schristos for (count = 0, pos = ctx->svc_address; count < 3 && pos && *pos; 14103c260e60Schristos pos++) { 14113c260e60Schristos if (*pos == '/') 14123c260e60Schristos count++; 14133c260e60Schristos *pos = tolower(*pos); 14143c260e60Schristos } 14153c260e60Schristos 14163c260e60Schristos ctx->curl = setup_curl_post(ctx, ctx->svc_address, ca_fname, username, 14173c260e60Schristos password, client_cert, client_key); 14183c260e60Schristos if (ctx->curl == NULL) 14193c260e60Schristos return -1; 14203c260e60Schristos 14213c260e60Schristos return 0; 14223c260e60Schristos } 14233c260e60Schristos 14243c260e60Schristos 14253c260e60Schristos int soap_init_client(struct http_ctx *ctx, const char *address, 14263c260e60Schristos const char *ca_fname, const char *username, 14273c260e60Schristos const char *password, const char *client_cert, 14283c260e60Schristos const char *client_key) 14293c260e60Schristos { 14303c260e60Schristos if (post_init_client(ctx, address, ca_fname, username, password, 14313c260e60Schristos client_cert, client_key) < 0) 14323c260e60Schristos return -1; 14333c260e60Schristos 14343c260e60Schristos ctx->curl_hdr = curl_slist_append(ctx->curl_hdr, 14353c260e60Schristos "Content-Type: application/soap+xml"); 14363c260e60Schristos ctx->curl_hdr = curl_slist_append(ctx->curl_hdr, "SOAPAction: "); 14373c260e60Schristos ctx->curl_hdr = curl_slist_append(ctx->curl_hdr, "Expect:"); 14383c260e60Schristos curl_easy_setopt(ctx->curl, CURLOPT_HTTPHEADER, ctx->curl_hdr); 14393c260e60Schristos 14403c260e60Schristos return 0; 14413c260e60Schristos } 14423c260e60Schristos 14433c260e60Schristos 14443c260e60Schristos int soap_reinit_client(struct http_ctx *ctx) 14453c260e60Schristos { 14463c260e60Schristos char *address = NULL; 14473c260e60Schristos char *ca_fname = NULL; 14483c260e60Schristos char *username = NULL; 14493c260e60Schristos char *password = NULL; 14503c260e60Schristos char *client_cert = NULL; 14513c260e60Schristos char *client_key = NULL; 14523c260e60Schristos int ret; 14533c260e60Schristos 14543c260e60Schristos clear_curl(ctx); 14553c260e60Schristos 14563c260e60Schristos clone_str(&address, ctx->svc_address); 14573c260e60Schristos clone_str(&ca_fname, ctx->svc_ca_fname); 14583c260e60Schristos clone_str(&username, ctx->svc_username); 14593c260e60Schristos clone_str(&password, ctx->svc_password); 14603c260e60Schristos clone_str(&client_cert, ctx->svc_client_cert); 14613c260e60Schristos clone_str(&client_key, ctx->svc_client_key); 14623c260e60Schristos 14633c260e60Schristos ret = soap_init_client(ctx, address, ca_fname, username, password, 14643c260e60Schristos client_cert, client_key); 14653c260e60Schristos os_free(address); 14663c260e60Schristos os_free(ca_fname); 14673c260e60Schristos str_clear_free(username); 14683c260e60Schristos str_clear_free(password); 14693c260e60Schristos os_free(client_cert); 14703c260e60Schristos os_free(client_key); 14713c260e60Schristos return ret; 14723c260e60Schristos } 14733c260e60Schristos 14743c260e60Schristos 14753c260e60Schristos static void free_curl_buf(struct http_ctx *ctx) 14763c260e60Schristos { 14773c260e60Schristos os_free(ctx->curl_buf); 14783c260e60Schristos ctx->curl_buf = NULL; 14793c260e60Schristos ctx->curl_buf_len = 0; 14803c260e60Schristos } 14813c260e60Schristos 14823c260e60Schristos 14833c260e60Schristos xml_node_t * soap_send_receive(struct http_ctx *ctx, xml_node_t *node) 14843c260e60Schristos { 14853c260e60Schristos char *str; 14863c260e60Schristos xml_node_t *envelope, *ret, *resp, *n; 14873c260e60Schristos CURLcode res; 14883c260e60Schristos long http = 0; 14893c260e60Schristos 14903c260e60Schristos ctx->last_err = NULL; 14913c260e60Schristos 14923c260e60Schristos wpa_printf(MSG_DEBUG, "SOAP: Sending message"); 14933c260e60Schristos envelope = soap_build_envelope(ctx->xml, node); 14943c260e60Schristos str = xml_node_to_str(ctx->xml, envelope); 14953c260e60Schristos xml_node_free(ctx->xml, envelope); 14963c260e60Schristos wpa_printf(MSG_MSGDUMP, "SOAP[%s]", str); 14973c260e60Schristos 14983c260e60Schristos curl_easy_setopt(ctx->curl, CURLOPT_POSTFIELDS, str); 14993c260e60Schristos free_curl_buf(ctx); 15003c260e60Schristos 15013c260e60Schristos res = curl_easy_perform(ctx->curl); 15023c260e60Schristos if (res != CURLE_OK) { 15033c260e60Schristos if (!ctx->last_err) 15043c260e60Schristos ctx->last_err = curl_easy_strerror(res); 15053c260e60Schristos wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s", 15063c260e60Schristos ctx->last_err); 15073c260e60Schristos os_free(str); 15083c260e60Schristos free_curl_buf(ctx); 15093c260e60Schristos return NULL; 15103c260e60Schristos } 15113c260e60Schristos os_free(str); 15123c260e60Schristos 15133c260e60Schristos curl_easy_getinfo(ctx->curl, CURLINFO_RESPONSE_CODE, &http); 15143c260e60Schristos wpa_printf(MSG_DEBUG, "SOAP: Server response code %ld", http); 15153c260e60Schristos if (http != 200) { 15163c260e60Schristos ctx->last_err = "HTTP download failed"; 15173c260e60Schristos wpa_printf(MSG_INFO, "HTTP download failed - code %ld", http); 15183c260e60Schristos free_curl_buf(ctx); 15193c260e60Schristos return NULL; 15203c260e60Schristos } 15213c260e60Schristos 15223c260e60Schristos if (ctx->curl_buf == NULL) 15233c260e60Schristos return NULL; 15243c260e60Schristos 15253c260e60Schristos wpa_printf(MSG_MSGDUMP, "Server response:\n%s", ctx->curl_buf); 15263c260e60Schristos resp = xml_node_from_buf(ctx->xml, ctx->curl_buf); 15273c260e60Schristos free_curl_buf(ctx); 15283c260e60Schristos if (resp == NULL) { 15293c260e60Schristos wpa_printf(MSG_INFO, "Could not parse SOAP response"); 15303c260e60Schristos ctx->last_err = "Could not parse SOAP response"; 15313c260e60Schristos return NULL; 15323c260e60Schristos } 15333c260e60Schristos 15343c260e60Schristos ret = soap_get_body(ctx->xml, resp); 15353c260e60Schristos if (ret == NULL) { 15363c260e60Schristos wpa_printf(MSG_INFO, "Could not get SOAP body"); 15373c260e60Schristos ctx->last_err = "Could not get SOAP body"; 15383c260e60Schristos return NULL; 15393c260e60Schristos } 15403c260e60Schristos 15413c260e60Schristos wpa_printf(MSG_DEBUG, "SOAP body localname: '%s'", 15423c260e60Schristos xml_node_get_localname(ctx->xml, ret)); 15433c260e60Schristos n = xml_node_copy(ctx->xml, ret); 15443c260e60Schristos xml_node_free(ctx->xml, resp); 15453c260e60Schristos 15463c260e60Schristos return n; 15473c260e60Schristos } 15483c260e60Schristos 15493c260e60Schristos 15503c260e60Schristos struct http_ctx * http_init_ctx(void *upper_ctx, struct xml_node_ctx *xml_ctx) 15513c260e60Schristos { 15523c260e60Schristos struct http_ctx *ctx; 15533c260e60Schristos 15543c260e60Schristos ctx = os_zalloc(sizeof(*ctx)); 15553c260e60Schristos if (ctx == NULL) 15563c260e60Schristos return NULL; 15573c260e60Schristos ctx->ctx = upper_ctx; 15583c260e60Schristos ctx->xml = xml_ctx; 15593c260e60Schristos ctx->ocsp = OPTIONAL_OCSP; 15603c260e60Schristos 15613c260e60Schristos curl_global_init(CURL_GLOBAL_ALL); 15623c260e60Schristos 15633c260e60Schristos return ctx; 15643c260e60Schristos } 15653c260e60Schristos 15663c260e60Schristos 15673c260e60Schristos void http_ocsp_set(struct http_ctx *ctx, int val) 15683c260e60Schristos { 15693c260e60Schristos if (val == 0) 15703c260e60Schristos ctx->ocsp = NO_OCSP; 15713c260e60Schristos else if (val == 1) 15723c260e60Schristos ctx->ocsp = OPTIONAL_OCSP; 15733c260e60Schristos if (val == 2) 15743c260e60Schristos ctx->ocsp = MANDATORY_OCSP; 15753c260e60Schristos } 15763c260e60Schristos 15773c260e60Schristos 15783c260e60Schristos void http_deinit_ctx(struct http_ctx *ctx) 15793c260e60Schristos { 15803c260e60Schristos clear_curl(ctx); 15813c260e60Schristos os_free(ctx->curl_buf); 15823c260e60Schristos curl_global_cleanup(); 15833c260e60Schristos 15843c260e60Schristos os_free(ctx->svc_address); 15853c260e60Schristos os_free(ctx->svc_ca_fname); 15863c260e60Schristos str_clear_free(ctx->svc_username); 15873c260e60Schristos str_clear_free(ctx->svc_password); 15883c260e60Schristos os_free(ctx->svc_client_cert); 15893c260e60Schristos os_free(ctx->svc_client_key); 15903c260e60Schristos 15913c260e60Schristos os_free(ctx); 15923c260e60Schristos } 15933c260e60Schristos 15943c260e60Schristos 15953c260e60Schristos int http_download_file(struct http_ctx *ctx, const char *url, 15963c260e60Schristos const char *fname, const char *ca_fname) 15973c260e60Schristos { 15983c260e60Schristos CURL *curl; 1599*bb618362Schristos FILE *f = NULL; 16003c260e60Schristos CURLcode res; 16013c260e60Schristos long http = 0; 1602*bb618362Schristos int ret = -1; 16033c260e60Schristos 16043c260e60Schristos ctx->last_err = NULL; 1605*bb618362Schristos ctx->url = url; 16063c260e60Schristos 16073c260e60Schristos wpa_printf(MSG_DEBUG, "curl: Download file from %s to %s (ca=%s)", 16083c260e60Schristos url, fname, ca_fname); 16093c260e60Schristos curl = curl_easy_init(); 16103c260e60Schristos if (curl == NULL) 1611*bb618362Schristos goto fail; 16123c260e60Schristos 16133c260e60Schristos f = fopen(fname, "wb"); 1614*bb618362Schristos if (!f) 1615*bb618362Schristos goto fail; 16163c260e60Schristos 16173c260e60Schristos curl_easy_setopt(curl, CURLOPT_URL, url); 16183c260e60Schristos if (ca_fname) { 16193c260e60Schristos curl_easy_setopt(curl, CURLOPT_CAINFO, ca_fname); 16203c260e60Schristos curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); 16213c260e60Schristos curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L); 16223c260e60Schristos } else { 16233c260e60Schristos curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 16243c260e60Schristos } 16253c260e60Schristos curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curl_cb_debug); 16263c260e60Schristos curl_easy_setopt(curl, CURLOPT_DEBUGDATA, ctx); 16273c260e60Schristos curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite); 16283c260e60Schristos curl_easy_setopt(curl, CURLOPT_WRITEDATA, f); 16293c260e60Schristos curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 16303c260e60Schristos 16313c260e60Schristos res = curl_easy_perform(curl); 16323c260e60Schristos if (res != CURLE_OK) { 16333c260e60Schristos if (!ctx->last_err) 16343c260e60Schristos ctx->last_err = curl_easy_strerror(res); 16353c260e60Schristos wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s", 16363c260e60Schristos ctx->last_err); 1637*bb618362Schristos goto fail; 16383c260e60Schristos } 16393c260e60Schristos 16403c260e60Schristos curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http); 16413c260e60Schristos wpa_printf(MSG_DEBUG, "curl: Server response code %ld", http); 16423c260e60Schristos if (http != 200) { 16433c260e60Schristos ctx->last_err = "HTTP download failed"; 16443c260e60Schristos wpa_printf(MSG_INFO, "HTTP download failed - code %ld", http); 1645*bb618362Schristos goto fail; 16463c260e60Schristos } 16473c260e60Schristos 1648*bb618362Schristos ret = 0; 1649*bb618362Schristos 1650*bb618362Schristos fail: 1651*bb618362Schristos ctx->url = NULL; 1652*bb618362Schristos if (curl) 16533c260e60Schristos curl_easy_cleanup(curl); 1654*bb618362Schristos if (f) 16553c260e60Schristos fclose(f); 16563c260e60Schristos 1657*bb618362Schristos return ret; 16583c260e60Schristos } 16593c260e60Schristos 16603c260e60Schristos 16613c260e60Schristos char * http_post(struct http_ctx *ctx, const char *url, const char *data, 16623c260e60Schristos const char *content_type, const char *ext_hdr, 16633c260e60Schristos const char *ca_fname, 16643c260e60Schristos const char *username, const char *password, 16653c260e60Schristos const char *client_cert, const char *client_key, 16663c260e60Schristos size_t *resp_len) 16673c260e60Schristos { 16683c260e60Schristos long http = 0; 16693c260e60Schristos CURLcode res; 1670*bb618362Schristos char *ret = NULL; 16713c260e60Schristos CURL *curl; 16723c260e60Schristos struct curl_slist *curl_hdr = NULL; 16733c260e60Schristos 16743c260e60Schristos ctx->last_err = NULL; 1675*bb618362Schristos ctx->url = url; 16763c260e60Schristos wpa_printf(MSG_DEBUG, "curl: HTTP POST to %s", url); 16773c260e60Schristos curl = setup_curl_post(ctx, url, ca_fname, username, password, 16783c260e60Schristos client_cert, client_key); 16793c260e60Schristos if (curl == NULL) 1680*bb618362Schristos goto fail; 16813c260e60Schristos 16823c260e60Schristos if (content_type) { 16833c260e60Schristos char ct[200]; 16843c260e60Schristos snprintf(ct, sizeof(ct), "Content-Type: %s", content_type); 16853c260e60Schristos curl_hdr = curl_slist_append(curl_hdr, ct); 16863c260e60Schristos } 16873c260e60Schristos if (ext_hdr) 16883c260e60Schristos curl_hdr = curl_slist_append(curl_hdr, ext_hdr); 16893c260e60Schristos curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_hdr); 16903c260e60Schristos 16913c260e60Schristos curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); 16923c260e60Schristos free_curl_buf(ctx); 16933c260e60Schristos 16943c260e60Schristos res = curl_easy_perform(curl); 16953c260e60Schristos if (res != CURLE_OK) { 16963c260e60Schristos if (!ctx->last_err) 16973c260e60Schristos ctx->last_err = curl_easy_strerror(res); 16983c260e60Schristos wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s", 16993c260e60Schristos ctx->last_err); 1700*bb618362Schristos goto fail; 17013c260e60Schristos } 17023c260e60Schristos 17033c260e60Schristos curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http); 17043c260e60Schristos wpa_printf(MSG_DEBUG, "curl: Server response code %ld", http); 17053c260e60Schristos if (http != 200) { 17063c260e60Schristos ctx->last_err = "HTTP POST failed"; 17073c260e60Schristos wpa_printf(MSG_INFO, "HTTP POST failed - code %ld", http); 1708*bb618362Schristos goto fail; 17093c260e60Schristos } 17103c260e60Schristos 17113c260e60Schristos if (ctx->curl_buf == NULL) 1712*bb618362Schristos goto fail; 17133c260e60Schristos 17143c260e60Schristos ret = ctx->curl_buf; 17153c260e60Schristos if (resp_len) 17163c260e60Schristos *resp_len = ctx->curl_buf_len; 17173c260e60Schristos ctx->curl_buf = NULL; 17183c260e60Schristos ctx->curl_buf_len = 0; 17193c260e60Schristos 17203c260e60Schristos wpa_printf(MSG_MSGDUMP, "Server response:\n%s", ret); 17213c260e60Schristos 1722*bb618362Schristos fail: 1723*bb618362Schristos free_curl_buf(ctx); 1724*bb618362Schristos ctx->url = NULL; 17253c260e60Schristos return ret; 17263c260e60Schristos } 17273c260e60Schristos 17283c260e60Schristos 17293c260e60Schristos void http_set_cert_cb(struct http_ctx *ctx, 17303c260e60Schristos int (*cb)(void *ctx, struct http_cert *cert), 17313c260e60Schristos void *cb_ctx) 17323c260e60Schristos { 17333c260e60Schristos ctx->cert_cb = cb; 17343c260e60Schristos ctx->cert_cb_ctx = cb_ctx; 17353c260e60Schristos } 17363c260e60Schristos 17373c260e60Schristos 17383c260e60Schristos const char * http_get_err(struct http_ctx *ctx) 17393c260e60Schristos { 17403c260e60Schristos return ctx->last_err; 17413c260e60Schristos } 1742