From 0a53dbb34f497778a86c61b201b385ca551fc4cf Mon Sep 17 00:00:00 2001 From: wiidev Date: Sat, 17 Oct 2020 18:29:03 +0100 Subject: [PATCH] Update wolfSSL and improve formatting --- source/libwolfssl/internal.h | 6 +- source/libwolfssl/libwolfssl.a | Bin 424132 -> 424450 bytes source/libwolfssl/openssl/evp.h | 6 +- source/libwolfssl/ssl.h | 12 +- source/libwolfssl/wolfcrypt/aes.h | 6 + source/libwolfssl/wolfcrypt/asn.h | 7 +- source/libwolfssl/wolfcrypt/chacha.h | 2 +- source/libwolfssl/wolfcrypt/ecc.h | 4 + source/libwolfssl/wolfcrypt/integer.h | 1 + .../libwolfssl/wolfcrypt/port/nxp/dcp_port.h | 77 ++ source/libwolfssl/wolfcrypt/settings.h | 26 +- source/libwolfssl/wolfcrypt/sha.h | 3 + source/libwolfssl/wolfcrypt/sha256.h | 2 + source/libwolfssl/wolfcrypt/tfm.h | 1 + source/libwolfssl/wolfcrypt/wc_port.h | 11 +- source/network/base64.h | 160 ++-- source/network/https.c | 872 +++++++++--------- source/network/https.h | 50 +- source/network/proxysettings.cpp | 78 +- source/network/proxysettings.h | 10 +- 20 files changed, 735 insertions(+), 599 deletions(-) create mode 100644 source/libwolfssl/wolfcrypt/port/nxp/dcp_port.h diff --git a/source/libwolfssl/internal.h b/source/libwolfssl/internal.h index ef2c4bf0..7a425fb5 100644 --- a/source/libwolfssl/internal.h +++ b/source/libwolfssl/internal.h @@ -1634,14 +1634,14 @@ WOLFSSL_LOCAL ProtocolVersion MakeTLSv1_3(void); WOLFSSL_LOCAL ProtocolVersion MakeDTLSv1_2(void); #ifdef WOLFSSL_SESSION_EXPORT - WOLFSSL_LOCAL int wolfSSL_dtls_import_internal(WOLFSSL* ssl, byte* buf, + WOLFSSL_LOCAL int wolfSSL_dtls_import_internal(WOLFSSL* ssl, const byte* buf, word32 sz); WOLFSSL_LOCAL int wolfSSL_dtls_export_internal(WOLFSSL* ssl, byte* buf, word32 sz); WOLFSSL_LOCAL int wolfSSL_dtls_export_state_internal(WOLFSSL* ssl, byte* buf, word32 sz); WOLFSSL_LOCAL int wolfSSL_dtls_import_state_internal(WOLFSSL* ssl, - byte* buf, word32 sz); + const byte* buf, word32 sz); WOLFSSL_LOCAL int wolfSSL_send_session(WOLFSSL* ssl); #endif #endif @@ -4167,6 +4167,8 @@ struct WOLFSSL { #endif /* HAVE_TLS_EXTENSIONS */ #ifdef HAVE_OCSP void* ocspIOCtx; + byte ocspProducedDate[MAX_DATE_SZ]; + int ocspProducedDateFormat; #ifdef OPENSSL_EXTRA byte* ocspResp; int ocspRespSz; diff --git a/source/libwolfssl/libwolfssl.a b/source/libwolfssl/libwolfssl.a index b36fabcef073f2924ddaf2678d56dc2761cb1a0f..e98409f4e7ad7f9b22c80aa94aba58e1c942dd76 100644 GIT binary patch delta 43525 zcmc(I4_s7L+W)zCE-=8LqoSdrj(`e+fJ!?2Q3gdF1(lKn6J<;+Y^g}8MjN@K(niJZ zl2DggDk`>RTeo#rHrN)8T6bTz++J&KV_UXpbBkIlN-8Rn-}l^m&YUZs_I-cvzWdqt zem=u|pXWU1`FGB_|IV4isgI`~8k$-^U0sx(wkR!ivBQz-pojUd!?Do0aPbnI?+GKs zvXGE<)&KvW?HdUB?>_2(C2;E$LjF~s`|c;?8$N1)`NR{1{QEyDA^l7KB_C^k^jvf_1|r9 zj6L<=9`U6Ps3PT-`F|z<_K*61Vbo+({a;7?$~0p6=RfNIrt-g_uKK_7{(tX)`p>6M zH?BPYKKZ9UFMdfBd{p{J|GfD;QU3iO_5Z@C$tJG<{|8YEo9e$m<-#~@tN*9bzxn*X zuKj}!zE1wyA≪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 delta 42799 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 diff --git a/source/libwolfssl/openssl/evp.h b/source/libwolfssl/openssl/evp.h index c7ae6488..89cb26cf 100644 --- a/source/libwolfssl/openssl/evp.h +++ b/source/libwolfssl/openssl/evp.h @@ -354,10 +354,12 @@ struct WOLFSSL_EVP_CIPHER_CTX { #define HAVE_WOLFSSL_EVP_CIPHER_CTX_IV int ivSz; #ifdef HAVE_AESGCM - byte* gcmDecryptBuffer; - int gcmDecryptBufferLen; + byte* gcmBuffer; + int gcmBufferLen; ALIGN16 unsigned char authTag[AES_BLOCK_SIZE]; int authTagSz; + byte* gcmAuthIn; + int gcmAuthInSz; #endif #endif }; diff --git a/source/libwolfssl/ssl.h b/source/libwolfssl/ssl.h index b160b824..0f89d508 100644 --- a/source/libwolfssl/ssl.h +++ b/source/libwolfssl/ssl.h @@ -743,7 +743,7 @@ typedef int (*wc_dtls_export)(WOLFSSL* ssl, #define WOLFSSL_DTLS_EXPORT_TYPES #endif /* WOLFSSL_DTLS_EXPORT_TYPES */ -WOLFSSL_API int wolfSSL_dtls_import(WOLFSSL* ssl, unsigned char* buf, +WOLFSSL_API int wolfSSL_dtls_import(WOLFSSL* ssl, const unsigned char* buf, unsigned int sz); WOLFSSL_API int wolfSSL_CTX_dtls_set_export(WOLFSSL_CTX* ctx, wc_dtls_export func); @@ -3735,6 +3735,16 @@ WOLFSSL_API void *wolfSSL_OPENSSL_memdup(const void *data, WOLFSSL_API void wolfSSL_ERR_load_BIO_strings(void); #endif +#if defined(HAVE_OCSP) && !defined(NO_ASN_TIME) + WOLFSSL_API int wolfSSL_get_ocsp_producedDate( + WOLFSSL *ssl, + byte *producedDate, + size_t producedDate_space, + int *producedDateFormat); + WOLFSSL_API int wolfSSL_get_ocsp_producedDate_tm(WOLFSSL *ssl, + struct tm *produced_tm); +#endif + #if defined(OPENSSL_ALL) \ || defined(WOLFSSL_NGINX) \ || defined(WOLFSSL_HAPROXY) \ diff --git a/source/libwolfssl/wolfcrypt/aes.h b/source/libwolfssl/wolfcrypt/aes.h index 9e60768c..b45ad78b 100644 --- a/source/libwolfssl/wolfcrypt/aes.h +++ b/source/libwolfssl/wolfcrypt/aes.h @@ -62,6 +62,9 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits #include #endif +#ifdef WOLFSSL_IMXRT_DCP + #include "fsl_dcp.h" +#endif #ifdef WOLFSSL_XILINX_CRYPT #include "xsecure_aes.h" @@ -225,6 +228,9 @@ struct Aes { #if defined(WOLFSSL_RENESAS_TSIP_TLS) && \ defined(WOLFSSL_RENESAS_TSIP_TLS_AES_CRYPT) TSIP_AES_CTX ctx; +#endif +#if defined(WOLFSSL_IMXRT_DCP) + dcp_handle_t handle; #endif void* heap; /* memory hint to use */ }; diff --git a/source/libwolfssl/wolfcrypt/asn.h b/source/libwolfssl/wolfcrypt/asn.h index 8a05e48e..0266cc79 100644 --- a/source/libwolfssl/wolfcrypt/asn.h +++ b/source/libwolfssl/wolfcrypt/asn.h @@ -538,7 +538,9 @@ enum Extensions_Sum { POLICY_CONST_OID = 150, ISSUE_ALT_NAMES_OID = 132, TLS_FEATURE_OID = 92, /* id-pe 24 */ - NETSCAPE_CT_OID = 753 /* 2.16.840.1.113730.1.1 */ + NETSCAPE_CT_OID = 753, /* 2.16.840.1.113730.1.1 */ + OCSP_NOCHECK_OID = 121 /* 1.3.6.1.5.5.7.48.1.5 + id-pkix-ocsp-nocheck */ }; enum CertificatePolicy_Sum { @@ -909,6 +911,9 @@ struct DecodedCert { byte weOwnAltNames : 1; /* altNames haven't been given to copy */ byte extKeyUsageSet : 1; byte extExtKeyUsageSet : 1; /* Extended Key Usage set */ +#ifdef HAVE_OCSP + byte ocspNoCheckSet : 1; /* id-pkix-ocsp-nocheck set */ +#endif byte extCRLdistSet : 1; byte extAuthInfoSet : 1; byte extBasicConstSet : 1; diff --git a/source/libwolfssl/wolfcrypt/chacha.h b/source/libwolfssl/wolfcrypt/chacha.h index 2582678f..40468e3c 100644 --- a/source/libwolfssl/wolfcrypt/chacha.h +++ b/source/libwolfssl/wolfcrypt/chacha.h @@ -79,7 +79,7 @@ typedef struct ChaCha { byte extra[12]; #endif word32 left; /* number of bytes leftover */ -#ifdef USE_INTEL_CHACHA_SPEEDUP +#if defined(USE_INTEL_CHACHA_SPEEDUP) || defined(WOLFSSL_ARMASM) word32 over[CHACHA_CHUNK_WORDS]; #endif } ChaCha; diff --git a/source/libwolfssl/wolfcrypt/ecc.h b/source/libwolfssl/wolfcrypt/ecc.h index d45ef3fa..9ed42d76 100644 --- a/source/libwolfssl/wolfcrypt/ecc.h +++ b/source/libwolfssl/wolfcrypt/ecc.h @@ -471,6 +471,10 @@ ECC_API int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, ECC_API int ecc_projective_dbl_point(ecc_point* P, ecc_point* R, mp_int* a, mp_int* modulus, mp_digit mp); +WOLFSSL_LOCAL +int ecc_projective_add_point_safe(ecc_point* A, ecc_point* B, ecc_point* R, + mp_int* a, mp_int* modulus, mp_digit mp, int* infinity); + #endif WOLFSSL_API diff --git a/source/libwolfssl/wolfcrypt/integer.h b/source/libwolfssl/wolfcrypt/integer.h index 1406ab7e..d62c54c2 100644 --- a/source/libwolfssl/wolfcrypt/integer.h +++ b/source/libwolfssl/wolfcrypt/integer.h @@ -305,6 +305,7 @@ MP_API int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d); MP_API void mp_zero (mp_int * a); MP_API void mp_clamp (mp_int * a); MP_API void mp_exch (mp_int * a, mp_int * b); +MP_API int mp_cond_swap_ct (mp_int * a, mp_int * b, int c, int m); MP_API void mp_rshd (mp_int * a, int b); MP_API void mp_rshb (mp_int * a, int b); MP_API int mp_mod_2d (mp_int * a, int b, mp_int * c); diff --git a/source/libwolfssl/wolfcrypt/port/nxp/dcp_port.h b/source/libwolfssl/wolfcrypt/port/nxp/dcp_port.h new file mode 100644 index 00000000..87099da8 --- /dev/null +++ b/source/libwolfssl/wolfcrypt/port/nxp/dcp_port.h @@ -0,0 +1,77 @@ +/* dcp_port.h + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#ifndef _DCP_PORT_H_ +#define _DCP_PORT_H_ + +#include +#ifdef USE_FAST_MATH + #include +#elif defined WOLFSSL_SP_MATH + #include +#else + #include +#endif + +#include +#include +#include "fsl_device_registers.h" +#include "fsl_debug_console.h" +#include "fsl_dcp.h" + +int wc_dcp_init(void); + +#ifndef NO_AES +int DCPAesInit(Aes* aes); +void DCPAesFree(Aes *aes); + +int DCPAesSetKey(Aes* aes, const byte* key, word32 len, const byte* iv, + int dir); +int DCPAesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz); +int DCPAesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz); +#endif + +#ifdef HAVE_AES_ECB +int DCPAesEcbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz); +int DCPAesEcbDecrypt(Aes* aes, byte* out, const byte* in, word32 sz); +#endif + +#ifndef NO_SHA256 +typedef struct wc_Sha256_DCP { + dcp_handle_t handle; + dcp_hash_ctx_t ctx; +} wc_Sha256; +#define WC_SHA256_TYPE_DEFINED + +void DCPSha256Free(wc_Sha256 *sha256); + +#endif + +#ifndef NO_SHA +typedef struct wc_Sha_DCP { + dcp_handle_t handle; + dcp_hash_ctx_t ctx; +} wc_Sha; +#define WC_SHA_TYPE_DEFINED + +void DCPShaFree(wc_Sha *sha); +#endif + +#endif diff --git a/source/libwolfssl/wolfcrypt/settings.h b/source/libwolfssl/wolfcrypt/settings.h index 5efa1afb..a305cec7 100644 --- a/source/libwolfssl/wolfcrypt/settings.h +++ b/source/libwolfssl/wolfcrypt/settings.h @@ -1091,7 +1091,9 @@ extern void uITRON4_free(void *p) ; /* random seed */ #define NO_OLD_RNGNAME - #if defined(FSL_FEATURE_SOC_TRNG_COUNT) && (FSL_FEATURE_SOC_TRNG_COUNT > 0) + #if defined(FREESCALE_NO_RNG) + /* nothing to define */ + #elif defined(FSL_FEATURE_SOC_TRNG_COUNT) && (FSL_FEATURE_SOC_TRNG_COUNT > 0) #define FREESCALE_KSDK_2_0_TRNG #elif defined(FSL_FEATURE_SOC_RNG_COUNT) && (FSL_FEATURE_SOC_RNG_COUNT > 0) #ifdef FREESCALE_KSDK_1_3 @@ -1621,6 +1623,12 @@ extern void uITRON4_free(void *p) ; #endif #endif +/* If DCP is used without SINGLE_THREADED, enforce WOLFSSL_CRYPT_HW_MUTEX */ +#if defined(WOLFSSL_IMXRT_DCP) && !defined(SINGLE_THREADED) + #undef WOLFSSL_CRYPT_HW_MUTEX + #define WOLFSSL_CRYPT_HW_MUTEX 1 +#endif + #if !defined(XMALLOC_USER) && !defined(MICRIUM_MALLOC) && \ !defined(WOLFSSL_LEANPSK) && !defined(NO_WOLFSSL_MEMORY) && \ !defined(XMALLOC_OVERRIDE) @@ -2124,10 +2132,18 @@ extern void uITRON4_free(void *p) ; #define SIZEOF_LONG 8 #define SIZEOF_LONG_LONG 8 #define CHAR_BIT 8 - #define WOLFSSL_SP_DIV_64 - #define WOLFSSL_SP_DIV_WORD_HALF - #define SP_HALF_SIZE 32 - #define SP_HALF_MAX 4294967295U + #ifndef WOLFSSL_SP_DIV_64 + #define WOLFSSL_SP_DIV_64 + #endif + #ifndef WOLFSSL_SP_DIV_WORD_HALF + #define WOLFSSL_SP_DIV_WORD_HALF + #endif + #ifndef SP_HALF_SIZE + #define SP_HALF_SIZE 32 + #endif + #ifndef SP_HALF_MAX + #define SP_HALF_MAX 4294967295U + #endif #endif diff --git a/source/libwolfssl/wolfcrypt/sha.h b/source/libwolfssl/wolfcrypt/sha.h index 428599c1..61267b63 100644 --- a/source/libwolfssl/wolfcrypt/sha.h +++ b/source/libwolfssl/wolfcrypt/sha.h @@ -72,6 +72,9 @@ #ifdef WOLFSSL_ESP32WROOM32_CRYPT #include #endif +#ifdef WOLFSSL_IMXRT_DCP + #include +#endif #if !defined(NO_OLD_SHA_NAMES) #define SHA WC_SHA diff --git a/source/libwolfssl/wolfcrypt/sha256.h b/source/libwolfssl/wolfcrypt/sha256.h index e6964d30..ee460d19 100644 --- a/source/libwolfssl/wolfcrypt/sha256.h +++ b/source/libwolfssl/wolfcrypt/sha256.h @@ -128,6 +128,8 @@ enum { #include "wolfssl/wolfcrypt/port/Renesas/renesas-tsip-crypt.h" #elif defined(WOLFSSL_PSOC6_CRYPTO) #include "wolfssl/wolfcrypt/port/cypress/psoc6_crypto.h" +#elif defined(WOLFSSL_IMXRT_DCP) + #include #else /* wc_Sha256 digest */ diff --git a/source/libwolfssl/wolfcrypt/tfm.h b/source/libwolfssl/wolfcrypt/tfm.h index 10af218a..f328f24b 100644 --- a/source/libwolfssl/wolfcrypt/tfm.h +++ b/source/libwolfssl/wolfcrypt/tfm.h @@ -832,6 +832,7 @@ MP_API int mp_lcm(fp_int *a, fp_int *b, fp_int *c); MP_API int mp_rand_prime(mp_int* N, int len, WC_RNG* rng, void* heap); MP_API int mp_exch(mp_int *a, mp_int *b); #endif /* WOLFSSL_KEY_GEN */ +MP_API int mp_cond_swap_ct (mp_int * a, mp_int * b, int c, int m); MP_API int mp_cnt_lsb(fp_int *a); MP_API int mp_div_2d(fp_int *a, int b, fp_int *c, fp_int *d); diff --git a/source/libwolfssl/wolfcrypt/wc_port.h b/source/libwolfssl/wolfcrypt/wc_port.h index 9ef56da4..d5225309 100644 --- a/source/libwolfssl/wolfcrypt/wc_port.h +++ b/source/libwolfssl/wolfcrypt/wc_port.h @@ -158,8 +158,8 @@ #else /* ! WOLFSSL_LINUXKM */ #ifdef BUILDING_WOLFSSL - #define SAVE_VECTOR_REGISTERS() ({}) - #define RESTORE_VECTOR_REGISTERS() ({}) + #define SAVE_VECTOR_REGISTERS() do{}while(0) + #define RESTORE_VECTOR_REGISTERS() do{}while(0) #endif #endif /* WOLFSSL_LINUXKM */ @@ -836,11 +836,12 @@ WOLFSSL_API int wolfCrypt_Cleanup(void); #endif #endif #if !defined(XGMTIME) && !defined(TIME_OVERRIDES) - #if defined(WOLFSSL_GMTIME) || !defined(HAVE_GMTIME_R) || defined(WOLF_C99) - #define XGMTIME(c, t) gmtime((c)) - #else + /* Always use gmtime_r if available. */ + #if defined(HAVE_GMTIME_R) #define XGMTIME(c, t) gmtime_r((c), (t)) #define NEED_TMP_TIME + #else + #define XGMTIME(c, t) gmtime((c)) #endif #endif #if !defined(XVALIDATE_DATE) && !defined(HAVE_VALIDATE_DATE) diff --git a/source/network/base64.h b/source/network/base64.h index 388c945b..5b5c10a1 100644 --- a/source/network/base64.h +++ b/source/network/base64.h @@ -70,104 +70,104 @@ static const unsigned char unb64[]={ // (you must pass pointer flen). char *base64(const void *binaryData, int len, int *flen) { - const unsigned char *bin = (const unsigned char *)binaryData; - char *res; + const unsigned char *bin = (const unsigned char *)binaryData; + char *res; - int rc = 0; // result counter - int byteNo; // I need this after the loop + int rc = 0; // result counter + int byteNo; // I need this after the loop - int modulusLen = len % 3; - int pad = ((modulusLen & 1) << 1) + ((modulusLen & 2) >> 1); // 2 gives 1 and 1 gives 2, but 0 gives 0. + int modulusLen = len % 3; + int pad = ((modulusLen & 1) << 1) + ((modulusLen & 2) >> 1); // 2 gives 1 and 1 gives 2, but 0 gives 0. - *flen = 4 * (len + pad) / 3; - res = (char *)MEM2_alloc(*flen + 1); // and one for the null - if (!res) - return 0; + *flen = 4 * (len + pad) / 3; + res = (char *)MEM2_alloc(*flen + 1); // and one for the null + if (!res) + return 0; - for (byteNo = 0; byteNo <= len - 3; byteNo += 3) - { - unsigned char BYTE0 = bin[byteNo]; - unsigned char BYTE1 = bin[byteNo + 1]; - unsigned char BYTE2 = bin[byteNo + 2]; - res[rc++] = b64[BYTE0 >> 2]; - res[rc++] = b64[((0x3 & BYTE0) << 4) + (BYTE1 >> 4)]; - res[rc++] = b64[((0x0f & BYTE1) << 2) + (BYTE2 >> 6)]; - res[rc++] = b64[0x3f & BYTE2]; - } + for (byteNo = 0; byteNo <= len - 3; byteNo += 3) + { + unsigned char BYTE0 = bin[byteNo]; + unsigned char BYTE1 = bin[byteNo + 1]; + unsigned char BYTE2 = bin[byteNo + 2]; + res[rc++] = b64[BYTE0 >> 2]; + res[rc++] = b64[((0x3 & BYTE0) << 4) + (BYTE1 >> 4)]; + res[rc++] = b64[((0x0f & BYTE1) << 2) + (BYTE2 >> 6)]; + res[rc++] = b64[0x3f & BYTE2]; + } - if (pad == 2) - { - res[rc++] = b64[bin[byteNo] >> 2]; - res[rc++] = b64[(0x3 & bin[byteNo]) << 4]; - res[rc++] = '='; - res[rc++] = '='; - } - else if (pad == 1) - { - res[rc++] = b64[bin[byteNo] >> 2]; - res[rc++] = b64[((0x3 & bin[byteNo]) << 4) + (bin[byteNo + 1] >> 4)]; - res[rc++] = b64[(0x0f & bin[byteNo + 1]) << 2]; - res[rc++] = '='; - } + if (pad == 2) + { + res[rc++] = b64[bin[byteNo] >> 2]; + res[rc++] = b64[(0x3 & bin[byteNo]) << 4]; + res[rc++] = '='; + res[rc++] = '='; + } + else if (pad == 1) + { + res[rc++] = b64[bin[byteNo] >> 2]; + res[rc++] = b64[((0x3 & bin[byteNo]) << 4) + (bin[byteNo + 1] >> 4)]; + res[rc++] = b64[(0x0f & bin[byteNo + 1]) << 2]; + res[rc++] = '='; + } - res[rc] = 0; // NULL TERMINATOR!;) - return res; + res[rc] = 0; // NULL TERMINATOR!;) + return res; } unsigned char *unbase64(const char *ascii, int len, int *flen) { - const unsigned char *safeAsciiPtr = (const unsigned char *)ascii; - unsigned char *bin; - int cb = 0; - int charNo; - int pad = 0; + const unsigned char *safeAsciiPtr = (const unsigned char *)ascii; + unsigned char *bin; + int cb = 0; + int charNo; + int pad = 0; - if ((len <= 0) || (len % 4 != 0)) - { // 2 accesses below would be OOB. - // catch empty string or incorrect padding size, return NULL as result. - *flen = 0; - return 0; - } - if (safeAsciiPtr[len - 1] == '=') - ++pad; - if (safeAsciiPtr[len - 2] == '=') - ++pad; + if ((len <= 0) || (len % 4 != 0)) + { // 2 accesses below would be OOB. + // catch empty string or incorrect padding size, return NULL as result. + *flen = 0; + return 0; + } + if (safeAsciiPtr[len - 1] == '=') + ++pad; + if (safeAsciiPtr[len - 2] == '=') + ++pad; - *flen = 3 * len / 4 - pad; - bin = (unsigned char *)MEM2_alloc(*flen); - if (!bin) - return 0; + *flen = 3 * len / 4 - pad; + bin = (unsigned char *)MEM2_alloc(*flen); + if (!bin) + return 0; - for (charNo = 0; charNo <= len - 4 - pad; charNo += 4) - { - int A = unb64[safeAsciiPtr[charNo]]; - int B = unb64[safeAsciiPtr[charNo + 1]]; - int C = unb64[safeAsciiPtr[charNo + 2]]; - int D = unb64[safeAsciiPtr[charNo + 3]]; + for (charNo = 0; charNo <= len - 4 - pad; charNo += 4) + { + int A = unb64[safeAsciiPtr[charNo]]; + int B = unb64[safeAsciiPtr[charNo + 1]]; + int C = unb64[safeAsciiPtr[charNo + 2]]; + int D = unb64[safeAsciiPtr[charNo + 3]]; - bin[cb++] = (A << 2) | (B >> 4); - bin[cb++] = (B << 4) | (C >> 2); - bin[cb++] = (C << 6) | (D); - } + bin[cb++] = (A << 2) | (B >> 4); + bin[cb++] = (B << 4) | (C >> 2); + bin[cb++] = (C << 6) | (D); + } - if (pad == 1) - { - int A = unb64[safeAsciiPtr[charNo]]; - int B = unb64[safeAsciiPtr[charNo + 1]]; - int C = unb64[safeAsciiPtr[charNo + 2]]; + if (pad == 1) + { + int A = unb64[safeAsciiPtr[charNo]]; + int B = unb64[safeAsciiPtr[charNo + 1]]; + int C = unb64[safeAsciiPtr[charNo + 2]]; - bin[cb++] = (A << 2) | (B >> 4); - bin[cb++] = (B << 4) | (C >> 2); - } - else if (pad == 2) - { - int A = unb64[safeAsciiPtr[charNo]]; - int B = unb64[safeAsciiPtr[charNo + 1]]; + bin[cb++] = (A << 2) | (B >> 4); + bin[cb++] = (B << 4) | (C >> 2); + } + else if (pad == 2) + { + int A = unb64[safeAsciiPtr[charNo]]; + int B = unb64[safeAsciiPtr[charNo + 1]]; - bin[cb++] = (A << 2) | (B >> 4); - } + bin[cb++] = (A << 2) | (B >> 4); + } - return bin; + return bin; } #endif diff --git a/source/network/https.c b/source/network/https.c index e07c1bb7..84cc5147 100644 --- a/source/network/https.c +++ b/source/network/https.c @@ -16,559 +16,565 @@ WOLFSSL_SESSION *session; int https_write(HTTP_INFO *httpinfo, char *buffer, int len, bool proxy) { - int ret, pos = 0; - int rlen = len > BLOCK_SIZE ? BLOCK_SIZE : len; - u64 time = gettime(); - while (ticks_to_millisecs(diff_ticks(time, gettime())) < READ_WRITE_TIMEOUT) - { - if (httpinfo->use_https && !proxy) - ret = wolfSSL_write(httpinfo->ssl, &buffer[pos], rlen); - else - ret = net_write(httpinfo->sock, &buffer[pos], rlen); - if (ret > 0) - { - pos += ret; - rlen = len - pos > BLOCK_SIZE ? BLOCK_SIZE : len - pos; - if (pos >= len) - return pos; - time = gettime(); - } - usleep(10000); - } + int ret, pos = 0; + int rlen = len > BLOCK_SIZE ? BLOCK_SIZE : len; + u64 time = gettime(); + while (ticks_to_millisecs(diff_ticks(time, gettime())) < READ_WRITE_TIMEOUT) + { + if (httpinfo->use_https && !proxy) + ret = wolfSSL_write(httpinfo->ssl, &buffer[pos], rlen); + else + ret = net_write(httpinfo->sock, &buffer[pos], rlen); + if (ret > 0) + { + pos += ret; + rlen = len - pos > BLOCK_SIZE ? BLOCK_SIZE : len - pos; + if (pos >= len) + return pos; + time = gettime(); + } + usleep(10000); + } #ifdef DEBUG_NETWORK - gprintf("The connection timed out (write)\n"); + gprintf("The connection timed out (write)\n"); #endif - return -ETIMEDOUT; + return -ETIMEDOUT; } int https_read(HTTP_INFO *httpinfo, char *buffer, int len, bool proxy) { - int ret = -ETIMEDOUT; - u64 time = gettime(); - if (len > BLOCK_SIZE) - len = BLOCK_SIZE; - while (ticks_to_millisecs(diff_ticks(time, gettime())) < READ_WRITE_TIMEOUT) - { - if (httpinfo->use_https && !proxy) - ret = wolfSSL_read(httpinfo->ssl, buffer, len); - else - ret = net_read(httpinfo->sock, buffer, len); - if (ret >= 0) - return ret; - usleep(10000); - } + int ret = -ETIMEDOUT; + u64 time = gettime(); + if (len > BLOCK_SIZE) + len = BLOCK_SIZE; + while (ticks_to_millisecs(diff_ticks(time, gettime())) < READ_WRITE_TIMEOUT) + { + if (httpinfo->use_https && !proxy) + ret = wolfSSL_read(httpinfo->ssl, buffer, len); + else + ret = net_read(httpinfo->sock, buffer, len); + if (ret >= 0) + return ret; + usleep(10000); + } #ifdef DEBUG_NETWORK - gprintf("The connection timed out (read)\n"); + gprintf("The connection timed out (read)\n"); #endif - return -ETIMEDOUT; + return -ETIMEDOUT; } int send_callback(__attribute__((unused)) WOLFSSL *ssl, char *buf, int sz, void *ctx) { - int sent = net_write(*(int *)ctx, buf, sz); - if (sent < 0) - { - if (sent == -EAGAIN) - return WOLFSSL_CBIO_ERR_WANT_WRITE; - else if (sent == -ECONNRESET) - return WOLFSSL_CBIO_ERR_CONN_RST; - else if (sent == -EINTR) - return WOLFSSL_CBIO_ERR_ISR; - else if (sent == -EPIPE) - return WOLFSSL_CBIO_ERR_CONN_CLOSE; - else - return WOLFSSL_CBIO_ERR_GENERAL; - } - return sent; + int sent = net_write(*(int *)ctx, buf, sz); + if (sent < 0) + { + if (sent == -EAGAIN) + return WOLFSSL_CBIO_ERR_WANT_WRITE; + else if (sent == -ECONNRESET) + return WOLFSSL_CBIO_ERR_CONN_RST; + else if (sent == -EINTR) + return WOLFSSL_CBIO_ERR_ISR; + else if (sent == -EPIPE) + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + else + return WOLFSSL_CBIO_ERR_GENERAL; + } + return sent; } int recv_callback(__attribute__((unused)) WOLFSSL *ssl, char *buf, int sz, void *ctx) { - int recvd = net_read(*(int *)ctx, buf, sz); - if (recvd < 0) - { - if (recvd == -EAGAIN) - return WOLFSSL_CBIO_ERR_WANT_READ; - else if (recvd == -ECONNRESET) - return WOLFSSL_CBIO_ERR_CONN_RST; - else if (recvd == -EINTR) - return WOLFSSL_CBIO_ERR_ISR; - else if (recvd == -ECONNABORTED) - return WOLFSSL_CBIO_ERR_CONN_CLOSE; - else - return WOLFSSL_CBIO_ERR_GENERAL; - } - else if (recvd == 0) - return WOLFSSL_CBIO_ERR_CONN_CLOSE; - return recvd; + int recvd = net_read(*(int *)ctx, buf, sz); + if (recvd < 0) + { + if (recvd == -EAGAIN) + return WOLFSSL_CBIO_ERR_WANT_READ; + else if (recvd == -ECONNRESET) + return WOLFSSL_CBIO_ERR_CONN_RST; + else if (recvd == -EINTR) + return WOLFSSL_CBIO_ERR_ISR; + else if (recvd == -ECONNABORTED) + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + else + return WOLFSSL_CBIO_ERR_GENERAL; + } + else if (recvd == 0) + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + return recvd; } void https_close(HTTP_INFO *httpinfo) { - if (httpinfo->use_https) - { - wolfSSL_shutdown(httpinfo->ssl); - wolfSSL_free(httpinfo->ssl); - wolfSSL_CTX_free(httpinfo->ctx); - } - net_close(httpinfo->sock); + if (httpinfo->use_https) + { + wolfSSL_shutdown(httpinfo->ssl); + wolfSSL_free(httpinfo->ssl); + wolfSSL_CTX_free(httpinfo->ctx); + } + net_close(httpinfo->sock); #ifdef DEBUG_NETWORK - gprintf("Closed socket and cleaned up\n"); + gprintf("Closed socket and cleaned up\n"); #endif } bool get_header_value(struct phr_header *headers, size_t num_headers, char *dst, char *header) { - for (size_t i = 0; i != num_headers; ++i) - { - if (strncasecmp(header, headers[i].name, headers[i].name_len) == 0) - { - strlcpy(dst, headers[i].value, headers[i].value_len + 1); - return true; - } - } - return false; + for (size_t i = 0; i != num_headers; ++i) + { + if (strncasecmp(header, headers[i].name, headers[i].name_len) == 0) + { + strlcpy(dst, headers[i].value, headers[i].value_len + 1); + return true; + } + } + return false; } u64 get_header_value_int(struct phr_header *headers, size_t num_headers, char *header) { - char header_value[30]; - if (!get_header_value(headers, num_headers, header_value, header)) - return 0; - return strtoull(header_value, NULL, 0); + char header_value[30]; + if (!get_header_value(headers, num_headers, header_value, header)) + return 0; + return strtoull(header_value, NULL, 0); } bool is_chunked(struct phr_header *headers, size_t num_headers) { - char encoding[9]; - if (!get_header_value(headers, num_headers, encoding, "transfer-encoding")) - return false; - return (strcasecmp(encoding, "chunked") == 0); + char encoding[9]; + if (!get_header_value(headers, num_headers, encoding, "transfer-encoding")) + return false; + return (strcasecmp(encoding, "chunked") == 0); } bool read_chunked(HTTP_INFO *httpinfo, struct download *buffer, size_t start_pos) { - struct phr_chunked_decoder decoder = {0}; - size_t rsize, capacity = 4096; - ssize_t pret; - int ret; - decoder.consume_trailer = true; + struct phr_chunked_decoder decoder = {0}; + size_t rsize, capacity = 4096; + ssize_t pret; + int ret; + decoder.consume_trailer = true; #ifdef DEBUG_NETWORK - gprintf("Data is chunked\n"); + gprintf("Data is chunked\n"); #endif - do - { - if (start_pos == capacity) - { + do + { + if (start_pos == capacity) + { #ifdef DEBUG_NETWORK - gprintf("Increased buffer size\n"); + gprintf("Increased buffer size\n"); #endif - capacity *= 2; - buffer->data = MEM2_realloc(buffer->data, capacity); - } - if ((ret = https_read(httpinfo, &buffer->data[start_pos], capacity - start_pos, false)) < 1) - return false; - rsize = ret; - pret = phr_decode_chunked(&decoder, &buffer->data[start_pos], &rsize); - if (pret == -1) - { + capacity *= 2; + buffer->data = MEM2_realloc(buffer->data, capacity); + } + if ((ret = https_read(httpinfo, &buffer->data[start_pos], capacity - start_pos, false)) < 1) + return false; + rsize = ret; + pret = phr_decode_chunked(&decoder, &buffer->data[start_pos], &rsize); + if (pret == -1) + { #ifdef DEBUG_NETWORK - gprintf("Parse error\n"); + gprintf("Parse error\n"); #endif - return false; - } - start_pos += rsize; - } while (pret == -2); - buffer->size = start_pos; - buffer->data = MEM2_realloc(buffer->data, buffer->size); - return true; + return false; + } + start_pos += rsize; + } while (pret == -2); + buffer->size = start_pos; + buffer->data = MEM2_realloc(buffer->data, buffer->size); + return true; } bool read_all(HTTP_INFO *httpinfo, struct download *buffer, size_t start_pos) { - size_t capacity = 4096; - int ret; + size_t capacity = 4096; + int ret; #ifdef DEBUG_NETWORK - gprintf("Data is not chunked\n"); + gprintf("Data is not chunked\n"); #endif - while (true) - { - if (start_pos == capacity) - { + while (true) + { + if (start_pos == capacity) + { #ifdef DEBUG_NETWORK - gprintf("Increased buffer size\n"); + gprintf("Increased buffer size\n"); #endif - capacity *= 2; - buffer->data = MEM2_realloc(buffer->data, capacity); - } - if ((ret = https_read(httpinfo, &buffer->data[start_pos], capacity - start_pos, false)) == 0) - break; - if (ret < 0) - return false; - start_pos += ret; - }; - buffer->size = start_pos; - buffer->data = MEM2_realloc(buffer->data, buffer->size); - return (buffer->content_length > 0 && buffer->content_length == start_pos); + capacity *= 2; + buffer->data = MEM2_realloc(buffer->data, capacity); + } + if ((ret = https_read(httpinfo, &buffer->data[start_pos], capacity - start_pos, false)) == 0) + break; + if (ret < 0) + return false; + start_pos += ret; + }; + buffer->size = start_pos; + buffer->data = MEM2_realloc(buffer->data, buffer->size); + return (buffer->content_length > 0 && buffer->content_length == start_pos); } bool get_response(HTTP_INFO *httpinfo, HTTP_RESPONSE *resp, bool proxy) { - int rret, minor_version; - size_t msg_len, prevbuflen; - const char *msg; + int rret, minor_version; + size_t msg_len, prevbuflen; + const char *msg; - while (true) - { - if ((rret = https_read(httpinfo, &resp->data[resp->buflen], 1, proxy)) < 1) - return false; - prevbuflen = resp->buflen; - resp->buflen += rret; - // Parse the response - resp->num_headers = sizeof(resp->headers) / sizeof(resp->headers[0]); - if ((resp->pret = phr_parse_response(resp->data, resp->buflen, &minor_version, &resp->status, &msg, &msg_len, resp->headers, &resp->num_headers, prevbuflen)) > 0) - return true; - else if (resp->pret == -1) - { + while (true) + { + if ((rret = https_read(httpinfo, &resp->data[resp->buflen], 1, proxy)) < 1) + return false; + prevbuflen = resp->buflen; + resp->buflen += rret; + // Parse the response + resp->num_headers = sizeof(resp->headers) / sizeof(resp->headers[0]); + if ((resp->pret = phr_parse_response(resp->data, resp->buflen, &minor_version, &resp->status, &msg, &msg_len, + resp->headers, &resp->num_headers, prevbuflen)) > 0) + return true; + else if (resp->pret == -1) + { #ifdef DEBUG_NETWORK - gprintf("pret error %i\n", resp->pret); + gprintf("pret error %i\n", resp->pret); #endif - return false; - } - if (resp->buflen == sizeof(resp->data)) - { + return false; + } + if (resp->buflen == sizeof(resp->data)) + { #ifdef DEBUG_NETWORK - gprintf("buflen error %lu\n", (unsigned long)resp->buflen); + gprintf("buflen error %lu\n", (unsigned long)resp->buflen); #endif - return false; - } - } - return false; + return false; + } + } + return false; } bool check_ip(char *str) { - int partA, partB, partC, partD; - char extra; - // We avoid using regex because it increases the file size - return (sscanf(str, "%d.%d.%d.%d%c", &partA, &partB, &partC, &partD, &extra) == 4); + int partA, partB, partC, partD; + char extra; + // We avoid using regex because it increases the file size + return (sscanf(str, "%d.%d.%d.%d%c", &partA, &partB, &partC, &partD, &extra) == 4); } bool connect_proxy(HTTP_INFO *httpinfo, char *host, char *username, char *password) { - HTTP_RESPONSE response = {0}; - char request[500]; - char credentials[66]; - char *auth; - int len; - if (username && password) - { - if (!snprintf(credentials, sizeof(credentials), "%s:%s", username, password)) - return false; - if (!(auth = base64(credentials, strlen(credentials), &len))) - return false; - len = snprintf(request, sizeof(request), "CONNECT %s:%i HTTP/1.1\r\nProxy-Authorization: Basic %s\r\nUser-Agent: curl/7.55.1\r\n\r\n", host, httpinfo->use_https ? 443 : 80, auth); - MEM2_free(auth); - } - else - len = snprintf(request, sizeof(request), "CONNECT %s:%i HTTP/1.1\r\nUser-Agent: curl/7.55.1\r\n\r\n", host, httpinfo->use_https ? 443 : 80); - if (len > 0 && https_write(httpinfo, request, len, true) != len) - return false; - if (get_response(httpinfo, &response, true)) - { - if (response.status == 200) - return true; - } - return false; + HTTP_RESPONSE response = {0}; + char request[500]; + char credentials[66]; + char *auth; + int len; + if (username && password) + { + if (!snprintf(credentials, sizeof(credentials), "%s:%s", username, password)) + return false; + if (!(auth = base64(credentials, strlen(credentials), &len))) + return false; + len = snprintf(request, sizeof(request), + "CONNECT %s:%i HTTP/1.1\r\nProxy-Authorization: Basic %s\r\nUser-Agent: curl/7.55.1\r\n\r\n", + host, httpinfo->use_https ? 443 : 80, auth); + MEM2_free(auth); + } + else + len = snprintf(request, sizeof(request), + "CONNECT %s:%i HTTP/1.1\r\nUser-Agent: curl/7.55.1\r\n\r\n", + host, httpinfo->use_https ? 443 : 80); + if (len > 0 && https_write(httpinfo, request, len, true) != len) + return false; + if (get_response(httpinfo, &response, true)) + { + if (response.status == 200) + return true; + } + return false; } int connect(char *host, u16 port) { - struct sockaddr_in sin; - s32 sock, ret; - u32 ipaddress; - u64 time; + struct sockaddr_in sin; + s32 sock, ret; + u32 ipaddress; + u64 time; #ifdef DEBUG_NETWORK - gprintf("Connecting to %s", host); + gprintf("Connecting to %s", host); #endif - if ((ipaddress = check_ip(host) ? inet_addr(host) : getipbynamecached(host)) == 0) - return -EFAULT; - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = ipaddress; + if ((ipaddress = check_ip(host) ? inet_addr(host) : getipbynamecached(host)) == 0) + return -EFAULT; + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = ipaddress; #ifdef DEBUG_NETWORK - if (!check_ip(host)) - gprintf(" (%s)", inet_ntoa(sin.sin_addr)); + if (!check_ip(host)) + gprintf(" (%s)", inet_ntoa(sin.sin_addr)); #endif - if ((sock = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0) - return sock; - net_fcntl(sock, F_SETFL, 4); - time = gettime(); - while (ticks_to_millisecs(diff_ticks(time, gettime())) < CONNECT_TIMEOUT) - { - if ((ret = net_connect(sock, (struct sockaddr *)&sin, sizeof(sin))) < 0) - { - if (ret == -EISCONN) - return sock; - if (ret == -EINPROGRESS || ret == -EALREADY) - { - usleep(10000); - continue; - } - net_close(sock); - return ret; - } - } - net_close(sock); - return -ETIMEDOUT; + if ((sock = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0) + return sock; + net_fcntl(sock, F_SETFL, 4); + time = gettime(); + while (ticks_to_millisecs(diff_ticks(time, gettime())) < CONNECT_TIMEOUT) + { + if ((ret = net_connect(sock, (struct sockaddr *)&sin, sizeof(sin))) < 0) + { + if (ret == -EISCONN) + return sock; + if (ret == -EINPROGRESS || ret == -EALREADY) + { + usleep(10000); + continue; + } + net_close(sock); + return ret; + } + } + net_close(sock); + return -ETIMEDOUT; } void downloadfile(const char *url, struct download *buffer) { - HTTP_INFO httpinfo = {0}; - // Always reset the size due to the image downloader looping - buffer->size = 0; - // Check if we're using HTTPS and set the path - char *path; - if (strncmp(url, "https://", 8) == 0) - { - httpinfo.use_https = 1; - path = strchr(url + 8, '/'); - } - else if (strncmp(url, "http://", 7) == 0) - { - httpinfo.use_https = 0; - path = strchr(url + 7, '/'); - } - else - return; - if (path == NULL) - return; - // Get the host - int domainlength = path - url - 7 - httpinfo.use_https; - char host[domainlength + 1]; - strlcpy(host, url + 7 + httpinfo.use_https, domainlength + 1); - // Start connecting - if (getProxyAddress() && getProxyPort() > 0) - httpinfo.sock = connect(getProxyAddress(), getProxyPort()); - else - httpinfo.sock = connect(host, httpinfo.use_https ? 443 : 80); + HTTP_INFO httpinfo = {0}; + // Always reset the size due to the image downloader looping + buffer->size = 0; + // Check if we're using HTTPS and set the path + char *path; + if (strncmp(url, "https://", 8) == 0) + { + httpinfo.use_https = 1; + path = strchr(url + 8, '/'); + } + else if (strncmp(url, "http://", 7) == 0) + { + httpinfo.use_https = 0; + path = strchr(url + 7, '/'); + } + else + return; + if (path == NULL) + return; + // Get the host + int domainlength = path - url - 7 - httpinfo.use_https; + char host[domainlength + 1]; + strlcpy(host, url + 7 + httpinfo.use_https, domainlength + 1); + // Start connecting + if (getProxyAddress() && getProxyPort() > 0) + httpinfo.sock = connect(getProxyAddress(), getProxyPort()); + else + httpinfo.sock = connect(host, httpinfo.use_https ? 443 : 80); - if (httpinfo.sock < 0) - { + if (httpinfo.sock < 0) + { #ifdef DEBUG_NETWORK - if (httpinfo.sock == -ETIMEDOUT) - gprintf("\nFailed to connect (timed out)\n"); - else - gprintf("\nFailed to connect (%i)\n", httpinfo.sock); + if (httpinfo.sock == -ETIMEDOUT) + gprintf("\nFailed to connect (timed out)\n"); + else + gprintf("\nFailed to connect (%i)\n", httpinfo.sock); #endif - return; - } + return; + } #ifdef DEBUG_NETWORK - gprintf("\nConnected\n"); + gprintf("\nConnected\n"); #endif - // Connect to a web proxy - if (getProxyAddress() && getProxyPort() > 0) - { - if (!connect_proxy(&httpinfo, host, getProxyUsername(), getProxyPassword())) - { + // Connect to a web proxy + if (getProxyAddress() && getProxyPort() > 0) + { + if (!connect_proxy(&httpinfo, host, getProxyUsername(), getProxyPassword())) + { #ifdef DEBUG_NETWORK - gprintf("Failed to connect to proxy (%s:%i)\n", getProxyAddress(), getProxyPort()); + gprintf("Failed to connect to proxy (%s:%i)\n", getProxyAddress(), getProxyPort()); #endif - https_close(&httpinfo); - return; - } - session = NULL; // Resume doesn't work with a proxy + https_close(&httpinfo); + return; + } + session = NULL; // Resume doesn't work with a proxy #ifdef DEBUG_NETWORK - gprintf("Proxy is ready to receive\n"); + gprintf("Proxy is ready to receive\n"); #endif - } - // Setup for HTTPS if it's necessary - if (httpinfo.use_https) - { - // Create a new SSL context - // wolfSSLv23_client_method() works but TLS 1.2 is slightly faster on Wii - if ((httpinfo.ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())) == NULL) - { + } + // Setup for HTTPS if it's necessary + if (httpinfo.use_https) + { + // Create a new SSL context + // wolfSSLv23_client_method() works but TLS 1.2 is slightly faster on Wii + if ((httpinfo.ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())) == NULL) + { #ifdef DEBUG_NETWORK - gprintf("Failed to create WOLFSSL_CTX\n"); + gprintf("Failed to create WOLFSSL_CTX\n"); #endif - https_close(&httpinfo); - return; - } - // Don't verify certificates - wolfSSL_CTX_set_verify(httpinfo.ctx, WOLFSSL_VERIFY_NONE, 0); - // Enable SNI - if (wolfSSL_CTX_UseSNI(httpinfo.ctx, 0, host, strlen(host)) != WOLFSSL_SUCCESS) - { + https_close(&httpinfo); + return; + } + // Don't verify certificates + wolfSSL_CTX_set_verify(httpinfo.ctx, WOLFSSL_VERIFY_NONE, 0); + // Enable SNI + if (wolfSSL_CTX_UseSNI(httpinfo.ctx, 0, host, strlen(host)) != WOLFSSL_SUCCESS) + { #ifdef DEBUG_NETWORK - gprintf("Failed to set SNI\n"); + gprintf("Failed to set SNI\n"); #endif - https_close(&httpinfo); - return; - } - // Custom I/O is essential due to how libogc handles errors - wolfSSL_SetIOSend(httpinfo.ctx, send_callback); - wolfSSL_SetIORecv(httpinfo.ctx, recv_callback); - // Create a new wolfSSL session - if ((httpinfo.ssl = wolfSSL_new(httpinfo.ctx)) == NULL) - { + https_close(&httpinfo); + return; + } + // Custom I/O is essential due to how libogc handles errors + wolfSSL_SetIOSend(httpinfo.ctx, send_callback); + wolfSSL_SetIORecv(httpinfo.ctx, recv_callback); + // Create a new wolfSSL session + if ((httpinfo.ssl = wolfSSL_new(httpinfo.ctx)) == NULL) + { #ifdef DEBUG_NETWORK - gprintf("SSL session creation failed\n"); + gprintf("SSL session creation failed\n"); #endif - https_close(&httpinfo); - return; - } - // Set the file descriptor - if (wolfSSL_set_fd(httpinfo.ssl, httpinfo.sock) != SSL_SUCCESS) - { + https_close(&httpinfo); + return; + } + // Set the file descriptor + if (wolfSSL_set_fd(httpinfo.ssl, httpinfo.sock) != SSL_SUCCESS) + { #ifdef DEBUG_NETWORK - gprintf("Failed to set SSL file descriptor\n"); + gprintf("Failed to set SSL file descriptor\n"); #endif - https_close(&httpinfo); - return; - } - // Attempt to resume the session - if (session != NULL && wolfSSL_set_session(httpinfo.ssl, session) != SSL_SUCCESS) - { + https_close(&httpinfo); + return; + } + // Attempt to resume the session + if (session != NULL && wolfSSL_set_session(httpinfo.ssl, session) != SSL_SUCCESS) + { #ifdef DEBUG_NETWORK - gprintf("Failed to set session (session timed out?)\n"); + gprintf("Failed to set session (session timed out?)\n"); #endif - session = NULL; - } - // Initiate a handshake - u64 time = gettime(); - while (true) - { - if (ticks_to_millisecs(diff_ticks(time, gettime())) > CONNECT_TIMEOUT) - { + session = NULL; + } + // Initiate a handshake + u64 time = gettime(); + while (true) + { + if (ticks_to_millisecs(diff_ticks(time, gettime())) > CONNECT_TIMEOUT) + { #ifdef DEBUG_NETWORK - gprintf("SSL handshake failed\n"); + gprintf("SSL handshake failed\n"); #endif - https_close(&httpinfo); - return; - } - if (wolfSSL_connect(httpinfo.ssl) == SSL_SUCCESS) - break; - usleep(10000); - } - // Check if we resumed successfully - if (session != NULL && !wolfSSL_session_reused(httpinfo.ssl)) - { + https_close(&httpinfo); + return; + } + if (wolfSSL_connect(httpinfo.ssl) == SSL_SUCCESS) + break; + usleep(10000); + } + // Check if we resumed successfully + if (session != NULL && !wolfSSL_session_reused(httpinfo.ssl)) + { #ifdef DEBUG_NETWORK - gprintf("Failed to resume session\n"); + gprintf("Failed to resume session\n"); #endif - session = NULL; - } - // Cipher info + session = NULL; + } + // Cipher info #ifdef DEBUG_NETWORK - /*char ciphers[4096]; + /*char ciphers[4096]; wolfSSL_get_ciphers(ciphers, (int)sizeof(ciphers)); gprintf("All supported ciphers: %s\n", ciphers);*/ - WOLFSSL_CIPHER *cipher = wolfSSL_get_current_cipher(httpinfo.ssl); - gprintf("Using: %s - %s\n", wolfSSL_get_version(httpinfo.ssl), wolfSSL_CIPHER_get_name(cipher)); + WOLFSSL_CIPHER *cipher = wolfSSL_get_current_cipher(httpinfo.ssl); + gprintf("Using: %s - %s\n", wolfSSL_get_version(httpinfo.ssl), wolfSSL_CIPHER_get_name(cipher)); #endif - } - // Send our request - char request[2300]; - int ret, len; - len = snprintf(request, sizeof(request), - "GET %s HTTP/1.1\r\n" - "Host: %s\r\n" - "User-Agent: WiiFlow-Lite\r\n" - "Connection: close\r\n" - "Pragma: no-cache\r\n" - "Cache-Control: no-cache\r\n\r\n", - path, host); - if ((ret = https_write(&httpinfo, request, len, false)) != len) - { + } + // Send our request + char request[2300]; + int ret, len; + len = snprintf(request, sizeof(request), + "GET %s HTTP/1.1\r\n" + "Host: %s\r\n" + "User-Agent: WiiFlow-Lite\r\n" + "Connection: close\r\n" + "Pragma: no-cache\r\n" + "Cache-Control: no-cache\r\n\r\n", + path, host); + if ((ret = https_write(&httpinfo, request, len, false)) != len) + { #ifdef DEBUG_NETWORK - gprintf("https_write error: %i\n", ret); + gprintf("https_write error: %i\n", ret); #endif - https_close(&httpinfo); - return; - } - // Check if we want a response - if (buffer->skip_response) - { + https_close(&httpinfo); + return; + } + // Check if we want a response + if (buffer->skip_response) + { #ifdef DEBUG_NETWORK - gprintf("Sent request to %s and skipping response\n", host); + gprintf("Sent request to %s and skipping response\n", host); #endif - https_close(&httpinfo); - return; - } - // Get the response - HTTP_RESPONSE response = {0}; - if (!get_response(&httpinfo, &response, false)) - { - https_close(&httpinfo); - return; - } - // The website wants to redirect us - if (response.status == 301 || response.status == 302) - { - https_close(&httpinfo); - if (loop == REDIRECT_LIMIT) - { + https_close(&httpinfo); + return; + } + // Get the response + HTTP_RESPONSE response = {0}; + if (!get_response(&httpinfo, &response, false)) + { + https_close(&httpinfo); + return; + } + // The website wants to redirect us + if (response.status == 301 || response.status == 302) + { + https_close(&httpinfo); + if (loop == REDIRECT_LIMIT) + { #ifdef DEBUG_NETWORK - gprintf("Reached redirect limit\n"); + gprintf("Reached redirect limit\n"); #endif - return; - } - loop++; - char location[2049]; - if (!get_header_value(response.headers, response.num_headers, location, "location")) - return; + return; + } + loop++; + char location[2049]; + if (!get_header_value(response.headers, response.num_headers, location, "location")) + return; #ifdef DEBUG_NETWORK - gprintf("Redirect #%i - %s\n", loop, location); + gprintf("Redirect #%i - %s\n", loop, location); #endif - downloadfile(location, buffer); - return; - } - // It's not 301 or 302, so reset the loop - loop = 0; - // We got what we wanted - if (response.status == 200) - { - buffer->data = MEM2_alloc(4096); - memcpy(buffer->data, &response.data[response.pret], response.buflen - response.pret); - // Determine how to read the data - bool dl_valid; - if (is_chunked(response.headers, response.num_headers)) - dl_valid = read_chunked(&httpinfo, buffer, response.buflen - response.pret); - else - { - buffer->content_length = get_header_value_int(response.headers, response.num_headers, "content-length"); - dl_valid = read_all(&httpinfo, buffer, response.buflen - response.pret); - } - // Check if the download is incomplete - if (!dl_valid || buffer->size < 1) - { - buffer->size = 0; - MEM2_free(buffer->data); + downloadfile(location, buffer); + return; + } + // It's not 301 or 302, so reset the loop + loop = 0; + // We got what we wanted + if (response.status == 200) + { + buffer->data = MEM2_alloc(4096); + memcpy(buffer->data, &response.data[response.pret], response.buflen - response.pret); + // Determine how to read the data + bool dl_valid; + if (is_chunked(response.headers, response.num_headers)) + dl_valid = read_chunked(&httpinfo, buffer, response.buflen - response.pret); + else + { + buffer->content_length = get_header_value_int(response.headers, response.num_headers, "content-length"); + dl_valid = read_all(&httpinfo, buffer, response.buflen - response.pret); + } + // Check if the download is incomplete + if (!dl_valid || buffer->size < 1) + { + buffer->size = 0; + MEM2_free(buffer->data); #ifdef DEBUG_NETWORK - gprintf("Removed incomplete download\n"); + gprintf("Removed incomplete download\n"); #endif - https_close(&httpinfo); - return; - } - // Save the session - if (httpinfo.use_https) - session = wolfSSL_get_session(httpinfo.ssl); - // Finished - https_close(&httpinfo); + https_close(&httpinfo); + return; + } + // Save the session + if (httpinfo.use_https) + session = wolfSSL_get_session(httpinfo.ssl); + // Finished + https_close(&httpinfo); #ifdef DEBUG_NETWORK - gprintf("Download size: %llu\n", (long long)buffer->size); - gprintf("------------- HEADERS -------------\n"); - for (size_t i = 0; i != response.num_headers; ++i) - gprintf("%.*s: %.*s\n", (int)response.headers[i].name_len, response.headers[i].name, (int)response.headers[i].value_len, response.headers[i].value); - gprintf("------------ COMPLETED ------------\n"); + gprintf("Download size: %llu\n", (long long)buffer->size); + gprintf("------------- HEADERS -------------\n"); + for (size_t i = 0; i != response.num_headers; ++i) + gprintf("%.*s: %.*s\n", (int)response.headers[i].name_len, response.headers[i].name, + (int)response.headers[i].value_len, response.headers[i].value); + gprintf("------------ COMPLETED ------------\n"); #endif - return; - } - // Close on all other status codes + return; + } + // Close on all other status codes #ifdef DEBUG_NETWORK - gprintf("Status code: %i - %s\n", response.status, url); + gprintf("Status code: %i - %s\n", response.status, url); #endif - https_close(&httpinfo); + https_close(&httpinfo); } diff --git a/source/network/https.h b/source/network/https.h index 7b602ce1..1886e423 100644 --- a/source/network/https.h +++ b/source/network/https.h @@ -21,34 +21,34 @@ extern "C" #define READ_WRITE_TIMEOUT 20000 #define BLOCK_SIZE 8192 - struct download - { - bool skip_response; // Used by WiinnerTag - u64 content_length; - u64 size; - char *data; - }; + struct download + { + bool skip_response; // Used by WiinnerTag + u64 content_length; + u64 size; + char *data; + }; - typedef struct - { - int status; - int pret; - size_t num_headers; - size_t buflen; - struct phr_header headers[100]; - char data[4096]; - } HTTP_RESPONSE; + typedef struct + { + int status; + int pret; + size_t num_headers; + size_t buflen; + struct phr_header headers[100]; + char data[4096]; + } HTTP_RESPONSE; - typedef struct - { - u8 use_https; - s32 sock; - WOLFSSL *ssl; - WOLFSSL_CTX *ctx; - } HTTP_INFO; + typedef struct + { + u8 use_https; + s32 sock; + WOLFSSL *ssl; + WOLFSSL_CTX *ctx; + } HTTP_INFO; - void downloadfile(const char *url, struct download *buffer); - int wolfSSL_CTX_UseSNI(WOLFSSL_CTX *ctx, unsigned char type, const void *data, unsigned short size); + void downloadfile(const char *url, struct download *buffer); + int wolfSSL_CTX_UseSNI(WOLFSSL_CTX *ctx, unsigned char type, const void *data, unsigned short size); #ifdef __cplusplus } diff --git a/source/network/proxysettings.cpp b/source/network/proxysettings.cpp index d0aca3c6..e9122a90 100644 --- a/source/network/proxysettings.cpp +++ b/source/network/proxysettings.cpp @@ -17,59 +17,59 @@ char proxy_password[33]; void getProxyInfo() { - char *buffer; - int fd = ISFS_Open("/shared2/sys/net/02/config.dat", ISFS_OPEN_READ); - if (fd >= 0) - { - fstats stats ATTRIBUTE_ALIGN(32); - if(ISFS_GetFileStats(fd, &stats) >= 0) - { - if (stats.file_length == 7004) - { - buffer = (char *)MEM2_alloc(ALIGN32(stats.file_length)); - if (buffer) - { - if (ISFS_Read(fd, buffer, stats.file_length) == 7004) - { - proxy_enabled = buffer[44]; - proxy_creds_enabled = buffer[45]; - strncpy(proxy_address, buffer + 48, sizeof(proxy_address) - 1); - proxy_port = ((buffer[304] & 0xFF) << 8) | (buffer[305] & 0xFF); - strncpy(proxy_username, buffer + 306, sizeof(proxy_username) - 1); - strncpy(proxy_password, buffer + 338, sizeof(proxy_password) - 1); - } - } - MEM2_free(buffer); - } - } - ISFS_Close(fd); - } + char *buffer; + int fd = ISFS_Open("/shared2/sys/net/02/config.dat", ISFS_OPEN_READ); + if (fd >= 0) + { + fstats stats ATTRIBUTE_ALIGN(32); + if (ISFS_GetFileStats(fd, &stats) >= 0) + { + if (stats.file_length == 7004) + { + buffer = (char *)MEM2_alloc(ALIGN32(stats.file_length)); + if (buffer) + { + if (ISFS_Read(fd, buffer, stats.file_length) == 7004) + { + proxy_enabled = buffer[44]; + proxy_creds_enabled = buffer[45]; + strncpy(proxy_address, buffer + 48, sizeof(proxy_address) - 1); + proxy_port = ((buffer[304] & 0xFF) << 8) | (buffer[305] & 0xFF); + strncpy(proxy_username, buffer + 306, sizeof(proxy_username) - 1); + strncpy(proxy_password, buffer + 338, sizeof(proxy_password) - 1); + } + } + MEM2_free(buffer); + } + } + ISFS_Close(fd); + } } char *getProxyAddress() { - if (mainMenu.proxyUseSystem) - return proxy_enabled ? proxy_address : NULL; - return (strlen(mainMenu.proxyAddress) > 6) ? mainMenu.proxyAddress : NULL; + if (mainMenu.proxyUseSystem) + return proxy_enabled ? proxy_address : NULL; + return (strlen(mainMenu.proxyAddress) > 6) ? mainMenu.proxyAddress : NULL; } u16 getProxyPort() { - if (mainMenu.proxyUseSystem) - return proxy_enabled ? proxy_port : 0; - return mainMenu.proxyPort; + if (mainMenu.proxyUseSystem) + return proxy_enabled ? proxy_port : 0; + return mainMenu.proxyPort; } char *getProxyUsername() { - if (mainMenu.proxyUseSystem) - return proxy_enabled && proxy_creds_enabled ? proxy_username : NULL; - return (strlen(mainMenu.proxyUsername) > 0) ? mainMenu.proxyUsername : NULL; + if (mainMenu.proxyUseSystem) + return proxy_enabled && proxy_creds_enabled ? proxy_username : NULL; + return (strlen(mainMenu.proxyUsername) > 0) ? mainMenu.proxyUsername : NULL; } char *getProxyPassword() { - if (mainMenu.proxyUseSystem) - return proxy_enabled && proxy_creds_enabled ? proxy_password : NULL; - return (strlen(mainMenu.proxyPassword) > 0) ? mainMenu.proxyPassword : NULL; + if (mainMenu.proxyUseSystem) + return proxy_enabled && proxy_creds_enabled ? proxy_password : NULL; + return (strlen(mainMenu.proxyPassword) > 0) ? mainMenu.proxyPassword : NULL; } diff --git a/source/network/proxysettings.h b/source/network/proxysettings.h index 892d7d64..7e874d78 100644 --- a/source/network/proxysettings.h +++ b/source/network/proxysettings.h @@ -6,11 +6,11 @@ extern "C" { #endif - void getProxyInfo(); - char *getProxyAddress(); - u16 getProxyPort(); - char *getProxyUsername(); - char *getProxyPassword(); + void getProxyInfo(); + char *getProxyAddress(); + u16 getProxyPort(); + char *getProxyUsername(); + char *getProxyPassword(); #ifdef __cplusplus } #endif