15b9c547cSRui Paulo /* 25b9c547cSRui Paulo * HTTP wrapper for libcurl 35b9c547cSRui Paulo * Copyright (c) 2012-2014, Qualcomm Atheros, Inc. 45b9c547cSRui Paulo * 55b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license. 65b9c547cSRui Paulo * See README for more details. 75b9c547cSRui Paulo */ 85b9c547cSRui Paulo 95b9c547cSRui Paulo #include "includes.h" 105b9c547cSRui Paulo #include <curl/curl.h> 115b9c547cSRui Paulo #ifdef EAP_TLS_OPENSSL 125b9c547cSRui Paulo #include <openssl/ssl.h> 135b9c547cSRui Paulo #include <openssl/asn1.h> 145b9c547cSRui Paulo #include <openssl/asn1t.h> 155b9c547cSRui Paulo #include <openssl/x509v3.h> 165b9c547cSRui Paulo 175b9c547cSRui Paulo #ifdef SSL_set_tlsext_status_type 185b9c547cSRui Paulo #ifndef OPENSSL_NO_TLSEXT 195b9c547cSRui Paulo #define HAVE_OCSP 205b9c547cSRui Paulo #include <openssl/err.h> 215b9c547cSRui Paulo #include <openssl/ocsp.h> 225b9c547cSRui Paulo #endif /* OPENSSL_NO_TLSEXT */ 235b9c547cSRui Paulo #endif /* SSL_set_tlsext_status_type */ 245b9c547cSRui Paulo #endif /* EAP_TLS_OPENSSL */ 255b9c547cSRui Paulo 265b9c547cSRui Paulo #include "common.h" 275b9c547cSRui Paulo #include "xml-utils.h" 285b9c547cSRui Paulo #include "http-utils.h" 29780fb4a2SCy Schubert #ifdef EAP_TLS_OPENSSL 30780fb4a2SCy Schubert #include "crypto/tls_openssl.h" 31780fb4a2SCy Schubert #endif /* EAP_TLS_OPENSSL */ 325b9c547cSRui Paulo 335b9c547cSRui Paulo 344bc52338SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L 354bc52338SCy Schubert static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x) 364bc52338SCy Schubert { 374bc52338SCy Schubert return ASN1_STRING_data((ASN1_STRING *) x); 384bc52338SCy Schubert } 394bc52338SCy Schubert #endif /* OpenSSL < 1.1.0 */ 404bc52338SCy Schubert 414bc52338SCy Schubert 425b9c547cSRui Paulo struct http_ctx { 435b9c547cSRui Paulo void *ctx; 445b9c547cSRui Paulo struct xml_node_ctx *xml; 455b9c547cSRui Paulo CURL *curl; 465b9c547cSRui Paulo struct curl_slist *curl_hdr; 475b9c547cSRui Paulo char *svc_address; 485b9c547cSRui Paulo char *svc_ca_fname; 495b9c547cSRui Paulo char *svc_username; 505b9c547cSRui Paulo char *svc_password; 515b9c547cSRui Paulo char *svc_client_cert; 525b9c547cSRui Paulo char *svc_client_key; 535b9c547cSRui Paulo char *curl_buf; 545b9c547cSRui Paulo size_t curl_buf_len; 555b9c547cSRui Paulo 565b9c547cSRui Paulo int (*cert_cb)(void *ctx, struct http_cert *cert); 575b9c547cSRui Paulo void *cert_cb_ctx; 585b9c547cSRui Paulo 595b9c547cSRui Paulo enum { 605b9c547cSRui Paulo NO_OCSP, OPTIONAL_OCSP, MANDATORY_OCSP 615b9c547cSRui Paulo } ocsp; 625b9c547cSRui Paulo X509 *peer_cert; 635b9c547cSRui Paulo X509 *peer_issuer; 645b9c547cSRui Paulo X509 *peer_issuer_issuer; 655b9c547cSRui Paulo 665b9c547cSRui Paulo const char *last_err; 67*a90b9d01SCy Schubert const char *url; 685b9c547cSRui Paulo }; 695b9c547cSRui Paulo 705b9c547cSRui Paulo 715b9c547cSRui Paulo static void clear_curl(struct http_ctx *ctx) 725b9c547cSRui Paulo { 735b9c547cSRui Paulo if (ctx->curl) { 745b9c547cSRui Paulo curl_easy_cleanup(ctx->curl); 755b9c547cSRui Paulo ctx->curl = NULL; 765b9c547cSRui Paulo } 775b9c547cSRui Paulo if (ctx->curl_hdr) { 785b9c547cSRui Paulo curl_slist_free_all(ctx->curl_hdr); 795b9c547cSRui Paulo ctx->curl_hdr = NULL; 805b9c547cSRui Paulo } 815b9c547cSRui Paulo } 825b9c547cSRui Paulo 835b9c547cSRui Paulo 845b9c547cSRui Paulo static void clone_str(char **dst, const char *src) 855b9c547cSRui Paulo { 865b9c547cSRui Paulo os_free(*dst); 875b9c547cSRui Paulo if (src) 885b9c547cSRui Paulo *dst = os_strdup(src); 895b9c547cSRui Paulo else 905b9c547cSRui Paulo *dst = NULL; 915b9c547cSRui Paulo } 925b9c547cSRui Paulo 935b9c547cSRui Paulo 945b9c547cSRui Paulo static void debug_dump(struct http_ctx *ctx, const char *title, 955b9c547cSRui Paulo const char *buf, size_t len) 965b9c547cSRui Paulo { 975b9c547cSRui Paulo char *txt; 985b9c547cSRui Paulo size_t i; 995b9c547cSRui Paulo 1005b9c547cSRui Paulo for (i = 0; i < len; i++) { 1015b9c547cSRui Paulo if (buf[i] < 32 && buf[i] != '\t' && buf[i] != '\n' && 1025b9c547cSRui Paulo buf[i] != '\r') { 1035b9c547cSRui Paulo wpa_hexdump_ascii(MSG_MSGDUMP, title, buf, len); 1045b9c547cSRui Paulo return; 1055b9c547cSRui Paulo } 1065b9c547cSRui Paulo } 1075b9c547cSRui Paulo 1085b9c547cSRui Paulo txt = os_malloc(len + 1); 1095b9c547cSRui Paulo if (txt == NULL) 1105b9c547cSRui Paulo return; 1115b9c547cSRui Paulo os_memcpy(txt, buf, len); 1125b9c547cSRui Paulo txt[len] = '\0'; 1135b9c547cSRui Paulo while (len > 0) { 1145b9c547cSRui Paulo len--; 1155b9c547cSRui Paulo if (txt[len] == '\n' || txt[len] == '\r') 1165b9c547cSRui Paulo txt[len] = '\0'; 1175b9c547cSRui Paulo else 1185b9c547cSRui Paulo break; 1195b9c547cSRui Paulo } 1205b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, "%s[%s]", title, txt); 1215b9c547cSRui Paulo os_free(txt); 1225b9c547cSRui Paulo } 1235b9c547cSRui Paulo 1245b9c547cSRui Paulo 1255b9c547cSRui Paulo static int curl_cb_debug(CURL *curl, curl_infotype info, char *buf, size_t len, 1265b9c547cSRui Paulo void *userdata) 1275b9c547cSRui Paulo { 1285b9c547cSRui Paulo struct http_ctx *ctx = userdata; 1295b9c547cSRui Paulo switch (info) { 1305b9c547cSRui Paulo case CURLINFO_TEXT: 1315b9c547cSRui Paulo debug_dump(ctx, "CURLINFO_TEXT", buf, len); 1325b9c547cSRui Paulo break; 1335b9c547cSRui Paulo case CURLINFO_HEADER_IN: 1345b9c547cSRui Paulo debug_dump(ctx, "CURLINFO_HEADER_IN", buf, len); 1355b9c547cSRui Paulo break; 1365b9c547cSRui Paulo case CURLINFO_HEADER_OUT: 1375b9c547cSRui Paulo debug_dump(ctx, "CURLINFO_HEADER_OUT", buf, len); 1385b9c547cSRui Paulo break; 1395b9c547cSRui Paulo case CURLINFO_DATA_IN: 1405b9c547cSRui Paulo debug_dump(ctx, "CURLINFO_DATA_IN", buf, len); 1415b9c547cSRui Paulo break; 1425b9c547cSRui Paulo case CURLINFO_DATA_OUT: 1435b9c547cSRui Paulo debug_dump(ctx, "CURLINFO_DATA_OUT", buf, len); 1445b9c547cSRui Paulo break; 1455b9c547cSRui Paulo case CURLINFO_SSL_DATA_IN: 1465b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "debug - CURLINFO_SSL_DATA_IN - %d", 1475b9c547cSRui Paulo (int) len); 1485b9c547cSRui Paulo break; 1495b9c547cSRui Paulo case CURLINFO_SSL_DATA_OUT: 1505b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "debug - CURLINFO_SSL_DATA_OUT - %d", 1515b9c547cSRui Paulo (int) len); 1525b9c547cSRui Paulo break; 1535b9c547cSRui Paulo case CURLINFO_END: 1545b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "debug - CURLINFO_END - %d", 1555b9c547cSRui Paulo (int) len); 1565b9c547cSRui Paulo break; 1575b9c547cSRui Paulo } 1585b9c547cSRui Paulo return 0; 1595b9c547cSRui Paulo } 1605b9c547cSRui Paulo 1615b9c547cSRui Paulo 1625b9c547cSRui Paulo static size_t curl_cb_write(void *ptr, size_t size, size_t nmemb, 1635b9c547cSRui Paulo void *userdata) 1645b9c547cSRui Paulo { 1655b9c547cSRui Paulo struct http_ctx *ctx = userdata; 1665b9c547cSRui Paulo char *n; 1675b9c547cSRui Paulo n = os_realloc(ctx->curl_buf, ctx->curl_buf_len + size * nmemb + 1); 1685b9c547cSRui Paulo if (n == NULL) 1695b9c547cSRui Paulo return 0; 1705b9c547cSRui Paulo ctx->curl_buf = n; 1715b9c547cSRui Paulo os_memcpy(n + ctx->curl_buf_len, ptr, size * nmemb); 1725b9c547cSRui Paulo n[ctx->curl_buf_len + size * nmemb] = '\0'; 1735b9c547cSRui Paulo ctx->curl_buf_len += size * nmemb; 1745b9c547cSRui Paulo return size * nmemb; 1755b9c547cSRui Paulo } 1765b9c547cSRui Paulo 1775b9c547cSRui Paulo 1785b9c547cSRui Paulo #ifdef EAP_TLS_OPENSSL 1795b9c547cSRui Paulo 1805b9c547cSRui Paulo static void debug_dump_cert(const char *title, X509 *cert) 1815b9c547cSRui Paulo { 1825b9c547cSRui Paulo BIO *out; 1835b9c547cSRui Paulo char *txt; 1845b9c547cSRui Paulo size_t rlen; 1855b9c547cSRui Paulo 1865b9c547cSRui Paulo out = BIO_new(BIO_s_mem()); 1875b9c547cSRui Paulo if (!out) 1885b9c547cSRui Paulo return; 1895b9c547cSRui Paulo 1905b9c547cSRui Paulo X509_print_ex(out, cert, XN_FLAG_COMPAT, X509_FLAG_COMPAT); 1915b9c547cSRui Paulo rlen = BIO_ctrl_pending(out); 1925b9c547cSRui Paulo txt = os_malloc(rlen + 1); 1935b9c547cSRui Paulo if (txt) { 1945b9c547cSRui Paulo int res = BIO_read(out, txt, rlen); 1955b9c547cSRui Paulo if (res > 0) { 1965b9c547cSRui Paulo txt[res] = '\0'; 1975b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, "%s:\n%s", title, txt); 1985b9c547cSRui Paulo } 1995b9c547cSRui Paulo os_free(txt); 2005b9c547cSRui Paulo } 2015b9c547cSRui Paulo BIO_free(out); 2025b9c547cSRui Paulo } 2035b9c547cSRui Paulo 2045b9c547cSRui Paulo 2055b9c547cSRui Paulo static void add_alt_name_othername(struct http_ctx *ctx, struct http_cert *cert, 2065b9c547cSRui Paulo OTHERNAME *o) 2075b9c547cSRui Paulo { 2085b9c547cSRui Paulo char txt[100]; 2095b9c547cSRui Paulo int res; 2105b9c547cSRui Paulo struct http_othername *on; 2115b9c547cSRui Paulo ASN1_TYPE *val; 2125b9c547cSRui Paulo 2135b9c547cSRui Paulo on = os_realloc_array(cert->othername, cert->num_othername + 1, 2145b9c547cSRui Paulo sizeof(struct http_othername)); 2155b9c547cSRui Paulo if (on == NULL) 2165b9c547cSRui Paulo return; 2175b9c547cSRui Paulo cert->othername = on; 2185b9c547cSRui Paulo on = &on[cert->num_othername]; 2195b9c547cSRui Paulo os_memset(on, 0, sizeof(*on)); 2205b9c547cSRui Paulo 2215b9c547cSRui Paulo res = OBJ_obj2txt(txt, sizeof(txt), o->type_id, 1); 2225b9c547cSRui Paulo if (res < 0 || res >= (int) sizeof(txt)) 2235b9c547cSRui Paulo return; 2245b9c547cSRui Paulo 2255b9c547cSRui Paulo on->oid = os_strdup(txt); 2265b9c547cSRui Paulo if (on->oid == NULL) 2275b9c547cSRui Paulo return; 2285b9c547cSRui Paulo 2295b9c547cSRui Paulo val = o->value; 2305b9c547cSRui Paulo on->data = val->value.octet_string->data; 2315b9c547cSRui Paulo on->len = val->value.octet_string->length; 2325b9c547cSRui Paulo 2335b9c547cSRui Paulo cert->num_othername++; 2345b9c547cSRui Paulo } 2355b9c547cSRui Paulo 2365b9c547cSRui Paulo 2375b9c547cSRui Paulo static void add_alt_name_dns(struct http_ctx *ctx, struct http_cert *cert, 2385b9c547cSRui Paulo ASN1_STRING *name) 2395b9c547cSRui Paulo { 2405b9c547cSRui Paulo char *buf; 2415b9c547cSRui Paulo char **n; 2425b9c547cSRui Paulo 2435b9c547cSRui Paulo buf = NULL; 2445b9c547cSRui Paulo if (ASN1_STRING_to_UTF8((unsigned char **) &buf, name) < 0) 2455b9c547cSRui Paulo return; 2465b9c547cSRui Paulo 2475b9c547cSRui Paulo n = os_realloc_array(cert->dnsname, cert->num_dnsname + 1, 2485b9c547cSRui Paulo sizeof(char *)); 2495b9c547cSRui Paulo if (n == NULL) 2505b9c547cSRui Paulo return; 2515b9c547cSRui Paulo 2525b9c547cSRui Paulo cert->dnsname = n; 2535b9c547cSRui Paulo n[cert->num_dnsname] = buf; 2545b9c547cSRui Paulo cert->num_dnsname++; 2555b9c547cSRui Paulo } 2565b9c547cSRui Paulo 2575b9c547cSRui Paulo 2585b9c547cSRui Paulo static void add_alt_name(struct http_ctx *ctx, struct http_cert *cert, 2595b9c547cSRui Paulo const GENERAL_NAME *name) 2605b9c547cSRui Paulo { 2615b9c547cSRui Paulo switch (name->type) { 2625b9c547cSRui Paulo case GEN_OTHERNAME: 2635b9c547cSRui Paulo add_alt_name_othername(ctx, cert, name->d.otherName); 2645b9c547cSRui Paulo break; 2655b9c547cSRui Paulo case GEN_DNS: 2665b9c547cSRui Paulo add_alt_name_dns(ctx, cert, name->d.dNSName); 2675b9c547cSRui Paulo break; 2685b9c547cSRui Paulo } 2695b9c547cSRui Paulo } 2705b9c547cSRui Paulo 2715b9c547cSRui Paulo 2725b9c547cSRui Paulo static void add_alt_names(struct http_ctx *ctx, struct http_cert *cert, 2735b9c547cSRui Paulo GENERAL_NAMES *names) 2745b9c547cSRui Paulo { 2755b9c547cSRui Paulo int num, i; 2765b9c547cSRui Paulo 2775b9c547cSRui Paulo num = sk_GENERAL_NAME_num(names); 2785b9c547cSRui Paulo for (i = 0; i < num; i++) { 2795b9c547cSRui Paulo const GENERAL_NAME *name; 2805b9c547cSRui Paulo name = sk_GENERAL_NAME_value(names, i); 2815b9c547cSRui Paulo add_alt_name(ctx, cert, name); 2825b9c547cSRui Paulo } 2835b9c547cSRui Paulo } 2845b9c547cSRui Paulo 2855b9c547cSRui Paulo 2865b9c547cSRui Paulo /* RFC 3709 */ 2875b9c547cSRui Paulo 2885b9c547cSRui Paulo typedef struct { 2895b9c547cSRui Paulo X509_ALGOR *hashAlg; 2905b9c547cSRui Paulo ASN1_OCTET_STRING *hashValue; 2915b9c547cSRui Paulo } HashAlgAndValue; 2925b9c547cSRui Paulo 2935b9c547cSRui Paulo typedef struct { 2945b9c547cSRui Paulo STACK_OF(HashAlgAndValue) *refStructHash; 2955b9c547cSRui Paulo STACK_OF(ASN1_IA5STRING) *refStructURI; 2965b9c547cSRui Paulo } LogotypeReference; 2975b9c547cSRui Paulo 2985b9c547cSRui Paulo typedef struct { 2995b9c547cSRui Paulo ASN1_IA5STRING *mediaType; 3005b9c547cSRui Paulo STACK_OF(HashAlgAndValue) *logotypeHash; 3015b9c547cSRui Paulo STACK_OF(ASN1_IA5STRING) *logotypeURI; 3025b9c547cSRui Paulo } LogotypeDetails; 3035b9c547cSRui Paulo 3045b9c547cSRui Paulo typedef struct { 3055b9c547cSRui Paulo int type; 3065b9c547cSRui Paulo union { 3075b9c547cSRui Paulo ASN1_INTEGER *numBits; 3085b9c547cSRui Paulo ASN1_INTEGER *tableSize; 3095b9c547cSRui Paulo } d; 3105b9c547cSRui Paulo } LogotypeImageResolution; 3115b9c547cSRui Paulo 3125b9c547cSRui Paulo typedef struct { 3135b9c547cSRui Paulo ASN1_INTEGER *type; /* LogotypeImageType ::= INTEGER */ 3145b9c547cSRui Paulo ASN1_INTEGER *fileSize; 3155b9c547cSRui Paulo ASN1_INTEGER *xSize; 3165b9c547cSRui Paulo ASN1_INTEGER *ySize; 3175b9c547cSRui Paulo LogotypeImageResolution *resolution; 3185b9c547cSRui Paulo ASN1_IA5STRING *language; 3195b9c547cSRui Paulo } LogotypeImageInfo; 3205b9c547cSRui Paulo 3215b9c547cSRui Paulo typedef struct { 3225b9c547cSRui Paulo LogotypeDetails *imageDetails; 3235b9c547cSRui Paulo LogotypeImageInfo *imageInfo; 3245b9c547cSRui Paulo } LogotypeImage; 3255b9c547cSRui Paulo 3265b9c547cSRui Paulo typedef struct { 3275b9c547cSRui Paulo ASN1_INTEGER *fileSize; 3285b9c547cSRui Paulo ASN1_INTEGER *playTime; 3295b9c547cSRui Paulo ASN1_INTEGER *channels; 3305b9c547cSRui Paulo ASN1_INTEGER *sampleRate; 3315b9c547cSRui Paulo ASN1_IA5STRING *language; 3325b9c547cSRui Paulo } LogotypeAudioInfo; 3335b9c547cSRui Paulo 3345b9c547cSRui Paulo typedef struct { 3355b9c547cSRui Paulo LogotypeDetails *audioDetails; 3365b9c547cSRui Paulo LogotypeAudioInfo *audioInfo; 3375b9c547cSRui Paulo } LogotypeAudio; 3385b9c547cSRui Paulo 3395b9c547cSRui Paulo typedef struct { 3405b9c547cSRui Paulo STACK_OF(LogotypeImage) *image; 3415b9c547cSRui Paulo STACK_OF(LogotypeAudio) *audio; 3425b9c547cSRui Paulo } LogotypeData; 3435b9c547cSRui Paulo 3445b9c547cSRui Paulo typedef struct { 3455b9c547cSRui Paulo int type; 3465b9c547cSRui Paulo union { 3475b9c547cSRui Paulo LogotypeData *direct; 3485b9c547cSRui Paulo LogotypeReference *indirect; 3495b9c547cSRui Paulo } d; 3505b9c547cSRui Paulo } LogotypeInfo; 3515b9c547cSRui Paulo 3525b9c547cSRui Paulo typedef struct { 3535b9c547cSRui Paulo ASN1_OBJECT *logotypeType; 3545b9c547cSRui Paulo LogotypeInfo *info; 3555b9c547cSRui Paulo } OtherLogotypeInfo; 3565b9c547cSRui Paulo 3575b9c547cSRui Paulo typedef struct { 3585b9c547cSRui Paulo STACK_OF(LogotypeInfo) *communityLogos; 3595b9c547cSRui Paulo LogotypeInfo *issuerLogo; 3605b9c547cSRui Paulo LogotypeInfo *subjectLogo; 3615b9c547cSRui Paulo STACK_OF(OtherLogotypeInfo) *otherLogos; 3625b9c547cSRui Paulo } LogotypeExtn; 3635b9c547cSRui Paulo 3645b9c547cSRui Paulo ASN1_SEQUENCE(HashAlgAndValue) = { 3655b9c547cSRui Paulo ASN1_SIMPLE(HashAlgAndValue, hashAlg, X509_ALGOR), 3665b9c547cSRui Paulo ASN1_SIMPLE(HashAlgAndValue, hashValue, ASN1_OCTET_STRING) 3675b9c547cSRui Paulo } ASN1_SEQUENCE_END(HashAlgAndValue); 3685b9c547cSRui Paulo 3695b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeReference) = { 3705b9c547cSRui Paulo ASN1_SEQUENCE_OF(LogotypeReference, refStructHash, HashAlgAndValue), 3715b9c547cSRui Paulo ASN1_SEQUENCE_OF(LogotypeReference, refStructURI, ASN1_IA5STRING) 3725b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeReference); 3735b9c547cSRui Paulo 3745b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeDetails) = { 3755b9c547cSRui Paulo ASN1_SIMPLE(LogotypeDetails, mediaType, ASN1_IA5STRING), 3765b9c547cSRui Paulo ASN1_SEQUENCE_OF(LogotypeDetails, logotypeHash, HashAlgAndValue), 3775b9c547cSRui Paulo ASN1_SEQUENCE_OF(LogotypeDetails, logotypeURI, ASN1_IA5STRING) 3785b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeDetails); 3795b9c547cSRui Paulo 3805b9c547cSRui Paulo ASN1_CHOICE(LogotypeImageResolution) = { 3815b9c547cSRui Paulo ASN1_IMP(LogotypeImageResolution, d.numBits, ASN1_INTEGER, 1), 3825b9c547cSRui Paulo ASN1_IMP(LogotypeImageResolution, d.tableSize, ASN1_INTEGER, 2) 3835b9c547cSRui Paulo } ASN1_CHOICE_END(LogotypeImageResolution); 3845b9c547cSRui Paulo 3855b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeImageInfo) = { 3865b9c547cSRui Paulo ASN1_IMP_OPT(LogotypeImageInfo, type, ASN1_INTEGER, 0), 3875b9c547cSRui Paulo ASN1_SIMPLE(LogotypeImageInfo, fileSize, ASN1_INTEGER), 3885b9c547cSRui Paulo ASN1_SIMPLE(LogotypeImageInfo, xSize, ASN1_INTEGER), 3895b9c547cSRui Paulo ASN1_SIMPLE(LogotypeImageInfo, ySize, ASN1_INTEGER), 3905b9c547cSRui Paulo ASN1_OPT(LogotypeImageInfo, resolution, LogotypeImageResolution), 3915b9c547cSRui Paulo ASN1_IMP_OPT(LogotypeImageInfo, language, ASN1_IA5STRING, 4), 3925b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeImageInfo); 3935b9c547cSRui Paulo 3945b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeImage) = { 3955b9c547cSRui Paulo ASN1_SIMPLE(LogotypeImage, imageDetails, LogotypeDetails), 3965b9c547cSRui Paulo ASN1_OPT(LogotypeImage, imageInfo, LogotypeImageInfo) 3975b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeImage); 3985b9c547cSRui Paulo 3995b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeAudioInfo) = { 4005b9c547cSRui Paulo ASN1_SIMPLE(LogotypeAudioInfo, fileSize, ASN1_INTEGER), 4015b9c547cSRui Paulo ASN1_SIMPLE(LogotypeAudioInfo, playTime, ASN1_INTEGER), 4025b9c547cSRui Paulo ASN1_SIMPLE(LogotypeAudioInfo, channels, ASN1_INTEGER), 4035b9c547cSRui Paulo ASN1_IMP_OPT(LogotypeAudioInfo, sampleRate, ASN1_INTEGER, 3), 4045b9c547cSRui Paulo ASN1_IMP_OPT(LogotypeAudioInfo, language, ASN1_IA5STRING, 4) 4055b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeAudioInfo); 4065b9c547cSRui Paulo 4075b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeAudio) = { 4085b9c547cSRui Paulo ASN1_SIMPLE(LogotypeAudio, audioDetails, LogotypeDetails), 4095b9c547cSRui Paulo ASN1_OPT(LogotypeAudio, audioInfo, LogotypeAudioInfo) 4105b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeAudio); 4115b9c547cSRui Paulo 4125b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeData) = { 4135b9c547cSRui Paulo ASN1_SEQUENCE_OF_OPT(LogotypeData, image, LogotypeImage), 4145b9c547cSRui Paulo ASN1_IMP_SEQUENCE_OF_OPT(LogotypeData, audio, LogotypeAudio, 1) 4155b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeData); 4165b9c547cSRui Paulo 4175b9c547cSRui Paulo ASN1_CHOICE(LogotypeInfo) = { 4185b9c547cSRui Paulo ASN1_IMP(LogotypeInfo, d.direct, LogotypeData, 0), 4195b9c547cSRui Paulo ASN1_IMP(LogotypeInfo, d.indirect, LogotypeReference, 1) 4205b9c547cSRui Paulo } ASN1_CHOICE_END(LogotypeInfo); 4215b9c547cSRui Paulo 4225b9c547cSRui Paulo ASN1_SEQUENCE(OtherLogotypeInfo) = { 4235b9c547cSRui Paulo ASN1_SIMPLE(OtherLogotypeInfo, logotypeType, ASN1_OBJECT), 4245b9c547cSRui Paulo ASN1_SIMPLE(OtherLogotypeInfo, info, LogotypeInfo) 4255b9c547cSRui Paulo } ASN1_SEQUENCE_END(OtherLogotypeInfo); 4265b9c547cSRui Paulo 4275b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeExtn) = { 4285b9c547cSRui Paulo ASN1_EXP_SEQUENCE_OF_OPT(LogotypeExtn, communityLogos, LogotypeInfo, 0), 4295b9c547cSRui Paulo ASN1_EXP_OPT(LogotypeExtn, issuerLogo, LogotypeInfo, 1), 4305b9c547cSRui Paulo ASN1_EXP_OPT(LogotypeExtn, issuerLogo, LogotypeInfo, 2), 4315b9c547cSRui Paulo ASN1_EXP_SEQUENCE_OF_OPT(LogotypeExtn, otherLogos, OtherLogotypeInfo, 3) 4325b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeExtn); 4335b9c547cSRui Paulo 4345b9c547cSRui Paulo IMPLEMENT_ASN1_FUNCTIONS(LogotypeExtn); 4355b9c547cSRui Paulo 4364bc52338SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L 4375b9c547cSRui Paulo #define sk_LogotypeInfo_num(st) SKM_sk_num(LogotypeInfo, (st)) 4385b9c547cSRui Paulo #define sk_LogotypeInfo_value(st, i) SKM_sk_value(LogotypeInfo, (st), (i)) 4395b9c547cSRui Paulo #define sk_LogotypeImage_num(st) SKM_sk_num(LogotypeImage, (st)) 4405b9c547cSRui Paulo #define sk_LogotypeImage_value(st, i) SKM_sk_value(LogotypeImage, (st), (i)) 4415b9c547cSRui Paulo #define sk_LogotypeAudio_num(st) SKM_sk_num(LogotypeAudio, (st)) 4425b9c547cSRui Paulo #define sk_LogotypeAudio_value(st, i) SKM_sk_value(LogotypeAudio, (st), (i)) 4435b9c547cSRui Paulo #define sk_HashAlgAndValue_num(st) SKM_sk_num(HashAlgAndValue, (st)) 4445b9c547cSRui Paulo #define sk_HashAlgAndValue_value(st, i) SKM_sk_value(HashAlgAndValue, (st), (i)) 4455b9c547cSRui Paulo #define sk_ASN1_IA5STRING_num(st) SKM_sk_num(ASN1_IA5STRING, (st)) 4465b9c547cSRui Paulo #define sk_ASN1_IA5STRING_value(st, i) SKM_sk_value(ASN1_IA5STRING, (st), (i)) 4474bc52338SCy Schubert #else 4484bc52338SCy Schubert DEFINE_STACK_OF(LogotypeInfo) 4494bc52338SCy Schubert DEFINE_STACK_OF(LogotypeImage) 4504bc52338SCy Schubert DEFINE_STACK_OF(LogotypeAudio) 4514bc52338SCy Schubert DEFINE_STACK_OF(HashAlgAndValue) 4524bc52338SCy Schubert DEFINE_STACK_OF(ASN1_IA5STRING) 4534bc52338SCy Schubert #endif 4545b9c547cSRui Paulo 4555b9c547cSRui Paulo 4565b9c547cSRui Paulo static void add_logo(struct http_ctx *ctx, struct http_cert *hcert, 4575b9c547cSRui Paulo HashAlgAndValue *hash, ASN1_IA5STRING *uri) 4585b9c547cSRui Paulo { 4595b9c547cSRui Paulo char txt[100]; 4605b9c547cSRui Paulo int res, len; 4615b9c547cSRui Paulo struct http_logo *n; 4625b9c547cSRui Paulo 4635b9c547cSRui Paulo if (hash == NULL || uri == NULL) 4645b9c547cSRui Paulo return; 4655b9c547cSRui Paulo 4665b9c547cSRui Paulo res = OBJ_obj2txt(txt, sizeof(txt), hash->hashAlg->algorithm, 1); 4675b9c547cSRui Paulo if (res < 0 || res >= (int) sizeof(txt)) 4685b9c547cSRui Paulo return; 4695b9c547cSRui Paulo 4705b9c547cSRui Paulo n = os_realloc_array(hcert->logo, hcert->num_logo + 1, 4715b9c547cSRui Paulo sizeof(struct http_logo)); 4725b9c547cSRui Paulo if (n == NULL) 4735b9c547cSRui Paulo return; 4745b9c547cSRui Paulo hcert->logo = n; 4755b9c547cSRui Paulo n = &hcert->logo[hcert->num_logo]; 4765b9c547cSRui Paulo os_memset(n, 0, sizeof(*n)); 4775b9c547cSRui Paulo 4785b9c547cSRui Paulo n->alg_oid = os_strdup(txt); 4795b9c547cSRui Paulo if (n->alg_oid == NULL) 4805b9c547cSRui Paulo return; 4815b9c547cSRui Paulo 4825b9c547cSRui Paulo n->hash_len = ASN1_STRING_length(hash->hashValue); 4834bc52338SCy Schubert n->hash = os_memdup(ASN1_STRING_get0_data(hash->hashValue), 4844bc52338SCy Schubert n->hash_len); 4855b9c547cSRui Paulo if (n->hash == NULL) { 4865b9c547cSRui Paulo os_free(n->alg_oid); 4875b9c547cSRui Paulo return; 4885b9c547cSRui Paulo } 4895b9c547cSRui Paulo 4905b9c547cSRui Paulo len = ASN1_STRING_length(uri); 4915b9c547cSRui Paulo n->uri = os_malloc(len + 1); 4925b9c547cSRui Paulo if (n->uri == NULL) { 4935b9c547cSRui Paulo os_free(n->alg_oid); 4945b9c547cSRui Paulo os_free(n->hash); 4955b9c547cSRui Paulo return; 4965b9c547cSRui Paulo } 4974bc52338SCy Schubert os_memcpy(n->uri, ASN1_STRING_get0_data(uri), len); 4985b9c547cSRui Paulo n->uri[len] = '\0'; 4995b9c547cSRui Paulo 5005b9c547cSRui Paulo hcert->num_logo++; 5015b9c547cSRui Paulo } 5025b9c547cSRui Paulo 5035b9c547cSRui Paulo 5045b9c547cSRui Paulo static void add_logo_direct(struct http_ctx *ctx, struct http_cert *hcert, 5055b9c547cSRui Paulo LogotypeData *data) 5065b9c547cSRui Paulo { 5075b9c547cSRui Paulo int i, num; 5085b9c547cSRui Paulo 5095b9c547cSRui Paulo if (data->image == NULL) 5105b9c547cSRui Paulo return; 5115b9c547cSRui Paulo 5125b9c547cSRui Paulo num = sk_LogotypeImage_num(data->image); 5135b9c547cSRui Paulo for (i = 0; i < num; i++) { 5145b9c547cSRui Paulo LogotypeImage *image; 5155b9c547cSRui Paulo LogotypeDetails *details; 5165b9c547cSRui Paulo int j, hash_num, uri_num; 5175b9c547cSRui Paulo HashAlgAndValue *found_hash = NULL; 5185b9c547cSRui Paulo 5195b9c547cSRui Paulo image = sk_LogotypeImage_value(data->image, i); 5205b9c547cSRui Paulo if (image == NULL) 5215b9c547cSRui Paulo continue; 5225b9c547cSRui Paulo 5235b9c547cSRui Paulo details = image->imageDetails; 5245b9c547cSRui Paulo if (details == NULL) 5255b9c547cSRui Paulo continue; 5265b9c547cSRui Paulo 5275b9c547cSRui Paulo hash_num = sk_HashAlgAndValue_num(details->logotypeHash); 5285b9c547cSRui Paulo for (j = 0; j < hash_num; j++) { 5295b9c547cSRui Paulo HashAlgAndValue *hash; 5305b9c547cSRui Paulo char txt[100]; 5315b9c547cSRui Paulo int res; 5325b9c547cSRui Paulo hash = sk_HashAlgAndValue_value(details->logotypeHash, 5335b9c547cSRui Paulo j); 5345b9c547cSRui Paulo if (hash == NULL) 5355b9c547cSRui Paulo continue; 5365b9c547cSRui Paulo res = OBJ_obj2txt(txt, sizeof(txt), 5375b9c547cSRui Paulo hash->hashAlg->algorithm, 1); 5385b9c547cSRui Paulo if (res < 0 || res >= (int) sizeof(txt)) 5395b9c547cSRui Paulo continue; 5405b9c547cSRui Paulo if (os_strcmp(txt, "2.16.840.1.101.3.4.2.1") == 0) { 5415b9c547cSRui Paulo found_hash = hash; 5425b9c547cSRui Paulo break; 5435b9c547cSRui Paulo } 5445b9c547cSRui Paulo } 5455b9c547cSRui Paulo 5465b9c547cSRui Paulo if (!found_hash) { 5475b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: No SHA256 hash found for the logo"); 5485b9c547cSRui Paulo continue; 5495b9c547cSRui Paulo } 5505b9c547cSRui Paulo 5515b9c547cSRui Paulo uri_num = sk_ASN1_IA5STRING_num(details->logotypeURI); 5525b9c547cSRui Paulo for (j = 0; j < uri_num; j++) { 5535b9c547cSRui Paulo ASN1_IA5STRING *uri; 5545b9c547cSRui Paulo uri = sk_ASN1_IA5STRING_value(details->logotypeURI, j); 5555b9c547cSRui Paulo add_logo(ctx, hcert, found_hash, uri); 5565b9c547cSRui Paulo } 5575b9c547cSRui Paulo } 5585b9c547cSRui Paulo } 5595b9c547cSRui Paulo 5605b9c547cSRui Paulo 5615b9c547cSRui Paulo static void add_logo_indirect(struct http_ctx *ctx, struct http_cert *hcert, 5625b9c547cSRui Paulo LogotypeReference *ref) 5635b9c547cSRui Paulo { 5645b9c547cSRui Paulo int j, hash_num, uri_num; 5655b9c547cSRui Paulo 5665b9c547cSRui Paulo hash_num = sk_HashAlgAndValue_num(ref->refStructHash); 5675b9c547cSRui Paulo uri_num = sk_ASN1_IA5STRING_num(ref->refStructURI); 5685b9c547cSRui Paulo if (hash_num != uri_num) { 5695b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unexpected LogotypeReference array size difference %d != %d", 5705b9c547cSRui Paulo hash_num, uri_num); 5715b9c547cSRui Paulo return; 5725b9c547cSRui Paulo } 5735b9c547cSRui Paulo 5745b9c547cSRui Paulo for (j = 0; j < hash_num; j++) { 5755b9c547cSRui Paulo HashAlgAndValue *hash; 5765b9c547cSRui Paulo ASN1_IA5STRING *uri; 5775b9c547cSRui Paulo hash = sk_HashAlgAndValue_value(ref->refStructHash, j); 5785b9c547cSRui Paulo uri = sk_ASN1_IA5STRING_value(ref->refStructURI, j); 5795b9c547cSRui Paulo add_logo(ctx, hcert, hash, uri); 5805b9c547cSRui Paulo } 5815b9c547cSRui Paulo } 5825b9c547cSRui Paulo 5835b9c547cSRui Paulo 5845b9c547cSRui Paulo static void i2r_HashAlgAndValue(HashAlgAndValue *hash, BIO *out, int indent) 5855b9c547cSRui Paulo { 5865b9c547cSRui Paulo int i; 5875b9c547cSRui Paulo const unsigned char *data; 5885b9c547cSRui Paulo 5895b9c547cSRui Paulo BIO_printf(out, "%*shashAlg: ", indent, ""); 5905b9c547cSRui Paulo i2a_ASN1_OBJECT(out, hash->hashAlg->algorithm); 5915b9c547cSRui Paulo BIO_printf(out, "\n"); 5925b9c547cSRui Paulo 5935b9c547cSRui Paulo BIO_printf(out, "%*shashValue: ", indent, ""); 5945b9c547cSRui Paulo data = hash->hashValue->data; 5955b9c547cSRui Paulo for (i = 0; i < hash->hashValue->length; i++) 5965b9c547cSRui Paulo BIO_printf(out, "%s%02x", i > 0 ? ":" : "", data[i]); 5975b9c547cSRui Paulo BIO_printf(out, "\n"); 5985b9c547cSRui Paulo } 5995b9c547cSRui Paulo 6005b9c547cSRui Paulo static void i2r_LogotypeDetails(LogotypeDetails *details, BIO *out, int indent) 6015b9c547cSRui Paulo { 6025b9c547cSRui Paulo int i, num; 6035b9c547cSRui Paulo 6045b9c547cSRui Paulo BIO_printf(out, "%*sLogotypeDetails\n", indent, ""); 6055b9c547cSRui Paulo if (details->mediaType) { 6065b9c547cSRui Paulo BIO_printf(out, "%*smediaType: ", indent, ""); 6075b9c547cSRui Paulo ASN1_STRING_print(out, details->mediaType); 6085b9c547cSRui Paulo BIO_printf(out, "\n"); 6095b9c547cSRui Paulo } 6105b9c547cSRui Paulo 6115b9c547cSRui Paulo num = details->logotypeHash ? 6125b9c547cSRui Paulo sk_HashAlgAndValue_num(details->logotypeHash) : 0; 6135b9c547cSRui Paulo for (i = 0; i < num; i++) { 6145b9c547cSRui Paulo HashAlgAndValue *hash; 6155b9c547cSRui Paulo hash = sk_HashAlgAndValue_value(details->logotypeHash, i); 6165b9c547cSRui Paulo i2r_HashAlgAndValue(hash, out, indent); 6175b9c547cSRui Paulo } 6185b9c547cSRui Paulo 6195b9c547cSRui Paulo num = details->logotypeURI ? 6205b9c547cSRui Paulo sk_ASN1_IA5STRING_num(details->logotypeURI) : 0; 6215b9c547cSRui Paulo for (i = 0; i < num; i++) { 6225b9c547cSRui Paulo ASN1_IA5STRING *uri; 6235b9c547cSRui Paulo uri = sk_ASN1_IA5STRING_value(details->logotypeURI, i); 6245b9c547cSRui Paulo BIO_printf(out, "%*slogotypeURI: ", indent, ""); 6255b9c547cSRui Paulo ASN1_STRING_print(out, uri); 6265b9c547cSRui Paulo BIO_printf(out, "\n"); 6275b9c547cSRui Paulo } 6285b9c547cSRui Paulo } 6295b9c547cSRui Paulo 6305b9c547cSRui Paulo static void i2r_LogotypeImageInfo(LogotypeImageInfo *info, BIO *out, int indent) 6315b9c547cSRui Paulo { 6325b9c547cSRui Paulo long val; 6335b9c547cSRui Paulo 6345b9c547cSRui Paulo BIO_printf(out, "%*sLogotypeImageInfo\n", indent, ""); 6355b9c547cSRui Paulo if (info->type) { 6365b9c547cSRui Paulo val = ASN1_INTEGER_get(info->type); 6375b9c547cSRui Paulo BIO_printf(out, "%*stype: %ld\n", indent, "", val); 6385b9c547cSRui Paulo } else { 6395b9c547cSRui Paulo BIO_printf(out, "%*stype: default (1)\n", indent, ""); 6405b9c547cSRui Paulo } 641780fb4a2SCy Schubert val = ASN1_INTEGER_get(info->fileSize); 642780fb4a2SCy Schubert BIO_printf(out, "%*sfileSize: %ld\n", indent, "", val); 6435b9c547cSRui Paulo val = ASN1_INTEGER_get(info->xSize); 6445b9c547cSRui Paulo BIO_printf(out, "%*sxSize: %ld\n", indent, "", val); 6455b9c547cSRui Paulo val = ASN1_INTEGER_get(info->ySize); 6465b9c547cSRui Paulo BIO_printf(out, "%*sySize: %ld\n", indent, "", val); 6475b9c547cSRui Paulo if (info->resolution) { 648780fb4a2SCy Schubert BIO_printf(out, "%*sresolution [%d]\n", indent, "", 649780fb4a2SCy Schubert info->resolution->type); 650780fb4a2SCy Schubert switch (info->resolution->type) { 651780fb4a2SCy Schubert case 0: 652780fb4a2SCy Schubert val = ASN1_INTEGER_get(info->resolution->d.numBits); 653780fb4a2SCy Schubert BIO_printf(out, "%*snumBits: %ld\n", indent, "", val); 654780fb4a2SCy Schubert break; 655780fb4a2SCy Schubert case 1: 656780fb4a2SCy Schubert val = ASN1_INTEGER_get(info->resolution->d.tableSize); 657780fb4a2SCy Schubert BIO_printf(out, "%*stableSize: %ld\n", indent, "", val); 658780fb4a2SCy Schubert break; 659780fb4a2SCy Schubert } 6605b9c547cSRui Paulo } 6615b9c547cSRui Paulo if (info->language) { 6625b9c547cSRui Paulo BIO_printf(out, "%*slanguage: ", indent, ""); 6635b9c547cSRui Paulo ASN1_STRING_print(out, info->language); 6645b9c547cSRui Paulo BIO_printf(out, "\n"); 6655b9c547cSRui Paulo } 6665b9c547cSRui Paulo } 6675b9c547cSRui Paulo 6685b9c547cSRui Paulo static void i2r_LogotypeImage(LogotypeImage *image, BIO *out, int indent) 6695b9c547cSRui Paulo { 6705b9c547cSRui Paulo BIO_printf(out, "%*sLogotypeImage\n", indent, ""); 6715b9c547cSRui Paulo if (image->imageDetails) { 6725b9c547cSRui Paulo i2r_LogotypeDetails(image->imageDetails, out, indent + 4); 6735b9c547cSRui Paulo } 6745b9c547cSRui Paulo if (image->imageInfo) { 6755b9c547cSRui Paulo i2r_LogotypeImageInfo(image->imageInfo, out, indent + 4); 6765b9c547cSRui Paulo } 6775b9c547cSRui Paulo } 6785b9c547cSRui Paulo 6795b9c547cSRui Paulo static void i2r_LogotypeData(LogotypeData *data, const char *title, BIO *out, 6805b9c547cSRui Paulo int indent) 6815b9c547cSRui Paulo { 6825b9c547cSRui Paulo int i, num; 6835b9c547cSRui Paulo 6845b9c547cSRui Paulo BIO_printf(out, "%*s%s - LogotypeData\n", indent, "", title); 6855b9c547cSRui Paulo 6865b9c547cSRui Paulo num = data->image ? sk_LogotypeImage_num(data->image) : 0; 6875b9c547cSRui Paulo for (i = 0; i < num; i++) { 6885b9c547cSRui Paulo LogotypeImage *image = sk_LogotypeImage_value(data->image, i); 6895b9c547cSRui Paulo i2r_LogotypeImage(image, out, indent + 4); 6905b9c547cSRui Paulo } 6915b9c547cSRui Paulo 6925b9c547cSRui Paulo num = data->audio ? sk_LogotypeAudio_num(data->audio) : 0; 6935b9c547cSRui Paulo for (i = 0; i < num; i++) { 6945b9c547cSRui Paulo BIO_printf(out, "%*saudio: TODO\n", indent, ""); 6955b9c547cSRui Paulo } 6965b9c547cSRui Paulo } 6975b9c547cSRui Paulo 6985b9c547cSRui Paulo static void i2r_LogotypeReference(LogotypeReference *ref, const char *title, 6995b9c547cSRui Paulo BIO *out, int indent) 7005b9c547cSRui Paulo { 7015b9c547cSRui Paulo int i, hash_num, uri_num; 7025b9c547cSRui Paulo 7035b9c547cSRui Paulo BIO_printf(out, "%*s%s - LogotypeReference\n", indent, "", title); 7045b9c547cSRui Paulo 7055b9c547cSRui Paulo hash_num = ref->refStructHash ? 7065b9c547cSRui Paulo sk_HashAlgAndValue_num(ref->refStructHash) : 0; 7075b9c547cSRui Paulo uri_num = ref->refStructURI ? 7085b9c547cSRui Paulo sk_ASN1_IA5STRING_num(ref->refStructURI) : 0; 7095b9c547cSRui Paulo if (hash_num != uri_num) { 7105b9c547cSRui Paulo BIO_printf(out, "%*sUnexpected LogotypeReference array size difference %d != %d\n", 7115b9c547cSRui Paulo indent, "", hash_num, uri_num); 7125b9c547cSRui Paulo return; 7135b9c547cSRui Paulo } 7145b9c547cSRui Paulo 7155b9c547cSRui Paulo for (i = 0; i < hash_num; i++) { 7165b9c547cSRui Paulo HashAlgAndValue *hash; 7175b9c547cSRui Paulo ASN1_IA5STRING *uri; 7185b9c547cSRui Paulo 7195b9c547cSRui Paulo hash = sk_HashAlgAndValue_value(ref->refStructHash, i); 7205b9c547cSRui Paulo i2r_HashAlgAndValue(hash, out, indent); 7215b9c547cSRui Paulo 7225b9c547cSRui Paulo uri = sk_ASN1_IA5STRING_value(ref->refStructURI, i); 7235b9c547cSRui Paulo BIO_printf(out, "%*srefStructURI: ", indent, ""); 7245b9c547cSRui Paulo ASN1_STRING_print(out, uri); 7255b9c547cSRui Paulo BIO_printf(out, "\n"); 7265b9c547cSRui Paulo } 7275b9c547cSRui Paulo } 7285b9c547cSRui Paulo 7295b9c547cSRui Paulo static void i2r_LogotypeInfo(LogotypeInfo *info, const char *title, BIO *out, 7305b9c547cSRui Paulo int indent) 7315b9c547cSRui Paulo { 7325b9c547cSRui Paulo switch (info->type) { 7335b9c547cSRui Paulo case 0: 7345b9c547cSRui Paulo i2r_LogotypeData(info->d.direct, title, out, indent); 7355b9c547cSRui Paulo break; 7365b9c547cSRui Paulo case 1: 7375b9c547cSRui Paulo i2r_LogotypeReference(info->d.indirect, title, out, indent); 7385b9c547cSRui Paulo break; 7395b9c547cSRui Paulo } 7405b9c547cSRui Paulo } 7415b9c547cSRui Paulo 7425b9c547cSRui Paulo static void debug_print_logotypeext(LogotypeExtn *logo) 7435b9c547cSRui Paulo { 7445b9c547cSRui Paulo BIO *out; 7455b9c547cSRui Paulo int i, num; 7465b9c547cSRui Paulo int indent = 0; 7475b9c547cSRui Paulo 7485b9c547cSRui Paulo out = BIO_new_fp(stdout, BIO_NOCLOSE); 7495b9c547cSRui Paulo if (out == NULL) 7505b9c547cSRui Paulo return; 7515b9c547cSRui Paulo 7525b9c547cSRui Paulo if (logo->communityLogos) { 7535b9c547cSRui Paulo num = sk_LogotypeInfo_num(logo->communityLogos); 7545b9c547cSRui Paulo for (i = 0; i < num; i++) { 7555b9c547cSRui Paulo LogotypeInfo *info; 7565b9c547cSRui Paulo info = sk_LogotypeInfo_value(logo->communityLogos, i); 7575b9c547cSRui Paulo i2r_LogotypeInfo(info, "communityLogo", out, indent); 7585b9c547cSRui Paulo } 7595b9c547cSRui Paulo } 7605b9c547cSRui Paulo 7615b9c547cSRui Paulo if (logo->issuerLogo) { 7625b9c547cSRui Paulo i2r_LogotypeInfo(logo->issuerLogo, "issuerLogo", out, indent ); 7635b9c547cSRui Paulo } 7645b9c547cSRui Paulo 7655b9c547cSRui Paulo if (logo->subjectLogo) { 7665b9c547cSRui Paulo i2r_LogotypeInfo(logo->subjectLogo, "subjectLogo", out, indent); 7675b9c547cSRui Paulo } 7685b9c547cSRui Paulo 7695b9c547cSRui Paulo if (logo->otherLogos) { 7705b9c547cSRui Paulo BIO_printf(out, "%*sotherLogos - TODO\n", indent, ""); 7715b9c547cSRui Paulo } 7725b9c547cSRui Paulo 7735b9c547cSRui Paulo BIO_free(out); 7745b9c547cSRui Paulo } 7755b9c547cSRui Paulo 7765b9c547cSRui Paulo 7775b9c547cSRui Paulo static void add_logotype_ext(struct http_ctx *ctx, struct http_cert *hcert, 7785b9c547cSRui Paulo X509 *cert) 7795b9c547cSRui Paulo { 7805b9c547cSRui Paulo ASN1_OBJECT *obj; 7815b9c547cSRui Paulo int pos; 7825b9c547cSRui Paulo X509_EXTENSION *ext; 7835b9c547cSRui Paulo ASN1_OCTET_STRING *os; 7845b9c547cSRui Paulo LogotypeExtn *logo; 7855b9c547cSRui Paulo const unsigned char *data; 7865b9c547cSRui Paulo int i, num; 7875b9c547cSRui Paulo 7885b9c547cSRui Paulo obj = OBJ_txt2obj("1.3.6.1.5.5.7.1.12", 0); 7895b9c547cSRui Paulo if (obj == NULL) 7905b9c547cSRui Paulo return; 7915b9c547cSRui Paulo 7925b9c547cSRui Paulo pos = X509_get_ext_by_OBJ(cert, obj, -1); 7935b9c547cSRui Paulo if (pos < 0) { 7945b9c547cSRui Paulo wpa_printf(MSG_INFO, "No logotype extension included"); 7955b9c547cSRui Paulo return; 7965b9c547cSRui Paulo } 7975b9c547cSRui Paulo 7985b9c547cSRui Paulo wpa_printf(MSG_INFO, "Parsing logotype extension"); 7995b9c547cSRui Paulo ext = X509_get_ext(cert, pos); 8005b9c547cSRui Paulo if (!ext) { 8015b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get logotype extension"); 8025b9c547cSRui Paulo return; 8035b9c547cSRui Paulo } 8045b9c547cSRui Paulo 8055b9c547cSRui Paulo os = X509_EXTENSION_get_data(ext); 8065b9c547cSRui Paulo if (os == NULL) { 8075b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get logotype extension data"); 8085b9c547cSRui Paulo return; 8095b9c547cSRui Paulo } 8105b9c547cSRui Paulo 8115b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "logotypeExtn", 8124bc52338SCy Schubert ASN1_STRING_get0_data(os), ASN1_STRING_length(os)); 8135b9c547cSRui Paulo 8144bc52338SCy Schubert data = ASN1_STRING_get0_data(os); 8155b9c547cSRui Paulo logo = d2i_LogotypeExtn(NULL, &data, ASN1_STRING_length(os)); 8165b9c547cSRui Paulo if (logo == NULL) { 8175b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to parse logotypeExtn"); 8185b9c547cSRui Paulo return; 8195b9c547cSRui Paulo } 8205b9c547cSRui Paulo 8215b9c547cSRui Paulo if (wpa_debug_level < MSG_INFO) 8225b9c547cSRui Paulo debug_print_logotypeext(logo); 8235b9c547cSRui Paulo 8245b9c547cSRui Paulo if (!logo->communityLogos) { 8255b9c547cSRui Paulo wpa_printf(MSG_INFO, "No communityLogos included"); 8265b9c547cSRui Paulo LogotypeExtn_free(logo); 8275b9c547cSRui Paulo return; 8285b9c547cSRui Paulo } 8295b9c547cSRui Paulo 8305b9c547cSRui Paulo num = sk_LogotypeInfo_num(logo->communityLogos); 8315b9c547cSRui Paulo for (i = 0; i < num; i++) { 8325b9c547cSRui Paulo LogotypeInfo *info; 8335b9c547cSRui Paulo info = sk_LogotypeInfo_value(logo->communityLogos, i); 8345b9c547cSRui Paulo switch (info->type) { 8355b9c547cSRui Paulo case 0: 8365b9c547cSRui Paulo add_logo_direct(ctx, hcert, info->d.direct); 8375b9c547cSRui Paulo break; 8385b9c547cSRui Paulo case 1: 8395b9c547cSRui Paulo add_logo_indirect(ctx, hcert, info->d.indirect); 8405b9c547cSRui Paulo break; 8415b9c547cSRui Paulo } 8425b9c547cSRui Paulo } 8435b9c547cSRui Paulo 8445b9c547cSRui Paulo LogotypeExtn_free(logo); 8455b9c547cSRui Paulo } 8465b9c547cSRui Paulo 8475b9c547cSRui Paulo 8485b9c547cSRui Paulo static void parse_cert(struct http_ctx *ctx, struct http_cert *hcert, 8495b9c547cSRui Paulo X509 *cert, GENERAL_NAMES **names) 8505b9c547cSRui Paulo { 8515b9c547cSRui Paulo os_memset(hcert, 0, sizeof(*hcert)); 852*a90b9d01SCy Schubert hcert->url = ctx->url ? ctx->url : ctx->svc_address; 8535b9c547cSRui Paulo 8545b9c547cSRui Paulo *names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); 8555b9c547cSRui Paulo if (*names) 8565b9c547cSRui Paulo add_alt_names(ctx, hcert, *names); 8575b9c547cSRui Paulo 8585b9c547cSRui Paulo add_logotype_ext(ctx, hcert, cert); 8595b9c547cSRui Paulo } 8605b9c547cSRui Paulo 8615b9c547cSRui Paulo 8625b9c547cSRui Paulo static void parse_cert_free(struct http_cert *hcert, GENERAL_NAMES *names) 8635b9c547cSRui Paulo { 8645b9c547cSRui Paulo unsigned int i; 8655b9c547cSRui Paulo 8665b9c547cSRui Paulo for (i = 0; i < hcert->num_dnsname; i++) 8675b9c547cSRui Paulo OPENSSL_free(hcert->dnsname[i]); 8685b9c547cSRui Paulo os_free(hcert->dnsname); 8695b9c547cSRui Paulo 8705b9c547cSRui Paulo for (i = 0; i < hcert->num_othername; i++) 8715b9c547cSRui Paulo os_free(hcert->othername[i].oid); 8725b9c547cSRui Paulo os_free(hcert->othername); 8735b9c547cSRui Paulo 8745b9c547cSRui Paulo for (i = 0; i < hcert->num_logo; i++) { 8755b9c547cSRui Paulo os_free(hcert->logo[i].alg_oid); 8765b9c547cSRui Paulo os_free(hcert->logo[i].hash); 8775b9c547cSRui Paulo os_free(hcert->logo[i].uri); 8785b9c547cSRui Paulo } 8795b9c547cSRui Paulo os_free(hcert->logo); 8805b9c547cSRui Paulo 8815b9c547cSRui Paulo sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); 8825b9c547cSRui Paulo } 8835b9c547cSRui Paulo 8845b9c547cSRui Paulo 8855b9c547cSRui Paulo static int validate_server_cert(struct http_ctx *ctx, X509 *cert) 8865b9c547cSRui Paulo { 8875b9c547cSRui Paulo GENERAL_NAMES *names; 8885b9c547cSRui Paulo struct http_cert hcert; 8895b9c547cSRui Paulo int ret; 8905b9c547cSRui Paulo 891325151a3SRui Paulo if (ctx->cert_cb == NULL) { 892325151a3SRui Paulo wpa_printf(MSG_DEBUG, "%s: no cert_cb configured", __func__); 8935b9c547cSRui Paulo return 0; 894325151a3SRui Paulo } 8955b9c547cSRui Paulo 8965b9c547cSRui Paulo if (0) { 8975b9c547cSRui Paulo BIO *out; 8985b9c547cSRui Paulo out = BIO_new_fp(stdout, BIO_NOCLOSE); 8995b9c547cSRui Paulo X509_print_ex(out, cert, XN_FLAG_COMPAT, X509_FLAG_COMPAT); 9005b9c547cSRui Paulo BIO_free(out); 9015b9c547cSRui Paulo } 9025b9c547cSRui Paulo 9035b9c547cSRui Paulo parse_cert(ctx, &hcert, cert, &names); 9045b9c547cSRui Paulo ret = ctx->cert_cb(ctx->cert_cb_ctx, &hcert); 9055b9c547cSRui Paulo parse_cert_free(&hcert, names); 9065b9c547cSRui Paulo 9075b9c547cSRui Paulo return ret; 9085b9c547cSRui Paulo } 9095b9c547cSRui Paulo 9105b9c547cSRui Paulo 9115b9c547cSRui Paulo void http_parse_x509_certificate(struct http_ctx *ctx, const char *fname) 9125b9c547cSRui Paulo { 9135b9c547cSRui Paulo BIO *in, *out; 9145b9c547cSRui Paulo X509 *cert; 9155b9c547cSRui Paulo GENERAL_NAMES *names; 9165b9c547cSRui Paulo struct http_cert hcert; 9175b9c547cSRui Paulo unsigned int i; 9185b9c547cSRui Paulo 9195b9c547cSRui Paulo in = BIO_new_file(fname, "r"); 9205b9c547cSRui Paulo if (in == NULL) { 9215b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not read '%s'", fname); 9225b9c547cSRui Paulo return; 9235b9c547cSRui Paulo } 9245b9c547cSRui Paulo 9255b9c547cSRui Paulo cert = d2i_X509_bio(in, NULL); 9265b9c547cSRui Paulo BIO_free(in); 9275b9c547cSRui Paulo 9285b9c547cSRui Paulo if (cert == NULL) { 9295b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not parse certificate"); 9305b9c547cSRui Paulo return; 9315b9c547cSRui Paulo } 9325b9c547cSRui Paulo 9335b9c547cSRui Paulo out = BIO_new_fp(stdout, BIO_NOCLOSE); 9345b9c547cSRui Paulo if (out) { 9355b9c547cSRui Paulo X509_print_ex(out, cert, XN_FLAG_COMPAT, 9365b9c547cSRui Paulo X509_FLAG_COMPAT); 9375b9c547cSRui Paulo BIO_free(out); 9385b9c547cSRui Paulo } 9395b9c547cSRui Paulo 9405b9c547cSRui Paulo wpa_printf(MSG_INFO, "Additional parsing information:"); 9415b9c547cSRui Paulo parse_cert(ctx, &hcert, cert, &names); 9425b9c547cSRui Paulo for (i = 0; i < hcert.num_othername; i++) { 9435b9c547cSRui Paulo if (os_strcmp(hcert.othername[i].oid, 9445b9c547cSRui Paulo "1.3.6.1.4.1.40808.1.1.1") == 0) { 9455b9c547cSRui Paulo char *name = os_zalloc(hcert.othername[i].len + 1); 9465b9c547cSRui Paulo if (name) { 9475b9c547cSRui Paulo os_memcpy(name, hcert.othername[i].data, 9485b9c547cSRui Paulo hcert.othername[i].len); 9495b9c547cSRui Paulo wpa_printf(MSG_INFO, 9505b9c547cSRui Paulo "id-wfa-hotspot-friendlyName: %s", 9515b9c547cSRui Paulo name); 9525b9c547cSRui Paulo os_free(name); 9535b9c547cSRui Paulo } 9545b9c547cSRui Paulo wpa_hexdump_ascii(MSG_INFO, 9555b9c547cSRui Paulo "id-wfa-hotspot-friendlyName", 9565b9c547cSRui Paulo hcert.othername[i].data, 9575b9c547cSRui Paulo hcert.othername[i].len); 9585b9c547cSRui Paulo } else { 9595b9c547cSRui Paulo wpa_printf(MSG_INFO, "subjAltName[othername]: oid=%s", 9605b9c547cSRui Paulo hcert.othername[i].oid); 9615b9c547cSRui Paulo wpa_hexdump_ascii(MSG_INFO, "unknown othername", 9625b9c547cSRui Paulo hcert.othername[i].data, 9635b9c547cSRui Paulo hcert.othername[i].len); 9645b9c547cSRui Paulo } 9655b9c547cSRui Paulo } 9665b9c547cSRui Paulo parse_cert_free(&hcert, names); 9675b9c547cSRui Paulo 9685b9c547cSRui Paulo X509_free(cert); 9695b9c547cSRui Paulo } 9705b9c547cSRui Paulo 9715b9c547cSRui Paulo 9725b9c547cSRui Paulo static int curl_cb_ssl_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) 9735b9c547cSRui Paulo { 9745b9c547cSRui Paulo struct http_ctx *ctx; 9755b9c547cSRui Paulo X509 *cert; 9765b9c547cSRui Paulo int err, depth; 9775b9c547cSRui Paulo char buf[256]; 9785b9c547cSRui Paulo X509_NAME *name; 9795b9c547cSRui Paulo const char *err_str; 9805b9c547cSRui Paulo SSL *ssl; 9815b9c547cSRui Paulo SSL_CTX *ssl_ctx; 9825b9c547cSRui Paulo 9835b9c547cSRui Paulo ssl = X509_STORE_CTX_get_ex_data(x509_ctx, 9845b9c547cSRui Paulo SSL_get_ex_data_X509_STORE_CTX_idx()); 98585732ac8SCy Schubert ssl_ctx = SSL_get_SSL_CTX(ssl); 9865b9c547cSRui Paulo ctx = SSL_CTX_get_app_data(ssl_ctx); 9875b9c547cSRui Paulo 988325151a3SRui Paulo wpa_printf(MSG_DEBUG, "curl_cb_ssl_verify, preverify_ok: %d", 989325151a3SRui Paulo preverify_ok); 9905b9c547cSRui Paulo 9915b9c547cSRui Paulo err = X509_STORE_CTX_get_error(x509_ctx); 9925b9c547cSRui Paulo err_str = X509_verify_cert_error_string(err); 9935b9c547cSRui Paulo depth = X509_STORE_CTX_get_error_depth(x509_ctx); 9945b9c547cSRui Paulo cert = X509_STORE_CTX_get_current_cert(x509_ctx); 9955b9c547cSRui Paulo if (!cert) { 9965b9c547cSRui Paulo wpa_printf(MSG_INFO, "No server certificate available"); 9975b9c547cSRui Paulo ctx->last_err = "No server certificate available"; 9985b9c547cSRui Paulo return 0; 9995b9c547cSRui Paulo } 10005b9c547cSRui Paulo 10015b9c547cSRui Paulo if (depth == 0) 10025b9c547cSRui Paulo ctx->peer_cert = cert; 10035b9c547cSRui Paulo else if (depth == 1) 10045b9c547cSRui Paulo ctx->peer_issuer = cert; 10055b9c547cSRui Paulo else if (depth == 2) 10065b9c547cSRui Paulo ctx->peer_issuer_issuer = cert; 10075b9c547cSRui Paulo 10085b9c547cSRui Paulo name = X509_get_subject_name(cert); 10095b9c547cSRui Paulo X509_NAME_oneline(name, buf, sizeof(buf)); 10105b9c547cSRui Paulo wpa_printf(MSG_INFO, "Server certificate chain - depth=%d err=%d (%s) subject=%s", 10115b9c547cSRui Paulo depth, err, err_str, buf); 10125b9c547cSRui Paulo debug_dump_cert("Server certificate chain - certificate", cert); 10135b9c547cSRui Paulo 10145b9c547cSRui Paulo if (depth == 0 && preverify_ok && validate_server_cert(ctx, cert) < 0) 10155b9c547cSRui Paulo return 0; 10165b9c547cSRui Paulo 1017780fb4a2SCy Schubert #ifdef OPENSSL_IS_BORINGSSL 1018780fb4a2SCy Schubert if (depth == 0 && ctx->ocsp != NO_OCSP && preverify_ok) { 1019780fb4a2SCy Schubert enum ocsp_result res; 1020780fb4a2SCy Schubert 1021780fb4a2SCy Schubert res = check_ocsp_resp(ssl_ctx, ssl, cert, ctx->peer_issuer, 1022780fb4a2SCy Schubert ctx->peer_issuer_issuer); 1023780fb4a2SCy Schubert if (res == OCSP_REVOKED) { 1024780fb4a2SCy Schubert preverify_ok = 0; 1025780fb4a2SCy Schubert wpa_printf(MSG_INFO, "OCSP: certificate revoked"); 1026780fb4a2SCy Schubert if (err == X509_V_OK) 1027780fb4a2SCy Schubert X509_STORE_CTX_set_error( 1028780fb4a2SCy Schubert x509_ctx, X509_V_ERR_CERT_REVOKED); 1029780fb4a2SCy Schubert } else if (res != OCSP_GOOD && (ctx->ocsp == MANDATORY_OCSP)) { 1030780fb4a2SCy Schubert preverify_ok = 0; 1031780fb4a2SCy Schubert wpa_printf(MSG_INFO, 1032780fb4a2SCy Schubert "OCSP: bad certificate status response"); 1033780fb4a2SCy Schubert } 1034780fb4a2SCy Schubert } 1035780fb4a2SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */ 1036780fb4a2SCy Schubert 10375b9c547cSRui Paulo if (!preverify_ok) 10385b9c547cSRui Paulo ctx->last_err = "TLS validation failed"; 10395b9c547cSRui Paulo 10405b9c547cSRui Paulo return preverify_ok; 10415b9c547cSRui Paulo } 10425b9c547cSRui Paulo 10435b9c547cSRui Paulo 10445b9c547cSRui Paulo #ifdef HAVE_OCSP 10455b9c547cSRui Paulo 10465b9c547cSRui Paulo static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp) 10475b9c547cSRui Paulo { 10485b9c547cSRui Paulo BIO *out; 10495b9c547cSRui Paulo size_t rlen; 10505b9c547cSRui Paulo char *txt; 10515b9c547cSRui Paulo int res; 10525b9c547cSRui Paulo 10535b9c547cSRui Paulo out = BIO_new(BIO_s_mem()); 10545b9c547cSRui Paulo if (!out) 10555b9c547cSRui Paulo return; 10565b9c547cSRui Paulo 10575b9c547cSRui Paulo OCSP_RESPONSE_print(out, rsp, 0); 10585b9c547cSRui Paulo rlen = BIO_ctrl_pending(out); 10595b9c547cSRui Paulo txt = os_malloc(rlen + 1); 10605b9c547cSRui Paulo if (!txt) { 10615b9c547cSRui Paulo BIO_free(out); 10625b9c547cSRui Paulo return; 10635b9c547cSRui Paulo } 10645b9c547cSRui Paulo 10655b9c547cSRui Paulo res = BIO_read(out, txt, rlen); 10665b9c547cSRui Paulo if (res > 0) { 10675b9c547cSRui Paulo txt[res] = '\0'; 10685b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, "OpenSSL: OCSP Response\n%s", txt); 10695b9c547cSRui Paulo } 10705b9c547cSRui Paulo os_free(txt); 10715b9c547cSRui Paulo BIO_free(out); 10725b9c547cSRui Paulo } 10735b9c547cSRui Paulo 10745b9c547cSRui Paulo 10755b9c547cSRui Paulo static void tls_show_errors(const char *func, const char *txt) 10765b9c547cSRui Paulo { 10775b9c547cSRui Paulo unsigned long err; 10785b9c547cSRui Paulo 10795b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: %s - %s %s", 10805b9c547cSRui Paulo func, txt, ERR_error_string(ERR_get_error(), NULL)); 10815b9c547cSRui Paulo 10825b9c547cSRui Paulo while ((err = ERR_get_error())) { 10835b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: pending error: %s", 10845b9c547cSRui Paulo ERR_error_string(err, NULL)); 10855b9c547cSRui Paulo } 10865b9c547cSRui Paulo } 10875b9c547cSRui Paulo 10885b9c547cSRui Paulo 10895b9c547cSRui Paulo static int ocsp_resp_cb(SSL *s, void *arg) 10905b9c547cSRui Paulo { 10915b9c547cSRui Paulo struct http_ctx *ctx = arg; 10925b9c547cSRui Paulo const unsigned char *p; 109385732ac8SCy Schubert int len, status, reason, res; 10945b9c547cSRui Paulo OCSP_RESPONSE *rsp; 10955b9c547cSRui Paulo OCSP_BASICRESP *basic; 10965b9c547cSRui Paulo OCSP_CERTID *id; 10975b9c547cSRui Paulo ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update; 10985b9c547cSRui Paulo X509_STORE *store; 10995b9c547cSRui Paulo STACK_OF(X509) *certs = NULL; 11005b9c547cSRui Paulo 11015b9c547cSRui Paulo len = SSL_get_tlsext_status_ocsp_resp(s, &p); 11025b9c547cSRui Paulo if (!p) { 11035b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received"); 11045b9c547cSRui Paulo if (ctx->ocsp == MANDATORY_OCSP) 11055b9c547cSRui Paulo ctx->last_err = "No OCSP response received"; 11065b9c547cSRui Paulo return (ctx->ocsp == MANDATORY_OCSP) ? 0 : 1; 11075b9c547cSRui Paulo } 11085b9c547cSRui Paulo 11095b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len); 11105b9c547cSRui Paulo 11115b9c547cSRui Paulo rsp = d2i_OCSP_RESPONSE(NULL, &p, len); 11125b9c547cSRui Paulo if (!rsp) { 11135b9c547cSRui Paulo wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response"); 11145b9c547cSRui Paulo ctx->last_err = "Failed to parse OCSP response"; 11155b9c547cSRui Paulo return 0; 11165b9c547cSRui Paulo } 11175b9c547cSRui Paulo 11185b9c547cSRui Paulo ocsp_debug_print_resp(rsp); 11195b9c547cSRui Paulo 11205b9c547cSRui Paulo status = OCSP_response_status(rsp); 11215b9c547cSRui Paulo if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { 11225b9c547cSRui Paulo wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)", 11235b9c547cSRui Paulo status, OCSP_response_status_str(status)); 11245b9c547cSRui Paulo ctx->last_err = "OCSP responder error"; 11255b9c547cSRui Paulo return 0; 11265b9c547cSRui Paulo } 11275b9c547cSRui Paulo 11285b9c547cSRui Paulo basic = OCSP_response_get1_basic(rsp); 11295b9c547cSRui Paulo if (!basic) { 11305b9c547cSRui Paulo wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse"); 11315b9c547cSRui Paulo ctx->last_err = "Could not find BasicOCSPResponse"; 11325b9c547cSRui Paulo return 0; 11335b9c547cSRui Paulo } 11345b9c547cSRui Paulo 11354bc52338SCy Schubert store = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(s)); 11365b9c547cSRui Paulo if (ctx->peer_issuer) { 11375b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Add issuer"); 11385b9c547cSRui Paulo debug_dump_cert("OpenSSL: Issuer certificate", 11395b9c547cSRui Paulo ctx->peer_issuer); 11405b9c547cSRui Paulo 11415b9c547cSRui Paulo if (X509_STORE_add_cert(store, ctx->peer_issuer) != 1) { 11425b9c547cSRui Paulo tls_show_errors(__func__, 11435b9c547cSRui Paulo "OpenSSL: Could not add issuer to certificate store"); 11445b9c547cSRui Paulo } 11455b9c547cSRui Paulo certs = sk_X509_new_null(); 11465b9c547cSRui Paulo if (certs) { 11475b9c547cSRui Paulo X509 *cert; 11485b9c547cSRui Paulo cert = X509_dup(ctx->peer_issuer); 11495b9c547cSRui Paulo if (cert && !sk_X509_push(certs, cert)) { 11505b9c547cSRui Paulo tls_show_errors( 11515b9c547cSRui Paulo __func__, 11525b9c547cSRui Paulo "OpenSSL: Could not add issuer to OCSP responder trust store"); 11535b9c547cSRui Paulo X509_free(cert); 11545b9c547cSRui Paulo sk_X509_free(certs); 11555b9c547cSRui Paulo certs = NULL; 11565b9c547cSRui Paulo } 11575b9c547cSRui Paulo if (certs && ctx->peer_issuer_issuer) { 11585b9c547cSRui Paulo cert = X509_dup(ctx->peer_issuer_issuer); 11595b9c547cSRui Paulo if (cert && !sk_X509_push(certs, cert)) { 11605b9c547cSRui Paulo tls_show_errors( 11615b9c547cSRui Paulo __func__, 11625b9c547cSRui Paulo "OpenSSL: Could not add issuer's issuer to OCSP responder trust store"); 11635b9c547cSRui Paulo X509_free(cert); 11645b9c547cSRui Paulo } 11655b9c547cSRui Paulo } 11665b9c547cSRui Paulo } 11675b9c547cSRui Paulo } 11685b9c547cSRui Paulo 11695b9c547cSRui Paulo status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER); 11705b9c547cSRui Paulo sk_X509_pop_free(certs, X509_free); 11715b9c547cSRui Paulo if (status <= 0) { 11725b9c547cSRui Paulo tls_show_errors(__func__, 11735b9c547cSRui Paulo "OpenSSL: OCSP response failed verification"); 11745b9c547cSRui Paulo OCSP_BASICRESP_free(basic); 11755b9c547cSRui Paulo OCSP_RESPONSE_free(rsp); 11765b9c547cSRui Paulo ctx->last_err = "OCSP response failed verification"; 11775b9c547cSRui Paulo return 0; 11785b9c547cSRui Paulo } 11795b9c547cSRui Paulo 11805b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded"); 11815b9c547cSRui Paulo 11825b9c547cSRui Paulo if (!ctx->peer_cert) { 11835b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check"); 11845b9c547cSRui Paulo OCSP_BASICRESP_free(basic); 11855b9c547cSRui Paulo OCSP_RESPONSE_free(rsp); 11865b9c547cSRui Paulo ctx->last_err = "Peer certificate not available for OCSP status check"; 11875b9c547cSRui Paulo return 0; 11885b9c547cSRui Paulo } 11895b9c547cSRui Paulo 11905b9c547cSRui Paulo if (!ctx->peer_issuer) { 11915b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check"); 11925b9c547cSRui Paulo OCSP_BASICRESP_free(basic); 11935b9c547cSRui Paulo OCSP_RESPONSE_free(rsp); 11945b9c547cSRui Paulo ctx->last_err = "Peer issuer certificate not available for OCSP status check"; 11955b9c547cSRui Paulo return 0; 11965b9c547cSRui Paulo } 11975b9c547cSRui Paulo 119885732ac8SCy Schubert id = OCSP_cert_to_id(EVP_sha256(), ctx->peer_cert, ctx->peer_issuer); 11995b9c547cSRui Paulo if (!id) { 120085732ac8SCy Schubert wpa_printf(MSG_DEBUG, 120185732ac8SCy Schubert "OpenSSL: Could not create OCSP certificate identifier (SHA256)"); 12025b9c547cSRui Paulo OCSP_BASICRESP_free(basic); 12035b9c547cSRui Paulo OCSP_RESPONSE_free(rsp); 12045b9c547cSRui Paulo ctx->last_err = "Could not create OCSP certificate identifier"; 12055b9c547cSRui Paulo return 0; 12065b9c547cSRui Paulo } 12075b9c547cSRui Paulo 120885732ac8SCy Schubert res = OCSP_resp_find_status(basic, id, &status, &reason, &produced_at, 120985732ac8SCy Schubert &this_update, &next_update); 121085732ac8SCy Schubert if (!res) { 121185732ac8SCy Schubert id = OCSP_cert_to_id(NULL, ctx->peer_cert, ctx->peer_issuer); 121285732ac8SCy Schubert if (!id) { 121385732ac8SCy Schubert wpa_printf(MSG_DEBUG, 121485732ac8SCy Schubert "OpenSSL: Could not create OCSP certificate identifier (SHA1)"); 121585732ac8SCy Schubert OCSP_BASICRESP_free(basic); 121685732ac8SCy Schubert OCSP_RESPONSE_free(rsp); 121785732ac8SCy Schubert ctx->last_err = 121885732ac8SCy Schubert "Could not create OCSP certificate identifier"; 121985732ac8SCy Schubert return 0; 122085732ac8SCy Schubert } 122185732ac8SCy Schubert 122285732ac8SCy Schubert res = OCSP_resp_find_status(basic, id, &status, &reason, 122385732ac8SCy Schubert &produced_at, &this_update, 122485732ac8SCy Schubert &next_update); 122585732ac8SCy Schubert } 122685732ac8SCy Schubert 122785732ac8SCy Schubert if (!res) { 12285b9c547cSRui Paulo wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s", 12295b9c547cSRui Paulo (ctx->ocsp == MANDATORY_OCSP) ? "" : 12305b9c547cSRui Paulo " (OCSP not required)"); 1231780fb4a2SCy Schubert OCSP_CERTID_free(id); 12325b9c547cSRui Paulo OCSP_BASICRESP_free(basic); 12335b9c547cSRui Paulo OCSP_RESPONSE_free(rsp); 12345b9c547cSRui Paulo if (ctx->ocsp == MANDATORY_OCSP) 12355b9c547cSRui Paulo 12365b9c547cSRui Paulo ctx->last_err = "Could not find current server certificate from OCSP response"; 12375b9c547cSRui Paulo return (ctx->ocsp == MANDATORY_OCSP) ? 0 : 1; 12385b9c547cSRui Paulo } 1239780fb4a2SCy Schubert OCSP_CERTID_free(id); 12405b9c547cSRui Paulo 12415b9c547cSRui Paulo if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) { 12425b9c547cSRui Paulo tls_show_errors(__func__, "OpenSSL: OCSP status times invalid"); 12435b9c547cSRui Paulo OCSP_BASICRESP_free(basic); 12445b9c547cSRui Paulo OCSP_RESPONSE_free(rsp); 12455b9c547cSRui Paulo ctx->last_err = "OCSP status times invalid"; 12465b9c547cSRui Paulo return 0; 12475b9c547cSRui Paulo } 12485b9c547cSRui Paulo 12495b9c547cSRui Paulo OCSP_BASICRESP_free(basic); 12505b9c547cSRui Paulo OCSP_RESPONSE_free(rsp); 12515b9c547cSRui Paulo 12525b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s", 12535b9c547cSRui Paulo OCSP_cert_status_str(status)); 12545b9c547cSRui Paulo 12555b9c547cSRui Paulo if (status == V_OCSP_CERTSTATUS_GOOD) 12565b9c547cSRui Paulo return 1; 12575b9c547cSRui Paulo if (status == V_OCSP_CERTSTATUS_REVOKED) { 12585b9c547cSRui Paulo ctx->last_err = "Server certificate has been revoked"; 12595b9c547cSRui Paulo return 0; 12605b9c547cSRui Paulo } 12615b9c547cSRui Paulo if (ctx->ocsp == MANDATORY_OCSP) { 12625b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required"); 12635b9c547cSRui Paulo ctx->last_err = "OCSP status unknown"; 12645b9c547cSRui Paulo return 0; 12655b9c547cSRui Paulo } 12665b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue"); 12675b9c547cSRui Paulo return 1; 12685b9c547cSRui Paulo } 12695b9c547cSRui Paulo 12705b9c547cSRui Paulo 12714bc52338SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L 12725b9c547cSRui Paulo static SSL_METHOD patch_ssl_method; 12735b9c547cSRui Paulo static const SSL_METHOD *real_ssl_method; 12745b9c547cSRui Paulo 12755b9c547cSRui Paulo static int curl_patch_ssl_new(SSL *s) 12765b9c547cSRui Paulo { 12774bc52338SCy Schubert SSL_CTX *ssl = SSL_get_SSL_CTX(s); 12785b9c547cSRui Paulo int ret; 12795b9c547cSRui Paulo 12805b9c547cSRui Paulo ssl->method = real_ssl_method; 12815b9c547cSRui Paulo s->method = real_ssl_method; 12825b9c547cSRui Paulo 12835b9c547cSRui Paulo ret = s->method->ssl_new(s); 12845b9c547cSRui Paulo SSL_set_tlsext_status_type(s, TLSEXT_STATUSTYPE_ocsp); 12855b9c547cSRui Paulo 12865b9c547cSRui Paulo return ret; 12875b9c547cSRui Paulo } 12884bc52338SCy Schubert #endif /* OpenSSL < 1.1.0 */ 12895b9c547cSRui Paulo 12905b9c547cSRui Paulo #endif /* HAVE_OCSP */ 12915b9c547cSRui Paulo 12925b9c547cSRui Paulo 12935b9c547cSRui Paulo static CURLcode curl_cb_ssl(CURL *curl, void *sslctx, void *parm) 12945b9c547cSRui Paulo { 12955b9c547cSRui Paulo struct http_ctx *ctx = parm; 12965b9c547cSRui Paulo SSL_CTX *ssl = sslctx; 12975b9c547cSRui Paulo 12985b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "curl_cb_ssl"); 12995b9c547cSRui Paulo SSL_CTX_set_app_data(ssl, ctx); 13005b9c547cSRui Paulo SSL_CTX_set_verify(ssl, SSL_VERIFY_PEER, curl_cb_ssl_verify); 13015b9c547cSRui Paulo 13025b9c547cSRui Paulo #ifdef HAVE_OCSP 13035b9c547cSRui Paulo if (ctx->ocsp != NO_OCSP) { 13045b9c547cSRui Paulo SSL_CTX_set_tlsext_status_cb(ssl, ocsp_resp_cb); 13055b9c547cSRui Paulo SSL_CTX_set_tlsext_status_arg(ssl, ctx); 13065b9c547cSRui Paulo 13074bc52338SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L 13085b9c547cSRui Paulo /* 13095b9c547cSRui Paulo * Use a temporary SSL_METHOD to get a callback on SSL_new() 13105b9c547cSRui Paulo * from libcurl since there is no proper callback registration 13115b9c547cSRui Paulo * available for this. 13125b9c547cSRui Paulo */ 13135b9c547cSRui Paulo os_memset(&patch_ssl_method, 0, sizeof(patch_ssl_method)); 13145b9c547cSRui Paulo patch_ssl_method.ssl_new = curl_patch_ssl_new; 13155b9c547cSRui Paulo real_ssl_method = ssl->method; 13165b9c547cSRui Paulo ssl->method = &patch_ssl_method; 13174bc52338SCy Schubert #endif /* OpenSSL < 1.1.0 */ 13185b9c547cSRui Paulo } 13195b9c547cSRui Paulo #endif /* HAVE_OCSP */ 13205b9c547cSRui Paulo 13215b9c547cSRui Paulo return CURLE_OK; 13225b9c547cSRui Paulo } 13235b9c547cSRui Paulo 13245b9c547cSRui Paulo #endif /* EAP_TLS_OPENSSL */ 13255b9c547cSRui Paulo 13265b9c547cSRui Paulo 13275b9c547cSRui Paulo static CURL * setup_curl_post(struct http_ctx *ctx, const char *address, 13285b9c547cSRui Paulo const char *ca_fname, const char *username, 13295b9c547cSRui Paulo const char *password, const char *client_cert, 13305b9c547cSRui Paulo const char *client_key) 13315b9c547cSRui Paulo { 13325b9c547cSRui Paulo CURL *curl; 1333325151a3SRui Paulo #ifdef EAP_TLS_OPENSSL 1334325151a3SRui Paulo const char *extra = " tls=openssl"; 1335325151a3SRui Paulo #else /* EAP_TLS_OPENSSL */ 1336325151a3SRui Paulo const char *extra = ""; 1337325151a3SRui Paulo #endif /* EAP_TLS_OPENSSL */ 13385b9c547cSRui Paulo 13395b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Start HTTP client: address=%s ca_fname=%s " 1340325151a3SRui Paulo "username=%s%s", address, ca_fname, username, extra); 13415b9c547cSRui Paulo 13425b9c547cSRui Paulo curl = curl_easy_init(); 13435b9c547cSRui Paulo if (curl == NULL) 13445b9c547cSRui Paulo return NULL; 13455b9c547cSRui Paulo 13465b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_URL, address); 13475b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_POST, 1L); 13485b9c547cSRui Paulo if (ca_fname) { 13495b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_CAINFO, ca_fname); 13505b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); 13515b9c547cSRui Paulo #ifdef EAP_TLS_OPENSSL 13525b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, curl_cb_ssl); 13535b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, ctx); 13544bc52338SCy Schubert #if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER >= 0x10100000L) 1355780fb4a2SCy Schubert /* For now, using the CURLOPT_SSL_VERIFYSTATUS option only 1356780fb4a2SCy Schubert * with BoringSSL since the OpenSSL specific callback hack to 1357780fb4a2SCy Schubert * enable OCSP is not available with BoringSSL. The OCSP 1358780fb4a2SCy Schubert * implementation within libcurl is not sufficient for the 1359780fb4a2SCy Schubert * Hotspot 2.0 OSU needs, so cannot use this with OpenSSL. 1360780fb4a2SCy Schubert */ 1361780fb4a2SCy Schubert if (ctx->ocsp != NO_OCSP) 1362780fb4a2SCy Schubert curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L); 1363780fb4a2SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */ 13645b9c547cSRui Paulo #endif /* EAP_TLS_OPENSSL */ 13655b9c547cSRui Paulo } else { 13665b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 13675b9c547cSRui Paulo } 13685b9c547cSRui Paulo if (client_cert && client_key) { 13695b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert); 13705b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_SSLKEY, client_key); 13715b9c547cSRui Paulo } 13725b9c547cSRui Paulo /* TODO: use curl_easy_getinfo() with CURLINFO_CERTINFO to fetch 13735b9c547cSRui Paulo * information about the server certificate */ 13745b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L); 13755b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curl_cb_debug); 13765b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_DEBUGDATA, ctx); 13775b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_cb_write); 13785b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_WRITEDATA, ctx); 13795b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 13805b9c547cSRui Paulo if (username) { 13815b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE); 13825b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_USERNAME, username); 13835b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_PASSWORD, password); 13845b9c547cSRui Paulo } 13855b9c547cSRui Paulo 13865b9c547cSRui Paulo return curl; 13875b9c547cSRui Paulo } 13885b9c547cSRui Paulo 13895b9c547cSRui Paulo 13905b9c547cSRui Paulo static int post_init_client(struct http_ctx *ctx, const char *address, 13915b9c547cSRui Paulo const char *ca_fname, const char *username, 13925b9c547cSRui Paulo const char *password, const char *client_cert, 13935b9c547cSRui Paulo const char *client_key) 13945b9c547cSRui Paulo { 13955b9c547cSRui Paulo char *pos; 13965b9c547cSRui Paulo int count; 13975b9c547cSRui Paulo 13985b9c547cSRui Paulo clone_str(&ctx->svc_address, address); 13995b9c547cSRui Paulo clone_str(&ctx->svc_ca_fname, ca_fname); 14005b9c547cSRui Paulo clone_str(&ctx->svc_username, username); 14015b9c547cSRui Paulo clone_str(&ctx->svc_password, password); 14025b9c547cSRui Paulo clone_str(&ctx->svc_client_cert, client_cert); 14035b9c547cSRui Paulo clone_str(&ctx->svc_client_key, client_key); 14045b9c547cSRui Paulo 14055b9c547cSRui Paulo /* 14065b9c547cSRui Paulo * Workaround for Apache "Hostname 'FOO' provided via SNI and hostname 14075b9c547cSRui Paulo * 'foo' provided via HTTP are different. 14085b9c547cSRui Paulo */ 14095b9c547cSRui Paulo for (count = 0, pos = ctx->svc_address; count < 3 && pos && *pos; 14105b9c547cSRui Paulo pos++) { 14115b9c547cSRui Paulo if (*pos == '/') 14125b9c547cSRui Paulo count++; 14135b9c547cSRui Paulo *pos = tolower(*pos); 14145b9c547cSRui Paulo } 14155b9c547cSRui Paulo 14165b9c547cSRui Paulo ctx->curl = setup_curl_post(ctx, ctx->svc_address, ca_fname, username, 14175b9c547cSRui Paulo password, client_cert, client_key); 14185b9c547cSRui Paulo if (ctx->curl == NULL) 14195b9c547cSRui Paulo return -1; 14205b9c547cSRui Paulo 14215b9c547cSRui Paulo return 0; 14225b9c547cSRui Paulo } 14235b9c547cSRui Paulo 14245b9c547cSRui Paulo 14255b9c547cSRui Paulo int soap_init_client(struct http_ctx *ctx, const char *address, 14265b9c547cSRui Paulo const char *ca_fname, const char *username, 14275b9c547cSRui Paulo const char *password, const char *client_cert, 14285b9c547cSRui Paulo const char *client_key) 14295b9c547cSRui Paulo { 14305b9c547cSRui Paulo if (post_init_client(ctx, address, ca_fname, username, password, 14315b9c547cSRui Paulo client_cert, client_key) < 0) 14325b9c547cSRui Paulo return -1; 14335b9c547cSRui Paulo 14345b9c547cSRui Paulo ctx->curl_hdr = curl_slist_append(ctx->curl_hdr, 14355b9c547cSRui Paulo "Content-Type: application/soap+xml"); 14365b9c547cSRui Paulo ctx->curl_hdr = curl_slist_append(ctx->curl_hdr, "SOAPAction: "); 14375b9c547cSRui Paulo ctx->curl_hdr = curl_slist_append(ctx->curl_hdr, "Expect:"); 14385b9c547cSRui Paulo curl_easy_setopt(ctx->curl, CURLOPT_HTTPHEADER, ctx->curl_hdr); 14395b9c547cSRui Paulo 14405b9c547cSRui Paulo return 0; 14415b9c547cSRui Paulo } 14425b9c547cSRui Paulo 14435b9c547cSRui Paulo 14445b9c547cSRui Paulo int soap_reinit_client(struct http_ctx *ctx) 14455b9c547cSRui Paulo { 14465b9c547cSRui Paulo char *address = NULL; 14475b9c547cSRui Paulo char *ca_fname = NULL; 14485b9c547cSRui Paulo char *username = NULL; 14495b9c547cSRui Paulo char *password = NULL; 14505b9c547cSRui Paulo char *client_cert = NULL; 14515b9c547cSRui Paulo char *client_key = NULL; 14525b9c547cSRui Paulo int ret; 14535b9c547cSRui Paulo 14545b9c547cSRui Paulo clear_curl(ctx); 14555b9c547cSRui Paulo 14565b9c547cSRui Paulo clone_str(&address, ctx->svc_address); 14575b9c547cSRui Paulo clone_str(&ca_fname, ctx->svc_ca_fname); 14585b9c547cSRui Paulo clone_str(&username, ctx->svc_username); 14595b9c547cSRui Paulo clone_str(&password, ctx->svc_password); 14605b9c547cSRui Paulo clone_str(&client_cert, ctx->svc_client_cert); 14615b9c547cSRui Paulo clone_str(&client_key, ctx->svc_client_key); 14625b9c547cSRui Paulo 14635b9c547cSRui Paulo ret = soap_init_client(ctx, address, ca_fname, username, password, 14645b9c547cSRui Paulo client_cert, client_key); 14655b9c547cSRui Paulo os_free(address); 14665b9c547cSRui Paulo os_free(ca_fname); 14675b9c547cSRui Paulo str_clear_free(username); 14685b9c547cSRui Paulo str_clear_free(password); 14695b9c547cSRui Paulo os_free(client_cert); 14705b9c547cSRui Paulo os_free(client_key); 14715b9c547cSRui Paulo return ret; 14725b9c547cSRui Paulo } 14735b9c547cSRui Paulo 14745b9c547cSRui Paulo 14755b9c547cSRui Paulo static void free_curl_buf(struct http_ctx *ctx) 14765b9c547cSRui Paulo { 14775b9c547cSRui Paulo os_free(ctx->curl_buf); 14785b9c547cSRui Paulo ctx->curl_buf = NULL; 14795b9c547cSRui Paulo ctx->curl_buf_len = 0; 14805b9c547cSRui Paulo } 14815b9c547cSRui Paulo 14825b9c547cSRui Paulo 14835b9c547cSRui Paulo xml_node_t * soap_send_receive(struct http_ctx *ctx, xml_node_t *node) 14845b9c547cSRui Paulo { 14855b9c547cSRui Paulo char *str; 14865b9c547cSRui Paulo xml_node_t *envelope, *ret, *resp, *n; 14875b9c547cSRui Paulo CURLcode res; 14885b9c547cSRui Paulo long http = 0; 14895b9c547cSRui Paulo 14905b9c547cSRui Paulo ctx->last_err = NULL; 14915b9c547cSRui Paulo 14925b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SOAP: Sending message"); 14935b9c547cSRui Paulo envelope = soap_build_envelope(ctx->xml, node); 14945b9c547cSRui Paulo str = xml_node_to_str(ctx->xml, envelope); 14955b9c547cSRui Paulo xml_node_free(ctx->xml, envelope); 14965b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, "SOAP[%s]", str); 14975b9c547cSRui Paulo 14985b9c547cSRui Paulo curl_easy_setopt(ctx->curl, CURLOPT_POSTFIELDS, str); 14995b9c547cSRui Paulo free_curl_buf(ctx); 15005b9c547cSRui Paulo 15015b9c547cSRui Paulo res = curl_easy_perform(ctx->curl); 15025b9c547cSRui Paulo if (res != CURLE_OK) { 15035b9c547cSRui Paulo if (!ctx->last_err) 15045b9c547cSRui Paulo ctx->last_err = curl_easy_strerror(res); 15055b9c547cSRui Paulo wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s", 15065b9c547cSRui Paulo ctx->last_err); 15075b9c547cSRui Paulo os_free(str); 15085b9c547cSRui Paulo free_curl_buf(ctx); 15095b9c547cSRui Paulo return NULL; 15105b9c547cSRui Paulo } 15115b9c547cSRui Paulo os_free(str); 15125b9c547cSRui Paulo 15135b9c547cSRui Paulo curl_easy_getinfo(ctx->curl, CURLINFO_RESPONSE_CODE, &http); 15145b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SOAP: Server response code %ld", http); 15155b9c547cSRui Paulo if (http != 200) { 15165b9c547cSRui Paulo ctx->last_err = "HTTP download failed"; 15175b9c547cSRui Paulo wpa_printf(MSG_INFO, "HTTP download failed - code %ld", http); 15185b9c547cSRui Paulo free_curl_buf(ctx); 15195b9c547cSRui Paulo return NULL; 15205b9c547cSRui Paulo } 15215b9c547cSRui Paulo 15225b9c547cSRui Paulo if (ctx->curl_buf == NULL) 15235b9c547cSRui Paulo return NULL; 15245b9c547cSRui Paulo 15255b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, "Server response:\n%s", ctx->curl_buf); 15265b9c547cSRui Paulo resp = xml_node_from_buf(ctx->xml, ctx->curl_buf); 15275b9c547cSRui Paulo free_curl_buf(ctx); 15285b9c547cSRui Paulo if (resp == NULL) { 15295b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not parse SOAP response"); 15305b9c547cSRui Paulo ctx->last_err = "Could not parse SOAP response"; 15315b9c547cSRui Paulo return NULL; 15325b9c547cSRui Paulo } 15335b9c547cSRui Paulo 15345b9c547cSRui Paulo ret = soap_get_body(ctx->xml, resp); 15355b9c547cSRui Paulo if (ret == NULL) { 15365b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get SOAP body"); 15375b9c547cSRui Paulo ctx->last_err = "Could not get SOAP body"; 15385b9c547cSRui Paulo return NULL; 15395b9c547cSRui Paulo } 15405b9c547cSRui Paulo 15415b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SOAP body localname: '%s'", 15425b9c547cSRui Paulo xml_node_get_localname(ctx->xml, ret)); 15435b9c547cSRui Paulo n = xml_node_copy(ctx->xml, ret); 15445b9c547cSRui Paulo xml_node_free(ctx->xml, resp); 15455b9c547cSRui Paulo 15465b9c547cSRui Paulo return n; 15475b9c547cSRui Paulo } 15485b9c547cSRui Paulo 15495b9c547cSRui Paulo 15505b9c547cSRui Paulo struct http_ctx * http_init_ctx(void *upper_ctx, struct xml_node_ctx *xml_ctx) 15515b9c547cSRui Paulo { 15525b9c547cSRui Paulo struct http_ctx *ctx; 15535b9c547cSRui Paulo 15545b9c547cSRui Paulo ctx = os_zalloc(sizeof(*ctx)); 15555b9c547cSRui Paulo if (ctx == NULL) 15565b9c547cSRui Paulo return NULL; 15575b9c547cSRui Paulo ctx->ctx = upper_ctx; 15585b9c547cSRui Paulo ctx->xml = xml_ctx; 15595b9c547cSRui Paulo ctx->ocsp = OPTIONAL_OCSP; 15605b9c547cSRui Paulo 15615b9c547cSRui Paulo curl_global_init(CURL_GLOBAL_ALL); 15625b9c547cSRui Paulo 15635b9c547cSRui Paulo return ctx; 15645b9c547cSRui Paulo } 15655b9c547cSRui Paulo 15665b9c547cSRui Paulo 15675b9c547cSRui Paulo void http_ocsp_set(struct http_ctx *ctx, int val) 15685b9c547cSRui Paulo { 15695b9c547cSRui Paulo if (val == 0) 15705b9c547cSRui Paulo ctx->ocsp = NO_OCSP; 15715b9c547cSRui Paulo else if (val == 1) 15725b9c547cSRui Paulo ctx->ocsp = OPTIONAL_OCSP; 15735b9c547cSRui Paulo if (val == 2) 15745b9c547cSRui Paulo ctx->ocsp = MANDATORY_OCSP; 15755b9c547cSRui Paulo } 15765b9c547cSRui Paulo 15775b9c547cSRui Paulo 15785b9c547cSRui Paulo void http_deinit_ctx(struct http_ctx *ctx) 15795b9c547cSRui Paulo { 15805b9c547cSRui Paulo clear_curl(ctx); 15815b9c547cSRui Paulo os_free(ctx->curl_buf); 15825b9c547cSRui Paulo curl_global_cleanup(); 15835b9c547cSRui Paulo 15845b9c547cSRui Paulo os_free(ctx->svc_address); 15855b9c547cSRui Paulo os_free(ctx->svc_ca_fname); 15865b9c547cSRui Paulo str_clear_free(ctx->svc_username); 15875b9c547cSRui Paulo str_clear_free(ctx->svc_password); 15885b9c547cSRui Paulo os_free(ctx->svc_client_cert); 15895b9c547cSRui Paulo os_free(ctx->svc_client_key); 15905b9c547cSRui Paulo 15915b9c547cSRui Paulo os_free(ctx); 15925b9c547cSRui Paulo } 15935b9c547cSRui Paulo 15945b9c547cSRui Paulo 15955b9c547cSRui Paulo int http_download_file(struct http_ctx *ctx, const char *url, 15965b9c547cSRui Paulo const char *fname, const char *ca_fname) 15975b9c547cSRui Paulo { 15985b9c547cSRui Paulo CURL *curl; 1599*a90b9d01SCy Schubert FILE *f = NULL; 16005b9c547cSRui Paulo CURLcode res; 16015b9c547cSRui Paulo long http = 0; 1602*a90b9d01SCy Schubert int ret = -1; 16035b9c547cSRui Paulo 16045b9c547cSRui Paulo ctx->last_err = NULL; 1605*a90b9d01SCy Schubert ctx->url = url; 16065b9c547cSRui Paulo 16075b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "curl: Download file from %s to %s (ca=%s)", 16085b9c547cSRui Paulo url, fname, ca_fname); 16095b9c547cSRui Paulo curl = curl_easy_init(); 16105b9c547cSRui Paulo if (curl == NULL) 1611*a90b9d01SCy Schubert goto fail; 16125b9c547cSRui Paulo 16135b9c547cSRui Paulo f = fopen(fname, "wb"); 1614*a90b9d01SCy Schubert if (!f) 1615*a90b9d01SCy Schubert goto fail; 16165b9c547cSRui Paulo 16175b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_URL, url); 16185b9c547cSRui Paulo if (ca_fname) { 16195b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_CAINFO, ca_fname); 16205b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); 16215b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L); 16225b9c547cSRui Paulo } else { 16235b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 16245b9c547cSRui Paulo } 16255b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curl_cb_debug); 16265b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_DEBUGDATA, ctx); 16275b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite); 16285b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_WRITEDATA, f); 16295b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 16305b9c547cSRui Paulo 16315b9c547cSRui Paulo res = curl_easy_perform(curl); 16325b9c547cSRui Paulo if (res != CURLE_OK) { 16335b9c547cSRui Paulo if (!ctx->last_err) 16345b9c547cSRui Paulo ctx->last_err = curl_easy_strerror(res); 16355b9c547cSRui Paulo wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s", 16365b9c547cSRui Paulo ctx->last_err); 1637*a90b9d01SCy Schubert goto fail; 16385b9c547cSRui Paulo } 16395b9c547cSRui Paulo 16405b9c547cSRui Paulo curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http); 16415b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "curl: Server response code %ld", http); 16425b9c547cSRui Paulo if (http != 200) { 16435b9c547cSRui Paulo ctx->last_err = "HTTP download failed"; 16445b9c547cSRui Paulo wpa_printf(MSG_INFO, "HTTP download failed - code %ld", http); 1645*a90b9d01SCy Schubert goto fail; 16465b9c547cSRui Paulo } 16475b9c547cSRui Paulo 1648*a90b9d01SCy Schubert ret = 0; 1649*a90b9d01SCy Schubert 1650*a90b9d01SCy Schubert fail: 1651*a90b9d01SCy Schubert ctx->url = NULL; 1652*a90b9d01SCy Schubert if (curl) 16535b9c547cSRui Paulo curl_easy_cleanup(curl); 1654*a90b9d01SCy Schubert if (f) 16555b9c547cSRui Paulo fclose(f); 16565b9c547cSRui Paulo 1657*a90b9d01SCy Schubert return ret; 16585b9c547cSRui Paulo } 16595b9c547cSRui Paulo 16605b9c547cSRui Paulo 16615b9c547cSRui Paulo char * http_post(struct http_ctx *ctx, const char *url, const char *data, 16625b9c547cSRui Paulo const char *content_type, const char *ext_hdr, 16635b9c547cSRui Paulo const char *ca_fname, 16645b9c547cSRui Paulo const char *username, const char *password, 16655b9c547cSRui Paulo const char *client_cert, const char *client_key, 16665b9c547cSRui Paulo size_t *resp_len) 16675b9c547cSRui Paulo { 16685b9c547cSRui Paulo long http = 0; 16695b9c547cSRui Paulo CURLcode res; 1670*a90b9d01SCy Schubert char *ret = NULL; 16715b9c547cSRui Paulo CURL *curl; 16725b9c547cSRui Paulo struct curl_slist *curl_hdr = NULL; 16735b9c547cSRui Paulo 16745b9c547cSRui Paulo ctx->last_err = NULL; 1675*a90b9d01SCy Schubert ctx->url = url; 16765b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "curl: HTTP POST to %s", url); 16775b9c547cSRui Paulo curl = setup_curl_post(ctx, url, ca_fname, username, password, 16785b9c547cSRui Paulo client_cert, client_key); 16795b9c547cSRui Paulo if (curl == NULL) 1680*a90b9d01SCy Schubert goto fail; 16815b9c547cSRui Paulo 16825b9c547cSRui Paulo if (content_type) { 16835b9c547cSRui Paulo char ct[200]; 16845b9c547cSRui Paulo snprintf(ct, sizeof(ct), "Content-Type: %s", content_type); 16855b9c547cSRui Paulo curl_hdr = curl_slist_append(curl_hdr, ct); 16865b9c547cSRui Paulo } 16875b9c547cSRui Paulo if (ext_hdr) 16885b9c547cSRui Paulo curl_hdr = curl_slist_append(curl_hdr, ext_hdr); 16895b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_hdr); 16905b9c547cSRui Paulo 16915b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); 16925b9c547cSRui Paulo free_curl_buf(ctx); 16935b9c547cSRui Paulo 16945b9c547cSRui Paulo res = curl_easy_perform(curl); 16955b9c547cSRui Paulo if (res != CURLE_OK) { 16965b9c547cSRui Paulo if (!ctx->last_err) 16975b9c547cSRui Paulo ctx->last_err = curl_easy_strerror(res); 16985b9c547cSRui Paulo wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s", 16995b9c547cSRui Paulo ctx->last_err); 1700*a90b9d01SCy Schubert goto fail; 17015b9c547cSRui Paulo } 17025b9c547cSRui Paulo 17035b9c547cSRui Paulo curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http); 17045b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "curl: Server response code %ld", http); 17055b9c547cSRui Paulo if (http != 200) { 17065b9c547cSRui Paulo ctx->last_err = "HTTP POST failed"; 17075b9c547cSRui Paulo wpa_printf(MSG_INFO, "HTTP POST failed - code %ld", http); 1708*a90b9d01SCy Schubert goto fail; 17095b9c547cSRui Paulo } 17105b9c547cSRui Paulo 17115b9c547cSRui Paulo if (ctx->curl_buf == NULL) 1712*a90b9d01SCy Schubert goto fail; 17135b9c547cSRui Paulo 17145b9c547cSRui Paulo ret = ctx->curl_buf; 17155b9c547cSRui Paulo if (resp_len) 17165b9c547cSRui Paulo *resp_len = ctx->curl_buf_len; 17175b9c547cSRui Paulo ctx->curl_buf = NULL; 17185b9c547cSRui Paulo ctx->curl_buf_len = 0; 17195b9c547cSRui Paulo 17205b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, "Server response:\n%s", ret); 17215b9c547cSRui Paulo 1722*a90b9d01SCy Schubert fail: 1723*a90b9d01SCy Schubert free_curl_buf(ctx); 1724*a90b9d01SCy Schubert ctx->url = NULL; 17255b9c547cSRui Paulo return ret; 17265b9c547cSRui Paulo } 17275b9c547cSRui Paulo 17285b9c547cSRui Paulo 17295b9c547cSRui Paulo void http_set_cert_cb(struct http_ctx *ctx, 17305b9c547cSRui Paulo int (*cb)(void *ctx, struct http_cert *cert), 17315b9c547cSRui Paulo void *cb_ctx) 17325b9c547cSRui Paulo { 17335b9c547cSRui Paulo ctx->cert_cb = cb; 17345b9c547cSRui Paulo ctx->cert_cb_ctx = cb_ctx; 17355b9c547cSRui Paulo } 17365b9c547cSRui Paulo 17375b9c547cSRui Paulo 17385b9c547cSRui Paulo const char * http_get_err(struct http_ctx *ctx) 17395b9c547cSRui Paulo { 17405b9c547cSRui Paulo return ctx->last_err; 17415b9c547cSRui Paulo } 1742