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