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 345b9c547cSRui Paulo struct http_ctx { 355b9c547cSRui Paulo void *ctx; 365b9c547cSRui Paulo struct xml_node_ctx *xml; 375b9c547cSRui Paulo CURL *curl; 385b9c547cSRui Paulo struct curl_slist *curl_hdr; 395b9c547cSRui Paulo char *svc_address; 405b9c547cSRui Paulo char *svc_ca_fname; 415b9c547cSRui Paulo char *svc_username; 425b9c547cSRui Paulo char *svc_password; 435b9c547cSRui Paulo char *svc_client_cert; 445b9c547cSRui Paulo char *svc_client_key; 455b9c547cSRui Paulo char *curl_buf; 465b9c547cSRui Paulo size_t curl_buf_len; 475b9c547cSRui Paulo 485b9c547cSRui Paulo int (*cert_cb)(void *ctx, struct http_cert *cert); 495b9c547cSRui Paulo void *cert_cb_ctx; 505b9c547cSRui Paulo 515b9c547cSRui Paulo enum { 525b9c547cSRui Paulo NO_OCSP, OPTIONAL_OCSP, MANDATORY_OCSP 535b9c547cSRui Paulo } ocsp; 545b9c547cSRui Paulo X509 *peer_cert; 555b9c547cSRui Paulo X509 *peer_issuer; 565b9c547cSRui Paulo X509 *peer_issuer_issuer; 575b9c547cSRui Paulo 585b9c547cSRui Paulo const char *last_err; 595b9c547cSRui Paulo }; 605b9c547cSRui Paulo 615b9c547cSRui Paulo 625b9c547cSRui Paulo static void clear_curl(struct http_ctx *ctx) 635b9c547cSRui Paulo { 645b9c547cSRui Paulo if (ctx->curl) { 655b9c547cSRui Paulo curl_easy_cleanup(ctx->curl); 665b9c547cSRui Paulo ctx->curl = NULL; 675b9c547cSRui Paulo } 685b9c547cSRui Paulo if (ctx->curl_hdr) { 695b9c547cSRui Paulo curl_slist_free_all(ctx->curl_hdr); 705b9c547cSRui Paulo ctx->curl_hdr = NULL; 715b9c547cSRui Paulo } 725b9c547cSRui Paulo } 735b9c547cSRui Paulo 745b9c547cSRui Paulo 755b9c547cSRui Paulo static void clone_str(char **dst, const char *src) 765b9c547cSRui Paulo { 775b9c547cSRui Paulo os_free(*dst); 785b9c547cSRui Paulo if (src) 795b9c547cSRui Paulo *dst = os_strdup(src); 805b9c547cSRui Paulo else 815b9c547cSRui Paulo *dst = NULL; 825b9c547cSRui Paulo } 835b9c547cSRui Paulo 845b9c547cSRui Paulo 855b9c547cSRui Paulo static void debug_dump(struct http_ctx *ctx, const char *title, 865b9c547cSRui Paulo const char *buf, size_t len) 875b9c547cSRui Paulo { 885b9c547cSRui Paulo char *txt; 895b9c547cSRui Paulo size_t i; 905b9c547cSRui Paulo 915b9c547cSRui Paulo for (i = 0; i < len; i++) { 925b9c547cSRui Paulo if (buf[i] < 32 && buf[i] != '\t' && buf[i] != '\n' && 935b9c547cSRui Paulo buf[i] != '\r') { 945b9c547cSRui Paulo wpa_hexdump_ascii(MSG_MSGDUMP, title, buf, len); 955b9c547cSRui Paulo return; 965b9c547cSRui Paulo } 975b9c547cSRui Paulo } 985b9c547cSRui Paulo 995b9c547cSRui Paulo txt = os_malloc(len + 1); 1005b9c547cSRui Paulo if (txt == NULL) 1015b9c547cSRui Paulo return; 1025b9c547cSRui Paulo os_memcpy(txt, buf, len); 1035b9c547cSRui Paulo txt[len] = '\0'; 1045b9c547cSRui Paulo while (len > 0) { 1055b9c547cSRui Paulo len--; 1065b9c547cSRui Paulo if (txt[len] == '\n' || txt[len] == '\r') 1075b9c547cSRui Paulo txt[len] = '\0'; 1085b9c547cSRui Paulo else 1095b9c547cSRui Paulo break; 1105b9c547cSRui Paulo } 1115b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, "%s[%s]", title, txt); 1125b9c547cSRui Paulo os_free(txt); 1135b9c547cSRui Paulo } 1145b9c547cSRui Paulo 1155b9c547cSRui Paulo 1165b9c547cSRui Paulo static int curl_cb_debug(CURL *curl, curl_infotype info, char *buf, size_t len, 1175b9c547cSRui Paulo void *userdata) 1185b9c547cSRui Paulo { 1195b9c547cSRui Paulo struct http_ctx *ctx = userdata; 1205b9c547cSRui Paulo switch (info) { 1215b9c547cSRui Paulo case CURLINFO_TEXT: 1225b9c547cSRui Paulo debug_dump(ctx, "CURLINFO_TEXT", buf, len); 1235b9c547cSRui Paulo break; 1245b9c547cSRui Paulo case CURLINFO_HEADER_IN: 1255b9c547cSRui Paulo debug_dump(ctx, "CURLINFO_HEADER_IN", buf, len); 1265b9c547cSRui Paulo break; 1275b9c547cSRui Paulo case CURLINFO_HEADER_OUT: 1285b9c547cSRui Paulo debug_dump(ctx, "CURLINFO_HEADER_OUT", buf, len); 1295b9c547cSRui Paulo break; 1305b9c547cSRui Paulo case CURLINFO_DATA_IN: 1315b9c547cSRui Paulo debug_dump(ctx, "CURLINFO_DATA_IN", buf, len); 1325b9c547cSRui Paulo break; 1335b9c547cSRui Paulo case CURLINFO_DATA_OUT: 1345b9c547cSRui Paulo debug_dump(ctx, "CURLINFO_DATA_OUT", buf, len); 1355b9c547cSRui Paulo break; 1365b9c547cSRui Paulo case CURLINFO_SSL_DATA_IN: 1375b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "debug - CURLINFO_SSL_DATA_IN - %d", 1385b9c547cSRui Paulo (int) len); 1395b9c547cSRui Paulo break; 1405b9c547cSRui Paulo case CURLINFO_SSL_DATA_OUT: 1415b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "debug - CURLINFO_SSL_DATA_OUT - %d", 1425b9c547cSRui Paulo (int) len); 1435b9c547cSRui Paulo break; 1445b9c547cSRui Paulo case CURLINFO_END: 1455b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "debug - CURLINFO_END - %d", 1465b9c547cSRui Paulo (int) len); 1475b9c547cSRui Paulo break; 1485b9c547cSRui Paulo } 1495b9c547cSRui Paulo return 0; 1505b9c547cSRui Paulo } 1515b9c547cSRui Paulo 1525b9c547cSRui Paulo 1535b9c547cSRui Paulo static size_t curl_cb_write(void *ptr, size_t size, size_t nmemb, 1545b9c547cSRui Paulo void *userdata) 1555b9c547cSRui Paulo { 1565b9c547cSRui Paulo struct http_ctx *ctx = userdata; 1575b9c547cSRui Paulo char *n; 1585b9c547cSRui Paulo n = os_realloc(ctx->curl_buf, ctx->curl_buf_len + size * nmemb + 1); 1595b9c547cSRui Paulo if (n == NULL) 1605b9c547cSRui Paulo return 0; 1615b9c547cSRui Paulo ctx->curl_buf = n; 1625b9c547cSRui Paulo os_memcpy(n + ctx->curl_buf_len, ptr, size * nmemb); 1635b9c547cSRui Paulo n[ctx->curl_buf_len + size * nmemb] = '\0'; 1645b9c547cSRui Paulo ctx->curl_buf_len += size * nmemb; 1655b9c547cSRui Paulo return size * nmemb; 1665b9c547cSRui Paulo } 1675b9c547cSRui Paulo 1685b9c547cSRui Paulo 1695b9c547cSRui Paulo #ifdef EAP_TLS_OPENSSL 1705b9c547cSRui Paulo 1715b9c547cSRui Paulo static void debug_dump_cert(const char *title, X509 *cert) 1725b9c547cSRui Paulo { 1735b9c547cSRui Paulo BIO *out; 1745b9c547cSRui Paulo char *txt; 1755b9c547cSRui Paulo size_t rlen; 1765b9c547cSRui Paulo 1775b9c547cSRui Paulo out = BIO_new(BIO_s_mem()); 1785b9c547cSRui Paulo if (!out) 1795b9c547cSRui Paulo return; 1805b9c547cSRui Paulo 1815b9c547cSRui Paulo X509_print_ex(out, cert, XN_FLAG_COMPAT, X509_FLAG_COMPAT); 1825b9c547cSRui Paulo rlen = BIO_ctrl_pending(out); 1835b9c547cSRui Paulo txt = os_malloc(rlen + 1); 1845b9c547cSRui Paulo if (txt) { 1855b9c547cSRui Paulo int res = BIO_read(out, txt, rlen); 1865b9c547cSRui Paulo if (res > 0) { 1875b9c547cSRui Paulo txt[res] = '\0'; 1885b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, "%s:\n%s", title, txt); 1895b9c547cSRui Paulo } 1905b9c547cSRui Paulo os_free(txt); 1915b9c547cSRui Paulo } 1925b9c547cSRui Paulo BIO_free(out); 1935b9c547cSRui Paulo } 1945b9c547cSRui Paulo 1955b9c547cSRui Paulo 1965b9c547cSRui Paulo static void add_alt_name_othername(struct http_ctx *ctx, struct http_cert *cert, 1975b9c547cSRui Paulo OTHERNAME *o) 1985b9c547cSRui Paulo { 1995b9c547cSRui Paulo char txt[100]; 2005b9c547cSRui Paulo int res; 2015b9c547cSRui Paulo struct http_othername *on; 2025b9c547cSRui Paulo ASN1_TYPE *val; 2035b9c547cSRui Paulo 2045b9c547cSRui Paulo on = os_realloc_array(cert->othername, cert->num_othername + 1, 2055b9c547cSRui Paulo sizeof(struct http_othername)); 2065b9c547cSRui Paulo if (on == NULL) 2075b9c547cSRui Paulo return; 2085b9c547cSRui Paulo cert->othername = on; 2095b9c547cSRui Paulo on = &on[cert->num_othername]; 2105b9c547cSRui Paulo os_memset(on, 0, sizeof(*on)); 2115b9c547cSRui Paulo 2125b9c547cSRui Paulo res = OBJ_obj2txt(txt, sizeof(txt), o->type_id, 1); 2135b9c547cSRui Paulo if (res < 0 || res >= (int) sizeof(txt)) 2145b9c547cSRui Paulo return; 2155b9c547cSRui Paulo 2165b9c547cSRui Paulo on->oid = os_strdup(txt); 2175b9c547cSRui Paulo if (on->oid == NULL) 2185b9c547cSRui Paulo return; 2195b9c547cSRui Paulo 2205b9c547cSRui Paulo val = o->value; 2215b9c547cSRui Paulo on->data = val->value.octet_string->data; 2225b9c547cSRui Paulo on->len = val->value.octet_string->length; 2235b9c547cSRui Paulo 2245b9c547cSRui Paulo cert->num_othername++; 2255b9c547cSRui Paulo } 2265b9c547cSRui Paulo 2275b9c547cSRui Paulo 2285b9c547cSRui Paulo static void add_alt_name_dns(struct http_ctx *ctx, struct http_cert *cert, 2295b9c547cSRui Paulo ASN1_STRING *name) 2305b9c547cSRui Paulo { 2315b9c547cSRui Paulo char *buf; 2325b9c547cSRui Paulo char **n; 2335b9c547cSRui Paulo 2345b9c547cSRui Paulo buf = NULL; 2355b9c547cSRui Paulo if (ASN1_STRING_to_UTF8((unsigned char **) &buf, name) < 0) 2365b9c547cSRui Paulo return; 2375b9c547cSRui Paulo 2385b9c547cSRui Paulo n = os_realloc_array(cert->dnsname, cert->num_dnsname + 1, 2395b9c547cSRui Paulo sizeof(char *)); 2405b9c547cSRui Paulo if (n == NULL) 2415b9c547cSRui Paulo return; 2425b9c547cSRui Paulo 2435b9c547cSRui Paulo cert->dnsname = n; 2445b9c547cSRui Paulo n[cert->num_dnsname] = buf; 2455b9c547cSRui Paulo cert->num_dnsname++; 2465b9c547cSRui Paulo } 2475b9c547cSRui Paulo 2485b9c547cSRui Paulo 2495b9c547cSRui Paulo static void add_alt_name(struct http_ctx *ctx, struct http_cert *cert, 2505b9c547cSRui Paulo const GENERAL_NAME *name) 2515b9c547cSRui Paulo { 2525b9c547cSRui Paulo switch (name->type) { 2535b9c547cSRui Paulo case GEN_OTHERNAME: 2545b9c547cSRui Paulo add_alt_name_othername(ctx, cert, name->d.otherName); 2555b9c547cSRui Paulo break; 2565b9c547cSRui Paulo case GEN_DNS: 2575b9c547cSRui Paulo add_alt_name_dns(ctx, cert, name->d.dNSName); 2585b9c547cSRui Paulo break; 2595b9c547cSRui Paulo } 2605b9c547cSRui Paulo } 2615b9c547cSRui Paulo 2625b9c547cSRui Paulo 2635b9c547cSRui Paulo static void add_alt_names(struct http_ctx *ctx, struct http_cert *cert, 2645b9c547cSRui Paulo GENERAL_NAMES *names) 2655b9c547cSRui Paulo { 2665b9c547cSRui Paulo int num, i; 2675b9c547cSRui Paulo 2685b9c547cSRui Paulo num = sk_GENERAL_NAME_num(names); 2695b9c547cSRui Paulo for (i = 0; i < num; i++) { 2705b9c547cSRui Paulo const GENERAL_NAME *name; 2715b9c547cSRui Paulo name = sk_GENERAL_NAME_value(names, i); 2725b9c547cSRui Paulo add_alt_name(ctx, cert, name); 2735b9c547cSRui Paulo } 2745b9c547cSRui Paulo } 2755b9c547cSRui Paulo 2765b9c547cSRui Paulo 2775b9c547cSRui Paulo /* RFC 3709 */ 2785b9c547cSRui Paulo 2795b9c547cSRui Paulo typedef struct { 2805b9c547cSRui Paulo X509_ALGOR *hashAlg; 2815b9c547cSRui Paulo ASN1_OCTET_STRING *hashValue; 2825b9c547cSRui Paulo } HashAlgAndValue; 2835b9c547cSRui Paulo 2845b9c547cSRui Paulo typedef struct { 2855b9c547cSRui Paulo STACK_OF(HashAlgAndValue) *refStructHash; 2865b9c547cSRui Paulo STACK_OF(ASN1_IA5STRING) *refStructURI; 2875b9c547cSRui Paulo } LogotypeReference; 2885b9c547cSRui Paulo 2895b9c547cSRui Paulo typedef struct { 2905b9c547cSRui Paulo ASN1_IA5STRING *mediaType; 2915b9c547cSRui Paulo STACK_OF(HashAlgAndValue) *logotypeHash; 2925b9c547cSRui Paulo STACK_OF(ASN1_IA5STRING) *logotypeURI; 2935b9c547cSRui Paulo } LogotypeDetails; 2945b9c547cSRui Paulo 2955b9c547cSRui Paulo typedef struct { 2965b9c547cSRui Paulo int type; 2975b9c547cSRui Paulo union { 2985b9c547cSRui Paulo ASN1_INTEGER *numBits; 2995b9c547cSRui Paulo ASN1_INTEGER *tableSize; 3005b9c547cSRui Paulo } d; 3015b9c547cSRui Paulo } LogotypeImageResolution; 3025b9c547cSRui Paulo 3035b9c547cSRui Paulo typedef struct { 3045b9c547cSRui Paulo ASN1_INTEGER *type; /* LogotypeImageType ::= INTEGER */ 3055b9c547cSRui Paulo ASN1_INTEGER *fileSize; 3065b9c547cSRui Paulo ASN1_INTEGER *xSize; 3075b9c547cSRui Paulo ASN1_INTEGER *ySize; 3085b9c547cSRui Paulo LogotypeImageResolution *resolution; 3095b9c547cSRui Paulo ASN1_IA5STRING *language; 3105b9c547cSRui Paulo } LogotypeImageInfo; 3115b9c547cSRui Paulo 3125b9c547cSRui Paulo typedef struct { 3135b9c547cSRui Paulo LogotypeDetails *imageDetails; 3145b9c547cSRui Paulo LogotypeImageInfo *imageInfo; 3155b9c547cSRui Paulo } LogotypeImage; 3165b9c547cSRui Paulo 3175b9c547cSRui Paulo typedef struct { 3185b9c547cSRui Paulo ASN1_INTEGER *fileSize; 3195b9c547cSRui Paulo ASN1_INTEGER *playTime; 3205b9c547cSRui Paulo ASN1_INTEGER *channels; 3215b9c547cSRui Paulo ASN1_INTEGER *sampleRate; 3225b9c547cSRui Paulo ASN1_IA5STRING *language; 3235b9c547cSRui Paulo } LogotypeAudioInfo; 3245b9c547cSRui Paulo 3255b9c547cSRui Paulo typedef struct { 3265b9c547cSRui Paulo LogotypeDetails *audioDetails; 3275b9c547cSRui Paulo LogotypeAudioInfo *audioInfo; 3285b9c547cSRui Paulo } LogotypeAudio; 3295b9c547cSRui Paulo 3305b9c547cSRui Paulo typedef struct { 3315b9c547cSRui Paulo STACK_OF(LogotypeImage) *image; 3325b9c547cSRui Paulo STACK_OF(LogotypeAudio) *audio; 3335b9c547cSRui Paulo } LogotypeData; 3345b9c547cSRui Paulo 3355b9c547cSRui Paulo typedef struct { 3365b9c547cSRui Paulo int type; 3375b9c547cSRui Paulo union { 3385b9c547cSRui Paulo LogotypeData *direct; 3395b9c547cSRui Paulo LogotypeReference *indirect; 3405b9c547cSRui Paulo } d; 3415b9c547cSRui Paulo } LogotypeInfo; 3425b9c547cSRui Paulo 3435b9c547cSRui Paulo typedef struct { 3445b9c547cSRui Paulo ASN1_OBJECT *logotypeType; 3455b9c547cSRui Paulo LogotypeInfo *info; 3465b9c547cSRui Paulo } OtherLogotypeInfo; 3475b9c547cSRui Paulo 3485b9c547cSRui Paulo typedef struct { 3495b9c547cSRui Paulo STACK_OF(LogotypeInfo) *communityLogos; 3505b9c547cSRui Paulo LogotypeInfo *issuerLogo; 3515b9c547cSRui Paulo LogotypeInfo *subjectLogo; 3525b9c547cSRui Paulo STACK_OF(OtherLogotypeInfo) *otherLogos; 3535b9c547cSRui Paulo } LogotypeExtn; 3545b9c547cSRui Paulo 3555b9c547cSRui Paulo ASN1_SEQUENCE(HashAlgAndValue) = { 3565b9c547cSRui Paulo ASN1_SIMPLE(HashAlgAndValue, hashAlg, X509_ALGOR), 3575b9c547cSRui Paulo ASN1_SIMPLE(HashAlgAndValue, hashValue, ASN1_OCTET_STRING) 3585b9c547cSRui Paulo } ASN1_SEQUENCE_END(HashAlgAndValue); 3595b9c547cSRui Paulo 3605b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeReference) = { 3615b9c547cSRui Paulo ASN1_SEQUENCE_OF(LogotypeReference, refStructHash, HashAlgAndValue), 3625b9c547cSRui Paulo ASN1_SEQUENCE_OF(LogotypeReference, refStructURI, ASN1_IA5STRING) 3635b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeReference); 3645b9c547cSRui Paulo 3655b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeDetails) = { 3665b9c547cSRui Paulo ASN1_SIMPLE(LogotypeDetails, mediaType, ASN1_IA5STRING), 3675b9c547cSRui Paulo ASN1_SEQUENCE_OF(LogotypeDetails, logotypeHash, HashAlgAndValue), 3685b9c547cSRui Paulo ASN1_SEQUENCE_OF(LogotypeDetails, logotypeURI, ASN1_IA5STRING) 3695b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeDetails); 3705b9c547cSRui Paulo 3715b9c547cSRui Paulo ASN1_CHOICE(LogotypeImageResolution) = { 3725b9c547cSRui Paulo ASN1_IMP(LogotypeImageResolution, d.numBits, ASN1_INTEGER, 1), 3735b9c547cSRui Paulo ASN1_IMP(LogotypeImageResolution, d.tableSize, ASN1_INTEGER, 2) 3745b9c547cSRui Paulo } ASN1_CHOICE_END(LogotypeImageResolution); 3755b9c547cSRui Paulo 3765b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeImageInfo) = { 3775b9c547cSRui Paulo ASN1_IMP_OPT(LogotypeImageInfo, type, ASN1_INTEGER, 0), 3785b9c547cSRui Paulo ASN1_SIMPLE(LogotypeImageInfo, fileSize, ASN1_INTEGER), 3795b9c547cSRui Paulo ASN1_SIMPLE(LogotypeImageInfo, xSize, ASN1_INTEGER), 3805b9c547cSRui Paulo ASN1_SIMPLE(LogotypeImageInfo, ySize, ASN1_INTEGER), 3815b9c547cSRui Paulo ASN1_OPT(LogotypeImageInfo, resolution, LogotypeImageResolution), 3825b9c547cSRui Paulo ASN1_IMP_OPT(LogotypeImageInfo, language, ASN1_IA5STRING, 4), 3835b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeImageInfo); 3845b9c547cSRui Paulo 3855b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeImage) = { 3865b9c547cSRui Paulo ASN1_SIMPLE(LogotypeImage, imageDetails, LogotypeDetails), 3875b9c547cSRui Paulo ASN1_OPT(LogotypeImage, imageInfo, LogotypeImageInfo) 3885b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeImage); 3895b9c547cSRui Paulo 3905b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeAudioInfo) = { 3915b9c547cSRui Paulo ASN1_SIMPLE(LogotypeAudioInfo, fileSize, ASN1_INTEGER), 3925b9c547cSRui Paulo ASN1_SIMPLE(LogotypeAudioInfo, playTime, ASN1_INTEGER), 3935b9c547cSRui Paulo ASN1_SIMPLE(LogotypeAudioInfo, channels, ASN1_INTEGER), 3945b9c547cSRui Paulo ASN1_IMP_OPT(LogotypeAudioInfo, sampleRate, ASN1_INTEGER, 3), 3955b9c547cSRui Paulo ASN1_IMP_OPT(LogotypeAudioInfo, language, ASN1_IA5STRING, 4) 3965b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeAudioInfo); 3975b9c547cSRui Paulo 3985b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeAudio) = { 3995b9c547cSRui Paulo ASN1_SIMPLE(LogotypeAudio, audioDetails, LogotypeDetails), 4005b9c547cSRui Paulo ASN1_OPT(LogotypeAudio, audioInfo, LogotypeAudioInfo) 4015b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeAudio); 4025b9c547cSRui Paulo 4035b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeData) = { 4045b9c547cSRui Paulo ASN1_SEQUENCE_OF_OPT(LogotypeData, image, LogotypeImage), 4055b9c547cSRui Paulo ASN1_IMP_SEQUENCE_OF_OPT(LogotypeData, audio, LogotypeAudio, 1) 4065b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeData); 4075b9c547cSRui Paulo 4085b9c547cSRui Paulo ASN1_CHOICE(LogotypeInfo) = { 4095b9c547cSRui Paulo ASN1_IMP(LogotypeInfo, d.direct, LogotypeData, 0), 4105b9c547cSRui Paulo ASN1_IMP(LogotypeInfo, d.indirect, LogotypeReference, 1) 4115b9c547cSRui Paulo } ASN1_CHOICE_END(LogotypeInfo); 4125b9c547cSRui Paulo 4135b9c547cSRui Paulo ASN1_SEQUENCE(OtherLogotypeInfo) = { 4145b9c547cSRui Paulo ASN1_SIMPLE(OtherLogotypeInfo, logotypeType, ASN1_OBJECT), 4155b9c547cSRui Paulo ASN1_SIMPLE(OtherLogotypeInfo, info, LogotypeInfo) 4165b9c547cSRui Paulo } ASN1_SEQUENCE_END(OtherLogotypeInfo); 4175b9c547cSRui Paulo 4185b9c547cSRui Paulo ASN1_SEQUENCE(LogotypeExtn) = { 4195b9c547cSRui Paulo ASN1_EXP_SEQUENCE_OF_OPT(LogotypeExtn, communityLogos, LogotypeInfo, 0), 4205b9c547cSRui Paulo ASN1_EXP_OPT(LogotypeExtn, issuerLogo, LogotypeInfo, 1), 4215b9c547cSRui Paulo ASN1_EXP_OPT(LogotypeExtn, issuerLogo, LogotypeInfo, 2), 4225b9c547cSRui Paulo ASN1_EXP_SEQUENCE_OF_OPT(LogotypeExtn, otherLogos, OtherLogotypeInfo, 3) 4235b9c547cSRui Paulo } ASN1_SEQUENCE_END(LogotypeExtn); 4245b9c547cSRui Paulo 4255b9c547cSRui Paulo IMPLEMENT_ASN1_FUNCTIONS(LogotypeExtn); 4265b9c547cSRui Paulo 427780fb4a2SCy Schubert #ifdef OPENSSL_IS_BORINGSSL 428780fb4a2SCy Schubert #define sk_LogotypeInfo_num(st) \ 429780fb4a2SCy Schubert sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeInfo) *, (st))) 430780fb4a2SCy Schubert #define sk_LogotypeInfo_value(st, i) (LogotypeInfo *) \ 431780fb4a2SCy Schubert sk_value(CHECKED_CAST(_STACK *, const STACK_OF(LogotypeInfo) *, (st)), (i)) 432780fb4a2SCy Schubert #define sk_LogotypeImage_num(st) \ 433780fb4a2SCy Schubert sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeImage) *, (st))) 434780fb4a2SCy Schubert #define sk_LogotypeImage_value(st, i) (LogotypeImage *) \ 435780fb4a2SCy Schubert sk_value(CHECKED_CAST(_STACK *, const STACK_OF(LogotypeImage) *, (st)), (i)) 436780fb4a2SCy Schubert #define sk_LogotypeAudio_num(st) \ 437780fb4a2SCy Schubert sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeAudio) *, (st))) 438780fb4a2SCy Schubert #define sk_LogotypeAudio_value(st, i) (LogotypeAudio *) \ 439780fb4a2SCy Schubert sk_value(CHECK_CAST(_STACK *, const STACK_OF(LogotypeAudio) *, (st)), (i)) 440780fb4a2SCy Schubert #define sk_HashAlgAndValue_num(st) \ 441780fb4a2SCy Schubert sk_num(CHECKED_CAST(_STACK *, STACK_OF(HashAlgAndValue) *, (st))) 442780fb4a2SCy Schubert #define sk_HashAlgAndValue_value(st, i) (HashAlgAndValue *) \ 443780fb4a2SCy Schubert sk_value(CHECKED_CAST(_STACK *, const STACK_OF(HashAlgAndValue) *, (st)), (i)) 444780fb4a2SCy Schubert #define sk_ASN1_IA5STRING_num(st) \ 445780fb4a2SCy Schubert sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_IA5STRING) *, (st))) 446780fb4a2SCy Schubert #define sk_ASN1_IA5STRING_value(st, i) (ASN1_IA5STRING *) \ 447780fb4a2SCy Schubert sk_value(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_IA5STRING) *, (st)), (i)) 448780fb4a2SCy Schubert #else /* OPENSSL_IS_BORINGSSL */ 4495b9c547cSRui Paulo #define sk_LogotypeInfo_num(st) SKM_sk_num(LogotypeInfo, (st)) 4505b9c547cSRui Paulo #define sk_LogotypeInfo_value(st, i) SKM_sk_value(LogotypeInfo, (st), (i)) 4515b9c547cSRui Paulo #define sk_LogotypeImage_num(st) SKM_sk_num(LogotypeImage, (st)) 4525b9c547cSRui Paulo #define sk_LogotypeImage_value(st, i) SKM_sk_value(LogotypeImage, (st), (i)) 4535b9c547cSRui Paulo #define sk_LogotypeAudio_num(st) SKM_sk_num(LogotypeAudio, (st)) 4545b9c547cSRui Paulo #define sk_LogotypeAudio_value(st, i) SKM_sk_value(LogotypeAudio, (st), (i)) 4555b9c547cSRui Paulo #define sk_HashAlgAndValue_num(st) SKM_sk_num(HashAlgAndValue, (st)) 4565b9c547cSRui Paulo #define sk_HashAlgAndValue_value(st, i) SKM_sk_value(HashAlgAndValue, (st), (i)) 4575b9c547cSRui Paulo #define sk_ASN1_IA5STRING_num(st) SKM_sk_num(ASN1_IA5STRING, (st)) 4585b9c547cSRui Paulo #define sk_ASN1_IA5STRING_value(st, i) SKM_sk_value(ASN1_IA5STRING, (st), (i)) 459780fb4a2SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */ 4605b9c547cSRui Paulo 4615b9c547cSRui Paulo 4625b9c547cSRui Paulo static void add_logo(struct http_ctx *ctx, struct http_cert *hcert, 4635b9c547cSRui Paulo HashAlgAndValue *hash, ASN1_IA5STRING *uri) 4645b9c547cSRui Paulo { 4655b9c547cSRui Paulo char txt[100]; 4665b9c547cSRui Paulo int res, len; 4675b9c547cSRui Paulo struct http_logo *n; 4685b9c547cSRui Paulo 4695b9c547cSRui Paulo if (hash == NULL || uri == NULL) 4705b9c547cSRui Paulo return; 4715b9c547cSRui Paulo 4725b9c547cSRui Paulo res = OBJ_obj2txt(txt, sizeof(txt), hash->hashAlg->algorithm, 1); 4735b9c547cSRui Paulo if (res < 0 || res >= (int) sizeof(txt)) 4745b9c547cSRui Paulo return; 4755b9c547cSRui Paulo 4765b9c547cSRui Paulo n = os_realloc_array(hcert->logo, hcert->num_logo + 1, 4775b9c547cSRui Paulo sizeof(struct http_logo)); 4785b9c547cSRui Paulo if (n == NULL) 4795b9c547cSRui Paulo return; 4805b9c547cSRui Paulo hcert->logo = n; 4815b9c547cSRui Paulo n = &hcert->logo[hcert->num_logo]; 4825b9c547cSRui Paulo os_memset(n, 0, sizeof(*n)); 4835b9c547cSRui Paulo 4845b9c547cSRui Paulo n->alg_oid = os_strdup(txt); 4855b9c547cSRui Paulo if (n->alg_oid == NULL) 4865b9c547cSRui Paulo return; 4875b9c547cSRui Paulo 4885b9c547cSRui Paulo n->hash_len = ASN1_STRING_length(hash->hashValue); 489*85732ac8SCy Schubert n->hash = os_memdup(ASN1_STRING_data(hash->hashValue), n->hash_len); 4905b9c547cSRui Paulo if (n->hash == NULL) { 4915b9c547cSRui Paulo os_free(n->alg_oid); 4925b9c547cSRui Paulo return; 4935b9c547cSRui Paulo } 4945b9c547cSRui Paulo 4955b9c547cSRui Paulo len = ASN1_STRING_length(uri); 4965b9c547cSRui Paulo n->uri = os_malloc(len + 1); 4975b9c547cSRui Paulo if (n->uri == NULL) { 4985b9c547cSRui Paulo os_free(n->alg_oid); 4995b9c547cSRui Paulo os_free(n->hash); 5005b9c547cSRui Paulo return; 5015b9c547cSRui Paulo } 5025b9c547cSRui Paulo os_memcpy(n->uri, ASN1_STRING_data(uri), len); 5035b9c547cSRui Paulo n->uri[len] = '\0'; 5045b9c547cSRui Paulo 5055b9c547cSRui Paulo hcert->num_logo++; 5065b9c547cSRui Paulo } 5075b9c547cSRui Paulo 5085b9c547cSRui Paulo 5095b9c547cSRui Paulo static void add_logo_direct(struct http_ctx *ctx, struct http_cert *hcert, 5105b9c547cSRui Paulo LogotypeData *data) 5115b9c547cSRui Paulo { 5125b9c547cSRui Paulo int i, num; 5135b9c547cSRui Paulo 5145b9c547cSRui Paulo if (data->image == NULL) 5155b9c547cSRui Paulo return; 5165b9c547cSRui Paulo 5175b9c547cSRui Paulo num = sk_LogotypeImage_num(data->image); 5185b9c547cSRui Paulo for (i = 0; i < num; i++) { 5195b9c547cSRui Paulo LogotypeImage *image; 5205b9c547cSRui Paulo LogotypeDetails *details; 5215b9c547cSRui Paulo int j, hash_num, uri_num; 5225b9c547cSRui Paulo HashAlgAndValue *found_hash = NULL; 5235b9c547cSRui Paulo 5245b9c547cSRui Paulo image = sk_LogotypeImage_value(data->image, i); 5255b9c547cSRui Paulo if (image == NULL) 5265b9c547cSRui Paulo continue; 5275b9c547cSRui Paulo 5285b9c547cSRui Paulo details = image->imageDetails; 5295b9c547cSRui Paulo if (details == NULL) 5305b9c547cSRui Paulo continue; 5315b9c547cSRui Paulo 5325b9c547cSRui Paulo hash_num = sk_HashAlgAndValue_num(details->logotypeHash); 5335b9c547cSRui Paulo for (j = 0; j < hash_num; j++) { 5345b9c547cSRui Paulo HashAlgAndValue *hash; 5355b9c547cSRui Paulo char txt[100]; 5365b9c547cSRui Paulo int res; 5375b9c547cSRui Paulo hash = sk_HashAlgAndValue_value(details->logotypeHash, 5385b9c547cSRui Paulo j); 5395b9c547cSRui Paulo if (hash == NULL) 5405b9c547cSRui Paulo continue; 5415b9c547cSRui Paulo res = OBJ_obj2txt(txt, sizeof(txt), 5425b9c547cSRui Paulo hash->hashAlg->algorithm, 1); 5435b9c547cSRui Paulo if (res < 0 || res >= (int) sizeof(txt)) 5445b9c547cSRui Paulo continue; 5455b9c547cSRui Paulo if (os_strcmp(txt, "2.16.840.1.101.3.4.2.1") == 0) { 5465b9c547cSRui Paulo found_hash = hash; 5475b9c547cSRui Paulo break; 5485b9c547cSRui Paulo } 5495b9c547cSRui Paulo } 5505b9c547cSRui Paulo 5515b9c547cSRui Paulo if (!found_hash) { 5525b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: No SHA256 hash found for the logo"); 5535b9c547cSRui Paulo continue; 5545b9c547cSRui Paulo } 5555b9c547cSRui Paulo 5565b9c547cSRui Paulo uri_num = sk_ASN1_IA5STRING_num(details->logotypeURI); 5575b9c547cSRui Paulo for (j = 0; j < uri_num; j++) { 5585b9c547cSRui Paulo ASN1_IA5STRING *uri; 5595b9c547cSRui Paulo uri = sk_ASN1_IA5STRING_value(details->logotypeURI, j); 5605b9c547cSRui Paulo add_logo(ctx, hcert, found_hash, uri); 5615b9c547cSRui Paulo } 5625b9c547cSRui Paulo } 5635b9c547cSRui Paulo } 5645b9c547cSRui Paulo 5655b9c547cSRui Paulo 5665b9c547cSRui Paulo static void add_logo_indirect(struct http_ctx *ctx, struct http_cert *hcert, 5675b9c547cSRui Paulo LogotypeReference *ref) 5685b9c547cSRui Paulo { 5695b9c547cSRui Paulo int j, hash_num, uri_num; 5705b9c547cSRui Paulo 5715b9c547cSRui Paulo hash_num = sk_HashAlgAndValue_num(ref->refStructHash); 5725b9c547cSRui Paulo uri_num = sk_ASN1_IA5STRING_num(ref->refStructURI); 5735b9c547cSRui Paulo if (hash_num != uri_num) { 5745b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unexpected LogotypeReference array size difference %d != %d", 5755b9c547cSRui Paulo hash_num, uri_num); 5765b9c547cSRui Paulo return; 5775b9c547cSRui Paulo } 5785b9c547cSRui Paulo 5795b9c547cSRui Paulo for (j = 0; j < hash_num; j++) { 5805b9c547cSRui Paulo HashAlgAndValue *hash; 5815b9c547cSRui Paulo ASN1_IA5STRING *uri; 5825b9c547cSRui Paulo hash = sk_HashAlgAndValue_value(ref->refStructHash, j); 5835b9c547cSRui Paulo uri = sk_ASN1_IA5STRING_value(ref->refStructURI, j); 5845b9c547cSRui Paulo add_logo(ctx, hcert, hash, uri); 5855b9c547cSRui Paulo } 5865b9c547cSRui Paulo } 5875b9c547cSRui Paulo 5885b9c547cSRui Paulo 5895b9c547cSRui Paulo static void i2r_HashAlgAndValue(HashAlgAndValue *hash, BIO *out, int indent) 5905b9c547cSRui Paulo { 5915b9c547cSRui Paulo int i; 5925b9c547cSRui Paulo const unsigned char *data; 5935b9c547cSRui Paulo 5945b9c547cSRui Paulo BIO_printf(out, "%*shashAlg: ", indent, ""); 5955b9c547cSRui Paulo i2a_ASN1_OBJECT(out, hash->hashAlg->algorithm); 5965b9c547cSRui Paulo BIO_printf(out, "\n"); 5975b9c547cSRui Paulo 5985b9c547cSRui Paulo BIO_printf(out, "%*shashValue: ", indent, ""); 5995b9c547cSRui Paulo data = hash->hashValue->data; 6005b9c547cSRui Paulo for (i = 0; i < hash->hashValue->length; i++) 6015b9c547cSRui Paulo BIO_printf(out, "%s%02x", i > 0 ? ":" : "", data[i]); 6025b9c547cSRui Paulo BIO_printf(out, "\n"); 6035b9c547cSRui Paulo } 6045b9c547cSRui Paulo 6055b9c547cSRui Paulo static void i2r_LogotypeDetails(LogotypeDetails *details, BIO *out, int indent) 6065b9c547cSRui Paulo { 6075b9c547cSRui Paulo int i, num; 6085b9c547cSRui Paulo 6095b9c547cSRui Paulo BIO_printf(out, "%*sLogotypeDetails\n", indent, ""); 6105b9c547cSRui Paulo if (details->mediaType) { 6115b9c547cSRui Paulo BIO_printf(out, "%*smediaType: ", indent, ""); 6125b9c547cSRui Paulo ASN1_STRING_print(out, details->mediaType); 6135b9c547cSRui Paulo BIO_printf(out, "\n"); 6145b9c547cSRui Paulo } 6155b9c547cSRui Paulo 6165b9c547cSRui Paulo num = details->logotypeHash ? 6175b9c547cSRui Paulo sk_HashAlgAndValue_num(details->logotypeHash) : 0; 6185b9c547cSRui Paulo for (i = 0; i < num; i++) { 6195b9c547cSRui Paulo HashAlgAndValue *hash; 6205b9c547cSRui Paulo hash = sk_HashAlgAndValue_value(details->logotypeHash, i); 6215b9c547cSRui Paulo i2r_HashAlgAndValue(hash, out, indent); 6225b9c547cSRui Paulo } 6235b9c547cSRui Paulo 6245b9c547cSRui Paulo num = details->logotypeURI ? 6255b9c547cSRui Paulo sk_ASN1_IA5STRING_num(details->logotypeURI) : 0; 6265b9c547cSRui Paulo for (i = 0; i < num; i++) { 6275b9c547cSRui Paulo ASN1_IA5STRING *uri; 6285b9c547cSRui Paulo uri = sk_ASN1_IA5STRING_value(details->logotypeURI, i); 6295b9c547cSRui Paulo BIO_printf(out, "%*slogotypeURI: ", indent, ""); 6305b9c547cSRui Paulo ASN1_STRING_print(out, uri); 6315b9c547cSRui Paulo BIO_printf(out, "\n"); 6325b9c547cSRui Paulo } 6335b9c547cSRui Paulo } 6345b9c547cSRui Paulo 6355b9c547cSRui Paulo static void i2r_LogotypeImageInfo(LogotypeImageInfo *info, BIO *out, int indent) 6365b9c547cSRui Paulo { 6375b9c547cSRui Paulo long val; 6385b9c547cSRui Paulo 6395b9c547cSRui Paulo BIO_printf(out, "%*sLogotypeImageInfo\n", indent, ""); 6405b9c547cSRui Paulo if (info->type) { 6415b9c547cSRui Paulo val = ASN1_INTEGER_get(info->type); 6425b9c547cSRui Paulo BIO_printf(out, "%*stype: %ld\n", indent, "", val); 6435b9c547cSRui Paulo } else { 6445b9c547cSRui Paulo BIO_printf(out, "%*stype: default (1)\n", indent, ""); 6455b9c547cSRui Paulo } 646780fb4a2SCy Schubert val = ASN1_INTEGER_get(info->fileSize); 647780fb4a2SCy Schubert BIO_printf(out, "%*sfileSize: %ld\n", indent, "", val); 6485b9c547cSRui Paulo val = ASN1_INTEGER_get(info->xSize); 6495b9c547cSRui Paulo BIO_printf(out, "%*sxSize: %ld\n", indent, "", val); 6505b9c547cSRui Paulo val = ASN1_INTEGER_get(info->ySize); 6515b9c547cSRui Paulo BIO_printf(out, "%*sySize: %ld\n", indent, "", val); 6525b9c547cSRui Paulo if (info->resolution) { 653780fb4a2SCy Schubert BIO_printf(out, "%*sresolution [%d]\n", indent, "", 654780fb4a2SCy Schubert info->resolution->type); 655780fb4a2SCy Schubert switch (info->resolution->type) { 656780fb4a2SCy Schubert case 0: 657780fb4a2SCy Schubert val = ASN1_INTEGER_get(info->resolution->d.numBits); 658780fb4a2SCy Schubert BIO_printf(out, "%*snumBits: %ld\n", indent, "", val); 659780fb4a2SCy Schubert break; 660780fb4a2SCy Schubert case 1: 661780fb4a2SCy Schubert val = ASN1_INTEGER_get(info->resolution->d.tableSize); 662780fb4a2SCy Schubert BIO_printf(out, "%*stableSize: %ld\n", indent, "", val); 663780fb4a2SCy Schubert break; 664780fb4a2SCy Schubert } 6655b9c547cSRui Paulo } 6665b9c547cSRui Paulo if (info->language) { 6675b9c547cSRui Paulo BIO_printf(out, "%*slanguage: ", indent, ""); 6685b9c547cSRui Paulo ASN1_STRING_print(out, info->language); 6695b9c547cSRui Paulo BIO_printf(out, "\n"); 6705b9c547cSRui Paulo } 6715b9c547cSRui Paulo } 6725b9c547cSRui Paulo 6735b9c547cSRui Paulo static void i2r_LogotypeImage(LogotypeImage *image, BIO *out, int indent) 6745b9c547cSRui Paulo { 6755b9c547cSRui Paulo BIO_printf(out, "%*sLogotypeImage\n", indent, ""); 6765b9c547cSRui Paulo if (image->imageDetails) { 6775b9c547cSRui Paulo i2r_LogotypeDetails(image->imageDetails, out, indent + 4); 6785b9c547cSRui Paulo } 6795b9c547cSRui Paulo if (image->imageInfo) { 6805b9c547cSRui Paulo i2r_LogotypeImageInfo(image->imageInfo, out, indent + 4); 6815b9c547cSRui Paulo } 6825b9c547cSRui Paulo } 6835b9c547cSRui Paulo 6845b9c547cSRui Paulo static void i2r_LogotypeData(LogotypeData *data, const char *title, BIO *out, 6855b9c547cSRui Paulo int indent) 6865b9c547cSRui Paulo { 6875b9c547cSRui Paulo int i, num; 6885b9c547cSRui Paulo 6895b9c547cSRui Paulo BIO_printf(out, "%*s%s - LogotypeData\n", indent, "", title); 6905b9c547cSRui Paulo 6915b9c547cSRui Paulo num = data->image ? sk_LogotypeImage_num(data->image) : 0; 6925b9c547cSRui Paulo for (i = 0; i < num; i++) { 6935b9c547cSRui Paulo LogotypeImage *image = sk_LogotypeImage_value(data->image, i); 6945b9c547cSRui Paulo i2r_LogotypeImage(image, out, indent + 4); 6955b9c547cSRui Paulo } 6965b9c547cSRui Paulo 6975b9c547cSRui Paulo num = data->audio ? sk_LogotypeAudio_num(data->audio) : 0; 6985b9c547cSRui Paulo for (i = 0; i < num; i++) { 6995b9c547cSRui Paulo BIO_printf(out, "%*saudio: TODO\n", indent, ""); 7005b9c547cSRui Paulo } 7015b9c547cSRui Paulo } 7025b9c547cSRui Paulo 7035b9c547cSRui Paulo static void i2r_LogotypeReference(LogotypeReference *ref, const char *title, 7045b9c547cSRui Paulo BIO *out, int indent) 7055b9c547cSRui Paulo { 7065b9c547cSRui Paulo int i, hash_num, uri_num; 7075b9c547cSRui Paulo 7085b9c547cSRui Paulo BIO_printf(out, "%*s%s - LogotypeReference\n", indent, "", title); 7095b9c547cSRui Paulo 7105b9c547cSRui Paulo hash_num = ref->refStructHash ? 7115b9c547cSRui Paulo sk_HashAlgAndValue_num(ref->refStructHash) : 0; 7125b9c547cSRui Paulo uri_num = ref->refStructURI ? 7135b9c547cSRui Paulo sk_ASN1_IA5STRING_num(ref->refStructURI) : 0; 7145b9c547cSRui Paulo if (hash_num != uri_num) { 7155b9c547cSRui Paulo BIO_printf(out, "%*sUnexpected LogotypeReference array size difference %d != %d\n", 7165b9c547cSRui Paulo indent, "", hash_num, uri_num); 7175b9c547cSRui Paulo return; 7185b9c547cSRui Paulo } 7195b9c547cSRui Paulo 7205b9c547cSRui Paulo for (i = 0; i < hash_num; i++) { 7215b9c547cSRui Paulo HashAlgAndValue *hash; 7225b9c547cSRui Paulo ASN1_IA5STRING *uri; 7235b9c547cSRui Paulo 7245b9c547cSRui Paulo hash = sk_HashAlgAndValue_value(ref->refStructHash, i); 7255b9c547cSRui Paulo i2r_HashAlgAndValue(hash, out, indent); 7265b9c547cSRui Paulo 7275b9c547cSRui Paulo uri = sk_ASN1_IA5STRING_value(ref->refStructURI, i); 7285b9c547cSRui Paulo BIO_printf(out, "%*srefStructURI: ", indent, ""); 7295b9c547cSRui Paulo ASN1_STRING_print(out, uri); 7305b9c547cSRui Paulo BIO_printf(out, "\n"); 7315b9c547cSRui Paulo } 7325b9c547cSRui Paulo } 7335b9c547cSRui Paulo 7345b9c547cSRui Paulo static void i2r_LogotypeInfo(LogotypeInfo *info, const char *title, BIO *out, 7355b9c547cSRui Paulo int indent) 7365b9c547cSRui Paulo { 7375b9c547cSRui Paulo switch (info->type) { 7385b9c547cSRui Paulo case 0: 7395b9c547cSRui Paulo i2r_LogotypeData(info->d.direct, title, out, indent); 7405b9c547cSRui Paulo break; 7415b9c547cSRui Paulo case 1: 7425b9c547cSRui Paulo i2r_LogotypeReference(info->d.indirect, title, out, indent); 7435b9c547cSRui Paulo break; 7445b9c547cSRui Paulo } 7455b9c547cSRui Paulo } 7465b9c547cSRui Paulo 7475b9c547cSRui Paulo static void debug_print_logotypeext(LogotypeExtn *logo) 7485b9c547cSRui Paulo { 7495b9c547cSRui Paulo BIO *out; 7505b9c547cSRui Paulo int i, num; 7515b9c547cSRui Paulo int indent = 0; 7525b9c547cSRui Paulo 7535b9c547cSRui Paulo out = BIO_new_fp(stdout, BIO_NOCLOSE); 7545b9c547cSRui Paulo if (out == NULL) 7555b9c547cSRui Paulo return; 7565b9c547cSRui Paulo 7575b9c547cSRui Paulo if (logo->communityLogos) { 7585b9c547cSRui Paulo num = sk_LogotypeInfo_num(logo->communityLogos); 7595b9c547cSRui Paulo for (i = 0; i < num; i++) { 7605b9c547cSRui Paulo LogotypeInfo *info; 7615b9c547cSRui Paulo info = sk_LogotypeInfo_value(logo->communityLogos, i); 7625b9c547cSRui Paulo i2r_LogotypeInfo(info, "communityLogo", out, indent); 7635b9c547cSRui Paulo } 7645b9c547cSRui Paulo } 7655b9c547cSRui Paulo 7665b9c547cSRui Paulo if (logo->issuerLogo) { 7675b9c547cSRui Paulo i2r_LogotypeInfo(logo->issuerLogo, "issuerLogo", out, indent ); 7685b9c547cSRui Paulo } 7695b9c547cSRui Paulo 7705b9c547cSRui Paulo if (logo->subjectLogo) { 7715b9c547cSRui Paulo i2r_LogotypeInfo(logo->subjectLogo, "subjectLogo", out, indent); 7725b9c547cSRui Paulo } 7735b9c547cSRui Paulo 7745b9c547cSRui Paulo if (logo->otherLogos) { 7755b9c547cSRui Paulo BIO_printf(out, "%*sotherLogos - TODO\n", indent, ""); 7765b9c547cSRui Paulo } 7775b9c547cSRui Paulo 7785b9c547cSRui Paulo BIO_free(out); 7795b9c547cSRui Paulo } 7805b9c547cSRui Paulo 7815b9c547cSRui Paulo 7825b9c547cSRui Paulo static void add_logotype_ext(struct http_ctx *ctx, struct http_cert *hcert, 7835b9c547cSRui Paulo X509 *cert) 7845b9c547cSRui Paulo { 7855b9c547cSRui Paulo ASN1_OBJECT *obj; 7865b9c547cSRui Paulo int pos; 7875b9c547cSRui Paulo X509_EXTENSION *ext; 7885b9c547cSRui Paulo ASN1_OCTET_STRING *os; 7895b9c547cSRui Paulo LogotypeExtn *logo; 7905b9c547cSRui Paulo const unsigned char *data; 7915b9c547cSRui Paulo int i, num; 7925b9c547cSRui Paulo 7935b9c547cSRui Paulo obj = OBJ_txt2obj("1.3.6.1.5.5.7.1.12", 0); 7945b9c547cSRui Paulo if (obj == NULL) 7955b9c547cSRui Paulo return; 7965b9c547cSRui Paulo 7975b9c547cSRui Paulo pos = X509_get_ext_by_OBJ(cert, obj, -1); 7985b9c547cSRui Paulo if (pos < 0) { 7995b9c547cSRui Paulo wpa_printf(MSG_INFO, "No logotype extension included"); 8005b9c547cSRui Paulo return; 8015b9c547cSRui Paulo } 8025b9c547cSRui Paulo 8035b9c547cSRui Paulo wpa_printf(MSG_INFO, "Parsing logotype extension"); 8045b9c547cSRui Paulo ext = X509_get_ext(cert, pos); 8055b9c547cSRui Paulo if (!ext) { 8065b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get logotype extension"); 8075b9c547cSRui Paulo return; 8085b9c547cSRui Paulo } 8095b9c547cSRui Paulo 8105b9c547cSRui Paulo os = X509_EXTENSION_get_data(ext); 8115b9c547cSRui Paulo if (os == NULL) { 8125b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get logotype extension data"); 8135b9c547cSRui Paulo return; 8145b9c547cSRui Paulo } 8155b9c547cSRui Paulo 8165b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "logotypeExtn", 8175b9c547cSRui Paulo ASN1_STRING_data(os), ASN1_STRING_length(os)); 8185b9c547cSRui Paulo 8195b9c547cSRui Paulo data = ASN1_STRING_data(os); 8205b9c547cSRui Paulo logo = d2i_LogotypeExtn(NULL, &data, ASN1_STRING_length(os)); 8215b9c547cSRui Paulo if (logo == NULL) { 8225b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to parse logotypeExtn"); 8235b9c547cSRui Paulo return; 8245b9c547cSRui Paulo } 8255b9c547cSRui Paulo 8265b9c547cSRui Paulo if (wpa_debug_level < MSG_INFO) 8275b9c547cSRui Paulo debug_print_logotypeext(logo); 8285b9c547cSRui Paulo 8295b9c547cSRui Paulo if (!logo->communityLogos) { 8305b9c547cSRui Paulo wpa_printf(MSG_INFO, "No communityLogos included"); 8315b9c547cSRui Paulo LogotypeExtn_free(logo); 8325b9c547cSRui Paulo return; 8335b9c547cSRui Paulo } 8345b9c547cSRui Paulo 8355b9c547cSRui Paulo num = sk_LogotypeInfo_num(logo->communityLogos); 8365b9c547cSRui Paulo for (i = 0; i < num; i++) { 8375b9c547cSRui Paulo LogotypeInfo *info; 8385b9c547cSRui Paulo info = sk_LogotypeInfo_value(logo->communityLogos, i); 8395b9c547cSRui Paulo switch (info->type) { 8405b9c547cSRui Paulo case 0: 8415b9c547cSRui Paulo add_logo_direct(ctx, hcert, info->d.direct); 8425b9c547cSRui Paulo break; 8435b9c547cSRui Paulo case 1: 8445b9c547cSRui Paulo add_logo_indirect(ctx, hcert, info->d.indirect); 8455b9c547cSRui Paulo break; 8465b9c547cSRui Paulo } 8475b9c547cSRui Paulo } 8485b9c547cSRui Paulo 8495b9c547cSRui Paulo LogotypeExtn_free(logo); 8505b9c547cSRui Paulo } 8515b9c547cSRui Paulo 8525b9c547cSRui Paulo 8535b9c547cSRui Paulo static void parse_cert(struct http_ctx *ctx, struct http_cert *hcert, 8545b9c547cSRui Paulo X509 *cert, GENERAL_NAMES **names) 8555b9c547cSRui Paulo { 8565b9c547cSRui Paulo os_memset(hcert, 0, sizeof(*hcert)); 8575b9c547cSRui Paulo 8585b9c547cSRui Paulo *names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); 8595b9c547cSRui Paulo if (*names) 8605b9c547cSRui Paulo add_alt_names(ctx, hcert, *names); 8615b9c547cSRui Paulo 8625b9c547cSRui Paulo add_logotype_ext(ctx, hcert, cert); 8635b9c547cSRui Paulo } 8645b9c547cSRui Paulo 8655b9c547cSRui Paulo 8665b9c547cSRui Paulo static void parse_cert_free(struct http_cert *hcert, GENERAL_NAMES *names) 8675b9c547cSRui Paulo { 8685b9c547cSRui Paulo unsigned int i; 8695b9c547cSRui Paulo 8705b9c547cSRui Paulo for (i = 0; i < hcert->num_dnsname; i++) 8715b9c547cSRui Paulo OPENSSL_free(hcert->dnsname[i]); 8725b9c547cSRui Paulo os_free(hcert->dnsname); 8735b9c547cSRui Paulo 8745b9c547cSRui Paulo for (i = 0; i < hcert->num_othername; i++) 8755b9c547cSRui Paulo os_free(hcert->othername[i].oid); 8765b9c547cSRui Paulo os_free(hcert->othername); 8775b9c547cSRui Paulo 8785b9c547cSRui Paulo for (i = 0; i < hcert->num_logo; i++) { 8795b9c547cSRui Paulo os_free(hcert->logo[i].alg_oid); 8805b9c547cSRui Paulo os_free(hcert->logo[i].hash); 8815b9c547cSRui Paulo os_free(hcert->logo[i].uri); 8825b9c547cSRui Paulo } 8835b9c547cSRui Paulo os_free(hcert->logo); 8845b9c547cSRui Paulo 8855b9c547cSRui Paulo sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); 8865b9c547cSRui Paulo } 8875b9c547cSRui Paulo 8885b9c547cSRui Paulo 8895b9c547cSRui Paulo static int validate_server_cert(struct http_ctx *ctx, X509 *cert) 8905b9c547cSRui Paulo { 8915b9c547cSRui Paulo GENERAL_NAMES *names; 8925b9c547cSRui Paulo struct http_cert hcert; 8935b9c547cSRui Paulo int ret; 8945b9c547cSRui Paulo 895325151a3SRui Paulo if (ctx->cert_cb == NULL) { 896325151a3SRui Paulo wpa_printf(MSG_DEBUG, "%s: no cert_cb configured", __func__); 8975b9c547cSRui Paulo return 0; 898325151a3SRui Paulo } 8995b9c547cSRui Paulo 9005b9c547cSRui Paulo if (0) { 9015b9c547cSRui Paulo BIO *out; 9025b9c547cSRui Paulo out = BIO_new_fp(stdout, BIO_NOCLOSE); 9035b9c547cSRui Paulo X509_print_ex(out, cert, XN_FLAG_COMPAT, X509_FLAG_COMPAT); 9045b9c547cSRui Paulo BIO_free(out); 9055b9c547cSRui Paulo } 9065b9c547cSRui Paulo 9075b9c547cSRui Paulo parse_cert(ctx, &hcert, cert, &names); 9085b9c547cSRui Paulo ret = ctx->cert_cb(ctx->cert_cb_ctx, &hcert); 9095b9c547cSRui Paulo parse_cert_free(&hcert, names); 9105b9c547cSRui Paulo 9115b9c547cSRui Paulo return ret; 9125b9c547cSRui Paulo } 9135b9c547cSRui Paulo 9145b9c547cSRui Paulo 9155b9c547cSRui Paulo void http_parse_x509_certificate(struct http_ctx *ctx, const char *fname) 9165b9c547cSRui Paulo { 9175b9c547cSRui Paulo BIO *in, *out; 9185b9c547cSRui Paulo X509 *cert; 9195b9c547cSRui Paulo GENERAL_NAMES *names; 9205b9c547cSRui Paulo struct http_cert hcert; 9215b9c547cSRui Paulo unsigned int i; 9225b9c547cSRui Paulo 9235b9c547cSRui Paulo in = BIO_new_file(fname, "r"); 9245b9c547cSRui Paulo if (in == NULL) { 9255b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not read '%s'", fname); 9265b9c547cSRui Paulo return; 9275b9c547cSRui Paulo } 9285b9c547cSRui Paulo 9295b9c547cSRui Paulo cert = d2i_X509_bio(in, NULL); 9305b9c547cSRui Paulo BIO_free(in); 9315b9c547cSRui Paulo 9325b9c547cSRui Paulo if (cert == NULL) { 9335b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not parse certificate"); 9345b9c547cSRui Paulo return; 9355b9c547cSRui Paulo } 9365b9c547cSRui Paulo 9375b9c547cSRui Paulo out = BIO_new_fp(stdout, BIO_NOCLOSE); 9385b9c547cSRui Paulo if (out) { 9395b9c547cSRui Paulo X509_print_ex(out, cert, XN_FLAG_COMPAT, 9405b9c547cSRui Paulo X509_FLAG_COMPAT); 9415b9c547cSRui Paulo BIO_free(out); 9425b9c547cSRui Paulo } 9435b9c547cSRui Paulo 9445b9c547cSRui Paulo wpa_printf(MSG_INFO, "Additional parsing information:"); 9455b9c547cSRui Paulo parse_cert(ctx, &hcert, cert, &names); 9465b9c547cSRui Paulo for (i = 0; i < hcert.num_othername; i++) { 9475b9c547cSRui Paulo if (os_strcmp(hcert.othername[i].oid, 9485b9c547cSRui Paulo "1.3.6.1.4.1.40808.1.1.1") == 0) { 9495b9c547cSRui Paulo char *name = os_zalloc(hcert.othername[i].len + 1); 9505b9c547cSRui Paulo if (name) { 9515b9c547cSRui Paulo os_memcpy(name, hcert.othername[i].data, 9525b9c547cSRui Paulo hcert.othername[i].len); 9535b9c547cSRui Paulo wpa_printf(MSG_INFO, 9545b9c547cSRui Paulo "id-wfa-hotspot-friendlyName: %s", 9555b9c547cSRui Paulo name); 9565b9c547cSRui Paulo os_free(name); 9575b9c547cSRui Paulo } 9585b9c547cSRui Paulo wpa_hexdump_ascii(MSG_INFO, 9595b9c547cSRui Paulo "id-wfa-hotspot-friendlyName", 9605b9c547cSRui Paulo hcert.othername[i].data, 9615b9c547cSRui Paulo hcert.othername[i].len); 9625b9c547cSRui Paulo } else { 9635b9c547cSRui Paulo wpa_printf(MSG_INFO, "subjAltName[othername]: oid=%s", 9645b9c547cSRui Paulo hcert.othername[i].oid); 9655b9c547cSRui Paulo wpa_hexdump_ascii(MSG_INFO, "unknown othername", 9665b9c547cSRui Paulo hcert.othername[i].data, 9675b9c547cSRui Paulo hcert.othername[i].len); 9685b9c547cSRui Paulo } 9695b9c547cSRui Paulo } 9705b9c547cSRui Paulo parse_cert_free(&hcert, names); 9715b9c547cSRui Paulo 9725b9c547cSRui Paulo X509_free(cert); 9735b9c547cSRui Paulo } 9745b9c547cSRui Paulo 9755b9c547cSRui Paulo 9765b9c547cSRui Paulo static int curl_cb_ssl_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) 9775b9c547cSRui Paulo { 9785b9c547cSRui Paulo struct http_ctx *ctx; 9795b9c547cSRui Paulo X509 *cert; 9805b9c547cSRui Paulo int err, depth; 9815b9c547cSRui Paulo char buf[256]; 9825b9c547cSRui Paulo X509_NAME *name; 9835b9c547cSRui Paulo const char *err_str; 9845b9c547cSRui Paulo SSL *ssl; 9855b9c547cSRui Paulo SSL_CTX *ssl_ctx; 9865b9c547cSRui Paulo 9875b9c547cSRui Paulo ssl = X509_STORE_CTX_get_ex_data(x509_ctx, 9885b9c547cSRui Paulo SSL_get_ex_data_X509_STORE_CTX_idx()); 989*85732ac8SCy Schubert ssl_ctx = SSL_get_SSL_CTX(ssl); 9905b9c547cSRui Paulo ctx = SSL_CTX_get_app_data(ssl_ctx); 9915b9c547cSRui Paulo 992325151a3SRui Paulo wpa_printf(MSG_DEBUG, "curl_cb_ssl_verify, preverify_ok: %d", 993325151a3SRui Paulo preverify_ok); 9945b9c547cSRui Paulo 9955b9c547cSRui Paulo err = X509_STORE_CTX_get_error(x509_ctx); 9965b9c547cSRui Paulo err_str = X509_verify_cert_error_string(err); 9975b9c547cSRui Paulo depth = X509_STORE_CTX_get_error_depth(x509_ctx); 9985b9c547cSRui Paulo cert = X509_STORE_CTX_get_current_cert(x509_ctx); 9995b9c547cSRui Paulo if (!cert) { 10005b9c547cSRui Paulo wpa_printf(MSG_INFO, "No server certificate available"); 10015b9c547cSRui Paulo ctx->last_err = "No server certificate available"; 10025b9c547cSRui Paulo return 0; 10035b9c547cSRui Paulo } 10045b9c547cSRui Paulo 10055b9c547cSRui Paulo if (depth == 0) 10065b9c547cSRui Paulo ctx->peer_cert = cert; 10075b9c547cSRui Paulo else if (depth == 1) 10085b9c547cSRui Paulo ctx->peer_issuer = cert; 10095b9c547cSRui Paulo else if (depth == 2) 10105b9c547cSRui Paulo ctx->peer_issuer_issuer = cert; 10115b9c547cSRui Paulo 10125b9c547cSRui Paulo name = X509_get_subject_name(cert); 10135b9c547cSRui Paulo X509_NAME_oneline(name, buf, sizeof(buf)); 10145b9c547cSRui Paulo wpa_printf(MSG_INFO, "Server certificate chain - depth=%d err=%d (%s) subject=%s", 10155b9c547cSRui Paulo depth, err, err_str, buf); 10165b9c547cSRui Paulo debug_dump_cert("Server certificate chain - certificate", cert); 10175b9c547cSRui Paulo 10185b9c547cSRui Paulo if (depth == 0 && preverify_ok && validate_server_cert(ctx, cert) < 0) 10195b9c547cSRui Paulo return 0; 10205b9c547cSRui Paulo 1021780fb4a2SCy Schubert #ifdef OPENSSL_IS_BORINGSSL 1022780fb4a2SCy Schubert if (depth == 0 && ctx->ocsp != NO_OCSP && preverify_ok) { 1023780fb4a2SCy Schubert enum ocsp_result res; 1024780fb4a2SCy Schubert 1025780fb4a2SCy Schubert res = check_ocsp_resp(ssl_ctx, ssl, cert, ctx->peer_issuer, 1026780fb4a2SCy Schubert ctx->peer_issuer_issuer); 1027780fb4a2SCy Schubert if (res == OCSP_REVOKED) { 1028780fb4a2SCy Schubert preverify_ok = 0; 1029780fb4a2SCy Schubert wpa_printf(MSG_INFO, "OCSP: certificate revoked"); 1030780fb4a2SCy Schubert if (err == X509_V_OK) 1031780fb4a2SCy Schubert X509_STORE_CTX_set_error( 1032780fb4a2SCy Schubert x509_ctx, X509_V_ERR_CERT_REVOKED); 1033780fb4a2SCy Schubert } else if (res != OCSP_GOOD && (ctx->ocsp == MANDATORY_OCSP)) { 1034780fb4a2SCy Schubert preverify_ok = 0; 1035780fb4a2SCy Schubert wpa_printf(MSG_INFO, 1036780fb4a2SCy Schubert "OCSP: bad certificate status response"); 1037780fb4a2SCy Schubert } 1038780fb4a2SCy Schubert } 1039780fb4a2SCy Schubert #endif /* OPENSSL_IS_BORINGSSL */ 1040780fb4a2SCy Schubert 10415b9c547cSRui Paulo if (!preverify_ok) 10425b9c547cSRui Paulo ctx->last_err = "TLS validation failed"; 10435b9c547cSRui Paulo 10445b9c547cSRui Paulo return preverify_ok; 10455b9c547cSRui Paulo } 10465b9c547cSRui Paulo 10475b9c547cSRui Paulo 10485b9c547cSRui Paulo #ifdef HAVE_OCSP 10495b9c547cSRui Paulo 10505b9c547cSRui Paulo static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp) 10515b9c547cSRui Paulo { 10525b9c547cSRui Paulo BIO *out; 10535b9c547cSRui Paulo size_t rlen; 10545b9c547cSRui Paulo char *txt; 10555b9c547cSRui Paulo int res; 10565b9c547cSRui Paulo 10575b9c547cSRui Paulo out = BIO_new(BIO_s_mem()); 10585b9c547cSRui Paulo if (!out) 10595b9c547cSRui Paulo return; 10605b9c547cSRui Paulo 10615b9c547cSRui Paulo OCSP_RESPONSE_print(out, rsp, 0); 10625b9c547cSRui Paulo rlen = BIO_ctrl_pending(out); 10635b9c547cSRui Paulo txt = os_malloc(rlen + 1); 10645b9c547cSRui Paulo if (!txt) { 10655b9c547cSRui Paulo BIO_free(out); 10665b9c547cSRui Paulo return; 10675b9c547cSRui Paulo } 10685b9c547cSRui Paulo 10695b9c547cSRui Paulo res = BIO_read(out, txt, rlen); 10705b9c547cSRui Paulo if (res > 0) { 10715b9c547cSRui Paulo txt[res] = '\0'; 10725b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, "OpenSSL: OCSP Response\n%s", txt); 10735b9c547cSRui Paulo } 10745b9c547cSRui Paulo os_free(txt); 10755b9c547cSRui Paulo BIO_free(out); 10765b9c547cSRui Paulo } 10775b9c547cSRui Paulo 10785b9c547cSRui Paulo 10795b9c547cSRui Paulo static void tls_show_errors(const char *func, const char *txt) 10805b9c547cSRui Paulo { 10815b9c547cSRui Paulo unsigned long err; 10825b9c547cSRui Paulo 10835b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: %s - %s %s", 10845b9c547cSRui Paulo func, txt, ERR_error_string(ERR_get_error(), NULL)); 10855b9c547cSRui Paulo 10865b9c547cSRui Paulo while ((err = ERR_get_error())) { 10875b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: pending error: %s", 10885b9c547cSRui Paulo ERR_error_string(err, NULL)); 10895b9c547cSRui Paulo } 10905b9c547cSRui Paulo } 10915b9c547cSRui Paulo 10925b9c547cSRui Paulo 10935b9c547cSRui Paulo static int ocsp_resp_cb(SSL *s, void *arg) 10945b9c547cSRui Paulo { 10955b9c547cSRui Paulo struct http_ctx *ctx = arg; 10965b9c547cSRui Paulo const unsigned char *p; 1097*85732ac8SCy Schubert int len, status, reason, res; 10985b9c547cSRui Paulo OCSP_RESPONSE *rsp; 10995b9c547cSRui Paulo OCSP_BASICRESP *basic; 11005b9c547cSRui Paulo OCSP_CERTID *id; 11015b9c547cSRui Paulo ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update; 11025b9c547cSRui Paulo X509_STORE *store; 11035b9c547cSRui Paulo STACK_OF(X509) *certs = NULL; 11045b9c547cSRui Paulo 11055b9c547cSRui Paulo len = SSL_get_tlsext_status_ocsp_resp(s, &p); 11065b9c547cSRui Paulo if (!p) { 11075b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received"); 11085b9c547cSRui Paulo if (ctx->ocsp == MANDATORY_OCSP) 11095b9c547cSRui Paulo ctx->last_err = "No OCSP response received"; 11105b9c547cSRui Paulo return (ctx->ocsp == MANDATORY_OCSP) ? 0 : 1; 11115b9c547cSRui Paulo } 11125b9c547cSRui Paulo 11135b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len); 11145b9c547cSRui Paulo 11155b9c547cSRui Paulo rsp = d2i_OCSP_RESPONSE(NULL, &p, len); 11165b9c547cSRui Paulo if (!rsp) { 11175b9c547cSRui Paulo wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response"); 11185b9c547cSRui Paulo ctx->last_err = "Failed to parse OCSP response"; 11195b9c547cSRui Paulo return 0; 11205b9c547cSRui Paulo } 11215b9c547cSRui Paulo 11225b9c547cSRui Paulo ocsp_debug_print_resp(rsp); 11235b9c547cSRui Paulo 11245b9c547cSRui Paulo status = OCSP_response_status(rsp); 11255b9c547cSRui Paulo if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { 11265b9c547cSRui Paulo wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)", 11275b9c547cSRui Paulo status, OCSP_response_status_str(status)); 11285b9c547cSRui Paulo ctx->last_err = "OCSP responder error"; 11295b9c547cSRui Paulo return 0; 11305b9c547cSRui Paulo } 11315b9c547cSRui Paulo 11325b9c547cSRui Paulo basic = OCSP_response_get1_basic(rsp); 11335b9c547cSRui Paulo if (!basic) { 11345b9c547cSRui Paulo wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse"); 11355b9c547cSRui Paulo ctx->last_err = "Could not find BasicOCSPResponse"; 11365b9c547cSRui Paulo return 0; 11375b9c547cSRui Paulo } 11385b9c547cSRui Paulo 11395b9c547cSRui Paulo store = SSL_CTX_get_cert_store(s->ctx); 11405b9c547cSRui Paulo if (ctx->peer_issuer) { 11415b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Add issuer"); 11425b9c547cSRui Paulo debug_dump_cert("OpenSSL: Issuer certificate", 11435b9c547cSRui Paulo ctx->peer_issuer); 11445b9c547cSRui Paulo 11455b9c547cSRui Paulo if (X509_STORE_add_cert(store, ctx->peer_issuer) != 1) { 11465b9c547cSRui Paulo tls_show_errors(__func__, 11475b9c547cSRui Paulo "OpenSSL: Could not add issuer to certificate store"); 11485b9c547cSRui Paulo } 11495b9c547cSRui Paulo certs = sk_X509_new_null(); 11505b9c547cSRui Paulo if (certs) { 11515b9c547cSRui Paulo X509 *cert; 11525b9c547cSRui Paulo cert = X509_dup(ctx->peer_issuer); 11535b9c547cSRui Paulo if (cert && !sk_X509_push(certs, cert)) { 11545b9c547cSRui Paulo tls_show_errors( 11555b9c547cSRui Paulo __func__, 11565b9c547cSRui Paulo "OpenSSL: Could not add issuer to OCSP responder trust store"); 11575b9c547cSRui Paulo X509_free(cert); 11585b9c547cSRui Paulo sk_X509_free(certs); 11595b9c547cSRui Paulo certs = NULL; 11605b9c547cSRui Paulo } 11615b9c547cSRui Paulo if (certs && ctx->peer_issuer_issuer) { 11625b9c547cSRui Paulo cert = X509_dup(ctx->peer_issuer_issuer); 11635b9c547cSRui Paulo if (cert && !sk_X509_push(certs, cert)) { 11645b9c547cSRui Paulo tls_show_errors( 11655b9c547cSRui Paulo __func__, 11665b9c547cSRui Paulo "OpenSSL: Could not add issuer's issuer to OCSP responder trust store"); 11675b9c547cSRui Paulo X509_free(cert); 11685b9c547cSRui Paulo } 11695b9c547cSRui Paulo } 11705b9c547cSRui Paulo } 11715b9c547cSRui Paulo } 11725b9c547cSRui Paulo 11735b9c547cSRui Paulo status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER); 11745b9c547cSRui Paulo sk_X509_pop_free(certs, X509_free); 11755b9c547cSRui Paulo if (status <= 0) { 11765b9c547cSRui Paulo tls_show_errors(__func__, 11775b9c547cSRui Paulo "OpenSSL: OCSP response failed verification"); 11785b9c547cSRui Paulo OCSP_BASICRESP_free(basic); 11795b9c547cSRui Paulo OCSP_RESPONSE_free(rsp); 11805b9c547cSRui Paulo ctx->last_err = "OCSP response failed verification"; 11815b9c547cSRui Paulo return 0; 11825b9c547cSRui Paulo } 11835b9c547cSRui Paulo 11845b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded"); 11855b9c547cSRui Paulo 11865b9c547cSRui Paulo if (!ctx->peer_cert) { 11875b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check"); 11885b9c547cSRui Paulo OCSP_BASICRESP_free(basic); 11895b9c547cSRui Paulo OCSP_RESPONSE_free(rsp); 11905b9c547cSRui Paulo ctx->last_err = "Peer certificate not available for OCSP status check"; 11915b9c547cSRui Paulo return 0; 11925b9c547cSRui Paulo } 11935b9c547cSRui Paulo 11945b9c547cSRui Paulo if (!ctx->peer_issuer) { 11955b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check"); 11965b9c547cSRui Paulo OCSP_BASICRESP_free(basic); 11975b9c547cSRui Paulo OCSP_RESPONSE_free(rsp); 11985b9c547cSRui Paulo ctx->last_err = "Peer issuer certificate not available for OCSP status check"; 11995b9c547cSRui Paulo return 0; 12005b9c547cSRui Paulo } 12015b9c547cSRui Paulo 1202*85732ac8SCy Schubert id = OCSP_cert_to_id(EVP_sha256(), ctx->peer_cert, ctx->peer_issuer); 12035b9c547cSRui Paulo if (!id) { 1204*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, 1205*85732ac8SCy Schubert "OpenSSL: Could not create OCSP certificate identifier (SHA256)"); 12065b9c547cSRui Paulo OCSP_BASICRESP_free(basic); 12075b9c547cSRui Paulo OCSP_RESPONSE_free(rsp); 12085b9c547cSRui Paulo ctx->last_err = "Could not create OCSP certificate identifier"; 12095b9c547cSRui Paulo return 0; 12105b9c547cSRui Paulo } 12115b9c547cSRui Paulo 1212*85732ac8SCy Schubert res = OCSP_resp_find_status(basic, id, &status, &reason, &produced_at, 1213*85732ac8SCy Schubert &this_update, &next_update); 1214*85732ac8SCy Schubert if (!res) { 1215*85732ac8SCy Schubert id = OCSP_cert_to_id(NULL, ctx->peer_cert, ctx->peer_issuer); 1216*85732ac8SCy Schubert if (!id) { 1217*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, 1218*85732ac8SCy Schubert "OpenSSL: Could not create OCSP certificate identifier (SHA1)"); 1219*85732ac8SCy Schubert OCSP_BASICRESP_free(basic); 1220*85732ac8SCy Schubert OCSP_RESPONSE_free(rsp); 1221*85732ac8SCy Schubert ctx->last_err = 1222*85732ac8SCy Schubert "Could not create OCSP certificate identifier"; 1223*85732ac8SCy Schubert return 0; 1224*85732ac8SCy Schubert } 1225*85732ac8SCy Schubert 1226*85732ac8SCy Schubert res = OCSP_resp_find_status(basic, id, &status, &reason, 1227*85732ac8SCy Schubert &produced_at, &this_update, 1228*85732ac8SCy Schubert &next_update); 1229*85732ac8SCy Schubert } 1230*85732ac8SCy Schubert 1231*85732ac8SCy Schubert if (!res) { 12325b9c547cSRui Paulo wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s", 12335b9c547cSRui Paulo (ctx->ocsp == MANDATORY_OCSP) ? "" : 12345b9c547cSRui Paulo " (OCSP not required)"); 1235780fb4a2SCy Schubert OCSP_CERTID_free(id); 12365b9c547cSRui Paulo OCSP_BASICRESP_free(basic); 12375b9c547cSRui Paulo OCSP_RESPONSE_free(rsp); 12385b9c547cSRui Paulo if (ctx->ocsp == MANDATORY_OCSP) 12395b9c547cSRui Paulo 12405b9c547cSRui Paulo ctx->last_err = "Could not find current server certificate from OCSP response"; 12415b9c547cSRui Paulo return (ctx->ocsp == MANDATORY_OCSP) ? 0 : 1; 12425b9c547cSRui Paulo } 1243780fb4a2SCy Schubert OCSP_CERTID_free(id); 12445b9c547cSRui Paulo 12455b9c547cSRui Paulo if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) { 12465b9c547cSRui Paulo tls_show_errors(__func__, "OpenSSL: OCSP status times invalid"); 12475b9c547cSRui Paulo OCSP_BASICRESP_free(basic); 12485b9c547cSRui Paulo OCSP_RESPONSE_free(rsp); 12495b9c547cSRui Paulo ctx->last_err = "OCSP status times invalid"; 12505b9c547cSRui Paulo return 0; 12515b9c547cSRui Paulo } 12525b9c547cSRui Paulo 12535b9c547cSRui Paulo OCSP_BASICRESP_free(basic); 12545b9c547cSRui Paulo OCSP_RESPONSE_free(rsp); 12555b9c547cSRui Paulo 12565b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s", 12575b9c547cSRui Paulo OCSP_cert_status_str(status)); 12585b9c547cSRui Paulo 12595b9c547cSRui Paulo if (status == V_OCSP_CERTSTATUS_GOOD) 12605b9c547cSRui Paulo return 1; 12615b9c547cSRui Paulo if (status == V_OCSP_CERTSTATUS_REVOKED) { 12625b9c547cSRui Paulo ctx->last_err = "Server certificate has been revoked"; 12635b9c547cSRui Paulo return 0; 12645b9c547cSRui Paulo } 12655b9c547cSRui Paulo if (ctx->ocsp == MANDATORY_OCSP) { 12665b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required"); 12675b9c547cSRui Paulo ctx->last_err = "OCSP status unknown"; 12685b9c547cSRui Paulo return 0; 12695b9c547cSRui Paulo } 12705b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue"); 12715b9c547cSRui Paulo return 1; 12725b9c547cSRui Paulo } 12735b9c547cSRui Paulo 12745b9c547cSRui Paulo 12755b9c547cSRui Paulo static SSL_METHOD patch_ssl_method; 12765b9c547cSRui Paulo static const SSL_METHOD *real_ssl_method; 12775b9c547cSRui Paulo 12785b9c547cSRui Paulo static int curl_patch_ssl_new(SSL *s) 12795b9c547cSRui Paulo { 12805b9c547cSRui Paulo SSL_CTX *ssl = s->ctx; 12815b9c547cSRui Paulo int ret; 12825b9c547cSRui Paulo 12835b9c547cSRui Paulo ssl->method = real_ssl_method; 12845b9c547cSRui Paulo s->method = real_ssl_method; 12855b9c547cSRui Paulo 12865b9c547cSRui Paulo ret = s->method->ssl_new(s); 12875b9c547cSRui Paulo SSL_set_tlsext_status_type(s, TLSEXT_STATUSTYPE_ocsp); 12885b9c547cSRui Paulo 12895b9c547cSRui Paulo return ret; 12905b9c547cSRui Paulo } 12915b9c547cSRui Paulo 12925b9c547cSRui Paulo #endif /* HAVE_OCSP */ 12935b9c547cSRui Paulo 12945b9c547cSRui Paulo 12955b9c547cSRui Paulo static CURLcode curl_cb_ssl(CURL *curl, void *sslctx, void *parm) 12965b9c547cSRui Paulo { 12975b9c547cSRui Paulo struct http_ctx *ctx = parm; 12985b9c547cSRui Paulo SSL_CTX *ssl = sslctx; 12995b9c547cSRui Paulo 13005b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "curl_cb_ssl"); 13015b9c547cSRui Paulo SSL_CTX_set_app_data(ssl, ctx); 13025b9c547cSRui Paulo SSL_CTX_set_verify(ssl, SSL_VERIFY_PEER, curl_cb_ssl_verify); 13035b9c547cSRui Paulo 13045b9c547cSRui Paulo #ifdef HAVE_OCSP 13055b9c547cSRui Paulo if (ctx->ocsp != NO_OCSP) { 13065b9c547cSRui Paulo SSL_CTX_set_tlsext_status_cb(ssl, ocsp_resp_cb); 13075b9c547cSRui Paulo SSL_CTX_set_tlsext_status_arg(ssl, ctx); 13085b9c547cSRui Paulo 13095b9c547cSRui Paulo /* 13105b9c547cSRui Paulo * Use a temporary SSL_METHOD to get a callback on SSL_new() 13115b9c547cSRui Paulo * from libcurl since there is no proper callback registration 13125b9c547cSRui Paulo * available for this. 13135b9c547cSRui Paulo */ 13145b9c547cSRui Paulo os_memset(&patch_ssl_method, 0, sizeof(patch_ssl_method)); 13155b9c547cSRui Paulo patch_ssl_method.ssl_new = curl_patch_ssl_new; 13165b9c547cSRui Paulo real_ssl_method = ssl->method; 13175b9c547cSRui Paulo ssl->method = &patch_ssl_method; 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); 1354780fb4a2SCy Schubert #ifdef OPENSSL_IS_BORINGSSL 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; 15995b9c547cSRui Paulo FILE *f; 16005b9c547cSRui Paulo CURLcode res; 16015b9c547cSRui Paulo long http = 0; 16025b9c547cSRui Paulo 16035b9c547cSRui Paulo ctx->last_err = NULL; 16045b9c547cSRui Paulo 16055b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "curl: Download file from %s to %s (ca=%s)", 16065b9c547cSRui Paulo url, fname, ca_fname); 16075b9c547cSRui Paulo curl = curl_easy_init(); 16085b9c547cSRui Paulo if (curl == NULL) 16095b9c547cSRui Paulo return -1; 16105b9c547cSRui Paulo 16115b9c547cSRui Paulo f = fopen(fname, "wb"); 16125b9c547cSRui Paulo if (f == NULL) { 16135b9c547cSRui Paulo curl_easy_cleanup(curl); 16145b9c547cSRui Paulo return -1; 16155b9c547cSRui Paulo } 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); 16375b9c547cSRui Paulo curl_easy_cleanup(curl); 16385b9c547cSRui Paulo fclose(f); 16395b9c547cSRui Paulo return -1; 16405b9c547cSRui Paulo } 16415b9c547cSRui Paulo 16425b9c547cSRui Paulo curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http); 16435b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "curl: Server response code %ld", http); 16445b9c547cSRui Paulo if (http != 200) { 16455b9c547cSRui Paulo ctx->last_err = "HTTP download failed"; 16465b9c547cSRui Paulo wpa_printf(MSG_INFO, "HTTP download failed - code %ld", http); 16475b9c547cSRui Paulo curl_easy_cleanup(curl); 16485b9c547cSRui Paulo fclose(f); 16495b9c547cSRui Paulo return -1; 16505b9c547cSRui Paulo } 16515b9c547cSRui Paulo 16525b9c547cSRui Paulo curl_easy_cleanup(curl); 16535b9c547cSRui Paulo fclose(f); 16545b9c547cSRui Paulo 16555b9c547cSRui Paulo return 0; 16565b9c547cSRui Paulo } 16575b9c547cSRui Paulo 16585b9c547cSRui Paulo 16595b9c547cSRui Paulo char * http_post(struct http_ctx *ctx, const char *url, const char *data, 16605b9c547cSRui Paulo const char *content_type, const char *ext_hdr, 16615b9c547cSRui Paulo const char *ca_fname, 16625b9c547cSRui Paulo const char *username, const char *password, 16635b9c547cSRui Paulo const char *client_cert, const char *client_key, 16645b9c547cSRui Paulo size_t *resp_len) 16655b9c547cSRui Paulo { 16665b9c547cSRui Paulo long http = 0; 16675b9c547cSRui Paulo CURLcode res; 16685b9c547cSRui Paulo char *ret; 16695b9c547cSRui Paulo CURL *curl; 16705b9c547cSRui Paulo struct curl_slist *curl_hdr = NULL; 16715b9c547cSRui Paulo 16725b9c547cSRui Paulo ctx->last_err = NULL; 16735b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "curl: HTTP POST to %s", url); 16745b9c547cSRui Paulo curl = setup_curl_post(ctx, url, ca_fname, username, password, 16755b9c547cSRui Paulo client_cert, client_key); 16765b9c547cSRui Paulo if (curl == NULL) 16775b9c547cSRui Paulo return NULL; 16785b9c547cSRui Paulo 16795b9c547cSRui Paulo if (content_type) { 16805b9c547cSRui Paulo char ct[200]; 16815b9c547cSRui Paulo snprintf(ct, sizeof(ct), "Content-Type: %s", content_type); 16825b9c547cSRui Paulo curl_hdr = curl_slist_append(curl_hdr, ct); 16835b9c547cSRui Paulo } 16845b9c547cSRui Paulo if (ext_hdr) 16855b9c547cSRui Paulo curl_hdr = curl_slist_append(curl_hdr, ext_hdr); 16865b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_hdr); 16875b9c547cSRui Paulo 16885b9c547cSRui Paulo curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); 16895b9c547cSRui Paulo free_curl_buf(ctx); 16905b9c547cSRui Paulo 16915b9c547cSRui Paulo res = curl_easy_perform(curl); 16925b9c547cSRui Paulo if (res != CURLE_OK) { 16935b9c547cSRui Paulo if (!ctx->last_err) 16945b9c547cSRui Paulo ctx->last_err = curl_easy_strerror(res); 16955b9c547cSRui Paulo wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s", 16965b9c547cSRui Paulo ctx->last_err); 16975b9c547cSRui Paulo free_curl_buf(ctx); 16985b9c547cSRui Paulo return NULL; 16995b9c547cSRui Paulo } 17005b9c547cSRui Paulo 17015b9c547cSRui Paulo curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http); 17025b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "curl: Server response code %ld", http); 17035b9c547cSRui Paulo if (http != 200) { 17045b9c547cSRui Paulo ctx->last_err = "HTTP POST failed"; 17055b9c547cSRui Paulo wpa_printf(MSG_INFO, "HTTP POST failed - code %ld", http); 17065b9c547cSRui Paulo free_curl_buf(ctx); 17075b9c547cSRui Paulo return NULL; 17085b9c547cSRui Paulo } 17095b9c547cSRui Paulo 17105b9c547cSRui Paulo if (ctx->curl_buf == NULL) 17115b9c547cSRui Paulo return NULL; 17125b9c547cSRui Paulo 17135b9c547cSRui Paulo ret = ctx->curl_buf; 17145b9c547cSRui Paulo if (resp_len) 17155b9c547cSRui Paulo *resp_len = ctx->curl_buf_len; 17165b9c547cSRui Paulo ctx->curl_buf = NULL; 17175b9c547cSRui Paulo ctx->curl_buf_len = 0; 17185b9c547cSRui Paulo 17195b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, "Server response:\n%s", ret); 17205b9c547cSRui Paulo 17215b9c547cSRui Paulo return ret; 17225b9c547cSRui Paulo } 17235b9c547cSRui Paulo 17245b9c547cSRui Paulo 17255b9c547cSRui Paulo void http_set_cert_cb(struct http_ctx *ctx, 17265b9c547cSRui Paulo int (*cb)(void *ctx, struct http_cert *cert), 17275b9c547cSRui Paulo void *cb_ctx) 17285b9c547cSRui Paulo { 17295b9c547cSRui Paulo ctx->cert_cb = cb; 17305b9c547cSRui Paulo ctx->cert_cb_ctx = cb_ctx; 17315b9c547cSRui Paulo } 17325b9c547cSRui Paulo 17335b9c547cSRui Paulo 17345b9c547cSRui Paulo const char * http_get_err(struct http_ctx *ctx) 17355b9c547cSRui Paulo { 17365b9c547cSRui Paulo return ctx->last_err; 17375b9c547cSRui Paulo } 1738