diff --git a/.gitmodules b/.gitmodules index 8cb714ad2..c655bb3cb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -74,3 +74,6 @@ [submodule "project/jni/application/bochs/bochs"] path = project/jni/application/bochs/bochs url = git@github.com:lubomyr/bochs.git +[submodule "project/jni/boringssl/boringssl/jni"] + path = project/jni/boringssl/boringssl/jni + url = https://android.googlesource.com/platform/external/boringssl diff --git a/project/jni/Makefile.prebuilt b/project/jni/Makefile.prebuilt index dddec5813..f98a827e1 100644 --- a/project/jni/Makefile.prebuilt +++ b/project/jni/Makefile.prebuilt @@ -11,6 +11,8 @@ ICU := $(foreach ARCH, $(ARCHES32), $(foreach NAME, $(ICU_LIBS), icuuc/lib/$(ARC OPENSSL := $(foreach ARCH, $(ARCHES32) $(ARCHES64), openssl/lib-$(ARCH)/libcrypto.a openssl/lib-$(ARCH)/libssl.a) +BORINGSSL := $(foreach ARCH, armeabi-v7a x86 arm64-v8a x86_64, boringssl/lib-$(ARCH)/libcrypto.a boringssl/lib-$(ARCH)/libssl.a) + LIBS := $(ICONV) $(ICU) $(OPENSSL) prebuilt-libraries: $(LIBS) @@ -32,3 +34,6 @@ $(ICONV) $(ICU): $(OPENSSL): cd openssl && ./compile.sh + +$(BORINGSSL): + cd boringssl && ./compile.sh diff --git a/project/jni/application/commandergenius/commandergenius b/project/jni/application/commandergenius/commandergenius index 094b0aac7..c5210b0c4 160000 --- a/project/jni/application/commandergenius/commandergenius +++ b/project/jni/application/commandergenius/commandergenius @@ -1 +1 @@ -Subproject commit 094b0aac7c6f68e1ce38f7e0ef5c9373b9e32e7e +Subproject commit c5210b0c4209d6c9b6a49350057877448882a776 diff --git a/project/jni/application/hid-pc-keyboard/src b/project/jni/application/hid-pc-keyboard/src index 4f96333c1..bf31c329b 160000 --- a/project/jni/application/hid-pc-keyboard/src +++ b/project/jni/application/hid-pc-keyboard/src @@ -1 +1 @@ -Subproject commit 4f96333c1ce2229b7ba46a50ef91ef3695163679 +Subproject commit bf31c329b1275c11f1e5243b5dba48ebca72239e diff --git a/project/jni/application/openarena/AndroidAppSettings.cfg b/project/jni/application/openarena/AndroidAppSettings.cfg index 9f08d32d9..29fb0b093 100644 --- a/project/jni/application/openarena/AndroidAppSettings.cfg +++ b/project/jni/application/openarena/AndroidAppSettings.cfg @@ -244,7 +244,7 @@ MultiABI='armeabi-v7a x86 mips' # Optional shared libraries to compile - removing some of them will save space # MP3 support by libMAD is encumbered by patents and libMAD is GPL-ed # Available libraries: mad (GPL-ed!) sdl_mixer sdl_image sdl_ttf sdl_net sdl_blitpool sdl_gfx sdl_sound intl xml2 lua jpeg png ogg flac tremor vorbis freetype xerces curl theora fluidsynth lzma lzo2 mikmod openal timidity zzip bzip2 yaml-cpp python boost_date_time boost_filesystem boost_iostreams boost_program_options boost_regex boost_signals boost_system boost_thread glu avcodec avdevice avfilter avformat avresample avutil swscale swresample bzip2 -CompiledLibraries="sdl_mixer sdl_image freetype curl vorbis ogg openal" +CompiledLibraries="sdl_mixer sdl_image freetype vorbis ogg openal" # Application uses custom build script AndroidBuild.sh instead of Android.mk (y) or (n) CustomBuildScript=y diff --git a/project/jni/application/openttd/src b/project/jni/application/openttd/src index b4b6e0705..2b5d1be8e 160000 --- a/project/jni/application/openttd/src +++ b/project/jni/application/openttd/src @@ -1 +1 @@ -Subproject commit b4b6e07057994b9c5c75552ae836483f1b51a114 +Subproject commit 2b5d1be8e7c30c7dc1c8350bc04a7a2d0e9aabe6 diff --git a/project/jni/application/supertux/AndroidAppSettings.cfg b/project/jni/application/supertux/AndroidAppSettings.cfg index 7b3e9b666..b7de1385b 100644 --- a/project/jni/application/supertux/AndroidAppSettings.cfg +++ b/project/jni/application/supertux/AndroidAppSettings.cfg @@ -235,7 +235,7 @@ FirstStartMenuOptions='' AppMinimumRAM=0 # GCC version, 4.6 (default) or 4.8, CLANG is not supported yet -NDK_TOOLCHAIN_VERSION=4.8 +NDK_TOOLCHAIN_VERSION=4.9 # Specify architectures to compile, 'all' or 'y' to compile for all architectures. # Available architectures: armeabi armeabi-v7a armeabi-v7a-hard x86 mips diff --git a/project/jni/application/xserver/pulseaudio b/project/jni/application/xserver/pulseaudio index 7a124fcec..f5bebe88c 160000 --- a/project/jni/application/xserver/pulseaudio +++ b/project/jni/application/xserver/pulseaudio @@ -1 +1 @@ -Subproject commit 7a124fcec654d645b1663d15401eb6a88e54cfff +Subproject commit f5bebe88cb4101b842b44183c7eb46aa9405eb9f diff --git a/project/jni/application/xserver/xserver b/project/jni/application/xserver/xserver index 4fceb37bc..a710794bc 160000 --- a/project/jni/application/xserver/xserver +++ b/project/jni/application/xserver/xserver @@ -1 +1 @@ -Subproject commit 4fceb37bc5d66a4d30dd5d6ce5a4b31e6ffeda96 +Subproject commit a710794bcbef76293fa34f18f3cbed321788a12a diff --git a/project/jni/boringssl/Android.mk b/project/jni/boringssl/Android.mk new file mode 100644 index 000000000..a63dffc7b --- /dev/null +++ b/project/jni/boringssl/Android.mk @@ -0,0 +1,21 @@ +LOCAL_PATH:=$(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := $(notdir $(LOCAL_PATH)) + +ifneq (boringssl,$(LOCAL_MODULE)) +ifneq ($(filter armeabi-v7a arm64-v8a x86 x86_64, $(TARGET_ARCH_ABI)),) + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include +LOCAL_SRC_FILES := lib-$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).a +LOCAL_BUILT_MODULE := # This fixes a bug in NDK r10d + +# NDK is buggy meh +obj/local/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).a: $(LOCAL_PATH)/$(LOCAL_SRC_FILES) + cp -f $< $@ + +include $(PREBUILT_STATIC_LIBRARY) + +endif +endif diff --git a/project/jni/boringssl/boringssl/jni b/project/jni/boringssl/boringssl/jni new file mode 160000 index 000000000..eac3b69c6 --- /dev/null +++ b/project/jni/boringssl/boringssl/jni @@ -0,0 +1 @@ +Subproject commit eac3b69c627af4ffd43b036ea2bcaa4d13cffb60 diff --git a/project/jni/boringssl/compile.sh b/project/jni/boringssl/compile.sh new file mode 100755 index 000000000..3dee8ddb0 --- /dev/null +++ b/project/jni/boringssl/compile.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +ARCH_LIST="armeabi-v7a arm64-v8a x86 x86_64" + +touch boringssl/jni/Empty.mk +echo APP_MODULES := libcrypto_static libssl_static > boringssl/jni/Application.mk +echo APP_ABI := $ARCH_LIST >> boringssl/jni/Application.mk +grep TARGET_ARCH boringssl/jni/crypto-sources.mk || echo 'LOCAL_SRC_FILES += $(LOCAL_SRC_FILES_$(TARGET_ARCH))' >> boringssl/jni/crypto-sources.mk +ndk-build -j8 V=1 -C boringssl BUILD_HOST_SHARED_LIBRARY=jni/Empty.mk BUILD_HOST_STATIC_LIBRARY=jni/Empty.mk BUILD_HOST_EXECUTABLE=jni/Empty.mk || exit 1 +for ARCH in $ARCH_LIST; do + mkdir -p lib-${ARCH} + cp -f boringssl/obj/local/$ARCH/libcrypto_static.a lib-${ARCH}/libcrypto.a || exit 1 + cp -f boringssl/obj/local/$ARCH/libssl_static.a lib-${ARCH}/libssl.a || exit 1 +done +rm -rf include +cp -a boringssl/jni/src/include ./ diff --git a/project/jni/boringssl/include/openssl/aead.h b/project/jni/boringssl/include/openssl/aead.h new file mode 100644 index 000000000..092d2f623 --- /dev/null +++ b/project/jni/boringssl/include/openssl/aead.h @@ -0,0 +1,346 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_AEAD_H +#define OPENSSL_HEADER_AEAD_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Authenticated Encryption with Additional Data. + * + * AEAD couples confidentiality and integrity in a single primitive. AEAD + * algorithms take a key and then can seal and open individual messages. Each + * message has a unique, per-message nonce and, optionally, additional data + * which is authenticated but not included in the ciphertext. + * + * The |EVP_AEAD_CTX_init| function initialises an |EVP_AEAD_CTX| structure and + * performs any precomputation needed to use |aead| with |key|. The length of + * the key, |key_len|, is given in bytes. + * + * The |tag_len| argument contains the length of the tags, in bytes, and allows + * for the processing of truncated authenticators. A zero value indicates that + * the default tag length should be used and this is defined as + * |EVP_AEAD_DEFAULT_TAG_LENGTH| in order to make the code clear. Using + * truncated tags increases an attacker's chance of creating a valid forgery. + * Be aware that the attacker's chance may increase more than exponentially as + * would naively be expected. + * + * When no longer needed, the initialised |EVP_AEAD_CTX| structure must be + * passed to |EVP_AEAD_CTX_cleanup|, which will deallocate any memory used. + * + * With an |EVP_AEAD_CTX| in hand, one can seal and open messages. These + * operations are intended to meet the standard notions of privacy and + * authenticity for authenticated encryption. For formal definitions see + * Bellare and Namprempre, "Authenticated encryption: relations among notions + * and analysis of the generic composition paradigm," Lecture Notes in Computer + * Science B<1976> (2000), 531–545, + * http://www-cse.ucsd.edu/~mihir/papers/oem.html. + * + * When sealing messages, a nonce must be given. The length of the nonce is + * fixed by the AEAD in use and is returned by |EVP_AEAD_nonce_length|. *The + * nonce must be unique for all messages with the same key*. This is critically + * important - nonce reuse may completely undermine the security of the AEAD. + * Nonces may be predictable and public, so long as they are unique. Uniqueness + * may be achieved with a simple counter or, if large enough, may be generated + * randomly. The nonce must be passed into the "open" operation by the receiver + * so must either be implicit (e.g. a counter), or must be transmitted along + * with the sealed message. + * + * The "seal" and "open" operations are atomic - an entire message must be + * encrypted or decrypted in a single call. Large messages may have to be split + * up in order to accomodate this. When doing so, be mindful of the need not to + * repeat nonces and the possibility that an attacker could duplicate, reorder + * or drop message chunks. For example, using a single key for a given (large) + * message and sealing chunks with nonces counting from zero would be secure as + * long as the number of chunks was securely transmitted. (Otherwise an + * attacker could truncate the message by dropping chunks from the end.) + * + * The number of chunks could be transmitted by prefixing it to the plaintext, + * for example. This also assumes that no other message would ever use the same + * key otherwise the rule that nonces must be unique for a given key would be + * violated. + * + * The "seal" and "open" operations also permit additional data to be + * authenticated via the |ad| parameter. This data is not included in the + * ciphertext and must be identical for both the "seal" and "open" call. This + * permits implicit context to be authenticated but may be empty if not needed. + * + * The "seal" and "open" operations may work in-place if the |out| and |in| + * arguments are equal. They may also be used to shift the data left inside the + * same buffer if |out| is less than |in|. However, |out| may not point inside + * the input data otherwise the input may be overwritten before it has been + * read. This situation will cause an error. + * + * The "seal" and "open" operations return one on success and zero on error. */ + + +/* AEAD algorithms. */ + +/* EVP_aead_aes_128_gcm is AES-128 in Galois Counter Mode. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_gcm(void); + +/* EVP_aead_aes_256_gcm is AES-256 in Galois Counter Mode. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_gcm(void); + +/* EVP_aead_chacha20_poly1305 is the AEAD built from ChaCha20 and + * Poly1305 as described in RFC 7539. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_chacha20_poly1305(void); + +/* EVP_aead_chacha20_poly1305_old is an AEAD built from ChaCha20 and + * Poly1305 that is used in the experimental ChaCha20-Poly1305 TLS cipher + * suites. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_chacha20_poly1305_old(void); + +/* EVP_aead_aes_128_key_wrap is AES-128 Key Wrap mode. This should never be + * used except to interoperate with existing systems that use this mode. + * + * If the nonce is empty then the default nonce will be used, otherwise it must + * be eight bytes long. The input must be a multiple of eight bytes long. No + * additional data can be given to this mode. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_key_wrap(void); + +/* EVP_aead_aes_256_key_wrap is AES-256 in Key Wrap mode. This should never be + * used except to interoperate with existing systems that use this mode. + * + * See |EVP_aead_aes_128_key_wrap| for details. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_key_wrap(void); + +/* EVP_aead_aes_128_ctr_hmac_sha256 is AES-128 in CTR mode with HMAC-SHA256 for + * authentication. The nonce is 12 bytes; the bottom 32-bits are used as the + * block counter, thus the maximum plaintext size is 64GB. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_ctr_hmac_sha256(void); + +/* EVP_aead_aes_256_ctr_hmac_sha256 is AES-256 in CTR mode with HMAC-SHA256 for + * authentication. See |EVP_aead_aes_128_ctr_hmac_sha256| for details. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_ctr_hmac_sha256(void); + +/* EVP_has_aes_hardware returns one if we enable hardware support for fast and + * constant-time AES-GCM. */ +OPENSSL_EXPORT int EVP_has_aes_hardware(void); + + +/* TLS-specific AEAD algorithms. + * + * These AEAD primitives do not meet the definition of generic AEADs. They are + * all specific to TLS and should not be used outside of that context. They must + * be initialized with |EVP_AEAD_CTX_init_with_direction|, are stateful, and may + * not be used concurrently. Any nonces are used as IVs, so they must be + * unpredictable. They only accept an |ad| parameter of length 11 (the standard + * TLS one with length omitted). */ + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_md5_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_sha1_tls(void); + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls_implicit_iv(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha256_tls(void); + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls_implicit_iv(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha256_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha384_tls(void); + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv(void); + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_null_sha1_tls(void); + + +/* SSLv3-specific AEAD algorithms. + * + * These AEAD primitives do not meet the definition of generic AEADs. They are + * all specific to SSLv3 and should not be used outside of that context. They + * must be initialized with |EVP_AEAD_CTX_init_with_direction|, are stateful, + * and may not be used concurrently. They only accept an |ad| parameter of + * length 9 (the standard TLS one with length and version omitted). */ + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_md5_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_sha1_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_null_sha1_ssl3(void); + + +/* Utility functions. */ + +/* EVP_AEAD_key_length returns the length, in bytes, of the keys used by + * |aead|. */ +OPENSSL_EXPORT size_t EVP_AEAD_key_length(const EVP_AEAD *aead); + +/* EVP_AEAD_nonce_length returns the length, in bytes, of the per-message nonce + * for |aead|. */ +OPENSSL_EXPORT size_t EVP_AEAD_nonce_length(const EVP_AEAD *aead); + +/* EVP_AEAD_max_overhead returns the maximum number of additional bytes added + * by the act of sealing data with |aead|. */ +OPENSSL_EXPORT size_t EVP_AEAD_max_overhead(const EVP_AEAD *aead); + +/* EVP_AEAD_max_tag_len returns the maximum tag length when using |aead|. This + * is the largest value that can be passed as |tag_len| to + * |EVP_AEAD_CTX_init|. */ +OPENSSL_EXPORT size_t EVP_AEAD_max_tag_len(const EVP_AEAD *aead); + + +/* AEAD operations. */ + +/* An EVP_AEAD_CTX represents an AEAD algorithm configured with a specific key + * and message-independent IV. */ +typedef struct evp_aead_ctx_st { + const EVP_AEAD *aead; + /* aead_state is an opaque pointer to whatever state the AEAD needs to + * maintain. */ + void *aead_state; +} EVP_AEAD_CTX; + +/* EVP_AEAD_MAX_KEY_LENGTH contains the maximum key length used by + * any AEAD defined in this header. */ +#define EVP_AEAD_MAX_KEY_LENGTH 80 + +/* EVP_AEAD_MAX_NONCE_LENGTH contains the maximum nonce length used by + * any AEAD defined in this header. */ +#define EVP_AEAD_MAX_NONCE_LENGTH 16 + +/* EVP_AEAD_MAX_OVERHEAD contains the maximum overhead used by any AEAD + * defined in this header. */ +#define EVP_AEAD_MAX_OVERHEAD 64 + +/* EVP_AEAD_DEFAULT_TAG_LENGTH is a magic value that can be passed to + * EVP_AEAD_CTX_init to indicate that the default tag length for an AEAD should + * be used. */ +#define EVP_AEAD_DEFAULT_TAG_LENGTH 0 + +/* evp_aead_direction_t denotes the direction of an AEAD operation. */ +enum evp_aead_direction_t { + evp_aead_open, + evp_aead_seal, +}; + +/* EVP_AEAD_CTX_zero sets an uninitialized |ctx| to the zero state. It must be + * initialized with |EVP_AEAD_CTX_init| before use. It is safe, but not + * necessary, to call |EVP_AEAD_CTX_cleanup| in this state. This may be used for + * more uniform cleanup of |EVP_AEAD_CTX|. */ +OPENSSL_EXPORT void EVP_AEAD_CTX_zero(EVP_AEAD_CTX *ctx); + +/* EVP_AEAD_CTX_init initializes |ctx| for the given AEAD algorithm. The |impl| + * argument is ignored and should be NULL. Authentication tags may be truncated + * by passing a size as |tag_len|. A |tag_len| of zero indicates the default + * tag length and this is defined as EVP_AEAD_DEFAULT_TAG_LENGTH for + * readability. + * + * Returns 1 on success. Otherwise returns 0 and pushes to the error stack. In + * the error case, you do not need to call |EVP_AEAD_CTX_cleanup|, but it's + * harmless to do so. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, + const uint8_t *key, size_t key_len, + size_t tag_len, ENGINE *impl); + +/* EVP_AEAD_CTX_init_with_direction calls |EVP_AEAD_CTX_init| for normal + * AEADs. For TLS-specific and SSL3-specific AEADs, it initializes |ctx| for a + * given direction. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_init_with_direction( + EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, const uint8_t *key, size_t key_len, + size_t tag_len, enum evp_aead_direction_t dir); + +/* EVP_AEAD_CTX_cleanup frees any data allocated by |ctx|. It is a no-op to + * call |EVP_AEAD_CTX_cleanup| on a |EVP_AEAD_CTX| that has been |memset| to + * all zeros. */ +OPENSSL_EXPORT void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx); + +/* EVP_AEAD_CTX_seal encrypts and authenticates |in_len| bytes from |in| and + * authenticates |ad_len| bytes from |ad| and writes the result to |out|. It + * returns one on success and zero otherwise. + * + * This function may be called (with the same |EVP_AEAD_CTX|) concurrently with + * itself or |EVP_AEAD_CTX_open|. + * + * At most |max_out_len| bytes are written to |out| and, in order to ensure + * success, |max_out_len| should be |in_len| plus the result of + * |EVP_AEAD_max_overhead|. On successful return, |*out_len| is set to the + * actual number of bytes written. + * + * The length of |nonce|, |nonce_len|, must be equal to the result of + * |EVP_AEAD_nonce_length| for this AEAD. + * + * |EVP_AEAD_CTX_seal| never results in a partial output. If |max_out_len| is + * insufficient, zero will be returned. (In this case, |*out_len| is set to + * zero.) + * + * If |in| and |out| alias then |out| must be <= |in|. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len); + +/* EVP_AEAD_CTX_open authenticates |in_len| bytes from |in| and |ad_len| bytes + * from |ad| and decrypts at most |in_len| bytes into |out|. It returns one on + * success and zero otherwise. + * + * This function may be called (with the same |EVP_AEAD_CTX|) concurrently with + * itself or |EVP_AEAD_CTX_seal|. + * + * At most |in_len| bytes are written to |out|. In order to ensure success, + * |max_out_len| should be at least |in_len|. On successful return, |*out_len| + * is set to the the actual number of bytes written. + * + * The length of |nonce|, |nonce_len|, must be equal to the result of + * |EVP_AEAD_nonce_length| for this AEAD. + * + * |EVP_AEAD_CTX_open| never results in a partial output. If |max_out_len| is + * insufficient, zero will be returned. (In this case, |*out_len| is set to + * zero.) + * + * If |in| and |out| alias then |out| must be <= |in|. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len); + + +/* Obscure functions. */ + +/* EVP_AEAD_CTX_get_rc4_state sets |*out_key| to point to an RC4 key structure. + * It returns one on success or zero if |ctx| doesn't have an RC4 key. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_get_rc4_state(const EVP_AEAD_CTX *ctx, + const RC4_KEY **out_key); + +/* EVP_AEAD_CTX_get_iv sets |*out_len| to the length of the IV for |ctx| and + * sets |*out_iv| to point to that many bytes of the current IV. This is only + * meaningful for AEADs with implicit IVs (i.e. CBC mode in SSLv3 and TLS 1.0). + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_get_iv(const EVP_AEAD_CTX *ctx, + const uint8_t **out_iv, size_t *out_len); + + +/* Deprecated functions. */ + +/* EVP_aead_chacha20_poly1305_rfc7539 calls |EVP_aead_chacha20_poly1305|. + * + * TODO(davidben): Remove this. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_chacha20_poly1305_rfc7539(void); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_AEAD_H */ diff --git a/project/jni/boringssl/include/openssl/aes.h b/project/jni/boringssl/include/openssl/aes.h new file mode 100644 index 000000000..ed060ff66 --- /dev/null +++ b/project/jni/boringssl/include/openssl/aes.h @@ -0,0 +1,158 @@ +/* ==================================================================== + * Copyright (c) 2002-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ + +#ifndef OPENSSL_HEADER_AES_H +#define OPENSSL_HEADER_AES_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Raw AES functions. */ + + +#define AES_ENCRYPT 1 +#define AES_DECRYPT 0 + +/* AES_MAXNR is the maximum number of AES rounds. */ +#define AES_MAXNR 14 + +#define AES_BLOCK_SIZE 16 + +/* aes_key_st should be an opaque type, but EVP requires that the size be + * known. */ +struct aes_key_st { + uint32_t rd_key[4 * (AES_MAXNR + 1)]; + unsigned rounds; +}; +typedef struct aes_key_st AES_KEY; + +/* AES_set_encrypt_key configures |aeskey| to encrypt with the |bits|-bit key, + * |key|. + * + * WARNING: unlike other OpenSSL functions, this returns zero on success and a + * negative number on error. */ +OPENSSL_EXPORT int AES_set_encrypt_key(const uint8_t *key, unsigned bits, + AES_KEY *aeskey); + +/* AES_set_decrypt_key configures |aeskey| to decrypt with the |bits|-bit key, + * |key|. + * + * WARNING: unlike other OpenSSL functions, this returns zero on success and a + * negative number on error. */ +OPENSSL_EXPORT int AES_set_decrypt_key(const uint8_t *key, unsigned bits, + AES_KEY *aeskey); + +/* AES_encrypt encrypts a single block from |in| to |out| with |key|. The |in| + * and |out| pointers may overlap. */ +OPENSSL_EXPORT void AES_encrypt(const uint8_t *in, uint8_t *out, + const AES_KEY *key); + +/* AES_decrypt decrypts a single block from |in| to |out| with |key|. The |in| + * and |out| pointers may overlap. */ +OPENSSL_EXPORT void AES_decrypt(const uint8_t *in, uint8_t *out, + const AES_KEY *key); + + +/* Block cipher modes. */ + +/* AES_ctr128_encrypt encrypts (or decrypts, it's the same in CTR mode) |len| + * bytes from |in| to |out|. The |num| parameter must be set to zero on the + * first call and |ivec| will be incremented. */ +OPENSSL_EXPORT void AES_ctr128_encrypt(const uint8_t *in, uint8_t *out, + size_t len, const AES_KEY *key, + uint8_t ivec[AES_BLOCK_SIZE], + uint8_t ecount_buf[AES_BLOCK_SIZE], + unsigned int *num); + +/* AES_ecb_encrypt encrypts (or decrypts, if |enc| == |AES_DECRYPT|) a single, + * 16 byte block from |in| to |out|. */ +OPENSSL_EXPORT void AES_ecb_encrypt(const uint8_t *in, uint8_t *out, + const AES_KEY *key, const int enc); + +/* AES_cbc_encrypt encrypts (or decrypts, if |enc| == |AES_DECRYPT|) |len| + * bytes from |in| to |out|. The length must be a multiple of the block size. */ +OPENSSL_EXPORT void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, uint8_t *ivec, + const int enc); + +/* AES_ofb128_encrypt encrypts (or decrypts, it's the same in OFB mode) |len| + * bytes from |in| to |out|. The |num| parameter must be set to zero on the + * first call. */ +OPENSSL_EXPORT void AES_ofb128_encrypt(const uint8_t *in, uint8_t *out, + size_t len, const AES_KEY *key, + uint8_t *ivec, int *num); + +/* AES_cfb128_encrypt encrypts (or decrypts, if |enc| == |AES_DECRYPT|) |len| + * bytes from |in| to |out|. The |num| parameter must be set to zero on the + * first call. */ +OPENSSL_EXPORT void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, + size_t len, const AES_KEY *key, + uint8_t *ivec, int *num, int enc); + + +/* Android compatibility section. + * + * These functions are declared, temporarily, for Android because + * wpa_supplicant will take a little time to sync with upstream. Outside of + * Android they'll have no definition. */ + +OPENSSL_EXPORT int AES_wrap_key(AES_KEY *key, const uint8_t *iv, uint8_t *out, + const uint8_t *in, unsigned in_len); +OPENSSL_EXPORT int AES_unwrap_key(AES_KEY *key, const uint8_t *iv, uint8_t *out, + const uint8_t *in, unsigned in_len); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_AES_H */ diff --git a/project/jni/boringssl/include/openssl/arm_arch.h b/project/jni/boringssl/include/openssl/arm_arch.h new file mode 100644 index 000000000..1471db90a --- /dev/null +++ b/project/jni/boringssl/include/openssl/arm_arch.h @@ -0,0 +1,127 @@ +/* ==================================================================== + * Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_ARM_ARCH_H +#define OPENSSL_HEADER_ARM_ARCH_H + +#if !defined(__ARM_ARCH__) +# if defined(__CC_ARM) +# define __ARM_ARCH__ __TARGET_ARCH_ARM +# if defined(__BIG_ENDIAN) +# define __ARMEB__ +# else +# define __ARMEL__ +# endif +# elif defined(__GNUC__) +# if defined(__aarch64__) +# define __ARM_ARCH__ 8 +# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define __ARMEB__ +# else +# define __ARMEL__ +# endif + /* Why doesn't gcc define __ARM_ARCH__? Instead it defines + * bunch of below macros. See all_architectires[] table in + * gcc/config/arm/arm.c. On a side note it defines + * __ARMEL__/__ARMEB__ for little-/big-endian. */ +# elif defined(__ARM_ARCH) +# define __ARM_ARCH__ __ARM_ARCH +# elif defined(__ARM_ARCH_8A__) +# define __ARM_ARCH__ 8 +# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \ + defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__) || \ + defined(__ARM_ARCH_7EM__) +# define __ARM_ARCH__ 7 +# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \ + defined(__ARM_ARCH_6K__)|| defined(__ARM_ARCH_6M__) || \ + defined(__ARM_ARCH_6Z__)|| defined(__ARM_ARCH_6ZK__) || \ + defined(__ARM_ARCH_6T2__) +# define __ARM_ARCH__ 6 +# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \ + defined(__ARM_ARCH_5E__)|| defined(__ARM_ARCH_5TE__) || \ + defined(__ARM_ARCH_5TEJ__) +# define __ARM_ARCH__ 5 +# elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) +# define __ARM_ARCH__ 4 +# else +# error "unsupported ARM architecture" +# endif +# endif +#endif + +/* Even when building for 32-bit ARM, support for aarch64 crypto instructions + * will be included. */ +#define __ARM_MAX_ARCH__ 8 + +/* ARMV7_NEON is true when a NEON unit is present in the current CPU. */ +#define ARMV7_NEON (1 << 0) + +/* ARMV7_NEON_FUNCTIONAL is true when the NEON unit doesn't contain subtle bugs. + * The Poly1305 NEON code is known to trigger bugs in the NEON units of some + * phones. If this bit isn't set then the Poly1305 NEON code won't be used. + * See https://code.google.com/p/chromium/issues/detail?id=341598. */ +#define ARMV7_NEON_FUNCTIONAL (1 << 10) + +/* ARMV8_AES indicates support for hardware AES instructions. */ +#define ARMV8_AES (1 << 2) + +/* ARMV8_SHA1 indicates support for hardware SHA-1 instructions. */ +#define ARMV8_SHA1 (1 << 3) + +/* ARMV8_SHA256 indicates support for hardware SHA-256 instructions. */ +#define ARMV8_SHA256 (1 << 4) + +/* ARMV8_PMULL indicates support for carryless multiplication. */ +#define ARMV8_PMULL (1 << 5) + + +#endif /* OPENSSL_HEADER_ARM_ARCH_H */ diff --git a/project/jni/boringssl/include/openssl/asn1.h b/project/jni/boringssl/include/openssl/asn1.h new file mode 100644 index 000000000..63bde181b --- /dev/null +++ b/project/jni/boringssl/include/openssl/asn1.h @@ -0,0 +1,1167 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_ASN1_H +#define HEADER_ASN1_H + +#include + +#include + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define V_ASN1_UNIVERSAL 0x00 +#define V_ASN1_APPLICATION 0x40 +#define V_ASN1_CONTEXT_SPECIFIC 0x80 +#define V_ASN1_PRIVATE 0xc0 + +#define V_ASN1_CONSTRUCTED 0x20 +#define V_ASN1_PRIMITIVE_TAG 0x1f +#define V_ASN1_PRIMATIVE_TAG 0x1f + +#define V_ASN1_APP_CHOOSE -2 /* let the recipient choose */ +#define V_ASN1_OTHER -3 /* used in ASN1_TYPE */ +#define V_ASN1_ANY -4 /* used in ASN1 template code */ + +#define V_ASN1_NEG 0x100 /* negative flag */ + +#define V_ASN1_UNDEF -1 +#define V_ASN1_EOC 0 +#define V_ASN1_BOOLEAN 1 /**/ +#define V_ASN1_INTEGER 2 +#define V_ASN1_NEG_INTEGER (2 | V_ASN1_NEG) +#define V_ASN1_BIT_STRING 3 +#define V_ASN1_OCTET_STRING 4 +#define V_ASN1_NULL 5 +#define V_ASN1_OBJECT 6 +#define V_ASN1_OBJECT_DESCRIPTOR 7 +#define V_ASN1_EXTERNAL 8 +#define V_ASN1_REAL 9 +#define V_ASN1_ENUMERATED 10 +#define V_ASN1_NEG_ENUMERATED (10 | V_ASN1_NEG) +#define V_ASN1_UTF8STRING 12 +#define V_ASN1_SEQUENCE 16 +#define V_ASN1_SET 17 +#define V_ASN1_NUMERICSTRING 18 /**/ +#define V_ASN1_PRINTABLESTRING 19 +#define V_ASN1_T61STRING 20 +#define V_ASN1_TELETEXSTRING 20 /* alias */ +#define V_ASN1_VIDEOTEXSTRING 21 /**/ +#define V_ASN1_IA5STRING 22 +#define V_ASN1_UTCTIME 23 +#define V_ASN1_GENERALIZEDTIME 24 /**/ +#define V_ASN1_GRAPHICSTRING 25 /**/ +#define V_ASN1_ISO64STRING 26 /**/ +#define V_ASN1_VISIBLESTRING 26 /* alias */ +#define V_ASN1_GENERALSTRING 27 /**/ +#define V_ASN1_UNIVERSALSTRING 28 /**/ +#define V_ASN1_BMPSTRING 30 + +/* For use with d2i_ASN1_type_bytes() */ +#define B_ASN1_NUMERICSTRING 0x0001 +#define B_ASN1_PRINTABLESTRING 0x0002 +#define B_ASN1_T61STRING 0x0004 +#define B_ASN1_TELETEXSTRING 0x0004 +#define B_ASN1_VIDEOTEXSTRING 0x0008 +#define B_ASN1_IA5STRING 0x0010 +#define B_ASN1_GRAPHICSTRING 0x0020 +#define B_ASN1_ISO64STRING 0x0040 +#define B_ASN1_VISIBLESTRING 0x0040 +#define B_ASN1_GENERALSTRING 0x0080 +#define B_ASN1_UNIVERSALSTRING 0x0100 +#define B_ASN1_OCTET_STRING 0x0200 +#define B_ASN1_BIT_STRING 0x0400 +#define B_ASN1_BMPSTRING 0x0800 +#define B_ASN1_UNKNOWN 0x1000 +#define B_ASN1_UTF8STRING 0x2000 +#define B_ASN1_UTCTIME 0x4000 +#define B_ASN1_GENERALIZEDTIME 0x8000 +#define B_ASN1_SEQUENCE 0x10000 + +/* For use with ASN1_mbstring_copy() */ +#define MBSTRING_FLAG 0x1000 +#define MBSTRING_UTF8 (MBSTRING_FLAG) +#define MBSTRING_ASC (MBSTRING_FLAG|1) +#define MBSTRING_BMP (MBSTRING_FLAG|2) +#define MBSTRING_UNIV (MBSTRING_FLAG|4) + +#define SMIME_OLDMIME 0x400 +#define SMIME_CRLFEOL 0x800 +#define SMIME_STREAM 0x1000 + +#define DECLARE_ASN1_SET_OF(type) /* filled in by mkstack.pl */ +#define IMPLEMENT_ASN1_SET_OF(type) /* nothing, no longer needed */ + +/* We MUST make sure that, except for constness, asn1_ctx_st and + asn1_const_ctx are exactly the same. Fortunately, as soon as + the old ASN1 parsing macros are gone, we can throw this away + as well... */ +typedef struct asn1_ctx_st + { + unsigned char *p;/* work char pointer */ + int eos; /* end of sequence read for indefinite encoding */ + int error; /* error code to use when returning an error */ + int inf; /* constructed if 0x20, indefinite is 0x21 */ + int tag; /* tag from last 'get object' */ + int xclass; /* class from last 'get object' */ + long slen; /* length of last 'get object' */ + unsigned char *max; /* largest value of p allowed */ + unsigned char *q;/* temporary variable */ + unsigned char **pp;/* variable */ + int line; /* used in error processing */ + } ASN1_CTX; + +typedef struct asn1_const_ctx_st + { + const unsigned char *p;/* work char pointer */ + int eos; /* end of sequence read for indefinite encoding */ + int error; /* error code to use when returning an error */ + int inf; /* constructed if 0x20, indefinite is 0x21 */ + int tag; /* tag from last 'get object' */ + int xclass; /* class from last 'get object' */ + long slen; /* length of last 'get object' */ + const unsigned char *max; /* largest value of p allowed */ + const unsigned char *q;/* temporary variable */ + const unsigned char **pp;/* variable */ + int line; /* used in error processing */ + } ASN1_const_CTX; + +/* These are used internally in the ASN1_OBJECT to keep track of + * whether the names and data need to be free()ed */ +#define ASN1_OBJECT_FLAG_DYNAMIC 0x01 /* internal use */ +#define ASN1_OBJECT_FLAG_CRITICAL 0x02 /* critical x509v3 object id */ +#define ASN1_OBJECT_FLAG_DYNAMIC_STRINGS 0x04 /* internal use */ +#define ASN1_OBJECT_FLAG_DYNAMIC_DATA 0x08 /* internal use */ +struct asn1_object_st + { + const char *sn,*ln; + int nid; + int length; + const unsigned char *data; /* data remains const after init */ + int flags; /* Should we free this one */ + }; + +#define ASN1_STRING_FLAG_BITS_LEFT 0x08 /* Set if 0x07 has bits left value */ +/* This indicates that the ASN1_STRING is not a real value but just a place + * holder for the location where indefinite length constructed data should + * be inserted in the memory buffer + */ +#define ASN1_STRING_FLAG_NDEF 0x010 + +/* This flag is used by the CMS code to indicate that a string is not + * complete and is a place holder for content when it had all been + * accessed. The flag will be reset when content has been written to it. + */ + +#define ASN1_STRING_FLAG_CONT 0x020 +/* This flag is used by ASN1 code to indicate an ASN1_STRING is an MSTRING + * type. + */ +#define ASN1_STRING_FLAG_MSTRING 0x040 +/* This is the base type that holds just about everything :-) */ +struct asn1_string_st + { + int length; + int type; + unsigned char *data; + /* The value of the following field depends on the type being + * held. It is mostly being used for BIT_STRING so if the + * input data has a non-zero 'unused bits' value, it will be + * handled correctly */ + long flags; + }; + +/* ASN1_ENCODING structure: this is used to save the received + * encoding of an ASN1 type. This is useful to get round + * problems with invalid encodings which can break signatures. + */ + +typedef struct ASN1_ENCODING_st + { + unsigned char *enc; /* DER encoding */ + long len; /* Length of encoding */ + int modified; /* set to 1 if 'enc' is invalid */ + } ASN1_ENCODING; + +/* Used with ASN1 LONG type: if a long is set to this it is omitted */ +#define ASN1_LONG_UNDEF 0x7fffffffL + +#define STABLE_FLAGS_MALLOC 0x01 +#define STABLE_NO_MASK 0x02 +#define DIRSTRING_TYPE \ + (B_ASN1_PRINTABLESTRING|B_ASN1_T61STRING|B_ASN1_BMPSTRING|B_ASN1_UTF8STRING) +#define PKCS9STRING_TYPE (DIRSTRING_TYPE|B_ASN1_IA5STRING) + +typedef struct asn1_string_table_st { + int nid; + long minsize; + long maxsize; + unsigned long mask; + unsigned long flags; +} ASN1_STRING_TABLE; + +/* size limits: this stuff is taken straight from RFC2459 */ + +#define ub_name 32768 +#define ub_common_name 64 +#define ub_locality_name 128 +#define ub_state_name 128 +#define ub_organization_name 64 +#define ub_organization_unit_name 64 +#define ub_title 64 +#define ub_email_address 128 + +/* Declarations for template structures: for full definitions + * see asn1t.h + */ +typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE; +typedef struct ASN1_TLC_st ASN1_TLC; +/* This is just an opaque pointer */ +typedef struct ASN1_VALUE_st ASN1_VALUE; + +/* Declare ASN1 functions: the implement macro in in asn1t.h */ + +#define DECLARE_ASN1_FUNCTIONS(type) DECLARE_ASN1_FUNCTIONS_name(type, type) + +#define DECLARE_ASN1_ALLOC_FUNCTIONS(type) \ + DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, type) + +#define DECLARE_ASN1_FUNCTIONS_name(type, name) \ + DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \ + DECLARE_ASN1_ENCODE_FUNCTIONS(type, name, name) + +#define DECLARE_ASN1_FUNCTIONS_fname(type, itname, name) \ + DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \ + DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) + +#define DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) \ + OPENSSL_EXPORT type *d2i_##name(type **a, const unsigned char **in, long len); \ + OPENSSL_EXPORT int i2d_##name(type *a, unsigned char **out); \ + DECLARE_ASN1_ITEM(itname) + +#define DECLARE_ASN1_ENCODE_FUNCTIONS_const(type, name) \ + OPENSSL_EXPORT type *d2i_##name(type **a, const unsigned char **in, long len); \ + OPENSSL_EXPORT int i2d_##name(const type *a, unsigned char **out); \ + DECLARE_ASN1_ITEM(name) + +#define DECLARE_ASN1_NDEF_FUNCTION(name) \ + OPENSSL_EXPORT int i2d_##name##_NDEF(name *a, unsigned char **out); + +#define DECLARE_ASN1_FUNCTIONS_const(name) \ + DECLARE_ASN1_ALLOC_FUNCTIONS(name) \ + DECLARE_ASN1_ENCODE_FUNCTIONS_const(name, name) + +#define DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \ + OPENSSL_EXPORT type *name##_new(void); \ + OPENSSL_EXPORT void name##_free(type *a); + +#define DECLARE_ASN1_PRINT_FUNCTION(stname) \ + DECLARE_ASN1_PRINT_FUNCTION_fname(stname, stname) + +#define DECLARE_ASN1_PRINT_FUNCTION_fname(stname, fname) \ + OPENSSL_EXPORT int fname##_print_ctx(BIO *out, stname *x, int indent, \ + const ASN1_PCTX *pctx); + +#define D2I_OF(type) type *(*)(type **,const unsigned char **,long) +#define I2D_OF(type) int (*)(type *,unsigned char **) +#define I2D_OF_const(type) int (*)(const type *,unsigned char **) + +#define CHECKED_D2I_OF(type, d2i) \ + ((d2i_of_void*) (1 ? d2i : ((D2I_OF(type))0))) +#define CHECKED_I2D_OF(type, i2d) \ + ((i2d_of_void*) (1 ? i2d : ((I2D_OF(type))0))) +#define CHECKED_NEW_OF(type, xnew) \ + ((void *(*)(void)) (1 ? xnew : ((type *(*)(void))0))) +#define CHECKED_PPTR_OF(type, p) \ + ((void**) (1 ? p : (type**)0)) + +#define TYPEDEF_D2I_OF(type) typedef type *d2i_of_##type(type **,const unsigned char **,long) +#define TYPEDEF_I2D_OF(type) typedef int i2d_of_##type(const type *,unsigned char **) +#define TYPEDEF_D2I2D_OF(type) TYPEDEF_D2I_OF(type); TYPEDEF_I2D_OF(type) + +TYPEDEF_D2I2D_OF(void); + +/* The following macros and typedefs allow an ASN1_ITEM + * to be embedded in a structure and referenced. Since + * the ASN1_ITEM pointers need to be globally accessible + * (possibly from shared libraries) they may exist in + * different forms. On platforms that support it the + * ASN1_ITEM structure itself will be globally exported. + * Other platforms will export a function that returns + * an ASN1_ITEM pointer. + * + * To handle both cases transparently the macros below + * should be used instead of hard coding an ASN1_ITEM + * pointer in a structure. + * + * The structure will look like this: + * + * typedef struct SOMETHING_st { + * ... + * ASN1_ITEM_EXP *iptr; + * ... + * } SOMETHING; + * + * It would be initialised as e.g.: + * + * SOMETHING somevar = {...,ASN1_ITEM_ref(X509),...}; + * + * and the actual pointer extracted with: + * + * const ASN1_ITEM *it = ASN1_ITEM_ptr(somevar.iptr); + * + * Finally an ASN1_ITEM pointer can be extracted from an + * appropriate reference with: ASN1_ITEM_rptr(X509). This + * would be used when a function takes an ASN1_ITEM * argument. + * + */ + +/* ASN1_ITEM pointer exported type */ +typedef const ASN1_ITEM ASN1_ITEM_EXP; + +/* Macro to obtain ASN1_ITEM pointer from exported type */ +#define ASN1_ITEM_ptr(iptr) (iptr) + +/* Macro to include ASN1_ITEM pointer from base type */ +#define ASN1_ITEM_ref(iptr) (&(iptr##_it)) + +#define ASN1_ITEM_rptr(ref) (&(ref##_it)) + +#define DECLARE_ASN1_ITEM(name) \ + extern OPENSSL_EXPORT const ASN1_ITEM name##_it; + +/* Parameters used by ASN1_STRING_print_ex() */ + +/* These determine which characters to escape: + * RFC2253 special characters, control characters and + * MSB set characters + */ + +#define ASN1_STRFLGS_ESC_2253 1 +#define ASN1_STRFLGS_ESC_CTRL 2 +#define ASN1_STRFLGS_ESC_MSB 4 + + +/* This flag determines how we do escaping: normally + * RC2253 backslash only, set this to use backslash and + * quote. + */ + +#define ASN1_STRFLGS_ESC_QUOTE 8 + + +/* These three flags are internal use only. */ + +/* Character is a valid PrintableString character */ +#define CHARTYPE_PRINTABLESTRING 0x10 +/* Character needs escaping if it is the first character */ +#define CHARTYPE_FIRST_ESC_2253 0x20 +/* Character needs escaping if it is the last character */ +#define CHARTYPE_LAST_ESC_2253 0x40 + +/* NB the internal flags are safely reused below by flags + * handled at the top level. + */ + +/* If this is set we convert all character strings + * to UTF8 first + */ + +#define ASN1_STRFLGS_UTF8_CONVERT 0x10 + +/* If this is set we don't attempt to interpret content: + * just assume all strings are 1 byte per character. This + * will produce some pretty odd looking output! + */ + +#define ASN1_STRFLGS_IGNORE_TYPE 0x20 + +/* If this is set we include the string type in the output */ +#define ASN1_STRFLGS_SHOW_TYPE 0x40 + +/* This determines which strings to display and which to + * 'dump' (hex dump of content octets or DER encoding). We can + * only dump non character strings or everything. If we + * don't dump 'unknown' they are interpreted as character + * strings with 1 octet per character and are subject to + * the usual escaping options. + */ + +#define ASN1_STRFLGS_DUMP_ALL 0x80 +#define ASN1_STRFLGS_DUMP_UNKNOWN 0x100 + +/* These determine what 'dumping' does, we can dump the + * content octets or the DER encoding: both use the + * RFC2253 #XXXXX notation. + */ + +#define ASN1_STRFLGS_DUMP_DER 0x200 + +/* All the string flags consistent with RFC2253, + * escaping control characters isn't essential in + * RFC2253 but it is advisable anyway. + */ + +#define ASN1_STRFLGS_RFC2253 (ASN1_STRFLGS_ESC_2253 | \ + ASN1_STRFLGS_ESC_CTRL | \ + ASN1_STRFLGS_ESC_MSB | \ + ASN1_STRFLGS_UTF8_CONVERT | \ + ASN1_STRFLGS_DUMP_UNKNOWN | \ + ASN1_STRFLGS_DUMP_DER) + +DECLARE_ASN1_SET_OF(ASN1_INTEGER) + +typedef struct asn1_type_st + { + int type; + union { + char *ptr; + ASN1_BOOLEAN boolean; + ASN1_STRING * asn1_string; + ASN1_OBJECT * object; + ASN1_INTEGER * integer; + ASN1_ENUMERATED * enumerated; + ASN1_BIT_STRING * bit_string; + ASN1_OCTET_STRING * octet_string; + ASN1_PRINTABLESTRING * printablestring; + ASN1_T61STRING * t61string; + ASN1_IA5STRING * ia5string; + ASN1_GENERALSTRING * generalstring; + ASN1_BMPSTRING * bmpstring; + ASN1_UNIVERSALSTRING * universalstring; + ASN1_UTCTIME * utctime; + ASN1_GENERALIZEDTIME * generalizedtime; + ASN1_VISIBLESTRING * visiblestring; + ASN1_UTF8STRING * utf8string; + /* set and sequence are left complete and still + * contain the set or sequence bytes */ + ASN1_STRING * set; + ASN1_STRING * sequence; + ASN1_VALUE * asn1_value; + } value; + } ASN1_TYPE; + +DECLARE_ASN1_SET_OF(ASN1_TYPE) + +typedef STACK_OF(ASN1_TYPE) ASN1_SEQUENCE_ANY; + +DECLARE_ASN1_ENCODE_FUNCTIONS_const(ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY) +DECLARE_ASN1_ENCODE_FUNCTIONS_const(ASN1_SEQUENCE_ANY, ASN1_SET_ANY) + +struct X509_algor_st + { + ASN1_OBJECT *algorithm; + ASN1_TYPE *parameter; + } /* X509_ALGOR */; + +DECLARE_ASN1_FUNCTIONS(X509_ALGOR) + +typedef struct NETSCAPE_X509_st + { + ASN1_OCTET_STRING *header; + X509 *cert; + } NETSCAPE_X509; + +/* This is used to contain a list of bit names */ +typedef struct BIT_STRING_BITNAME_st { + int bitnum; + const char *lname; + const char *sname; +} BIT_STRING_BITNAME; + + +#define M_ASN1_STRING_length(x) ((x)->length) +#define M_ASN1_STRING_length_set(x, n) ((x)->length = (n)) +#define M_ASN1_STRING_type(x) ((x)->type) +#define M_ASN1_STRING_data(x) ((x)->data) + +/* Macros for string operations */ +#define M_ASN1_BIT_STRING_new() (ASN1_BIT_STRING *)\ + ASN1_STRING_type_new(V_ASN1_BIT_STRING) +#define M_ASN1_BIT_STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_BIT_STRING_dup(a) (ASN1_BIT_STRING *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) +#define M_ASN1_BIT_STRING_cmp(a,b) ASN1_STRING_cmp(\ + (const ASN1_STRING *)a,(const ASN1_STRING *)b) +#define M_ASN1_BIT_STRING_set(a,b,c) ASN1_STRING_set((ASN1_STRING *)a,b,c) + +#define M_ASN1_INTEGER_new() (ASN1_INTEGER *)\ + ASN1_STRING_type_new(V_ASN1_INTEGER) +#define M_ASN1_INTEGER_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_INTEGER_dup(a) (ASN1_INTEGER *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) +#define M_ASN1_INTEGER_cmp(a,b) ASN1_STRING_cmp(\ + (const ASN1_STRING *)a,(const ASN1_STRING *)b) + +#define M_ASN1_ENUMERATED_new() (ASN1_ENUMERATED *)\ + ASN1_STRING_type_new(V_ASN1_ENUMERATED) +#define M_ASN1_ENUMERATED_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_ENUMERATED_dup(a) (ASN1_ENUMERATED *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) +#define M_ASN1_ENUMERATED_cmp(a,b) ASN1_STRING_cmp(\ + (const ASN1_STRING *)a,(const ASN1_STRING *)b) + +#define M_ASN1_OCTET_STRING_new() (ASN1_OCTET_STRING *)\ + ASN1_STRING_type_new(V_ASN1_OCTET_STRING) +#define M_ASN1_OCTET_STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_OCTET_STRING_dup(a) (ASN1_OCTET_STRING *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) +#define M_ASN1_OCTET_STRING_cmp(a,b) ASN1_STRING_cmp(\ + (const ASN1_STRING *)a,(const ASN1_STRING *)b) +#define M_ASN1_OCTET_STRING_set(a,b,c) ASN1_STRING_set((ASN1_STRING *)a,b,c) +#define M_ASN1_OCTET_STRING_print(a,b) ASN1_STRING_print(a,(ASN1_STRING *)b) +#define M_i2d_ASN1_OCTET_STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_OCTET_STRING,\ + V_ASN1_UNIVERSAL) + +#define B_ASN1_TIME \ + B_ASN1_UTCTIME | \ + B_ASN1_GENERALIZEDTIME + +#define B_ASN1_PRINTABLE \ + B_ASN1_NUMERICSTRING| \ + B_ASN1_PRINTABLESTRING| \ + B_ASN1_T61STRING| \ + B_ASN1_IA5STRING| \ + B_ASN1_BIT_STRING| \ + B_ASN1_UNIVERSALSTRING|\ + B_ASN1_BMPSTRING|\ + B_ASN1_UTF8STRING|\ + B_ASN1_SEQUENCE|\ + B_ASN1_UNKNOWN + +#define B_ASN1_DIRECTORYSTRING \ + B_ASN1_PRINTABLESTRING| \ + B_ASN1_TELETEXSTRING|\ + B_ASN1_BMPSTRING|\ + B_ASN1_UNIVERSALSTRING|\ + B_ASN1_UTF8STRING + +#define B_ASN1_DISPLAYTEXT \ + B_ASN1_IA5STRING| \ + B_ASN1_VISIBLESTRING| \ + B_ASN1_BMPSTRING|\ + B_ASN1_UTF8STRING + +#define M_ASN1_PRINTABLE_new() ASN1_STRING_type_new(V_ASN1_T61STRING) +#define M_ASN1_PRINTABLE_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_PRINTABLE(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\ + pp,a->type,V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_PRINTABLE(a,pp,l) \ + d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \ + B_ASN1_PRINTABLE) + +#define M_DIRECTORYSTRING_new() ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING) +#define M_DIRECTORYSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_DIRECTORYSTRING(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\ + pp,a->type,V_ASN1_UNIVERSAL) +#define M_d2i_DIRECTORYSTRING(a,pp,l) \ + d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \ + B_ASN1_DIRECTORYSTRING) + +#define M_DISPLAYTEXT_new() ASN1_STRING_type_new(V_ASN1_VISIBLESTRING) +#define M_DISPLAYTEXT_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_DISPLAYTEXT(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\ + pp,a->type,V_ASN1_UNIVERSAL) +#define M_d2i_DISPLAYTEXT(a,pp,l) \ + d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \ + B_ASN1_DISPLAYTEXT) + +#define M_ASN1_PRINTABLESTRING_new() (ASN1_PRINTABLESTRING *)\ + ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING) +#define M_ASN1_PRINTABLESTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_PRINTABLESTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_PRINTABLESTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_PRINTABLESTRING(a,pp,l) \ + (ASN1_PRINTABLESTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_PRINTABLESTRING) + +#define M_ASN1_T61STRING_new() (ASN1_T61STRING *)\ + ASN1_STRING_type_new(V_ASN1_T61STRING) +#define M_ASN1_T61STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_T61STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_T61STRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_T61STRING(a,pp,l) \ + (ASN1_T61STRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_T61STRING) + +#define M_ASN1_IA5STRING_new() (ASN1_IA5STRING *)\ + ASN1_STRING_type_new(V_ASN1_IA5STRING) +#define M_ASN1_IA5STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_IA5STRING_dup(a) \ + (ASN1_IA5STRING *)ASN1_STRING_dup((const ASN1_STRING *)a) +#define M_i2d_ASN1_IA5STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_IA5STRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_IA5STRING(a,pp,l) \ + (ASN1_IA5STRING *)d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l,\ + B_ASN1_IA5STRING) + +#define M_ASN1_UTCTIME_new() (ASN1_UTCTIME *)\ + ASN1_STRING_type_new(V_ASN1_UTCTIME) +#define M_ASN1_UTCTIME_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_UTCTIME_dup(a) (ASN1_UTCTIME *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) + +#define M_ASN1_GENERALIZEDTIME_new() (ASN1_GENERALIZEDTIME *)\ + ASN1_STRING_type_new(V_ASN1_GENERALIZEDTIME) +#define M_ASN1_GENERALIZEDTIME_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_GENERALIZEDTIME_dup(a) (ASN1_GENERALIZEDTIME *)ASN1_STRING_dup(\ + (const ASN1_STRING *)a) + +#define M_ASN1_TIME_new() (ASN1_TIME *)\ + ASN1_STRING_type_new(V_ASN1_UTCTIME) +#define M_ASN1_TIME_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_TIME_dup(a) (ASN1_TIME *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) + +#define M_ASN1_GENERALSTRING_new() (ASN1_GENERALSTRING *)\ + ASN1_STRING_type_new(V_ASN1_GENERALSTRING) +#define M_ASN1_GENERALSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_GENERALSTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_GENERALSTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_GENERALSTRING(a,pp,l) \ + (ASN1_GENERALSTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_GENERALSTRING) + +#define M_ASN1_UNIVERSALSTRING_new() (ASN1_UNIVERSALSTRING *)\ + ASN1_STRING_type_new(V_ASN1_UNIVERSALSTRING) +#define M_ASN1_UNIVERSALSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_UNIVERSALSTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UNIVERSALSTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_UNIVERSALSTRING(a,pp,l) \ + (ASN1_UNIVERSALSTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_UNIVERSALSTRING) + +#define M_ASN1_BMPSTRING_new() (ASN1_BMPSTRING *)\ + ASN1_STRING_type_new(V_ASN1_BMPSTRING) +#define M_ASN1_BMPSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_BMPSTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_BMPSTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_BMPSTRING(a,pp,l) \ + (ASN1_BMPSTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_BMPSTRING) + +#define M_ASN1_VISIBLESTRING_new() (ASN1_VISIBLESTRING *)\ + ASN1_STRING_type_new(V_ASN1_VISIBLESTRING) +#define M_ASN1_VISIBLESTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_VISIBLESTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_VISIBLESTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_VISIBLESTRING(a,pp,l) \ + (ASN1_VISIBLESTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_VISIBLESTRING) + +#define M_ASN1_UTF8STRING_new() (ASN1_UTF8STRING *)\ + ASN1_STRING_type_new(V_ASN1_UTF8STRING) +#define M_ASN1_UTF8STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_UTF8STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UTF8STRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_UTF8STRING(a,pp,l) \ + (ASN1_UTF8STRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_UTF8STRING) + + /* for the is_set parameter to i2d_ASN1_SET */ +#define IS_SEQUENCE 0 +#define IS_SET 1 + +DECLARE_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE) + +OPENSSL_EXPORT int ASN1_TYPE_get(ASN1_TYPE *a); +OPENSSL_EXPORT void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value); +OPENSSL_EXPORT int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value); +OPENSSL_EXPORT int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b); + +OPENSSL_EXPORT ASN1_OBJECT * ASN1_OBJECT_new(void ); +OPENSSL_EXPORT void ASN1_OBJECT_free(ASN1_OBJECT *a); +OPENSSL_EXPORT int i2d_ASN1_OBJECT(ASN1_OBJECT *a,unsigned char **pp); +OPENSSL_EXPORT ASN1_OBJECT * c2i_ASN1_OBJECT(ASN1_OBJECT **a,const unsigned char **pp, + long length); +OPENSSL_EXPORT ASN1_OBJECT * d2i_ASN1_OBJECT(ASN1_OBJECT **a,const unsigned char **pp, + long length); + +DECLARE_ASN1_ITEM(ASN1_OBJECT) + +DECLARE_ASN1_SET_OF(ASN1_OBJECT) + +OPENSSL_EXPORT ASN1_STRING * ASN1_STRING_new(void); +OPENSSL_EXPORT void ASN1_STRING_free(ASN1_STRING *a); +OPENSSL_EXPORT int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str); +OPENSSL_EXPORT ASN1_STRING * ASN1_STRING_dup(const ASN1_STRING *a); +OPENSSL_EXPORT ASN1_STRING * ASN1_STRING_type_new(int type ); +OPENSSL_EXPORT int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b); + /* Since this is used to store all sorts of things, via macros, for now, make + its data void * */ +OPENSSL_EXPORT int ASN1_STRING_set(ASN1_STRING *str, const void *data, int len); +OPENSSL_EXPORT void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len); +OPENSSL_EXPORT int ASN1_STRING_length(const ASN1_STRING *x); +OPENSSL_EXPORT void ASN1_STRING_length_set(ASN1_STRING *x, int n); +OPENSSL_EXPORT int ASN1_STRING_type(ASN1_STRING *x); +OPENSSL_EXPORT unsigned char * ASN1_STRING_data(ASN1_STRING *x); + +DECLARE_ASN1_FUNCTIONS(ASN1_BIT_STRING) +OPENSSL_EXPORT int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a,unsigned char **pp); +OPENSSL_EXPORT ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,const unsigned char **pp, long length); +OPENSSL_EXPORT int ASN1_BIT_STRING_set(ASN1_BIT_STRING *a, unsigned char *d, int length ); +OPENSSL_EXPORT int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value); +OPENSSL_EXPORT int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n); +OPENSSL_EXPORT int ASN1_BIT_STRING_check(ASN1_BIT_STRING *a, unsigned char *flags, int flags_len); + +OPENSSL_EXPORT int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs, BIT_STRING_BITNAME *tbl, int indent); +OPENSSL_EXPORT int ASN1_BIT_STRING_num_asc(char *name, BIT_STRING_BITNAME *tbl); +OPENSSL_EXPORT int ASN1_BIT_STRING_set_asc(ASN1_BIT_STRING *bs, char *name, int value, BIT_STRING_BITNAME *tbl); + +OPENSSL_EXPORT int i2d_ASN1_BOOLEAN(int a,unsigned char **pp); +OPENSSL_EXPORT int d2i_ASN1_BOOLEAN(int *a,const unsigned char **pp,long length); + +DECLARE_ASN1_FUNCTIONS(ASN1_INTEGER) +OPENSSL_EXPORT int i2c_ASN1_INTEGER(ASN1_INTEGER *a,unsigned char **pp); +OPENSSL_EXPORT ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a,const unsigned char **pp, long length); +OPENSSL_EXPORT ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a,const unsigned char **pp, long length); +OPENSSL_EXPORT ASN1_INTEGER * ASN1_INTEGER_dup(const ASN1_INTEGER *x); +OPENSSL_EXPORT int ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y); + +DECLARE_ASN1_FUNCTIONS(ASN1_ENUMERATED) + +OPENSSL_EXPORT int ASN1_UTCTIME_check(const ASN1_UTCTIME *a); +OPENSSL_EXPORT ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s,time_t t); +OPENSSL_EXPORT ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, int offset_day, long offset_sec); +OPENSSL_EXPORT int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str); +OPENSSL_EXPORT int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t); +#if 0 +time_t ASN1_UTCTIME_get(const ASN1_UTCTIME *s); +#endif + +OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *a); +OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s,time_t t); +OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s, time_t t, int offset_day, long offset_sec); +OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str); +OPENSSL_EXPORT int ASN1_TIME_diff(int *pday, int *psec, const ASN1_TIME *from, const ASN1_TIME *to); + +DECLARE_ASN1_FUNCTIONS(ASN1_OCTET_STRING) +OPENSSL_EXPORT ASN1_OCTET_STRING * ASN1_OCTET_STRING_dup(const ASN1_OCTET_STRING *a); +OPENSSL_EXPORT int ASN1_OCTET_STRING_cmp(const ASN1_OCTET_STRING *a, const ASN1_OCTET_STRING *b); +OPENSSL_EXPORT int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *str, const unsigned char *data, int len); + +DECLARE_ASN1_FUNCTIONS(ASN1_VISIBLESTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_UNIVERSALSTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_UTF8STRING) +DECLARE_ASN1_FUNCTIONS(ASN1_NULL) +DECLARE_ASN1_FUNCTIONS(ASN1_BMPSTRING) + +OPENSSL_EXPORT int UTF8_getc(const unsigned char *str, int len, unsigned long *val); +OPENSSL_EXPORT int UTF8_putc(unsigned char *str, int len, unsigned long value); + +DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE) + +DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING) +DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT) +DECLARE_ASN1_FUNCTIONS(ASN1_PRINTABLESTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_T61STRING) +DECLARE_ASN1_FUNCTIONS(ASN1_IA5STRING) +DECLARE_ASN1_FUNCTIONS(ASN1_GENERALSTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_UTCTIME) +DECLARE_ASN1_FUNCTIONS(ASN1_GENERALIZEDTIME) +DECLARE_ASN1_FUNCTIONS(ASN1_TIME) + +DECLARE_ASN1_ITEM(ASN1_OCTET_STRING_NDEF) + +OPENSSL_EXPORT ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s,time_t t); +OPENSSL_EXPORT ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s,time_t t, int offset_day, long offset_sec); +OPENSSL_EXPORT int ASN1_TIME_check(ASN1_TIME *t); +OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out); +OPENSSL_EXPORT int ASN1_TIME_set_string(ASN1_TIME *s, const char *str); + +OPENSSL_EXPORT int i2d_ASN1_SET(STACK_OF(OPENSSL_BLOCK) *a, unsigned char **pp, i2d_of_void *i2d, int ex_tag, int ex_class, int is_set); +OPENSSL_EXPORT STACK_OF(OPENSSL_BLOCK) *d2i_ASN1_SET(STACK_OF(OPENSSL_BLOCK) **a, + const unsigned char **pp, + long length, d2i_of_void *d2i, + void (*free_func)(OPENSSL_BLOCK), int ex_tag, + int ex_class); + +OPENSSL_EXPORT int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a); +OPENSSL_EXPORT int a2i_ASN1_INTEGER(BIO *bp,ASN1_INTEGER *bs,char *buf,int size); +OPENSSL_EXPORT int i2a_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *a); +OPENSSL_EXPORT int a2i_ASN1_ENUMERATED(BIO *bp,ASN1_ENUMERATED *bs,char *buf,int size); +OPENSSL_EXPORT int i2a_ASN1_OBJECT(BIO *bp,ASN1_OBJECT *a); +OPENSSL_EXPORT int a2i_ASN1_STRING(BIO *bp,ASN1_STRING *bs,char *buf,int size); +OPENSSL_EXPORT int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type); +OPENSSL_EXPORT int i2t_ASN1_OBJECT(char *buf,int buf_len,ASN1_OBJECT *a); + +OPENSSL_EXPORT int a2d_ASN1_OBJECT(unsigned char *out,int olen, const char *buf, int num); +OPENSSL_EXPORT ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data,int len, const char *sn, const char *ln); + +OPENSSL_EXPORT int ASN1_INTEGER_set(ASN1_INTEGER *a, long v); +OPENSSL_EXPORT long ASN1_INTEGER_get(const ASN1_INTEGER *a); +OPENSSL_EXPORT ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai); +OPENSSL_EXPORT BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai,BIGNUM *bn); + +OPENSSL_EXPORT int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v); +OPENSSL_EXPORT long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a); +OPENSSL_EXPORT ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai); +OPENSSL_EXPORT BIGNUM *ASN1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai,BIGNUM *bn); + +/* General */ +/* given a string, return the correct type, max is the maximum length */ +OPENSSL_EXPORT int ASN1_PRINTABLE_type(const unsigned char *s, int max); + +OPENSSL_EXPORT int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char **pp, int tag, int xclass); +OPENSSL_EXPORT ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp, long length, int Ptag, int Pclass); +OPENSSL_EXPORT unsigned long ASN1_tag2bit(int tag); +/* type is one or more of the B_ASN1_ values. */ +OPENSSL_EXPORT ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING **a,const unsigned char **pp, long length,int type); + +/* PARSING */ +OPENSSL_EXPORT int asn1_Finish(ASN1_CTX *c); +OPENSSL_EXPORT int asn1_const_Finish(ASN1_const_CTX *c); + +/* SPECIALS */ +OPENSSL_EXPORT int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, int *pclass, long omax); +OPENSSL_EXPORT int ASN1_check_infinite_end(unsigned char **p,long len); +OPENSSL_EXPORT int ASN1_const_check_infinite_end(const unsigned char **p,long len); +OPENSSL_EXPORT void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag, int xclass); +OPENSSL_EXPORT int ASN1_put_eoc(unsigned char **pp); +OPENSSL_EXPORT int ASN1_object_size(int constructed, int length, int tag); + +/* Used to implement other functions */ +OPENSSL_EXPORT void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x); + +#define ASN1_dup_of(type,i2d,d2i,x) \ + ((type*)ASN1_dup(CHECKED_I2D_OF(type, i2d), \ + CHECKED_D2I_OF(type, d2i), \ + CHECKED_PTR_OF(type, x))) + +#define ASN1_dup_of_const(type,i2d,d2i,x) \ + ((type*)ASN1_dup(CHECKED_I2D_OF(const type, i2d), \ + CHECKED_D2I_OF(type, d2i), \ + CHECKED_PTR_OF(const type, x))) + +OPENSSL_EXPORT void *ASN1_item_dup(const ASN1_ITEM *it, void *x); + +/* ASN1 alloc/free macros for when a type is only used internally */ + +#define M_ASN1_new_of(type) (type *)ASN1_item_new(ASN1_ITEM_rptr(type)) +#define M_ASN1_free_of(x, type) \ + ASN1_item_free(CHECKED_PTR_OF(type, x), ASN1_ITEM_rptr(type)) + +#ifndef OPENSSL_NO_FP_API +OPENSSL_EXPORT void *ASN1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x); + +#define ASN1_d2i_fp_of(type,xnew,d2i,in,x) \ + ((type*)ASN1_d2i_fp(CHECKED_NEW_OF(type, xnew), \ + CHECKED_D2I_OF(type, d2i), \ + in, \ + CHECKED_PPTR_OF(type, x))) + +OPENSSL_EXPORT void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x); +OPENSSL_EXPORT int ASN1_i2d_fp(i2d_of_void *i2d,FILE *out,void *x); + +#define ASN1_i2d_fp_of(type,i2d,out,x) \ + (ASN1_i2d_fp(CHECKED_I2D_OF(type, i2d), \ + out, \ + CHECKED_PTR_OF(type, x))) + +#define ASN1_i2d_fp_of_const(type,i2d,out,x) \ + (ASN1_i2d_fp(CHECKED_I2D_OF(const type, i2d), \ + out, \ + CHECKED_PTR_OF(const type, x))) + +OPENSSL_EXPORT int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x); +OPENSSL_EXPORT int ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags); +#endif + +OPENSSL_EXPORT int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in); + +OPENSSL_EXPORT void *ASN1_d2i_bio(void *(*xnew)(void), d2i_of_void *d2i, BIO *in, void **x); + +#define ASN1_d2i_bio_of(type,xnew,d2i,in,x) \ + ((type*)ASN1_d2i_bio( CHECKED_NEW_OF(type, xnew), \ + CHECKED_D2I_OF(type, d2i), \ + in, \ + CHECKED_PPTR_OF(type, x))) + +OPENSSL_EXPORT void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x); +OPENSSL_EXPORT int ASN1_i2d_bio(i2d_of_void *i2d,BIO *out, void *x); + +#define ASN1_i2d_bio_of(type,i2d,out,x) \ + (ASN1_i2d_bio(CHECKED_I2D_OF(type, i2d), \ + out, \ + CHECKED_PTR_OF(type, x))) + +#define ASN1_i2d_bio_of_const(type,i2d,out,x) \ + (ASN1_i2d_bio(CHECKED_I2D_OF(const type, i2d), \ + out, \ + CHECKED_PTR_OF(const type, x))) + +OPENSSL_EXPORT int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x); +OPENSSL_EXPORT int ASN1_UTCTIME_print(BIO *fp, const ASN1_UTCTIME *a); +OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_print(BIO *fp, const ASN1_GENERALIZEDTIME *a); +OPENSSL_EXPORT int ASN1_TIME_print(BIO *fp, const ASN1_TIME *a); +OPENSSL_EXPORT int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v); +OPENSSL_EXPORT int ASN1_STRING_print_ex(BIO *out, ASN1_STRING *str, unsigned long flags); +OPENSSL_EXPORT int ASN1_bn_print(BIO *bp, const char *number, const BIGNUM *num, unsigned char *buf, int off); +OPENSSL_EXPORT int ASN1_parse(BIO *bp,const unsigned char *pp,long len,int indent); +OPENSSL_EXPORT int ASN1_parse_dump(BIO *bp,const unsigned char *pp,long len,int indent,int dump); +OPENSSL_EXPORT const char *ASN1_tag2str(int tag); + +/* Used to load and write netscape format cert */ + +DECLARE_ASN1_FUNCTIONS(NETSCAPE_X509) + +int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s); + +OPENSSL_EXPORT STACK_OF(OPENSSL_BLOCK) *ASN1_seq_unpack(const unsigned char *buf, int len, d2i_of_void *d2i, void (*free_func)(OPENSSL_BLOCK)); +OPENSSL_EXPORT unsigned char *ASN1_seq_pack(STACK_OF(OPENSSL_BLOCK) *safes, i2d_of_void *i2d, unsigned char **buf, int *len ); +OPENSSL_EXPORT void *ASN1_unpack_string(ASN1_STRING *oct, d2i_of_void *d2i); +OPENSSL_EXPORT void *ASN1_item_unpack(ASN1_STRING *oct, const ASN1_ITEM *it); +OPENSSL_EXPORT ASN1_STRING *ASN1_pack_string(void *obj, i2d_of_void *i2d, ASN1_OCTET_STRING **oct); + +#define ASN1_pack_string_of(type,obj,i2d,oct) \ + (ASN1_pack_string(CHECKED_PTR_OF(type, obj), \ + CHECKED_I2D_OF(type, i2d), \ + oct)) + +OPENSSL_EXPORT ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_OCTET_STRING **oct); + +OPENSSL_EXPORT void ASN1_STRING_set_default_mask(unsigned long mask); +OPENSSL_EXPORT int ASN1_STRING_set_default_mask_asc(const char *p); +OPENSSL_EXPORT unsigned long ASN1_STRING_get_default_mask(void); +OPENSSL_EXPORT int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len, int inform, unsigned long mask); +OPENSSL_EXPORT int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, int inform, unsigned long mask, long minsize, long maxsize); + +OPENSSL_EXPORT ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in, int inlen, int inform, int nid); +OPENSSL_EXPORT ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid); +OPENSSL_EXPORT int ASN1_STRING_TABLE_add(int, long, long, unsigned long, unsigned long); +OPENSSL_EXPORT void ASN1_STRING_TABLE_cleanup(void); + +/* ASN1 template functions */ + +/* Old API compatible functions */ +OPENSSL_EXPORT ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it); +OPENSSL_EXPORT void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it); +OPENSSL_EXPORT ASN1_VALUE * ASN1_item_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_ITEM *it); +OPENSSL_EXPORT int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it); +OPENSSL_EXPORT int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it); + +OPENSSL_EXPORT void ASN1_add_oid_module(void); + +OPENSSL_EXPORT ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf); +OPENSSL_EXPORT ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf); + +/* ASN1 Print flags */ + +/* Indicate missing OPTIONAL fields */ +#define ASN1_PCTX_FLAGS_SHOW_ABSENT 0x001 +/* Mark start and end of SEQUENCE */ +#define ASN1_PCTX_FLAGS_SHOW_SEQUENCE 0x002 +/* Mark start and end of SEQUENCE/SET OF */ +#define ASN1_PCTX_FLAGS_SHOW_SSOF 0x004 +/* Show the ASN1 type of primitives */ +#define ASN1_PCTX_FLAGS_SHOW_TYPE 0x008 +/* Don't show ASN1 type of ANY */ +#define ASN1_PCTX_FLAGS_NO_ANY_TYPE 0x010 +/* Don't show ASN1 type of MSTRINGs */ +#define ASN1_PCTX_FLAGS_NO_MSTRING_TYPE 0x020 +/* Don't show field names in SEQUENCE */ +#define ASN1_PCTX_FLAGS_NO_FIELD_NAME 0x040 +/* Show structure names of each SEQUENCE field */ +#define ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME 0x080 +/* Don't show structure name even at top level */ +#define ASN1_PCTX_FLAGS_NO_STRUCT_NAME 0x100 + +OPENSSL_EXPORT int ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent, const ASN1_ITEM *it, const ASN1_PCTX *pctx); +OPENSSL_EXPORT ASN1_PCTX *ASN1_PCTX_new(void); +OPENSSL_EXPORT void ASN1_PCTX_free(ASN1_PCTX *p); +OPENSSL_EXPORT unsigned long ASN1_PCTX_get_flags(ASN1_PCTX *p); +OPENSSL_EXPORT void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags); +OPENSSL_EXPORT unsigned long ASN1_PCTX_get_nm_flags(ASN1_PCTX *p); +OPENSSL_EXPORT void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags); +OPENSSL_EXPORT unsigned long ASN1_PCTX_get_cert_flags(ASN1_PCTX *p); +OPENSSL_EXPORT void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags); +OPENSSL_EXPORT unsigned long ASN1_PCTX_get_oid_flags(ASN1_PCTX *p); +OPENSSL_EXPORT void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags); +OPENSSL_EXPORT unsigned long ASN1_PCTX_get_str_flags(ASN1_PCTX *p); +OPENSSL_EXPORT void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags); + +OPENSSL_EXPORT const BIO_METHOD *BIO_f_asn1(void); + +OPENSSL_EXPORT BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it); + +OPENSSL_EXPORT int i2d_ASN1_bio_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags, const ASN1_ITEM *it); +OPENSSL_EXPORT int PEM_write_bio_ASN1_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags, const char *hdr, const ASN1_ITEM *it); +OPENSSL_EXPORT ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it); +OPENSSL_EXPORT int SMIME_crlf_copy(BIO *in, BIO *out, int flags); +OPENSSL_EXPORT int SMIME_text(BIO *in, BIO *out); + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_ASN1_strings(void); + +typedef int asn1_ps_func(BIO *b, unsigned char **pbuf, int *plen, void *parg); +OPENSSL_EXPORT int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, asn1_ps_func *prefix_free); +OPENSSL_EXPORT int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, asn1_ps_func **pprefix_free); +OPENSSL_EXPORT int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, asn1_ps_func *suffix_free); +OPENSSL_EXPORT int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, asn1_ps_func **psuffix_free); + +#ifdef __cplusplus +} +#endif + +#define ASN1_R_ASN1_LENGTH_MISMATCH 100 +#define ASN1_R_AUX_ERROR 101 +#define ASN1_R_BAD_GET_ASN1_OBJECT_CALL 102 +#define ASN1_R_BAD_OBJECT_HEADER 103 +#define ASN1_R_BMPSTRING_IS_WRONG_LENGTH 104 +#define ASN1_R_BN_LIB 105 +#define ASN1_R_BOOLEAN_IS_WRONG_LENGTH 106 +#define ASN1_R_BUFFER_TOO_SMALL 107 +#define ASN1_R_DECODE_ERROR 108 +#define ASN1_R_DEPTH_EXCEEDED 109 +#define ASN1_R_ENCODE_ERROR 110 +#define ASN1_R_ERROR_GETTING_TIME 111 +#define ASN1_R_EXPECTING_AN_ASN1_SEQUENCE 112 +#define ASN1_R_EXPECTING_AN_INTEGER 113 +#define ASN1_R_EXPECTING_AN_OBJECT 114 +#define ASN1_R_EXPECTING_A_BOOLEAN 115 +#define ASN1_R_EXPECTING_A_TIME 116 +#define ASN1_R_EXPLICIT_LENGTH_MISMATCH 117 +#define ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED 118 +#define ASN1_R_FIELD_MISSING 119 +#define ASN1_R_FIRST_NUM_TOO_LARGE 120 +#define ASN1_R_HEADER_TOO_LONG 121 +#define ASN1_R_ILLEGAL_BITSTRING_FORMAT 122 +#define ASN1_R_ILLEGAL_BOOLEAN 123 +#define ASN1_R_ILLEGAL_CHARACTERS 124 +#define ASN1_R_ILLEGAL_FORMAT 125 +#define ASN1_R_ILLEGAL_HEX 126 +#define ASN1_R_ILLEGAL_IMPLICIT_TAG 127 +#define ASN1_R_ILLEGAL_INTEGER 128 +#define ASN1_R_ILLEGAL_NESTED_TAGGING 129 +#define ASN1_R_ILLEGAL_NULL 130 +#define ASN1_R_ILLEGAL_NULL_VALUE 131 +#define ASN1_R_ILLEGAL_OBJECT 132 +#define ASN1_R_ILLEGAL_OPTIONAL_ANY 133 +#define ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE 134 +#define ASN1_R_ILLEGAL_TAGGED_ANY 135 +#define ASN1_R_ILLEGAL_TIME_VALUE 136 +#define ASN1_R_INTEGER_NOT_ASCII_FORMAT 137 +#define ASN1_R_INTEGER_TOO_LARGE_FOR_LONG 138 +#define ASN1_R_INVALID_BIT_STRING_BITS_LEFT 139 +#define ASN1_R_INVALID_BMPSTRING_LENGTH 140 +#define ASN1_R_INVALID_DIGIT 141 +#define ASN1_R_INVALID_MODIFIER 142 +#define ASN1_R_INVALID_NUMBER 143 +#define ASN1_R_INVALID_OBJECT_ENCODING 144 +#define ASN1_R_INVALID_SEPARATOR 145 +#define ASN1_R_INVALID_TIME_FORMAT 146 +#define ASN1_R_INVALID_UNIVERSALSTRING_LENGTH 147 +#define ASN1_R_INVALID_UTF8STRING 148 +#define ASN1_R_LIST_ERROR 149 +#define ASN1_R_MISSING_ASN1_EOS 150 +#define ASN1_R_MISSING_EOC 151 +#define ASN1_R_MISSING_SECOND_NUMBER 152 +#define ASN1_R_MISSING_VALUE 153 +#define ASN1_R_MSTRING_NOT_UNIVERSAL 154 +#define ASN1_R_MSTRING_WRONG_TAG 155 +#define ASN1_R_NESTED_ASN1_ERROR 156 +#define ASN1_R_NESTED_ASN1_STRING 157 +#define ASN1_R_NON_HEX_CHARACTERS 158 +#define ASN1_R_NOT_ASCII_FORMAT 159 +#define ASN1_R_NOT_ENOUGH_DATA 160 +#define ASN1_R_NO_MATCHING_CHOICE_TYPE 161 +#define ASN1_R_NULL_IS_WRONG_LENGTH 162 +#define ASN1_R_OBJECT_NOT_ASCII_FORMAT 163 +#define ASN1_R_ODD_NUMBER_OF_CHARS 164 +#define ASN1_R_SECOND_NUMBER_TOO_LARGE 165 +#define ASN1_R_SEQUENCE_LENGTH_MISMATCH 166 +#define ASN1_R_SEQUENCE_NOT_CONSTRUCTED 167 +#define ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG 168 +#define ASN1_R_SHORT_LINE 169 +#define ASN1_R_STREAMING_NOT_SUPPORTED 170 +#define ASN1_R_STRING_TOO_LONG 171 +#define ASN1_R_STRING_TOO_SHORT 172 +#define ASN1_R_TAG_VALUE_TOO_HIGH 173 +#define ASN1_R_TIME_NOT_ASCII_FORMAT 174 +#define ASN1_R_TOO_LONG 175 +#define ASN1_R_TYPE_NOT_CONSTRUCTED 176 +#define ASN1_R_TYPE_NOT_PRIMITIVE 177 +#define ASN1_R_UNEXPECTED_EOC 178 +#define ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH 179 +#define ASN1_R_UNKNOWN_FORMAT 180 +#define ASN1_R_UNKNOWN_TAG 181 +#define ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE 182 +#define ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE 183 +#define ASN1_R_UNSUPPORTED_TYPE 184 +#define ASN1_R_WRONG_TAG 185 +#define ASN1_R_WRONG_TYPE 186 + +#endif diff --git a/project/jni/boringssl/include/openssl/asn1_mac.h b/project/jni/boringssl/include/openssl/asn1_mac.h new file mode 100644 index 000000000..f319beec0 --- /dev/null +++ b/project/jni/boringssl/include/openssl/asn1_mac.h @@ -0,0 +1,75 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_ASN1_MAC_H +#define HEADER_ASN1_MAC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +OPENSSL_EXPORT int asn1_GetSequence(ASN1_const_CTX *c, long *length); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/project/jni/boringssl/include/openssl/asn1t.h b/project/jni/boringssl/include/openssl/asn1t.h new file mode 100644 index 000000000..b43c33281 --- /dev/null +++ b/project/jni/boringssl/include/openssl/asn1t.h @@ -0,0 +1,906 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 2000-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +#ifndef HEADER_ASN1T_H +#define HEADER_ASN1T_H + +#include +#include + +#ifdef OPENSSL_BUILD_SHLIBCRYPTO +# undef OPENSSL_EXTERN +# define OPENSSL_EXTERN OPENSSL_EXPORT +#endif + +/* ASN1 template defines, structures and functions */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */ +#define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)(iptr)) + + +/* Macros for start and end of ASN1_ITEM definition */ + +#define ASN1_ITEM_start(itname) \ + const ASN1_ITEM itname##_it = { + +#define ASN1_ITEM_end(itname) \ + }; + +/* Macros to aid ASN1 template writing */ + +#define ASN1_ITEM_TEMPLATE(tname) \ + static const ASN1_TEMPLATE tname##_item_tt + +#define ASN1_ITEM_TEMPLATE_END(tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_PRIMITIVE,\ + -1,\ + &tname##_item_tt,\ + 0,\ + NULL,\ + 0,\ + #tname \ + ASN1_ITEM_end(tname) + + +/* This is a ASN1 type which just embeds a template */ + +/* This pair helps declare a SEQUENCE. We can do: + * + * ASN1_SEQUENCE(stname) = { + * ... SEQUENCE components ... + * } ASN1_SEQUENCE_END(stname) + * + * This will produce an ASN1_ITEM called stname_it + * for a structure called stname. + * + * If you want the same structure but a different + * name then use: + * + * ASN1_SEQUENCE(itname) = { + * ... SEQUENCE components ... + * } ASN1_SEQUENCE_END_name(stname, itname) + * + * This will create an item called itname_it using + * a structure called stname. + */ + +#define ASN1_SEQUENCE(tname) \ + static const ASN1_TEMPLATE tname##_seq_tt[] + +#define ASN1_SEQUENCE_END(stname) ASN1_SEQUENCE_END_name(stname, stname) + +#define ASN1_SEQUENCE_END_name(stname, tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +#define ASN1_NDEF_SEQUENCE(tname) \ + ASN1_SEQUENCE(tname) + +#define ASN1_NDEF_SEQUENCE_cb(tname, cb) \ + ASN1_SEQUENCE_cb(tname, cb) + +#define ASN1_SEQUENCE_cb(tname, cb) \ + static const ASN1_AUX tname##_aux = {NULL, 0, 0, cb, 0}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_BROKEN_SEQUENCE(tname) \ + static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_BROKEN, 0, 0, 0}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_SEQUENCE_ref(tname, cb) \ + static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_REFCOUNT, offsetof(tname, references), cb, 0}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_SEQUENCE_enc(tname, enc, cb) \ + static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_ENCODING, 0, cb, offsetof(tname, enc)}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_NDEF_SEQUENCE_END(tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_NDEF_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(tname),\ + #tname \ + ASN1_ITEM_end(tname) + +#define ASN1_BROKEN_SEQUENCE_END(stname) ASN1_SEQUENCE_END_ref(stname, stname) + +#define ASN1_SEQUENCE_END_enc(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname) + +#define ASN1_SEQUENCE_END_cb(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname) + +#define ASN1_SEQUENCE_END_ref(stname, tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + &tname##_aux,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +#define ASN1_NDEF_SEQUENCE_END_cb(stname, tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_NDEF_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + &tname##_aux,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + + +/* This pair helps declare a CHOICE type. We can do: + * + * ASN1_CHOICE(chname) = { + * ... CHOICE options ... + * ASN1_CHOICE_END(chname) + * + * This will produce an ASN1_ITEM called chname_it + * for a structure called chname. The structure + * definition must look like this: + * typedef struct { + * int type; + * union { + * ASN1_SOMETHING *opt1; + * ASN1_SOMEOTHER *opt2; + * } value; + * } chname; + * + * the name of the selector must be 'type'. + * to use an alternative selector name use the + * ASN1_CHOICE_END_selector() version. + */ + +#define ASN1_CHOICE(tname) \ + static const ASN1_TEMPLATE tname##_ch_tt[] + +#define ASN1_CHOICE_cb(tname, cb) \ + static const ASN1_AUX tname##_aux = {NULL, 0, 0, cb, 0}; \ + ASN1_CHOICE(tname) + +#define ASN1_CHOICE_END(stname) ASN1_CHOICE_END_name(stname, stname) + +#define ASN1_CHOICE_END_name(stname, tname) ASN1_CHOICE_END_selector(stname, tname, type) + +#define ASN1_CHOICE_END_selector(stname, tname, selname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_CHOICE,\ + offsetof(stname,selname) ,\ + tname##_ch_tt,\ + sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +#define ASN1_CHOICE_END_cb(stname, tname, selname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_CHOICE,\ + offsetof(stname,selname) ,\ + tname##_ch_tt,\ + sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\ + &tname##_aux,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +/* This helps with the template wrapper form of ASN1_ITEM */ + +#define ASN1_EX_TEMPLATE_TYPE(flags, tag, name, type) { \ + (flags), (tag), 0,\ + #name, ASN1_ITEM_ref(type) } + +/* These help with SEQUENCE or CHOICE components */ + +/* used to declare other types */ + +#define ASN1_EX_TYPE(flags, tag, stname, field, type) { \ + (flags), (tag), offsetof(stname, field),\ + #field, ASN1_ITEM_ref(type) } + +/* used when the structure is combined with the parent */ + +#define ASN1_EX_COMBINE(flags, tag, type) { \ + (flags)|ASN1_TFLG_COMBINE, (tag), 0, NULL, ASN1_ITEM_ref(type) } + +/* implicit and explicit helper macros */ + +#define ASN1_IMP_EX(stname, field, type, tag, ex) \ + ASN1_EX_TYPE(ASN1_TFLG_IMPLICIT | ex, tag, stname, field, type) + +#define ASN1_EXP_EX(stname, field, type, tag, ex) \ + ASN1_EX_TYPE(ASN1_TFLG_EXPLICIT | ex, tag, stname, field, type) + +/* Any defined by macros: the field used is in the table itself */ + +#define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) } +#define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) } +/* Plain simple type */ +#define ASN1_SIMPLE(stname, field, type) ASN1_EX_TYPE(0,0, stname, field, type) + +/* OPTIONAL simple type */ +#define ASN1_OPT(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_OPTIONAL, 0, stname, field, type) + +/* IMPLICIT tagged simple type */ +#define ASN1_IMP(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, 0) + +/* IMPLICIT tagged OPTIONAL simple type */ +#define ASN1_IMP_OPT(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL) + +/* Same as above but EXPLICIT */ + +#define ASN1_EXP(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, 0) +#define ASN1_EXP_OPT(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL) + +/* SEQUENCE OF type */ +#define ASN1_SEQUENCE_OF(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, stname, field, type) + +/* OPTIONAL SEQUENCE OF */ +#define ASN1_SEQUENCE_OF_OPT(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type) + +/* Same as above but for SET OF */ + +#define ASN1_SET_OF(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SET_OF, 0, stname, field, type) + +#define ASN1_SET_OF_OPT(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type) + +/* Finally compound types of SEQUENCE, SET, IMPLICIT, EXPLICIT and OPTIONAL */ + +#define ASN1_IMP_SET_OF(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF) + +#define ASN1_EXP_SET_OF(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF) + +#define ASN1_IMP_SET_OF_OPT(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL) + +#define ASN1_EXP_SET_OF_OPT(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL) + +#define ASN1_IMP_SEQUENCE_OF(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF) + +#define ASN1_IMP_SEQUENCE_OF_OPT(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL) + +#define ASN1_EXP_SEQUENCE_OF(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF) + +#define ASN1_EXP_SEQUENCE_OF_OPT(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL) + +/* EXPLICIT using indefinite length constructed form */ +#define ASN1_NDEF_EXP(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_NDEF) + +/* EXPLICIT OPTIONAL using indefinite length constructed form */ +#define ASN1_NDEF_EXP_OPT(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL|ASN1_TFLG_NDEF) + +/* Macros for the ASN1_ADB structure */ + +#define ASN1_ADB(name) \ + static const ASN1_ADB_TABLE name##_adbtbl[] + +#define ASN1_ADB_END(name, flags, field, app_table, def, none) \ + ;\ + static const ASN1_ADB name##_adb = {\ + flags,\ + offsetof(name, field),\ + app_table,\ + name##_adbtbl,\ + sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE),\ + def,\ + none\ + } + +#define ADB_ENTRY(val, template) {val, template} + +#define ASN1_ADB_TEMPLATE(name) \ + static const ASN1_TEMPLATE name##_tt + +/* This is the ASN1 template structure that defines + * a wrapper round the actual type. It determines the + * actual position of the field in the value structure, + * various flags such as OPTIONAL and the field name. + */ + +struct ASN1_TEMPLATE_st { +unsigned long flags; /* Various flags */ +long tag; /* tag, not used if no tagging */ +unsigned long offset; /* Offset of this field in structure */ +#ifndef NO_ASN1_FIELD_NAMES +const char *field_name; /* Field name */ +#endif +ASN1_ITEM_EXP *item; /* Relevant ASN1_ITEM or ASN1_ADB */ +}; + +/* Macro to extract ASN1_ITEM and ASN1_ADB pointer from ASN1_TEMPLATE */ + +#define ASN1_TEMPLATE_item(t) (t->item_ptr) +#define ASN1_TEMPLATE_adb(t) (t->item_ptr) + +typedef struct ASN1_ADB_TABLE_st ASN1_ADB_TABLE; +typedef struct ASN1_ADB_st ASN1_ADB; + +struct ASN1_ADB_st { + unsigned long flags; /* Various flags */ + unsigned long offset; /* Offset of selector field */ + STACK_OF(ASN1_ADB_TABLE) **app_items; /* Application defined items */ + const ASN1_ADB_TABLE *tbl; /* Table of possible types */ + long tblcount; /* Number of entries in tbl */ + const ASN1_TEMPLATE *default_tt; /* Type to use if no match */ + const ASN1_TEMPLATE *null_tt; /* Type to use if selector is NULL */ +}; + +struct ASN1_ADB_TABLE_st { + long value; /* NID for an object or value for an int */ + const ASN1_TEMPLATE tt; /* item for this value */ +}; + +/* template flags */ + +/* Field is optional */ +#define ASN1_TFLG_OPTIONAL (0x1) + +/* Field is a SET OF */ +#define ASN1_TFLG_SET_OF (0x1 << 1) + +/* Field is a SEQUENCE OF */ +#define ASN1_TFLG_SEQUENCE_OF (0x2 << 1) + +/* Special case: this refers to a SET OF that + * will be sorted into DER order when encoded *and* + * the corresponding STACK will be modified to match + * the new order. + */ +#define ASN1_TFLG_SET_ORDER (0x3 << 1) + +/* Mask for SET OF or SEQUENCE OF */ +#define ASN1_TFLG_SK_MASK (0x3 << 1) + +/* These flags mean the tag should be taken from the + * tag field. If EXPLICIT then the underlying type + * is used for the inner tag. + */ + +/* IMPLICIT tagging */ +#define ASN1_TFLG_IMPTAG (0x1 << 3) + + +/* EXPLICIT tagging, inner tag from underlying type */ +#define ASN1_TFLG_EXPTAG (0x2 << 3) + +#define ASN1_TFLG_TAG_MASK (0x3 << 3) + +/* context specific IMPLICIT */ +#define ASN1_TFLG_IMPLICIT ASN1_TFLG_IMPTAG|ASN1_TFLG_CONTEXT + +/* context specific EXPLICIT */ +#define ASN1_TFLG_EXPLICIT ASN1_TFLG_EXPTAG|ASN1_TFLG_CONTEXT + +/* If tagging is in force these determine the + * type of tag to use. Otherwise the tag is + * determined by the underlying type. These + * values reflect the actual octet format. + */ + +/* Universal tag */ +#define ASN1_TFLG_UNIVERSAL (0x0<<6) +/* Application tag */ +#define ASN1_TFLG_APPLICATION (0x1<<6) +/* Context specific tag */ +#define ASN1_TFLG_CONTEXT (0x2<<6) +/* Private tag */ +#define ASN1_TFLG_PRIVATE (0x3<<6) + +#define ASN1_TFLG_TAG_CLASS (0x3<<6) + +/* These are for ANY DEFINED BY type. In this case + * the 'item' field points to an ASN1_ADB structure + * which contains a table of values to decode the + * relevant type + */ + +#define ASN1_TFLG_ADB_MASK (0x3<<8) + +#define ASN1_TFLG_ADB_OID (0x1<<8) + +#define ASN1_TFLG_ADB_INT (0x1<<9) + +/* This flag means a parent structure is passed + * instead of the field: this is useful is a + * SEQUENCE is being combined with a CHOICE for + * example. Since this means the structure and + * item name will differ we need to use the + * ASN1_CHOICE_END_name() macro for example. + */ + +#define ASN1_TFLG_COMBINE (0x1<<10) + +/* This flag when present in a SEQUENCE OF, SET OF + * or EXPLICIT causes indefinite length constructed + * encoding to be used if required. + */ + +#define ASN1_TFLG_NDEF (0x1<<11) + +/* This is the actual ASN1 item itself */ + +struct ASN1_ITEM_st { +char itype; /* The item type, primitive, SEQUENCE, CHOICE or extern */ +long utype; /* underlying type */ +const ASN1_TEMPLATE *templates; /* If SEQUENCE or CHOICE this contains the contents */ +long tcount; /* Number of templates if SEQUENCE or CHOICE */ +const void *funcs; /* functions that handle this type */ +long size; /* Structure size (usually)*/ +#ifndef NO_ASN1_FIELD_NAMES +const char *sname; /* Structure name */ +#endif +}; + +/* These are values for the itype field and + * determine how the type is interpreted. + * + * For PRIMITIVE types the underlying type + * determines the behaviour if items is NULL. + * + * Otherwise templates must contain a single + * template and the type is treated in the + * same way as the type specified in the template. + * + * For SEQUENCE types the templates field points + * to the members, the size field is the + * structure size. + * + * For CHOICE types the templates field points + * to each possible member (typically a union) + * and the 'size' field is the offset of the + * selector. + * + * The 'funcs' field is used for application + * specific functions. + * + * For COMPAT types the funcs field gives a + * set of functions that handle this type, this + * supports the old d2i, i2d convention. + * + * The EXTERN type uses a new style d2i/i2d. + * The new style should be used where possible + * because it avoids things like the d2i IMPLICIT + * hack. + * + * MSTRING is a multiple string type, it is used + * for a CHOICE of character strings where the + * actual strings all occupy an ASN1_STRING + * structure. In this case the 'utype' field + * has a special meaning, it is used as a mask + * of acceptable types using the B_ASN1 constants. + * + * NDEF_SEQUENCE is the same as SEQUENCE except + * that it will use indefinite length constructed + * encoding if requested. + * + */ + +#define ASN1_ITYPE_PRIMITIVE 0x0 + +#define ASN1_ITYPE_SEQUENCE 0x1 + +#define ASN1_ITYPE_CHOICE 0x2 + +#define ASN1_ITYPE_COMPAT 0x3 + +#define ASN1_ITYPE_EXTERN 0x4 + +#define ASN1_ITYPE_MSTRING 0x5 + +#define ASN1_ITYPE_NDEF_SEQUENCE 0x6 + +/* Cache for ASN1 tag and length, so we + * don't keep re-reading it for things + * like CHOICE + */ + +struct ASN1_TLC_st{ + char valid; /* Values below are valid */ + int ret; /* return value */ + long plen; /* length */ + int ptag; /* class value */ + int pclass; /* class value */ + int hdrlen; /* header length */ +}; + +/* Typedefs for ASN1 function pointers */ + +typedef ASN1_VALUE * ASN1_new_func(void); +typedef void ASN1_free_func(ASN1_VALUE *a); +typedef ASN1_VALUE * ASN1_d2i_func(ASN1_VALUE **a, const unsigned char ** in, long length); +typedef int ASN1_i2d_func(ASN1_VALUE * a, unsigned char **in); + +typedef int ASN1_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx); + +typedef int ASN1_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass); +typedef int ASN1_ex_new_func(ASN1_VALUE **pval, const ASN1_ITEM *it); +typedef void ASN1_ex_free_func(ASN1_VALUE **pval, const ASN1_ITEM *it); + +typedef int ASN1_ex_print_func(BIO *out, ASN1_VALUE **pval, + int indent, const char *fname, + const ASN1_PCTX *pctx); + +typedef int ASN1_primitive_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it); +typedef int ASN1_primitive_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it); +typedef int ASN1_primitive_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it, int indent, const ASN1_PCTX *pctx); + +typedef struct ASN1_COMPAT_FUNCS_st { + ASN1_new_func *asn1_new; + ASN1_free_func *asn1_free; + ASN1_d2i_func *asn1_d2i; + ASN1_i2d_func *asn1_i2d; +} ASN1_COMPAT_FUNCS; + +typedef struct ASN1_EXTERN_FUNCS_st { + void *app_data; + ASN1_ex_new_func *asn1_ex_new; + ASN1_ex_free_func *asn1_ex_free; + ASN1_ex_free_func *asn1_ex_clear; + ASN1_ex_d2i *asn1_ex_d2i; + ASN1_ex_i2d *asn1_ex_i2d; + ASN1_ex_print_func *asn1_ex_print; +} ASN1_EXTERN_FUNCS; + +typedef struct ASN1_PRIMITIVE_FUNCS_st { + void *app_data; + unsigned long flags; + ASN1_ex_new_func *prim_new; + ASN1_ex_free_func *prim_free; + ASN1_ex_free_func *prim_clear; + ASN1_primitive_c2i *prim_c2i; + ASN1_primitive_i2c *prim_i2c; + ASN1_primitive_print *prim_print; +} ASN1_PRIMITIVE_FUNCS; + +/* This is the ASN1_AUX structure: it handles various + * miscellaneous requirements. For example the use of + * reference counts and an informational callback. + * + * The "informational callback" is called at various + * points during the ASN1 encoding and decoding. It can + * be used to provide minor customisation of the structures + * used. This is most useful where the supplied routines + * *almost* do the right thing but need some extra help + * at a few points. If the callback returns zero then + * it is assumed a fatal error has occurred and the + * main operation should be abandoned. + * + * If major changes in the default behaviour are required + * then an external type is more appropriate. + */ + +typedef int ASN1_aux_cb(int operation, ASN1_VALUE **in, const ASN1_ITEM *it, + void *exarg); + +typedef struct ASN1_AUX_st { + void *app_data; + int flags; + int ref_offset; /* Offset of reference value */ + ASN1_aux_cb *asn1_cb; + int enc_offset; /* Offset of ASN1_ENCODING structure */ +} ASN1_AUX; + +/* For print related callbacks exarg points to this structure */ +typedef struct ASN1_PRINT_ARG_st { + BIO *out; + int indent; + const ASN1_PCTX *pctx; +} ASN1_PRINT_ARG; + +/* For streaming related callbacks exarg points to this structure */ +typedef struct ASN1_STREAM_ARG_st { + /* BIO to stream through */ + BIO *out; + /* BIO with filters appended */ + BIO *ndef_bio; + /* Streaming I/O boundary */ + unsigned char **boundary; +} ASN1_STREAM_ARG; + +/* Flags in ASN1_AUX */ + +/* Use a reference count */ +#define ASN1_AFLG_REFCOUNT 1 +/* Save the encoding of structure (useful for signatures) */ +#define ASN1_AFLG_ENCODING 2 +/* The Sequence length is invalid */ +#define ASN1_AFLG_BROKEN 4 + +/* operation values for asn1_cb */ + +#define ASN1_OP_NEW_PRE 0 +#define ASN1_OP_NEW_POST 1 +#define ASN1_OP_FREE_PRE 2 +#define ASN1_OP_FREE_POST 3 +#define ASN1_OP_D2I_PRE 4 +#define ASN1_OP_D2I_POST 5 +#define ASN1_OP_I2D_PRE 6 +#define ASN1_OP_I2D_POST 7 +#define ASN1_OP_PRINT_PRE 8 +#define ASN1_OP_PRINT_POST 9 +#define ASN1_OP_STREAM_PRE 10 +#define ASN1_OP_STREAM_POST 11 +#define ASN1_OP_DETACHED_PRE 12 +#define ASN1_OP_DETACHED_POST 13 + +/* Macro to implement a primitive type */ +#define IMPLEMENT_ASN1_TYPE(stname) IMPLEMENT_ASN1_TYPE_ex(stname, stname, 0) +#define IMPLEMENT_ASN1_TYPE_ex(itname, vname, ex) \ + ASN1_ITEM_start(itname) \ + ASN1_ITYPE_PRIMITIVE, V_##vname, NULL, 0, NULL, ex, #itname \ + ASN1_ITEM_end(itname) + +/* Macro to implement a multi string type */ +#define IMPLEMENT_ASN1_MSTRING(itname, mask) \ + ASN1_ITEM_start(itname) \ + ASN1_ITYPE_MSTRING, mask, NULL, 0, NULL, sizeof(ASN1_STRING), #itname \ + ASN1_ITEM_end(itname) + +/* Macro to implement an ASN1_ITEM in terms of old style funcs */ + +#define IMPLEMENT_COMPAT_ASN1(sname) IMPLEMENT_COMPAT_ASN1_type(sname, V_ASN1_SEQUENCE) + +#define IMPLEMENT_COMPAT_ASN1_type(sname, tag) \ + static const ASN1_COMPAT_FUNCS sname##_ff = { \ + (ASN1_new_func *)sname##_new, \ + (ASN1_free_func *)sname##_free, \ + (ASN1_d2i_func *)d2i_##sname, \ + (ASN1_i2d_func *)i2d_##sname, \ + }; \ + ASN1_ITEM_start(sname) \ + ASN1_ITYPE_COMPAT, \ + tag, \ + NULL, \ + 0, \ + &sname##_ff, \ + 0, \ + #sname \ + ASN1_ITEM_end(sname) + +#define IMPLEMENT_EXTERN_ASN1(sname, tag, fptrs) \ + ASN1_ITEM_start(sname) \ + ASN1_ITYPE_EXTERN, \ + tag, \ + NULL, \ + 0, \ + &fptrs, \ + 0, \ + #sname \ + ASN1_ITEM_end(sname) + +/* Macro to implement standard functions in terms of ASN1_ITEM structures */ + +#define IMPLEMENT_ASN1_FUNCTIONS(stname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, stname, stname) + +#define IMPLEMENT_ASN1_FUNCTIONS_name(stname, itname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, itname) + +#define IMPLEMENT_ASN1_FUNCTIONS_ENCODE_name(stname, itname) \ + IMPLEMENT_ASN1_FUNCTIONS_ENCODE_fname(stname, itname, itname) + +#define IMPLEMENT_STATIC_ASN1_ALLOC_FUNCTIONS(stname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(static, stname, stname, stname) + +#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS(stname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, stname, stname) + +#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(pre, stname, itname, fname) \ + pre stname *fname##_new(void) \ + { \ + return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \ + } \ + pre void fname##_free(stname *a) \ + { \ + ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \ + } + +#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) \ + stname *fname##_new(void) \ + { \ + return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \ + } \ + void fname##_free(stname *a) \ + { \ + ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \ + } + +#define IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) + +#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \ + stname *d2i_##fname(stname **a, const unsigned char **in, long len) \ + { \ + return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\ + } \ + int i2d_##fname(stname *a, unsigned char **out) \ + { \ + return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\ + } + +#define IMPLEMENT_ASN1_NDEF_FUNCTION(stname) \ + int i2d_##stname##_NDEF(stname *a, unsigned char **out) \ + { \ + return ASN1_item_ndef_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(stname));\ + } + +/* This includes evil casts to remove const: they will go away when full + * ASN1 constification is done. + */ +#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \ + stname *d2i_##fname(stname **a, const unsigned char **in, long len) \ + { \ + return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\ + } \ + int i2d_##fname(const stname *a, unsigned char **out) \ + { \ + return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\ + } + +#define IMPLEMENT_ASN1_DUP_FUNCTION(stname) \ + stname * stname##_dup(stname *x) \ + { \ + return ASN1_item_dup(ASN1_ITEM_rptr(stname), x); \ + } + +#define IMPLEMENT_ASN1_PRINT_FUNCTION(stname) \ + IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, stname, stname) + +#define IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, itname, fname) \ + int fname##_print_ctx(BIO *out, stname *x, int indent, \ + const ASN1_PCTX *pctx) \ + { \ + return ASN1_item_print(out, (ASN1_VALUE *)x, indent, \ + ASN1_ITEM_rptr(itname), pctx); \ + } + +#define IMPLEMENT_ASN1_FUNCTIONS_const(name) \ + IMPLEMENT_ASN1_FUNCTIONS_const_fname(name, name, name) + +#define IMPLEMENT_ASN1_FUNCTIONS_const_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) + +/* external definitions for primitive types */ + +DECLARE_ASN1_ITEM(ASN1_BOOLEAN) +DECLARE_ASN1_ITEM(ASN1_TBOOLEAN) +DECLARE_ASN1_ITEM(ASN1_FBOOLEAN) +DECLARE_ASN1_ITEM(ASN1_SEQUENCE) +DECLARE_ASN1_ITEM(CBIGNUM) +DECLARE_ASN1_ITEM(BIGNUM) +DECLARE_ASN1_ITEM(LONG) +DECLARE_ASN1_ITEM(ZLONG) + +DECLARE_STACK_OF(ASN1_VALUE) + +/* Functions used internally by the ASN1 code */ + +int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it); +void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it); +int ASN1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); +int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it); + +void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); +int ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt); +int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx); + +int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass); +int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt); +void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it); + +int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it); +int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it); + +int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it); +int asn1_set_choice_selector(ASN1_VALUE **pval, int value, const ASN1_ITEM *it); + +ASN1_VALUE ** asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); + +const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt, int nullerr); + +void asn1_refcount_set_one(ASN1_VALUE **pval, const ASN1_ITEM *it); +int asn1_refcount_dec_and_test_zero(ASN1_VALUE **pval, const ASN1_ITEM *it); + +void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it); +void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it); +int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval, const ASN1_ITEM *it); +int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen, const ASN1_ITEM *it); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/project/jni/boringssl/include/openssl/base.h b/project/jni/boringssl/include/openssl/base.h new file mode 100644 index 000000000..47b3ccb99 --- /dev/null +++ b/project/jni/boringssl/include/openssl/base.h @@ -0,0 +1,261 @@ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_BASE_H +#define OPENSSL_HEADER_BASE_H + + +/* This file should be the first included by all BoringSSL headers. */ + +#include +#include +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#if defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) +#define OPENSSL_64_BIT +#define OPENSSL_X86_64 +#elif defined(__x86) || defined(__i386) || defined(__i386__) || defined(_M_IX86) +#define OPENSSL_32_BIT +#define OPENSSL_X86 +#elif defined(__aarch64__) +#define OPENSSL_64_BIT +#define OPENSSL_AARCH64 +#elif defined(__arm) || defined(__arm__) || defined(_M_ARM) +#define OPENSSL_32_BIT +#define OPENSSL_ARM +#elif defined(__PPC64__) || defined(__powerpc64__) +#define OPENSSL_64_BIT +#elif defined(__mips__) && !defined(__LP64__) +#define OPENSSL_32_BIT +#define OPENSSL_MIPS +#elif defined(__mips__) && defined(__LP64__) +#define OPENSSL_64_BIT +#define OPENSSL_MIPS64 +#elif defined(__pnacl__) +#define OPENSSL_32_BIT +#define OPENSSL_PNACL +#else +#error "Unknown target CPU" +#endif + +#if defined(__APPLE__) +#define OPENSSL_APPLE +#endif + +#if defined(_WIN32) +#define OPENSSL_WINDOWS +#endif + +#if defined(TRUSTY) +#define OPENSSL_TRUSTY +#define OPENSSL_NO_THREADS +#endif + +#define OPENSSL_IS_BORINGSSL +#define BORINGSSL_201510 +#define OPENSSL_VERSION_NUMBER 0x10002000 +#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER + +#if defined(BORINGSSL_SHARED_LIBRARY) + +#if defined(OPENSSL_WINDOWS) + +#if defined(BORINGSSL_IMPLEMENTATION) +#define OPENSSL_EXPORT __declspec(dllexport) +#else +#define OPENSSL_EXPORT __declspec(dllimport) +#endif + +#else /* defined(OPENSSL_WINDOWS) */ + +#if defined(BORINGSSL_IMPLEMENTATION) +#define OPENSSL_EXPORT __attribute__((visibility("default"))) +#else +#define OPENSSL_EXPORT +#endif + +#endif /* defined(OPENSSL_WINDOWS) */ + +#else /* defined(BORINGSSL_SHARED_LIBRARY) */ + +#define OPENSSL_EXPORT + +#endif /* defined(BORINGSSL_SHARED_LIBRARY) */ + +/* CRYPTO_THREADID is a dummy value. */ +typedef int CRYPTO_THREADID; + +typedef int ASN1_BOOLEAN; +typedef int ASN1_NULL; +typedef struct ASN1_ITEM_st ASN1_ITEM; +typedef struct asn1_object_st ASN1_OBJECT; +typedef struct asn1_pctx_st ASN1_PCTX; +typedef struct asn1_string_st ASN1_BIT_STRING; +typedef struct asn1_string_st ASN1_BMPSTRING; +typedef struct asn1_string_st ASN1_ENUMERATED; +typedef struct asn1_string_st ASN1_GENERALIZEDTIME; +typedef struct asn1_string_st ASN1_GENERALSTRING; +typedef struct asn1_string_st ASN1_IA5STRING; +typedef struct asn1_string_st ASN1_INTEGER; +typedef struct asn1_string_st ASN1_OCTET_STRING; +typedef struct asn1_string_st ASN1_PRINTABLESTRING; +typedef struct asn1_string_st ASN1_STRING; +typedef struct asn1_string_st ASN1_T61STRING; +typedef struct asn1_string_st ASN1_TIME; +typedef struct asn1_string_st ASN1_UNIVERSALSTRING; +typedef struct asn1_string_st ASN1_UTCTIME; +typedef struct asn1_string_st ASN1_UTF8STRING; +typedef struct asn1_string_st ASN1_VISIBLESTRING; + +typedef struct AUTHORITY_KEYID_st AUTHORITY_KEYID; +typedef struct DIST_POINT_st DIST_POINT; +typedef struct ISSUING_DIST_POINT_st ISSUING_DIST_POINT; +typedef struct NAME_CONSTRAINTS_st NAME_CONSTRAINTS; +typedef struct Netscape_certificate_sequence NETSCAPE_CERT_SEQUENCE; +typedef struct Netscape_spkac_st NETSCAPE_SPKAC; +typedef struct Netscape_spki_st NETSCAPE_SPKI; +typedef struct PBE2PARAM_st PBE2PARAM; +typedef struct PBEPARAM_st PBEPARAM; +typedef struct PBKDF2PARAM_st PBKDF2PARAM; +typedef struct X509_POLICY_CACHE_st X509_POLICY_CACHE; +typedef struct X509_POLICY_LEVEL_st X509_POLICY_LEVEL; +typedef struct X509_POLICY_NODE_st X509_POLICY_NODE; +typedef struct X509_POLICY_TREE_st X509_POLICY_TREE; +typedef struct X509_algor_st X509_ALGOR; +typedef struct X509_crl_info_st X509_CRL_INFO; +typedef struct X509_crl_st X509_CRL; +typedef struct X509_extension_st X509_EXTENSION; +typedef struct X509_info_st X509_INFO; +typedef struct X509_name_entry_st X509_NAME_ENTRY; +typedef struct X509_name_st X509_NAME; +typedef struct X509_objects_st X509_OBJECTS; +typedef struct X509_pubkey_st X509_PUBKEY; +typedef struct X509_req_info_st X509_REQ_INFO; +typedef struct X509_req_st X509_REQ; +typedef struct X509_sig_st X509_SIG; +typedef struct X509_val_st X509_VAL; +typedef struct bignum_ctx BN_CTX; +typedef struct bignum_st BIGNUM; +typedef struct bio_method_st BIO_METHOD; +typedef struct bio_st BIO; +typedef struct bn_gencb_st BN_GENCB; +typedef struct bn_mont_ctx_st BN_MONT_CTX; +typedef struct buf_mem_st BUF_MEM; +typedef struct cbb_st CBB; +typedef struct cbs_st CBS; +typedef struct cmac_ctx_st CMAC_CTX; +typedef struct conf_st CONF; +typedef struct conf_value_st CONF_VALUE; +typedef struct dh_st DH; +typedef struct dsa_st DSA; +typedef struct ec_key_st EC_KEY; +typedef struct ecdsa_method_st ECDSA_METHOD; +typedef struct ecdsa_sig_st ECDSA_SIG; +typedef struct engine_st ENGINE; +typedef struct env_md_ctx_st EVP_MD_CTX; +typedef struct env_md_st EVP_MD; +typedef struct evp_aead_st EVP_AEAD; +typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX; +typedef struct evp_cipher_st EVP_CIPHER; +typedef struct evp_encode_ctx_st EVP_ENCODE_CTX; +typedef struct evp_pkey_asn1_method_st EVP_PKEY_ASN1_METHOD; +typedef struct evp_pkey_ctx_st EVP_PKEY_CTX; +typedef struct evp_pkey_method_st EVP_PKEY_METHOD; +typedef struct evp_pkey_st EVP_PKEY; +typedef struct hmac_ctx_st HMAC_CTX; +typedef struct md4_state_st MD4_CTX; +typedef struct md5_state_st MD5_CTX; +typedef struct pkcs12_st PKCS12; +typedef struct pkcs8_priv_key_info_st PKCS8_PRIV_KEY_INFO; +typedef struct private_key_st X509_PKEY; +typedef struct rand_meth_st RAND_METHOD; +typedef struct rc4_key_st RC4_KEY; +typedef struct rsa_meth_st RSA_METHOD; +typedef struct rsa_st RSA; +typedef struct sha256_state_st SHA256_CTX; +typedef struct sha512_state_st SHA512_CTX; +typedef struct sha_state_st SHA_CTX; +typedef struct srtp_protection_profile_st SRTP_PROTECTION_PROFILE; +typedef struct ssl_cipher_st SSL_CIPHER; +typedef struct ssl_ctx_st SSL_CTX; +typedef struct ssl_custom_extension SSL_CUSTOM_EXTENSION; +typedef struct ssl_method_st SSL_METHOD; +typedef struct ssl_session_st SSL_SESSION; +typedef struct ssl_st SSL; +typedef struct st_ERR_FNS ERR_FNS; +typedef struct v3_ext_ctx X509V3_CTX; +typedef struct x509_attributes_st X509_ATTRIBUTE; +typedef struct x509_cert_aux_st X509_CERT_AUX; +typedef struct x509_cert_pair_st X509_CERT_PAIR; +typedef struct x509_cinf_st X509_CINF; +typedef struct x509_crl_method_st X509_CRL_METHOD; +typedef struct x509_revoked_st X509_REVOKED; +typedef struct x509_st X509; +typedef struct x509_store_ctx_st X509_STORE_CTX; +typedef struct x509_store_st X509_STORE; +typedef struct x509_trust_st X509_TRUST; + +typedef void *OPENSSL_BLOCK; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BASE_H */ diff --git a/project/jni/boringssl/include/openssl/base64.h b/project/jni/boringssl/include/openssl/base64.h new file mode 100644 index 000000000..f28e7ddb5 --- /dev/null +++ b/project/jni/boringssl/include/openssl/base64.h @@ -0,0 +1,184 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BASE64_H +#define OPENSSL_HEADER_BASE64_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* base64 functions. + * + * For historical reasons, these functions have the EVP_ prefix but just do + * base64 encoding and decoding. */ + + +/* Encoding */ + +/* EVP_EncodeBlock encodes |src_len| bytes from |src| and writes the + * result to |dst| with a trailing NUL. It returns the number of bytes + * written, not including this trailing NUL. */ +OPENSSL_EXPORT size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, + size_t src_len); + +/* EVP_EncodedLength sets |*out_len| to the number of bytes that will be needed + * to call |EVP_EncodeBlock| on an input of length |len|. This includes the + * final NUL that |EVP_EncodeBlock| writes. It returns one on success or zero + * on error. */ +OPENSSL_EXPORT int EVP_EncodedLength(size_t *out_len, size_t len); + + +/* Decoding */ + +/* EVP_DecodedLength sets |*out_len| to the maximum number of bytes + * that will be needed to call |EVP_DecodeBase64| on an input of + * length |len|. */ +OPENSSL_EXPORT int EVP_DecodedLength(size_t *out_len, size_t len); + +/* EVP_DecodeBase64 decodes |in_len| bytes from base64 and writes + * |*out_len| bytes to |out|. |max_out| is the size of the output + * buffer. If it is not enough for the maximum output size, the + * operation fails. */ +OPENSSL_EXPORT int EVP_DecodeBase64(uint8_t *out, size_t *out_len, + size_t max_out, const uint8_t *in, + size_t in_len); + + +/* Deprecated functions. + * + * OpenSSL provides a streaming base64 implementation, however its behavior is + * very specific to PEM. It is also very lenient of invalid input. Use of any of + * these functions is thus deprecated. + * + * TODO(davidben): Import upstream's rewrite that rejects the invalid input. */ + +/* EVP_EncodeInit initialises |*ctx|, which is typically stack + * allocated, for an encoding operation. + * + * NOTE: The encoding operation breaks its output with newlines every + * 64 characters of output (48 characters of input). Use + * EVP_EncodeBlock to encode raw base64. */ +OPENSSL_EXPORT void EVP_EncodeInit(EVP_ENCODE_CTX *ctx); + +/* EVP_EncodeUpdate encodes |in_len| bytes from |in| and writes an encoded + * version of them to |out| and sets |*out_len| to the number of bytes written. + * Some state may be contained in |ctx| so |EVP_EncodeFinal| must be used to + * flush it before using the encoded data. */ +OPENSSL_EXPORT void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, + int *out_len, const uint8_t *in, + size_t in_len); + +/* EVP_EncodeFinal flushes any remaining output bytes from |ctx| to |out| and + * sets |*out_len| to the number of bytes written. */ +OPENSSL_EXPORT void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, + int *out_len); + +/* EVP_DecodeInit initialises |*ctx|, which is typically stack allocated, for + * a decoding operation. + * + * TODO(davidben): This isn't a straight-up base64 decode either. Document + * and/or fix exactly what's going on here; maximum line length and such. */ +OPENSSL_EXPORT void EVP_DecodeInit(EVP_ENCODE_CTX *ctx); + +/* EVP_DecodeUpdate decodes |in_len| bytes from |in| and writes the decoded + * data to |out| and sets |*out_len| to the number of bytes written. Some state + * may be contained in |ctx| so |EVP_DecodeFinal| must be used to flush it + * before using the encoded data. + * + * It returns -1 on error, one if a full line of input was processed and zero + * if the line was short (i.e. it was the last line). */ +OPENSSL_EXPORT int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, + int *out_len, const uint8_t *in, + size_t in_len); + +/* EVP_DecodeFinal flushes any remaining output bytes from |ctx| to |out| and + * sets |*out_len| to the number of bytes written. It returns one on success + * and minus one on error. */ +OPENSSL_EXPORT int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, + int *out_len); + +/* EVP_DecodeBlock encodes |src_len| bytes from |src| and writes the result to + * |dst|. It returns the number of bytes written or -1 on error. + * + * WARNING: EVP_DecodeBlock's return value does not take padding into + * account. It also strips leading whitespace and trailing + * whitespace. */ +OPENSSL_EXPORT int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, + size_t src_len); + + +struct evp_encode_ctx_st { + unsigned num; /* number saved in a partial encode/decode */ + unsigned length; /* The length is either the output line length + * (in input bytes) or the shortest input line + * length that is ok. Once decoding begins, + * the length is adjusted up each time a longer + * line is decoded */ + uint8_t enc_data[80]; /* data to encode */ + unsigned line_num; /* number read on current line */ + int expect_nl; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BASE64_H */ diff --git a/project/jni/boringssl/include/openssl/bio.h b/project/jni/boringssl/include/openssl/bio.h new file mode 100644 index 000000000..c88a3e187 --- /dev/null +++ b/project/jni/boringssl/include/openssl/bio.h @@ -0,0 +1,902 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BIO_H +#define OPENSSL_HEADER_BIO_H + +#include + +#include /* For FILE */ + +#include /* for ERR_print_errors_fp */ +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* BIO abstracts over a file-descriptor like interface. */ + + +/* Allocation and freeing. */ + +/* BIO_new creates a new BIO with the given type and a reference count of one. + * It returns the fresh |BIO|, or NULL on error. */ +OPENSSL_EXPORT BIO *BIO_new(const BIO_METHOD *type); + +/* BIO_free decrements the reference count of |bio|. If the reference count + * drops to zero, it (optionally) calls the BIO's callback with |BIO_CB_FREE|, + * frees the ex_data and then, if the BIO has a destroy callback for the + * method, calls it. Finally it frees |bio| itself. It then repeats that for + * the next BIO in the chain, if any. + * + * It returns one on success or zero otherwise. */ +OPENSSL_EXPORT int BIO_free(BIO *bio); + +/* BIO_vfree performs the same actions as |BIO_free|, but has a void return + * value. This is provided for API-compat. + * + * TODO(fork): remove. */ +OPENSSL_EXPORT void BIO_vfree(BIO *bio); + +/* BIO_up_ref increments the reference count of |bio| and returns it. */ +OPENSSL_EXPORT BIO *BIO_up_ref(BIO *bio); + + +/* Basic I/O. */ + +/* BIO_read attempts to read |len| bytes into |data|. It returns the number of + * bytes read, zero on EOF, or a negative number on error. */ +OPENSSL_EXPORT int BIO_read(BIO *bio, void *data, int len); + +/* BIO_gets "reads a line" from |bio| and puts at most |size| bytes into |buf|. + * It returns the number of bytes read or a negative number on error. The + * phrase "reads a line" is in quotes in the previous sentence because the + * exact operation depends on the BIO's method. For example, a digest BIO will + * return the digest in response to a |BIO_gets| call. + * + * TODO(fork): audit the set of BIOs that we end up needing. If all actually + * return a line for this call, remove the warning above. */ +OPENSSL_EXPORT int BIO_gets(BIO *bio, char *buf, int size); + +/* BIO_write writes |len| bytes from |data| to BIO. It returns the number of + * bytes written or a negative number on error. */ +OPENSSL_EXPORT int BIO_write(BIO *bio, const void *data, int len); + +/* BIO_puts writes a NUL terminated string from |buf| to |bio|. It returns the + * number of bytes written or a negative number on error. */ +OPENSSL_EXPORT int BIO_puts(BIO *bio, const char *buf); + +/* BIO_flush flushes any buffered output. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int BIO_flush(BIO *bio); + + +/* Low-level control functions. + * + * These are generic functions for sending control requests to a BIO. In + * general one should use the wrapper functions like |BIO_get_close|. */ + +/* BIO_ctrl sends the control request |cmd| to |bio|. The |cmd| argument should + * be one of the |BIO_C_*| values. */ +OPENSSL_EXPORT long BIO_ctrl(BIO *bio, int cmd, long larg, void *parg); + +/* BIO_ptr_ctrl acts like |BIO_ctrl| but passes the address of a |void*| + * pointer as |parg| and returns the value that is written to it, or NULL if + * the control request returns <= 0. */ +OPENSSL_EXPORT char *BIO_ptr_ctrl(BIO *bp, int cmd, long larg); + +/* BIO_int_ctrl acts like |BIO_ctrl| but passes the address of a copy of |iarg| + * as |parg|. */ +OPENSSL_EXPORT long BIO_int_ctrl(BIO *bp, int cmd, long larg, int iarg); + +/* BIO_reset resets |bio| to its initial state, the precise meaning of which + * depends on the concrete type of |bio|. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int BIO_reset(BIO *bio); + +/* BIO_set_flags ORs |flags| with |bio->flags|. */ +OPENSSL_EXPORT void BIO_set_flags(BIO *bio, int flags); + +/* BIO_test_flags returns |bio->flags| AND |flags|. */ +OPENSSL_EXPORT int BIO_test_flags(const BIO *bio, int flags); + +/* BIO_should_read returns non-zero if |bio| encountered a temporary error + * while reading (i.e. EAGAIN), indicating that the caller should retry the + * read. */ +OPENSSL_EXPORT int BIO_should_read(const BIO *bio); + +/* BIO_should_write returns non-zero if |bio| encountered a temporary error + * while writing (i.e. EAGAIN), indicating that the caller should retry the + * write. */ +OPENSSL_EXPORT int BIO_should_write(const BIO *bio); + +/* BIO_should_retry returns non-zero if the reason that caused a failed I/O + * operation is temporary and thus the operation should be retried. Otherwise, + * it was a permanent error and it returns zero. */ +OPENSSL_EXPORT int BIO_should_retry(const BIO *bio); + +/* BIO_should_io_special returns non-zero if |bio| encountered a temporary + * error while performing a special I/O operation, indicating that the caller + * should retry. The operation that caused the error is returned by + * |BIO_get_retry_reason|. */ +OPENSSL_EXPORT int BIO_should_io_special(const BIO *bio); + +/* BIO_RR_SSL_X509_LOOKUP indicates that an SSL BIO blocked because the SSL + * library returned with SSL_ERROR_WANT_X509_LOOKUP. + * + * TODO(fork): remove. */ +#define BIO_RR_SSL_X509_LOOKUP 0x01 + +/* BIO_RR_CONNECT indicates that a connect would have blocked */ +#define BIO_RR_CONNECT 0x02 + +/* BIO_RR_ACCEPT indicates that an accept would have blocked */ +#define BIO_RR_ACCEPT 0x03 + +/* BIO_RR_SSL_CHANNEL_ID_LOOKUP indicates that the ChannelID code cannot find + * a private key for a TLS connection. */ +#define BIO_RR_SSL_CHANNEL_ID_LOOKUP 0x04 + +/* BIO_get_retry_reason returns the special I/O operation that needs to be + * retried. The return value is one of the |BIO_RR_*| values. */ +OPENSSL_EXPORT int BIO_get_retry_reason(const BIO *bio); + +/* BIO_clear_flags ANDs |bio->flags| with the bitwise-complement of |flags|. */ +OPENSSL_EXPORT void BIO_clear_flags(BIO *bio, int flags); + +/* BIO_set_retry_read sets the |BIO_FLAGS_READ| and |BIO_FLAGS_SHOULD_RETRY| + * flags on |bio|. */ +OPENSSL_EXPORT void BIO_set_retry_read(BIO *bio); + +/* BIO_set_retry_write sets the |BIO_FLAGS_WRITE| and |BIO_FLAGS_SHOULD_RETRY| + * flags on |bio|. */ +OPENSSL_EXPORT void BIO_set_retry_write(BIO *bio); + +/* BIO_get_retry_flags gets the |BIO_FLAGS_READ|, |BIO_FLAGS_WRITE|, + * |BIO_FLAGS_IO_SPECIAL| and |BIO_FLAGS_SHOULD_RETRY| flags from |bio|. */ +OPENSSL_EXPORT int BIO_get_retry_flags(BIO *bio); + +/* BIO_clear_retry_flags clears the |BIO_FLAGS_READ|, |BIO_FLAGS_WRITE|, + * |BIO_FLAGS_IO_SPECIAL| and |BIO_FLAGS_SHOULD_RETRY| flags from |bio|. */ +OPENSSL_EXPORT void BIO_clear_retry_flags(BIO *bio); + +/* BIO_method_type returns the type of |bio|, which is one of the |BIO_TYPE_*| + * values. */ +OPENSSL_EXPORT int BIO_method_type(const BIO *bio); + +/* bio_info_cb is the type of a callback function that can be called for most + * BIO operations. The |event| argument is one of |BIO_CB_*| and can be ORed + * with |BIO_CB_RETURN| if the callback is being made after the operation in + * question. In that case, |return_value| will contain the return value from + * the operation. */ +typedef long (*bio_info_cb)(BIO *bio, int event, const char *parg, int cmd, + long larg, long return_value); + +/* BIO_callback_ctrl allows the callback function to be manipulated. The |cmd| + * arg will generally be |BIO_CTRL_SET_CALLBACK| but arbitary command values + * can be interpreted by the |BIO|. */ +OPENSSL_EXPORT long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp); + +/* BIO_pending returns the number of bytes pending to be read. */ +OPENSSL_EXPORT size_t BIO_pending(const BIO *bio); + +/* BIO_ctrl_pending calls |BIO_pending| and exists only for compatibility with + * OpenSSL. */ +OPENSSL_EXPORT size_t BIO_ctrl_pending(const BIO *bio); + +/* BIO_wpending returns the number of bytes pending to be written. */ +OPENSSL_EXPORT size_t BIO_wpending(const BIO *bio); + +/* BIO_set_close sets the close flag for |bio|. The meaning of which depends on + * the type of |bio| but, for example, a memory BIO interprets the close flag + * as meaning that it owns its buffer. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int BIO_set_close(BIO *bio, int close_flag); + +/* BIO_set_callback sets a callback function that will be called before and + * after most operations. See the comment above |bio_info_cb|. */ +OPENSSL_EXPORT void BIO_set_callback(BIO *bio, bio_info_cb callback_func); + +/* BIO_set_callback_arg sets the opaque pointer value that can be read within a + * callback with |BIO_get_callback_arg|. */ +OPENSSL_EXPORT void BIO_set_callback_arg(BIO *bio, char *arg); + +/* BIO_get_callback_arg returns the last value of the opaque callback pointer + * set by |BIO_set_callback_arg|. */ +OPENSSL_EXPORT char *BIO_get_callback_arg(const BIO *bio); + +/* BIO_number_read returns the number of bytes that have been read from + * |bio|. */ +OPENSSL_EXPORT size_t BIO_number_read(const BIO *bio); + +/* BIO_number_written returns the number of bytes that have been written to + * |bio|. */ +OPENSSL_EXPORT size_t BIO_number_written(const BIO *bio); + + +/* Managing chains of BIOs. + * + * BIOs can be put into chains where the output of one is used as the input of + * the next etc. The most common case is a buffering BIO, which accepts and + * buffers writes until flushed into the next BIO in the chain. */ + +/* BIO_push adds |appended_bio| to the end of the chain with |bio| at the head. + * It returns |bio|. Note that |appended_bio| may be the head of a chain itself + * and thus this function can be used to join two chains. + * + * BIO_push takes ownership of the caller's reference to |appended_bio|. */ +OPENSSL_EXPORT BIO *BIO_push(BIO *bio, BIO *appended_bio); + +/* BIO_pop removes |bio| from the head of a chain and returns the next BIO in + * the chain, or NULL if there is no next BIO. + * + * The caller takes ownership of the chain's reference to |bio|. */ +OPENSSL_EXPORT BIO *BIO_pop(BIO *bio); + +/* BIO_next returns the next BIO in the chain after |bio|, or NULL if there is + * no such BIO. */ +OPENSSL_EXPORT BIO *BIO_next(BIO *bio); + +/* BIO_free_all calls |BIO_free|. + * + * TODO(fork): update callers and remove. */ +OPENSSL_EXPORT void BIO_free_all(BIO *bio); + +/* BIO_find_type walks a chain of BIOs and returns the first that matches + * |type|, which is one of the |BIO_TYPE_*| values. */ +OPENSSL_EXPORT BIO *BIO_find_type(BIO *bio, int type); + +/* BIO_copy_next_retry sets the retry flags and |retry_reason| of |bio| from + * the next BIO in the chain. */ +OPENSSL_EXPORT void BIO_copy_next_retry(BIO *bio); + + +/* Printf functions. + * + * These functions are versions of printf functions that output to a BIO rather + * than a FILE. */ +#ifdef __GNUC__ +#define __bio_h__attr__ __attribute__ +#else +#define __bio_h__attr__(x) +#endif +OPENSSL_EXPORT int BIO_printf(BIO *bio, const char *format, ...) + __bio_h__attr__((__format__(__printf__, 2, 3))); +#undef __bio_h__attr__ + + +/* Utility functions. */ + +/* BIO_indent prints min(|indent|, |max_indent|) spaces. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int BIO_indent(BIO *bio, unsigned indent, unsigned max_indent); + +/* BIO_hexdump writes a hex dump of |data| to |bio|. Each line will be indented + * by |indent| spaces. */ +OPENSSL_EXPORT int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len, + unsigned indent); + +/* BIO_print_errors prints the current contents of the error stack to |bio| + * using human readable strings where possible. */ +OPENSSL_EXPORT void BIO_print_errors(BIO *bio); + +/* BIO_read_asn1 reads a single ASN.1 object from |bio|. If successful it sets + * |*out| to be an allocated buffer (that should be freed with |OPENSSL_free|), + * |*out_size| to the length, in bytes, of that buffer and returns one. + * Otherwise it returns zero. + * + * If the length of the object is greater than |max_len| or 2^32 then the + * function will fail. Long-form tags are not supported. If the length of the + * object is indefinite the full contents of |bio| are read, unless it would be + * greater than |max_len|, in which case the function fails. + * + * If the function fails then some unknown amount of data may have been read + * from |bio|. */ +OPENSSL_EXPORT int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, + size_t max_len); + + +/* Memory BIOs. + * + * Memory BIOs can be used as a read-only source (with |BIO_new_mem_buf|) or a + * writable sink (with |BIO_new|, |BIO_s_mem| and |BIO_get_mem_buf|). Data + * written to a writable, memory BIO can be recalled by reading from it. + * + * Calling |BIO_reset| on a read-only BIO resets it to the original contents. + * On a writable BIO, it clears any data. + * + * If the close flag is set to |BIO_NOCLOSE| (not the default) then the + * underlying |BUF_MEM| will not be freed when the |BIO| is freed. + * + * Memory BIOs support |BIO_gets| and |BIO_puts|. + * + * |BIO_eof| is true if no data is in the BIO. + * + * |BIO_ctrl_pending| returns the number of bytes currently stored. */ + +/* BIO_s_mem returns a |BIO_METHOD| that uses a in-memory buffer. */ +OPENSSL_EXPORT const BIO_METHOD *BIO_s_mem(void); + +/* BIO_new_mem_buf creates BIO that reads and writes from |len| bytes at |buf|. + * It does not take ownership of |buf|. It returns the BIO or NULL on error. + * + * If |len| is negative, then |buf| is treated as a NUL-terminated string, but + * don't depend on this in new code. */ +OPENSSL_EXPORT BIO *BIO_new_mem_buf(void *buf, int len); + +/* BIO_mem_contents sets |*out_contents| to point to the current contents of + * |bio| and |*out_len| to contain the length of that data. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int BIO_mem_contents(const BIO *bio, + const uint8_t **out_contents, + size_t *out_len); + +/* BIO_get_mem_data sets |*contents| to point to the current contents of |bio| + * and returns the length of the data. + * + * WARNING: don't use this, use |BIO_mem_contents|. A return value of zero from + * this function can mean either that it failed or that the memory buffer is + * empty. */ +OPENSSL_EXPORT long BIO_get_mem_data(BIO *bio, char **contents); + +/* BIO_get_mem_ptr sets |*out| to a BUF_MEM containing the current contents of + * |bio|. It returns one on success or zero on error. */ +OPENSSL_EXPORT int BIO_get_mem_ptr(BIO *bio, BUF_MEM **out); + +/* BIO_set_mem_buf sets |b| as the contents of |bio|. If |take_ownership| is + * non-zero, then |b| will be freed when |bio| is closed. Returns one on + * success or zero otherwise. */ +OPENSSL_EXPORT int BIO_set_mem_buf(BIO *bio, BUF_MEM *b, int take_ownership); + +/* BIO_set_mem_eof_return sets the value that will be returned from reading + * |bio| when empty. If |eof_value| is zero then an empty memory BIO will + * return EOF (that is it will return zero and |BIO_should_retry| will be + * false). If |eof_value| is non zero then it will return |eof_value| when it + * is empty and it will set the read retry flag (that is |BIO_read_retry| is + * true). To avoid ambiguity with a normal positive return value, |eof_value| + * should be set to a negative value, typically -1. + * + * For a read-only BIO, the default is zero (EOF). For a writable BIO, the + * default is -1 so that additional data can be written once exhausted. */ +OPENSSL_EXPORT int BIO_set_mem_eof_return(BIO *bio, int eof_value); + + +/* File descriptor BIOs. + * + * File descriptor BIOs are wrappers around the system's |read| and |write| + * functions. If the close flag is set then then |close| is called on the + * underlying file descriptor when the BIO is freed. + * + * |BIO_reset| attempts to seek the file pointer to the start of file using + * |lseek|. + * + * |BIO_seek| sets the file pointer to position |off| from start of file using + * |lseek|. + * + * |BIO_tell| returns the current file position. */ + +/* BIO_s_fd returns a |BIO_METHOD| for file descriptor fds. */ +OPENSSL_EXPORT const BIO_METHOD *BIO_s_fd(void); + +/* BIO_new_fd creates a new file descriptor BIO wrapping |fd|. If |close_flag| + * is non-zero, then |fd| will be closed when the BIO is. */ +OPENSSL_EXPORT BIO *BIO_new_fd(int fd, int close_flag); + +/* BIO_set_fd sets the file descriptor of |bio| to |fd|. If |close_flag| is + * non-zero then |fd| will be closed when |bio| is. It returns one on success + * or zero on error. */ +OPENSSL_EXPORT int BIO_set_fd(BIO *bio, int fd, int close_flag); + +/* BIO_get_fd returns the file descriptor currently in use by |bio| or -1 if + * |bio| does not wrap a file descriptor. If there is a file descriptor and + * |out_fd| is not NULL, it also sets |*out_fd| to the file descriptor. */ +OPENSSL_EXPORT int BIO_get_fd(BIO *bio, int *out_fd); + + +/* File BIOs. + * + * File BIOs are wrappers around a C |FILE| object. + * + * |BIO_flush| on a file BIO calls |fflush| on the wrapped stream. + * + * |BIO_reset| attempts to seek the file pointer to the start of file using + * |fseek|. + * + * |BIO_seek| sets the file pointer to the given position from the start of + * file using |fseek|. + * + * |BIO_eof| calls |feof|. + * + * Setting the close flag causes |fclose| to be called on the stream when the + * BIO is freed. */ + +/* BIO_s_file returns a BIO_METHOD that wraps a |FILE|. */ +OPENSSL_EXPORT const BIO_METHOD *BIO_s_file(void); + +/* BIO_new_file creates a file BIO by opening |filename| with the given mode. + * See the |fopen| manual page for details of the mode argument. */ +OPENSSL_EXPORT BIO *BIO_new_file(const char *filename, const char *mode); + +/* BIO_new_fp creates a new file BIO that wraps the given |FILE|. If + * |close_flag| is |BIO_CLOSE|, then |fclose| will be called on |stream| when + * the BIO is closed. */ +OPENSSL_EXPORT BIO *BIO_new_fp(FILE *stream, int close_flag); + +/* BIO_get_fp sets |*out_file| to the current |FILE| for |bio|. It returns one + * on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_get_fp(BIO *bio, FILE **out_file); + +/* BIO_set_fp sets the |FILE| for |bio|. If |close_flag| is |BIO_CLOSE| then + * |fclose| will be called on |file| when |bio| is closed. It returns one on + * sucess and zero otherwise. */ +OPENSSL_EXPORT int BIO_set_fp(BIO *bio, FILE *file, int close_flag); + +/* BIO_read_filename opens |filename| for reading and sets the result as the + * |FILE| for |bio|. It returns one on success and zero otherwise. The |FILE| + * will be closed when |bio| is freed. */ +OPENSSL_EXPORT int BIO_read_filename(BIO *bio, const char *filename); + +/* BIO_write_filename opens |filename| for writing and sets the result as the + * |FILE| for |bio|. It returns one on success and zero otherwise. The |FILE| + * will be closed when |bio| is freed. */ +OPENSSL_EXPORT int BIO_write_filename(BIO *bio, const char *filename); + +/* BIO_append_filename opens |filename| for appending and sets the result as + * the |FILE| for |bio|. It returns one on success and zero otherwise. The + * |FILE| will be closed when |bio| is freed. */ +OPENSSL_EXPORT int BIO_append_filename(BIO *bio, const char *filename); + +/* BIO_rw_filename opens |filename| for reading and writing and sets the result + * as the |FILE| for |bio|. It returns one on success and zero otherwise. The + * |FILE| will be closed when |bio| is freed. */ +OPENSSL_EXPORT int BIO_rw_filename(BIO *bio, const char *filename); + + +/* Buffer BIOs. + * + * Buffer BIOs are a filter-type BIO, i.e. they are designed to be used in a + * chain of BIOs. They provide buffering to reduce the number of operations on + * the underlying BIOs. */ + +OPENSSL_EXPORT const BIO_METHOD *BIO_f_buffer(void); + +/* BIO_set_read_buffer_size sets the size, in bytes, of the read buffer and + * clears it. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int BIO_set_read_buffer_size(BIO *bio, int buffer_size); + +/* BIO_set_write_buffer_size sets the size, in bytes, of the write buffer and + * clears it. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int BIO_set_write_buffer_size(BIO *bio, int buffer_size); + + +/* Socket BIOs. */ + +OPENSSL_EXPORT const BIO_METHOD *BIO_s_socket(void); + +/* BIO_new_socket allocates and initialises a fresh BIO which will read and + * write to the socket |fd|. If |close_flag| is |BIO_CLOSE| then closing the + * BIO will close |fd|. It returns the fresh |BIO| or NULL on error. */ +OPENSSL_EXPORT BIO *BIO_new_socket(int fd, int close_flag); + + +/* Connect BIOs. + * + * A connection BIO creates a network connection and transfers data over the + * resulting socket. */ + +OPENSSL_EXPORT const BIO_METHOD *BIO_s_connect(void); + +/* BIO_new_connect returns a BIO that connects to the given hostname and port. + * The |host_and_optional_port| argument should be of the form + * "www.example.com" or "www.example.com:443". If the port is omitted, it must + * be provided with |BIO_set_conn_port|. + * + * It returns the new BIO on success, or NULL on error. */ +OPENSSL_EXPORT BIO *BIO_new_connect(const char *host_and_optional_port); + +/* BIO_set_conn_hostname sets |host_and_optional_port| as the hostname and + * optional port that |bio| will connect to. If the port is omitted, it must be + * provided with |BIO_set_conn_port|. + * + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_set_conn_hostname(BIO *bio, + const char *host_and_optional_port); + +/* BIO_set_conn_port sets |port_str| as the port or service name that |bio| + * will connect to. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_set_conn_port(BIO *bio, const char *port_str); + +/* BIO_set_nbio sets whether |bio| will use non-blocking I/O operations. It + * returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_set_nbio(BIO *bio, int on); + + +/* Datagram BIOs. + * + * TODO(fork): not implemented. */ + +#define BIO_CTRL_DGRAM_QUERY_MTU 40 /* as kernel for current MTU */ + +#define BIO_CTRL_DGRAM_SET_MTU 42 /* set cached value for MTU. want to use + this if asking the kernel fails */ + +#define BIO_CTRL_DGRAM_MTU_EXCEEDED 43 /* check whether the MTU was exceed in + the previous write operation. */ + +#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT \ + 45 /* Next DTLS handshake timeout to adjust socket timeouts */ + +#define BIO_CTRL_DGRAM_GET_PEER 46 + +#define BIO_CTRL_DGRAM_GET_FALLBACK_MTU 47 + + +/* BIO Pairs. + * + * BIO pairs provide a "loopback" like system: a pair of BIOs where data + * written to one can be read from the other and vice versa. */ + +/* BIO_new_bio_pair sets |*out1| and |*out2| to two freshly created BIOs where + * data written to one can be read from the other and vice versa. The + * |writebuf1| argument gives the size of the buffer used in |*out1| and + * |writebuf2| for |*out2|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int BIO_new_bio_pair(BIO **out1, size_t writebuf1, BIO **out2, + size_t writebuf2); + +/* BIO_new_bio_pair_external_buf is the same as |BIO_new_bio_pair| with the + * difference that the caller keeps ownership of the write buffers + * |ext_writebuf1_len| and |ext_writebuf2_len|. This is useful when using zero + * copy API for read and write operations, in cases where the buffers need to + * outlive the BIO pairs. It returns one on success and zero on error. */ +OPENSSL_EXPORT int BIO_new_bio_pair_external_buf(BIO** bio1_p, + size_t writebuf1_len, + uint8_t* ext_writebuf1, + BIO** bio2_p, + size_t writebuf2_len, + uint8_t* ext_writebuf2); + +/* BIO_ctrl_get_read_request returns the number of bytes that the other side of + * |bio| tried (unsuccessfully) to read. */ +OPENSSL_EXPORT size_t BIO_ctrl_get_read_request(BIO *bio); + +/* BIO_ctrl_get_write_guarantee returns the number of bytes that |bio| (which + * must have been returned by |BIO_new_bio_pair|) will accept on the next + * |BIO_write| call. */ +OPENSSL_EXPORT size_t BIO_ctrl_get_write_guarantee(BIO *bio); + +/* BIO_shutdown_wr marks |bio| as closed, from the point of view of the other + * side of the pair. Future |BIO_write| calls on |bio| will fail. It returns + * one on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_shutdown_wr(BIO *bio); + + +/* Zero copy versions of BIO_read and BIO_write for BIO pairs. */ + +/* BIO_zero_copy_get_read_buf initiates a zero copy read operation. + * |out_read_buf| is set to the internal read buffer, and |out_buf_offset| is + * set to the current read position of |out_read_buf|. The number of bytes + * available for read from |out_read_buf| + |out_buf_offset| is returned in + * |out_available_bytes|. Note that this function might report fewer bytes + * available than |BIO_pending|, if the internal ring buffer is wrapped. It + * returns one on success. In case of error it returns zero and pushes to the + * error stack. + * + * The zero copy read operation is completed by calling + * |BIO_zero_copy_get_read_buf_done|. Neither |BIO_zero_copy_get_read_buf| nor + * any other I/O read operation may be called while a zero copy read operation + * is active. */ +OPENSSL_EXPORT int BIO_zero_copy_get_read_buf(BIO* bio, + uint8_t** out_read_buf, + size_t* out_buf_offset, + size_t* out_available_bytes); + +/* BIO_zero_copy_get_read_buf_done must be called after reading from a BIO using + * |BIO_zero_copy_get_read_buf| to finish the read operation. The |bytes_read| + * argument is the number of bytes read. + * + * It returns one on success. In case of error it returns zero and pushes to the + * error stack. */ +OPENSSL_EXPORT int BIO_zero_copy_get_read_buf_done(BIO* bio, size_t bytes_read); + +/* BIO_zero_copy_get_write_buf initiates a zero copy write operation. + * |out_write_buf| is set to to the internal write buffer, and |out_buf_offset| + * is set to the current write position of |out_write_buf|. + * The number of bytes available for write from |out_write_buf| + + * |out_buf_offset| is returned in |out_available_bytes|. Note that this + * function might report fewer bytes available than + * |BIO_ctrl_get_write_guarantee|, if the internal buffer is wrapped. It returns + * one on success. In case of error it returns zero and pushes to the error + * stack. + * + * The zero copy write operation is completed by calling + * |BIO_zero_copy_get_write_buf_done|. Neither |BIO_zero_copy_get_write_buf| + * nor any other I/O write operation may be called while a zero copy write + * operation is active. */ +OPENSSL_EXPORT int BIO_zero_copy_get_write_buf(BIO* bio, + uint8_t** out_write_buf, + size_t* out_buf_offset, + size_t* out_available_bytes); + +/* BIO_zero_copy_get_write_buf_done must be called after writing to a BIO using + * |BIO_zero_copy_get_write_buf| to finish the write operation. The + * |bytes_written| argument gives the number of bytes written. + * + * It returns one on success. In case of error it returns zero and pushes to the + * error stack. */ +OPENSSL_EXPORT int BIO_zero_copy_get_write_buf_done(BIO* bio, + size_t bytes_written); + + +/* BIO_NOCLOSE and |BIO_CLOSE| can be used as symbolic arguments when a "close + * flag" is passed to a BIO function. */ +#define BIO_NOCLOSE 0 +#define BIO_CLOSE 1 + +/* These are passed to the BIO callback */ +#define BIO_CB_FREE 0x01 +#define BIO_CB_READ 0x02 +#define BIO_CB_WRITE 0x03 +#define BIO_CB_PUTS 0x04 +#define BIO_CB_GETS 0x05 +#define BIO_CB_CTRL 0x06 + +/* The callback is called before and after the underling operation, + * The BIO_CB_RETURN flag indicates if it is after the call */ +#define BIO_CB_RETURN 0x80 + +/* These are values of the |cmd| argument to |BIO_ctrl|. */ +#define BIO_CTRL_RESET 1 /* opt - rewind/zero etc */ +#define BIO_CTRL_EOF 2 /* opt - are we at the eof */ +#define BIO_CTRL_INFO 3 /* opt - extra tit-bits */ +#define BIO_CTRL_SET 4 /* man - set the 'IO' type */ +#define BIO_CTRL_GET 5 /* man - get the 'IO' type */ +#define BIO_CTRL_GET_CLOSE 8 /* man - set the 'close' on free */ +#define BIO_CTRL_SET_CLOSE 9 /* man - set the 'close' on free */ +#define BIO_CTRL_PENDING 10 /* opt - is their more data buffered */ +#define BIO_CTRL_FLUSH 11 /* opt - 'flush' buffered output */ +#define BIO_CTRL_WPENDING 13 /* opt - number of bytes still to write */ +/* callback is int cb(BIO *bio,state,ret); */ +#define BIO_CTRL_SET_CALLBACK 14 /* opt - set callback function */ +#define BIO_CTRL_GET_CALLBACK 15 /* opt - set callback function */ +#define BIO_CTRL_SET_FILENAME 30 /* BIO_s_file special */ + + +/* Android compatibility section. + * + * A previous version of BoringSSL used in Android renamed ERR_print_errors_fp + * to BIO_print_errors_fp. It has subsequently been renamed back to + * ERR_print_errors_fp. */ +#define BIO_print_errors_fp ERR_print_errors_fp + + +/* Deprecated functions. */ + +/* BIO_f_base64 returns a filter |BIO| that base64-encodes data written into + * it, and decodes data read from it. |BIO_gets| is not supported. Call + * |BIO_flush| when done writing, to signal that no more data are to be + * encoded. The flag |BIO_FLAGS_BASE64_NO_NL| may be set to encode all the data + * on one line. */ +OPENSSL_EXPORT const BIO_METHOD *BIO_f_base64(void); + +/* ERR_print_errors is an alias for |BIO_print_errors|. */ +OPENSSL_EXPORT void ERR_print_errors(BIO *bio); + + +/* Private functions */ + +#define BIO_FLAGS_READ 0x01 +#define BIO_FLAGS_WRITE 0x02 +#define BIO_FLAGS_IO_SPECIAL 0x04 +#define BIO_FLAGS_RWS (BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL) +#define BIO_FLAGS_SHOULD_RETRY 0x08 +#define BIO_FLAGS_BASE64_NO_NL 0x100 +/* This is used with memory BIOs: it means we shouldn't free up or change the + * data in any way. */ +#define BIO_FLAGS_MEM_RDONLY 0x200 + +/* These are the 'types' of BIOs */ +#define BIO_TYPE_NONE 0 +#define BIO_TYPE_MEM (1 | 0x0400) +#define BIO_TYPE_FILE (2 | 0x0400) +#define BIO_TYPE_FD (4 | 0x0400 | 0x0100) +#define BIO_TYPE_SOCKET (5 | 0x0400 | 0x0100) +#define BIO_TYPE_NULL (6 | 0x0400) +#define BIO_TYPE_SSL (7 | 0x0200) +#define BIO_TYPE_MD (8 | 0x0200) /* passive filter */ +#define BIO_TYPE_BUFFER (9 | 0x0200) /* filter */ +#define BIO_TYPE_CIPHER (10 | 0x0200) /* filter */ +#define BIO_TYPE_BASE64 (11 | 0x0200) /* filter */ +#define BIO_TYPE_CONNECT (12 | 0x0400 | 0x0100) /* socket - connect */ +#define BIO_TYPE_ACCEPT (13 | 0x0400 | 0x0100) /* socket for accept */ +#define BIO_TYPE_PROXY_CLIENT (14 | 0x0200) /* client proxy BIO */ +#define BIO_TYPE_PROXY_SERVER (15 | 0x0200) /* server proxy BIO */ +#define BIO_TYPE_NBIO_TEST (16 | 0x0200) /* server proxy BIO */ +#define BIO_TYPE_NULL_FILTER (17 | 0x0200) +#define BIO_TYPE_BER (18 | 0x0200) /* BER -> bin filter */ +#define BIO_TYPE_BIO (19 | 0x0400) /* (half a) BIO pair */ +#define BIO_TYPE_LINEBUFFER (20 | 0x0200) /* filter */ +#define BIO_TYPE_DGRAM (21 | 0x0400 | 0x0100) +#define BIO_TYPE_ASN1 (22 | 0x0200) /* filter */ +#define BIO_TYPE_COMP (23 | 0x0200) /* filter */ + +#define BIO_TYPE_DESCRIPTOR 0x0100 /* socket, fd, connect or accept */ +#define BIO_TYPE_FILTER 0x0200 +#define BIO_TYPE_SOURCE_SINK 0x0400 + +struct bio_method_st { + int type; + const char *name; + int (*bwrite)(BIO *, const char *, int); + int (*bread)(BIO *, char *, int); + /* TODO(fork): remove bputs. */ + int (*bputs)(BIO *, const char *); + int (*bgets)(BIO *, char *, int); + long (*ctrl)(BIO *, int, long, void *); + int (*create)(BIO *); + int (*destroy)(BIO *); + long (*callback_ctrl)(BIO *, int, bio_info_cb); +}; + +struct bio_st { + const BIO_METHOD *method; + /* bio, mode, argp, argi, argl, ret */ + long (*callback)(BIO *, int, const char *, int, long, long); + char *cb_arg; /* first argument for the callback */ + + /* init is non-zero if this |BIO| has been initialised. */ + int init; + /* shutdown is often used by specific |BIO_METHOD|s to determine whether + * they own some underlying resource. This flag can often by controlled by + * |BIO_set_close|. For example, whether an fd BIO closes the underlying fd + * when it, itself, is closed. */ + int shutdown; + int flags; + int retry_reason; + /* num is a BIO-specific value. For example, in fd BIOs it's used to store a + * file descriptor. */ + int num; + CRYPTO_refcount_t references; + void *ptr; + /* next_bio points to the next |BIO| in a chain. This |BIO| owns a reference + * to |next_bio|. */ + BIO *next_bio; /* used by filter BIOs */ + size_t num_read, num_write; +}; + +#define BIO_C_SET_CONNECT 100 +#define BIO_C_DO_STATE_MACHINE 101 +#define BIO_C_SET_NBIO 102 +#define BIO_C_SET_PROXY_PARAM 103 +#define BIO_C_SET_FD 104 +#define BIO_C_GET_FD 105 +#define BIO_C_SET_FILE_PTR 106 +#define BIO_C_GET_FILE_PTR 107 +#define BIO_C_SET_FILENAME 108 +#define BIO_C_SET_SSL 109 +#define BIO_C_GET_SSL 110 +#define BIO_C_SET_MD 111 +#define BIO_C_GET_MD 112 +#define BIO_C_GET_CIPHER_STATUS 113 +#define BIO_C_SET_BUF_MEM 114 +#define BIO_C_GET_BUF_MEM_PTR 115 +#define BIO_C_GET_BUFF_NUM_LINES 116 +#define BIO_C_SET_BUFF_SIZE 117 +#define BIO_C_SET_ACCEPT 118 +#define BIO_C_SSL_MODE 119 +#define BIO_C_GET_MD_CTX 120 +#define BIO_C_GET_PROXY_PARAM 121 +#define BIO_C_SET_BUFF_READ_DATA 122 /* data to read first */ +#define BIO_C_GET_ACCEPT 124 +#define BIO_C_SET_SSL_RENEGOTIATE_BYTES 125 +#define BIO_C_GET_SSL_NUM_RENEGOTIATES 126 +#define BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT 127 +#define BIO_C_FILE_SEEK 128 +#define BIO_C_GET_CIPHER_CTX 129 +#define BIO_C_SET_BUF_MEM_EOF_RETURN 130/*return end of input value*/ +#define BIO_C_SET_BIND_MODE 131 +#define BIO_C_GET_BIND_MODE 132 +#define BIO_C_FILE_TELL 133 +#define BIO_C_GET_SOCKS 134 +#define BIO_C_SET_SOCKS 135 + +#define BIO_C_SET_WRITE_BUF_SIZE 136/* for BIO_s_bio */ +#define BIO_C_GET_WRITE_BUF_SIZE 137 +#define BIO_C_GET_WRITE_GUARANTEE 140 +#define BIO_C_GET_READ_REQUEST 141 +#define BIO_C_SHUTDOWN_WR 142 +#define BIO_C_NREAD0 143 +#define BIO_C_NREAD 144 +#define BIO_C_NWRITE0 145 +#define BIO_C_NWRITE 146 +#define BIO_C_RESET_READ_REQUEST 147 +#define BIO_C_SET_MD_CTX 148 + +#define BIO_C_SET_PREFIX 149 +#define BIO_C_GET_PREFIX 150 +#define BIO_C_SET_SUFFIX 151 +#define BIO_C_GET_SUFFIX 152 + +#define BIO_C_SET_EX_ARG 153 +#define BIO_C_GET_EX_ARG 154 + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define BIO_R_BAD_FOPEN_MODE 100 +#define BIO_R_BROKEN_PIPE 101 +#define BIO_R_CONNECT_ERROR 102 +#define BIO_R_ERROR_SETTING_NBIO 103 +#define BIO_R_INVALID_ARGUMENT 104 +#define BIO_R_IN_USE 105 +#define BIO_R_KEEPALIVE 106 +#define BIO_R_NBIO_CONNECT_ERROR 107 +#define BIO_R_NO_HOSTNAME_SPECIFIED 108 +#define BIO_R_NO_PORT_SPECIFIED 109 +#define BIO_R_NO_SUCH_FILE 110 +#define BIO_R_NULL_PARAMETER 111 +#define BIO_R_SYS_LIB 112 +#define BIO_R_UNABLE_TO_CREATE_SOCKET 113 +#define BIO_R_UNINITIALIZED 114 +#define BIO_R_UNSUPPORTED_METHOD 115 +#define BIO_R_WRITE_TO_READ_ONLY_BIO 116 + +#endif /* OPENSSL_HEADER_BIO_H */ diff --git a/project/jni/boringssl/include/openssl/blowfish.h b/project/jni/boringssl/include/openssl/blowfish.h new file mode 100644 index 000000000..fa60d5336 --- /dev/null +++ b/project/jni/boringssl/include/openssl/blowfish.h @@ -0,0 +1,93 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BLOWFISH_H +#define OPENSSL_HEADER_BLOWFISH_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define BF_ENCRYPT 1 +#define BF_DECRYPT 0 + +#define BF_ROUNDS 16 +#define BF_BLOCK 8 + +typedef struct bf_key_st { + uint32_t P[BF_ROUNDS + 2]; + uint32_t S[4 * 256]; +} BF_KEY; + +OPENSSL_EXPORT void BF_set_key(BF_KEY *key, size_t len, const uint8_t *data); +OPENSSL_EXPORT void BF_encrypt(uint32_t *data, const BF_KEY *key); +OPENSSL_EXPORT void BF_decrypt(uint32_t *data, const BF_KEY *key); + +OPENSSL_EXPORT void BF_ecb_encrypt(const uint8_t *in, uint8_t *out, + const BF_KEY *key, int enc); +OPENSSL_EXPORT void BF_cbc_encrypt(const uint8_t *in, uint8_t *out, long length, + const BF_KEY *schedule, uint8_t *ivec, + int enc); + + +#ifdef __cplusplus +} +#endif + +#endif /* OPENSSL_HEADER_BLOWFISH_H */ diff --git a/project/jni/boringssl/include/openssl/bn.h b/project/jni/boringssl/include/openssl/bn.h new file mode 100644 index 000000000..6e971e48f --- /dev/null +++ b/project/jni/boringssl/include/openssl/bn.h @@ -0,0 +1,888 @@ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the Eric Young open source + * license provided above. + * + * The binary polynomial arithmetic software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#ifndef OPENSSL_HEADER_BN_H +#define OPENSSL_HEADER_BN_H + +#include +#include + +#include /* for PRIu64 and friends */ +#include /* for FILE* */ + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* BN provides support for working with arbitary sized integers. For example, + * although the largest integer supported by the compiler might be 64 bits, BN + * will allow you to work with numbers until you run out of memory. */ + + +/* BN_ULONG is the native word size when working with big integers. + * + * Note: on some platforms, inttypes.h does not define print format macros in + * C++ unless |__STDC_FORMAT_MACROS| defined. As this is a public header, bn.h + * does not define |__STDC_FORMAT_MACROS| itself. C++ source files which use the + * FMT macros must define it externally. */ +#if defined(OPENSSL_64_BIT) +#define BN_ULONG uint64_t +#define BN_BITS2 64 +#define BN_DEC_FMT1 "%" PRIu64 +#define BN_DEC_FMT2 "%019" PRIu64 +#define BN_HEX_FMT1 "%" PRIx64 +#elif defined(OPENSSL_32_BIT) +#define BN_ULONG uint32_t +#define BN_BITS2 32 +#define BN_DEC_FMT1 "%" PRIu32 +#define BN_DEC_FMT2 "%09" PRIu32 +#define BN_HEX_FMT1 "%" PRIx32 +#else +#error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT" +#endif + + +/* Allocation and freeing. */ + +/* BN_new creates a new, allocated BIGNUM and initialises it. */ +OPENSSL_EXPORT BIGNUM *BN_new(void); + +/* BN_init initialises a stack allocated |BIGNUM|. */ +OPENSSL_EXPORT void BN_init(BIGNUM *bn); + +/* BN_free frees the data referenced by |bn| and, if |bn| was originally + * allocated on the heap, frees |bn| also. */ +OPENSSL_EXPORT void BN_free(BIGNUM *bn); + +/* BN_clear_free erases and frees the data referenced by |bn| and, if |bn| was + * originally allocated on the heap, frees |bn| also. */ +OPENSSL_EXPORT void BN_clear_free(BIGNUM *bn); + +/* BN_dup allocates a new BIGNUM and sets it equal to |src|. It returns the + * allocated BIGNUM on success or NULL otherwise. */ +OPENSSL_EXPORT BIGNUM *BN_dup(const BIGNUM *src); + +/* BN_copy sets |dest| equal to |src| and returns |dest| or NULL on allocation + * failure. */ +OPENSSL_EXPORT BIGNUM *BN_copy(BIGNUM *dest, const BIGNUM *src); + +/* BN_clear sets |bn| to zero and erases the old data. */ +OPENSSL_EXPORT void BN_clear(BIGNUM *bn); + +/* BN_value_one returns a static BIGNUM with value 1. */ +OPENSSL_EXPORT const BIGNUM *BN_value_one(void); + +/* BN_with_flags initialises a stack allocated |BIGNUM| with pointers to the + * contents of |in| but with |flags| ORed into the flags field. + * + * Note: the two BIGNUMs share state and so |out| should /not/ be passed to + * |BN_free|. */ +OPENSSL_EXPORT void BN_with_flags(BIGNUM *out, const BIGNUM *in, int flags); + + +/* Basic functions. */ + +/* BN_num_bits returns the minimum number of bits needed to represent the + * absolute value of |bn|. */ +OPENSSL_EXPORT unsigned BN_num_bits(const BIGNUM *bn); + +/* BN_num_bytes returns the minimum number of bytes needed to represent the + * absolute value of |bn|. */ +OPENSSL_EXPORT unsigned BN_num_bytes(const BIGNUM *bn); + +/* BN_zero sets |bn| to zero. */ +OPENSSL_EXPORT void BN_zero(BIGNUM *bn); + +/* BN_one sets |bn| to one. It returns one on success or zero on allocation + * failure. */ +OPENSSL_EXPORT int BN_one(BIGNUM *bn); + +/* BN_set_word sets |bn| to |value|. It returns one on success or zero on + * allocation failure. */ +OPENSSL_EXPORT int BN_set_word(BIGNUM *bn, BN_ULONG value); + +/* BN_set_negative sets the sign of |bn|. */ +OPENSSL_EXPORT void BN_set_negative(BIGNUM *bn, int sign); + +/* BN_is_negative returns one if |bn| is negative and zero otherwise. */ +OPENSSL_EXPORT int BN_is_negative(const BIGNUM *bn); + +/* BN_get_flags returns |bn->flags| & |flags|. */ +OPENSSL_EXPORT int BN_get_flags(const BIGNUM *bn, int flags); + +/* BN_set_flags sets |flags| on |bn|. */ +OPENSSL_EXPORT void BN_set_flags(BIGNUM *bn, int flags); + + +/* Conversion functions. */ + +/* BN_bin2bn sets |*ret| to the value of |len| bytes from |in|, interpreted as + * a big-endian number, and returns |ret|. If |ret| is NULL then a fresh + * |BIGNUM| is allocated and returned. It returns NULL on allocation + * failure. */ +OPENSSL_EXPORT BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret); + +/* BN_bn2bin serialises the absolute value of |in| to |out| as a big-endian + * integer, which must have |BN_num_bytes| of space available. It returns the + * number of bytes written. */ +OPENSSL_EXPORT size_t BN_bn2bin(const BIGNUM *in, uint8_t *out); + +/* BN_bn2bin_padded serialises the absolute value of |in| to |out| as a + * big-endian integer. The integer is padded with leading zeros up to size + * |len|. If |len| is smaller than |BN_num_bytes|, the function fails and + * returns 0. Otherwise, it returns 1. */ +OPENSSL_EXPORT int BN_bn2bin_padded(uint8_t *out, size_t len, const BIGNUM *in); + +/* BN_bn2cbb_padded behaves like |BN_bn2bin_padded| but writes to a |CBB|. */ +OPENSSL_EXPORT int BN_bn2cbb_padded(CBB *out, size_t len, const BIGNUM *in); + +/* BN_bn2hex returns an allocated string that contains a NUL-terminated, hex + * representation of |bn|. If |bn| is negative, the first char in the resulting + * string will be '-'. Returns NULL on allocation failure. */ +OPENSSL_EXPORT char *BN_bn2hex(const BIGNUM *bn); + +/* BN_hex2bn parses the leading hex number from |in|, which may be proceeded by + * a '-' to indicate a negative number and may contain trailing, non-hex data. + * If |outp| is not NULL, it constructs a BIGNUM equal to the hex number and + * stores it in |*outp|. If |*outp| is NULL then it allocates a new BIGNUM and + * updates |*outp|. It returns the number of bytes of |in| processed or zero on + * error. */ +OPENSSL_EXPORT int BN_hex2bn(BIGNUM **outp, const char *in); + +/* BN_bn2dec returns an allocated string that contains a NUL-terminated, + * decimal representation of |bn|. If |bn| is negative, the first char in the + * resulting string will be '-'. Returns NULL on allocation failure. */ +OPENSSL_EXPORT char *BN_bn2dec(const BIGNUM *a); + +/* BN_dec2bn parses the leading decimal number from |in|, which may be + * proceeded by a '-' to indicate a negative number and may contain trailing, + * non-decimal data. If |outp| is not NULL, it constructs a BIGNUM equal to the + * decimal number and stores it in |*outp|. If |*outp| is NULL then it + * allocates a new BIGNUM and updates |*outp|. It returns the number of bytes + * of |in| processed or zero on error. */ +OPENSSL_EXPORT int BN_dec2bn(BIGNUM **outp, const char *in); + +/* BN_asc2bn acts like |BN_dec2bn| or |BN_hex2bn| depending on whether |in| + * begins with "0X" or "0x" (indicating hex) or not (indicating decimal). A + * leading '-' is still permitted and comes before the optional 0X/0x. It + * returns one on success or zero on error. */ +OPENSSL_EXPORT int BN_asc2bn(BIGNUM **outp, const char *in); + +/* BN_print writes a hex encoding of |a| to |bio|. It returns one on success + * and zero on error. */ +OPENSSL_EXPORT int BN_print(BIO *bio, const BIGNUM *a); + +/* BN_print_fp acts like |BIO_print|, but wraps |fp| in a |BIO| first. */ +OPENSSL_EXPORT int BN_print_fp(FILE *fp, const BIGNUM *a); + +/* BN_get_word returns the absolute value of |bn| as a single word. If |bn| is + * too large to be represented as a single word, the maximum possible value + * will be returned. */ +OPENSSL_EXPORT BN_ULONG BN_get_word(const BIGNUM *bn); + + +/* ASN.1 functions. */ + +/* BN_cbs2unsigned parses a non-negative DER INTEGER from |cbs| writes the + * result to |ret|. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int BN_cbs2unsigned(CBS *cbs, BIGNUM *ret); + +/* BN_cbs2unsigned_buggy acts like |BN_cbs2unsigned| but tolerates some invalid + * encodings. Do not use this function. */ +OPENSSL_EXPORT int BN_cbs2unsigned_buggy(CBS *cbs, BIGNUM *ret); + +/* BN_bn2cbb marshals |bn| as a non-negative DER INTEGER and appends the result + * to |cbb|. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int BN_bn2cbb(CBB *cbb, const BIGNUM *bn); + + +/* Internal functions. + * + * These functions are useful for code that is doing low-level manipulations of + * BIGNUM values. However, be sure that no other function in this file does + * what you want before turning to these. */ + +/* bn_correct_top decrements |bn->top| until |bn->d[top-1]| is non-zero or + * until |top| is zero. */ +OPENSSL_EXPORT void bn_correct_top(BIGNUM *bn); + +/* bn_wexpand ensures that |bn| has at least |words| works of space without + * altering its value. It returns one on success or zero on allocation + * failure. */ +OPENSSL_EXPORT BIGNUM *bn_wexpand(BIGNUM *bn, size_t words); + + +/* BIGNUM pools. + * + * Certain BIGNUM operations need to use many temporary variables and + * allocating and freeing them can be quite slow. Thus such opertions typically + * take a |BN_CTX| parameter, which contains a pool of |BIGNUMs|. The |ctx| + * argument to a public function may be NULL, in which case a local |BN_CTX| + * will be created just for the lifetime of that call. + * + * A function must call |BN_CTX_start| first. Then, |BN_CTX_get| may be called + * repeatedly to obtain temporary |BIGNUM|s. All |BN_CTX_get| calls must be made + * before calling any other functions that use the |ctx| as an argument. + * + * Finally, |BN_CTX_end| must be called before returning from the function. + * When |BN_CTX_end| is called, the |BIGNUM| pointers obtained from + * |BN_CTX_get| become invalid. */ + +/* BN_CTX_new returns a new, empty BN_CTX or NULL on allocation failure. */ +OPENSSL_EXPORT BN_CTX *BN_CTX_new(void); + +/* BN_CTX_free frees all BIGNUMs contained in |ctx| and then frees |ctx| + * itself. */ +OPENSSL_EXPORT void BN_CTX_free(BN_CTX *ctx); + +/* BN_CTX_start "pushes" a new entry onto the |ctx| stack and allows future + * calls to |BN_CTX_get|. */ +OPENSSL_EXPORT void BN_CTX_start(BN_CTX *ctx); + +/* BN_CTX_get returns a new |BIGNUM|, or NULL on allocation failure. Once + * |BN_CTX_get| has returned NULL, all future calls will also return NULL until + * |BN_CTX_end| is called. */ +OPENSSL_EXPORT BIGNUM *BN_CTX_get(BN_CTX *ctx); + +/* BN_CTX_end invalidates all |BIGNUM|s returned from |BN_CTX_get| since the + * matching |BN_CTX_start| call. */ +OPENSSL_EXPORT void BN_CTX_end(BN_CTX *ctx); + + +/* Simple arithmetic */ + +/* BN_add sets |r| = |a| + |b|, where |r| may be the same pointer as either |a| + * or |b|. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); + +/* BN_uadd sets |r| = |a| + |b|, where |a| and |b| are non-negative and |r| may + * be the same pointer as either |a| or |b|. It returns one on success and zero + * on allocation failure. */ +OPENSSL_EXPORT int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); + +/* BN_add_word adds |w| to |a|. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BN_add_word(BIGNUM *a, BN_ULONG w); + +/* BN_sub sets |r| = |a| - |b|, where |r| must be a distinct pointer from |a| + * and |b|. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); + +/* BN_usub sets |r| = |a| - |b|, where |a| and |b| are non-negative integers, + * |b| < |a| and |r| must be a distinct pointer from |a| and |b|. It returns + * one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); + +/* BN_sub_word subtracts |w| from |a|. It returns one on success and zero on + * allocation failure. */ +OPENSSL_EXPORT int BN_sub_word(BIGNUM *a, BN_ULONG w); + +/* BN_mul sets |r| = |a| * |b|, where |r| may be the same pointer as |a| or + * |b|. Returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + BN_CTX *ctx); + +/* BN_mul_word sets |bn| = |bn| * |w|. It returns one on success or zero on + * allocation failure. */ +OPENSSL_EXPORT int BN_mul_word(BIGNUM *bn, BN_ULONG w); + +/* BN_sqr sets |r| = |a|^2 (i.e. squares), where |r| may be the same pointer as + * |a|. Returns one on success and zero otherwise. This is more efficient than + * BN_mul(r, a, a, ctx). */ +OPENSSL_EXPORT int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx); + +/* BN_div divides |numerator| by |divisor| and places the result in |quotient| + * and the remainder in |rem|. Either of |quotient| or |rem| may be NULL, in + * which case the respective value is not returned. The result is rounded + * towards zero; thus if |numerator| is negative, the remainder will be zero or + * negative. It returns one on success or zero on error. */ +OPENSSL_EXPORT int BN_div(BIGNUM *quotient, BIGNUM *rem, + const BIGNUM *numerator, const BIGNUM *divisor, + BN_CTX *ctx); + +/* BN_div_word sets |numerator| = |numerator|/|divisor| and returns the + * remainder or (BN_ULONG)-1 on error. */ +OPENSSL_EXPORT BN_ULONG BN_div_word(BIGNUM *numerator, BN_ULONG divisor); + +/* BN_sqrt sets |*out_sqrt| (which may be the same |BIGNUM| as |in|) to the + * square root of |in|, using |ctx|. It returns one on success or zero on + * error. Negative numbers and non-square numbers will result in an error with + * appropriate errors on the error queue. */ +OPENSSL_EXPORT int BN_sqrt(BIGNUM *out_sqrt, const BIGNUM *in, BN_CTX *ctx); + + +/* Comparison functions */ + +/* BN_cmp returns a value less than, equal to or greater than zero if |a| is + * less than, equal to or greater than |b|, respectively. */ +OPENSSL_EXPORT int BN_cmp(const BIGNUM *a, const BIGNUM *b); + +/* BN_ucmp returns a value less than, equal to or greater than zero if the + * absolute value of |a| is less than, equal to or greater than the absolute + * value of |b|, respectively. */ +OPENSSL_EXPORT int BN_ucmp(const BIGNUM *a, const BIGNUM *b); + +/* BN_abs_is_word returns one if the absolute value of |bn| equals |w| and zero + * otherwise. */ +OPENSSL_EXPORT int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w); + +/* BN_is_zero returns one if |bn| is zero and zero otherwise. */ +OPENSSL_EXPORT int BN_is_zero(const BIGNUM *bn); + +/* BN_is_one returns one if |bn| equals one and zero otherwise. */ +OPENSSL_EXPORT int BN_is_one(const BIGNUM *bn); + +/* BN_is_word returns one if |bn| is exactly |w| and zero otherwise. */ +OPENSSL_EXPORT int BN_is_word(const BIGNUM *bn, BN_ULONG w); + +/* BN_is_odd returns one if |bn| is odd and zero otherwise. */ +OPENSSL_EXPORT int BN_is_odd(const BIGNUM *bn); + + +/* Bitwise operations. */ + +/* BN_lshift sets |r| equal to |a| << n. The |a| and |r| arguments may be the + * same |BIGNUM|. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_lshift(BIGNUM *r, const BIGNUM *a, int n); + +/* BN_lshift1 sets |r| equal to |a| << 1, where |r| and |a| may be the same + * pointer. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_lshift1(BIGNUM *r, const BIGNUM *a); + +/* BN_rshift sets |r| equal to |a| >> n, where |r| and |a| may be the same + * pointer. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_rshift(BIGNUM *r, const BIGNUM *a, int n); + +/* BN_rshift1 sets |r| equal to |a| >> 1, where |r| and |a| may be the same + * pointer. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_rshift1(BIGNUM *r, const BIGNUM *a); + +/* BN_set_bit sets the |n|th, least-significant bit in |a|. For example, if |a| + * is 2 then setting bit zero will make it 3. It returns one on success or zero + * on allocation failure. */ +OPENSSL_EXPORT int BN_set_bit(BIGNUM *a, int n); + +/* BN_clear_bit clears the |n|th, least-significant bit in |a|. For example, if + * |a| is 3, clearing bit zero will make it two. It returns one on success or + * zero on allocation failure. */ +OPENSSL_EXPORT int BN_clear_bit(BIGNUM *a, int n); + +/* BN_is_bit_set returns the value of the |n|th, least-significant bit in |a|, + * or zero if the bit doesn't exist. */ +OPENSSL_EXPORT int BN_is_bit_set(const BIGNUM *a, int n); + +/* BN_mask_bits truncates |a| so that it is only |n| bits long. It returns one + * on success or zero if |n| is greater than the length of |a| already. */ +OPENSSL_EXPORT int BN_mask_bits(BIGNUM *a, int n); + + +/* Modulo arithmetic. */ + +/* BN_mod_word returns |a| mod |w|. */ +OPENSSL_EXPORT BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w); + +/* BN_mod is a helper macro that calls |BN_div| and discards the quotient. */ +#define BN_mod(rem, numerator, divisor, ctx) \ + BN_div(NULL, (rem), (numerator), (divisor), (ctx)) + +/* BN_nnmod is a non-negative modulo function. It acts like |BN_mod|, but 0 <= + * |rem| < |divisor| is always true. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int BN_nnmod(BIGNUM *rem, const BIGNUM *numerator, + const BIGNUM *divisor, BN_CTX *ctx); + +/* BN_mod_add sets |r| = |a| + |b| mod |m|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m, BN_CTX *ctx); + +/* BN_mod_add_quick acts like |BN_mod_add| but requires that |a| and |b| be + * non-negative and less than |m|. */ +OPENSSL_EXPORT int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m); + +/* BN_mod_sub sets |r| = |a| - |b| mod |m|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m, BN_CTX *ctx); + +/* BN_mod_sub_quick acts like |BN_mod_sub| but requires that |a| and |b| be + * non-negative and less than |m|. */ +OPENSSL_EXPORT int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m); + +/* BN_mod_mul sets |r| = |a|*|b| mod |m|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m, BN_CTX *ctx); + +/* BN_mod_sqr sets |r| = |a|^2 mod |m|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, + BN_CTX *ctx); + +/* BN_mod_lshift sets |r| = (|a| << n) mod |m|, where |r| and |a| may be the + * same pointer. It returns one on success and zero on error. */ +OPENSSL_EXPORT int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, + const BIGNUM *m, BN_CTX *ctx); + +/* BN_mod_lshift_quick acts like |BN_mod_lshift| but requires that |a| be + * non-negative and less than |m|. */ +OPENSSL_EXPORT int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, + const BIGNUM *m); + +/* BN_mod_lshift1 sets |r| = (|a| << 1) mod |m|, where |r| and |a| may be the + * same pointer. It returns one on success and zero on error. */ +OPENSSL_EXPORT int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, + BN_CTX *ctx); + +/* BN_mod_lshift1_quick acts like |BN_mod_lshift1| but requires that |a| be + * non-negative and less than |m|. */ +OPENSSL_EXPORT int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, + const BIGNUM *m); + +/* BN_mod_sqrt returns a |BIGNUM|, r, such that r^2 == a (mod p). */ +OPENSSL_EXPORT BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, + BN_CTX *ctx); + + +/* Random and prime number generation. */ + +/* BN_rand sets |rnd| to a random number of length |bits|. If |top| is zero, the + * most-significant bit, if any, will be set. If |top| is one, the two most + * significant bits, if any, will be set. + * + * If |top| is -1 then no extra action will be taken and |BN_num_bits(rnd)| may + * not equal |bits| if the most significant bits randomly ended up as zeros. + * + * If |bottom| is non-zero, the least-significant bit, if any, will be set. The + * function returns one on success or zero otherwise. */ +OPENSSL_EXPORT int BN_rand(BIGNUM *rnd, int bits, int top, int bottom); + +/* BN_pseudo_rand is an alias for |BN_rand|. */ +OPENSSL_EXPORT int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom); + +/* BN_rand_range sets |rnd| to a random value [0..range). It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int BN_rand_range(BIGNUM *rnd, const BIGNUM *range); + +/* BN_pseudo_rand_range is an alias for BN_rand_range. */ +OPENSSL_EXPORT int BN_pseudo_rand_range(BIGNUM *rnd, const BIGNUM *range); + +/* BN_generate_dsa_nonce generates a random number 0 <= out < range. Unlike + * BN_rand_range, it also includes the contents of |priv| and |message| in the + * generation so that an RNG failure isn't fatal as long as |priv| remains + * secret. This is intended for use in DSA and ECDSA where an RNG weakness + * leads directly to private key exposure unless this function is used. + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, + const BIGNUM *priv, + const uint8_t *message, + size_t message_len, BN_CTX *ctx); + +/* BN_GENCB holds a callback function that is used by generation functions that + * can take a very long time to complete. Use |BN_GENCB_set| to initialise a + * |BN_GENCB| structure. + * + * The callback receives the address of that |BN_GENCB| structure as its last + * argument and the user is free to put an arbitary pointer in |arg|. The other + * arguments are set as follows: + * event=BN_GENCB_GENERATED, n=i: after generating the i'th possible prime + * number. + * event=BN_GENCB_PRIME_TEST, n=-1: when finished trial division primality + * checks. + * event=BN_GENCB_PRIME_TEST, n=i: when the i'th primality test has finished. + * + * The callback can return zero to abort the generation progress or one to + * allow it to continue. + * + * When other code needs to call a BN generation function it will often take a + * BN_GENCB argument and may call the function with other argument values. */ +#define BN_GENCB_GENERATED 0 +#define BN_GENCB_PRIME_TEST 1 + +struct bn_gencb_st { + void *arg; /* callback-specific data */ + int (*callback)(int event, int n, struct bn_gencb_st *); +}; + +/* BN_GENCB_set configures |callback| to call |f| and sets |callout->arg| to + * |arg|. */ +OPENSSL_EXPORT void BN_GENCB_set(BN_GENCB *callback, + int (*f)(int event, int n, + struct bn_gencb_st *), + void *arg); + +/* BN_GENCB_call calls |callback|, if not NULL, and returns the return value of + * the callback, or 1 if |callback| is NULL. */ +OPENSSL_EXPORT int BN_GENCB_call(BN_GENCB *callback, int event, int n); + +/* BN_generate_prime_ex sets |ret| to a prime number of |bits| length. If safe + * is non-zero then the prime will be such that (ret-1)/2 is also a prime. + * (This is needed for Diffie-Hellman groups to ensure that the only subgroups + * are of size 2 and (p-1)/2.). + * + * If |add| is not NULL, the prime will fulfill the condition |ret| % |add| == + * |rem| in order to suit a given generator. (If |rem| is NULL then |ret| % + * |add| == 1.) + * + * If |cb| is not NULL, it will be called during processing to give an + * indication of progress. See the comments for |BN_GENCB|. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe, + const BIGNUM *add, const BIGNUM *rem, + BN_GENCB *cb); + +/* BN_prime_checks is magic value that can be used as the |checks| argument to + * the primality testing functions in order to automatically select a number of + * Miller-Rabin checks that gives a false positive rate of ~2^{-80}. */ +#define BN_prime_checks 0 + +/* BN_primality_test sets |*is_probably_prime| to one if |candidate| is + * probably a prime number by the Miller-Rabin test or zero if it's certainly + * not. + * + * If |do_trial_division| is non-zero then |candidate| will be tested against a + * list of small primes before Miller-Rabin tests. The probability of this + * function returning a false positive is 2^{2*checks}. If |checks| is + * |BN_prime_checks| then a value that results in approximately 2^{-80} false + * positive probability is used. If |cb| is not NULL then it is called during + * the checking process. See the comment above |BN_GENCB|. + * + * The function returns one on success and zero on error. + * + * (If you are unsure whether you want |do_trial_division|, don't set it.) */ +OPENSSL_EXPORT int BN_primality_test(int *is_probably_prime, + const BIGNUM *candidate, int checks, + BN_CTX *ctx, int do_trial_division, + BN_GENCB *cb); + +/* BN_is_prime_fasttest_ex returns one if |candidate| is probably a prime + * number by the Miller-Rabin test, zero if it's certainly not and -1 on error. + * + * If |do_trial_division| is non-zero then |candidate| will be tested against a + * list of small primes before Miller-Rabin tests. The probability of this + * function returning one when |candidate| is composite is 2^{2*checks}. If + * |checks| is |BN_prime_checks| then a value that results in approximately + * 2^{-80} false positive probability is used. If |cb| is not NULL then it is + * called during the checking process. See the comment above |BN_GENCB|. + * + * WARNING: deprecated. Use |BN_primality_test|. */ +OPENSSL_EXPORT int BN_is_prime_fasttest_ex(const BIGNUM *candidate, int checks, + BN_CTX *ctx, int do_trial_division, + BN_GENCB *cb); + +/* BN_is_prime_ex acts the same as |BN_is_prime_fasttest_ex| with + * |do_trial_division| set to zero. + * + * WARNING: deprecated: Use |BN_primality_test|. */ +OPENSSL_EXPORT int BN_is_prime_ex(const BIGNUM *candidate, int checks, + BN_CTX *ctx, BN_GENCB *cb); + + +/* Number theory functions */ + +/* BN_gcd sets |r| = gcd(|a|, |b|). It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int BN_gcd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + BN_CTX *ctx); + +/* BN_mod_inverse sets |out| equal to |a|^-1, mod |n|. If either of |a| or |n| + * have |BN_FLG_CONSTTIME| set then the operation is performed in constant + * time. If |out| is NULL, a fresh BIGNUM is allocated. It returns the result + * or NULL on error. */ +OPENSSL_EXPORT BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, + const BIGNUM *n, BN_CTX *ctx); + +/* BN_mod_inverse_ex acts like |BN_mod_inverse| except that, when it returns + * zero, it will set |*out_no_inverse| to one if the failure was caused because + * |a| has no inverse mod |n|. Otherwise it will set |*out_no_inverse| to + * zero. */ +OPENSSL_EXPORT BIGNUM *BN_mod_inverse_ex(BIGNUM *out, int *out_no_inverse, + const BIGNUM *a, const BIGNUM *n, + BN_CTX *ctx); + +/* BN_kronecker returns the Kronecker symbol of |a| and |b| (which is -1, 0 or + * 1), or -2 on error. */ +OPENSSL_EXPORT int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx); + + +/* Montgomery arithmetic. */ + +/* BN_MONT_CTX contains the precomputed values needed to work in a specific + * Montgomery domain. */ + +/* BN_MONT_CTX_new returns a fresh BN_MONT_CTX or NULL on allocation failure. */ +OPENSSL_EXPORT BN_MONT_CTX *BN_MONT_CTX_new(void); + +/* BN_MONT_CTX_free frees memory associated with |mont|. */ +OPENSSL_EXPORT void BN_MONT_CTX_free(BN_MONT_CTX *mont); + +/* BN_MONT_CTX_copy sets |to| equal to |from|. It returns |to| on success or + * NULL on error. */ +OPENSSL_EXPORT BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, + const BN_MONT_CTX *from); + +/* BN_MONT_CTX_set sets up a Montgomery context given the modulus, |mod|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, + BN_CTX *ctx); + +/* BN_MONT_CTX_set_locked takes |lock| and checks whether |*pmont| is NULL. If + * so, it creates a new |BN_MONT_CTX| and sets the modulus for it to |mod|. It + * then stores it as |*pmont| and returns it, or NULL on error. + * + * If |*pmont| is already non-NULL then the existing value is returned. */ +BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock, + const BIGNUM *mod, BN_CTX *bn_ctx); + +/* BN_to_montgomery sets |ret| equal to |a| in the Montgomery domain. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, + const BN_MONT_CTX *mont, BN_CTX *ctx); + +/* BN_from_montgomery sets |ret| equal to |a| * R^-1, i.e. translates values + * out of the Montgomery domain. It returns one on success or zero on error. */ +OPENSSL_EXPORT int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, + const BN_MONT_CTX *mont, BN_CTX *ctx); + +/* BN_mod_mul_montgomery set |r| equal to |a| * |b|, in the Montgomery domain. + * Both |a| and |b| must already be in the Montgomery domain (by + * |BN_to_montgomery|). It returns one on success or zero on error. */ +OPENSSL_EXPORT int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, + const BN_MONT_CTX *mont, BN_CTX *ctx); + + +/* Exponentiation. */ + +/* BN_exp sets |r| equal to |a|^{|p|}. It does so with a square-and-multiply + * algorithm that leaks side-channel information. It returns one on success or + * zero otherwise. */ +OPENSSL_EXPORT int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + BN_CTX *ctx); + +/* BN_mod_exp sets |r| equal to |a|^{|p|} mod |m|. It does so with the best + * algorithm for the values provided and can run in constant time if + * |BN_FLG_CONSTTIME| is set for |p|. It returns one on success or zero + * otherwise. */ +OPENSSL_EXPORT int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx); + +OPENSSL_EXPORT int BN_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + const BN_MONT_CTX *mont); + +OPENSSL_EXPORT int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, + const BIGNUM *p, const BIGNUM *m, + BN_CTX *ctx, + const BN_MONT_CTX *mont); + +OPENSSL_EXPORT int BN_mod_exp_mont_word(BIGNUM *r, BN_ULONG a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + const BN_MONT_CTX *mont); +OPENSSL_EXPORT int BN_mod_exp2_mont(BIGNUM *r, const BIGNUM *a1, + const BIGNUM *p1, const BIGNUM *a2, + const BIGNUM *p2, const BIGNUM *m, + BN_CTX *ctx, const BN_MONT_CTX *mont); + + +/* Deprecated functions */ + +/* BN_bn2mpi serialises the value of |in| to |out|, using a format that consists + * of the number's length in bytes represented as a 4-byte big-endian number, + * and the number itself in big-endian format, where the most significant bit + * signals a negative number. (The representation of numbers with the MSB set is + * prefixed with null byte). |out| must have sufficient space available; to + * find the needed amount of space, call the function with |out| set to NULL. */ +OPENSSL_EXPORT size_t BN_bn2mpi(const BIGNUM *in, uint8_t *out); + +/* BN_mpi2bn parses |len| bytes from |in| and returns the resulting value. The + * bytes at |in| are expected to be in the format emitted by |BN_bn2mpi|. + * + * If |out| is NULL then a fresh |BIGNUM| is allocated and returned, otherwise + * |out| is reused and returned. On error, NULL is returned and the error queue + * is updated. */ +OPENSSL_EXPORT BIGNUM *BN_mpi2bn(const uint8_t *in, size_t len, BIGNUM *out); + + +/* Private functions */ + +struct bignum_st { + BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks in little-endian + order. */ + int top; /* Index of last used element in |d|, plus one. */ + int dmax; /* Size of |d|, in words. */ + int neg; /* one if the number is negative */ + int flags; /* bitmask of BN_FLG_* values */ +}; + +struct bn_mont_ctx_st { + BIGNUM RR; /* used to convert to montgomery form */ + BIGNUM N; /* The modulus */ + BN_ULONG n0[2]; /* least significant words of (R*Ri-1)/N */ +}; + +OPENSSL_EXPORT unsigned BN_num_bits_word(BN_ULONG l); + +#define BN_FLG_MALLOCED 0x01 +#define BN_FLG_STATIC_DATA 0x02 +/* avoid leaking exponent information through timing, BN_mod_exp_mont() will + * call BN_mod_exp_mont_consttime, BN_div() will call BN_div_no_branch, + * BN_mod_inverse() will call BN_mod_inverse_no_branch. */ +#define BN_FLG_CONSTTIME 0x04 + + +/* Android compatibility section. + * + * These functions are declared, temporarily, for Android because + * wpa_supplicant will take a little time to sync with upstream. Outside of + * Android they'll have no definition. */ + +OPENSSL_EXPORT BIGNUM *get_rfc3526_prime_1536(BIGNUM *bn); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define BN_R_ARG2_LT_ARG3 100 +#define BN_R_BAD_RECIPROCAL 101 +#define BN_R_BIGNUM_TOO_LONG 102 +#define BN_R_BITS_TOO_SMALL 103 +#define BN_R_CALLED_WITH_EVEN_MODULUS 104 +#define BN_R_DIV_BY_ZERO 105 +#define BN_R_EXPAND_ON_STATIC_BIGNUM_DATA 106 +#define BN_R_INPUT_NOT_REDUCED 107 +#define BN_R_INVALID_RANGE 108 +#define BN_R_NEGATIVE_NUMBER 109 +#define BN_R_NOT_A_SQUARE 110 +#define BN_R_NOT_INITIALIZED 111 +#define BN_R_NO_INVERSE 112 +#define BN_R_PRIVATE_KEY_TOO_LARGE 113 +#define BN_R_P_IS_NOT_PRIME 114 +#define BN_R_TOO_MANY_ITERATIONS 115 +#define BN_R_TOO_MANY_TEMPORARY_VARIABLES 116 +#define BN_R_BAD_ENCODING 117 +#define BN_R_ENCODE_ERROR 118 + +#endif /* OPENSSL_HEADER_BN_H */ diff --git a/project/jni/boringssl/include/openssl/buf.h b/project/jni/boringssl/include/openssl/buf.h new file mode 100644 index 000000000..76e3795e4 --- /dev/null +++ b/project/jni/boringssl/include/openssl/buf.h @@ -0,0 +1,118 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BUFFER_H +#define OPENSSL_HEADER_BUFFER_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Memory and string functions, see also mem.h. */ + + +/* BUF_MEM is a generic buffer object used by OpenSSL. */ +struct buf_mem_st { + size_t length; /* current number of bytes */ + char *data; + size_t max; /* size of buffer */ +}; + +/* BUF_MEM_new creates a new BUF_MEM which has no allocated data buffer. */ +OPENSSL_EXPORT BUF_MEM *BUF_MEM_new(void); + +/* BUF_MEM_free frees |buf->data| if needed and then frees |buf| itself. */ +OPENSSL_EXPORT void BUF_MEM_free(BUF_MEM *buf); + +/* BUF_MEM_grow ensures that |buf| has length |len| and allocates memory if + * needed. If the length of |buf| increased, the new bytes are filled with + * zeros. It returns the length of |buf|, or zero if there's an error. */ +OPENSSL_EXPORT size_t BUF_MEM_grow(BUF_MEM *buf, size_t len); + +/* BUF_MEM_grow_clean acts the same as |BUF_MEM_grow|, but clears the previous + * contents of memory if reallocing. */ +OPENSSL_EXPORT size_t BUF_MEM_grow_clean(BUF_MEM *str, size_t len); + +/* BUF_strdup returns an allocated, duplicate of |str|. */ +OPENSSL_EXPORT char *BUF_strdup(const char *str); + +/* BUF_strnlen returns the number of characters in |str|, excluding the NUL + * byte, but at most |max_len|. This function never reads more than |max_len| + * bytes from |str|. */ +OPENSSL_EXPORT size_t BUF_strnlen(const char *str, size_t max_len); + +/* BUF_strndup returns an allocated, duplicate of |str|, which is, at most, + * |size| bytes. The result is always NUL terminated. */ +OPENSSL_EXPORT char *BUF_strndup(const char *str, size_t size); + +/* BUF_memdup returns an allocated, duplicate of |size| bytes from |data|. */ +OPENSSL_EXPORT void *BUF_memdup(const void *data, size_t size); + +/* BUF_strlcpy acts like strlcpy(3). */ +OPENSSL_EXPORT size_t BUF_strlcpy(char *dst, const char *src, size_t dst_size); + +/* BUF_strlcat acts like strlcat(3). */ +OPENSSL_EXPORT size_t BUF_strlcat(char *dst, const char *src, size_t size); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BUFFER_H */ diff --git a/project/jni/boringssl/include/openssl/buffer.h b/project/jni/boringssl/include/openssl/buffer.h new file mode 100644 index 000000000..c6b721c27 --- /dev/null +++ b/project/jni/boringssl/include/openssl/buffer.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "buf.h" diff --git a/project/jni/boringssl/include/openssl/bytestring.h b/project/jni/boringssl/include/openssl/bytestring.h new file mode 100644 index 000000000..9193e11fd --- /dev/null +++ b/project/jni/boringssl/include/openssl/bytestring.h @@ -0,0 +1,378 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_BYTESTRING_H +#define OPENSSL_HEADER_BYTESTRING_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Bytestrings are used for parsing and building TLS and ASN.1 messages. + * + * A "CBS" (CRYPTO ByteString) represents a string of bytes in memory and + * provides utility functions for safely parsing length-prefixed structures + * like TLS and ASN.1 from it. + * + * A "CBB" (CRYPTO ByteBuilder) is a memory buffer that grows as needed and + * provides utility functions for building length-prefixed messages. */ + + +/* CRYPTO ByteString */ + +struct cbs_st { + const uint8_t *data; + size_t len; +}; + +/* CBS_init sets |cbs| to point to |data|. It does not take ownership of + * |data|. */ +OPENSSL_EXPORT void CBS_init(CBS *cbs, const uint8_t *data, size_t len); + +/* CBS_skip advances |cbs| by |len| bytes. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int CBS_skip(CBS *cbs, size_t len); + +/* CBS_data returns a pointer to the contents of |cbs|. */ +OPENSSL_EXPORT const uint8_t *CBS_data(const CBS *cbs); + +/* CBS_len returns the number of bytes remaining in |cbs|. */ +OPENSSL_EXPORT size_t CBS_len(const CBS *cbs); + +/* CBS_stow copies the current contents of |cbs| into |*out_ptr| and + * |*out_len|. If |*out_ptr| is not NULL, the contents are freed with + * OPENSSL_free. It returns one on success and zero on allocation failure. On + * success, |*out_ptr| should be freed with OPENSSL_free. If |cbs| is empty, + * |*out_ptr| will be NULL. */ +OPENSSL_EXPORT int CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len); + +/* CBS_strdup copies the current contents of |cbs| into |*out_ptr| as a + * NUL-terminated C string. If |*out_ptr| is not NULL, the contents are freed + * with OPENSSL_free. It returns one on success and zero on allocation + * failure. On success, |*out_ptr| should be freed with OPENSSL_free. + * + * NOTE: If |cbs| contains NUL bytes, the string will be truncated. Call + * |CBS_contains_zero_byte(cbs)| to check for NUL bytes. */ +OPENSSL_EXPORT int CBS_strdup(const CBS *cbs, char **out_ptr); + +/* CBS_contains_zero_byte returns one if the current contents of |cbs| contains + * a NUL byte and zero otherwise. */ +OPENSSL_EXPORT int CBS_contains_zero_byte(const CBS *cbs); + +/* CBS_mem_equal compares the current contents of |cbs| with the |len| bytes + * starting at |data|. If they're equal, it returns one, otherwise zero. If the + * lengths match, it uses a constant-time comparison. */ +OPENSSL_EXPORT int CBS_mem_equal(const CBS *cbs, const uint8_t *data, + size_t len); + +/* CBS_get_u8 sets |*out| to the next uint8_t from |cbs| and advances |cbs|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u8(CBS *cbs, uint8_t *out); + +/* CBS_get_u16 sets |*out| to the next, big-endian uint16_t from |cbs| and + * advances |cbs|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u16(CBS *cbs, uint16_t *out); + +/* CBS_get_u24 sets |*out| to the next, big-endian 24-bit value from |cbs| and + * advances |cbs|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u24(CBS *cbs, uint32_t *out); + +/* CBS_get_u32 sets |*out| to the next, big-endian uint32_t value from |cbs| + * and advances |cbs|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u32(CBS *cbs, uint32_t *out); + +/* CBS_get_bytes sets |*out| to the next |len| bytes from |cbs| and advances + * |cbs|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_bytes(CBS *cbs, CBS *out, size_t len); + +/* CBS_copy_bytes copies the next |len| bytes from |cbs| to |out| and advances + * |cbs|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_copy_bytes(CBS *cbs, uint8_t *out, size_t len); + +/* CBS_get_u8_length_prefixed sets |*out| to the contents of an 8-bit, + * length-prefixed value from |cbs| and advances |cbs| over it. It returns one + * on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u8_length_prefixed(CBS *cbs, CBS *out); + +/* CBS_get_u16_length_prefixed sets |*out| to the contents of a 16-bit, + * big-endian, length-prefixed value from |cbs| and advances |cbs| over it. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u16_length_prefixed(CBS *cbs, CBS *out); + +/* CBS_get_u24_length_prefixed sets |*out| to the contents of a 24-bit, + * big-endian, length-prefixed value from |cbs| and advances |cbs| over it. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out); + + +/* Parsing ASN.1 */ + +#define CBS_ASN1_BOOLEAN 0x1 +#define CBS_ASN1_INTEGER 0x2 +#define CBS_ASN1_BITSTRING 0x3 +#define CBS_ASN1_OCTETSTRING 0x4 +#define CBS_ASN1_NULL 0x5 +#define CBS_ASN1_OBJECT 0x6 +#define CBS_ASN1_ENUMERATED 0xa +#define CBS_ASN1_SEQUENCE (0x10 | CBS_ASN1_CONSTRUCTED) +#define CBS_ASN1_SET (0x11 | CBS_ASN1_CONSTRUCTED) +#define CBS_ASN1_GENERALIZEDTIME 0x18 + +#define CBS_ASN1_CONSTRUCTED 0x20 +#define CBS_ASN1_CONTEXT_SPECIFIC 0x80 + +/* CBS_get_asn1 sets |*out| to the contents of DER-encoded, ASN.1 element (not + * including tag and length bytes) and advances |cbs| over it. The ASN.1 + * element must match |tag_value|. It returns one on success and zero + * on error. + * + * Tag numbers greater than 30 are not supported (i.e. short form only). */ +OPENSSL_EXPORT int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value); + +/* CBS_get_asn1_element acts like |CBS_get_asn1| but |out| will include the + * ASN.1 header bytes too. */ +OPENSSL_EXPORT int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value); + +/* CBS_peek_asn1_tag looks ahead at the next ASN.1 tag and returns one + * if the next ASN.1 element on |cbs| would have tag |tag_value|. If + * |cbs| is empty or the tag does not match, it returns zero. Note: if + * it returns one, CBS_get_asn1 may still fail if the rest of the + * element is malformed. */ +OPENSSL_EXPORT int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value); + +/* CBS_get_any_asn1_element sets |*out| to contain the next ASN.1 element from + * |*cbs| (including header bytes) and advances |*cbs|. It sets |*out_tag| to + * the tag number and |*out_header_len| to the length of the ASN.1 header. Each + * of |out|, |out_tag|, and |out_header_len| may be NULL to ignore the value. + * + * Tag numbers greater than 30 are not supported (i.e. short form only). */ +OPENSSL_EXPORT int CBS_get_any_asn1_element(CBS *cbs, CBS *out, + unsigned *out_tag, + size_t *out_header_len); + +/* CBS_get_any_ber_asn1_element acts the same as |CBS_get_any_asn1_element| but + * also allows indefinite-length elements to be returned. In that case, + * |*out_header_len| and |CBS_len(out)| will both be two as only the header is + * returned, otherwise it behaves the same as the previous function. */ +OPENSSL_EXPORT int CBS_get_any_ber_asn1_element(CBS *cbs, CBS *out, + unsigned *out_tag, + size_t *out_header_len); + +/* CBS_get_asn1_uint64 gets an ASN.1 INTEGER from |cbs| using |CBS_get_asn1| + * and sets |*out| to its value. It returns one on success and zero on error, + * where error includes the integer being negative, or too large to represent + * in 64 bits. */ +OPENSSL_EXPORT int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out); + +/* CBS_get_optional_asn1 gets an optional explicitly-tagged element from |cbs| + * tagged with |tag| and sets |*out| to its contents. If present and if + * |out_present| is not NULL, it sets |*out_present| to one, otherwise zero. It + * returns one on success, whether or not the element was present, and zero on + * decode failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, + unsigned tag); + +/* CBS_get_optional_asn1_octet_string gets an optional + * explicitly-tagged OCTET STRING from |cbs|. If present, it sets + * |*out| to the string and |*out_present| to one. Otherwise, it sets + * |*out| to empty and |*out_present| to zero. |out_present| may be + * NULL. It returns one on success, whether or not the element was + * present, and zero on decode failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, + int *out_present, + unsigned tag); + +/* CBS_get_optional_asn1_uint64 gets an optional explicitly-tagged + * INTEGER from |cbs|. If present, it sets |*out| to the + * value. Otherwise, it sets |*out| to |default_value|. It returns one + * on success, whether or not the element was present, and zero on + * decode failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, + unsigned tag, + uint64_t default_value); + +/* CBS_get_optional_asn1_bool gets an optional, explicitly-tagged BOOLEAN from + * |cbs|. If present, it sets |*out| to either zero or one, based on the + * boolean. Otherwise, it sets |*out| to |default_value|. It returns one on + * success, whether or not the element was present, and zero on decode + * failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, + int default_value); + + +/* CRYPTO ByteBuilder. + * + * |CBB| objects allow one to build length-prefixed serialisations. A |CBB| + * object is associated with a buffer and new buffers are created with + * |CBB_init|. Several |CBB| objects can point at the same buffer when a + * length-prefix is pending, however only a single |CBB| can be 'current' at + * any one time. For example, if one calls |CBB_add_u8_length_prefixed| then + * the new |CBB| points at the same buffer as the original. But if the original + * |CBB| is used then the length prefix is written out and the new |CBB| must + * not be used again. + * + * If one needs to force a length prefix to be written out because a |CBB| is + * going out of scope, use |CBB_flush|. */ + +struct cbb_buffer_st { + uint8_t *buf; + size_t len; /* The number of valid bytes. */ + size_t cap; /* The size of buf. */ + char can_resize; /* One iff |buf| is owned by this object. If not then |buf| + cannot be resized. */ +}; + +struct cbb_st { + struct cbb_buffer_st *base; + /* child points to a child CBB if a length-prefix is pending. */ + CBB *child; + /* offset is the number of bytes from the start of |base->buf| to this |CBB|'s + * pending length prefix. */ + size_t offset; + /* pending_len_len contains the number of bytes in this |CBB|'s pending + * length-prefix, or zero if no length-prefix is pending. */ + uint8_t pending_len_len; + char pending_is_asn1; + /* is_top_level is true iff this is a top-level |CBB| (as opposed to a child + * |CBB|). Top-level objects are valid arguments for |CBB_finish|. */ + char is_top_level; +}; + +/* CBB_zero sets an uninitialised |cbb| to the zero state. It must be + * initialised with |CBB_init| or |CBB_init_fixed| before use, but it is safe to + * call |CBB_cleanup| without a successful |CBB_init|. This may be used for more + * uniform cleanup of a |CBB|. */ +OPENSSL_EXPORT void CBB_zero(CBB *cbb); + +/* CBB_init initialises |cbb| with |initial_capacity|. Since a |CBB| grows as + * needed, the |initial_capacity| is just a hint. It returns one on success or + * zero on error. */ +OPENSSL_EXPORT int CBB_init(CBB *cbb, size_t initial_capacity); + +/* CBB_init_fixed initialises |cbb| to write to |len| bytes at |buf|. Since + * |buf| cannot grow, trying to write more than |len| bytes will cause CBB + * functions to fail. It returns one on success or zero on error. */ +OPENSSL_EXPORT int CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len); + +/* CBB_cleanup frees all resources owned by |cbb| and other |CBB| objects + * writing to the same buffer. This should be used in an error case where a + * serialisation is abandoned. + * + * This function can only be called on a "top level" |CBB|, i.e. one initialised + * with |CBB_init| or |CBB_init_fixed|, or a |CBB| set to the zero state with + * |CBB_zero|. */ +OPENSSL_EXPORT void CBB_cleanup(CBB *cbb); + +/* CBB_finish completes any pending length prefix and sets |*out_data| to a + * malloced buffer and |*out_len| to the length of that buffer. The caller + * takes ownership of the buffer and, unless the buffer was fixed with + * |CBB_init_fixed|, must call |OPENSSL_free| when done. + * + * It can only be called on a "top level" |CBB|, i.e. one initialised with + * |CBB_init| or |CBB_init_fixed|. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len); + +/* CBB_flush causes any pending length prefixes to be written out and any child + * |CBB| objects of |cbb| to be invalidated. It returns one on success or zero + * on error. */ +OPENSSL_EXPORT int CBB_flush(CBB *cbb); + +/* CBB_data returns a pointer to the bytes written to |cbb|. It does not flush + * |cbb|. The pointer is valid until the next operation to |cbb|. + * + * To avoid unfinalized length prefixes, it is a fatal error to call this on a + * CBB with any active children. */ +OPENSSL_EXPORT const uint8_t *CBB_data(const CBB *cbb); + +/* CBB_len returns the number of bytes written to |cbb|. It does not flush + * |cbb|. + * + * To avoid unfinalized length prefixes, it is a fatal error to call this on a + * CBB with any active children. */ +OPENSSL_EXPORT size_t CBB_len(const CBB *cbb); + +/* CBB_add_u8_length_prefixed sets |*out_contents| to a new child of |cbb|. The + * data written to |*out_contents| will be prefixed in |cbb| with an 8-bit + * length. It returns one on success or zero on error. */ +OPENSSL_EXPORT int CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents); + +/* CBB_add_u16_length_prefixed sets |*out_contents| to a new child of |cbb|. + * The data written to |*out_contents| will be prefixed in |cbb| with a 16-bit, + * big-endian length. It returns one on success or zero on error. */ +OPENSSL_EXPORT int CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents); + +/* CBB_add_u24_length_prefixed sets |*out_contents| to a new child of |cbb|. + * The data written to |*out_contents| will be prefixed in |cbb| with a 24-bit, + * big-endian length. It returns one on success or zero on error. */ +OPENSSL_EXPORT int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents); + +/* CBB_add_asn1 sets |*out_contents| to a |CBB| into which the contents of an + * ASN.1 object can be written. The |tag| argument will be used as the tag for + * the object. Passing in |tag| number 31 will return in an error since only + * single octet identifiers are supported. It returns one on success or zero + * on error. */ +OPENSSL_EXPORT int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag); + +/* CBB_add_bytes appends |len| bytes from |data| to |cbb|. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len); + +/* CBB_add_space appends |len| bytes to |cbb| and sets |*out_data| to point to + * the beginning of that space. The caller must then write |len| bytes of + * actual contents to |*out_data|. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len); + +/* CBB_reserve ensures |cbb| has room for |len| additional bytes and sets + * |*out_data| to point to the beginning of that space. It returns one on + * success and zero otherwise. The caller may write up to |len| bytes to + * |*out_data| and call |CBB_did_write| to complete the write. |*out_data| is + * valid until the next operation on |cbb| or an ancestor |CBB|. */ +OPENSSL_EXPORT int CBB_reserve(CBB *cbb, uint8_t **out_data, size_t len); + +/* CBB_did_write advances |cbb| by |len| bytes, assuming the space has been + * written to by the caller. It returns one on success and zero on error. */ +OPENSSL_EXPORT int CBB_did_write(CBB *cbb, size_t len); + +/* CBB_add_u8 appends an 8-bit number from |value| to |cbb|. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int CBB_add_u8(CBB *cbb, uint8_t value); + +/* CBB_add_u16 appends a 16-bit, big-endian number from |value| to |cbb|. It + * returns one on success and zero otherwise. */ +OPENSSL_EXPORT int CBB_add_u16(CBB *cbb, uint16_t value); + +/* CBB_add_u24 appends a 24-bit, big-endian number from |value| to |cbb|. It + * returns one on success and zero otherwise. */ +OPENSSL_EXPORT int CBB_add_u24(CBB *cbb, uint32_t value); + +/* CBB_discard_child discards the current unflushed child of |cbb|. Neither the + * child's contents nor the length prefix will be included in the output. */ +OPENSSL_EXPORT void CBB_discard_child(CBB *cbb); + +/* CBB_add_asn1_uint64 writes an ASN.1 INTEGER into |cbb| using |CBB_add_asn1| + * and writes |value| in its contents. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int CBB_add_asn1_uint64(CBB *cbb, uint64_t value); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BYTESTRING_H */ diff --git a/project/jni/boringssl/include/openssl/cast.h b/project/jni/boringssl/include/openssl/cast.h new file mode 100644 index 000000000..802172394 --- /dev/null +++ b/project/jni/boringssl/include/openssl/cast.h @@ -0,0 +1,96 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_CAST_H +#define OPENSSL_HEADER_CAST_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define CAST_ENCRYPT 1 +#define CAST_DECRYPT 0 + +#define CAST_BLOCK 8 +#define CAST_KEY_LENGTH 16 + +typedef struct cast_key_st { + uint32_t data[32]; + int short_key; /* Use reduced rounds for short key */ +} CAST_KEY; + +OPENSSL_EXPORT void CAST_set_key(CAST_KEY *key, size_t len, + const uint8_t *data); +OPENSSL_EXPORT void CAST_ecb_encrypt(const uint8_t *in, uint8_t *out, + const CAST_KEY *key, int enc); +OPENSSL_EXPORT void CAST_encrypt(uint32_t *data, const CAST_KEY *key); +OPENSSL_EXPORT void CAST_decrypt(uint32_t *data, const CAST_KEY *key); +OPENSSL_EXPORT void CAST_cbc_encrypt(const uint8_t *in, uint8_t *out, + long length, const CAST_KEY *ks, + uint8_t *iv, int enc); + +OPENSSL_EXPORT void CAST_cfb64_encrypt(const uint8_t *in, uint8_t *out, + long length, const CAST_KEY *schedule, + uint8_t *ivec, int *num, int enc); + +#ifdef __cplusplus +} +#endif + +#endif /* OPENSSL_HEADER_CAST_H */ diff --git a/project/jni/boringssl/include/openssl/chacha.h b/project/jni/boringssl/include/openssl/chacha.h new file mode 100644 index 000000000..64713c248 --- /dev/null +++ b/project/jni/boringssl/include/openssl/chacha.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_CHACHA_H +#define OPENSSL_HEADER_CHACHA_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* CRYPTO_chacha_20 encrypts |in_len| bytes from |in| with the given key and + * nonce and writes the result to |out|, which may be equal to |in|. The + * initial block counter is specified by |counter|. */ +OPENSSL_EXPORT void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, + size_t in_len, const uint8_t key[32], + const uint8_t nonce[12], uint32_t counter); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CHACHA_H */ diff --git a/project/jni/boringssl/include/openssl/cipher.h b/project/jni/boringssl/include/openssl/cipher.h new file mode 100644 index 000000000..fb7171f0b --- /dev/null +++ b/project/jni/boringssl/include/openssl/cipher.h @@ -0,0 +1,571 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_CIPHER_H +#define OPENSSL_HEADER_CIPHER_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Ciphers. */ + + +/* Cipher primitives. + * + * The following functions return |EVP_CIPHER| objects that implement the named + * cipher algorithm. */ + +OPENSSL_EXPORT const EVP_CIPHER *EVP_rc4(void); + +OPENSSL_EXPORT const EVP_CIPHER *EVP_des_cbc(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_des_ecb(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_des_ede(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_des_ede_cbc(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_des_ede3_cbc(void); + +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_ecb(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_cbc(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_ctr(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_ofb(void); + +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_ecb(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_cbc(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_ctr(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_ofb(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_xts(void); + +/* EVP_enc_null returns a 'cipher' that passes plaintext through as + * ciphertext. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_enc_null(void); + +/* EVP_rc2_cbc returns a cipher that implements 128-bit RC2 in CBC mode. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_rc2_cbc(void); + +/* EVP_rc2_40_cbc returns a cipher that implements 40-bit RC2 in CBC mode. This + * is obviously very, very weak and is included only in order to read PKCS#12 + * files, which often encrypt the certificate chain using this cipher. It is + * deliberately not exported. */ +const EVP_CIPHER *EVP_rc2_40_cbc(void); + +/* EVP_get_cipherbynid returns the cipher corresponding to the given NID, or + * NULL if no such cipher is known. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_get_cipherbynid(int nid); + + +/* Cipher context allocation. + * + * An |EVP_CIPHER_CTX| represents the state of an encryption or decryption in + * progress. */ + +/* EVP_CIPHER_CTX_init initialises an, already allocated, |EVP_CIPHER_CTX|. */ +OPENSSL_EXPORT void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_new allocates a fresh |EVP_CIPHER_CTX|, calls + * |EVP_CIPHER_CTX_init| and returns it, or NULL on allocation failure. */ +OPENSSL_EXPORT EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void); + +/* EVP_CIPHER_CTX_cleanup frees any memory referenced by |ctx|. It returns + * one. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_free calls |EVP_CIPHER_CTX_cleanup| on |ctx| and then frees + * |ctx| itself. */ +OPENSSL_EXPORT void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_copy sets |out| to be a duplicate of the current state of + * |in|. The |out| argument must have been previously initialised. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, + const EVP_CIPHER_CTX *in); + + +/* Cipher context configuration. */ + +/* EVP_CipherInit_ex configures |ctx| for a fresh encryption (or decryption, if + * |enc| is zero) operation using |cipher|. If |ctx| has been previously + * configured with a cipher then |cipher|, |key| and |iv| may be |NULL| and + * |enc| may be -1 to reuse the previous values. The operation will use |key| + * as the key and |iv| as the IV (if any). These should have the correct + * lengths given by |EVP_CIPHER_key_length| and |EVP_CIPHER_iv_length|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, ENGINE *engine, + const uint8_t *key, const uint8_t *iv, + int enc); + +/* EVP_EncryptInit_ex calls |EVP_CipherInit_ex| with |enc| equal to one. */ +OPENSSL_EXPORT int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, ENGINE *impl, + const uint8_t *key, const uint8_t *iv); + +/* EVP_DecryptInit_ex calls |EVP_CipherInit_ex| with |enc| equal to zero. */ +OPENSSL_EXPORT int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, ENGINE *impl, + const uint8_t *key, const uint8_t *iv); + + +/* Cipher operations. */ + +/* EVP_EncryptUpdate encrypts |in_len| bytes from |in| to |out|. The number + * of output bytes may be up to |in_len| plus the block length minus one and + * |out| must have sufficient space. The number of bytes actually output is + * written to |*out_len|. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, + int *out_len, const uint8_t *in, + int in_len); + +/* EVP_EncryptFinal_ex writes at most a block of ciphertext to |out| and sets + * |*out_len| to the number of bytes written. If padding is enabled (the + * default) then standard padding is applied to create the final block. If + * padding is disabled (with |EVP_CIPHER_CTX_set_padding|) then any partial + * block remaining will cause an error. The function returns one on success and + * zero otherwise. */ +OPENSSL_EXPORT int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, + int *out_len); + +/* EVP_DecryptUpdate decrypts |in_len| bytes from |in| to |out|. The number of + * output bytes may be up to |in_len| plus the block length minus one and |out| + * must have sufficient space. The number of bytes actually output is written + * to |*out_len|. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, + int *out_len, const uint8_t *in, + int in_len); + +/* EVP_DecryptFinal_ex writes at most a block of ciphertext to |out| and sets + * |*out_len| to the number of bytes written. If padding is enabled (the + * default) then padding is removed from the final block. + * + * WARNING: it is unsafe to call this function with unauthenticted + * ciphertext if padding is enabled. */ +OPENSSL_EXPORT int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, + int *out_len); + +/* EVP_Cipher performs a one-shot encryption/decryption operation. No partial + * blocks are maintained between calls. However, any internal cipher state is + * still updated. For CBC-mode ciphers, the IV is updated to the final + * ciphertext block. For stream ciphers, the stream is advanced past the bytes + * used. It returns one on success and zero otherwise, unless |EVP_CIPHER_flags| + * has |EVP_CIPH_FLAG_CUSTOM_CIPHER| set. Then it returns the number of bytes + * written or -1 on error. + * + * WARNING: this differs from the usual return value convention when using + * |EVP_CIPH_FLAG_CUSTOM_CIPHER|. + * + * TODO(davidben): The normal ciphers currently never fail, even if, e.g., + * |in_len| is not a multiple of the block size for CBC-mode decryption. The + * input just gets rounded up while the output gets truncated. This should + * either be officially documented or fail. */ +OPENSSL_EXPORT int EVP_Cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, + const uint8_t *in, size_t in_len); + +/* EVP_CipherUpdate calls either |EVP_EncryptUpdate| or |EVP_DecryptUpdate| + * depending on how |ctx| has been setup. */ +OPENSSL_EXPORT int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, + int *out_len, const uint8_t *in, + int in_len); + +/* EVP_CipherFinal_ex calls either |EVP_EncryptFinal_ex| or + * |EVP_DecryptFinal_ex| depending on how |ctx| has been setup. */ +OPENSSL_EXPORT int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, + int *out_len); + + +/* Cipher context accessors. */ + +/* EVP_CIPHER_CTX_cipher returns the |EVP_CIPHER| underlying |ctx|, or NULL if + * none has been set. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_CIPHER_CTX_cipher( + const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_nid returns a NID identifying the |EVP_CIPHER| underlying + * |ctx| (e.g. |NID_aes_128_gcm|). It will crash if no cipher has been + * configured. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_block_size returns the block size, in bytes, of the cipher + * underlying |ctx|, or one if the cipher is a stream cipher. It will crash if + * no cipher has been configured. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_key_length returns the key size, in bytes, of the cipher + * underlying |ctx| or zero if no cipher has been configured. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_iv_length returns the IV size, in bytes, of the cipher + * underlying |ctx|. It will crash if no cipher has been configured. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_get_app_data returns the opaque, application data pointer for + * |ctx|, or NULL if none has been set. */ +OPENSSL_EXPORT void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_set_app_data sets the opaque, application data pointer for + * |ctx| to |data|. */ +OPENSSL_EXPORT void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, + void *data); + +/* EVP_CIPHER_CTX_flags returns a value which is the OR of zero or more + * |EVP_CIPH_*| flags. It will crash if no cipher has been configured. */ +OPENSSL_EXPORT uint32_t EVP_CIPHER_CTX_flags(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_mode returns one of the |EVP_CIPH_*| cipher mode values + * enumerated below. It will crash if no cipher has been configured. */ +OPENSSL_EXPORT uint32_t EVP_CIPHER_CTX_mode(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_ctrl is an |ioctl| like function. The |command| argument + * should be one of the |EVP_CTRL_*| values. The |arg| and |ptr| arguments are + * specific to the command in question. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int command, + int arg, void *ptr); + +/* EVP_CIPHER_CTX_set_padding sets whether padding is enabled for |ctx| and + * returns one. Pass a non-zero |pad| to enable padding (the default) or zero + * to disable. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad); + +/* EVP_CIPHER_CTX_set_key_length sets the key length for |ctx|. This is only + * valid for ciphers that can take a variable length key. It returns one on + * success and zero on error. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *ctx, unsigned key_len); + + +/* Cipher accessors. */ + +/* EVP_CIPHER_nid returns a NID identifing |cipher|. (For example, + * |NID_aes_128_gcm|.) */ +OPENSSL_EXPORT int EVP_CIPHER_nid(const EVP_CIPHER *cipher); + +/* EVP_CIPHER_block_size returns the block size, in bytes, for |cipher|, or one + * if |cipher| is a stream cipher. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_block_size(const EVP_CIPHER *cipher); + +/* EVP_CIPHER_key_length returns the key size, in bytes, for |cipher|. If + * |cipher| can take a variable key length then this function returns the + * default key length and |EVP_CIPHER_flags| will return a value with + * |EVP_CIPH_VARIABLE_LENGTH| set. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_key_length(const EVP_CIPHER *cipher); + +/* EVP_CIPHER_iv_length returns the IV size, in bytes, of |cipher|, or zero if + * |cipher| doesn't take an IV. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_iv_length(const EVP_CIPHER *cipher); + +/* EVP_CIPHER_flags returns a value which is the OR of zero or more + * |EVP_CIPH_*| flags. */ +OPENSSL_EXPORT uint32_t EVP_CIPHER_flags(const EVP_CIPHER *cipher); + +/* EVP_CIPHER_mode returns one of the cipher mode values enumerated below. */ +OPENSSL_EXPORT uint32_t EVP_CIPHER_mode(const EVP_CIPHER *cipher); + + +/* Key derivation. */ + +/* EVP_BytesToKey generates a key and IV for the cipher |type| by iterating + * |md| |count| times using |data| and |salt|. On entry, the |key| and |iv| + * buffers must have enough space to hold a key and IV for |type|. It returns + * the length of the key on success or zero on error. */ +OPENSSL_EXPORT int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md, + const uint8_t *salt, const uint8_t *data, + size_t data_len, unsigned count, uint8_t *key, + uint8_t *iv); + + +/* Cipher modes (for |EVP_CIPHER_mode|). */ + +#define EVP_CIPH_STREAM_CIPHER 0x0 +#define EVP_CIPH_ECB_MODE 0x1 +#define EVP_CIPH_CBC_MODE 0x2 +#define EVP_CIPH_CFB_MODE 0x3 +#define EVP_CIPH_OFB_MODE 0x4 +#define EVP_CIPH_CTR_MODE 0x5 +#define EVP_CIPH_GCM_MODE 0x6 +#define EVP_CIPH_XTS_MODE 0x7 + + +/* Cipher flags (for |EVP_CIPHER_flags|). */ + +/* EVP_CIPH_VARIABLE_LENGTH indicates that the cipher takes a variable length + * key. */ +#define EVP_CIPH_VARIABLE_LENGTH 0x40 + +/* EVP_CIPH_ALWAYS_CALL_INIT indicates that the |init| function for the cipher + * should always be called when initialising a new operation, even if the key + * is NULL to indicate that the same key is being used. */ +#define EVP_CIPH_ALWAYS_CALL_INIT 0x80 + +/* EVP_CIPH_CUSTOM_IV indicates that the cipher manages the IV itself rather + * than keeping it in the |iv| member of |EVP_CIPHER_CTX|. */ +#define EVP_CIPH_CUSTOM_IV 0x100 + +/* EVP_CIPH_CTRL_INIT indicates that EVP_CTRL_INIT should be used when + * initialising an |EVP_CIPHER_CTX|. */ +#define EVP_CIPH_CTRL_INIT 0x200 + +/* EVP_CIPH_FLAG_CUSTOM_CIPHER indicates that the cipher manages blocking + * itself. This causes EVP_(En|De)crypt_ex to be simple wrapper functions. */ +#define EVP_CIPH_FLAG_CUSTOM_CIPHER 0x400 + +/* EVP_CIPH_FLAG_AEAD_CIPHER specifies that the cipher is an AEAD. This is an + * older version of the proper AEAD interface. See aead.h for the current + * one. */ +#define EVP_CIPH_FLAG_AEAD_CIPHER 0x800 + +/* EVP_CIPH_CUSTOM_COPY indicates that the |ctrl| callback should be called + * with |EVP_CTRL_COPY| at the end of normal |EVP_CIPHER_CTX_copy| + * processing. */ +#define EVP_CIPH_CUSTOM_COPY 0x1000 + + +/* Deprecated functions */ + +/* EVP_CipherInit acts like EVP_CipherInit_ex except that |EVP_CIPHER_CTX_init| + * is called on |cipher| first, if |cipher| is not NULL. */ +OPENSSL_EXPORT int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const uint8_t *key, const uint8_t *iv, + int enc); + +/* EVP_EncryptInit calls |EVP_CipherInit| with |enc| equal to one. */ +OPENSSL_EXPORT int EVP_EncryptInit(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, const uint8_t *key, + const uint8_t *iv); + +/* EVP_DecryptInit calls |EVP_CipherInit| with |enc| equal to zero. */ +OPENSSL_EXPORT int EVP_DecryptInit(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, const uint8_t *key, + const uint8_t *iv); + +/* EVP_add_cipher_alias does nothing and returns one. */ +OPENSSL_EXPORT int EVP_add_cipher_alias(const char *a, const char *b); + +/* EVP_get_cipherbyname returns an |EVP_CIPHER| given a human readable name in + * |name|, or NULL if the name is unknown. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_get_cipherbyname(const char *name); + +/* These AEADs are deprecated AES-GCM implementations that set + * |EVP_CIPH_FLAG_CUSTOM_CIPHER|. Use |EVP_aead_aes_128_gcm| and + * |EVP_aead_aes_256_gcm| instead. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_gcm(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_gcm(void); + +/* These are deprecated, 192-bit version of AES. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_192_ecb(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_192_cbc(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_192_ctr(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_192_gcm(void); + + +/* Private functions. */ + +/* EVP_CIPH_NO_PADDING disables padding in block ciphers. */ +#define EVP_CIPH_NO_PADDING 0x800 + +/* EVP_CIPHER_CTX_ctrl commands. */ +#define EVP_CTRL_INIT 0x0 +#define EVP_CTRL_SET_KEY_LENGTH 0x1 +#define EVP_CTRL_GET_RC2_KEY_BITS 0x2 +#define EVP_CTRL_SET_RC2_KEY_BITS 0x3 +#define EVP_CTRL_GET_RC5_ROUNDS 0x4 +#define EVP_CTRL_SET_RC5_ROUNDS 0x5 +#define EVP_CTRL_RAND_KEY 0x6 +#define EVP_CTRL_PBE_PRF_NID 0x7 +#define EVP_CTRL_COPY 0x8 +#define EVP_CTRL_GCM_SET_IVLEN 0x9 +#define EVP_CTRL_GCM_GET_TAG 0x10 +#define EVP_CTRL_GCM_SET_TAG 0x11 +#define EVP_CTRL_GCM_SET_IV_FIXED 0x12 +#define EVP_CTRL_GCM_IV_GEN 0x13 +#define EVP_CTRL_AEAD_SET_MAC_KEY 0x17 +/* Set the GCM invocation field, decrypt only */ +#define EVP_CTRL_GCM_SET_IV_INV 0x18 + +/* GCM TLS constants */ +/* Length of fixed part of IV derived from PRF */ +#define EVP_GCM_TLS_FIXED_IV_LEN 4 +/* Length of explicit part of IV part of TLS records */ +#define EVP_GCM_TLS_EXPLICIT_IV_LEN 8 +/* Length of tag for TLS */ +#define EVP_GCM_TLS_TAG_LEN 16 + +#define EVP_MAX_KEY_LENGTH 64 +#define EVP_MAX_IV_LENGTH 16 +#define EVP_MAX_BLOCK_LENGTH 32 + +struct evp_cipher_ctx_st { + /* cipher contains the underlying cipher for this context. */ + const EVP_CIPHER *cipher; + + /* app_data is a pointer to opaque, user data. */ + void *app_data; /* application stuff */ + + /* cipher_data points to the |cipher| specific state. */ + void *cipher_data; + + /* key_len contains the length of the key, which may differ from + * |cipher->key_len| if the cipher can take a variable key length. */ + unsigned key_len; + + /* encrypt is one if encrypting and zero if decrypting. */ + int encrypt; + + /* flags contains the OR of zero or more |EVP_CIPH_*| flags, above. */ + uint32_t flags; + + /* oiv contains the original IV value. */ + uint8_t oiv[EVP_MAX_IV_LENGTH]; + + /* iv contains the current IV value, which may have been updated. */ + uint8_t iv[EVP_MAX_IV_LENGTH]; + + /* buf contains a partial block which is used by, for example, CTR mode to + * store unused keystream bytes. */ + uint8_t buf[EVP_MAX_BLOCK_LENGTH]; + + /* buf_len contains the number of bytes of a partial block contained in + * |buf|. */ + int buf_len; + + /* num contains the number of bytes of |iv| which are valid for modes that + * manage partial blocks themselves. */ + int num; + + /* final_used is non-zero if the |final| buffer contains plaintext. */ + int final_used; + + /* block_mask contains |cipher->block_size| minus one. (The block size + * assumed to be a power of two.) */ + int block_mask; + + uint8_t final[EVP_MAX_BLOCK_LENGTH]; /* possible final block */ +} /* EVP_CIPHER_CTX */; + +typedef struct evp_cipher_info_st { + const EVP_CIPHER *cipher; + unsigned char iv[EVP_MAX_IV_LENGTH]; +} EVP_CIPHER_INFO; + +struct evp_cipher_st { + /* type contains a NID identifing the cipher. (e.g. NID_aes_128_gcm.) */ + int nid; + + /* block_size contains the block size, in bytes, of the cipher, or 1 for a + * stream cipher. */ + unsigned block_size; + + /* key_len contains the key size, in bytes, for the cipher. If the cipher + * takes a variable key size then this contains the default size. */ + unsigned key_len; + + /* iv_len contains the IV size, in bytes, or zero if inapplicable. */ + unsigned iv_len; + + /* ctx_size contains the size, in bytes, of the per-key context for this + * cipher. */ + unsigned ctx_size; + + /* flags contains the OR of a number of flags. See |EVP_CIPH_*|. */ + uint32_t flags; + + /* app_data is a pointer to opaque, user data. */ + void *app_data; + + int (*init)(EVP_CIPHER_CTX *ctx, const uint8_t *key, const uint8_t *iv, + int enc); + + int (*cipher)(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t inl); + + /* cleanup, if non-NULL, releases memory associated with the context. It is + * called if |EVP_CTRL_INIT| succeeds. Note that |init| may not have been + * called at this point. */ + void (*cleanup)(EVP_CIPHER_CTX *); + + int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr); +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define CIPHER_R_AES_KEY_SETUP_FAILED 100 +#define CIPHER_R_BAD_DECRYPT 101 +#define CIPHER_R_BAD_KEY_LENGTH 102 +#define CIPHER_R_BUFFER_TOO_SMALL 103 +#define CIPHER_R_CTRL_NOT_IMPLEMENTED 104 +#define CIPHER_R_CTRL_OPERATION_NOT_IMPLEMENTED 105 +#define CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH 106 +#define CIPHER_R_INITIALIZATION_ERROR 107 +#define CIPHER_R_INPUT_NOT_INITIALIZED 108 +#define CIPHER_R_INVALID_AD_SIZE 109 +#define CIPHER_R_INVALID_KEY_LENGTH 110 +#define CIPHER_R_INVALID_NONCE_SIZE 111 +#define CIPHER_R_INVALID_OPERATION 112 +#define CIPHER_R_IV_TOO_LARGE 113 +#define CIPHER_R_NO_CIPHER_SET 114 +#define CIPHER_R_OUTPUT_ALIASES_INPUT 115 +#define CIPHER_R_TAG_TOO_LARGE 116 +#define CIPHER_R_TOO_LARGE 117 +#define CIPHER_R_UNSUPPORTED_AD_SIZE 118 +#define CIPHER_R_UNSUPPORTED_INPUT_SIZE 119 +#define CIPHER_R_UNSUPPORTED_KEY_SIZE 120 +#define CIPHER_R_UNSUPPORTED_NONCE_SIZE 121 +#define CIPHER_R_UNSUPPORTED_TAG_SIZE 122 +#define CIPHER_R_WRONG_FINAL_BLOCK_LENGTH 123 +#define CIPHER_R_NO_DIRECTION_SET 124 + +#endif /* OPENSSL_HEADER_CIPHER_H */ diff --git a/project/jni/boringssl/include/openssl/cmac.h b/project/jni/boringssl/include/openssl/cmac.h new file mode 100644 index 000000000..0bb44b952 --- /dev/null +++ b/project/jni/boringssl/include/openssl/cmac.h @@ -0,0 +1,76 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_CMAC_H +#define OPENSSL_HEADER_CMAC_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* CMAC. + * + * CMAC is a MAC based on AES-CBC and defined in + * https://tools.ietf.org/html/rfc4493#section-2.3. */ + + +/* One-shot functions. */ + +/* AES_CMAC calculates the 16-byte, CMAC authenticator of |in_len| bytes of + * |in| and writes it to |out|. The |key_len| may be 16 or 32 bytes to select + * between AES-128 and AES-256. It returns one on success or zero on error. */ +OPENSSL_EXPORT int AES_CMAC(uint8_t out[16], const uint8_t *key, size_t key_len, + const uint8_t *in, size_t in_len); + + +/* Incremental interface. */ + +/* CMAC_CTX_new allocates a fresh |CMAC_CTX| and returns it, or NULL on + * error. */ +OPENSSL_EXPORT CMAC_CTX *CMAC_CTX_new(void); + +/* CMAC_CTX_free frees a |CMAC_CTX|. */ +OPENSSL_EXPORT void CMAC_CTX_free(CMAC_CTX *ctx); + +/* CMAC_Init configures |ctx| to use the given |key| and |cipher|. The CMAC RFC + * only specifies the use of AES-128 thus |key_len| should be 16 and |cipher| + * should be |EVP_aes_128_cbc()|. However, this implementation also supports + * AES-256 by setting |key_len| to 32 and |cipher| to |EVP_aes_256_cbc()|. The + * |engine| argument is ignored. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t key_len, + const EVP_CIPHER *cipher, ENGINE *engine); + + +/* CMAC_Reset resets |ctx| so that a fresh message can be authenticated. */ +OPENSSL_EXPORT int CMAC_Reset(CMAC_CTX *ctx); + +/* CMAC_Update processes |in_len| bytes of message from |in|. It returns one on + * success or zero on error. */ +OPENSSL_EXPORT int CMAC_Update(CMAC_CTX *ctx, const uint8_t *in, size_t in_len); + +/* CMAC_Final sets |*out_len| to 16 and, if |out| is not NULL, writes 16 bytes + * of authenticator to it. It returns one on success or zero on error. */ +OPENSSL_EXPORT int CMAC_Final(CMAC_CTX *ctx, uint8_t *out, size_t *out_len); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CMAC_H */ diff --git a/project/jni/boringssl/include/openssl/conf.h b/project/jni/boringssl/include/openssl/conf.h new file mode 100644 index 000000000..a2741a8ae --- /dev/null +++ b/project/jni/boringssl/include/openssl/conf.h @@ -0,0 +1,145 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_CONF_H +#define OPENSSL_HEADER_CONF_H + +#include + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Config files look like: + * + * # Comment + * + * # This key is in the default section. + * key=value + * + * [section_name] + * key2=value2 + * + * Config files are representated by a |CONF|. */ + +struct conf_value_st { + char *section; + char *name; + char *value; +}; + +struct conf_st { + LHASH_OF(CONF_VALUE) *data; +}; + + +/* NCONF_new returns a fresh, empty |CONF|, or NULL on error. The |method| + * argument must be NULL. */ +CONF *NCONF_new(void *method); + +/* NCONF_free frees all the data owned by |conf| and then |conf| itself. */ +void NCONF_free(CONF *conf); + +/* NCONF_load parses the file named |filename| and adds the values found to + * |conf|. It returns one on success and zero on error. In the event of an + * error, if |out_error_line| is not NULL, |*out_error_line| is set to the + * number of the line that contained the error. */ +int NCONF_load(CONF *conf, const char *filename, long *out_error_line); + +/* NCONF_load_bio acts like |NCONF_load| but reads from |bio| rather than from + * a named file. */ +int NCONF_load_bio(CONF *conf, BIO *bio, long *out_error_line); + +/* NCONF_get_section returns a stack of values for a given section in |conf|. + * If |section| is NULL, the default section is returned. It returns NULL on + * error. */ +STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf, const char *section); + +/* NCONF_get_string returns the value of the key |name|, in section |section|. + * The |section| argument may be NULL to indicate the default section. It + * returns the value or NULL on error. */ +const char *NCONF_get_string(const CONF *conf, const char *section, + const char *name); + + +/* Utility functions */ + +/* CONF_parse_list takes a list separated by 'sep' and calls |list_cb| giving + * the start and length of each member, optionally stripping leading and + * trailing whitespace. This can be used to parse comma separated lists for + * example. If |list_cb| returns <= 0, then the iteration is halted and that + * value is returned immediately. Otherwise it returns one. Note that |list_cb| + * may be called on an empty member. */ +int CONF_parse_list(const char *list, char sep, int remove_whitespace, + int (*list_cb)(const char *elem, int len, void *usr), + void *arg); + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define CONF_R_LIST_CANNOT_BE_NULL 100 +#define CONF_R_MISSING_CLOSE_SQUARE_BRACKET 101 +#define CONF_R_MISSING_EQUAL_SIGN 102 +#define CONF_R_NO_CLOSE_BRACE 103 +#define CONF_R_UNABLE_TO_CREATE_NEW_SECTION 104 +#define CONF_R_VARIABLE_HAS_NO_VALUE 105 + +#endif /* OPENSSL_HEADER_THREAD_H */ diff --git a/project/jni/boringssl/include/openssl/cpu.h b/project/jni/boringssl/include/openssl/cpu.h new file mode 100644 index 000000000..e946304a3 --- /dev/null +++ b/project/jni/boringssl/include/openssl/cpu.h @@ -0,0 +1,184 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_CPU_H +#define OPENSSL_HEADER_CPU_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Runtime CPU feature support */ + + +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) +/* OPENSSL_ia32cap_P contains the Intel CPUID bits when running on an x86 or + * x86-64 system. + * + * Index 0: + * EDX for CPUID where EAX = 1 + * Bit 20 is always zero + * Bit 28 is adjusted to reflect whether the data cache is shared between + * multiple logical cores + * Bit 30 is used to indicate an Intel CPU + * Index 1: + * ECX for CPUID where EAX = 1 + * Bit 11 is used to indicate AMD XOP support, not SDBG + * Index 2: + * EBX for CPUID where EAX = 7 + * Index 3 is set to zero. + * + * Note: the CPUID bits are pre-adjusted for the OSXSAVE bit and the YMM and XMM + * bits in XCR0, so it is not necessary to check those. */ +extern uint32_t OPENSSL_ia32cap_P[4]; +#endif + +#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) + +#if defined(OPENSSL_APPLE) +/* iOS builds use the static ARM configuration. */ +#define OPENSSL_STATIC_ARMCAP +#endif + +#if !defined(OPENSSL_STATIC_ARMCAP) + +/* CRYPTO_is_NEON_capable_at_runtime returns true if the current CPU has a NEON + * unit. Note that |OPENSSL_armcap_P| also exists and contains the same + * information in a form that's easier for assembly to use. */ +OPENSSL_EXPORT char CRYPTO_is_NEON_capable_at_runtime(void); + +/* CRYPTO_is_NEON_capable returns true if the current CPU has a NEON unit. If + * this is known statically then it returns one immediately. */ +static inline int CRYPTO_is_NEON_capable(void) { +#if defined(__ARM_NEON__) + return 1; +#else + return CRYPTO_is_NEON_capable_at_runtime(); +#endif +} + +/* CRYPTO_set_NEON_capable sets the return value of |CRYPTO_is_NEON_capable|. + * By default, unless the code was compiled with |-mfpu=neon|, NEON is assumed + * not to be present. It is not autodetected. Calling this with a zero + * argument also causes |CRYPTO_is_NEON_functional| to return false. */ +OPENSSL_EXPORT void CRYPTO_set_NEON_capable(char neon_capable); + +/* CRYPTO_is_NEON_functional returns true if the current CPU has a /working/ + * NEON unit. Some phones have a NEON unit, but the Poly1305 NEON code causes + * it to fail. See https://code.google.com/p/chromium/issues/detail?id=341598 */ +OPENSSL_EXPORT char CRYPTO_is_NEON_functional(void); + +/* CRYPTO_set_NEON_functional sets the "NEON functional" flag. For + * |CRYPTO_is_NEON_functional| to return true, both this flag and the NEON flag + * must be true. By default NEON is assumed to be functional if the code was + * compiled with |-mfpu=neon| or if |CRYPTO_set_NEON_capable| has been called + * with a non-zero argument. */ +OPENSSL_EXPORT void CRYPTO_set_NEON_functional(char neon_functional); + +/* CRYPTO_is_ARMv8_AES_capable returns true if the current CPU supports the + * ARMv8 AES instruction. */ +int CRYPTO_is_ARMv8_AES_capable(void); + +/* CRYPTO_is_ARMv8_PMULL_capable returns true if the current CPU supports the + * ARMv8 PMULL instruction. */ +int CRYPTO_is_ARMv8_PMULL_capable(void); + +#else + +static inline int CRYPTO_is_NEON_capable(void) { +#if defined(OPENSSL_STATIC_ARMCAP_NEON) || defined(__ARM_NEON__) + return 1; +#else + return 0; +#endif +} + +static inline int CRYPTO_is_NEON_functional(void) { + return CRYPTO_is_NEON_capable(); +} + +static inline int CRYPTO_is_ARMv8_AES_capable(void) { +#if defined(OPENSSL_STATIC_ARMCAP_AES) + return 1; +#else + return 0; +#endif +} + +static inline int CRYPTO_is_ARMv8_PMULL_capable(void) { +#if defined(OPENSSL_STATIC_ARMCAP_PMULL) + return 1; +#else + return 0; +#endif +} + +#endif /* OPENSSL_STATIC_ARMCAP */ +#endif /* OPENSSL_ARM */ + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CPU_H */ diff --git a/project/jni/boringssl/include/openssl/crypto.h b/project/jni/boringssl/include/openssl/crypto.h new file mode 100644 index 000000000..b42188473 --- /dev/null +++ b/project/jni/boringssl/include/openssl/crypto.h @@ -0,0 +1,68 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_CRYPTO_H +#define OPENSSL_HEADER_CRYPTO_H + +#include + +/* Upstream OpenSSL defines |OPENSSL_malloc|, etc., in crypto.h rather than + * mem.h. */ +#include + +/* Upstream OpenSSL defines |CRYPTO_LOCK|, etc., in crypto.h rather than + * thread.h. */ +#include + + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* crypto.h contains functions for initializing the crypto library. */ + + +/* CRYPTO_library_init initializes the crypto library. It must be called if the + * library is built with BORINGSSL_NO_STATIC_INITIALIZER. Otherwise, it does + * nothing and a static initializer is used instead. */ +OPENSSL_EXPORT void CRYPTO_library_init(void); + + +/* Deprecated functions. */ + +#define OPENSSL_VERSION_TEXT "BoringSSL" + +#define SSLEAY_VERSION 0 + +/* SSLeay_version is a compatibility function that returns the string + * "BoringSSL". */ +OPENSSL_EXPORT const char *SSLeay_version(int unused); + +/* SSLeay is a compatibility function that returns OPENSSL_VERSION_NUMBER from + * base.h. */ +OPENSSL_EXPORT unsigned long SSLeay(void); + +/* CRYPTO_malloc_init returns one. */ +OPENSSL_EXPORT int CRYPTO_malloc_init(void); + +/* ENGINE_load_builtin_engines does nothing. */ +OPENSSL_EXPORT void ENGINE_load_builtin_engines(void); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CRYPTO_H */ diff --git a/project/jni/boringssl/include/openssl/curve25519.h b/project/jni/boringssl/include/openssl/curve25519.h new file mode 100644 index 000000000..30c647015 --- /dev/null +++ b/project/jni/boringssl/include/openssl/curve25519.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_CURVE25519_H +#define OPENSSL_HEADER_CURVE25519_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Curve25519. + * + * Curve25519 is an elliptic curve. See + * https://tools.ietf.org/html/draft-irtf-cfrg-curves-11. */ + + +/* X25519. + * + * Curve25519 is an elliptic curve. The same name is also sometimes used for + * the Diffie-Hellman primitive built from it but “X25519” is a more precise + * name for that, which is the one used here. See http://cr.yp.to/ecdh.html and + * https://tools.ietf.org/html/draft-irtf-cfrg-curves-11. */ + +/* X25519_keypair sets |out_public_value| and |out_private_key| to a freshly + * generated, public–private key pair. */ +OPENSSL_EXPORT void X25519_keypair(uint8_t out_public_value[32], + uint8_t out_private_key[32]); + +/* X25519 writes a shared key to |out_shared_key| that is calculated from the + * given private key and the peer's public value. It returns one on success and + * zero on error. + * + * Don't use the shared key directly, rather use a KDF and also include the two + * public values as inputs. */ +OPENSSL_EXPORT int X25519(uint8_t out_shared_key[32], + const uint8_t private_key[32], + const uint8_t peers_public_value[32]); + +/* X25519_public_from_private calculates a Diffie-Hellman public value from the + * given private key and writes it to |out_public_value|. */ +OPENSSL_EXPORT void X25519_public_from_private(uint8_t out_public_value[32], + const uint8_t private_key[32]); + + +/* Ed25519. + * + * Ed25519 is a signature scheme using a twisted-Edwards curve that is + * birationally equivalent to curve25519. */ + +#define ED25519_PRIVATE_KEY_LEN 64 +#define ED25519_PUBLIC_KEY_LEN 32 +#define ED25519_SIGNATURE_LEN 64 + +/* ED25519_keypair sets |out_public_key| and |out_private_key| to a freshly + * generated, public–private key pair. */ +OPENSSL_EXPORT void ED25519_keypair(uint8_t out_public_key[32], + uint8_t out_private_key[64]); + +/* ED25519_sign sets |out_sig| to be a signature of |message_len| bytes from + * |message| using |private_key|. It returns one on success or zero on + * error. */ +OPENSSL_EXPORT int ED25519_sign(uint8_t out_sig[64], const uint8_t *message, + size_t message_len, + const uint8_t private_key[64]); + +/* ED25519_verify returns one iff |signature| is a valid signature, by + * |public_key| of |message_len| bytes from |message|. It returns zero + * otherwise. */ +OPENSSL_EXPORT int ED25519_verify(const uint8_t *message, size_t message_len, + const uint8_t signature[64], + const uint8_t public_key[32]); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CURVE25519_H */ diff --git a/project/jni/boringssl/include/openssl/des.h b/project/jni/boringssl/include/openssl/des.h new file mode 100644 index 000000000..2b8dd0f62 --- /dev/null +++ b/project/jni/boringssl/include/openssl/des.h @@ -0,0 +1,177 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_DES_H +#define OPENSSL_HEADER_DES_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* DES. */ + + +typedef struct DES_cblock_st { + uint8_t bytes[8]; +} DES_cblock; + +typedef struct DES_ks { + uint32_t subkeys[16][2]; +} DES_key_schedule; + + +#define DES_KEY_SZ (sizeof(DES_cblock)) +#define DES_SCHEDULE_SZ (sizeof(DES_key_schedule)) + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +#define DES_CBC_MODE 0 +#define DES_PCBC_MODE 1 + +/* DES_set_key performs a key schedule and initialises |schedule| with |key|. */ +OPENSSL_EXPORT void DES_set_key(const DES_cblock *key, + DES_key_schedule *schedule); + +/* DES_set_odd_parity sets the parity bits (the least-significant bits in each + * byte) of |key| given the other bits in each byte. */ +OPENSSL_EXPORT void DES_set_odd_parity(DES_cblock *key); + +/* DES_ecb_encrypt encrypts (or decrypts, if |is_encrypt| is |DES_DECRYPT|) a + * single DES block (8 bytes) from in to out, using the key configured in + * |schedule|. */ +OPENSSL_EXPORT void DES_ecb_encrypt(const DES_cblock *in, DES_cblock *out, + const DES_key_schedule *schedule, + int is_encrypt); + +/* DES_ncbc_encrypt encrypts (or decrypts, if |enc| is |DES_DECRYPT|) |len| + * bytes from |in| to |out| with DES in CBC mode. */ +OPENSSL_EXPORT void DES_ncbc_encrypt(const uint8_t *in, uint8_t *out, + size_t len, + const DES_key_schedule *schedule, + DES_cblock *ivec, int enc); + +/* DES_ecb3_encrypt encrypts (or decrypts, if |enc| is |DES_DECRYPT|) a single + * block (8 bytes) of data from |input| to |output| using 3DES. */ +OPENSSL_EXPORT void DES_ecb3_encrypt(const DES_cblock *input, + DES_cblock *output, + const DES_key_schedule *ks1, + const DES_key_schedule *ks2, + const DES_key_schedule *ks3, + int enc); + +/* DES_ede3_cbc_encrypt encrypts (or decrypts, if |enc| is |DES_DECRYPT|) |len| + * bytes from |in| to |out| with 3DES in CBC mode. 3DES uses three keys, thus + * the function takes three different |DES_key_schedule|s. */ +OPENSSL_EXPORT void DES_ede3_cbc_encrypt(const uint8_t *in, uint8_t *out, + size_t len, + const DES_key_schedule *ks1, + const DES_key_schedule *ks2, + const DES_key_schedule *ks3, + DES_cblock *ivec, int enc); + +/* DES_ede2_cbc_encrypt encrypts (or decrypts, if |enc| is |DES_DECRYPT|) |len| + * bytes from |in| to |out| with 3DES in CBC mode. With this keying option, the + * first and third 3DES keys are identical. Thus, this function takes only two + * different |DES_key_schedule|s. */ +OPENSSL_EXPORT void DES_ede2_cbc_encrypt(const uint8_t *in, uint8_t *out, + size_t len, + const DES_key_schedule *ks1, + const DES_key_schedule *ks2, + DES_cblock *ivec, int enc); + + +/* Deprecated functions. */ + +/* DES_set_key_unchecked calls |DES_set_key|. */ +OPENSSL_EXPORT void DES_set_key_unchecked(const DES_cblock *key, + DES_key_schedule *schedule); + +OPENSSL_EXPORT void DES_ede3_cfb64_encrypt(const uint8_t *in, uint8_t *out, + long length, DES_key_schedule *ks1, + DES_key_schedule *ks2, + DES_key_schedule *ks3, + DES_cblock *ivec, int *num, int enc); + +OPENSSL_EXPORT void DES_ede3_cfb_encrypt(const uint8_t *in, uint8_t *out, + int numbits, long length, + DES_key_schedule *ks1, + DES_key_schedule *ks2, + DES_key_schedule *ks3, + DES_cblock *ivec, int enc); + + +/* Private functions. + * + * These functions are only exported for use in |decrepit|. */ + +OPENSSL_EXPORT void DES_decrypt3(uint32_t *data, const DES_key_schedule *ks1, + const DES_key_schedule *ks2, + const DES_key_schedule *ks3); + +OPENSSL_EXPORT void DES_encrypt3(uint32_t *data, const DES_key_schedule *ks1, + const DES_key_schedule *ks2, + const DES_key_schedule *ks3); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_DES_H */ diff --git a/project/jni/boringssl/include/openssl/dh.h b/project/jni/boringssl/include/openssl/dh.h new file mode 100644 index 000000000..2c49fc834 --- /dev/null +++ b/project/jni/boringssl/include/openssl/dh.h @@ -0,0 +1,238 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_DH_H +#define OPENSSL_HEADER_DH_H + +#include + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* DH contains functions for performing Diffie-Hellman key agreement in + * multiplicative groups. */ + + +/* Allocation and destruction. */ + +/* DH_new returns a new, empty DH object or NULL on error. */ +OPENSSL_EXPORT DH *DH_new(void); + +/* DH_free decrements the reference count of |dh| and frees it if the reference + * count drops to zero. */ +OPENSSL_EXPORT void DH_free(DH *dh); + +/* DH_up_ref increments the reference count of |dh|. */ +OPENSSL_EXPORT int DH_up_ref(DH *dh); + + +/* Standard parameters. + * + * These functions return new DH objects with standard parameters. They return + * NULL on allocation failure. The |engine| parameter is ignored. */ + +/* These parameters are taken from RFC 5114. */ + +OPENSSL_EXPORT DH *DH_get_1024_160(const ENGINE *engine); +OPENSSL_EXPORT DH *DH_get_2048_224(const ENGINE *engine); +OPENSSL_EXPORT DH *DH_get_2048_256(const ENGINE *engine); + + +/* Parameter generation. */ + +#define DH_GENERATOR_2 2 +#define DH_GENERATOR_5 5 + +/* DH_generate_parameters_ex generates a suitable Diffie-Hellman group with a + * prime that is |prime_bits| long and stores it in |dh|. The generator of the + * group will be |generator|, which should be |DH_GENERATOR_2| unless there's a + * good reason to use a different value. The |cb| argument contains a callback + * function that will be called during the generation. See the documentation in + * |bn.h| about this. In addition to the callback invocations from |BN|, |cb| + * will also be called with |event| equal to three when the generation is + * complete. */ +OPENSSL_EXPORT int DH_generate_parameters_ex(DH *dh, int prime_bits, + int generator, BN_GENCB *cb); + + +/* Diffie-Hellman operations. */ + +/* DH_generate_key generates a new, random, private key and stores it in + * |dh|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int DH_generate_key(DH *dh); + +/* DH_compute_key calculates the shared key between |dh| and |peers_key| and + * writes it as a big-endian integer into |out|, which must have |DH_size| + * bytes of space. It returns the number of bytes written, or a negative number + * on error. */ +OPENSSL_EXPORT int DH_compute_key(uint8_t *out, const BIGNUM *peers_key, + DH *dh); + + +/* Utility functions. */ + +/* DH_size returns the number of bytes in the DH group's prime. */ +OPENSSL_EXPORT int DH_size(const DH *dh); + +/* DH_num_bits returns the minimum number of bits needed to represent the + * absolute value of the DH group's prime. */ +OPENSSL_EXPORT unsigned DH_num_bits(const DH *dh); + +#define DH_CHECK_P_NOT_PRIME 0x01 +#define DH_CHECK_P_NOT_SAFE_PRIME 0x02 +#define DH_CHECK_UNABLE_TO_CHECK_GENERATOR 0x04 +#define DH_CHECK_NOT_SUITABLE_GENERATOR 0x08 +#define DH_CHECK_Q_NOT_PRIME 0x10 +#define DH_CHECK_INVALID_Q_VALUE 0x20 +#define DH_CHECK_INVALID_J_VALUE 0x40 + +/* These are compatibility defines. */ +#define DH_NOT_SUITABLE_GENERATOR DH_CHECK_NOT_SUITABLE_GENERATOR +#define DH_UNABLE_TO_CHECK_GENERATOR DH_CHECK_UNABLE_TO_CHECK_GENERATOR + +/* DH_check checks the suitability of |dh| as a Diffie-Hellman group. and sets + * |DH_CHECK_*| flags in |*out_flags| if it finds any errors. It returns one if + * |*out_flags| was successfully set and zero on error. + * + * Note: these checks may be quite computationally expensive. */ +OPENSSL_EXPORT int DH_check(const DH *dh, int *out_flags); + +#define DH_CHECK_PUBKEY_TOO_SMALL 1 +#define DH_CHECK_PUBKEY_TOO_LARGE 2 + +/* DH_check_pub_key checks the suitability of |pub_key| as a public key for the + * DH group in |dh| and sets |DH_CHECK_PUBKEY_*| flags in |*out_flags| if it + * finds any errors. It returns one if |*out_flags| was successfully set and + * zero on error. */ +OPENSSL_EXPORT int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, + int *out_flags); + +/* DHparams_dup allocates a fresh |DH| and copies the parameters from |dh| into + * it. It returns the new |DH| or NULL on error. */ +OPENSSL_EXPORT DH *DHparams_dup(const DH *dh); + + +/* ASN.1 functions. */ + +/* d2i_DHparams parses an ASN.1, DER encoded Diffie-Hellman parameters + * structure from |len| bytes at |*inp|. If |ret| is not NULL then, on exit, a + * pointer to the result is in |*ret|. If |*ret| is already non-NULL on entry + * then the result is written directly into |*ret|, otherwise a fresh |DH| is + * allocated. On successful exit, |*inp| is advanced past the DER structure. It + * returns the result or NULL on error. */ +OPENSSL_EXPORT DH *d2i_DHparams(DH **ret, const unsigned char **inp, long len); + +/* i2d_DHparams marshals |in| to an ASN.1, DER structure. If |outp| is not NULL + * then the result is written to |*outp| and |*outp| is advanced just past the + * output. It returns the number of bytes in the result, whether written or + * not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_DHparams(const DH *in, unsigned char **outp); + + +/* ex_data functions. + * + * See |ex_data.h| for details. */ + +OPENSSL_EXPORT int DH_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_unused *unused, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int DH_set_ex_data(DH *d, int idx, void *arg); +OPENSSL_EXPORT void *DH_get_ex_data(DH *d, int idx); + + +struct dh_st { + BIGNUM *p; + BIGNUM *g; + BIGNUM *pub_key; /* g^x mod p */ + BIGNUM *priv_key; /* x */ + + /* priv_length contains the length, in bits, of the private value. If zero, + * the private value will be the same length as |p|. */ + unsigned priv_length; + + CRYPTO_MUTEX method_mont_p_lock; + BN_MONT_CTX *method_mont_p; + + /* Place holders if we want to do X9.42 DH */ + BIGNUM *q; + BIGNUM *j; + unsigned char *seed; + int seedlen; + BIGNUM *counter; + + int flags; + CRYPTO_refcount_t references; + CRYPTO_EX_DATA ex_data; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define DH_R_BAD_GENERATOR 100 +#define DH_R_INVALID_PUBKEY 101 +#define DH_R_MODULUS_TOO_LARGE 102 +#define DH_R_NO_PRIVATE_VALUE 103 + +#endif /* OPENSSL_HEADER_DH_H */ diff --git a/project/jni/boringssl/include/openssl/digest.h b/project/jni/boringssl/include/openssl/digest.h new file mode 100644 index 000000000..80028efda --- /dev/null +++ b/project/jni/boringssl/include/openssl/digest.h @@ -0,0 +1,258 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_DIGEST_H +#define OPENSSL_HEADER_DIGEST_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Digest functions. + * + * An EVP_MD abstracts the details of a specific hash function allowing code to + * deal with the concept of a "hash function" without needing to know exactly + * which hash function it is. */ + + +/* Hash algorithms. + * + * The following functions return |EVP_MD| objects that implement the named hash + * function. */ + +OPENSSL_EXPORT const EVP_MD *EVP_md4(void); +OPENSSL_EXPORT const EVP_MD *EVP_md5(void); +OPENSSL_EXPORT const EVP_MD *EVP_sha1(void); +OPENSSL_EXPORT const EVP_MD *EVP_sha224(void); +OPENSSL_EXPORT const EVP_MD *EVP_sha256(void); +OPENSSL_EXPORT const EVP_MD *EVP_sha384(void); +OPENSSL_EXPORT const EVP_MD *EVP_sha512(void); + +/* EVP_md5_sha1 is a TLS-specific |EVP_MD| which computes the concatenation of + * MD5 and SHA-1, as used in TLS 1.1 and below. */ +OPENSSL_EXPORT const EVP_MD *EVP_md5_sha1(void); + +/* EVP_get_digestbynid returns an |EVP_MD| for the given NID, or NULL if no + * such digest is known. */ +OPENSSL_EXPORT const EVP_MD *EVP_get_digestbynid(int nid); + +/* EVP_get_digestbyobj returns an |EVP_MD| for the given |ASN1_OBJECT|, or NULL + * if no such digest is known. */ +OPENSSL_EXPORT const EVP_MD *EVP_get_digestbyobj(const ASN1_OBJECT *obj); + + +/* Digest contexts. + * + * An EVP_MD_CTX represents the state of a specific digest operation in + * progress. */ + +/* EVP_MD_CTX_init initialises an, already allocated, |EVP_MD_CTX|. */ +OPENSSL_EXPORT void EVP_MD_CTX_init(EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_create allocates and initialises a fresh |EVP_MD_CTX| and returns + * it, or NULL on allocation failure. */ +OPENSSL_EXPORT EVP_MD_CTX *EVP_MD_CTX_create(void); + +/* EVP_MD_CTX_cleanup frees any resources owned by |ctx| and resets it to a + * freshly initialised state. It does not free |ctx| itself. It returns one. */ +OPENSSL_EXPORT int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_destroy calls |EVP_MD_CTX_cleanup| and then frees |ctx| itself. */ +OPENSSL_EXPORT void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_copy_ex sets |out|, which must already be initialised, to be a + * copy of |in|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in); + + +/* Digest operations. */ + +/* EVP_DigestInit_ex configures |ctx|, which must already have been + * initialised, for a fresh hashing operation using |type|. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, + ENGINE *engine); + +/* EVP_DigestInit acts like |EVP_DigestInit_ex| except that |ctx| is + * initialised before use. */ +OPENSSL_EXPORT int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type); + +/* EVP_DigestUpdate hashes |len| bytes from |data| into the hashing operation + * in |ctx|. It returns one. */ +OPENSSL_EXPORT int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, + size_t len); + +/* EVP_MAX_MD_SIZE is the largest digest size supported, in bytes. + * Functions that output a digest generally require the buffer have + * at least this much space. */ +#define EVP_MAX_MD_SIZE 64 /* SHA-512 is the longest so far. */ + +/* EVP_DigestFinal_ex finishes the digest in |ctx| and writes the output to + * |md_out|. At most |EVP_MAX_MD_SIZE| bytes are written. If |out_size| is not + * NULL then |*out_size| is set to the number of bytes written. It returns one. + * After this call, the hash cannot be updated or finished again until + * |EVP_DigestInit_ex| is called to start another hashing operation. */ +OPENSSL_EXPORT int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, uint8_t *md_out, + unsigned int *out_size); + +/* EVP_DigestFinal acts like |EVP_DigestFinal_ex| except that + * |EVP_MD_CTX_cleanup| is called on |ctx| before returning. */ +OPENSSL_EXPORT int EVP_DigestFinal(EVP_MD_CTX *ctx, uint8_t *md_out, + unsigned int *out_size); + +/* EVP_Digest performs a complete hashing operation in one call. It hashes + * |len| bytes from |data| and writes the digest to |md_out|. At most + * |EVP_MAX_MD_SIZE| bytes are written. If |out_size| is not NULL then + * |*out_size| is set to the number of bytes written. It returns one on success + * and zero otherwise. */ +OPENSSL_EXPORT int EVP_Digest(const void *data, size_t len, uint8_t *md_out, + unsigned int *md_out_size, const EVP_MD *type, + ENGINE *impl); + + +/* Digest function accessors. + * + * These functions allow code to learn details about an abstract hash + * function. */ + +/* EVP_MD_type returns a NID identifing |md|. (For example, |NID_sha256|.) */ +OPENSSL_EXPORT int EVP_MD_type(const EVP_MD *md); + +/* EVP_MD_flags returns the flags for |md|, which is a set of |EVP_MD_FLAG_*| + * values, ORed together. */ +OPENSSL_EXPORT uint32_t EVP_MD_flags(const EVP_MD *md); + +/* EVP_MD_size returns the digest size of |md|, in bytes. */ +OPENSSL_EXPORT size_t EVP_MD_size(const EVP_MD *md); + +/* EVP_MD_block_size returns the native block-size of |md|, in bytes. */ +OPENSSL_EXPORT size_t EVP_MD_block_size(const EVP_MD *md); + +/* EVP_MD_FLAG_PKEY_DIGEST indicates the the digest function is used with a + * specific public key in order to verify signatures. (For example, + * EVP_dss1.) */ +#define EVP_MD_FLAG_PKEY_DIGEST 1 + +/* EVP_MD_FLAG_DIGALGID_ABSENT indicates that the parameter type in an X.509 + * DigestAlgorithmIdentifier representing this digest function should be + * undefined rather than NULL. */ +#define EVP_MD_FLAG_DIGALGID_ABSENT 2 + + +/* Deprecated functions. */ + +/* EVP_MD_CTX_copy sets |out|, which must /not/ be initialised, to be a copy of + * |in|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in); + +/* EVP_add_digest does nothing and returns one. It exists only for + * compatibility with OpenSSL. */ +OPENSSL_EXPORT int EVP_add_digest(const EVP_MD *digest); + +/* EVP_get_digestbyname returns an |EVP_MD| given a human readable name in + * |name|, or NULL if the name is unknown. */ +OPENSSL_EXPORT const EVP_MD *EVP_get_digestbyname(const char *); + + +/* Digest operation accessors. */ + +/* EVP_MD_CTX_md returns the underlying digest function, or NULL if one has not + * been set. */ +OPENSSL_EXPORT const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_size returns the digest size of |ctx|, in bytes. It + * will crash if a digest hasn't been set on |ctx|. */ +OPENSSL_EXPORT unsigned EVP_MD_CTX_size(const EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_block_size returns the block size of the digest function used by + * |ctx|, in bytes. It will crash if a digest hasn't been set on |ctx|. */ +OPENSSL_EXPORT unsigned EVP_MD_CTX_block_size(const EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_type returns a NID describing the digest function used by |ctx|. + * (For example, |NID_sha256|.) It will crash if a digest hasn't been set on + * |ctx|. */ +OPENSSL_EXPORT int EVP_MD_CTX_type(const EVP_MD_CTX *ctx); + + +struct evp_md_pctx_ops; + +struct env_md_ctx_st { + /* digest is the underlying digest function, or NULL if not set. */ + const EVP_MD *digest; + /* md_data points to a block of memory that contains the hash-specific + * context. */ + void *md_data; + + /* pctx is an opaque (at this layer) pointer to additional context that + * EVP_PKEY functions may store in this object. */ + EVP_PKEY_CTX *pctx; + + /* pctx_ops, if not NULL, points to a vtable that contains functions to + * manipulate |pctx|. */ + const struct evp_md_pctx_ops *pctx_ops; +} /* EVP_MD_CTX */; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define DIGEST_R_INPUT_NOT_INITIALIZED 100 + +#endif /* OPENSSL_HEADER_DIGEST_H */ diff --git a/project/jni/boringssl/include/openssl/dsa.h b/project/jni/boringssl/include/openssl/dsa.h new file mode 100644 index 000000000..2045fe736 --- /dev/null +++ b/project/jni/boringssl/include/openssl/dsa.h @@ -0,0 +1,343 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * The DSS routines are based on patches supplied by + * Steven Schoch . */ + +#ifndef OPENSSL_HEADER_DSA_H +#define OPENSSL_HEADER_DSA_H + +#include + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* DSA contains functions for signing and verifing with the Digital Signature + * Algorithm. */ + + +/* Allocation and destruction. */ + +/* DSA_new returns a new, empty DSA object or NULL on error. */ +OPENSSL_EXPORT DSA *DSA_new(void); + +/* DSA_free decrements the reference count of |dsa| and frees it if the + * reference count drops to zero. */ +OPENSSL_EXPORT void DSA_free(DSA *dsa); + +/* DSA_up_ref increments the reference count of |dsa|. */ +OPENSSL_EXPORT int DSA_up_ref(DSA *dsa); + + +/* Parameter generation. */ + +/* DSA_generate_parameters_ex generates a set of DSA parameters by following + * the procedure given in FIPS 186-4, appendix A. + * (http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf) + * + * The larger prime will have a length of |bits| (e.g. 2048). The |seed| value + * allows others to generate and verify the same parameters and should be + * random input which is kept for reference. If |out_counter| or |out_h| are + * not NULL then the counter and h value used in the generation are written to + * them. + * + * The |cb| argument is passed to |BN_generate_prime_ex| and is thus called + * during the generation process in order to indicate progress. See the + * comments for that function for details. In addition to the calls made by + * |BN_generate_prime_ex|, |DSA_generate_parameters_ex| will call it with + * |event| equal to 2 and 3 at different stages of the process. + * + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int DSA_generate_parameters_ex(DSA *dsa, unsigned bits, + const uint8_t *seed, + size_t seed_len, int *out_counter, + unsigned long *out_h, + BN_GENCB *cb); + +/* DSAparams_dup returns a freshly allocated |DSA| that contains a copy of the + * parameters from |dsa|. It returns NULL on error. */ +OPENSSL_EXPORT DSA *DSAparams_dup(const DSA *dsa); + + +/* Key generation. */ + +/* DSA_generate_key generates a public/private key pair in |dsa|, which must + * already have parameters setup. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int DSA_generate_key(DSA *dsa); + + +/* Signatures. */ + +/* DSA_SIG contains a DSA signature as a pair of integers. */ +typedef struct DSA_SIG_st { + BIGNUM *r, *s; +} DSA_SIG; + +/* DSA_SIG_new returns a freshly allocated, DIG_SIG structure or NULL on error. + * Both |r| and |s| in the signature will be NULL. */ +OPENSSL_EXPORT DSA_SIG *DSA_SIG_new(void); + +/* DSA_SIG_free frees the contents of |sig| and then frees |sig| itself. */ +OPENSSL_EXPORT void DSA_SIG_free(DSA_SIG *sig); + +/* DSA_do_sign returns a signature of the hash in |digest| by the key in |dsa| + * and returns an allocated, DSA_SIG structure, or NULL on error. */ +OPENSSL_EXPORT DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, + DSA *dsa); + +/* DSA_do_verify verifies that |sig| is a valid signature, by the public key in + * |dsa|, of the hash in |digest|. It returns one if so, zero if invalid and -1 + * on error. + * + * WARNING: do not use. This function returns -1 for error, 0 for invalid and 1 + * for valid. However, this is dangerously different to the usual OpenSSL + * convention and could be a disaster if a user did |if (DSA_do_verify(...))|. + * Because of this, |DSA_check_signature| is a safer version of this. + * + * TODO(fork): deprecate. */ +OPENSSL_EXPORT int DSA_do_verify(const uint8_t *digest, size_t digest_len, + DSA_SIG *sig, const DSA *dsa); + +/* DSA_do_check_signature sets |*out_valid| to zero. Then it verifies that |sig| + * is a valid signature, by the public key in |dsa| of the hash in |digest| + * and, if so, it sets |*out_valid| to one. + * + * It returns one if it was able to verify the signature as valid or invalid, + * and zero on error. */ +OPENSSL_EXPORT int DSA_do_check_signature(int *out_valid, const uint8_t *digest, + size_t digest_len, DSA_SIG *sig, + const DSA *dsa); + + +/* ASN.1 signatures. + * + * These functions also perform DSA signature operations, but deal with ASN.1 + * encoded signatures as opposed to raw |BIGNUM|s. If you don't know what + * encoding a DSA signature is in, it's probably ASN.1. */ + +/* DSA_sign signs |digest| with the key in |dsa| and writes the resulting + * signature, in ASN.1 form, to |out_sig| and the length of the signature to + * |*out_siglen|. There must be, at least, |DSA_size(dsa)| bytes of space in + * |out_sig|. It returns one on success and zero otherwise. + * + * (The |type| argument is ignored.) */ +OPENSSL_EXPORT int DSA_sign(int type, const uint8_t *digest, size_t digest_len, + uint8_t *out_sig, unsigned int *out_siglen, + DSA *dsa); + +/* DSA_verify verifies that |sig| is a valid, ASN.1 signature, by the public + * key in |dsa|, of the hash in |digest|. It returns one if so, zero if invalid + * and -1 on error. + * + * (The |type| argument is ignored.) + * + * WARNING: do not use. This function returns -1 for error, 0 for invalid and 1 + * for valid. However, this is dangerously different to the usual OpenSSL + * convention and could be a disaster if a user did |if (DSA_do_verify(...))|. + * Because of this, |DSA_check_signature| is a safer version of this. + * + * TODO(fork): deprecate. */ +OPENSSL_EXPORT int DSA_verify(int type, const uint8_t *digest, + size_t digest_len, const uint8_t *sig, + size_t sig_len, const DSA *dsa); + +/* DSA_check_signature sets |*out_valid| to zero. Then it verifies that |sig| + * is a valid, ASN.1 signature, by the public key in |dsa|, of the hash in + * |digest|. If so, it sets |*out_valid| to one. + * + * It returns one if it was able to verify the signature as valid or invalid, + * and zero on error. */ +OPENSSL_EXPORT int DSA_check_signature(int *out_valid, const uint8_t *digest, + size_t digest_len, const uint8_t *sig, + size_t sig_len, const DSA *dsa); + +/* DSA_size returns the size, in bytes, of an ASN.1 encoded, DSA signature + * generated by |dsa|. Parameters must already have been setup in |dsa|. */ +OPENSSL_EXPORT int DSA_size(const DSA *dsa); + + +/* ASN.1 encoding. */ + +/* d2i_DSA_SIG parses an ASN.1, DER-encoded, DSA signature from |len| bytes at + * |*inp|. If |out_sig| is not NULL then, on exit, a pointer to the result is + * in |*out_sig|. If |*out_sig| is already non-NULL on entry then the result is + * written directly into |*out_sig|, otherwise a fresh |DSA_SIG| is allocated. + * On successful exit, |*inp| is advanced past the DER structure. It returns + * the result or NULL on error. */ +OPENSSL_EXPORT DSA_SIG *d2i_DSA_SIG(DSA_SIG **out_sig, const uint8_t **inp, + long len); + +/* i2d_DSA_SIG marshals |in| to an ASN.1, DER structure. If |outp| is not NULL + * then the result is written to |*outp| and |*outp| is advanced just past the + * output. It returns the number of bytes in the result, whether written or not, + * or a negative value on error. */ +OPENSSL_EXPORT int i2d_DSA_SIG(const DSA_SIG *in, uint8_t **outp); + +/* d2i_DSAPublicKey parses an ASN.1, DER-encoded, DSA public key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. If |*out| is already non-NULL on entry then the result is + * written directly into |*out|, otherwise a fresh |DSA| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT DSA *d2i_DSAPublicKey(DSA **out, const uint8_t **inp, long len); + +/* i2d_DSAPublicKey marshals a public key from |in| to an ASN.1, DER structure. + * If |outp| is not NULL then the result is written to |*outp| and |*outp| is + * advanced just past the output. It returns the number of bytes in the result, + * whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_DSAPublicKey(const DSA *in, unsigned char **outp); + +/* d2i_DSAPrivateKey parses an ASN.1, DER-encoded, DSA private key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. If |*out| is already non-NULL on entry then the result is + * written directly into |*out|, otherwise a fresh |DSA| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT DSA *d2i_DSAPrivateKey(DSA **out, const uint8_t **inp, long len); + +/* i2d_DSAPrivateKey marshals a private key from |in| to an ASN.1, DER structure. + * If |outp| is not NULL then the result is written to |*outp| and |*outp| is + * advanced just past the output. It returns the number of bytes in the result, + * whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_DSAPrivateKey(const DSA *in, unsigned char **outp); + +/* d2i_DSAparams parses ASN.1, DER-encoded, DSA parameters from |len| bytes at + * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in + * |*out|. If |*out| is already non-NULL on entry then the result is written + * directly into |*out|, otherwise a fresh |DSA| is allocated. On successful + * exit, |*inp| is advanced past the DER structure. It returns the result or + * NULL on error. */ +OPENSSL_EXPORT DSA *d2i_DSAparams(DSA **out, const uint8_t **inp, long len); + +/* i2d_DSAparams marshals DSA parameters from |in| to an ASN.1, DER structure. + * If |outp| is not NULL then the result is written to |*outp| and |*outp| is + * advanced just past the output. It returns the number of bytes in the result, + * whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_DSAparams(const DSA *in, unsigned char **outp); + + +/* Precomputation. */ + +/* DSA_sign_setup precomputes the message independent part of the DSA signature + * and writes them to |*out_kinv| and |*out_r|. Returns one on success, zero on + * error. + * + * TODO(fork): decide what to do with this. Since making DSA* opaque there's no + * way for the user to install them. Also, it forces the DSA* not to be const + * when passing to the signing function. */ +OPENSSL_EXPORT int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx, + BIGNUM **out_kinv, BIGNUM **out_r); + + +/* Conversion. */ + +/* DSA_dup_DH returns a |DH| constructed from the parameters of |dsa|. This is + * sometimes needed when Diffie-Hellman parameters are stored in the form of + * DSA parameters. It returns an allocated |DH| on success or NULL on error. */ +OPENSSL_EXPORT DH *DSA_dup_DH(const DSA *dsa); + + +/* ex_data functions. + * + * See |ex_data.h| for details. */ + +OPENSSL_EXPORT int DSA_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_unused *unused, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int DSA_set_ex_data(DSA *d, int idx, void *arg); +OPENSSL_EXPORT void *DSA_get_ex_data(const DSA *d, int idx); + + +struct dsa_st { + long version; + int write_params; + BIGNUM *p; + BIGNUM *q; /* == 20 */ + BIGNUM *g; + + BIGNUM *pub_key; /* y public key */ + BIGNUM *priv_key; /* x private key */ + + BIGNUM *kinv; /* Signing pre-calc */ + BIGNUM *r; /* Signing pre-calc */ + + int flags; + /* Normally used to cache montgomery values */ + CRYPTO_MUTEX method_mont_p_lock; + BN_MONT_CTX *method_mont_p; + CRYPTO_refcount_t references; + CRYPTO_EX_DATA ex_data; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define DSA_R_BAD_Q_VALUE 100 +#define DSA_R_MISSING_PARAMETERS 101 +#define DSA_R_MODULUS_TOO_LARGE 102 +#define DSA_R_NEED_NEW_SETUP_VALUES 103 + +#endif /* OPENSSL_HEADER_DSA_H */ diff --git a/project/jni/boringssl/include/openssl/dtls1.h b/project/jni/boringssl/include/openssl/dtls1.h new file mode 100644 index 000000000..38ca801cb --- /dev/null +++ b/project/jni/boringssl/include/openssl/dtls1.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ diff --git a/project/jni/boringssl/include/openssl/ec.h b/project/jni/boringssl/include/openssl/ec.h new file mode 100644 index 000000000..667be3b3b --- /dev/null +++ b/project/jni/boringssl/include/openssl/ec.h @@ -0,0 +1,355 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#ifndef OPENSSL_HEADER_EC_H +#define OPENSSL_HEADER_EC_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Low-level operations on elliptic curves. */ + + +typedef struct ec_group_st EC_GROUP; +typedef struct ec_point_st EC_POINT; + +/** Enum for the point conversion form as defined in X9.62 (ECDSA) + * for the encoding of a elliptic curve point (x,y) */ +typedef enum { + /** the point is encoded as z||x, where the octet z specifies + * which solution of the quadratic equation y is */ + POINT_CONVERSION_COMPRESSED = 2, + /** the point is encoded as z||x||y, where z is the octet 0x04 */ + POINT_CONVERSION_UNCOMPRESSED = 4 +} point_conversion_form_t; + + +/* Elliptic curve groups. */ + +/* EC_GROUP_new_by_curve_name returns a fresh EC_GROUP object for the elliptic + * curve specified by |nid|, or NULL on error. + * + * The supported NIDs are: + * NID_secp224r1, + * NID_X9_62_prime256v1, + * NID_secp384r1, + * NID_secp521r1 */ +OPENSSL_EXPORT EC_GROUP *EC_GROUP_new_by_curve_name(int nid); + +/* EC_GROUP_free frees |group| and the data that it points to. */ +OPENSSL_EXPORT void EC_GROUP_free(EC_GROUP *group); + +/* EC_GROUP_dup returns a fresh |EC_GROUP| which is equal to |a| or NULL on + * error. */ +OPENSSL_EXPORT EC_GROUP *EC_GROUP_dup(const EC_GROUP *a); + +/* EC_GROUP_cmp returns zero if |a| and |b| are the same group and non-zero + * otherwise. */ +OPENSSL_EXPORT int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, + BN_CTX *ignored); + +/* EC_GROUP_get0_generator returns a pointer to the internal |EC_POINT| object + * in |group| that specifies the generator for the group. */ +OPENSSL_EXPORT const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group); + +/* EC_GROUP_get0_order returns a pointer to the internal |BIGNUM| object in + * |group| that specifies the order of the group. */ +OPENSSL_EXPORT const BIGNUM *EC_GROUP_get0_order(const EC_GROUP *group); + +/* EC_GROUP_get_cofactor sets |*cofactor| to the cofactor of |group| using + * |ctx|, if it's not NULL. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_GROUP_get_cofactor(const EC_GROUP *group, + BIGNUM *cofactor, BN_CTX *ctx); + +/* EC_GROUP_get_curve_GFp gets various parameters about a group. It sets + * |*out_p| to the order of the coordinate field and |*out_a| and |*out_b| to + * the parameters of the curve when expressed as y² = x³ + ax + b. Any of the + * output parameters can be NULL. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *out_p, + BIGNUM *out_a, BIGNUM *out_b, + BN_CTX *ctx); + +/* EC_GROUP_get_curve_name returns a NID that identifies |group|. */ +OPENSSL_EXPORT int EC_GROUP_get_curve_name(const EC_GROUP *group); + +/* EC_GROUP_get_degree returns the number of bits needed to represent an + * element of the field underlying |group|. */ +OPENSSL_EXPORT unsigned EC_GROUP_get_degree(const EC_GROUP *group); + + +/* Points on elliptic curves. */ + +/* EC_POINT_new returns a fresh |EC_POINT| object in the given group, or NULL + * on error. */ +OPENSSL_EXPORT EC_POINT *EC_POINT_new(const EC_GROUP *group); + +/* EC_POINT_free frees |point| and the data that it points to. */ +OPENSSL_EXPORT void EC_POINT_free(EC_POINT *point); + +/* EC_POINT_clear_free clears the data that |point| points to, frees it and + * then frees |point| itself. */ +OPENSSL_EXPORT void EC_POINT_clear_free(EC_POINT *point); + +/* EC_POINT_copy sets |*dest| equal to |*src|. It returns one on success and + * zero otherwise. */ +OPENSSL_EXPORT int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src); + +/* EC_POINT_dup returns a fresh |EC_POINT| that contains the same values as + * |src|, or NULL on error. */ +OPENSSL_EXPORT EC_POINT *EC_POINT_dup(const EC_POINT *src, + const EC_GROUP *group); + +/* EC_POINT_set_to_infinity sets |point| to be the "point at infinity" for the + * given group. */ +OPENSSL_EXPORT int EC_POINT_set_to_infinity(const EC_GROUP *group, + EC_POINT *point); + +/* EC_POINT_is_at_infinity returns one iff |point| is the point at infinity and + * zero otherwise. */ +OPENSSL_EXPORT int EC_POINT_is_at_infinity(const EC_GROUP *group, + const EC_POINT *point); + +/* EC_POINT_is_on_curve returns one if |point| is an element of |group| and + * zero otheriwse. If |ctx| is non-NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_is_on_curve(const EC_GROUP *group, + const EC_POINT *point, BN_CTX *ctx); + +/* EC_POINT_cmp returns zero if |a| is equal to |b|, greater than zero is + * non-equal and -1 on error. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, + const EC_POINT *b, BN_CTX *ctx); + +/* EC_POINT_make_affine converts |point| to affine form, internally. It returns + * one on success and zero otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, + BN_CTX *ctx); + +/* EC_POINTs_make_affine converts |num| points from |points| to affine form, + * internally. It returns one on success and zero otherwise. If |ctx| is not + * NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINTs_make_affine(const EC_GROUP *group, size_t num, + EC_POINT *points[], BN_CTX *ctx); + + +/* Point conversion. */ + +/* EC_POINT_get_affine_coordinates_GFp sets |x| and |y| to the affine value of + * |point| using |ctx|, if it's not NULL. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, + const EC_POINT *point, + BIGNUM *x, BIGNUM *y, + BN_CTX *ctx); + +/* EC_POINT_set_affine_coordinates_GFp sets the value of |p| to be (|x|, |y|). + * The |ctx| argument may be used if not NULL. It returns one on success or + * zero on error. Note that, unlike with OpenSSL, it's considered an error if + * the point is not on the curve. */ +OPENSSL_EXPORT int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, + EC_POINT *point, + const BIGNUM *x, + const BIGNUM *y, + BN_CTX *ctx); + +/* EC_POINT_point2oct serialises |point| into the X9.62 form given by |form| + * into, at most, |len| bytes at |buf|. It returns the number of bytes written + * or zero on error if |buf| is non-NULL, else the number of bytes needed. The + * |ctx| argument may be used if not NULL. */ +OPENSSL_EXPORT size_t EC_POINT_point2oct(const EC_GROUP *group, + const EC_POINT *point, + point_conversion_form_t form, + uint8_t *buf, size_t len, BN_CTX *ctx); + +/* EC_POINT_oct2point sets |point| from |len| bytes of X9.62 format + * serialisation in |buf|. It returns one on success and zero otherwise. The + * |ctx| argument may be used if not NULL. */ +OPENSSL_EXPORT int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point, + const uint8_t *buf, size_t len, + BN_CTX *ctx); + +/* EC_POINT_set_compressed_coordinates_GFp sets |point| to equal the point with + * the given |x| coordinate and the y coordinate specified by |y_bit| (see + * X9.62). It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_POINT_set_compressed_coordinates_GFp( + const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, int y_bit, + BN_CTX *ctx); + + +/* Group operations. */ + +/* EC_POINT_add sets |r| equal to |a| plus |b|. It returns one on success and + * zero otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, + const EC_POINT *a, const EC_POINT *b, + BN_CTX *ctx); + +/* EC_POINT_dbl sets |r| equal to |a| plus |a|. It returns one on success and + * zero otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, + const EC_POINT *a, BN_CTX *ctx); + +/* EC_POINT_invert sets |a| equal to minus |a|. It returns one on success and zero + * otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, + BN_CTX *ctx); + +/* EC_POINT_mul sets r = generator*n + q*m. It returns one on success and zero + * otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, + const BIGNUM *n, const EC_POINT *q, + const BIGNUM *m, BN_CTX *ctx); + + +/* Deprecated functions. */ + +/* EC_GROUP_new_curve_GFp creates a new, arbitrary elliptic curve group based + * on the equation y² = x³ + a·x + b. It returns the new group or NULL on + * error. + * + * |EC_GROUP|s returned by this function will always compare as unequal via + * |EC_GROUP_cmp| (even to themselves). |EC_GROUP_get_curve_name| will always + * return |NID_undef|. */ +OPENSSL_EXPORT EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, + const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx); + +/* EC_GROUP_get_order sets |*order| to the order of |group|, if it's not + * NULL. It returns one on success and zero otherwise. |ctx| is ignored. Use + * |EC_GROUP_get0_order| instead. */ +OPENSSL_EXPORT int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, + BN_CTX *ctx); + +/* EC_GROUP_set_generator sets the generator for |group| to |generator|, which + * must have the given order and cofactor. This should only be used with + * |EC_GROUP| objects returned by |EC_GROUP_new_curve_GFp|. */ +OPENSSL_EXPORT int EC_GROUP_set_generator(EC_GROUP *group, + const EC_POINT *generator, + const BIGNUM *order, + const BIGNUM *cofactor); + +/* EC_GROUP_set_asn1_flag does nothing. */ +OPENSSL_EXPORT void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag); + +#define OPENSSL_EC_NAMED_CURVE 0 + +typedef struct ec_method_st EC_METHOD; + +/* EC_GROUP_method_of returns NULL. */ +OPENSSL_EXPORT const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *group); + +/* EC_METHOD_get_field_type returns NID_X9_62_prime_field. */ +OPENSSL_EXPORT int EC_METHOD_get_field_type(const EC_METHOD *meth); + +/* EC_GROUP_set_point_conversion_form aborts the process if |form| is not + * |POINT_CONVERSION_UNCOMPRESSED| and otherwise does nothing. */ +OPENSSL_EXPORT void EC_GROUP_set_point_conversion_form( + EC_GROUP *group, point_conversion_form_t form); + + +/* Old code expects to get EC_KEY from ec.h. */ +#include + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define EC_R_BUFFER_TOO_SMALL 100 +#define EC_R_COORDINATES_OUT_OF_RANGE 101 +#define EC_R_D2I_ECPKPARAMETERS_FAILURE 102 +#define EC_R_EC_GROUP_NEW_BY_NAME_FAILURE 103 +#define EC_R_GROUP2PKPARAMETERS_FAILURE 104 +#define EC_R_I2D_ECPKPARAMETERS_FAILURE 105 +#define EC_R_INCOMPATIBLE_OBJECTS 106 +#define EC_R_INVALID_COMPRESSED_POINT 107 +#define EC_R_INVALID_COMPRESSION_BIT 108 +#define EC_R_INVALID_ENCODING 109 +#define EC_R_INVALID_FIELD 110 +#define EC_R_INVALID_FORM 111 +#define EC_R_INVALID_GROUP_ORDER 112 +#define EC_R_INVALID_PRIVATE_KEY 113 +#define EC_R_MISSING_PARAMETERS 114 +#define EC_R_MISSING_PRIVATE_KEY 115 +#define EC_R_NON_NAMED_CURVE 116 +#define EC_R_NOT_INITIALIZED 117 +#define EC_R_PKPARAMETERS2GROUP_FAILURE 118 +#define EC_R_POINT_AT_INFINITY 119 +#define EC_R_POINT_IS_NOT_ON_CURVE 120 +#define EC_R_SLOT_FULL 121 +#define EC_R_UNDEFINED_GENERATOR 122 +#define EC_R_UNKNOWN_GROUP 123 +#define EC_R_UNKNOWN_ORDER 124 +#define EC_R_WRONG_ORDER 125 +#define EC_R_BIGNUM_OUT_OF_RANGE 126 +#define EC_R_WRONG_CURVE_PARAMETERS 127 + +#endif /* OPENSSL_HEADER_EC_H */ diff --git a/project/jni/boringssl/include/openssl/ec_key.h b/project/jni/boringssl/include/openssl/ec_key.h new file mode 100644 index 000000000..afd95d6a1 --- /dev/null +++ b/project/jni/boringssl/include/openssl/ec_key.h @@ -0,0 +1,280 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#ifndef OPENSSL_HEADER_EC_KEY_H +#define OPENSSL_HEADER_EC_KEY_H + +#include + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* ec_key.h contains functions that handle elliptic-curve points that are + * public/private keys. */ + + +/* EC key objects. */ + +/* EC_KEY_new returns a fresh |EC_KEY| object or NULL on error. */ +OPENSSL_EXPORT EC_KEY *EC_KEY_new(void); + +/* EC_KEY_new_method acts the same as |EC_KEY_new|, but takes an explicit + * |ENGINE|. */ +OPENSSL_EXPORT EC_KEY *EC_KEY_new_method(const ENGINE *engine); + +/* EC_KEY_new_by_curve_name returns a fresh EC_KEY for group specified by |nid| + * or NULL on error. */ +OPENSSL_EXPORT EC_KEY *EC_KEY_new_by_curve_name(int nid); + +/* EC_KEY_free frees all the data owned by |key| and |key| itself. */ +OPENSSL_EXPORT void EC_KEY_free(EC_KEY *key); + +/* EC_KEY_copy sets |dst| equal to |src| and returns |dst| or NULL on error. */ +OPENSSL_EXPORT EC_KEY *EC_KEY_copy(EC_KEY *dst, const EC_KEY *src); + +/* EC_KEY_dup returns a fresh copy of |src| or NULL on error. */ +OPENSSL_EXPORT EC_KEY *EC_KEY_dup(const EC_KEY *src); + +/* EC_KEY_up_ref increases the reference count of |key|. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_up_ref(EC_KEY *key); + +/* EC_KEY_is_opaque returns one if |key| is opaque and doesn't expose its key + * material. Otherwise it return zero. */ +OPENSSL_EXPORT int EC_KEY_is_opaque(const EC_KEY *key); + +/* EC_KEY_get0_group returns a pointer to the |EC_GROUP| object inside |key|. */ +OPENSSL_EXPORT const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key); + +/* EC_KEY_set_group sets the |EC_GROUP| object that |key| will use to |group|. + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group); + +/* EC_KEY_get0_private_key returns a pointer to the private key inside |key|. */ +OPENSSL_EXPORT const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key); + +/* EC_KEY_set_private_key sets the private key of |key| to |priv|. It returns + * one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *prv); + +/* EC_KEY_get0_public_key returns a pointer to the public key point inside + * |key|. */ +OPENSSL_EXPORT const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key); + +/* EC_KEY_set_public_key sets the public key of |key| to |pub|, by copying it. + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub); + +#define EC_PKEY_NO_PARAMETERS 0x001 +#define EC_PKEY_NO_PUBKEY 0x002 + +/* EC_KEY_get_enc_flags returns the encoding flags for |key|, which is a + * bitwise-OR of |EC_PKEY_*| values. */ +OPENSSL_EXPORT unsigned EC_KEY_get_enc_flags(const EC_KEY *key); + +/* EC_KEY_set_enc_flags sets the encoding flags for |key|, which is a + * bitwise-OR of |EC_PKEY_*| values. */ +OPENSSL_EXPORT void EC_KEY_set_enc_flags(EC_KEY *key, unsigned flags); + +/* EC_KEY_get_conv_form returns the conversation form that will be used by + * |key|. */ +OPENSSL_EXPORT point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key); + +/* EC_KEY_set_conv_form sets the conversion form to be used by |key|. */ +OPENSSL_EXPORT void EC_KEY_set_conv_form(EC_KEY *key, + point_conversion_form_t cform); + +/* EC_KEY_check_key performs several checks on |key| (possibly including an + * expensive check that the public key is in the primary subgroup). It returns + * one if all checks pass and zero otherwise. If it returns zero then detail + * about the problem can be found on the error stack. */ +OPENSSL_EXPORT int EC_KEY_check_key(const EC_KEY *key); + +/* EC_KEY_set_public_key_affine_coordinates sets the public key in |key| to + * (|x|, |y|). It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, + BIGNUM *x, + BIGNUM *y); + + +/* Key generation. */ + +/* EC_KEY_generate_key generates a random, private key, calculates the + * corresponding public key and stores both in |key|. It returns one on success + * or zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_generate_key(EC_KEY *key); + + +/* Serialisation. */ + +/* d2i_ECPrivateKey parses an ASN.1, DER-encoded, private key from |len| bytes + * at |*inp|. If |out_key| is not NULL then, on exit, a pointer to the result + * is in |*out_key|. If |*out_key| is already non-NULL on entry then the result + * is written directly into |*out_key|, otherwise a fresh |EC_KEY| is + * allocated. On successful exit, |*inp| is advanced past the DER structure. It + * returns the result or NULL on error. */ +OPENSSL_EXPORT EC_KEY *d2i_ECPrivateKey(EC_KEY **out_key, const uint8_t **inp, + long len); + +/* i2d_ECPrivateKey marshals an EC private key from |key| to an ASN.1, DER + * structure. If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_ECPrivateKey(const EC_KEY *key, uint8_t **outp); + +/* d2i_ECParameters parses an ASN.1, DER-encoded, set of EC parameters from + * |len| bytes at |*inp|. If |out_key| is not NULL then, on exit, a pointer to + * the result is in |*out_key|. If |*out_key| is already non-NULL on entry then + * the result is written directly into |*out_key|, otherwise a fresh |EC_KEY| + * is allocated. On successful exit, |*inp| is advanced past the DER structure. + * It returns the result or NULL on error. */ +OPENSSL_EXPORT EC_KEY *d2i_ECParameters(EC_KEY **out_key, const uint8_t **inp, + long len); + +/* i2d_ECParameters marshals EC parameters from |key| to an ASN.1, DER + * structure. If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_ECParameters(const EC_KEY *key, uint8_t **outp); + +/* o2i_ECPublicKey parses an EC point from |len| bytes at |*inp| into + * |*out_key|. Note that this differs from the d2i format in that |*out_key| + * must be non-NULL with a group set. On successful exit, |*inp| is advanced by + * |len| bytes. It returns |*out_key| or NULL on error. */ +OPENSSL_EXPORT EC_KEY *o2i_ECPublicKey(EC_KEY **out_key, const uint8_t **inp, + long len); + +/* i2o_ECPublicKey marshals an EC point from |key|. If |outp| is not NULL then + * the result is written to |*outp| and |*outp| is advanced just past the + * output. It returns the number of bytes in the result, whether written or + * not, or a negative value on error. */ +OPENSSL_EXPORT int i2o_ECPublicKey(const EC_KEY *key, unsigned char **outp); + + +/* ex_data functions. + * + * These functions are wrappers. See |ex_data.h| for details. */ + +OPENSSL_EXPORT int EC_KEY_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_unused *unused, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int EC_KEY_set_ex_data(EC_KEY *r, int idx, void *arg); +OPENSSL_EXPORT void *EC_KEY_get_ex_data(const EC_KEY *r, int idx); + + +/* ECDSA method. */ + +/* ECDSA_FLAG_OPAQUE specifies that this ECDSA_METHOD does not expose its key + * material. This may be set if, for instance, it is wrapping some other crypto + * API, like a platform key store. */ +#define ECDSA_FLAG_OPAQUE 1 + +/* ecdsa_method_st is a structure of function pointers for implementing ECDSA. + * See engine.h. */ +struct ecdsa_method_st { + struct openssl_method_common_st common; + + void *app_data; + + int (*init)(EC_KEY *key); + int (*finish)(EC_KEY *key); + + /* group_order_size returns the number of bytes needed to represent the order + * of the group. This is used to calculate the maximum size of an ECDSA + * signature in |ECDSA_size|. */ + size_t (*group_order_size)(const EC_KEY *key); + + /* sign matches the arguments and behaviour of |ECDSA_sign|. */ + int (*sign)(const uint8_t *digest, size_t digest_len, uint8_t *sig, + unsigned int *sig_len, EC_KEY *eckey); + + /* verify matches the arguments and behaviour of |ECDSA_verify|. */ + int (*verify)(const uint8_t *digest, size_t digest_len, const uint8_t *sig, + size_t sig_len, EC_KEY *eckey); + + int flags; +}; + + +/* Deprecated functions. */ + +/* EC_KEY_set_asn1_flag does nothing. */ +OPENSSL_EXPORT void EC_KEY_set_asn1_flag(EC_KEY *key, int flag); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_EC_KEY_H */ diff --git a/project/jni/boringssl/include/openssl/ecdh.h b/project/jni/boringssl/include/openssl/ecdh.h new file mode 100644 index 000000000..5fe3ae992 --- /dev/null +++ b/project/jni/boringssl/include/openssl/ecdh.h @@ -0,0 +1,102 @@ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * The Elliptic Curve Public-Key Crypto Library (ECC Code) included + * herein is developed by SUN MICROSYSTEMS, INC., and is contributed + * to the OpenSSL project. + * + * The ECC Code is licensed pursuant to the OpenSSL open source + * license provided below. + * + * The ECDH software is originally written by Douglas Stebila of + * Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright (c) 2000-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_ECDH_H +#define OPENSSL_HEADER_ECDH_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Elliptic curve Diffie-Hellman. */ + + +/* ECDH_compute_key calculates the shared key between |pub_key| and |priv_key|. + * If |kdf| is not NULL, then it is called with the bytes of the shared key and + * the parameter |out|. When |kdf| returns, the value of |*outlen| becomes the + * return value. Otherwise, as many bytes of the shared key as will fit are + * copied directly to, at most, |outlen| bytes at |out|. It returns the number + * of bytes written to |out|, or -1 on error. */ +OPENSSL_EXPORT int ECDH_compute_key(void *out, size_t outlen, + const EC_POINT *pub_key, EC_KEY *priv_key, + void *(*kdf)(const void *in, size_t inlen, + void *out, size_t *outlen)); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define ECDH_R_KDF_FAILED 100 +#define ECDH_R_NO_PRIVATE_VALUE 101 +#define ECDH_R_POINT_ARITHMETIC_FAILURE 102 + +#endif /* OPENSSL_HEADER_ECDH_H */ diff --git a/project/jni/boringssl/include/openssl/ecdsa.h b/project/jni/boringssl/include/openssl/ecdsa.h new file mode 100644 index 000000000..f3f68eb2f --- /dev/null +++ b/project/jni/boringssl/include/openssl/ecdsa.h @@ -0,0 +1,206 @@ +/* ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_ECDSA_H +#define OPENSSL_HEADER_ECDSA_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* ECDSA contains functions for signing and verifying with the Digital Signature + * Algorithm over elliptic curves. */ + + +/* Signing and verifing. */ + +/* ECDSA_sign signs |digest_len| bytes from |digest| with |key| and writes the + * resulting signature to |sig|, which must have |ECDSA_size(key)| bytes of + * space. On successful exit, |*sig_len| is set to the actual number of bytes + * written. The |type| argument should be zero. It returns one on success and + * zero otherwise. */ +OPENSSL_EXPORT int ECDSA_sign(int type, const uint8_t *digest, + size_t digest_len, uint8_t *sig, + unsigned int *sig_len, EC_KEY *key); + +/* ECDSA_verify verifies that |sig_len| bytes from |sig| constitute a valid + * signature by |key| of |digest|. (The |type| argument should be zero.) It + * returns one on success or zero if the signature is invalid or an error + * occured. */ +OPENSSL_EXPORT int ECDSA_verify(int type, const uint8_t *digest, + size_t digest_len, const uint8_t *sig, + size_t sig_len, EC_KEY *key); + +/* ECDSA_size returns the maximum size of an ECDSA signature using |key|. It + * returns zero on error. */ +OPENSSL_EXPORT size_t ECDSA_size(const EC_KEY *key); + + +/* Low-level signing and verification. + * + * Low-level functions handle signatures as |ECDSA_SIG| structures which allow + * the two values in an ECDSA signature to be handled separately. */ + +struct ecdsa_sig_st { + BIGNUM *r; + BIGNUM *s; +}; + +/* ECDSA_SIG_new returns a fresh |ECDSA_SIG| structure or NULL on error. */ +OPENSSL_EXPORT ECDSA_SIG *ECDSA_SIG_new(void); + +/* ECDSA_SIG_free frees |sig| its member |BIGNUM|s. */ +OPENSSL_EXPORT void ECDSA_SIG_free(ECDSA_SIG *sig); + +/* ECDSA_do_sign signs |digest_len| bytes from |digest| with |key| and returns + * the resulting signature structure, or NULL on error. */ +OPENSSL_EXPORT ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, + size_t digest_len, EC_KEY *key); + +/* ECDSA_do_verify verifies that |sig| constitutes a valid signature by |key| + * of |digest|. It returns one on success or zero if the signature is invalid + * or on error. */ +OPENSSL_EXPORT int ECDSA_do_verify(const uint8_t *digest, size_t digest_len, + const ECDSA_SIG *sig, EC_KEY *key); + + +/* Signing with precomputation. + * + * Parts of the ECDSA signature can be independent of the message to be signed + * thus it's possible to precompute them and reduce the signing latency. + * + * TODO(fork): remove support for this as it cannot support safe-randomness. */ + +/* ECDSA_sign_setup precomputes parts of an ECDSA signing operation. It sets + * |*kinv| and |*rp| to the precomputed values and uses the |ctx| argument, if + * not NULL. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, + BIGNUM **rp); + +/* ECDSA_do_sign_ex is the same as |ECDSA_do_sign| but takes precomputed values + * as generated by |ECDSA_sign_setup|. */ +OPENSSL_EXPORT ECDSA_SIG *ECDSA_do_sign_ex(const uint8_t *digest, + size_t digest_len, + const BIGNUM *kinv, const BIGNUM *rp, + EC_KEY *eckey); + +/* ECDSA_sign_ex is the same as |ECDSA_sign| but takes precomputed values as + * generated by |ECDSA_sign_setup|. */ +OPENSSL_EXPORT int ECDSA_sign_ex(int type, const uint8_t *digest, + size_t digest_len, uint8_t *sig, + unsigned int *sig_len, const BIGNUM *kinv, + const BIGNUM *rp, EC_KEY *eckey); + + +/* ASN.1 functions. */ + +/* ECDSA_SIG_parse parses a DER-encoded ECDSA-Sig-Value structure from |cbs| and + * advances |cbs|. It returns a newly-allocated |ECDSA_SIG| or NULL on error. */ +OPENSSL_EXPORT ECDSA_SIG *ECDSA_SIG_parse(CBS *cbs); + +/* ECDSA_SIG_from_bytes parses |in| as a DER-encoded ECDSA-Sig-Value structure. + * It returns a newly-allocated |ECDSA_SIG| structure or NULL on error. */ +OPENSSL_EXPORT ECDSA_SIG *ECDSA_SIG_from_bytes(const uint8_t *in, + size_t in_len); + +/* ECDSA_SIG_marshal marshals |sig| as a DER-encoded ECDSA-Sig-Value and appends + * the result to |cbb|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int ECDSA_SIG_marshal(CBB *cbb, const ECDSA_SIG *sig); + +/* ECDSA_SIG_to_bytes marshals |sig| as a DER-encoded ECDSA-Sig-Value and, on + * success, sets |*out_bytes| to a newly allocated buffer containing the result + * and returns one. Otherwise, it returns zero. The result should be freed with + * |OPENSSL_free|. */ +OPENSSL_EXPORT int ECDSA_SIG_to_bytes(uint8_t **out_bytes, size_t *out_len, + const ECDSA_SIG *sig); + +/* ECDSA_SIG_max_len returns the maximum length of a DER-encoded ECDSA-Sig-Value + * structure for a group whose order is represented in |order_len| bytes, or + * zero on overflow. */ +OPENSSL_EXPORT size_t ECDSA_SIG_max_len(size_t order_len); + + +/* Deprecated functions. */ + +/* d2i_ECDSA_SIG parses an ASN.1, DER-encoded, signature from |len| bytes at + * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in + * |*out|. If |*out| is already non-NULL on entry then the result is written + * directly into |*out|, otherwise a fresh |ECDSA_SIG| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **out, const uint8_t **inp, + long len); + +/* i2d_ECDSA_SIG marshals a signature from |sig| to an ASN.1, DER + * structure. If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_ECDSA_SIG(const ECDSA_SIG *sig, uint8_t **outp); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define ECDSA_R_BAD_SIGNATURE 100 +#define ECDSA_R_MISSING_PARAMETERS 101 +#define ECDSA_R_NEED_NEW_SETUP_VALUES 102 +#define ECDSA_R_NOT_IMPLEMENTED 103 +#define ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED 104 +#define ECDSA_R_ENCODE_ERROR 105 + +#endif /* OPENSSL_HEADER_ECDSA_H */ diff --git a/project/jni/boringssl/include/openssl/engine.h b/project/jni/boringssl/include/openssl/engine.h new file mode 100644 index 000000000..128a2ae12 --- /dev/null +++ b/project/jni/boringssl/include/openssl/engine.h @@ -0,0 +1,98 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_ENGINE_H +#define OPENSSL_HEADER_ENGINE_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Engines are collections of methods. Methods are tables of function pointers, + * defined for certain algorithms, that allow operations on those algorithms to + * be overridden via a callback. This can be used, for example, to implement an + * RSA* that forwards operations to a hardware module. + * + * Methods are reference counted but |ENGINE|s are not. When creating a method, + * you should zero the whole structure and fill in the function pointers that + * you wish before setting it on an |ENGINE|. Any functions pointers that + * are NULL indicate that the default behaviour should be used. */ + + +/* Allocation and destruction. */ + +/* ENGINE_new returns an empty ENGINE that uses the default method for all + * algorithms. */ +OPENSSL_EXPORT ENGINE *ENGINE_new(void); + +/* ENGINE_free decrements the reference counts for all methods linked from + * |engine| and frees |engine| itself. */ +OPENSSL_EXPORT void ENGINE_free(ENGINE *engine); + + +/* Method accessors. + * + * Method accessors take a method pointer and the size of the structure. The + * size allows for ABI compatibility in the case that the method structure is + * extended with extra elements at the end. Methods are always copied by the + * set functions. + * + * Set functions return one on success and zero on allocation failure. */ + +OPENSSL_EXPORT int ENGINE_set_RSA_method(ENGINE *engine, + const RSA_METHOD *method, + size_t method_size); +OPENSSL_EXPORT RSA_METHOD *ENGINE_get_RSA_method(const ENGINE *engine); + +OPENSSL_EXPORT int ENGINE_set_ECDSA_method(ENGINE *engine, + const ECDSA_METHOD *method, + size_t method_size); +OPENSSL_EXPORT ECDSA_METHOD *ENGINE_get_ECDSA_method(const ENGINE *engine); + + +/* Generic method functions. + * + * These functions take a void* type but actually operate on all method + * structures. */ + +/* METHOD_ref increments the reference count of |method|. This is a no-op for + * now because all methods are currently static. */ +void METHOD_ref(void *method); + +/* METHOD_unref decrements the reference count of |method| and frees it if the + * reference count drops to zero. This is a no-op for now because all methods + * are currently static. */ +void METHOD_unref(void *method); + + +/* Private functions. */ + +/* openssl_method_common_st contains the common part of all method structures. + * This must be the first member of all method structures. */ +struct openssl_method_common_st { + int references; /* dummy – not used. */ + char is_static; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define ENGINE_R_OPERATION_NOT_SUPPORTED 100 + +#endif /* OPENSSL_HEADER_ENGINE_H */ diff --git a/project/jni/boringssl/include/openssl/err.h b/project/jni/boringssl/include/openssl/err.h new file mode 100644 index 000000000..40361d791 --- /dev/null +++ b/project/jni/boringssl/include/openssl/err.h @@ -0,0 +1,487 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_ERR_H +#define OPENSSL_HEADER_ERR_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Error queue handling functions. + * + * Errors in OpenSSL are generally signalled by the return value of a function. + * When a function fails it may add an entry to a per-thread error queue, + * which is managed by the functions in this header. + * + * Each error contains: + * 1) The library (i.e. ec, pem, rsa) which created it. + * 2) The file and line number of the call that added the error. + * 3) A pointer to some error specific data, which may be NULL. + * + * The library identifier and reason code are packed in a uint32_t and there + * exist various functions for unpacking it. + * + * The typical behaviour is that an error will occur deep in a call queue and + * that code will push an error onto the error queue. As the error queue + * unwinds, other functions will push their own errors. Thus, the "least + * recent" error is the most specific and the other errors will provide a + * backtrace of sorts. */ + + +/* Startup and shutdown. */ + +/* ERR_load_BIO_strings does nothing. + * + * TODO(fork): remove. libjingle calls this. */ +OPENSSL_EXPORT void ERR_load_BIO_strings(void); + +/* ERR_load_ERR_strings does nothing. */ +OPENSSL_EXPORT void ERR_load_ERR_strings(void); + +/* ERR_load_crypto_strings does nothing. */ +OPENSSL_EXPORT void ERR_load_crypto_strings(void); + +/* ERR_free_strings does nothing. */ +OPENSSL_EXPORT void ERR_free_strings(void); + + +/* Reading and formatting errors. */ + +/* ERR_get_error gets the packed error code for the least recent error and + * removes that error from the queue. If there are no errors in the queue then + * it returns zero. */ +OPENSSL_EXPORT uint32_t ERR_get_error(void); + +/* ERR_get_error_line acts like |ERR_get_error|, except that the file and line + * number of the call that added the error are also returned. */ +OPENSSL_EXPORT uint32_t ERR_get_error_line(const char **file, int *line); + +/* ERR_get_error_line_data acts like |ERR_get_error_line|, but also returns the + * error-specific data pointer and flags. The flags are a bitwise-OR of + * |ERR_FLAG_*| values. The error-specific data is owned by the error queue + * and the pointer becomes invalid after the next call that affects the same + * thread's error queue. If |*flags| contains |ERR_FLAG_STRING| then |*data| is + * human-readable. */ +OPENSSL_EXPORT uint32_t ERR_get_error_line_data(const char **file, int *line, + const char **data, int *flags); + +/* The "peek" functions act like the |ERR_get_error| functions, above, but they + * do not remove the error from the queue. */ +OPENSSL_EXPORT uint32_t ERR_peek_error(void); +OPENSSL_EXPORT uint32_t ERR_peek_error_line(const char **file, int *line); +OPENSSL_EXPORT uint32_t ERR_peek_error_line_data(const char **file, int *line, + const char **data, int *flags); + +/* The "peek last" functions act like the "peek" functions, above, except that + * they return the most recent error. */ +OPENSSL_EXPORT uint32_t ERR_peek_last_error(void); +OPENSSL_EXPORT uint32_t ERR_peek_last_error_line(const char **file, int *line); +OPENSSL_EXPORT uint32_t ERR_peek_last_error_line_data(const char **file, + int *line, + const char **data, + int *flags); + +/* ERR_error_string generates a human-readable string representing + * |packed_error|, places it at |buf| (which must be at least + * ERR_ERROR_STRING_BUF_LEN bytes long) and returns |buf|. If |buf| is NULL, + * the error string is placed in a static buffer which is returned. (The static + * buffer may be overridden by concurrent calls in other threads so this form + * is deprecated.) + * + * The string will have the following format: + * + * error:[error code]:[library name]:OPENSSL_internal:[reason string] + * + * error code is an 8 digit hexadecimal number; library name and reason string + * are ASCII text. + * + * TODO(fork): remove in favour of |ERR_error_string_n|. */ +OPENSSL_EXPORT char *ERR_error_string(uint32_t packed_error, char *buf); +#define ERR_ERROR_STRING_BUF_LEN 256 + +/* ERR_error_string_n is a variant of |ERR_error_string| that writes at most + * len characters (including the terminating NUL) and truncates the string if + * necessary. If |len| is greater than zero then |buf| is always NUL + * terminated. */ +OPENSSL_EXPORT void ERR_error_string_n(uint32_t packed_error, char *buf, + size_t len); + +/* ERR_lib_error_string returns a string representation of the library that + * generated |packed_error|. */ +OPENSSL_EXPORT const char *ERR_lib_error_string(uint32_t packed_error); + +/* ERR_reason_error_string returns a string representation of the reason for + * |packed_error|. */ +OPENSSL_EXPORT const char *ERR_reason_error_string(uint32_t packed_error); + +/* ERR_print_errors_callback_t is the type of a function used by + * |ERR_print_errors_cb|. It takes a pointer to a human readable string (and + * its length) that describes an entry in the error queue. The |ctx| argument + * is an opaque pointer given to |ERR_print_errors_cb|. + * + * It should return one on success or zero on error, which will stop the + * iteration over the error queue. */ +typedef int (*ERR_print_errors_callback_t)(const char *str, size_t len, + void *ctx); + +/* ERR_print_errors_cb calls |callback| with a string representation of each + * error in the current thread's error queue, from the least recent to the most + * recent error. + * + * The string will have the following format (which differs from + * |ERR_error_string|): + * + * [thread id]:error:[error code]:[library name]:OPENSSL_internal: + * [reason string]:[file]:[line number]:[optional string data] + * + * (All in one line.) + * + * The callback can return one to continue the iteration or zero to stop it. + * The |ctx| argument is an opaque value that is passed through to the + * callback. */ +OPENSSL_EXPORT void ERR_print_errors_cb(ERR_print_errors_callback_t callback, + void *ctx); + +/* ERR_print_errors_fp prints the current contents of the error stack to |file| + * using human readable strings where possible. */ +OPENSSL_EXPORT void ERR_print_errors_fp(FILE *file); + + +/* Clearing errors. */ + +/* ERR_clear_error clears the error queue for the current thread. */ +OPENSSL_EXPORT void ERR_clear_error(void); + +/* ERR_remove_thread_state clears the error queue for the current thread if + * |tid| is NULL. Otherwise it calls |assert(0)|, because it's no longer + * possible to delete the error queue for other threads. + * + * Error queues are thread-local data and are deleted automatically. You do not + * need to call this function. Use |ERR_clear_error|. */ +OPENSSL_EXPORT void ERR_remove_thread_state(const CRYPTO_THREADID *tid); + + +/* Custom errors. */ + +/* ERR_get_next_error_library returns a value suitable for passing as the + * |library| argument to |ERR_put_error|. This is intended for code that wishes + * to push its own, non-standard errors to the error queue. */ +OPENSSL_EXPORT int ERR_get_next_error_library(void); + + +/* Deprecated functions. */ + +/* ERR_remove_state calls |ERR_clear_error|. */ +OPENSSL_EXPORT void ERR_remove_state(unsigned long pid); + +/* ERR_func_error_string returns the string "OPENSSL_internal". */ +OPENSSL_EXPORT const char *ERR_func_error_string(uint32_t packed_error); + + +/* Private functions. */ + +/* ERR_clear_system_error clears the system's error value (i.e. errno). */ +OPENSSL_EXPORT void ERR_clear_system_error(void); + +/* OPENSSL_PUT_ERROR is used by OpenSSL code to add an error to the error + * queue. */ +#define OPENSSL_PUT_ERROR(library, reason) \ + ERR_put_error(ERR_LIB_##library, 0, reason, __FILE__, __LINE__) + +/* OPENSSL_PUT_SYSTEM_ERROR is used by OpenSSL code to add an error from the + * operating system to the error queue. + * TODO(fork): include errno. */ +#define OPENSSL_PUT_SYSTEM_ERROR() \ + ERR_put_error(ERR_LIB_SYS, 0, 0, __FILE__, __LINE__); + +/* ERR_put_error adds an error to the error queue, dropping the least recent + * error if neccessary for space reasons. */ +OPENSSL_EXPORT void ERR_put_error(int library, int unused, int reason, + const char *file, unsigned line); + +/* ERR_add_error_data takes a variable number (|count|) of const char* + * pointers, concatenates them and sets the result as the data on the most + * recent error. */ +OPENSSL_EXPORT void ERR_add_error_data(unsigned count, ...); + +/* ERR_add_error_dataf takes a printf-style format and arguments, and sets the + * result as the data on the most recent error. */ +OPENSSL_EXPORT void ERR_add_error_dataf(const char *format, ...); + +/* ERR_set_mark "marks" the most recent error for use with |ERR_pop_to_mark|. + * It returns one if an error was marked and zero if there are no errors. */ +OPENSSL_EXPORT int ERR_set_mark(void); + +/* ERR_pop_to_mark removes errors from the most recent to the least recent + * until (and not including) a "marked" error. It returns zero if no marked + * error was found (and thus all errors were removed) and one otherwise. Errors + * are marked using |ERR_set_mark|. */ +OPENSSL_EXPORT int ERR_pop_to_mark(void); + +struct err_error_st { + /* file contains the filename where the error occured. */ + const char *file; + /* data contains optional data. It must be freed with |OPENSSL_free| if + * |flags&ERR_FLAG_MALLOCED|. */ + char *data; + /* packed contains the error library and reason, as packed by ERR_PACK. */ + uint32_t packed; + /* line contains the line number where the error occured. */ + uint16_t line; + /* flags contains a bitwise-OR of ERR_FLAG_* values. */ + uint8_t flags; +}; + +/* ERR_FLAG_STRING means that the |data| member is a NUL-terminated string that + * can be printed. */ +#define ERR_FLAG_STRING 1 +/* ERR_TXT_STRING is provided for compatibility with code that assumes that + * it's using OpenSSL. */ +#define ERR_TXT_STRING ERR_FLAG_STRING + +/* ERR_FLAG_PUBLIC_MASK is applied to the flags field before it is returned + * from functions like |ERR_get_error_line_data|. */ +#define ERR_FLAG_PUBLIC_MASK 0xf + +/* The following flag values are internal and are masked when flags are + * returned from functions like |ERR_get_error_line_data|. */ + +/* ERR_FLAG_MALLOCED means the the |data| member must be freed when no longer + * needed. */ +#define ERR_FLAG_MALLOCED 16 +/* ERR_FLAG_MARK is used to indicate a reversion point in the queue. See + * |ERR_pop_to_mark|. */ +#define ERR_FLAG_MARK 32 + +/* ERR_NUM_ERRORS is the limit of the number of errors in the queue. */ +#define ERR_NUM_ERRORS 16 + +/* ERR_STATE contains the per-thread, error queue. */ +typedef struct err_state_st { + /* errors contains the ERR_NUM_ERRORS most recent errors, organised as a ring + * buffer. */ + struct err_error_st errors[ERR_NUM_ERRORS]; + /* top contains the index one past the most recent error. If |top| equals + * |bottom| then the queue is empty. */ + unsigned top; + /* bottom contains the index of the last error in the queue. */ + unsigned bottom; + + /* to_free, if not NULL, contains a pointer owned by this structure that was + * previously a |data| pointer of one of the elements of |errors|. */ + void *to_free; +} ERR_STATE; + +enum { + ERR_LIB_NONE = 1, + ERR_LIB_SYS, + ERR_LIB_BN, + ERR_LIB_RSA, + ERR_LIB_DH, + ERR_LIB_EVP, + ERR_LIB_BUF, + ERR_LIB_OBJ, + ERR_LIB_PEM, + ERR_LIB_DSA, + ERR_LIB_X509, + ERR_LIB_ASN1, + ERR_LIB_CONF, + ERR_LIB_CRYPTO, + ERR_LIB_EC, + ERR_LIB_SSL, + ERR_LIB_BIO, + ERR_LIB_PKCS7, + ERR_LIB_PKCS8, + ERR_LIB_X509V3, + ERR_LIB_RAND, + ERR_LIB_ENGINE, + ERR_LIB_OCSP, + ERR_LIB_UI, + ERR_LIB_COMP, + ERR_LIB_ECDSA, + ERR_LIB_ECDH, + ERR_LIB_HMAC, + ERR_LIB_DIGEST, + ERR_LIB_CIPHER, + ERR_LIB_HKDF, + ERR_LIB_USER, + ERR_NUM_LIBS +}; + +#define ERR_R_SYS_LIB ERR_LIB_SYS +#define ERR_R_BN_LIB ERR_LIB_BN +#define ERR_R_RSA_LIB ERR_LIB_RSA +#define ERR_R_DH_LIB ERR_LIB_DH +#define ERR_R_EVP_LIB ERR_LIB_EVP +#define ERR_R_BUF_LIB ERR_LIB_BUF +#define ERR_R_OBJ_LIB ERR_LIB_OBJ +#define ERR_R_PEM_LIB ERR_LIB_PEM +#define ERR_R_DSA_LIB ERR_LIB_DSA +#define ERR_R_X509_LIB ERR_LIB_X509 +#define ERR_R_ASN1_LIB ERR_LIB_ASN1 +#define ERR_R_CONF_LIB ERR_LIB_CONF +#define ERR_R_CRYPTO_LIB ERR_LIB_CRYPTO +#define ERR_R_EC_LIB ERR_LIB_EC +#define ERR_R_SSL_LIB ERR_LIB_SSL +#define ERR_R_BIO_LIB ERR_LIB_BIO +#define ERR_R_PKCS7_LIB ERR_LIB_PKCS7 +#define ERR_R_PKCS8_LIB ERR_LIB_PKCS8 +#define ERR_R_X509V3_LIB ERR_LIB_X509V3 +#define ERR_R_RAND_LIB ERR_LIB_RAND +#define ERR_R_DSO_LIB ERR_LIB_DSO +#define ERR_R_ENGINE_LIB ERR_LIB_ENGINE +#define ERR_R_OCSP_LIB ERR_LIB_OCSP +#define ERR_R_UI_LIB ERR_LIB_UI +#define ERR_R_COMP_LIB ERR_LIB_COMP +#define ERR_R_ECDSA_LIB ERR_LIB_ECDSA +#define ERR_R_ECDH_LIB ERR_LIB_ECDH +#define ERR_R_STORE_LIB ERR_LIB_STORE +#define ERR_R_FIPS_LIB ERR_LIB_FIPS +#define ERR_R_CMS_LIB ERR_LIB_CMS +#define ERR_R_TS_LIB ERR_LIB_TS +#define ERR_R_HMAC_LIB ERR_LIB_HMAC +#define ERR_R_JPAKE_LIB ERR_LIB_JPAKE +#define ERR_R_USER_LIB ERR_LIB_USER +#define ERR_R_DIGEST_LIB ERR_LIB_DIGEST +#define ERR_R_CIPHER_LIB ERR_LIB_CIPHER +#define ERR_R_HKDF_LIB ERR_LIB_HKDF + +/* Global reasons. */ +#define ERR_R_FATAL 64 +#define ERR_R_MALLOC_FAILURE (1 | ERR_R_FATAL) +#define ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED (2 | ERR_R_FATAL) +#define ERR_R_PASSED_NULL_PARAMETER (3 | ERR_R_FATAL) +#define ERR_R_INTERNAL_ERROR (4 | ERR_R_FATAL) +#define ERR_R_OVERFLOW (5 | ERR_R_FATAL) + +#define ERR_PACK(lib, reason) \ + (((((uint32_t)lib) & 0xff) << 24) | ((((uint32_t)reason) & 0xfff))) + +#define ERR_GET_LIB(packed_error) ((int)(((packed_error) >> 24) & 0xff)) +#define ERR_GET_FUNC(packed_error) 0 +#define ERR_GET_REASON(packed_error) ((int)((packed_error) & 0xfff)) + +/* OPENSSL_DECLARE_ERROR_REASON is used by util/make_errors.h (which generates + * the error defines) to recognise that an additional reason value is needed. + * This is needed when the reason value is used outside of an + * |OPENSSL_PUT_ERROR| macro. The resulting define will be + * ${lib}_R_${reason}. */ +#define OPENSSL_DECLARE_ERROR_REASON(lib, reason) + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_ERR_H */ diff --git a/project/jni/boringssl/include/openssl/evp.h b/project/jni/boringssl/include/openssl/evp.h new file mode 100644 index 000000000..be2ea332d --- /dev/null +++ b/project/jni/boringssl/include/openssl/evp.h @@ -0,0 +1,750 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_EVP_H +#define OPENSSL_HEADER_EVP_H + +#include + +#include + +/* OpenSSL included digest and cipher functions in this header so we include + * them for users that still expect that. + * + * TODO(fork): clean up callers so that they include what they use. */ +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* EVP abstracts over public/private key algorithms. */ + + +/* Public key objects. */ + +/* EVP_PKEY_new creates a new, empty public-key object and returns it or NULL + * on allocation failure. */ +OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_new(void); + +/* EVP_PKEY_free frees all data referenced by |pkey| and then frees |pkey| + * itself. */ +OPENSSL_EXPORT void EVP_PKEY_free(EVP_PKEY *pkey); + +/* EVP_PKEY_up_ref increments the reference count of |pkey| and returns it. */ +OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_up_ref(EVP_PKEY *pkey); + +/* EVP_PKEY_is_opaque returns one if |pkey| is opaque. Opaque keys are backed by + * custom implementations which do not expose key material and parameters. It is + * an error to attempt to duplicate, export, or compare an opaque key. */ +OPENSSL_EXPORT int EVP_PKEY_is_opaque(const EVP_PKEY *pkey); + +/* EVP_PKEY_supports_digest returns one if |pkey| supports digests of + * type |md|. This is intended for use with EVP_PKEYs backing custom + * implementations which can't sign all digests. */ +OPENSSL_EXPORT int EVP_PKEY_supports_digest(const EVP_PKEY *pkey, + const EVP_MD *md); + +/* EVP_PKEY_cmp compares |a| and |b| and returns one if they are equal, zero if + * not and a negative number on error. + * + * WARNING: this differs from the traditional return value of a "cmp" + * function. */ +OPENSSL_EXPORT int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b); + +/* EVP_PKEY_copy_parameters sets the parameters of |to| to equal the parameters + * of |from|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from); + +/* EVP_PKEY_missing_parameters returns one if |pkey| is missing needed + * parameters or zero if not, or if the algorithm doesn't take parameters. */ +OPENSSL_EXPORT int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey); + +/* EVP_PKEY_size returns the maximum size, in bytes, of a signature signed by + * |pkey|. For an RSA key, this returns the number of bytes needed to represent + * the modulus. For an EC key, this returns the maximum size of a DER-encoded + * ECDSA signature. */ +OPENSSL_EXPORT int EVP_PKEY_size(const EVP_PKEY *pkey); + +/* EVP_PKEY_bits returns the "size", in bits, of |pkey|. For an RSA key, this + * returns the bit length of the modulus. For an EC key, this returns the bit + * length of the group order. */ +OPENSSL_EXPORT int EVP_PKEY_bits(EVP_PKEY *pkey); + +/* EVP_PKEY_id returns the type of |pkey|, which is one of the |EVP_PKEY_*| + * values. */ +OPENSSL_EXPORT int EVP_PKEY_id(const EVP_PKEY *pkey); + +/* EVP_PKEY_type returns a canonicalised form of |NID|. For example, + * |EVP_PKEY_RSA2| will be turned into |EVP_PKEY_RSA|. */ +OPENSSL_EXPORT int EVP_PKEY_type(int nid); + + +/* Getting and setting concrete public key types. + * + * The following functions get and set the underlying public key in an + * |EVP_PKEY| object. The |set1| functions take an additional reference to the + * underlying key and return one on success or zero on error. The |assign| + * functions adopt the caller's reference. The |get1| functions return a fresh + * reference to the underlying object or NULL if |pkey| is not of the correct + * type. The |get0| functions behave the same but return a non-owning + * pointer. */ + +OPENSSL_EXPORT int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key); +OPENSSL_EXPORT int EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key); +OPENSSL_EXPORT RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey); +OPENSSL_EXPORT RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey); + +OPENSSL_EXPORT int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, DSA *key); +OPENSSL_EXPORT int EVP_PKEY_assign_DSA(EVP_PKEY *pkey, DSA *key); +OPENSSL_EXPORT DSA *EVP_PKEY_get0_DSA(EVP_PKEY *pkey); +OPENSSL_EXPORT DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey); + +OPENSSL_EXPORT int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, EC_KEY *key); +OPENSSL_EXPORT int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key); +OPENSSL_EXPORT EC_KEY *EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey); +OPENSSL_EXPORT EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey); + +#define EVP_PKEY_NONE NID_undef +#define EVP_PKEY_RSA NID_rsaEncryption +#define EVP_PKEY_RSA2 NID_rsa +#define EVP_PKEY_DSA NID_dsa +#define EVP_PKEY_EC NID_X9_62_id_ecPublicKey + +/* EVP_PKEY_assign sets the underlying key of |pkey| to |key|, which must be of + * the given type. The |type| argument should be one of the |EVP_PKEY_*| + * values. */ +OPENSSL_EXPORT int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key); + +/* EVP_PKEY_set_type sets the type of |pkey| to |type|, which should be one of + * the |EVP_PKEY_*| values. It returns one if sucessful or zero otherwise. If + * |pkey| is NULL, it simply reports whether the type is known. */ +OPENSSL_EXPORT int EVP_PKEY_set_type(EVP_PKEY *pkey, int type); + +/* EVP_PKEY_cmp_parameters compares the parameters of |a| and |b|. It returns + * one if they match, zero if not, or a negative number of on error. + * + * WARNING: the return value differs from the usual return value convention. */ +OPENSSL_EXPORT int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, + const EVP_PKEY *b); + + +/* ASN.1 functions */ + +/* d2i_PrivateKey parses an ASN.1, DER-encoded, private key from |len| bytes at + * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in + * |*out|. If |*out| is already non-NULL on entry then the result is written + * directly into |*out|, otherwise a fresh |EVP_PKEY| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, + const uint8_t **inp, long len); + +/* d2i_AutoPrivateKey acts the same as |d2i_PrivateKey|, but detects the type + * of the private key. */ +OPENSSL_EXPORT EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, + long len); + +/* i2d_PrivateKey marshals a private key from |key| to an ASN.1, DER + * structure. If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_PrivateKey(const EVP_PKEY *key, uint8_t **outp); + +/* i2d_PublicKey marshals a public key from |key| to a type-specific format. + * If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. + * + * RSA keys are serialized as a DER-encoded RSAPublicKey (RFC 3447) structure. + * EC keys are serialized as an EC point per SEC 1. */ +OPENSSL_EXPORT int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp); + + +/* Signing */ + +/* EVP_DigestSignInit sets up |ctx| for a signing operation with |type| and + * |pkey|. The |ctx| argument must have been initialised with + * |EVP_MD_CTX_init|. If |pctx| is not NULL, the |EVP_PKEY_CTX| of the signing + * operation will be written to |*pctx|; this can be used to set alternative + * signing options. + * + * It returns one on success, or zero on error. */ +OPENSSL_EXPORT int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, + EVP_PKEY *pkey); + +/* EVP_DigestSignUpdate appends |len| bytes from |data| to the data which will + * be signed in |EVP_DigestSignFinal|. It returns one. */ +OPENSSL_EXPORT int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, + size_t len); + +/* EVP_DigestSignFinal signs the data that has been included by one or more + * calls to |EVP_DigestSignUpdate|. If |out_sig| is NULL then |*out_sig_len| is + * set to the maximum number of output bytes. Otherwise, on entry, + * |*out_sig_len| must contain the length of the |out_sig| buffer. If the call + * is successful, the signature is written to |out_sig| and |*out_sig_len| is + * set to its length. + * + * It returns one on success, or zero on error. */ +OPENSSL_EXPORT int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig, + size_t *out_sig_len); + +/* EVP_DigestSignAlgorithm encodes the signing parameters of |ctx| as an + * AlgorithmIdentifer and saves the result in |algor|. + * + * It returns one on success, or zero on error. + * + * TODO(davidben): This API should eventually lose the dependency on + * crypto/asn1/. */ +OPENSSL_EXPORT int EVP_DigestSignAlgorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor); + + +/* Verifying */ + +/* EVP_DigestVerifyInit sets up |ctx| for a signature verification operation + * with |type| and |pkey|. The |ctx| argument must have been initialised with + * |EVP_MD_CTX_init|. If |pctx| is not NULL, the |EVP_PKEY_CTX| of the signing + * operation will be written to |*pctx|; this can be used to set alternative + * signing options. + * + * It returns one on success, or zero on error. */ +OPENSSL_EXPORT int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, + EVP_PKEY *pkey); + +/* EVP_DigestVerifyInitFromAlgorithm sets up |ctx| for a signature verification + * operation with public key |pkey| and parameters from |algor|. The |ctx| + * argument must have been initialised with |EVP_MD_CTX_init|. + * + * It returns one on success, or zero on error. + * + * TODO(davidben): This API should eventually lose the dependency on + * crypto/asn1/. */ +OPENSSL_EXPORT int EVP_DigestVerifyInitFromAlgorithm(EVP_MD_CTX *ctx, + X509_ALGOR *algor, + EVP_PKEY *pkey); + +/* EVP_DigestVerifyUpdate appends |len| bytes from |data| to the data which + * will be verified by |EVP_DigestVerifyFinal|. It returns one. */ +OPENSSL_EXPORT int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, + size_t len); + +/* EVP_DigestVerifyFinal verifies that |sig_len| bytes of |sig| are a valid + * signature for the data that has been included by one or more calls to + * |EVP_DigestVerifyUpdate|. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, + size_t sig_len); + + +/* Signing (old functions) */ + +/* EVP_SignInit_ex configures |ctx|, which must already have been initialised, + * for a fresh signing operation using the hash function |type|. It returns one + * on success and zero otherwise. + * + * (In order to initialise |ctx|, either obtain it initialised with + * |EVP_MD_CTX_create|, or use |EVP_MD_CTX_init|.) */ +OPENSSL_EXPORT int EVP_SignInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, + ENGINE *impl); + +/* EVP_SignInit is a deprecated version of |EVP_SignInit_ex|. + * + * TODO(fork): remove. */ +OPENSSL_EXPORT int EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type); + +/* EVP_SignUpdate appends |len| bytes from |data| to the data which will be + * signed in |EVP_SignFinal|. */ +OPENSSL_EXPORT int EVP_SignUpdate(EVP_MD_CTX *ctx, const void *data, + size_t len); + +/* EVP_SignFinal signs the data that has been included by one or more calls to + * |EVP_SignUpdate|, using the key |pkey|, and writes it to |sig|. On entry, + * |sig| must point to at least |EVP_PKEY_size(pkey)| bytes of space. The + * actual size of the signature is written to |*out_sig_len|. + * + * It returns one on success and zero otherwise. + * + * It does not modify |ctx|, thus it's possible to continue to use |ctx| in + * order to sign a longer message. */ +OPENSSL_EXPORT int EVP_SignFinal(const EVP_MD_CTX *ctx, uint8_t *sig, + unsigned int *out_sig_len, EVP_PKEY *pkey); + + +/* Verifying (old functions) */ + +/* EVP_VerifyInit_ex configures |ctx|, which must already have been + * initialised, for a fresh signature verification operation using the hash + * function |type|. It returns one on success and zero otherwise. + * + * (In order to initialise |ctx|, either obtain it initialised with + * |EVP_MD_CTX_create|, or use |EVP_MD_CTX_init|.) */ +OPENSSL_EXPORT int EVP_VerifyInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, + ENGINE *impl); + +/* EVP_VerifyInit is a deprecated version of |EVP_VerifyInit_ex|. + * + * TODO(fork): remove. */ +OPENSSL_EXPORT int EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type); + +/* EVP_VerifyUpdate appends |len| bytes from |data| to the data which will be + * signed in |EVP_VerifyFinal|. */ +OPENSSL_EXPORT int EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *data, + size_t len); + +/* EVP_VerifyFinal verifies that |sig_len| bytes of |sig| are a valid + * signature, by |pkey|, for the data that has been included by one or more + * calls to |EVP_VerifyUpdate|. + * + * It returns one on success and zero otherwise. + * + * It does not modify |ctx|, thus it's possible to continue to use |ctx| in + * order to sign a longer message. */ +OPENSSL_EXPORT int EVP_VerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, + size_t sig_len, EVP_PKEY *pkey); + + +/* Printing */ + +/* EVP_PKEY_print_public prints a textual representation of the public key in + * |pkey| to |out|. Returns one on success or zero otherwise. */ +OPENSSL_EXPORT int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, + int indent, ASN1_PCTX *pctx); + +/* EVP_PKEY_print_private prints a textual representation of the private key in + * |pkey| to |out|. Returns one on success or zero otherwise. */ +OPENSSL_EXPORT int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, + int indent, ASN1_PCTX *pctx); + +/* EVP_PKEY_print_params prints a textual representation of the parameters in + * |pkey| to |out|. Returns one on success or zero otherwise. */ +OPENSSL_EXPORT int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, + int indent, ASN1_PCTX *pctx); + + +/* Password stretching. + * + * Password stretching functions take a low-entropy password and apply a slow + * function that results in a key suitable for use in symmetric + * cryptography. */ + +/* PKCS5_PBKDF2_HMAC computes |iterations| iterations of PBKDF2 of |password| + * and |salt|, using |digest|, and outputs |key_len| bytes to |out_key|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS5_PBKDF2_HMAC(const char *password, size_t password_len, + const uint8_t *salt, size_t salt_len, + unsigned iterations, const EVP_MD *digest, + size_t key_len, uint8_t *out_key); + +/* PKCS5_PBKDF2_HMAC_SHA1 is the same as PKCS5_PBKDF2_HMAC, but with |digest| + * fixed to |EVP_sha1|. */ +OPENSSL_EXPORT int PKCS5_PBKDF2_HMAC_SHA1(const char *password, + size_t password_len, const uint8_t *salt, + size_t salt_len, unsigned iterations, + size_t key_len, uint8_t *out_key); + + +/* Public key contexts. + * + * |EVP_PKEY_CTX| objects hold the context of an operation (e.g. signing or + * encrypting) that uses a public key. */ + +/* EVP_PKEY_CTX_new allocates a fresh |EVP_PKEY_CTX| for use with |pkey|. It + * returns the context or NULL on error. */ +OPENSSL_EXPORT EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e); + +/* EVP_PKEY_CTX_new_id allocates a fresh |EVP_PKEY_CTX| for a key of type |id| + * (e.g. |EVP_PKEY_HMAC|). This can be used for key generation where + * |EVP_PKEY_CTX_new| can't be used because there isn't an |EVP_PKEY| to pass + * it. It returns the context or NULL on error. */ +OPENSSL_EXPORT EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e); + +/* EVP_PKEY_CTX_free frees |ctx| and the data it owns. */ +OPENSSL_EXPORT void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_CTX_dup allocates a fresh |EVP_PKEY_CTX| and sets it equal to the + * state of |ctx|. It returns the fresh |EVP_PKEY_CTX| or NULL on error. */ +OPENSSL_EXPORT EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_CTX_get0_pkey returns the |EVP_PKEY| associated with |ctx|. */ +OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_CTX_set_app_data sets an opaque pointer on |ctx|. */ +OPENSSL_EXPORT void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data); + +/* EVP_PKEY_CTX_get_app_data returns the opaque pointer from |ctx| that was + * previously set with |EVP_PKEY_CTX_set_app_data|, or NULL if none has been + * set. */ +OPENSSL_EXPORT void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_sign_init initialises an |EVP_PKEY_CTX| for a signing operation. It + * should be called before |EVP_PKEY_sign|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_sign signs |data_len| bytes from |data| using |ctx|. If |sig| is + * NULL, the maximum size of the signature is written to + * |out_sig_len|. Otherwise, |*sig_len| must contain the number of bytes of + * space available at |sig|. If sufficient, the signature will be written to + * |sig| and |*sig_len| updated with the true length. + * + * WARNING: Setting |sig| to NULL only gives the maximum size of the + * signature. The actual signature may be smaller. + * + * It returns one on success or zero on error. (Note: this differs from + * OpenSSL, which can also return negative values to indicate an error. ) */ +OPENSSL_EXPORT int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, + size_t *sig_len, const uint8_t *data, + size_t data_len); + +/* EVP_PKEY_verify_init initialises an |EVP_PKEY_CTX| for a signature + * verification operation. It should be called before |EVP_PKEY_verify|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_verify verifies that |sig_len| bytes from |sig| are a valid signature + * for |data|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, + size_t sig_len, const uint8_t *data, + size_t data_len); + +/* EVP_PKEY_encrypt_init initialises an |EVP_PKEY_CTX| for an encryption + * operation. It should be called before |EVP_PKEY_encrypt|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_encrypt encrypts |in_len| bytes from |in|. If |out| is NULL, the + * maximum size of the ciphertext is written to |out_len|. Otherwise, |*out_len| + * must contain the number of bytes of space available at |out|. If sufficient, + * the ciphertext will be written to |out| and |*out_len| updated with the true + * length. + * + * WARNING: Setting |out| to NULL only gives the maximum size of the + * ciphertext. The actual ciphertext may be smaller. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, + size_t *out_len, const uint8_t *in, + size_t in_len); + +/* EVP_PKEY_decrypt_init initialises an |EVP_PKEY_CTX| for a decryption + * operation. It should be called before |EVP_PKEY_decrypt|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_decrypt decrypts |in_len| bytes from |in|. If |out| is NULL, the + * maximum size of the plaintext is written to |out_len|. Otherwise, |*out_len| + * must contain the number of bytes of space available at |out|. If sufficient, + * the ciphertext will be written to |out| and |*out_len| updated with the true + * length. + * + * WARNING: Setting |out| to NULL only gives the maximum size of the + * plaintext. The actual plaintext may be smaller. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out, + size_t *out_len, const uint8_t *in, + size_t in_len); + +/* EVP_PKEY_derive_init initialises an |EVP_PKEY_CTX| for a key derivation + * operation. It should be called before |EVP_PKEY_derive_set_peer| and + * |EVP_PKEY_derive|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_derive_set_peer sets the peer's key to be used for key derivation + * by |ctx| to |peer|. It should be called after |EVP_PKEY_derive_init|. (For + * example, this is used to set the peer's key in (EC)DH.) It returns one on + * success and zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer); + +/* EVP_PKEY_derive derives a shared key between the two keys configured in + * |ctx|. If |key| is non-NULL then, on entry, |out_key_len| must contain the + * amount of space at |key|. If sufficient then the shared key will be written + * to |key| and |*out_key_len| will be set to the length. If |key| is NULL then + * |out_key_len| will be set to the maximum length. + * + * WARNING: Setting |out| to NULL only gives the maximum size of the key. The + * actual key may be smaller. + * + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, uint8_t *key, + size_t *out_key_len); + +/* EVP_PKEY_keygen_init initialises an |EVP_PKEY_CTX| for a key generation + * operation. It should be called before |EVP_PKEY_keygen|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_keygen performs a key generation operation using the values from + * |ctx| and sets |*ppkey| to a fresh |EVP_PKEY| containing the resulting key. + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey); + + +/* Generic control functions. */ + +/* EVP_PKEY_CTX_set_signature_md sets |md| as the digest to be used in a + * signature operation. It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, + const EVP_MD *md); + +/* EVP_PKEY_CTX_get_signature_md sets |*out_md| to the digest to be used in a + * signature operation. It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, + const EVP_MD **out_md); + + +/* RSA specific control functions. */ + +/* EVP_PKEY_CTX_set_rsa_padding sets the padding type to use. It should be one + * of the |RSA_*_PADDING| values. Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int padding); + +/* EVP_PKEY_CTX_get_rsa_padding sets |*out_padding| to the current padding + * value, which is one of the |RSA_*_PADDING| values. Returns one on success or + * zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, + int *out_padding); + +/* EVP_PKEY_CTX_set_rsa_pss_saltlen sets the length of the salt in a PSS-padded + * signature. A value of -1 cause the salt to be the same length as the digest + * in the signature. A value of -2 causes the salt to be the maximum length + * that will fit. Otherwise the value gives the size of the salt in bytes. + * + * Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, + int salt_len); + +/* EVP_PKEY_CTX_get_rsa_pss_saltlen sets |*out_salt_len| to the salt length of + * a PSS-padded signature. See the documentation for + * |EVP_PKEY_CTX_set_rsa_pss_saltlen| for details of the special values that it + * can take. + * + * Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, + int *out_salt_len); + +/* EVP_PKEY_CTX_set_rsa_keygen_bits sets the size of the desired RSA modulus, + * in bits, for key generation. Returns one on success or zero on + * error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX *ctx, + int bits); + +/* EVP_PKEY_CTX_set_rsa_keygen_pubexp sets |e| as the public exponent for key + * generation. Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, + BIGNUM *e); + +/* EVP_PKEY_CTX_set_rsa_oaep_md sets |md| as the digest used in OAEP padding. + * Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, + const EVP_MD *md); + +/* EVP_PKEY_CTX_get_rsa_oaep_md sets |*out_md| to the digest function used in + * OAEP padding. Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, + const EVP_MD **out_md); + +/* EVP_PKEY_CTX_set_rsa_mgf1_md sets |md| as the digest used in MGF1. Returns + * one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, + const EVP_MD *md); + +/* EVP_PKEY_CTX_get_rsa_mgf1_md sets |*out_md| to the digest function used in + * MGF1. Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, + const EVP_MD **out_md); + +/* EVP_PKEY_CTX_set0_rsa_oaep_label sets |label_len| bytes from |label| as the + * label used in OAEP. DANGER: On success, this call takes ownership of |label| + * and will call |OPENSSL_free| on it when |ctx| is destroyed. + * + * Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, + const uint8_t *label, + size_t label_len); + +/* EVP_PKEY_CTX_get0_rsa_oaep_label sets |*out_label| to point to the internal + * buffer containing the OAEP label (which may be NULL) and returns the length + * of the label or a negative value on error. + * + * WARNING: the return value differs from the usual return value convention. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx, + const uint8_t **out_label); + + +/* Deprecated functions. */ + +/* EVP_PKEY_DH is defined for compatibility, but it is impossible to create an + * |EVP_PKEY| of that type. */ +#define EVP_PKEY_DH NID_dhKeyAgreement + +/* OpenSSL_add_all_algorithms does nothing. */ +OPENSSL_EXPORT void OpenSSL_add_all_algorithms(void); + +/* OpenSSL_add_all_ciphers does nothing. */ +OPENSSL_EXPORT void OpenSSL_add_all_ciphers(void); + +/* OpenSSL_add_all_digests does nothing. */ +OPENSSL_EXPORT void OpenSSL_add_all_digests(void); + +/* EVP_cleanup does nothing. */ +OPENSSL_EXPORT void EVP_cleanup(void); + + +/* Private functions */ + +/* EVP_PKEY_asn1_find returns the ASN.1 method table for the given |nid|, which + * should be one of the |EVP_PKEY_*| values. It returns NULL if |nid| is + * unknown. */ +OPENSSL_EXPORT const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pengine, + int nid); + +/* EVP_PKEY_asn1_find_str returns an |EVP_PKEY_ASN1_METHOD| by matching values + * of the |len| bytes at |name|. For example, if name equals "EC" then it will + * return an ECC method. The |pengine| argument is ignored. + * + * TODO(fork): move to PEM? */ +OPENSSL_EXPORT const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str( + ENGINE **pengine, const char *name, size_t len); + +struct evp_pkey_st { + CRYPTO_refcount_t references; + + /* type contains one of the EVP_PKEY_* values or NID_undef and determines + * which element (if any) of the |pkey| union is valid. */ + int type; + + union { + char *ptr; + RSA *rsa; + DSA *dsa; + DH *dh; + EC_KEY *ec; + } pkey; + + /* ameth contains a pointer to a method table that contains many ASN.1 + * methods for the key type. */ + const EVP_PKEY_ASN1_METHOD *ameth; +} /* EVP_PKEY */; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define EVP_R_BUFFER_TOO_SMALL 100 +#define EVP_R_COMMAND_NOT_SUPPORTED 101 +#define EVP_R_DIFFERENT_KEY_TYPES 104 +#define EVP_R_DIFFERENT_PARAMETERS 105 +#define EVP_R_EXPECTING_AN_EC_KEY_KEY 107 +#define EVP_R_EXPECTING_A_DH_KEY 109 +#define EVP_R_EXPECTING_A_DSA_KEY 110 +#define EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 111 +#define EVP_R_INVALID_CURVE 112 +#define EVP_R_INVALID_DIGEST_LENGTH 113 +#define EVP_R_INVALID_DIGEST_TYPE 114 +#define EVP_R_INVALID_KEYBITS 115 +#define EVP_R_INVALID_MGF1_MD 116 +#define EVP_R_INVALID_PADDING_MODE 118 +#define EVP_R_INVALID_PSS_PARAMETERS 119 +#define EVP_R_INVALID_SALT_LENGTH 121 +#define EVP_R_INVALID_TRAILER 122 +#define EVP_R_KEYS_NOT_SET 123 +#define EVP_R_MISSING_PARAMETERS 124 +#define EVP_R_NO_DEFAULT_DIGEST 125 +#define EVP_R_NO_KEY_SET 126 +#define EVP_R_NO_MDC2_SUPPORT 127 +#define EVP_R_NO_NID_FOR_CURVE 128 +#define EVP_R_NO_OPERATION_SET 129 +#define EVP_R_NO_PARAMETERS_SET 130 +#define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 131 +#define EVP_R_OPERATON_NOT_INITIALIZED 132 +#define EVP_R_UNKNOWN_DIGEST 133 +#define EVP_R_UNKNOWN_MASK_DIGEST 134 +#define EVP_R_UNSUPPORTED_ALGORITHM 138 +#define EVP_R_UNSUPPORTED_MASK_ALGORITHM 139 +#define EVP_R_UNSUPPORTED_MASK_PARAMETER 140 +#define EVP_R_EXPECTING_AN_RSA_KEY 141 +#define EVP_R_INVALID_OPERATION 142 +#define EVP_R_DECODE_ERROR 143 +#define EVP_R_INVALID_PSS_SALTLEN 144 +#define EVP_R_UNKNOWN_PUBLIC_KEY_TYPE 145 +#define EVP_R_CONTEXT_NOT_INITIALISED 146 +#define EVP_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED 147 +#define EVP_R_WRONG_PUBLIC_KEY_TYPE 148 +#define EVP_R_UNKNOWN_SIGNATURE_ALGORITHM 149 +#define EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 150 +#define EVP_R_BN_DECODE_ERROR 151 +#define EVP_R_PARAMETER_ENCODING_ERROR 152 +#define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 153 +#define EVP_R_UNSUPPORTED_SIGNATURE_TYPE 154 + +#endif /* OPENSSL_HEADER_EVP_H */ diff --git a/project/jni/boringssl/include/openssl/ex_data.h b/project/jni/boringssl/include/openssl/ex_data.h new file mode 100644 index 000000000..e78e0703a --- /dev/null +++ b/project/jni/boringssl/include/openssl/ex_data.h @@ -0,0 +1,213 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_EX_DATA_H +#define OPENSSL_HEADER_EX_DATA_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* ex_data is a mechanism for associating arbitrary extra data with objects. + * For each type of object that supports ex_data, different users can be + * assigned indexes in which to store their data. Each index has callback + * functions that are called when an object of that type is freed or + * duplicated. */ + + +typedef struct crypto_ex_data_st CRYPTO_EX_DATA; + + +/* Type-specific functions. + * + * Each type that supports ex_data provides three functions: */ + +#if 0 /* Sample */ + +/* TYPE_get_ex_new_index allocates a new index for |TYPE|. See the + * descriptions of the callback typedefs for details of when they are + * called. Any of the callback arguments may be NULL. The |argl| and |argp| + * arguments are opaque values that are passed to the callbacks. It returns the + * new index or a negative number on error. + * + * TODO(fork): this should follow the standard calling convention. */ +OPENSSL_EXPORT int TYPE_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_unused *unused, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); + +/* TYPE_set_ex_data sets an extra data pointer on |t|. The |index| argument + * should have been returned from a previous call to |TYPE_get_ex_new_index|. */ +OPENSSL_EXPORT int TYPE_set_ex_data(TYPE *t, int index, void *arg); + +/* TYPE_get_ex_data returns an extra data pointer for |t|, or NULL if no such + * pointer exists. The |index| argument should have been returned from a + * previous call to |TYPE_get_ex_new_index|. */ +OPENSSL_EXPORT void *TYPE_get_ex_data(const TYPE *t, int index); + +#endif /* Sample */ + + +/* Callback types. */ + +/* CRYPTO_EX_free is a callback function that is called when an object of the + * class with extra data pointers is being destroyed. For example, if this + * callback has been passed to |SSL_get_ex_new_index| then it may be called each + * time an |SSL*| is destroyed. + * + * The callback is passed the new object (i.e. the |SSL*|) in |parent|. The + * arguments |argl| and |argp| contain opaque values that were given to + * |CRYPTO_get_ex_new_index|. The callback should return one on success, but + * the value is ignored. + * + * This callback may be called with a NULL value for |ptr| if |parent| has no + * value set for this index. However, the callbacks may also be skipped entirely + * if no extra data pointers are set on |parent| at all. */ +typedef void CRYPTO_EX_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, + int index, long argl, void *argp); + +/* CRYPTO_EX_dup is a callback function that is called when an object of the + * class is being copied and thus the ex_data linked to it also needs to be + * copied. On entry, |*from_d| points to the data for this index from the + * original object. When the callback returns, |*from_d| will be set as the + * data for this index in |to|. + * + * This callback may be called with a NULL value for |*from_d| if |from| has no + * value set for this index. However, the callbacks may also be skipped entirely + * if no extra data pointers are set on |from| at all. */ +typedef int CRYPTO_EX_dup(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from, + void **from_d, int index, long argl, void *argp); + + +/* Deprecated functions. */ + +/* CRYPTO_cleanup_all_ex_data does nothing. */ +OPENSSL_EXPORT void CRYPTO_cleanup_all_ex_data(void); + + +/* Private structures. */ + +/* CRYPTO_EX_unused is a placeholder for an unused callback. It is aliased to + * int to ensure non-NULL callers fail to compile rather than fail silently. */ +typedef int CRYPTO_EX_unused; + +struct crypto_ex_data_st { + STACK_OF(void) *sk; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_EX_DATA_H */ diff --git a/project/jni/boringssl/include/openssl/hkdf.h b/project/jni/boringssl/include/openssl/hkdf.h new file mode 100644 index 000000000..b7a0dc25e --- /dev/null +++ b/project/jni/boringssl/include/openssl/hkdf.h @@ -0,0 +1,44 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_HKDF_H +#define OPENSSL_HEADER_HKDF_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Computes HKDF (as specified by RFC 5869) of initial keying material |secret| + * with |salt| and |info| using |digest|, and outputs |out_len| bytes to + * |out_key|. It returns one on success and zero on error. + * + * HKDF is an Extract-and-Expand algorithm. It does not do any key stretching, + * and as such, is not suited to be used alone to generate a key from a + * password. */ +OPENSSL_EXPORT int HKDF(uint8_t *out_key, size_t out_len, const EVP_MD *digest, + const uint8_t *secret, size_t secret_len, + const uint8_t *salt, size_t salt_len, + const uint8_t *info, size_t info_len); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define HKDF_R_OUTPUT_TOO_LARGE 100 + +#endif /* OPENSSL_HEADER_HKDF_H */ diff --git a/project/jni/boringssl/include/openssl/hmac.h b/project/jni/boringssl/include/openssl/hmac.h new file mode 100644 index 000000000..e521212d4 --- /dev/null +++ b/project/jni/boringssl/include/openssl/hmac.h @@ -0,0 +1,160 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_HMAC_H +#define OPENSSL_HEADER_HMAC_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* HMAC contains functions for constructing PRFs from Merkle–Damgård hash + * functions using HMAC. */ + + +/* One-shot operation. */ + +/* HMAC calculates the HMAC of |data_len| bytes of |data|, using the given key + * and hash function, and writes the result to |out|. On entry, |out| must + * contain |EVP_MAX_MD_SIZE| bytes of space. The actual length of the result is + * written to |*out_len|. It returns |out| or NULL on error. */ +OPENSSL_EXPORT uint8_t *HMAC(const EVP_MD *evp_md, const void *key, + size_t key_len, const uint8_t *data, + size_t data_len, uint8_t *out, + unsigned int *out_len); + + +/* Incremental operation. */ + +/* HMAC_CTX_init initialises |ctx| for use in an HMAC operation. It's assumed + * that HMAC_CTX objects will be allocated on the stack thus no allocation + * function is provided. If needed, allocate |sizeof(HMAC_CTX)| and call + * |HMAC_CTX_init| on it. */ +OPENSSL_EXPORT void HMAC_CTX_init(HMAC_CTX *ctx); + +/* HMAC_CTX_cleanup frees data owned by |ctx|. */ +OPENSSL_EXPORT void HMAC_CTX_cleanup(HMAC_CTX *ctx); + +/* HMAC_Init_ex sets up an initialised |HMAC_CTX| to use |md| as the hash + * function and |key| as the key. For a non-initial call, |md| may be NULL, in + * which case the previous hash function will be used. If the hash function has + * not changed and |key| is NULL, |ctx| reuses the previous key. It returns one + * on success or zero otherwise. + * + * WARNING: NULL and empty keys are ambiguous on non-initial calls. Passing NULL + * |key| but repeating the previous |md| reuses the previous key rather than the + * empty key. */ +OPENSSL_EXPORT int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len, + const EVP_MD *md, ENGINE *impl); + +/* HMAC_Update hashes |data_len| bytes from |data| into the current HMAC + * operation in |ctx|. It returns one. */ +OPENSSL_EXPORT int HMAC_Update(HMAC_CTX *ctx, const uint8_t *data, + size_t data_len); + +/* HMAC_Final completes the HMAC operation in |ctx| and writes the result to + * |out| and the sets |*out_len| to the length of the result. On entry, |out| + * must contain at least |EVP_MAX_MD_SIZE| bytes of space. It returns one on + * success or zero on error. */ +OPENSSL_EXPORT int HMAC_Final(HMAC_CTX *ctx, uint8_t *out, + unsigned int *out_len); + + +/* Utility functions. */ + +/* HMAC_size returns the size, in bytes, of the HMAC that will be produced by + * |ctx|. On entry, |ctx| must have been setup with |HMAC_Init_ex|. */ +OPENSSL_EXPORT size_t HMAC_size(const HMAC_CTX *ctx); + +/* HMAC_CTX_copy_ex sets |dest| equal to |src|. On entry, |dest| must have been + * initialised by calling |HMAC_CTX_init|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int HMAC_CTX_copy_ex(HMAC_CTX *dest, const HMAC_CTX *src); + + +/* Deprecated functions. */ + +OPENSSL_EXPORT int HMAC_Init(HMAC_CTX *ctx, const void *key, int key_len, + const EVP_MD *md); + +/* HMAC_CTX_copy calls |HMAC_CTX_init| on |dest| and then sets it equal to + * |src|. On entry, |dest| must /not/ be initialised for an operation with + * |HMAC_Init_ex|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int HMAC_CTX_copy(HMAC_CTX *dest, const HMAC_CTX *src); + + +/* Private functions */ + +#define HMAC_MAX_MD_CBLOCK 128 /* largest known is SHA512 */ + +struct hmac_ctx_st { + const EVP_MD *md; + EVP_MD_CTX md_ctx; + EVP_MD_CTX i_ctx; + EVP_MD_CTX o_ctx; +} /* HMAC_CTX */; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_HMAC_H */ diff --git a/project/jni/boringssl/include/openssl/lhash.h b/project/jni/boringssl/include/openssl/lhash.h new file mode 100644 index 000000000..0d6d3aef1 --- /dev/null +++ b/project/jni/boringssl/include/openssl/lhash.h @@ -0,0 +1,192 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_LHASH_H +#define OPENSSL_HEADER_LHASH_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* lhash is a traditional, chaining hash table that automatically expands and + * contracts as needed. One should not use the lh_* functions directly, rather + * use the type-safe macro wrappers: + * + * A hash table of a specific type of object has type |LHASH_OF(type)|. This + * can be defined (once) with |DEFINE_LHASH_OF(type)| and declared where needed + * with |DECLARE_LHASH_OF(type)|. For example: + * + * struct foo { + * int bar; + * }; + * + * DEFINE_LHASH_OF(struct foo); + * + * Although note that the hash table will contain /pointers/ to |foo|. + * + * A macro will be defined for each of the lh_* functions below. For + * LHASH_OF(foo), the macros would be lh_foo_new, lh_foo_num_items etc. */ + + +#define LHASH_OF(type) struct lhash_st_##type + +#define DEFINE_LHASH_OF(type) LHASH_OF(type) { int dummy; } + +#define DECLARE_LHASH_OF(type) LHASH_OF(type); + +/* The make_macros.sh script in this directory parses the following lines and + * generates the lhash_macros.h file that contains macros for the following + * types of stacks: + * + * LHASH_OF:ASN1_OBJECT + * LHASH_OF:CONF_VALUE + * LHASH_OF:SSL_SESSION */ + +#define IN_LHASH_H +#include +#undef IN_LHASH_H + + +/* lhash_item_st is an element of a hash chain. It points to the opaque data + * for this element and to the next item in the chain. The linked-list is NULL + * terminated. */ +typedef struct lhash_item_st { + void *data; + struct lhash_item_st *next; + /* hash contains the cached, hash value of |data|. */ + uint32_t hash; +} LHASH_ITEM; + +/* lhash_cmp_func is a comparison function that returns a value equal, or not + * equal, to zero depending on whether |*a| is equal, or not equal to |*b|, + * respectively. Note the difference between this and |stack_cmp_func| in that + * this takes pointers to the objects directly. */ +typedef int (*lhash_cmp_func)(const void *a, const void *b); + +/* lhash_hash_func is a function that maps an object to a uniformly distributed + * uint32_t. */ +typedef uint32_t (*lhash_hash_func)(const void *a); + +typedef struct lhash_st { + /* num_items contains the total number of items in the hash table. */ + size_t num_items; + /* buckets is an array of |num_buckets| pointers. Each points to the head of + * a chain of LHASH_ITEM objects that have the same hash value, mod + * |num_buckets|. */ + LHASH_ITEM **buckets; + /* num_buckets contains the length of |buckets|. This value is always >= + * kMinNumBuckets. */ + size_t num_buckets; + /* callback_depth contains the current depth of |lh_doall| or |lh_doall_arg| + * calls. If non-zero then this suppresses resizing of the |buckets| array, + * which would otherwise disrupt the iteration. */ + unsigned callback_depth; + + lhash_cmp_func comp; + lhash_hash_func hash; +} _LHASH; + +/* lh_new returns a new, empty hash table or NULL on error. If |comp| is NULL, + * |strcmp| will be used. If |hash| is NULL, a generic hash function will be + * used. */ +OPENSSL_EXPORT _LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp); + +/* lh_free frees the hash table itself but none of the elements. See + * |lh_doall|. */ +OPENSSL_EXPORT void lh_free(_LHASH *lh); + +/* lh_num_items returns the number of items in |lh|. */ +OPENSSL_EXPORT size_t lh_num_items(const _LHASH *lh); + +/* lh_retrieve finds an element equal to |data| in the hash table and returns + * it. If no such element exists, it returns NULL. */ +OPENSSL_EXPORT void *lh_retrieve(const _LHASH *lh, const void *data); + +/* lh_insert inserts |data| into the hash table. If an existing element is + * equal to |data| (with respect to the comparison function) then |*old_data| + * will be set to that value and it will be replaced. Otherwise, or in the + * event of an error, |*old_data| will be set to NULL. It returns one on + * success or zero in the case of an allocation error. */ +OPENSSL_EXPORT int lh_insert(_LHASH *lh, void **old_data, void *data); + +/* lh_delete removes an element equal to |data| from the hash table and returns + * it. If no such element is found, it returns NULL. */ +OPENSSL_EXPORT void *lh_delete(_LHASH *lh, const void *data); + +/* lh_doall calls |func| on each element of the hash table. + * TODO(fork): rename this */ +OPENSSL_EXPORT void lh_doall(_LHASH *lh, void (*func)(void *)); + +/* lh_doall_arg calls |func| on each element of the hash table and also passes + * |arg| as the second argument. + * TODO(fork): rename this */ +OPENSSL_EXPORT void lh_doall_arg(_LHASH *lh, void (*func)(void *, void *), + void *arg); + +/* lh_strhash is the default hash function which processes NUL-terminated + * strings. */ +OPENSSL_EXPORT uint32_t lh_strhash(const char *c); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_LHASH_H */ diff --git a/project/jni/boringssl/include/openssl/lhash_macros.h b/project/jni/boringssl/include/openssl/lhash_macros.h new file mode 100644 index 000000000..1d981073e --- /dev/null +++ b/project/jni/boringssl/include/openssl/lhash_macros.h @@ -0,0 +1,132 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#if !defined(IN_LHASH_H) +#error "Don't include this file directly. Include lhash.h" +#endif + +/* ASN1_OBJECT */ +#define lh_ASN1_OBJECT_new(hash, comp) \ + ((LHASH_OF(ASN1_OBJECT) *)lh_new( \ + CHECKED_CAST(lhash_hash_func, uint32_t (*)(const ASN1_OBJECT *), hash), \ + CHECKED_CAST(lhash_cmp_func, \ + int (*)(const ASN1_OBJECT *a, const ASN1_OBJECT *b), \ + comp))) + +#define lh_ASN1_OBJECT_free(lh) \ + lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh)); + +#define lh_ASN1_OBJECT_num_items(lh) \ + lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh)) + +#define lh_ASN1_OBJECT_retrieve(lh, data) \ + ((ASN1_OBJECT *)lh_retrieve( \ + CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \ + CHECKED_CAST(void *, ASN1_OBJECT *, data))) + +#define lh_ASN1_OBJECT_insert(lh, old_data, data) \ + lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \ + CHECKED_CAST(void **, ASN1_OBJECT **, old_data), \ + CHECKED_CAST(void *, ASN1_OBJECT *, data)) + +#define lh_ASN1_OBJECT_delete(lh, data) \ + ((ASN1_OBJECT *)lh_delete( \ + CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \ + CHECKED_CAST(void *, ASN1_OBJECT *, data))) + +#define lh_ASN1_OBJECT_doall(lh, func) \ + lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_OBJECT *), func)); + +#define lh_ASN1_OBJECT_doall_arg(lh, func, arg) \ + lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \ + CHECKED_CAST(void (*)(void *, void *), \ + void (*)(ASN1_OBJECT *, void *), func), \ + arg); + +/* CONF_VALUE */ +#define lh_CONF_VALUE_new(hash, comp) \ + ((LHASH_OF(CONF_VALUE) *)lh_new( \ + CHECKED_CAST(lhash_hash_func, uint32_t (*)(const CONF_VALUE *), hash), \ + CHECKED_CAST(lhash_cmp_func, \ + int (*)(const CONF_VALUE *a, const CONF_VALUE *b), comp))) + +#define lh_CONF_VALUE_free(lh) \ + lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh)); + +#define lh_CONF_VALUE_num_items(lh) \ + lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh)) + +#define lh_CONF_VALUE_retrieve(lh, data) \ + ((CONF_VALUE *)lh_retrieve( \ + CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \ + CHECKED_CAST(void *, CONF_VALUE *, data))) + +#define lh_CONF_VALUE_insert(lh, old_data, data) \ + lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \ + CHECKED_CAST(void **, CONF_VALUE **, old_data), \ + CHECKED_CAST(void *, CONF_VALUE *, data)) + +#define lh_CONF_VALUE_delete(lh, data) \ + ((CONF_VALUE *)lh_delete(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \ + CHECKED_CAST(void *, CONF_VALUE *, data))) + +#define lh_CONF_VALUE_doall(lh, func) \ + lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \ + CHECKED_CAST(void (*)(void *), void (*)(CONF_VALUE *), func)); + +#define lh_CONF_VALUE_doall_arg(lh, func, arg) \ + lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \ + CHECKED_CAST(void (*)(void *, void *), \ + void (*)(CONF_VALUE *, void *), func), \ + arg); + +/* SSL_SESSION */ +#define lh_SSL_SESSION_new(hash, comp) \ + ((LHASH_OF(SSL_SESSION) *)lh_new( \ + CHECKED_CAST(lhash_hash_func, uint32_t (*)(const SSL_SESSION *), hash), \ + CHECKED_CAST(lhash_cmp_func, \ + int (*)(const SSL_SESSION *a, const SSL_SESSION *b), \ + comp))) + +#define lh_SSL_SESSION_free(lh) \ + lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh)); + +#define lh_SSL_SESSION_num_items(lh) \ + lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh)) + +#define lh_SSL_SESSION_retrieve(lh, data) \ + ((SSL_SESSION *)lh_retrieve( \ + CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \ + CHECKED_CAST(void *, SSL_SESSION *, data))) + +#define lh_SSL_SESSION_insert(lh, old_data, data) \ + lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \ + CHECKED_CAST(void **, SSL_SESSION **, old_data), \ + CHECKED_CAST(void *, SSL_SESSION *, data)) + +#define lh_SSL_SESSION_delete(lh, data) \ + ((SSL_SESSION *)lh_delete( \ + CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \ + CHECKED_CAST(void *, SSL_SESSION *, data))) + +#define lh_SSL_SESSION_doall(lh, func) \ + lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \ + CHECKED_CAST(void (*)(void *), void (*)(SSL_SESSION *), func)); + +#define lh_SSL_SESSION_doall_arg(lh, func, arg) \ + lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \ + CHECKED_CAST(void (*)(void *, void *), \ + void (*)(SSL_SESSION *, void *), func), \ + arg); diff --git a/project/jni/boringssl/include/openssl/md4.h b/project/jni/boringssl/include/openssl/md4.h new file mode 100644 index 000000000..93c7af831 --- /dev/null +++ b/project/jni/boringssl/include/openssl/md4.h @@ -0,0 +1,102 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_MD4_H +#define OPENSSL_HEADER_MD4_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* MD4. */ + +/* MD4_CBLOCK is the block size of MD4. */ +#define MD4_CBLOCK 64 + +/* MD4_DIGEST_LENGTH is the length of an MD4 digest. */ +#define MD4_DIGEST_LENGTH 16 + +/* MD4_Init initialises |md4| and returns one. */ +OPENSSL_EXPORT int MD4_Init(MD4_CTX *md4); + +/* MD4_Update adds |len| bytes from |data| to |md4| and returns one. */ +OPENSSL_EXPORT int MD4_Update(MD4_CTX *md4, const void *data, size_t len); + +/* MD4_Final adds the final padding to |md4| and writes the resulting digest to + * |md|, which must have at least |MD4_DIGEST_LENGTH| bytes of space. It + * returns one. */ +OPENSSL_EXPORT int MD4_Final(uint8_t *md, MD4_CTX *md4); + +/* MD4_Transform is a low-level function that performs a single, MD4 block + * transformation using the state from |md4| and 64 bytes from |block|. */ +OPENSSL_EXPORT void MD4_Transform(MD4_CTX *md4, const uint8_t *block); + +struct md4_state_st { + uint32_t h[4]; + uint32_t Nl, Nh; + uint8_t data[MD4_CBLOCK]; + unsigned num; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_MD4_H */ diff --git a/project/jni/boringssl/include/openssl/md5.h b/project/jni/boringssl/include/openssl/md5.h new file mode 100644 index 000000000..55162f023 --- /dev/null +++ b/project/jni/boringssl/include/openssl/md5.h @@ -0,0 +1,107 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_MD5_H +#define OPENSSL_HEADER_MD5_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* MD5. */ + + +/* MD5_CBLOCK is the block size of MD5. */ +#define MD5_CBLOCK 64 + +/* MD5_DIGEST_LENGTH is the length of an MD5 digest. */ +#define MD5_DIGEST_LENGTH 16 + +/* MD5_Init initialises |md5| and returns one. */ +OPENSSL_EXPORT int MD5_Init(MD5_CTX *md5); + +/* MD5_Update adds |len| bytes from |data| to |md5| and returns one. */ +OPENSSL_EXPORT int MD5_Update(MD5_CTX *md5, const void *data, size_t len); + +/* MD5_Final adds the final padding to |md5| and writes the resulting digest to + * |md|, which must have at least |MD5_DIGEST_LENGTH| bytes of space. It + * returns one. */ +OPENSSL_EXPORT int MD5_Final(uint8_t *md, MD5_CTX *md5); + +/* MD5 writes the digest of |len| bytes from |data| to |out| and returns |out|. + * There must be at least |MD5_DIGEST_LENGTH| bytes of space in |out|. */ +OPENSSL_EXPORT uint8_t *MD5(const uint8_t *data, size_t len, uint8_t *out); + +/* MD5_Transform is a low-level function that performs a single, MD5 block + * transformation using the state from |md5| and 64 bytes from |block|. */ +OPENSSL_EXPORT void MD5_Transform(MD5_CTX *md5, const uint8_t *block); + +struct md5_state_st { + uint32_t h[4]; + uint32_t Nl, Nh; + uint8_t data[MD5_CBLOCK]; + unsigned num; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_MD5_H */ diff --git a/project/jni/boringssl/include/openssl/mem.h b/project/jni/boringssl/include/openssl/mem.h new file mode 100644 index 000000000..c8e2b3ef0 --- /dev/null +++ b/project/jni/boringssl/include/openssl/mem.h @@ -0,0 +1,140 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_MEM_H +#define OPENSSL_HEADER_MEM_H + +#include + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Memory and string functions, see also buf.h. + * + * OpenSSL has, historically, had a complex set of malloc debugging options. + * However, that was written in a time before Valgrind and ASAN. Since we now + * have those tools, the OpenSSL allocation functions are simply macros around + * the standard memory functions. */ + + +#define OPENSSL_malloc malloc +#define OPENSSL_realloc realloc +#define OPENSSL_free free + +/* OPENSSL_realloc_clean acts like |realloc|, but clears the previous memory + * buffer. Because this is implemented as a wrapper around |malloc|, it needs + * to be given the size of the buffer pointed to by |ptr|. */ +void *OPENSSL_realloc_clean(void *ptr, size_t old_size, size_t new_size); + +/* OPENSSL_cleanse zeros out |len| bytes of memory at |ptr|. This is similar to + * |memset_s| from C11. */ +OPENSSL_EXPORT void OPENSSL_cleanse(void *ptr, size_t len); + +/* CRYPTO_memcmp returns zero iff the |len| bytes at |a| and |b| are equal. It + * takes an amount of time dependent on |len|, but independent of the contents + * of |a| and |b|. Unlike memcmp, it cannot be used to put elements into a + * defined order as the return value when a != b is undefined, other than to be + * non-zero. */ +OPENSSL_EXPORT int CRYPTO_memcmp(const void *a, const void *b, size_t len); + +/* OPENSSL_hash32 implements the 32 bit, FNV-1a hash. */ +OPENSSL_EXPORT uint32_t OPENSSL_hash32(const void *ptr, size_t len); + +/* OPENSSL_strdup has the same behaviour as strdup(3). */ +OPENSSL_EXPORT char *OPENSSL_strdup(const char *s); + +/* OPENSSL_strnlen has the same behaviour as strnlen(3). */ +OPENSSL_EXPORT size_t OPENSSL_strnlen(const char *s, size_t len); + +/* OPENSSL_strcasecmp has the same behaviour as strcasecmp(3). */ +OPENSSL_EXPORT int OPENSSL_strcasecmp(const char *a, const char *b); + +/* OPENSSL_strncasecmp has the same behaviour as strncasecmp(3). */ +OPENSSL_EXPORT int OPENSSL_strncasecmp(const char *a, const char *b, size_t n); + +/* DECIMAL_SIZE returns an upper bound for the length of the decimal + * representation of the given type. */ +#define DECIMAL_SIZE(type) ((sizeof(type)*8+2)/3+1) + +/* Printf functions. + * + * These functions are either OpenSSL wrappers for standard functions (i.e. + * |BIO_snprintf| and |BIO_vsnprintf|) which don't exist in C89, or are + * versions of printf functions that output to a BIO rather than a FILE. */ +#ifdef __GNUC__ +#define __bio_h__attr__ __attribute__ +#else +#define __bio_h__attr__(x) +#endif +OPENSSL_EXPORT int BIO_snprintf(char *buf, size_t n, const char *format, ...) + __bio_h__attr__((__format__(__printf__, 3, 4))); + +OPENSSL_EXPORT int BIO_vsnprintf(char *buf, size_t n, const char *format, + va_list args) + __bio_h__attr__((__format__(__printf__, 3, 0))); +#undef __bio_h__attr__ + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_MEM_H */ diff --git a/project/jni/boringssl/include/openssl/obj.h b/project/jni/boringssl/include/openssl/obj.h new file mode 100644 index 000000000..32a489484 --- /dev/null +++ b/project/jni/boringssl/include/openssl/obj.h @@ -0,0 +1,198 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_OBJ_H +#define OPENSSL_HEADER_OBJ_H + +#include + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* The objects library deals with the registration and indexing of ASN.1 object + * identifiers. These values are often written as a dotted sequence of numbers, + * e.g. 1.2.840.113549.1.9.16.3.9. + * + * Internally, OpenSSL likes to deal with these values by numbering them with + * numbers called "nids". OpenSSL has a large, built-in database of common + * object identifiers and also has both short and long names for them. + * + * This library provides functions for translating between object identifiers, + * nids, short names and long names. + * + * The nid values should not be used outside of a single process: they are not + * stable identifiers. */ + + +/* Basic operations. */ + +/* OBJ_dup returns a duplicate copy of |obj| or NULL on allocation failure. */ +OPENSSL_EXPORT ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *obj); + +/* OBJ_cmp returns a value less than, equal to or greater than zero if |a| is + * less than, equal to or greater than |b|, respectively. */ +OPENSSL_EXPORT int OBJ_cmp(const ASN1_OBJECT *a, const ASN1_OBJECT *b); + + +/* Looking up nids. */ + +/* OBJ_obj2nid returns the nid corresponding to |obj|, or |NID_undef| if no + * such object is known. */ +OPENSSL_EXPORT int OBJ_obj2nid(const ASN1_OBJECT *obj); + +/* OBJ_cbs2nid returns the nid corresponding to the DER data in |cbs|, or + * |NID_undef| if no such object is known. */ +OPENSSL_EXPORT int OBJ_cbs2nid(const CBS *cbs); + +/* OBJ_sn2nid returns the nid corresponding to |short_name|, or |NID_undef| if + * no such short name is known. */ +OPENSSL_EXPORT int OBJ_sn2nid(const char *short_name); + +/* OBJ_ln2nid returns the nid corresponding to |long_name|, or |NID_undef| if + * no such long name is known. */ +OPENSSL_EXPORT int OBJ_ln2nid(const char *long_name); + +/* OBJ_txt2nid returns the nid corresponding to |s|, which may be a short name, + * long name, or an ASCII string containing a dotted sequence of numbers. It + * returns the nid or NID_undef if unknown. */ +OPENSSL_EXPORT int OBJ_txt2nid(const char *s); + + +/* Getting information about nids. */ + +/* OBJ_nid2obj returns the ASN1_OBJECT corresponding to |nid|, or NULL if |nid| + * is unknown. */ +OPENSSL_EXPORT const ASN1_OBJECT *OBJ_nid2obj(int nid); + +/* OBJ_nid2sn returns the short name for |nid|, or NULL if |nid| is unknown. */ +OPENSSL_EXPORT const char *OBJ_nid2sn(int nid); + +/* OBJ_nid2ln returns the long name for |nid|, or NULL if |nid| is unknown. */ +OPENSSL_EXPORT const char *OBJ_nid2ln(int nid); + +/* OBJ_nid2cbb writes |nid| as an ASN.1 OBJECT IDENTIFIER to |out|. It returns + * one on success or zero otherwise. */ +OPENSSL_EXPORT int OBJ_nid2cbb(CBB *out, int nid); + + +/* Dealing with textual representations of object identifiers. */ + +/* OBJ_txt2obj returns an ASN1_OBJECT for the textual respresentation in |s|. + * If |dont_search_names| is zero, then |s| will be matched against the long + * and short names of a known objects to find a match. Otherwise |s| must + * contain an ASCII string with a dotted sequence of numbers. The resulting + * object need not be previously known. It returns a freshly allocated + * |ASN1_OBJECT| or NULL on error. */ +OPENSSL_EXPORT ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names); + +/* OBJ_obj2txt converts |obj| to a textual representation. If + * |dont_return_name| is zero then |obj| will be matched against known objects + * and the long (preferably) or short name will be used if found. Otherwise + * |obj| will be converted into a dotted sequence of integers. If |out| is not + * NULL, then at most |out_len| bytes of the textual form will be written + * there. If |out_len| is at least one, then string written to |out| will + * always be NUL terminated. It returns the number of characters that could + * have been written, not including the final NUL, or -1 on error. */ +OPENSSL_EXPORT int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj, + int dont_return_name); + + +/* Adding objects at runtime. */ + +/* OBJ_create adds a known object and returns the nid of the new object, or + * NID_undef on error. */ +OPENSSL_EXPORT int OBJ_create(const char *oid, const char *short_name, + const char *long_name); + + +/* Handling signature algorithm identifiers. + * + * Some NIDs (e.g. sha256WithRSAEncryption) specify both a digest algorithm and + * a public key algorithm. The following functions map between pairs of digest + * and public-key algorithms and the NIDs that specify their combination. + * + * Sometimes the combination NID leaves the digest unspecified (e.g. + * rsassaPss). In these cases, the digest NID is |NID_undef|. */ + +/* OBJ_find_sigid_algs finds the digest and public-key NIDs that correspond to + * the signing algorithm |sign_nid|. If successful, it sets |*out_digest_nid| + * and |*out_pkey_nid| and returns one. Otherwise it returns zero. Any of + * |out_digest_nid| or |out_pkey_nid| can be NULL if the caller doesn't need + * that output value. */ +OPENSSL_EXPORT int OBJ_find_sigid_algs(int sign_nid, int *out_digest_nid, + int *out_pkey_nid); + +/* OBJ_find_sigid_by_algs finds the signature NID that corresponds to the + * combination of |digest_nid| and |pkey_nid|. If success, it sets + * |*out_sign_nid| and returns one. Otherwise it returns zero. The + * |out_sign_nid| argument can be NULL if the caller only wishes to learn + * whether the combination is valid. */ +OPENSSL_EXPORT int OBJ_find_sigid_by_algs(int *out_sign_nid, int digest_nid, + int pkey_nid); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define OBJ_R_UNKNOWN_NID 100 + +#endif /* OPENSSL_HEADER_OBJ_H */ diff --git a/project/jni/boringssl/include/openssl/obj_mac.h b/project/jni/boringssl/include/openssl/obj_mac.h new file mode 100644 index 000000000..b636adcfc --- /dev/null +++ b/project/jni/boringssl/include/openssl/obj_mac.h @@ -0,0 +1,4144 @@ +/* THIS FILE IS GENERATED FROM objects.txt by objects.pl via the + * following command: + * perl objects.pl objects.txt obj_mac.num ../../include/openssl/obj_mac.h */ + +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#define SN_undef "UNDEF" +#define LN_undef "undefined" +#define NID_undef 0 +#define OBJ_undef 0L + +#define SN_itu_t "ITU-T" +#define LN_itu_t "itu-t" +#define NID_itu_t 645 +#define OBJ_itu_t 0L + +#define NID_ccitt 404 +#define OBJ_ccitt OBJ_itu_t + +#define SN_iso "ISO" +#define LN_iso "iso" +#define NID_iso 181 +#define OBJ_iso 1L + +#define SN_joint_iso_itu_t "JOINT-ISO-ITU-T" +#define LN_joint_iso_itu_t "joint-iso-itu-t" +#define NID_joint_iso_itu_t 646 +#define OBJ_joint_iso_itu_t 2L + +#define NID_joint_iso_ccitt 393 +#define OBJ_joint_iso_ccitt OBJ_joint_iso_itu_t + +#define SN_member_body "member-body" +#define LN_member_body "ISO Member Body" +#define NID_member_body 182 +#define OBJ_member_body OBJ_iso,2L + +#define SN_identified_organization "identified-organization" +#define NID_identified_organization 676 +#define OBJ_identified_organization OBJ_iso,3L + +#define SN_hmac_md5 "HMAC-MD5" +#define LN_hmac_md5 "hmac-md5" +#define NID_hmac_md5 780 +#define OBJ_hmac_md5 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,1L + +#define SN_hmac_sha1 "HMAC-SHA1" +#define LN_hmac_sha1 "hmac-sha1" +#define NID_hmac_sha1 781 +#define OBJ_hmac_sha1 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,2L + +#define SN_certicom_arc "certicom-arc" +#define NID_certicom_arc 677 +#define OBJ_certicom_arc OBJ_identified_organization,132L + +#define SN_international_organizations "international-organizations" +#define LN_international_organizations "International Organizations" +#define NID_international_organizations 647 +#define OBJ_international_organizations OBJ_joint_iso_itu_t,23L + +#define SN_wap "wap" +#define NID_wap 678 +#define OBJ_wap OBJ_international_organizations,43L + +#define SN_wap_wsg "wap-wsg" +#define NID_wap_wsg 679 +#define OBJ_wap_wsg OBJ_wap,1L + +#define SN_selected_attribute_types "selected-attribute-types" +#define LN_selected_attribute_types "Selected Attribute Types" +#define NID_selected_attribute_types 394 +#define OBJ_selected_attribute_types OBJ_joint_iso_itu_t,5L,1L,5L + +#define SN_clearance "clearance" +#define NID_clearance 395 +#define OBJ_clearance OBJ_selected_attribute_types,55L + +#define SN_ISO_US "ISO-US" +#define LN_ISO_US "ISO US Member Body" +#define NID_ISO_US 183 +#define OBJ_ISO_US OBJ_member_body,840L + +#define SN_X9_57 "X9-57" +#define LN_X9_57 "X9.57" +#define NID_X9_57 184 +#define OBJ_X9_57 OBJ_ISO_US,10040L + +#define SN_X9cm "X9cm" +#define LN_X9cm "X9.57 CM ?" +#define NID_X9cm 185 +#define OBJ_X9cm OBJ_X9_57,4L + +#define SN_dsa "DSA" +#define LN_dsa "dsaEncryption" +#define NID_dsa 116 +#define OBJ_dsa OBJ_X9cm,1L + +#define SN_dsaWithSHA1 "DSA-SHA1" +#define LN_dsaWithSHA1 "dsaWithSHA1" +#define NID_dsaWithSHA1 113 +#define OBJ_dsaWithSHA1 OBJ_X9cm,3L + +#define SN_ansi_X9_62 "ansi-X9-62" +#define LN_ansi_X9_62 "ANSI X9.62" +#define NID_ansi_X9_62 405 +#define OBJ_ansi_X9_62 OBJ_ISO_US,10045L + +#define OBJ_X9_62_id_fieldType OBJ_ansi_X9_62,1L + +#define SN_X9_62_prime_field "prime-field" +#define NID_X9_62_prime_field 406 +#define OBJ_X9_62_prime_field OBJ_X9_62_id_fieldType,1L + +#define SN_X9_62_characteristic_two_field "characteristic-two-field" +#define NID_X9_62_characteristic_two_field 407 +#define OBJ_X9_62_characteristic_two_field OBJ_X9_62_id_fieldType,2L + +#define SN_X9_62_id_characteristic_two_basis "id-characteristic-two-basis" +#define NID_X9_62_id_characteristic_two_basis 680 +#define OBJ_X9_62_id_characteristic_two_basis OBJ_X9_62_characteristic_two_field,3L + +#define SN_X9_62_onBasis "onBasis" +#define NID_X9_62_onBasis 681 +#define OBJ_X9_62_onBasis OBJ_X9_62_id_characteristic_two_basis,1L + +#define SN_X9_62_tpBasis "tpBasis" +#define NID_X9_62_tpBasis 682 +#define OBJ_X9_62_tpBasis OBJ_X9_62_id_characteristic_two_basis,2L + +#define SN_X9_62_ppBasis "ppBasis" +#define NID_X9_62_ppBasis 683 +#define OBJ_X9_62_ppBasis OBJ_X9_62_id_characteristic_two_basis,3L + +#define OBJ_X9_62_id_publicKeyType OBJ_ansi_X9_62,2L + +#define SN_X9_62_id_ecPublicKey "id-ecPublicKey" +#define NID_X9_62_id_ecPublicKey 408 +#define OBJ_X9_62_id_ecPublicKey OBJ_X9_62_id_publicKeyType,1L + +#define OBJ_X9_62_ellipticCurve OBJ_ansi_X9_62,3L + +#define OBJ_X9_62_c_TwoCurve OBJ_X9_62_ellipticCurve,0L + +#define SN_X9_62_c2pnb163v1 "c2pnb163v1" +#define NID_X9_62_c2pnb163v1 684 +#define OBJ_X9_62_c2pnb163v1 OBJ_X9_62_c_TwoCurve,1L + +#define SN_X9_62_c2pnb163v2 "c2pnb163v2" +#define NID_X9_62_c2pnb163v2 685 +#define OBJ_X9_62_c2pnb163v2 OBJ_X9_62_c_TwoCurve,2L + +#define SN_X9_62_c2pnb163v3 "c2pnb163v3" +#define NID_X9_62_c2pnb163v3 686 +#define OBJ_X9_62_c2pnb163v3 OBJ_X9_62_c_TwoCurve,3L + +#define SN_X9_62_c2pnb176v1 "c2pnb176v1" +#define NID_X9_62_c2pnb176v1 687 +#define OBJ_X9_62_c2pnb176v1 OBJ_X9_62_c_TwoCurve,4L + +#define SN_X9_62_c2tnb191v1 "c2tnb191v1" +#define NID_X9_62_c2tnb191v1 688 +#define OBJ_X9_62_c2tnb191v1 OBJ_X9_62_c_TwoCurve,5L + +#define SN_X9_62_c2tnb191v2 "c2tnb191v2" +#define NID_X9_62_c2tnb191v2 689 +#define OBJ_X9_62_c2tnb191v2 OBJ_X9_62_c_TwoCurve,6L + +#define SN_X9_62_c2tnb191v3 "c2tnb191v3" +#define NID_X9_62_c2tnb191v3 690 +#define OBJ_X9_62_c2tnb191v3 OBJ_X9_62_c_TwoCurve,7L + +#define SN_X9_62_c2onb191v4 "c2onb191v4" +#define NID_X9_62_c2onb191v4 691 +#define OBJ_X9_62_c2onb191v4 OBJ_X9_62_c_TwoCurve,8L + +#define SN_X9_62_c2onb191v5 "c2onb191v5" +#define NID_X9_62_c2onb191v5 692 +#define OBJ_X9_62_c2onb191v5 OBJ_X9_62_c_TwoCurve,9L + +#define SN_X9_62_c2pnb208w1 "c2pnb208w1" +#define NID_X9_62_c2pnb208w1 693 +#define OBJ_X9_62_c2pnb208w1 OBJ_X9_62_c_TwoCurve,10L + +#define SN_X9_62_c2tnb239v1 "c2tnb239v1" +#define NID_X9_62_c2tnb239v1 694 +#define OBJ_X9_62_c2tnb239v1 OBJ_X9_62_c_TwoCurve,11L + +#define SN_X9_62_c2tnb239v2 "c2tnb239v2" +#define NID_X9_62_c2tnb239v2 695 +#define OBJ_X9_62_c2tnb239v2 OBJ_X9_62_c_TwoCurve,12L + +#define SN_X9_62_c2tnb239v3 "c2tnb239v3" +#define NID_X9_62_c2tnb239v3 696 +#define OBJ_X9_62_c2tnb239v3 OBJ_X9_62_c_TwoCurve,13L + +#define SN_X9_62_c2onb239v4 "c2onb239v4" +#define NID_X9_62_c2onb239v4 697 +#define OBJ_X9_62_c2onb239v4 OBJ_X9_62_c_TwoCurve,14L + +#define SN_X9_62_c2onb239v5 "c2onb239v5" +#define NID_X9_62_c2onb239v5 698 +#define OBJ_X9_62_c2onb239v5 OBJ_X9_62_c_TwoCurve,15L + +#define SN_X9_62_c2pnb272w1 "c2pnb272w1" +#define NID_X9_62_c2pnb272w1 699 +#define OBJ_X9_62_c2pnb272w1 OBJ_X9_62_c_TwoCurve,16L + +#define SN_X9_62_c2pnb304w1 "c2pnb304w1" +#define NID_X9_62_c2pnb304w1 700 +#define OBJ_X9_62_c2pnb304w1 OBJ_X9_62_c_TwoCurve,17L + +#define SN_X9_62_c2tnb359v1 "c2tnb359v1" +#define NID_X9_62_c2tnb359v1 701 +#define OBJ_X9_62_c2tnb359v1 OBJ_X9_62_c_TwoCurve,18L + +#define SN_X9_62_c2pnb368w1 "c2pnb368w1" +#define NID_X9_62_c2pnb368w1 702 +#define OBJ_X9_62_c2pnb368w1 OBJ_X9_62_c_TwoCurve,19L + +#define SN_X9_62_c2tnb431r1 "c2tnb431r1" +#define NID_X9_62_c2tnb431r1 703 +#define OBJ_X9_62_c2tnb431r1 OBJ_X9_62_c_TwoCurve,20L + +#define OBJ_X9_62_primeCurve OBJ_X9_62_ellipticCurve,1L + +#define SN_X9_62_prime192v1 "prime192v1" +#define NID_X9_62_prime192v1 409 +#define OBJ_X9_62_prime192v1 OBJ_X9_62_primeCurve,1L + +#define SN_X9_62_prime192v2 "prime192v2" +#define NID_X9_62_prime192v2 410 +#define OBJ_X9_62_prime192v2 OBJ_X9_62_primeCurve,2L + +#define SN_X9_62_prime192v3 "prime192v3" +#define NID_X9_62_prime192v3 411 +#define OBJ_X9_62_prime192v3 OBJ_X9_62_primeCurve,3L + +#define SN_X9_62_prime239v1 "prime239v1" +#define NID_X9_62_prime239v1 412 +#define OBJ_X9_62_prime239v1 OBJ_X9_62_primeCurve,4L + +#define SN_X9_62_prime239v2 "prime239v2" +#define NID_X9_62_prime239v2 413 +#define OBJ_X9_62_prime239v2 OBJ_X9_62_primeCurve,5L + +#define SN_X9_62_prime239v3 "prime239v3" +#define NID_X9_62_prime239v3 414 +#define OBJ_X9_62_prime239v3 OBJ_X9_62_primeCurve,6L + +#define SN_X9_62_prime256v1 "prime256v1" +#define NID_X9_62_prime256v1 415 +#define OBJ_X9_62_prime256v1 OBJ_X9_62_primeCurve,7L + +#define OBJ_X9_62_id_ecSigType OBJ_ansi_X9_62,4L + +#define SN_ecdsa_with_SHA1 "ecdsa-with-SHA1" +#define NID_ecdsa_with_SHA1 416 +#define OBJ_ecdsa_with_SHA1 OBJ_X9_62_id_ecSigType,1L + +#define SN_ecdsa_with_Recommended "ecdsa-with-Recommended" +#define NID_ecdsa_with_Recommended 791 +#define OBJ_ecdsa_with_Recommended OBJ_X9_62_id_ecSigType,2L + +#define SN_ecdsa_with_Specified "ecdsa-with-Specified" +#define NID_ecdsa_with_Specified 792 +#define OBJ_ecdsa_with_Specified OBJ_X9_62_id_ecSigType,3L + +#define SN_ecdsa_with_SHA224 "ecdsa-with-SHA224" +#define NID_ecdsa_with_SHA224 793 +#define OBJ_ecdsa_with_SHA224 OBJ_ecdsa_with_Specified,1L + +#define SN_ecdsa_with_SHA256 "ecdsa-with-SHA256" +#define NID_ecdsa_with_SHA256 794 +#define OBJ_ecdsa_with_SHA256 OBJ_ecdsa_with_Specified,2L + +#define SN_ecdsa_with_SHA384 "ecdsa-with-SHA384" +#define NID_ecdsa_with_SHA384 795 +#define OBJ_ecdsa_with_SHA384 OBJ_ecdsa_with_Specified,3L + +#define SN_ecdsa_with_SHA512 "ecdsa-with-SHA512" +#define NID_ecdsa_with_SHA512 796 +#define OBJ_ecdsa_with_SHA512 OBJ_ecdsa_with_Specified,4L + +#define OBJ_secg_ellipticCurve OBJ_certicom_arc,0L + +#define SN_secp112r1 "secp112r1" +#define NID_secp112r1 704 +#define OBJ_secp112r1 OBJ_secg_ellipticCurve,6L + +#define SN_secp112r2 "secp112r2" +#define NID_secp112r2 705 +#define OBJ_secp112r2 OBJ_secg_ellipticCurve,7L + +#define SN_secp128r1 "secp128r1" +#define NID_secp128r1 706 +#define OBJ_secp128r1 OBJ_secg_ellipticCurve,28L + +#define SN_secp128r2 "secp128r2" +#define NID_secp128r2 707 +#define OBJ_secp128r2 OBJ_secg_ellipticCurve,29L + +#define SN_secp160k1 "secp160k1" +#define NID_secp160k1 708 +#define OBJ_secp160k1 OBJ_secg_ellipticCurve,9L + +#define SN_secp160r1 "secp160r1" +#define NID_secp160r1 709 +#define OBJ_secp160r1 OBJ_secg_ellipticCurve,8L + +#define SN_secp160r2 "secp160r2" +#define NID_secp160r2 710 +#define OBJ_secp160r2 OBJ_secg_ellipticCurve,30L + +#define SN_secp192k1 "secp192k1" +#define NID_secp192k1 711 +#define OBJ_secp192k1 OBJ_secg_ellipticCurve,31L + +#define SN_secp224k1 "secp224k1" +#define NID_secp224k1 712 +#define OBJ_secp224k1 OBJ_secg_ellipticCurve,32L + +#define SN_secp224r1 "secp224r1" +#define NID_secp224r1 713 +#define OBJ_secp224r1 OBJ_secg_ellipticCurve,33L + +#define SN_secp256k1 "secp256k1" +#define NID_secp256k1 714 +#define OBJ_secp256k1 OBJ_secg_ellipticCurve,10L + +#define SN_secp384r1 "secp384r1" +#define NID_secp384r1 715 +#define OBJ_secp384r1 OBJ_secg_ellipticCurve,34L + +#define SN_secp521r1 "secp521r1" +#define NID_secp521r1 716 +#define OBJ_secp521r1 OBJ_secg_ellipticCurve,35L + +#define SN_sect113r1 "sect113r1" +#define NID_sect113r1 717 +#define OBJ_sect113r1 OBJ_secg_ellipticCurve,4L + +#define SN_sect113r2 "sect113r2" +#define NID_sect113r2 718 +#define OBJ_sect113r2 OBJ_secg_ellipticCurve,5L + +#define SN_sect131r1 "sect131r1" +#define NID_sect131r1 719 +#define OBJ_sect131r1 OBJ_secg_ellipticCurve,22L + +#define SN_sect131r2 "sect131r2" +#define NID_sect131r2 720 +#define OBJ_sect131r2 OBJ_secg_ellipticCurve,23L + +#define SN_sect163k1 "sect163k1" +#define NID_sect163k1 721 +#define OBJ_sect163k1 OBJ_secg_ellipticCurve,1L + +#define SN_sect163r1 "sect163r1" +#define NID_sect163r1 722 +#define OBJ_sect163r1 OBJ_secg_ellipticCurve,2L + +#define SN_sect163r2 "sect163r2" +#define NID_sect163r2 723 +#define OBJ_sect163r2 OBJ_secg_ellipticCurve,15L + +#define SN_sect193r1 "sect193r1" +#define NID_sect193r1 724 +#define OBJ_sect193r1 OBJ_secg_ellipticCurve,24L + +#define SN_sect193r2 "sect193r2" +#define NID_sect193r2 725 +#define OBJ_sect193r2 OBJ_secg_ellipticCurve,25L + +#define SN_sect233k1 "sect233k1" +#define NID_sect233k1 726 +#define OBJ_sect233k1 OBJ_secg_ellipticCurve,26L + +#define SN_sect233r1 "sect233r1" +#define NID_sect233r1 727 +#define OBJ_sect233r1 OBJ_secg_ellipticCurve,27L + +#define SN_sect239k1 "sect239k1" +#define NID_sect239k1 728 +#define OBJ_sect239k1 OBJ_secg_ellipticCurve,3L + +#define SN_sect283k1 "sect283k1" +#define NID_sect283k1 729 +#define OBJ_sect283k1 OBJ_secg_ellipticCurve,16L + +#define SN_sect283r1 "sect283r1" +#define NID_sect283r1 730 +#define OBJ_sect283r1 OBJ_secg_ellipticCurve,17L + +#define SN_sect409k1 "sect409k1" +#define NID_sect409k1 731 +#define OBJ_sect409k1 OBJ_secg_ellipticCurve,36L + +#define SN_sect409r1 "sect409r1" +#define NID_sect409r1 732 +#define OBJ_sect409r1 OBJ_secg_ellipticCurve,37L + +#define SN_sect571k1 "sect571k1" +#define NID_sect571k1 733 +#define OBJ_sect571k1 OBJ_secg_ellipticCurve,38L + +#define SN_sect571r1 "sect571r1" +#define NID_sect571r1 734 +#define OBJ_sect571r1 OBJ_secg_ellipticCurve,39L + +#define OBJ_wap_wsg_idm_ecid OBJ_wap_wsg,4L + +#define SN_wap_wsg_idm_ecid_wtls1 "wap-wsg-idm-ecid-wtls1" +#define NID_wap_wsg_idm_ecid_wtls1 735 +#define OBJ_wap_wsg_idm_ecid_wtls1 OBJ_wap_wsg_idm_ecid,1L + +#define SN_wap_wsg_idm_ecid_wtls3 "wap-wsg-idm-ecid-wtls3" +#define NID_wap_wsg_idm_ecid_wtls3 736 +#define OBJ_wap_wsg_idm_ecid_wtls3 OBJ_wap_wsg_idm_ecid,3L + +#define SN_wap_wsg_idm_ecid_wtls4 "wap-wsg-idm-ecid-wtls4" +#define NID_wap_wsg_idm_ecid_wtls4 737 +#define OBJ_wap_wsg_idm_ecid_wtls4 OBJ_wap_wsg_idm_ecid,4L + +#define SN_wap_wsg_idm_ecid_wtls5 "wap-wsg-idm-ecid-wtls5" +#define NID_wap_wsg_idm_ecid_wtls5 738 +#define OBJ_wap_wsg_idm_ecid_wtls5 OBJ_wap_wsg_idm_ecid,5L + +#define SN_wap_wsg_idm_ecid_wtls6 "wap-wsg-idm-ecid-wtls6" +#define NID_wap_wsg_idm_ecid_wtls6 739 +#define OBJ_wap_wsg_idm_ecid_wtls6 OBJ_wap_wsg_idm_ecid,6L + +#define SN_wap_wsg_idm_ecid_wtls7 "wap-wsg-idm-ecid-wtls7" +#define NID_wap_wsg_idm_ecid_wtls7 740 +#define OBJ_wap_wsg_idm_ecid_wtls7 OBJ_wap_wsg_idm_ecid,7L + +#define SN_wap_wsg_idm_ecid_wtls8 "wap-wsg-idm-ecid-wtls8" +#define NID_wap_wsg_idm_ecid_wtls8 741 +#define OBJ_wap_wsg_idm_ecid_wtls8 OBJ_wap_wsg_idm_ecid,8L + +#define SN_wap_wsg_idm_ecid_wtls9 "wap-wsg-idm-ecid-wtls9" +#define NID_wap_wsg_idm_ecid_wtls9 742 +#define OBJ_wap_wsg_idm_ecid_wtls9 OBJ_wap_wsg_idm_ecid,9L + +#define SN_wap_wsg_idm_ecid_wtls10 "wap-wsg-idm-ecid-wtls10" +#define NID_wap_wsg_idm_ecid_wtls10 743 +#define OBJ_wap_wsg_idm_ecid_wtls10 OBJ_wap_wsg_idm_ecid,10L + +#define SN_wap_wsg_idm_ecid_wtls11 "wap-wsg-idm-ecid-wtls11" +#define NID_wap_wsg_idm_ecid_wtls11 744 +#define OBJ_wap_wsg_idm_ecid_wtls11 OBJ_wap_wsg_idm_ecid,11L + +#define SN_wap_wsg_idm_ecid_wtls12 "wap-wsg-idm-ecid-wtls12" +#define NID_wap_wsg_idm_ecid_wtls12 745 +#define OBJ_wap_wsg_idm_ecid_wtls12 OBJ_wap_wsg_idm_ecid,12L + +#define SN_cast5_cbc "CAST5-CBC" +#define LN_cast5_cbc "cast5-cbc" +#define NID_cast5_cbc 108 +#define OBJ_cast5_cbc OBJ_ISO_US,113533L,7L,66L,10L + +#define SN_cast5_ecb "CAST5-ECB" +#define LN_cast5_ecb "cast5-ecb" +#define NID_cast5_ecb 109 + +#define SN_cast5_cfb64 "CAST5-CFB" +#define LN_cast5_cfb64 "cast5-cfb" +#define NID_cast5_cfb64 110 + +#define SN_cast5_ofb64 "CAST5-OFB" +#define LN_cast5_ofb64 "cast5-ofb" +#define NID_cast5_ofb64 111 + +#define LN_pbeWithMD5AndCast5_CBC "pbeWithMD5AndCast5CBC" +#define NID_pbeWithMD5AndCast5_CBC 112 +#define OBJ_pbeWithMD5AndCast5_CBC OBJ_ISO_US,113533L,7L,66L,12L + +#define SN_id_PasswordBasedMAC "id-PasswordBasedMAC" +#define LN_id_PasswordBasedMAC "password based MAC" +#define NID_id_PasswordBasedMAC 782 +#define OBJ_id_PasswordBasedMAC OBJ_ISO_US,113533L,7L,66L,13L + +#define SN_id_DHBasedMac "id-DHBasedMac" +#define LN_id_DHBasedMac "Diffie-Hellman based MAC" +#define NID_id_DHBasedMac 783 +#define OBJ_id_DHBasedMac OBJ_ISO_US,113533L,7L,66L,30L + +#define SN_rsadsi "rsadsi" +#define LN_rsadsi "RSA Data Security, Inc." +#define NID_rsadsi 1 +#define OBJ_rsadsi OBJ_ISO_US,113549L + +#define SN_pkcs "pkcs" +#define LN_pkcs "RSA Data Security, Inc. PKCS" +#define NID_pkcs 2 +#define OBJ_pkcs OBJ_rsadsi,1L + +#define SN_pkcs1 "pkcs1" +#define NID_pkcs1 186 +#define OBJ_pkcs1 OBJ_pkcs,1L + +#define LN_rsaEncryption "rsaEncryption" +#define NID_rsaEncryption 6 +#define OBJ_rsaEncryption OBJ_pkcs1,1L + +#define SN_md2WithRSAEncryption "RSA-MD2" +#define LN_md2WithRSAEncryption "md2WithRSAEncryption" +#define NID_md2WithRSAEncryption 7 +#define OBJ_md2WithRSAEncryption OBJ_pkcs1,2L + +#define SN_md4WithRSAEncryption "RSA-MD4" +#define LN_md4WithRSAEncryption "md4WithRSAEncryption" +#define NID_md4WithRSAEncryption 396 +#define OBJ_md4WithRSAEncryption OBJ_pkcs1,3L + +#define SN_md5WithRSAEncryption "RSA-MD5" +#define LN_md5WithRSAEncryption "md5WithRSAEncryption" +#define NID_md5WithRSAEncryption 8 +#define OBJ_md5WithRSAEncryption OBJ_pkcs1,4L + +#define SN_sha1WithRSAEncryption "RSA-SHA1" +#define LN_sha1WithRSAEncryption "sha1WithRSAEncryption" +#define NID_sha1WithRSAEncryption 65 +#define OBJ_sha1WithRSAEncryption OBJ_pkcs1,5L + +#define SN_rsaesOaep "RSAES-OAEP" +#define LN_rsaesOaep "rsaesOaep" +#define NID_rsaesOaep 919 +#define OBJ_rsaesOaep OBJ_pkcs1,7L + +#define SN_mgf1 "MGF1" +#define LN_mgf1 "mgf1" +#define NID_mgf1 911 +#define OBJ_mgf1 OBJ_pkcs1,8L + +#define SN_pSpecified "PSPECIFIED" +#define LN_pSpecified "pSpecified" +#define NID_pSpecified 935 +#define OBJ_pSpecified OBJ_pkcs1,9L + +#define SN_rsassaPss "RSASSA-PSS" +#define LN_rsassaPss "rsassaPss" +#define NID_rsassaPss 912 +#define OBJ_rsassaPss OBJ_pkcs1,10L + +#define SN_sha256WithRSAEncryption "RSA-SHA256" +#define LN_sha256WithRSAEncryption "sha256WithRSAEncryption" +#define NID_sha256WithRSAEncryption 668 +#define OBJ_sha256WithRSAEncryption OBJ_pkcs1,11L + +#define SN_sha384WithRSAEncryption "RSA-SHA384" +#define LN_sha384WithRSAEncryption "sha384WithRSAEncryption" +#define NID_sha384WithRSAEncryption 669 +#define OBJ_sha384WithRSAEncryption OBJ_pkcs1,12L + +#define SN_sha512WithRSAEncryption "RSA-SHA512" +#define LN_sha512WithRSAEncryption "sha512WithRSAEncryption" +#define NID_sha512WithRSAEncryption 670 +#define OBJ_sha512WithRSAEncryption OBJ_pkcs1,13L + +#define SN_sha224WithRSAEncryption "RSA-SHA224" +#define LN_sha224WithRSAEncryption "sha224WithRSAEncryption" +#define NID_sha224WithRSAEncryption 671 +#define OBJ_sha224WithRSAEncryption OBJ_pkcs1,14L + +#define SN_pkcs3 "pkcs3" +#define NID_pkcs3 27 +#define OBJ_pkcs3 OBJ_pkcs,3L + +#define LN_dhKeyAgreement "dhKeyAgreement" +#define NID_dhKeyAgreement 28 +#define OBJ_dhKeyAgreement OBJ_pkcs3,1L + +#define SN_pkcs5 "pkcs5" +#define NID_pkcs5 187 +#define OBJ_pkcs5 OBJ_pkcs,5L + +#define SN_pbeWithMD2AndDES_CBC "PBE-MD2-DES" +#define LN_pbeWithMD2AndDES_CBC "pbeWithMD2AndDES-CBC" +#define NID_pbeWithMD2AndDES_CBC 9 +#define OBJ_pbeWithMD2AndDES_CBC OBJ_pkcs5,1L + +#define SN_pbeWithMD5AndDES_CBC "PBE-MD5-DES" +#define LN_pbeWithMD5AndDES_CBC "pbeWithMD5AndDES-CBC" +#define NID_pbeWithMD5AndDES_CBC 10 +#define OBJ_pbeWithMD5AndDES_CBC OBJ_pkcs5,3L + +#define SN_pbeWithMD2AndRC2_CBC "PBE-MD2-RC2-64" +#define LN_pbeWithMD2AndRC2_CBC "pbeWithMD2AndRC2-CBC" +#define NID_pbeWithMD2AndRC2_CBC 168 +#define OBJ_pbeWithMD2AndRC2_CBC OBJ_pkcs5,4L + +#define SN_pbeWithMD5AndRC2_CBC "PBE-MD5-RC2-64" +#define LN_pbeWithMD5AndRC2_CBC "pbeWithMD5AndRC2-CBC" +#define NID_pbeWithMD5AndRC2_CBC 169 +#define OBJ_pbeWithMD5AndRC2_CBC OBJ_pkcs5,6L + +#define SN_pbeWithSHA1AndDES_CBC "PBE-SHA1-DES" +#define LN_pbeWithSHA1AndDES_CBC "pbeWithSHA1AndDES-CBC" +#define NID_pbeWithSHA1AndDES_CBC 170 +#define OBJ_pbeWithSHA1AndDES_CBC OBJ_pkcs5,10L + +#define SN_pbeWithSHA1AndRC2_CBC "PBE-SHA1-RC2-64" +#define LN_pbeWithSHA1AndRC2_CBC "pbeWithSHA1AndRC2-CBC" +#define NID_pbeWithSHA1AndRC2_CBC 68 +#define OBJ_pbeWithSHA1AndRC2_CBC OBJ_pkcs5,11L + +#define LN_id_pbkdf2 "PBKDF2" +#define NID_id_pbkdf2 69 +#define OBJ_id_pbkdf2 OBJ_pkcs5,12L + +#define LN_pbes2 "PBES2" +#define NID_pbes2 161 +#define OBJ_pbes2 OBJ_pkcs5,13L + +#define LN_pbmac1 "PBMAC1" +#define NID_pbmac1 162 +#define OBJ_pbmac1 OBJ_pkcs5,14L + +#define SN_pkcs7 "pkcs7" +#define NID_pkcs7 20 +#define OBJ_pkcs7 OBJ_pkcs,7L + +#define LN_pkcs7_data "pkcs7-data" +#define NID_pkcs7_data 21 +#define OBJ_pkcs7_data OBJ_pkcs7,1L + +#define LN_pkcs7_signed "pkcs7-signedData" +#define NID_pkcs7_signed 22 +#define OBJ_pkcs7_signed OBJ_pkcs7,2L + +#define LN_pkcs7_enveloped "pkcs7-envelopedData" +#define NID_pkcs7_enveloped 23 +#define OBJ_pkcs7_enveloped OBJ_pkcs7,3L + +#define LN_pkcs7_signedAndEnveloped "pkcs7-signedAndEnvelopedData" +#define NID_pkcs7_signedAndEnveloped 24 +#define OBJ_pkcs7_signedAndEnveloped OBJ_pkcs7,4L + +#define LN_pkcs7_digest "pkcs7-digestData" +#define NID_pkcs7_digest 25 +#define OBJ_pkcs7_digest OBJ_pkcs7,5L + +#define LN_pkcs7_encrypted "pkcs7-encryptedData" +#define NID_pkcs7_encrypted 26 +#define OBJ_pkcs7_encrypted OBJ_pkcs7,6L + +#define SN_pkcs9 "pkcs9" +#define NID_pkcs9 47 +#define OBJ_pkcs9 OBJ_pkcs,9L + +#define LN_pkcs9_emailAddress "emailAddress" +#define NID_pkcs9_emailAddress 48 +#define OBJ_pkcs9_emailAddress OBJ_pkcs9,1L + +#define LN_pkcs9_unstructuredName "unstructuredName" +#define NID_pkcs9_unstructuredName 49 +#define OBJ_pkcs9_unstructuredName OBJ_pkcs9,2L + +#define LN_pkcs9_contentType "contentType" +#define NID_pkcs9_contentType 50 +#define OBJ_pkcs9_contentType OBJ_pkcs9,3L + +#define LN_pkcs9_messageDigest "messageDigest" +#define NID_pkcs9_messageDigest 51 +#define OBJ_pkcs9_messageDigest OBJ_pkcs9,4L + +#define LN_pkcs9_signingTime "signingTime" +#define NID_pkcs9_signingTime 52 +#define OBJ_pkcs9_signingTime OBJ_pkcs9,5L + +#define LN_pkcs9_countersignature "countersignature" +#define NID_pkcs9_countersignature 53 +#define OBJ_pkcs9_countersignature OBJ_pkcs9,6L + +#define LN_pkcs9_challengePassword "challengePassword" +#define NID_pkcs9_challengePassword 54 +#define OBJ_pkcs9_challengePassword OBJ_pkcs9,7L + +#define LN_pkcs9_unstructuredAddress "unstructuredAddress" +#define NID_pkcs9_unstructuredAddress 55 +#define OBJ_pkcs9_unstructuredAddress OBJ_pkcs9,8L + +#define LN_pkcs9_extCertAttributes "extendedCertificateAttributes" +#define NID_pkcs9_extCertAttributes 56 +#define OBJ_pkcs9_extCertAttributes OBJ_pkcs9,9L + +#define SN_ext_req "extReq" +#define LN_ext_req "Extension Request" +#define NID_ext_req 172 +#define OBJ_ext_req OBJ_pkcs9,14L + +#define SN_SMIMECapabilities "SMIME-CAPS" +#define LN_SMIMECapabilities "S/MIME Capabilities" +#define NID_SMIMECapabilities 167 +#define OBJ_SMIMECapabilities OBJ_pkcs9,15L + +#define SN_SMIME "SMIME" +#define LN_SMIME "S/MIME" +#define NID_SMIME 188 +#define OBJ_SMIME OBJ_pkcs9,16L + +#define SN_id_smime_mod "id-smime-mod" +#define NID_id_smime_mod 189 +#define OBJ_id_smime_mod OBJ_SMIME,0L + +#define SN_id_smime_ct "id-smime-ct" +#define NID_id_smime_ct 190 +#define OBJ_id_smime_ct OBJ_SMIME,1L + +#define SN_id_smime_aa "id-smime-aa" +#define NID_id_smime_aa 191 +#define OBJ_id_smime_aa OBJ_SMIME,2L + +#define SN_id_smime_alg "id-smime-alg" +#define NID_id_smime_alg 192 +#define OBJ_id_smime_alg OBJ_SMIME,3L + +#define SN_id_smime_cd "id-smime-cd" +#define NID_id_smime_cd 193 +#define OBJ_id_smime_cd OBJ_SMIME,4L + +#define SN_id_smime_spq "id-smime-spq" +#define NID_id_smime_spq 194 +#define OBJ_id_smime_spq OBJ_SMIME,5L + +#define SN_id_smime_cti "id-smime-cti" +#define NID_id_smime_cti 195 +#define OBJ_id_smime_cti OBJ_SMIME,6L + +#define SN_id_smime_mod_cms "id-smime-mod-cms" +#define NID_id_smime_mod_cms 196 +#define OBJ_id_smime_mod_cms OBJ_id_smime_mod,1L + +#define SN_id_smime_mod_ess "id-smime-mod-ess" +#define NID_id_smime_mod_ess 197 +#define OBJ_id_smime_mod_ess OBJ_id_smime_mod,2L + +#define SN_id_smime_mod_oid "id-smime-mod-oid" +#define NID_id_smime_mod_oid 198 +#define OBJ_id_smime_mod_oid OBJ_id_smime_mod,3L + +#define SN_id_smime_mod_msg_v3 "id-smime-mod-msg-v3" +#define NID_id_smime_mod_msg_v3 199 +#define OBJ_id_smime_mod_msg_v3 OBJ_id_smime_mod,4L + +#define SN_id_smime_mod_ets_eSignature_88 "id-smime-mod-ets-eSignature-88" +#define NID_id_smime_mod_ets_eSignature_88 200 +#define OBJ_id_smime_mod_ets_eSignature_88 OBJ_id_smime_mod,5L + +#define SN_id_smime_mod_ets_eSignature_97 "id-smime-mod-ets-eSignature-97" +#define NID_id_smime_mod_ets_eSignature_97 201 +#define OBJ_id_smime_mod_ets_eSignature_97 OBJ_id_smime_mod,6L + +#define SN_id_smime_mod_ets_eSigPolicy_88 "id-smime-mod-ets-eSigPolicy-88" +#define NID_id_smime_mod_ets_eSigPolicy_88 202 +#define OBJ_id_smime_mod_ets_eSigPolicy_88 OBJ_id_smime_mod,7L + +#define SN_id_smime_mod_ets_eSigPolicy_97 "id-smime-mod-ets-eSigPolicy-97" +#define NID_id_smime_mod_ets_eSigPolicy_97 203 +#define OBJ_id_smime_mod_ets_eSigPolicy_97 OBJ_id_smime_mod,8L + +#define SN_id_smime_ct_receipt "id-smime-ct-receipt" +#define NID_id_smime_ct_receipt 204 +#define OBJ_id_smime_ct_receipt OBJ_id_smime_ct,1L + +#define SN_id_smime_ct_authData "id-smime-ct-authData" +#define NID_id_smime_ct_authData 205 +#define OBJ_id_smime_ct_authData OBJ_id_smime_ct,2L + +#define SN_id_smime_ct_publishCert "id-smime-ct-publishCert" +#define NID_id_smime_ct_publishCert 206 +#define OBJ_id_smime_ct_publishCert OBJ_id_smime_ct,3L + +#define SN_id_smime_ct_TSTInfo "id-smime-ct-TSTInfo" +#define NID_id_smime_ct_TSTInfo 207 +#define OBJ_id_smime_ct_TSTInfo OBJ_id_smime_ct,4L + +#define SN_id_smime_ct_TDTInfo "id-smime-ct-TDTInfo" +#define NID_id_smime_ct_TDTInfo 208 +#define OBJ_id_smime_ct_TDTInfo OBJ_id_smime_ct,5L + +#define SN_id_smime_ct_contentInfo "id-smime-ct-contentInfo" +#define NID_id_smime_ct_contentInfo 209 +#define OBJ_id_smime_ct_contentInfo OBJ_id_smime_ct,6L + +#define SN_id_smime_ct_DVCSRequestData "id-smime-ct-DVCSRequestData" +#define NID_id_smime_ct_DVCSRequestData 210 +#define OBJ_id_smime_ct_DVCSRequestData OBJ_id_smime_ct,7L + +#define SN_id_smime_ct_DVCSResponseData "id-smime-ct-DVCSResponseData" +#define NID_id_smime_ct_DVCSResponseData 211 +#define OBJ_id_smime_ct_DVCSResponseData OBJ_id_smime_ct,8L + +#define SN_id_smime_ct_compressedData "id-smime-ct-compressedData" +#define NID_id_smime_ct_compressedData 786 +#define OBJ_id_smime_ct_compressedData OBJ_id_smime_ct,9L + +#define SN_id_ct_asciiTextWithCRLF "id-ct-asciiTextWithCRLF" +#define NID_id_ct_asciiTextWithCRLF 787 +#define OBJ_id_ct_asciiTextWithCRLF OBJ_id_smime_ct,27L + +#define SN_id_smime_aa_receiptRequest "id-smime-aa-receiptRequest" +#define NID_id_smime_aa_receiptRequest 212 +#define OBJ_id_smime_aa_receiptRequest OBJ_id_smime_aa,1L + +#define SN_id_smime_aa_securityLabel "id-smime-aa-securityLabel" +#define NID_id_smime_aa_securityLabel 213 +#define OBJ_id_smime_aa_securityLabel OBJ_id_smime_aa,2L + +#define SN_id_smime_aa_mlExpandHistory "id-smime-aa-mlExpandHistory" +#define NID_id_smime_aa_mlExpandHistory 214 +#define OBJ_id_smime_aa_mlExpandHistory OBJ_id_smime_aa,3L + +#define SN_id_smime_aa_contentHint "id-smime-aa-contentHint" +#define NID_id_smime_aa_contentHint 215 +#define OBJ_id_smime_aa_contentHint OBJ_id_smime_aa,4L + +#define SN_id_smime_aa_msgSigDigest "id-smime-aa-msgSigDigest" +#define NID_id_smime_aa_msgSigDigest 216 +#define OBJ_id_smime_aa_msgSigDigest OBJ_id_smime_aa,5L + +#define SN_id_smime_aa_encapContentType "id-smime-aa-encapContentType" +#define NID_id_smime_aa_encapContentType 217 +#define OBJ_id_smime_aa_encapContentType OBJ_id_smime_aa,6L + +#define SN_id_smime_aa_contentIdentifier "id-smime-aa-contentIdentifier" +#define NID_id_smime_aa_contentIdentifier 218 +#define OBJ_id_smime_aa_contentIdentifier OBJ_id_smime_aa,7L + +#define SN_id_smime_aa_macValue "id-smime-aa-macValue" +#define NID_id_smime_aa_macValue 219 +#define OBJ_id_smime_aa_macValue OBJ_id_smime_aa,8L + +#define SN_id_smime_aa_equivalentLabels "id-smime-aa-equivalentLabels" +#define NID_id_smime_aa_equivalentLabels 220 +#define OBJ_id_smime_aa_equivalentLabels OBJ_id_smime_aa,9L + +#define SN_id_smime_aa_contentReference "id-smime-aa-contentReference" +#define NID_id_smime_aa_contentReference 221 +#define OBJ_id_smime_aa_contentReference OBJ_id_smime_aa,10L + +#define SN_id_smime_aa_encrypKeyPref "id-smime-aa-encrypKeyPref" +#define NID_id_smime_aa_encrypKeyPref 222 +#define OBJ_id_smime_aa_encrypKeyPref OBJ_id_smime_aa,11L + +#define SN_id_smime_aa_signingCertificate "id-smime-aa-signingCertificate" +#define NID_id_smime_aa_signingCertificate 223 +#define OBJ_id_smime_aa_signingCertificate OBJ_id_smime_aa,12L + +#define SN_id_smime_aa_smimeEncryptCerts "id-smime-aa-smimeEncryptCerts" +#define NID_id_smime_aa_smimeEncryptCerts 224 +#define OBJ_id_smime_aa_smimeEncryptCerts OBJ_id_smime_aa,13L + +#define SN_id_smime_aa_timeStampToken "id-smime-aa-timeStampToken" +#define NID_id_smime_aa_timeStampToken 225 +#define OBJ_id_smime_aa_timeStampToken OBJ_id_smime_aa,14L + +#define SN_id_smime_aa_ets_sigPolicyId "id-smime-aa-ets-sigPolicyId" +#define NID_id_smime_aa_ets_sigPolicyId 226 +#define OBJ_id_smime_aa_ets_sigPolicyId OBJ_id_smime_aa,15L + +#define SN_id_smime_aa_ets_commitmentType "id-smime-aa-ets-commitmentType" +#define NID_id_smime_aa_ets_commitmentType 227 +#define OBJ_id_smime_aa_ets_commitmentType OBJ_id_smime_aa,16L + +#define SN_id_smime_aa_ets_signerLocation "id-smime-aa-ets-signerLocation" +#define NID_id_smime_aa_ets_signerLocation 228 +#define OBJ_id_smime_aa_ets_signerLocation OBJ_id_smime_aa,17L + +#define SN_id_smime_aa_ets_signerAttr "id-smime-aa-ets-signerAttr" +#define NID_id_smime_aa_ets_signerAttr 229 +#define OBJ_id_smime_aa_ets_signerAttr OBJ_id_smime_aa,18L + +#define SN_id_smime_aa_ets_otherSigCert "id-smime-aa-ets-otherSigCert" +#define NID_id_smime_aa_ets_otherSigCert 230 +#define OBJ_id_smime_aa_ets_otherSigCert OBJ_id_smime_aa,19L + +#define SN_id_smime_aa_ets_contentTimestamp "id-smime-aa-ets-contentTimestamp" +#define NID_id_smime_aa_ets_contentTimestamp 231 +#define OBJ_id_smime_aa_ets_contentTimestamp OBJ_id_smime_aa,20L + +#define SN_id_smime_aa_ets_CertificateRefs "id-smime-aa-ets-CertificateRefs" +#define NID_id_smime_aa_ets_CertificateRefs 232 +#define OBJ_id_smime_aa_ets_CertificateRefs OBJ_id_smime_aa,21L + +#define SN_id_smime_aa_ets_RevocationRefs "id-smime-aa-ets-RevocationRefs" +#define NID_id_smime_aa_ets_RevocationRefs 233 +#define OBJ_id_smime_aa_ets_RevocationRefs OBJ_id_smime_aa,22L + +#define SN_id_smime_aa_ets_certValues "id-smime-aa-ets-certValues" +#define NID_id_smime_aa_ets_certValues 234 +#define OBJ_id_smime_aa_ets_certValues OBJ_id_smime_aa,23L + +#define SN_id_smime_aa_ets_revocationValues "id-smime-aa-ets-revocationValues" +#define NID_id_smime_aa_ets_revocationValues 235 +#define OBJ_id_smime_aa_ets_revocationValues OBJ_id_smime_aa,24L + +#define SN_id_smime_aa_ets_escTimeStamp "id-smime-aa-ets-escTimeStamp" +#define NID_id_smime_aa_ets_escTimeStamp 236 +#define OBJ_id_smime_aa_ets_escTimeStamp OBJ_id_smime_aa,25L + +#define SN_id_smime_aa_ets_certCRLTimestamp "id-smime-aa-ets-certCRLTimestamp" +#define NID_id_smime_aa_ets_certCRLTimestamp 237 +#define OBJ_id_smime_aa_ets_certCRLTimestamp OBJ_id_smime_aa,26L + +#define SN_id_smime_aa_ets_archiveTimeStamp "id-smime-aa-ets-archiveTimeStamp" +#define NID_id_smime_aa_ets_archiveTimeStamp 238 +#define OBJ_id_smime_aa_ets_archiveTimeStamp OBJ_id_smime_aa,27L + +#define SN_id_smime_aa_signatureType "id-smime-aa-signatureType" +#define NID_id_smime_aa_signatureType 239 +#define OBJ_id_smime_aa_signatureType OBJ_id_smime_aa,28L + +#define SN_id_smime_aa_dvcs_dvc "id-smime-aa-dvcs-dvc" +#define NID_id_smime_aa_dvcs_dvc 240 +#define OBJ_id_smime_aa_dvcs_dvc OBJ_id_smime_aa,29L + +#define SN_id_smime_alg_ESDHwith3DES "id-smime-alg-ESDHwith3DES" +#define NID_id_smime_alg_ESDHwith3DES 241 +#define OBJ_id_smime_alg_ESDHwith3DES OBJ_id_smime_alg,1L + +#define SN_id_smime_alg_ESDHwithRC2 "id-smime-alg-ESDHwithRC2" +#define NID_id_smime_alg_ESDHwithRC2 242 +#define OBJ_id_smime_alg_ESDHwithRC2 OBJ_id_smime_alg,2L + +#define SN_id_smime_alg_3DESwrap "id-smime-alg-3DESwrap" +#define NID_id_smime_alg_3DESwrap 243 +#define OBJ_id_smime_alg_3DESwrap OBJ_id_smime_alg,3L + +#define SN_id_smime_alg_RC2wrap "id-smime-alg-RC2wrap" +#define NID_id_smime_alg_RC2wrap 244 +#define OBJ_id_smime_alg_RC2wrap OBJ_id_smime_alg,4L + +#define SN_id_smime_alg_ESDH "id-smime-alg-ESDH" +#define NID_id_smime_alg_ESDH 245 +#define OBJ_id_smime_alg_ESDH OBJ_id_smime_alg,5L + +#define SN_id_smime_alg_CMS3DESwrap "id-smime-alg-CMS3DESwrap" +#define NID_id_smime_alg_CMS3DESwrap 246 +#define OBJ_id_smime_alg_CMS3DESwrap OBJ_id_smime_alg,6L + +#define SN_id_smime_alg_CMSRC2wrap "id-smime-alg-CMSRC2wrap" +#define NID_id_smime_alg_CMSRC2wrap 247 +#define OBJ_id_smime_alg_CMSRC2wrap OBJ_id_smime_alg,7L + +#define SN_id_alg_PWRI_KEK "id-alg-PWRI-KEK" +#define NID_id_alg_PWRI_KEK 893 +#define OBJ_id_alg_PWRI_KEK OBJ_id_smime_alg,9L + +#define SN_id_smime_cd_ldap "id-smime-cd-ldap" +#define NID_id_smime_cd_ldap 248 +#define OBJ_id_smime_cd_ldap OBJ_id_smime_cd,1L + +#define SN_id_smime_spq_ets_sqt_uri "id-smime-spq-ets-sqt-uri" +#define NID_id_smime_spq_ets_sqt_uri 249 +#define OBJ_id_smime_spq_ets_sqt_uri OBJ_id_smime_spq,1L + +#define SN_id_smime_spq_ets_sqt_unotice "id-smime-spq-ets-sqt-unotice" +#define NID_id_smime_spq_ets_sqt_unotice 250 +#define OBJ_id_smime_spq_ets_sqt_unotice OBJ_id_smime_spq,2L + +#define SN_id_smime_cti_ets_proofOfOrigin "id-smime-cti-ets-proofOfOrigin" +#define NID_id_smime_cti_ets_proofOfOrigin 251 +#define OBJ_id_smime_cti_ets_proofOfOrigin OBJ_id_smime_cti,1L + +#define SN_id_smime_cti_ets_proofOfReceipt "id-smime-cti-ets-proofOfReceipt" +#define NID_id_smime_cti_ets_proofOfReceipt 252 +#define OBJ_id_smime_cti_ets_proofOfReceipt OBJ_id_smime_cti,2L + +#define SN_id_smime_cti_ets_proofOfDelivery "id-smime-cti-ets-proofOfDelivery" +#define NID_id_smime_cti_ets_proofOfDelivery 253 +#define OBJ_id_smime_cti_ets_proofOfDelivery OBJ_id_smime_cti,3L + +#define SN_id_smime_cti_ets_proofOfSender "id-smime-cti-ets-proofOfSender" +#define NID_id_smime_cti_ets_proofOfSender 254 +#define OBJ_id_smime_cti_ets_proofOfSender OBJ_id_smime_cti,4L + +#define SN_id_smime_cti_ets_proofOfApproval "id-smime-cti-ets-proofOfApproval" +#define NID_id_smime_cti_ets_proofOfApproval 255 +#define OBJ_id_smime_cti_ets_proofOfApproval OBJ_id_smime_cti,5L + +#define SN_id_smime_cti_ets_proofOfCreation "id-smime-cti-ets-proofOfCreation" +#define NID_id_smime_cti_ets_proofOfCreation 256 +#define OBJ_id_smime_cti_ets_proofOfCreation OBJ_id_smime_cti,6L + +#define LN_friendlyName "friendlyName" +#define NID_friendlyName 156 +#define OBJ_friendlyName OBJ_pkcs9,20L + +#define LN_localKeyID "localKeyID" +#define NID_localKeyID 157 +#define OBJ_localKeyID OBJ_pkcs9,21L + +#define SN_ms_csp_name "CSPName" +#define LN_ms_csp_name "Microsoft CSP Name" +#define NID_ms_csp_name 417 +#define OBJ_ms_csp_name 1L,3L,6L,1L,4L,1L,311L,17L,1L + +#define SN_LocalKeySet "LocalKeySet" +#define LN_LocalKeySet "Microsoft Local Key set" +#define NID_LocalKeySet 856 +#define OBJ_LocalKeySet 1L,3L,6L,1L,4L,1L,311L,17L,2L + +#define OBJ_certTypes OBJ_pkcs9,22L + +#define LN_x509Certificate "x509Certificate" +#define NID_x509Certificate 158 +#define OBJ_x509Certificate OBJ_certTypes,1L + +#define LN_sdsiCertificate "sdsiCertificate" +#define NID_sdsiCertificate 159 +#define OBJ_sdsiCertificate OBJ_certTypes,2L + +#define OBJ_crlTypes OBJ_pkcs9,23L + +#define LN_x509Crl "x509Crl" +#define NID_x509Crl 160 +#define OBJ_x509Crl OBJ_crlTypes,1L + +#define OBJ_pkcs12 OBJ_pkcs,12L + +#define OBJ_pkcs12_pbeids OBJ_pkcs12,1L + +#define SN_pbe_WithSHA1And128BitRC4 "PBE-SHA1-RC4-128" +#define LN_pbe_WithSHA1And128BitRC4 "pbeWithSHA1And128BitRC4" +#define NID_pbe_WithSHA1And128BitRC4 144 +#define OBJ_pbe_WithSHA1And128BitRC4 OBJ_pkcs12_pbeids,1L + +#define SN_pbe_WithSHA1And40BitRC4 "PBE-SHA1-RC4-40" +#define LN_pbe_WithSHA1And40BitRC4 "pbeWithSHA1And40BitRC4" +#define NID_pbe_WithSHA1And40BitRC4 145 +#define OBJ_pbe_WithSHA1And40BitRC4 OBJ_pkcs12_pbeids,2L + +#define SN_pbe_WithSHA1And3_Key_TripleDES_CBC "PBE-SHA1-3DES" +#define LN_pbe_WithSHA1And3_Key_TripleDES_CBC "pbeWithSHA1And3-KeyTripleDES-CBC" +#define NID_pbe_WithSHA1And3_Key_TripleDES_CBC 146 +#define OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC OBJ_pkcs12_pbeids,3L + +#define SN_pbe_WithSHA1And2_Key_TripleDES_CBC "PBE-SHA1-2DES" +#define LN_pbe_WithSHA1And2_Key_TripleDES_CBC "pbeWithSHA1And2-KeyTripleDES-CBC" +#define NID_pbe_WithSHA1And2_Key_TripleDES_CBC 147 +#define OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC OBJ_pkcs12_pbeids,4L + +#define SN_pbe_WithSHA1And128BitRC2_CBC "PBE-SHA1-RC2-128" +#define LN_pbe_WithSHA1And128BitRC2_CBC "pbeWithSHA1And128BitRC2-CBC" +#define NID_pbe_WithSHA1And128BitRC2_CBC 148 +#define OBJ_pbe_WithSHA1And128BitRC2_CBC OBJ_pkcs12_pbeids,5L + +#define SN_pbe_WithSHA1And40BitRC2_CBC "PBE-SHA1-RC2-40" +#define LN_pbe_WithSHA1And40BitRC2_CBC "pbeWithSHA1And40BitRC2-CBC" +#define NID_pbe_WithSHA1And40BitRC2_CBC 149 +#define OBJ_pbe_WithSHA1And40BitRC2_CBC OBJ_pkcs12_pbeids,6L + +#define OBJ_pkcs12_Version1 OBJ_pkcs12,10L + +#define OBJ_pkcs12_BagIds OBJ_pkcs12_Version1,1L + +#define LN_keyBag "keyBag" +#define NID_keyBag 150 +#define OBJ_keyBag OBJ_pkcs12_BagIds,1L + +#define LN_pkcs8ShroudedKeyBag "pkcs8ShroudedKeyBag" +#define NID_pkcs8ShroudedKeyBag 151 +#define OBJ_pkcs8ShroudedKeyBag OBJ_pkcs12_BagIds,2L + +#define LN_certBag "certBag" +#define NID_certBag 152 +#define OBJ_certBag OBJ_pkcs12_BagIds,3L + +#define LN_crlBag "crlBag" +#define NID_crlBag 153 +#define OBJ_crlBag OBJ_pkcs12_BagIds,4L + +#define LN_secretBag "secretBag" +#define NID_secretBag 154 +#define OBJ_secretBag OBJ_pkcs12_BagIds,5L + +#define LN_safeContentsBag "safeContentsBag" +#define NID_safeContentsBag 155 +#define OBJ_safeContentsBag OBJ_pkcs12_BagIds,6L + +#define SN_md2 "MD2" +#define LN_md2 "md2" +#define NID_md2 3 +#define OBJ_md2 OBJ_rsadsi,2L,2L + +#define SN_md4 "MD4" +#define LN_md4 "md4" +#define NID_md4 257 +#define OBJ_md4 OBJ_rsadsi,2L,4L + +#define SN_md5 "MD5" +#define LN_md5 "md5" +#define NID_md5 4 +#define OBJ_md5 OBJ_rsadsi,2L,5L + +#define SN_md5_sha1 "MD5-SHA1" +#define LN_md5_sha1 "md5-sha1" +#define NID_md5_sha1 114 + +#define LN_hmacWithMD5 "hmacWithMD5" +#define NID_hmacWithMD5 797 +#define OBJ_hmacWithMD5 OBJ_rsadsi,2L,6L + +#define LN_hmacWithSHA1 "hmacWithSHA1" +#define NID_hmacWithSHA1 163 +#define OBJ_hmacWithSHA1 OBJ_rsadsi,2L,7L + +#define LN_hmacWithSHA224 "hmacWithSHA224" +#define NID_hmacWithSHA224 798 +#define OBJ_hmacWithSHA224 OBJ_rsadsi,2L,8L + +#define LN_hmacWithSHA256 "hmacWithSHA256" +#define NID_hmacWithSHA256 799 +#define OBJ_hmacWithSHA256 OBJ_rsadsi,2L,9L + +#define LN_hmacWithSHA384 "hmacWithSHA384" +#define NID_hmacWithSHA384 800 +#define OBJ_hmacWithSHA384 OBJ_rsadsi,2L,10L + +#define LN_hmacWithSHA512 "hmacWithSHA512" +#define NID_hmacWithSHA512 801 +#define OBJ_hmacWithSHA512 OBJ_rsadsi,2L,11L + +#define SN_rc2_cbc "RC2-CBC" +#define LN_rc2_cbc "rc2-cbc" +#define NID_rc2_cbc 37 +#define OBJ_rc2_cbc OBJ_rsadsi,3L,2L + +#define SN_rc2_ecb "RC2-ECB" +#define LN_rc2_ecb "rc2-ecb" +#define NID_rc2_ecb 38 + +#define SN_rc2_cfb64 "RC2-CFB" +#define LN_rc2_cfb64 "rc2-cfb" +#define NID_rc2_cfb64 39 + +#define SN_rc2_ofb64 "RC2-OFB" +#define LN_rc2_ofb64 "rc2-ofb" +#define NID_rc2_ofb64 40 + +#define SN_rc2_40_cbc "RC2-40-CBC" +#define LN_rc2_40_cbc "rc2-40-cbc" +#define NID_rc2_40_cbc 98 + +#define SN_rc2_64_cbc "RC2-64-CBC" +#define LN_rc2_64_cbc "rc2-64-cbc" +#define NID_rc2_64_cbc 166 + +#define SN_rc4 "RC4" +#define LN_rc4 "rc4" +#define NID_rc4 5 +#define OBJ_rc4 OBJ_rsadsi,3L,4L + +#define SN_rc4_40 "RC4-40" +#define LN_rc4_40 "rc4-40" +#define NID_rc4_40 97 + +#define SN_des_ede3_cbc "DES-EDE3-CBC" +#define LN_des_ede3_cbc "des-ede3-cbc" +#define NID_des_ede3_cbc 44 +#define OBJ_des_ede3_cbc OBJ_rsadsi,3L,7L + +#define SN_rc5_cbc "RC5-CBC" +#define LN_rc5_cbc "rc5-cbc" +#define NID_rc5_cbc 120 +#define OBJ_rc5_cbc OBJ_rsadsi,3L,8L + +#define SN_rc5_ecb "RC5-ECB" +#define LN_rc5_ecb "rc5-ecb" +#define NID_rc5_ecb 121 + +#define SN_rc5_cfb64 "RC5-CFB" +#define LN_rc5_cfb64 "rc5-cfb" +#define NID_rc5_cfb64 122 + +#define SN_rc5_ofb64 "RC5-OFB" +#define LN_rc5_ofb64 "rc5-ofb" +#define NID_rc5_ofb64 123 + +#define SN_ms_ext_req "msExtReq" +#define LN_ms_ext_req "Microsoft Extension Request" +#define NID_ms_ext_req 171 +#define OBJ_ms_ext_req 1L,3L,6L,1L,4L,1L,311L,2L,1L,14L + +#define SN_ms_code_ind "msCodeInd" +#define LN_ms_code_ind "Microsoft Individual Code Signing" +#define NID_ms_code_ind 134 +#define OBJ_ms_code_ind 1L,3L,6L,1L,4L,1L,311L,2L,1L,21L + +#define SN_ms_code_com "msCodeCom" +#define LN_ms_code_com "Microsoft Commercial Code Signing" +#define NID_ms_code_com 135 +#define OBJ_ms_code_com 1L,3L,6L,1L,4L,1L,311L,2L,1L,22L + +#define SN_ms_ctl_sign "msCTLSign" +#define LN_ms_ctl_sign "Microsoft Trust List Signing" +#define NID_ms_ctl_sign 136 +#define OBJ_ms_ctl_sign 1L,3L,6L,1L,4L,1L,311L,10L,3L,1L + +#define SN_ms_sgc "msSGC" +#define LN_ms_sgc "Microsoft Server Gated Crypto" +#define NID_ms_sgc 137 +#define OBJ_ms_sgc 1L,3L,6L,1L,4L,1L,311L,10L,3L,3L + +#define SN_ms_efs "msEFS" +#define LN_ms_efs "Microsoft Encrypted File System" +#define NID_ms_efs 138 +#define OBJ_ms_efs 1L,3L,6L,1L,4L,1L,311L,10L,3L,4L + +#define SN_ms_smartcard_login "msSmartcardLogin" +#define LN_ms_smartcard_login "Microsoft Smartcardlogin" +#define NID_ms_smartcard_login 648 +#define OBJ_ms_smartcard_login 1L,3L,6L,1L,4L,1L,311L,20L,2L,2L + +#define SN_ms_upn "msUPN" +#define LN_ms_upn "Microsoft Universal Principal Name" +#define NID_ms_upn 649 +#define OBJ_ms_upn 1L,3L,6L,1L,4L,1L,311L,20L,2L,3L + +#define SN_idea_cbc "IDEA-CBC" +#define LN_idea_cbc "idea-cbc" +#define NID_idea_cbc 34 +#define OBJ_idea_cbc 1L,3L,6L,1L,4L,1L,188L,7L,1L,1L,2L + +#define SN_idea_ecb "IDEA-ECB" +#define LN_idea_ecb "idea-ecb" +#define NID_idea_ecb 36 + +#define SN_idea_cfb64 "IDEA-CFB" +#define LN_idea_cfb64 "idea-cfb" +#define NID_idea_cfb64 35 + +#define SN_idea_ofb64 "IDEA-OFB" +#define LN_idea_ofb64 "idea-ofb" +#define NID_idea_ofb64 46 + +#define SN_bf_cbc "BF-CBC" +#define LN_bf_cbc "bf-cbc" +#define NID_bf_cbc 91 +#define OBJ_bf_cbc 1L,3L,6L,1L,4L,1L,3029L,1L,2L + +#define SN_bf_ecb "BF-ECB" +#define LN_bf_ecb "bf-ecb" +#define NID_bf_ecb 92 + +#define SN_bf_cfb64 "BF-CFB" +#define LN_bf_cfb64 "bf-cfb" +#define NID_bf_cfb64 93 + +#define SN_bf_ofb64 "BF-OFB" +#define LN_bf_ofb64 "bf-ofb" +#define NID_bf_ofb64 94 + +#define SN_id_pkix "PKIX" +#define NID_id_pkix 127 +#define OBJ_id_pkix 1L,3L,6L,1L,5L,5L,7L + +#define SN_id_pkix_mod "id-pkix-mod" +#define NID_id_pkix_mod 258 +#define OBJ_id_pkix_mod OBJ_id_pkix,0L + +#define SN_id_pe "id-pe" +#define NID_id_pe 175 +#define OBJ_id_pe OBJ_id_pkix,1L + +#define SN_id_qt "id-qt" +#define NID_id_qt 259 +#define OBJ_id_qt OBJ_id_pkix,2L + +#define SN_id_kp "id-kp" +#define NID_id_kp 128 +#define OBJ_id_kp OBJ_id_pkix,3L + +#define SN_id_it "id-it" +#define NID_id_it 260 +#define OBJ_id_it OBJ_id_pkix,4L + +#define SN_id_pkip "id-pkip" +#define NID_id_pkip 261 +#define OBJ_id_pkip OBJ_id_pkix,5L + +#define SN_id_alg "id-alg" +#define NID_id_alg 262 +#define OBJ_id_alg OBJ_id_pkix,6L + +#define SN_id_cmc "id-cmc" +#define NID_id_cmc 263 +#define OBJ_id_cmc OBJ_id_pkix,7L + +#define SN_id_on "id-on" +#define NID_id_on 264 +#define OBJ_id_on OBJ_id_pkix,8L + +#define SN_id_pda "id-pda" +#define NID_id_pda 265 +#define OBJ_id_pda OBJ_id_pkix,9L + +#define SN_id_aca "id-aca" +#define NID_id_aca 266 +#define OBJ_id_aca OBJ_id_pkix,10L + +#define SN_id_qcs "id-qcs" +#define NID_id_qcs 267 +#define OBJ_id_qcs OBJ_id_pkix,11L + +#define SN_id_cct "id-cct" +#define NID_id_cct 268 +#define OBJ_id_cct OBJ_id_pkix,12L + +#define SN_id_ppl "id-ppl" +#define NID_id_ppl 662 +#define OBJ_id_ppl OBJ_id_pkix,21L + +#define SN_id_ad "id-ad" +#define NID_id_ad 176 +#define OBJ_id_ad OBJ_id_pkix,48L + +#define SN_id_pkix1_explicit_88 "id-pkix1-explicit-88" +#define NID_id_pkix1_explicit_88 269 +#define OBJ_id_pkix1_explicit_88 OBJ_id_pkix_mod,1L + +#define SN_id_pkix1_implicit_88 "id-pkix1-implicit-88" +#define NID_id_pkix1_implicit_88 270 +#define OBJ_id_pkix1_implicit_88 OBJ_id_pkix_mod,2L + +#define SN_id_pkix1_explicit_93 "id-pkix1-explicit-93" +#define NID_id_pkix1_explicit_93 271 +#define OBJ_id_pkix1_explicit_93 OBJ_id_pkix_mod,3L + +#define SN_id_pkix1_implicit_93 "id-pkix1-implicit-93" +#define NID_id_pkix1_implicit_93 272 +#define OBJ_id_pkix1_implicit_93 OBJ_id_pkix_mod,4L + +#define SN_id_mod_crmf "id-mod-crmf" +#define NID_id_mod_crmf 273 +#define OBJ_id_mod_crmf OBJ_id_pkix_mod,5L + +#define SN_id_mod_cmc "id-mod-cmc" +#define NID_id_mod_cmc 274 +#define OBJ_id_mod_cmc OBJ_id_pkix_mod,6L + +#define SN_id_mod_kea_profile_88 "id-mod-kea-profile-88" +#define NID_id_mod_kea_profile_88 275 +#define OBJ_id_mod_kea_profile_88 OBJ_id_pkix_mod,7L + +#define SN_id_mod_kea_profile_93 "id-mod-kea-profile-93" +#define NID_id_mod_kea_profile_93 276 +#define OBJ_id_mod_kea_profile_93 OBJ_id_pkix_mod,8L + +#define SN_id_mod_cmp "id-mod-cmp" +#define NID_id_mod_cmp 277 +#define OBJ_id_mod_cmp OBJ_id_pkix_mod,9L + +#define SN_id_mod_qualified_cert_88 "id-mod-qualified-cert-88" +#define NID_id_mod_qualified_cert_88 278 +#define OBJ_id_mod_qualified_cert_88 OBJ_id_pkix_mod,10L + +#define SN_id_mod_qualified_cert_93 "id-mod-qualified-cert-93" +#define NID_id_mod_qualified_cert_93 279 +#define OBJ_id_mod_qualified_cert_93 OBJ_id_pkix_mod,11L + +#define SN_id_mod_attribute_cert "id-mod-attribute-cert" +#define NID_id_mod_attribute_cert 280 +#define OBJ_id_mod_attribute_cert OBJ_id_pkix_mod,12L + +#define SN_id_mod_timestamp_protocol "id-mod-timestamp-protocol" +#define NID_id_mod_timestamp_protocol 281 +#define OBJ_id_mod_timestamp_protocol OBJ_id_pkix_mod,13L + +#define SN_id_mod_ocsp "id-mod-ocsp" +#define NID_id_mod_ocsp 282 +#define OBJ_id_mod_ocsp OBJ_id_pkix_mod,14L + +#define SN_id_mod_dvcs "id-mod-dvcs" +#define NID_id_mod_dvcs 283 +#define OBJ_id_mod_dvcs OBJ_id_pkix_mod,15L + +#define SN_id_mod_cmp2000 "id-mod-cmp2000" +#define NID_id_mod_cmp2000 284 +#define OBJ_id_mod_cmp2000 OBJ_id_pkix_mod,16L + +#define SN_info_access "authorityInfoAccess" +#define LN_info_access "Authority Information Access" +#define NID_info_access 177 +#define OBJ_info_access OBJ_id_pe,1L + +#define SN_biometricInfo "biometricInfo" +#define LN_biometricInfo "Biometric Info" +#define NID_biometricInfo 285 +#define OBJ_biometricInfo OBJ_id_pe,2L + +#define SN_qcStatements "qcStatements" +#define NID_qcStatements 286 +#define OBJ_qcStatements OBJ_id_pe,3L + +#define SN_ac_auditEntity "ac-auditEntity" +#define NID_ac_auditEntity 287 +#define OBJ_ac_auditEntity OBJ_id_pe,4L + +#define SN_ac_targeting "ac-targeting" +#define NID_ac_targeting 288 +#define OBJ_ac_targeting OBJ_id_pe,5L + +#define SN_aaControls "aaControls" +#define NID_aaControls 289 +#define OBJ_aaControls OBJ_id_pe,6L + +#define SN_sbgp_ipAddrBlock "sbgp-ipAddrBlock" +#define NID_sbgp_ipAddrBlock 290 +#define OBJ_sbgp_ipAddrBlock OBJ_id_pe,7L + +#define SN_sbgp_autonomousSysNum "sbgp-autonomousSysNum" +#define NID_sbgp_autonomousSysNum 291 +#define OBJ_sbgp_autonomousSysNum OBJ_id_pe,8L + +#define SN_sbgp_routerIdentifier "sbgp-routerIdentifier" +#define NID_sbgp_routerIdentifier 292 +#define OBJ_sbgp_routerIdentifier OBJ_id_pe,9L + +#define SN_ac_proxying "ac-proxying" +#define NID_ac_proxying 397 +#define OBJ_ac_proxying OBJ_id_pe,10L + +#define SN_sinfo_access "subjectInfoAccess" +#define LN_sinfo_access "Subject Information Access" +#define NID_sinfo_access 398 +#define OBJ_sinfo_access OBJ_id_pe,11L + +#define SN_proxyCertInfo "proxyCertInfo" +#define LN_proxyCertInfo "Proxy Certificate Information" +#define NID_proxyCertInfo 663 +#define OBJ_proxyCertInfo OBJ_id_pe,14L + +#define SN_id_qt_cps "id-qt-cps" +#define LN_id_qt_cps "Policy Qualifier CPS" +#define NID_id_qt_cps 164 +#define OBJ_id_qt_cps OBJ_id_qt,1L + +#define SN_id_qt_unotice "id-qt-unotice" +#define LN_id_qt_unotice "Policy Qualifier User Notice" +#define NID_id_qt_unotice 165 +#define OBJ_id_qt_unotice OBJ_id_qt,2L + +#define SN_textNotice "textNotice" +#define NID_textNotice 293 +#define OBJ_textNotice OBJ_id_qt,3L + +#define SN_server_auth "serverAuth" +#define LN_server_auth "TLS Web Server Authentication" +#define NID_server_auth 129 +#define OBJ_server_auth OBJ_id_kp,1L + +#define SN_client_auth "clientAuth" +#define LN_client_auth "TLS Web Client Authentication" +#define NID_client_auth 130 +#define OBJ_client_auth OBJ_id_kp,2L + +#define SN_code_sign "codeSigning" +#define LN_code_sign "Code Signing" +#define NID_code_sign 131 +#define OBJ_code_sign OBJ_id_kp,3L + +#define SN_email_protect "emailProtection" +#define LN_email_protect "E-mail Protection" +#define NID_email_protect 132 +#define OBJ_email_protect OBJ_id_kp,4L + +#define SN_ipsecEndSystem "ipsecEndSystem" +#define LN_ipsecEndSystem "IPSec End System" +#define NID_ipsecEndSystem 294 +#define OBJ_ipsecEndSystem OBJ_id_kp,5L + +#define SN_ipsecTunnel "ipsecTunnel" +#define LN_ipsecTunnel "IPSec Tunnel" +#define NID_ipsecTunnel 295 +#define OBJ_ipsecTunnel OBJ_id_kp,6L + +#define SN_ipsecUser "ipsecUser" +#define LN_ipsecUser "IPSec User" +#define NID_ipsecUser 296 +#define OBJ_ipsecUser OBJ_id_kp,7L + +#define SN_time_stamp "timeStamping" +#define LN_time_stamp "Time Stamping" +#define NID_time_stamp 133 +#define OBJ_time_stamp OBJ_id_kp,8L + +#define SN_OCSP_sign "OCSPSigning" +#define LN_OCSP_sign "OCSP Signing" +#define NID_OCSP_sign 180 +#define OBJ_OCSP_sign OBJ_id_kp,9L + +#define SN_dvcs "DVCS" +#define LN_dvcs "dvcs" +#define NID_dvcs 297 +#define OBJ_dvcs OBJ_id_kp,10L + +#define SN_id_it_caProtEncCert "id-it-caProtEncCert" +#define NID_id_it_caProtEncCert 298 +#define OBJ_id_it_caProtEncCert OBJ_id_it,1L + +#define SN_id_it_signKeyPairTypes "id-it-signKeyPairTypes" +#define NID_id_it_signKeyPairTypes 299 +#define OBJ_id_it_signKeyPairTypes OBJ_id_it,2L + +#define SN_id_it_encKeyPairTypes "id-it-encKeyPairTypes" +#define NID_id_it_encKeyPairTypes 300 +#define OBJ_id_it_encKeyPairTypes OBJ_id_it,3L + +#define SN_id_it_preferredSymmAlg "id-it-preferredSymmAlg" +#define NID_id_it_preferredSymmAlg 301 +#define OBJ_id_it_preferredSymmAlg OBJ_id_it,4L + +#define SN_id_it_caKeyUpdateInfo "id-it-caKeyUpdateInfo" +#define NID_id_it_caKeyUpdateInfo 302 +#define OBJ_id_it_caKeyUpdateInfo OBJ_id_it,5L + +#define SN_id_it_currentCRL "id-it-currentCRL" +#define NID_id_it_currentCRL 303 +#define OBJ_id_it_currentCRL OBJ_id_it,6L + +#define SN_id_it_unsupportedOIDs "id-it-unsupportedOIDs" +#define NID_id_it_unsupportedOIDs 304 +#define OBJ_id_it_unsupportedOIDs OBJ_id_it,7L + +#define SN_id_it_subscriptionRequest "id-it-subscriptionRequest" +#define NID_id_it_subscriptionRequest 305 +#define OBJ_id_it_subscriptionRequest OBJ_id_it,8L + +#define SN_id_it_subscriptionResponse "id-it-subscriptionResponse" +#define NID_id_it_subscriptionResponse 306 +#define OBJ_id_it_subscriptionResponse OBJ_id_it,9L + +#define SN_id_it_keyPairParamReq "id-it-keyPairParamReq" +#define NID_id_it_keyPairParamReq 307 +#define OBJ_id_it_keyPairParamReq OBJ_id_it,10L + +#define SN_id_it_keyPairParamRep "id-it-keyPairParamRep" +#define NID_id_it_keyPairParamRep 308 +#define OBJ_id_it_keyPairParamRep OBJ_id_it,11L + +#define SN_id_it_revPassphrase "id-it-revPassphrase" +#define NID_id_it_revPassphrase 309 +#define OBJ_id_it_revPassphrase OBJ_id_it,12L + +#define SN_id_it_implicitConfirm "id-it-implicitConfirm" +#define NID_id_it_implicitConfirm 310 +#define OBJ_id_it_implicitConfirm OBJ_id_it,13L + +#define SN_id_it_confirmWaitTime "id-it-confirmWaitTime" +#define NID_id_it_confirmWaitTime 311 +#define OBJ_id_it_confirmWaitTime OBJ_id_it,14L + +#define SN_id_it_origPKIMessage "id-it-origPKIMessage" +#define NID_id_it_origPKIMessage 312 +#define OBJ_id_it_origPKIMessage OBJ_id_it,15L + +#define SN_id_it_suppLangTags "id-it-suppLangTags" +#define NID_id_it_suppLangTags 784 +#define OBJ_id_it_suppLangTags OBJ_id_it,16L + +#define SN_id_regCtrl "id-regCtrl" +#define NID_id_regCtrl 313 +#define OBJ_id_regCtrl OBJ_id_pkip,1L + +#define SN_id_regInfo "id-regInfo" +#define NID_id_regInfo 314 +#define OBJ_id_regInfo OBJ_id_pkip,2L + +#define SN_id_regCtrl_regToken "id-regCtrl-regToken" +#define NID_id_regCtrl_regToken 315 +#define OBJ_id_regCtrl_regToken OBJ_id_regCtrl,1L + +#define SN_id_regCtrl_authenticator "id-regCtrl-authenticator" +#define NID_id_regCtrl_authenticator 316 +#define OBJ_id_regCtrl_authenticator OBJ_id_regCtrl,2L + +#define SN_id_regCtrl_pkiPublicationInfo "id-regCtrl-pkiPublicationInfo" +#define NID_id_regCtrl_pkiPublicationInfo 317 +#define OBJ_id_regCtrl_pkiPublicationInfo OBJ_id_regCtrl,3L + +#define SN_id_regCtrl_pkiArchiveOptions "id-regCtrl-pkiArchiveOptions" +#define NID_id_regCtrl_pkiArchiveOptions 318 +#define OBJ_id_regCtrl_pkiArchiveOptions OBJ_id_regCtrl,4L + +#define SN_id_regCtrl_oldCertID "id-regCtrl-oldCertID" +#define NID_id_regCtrl_oldCertID 319 +#define OBJ_id_regCtrl_oldCertID OBJ_id_regCtrl,5L + +#define SN_id_regCtrl_protocolEncrKey "id-regCtrl-protocolEncrKey" +#define NID_id_regCtrl_protocolEncrKey 320 +#define OBJ_id_regCtrl_protocolEncrKey OBJ_id_regCtrl,6L + +#define SN_id_regInfo_utf8Pairs "id-regInfo-utf8Pairs" +#define NID_id_regInfo_utf8Pairs 321 +#define OBJ_id_regInfo_utf8Pairs OBJ_id_regInfo,1L + +#define SN_id_regInfo_certReq "id-regInfo-certReq" +#define NID_id_regInfo_certReq 322 +#define OBJ_id_regInfo_certReq OBJ_id_regInfo,2L + +#define SN_id_alg_des40 "id-alg-des40" +#define NID_id_alg_des40 323 +#define OBJ_id_alg_des40 OBJ_id_alg,1L + +#define SN_id_alg_noSignature "id-alg-noSignature" +#define NID_id_alg_noSignature 324 +#define OBJ_id_alg_noSignature OBJ_id_alg,2L + +#define SN_id_alg_dh_sig_hmac_sha1 "id-alg-dh-sig-hmac-sha1" +#define NID_id_alg_dh_sig_hmac_sha1 325 +#define OBJ_id_alg_dh_sig_hmac_sha1 OBJ_id_alg,3L + +#define SN_id_alg_dh_pop "id-alg-dh-pop" +#define NID_id_alg_dh_pop 326 +#define OBJ_id_alg_dh_pop OBJ_id_alg,4L + +#define SN_id_cmc_statusInfo "id-cmc-statusInfo" +#define NID_id_cmc_statusInfo 327 +#define OBJ_id_cmc_statusInfo OBJ_id_cmc,1L + +#define SN_id_cmc_identification "id-cmc-identification" +#define NID_id_cmc_identification 328 +#define OBJ_id_cmc_identification OBJ_id_cmc,2L + +#define SN_id_cmc_identityProof "id-cmc-identityProof" +#define NID_id_cmc_identityProof 329 +#define OBJ_id_cmc_identityProof OBJ_id_cmc,3L + +#define SN_id_cmc_dataReturn "id-cmc-dataReturn" +#define NID_id_cmc_dataReturn 330 +#define OBJ_id_cmc_dataReturn OBJ_id_cmc,4L + +#define SN_id_cmc_transactionId "id-cmc-transactionId" +#define NID_id_cmc_transactionId 331 +#define OBJ_id_cmc_transactionId OBJ_id_cmc,5L + +#define SN_id_cmc_senderNonce "id-cmc-senderNonce" +#define NID_id_cmc_senderNonce 332 +#define OBJ_id_cmc_senderNonce OBJ_id_cmc,6L + +#define SN_id_cmc_recipientNonce "id-cmc-recipientNonce" +#define NID_id_cmc_recipientNonce 333 +#define OBJ_id_cmc_recipientNonce OBJ_id_cmc,7L + +#define SN_id_cmc_addExtensions "id-cmc-addExtensions" +#define NID_id_cmc_addExtensions 334 +#define OBJ_id_cmc_addExtensions OBJ_id_cmc,8L + +#define SN_id_cmc_encryptedPOP "id-cmc-encryptedPOP" +#define NID_id_cmc_encryptedPOP 335 +#define OBJ_id_cmc_encryptedPOP OBJ_id_cmc,9L + +#define SN_id_cmc_decryptedPOP "id-cmc-decryptedPOP" +#define NID_id_cmc_decryptedPOP 336 +#define OBJ_id_cmc_decryptedPOP OBJ_id_cmc,10L + +#define SN_id_cmc_lraPOPWitness "id-cmc-lraPOPWitness" +#define NID_id_cmc_lraPOPWitness 337 +#define OBJ_id_cmc_lraPOPWitness OBJ_id_cmc,11L + +#define SN_id_cmc_getCert "id-cmc-getCert" +#define NID_id_cmc_getCert 338 +#define OBJ_id_cmc_getCert OBJ_id_cmc,15L + +#define SN_id_cmc_getCRL "id-cmc-getCRL" +#define NID_id_cmc_getCRL 339 +#define OBJ_id_cmc_getCRL OBJ_id_cmc,16L + +#define SN_id_cmc_revokeRequest "id-cmc-revokeRequest" +#define NID_id_cmc_revokeRequest 340 +#define OBJ_id_cmc_revokeRequest OBJ_id_cmc,17L + +#define SN_id_cmc_regInfo "id-cmc-regInfo" +#define NID_id_cmc_regInfo 341 +#define OBJ_id_cmc_regInfo OBJ_id_cmc,18L + +#define SN_id_cmc_responseInfo "id-cmc-responseInfo" +#define NID_id_cmc_responseInfo 342 +#define OBJ_id_cmc_responseInfo OBJ_id_cmc,19L + +#define SN_id_cmc_queryPending "id-cmc-queryPending" +#define NID_id_cmc_queryPending 343 +#define OBJ_id_cmc_queryPending OBJ_id_cmc,21L + +#define SN_id_cmc_popLinkRandom "id-cmc-popLinkRandom" +#define NID_id_cmc_popLinkRandom 344 +#define OBJ_id_cmc_popLinkRandom OBJ_id_cmc,22L + +#define SN_id_cmc_popLinkWitness "id-cmc-popLinkWitness" +#define NID_id_cmc_popLinkWitness 345 +#define OBJ_id_cmc_popLinkWitness OBJ_id_cmc,23L + +#define SN_id_cmc_confirmCertAcceptance "id-cmc-confirmCertAcceptance" +#define NID_id_cmc_confirmCertAcceptance 346 +#define OBJ_id_cmc_confirmCertAcceptance OBJ_id_cmc,24L + +#define SN_id_on_personalData "id-on-personalData" +#define NID_id_on_personalData 347 +#define OBJ_id_on_personalData OBJ_id_on,1L + +#define SN_id_on_permanentIdentifier "id-on-permanentIdentifier" +#define LN_id_on_permanentIdentifier "Permanent Identifier" +#define NID_id_on_permanentIdentifier 858 +#define OBJ_id_on_permanentIdentifier OBJ_id_on,3L + +#define SN_id_pda_dateOfBirth "id-pda-dateOfBirth" +#define NID_id_pda_dateOfBirth 348 +#define OBJ_id_pda_dateOfBirth OBJ_id_pda,1L + +#define SN_id_pda_placeOfBirth "id-pda-placeOfBirth" +#define NID_id_pda_placeOfBirth 349 +#define OBJ_id_pda_placeOfBirth OBJ_id_pda,2L + +#define SN_id_pda_gender "id-pda-gender" +#define NID_id_pda_gender 351 +#define OBJ_id_pda_gender OBJ_id_pda,3L + +#define SN_id_pda_countryOfCitizenship "id-pda-countryOfCitizenship" +#define NID_id_pda_countryOfCitizenship 352 +#define OBJ_id_pda_countryOfCitizenship OBJ_id_pda,4L + +#define SN_id_pda_countryOfResidence "id-pda-countryOfResidence" +#define NID_id_pda_countryOfResidence 353 +#define OBJ_id_pda_countryOfResidence OBJ_id_pda,5L + +#define SN_id_aca_authenticationInfo "id-aca-authenticationInfo" +#define NID_id_aca_authenticationInfo 354 +#define OBJ_id_aca_authenticationInfo OBJ_id_aca,1L + +#define SN_id_aca_accessIdentity "id-aca-accessIdentity" +#define NID_id_aca_accessIdentity 355 +#define OBJ_id_aca_accessIdentity OBJ_id_aca,2L + +#define SN_id_aca_chargingIdentity "id-aca-chargingIdentity" +#define NID_id_aca_chargingIdentity 356 +#define OBJ_id_aca_chargingIdentity OBJ_id_aca,3L + +#define SN_id_aca_group "id-aca-group" +#define NID_id_aca_group 357 +#define OBJ_id_aca_group OBJ_id_aca,4L + +#define SN_id_aca_role "id-aca-role" +#define NID_id_aca_role 358 +#define OBJ_id_aca_role OBJ_id_aca,5L + +#define SN_id_aca_encAttrs "id-aca-encAttrs" +#define NID_id_aca_encAttrs 399 +#define OBJ_id_aca_encAttrs OBJ_id_aca,6L + +#define SN_id_qcs_pkixQCSyntax_v1 "id-qcs-pkixQCSyntax-v1" +#define NID_id_qcs_pkixQCSyntax_v1 359 +#define OBJ_id_qcs_pkixQCSyntax_v1 OBJ_id_qcs,1L + +#define SN_id_cct_crs "id-cct-crs" +#define NID_id_cct_crs 360 +#define OBJ_id_cct_crs OBJ_id_cct,1L + +#define SN_id_cct_PKIData "id-cct-PKIData" +#define NID_id_cct_PKIData 361 +#define OBJ_id_cct_PKIData OBJ_id_cct,2L + +#define SN_id_cct_PKIResponse "id-cct-PKIResponse" +#define NID_id_cct_PKIResponse 362 +#define OBJ_id_cct_PKIResponse OBJ_id_cct,3L + +#define SN_id_ppl_anyLanguage "id-ppl-anyLanguage" +#define LN_id_ppl_anyLanguage "Any language" +#define NID_id_ppl_anyLanguage 664 +#define OBJ_id_ppl_anyLanguage OBJ_id_ppl,0L + +#define SN_id_ppl_inheritAll "id-ppl-inheritAll" +#define LN_id_ppl_inheritAll "Inherit all" +#define NID_id_ppl_inheritAll 665 +#define OBJ_id_ppl_inheritAll OBJ_id_ppl,1L + +#define SN_Independent "id-ppl-independent" +#define LN_Independent "Independent" +#define NID_Independent 667 +#define OBJ_Independent OBJ_id_ppl,2L + +#define SN_ad_OCSP "OCSP" +#define LN_ad_OCSP "OCSP" +#define NID_ad_OCSP 178 +#define OBJ_ad_OCSP OBJ_id_ad,1L + +#define SN_ad_ca_issuers "caIssuers" +#define LN_ad_ca_issuers "CA Issuers" +#define NID_ad_ca_issuers 179 +#define OBJ_ad_ca_issuers OBJ_id_ad,2L + +#define SN_ad_timeStamping "ad_timestamping" +#define LN_ad_timeStamping "AD Time Stamping" +#define NID_ad_timeStamping 363 +#define OBJ_ad_timeStamping OBJ_id_ad,3L + +#define SN_ad_dvcs "AD_DVCS" +#define LN_ad_dvcs "ad dvcs" +#define NID_ad_dvcs 364 +#define OBJ_ad_dvcs OBJ_id_ad,4L + +#define SN_caRepository "caRepository" +#define LN_caRepository "CA Repository" +#define NID_caRepository 785 +#define OBJ_caRepository OBJ_id_ad,5L + +#define OBJ_id_pkix_OCSP OBJ_ad_OCSP + +#define SN_id_pkix_OCSP_basic "basicOCSPResponse" +#define LN_id_pkix_OCSP_basic "Basic OCSP Response" +#define NID_id_pkix_OCSP_basic 365 +#define OBJ_id_pkix_OCSP_basic OBJ_id_pkix_OCSP,1L + +#define SN_id_pkix_OCSP_Nonce "Nonce" +#define LN_id_pkix_OCSP_Nonce "OCSP Nonce" +#define NID_id_pkix_OCSP_Nonce 366 +#define OBJ_id_pkix_OCSP_Nonce OBJ_id_pkix_OCSP,2L + +#define SN_id_pkix_OCSP_CrlID "CrlID" +#define LN_id_pkix_OCSP_CrlID "OCSP CRL ID" +#define NID_id_pkix_OCSP_CrlID 367 +#define OBJ_id_pkix_OCSP_CrlID OBJ_id_pkix_OCSP,3L + +#define SN_id_pkix_OCSP_acceptableResponses "acceptableResponses" +#define LN_id_pkix_OCSP_acceptableResponses "Acceptable OCSP Responses" +#define NID_id_pkix_OCSP_acceptableResponses 368 +#define OBJ_id_pkix_OCSP_acceptableResponses OBJ_id_pkix_OCSP,4L + +#define SN_id_pkix_OCSP_noCheck "noCheck" +#define LN_id_pkix_OCSP_noCheck "OCSP No Check" +#define NID_id_pkix_OCSP_noCheck 369 +#define OBJ_id_pkix_OCSP_noCheck OBJ_id_pkix_OCSP,5L + +#define SN_id_pkix_OCSP_archiveCutoff "archiveCutoff" +#define LN_id_pkix_OCSP_archiveCutoff "OCSP Archive Cutoff" +#define NID_id_pkix_OCSP_archiveCutoff 370 +#define OBJ_id_pkix_OCSP_archiveCutoff OBJ_id_pkix_OCSP,6L + +#define SN_id_pkix_OCSP_serviceLocator "serviceLocator" +#define LN_id_pkix_OCSP_serviceLocator "OCSP Service Locator" +#define NID_id_pkix_OCSP_serviceLocator 371 +#define OBJ_id_pkix_OCSP_serviceLocator OBJ_id_pkix_OCSP,7L + +#define SN_id_pkix_OCSP_extendedStatus "extendedStatus" +#define LN_id_pkix_OCSP_extendedStatus "Extended OCSP Status" +#define NID_id_pkix_OCSP_extendedStatus 372 +#define OBJ_id_pkix_OCSP_extendedStatus OBJ_id_pkix_OCSP,8L + +#define SN_id_pkix_OCSP_valid "valid" +#define NID_id_pkix_OCSP_valid 373 +#define OBJ_id_pkix_OCSP_valid OBJ_id_pkix_OCSP,9L + +#define SN_id_pkix_OCSP_path "path" +#define NID_id_pkix_OCSP_path 374 +#define OBJ_id_pkix_OCSP_path OBJ_id_pkix_OCSP,10L + +#define SN_id_pkix_OCSP_trustRoot "trustRoot" +#define LN_id_pkix_OCSP_trustRoot "Trust Root" +#define NID_id_pkix_OCSP_trustRoot 375 +#define OBJ_id_pkix_OCSP_trustRoot OBJ_id_pkix_OCSP,11L + +#define SN_algorithm "algorithm" +#define LN_algorithm "algorithm" +#define NID_algorithm 376 +#define OBJ_algorithm 1L,3L,14L,3L,2L + +#define SN_md5WithRSA "RSA-NP-MD5" +#define LN_md5WithRSA "md5WithRSA" +#define NID_md5WithRSA 104 +#define OBJ_md5WithRSA OBJ_algorithm,3L + +#define SN_des_ecb "DES-ECB" +#define LN_des_ecb "des-ecb" +#define NID_des_ecb 29 +#define OBJ_des_ecb OBJ_algorithm,6L + +#define SN_des_cbc "DES-CBC" +#define LN_des_cbc "des-cbc" +#define NID_des_cbc 31 +#define OBJ_des_cbc OBJ_algorithm,7L + +#define SN_des_ofb64 "DES-OFB" +#define LN_des_ofb64 "des-ofb" +#define NID_des_ofb64 45 +#define OBJ_des_ofb64 OBJ_algorithm,8L + +#define SN_des_cfb64 "DES-CFB" +#define LN_des_cfb64 "des-cfb" +#define NID_des_cfb64 30 +#define OBJ_des_cfb64 OBJ_algorithm,9L + +#define SN_rsaSignature "rsaSignature" +#define NID_rsaSignature 377 +#define OBJ_rsaSignature OBJ_algorithm,11L + +#define SN_dsa_2 "DSA-old" +#define LN_dsa_2 "dsaEncryption-old" +#define NID_dsa_2 67 +#define OBJ_dsa_2 OBJ_algorithm,12L + +#define SN_dsaWithSHA "DSA-SHA" +#define LN_dsaWithSHA "dsaWithSHA" +#define NID_dsaWithSHA 66 +#define OBJ_dsaWithSHA OBJ_algorithm,13L + +#define SN_shaWithRSAEncryption "RSA-SHA" +#define LN_shaWithRSAEncryption "shaWithRSAEncryption" +#define NID_shaWithRSAEncryption 42 +#define OBJ_shaWithRSAEncryption OBJ_algorithm,15L + +#define SN_des_ede_ecb "DES-EDE" +#define LN_des_ede_ecb "des-ede" +#define NID_des_ede_ecb 32 +#define OBJ_des_ede_ecb OBJ_algorithm,17L + +#define SN_des_ede3_ecb "DES-EDE3" +#define LN_des_ede3_ecb "des-ede3" +#define NID_des_ede3_ecb 33 + +#define SN_des_ede_cbc "DES-EDE-CBC" +#define LN_des_ede_cbc "des-ede-cbc" +#define NID_des_ede_cbc 43 + +#define SN_des_ede_cfb64 "DES-EDE-CFB" +#define LN_des_ede_cfb64 "des-ede-cfb" +#define NID_des_ede_cfb64 60 + +#define SN_des_ede3_cfb64 "DES-EDE3-CFB" +#define LN_des_ede3_cfb64 "des-ede3-cfb" +#define NID_des_ede3_cfb64 61 + +#define SN_des_ede_ofb64 "DES-EDE-OFB" +#define LN_des_ede_ofb64 "des-ede-ofb" +#define NID_des_ede_ofb64 62 + +#define SN_des_ede3_ofb64 "DES-EDE3-OFB" +#define LN_des_ede3_ofb64 "des-ede3-ofb" +#define NID_des_ede3_ofb64 63 + +#define SN_desx_cbc "DESX-CBC" +#define LN_desx_cbc "desx-cbc" +#define NID_desx_cbc 80 + +#define SN_sha "SHA" +#define LN_sha "sha" +#define NID_sha 41 +#define OBJ_sha OBJ_algorithm,18L + +#define SN_sha1 "SHA1" +#define LN_sha1 "sha1" +#define NID_sha1 64 +#define OBJ_sha1 OBJ_algorithm,26L + +#define SN_dsaWithSHA1_2 "DSA-SHA1-old" +#define LN_dsaWithSHA1_2 "dsaWithSHA1-old" +#define NID_dsaWithSHA1_2 70 +#define OBJ_dsaWithSHA1_2 OBJ_algorithm,27L + +#define SN_sha1WithRSA "RSA-SHA1-2" +#define LN_sha1WithRSA "sha1WithRSA" +#define NID_sha1WithRSA 115 +#define OBJ_sha1WithRSA OBJ_algorithm,29L + +#define SN_ripemd160 "RIPEMD160" +#define LN_ripemd160 "ripemd160" +#define NID_ripemd160 117 +#define OBJ_ripemd160 1L,3L,36L,3L,2L,1L + +#define SN_ripemd160WithRSA "RSA-RIPEMD160" +#define LN_ripemd160WithRSA "ripemd160WithRSA" +#define NID_ripemd160WithRSA 119 +#define OBJ_ripemd160WithRSA 1L,3L,36L,3L,3L,1L,2L + +#define SN_sxnet "SXNetID" +#define LN_sxnet "Strong Extranet ID" +#define NID_sxnet 143 +#define OBJ_sxnet 1L,3L,101L,1L,4L,1L + +#define SN_X500 "X500" +#define LN_X500 "directory services (X.500)" +#define NID_X500 11 +#define OBJ_X500 2L,5L + +#define SN_X509 "X509" +#define NID_X509 12 +#define OBJ_X509 OBJ_X500,4L + +#define SN_commonName "CN" +#define LN_commonName "commonName" +#define NID_commonName 13 +#define OBJ_commonName OBJ_X509,3L + +#define SN_surname "SN" +#define LN_surname "surname" +#define NID_surname 100 +#define OBJ_surname OBJ_X509,4L + +#define LN_serialNumber "serialNumber" +#define NID_serialNumber 105 +#define OBJ_serialNumber OBJ_X509,5L + +#define SN_countryName "C" +#define LN_countryName "countryName" +#define NID_countryName 14 +#define OBJ_countryName OBJ_X509,6L + +#define SN_localityName "L" +#define LN_localityName "localityName" +#define NID_localityName 15 +#define OBJ_localityName OBJ_X509,7L + +#define SN_stateOrProvinceName "ST" +#define LN_stateOrProvinceName "stateOrProvinceName" +#define NID_stateOrProvinceName 16 +#define OBJ_stateOrProvinceName OBJ_X509,8L + +#define SN_streetAddress "street" +#define LN_streetAddress "streetAddress" +#define NID_streetAddress 660 +#define OBJ_streetAddress OBJ_X509,9L + +#define SN_organizationName "O" +#define LN_organizationName "organizationName" +#define NID_organizationName 17 +#define OBJ_organizationName OBJ_X509,10L + +#define SN_organizationalUnitName "OU" +#define LN_organizationalUnitName "organizationalUnitName" +#define NID_organizationalUnitName 18 +#define OBJ_organizationalUnitName OBJ_X509,11L + +#define SN_title "title" +#define LN_title "title" +#define NID_title 106 +#define OBJ_title OBJ_X509,12L + +#define LN_description "description" +#define NID_description 107 +#define OBJ_description OBJ_X509,13L + +#define LN_searchGuide "searchGuide" +#define NID_searchGuide 859 +#define OBJ_searchGuide OBJ_X509,14L + +#define LN_businessCategory "businessCategory" +#define NID_businessCategory 860 +#define OBJ_businessCategory OBJ_X509,15L + +#define LN_postalAddress "postalAddress" +#define NID_postalAddress 861 +#define OBJ_postalAddress OBJ_X509,16L + +#define LN_postalCode "postalCode" +#define NID_postalCode 661 +#define OBJ_postalCode OBJ_X509,17L + +#define LN_postOfficeBox "postOfficeBox" +#define NID_postOfficeBox 862 +#define OBJ_postOfficeBox OBJ_X509,18L + +#define LN_physicalDeliveryOfficeName "physicalDeliveryOfficeName" +#define NID_physicalDeliveryOfficeName 863 +#define OBJ_physicalDeliveryOfficeName OBJ_X509,19L + +#define LN_telephoneNumber "telephoneNumber" +#define NID_telephoneNumber 864 +#define OBJ_telephoneNumber OBJ_X509,20L + +#define LN_telexNumber "telexNumber" +#define NID_telexNumber 865 +#define OBJ_telexNumber OBJ_X509,21L + +#define LN_teletexTerminalIdentifier "teletexTerminalIdentifier" +#define NID_teletexTerminalIdentifier 866 +#define OBJ_teletexTerminalIdentifier OBJ_X509,22L + +#define LN_facsimileTelephoneNumber "facsimileTelephoneNumber" +#define NID_facsimileTelephoneNumber 867 +#define OBJ_facsimileTelephoneNumber OBJ_X509,23L + +#define LN_x121Address "x121Address" +#define NID_x121Address 868 +#define OBJ_x121Address OBJ_X509,24L + +#define LN_internationaliSDNNumber "internationaliSDNNumber" +#define NID_internationaliSDNNumber 869 +#define OBJ_internationaliSDNNumber OBJ_X509,25L + +#define LN_registeredAddress "registeredAddress" +#define NID_registeredAddress 870 +#define OBJ_registeredAddress OBJ_X509,26L + +#define LN_destinationIndicator "destinationIndicator" +#define NID_destinationIndicator 871 +#define OBJ_destinationIndicator OBJ_X509,27L + +#define LN_preferredDeliveryMethod "preferredDeliveryMethod" +#define NID_preferredDeliveryMethod 872 +#define OBJ_preferredDeliveryMethod OBJ_X509,28L + +#define LN_presentationAddress "presentationAddress" +#define NID_presentationAddress 873 +#define OBJ_presentationAddress OBJ_X509,29L + +#define LN_supportedApplicationContext "supportedApplicationContext" +#define NID_supportedApplicationContext 874 +#define OBJ_supportedApplicationContext OBJ_X509,30L + +#define SN_member "member" +#define NID_member 875 +#define OBJ_member OBJ_X509,31L + +#define SN_owner "owner" +#define NID_owner 876 +#define OBJ_owner OBJ_X509,32L + +#define LN_roleOccupant "roleOccupant" +#define NID_roleOccupant 877 +#define OBJ_roleOccupant OBJ_X509,33L + +#define SN_seeAlso "seeAlso" +#define NID_seeAlso 878 +#define OBJ_seeAlso OBJ_X509,34L + +#define LN_userPassword "userPassword" +#define NID_userPassword 879 +#define OBJ_userPassword OBJ_X509,35L + +#define LN_userCertificate "userCertificate" +#define NID_userCertificate 880 +#define OBJ_userCertificate OBJ_X509,36L + +#define LN_cACertificate "cACertificate" +#define NID_cACertificate 881 +#define OBJ_cACertificate OBJ_X509,37L + +#define LN_authorityRevocationList "authorityRevocationList" +#define NID_authorityRevocationList 882 +#define OBJ_authorityRevocationList OBJ_X509,38L + +#define LN_certificateRevocationList "certificateRevocationList" +#define NID_certificateRevocationList 883 +#define OBJ_certificateRevocationList OBJ_X509,39L + +#define LN_crossCertificatePair "crossCertificatePair" +#define NID_crossCertificatePair 884 +#define OBJ_crossCertificatePair OBJ_X509,40L + +#define SN_name "name" +#define LN_name "name" +#define NID_name 173 +#define OBJ_name OBJ_X509,41L + +#define SN_givenName "GN" +#define LN_givenName "givenName" +#define NID_givenName 99 +#define OBJ_givenName OBJ_X509,42L + +#define SN_initials "initials" +#define LN_initials "initials" +#define NID_initials 101 +#define OBJ_initials OBJ_X509,43L + +#define LN_generationQualifier "generationQualifier" +#define NID_generationQualifier 509 +#define OBJ_generationQualifier OBJ_X509,44L + +#define LN_x500UniqueIdentifier "x500UniqueIdentifier" +#define NID_x500UniqueIdentifier 503 +#define OBJ_x500UniqueIdentifier OBJ_X509,45L + +#define SN_dnQualifier "dnQualifier" +#define LN_dnQualifier "dnQualifier" +#define NID_dnQualifier 174 +#define OBJ_dnQualifier OBJ_X509,46L + +#define LN_enhancedSearchGuide "enhancedSearchGuide" +#define NID_enhancedSearchGuide 885 +#define OBJ_enhancedSearchGuide OBJ_X509,47L + +#define LN_protocolInformation "protocolInformation" +#define NID_protocolInformation 886 +#define OBJ_protocolInformation OBJ_X509,48L + +#define LN_distinguishedName "distinguishedName" +#define NID_distinguishedName 887 +#define OBJ_distinguishedName OBJ_X509,49L + +#define LN_uniqueMember "uniqueMember" +#define NID_uniqueMember 888 +#define OBJ_uniqueMember OBJ_X509,50L + +#define LN_houseIdentifier "houseIdentifier" +#define NID_houseIdentifier 889 +#define OBJ_houseIdentifier OBJ_X509,51L + +#define LN_supportedAlgorithms "supportedAlgorithms" +#define NID_supportedAlgorithms 890 +#define OBJ_supportedAlgorithms OBJ_X509,52L + +#define LN_deltaRevocationList "deltaRevocationList" +#define NID_deltaRevocationList 891 +#define OBJ_deltaRevocationList OBJ_X509,53L + +#define SN_dmdName "dmdName" +#define NID_dmdName 892 +#define OBJ_dmdName OBJ_X509,54L + +#define LN_pseudonym "pseudonym" +#define NID_pseudonym 510 +#define OBJ_pseudonym OBJ_X509,65L + +#define SN_role "role" +#define LN_role "role" +#define NID_role 400 +#define OBJ_role OBJ_X509,72L + +#define SN_X500algorithms "X500algorithms" +#define LN_X500algorithms "directory services - algorithms" +#define NID_X500algorithms 378 +#define OBJ_X500algorithms OBJ_X500,8L + +#define SN_rsa "RSA" +#define LN_rsa "rsa" +#define NID_rsa 19 +#define OBJ_rsa OBJ_X500algorithms,1L,1L + +#define SN_mdc2WithRSA "RSA-MDC2" +#define LN_mdc2WithRSA "mdc2WithRSA" +#define NID_mdc2WithRSA 96 +#define OBJ_mdc2WithRSA OBJ_X500algorithms,3L,100L + +#define SN_mdc2 "MDC2" +#define LN_mdc2 "mdc2" +#define NID_mdc2 95 +#define OBJ_mdc2 OBJ_X500algorithms,3L,101L + +#define SN_id_ce "id-ce" +#define NID_id_ce 81 +#define OBJ_id_ce OBJ_X500,29L + +#define SN_subject_directory_attributes "subjectDirectoryAttributes" +#define LN_subject_directory_attributes "X509v3 Subject Directory Attributes" +#define NID_subject_directory_attributes 769 +#define OBJ_subject_directory_attributes OBJ_id_ce,9L + +#define SN_subject_key_identifier "subjectKeyIdentifier" +#define LN_subject_key_identifier "X509v3 Subject Key Identifier" +#define NID_subject_key_identifier 82 +#define OBJ_subject_key_identifier OBJ_id_ce,14L + +#define SN_key_usage "keyUsage" +#define LN_key_usage "X509v3 Key Usage" +#define NID_key_usage 83 +#define OBJ_key_usage OBJ_id_ce,15L + +#define SN_private_key_usage_period "privateKeyUsagePeriod" +#define LN_private_key_usage_period "X509v3 Private Key Usage Period" +#define NID_private_key_usage_period 84 +#define OBJ_private_key_usage_period OBJ_id_ce,16L + +#define SN_subject_alt_name "subjectAltName" +#define LN_subject_alt_name "X509v3 Subject Alternative Name" +#define NID_subject_alt_name 85 +#define OBJ_subject_alt_name OBJ_id_ce,17L + +#define SN_issuer_alt_name "issuerAltName" +#define LN_issuer_alt_name "X509v3 Issuer Alternative Name" +#define NID_issuer_alt_name 86 +#define OBJ_issuer_alt_name OBJ_id_ce,18L + +#define SN_basic_constraints "basicConstraints" +#define LN_basic_constraints "X509v3 Basic Constraints" +#define NID_basic_constraints 87 +#define OBJ_basic_constraints OBJ_id_ce,19L + +#define SN_crl_number "crlNumber" +#define LN_crl_number "X509v3 CRL Number" +#define NID_crl_number 88 +#define OBJ_crl_number OBJ_id_ce,20L + +#define SN_crl_reason "CRLReason" +#define LN_crl_reason "X509v3 CRL Reason Code" +#define NID_crl_reason 141 +#define OBJ_crl_reason OBJ_id_ce,21L + +#define SN_invalidity_date "invalidityDate" +#define LN_invalidity_date "Invalidity Date" +#define NID_invalidity_date 142 +#define OBJ_invalidity_date OBJ_id_ce,24L + +#define SN_delta_crl "deltaCRL" +#define LN_delta_crl "X509v3 Delta CRL Indicator" +#define NID_delta_crl 140 +#define OBJ_delta_crl OBJ_id_ce,27L + +#define SN_issuing_distribution_point "issuingDistributionPoint" +#define LN_issuing_distribution_point "X509v3 Issuing Distribution Point" +#define NID_issuing_distribution_point 770 +#define OBJ_issuing_distribution_point OBJ_id_ce,28L + +#define SN_certificate_issuer "certificateIssuer" +#define LN_certificate_issuer "X509v3 Certificate Issuer" +#define NID_certificate_issuer 771 +#define OBJ_certificate_issuer OBJ_id_ce,29L + +#define SN_name_constraints "nameConstraints" +#define LN_name_constraints "X509v3 Name Constraints" +#define NID_name_constraints 666 +#define OBJ_name_constraints OBJ_id_ce,30L + +#define SN_crl_distribution_points "crlDistributionPoints" +#define LN_crl_distribution_points "X509v3 CRL Distribution Points" +#define NID_crl_distribution_points 103 +#define OBJ_crl_distribution_points OBJ_id_ce,31L + +#define SN_certificate_policies "certificatePolicies" +#define LN_certificate_policies "X509v3 Certificate Policies" +#define NID_certificate_policies 89 +#define OBJ_certificate_policies OBJ_id_ce,32L + +#define SN_any_policy "anyPolicy" +#define LN_any_policy "X509v3 Any Policy" +#define NID_any_policy 746 +#define OBJ_any_policy OBJ_certificate_policies,0L + +#define SN_policy_mappings "policyMappings" +#define LN_policy_mappings "X509v3 Policy Mappings" +#define NID_policy_mappings 747 +#define OBJ_policy_mappings OBJ_id_ce,33L + +#define SN_authority_key_identifier "authorityKeyIdentifier" +#define LN_authority_key_identifier "X509v3 Authority Key Identifier" +#define NID_authority_key_identifier 90 +#define OBJ_authority_key_identifier OBJ_id_ce,35L + +#define SN_policy_constraints "policyConstraints" +#define LN_policy_constraints "X509v3 Policy Constraints" +#define NID_policy_constraints 401 +#define OBJ_policy_constraints OBJ_id_ce,36L + +#define SN_ext_key_usage "extendedKeyUsage" +#define LN_ext_key_usage "X509v3 Extended Key Usage" +#define NID_ext_key_usage 126 +#define OBJ_ext_key_usage OBJ_id_ce,37L + +#define SN_freshest_crl "freshestCRL" +#define LN_freshest_crl "X509v3 Freshest CRL" +#define NID_freshest_crl 857 +#define OBJ_freshest_crl OBJ_id_ce,46L + +#define SN_inhibit_any_policy "inhibitAnyPolicy" +#define LN_inhibit_any_policy "X509v3 Inhibit Any Policy" +#define NID_inhibit_any_policy 748 +#define OBJ_inhibit_any_policy OBJ_id_ce,54L + +#define SN_target_information "targetInformation" +#define LN_target_information "X509v3 AC Targeting" +#define NID_target_information 402 +#define OBJ_target_information OBJ_id_ce,55L + +#define SN_no_rev_avail "noRevAvail" +#define LN_no_rev_avail "X509v3 No Revocation Available" +#define NID_no_rev_avail 403 +#define OBJ_no_rev_avail OBJ_id_ce,56L + +#define SN_anyExtendedKeyUsage "anyExtendedKeyUsage" +#define LN_anyExtendedKeyUsage "Any Extended Key Usage" +#define NID_anyExtendedKeyUsage 910 +#define OBJ_anyExtendedKeyUsage OBJ_ext_key_usage,0L + +#define SN_netscape "Netscape" +#define LN_netscape "Netscape Communications Corp." +#define NID_netscape 57 +#define OBJ_netscape 2L,16L,840L,1L,113730L + +#define SN_netscape_cert_extension "nsCertExt" +#define LN_netscape_cert_extension "Netscape Certificate Extension" +#define NID_netscape_cert_extension 58 +#define OBJ_netscape_cert_extension OBJ_netscape,1L + +#define SN_netscape_data_type "nsDataType" +#define LN_netscape_data_type "Netscape Data Type" +#define NID_netscape_data_type 59 +#define OBJ_netscape_data_type OBJ_netscape,2L + +#define SN_netscape_cert_type "nsCertType" +#define LN_netscape_cert_type "Netscape Cert Type" +#define NID_netscape_cert_type 71 +#define OBJ_netscape_cert_type OBJ_netscape_cert_extension,1L + +#define SN_netscape_base_url "nsBaseUrl" +#define LN_netscape_base_url "Netscape Base Url" +#define NID_netscape_base_url 72 +#define OBJ_netscape_base_url OBJ_netscape_cert_extension,2L + +#define SN_netscape_revocation_url "nsRevocationUrl" +#define LN_netscape_revocation_url "Netscape Revocation Url" +#define NID_netscape_revocation_url 73 +#define OBJ_netscape_revocation_url OBJ_netscape_cert_extension,3L + +#define SN_netscape_ca_revocation_url "nsCaRevocationUrl" +#define LN_netscape_ca_revocation_url "Netscape CA Revocation Url" +#define NID_netscape_ca_revocation_url 74 +#define OBJ_netscape_ca_revocation_url OBJ_netscape_cert_extension,4L + +#define SN_netscape_renewal_url "nsRenewalUrl" +#define LN_netscape_renewal_url "Netscape Renewal Url" +#define NID_netscape_renewal_url 75 +#define OBJ_netscape_renewal_url OBJ_netscape_cert_extension,7L + +#define SN_netscape_ca_policy_url "nsCaPolicyUrl" +#define LN_netscape_ca_policy_url "Netscape CA Policy Url" +#define NID_netscape_ca_policy_url 76 +#define OBJ_netscape_ca_policy_url OBJ_netscape_cert_extension,8L + +#define SN_netscape_ssl_server_name "nsSslServerName" +#define LN_netscape_ssl_server_name "Netscape SSL Server Name" +#define NID_netscape_ssl_server_name 77 +#define OBJ_netscape_ssl_server_name OBJ_netscape_cert_extension,12L + +#define SN_netscape_comment "nsComment" +#define LN_netscape_comment "Netscape Comment" +#define NID_netscape_comment 78 +#define OBJ_netscape_comment OBJ_netscape_cert_extension,13L + +#define SN_netscape_cert_sequence "nsCertSequence" +#define LN_netscape_cert_sequence "Netscape Certificate Sequence" +#define NID_netscape_cert_sequence 79 +#define OBJ_netscape_cert_sequence OBJ_netscape_data_type,5L + +#define SN_ns_sgc "nsSGC" +#define LN_ns_sgc "Netscape Server Gated Crypto" +#define NID_ns_sgc 139 +#define OBJ_ns_sgc OBJ_netscape,4L,1L + +#define SN_org "ORG" +#define LN_org "org" +#define NID_org 379 +#define OBJ_org OBJ_iso,3L + +#define SN_dod "DOD" +#define LN_dod "dod" +#define NID_dod 380 +#define OBJ_dod OBJ_org,6L + +#define SN_iana "IANA" +#define LN_iana "iana" +#define NID_iana 381 +#define OBJ_iana OBJ_dod,1L + +#define OBJ_internet OBJ_iana + +#define SN_Directory "directory" +#define LN_Directory "Directory" +#define NID_Directory 382 +#define OBJ_Directory OBJ_internet,1L + +#define SN_Management "mgmt" +#define LN_Management "Management" +#define NID_Management 383 +#define OBJ_Management OBJ_internet,2L + +#define SN_Experimental "experimental" +#define LN_Experimental "Experimental" +#define NID_Experimental 384 +#define OBJ_Experimental OBJ_internet,3L + +#define SN_Private "private" +#define LN_Private "Private" +#define NID_Private 385 +#define OBJ_Private OBJ_internet,4L + +#define SN_Security "security" +#define LN_Security "Security" +#define NID_Security 386 +#define OBJ_Security OBJ_internet,5L + +#define SN_SNMPv2 "snmpv2" +#define LN_SNMPv2 "SNMPv2" +#define NID_SNMPv2 387 +#define OBJ_SNMPv2 OBJ_internet,6L + +#define LN_Mail "Mail" +#define NID_Mail 388 +#define OBJ_Mail OBJ_internet,7L + +#define SN_Enterprises "enterprises" +#define LN_Enterprises "Enterprises" +#define NID_Enterprises 389 +#define OBJ_Enterprises OBJ_Private,1L + +#define SN_dcObject "dcobject" +#define LN_dcObject "dcObject" +#define NID_dcObject 390 +#define OBJ_dcObject OBJ_Enterprises,1466L,344L + +#define SN_mime_mhs "mime-mhs" +#define LN_mime_mhs "MIME MHS" +#define NID_mime_mhs 504 +#define OBJ_mime_mhs OBJ_Mail,1L + +#define SN_mime_mhs_headings "mime-mhs-headings" +#define LN_mime_mhs_headings "mime-mhs-headings" +#define NID_mime_mhs_headings 505 +#define OBJ_mime_mhs_headings OBJ_mime_mhs,1L + +#define SN_mime_mhs_bodies "mime-mhs-bodies" +#define LN_mime_mhs_bodies "mime-mhs-bodies" +#define NID_mime_mhs_bodies 506 +#define OBJ_mime_mhs_bodies OBJ_mime_mhs,2L + +#define SN_id_hex_partial_message "id-hex-partial-message" +#define LN_id_hex_partial_message "id-hex-partial-message" +#define NID_id_hex_partial_message 507 +#define OBJ_id_hex_partial_message OBJ_mime_mhs_headings,1L + +#define SN_id_hex_multipart_message "id-hex-multipart-message" +#define LN_id_hex_multipart_message "id-hex-multipart-message" +#define NID_id_hex_multipart_message 508 +#define OBJ_id_hex_multipart_message OBJ_mime_mhs_headings,2L + +#define SN_zlib_compression "ZLIB" +#define LN_zlib_compression "zlib compression" +#define NID_zlib_compression 125 +#define OBJ_zlib_compression OBJ_id_smime_alg,8L + +#define OBJ_csor 2L,16L,840L,1L,101L,3L + +#define OBJ_nistAlgorithms OBJ_csor,4L + +#define OBJ_aes OBJ_nistAlgorithms,1L + +#define SN_aes_128_ecb "AES-128-ECB" +#define LN_aes_128_ecb "aes-128-ecb" +#define NID_aes_128_ecb 418 +#define OBJ_aes_128_ecb OBJ_aes,1L + +#define SN_aes_128_cbc "AES-128-CBC" +#define LN_aes_128_cbc "aes-128-cbc" +#define NID_aes_128_cbc 419 +#define OBJ_aes_128_cbc OBJ_aes,2L + +#define SN_aes_128_ofb128 "AES-128-OFB" +#define LN_aes_128_ofb128 "aes-128-ofb" +#define NID_aes_128_ofb128 420 +#define OBJ_aes_128_ofb128 OBJ_aes,3L + +#define SN_aes_128_cfb128 "AES-128-CFB" +#define LN_aes_128_cfb128 "aes-128-cfb" +#define NID_aes_128_cfb128 421 +#define OBJ_aes_128_cfb128 OBJ_aes,4L + +#define SN_id_aes128_wrap "id-aes128-wrap" +#define NID_id_aes128_wrap 788 +#define OBJ_id_aes128_wrap OBJ_aes,5L + +#define SN_aes_128_gcm "id-aes128-GCM" +#define LN_aes_128_gcm "aes-128-gcm" +#define NID_aes_128_gcm 895 +#define OBJ_aes_128_gcm OBJ_aes,6L + +#define SN_aes_128_ccm "id-aes128-CCM" +#define LN_aes_128_ccm "aes-128-ccm" +#define NID_aes_128_ccm 896 +#define OBJ_aes_128_ccm OBJ_aes,7L + +#define SN_id_aes128_wrap_pad "id-aes128-wrap-pad" +#define NID_id_aes128_wrap_pad 897 +#define OBJ_id_aes128_wrap_pad OBJ_aes,8L + +#define SN_aes_192_ecb "AES-192-ECB" +#define LN_aes_192_ecb "aes-192-ecb" +#define NID_aes_192_ecb 422 +#define OBJ_aes_192_ecb OBJ_aes,21L + +#define SN_aes_192_cbc "AES-192-CBC" +#define LN_aes_192_cbc "aes-192-cbc" +#define NID_aes_192_cbc 423 +#define OBJ_aes_192_cbc OBJ_aes,22L + +#define SN_aes_192_ofb128 "AES-192-OFB" +#define LN_aes_192_ofb128 "aes-192-ofb" +#define NID_aes_192_ofb128 424 +#define OBJ_aes_192_ofb128 OBJ_aes,23L + +#define SN_aes_192_cfb128 "AES-192-CFB" +#define LN_aes_192_cfb128 "aes-192-cfb" +#define NID_aes_192_cfb128 425 +#define OBJ_aes_192_cfb128 OBJ_aes,24L + +#define SN_id_aes192_wrap "id-aes192-wrap" +#define NID_id_aes192_wrap 789 +#define OBJ_id_aes192_wrap OBJ_aes,25L + +#define SN_aes_192_gcm "id-aes192-GCM" +#define LN_aes_192_gcm "aes-192-gcm" +#define NID_aes_192_gcm 898 +#define OBJ_aes_192_gcm OBJ_aes,26L + +#define SN_aes_192_ccm "id-aes192-CCM" +#define LN_aes_192_ccm "aes-192-ccm" +#define NID_aes_192_ccm 899 +#define OBJ_aes_192_ccm OBJ_aes,27L + +#define SN_id_aes192_wrap_pad "id-aes192-wrap-pad" +#define NID_id_aes192_wrap_pad 900 +#define OBJ_id_aes192_wrap_pad OBJ_aes,28L + +#define SN_aes_256_ecb "AES-256-ECB" +#define LN_aes_256_ecb "aes-256-ecb" +#define NID_aes_256_ecb 426 +#define OBJ_aes_256_ecb OBJ_aes,41L + +#define SN_aes_256_cbc "AES-256-CBC" +#define LN_aes_256_cbc "aes-256-cbc" +#define NID_aes_256_cbc 427 +#define OBJ_aes_256_cbc OBJ_aes,42L + +#define SN_aes_256_ofb128 "AES-256-OFB" +#define LN_aes_256_ofb128 "aes-256-ofb" +#define NID_aes_256_ofb128 428 +#define OBJ_aes_256_ofb128 OBJ_aes,43L + +#define SN_aes_256_cfb128 "AES-256-CFB" +#define LN_aes_256_cfb128 "aes-256-cfb" +#define NID_aes_256_cfb128 429 +#define OBJ_aes_256_cfb128 OBJ_aes,44L + +#define SN_id_aes256_wrap "id-aes256-wrap" +#define NID_id_aes256_wrap 790 +#define OBJ_id_aes256_wrap OBJ_aes,45L + +#define SN_aes_256_gcm "id-aes256-GCM" +#define LN_aes_256_gcm "aes-256-gcm" +#define NID_aes_256_gcm 901 +#define OBJ_aes_256_gcm OBJ_aes,46L + +#define SN_aes_256_ccm "id-aes256-CCM" +#define LN_aes_256_ccm "aes-256-ccm" +#define NID_aes_256_ccm 902 +#define OBJ_aes_256_ccm OBJ_aes,47L + +#define SN_id_aes256_wrap_pad "id-aes256-wrap-pad" +#define NID_id_aes256_wrap_pad 903 +#define OBJ_id_aes256_wrap_pad OBJ_aes,48L + +#define SN_aes_128_cfb1 "AES-128-CFB1" +#define LN_aes_128_cfb1 "aes-128-cfb1" +#define NID_aes_128_cfb1 650 + +#define SN_aes_192_cfb1 "AES-192-CFB1" +#define LN_aes_192_cfb1 "aes-192-cfb1" +#define NID_aes_192_cfb1 651 + +#define SN_aes_256_cfb1 "AES-256-CFB1" +#define LN_aes_256_cfb1 "aes-256-cfb1" +#define NID_aes_256_cfb1 652 + +#define SN_aes_128_cfb8 "AES-128-CFB8" +#define LN_aes_128_cfb8 "aes-128-cfb8" +#define NID_aes_128_cfb8 653 + +#define SN_aes_192_cfb8 "AES-192-CFB8" +#define LN_aes_192_cfb8 "aes-192-cfb8" +#define NID_aes_192_cfb8 654 + +#define SN_aes_256_cfb8 "AES-256-CFB8" +#define LN_aes_256_cfb8 "aes-256-cfb8" +#define NID_aes_256_cfb8 655 + +#define SN_aes_128_ctr "AES-128-CTR" +#define LN_aes_128_ctr "aes-128-ctr" +#define NID_aes_128_ctr 904 + +#define SN_aes_192_ctr "AES-192-CTR" +#define LN_aes_192_ctr "aes-192-ctr" +#define NID_aes_192_ctr 905 + +#define SN_aes_256_ctr "AES-256-CTR" +#define LN_aes_256_ctr "aes-256-ctr" +#define NID_aes_256_ctr 906 + +#define SN_aes_128_xts "AES-128-XTS" +#define LN_aes_128_xts "aes-128-xts" +#define NID_aes_128_xts 913 + +#define SN_aes_256_xts "AES-256-XTS" +#define LN_aes_256_xts "aes-256-xts" +#define NID_aes_256_xts 914 + +#define SN_des_cfb1 "DES-CFB1" +#define LN_des_cfb1 "des-cfb1" +#define NID_des_cfb1 656 + +#define SN_des_cfb8 "DES-CFB8" +#define LN_des_cfb8 "des-cfb8" +#define NID_des_cfb8 657 + +#define SN_des_ede3_cfb1 "DES-EDE3-CFB1" +#define LN_des_ede3_cfb1 "des-ede3-cfb1" +#define NID_des_ede3_cfb1 658 + +#define SN_des_ede3_cfb8 "DES-EDE3-CFB8" +#define LN_des_ede3_cfb8 "des-ede3-cfb8" +#define NID_des_ede3_cfb8 659 + +#define OBJ_nist_hashalgs OBJ_nistAlgorithms,2L + +#define SN_sha256 "SHA256" +#define LN_sha256 "sha256" +#define NID_sha256 672 +#define OBJ_sha256 OBJ_nist_hashalgs,1L + +#define SN_sha384 "SHA384" +#define LN_sha384 "sha384" +#define NID_sha384 673 +#define OBJ_sha384 OBJ_nist_hashalgs,2L + +#define SN_sha512 "SHA512" +#define LN_sha512 "sha512" +#define NID_sha512 674 +#define OBJ_sha512 OBJ_nist_hashalgs,3L + +#define SN_sha224 "SHA224" +#define LN_sha224 "sha224" +#define NID_sha224 675 +#define OBJ_sha224 OBJ_nist_hashalgs,4L + +#define OBJ_dsa_with_sha2 OBJ_nistAlgorithms,3L + +#define SN_dsa_with_SHA224 "dsa_with_SHA224" +#define NID_dsa_with_SHA224 802 +#define OBJ_dsa_with_SHA224 OBJ_dsa_with_sha2,1L + +#define SN_dsa_with_SHA256 "dsa_with_SHA256" +#define NID_dsa_with_SHA256 803 +#define OBJ_dsa_with_SHA256 OBJ_dsa_with_sha2,2L + +#define SN_hold_instruction_code "holdInstructionCode" +#define LN_hold_instruction_code "Hold Instruction Code" +#define NID_hold_instruction_code 430 +#define OBJ_hold_instruction_code OBJ_id_ce,23L + +#define OBJ_holdInstruction OBJ_X9_57,2L + +#define SN_hold_instruction_none "holdInstructionNone" +#define LN_hold_instruction_none "Hold Instruction None" +#define NID_hold_instruction_none 431 +#define OBJ_hold_instruction_none OBJ_holdInstruction,1L + +#define SN_hold_instruction_call_issuer "holdInstructionCallIssuer" +#define LN_hold_instruction_call_issuer "Hold Instruction Call Issuer" +#define NID_hold_instruction_call_issuer 432 +#define OBJ_hold_instruction_call_issuer OBJ_holdInstruction,2L + +#define SN_hold_instruction_reject "holdInstructionReject" +#define LN_hold_instruction_reject "Hold Instruction Reject" +#define NID_hold_instruction_reject 433 +#define OBJ_hold_instruction_reject OBJ_holdInstruction,3L + +#define SN_data "data" +#define NID_data 434 +#define OBJ_data OBJ_itu_t,9L + +#define SN_pss "pss" +#define NID_pss 435 +#define OBJ_pss OBJ_data,2342L + +#define SN_ucl "ucl" +#define NID_ucl 436 +#define OBJ_ucl OBJ_pss,19200300L + +#define SN_pilot "pilot" +#define NID_pilot 437 +#define OBJ_pilot OBJ_ucl,100L + +#define LN_pilotAttributeType "pilotAttributeType" +#define NID_pilotAttributeType 438 +#define OBJ_pilotAttributeType OBJ_pilot,1L + +#define LN_pilotAttributeSyntax "pilotAttributeSyntax" +#define NID_pilotAttributeSyntax 439 +#define OBJ_pilotAttributeSyntax OBJ_pilot,3L + +#define LN_pilotObjectClass "pilotObjectClass" +#define NID_pilotObjectClass 440 +#define OBJ_pilotObjectClass OBJ_pilot,4L + +#define LN_pilotGroups "pilotGroups" +#define NID_pilotGroups 441 +#define OBJ_pilotGroups OBJ_pilot,10L + +#define LN_iA5StringSyntax "iA5StringSyntax" +#define NID_iA5StringSyntax 442 +#define OBJ_iA5StringSyntax OBJ_pilotAttributeSyntax,4L + +#define LN_caseIgnoreIA5StringSyntax "caseIgnoreIA5StringSyntax" +#define NID_caseIgnoreIA5StringSyntax 443 +#define OBJ_caseIgnoreIA5StringSyntax OBJ_pilotAttributeSyntax,5L + +#define LN_pilotObject "pilotObject" +#define NID_pilotObject 444 +#define OBJ_pilotObject OBJ_pilotObjectClass,3L + +#define LN_pilotPerson "pilotPerson" +#define NID_pilotPerson 445 +#define OBJ_pilotPerson OBJ_pilotObjectClass,4L + +#define SN_account "account" +#define NID_account 446 +#define OBJ_account OBJ_pilotObjectClass,5L + +#define SN_document "document" +#define NID_document 447 +#define OBJ_document OBJ_pilotObjectClass,6L + +#define SN_room "room" +#define NID_room 448 +#define OBJ_room OBJ_pilotObjectClass,7L + +#define LN_documentSeries "documentSeries" +#define NID_documentSeries 449 +#define OBJ_documentSeries OBJ_pilotObjectClass,9L + +#define SN_Domain "domain" +#define LN_Domain "Domain" +#define NID_Domain 392 +#define OBJ_Domain OBJ_pilotObjectClass,13L + +#define LN_rFC822localPart "rFC822localPart" +#define NID_rFC822localPart 450 +#define OBJ_rFC822localPart OBJ_pilotObjectClass,14L + +#define LN_dNSDomain "dNSDomain" +#define NID_dNSDomain 451 +#define OBJ_dNSDomain OBJ_pilotObjectClass,15L + +#define LN_domainRelatedObject "domainRelatedObject" +#define NID_domainRelatedObject 452 +#define OBJ_domainRelatedObject OBJ_pilotObjectClass,17L + +#define LN_friendlyCountry "friendlyCountry" +#define NID_friendlyCountry 453 +#define OBJ_friendlyCountry OBJ_pilotObjectClass,18L + +#define LN_simpleSecurityObject "simpleSecurityObject" +#define NID_simpleSecurityObject 454 +#define OBJ_simpleSecurityObject OBJ_pilotObjectClass,19L + +#define LN_pilotOrganization "pilotOrganization" +#define NID_pilotOrganization 455 +#define OBJ_pilotOrganization OBJ_pilotObjectClass,20L + +#define LN_pilotDSA "pilotDSA" +#define NID_pilotDSA 456 +#define OBJ_pilotDSA OBJ_pilotObjectClass,21L + +#define LN_qualityLabelledData "qualityLabelledData" +#define NID_qualityLabelledData 457 +#define OBJ_qualityLabelledData OBJ_pilotObjectClass,22L + +#define SN_userId "UID" +#define LN_userId "userId" +#define NID_userId 458 +#define OBJ_userId OBJ_pilotAttributeType,1L + +#define LN_textEncodedORAddress "textEncodedORAddress" +#define NID_textEncodedORAddress 459 +#define OBJ_textEncodedORAddress OBJ_pilotAttributeType,2L + +#define SN_rfc822Mailbox "mail" +#define LN_rfc822Mailbox "rfc822Mailbox" +#define NID_rfc822Mailbox 460 +#define OBJ_rfc822Mailbox OBJ_pilotAttributeType,3L + +#define SN_info "info" +#define NID_info 461 +#define OBJ_info OBJ_pilotAttributeType,4L + +#define LN_favouriteDrink "favouriteDrink" +#define NID_favouriteDrink 462 +#define OBJ_favouriteDrink OBJ_pilotAttributeType,5L + +#define LN_roomNumber "roomNumber" +#define NID_roomNumber 463 +#define OBJ_roomNumber OBJ_pilotAttributeType,6L + +#define SN_photo "photo" +#define NID_photo 464 +#define OBJ_photo OBJ_pilotAttributeType,7L + +#define LN_userClass "userClass" +#define NID_userClass 465 +#define OBJ_userClass OBJ_pilotAttributeType,8L + +#define SN_host "host" +#define NID_host 466 +#define OBJ_host OBJ_pilotAttributeType,9L + +#define SN_manager "manager" +#define NID_manager 467 +#define OBJ_manager OBJ_pilotAttributeType,10L + +#define LN_documentIdentifier "documentIdentifier" +#define NID_documentIdentifier 468 +#define OBJ_documentIdentifier OBJ_pilotAttributeType,11L + +#define LN_documentTitle "documentTitle" +#define NID_documentTitle 469 +#define OBJ_documentTitle OBJ_pilotAttributeType,12L + +#define LN_documentVersion "documentVersion" +#define NID_documentVersion 470 +#define OBJ_documentVersion OBJ_pilotAttributeType,13L + +#define LN_documentAuthor "documentAuthor" +#define NID_documentAuthor 471 +#define OBJ_documentAuthor OBJ_pilotAttributeType,14L + +#define LN_documentLocation "documentLocation" +#define NID_documentLocation 472 +#define OBJ_documentLocation OBJ_pilotAttributeType,15L + +#define LN_homeTelephoneNumber "homeTelephoneNumber" +#define NID_homeTelephoneNumber 473 +#define OBJ_homeTelephoneNumber OBJ_pilotAttributeType,20L + +#define SN_secretary "secretary" +#define NID_secretary 474 +#define OBJ_secretary OBJ_pilotAttributeType,21L + +#define LN_otherMailbox "otherMailbox" +#define NID_otherMailbox 475 +#define OBJ_otherMailbox OBJ_pilotAttributeType,22L + +#define LN_lastModifiedTime "lastModifiedTime" +#define NID_lastModifiedTime 476 +#define OBJ_lastModifiedTime OBJ_pilotAttributeType,23L + +#define LN_lastModifiedBy "lastModifiedBy" +#define NID_lastModifiedBy 477 +#define OBJ_lastModifiedBy OBJ_pilotAttributeType,24L + +#define SN_domainComponent "DC" +#define LN_domainComponent "domainComponent" +#define NID_domainComponent 391 +#define OBJ_domainComponent OBJ_pilotAttributeType,25L + +#define LN_aRecord "aRecord" +#define NID_aRecord 478 +#define OBJ_aRecord OBJ_pilotAttributeType,26L + +#define LN_pilotAttributeType27 "pilotAttributeType27" +#define NID_pilotAttributeType27 479 +#define OBJ_pilotAttributeType27 OBJ_pilotAttributeType,27L + +#define LN_mXRecord "mXRecord" +#define NID_mXRecord 480 +#define OBJ_mXRecord OBJ_pilotAttributeType,28L + +#define LN_nSRecord "nSRecord" +#define NID_nSRecord 481 +#define OBJ_nSRecord OBJ_pilotAttributeType,29L + +#define LN_sOARecord "sOARecord" +#define NID_sOARecord 482 +#define OBJ_sOARecord OBJ_pilotAttributeType,30L + +#define LN_cNAMERecord "cNAMERecord" +#define NID_cNAMERecord 483 +#define OBJ_cNAMERecord OBJ_pilotAttributeType,31L + +#define LN_associatedDomain "associatedDomain" +#define NID_associatedDomain 484 +#define OBJ_associatedDomain OBJ_pilotAttributeType,37L + +#define LN_associatedName "associatedName" +#define NID_associatedName 485 +#define OBJ_associatedName OBJ_pilotAttributeType,38L + +#define LN_homePostalAddress "homePostalAddress" +#define NID_homePostalAddress 486 +#define OBJ_homePostalAddress OBJ_pilotAttributeType,39L + +#define LN_personalTitle "personalTitle" +#define NID_personalTitle 487 +#define OBJ_personalTitle OBJ_pilotAttributeType,40L + +#define LN_mobileTelephoneNumber "mobileTelephoneNumber" +#define NID_mobileTelephoneNumber 488 +#define OBJ_mobileTelephoneNumber OBJ_pilotAttributeType,41L + +#define LN_pagerTelephoneNumber "pagerTelephoneNumber" +#define NID_pagerTelephoneNumber 489 +#define OBJ_pagerTelephoneNumber OBJ_pilotAttributeType,42L + +#define LN_friendlyCountryName "friendlyCountryName" +#define NID_friendlyCountryName 490 +#define OBJ_friendlyCountryName OBJ_pilotAttributeType,43L + +#define LN_organizationalStatus "organizationalStatus" +#define NID_organizationalStatus 491 +#define OBJ_organizationalStatus OBJ_pilotAttributeType,45L + +#define LN_janetMailbox "janetMailbox" +#define NID_janetMailbox 492 +#define OBJ_janetMailbox OBJ_pilotAttributeType,46L + +#define LN_mailPreferenceOption "mailPreferenceOption" +#define NID_mailPreferenceOption 493 +#define OBJ_mailPreferenceOption OBJ_pilotAttributeType,47L + +#define LN_buildingName "buildingName" +#define NID_buildingName 494 +#define OBJ_buildingName OBJ_pilotAttributeType,48L + +#define LN_dSAQuality "dSAQuality" +#define NID_dSAQuality 495 +#define OBJ_dSAQuality OBJ_pilotAttributeType,49L + +#define LN_singleLevelQuality "singleLevelQuality" +#define NID_singleLevelQuality 496 +#define OBJ_singleLevelQuality OBJ_pilotAttributeType,50L + +#define LN_subtreeMinimumQuality "subtreeMinimumQuality" +#define NID_subtreeMinimumQuality 497 +#define OBJ_subtreeMinimumQuality OBJ_pilotAttributeType,51L + +#define LN_subtreeMaximumQuality "subtreeMaximumQuality" +#define NID_subtreeMaximumQuality 498 +#define OBJ_subtreeMaximumQuality OBJ_pilotAttributeType,52L + +#define LN_personalSignature "personalSignature" +#define NID_personalSignature 499 +#define OBJ_personalSignature OBJ_pilotAttributeType,53L + +#define LN_dITRedirect "dITRedirect" +#define NID_dITRedirect 500 +#define OBJ_dITRedirect OBJ_pilotAttributeType,54L + +#define SN_audio "audio" +#define NID_audio 501 +#define OBJ_audio OBJ_pilotAttributeType,55L + +#define LN_documentPublisher "documentPublisher" +#define NID_documentPublisher 502 +#define OBJ_documentPublisher OBJ_pilotAttributeType,56L + +#define SN_id_set "id-set" +#define LN_id_set "Secure Electronic Transactions" +#define NID_id_set 512 +#define OBJ_id_set OBJ_international_organizations,42L + +#define SN_set_ctype "set-ctype" +#define LN_set_ctype "content types" +#define NID_set_ctype 513 +#define OBJ_set_ctype OBJ_id_set,0L + +#define SN_set_msgExt "set-msgExt" +#define LN_set_msgExt "message extensions" +#define NID_set_msgExt 514 +#define OBJ_set_msgExt OBJ_id_set,1L + +#define SN_set_attr "set-attr" +#define NID_set_attr 515 +#define OBJ_set_attr OBJ_id_set,3L + +#define SN_set_policy "set-policy" +#define NID_set_policy 516 +#define OBJ_set_policy OBJ_id_set,5L + +#define SN_set_certExt "set-certExt" +#define LN_set_certExt "certificate extensions" +#define NID_set_certExt 517 +#define OBJ_set_certExt OBJ_id_set,7L + +#define SN_set_brand "set-brand" +#define NID_set_brand 518 +#define OBJ_set_brand OBJ_id_set,8L + +#define SN_setct_PANData "setct-PANData" +#define NID_setct_PANData 519 +#define OBJ_setct_PANData OBJ_set_ctype,0L + +#define SN_setct_PANToken "setct-PANToken" +#define NID_setct_PANToken 520 +#define OBJ_setct_PANToken OBJ_set_ctype,1L + +#define SN_setct_PANOnly "setct-PANOnly" +#define NID_setct_PANOnly 521 +#define OBJ_setct_PANOnly OBJ_set_ctype,2L + +#define SN_setct_OIData "setct-OIData" +#define NID_setct_OIData 522 +#define OBJ_setct_OIData OBJ_set_ctype,3L + +#define SN_setct_PI "setct-PI" +#define NID_setct_PI 523 +#define OBJ_setct_PI OBJ_set_ctype,4L + +#define SN_setct_PIData "setct-PIData" +#define NID_setct_PIData 524 +#define OBJ_setct_PIData OBJ_set_ctype,5L + +#define SN_setct_PIDataUnsigned "setct-PIDataUnsigned" +#define NID_setct_PIDataUnsigned 525 +#define OBJ_setct_PIDataUnsigned OBJ_set_ctype,6L + +#define SN_setct_HODInput "setct-HODInput" +#define NID_setct_HODInput 526 +#define OBJ_setct_HODInput OBJ_set_ctype,7L + +#define SN_setct_AuthResBaggage "setct-AuthResBaggage" +#define NID_setct_AuthResBaggage 527 +#define OBJ_setct_AuthResBaggage OBJ_set_ctype,8L + +#define SN_setct_AuthRevReqBaggage "setct-AuthRevReqBaggage" +#define NID_setct_AuthRevReqBaggage 528 +#define OBJ_setct_AuthRevReqBaggage OBJ_set_ctype,9L + +#define SN_setct_AuthRevResBaggage "setct-AuthRevResBaggage" +#define NID_setct_AuthRevResBaggage 529 +#define OBJ_setct_AuthRevResBaggage OBJ_set_ctype,10L + +#define SN_setct_CapTokenSeq "setct-CapTokenSeq" +#define NID_setct_CapTokenSeq 530 +#define OBJ_setct_CapTokenSeq OBJ_set_ctype,11L + +#define SN_setct_PInitResData "setct-PInitResData" +#define NID_setct_PInitResData 531 +#define OBJ_setct_PInitResData OBJ_set_ctype,12L + +#define SN_setct_PI_TBS "setct-PI-TBS" +#define NID_setct_PI_TBS 532 +#define OBJ_setct_PI_TBS OBJ_set_ctype,13L + +#define SN_setct_PResData "setct-PResData" +#define NID_setct_PResData 533 +#define OBJ_setct_PResData OBJ_set_ctype,14L + +#define SN_setct_AuthReqTBS "setct-AuthReqTBS" +#define NID_setct_AuthReqTBS 534 +#define OBJ_setct_AuthReqTBS OBJ_set_ctype,16L + +#define SN_setct_AuthResTBS "setct-AuthResTBS" +#define NID_setct_AuthResTBS 535 +#define OBJ_setct_AuthResTBS OBJ_set_ctype,17L + +#define SN_setct_AuthResTBSX "setct-AuthResTBSX" +#define NID_setct_AuthResTBSX 536 +#define OBJ_setct_AuthResTBSX OBJ_set_ctype,18L + +#define SN_setct_AuthTokenTBS "setct-AuthTokenTBS" +#define NID_setct_AuthTokenTBS 537 +#define OBJ_setct_AuthTokenTBS OBJ_set_ctype,19L + +#define SN_setct_CapTokenData "setct-CapTokenData" +#define NID_setct_CapTokenData 538 +#define OBJ_setct_CapTokenData OBJ_set_ctype,20L + +#define SN_setct_CapTokenTBS "setct-CapTokenTBS" +#define NID_setct_CapTokenTBS 539 +#define OBJ_setct_CapTokenTBS OBJ_set_ctype,21L + +#define SN_setct_AcqCardCodeMsg "setct-AcqCardCodeMsg" +#define NID_setct_AcqCardCodeMsg 540 +#define OBJ_setct_AcqCardCodeMsg OBJ_set_ctype,22L + +#define SN_setct_AuthRevReqTBS "setct-AuthRevReqTBS" +#define NID_setct_AuthRevReqTBS 541 +#define OBJ_setct_AuthRevReqTBS OBJ_set_ctype,23L + +#define SN_setct_AuthRevResData "setct-AuthRevResData" +#define NID_setct_AuthRevResData 542 +#define OBJ_setct_AuthRevResData OBJ_set_ctype,24L + +#define SN_setct_AuthRevResTBS "setct-AuthRevResTBS" +#define NID_setct_AuthRevResTBS 543 +#define OBJ_setct_AuthRevResTBS OBJ_set_ctype,25L + +#define SN_setct_CapReqTBS "setct-CapReqTBS" +#define NID_setct_CapReqTBS 544 +#define OBJ_setct_CapReqTBS OBJ_set_ctype,26L + +#define SN_setct_CapReqTBSX "setct-CapReqTBSX" +#define NID_setct_CapReqTBSX 545 +#define OBJ_setct_CapReqTBSX OBJ_set_ctype,27L + +#define SN_setct_CapResData "setct-CapResData" +#define NID_setct_CapResData 546 +#define OBJ_setct_CapResData OBJ_set_ctype,28L + +#define SN_setct_CapRevReqTBS "setct-CapRevReqTBS" +#define NID_setct_CapRevReqTBS 547 +#define OBJ_setct_CapRevReqTBS OBJ_set_ctype,29L + +#define SN_setct_CapRevReqTBSX "setct-CapRevReqTBSX" +#define NID_setct_CapRevReqTBSX 548 +#define OBJ_setct_CapRevReqTBSX OBJ_set_ctype,30L + +#define SN_setct_CapRevResData "setct-CapRevResData" +#define NID_setct_CapRevResData 549 +#define OBJ_setct_CapRevResData OBJ_set_ctype,31L + +#define SN_setct_CredReqTBS "setct-CredReqTBS" +#define NID_setct_CredReqTBS 550 +#define OBJ_setct_CredReqTBS OBJ_set_ctype,32L + +#define SN_setct_CredReqTBSX "setct-CredReqTBSX" +#define NID_setct_CredReqTBSX 551 +#define OBJ_setct_CredReqTBSX OBJ_set_ctype,33L + +#define SN_setct_CredResData "setct-CredResData" +#define NID_setct_CredResData 552 +#define OBJ_setct_CredResData OBJ_set_ctype,34L + +#define SN_setct_CredRevReqTBS "setct-CredRevReqTBS" +#define NID_setct_CredRevReqTBS 553 +#define OBJ_setct_CredRevReqTBS OBJ_set_ctype,35L + +#define SN_setct_CredRevReqTBSX "setct-CredRevReqTBSX" +#define NID_setct_CredRevReqTBSX 554 +#define OBJ_setct_CredRevReqTBSX OBJ_set_ctype,36L + +#define SN_setct_CredRevResData "setct-CredRevResData" +#define NID_setct_CredRevResData 555 +#define OBJ_setct_CredRevResData OBJ_set_ctype,37L + +#define SN_setct_PCertReqData "setct-PCertReqData" +#define NID_setct_PCertReqData 556 +#define OBJ_setct_PCertReqData OBJ_set_ctype,38L + +#define SN_setct_PCertResTBS "setct-PCertResTBS" +#define NID_setct_PCertResTBS 557 +#define OBJ_setct_PCertResTBS OBJ_set_ctype,39L + +#define SN_setct_BatchAdminReqData "setct-BatchAdminReqData" +#define NID_setct_BatchAdminReqData 558 +#define OBJ_setct_BatchAdminReqData OBJ_set_ctype,40L + +#define SN_setct_BatchAdminResData "setct-BatchAdminResData" +#define NID_setct_BatchAdminResData 559 +#define OBJ_setct_BatchAdminResData OBJ_set_ctype,41L + +#define SN_setct_CardCInitResTBS "setct-CardCInitResTBS" +#define NID_setct_CardCInitResTBS 560 +#define OBJ_setct_CardCInitResTBS OBJ_set_ctype,42L + +#define SN_setct_MeAqCInitResTBS "setct-MeAqCInitResTBS" +#define NID_setct_MeAqCInitResTBS 561 +#define OBJ_setct_MeAqCInitResTBS OBJ_set_ctype,43L + +#define SN_setct_RegFormResTBS "setct-RegFormResTBS" +#define NID_setct_RegFormResTBS 562 +#define OBJ_setct_RegFormResTBS OBJ_set_ctype,44L + +#define SN_setct_CertReqData "setct-CertReqData" +#define NID_setct_CertReqData 563 +#define OBJ_setct_CertReqData OBJ_set_ctype,45L + +#define SN_setct_CertReqTBS "setct-CertReqTBS" +#define NID_setct_CertReqTBS 564 +#define OBJ_setct_CertReqTBS OBJ_set_ctype,46L + +#define SN_setct_CertResData "setct-CertResData" +#define NID_setct_CertResData 565 +#define OBJ_setct_CertResData OBJ_set_ctype,47L + +#define SN_setct_CertInqReqTBS "setct-CertInqReqTBS" +#define NID_setct_CertInqReqTBS 566 +#define OBJ_setct_CertInqReqTBS OBJ_set_ctype,48L + +#define SN_setct_ErrorTBS "setct-ErrorTBS" +#define NID_setct_ErrorTBS 567 +#define OBJ_setct_ErrorTBS OBJ_set_ctype,49L + +#define SN_setct_PIDualSignedTBE "setct-PIDualSignedTBE" +#define NID_setct_PIDualSignedTBE 568 +#define OBJ_setct_PIDualSignedTBE OBJ_set_ctype,50L + +#define SN_setct_PIUnsignedTBE "setct-PIUnsignedTBE" +#define NID_setct_PIUnsignedTBE 569 +#define OBJ_setct_PIUnsignedTBE OBJ_set_ctype,51L + +#define SN_setct_AuthReqTBE "setct-AuthReqTBE" +#define NID_setct_AuthReqTBE 570 +#define OBJ_setct_AuthReqTBE OBJ_set_ctype,52L + +#define SN_setct_AuthResTBE "setct-AuthResTBE" +#define NID_setct_AuthResTBE 571 +#define OBJ_setct_AuthResTBE OBJ_set_ctype,53L + +#define SN_setct_AuthResTBEX "setct-AuthResTBEX" +#define NID_setct_AuthResTBEX 572 +#define OBJ_setct_AuthResTBEX OBJ_set_ctype,54L + +#define SN_setct_AuthTokenTBE "setct-AuthTokenTBE" +#define NID_setct_AuthTokenTBE 573 +#define OBJ_setct_AuthTokenTBE OBJ_set_ctype,55L + +#define SN_setct_CapTokenTBE "setct-CapTokenTBE" +#define NID_setct_CapTokenTBE 574 +#define OBJ_setct_CapTokenTBE OBJ_set_ctype,56L + +#define SN_setct_CapTokenTBEX "setct-CapTokenTBEX" +#define NID_setct_CapTokenTBEX 575 +#define OBJ_setct_CapTokenTBEX OBJ_set_ctype,57L + +#define SN_setct_AcqCardCodeMsgTBE "setct-AcqCardCodeMsgTBE" +#define NID_setct_AcqCardCodeMsgTBE 576 +#define OBJ_setct_AcqCardCodeMsgTBE OBJ_set_ctype,58L + +#define SN_setct_AuthRevReqTBE "setct-AuthRevReqTBE" +#define NID_setct_AuthRevReqTBE 577 +#define OBJ_setct_AuthRevReqTBE OBJ_set_ctype,59L + +#define SN_setct_AuthRevResTBE "setct-AuthRevResTBE" +#define NID_setct_AuthRevResTBE 578 +#define OBJ_setct_AuthRevResTBE OBJ_set_ctype,60L + +#define SN_setct_AuthRevResTBEB "setct-AuthRevResTBEB" +#define NID_setct_AuthRevResTBEB 579 +#define OBJ_setct_AuthRevResTBEB OBJ_set_ctype,61L + +#define SN_setct_CapReqTBE "setct-CapReqTBE" +#define NID_setct_CapReqTBE 580 +#define OBJ_setct_CapReqTBE OBJ_set_ctype,62L + +#define SN_setct_CapReqTBEX "setct-CapReqTBEX" +#define NID_setct_CapReqTBEX 581 +#define OBJ_setct_CapReqTBEX OBJ_set_ctype,63L + +#define SN_setct_CapResTBE "setct-CapResTBE" +#define NID_setct_CapResTBE 582 +#define OBJ_setct_CapResTBE OBJ_set_ctype,64L + +#define SN_setct_CapRevReqTBE "setct-CapRevReqTBE" +#define NID_setct_CapRevReqTBE 583 +#define OBJ_setct_CapRevReqTBE OBJ_set_ctype,65L + +#define SN_setct_CapRevReqTBEX "setct-CapRevReqTBEX" +#define NID_setct_CapRevReqTBEX 584 +#define OBJ_setct_CapRevReqTBEX OBJ_set_ctype,66L + +#define SN_setct_CapRevResTBE "setct-CapRevResTBE" +#define NID_setct_CapRevResTBE 585 +#define OBJ_setct_CapRevResTBE OBJ_set_ctype,67L + +#define SN_setct_CredReqTBE "setct-CredReqTBE" +#define NID_setct_CredReqTBE 586 +#define OBJ_setct_CredReqTBE OBJ_set_ctype,68L + +#define SN_setct_CredReqTBEX "setct-CredReqTBEX" +#define NID_setct_CredReqTBEX 587 +#define OBJ_setct_CredReqTBEX OBJ_set_ctype,69L + +#define SN_setct_CredResTBE "setct-CredResTBE" +#define NID_setct_CredResTBE 588 +#define OBJ_setct_CredResTBE OBJ_set_ctype,70L + +#define SN_setct_CredRevReqTBE "setct-CredRevReqTBE" +#define NID_setct_CredRevReqTBE 589 +#define OBJ_setct_CredRevReqTBE OBJ_set_ctype,71L + +#define SN_setct_CredRevReqTBEX "setct-CredRevReqTBEX" +#define NID_setct_CredRevReqTBEX 590 +#define OBJ_setct_CredRevReqTBEX OBJ_set_ctype,72L + +#define SN_setct_CredRevResTBE "setct-CredRevResTBE" +#define NID_setct_CredRevResTBE 591 +#define OBJ_setct_CredRevResTBE OBJ_set_ctype,73L + +#define SN_setct_BatchAdminReqTBE "setct-BatchAdminReqTBE" +#define NID_setct_BatchAdminReqTBE 592 +#define OBJ_setct_BatchAdminReqTBE OBJ_set_ctype,74L + +#define SN_setct_BatchAdminResTBE "setct-BatchAdminResTBE" +#define NID_setct_BatchAdminResTBE 593 +#define OBJ_setct_BatchAdminResTBE OBJ_set_ctype,75L + +#define SN_setct_RegFormReqTBE "setct-RegFormReqTBE" +#define NID_setct_RegFormReqTBE 594 +#define OBJ_setct_RegFormReqTBE OBJ_set_ctype,76L + +#define SN_setct_CertReqTBE "setct-CertReqTBE" +#define NID_setct_CertReqTBE 595 +#define OBJ_setct_CertReqTBE OBJ_set_ctype,77L + +#define SN_setct_CertReqTBEX "setct-CertReqTBEX" +#define NID_setct_CertReqTBEX 596 +#define OBJ_setct_CertReqTBEX OBJ_set_ctype,78L + +#define SN_setct_CertResTBE "setct-CertResTBE" +#define NID_setct_CertResTBE 597 +#define OBJ_setct_CertResTBE OBJ_set_ctype,79L + +#define SN_setct_CRLNotificationTBS "setct-CRLNotificationTBS" +#define NID_setct_CRLNotificationTBS 598 +#define OBJ_setct_CRLNotificationTBS OBJ_set_ctype,80L + +#define SN_setct_CRLNotificationResTBS "setct-CRLNotificationResTBS" +#define NID_setct_CRLNotificationResTBS 599 +#define OBJ_setct_CRLNotificationResTBS OBJ_set_ctype,81L + +#define SN_setct_BCIDistributionTBS "setct-BCIDistributionTBS" +#define NID_setct_BCIDistributionTBS 600 +#define OBJ_setct_BCIDistributionTBS OBJ_set_ctype,82L + +#define SN_setext_genCrypt "setext-genCrypt" +#define LN_setext_genCrypt "generic cryptogram" +#define NID_setext_genCrypt 601 +#define OBJ_setext_genCrypt OBJ_set_msgExt,1L + +#define SN_setext_miAuth "setext-miAuth" +#define LN_setext_miAuth "merchant initiated auth" +#define NID_setext_miAuth 602 +#define OBJ_setext_miAuth OBJ_set_msgExt,3L + +#define SN_setext_pinSecure "setext-pinSecure" +#define NID_setext_pinSecure 603 +#define OBJ_setext_pinSecure OBJ_set_msgExt,4L + +#define SN_setext_pinAny "setext-pinAny" +#define NID_setext_pinAny 604 +#define OBJ_setext_pinAny OBJ_set_msgExt,5L + +#define SN_setext_track2 "setext-track2" +#define NID_setext_track2 605 +#define OBJ_setext_track2 OBJ_set_msgExt,7L + +#define SN_setext_cv "setext-cv" +#define LN_setext_cv "additional verification" +#define NID_setext_cv 606 +#define OBJ_setext_cv OBJ_set_msgExt,8L + +#define SN_set_policy_root "set-policy-root" +#define NID_set_policy_root 607 +#define OBJ_set_policy_root OBJ_set_policy,0L + +#define SN_setCext_hashedRoot "setCext-hashedRoot" +#define NID_setCext_hashedRoot 608 +#define OBJ_setCext_hashedRoot OBJ_set_certExt,0L + +#define SN_setCext_certType "setCext-certType" +#define NID_setCext_certType 609 +#define OBJ_setCext_certType OBJ_set_certExt,1L + +#define SN_setCext_merchData "setCext-merchData" +#define NID_setCext_merchData 610 +#define OBJ_setCext_merchData OBJ_set_certExt,2L + +#define SN_setCext_cCertRequired "setCext-cCertRequired" +#define NID_setCext_cCertRequired 611 +#define OBJ_setCext_cCertRequired OBJ_set_certExt,3L + +#define SN_setCext_tunneling "setCext-tunneling" +#define NID_setCext_tunneling 612 +#define OBJ_setCext_tunneling OBJ_set_certExt,4L + +#define SN_setCext_setExt "setCext-setExt" +#define NID_setCext_setExt 613 +#define OBJ_setCext_setExt OBJ_set_certExt,5L + +#define SN_setCext_setQualf "setCext-setQualf" +#define NID_setCext_setQualf 614 +#define OBJ_setCext_setQualf OBJ_set_certExt,6L + +#define SN_setCext_PGWYcapabilities "setCext-PGWYcapabilities" +#define NID_setCext_PGWYcapabilities 615 +#define OBJ_setCext_PGWYcapabilities OBJ_set_certExt,7L + +#define SN_setCext_TokenIdentifier "setCext-TokenIdentifier" +#define NID_setCext_TokenIdentifier 616 +#define OBJ_setCext_TokenIdentifier OBJ_set_certExt,8L + +#define SN_setCext_Track2Data "setCext-Track2Data" +#define NID_setCext_Track2Data 617 +#define OBJ_setCext_Track2Data OBJ_set_certExt,9L + +#define SN_setCext_TokenType "setCext-TokenType" +#define NID_setCext_TokenType 618 +#define OBJ_setCext_TokenType OBJ_set_certExt,10L + +#define SN_setCext_IssuerCapabilities "setCext-IssuerCapabilities" +#define NID_setCext_IssuerCapabilities 619 +#define OBJ_setCext_IssuerCapabilities OBJ_set_certExt,11L + +#define SN_setAttr_Cert "setAttr-Cert" +#define NID_setAttr_Cert 620 +#define OBJ_setAttr_Cert OBJ_set_attr,0L + +#define SN_setAttr_PGWYcap "setAttr-PGWYcap" +#define LN_setAttr_PGWYcap "payment gateway capabilities" +#define NID_setAttr_PGWYcap 621 +#define OBJ_setAttr_PGWYcap OBJ_set_attr,1L + +#define SN_setAttr_TokenType "setAttr-TokenType" +#define NID_setAttr_TokenType 622 +#define OBJ_setAttr_TokenType OBJ_set_attr,2L + +#define SN_setAttr_IssCap "setAttr-IssCap" +#define LN_setAttr_IssCap "issuer capabilities" +#define NID_setAttr_IssCap 623 +#define OBJ_setAttr_IssCap OBJ_set_attr,3L + +#define SN_set_rootKeyThumb "set-rootKeyThumb" +#define NID_set_rootKeyThumb 624 +#define OBJ_set_rootKeyThumb OBJ_setAttr_Cert,0L + +#define SN_set_addPolicy "set-addPolicy" +#define NID_set_addPolicy 625 +#define OBJ_set_addPolicy OBJ_setAttr_Cert,1L + +#define SN_setAttr_Token_EMV "setAttr-Token-EMV" +#define NID_setAttr_Token_EMV 626 +#define OBJ_setAttr_Token_EMV OBJ_setAttr_TokenType,1L + +#define SN_setAttr_Token_B0Prime "setAttr-Token-B0Prime" +#define NID_setAttr_Token_B0Prime 627 +#define OBJ_setAttr_Token_B0Prime OBJ_setAttr_TokenType,2L + +#define SN_setAttr_IssCap_CVM "setAttr-IssCap-CVM" +#define NID_setAttr_IssCap_CVM 628 +#define OBJ_setAttr_IssCap_CVM OBJ_setAttr_IssCap,3L + +#define SN_setAttr_IssCap_T2 "setAttr-IssCap-T2" +#define NID_setAttr_IssCap_T2 629 +#define OBJ_setAttr_IssCap_T2 OBJ_setAttr_IssCap,4L + +#define SN_setAttr_IssCap_Sig "setAttr-IssCap-Sig" +#define NID_setAttr_IssCap_Sig 630 +#define OBJ_setAttr_IssCap_Sig OBJ_setAttr_IssCap,5L + +#define SN_setAttr_GenCryptgrm "setAttr-GenCryptgrm" +#define LN_setAttr_GenCryptgrm "generate cryptogram" +#define NID_setAttr_GenCryptgrm 631 +#define OBJ_setAttr_GenCryptgrm OBJ_setAttr_IssCap_CVM,1L + +#define SN_setAttr_T2Enc "setAttr-T2Enc" +#define LN_setAttr_T2Enc "encrypted track 2" +#define NID_setAttr_T2Enc 632 +#define OBJ_setAttr_T2Enc OBJ_setAttr_IssCap_T2,1L + +#define SN_setAttr_T2cleartxt "setAttr-T2cleartxt" +#define LN_setAttr_T2cleartxt "cleartext track 2" +#define NID_setAttr_T2cleartxt 633 +#define OBJ_setAttr_T2cleartxt OBJ_setAttr_IssCap_T2,2L + +#define SN_setAttr_TokICCsig "setAttr-TokICCsig" +#define LN_setAttr_TokICCsig "ICC or token signature" +#define NID_setAttr_TokICCsig 634 +#define OBJ_setAttr_TokICCsig OBJ_setAttr_IssCap_Sig,1L + +#define SN_setAttr_SecDevSig "setAttr-SecDevSig" +#define LN_setAttr_SecDevSig "secure device signature" +#define NID_setAttr_SecDevSig 635 +#define OBJ_setAttr_SecDevSig OBJ_setAttr_IssCap_Sig,2L + +#define SN_set_brand_IATA_ATA "set-brand-IATA-ATA" +#define NID_set_brand_IATA_ATA 636 +#define OBJ_set_brand_IATA_ATA OBJ_set_brand,1L + +#define SN_set_brand_Diners "set-brand-Diners" +#define NID_set_brand_Diners 637 +#define OBJ_set_brand_Diners OBJ_set_brand,30L + +#define SN_set_brand_AmericanExpress "set-brand-AmericanExpress" +#define NID_set_brand_AmericanExpress 638 +#define OBJ_set_brand_AmericanExpress OBJ_set_brand,34L + +#define SN_set_brand_JCB "set-brand-JCB" +#define NID_set_brand_JCB 639 +#define OBJ_set_brand_JCB OBJ_set_brand,35L + +#define SN_set_brand_Visa "set-brand-Visa" +#define NID_set_brand_Visa 640 +#define OBJ_set_brand_Visa OBJ_set_brand,4L + +#define SN_set_brand_MasterCard "set-brand-MasterCard" +#define NID_set_brand_MasterCard 641 +#define OBJ_set_brand_MasterCard OBJ_set_brand,5L + +#define SN_set_brand_Novus "set-brand-Novus" +#define NID_set_brand_Novus 642 +#define OBJ_set_brand_Novus OBJ_set_brand,6011L + +#define SN_des_cdmf "DES-CDMF" +#define LN_des_cdmf "des-cdmf" +#define NID_des_cdmf 643 +#define OBJ_des_cdmf OBJ_rsadsi,3L,10L + +#define SN_rsaOAEPEncryptionSET "rsaOAEPEncryptionSET" +#define NID_rsaOAEPEncryptionSET 644 +#define OBJ_rsaOAEPEncryptionSET OBJ_rsadsi,1L,1L,6L + +#define SN_ipsec3 "Oakley-EC2N-3" +#define LN_ipsec3 "ipsec3" +#define NID_ipsec3 749 + +#define SN_ipsec4 "Oakley-EC2N-4" +#define LN_ipsec4 "ipsec4" +#define NID_ipsec4 750 + +#define SN_whirlpool "whirlpool" +#define NID_whirlpool 804 +#define OBJ_whirlpool OBJ_iso,0L,10118L,3L,0L,55L + +#define SN_cryptopro "cryptopro" +#define NID_cryptopro 805 +#define OBJ_cryptopro OBJ_member_body,643L,2L,2L + +#define SN_cryptocom "cryptocom" +#define NID_cryptocom 806 +#define OBJ_cryptocom OBJ_member_body,643L,2L,9L + +#define SN_id_GostR3411_94_with_GostR3410_2001 "id-GostR3411-94-with-GostR3410-2001" +#define LN_id_GostR3411_94_with_GostR3410_2001 "GOST R 34.11-94 with GOST R 34.10-2001" +#define NID_id_GostR3411_94_with_GostR3410_2001 807 +#define OBJ_id_GostR3411_94_with_GostR3410_2001 OBJ_cryptopro,3L + +#define SN_id_GostR3411_94_with_GostR3410_94 "id-GostR3411-94-with-GostR3410-94" +#define LN_id_GostR3411_94_with_GostR3410_94 "GOST R 34.11-94 with GOST R 34.10-94" +#define NID_id_GostR3411_94_with_GostR3410_94 808 +#define OBJ_id_GostR3411_94_with_GostR3410_94 OBJ_cryptopro,4L + +#define SN_id_GostR3411_94 "md_gost94" +#define LN_id_GostR3411_94 "GOST R 34.11-94" +#define NID_id_GostR3411_94 809 +#define OBJ_id_GostR3411_94 OBJ_cryptopro,9L + +#define SN_id_HMACGostR3411_94 "id-HMACGostR3411-94" +#define LN_id_HMACGostR3411_94 "HMAC GOST 34.11-94" +#define NID_id_HMACGostR3411_94 810 +#define OBJ_id_HMACGostR3411_94 OBJ_cryptopro,10L + +#define SN_id_GostR3410_2001 "gost2001" +#define LN_id_GostR3410_2001 "GOST R 34.10-2001" +#define NID_id_GostR3410_2001 811 +#define OBJ_id_GostR3410_2001 OBJ_cryptopro,19L + +#define SN_id_GostR3410_94 "gost94" +#define LN_id_GostR3410_94 "GOST R 34.10-94" +#define NID_id_GostR3410_94 812 +#define OBJ_id_GostR3410_94 OBJ_cryptopro,20L + +#define SN_id_Gost28147_89 "gost89" +#define LN_id_Gost28147_89 "GOST 28147-89" +#define NID_id_Gost28147_89 813 +#define OBJ_id_Gost28147_89 OBJ_cryptopro,21L + +#define SN_gost89_cnt "gost89-cnt" +#define NID_gost89_cnt 814 + +#define SN_id_Gost28147_89_MAC "gost-mac" +#define LN_id_Gost28147_89_MAC "GOST 28147-89 MAC" +#define NID_id_Gost28147_89_MAC 815 +#define OBJ_id_Gost28147_89_MAC OBJ_cryptopro,22L + +#define SN_id_GostR3411_94_prf "prf-gostr3411-94" +#define LN_id_GostR3411_94_prf "GOST R 34.11-94 PRF" +#define NID_id_GostR3411_94_prf 816 +#define OBJ_id_GostR3411_94_prf OBJ_cryptopro,23L + +#define SN_id_GostR3410_2001DH "id-GostR3410-2001DH" +#define LN_id_GostR3410_2001DH "GOST R 34.10-2001 DH" +#define NID_id_GostR3410_2001DH 817 +#define OBJ_id_GostR3410_2001DH OBJ_cryptopro,98L + +#define SN_id_GostR3410_94DH "id-GostR3410-94DH" +#define LN_id_GostR3410_94DH "GOST R 34.10-94 DH" +#define NID_id_GostR3410_94DH 818 +#define OBJ_id_GostR3410_94DH OBJ_cryptopro,99L + +#define SN_id_Gost28147_89_CryptoPro_KeyMeshing "id-Gost28147-89-CryptoPro-KeyMeshing" +#define NID_id_Gost28147_89_CryptoPro_KeyMeshing 819 +#define OBJ_id_Gost28147_89_CryptoPro_KeyMeshing OBJ_cryptopro,14L,1L + +#define SN_id_Gost28147_89_None_KeyMeshing "id-Gost28147-89-None-KeyMeshing" +#define NID_id_Gost28147_89_None_KeyMeshing 820 +#define OBJ_id_Gost28147_89_None_KeyMeshing OBJ_cryptopro,14L,0L + +#define SN_id_GostR3411_94_TestParamSet "id-GostR3411-94-TestParamSet" +#define NID_id_GostR3411_94_TestParamSet 821 +#define OBJ_id_GostR3411_94_TestParamSet OBJ_cryptopro,30L,0L + +#define SN_id_GostR3411_94_CryptoProParamSet "id-GostR3411-94-CryptoProParamSet" +#define NID_id_GostR3411_94_CryptoProParamSet 822 +#define OBJ_id_GostR3411_94_CryptoProParamSet OBJ_cryptopro,30L,1L + +#define SN_id_Gost28147_89_TestParamSet "id-Gost28147-89-TestParamSet" +#define NID_id_Gost28147_89_TestParamSet 823 +#define OBJ_id_Gost28147_89_TestParamSet OBJ_cryptopro,31L,0L + +#define SN_id_Gost28147_89_CryptoPro_A_ParamSet "id-Gost28147-89-CryptoPro-A-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_A_ParamSet 824 +#define OBJ_id_Gost28147_89_CryptoPro_A_ParamSet OBJ_cryptopro,31L,1L + +#define SN_id_Gost28147_89_CryptoPro_B_ParamSet "id-Gost28147-89-CryptoPro-B-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_B_ParamSet 825 +#define OBJ_id_Gost28147_89_CryptoPro_B_ParamSet OBJ_cryptopro,31L,2L + +#define SN_id_Gost28147_89_CryptoPro_C_ParamSet "id-Gost28147-89-CryptoPro-C-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_C_ParamSet 826 +#define OBJ_id_Gost28147_89_CryptoPro_C_ParamSet OBJ_cryptopro,31L,3L + +#define SN_id_Gost28147_89_CryptoPro_D_ParamSet "id-Gost28147-89-CryptoPro-D-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_D_ParamSet 827 +#define OBJ_id_Gost28147_89_CryptoPro_D_ParamSet OBJ_cryptopro,31L,4L + +#define SN_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet 828 +#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet OBJ_cryptopro,31L,5L + +#define SN_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet 829 +#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet OBJ_cryptopro,31L,6L + +#define SN_id_Gost28147_89_CryptoPro_RIC_1_ParamSet "id-Gost28147-89-CryptoPro-RIC-1-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet 830 +#define OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet OBJ_cryptopro,31L,7L + +#define SN_id_GostR3410_94_TestParamSet "id-GostR3410-94-TestParamSet" +#define NID_id_GostR3410_94_TestParamSet 831 +#define OBJ_id_GostR3410_94_TestParamSet OBJ_cryptopro,32L,0L + +#define SN_id_GostR3410_94_CryptoPro_A_ParamSet "id-GostR3410-94-CryptoPro-A-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_A_ParamSet 832 +#define OBJ_id_GostR3410_94_CryptoPro_A_ParamSet OBJ_cryptopro,32L,2L + +#define SN_id_GostR3410_94_CryptoPro_B_ParamSet "id-GostR3410-94-CryptoPro-B-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_B_ParamSet 833 +#define OBJ_id_GostR3410_94_CryptoPro_B_ParamSet OBJ_cryptopro,32L,3L + +#define SN_id_GostR3410_94_CryptoPro_C_ParamSet "id-GostR3410-94-CryptoPro-C-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_C_ParamSet 834 +#define OBJ_id_GostR3410_94_CryptoPro_C_ParamSet OBJ_cryptopro,32L,4L + +#define SN_id_GostR3410_94_CryptoPro_D_ParamSet "id-GostR3410-94-CryptoPro-D-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_D_ParamSet 835 +#define OBJ_id_GostR3410_94_CryptoPro_D_ParamSet OBJ_cryptopro,32L,5L + +#define SN_id_GostR3410_94_CryptoPro_XchA_ParamSet "id-GostR3410-94-CryptoPro-XchA-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_XchA_ParamSet 836 +#define OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet OBJ_cryptopro,33L,1L + +#define SN_id_GostR3410_94_CryptoPro_XchB_ParamSet "id-GostR3410-94-CryptoPro-XchB-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_XchB_ParamSet 837 +#define OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet OBJ_cryptopro,33L,2L + +#define SN_id_GostR3410_94_CryptoPro_XchC_ParamSet "id-GostR3410-94-CryptoPro-XchC-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_XchC_ParamSet 838 +#define OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet OBJ_cryptopro,33L,3L + +#define SN_id_GostR3410_2001_TestParamSet "id-GostR3410-2001-TestParamSet" +#define NID_id_GostR3410_2001_TestParamSet 839 +#define OBJ_id_GostR3410_2001_TestParamSet OBJ_cryptopro,35L,0L + +#define SN_id_GostR3410_2001_CryptoPro_A_ParamSet "id-GostR3410-2001-CryptoPro-A-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_A_ParamSet 840 +#define OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet OBJ_cryptopro,35L,1L + +#define SN_id_GostR3410_2001_CryptoPro_B_ParamSet "id-GostR3410-2001-CryptoPro-B-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_B_ParamSet 841 +#define OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet OBJ_cryptopro,35L,2L + +#define SN_id_GostR3410_2001_CryptoPro_C_ParamSet "id-GostR3410-2001-CryptoPro-C-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_C_ParamSet 842 +#define OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet OBJ_cryptopro,35L,3L + +#define SN_id_GostR3410_2001_CryptoPro_XchA_ParamSet "id-GostR3410-2001-CryptoPro-XchA-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet 843 +#define OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet OBJ_cryptopro,36L,0L + +#define SN_id_GostR3410_2001_CryptoPro_XchB_ParamSet "id-GostR3410-2001-CryptoPro-XchB-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet 844 +#define OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet OBJ_cryptopro,36L,1L + +#define SN_id_GostR3410_94_a "id-GostR3410-94-a" +#define NID_id_GostR3410_94_a 845 +#define OBJ_id_GostR3410_94_a OBJ_id_GostR3410_94,1L + +#define SN_id_GostR3410_94_aBis "id-GostR3410-94-aBis" +#define NID_id_GostR3410_94_aBis 846 +#define OBJ_id_GostR3410_94_aBis OBJ_id_GostR3410_94,2L + +#define SN_id_GostR3410_94_b "id-GostR3410-94-b" +#define NID_id_GostR3410_94_b 847 +#define OBJ_id_GostR3410_94_b OBJ_id_GostR3410_94,3L + +#define SN_id_GostR3410_94_bBis "id-GostR3410-94-bBis" +#define NID_id_GostR3410_94_bBis 848 +#define OBJ_id_GostR3410_94_bBis OBJ_id_GostR3410_94,4L + +#define SN_id_Gost28147_89_cc "id-Gost28147-89-cc" +#define LN_id_Gost28147_89_cc "GOST 28147-89 Cryptocom ParamSet" +#define NID_id_Gost28147_89_cc 849 +#define OBJ_id_Gost28147_89_cc OBJ_cryptocom,1L,6L,1L + +#define SN_id_GostR3410_94_cc "gost94cc" +#define LN_id_GostR3410_94_cc "GOST 34.10-94 Cryptocom" +#define NID_id_GostR3410_94_cc 850 +#define OBJ_id_GostR3410_94_cc OBJ_cryptocom,1L,5L,3L + +#define SN_id_GostR3410_2001_cc "gost2001cc" +#define LN_id_GostR3410_2001_cc "GOST 34.10-2001 Cryptocom" +#define NID_id_GostR3410_2001_cc 851 +#define OBJ_id_GostR3410_2001_cc OBJ_cryptocom,1L,5L,4L + +#define SN_id_GostR3411_94_with_GostR3410_94_cc "id-GostR3411-94-with-GostR3410-94-cc" +#define LN_id_GostR3411_94_with_GostR3410_94_cc "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom" +#define NID_id_GostR3411_94_with_GostR3410_94_cc 852 +#define OBJ_id_GostR3411_94_with_GostR3410_94_cc OBJ_cryptocom,1L,3L,3L + +#define SN_id_GostR3411_94_with_GostR3410_2001_cc "id-GostR3411-94-with-GostR3410-2001-cc" +#define LN_id_GostR3411_94_with_GostR3410_2001_cc "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom" +#define NID_id_GostR3411_94_with_GostR3410_2001_cc 853 +#define OBJ_id_GostR3411_94_with_GostR3410_2001_cc OBJ_cryptocom,1L,3L,4L + +#define SN_id_GostR3410_2001_ParamSet_cc "id-GostR3410-2001-ParamSet-cc" +#define LN_id_GostR3410_2001_ParamSet_cc "GOST R 3410-2001 Parameter Set Cryptocom" +#define NID_id_GostR3410_2001_ParamSet_cc 854 +#define OBJ_id_GostR3410_2001_ParamSet_cc OBJ_cryptocom,1L,8L,1L + +#define SN_camellia_128_cbc "CAMELLIA-128-CBC" +#define LN_camellia_128_cbc "camellia-128-cbc" +#define NID_camellia_128_cbc 751 +#define OBJ_camellia_128_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,2L + +#define SN_camellia_192_cbc "CAMELLIA-192-CBC" +#define LN_camellia_192_cbc "camellia-192-cbc" +#define NID_camellia_192_cbc 752 +#define OBJ_camellia_192_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,3L + +#define SN_camellia_256_cbc "CAMELLIA-256-CBC" +#define LN_camellia_256_cbc "camellia-256-cbc" +#define NID_camellia_256_cbc 753 +#define OBJ_camellia_256_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,4L + +#define SN_id_camellia128_wrap "id-camellia128-wrap" +#define NID_id_camellia128_wrap 907 +#define OBJ_id_camellia128_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,2L + +#define SN_id_camellia192_wrap "id-camellia192-wrap" +#define NID_id_camellia192_wrap 908 +#define OBJ_id_camellia192_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,3L + +#define SN_id_camellia256_wrap "id-camellia256-wrap" +#define NID_id_camellia256_wrap 909 +#define OBJ_id_camellia256_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,4L + +#define OBJ_ntt_ds 0L,3L,4401L,5L + +#define OBJ_camellia OBJ_ntt_ds,3L,1L,9L + +#define SN_camellia_128_ecb "CAMELLIA-128-ECB" +#define LN_camellia_128_ecb "camellia-128-ecb" +#define NID_camellia_128_ecb 754 +#define OBJ_camellia_128_ecb OBJ_camellia,1L + +#define SN_camellia_128_ofb128 "CAMELLIA-128-OFB" +#define LN_camellia_128_ofb128 "camellia-128-ofb" +#define NID_camellia_128_ofb128 766 +#define OBJ_camellia_128_ofb128 OBJ_camellia,3L + +#define SN_camellia_128_cfb128 "CAMELLIA-128-CFB" +#define LN_camellia_128_cfb128 "camellia-128-cfb" +#define NID_camellia_128_cfb128 757 +#define OBJ_camellia_128_cfb128 OBJ_camellia,4L + +#define SN_camellia_192_ecb "CAMELLIA-192-ECB" +#define LN_camellia_192_ecb "camellia-192-ecb" +#define NID_camellia_192_ecb 755 +#define OBJ_camellia_192_ecb OBJ_camellia,21L + +#define SN_camellia_192_ofb128 "CAMELLIA-192-OFB" +#define LN_camellia_192_ofb128 "camellia-192-ofb" +#define NID_camellia_192_ofb128 767 +#define OBJ_camellia_192_ofb128 OBJ_camellia,23L + +#define SN_camellia_192_cfb128 "CAMELLIA-192-CFB" +#define LN_camellia_192_cfb128 "camellia-192-cfb" +#define NID_camellia_192_cfb128 758 +#define OBJ_camellia_192_cfb128 OBJ_camellia,24L + +#define SN_camellia_256_ecb "CAMELLIA-256-ECB" +#define LN_camellia_256_ecb "camellia-256-ecb" +#define NID_camellia_256_ecb 756 +#define OBJ_camellia_256_ecb OBJ_camellia,41L + +#define SN_camellia_256_ofb128 "CAMELLIA-256-OFB" +#define LN_camellia_256_ofb128 "camellia-256-ofb" +#define NID_camellia_256_ofb128 768 +#define OBJ_camellia_256_ofb128 OBJ_camellia,43L + +#define SN_camellia_256_cfb128 "CAMELLIA-256-CFB" +#define LN_camellia_256_cfb128 "camellia-256-cfb" +#define NID_camellia_256_cfb128 759 +#define OBJ_camellia_256_cfb128 OBJ_camellia,44L + +#define SN_camellia_128_cfb1 "CAMELLIA-128-CFB1" +#define LN_camellia_128_cfb1 "camellia-128-cfb1" +#define NID_camellia_128_cfb1 760 + +#define SN_camellia_192_cfb1 "CAMELLIA-192-CFB1" +#define LN_camellia_192_cfb1 "camellia-192-cfb1" +#define NID_camellia_192_cfb1 761 + +#define SN_camellia_256_cfb1 "CAMELLIA-256-CFB1" +#define LN_camellia_256_cfb1 "camellia-256-cfb1" +#define NID_camellia_256_cfb1 762 + +#define SN_camellia_128_cfb8 "CAMELLIA-128-CFB8" +#define LN_camellia_128_cfb8 "camellia-128-cfb8" +#define NID_camellia_128_cfb8 763 + +#define SN_camellia_192_cfb8 "CAMELLIA-192-CFB8" +#define LN_camellia_192_cfb8 "camellia-192-cfb8" +#define NID_camellia_192_cfb8 764 + +#define SN_camellia_256_cfb8 "CAMELLIA-256-CFB8" +#define LN_camellia_256_cfb8 "camellia-256-cfb8" +#define NID_camellia_256_cfb8 765 + +#define SN_kisa "KISA" +#define LN_kisa "kisa" +#define NID_kisa 773 +#define OBJ_kisa OBJ_member_body,410L,200004L + +#define SN_seed_ecb "SEED-ECB" +#define LN_seed_ecb "seed-ecb" +#define NID_seed_ecb 776 +#define OBJ_seed_ecb OBJ_kisa,1L,3L + +#define SN_seed_cbc "SEED-CBC" +#define LN_seed_cbc "seed-cbc" +#define NID_seed_cbc 777 +#define OBJ_seed_cbc OBJ_kisa,1L,4L + +#define SN_seed_cfb128 "SEED-CFB" +#define LN_seed_cfb128 "seed-cfb" +#define NID_seed_cfb128 779 +#define OBJ_seed_cfb128 OBJ_kisa,1L,5L + +#define SN_seed_ofb128 "SEED-OFB" +#define LN_seed_ofb128 "seed-ofb" +#define NID_seed_ofb128 778 +#define OBJ_seed_ofb128 OBJ_kisa,1L,6L + +#define SN_hmac "HMAC" +#define LN_hmac "hmac" +#define NID_hmac 855 + +#define SN_cmac "CMAC" +#define LN_cmac "cmac" +#define NID_cmac 894 + +#define SN_rc4_hmac_md5 "RC4-HMAC-MD5" +#define LN_rc4_hmac_md5 "rc4-hmac-md5" +#define NID_rc4_hmac_md5 915 + +#define SN_aes_128_cbc_hmac_sha1 "AES-128-CBC-HMAC-SHA1" +#define LN_aes_128_cbc_hmac_sha1 "aes-128-cbc-hmac-sha1" +#define NID_aes_128_cbc_hmac_sha1 916 + +#define SN_aes_192_cbc_hmac_sha1 "AES-192-CBC-HMAC-SHA1" +#define LN_aes_192_cbc_hmac_sha1 "aes-192-cbc-hmac-sha1" +#define NID_aes_192_cbc_hmac_sha1 917 + +#define SN_aes_256_cbc_hmac_sha1 "AES-256-CBC-HMAC-SHA1" +#define LN_aes_256_cbc_hmac_sha1 "aes-256-cbc-hmac-sha1" +#define NID_aes_256_cbc_hmac_sha1 918 + +#define SN_dhpublicnumber "dhpublicnumber" +#define LN_dhpublicnumber "X9.42 DH" +#define NID_dhpublicnumber 920 +#define OBJ_dhpublicnumber OBJ_ISO_US,10046L,2L,1L + +#define SN_brainpoolP160r1 "brainpoolP160r1" +#define NID_brainpoolP160r1 921 +#define OBJ_brainpoolP160r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,1L + +#define SN_brainpoolP160t1 "brainpoolP160t1" +#define NID_brainpoolP160t1 922 +#define OBJ_brainpoolP160t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,2L + +#define SN_brainpoolP192r1 "brainpoolP192r1" +#define NID_brainpoolP192r1 923 +#define OBJ_brainpoolP192r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,3L + +#define SN_brainpoolP192t1 "brainpoolP192t1" +#define NID_brainpoolP192t1 924 +#define OBJ_brainpoolP192t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,4L + +#define SN_brainpoolP224r1 "brainpoolP224r1" +#define NID_brainpoolP224r1 925 +#define OBJ_brainpoolP224r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,5L + +#define SN_brainpoolP224t1 "brainpoolP224t1" +#define NID_brainpoolP224t1 926 +#define OBJ_brainpoolP224t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,6L + +#define SN_brainpoolP256r1 "brainpoolP256r1" +#define NID_brainpoolP256r1 927 +#define OBJ_brainpoolP256r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,7L + +#define SN_brainpoolP256t1 "brainpoolP256t1" +#define NID_brainpoolP256t1 928 +#define OBJ_brainpoolP256t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,8L + +#define SN_brainpoolP320r1 "brainpoolP320r1" +#define NID_brainpoolP320r1 929 +#define OBJ_brainpoolP320r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,9L + +#define SN_brainpoolP320t1 "brainpoolP320t1" +#define NID_brainpoolP320t1 930 +#define OBJ_brainpoolP320t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,10L + +#define SN_brainpoolP384r1 "brainpoolP384r1" +#define NID_brainpoolP384r1 931 +#define OBJ_brainpoolP384r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,11L + +#define SN_brainpoolP384t1 "brainpoolP384t1" +#define NID_brainpoolP384t1 932 +#define OBJ_brainpoolP384t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,12L + +#define SN_brainpoolP512r1 "brainpoolP512r1" +#define NID_brainpoolP512r1 933 +#define OBJ_brainpoolP512r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,13L + +#define SN_brainpoolP512t1 "brainpoolP512t1" +#define NID_brainpoolP512t1 934 +#define OBJ_brainpoolP512t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,14L + +#define OBJ_x9_63_scheme 1L,3L,133L,16L,840L,63L,0L + +#define OBJ_secg_scheme OBJ_certicom_arc,1L + +#define SN_dhSinglePass_stdDH_sha1kdf_scheme "dhSinglePass-stdDH-sha1kdf-scheme" +#define NID_dhSinglePass_stdDH_sha1kdf_scheme 936 +#define OBJ_dhSinglePass_stdDH_sha1kdf_scheme OBJ_x9_63_scheme,2L + +#define SN_dhSinglePass_stdDH_sha224kdf_scheme "dhSinglePass-stdDH-sha224kdf-scheme" +#define NID_dhSinglePass_stdDH_sha224kdf_scheme 937 +#define OBJ_dhSinglePass_stdDH_sha224kdf_scheme OBJ_secg_scheme,11L,0L + +#define SN_dhSinglePass_stdDH_sha256kdf_scheme "dhSinglePass-stdDH-sha256kdf-scheme" +#define NID_dhSinglePass_stdDH_sha256kdf_scheme 938 +#define OBJ_dhSinglePass_stdDH_sha256kdf_scheme OBJ_secg_scheme,11L,1L + +#define SN_dhSinglePass_stdDH_sha384kdf_scheme "dhSinglePass-stdDH-sha384kdf-scheme" +#define NID_dhSinglePass_stdDH_sha384kdf_scheme 939 +#define OBJ_dhSinglePass_stdDH_sha384kdf_scheme OBJ_secg_scheme,11L,2L + +#define SN_dhSinglePass_stdDH_sha512kdf_scheme "dhSinglePass-stdDH-sha512kdf-scheme" +#define NID_dhSinglePass_stdDH_sha512kdf_scheme 940 +#define OBJ_dhSinglePass_stdDH_sha512kdf_scheme OBJ_secg_scheme,11L,3L + +#define SN_dhSinglePass_cofactorDH_sha1kdf_scheme "dhSinglePass-cofactorDH-sha1kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha1kdf_scheme 941 +#define OBJ_dhSinglePass_cofactorDH_sha1kdf_scheme OBJ_x9_63_scheme,3L + +#define SN_dhSinglePass_cofactorDH_sha224kdf_scheme "dhSinglePass-cofactorDH-sha224kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha224kdf_scheme 942 +#define OBJ_dhSinglePass_cofactorDH_sha224kdf_scheme OBJ_secg_scheme,14L,0L + +#define SN_dhSinglePass_cofactorDH_sha256kdf_scheme "dhSinglePass-cofactorDH-sha256kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha256kdf_scheme 943 +#define OBJ_dhSinglePass_cofactorDH_sha256kdf_scheme OBJ_secg_scheme,14L,1L + +#define SN_dhSinglePass_cofactorDH_sha384kdf_scheme "dhSinglePass-cofactorDH-sha384kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha384kdf_scheme 944 +#define OBJ_dhSinglePass_cofactorDH_sha384kdf_scheme OBJ_secg_scheme,14L,2L + +#define SN_dhSinglePass_cofactorDH_sha512kdf_scheme "dhSinglePass-cofactorDH-sha512kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha512kdf_scheme 945 +#define OBJ_dhSinglePass_cofactorDH_sha512kdf_scheme OBJ_secg_scheme,14L,3L + +#define SN_dh_std_kdf "dh-std-kdf" +#define NID_dh_std_kdf 946 + +#define SN_dh_cofactor_kdf "dh-cofactor-kdf" +#define NID_dh_cofactor_kdf 947 + +#define SN_x25519 "X25519" +#define LN_x25519 "x25519" +#define NID_x25519 948 + diff --git a/project/jni/boringssl/include/openssl/objects.h b/project/jni/boringssl/include/openssl/objects.h new file mode 100644 index 000000000..dd6556f26 --- /dev/null +++ b/project/jni/boringssl/include/openssl/objects.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "obj.h" diff --git a/project/jni/boringssl/include/openssl/opensslfeatures.h b/project/jni/boringssl/include/openssl/opensslfeatures.h new file mode 100644 index 000000000..c3f97d5a4 --- /dev/null +++ b/project/jni/boringssl/include/openssl/opensslfeatures.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#ifndef OPENSSL_HEADER_OPENSSLFEATURES_H +#define OPENSSL_HEADER_OPENSSLFEATURES_H + + +#define OPENSSL_NO_BF +#define OPENSSL_NO_BUF_FREELISTS +#define OPENSSL_NO_CAMELLIA +#define OPENSSL_NO_CAPIENG +#define OPENSSL_NO_CAST +#define OPENSSL_NO_CMS +#define OPENSSL_NO_COMP +#define OPENSSL_NO_DANE +#define OPENSSL_NO_DEPRECATED +#define OPENSSL_NO_DYNAMIC_ENGINE +#define OPENSSL_NO_EC_NISTP_64_GCC_128 +#define OPENSSL_NO_EC2M +#define OPENSSL_NO_ENGINE +#define OPENSSL_NO_GMP +#define OPENSSL_NO_GOST +#define OPENSSL_NO_HEARTBEATS +#define OPENSSL_NO_HW +#define OPENSSL_NO_IDEA +#define OPENSSL_NO_JPAKE +#define OPENSSL_NO_KRB5 +#define OPENSSL_NO_MD2 +#define OPENSSL_NO_MDC2 +#define OPENSSL_NO_OCB +#define OPENSSL_NO_OCSP +#define OPENSSL_NO_RC2 +#define OPENSSL_NO_RC5 +#define OPENSSL_NO_RFC3779 +#define OPENSSL_NO_RIPEMD +#define OPENSSL_NO_RMD160 +#define OPENSSL_NO_SCTP +#define OPENSSL_NO_SEED +#define OPENSSL_NO_SRP +#define OPENSSL_NO_SSL2 +#define OPENSSL_NO_STATIC_ENGINE +#define OPENSSL_NO_STORE +#define OPENSSL_NO_WHIRLPOOL + + +#endif /* OPENSSL_HEADER_OPENSSLFEATURES_H */ diff --git a/project/jni/boringssl/include/openssl/opensslv.h b/project/jni/boringssl/include/openssl/opensslv.h new file mode 100644 index 000000000..a3555d4f8 --- /dev/null +++ b/project/jni/boringssl/include/openssl/opensslv.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "crypto.h" diff --git a/project/jni/boringssl/include/openssl/ossl_typ.h b/project/jni/boringssl/include/openssl/ossl_typ.h new file mode 100644 index 000000000..c2b3fe7c5 --- /dev/null +++ b/project/jni/boringssl/include/openssl/ossl_typ.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "base.h" diff --git a/project/jni/boringssl/include/openssl/pem.h b/project/jni/boringssl/include/openssl/pem.h new file mode 100644 index 000000000..a6687a69c --- /dev/null +++ b/project/jni/boringssl/include/openssl/pem.h @@ -0,0 +1,517 @@ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_PEM_H +#define OPENSSL_HEADER_PEM_H + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define PEM_BUFSIZE 1024 + +#define PEM_OBJ_UNDEF 0 +#define PEM_OBJ_X509 1 +#define PEM_OBJ_X509_REQ 2 +#define PEM_OBJ_CRL 3 +#define PEM_OBJ_SSL_SESSION 4 +#define PEM_OBJ_PRIV_KEY 10 +#define PEM_OBJ_PRIV_RSA 11 +#define PEM_OBJ_PRIV_DSA 12 +#define PEM_OBJ_PRIV_DH 13 +#define PEM_OBJ_PUB_RSA 14 +#define PEM_OBJ_PUB_DSA 15 +#define PEM_OBJ_PUB_DH 16 +#define PEM_OBJ_DHPARAMS 17 +#define PEM_OBJ_DSAPARAMS 18 +#define PEM_OBJ_PRIV_RSA_PUBLIC 19 +#define PEM_OBJ_PRIV_ECDSA 20 +#define PEM_OBJ_PUB_ECDSA 21 +#define PEM_OBJ_ECPARAMETERS 22 + +#define PEM_ERROR 30 +#define PEM_DEK_DES_CBC 40 +#define PEM_DEK_IDEA_CBC 45 +#define PEM_DEK_DES_EDE 50 +#define PEM_DEK_DES_ECB 60 +#define PEM_DEK_RSA 70 +#define PEM_DEK_RSA_MD2 80 +#define PEM_DEK_RSA_MD5 90 + +#define PEM_MD_MD2 NID_md2 +#define PEM_MD_MD5 NID_md5 +#define PEM_MD_SHA NID_sha +#define PEM_MD_MD2_RSA NID_md2WithRSAEncryption +#define PEM_MD_MD5_RSA NID_md5WithRSAEncryption +#define PEM_MD_SHA_RSA NID_sha1WithRSAEncryption + +#define PEM_STRING_X509_OLD "X509 CERTIFICATE" +#define PEM_STRING_X509 "CERTIFICATE" +#define PEM_STRING_X509_PAIR "CERTIFICATE PAIR" +#define PEM_STRING_X509_TRUSTED "TRUSTED CERTIFICATE" +#define PEM_STRING_X509_REQ_OLD "NEW CERTIFICATE REQUEST" +#define PEM_STRING_X509_REQ "CERTIFICATE REQUEST" +#define PEM_STRING_X509_CRL "X509 CRL" +#define PEM_STRING_EVP_PKEY "ANY PRIVATE KEY" +#define PEM_STRING_PUBLIC "PUBLIC KEY" +#define PEM_STRING_RSA "RSA PRIVATE KEY" +#define PEM_STRING_RSA_PUBLIC "RSA PUBLIC KEY" +#define PEM_STRING_DSA "DSA PRIVATE KEY" +#define PEM_STRING_DSA_PUBLIC "DSA PUBLIC KEY" +#define PEM_STRING_PKCS7 "PKCS7" +#define PEM_STRING_PKCS7_SIGNED "PKCS #7 SIGNED DATA" +#define PEM_STRING_PKCS8 "ENCRYPTED PRIVATE KEY" +#define PEM_STRING_PKCS8INF "PRIVATE KEY" +#define PEM_STRING_DHPARAMS "DH PARAMETERS" +#define PEM_STRING_SSL_SESSION "SSL SESSION PARAMETERS" +#define PEM_STRING_DSAPARAMS "DSA PARAMETERS" +#define PEM_STRING_ECDSA_PUBLIC "ECDSA PUBLIC KEY" +#define PEM_STRING_ECPRIVATEKEY "EC PRIVATE KEY" +#define PEM_STRING_PARAMETERS "PARAMETERS" +#define PEM_STRING_CMS "CMS" + + /* Note that this structure is initialised by PEM_SealInit and cleaned up + by PEM_SealFinal (at least for now) */ +typedef struct PEM_Encode_Seal_st + { + EVP_ENCODE_CTX encode; + EVP_MD_CTX md; + EVP_CIPHER_CTX cipher; + } PEM_ENCODE_SEAL_CTX; + +/* enc_type is one off */ +#define PEM_TYPE_ENCRYPTED 10 +#define PEM_TYPE_MIC_ONLY 20 +#define PEM_TYPE_MIC_CLEAR 30 +#define PEM_TYPE_CLEAR 40 + +typedef struct pem_recip_st + { + char *name; + X509_NAME *dn; + + int cipher; + int key_enc; + /* char iv[8]; unused and wrong size */ + } PEM_USER; + +typedef struct pem_ctx_st + { + int type; /* what type of object */ + + struct { + int version; + int mode; + } proc_type; + + char *domain; + + struct { + int cipher; + /* unused, and wrong size + unsigned char iv[8]; */ + } DEK_info; + + PEM_USER *originator; + + int num_recipient; + PEM_USER **recipient; + + EVP_MD *md; /* signature type */ + + int md_enc; /* is the md encrypted or not? */ + int md_len; /* length of md_data */ + char *md_data; /* message digest, could be pkey encrypted */ + + EVP_CIPHER *dec; /* date encryption cipher */ + int key_len; /* key length */ + unsigned char *key; /* key */ + /* unused, and wrong size + unsigned char iv[8]; */ + + + int data_enc; /* is the data encrypted */ + int data_len; + unsigned char *data; + } PEM_CTX; + +/* These macros make the PEM_read/PEM_write functions easier to maintain and + * write. Now they are all implemented with either: + * IMPLEMENT_PEM_rw(...) or IMPLEMENT_PEM_rw_cb(...) + */ + +#ifdef OPENSSL_NO_FP_API + +#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) /**/ +#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) /**/ +#define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) /**/ +#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) /**/ +#define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) /**/ + +#else + +#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) \ +OPENSSL_EXPORT type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u)\ +{ \ +return PEM_ASN1_read((d2i_of_void *)d2i_##asn1, str,fp,(void **)x,cb,u); \ +} + +#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x) \ +{ \ +return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,NULL,NULL,0,NULL,NULL); \ +} + +#define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_##name(FILE *fp, const type *x) \ +{ \ +return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,(void *)x,NULL,NULL,0,NULL,NULL); \ +} + +#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, \ + void *u) \ + { \ + return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u); \ + } + +#define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, \ + void *u) \ + { \ + return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u); \ + } + +#endif + +#define IMPLEMENT_PEM_read_bio(name, type, str, asn1) \ +OPENSSL_EXPORT type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u)\ +{ \ +return PEM_ASN1_read_bio((d2i_of_void *)d2i_##asn1, str,bp,(void **)x,cb,u); \ +} + +#define IMPLEMENT_PEM_write_bio(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x) \ +{ \ +return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,x,NULL,NULL,0,NULL,NULL); \ +} + +#define IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, const type *x) \ +{ \ +return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,(void *)x,NULL,NULL,0,NULL,NULL); \ +} + +#define IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \ + { \ + return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,x,enc,kstr,klen,cb,u); \ + } + +#define IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \ + { \ + return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,(void *)x,enc,kstr,klen,cb,u); \ + } + +#define IMPLEMENT_PEM_write(name, type, str, asn1) \ + IMPLEMENT_PEM_write_bio(name, type, str, asn1) \ + IMPLEMENT_PEM_write_fp(name, type, str, asn1) + +#define IMPLEMENT_PEM_write_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) + +#define IMPLEMENT_PEM_write_cb(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) + +#define IMPLEMENT_PEM_write_cb_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) + +#define IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_read_bio(name, type, str, asn1) \ + IMPLEMENT_PEM_read_fp(name, type, str, asn1) + +#define IMPLEMENT_PEM_rw(name, type, str, asn1) \ + IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_write(name, type, str, asn1) + +#define IMPLEMENT_PEM_rw_const(name, type, str, asn1) \ + IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_write_const(name, type, str, asn1) + +#define IMPLEMENT_PEM_rw_cb(name, type, str, asn1) \ + IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb(name, type, str, asn1) + +/* These are the same except they are for the declarations */ + +#if defined(OPENSSL_NO_FP_API) + +#define DECLARE_PEM_read_fp(name, type) /**/ +#define DECLARE_PEM_write_fp(name, type) /**/ +#define DECLARE_PEM_write_cb_fp(name, type) /**/ + +#else + +#define DECLARE_PEM_read_fp(name, type) \ + OPENSSL_EXPORT type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u); + +#define DECLARE_PEM_write_fp(name, type) \ + OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x); + +#define DECLARE_PEM_write_fp_const(name, type) \ + OPENSSL_EXPORT int PEM_write_##name(FILE *fp, const type *x); + +#define DECLARE_PEM_write_cb_fp(name, type) \ + OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u); + +#endif + +#define DECLARE_PEM_read_bio(name, type) \ + OPENSSL_EXPORT type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u); + +#define DECLARE_PEM_write_bio(name, type) \ + OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x); + +#define DECLARE_PEM_write_bio_const(name, type) \ + OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, const type *x); + +#define DECLARE_PEM_write_cb_bio(name, type) \ + OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u); + + +#define DECLARE_PEM_write(name, type) \ + DECLARE_PEM_write_bio(name, type) \ + DECLARE_PEM_write_fp(name, type) + +#define DECLARE_PEM_write_const(name, type) \ + DECLARE_PEM_write_bio_const(name, type) \ + DECLARE_PEM_write_fp_const(name, type) + +#define DECLARE_PEM_write_cb(name, type) \ + DECLARE_PEM_write_cb_bio(name, type) \ + DECLARE_PEM_write_cb_fp(name, type) + +#define DECLARE_PEM_read(name, type) \ + DECLARE_PEM_read_bio(name, type) \ + DECLARE_PEM_read_fp(name, type) + +#define DECLARE_PEM_rw(name, type) \ + DECLARE_PEM_read(name, type) \ + DECLARE_PEM_write(name, type) + +#define DECLARE_PEM_rw_const(name, type) \ + DECLARE_PEM_read(name, type) \ + DECLARE_PEM_write_const(name, type) + +#define DECLARE_PEM_rw_cb(name, type) \ + DECLARE_PEM_read(name, type) \ + DECLARE_PEM_write_cb(name, type) + +/* "userdata": new with OpenSSL 0.9.4 */ +typedef int pem_password_cb(char *buf, int size, int rwflag, void *userdata); + +OPENSSL_EXPORT int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher); +OPENSSL_EXPORT int PEM_do_header (EVP_CIPHER_INFO *cipher, unsigned char *data,long *len, pem_password_cb *callback,void *u); + +OPENSSL_EXPORT int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data,long *len); +OPENSSL_EXPORT int PEM_write_bio(BIO *bp,const char *name, const char *hdr, const unsigned char *data, long len); +OPENSSL_EXPORT int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, const char *name, BIO *bp, pem_password_cb *cb, void *u); +OPENSSL_EXPORT void * PEM_ASN1_read_bio(d2i_of_void *d2i, const char *name, BIO *bp, void **x, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int PEM_ASN1_write_bio(i2d_of_void *i2d,const char *name,BIO *bp, void *x, const EVP_CIPHER *enc,unsigned char *kstr,int klen, pem_password_cb *cb, void *u); + +OPENSSL_EXPORT STACK_OF(X509_INFO) * PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int PEM_X509_INFO_write_bio(BIO *bp,X509_INFO *xi, EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cd, void *u); + +OPENSSL_EXPORT int PEM_read(FILE *fp, char **name, char **header, unsigned char **data,long *len); +OPENSSL_EXPORT int PEM_write(FILE *fp, const char *name, const char *hdr, const unsigned char *data, long len); +OPENSSL_EXPORT void * PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int PEM_ASN1_write(i2d_of_void *i2d,const char *name,FILE *fp, void *x,const EVP_CIPHER *enc,unsigned char *kstr, int klen,pem_password_cb *callback, void *u); +OPENSSL_EXPORT STACK_OF(X509_INFO) * PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u); + +OPENSSL_EXPORT int PEM_SealInit(PEM_ENCODE_SEAL_CTX *ctx, EVP_CIPHER *type, EVP_MD *md_type, unsigned char **ek, int *ekl, unsigned char *iv, EVP_PKEY **pubk, int npubk); +OPENSSL_EXPORT void PEM_SealUpdate(PEM_ENCODE_SEAL_CTX *ctx, unsigned char *out, int *outl, unsigned char *in, int inl); +OPENSSL_EXPORT int PEM_SealFinal(PEM_ENCODE_SEAL_CTX *ctx, unsigned char *sig,int *sigl, unsigned char *out, int *outl, EVP_PKEY *priv); + +OPENSSL_EXPORT void PEM_SignInit(EVP_MD_CTX *ctx, EVP_MD *type); +OPENSSL_EXPORT void PEM_SignUpdate(EVP_MD_CTX *ctx,unsigned char *d,unsigned int cnt); +OPENSSL_EXPORT int PEM_SignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, unsigned int *siglen, EVP_PKEY *pkey); + +/* PEM_def_callback treats |userdata| as a string and copies it into |buf|, + * assuming its |size| is sufficient. Returns the length of the string, or 0 + * if there is not enough room. If either |buf| or |userdata| is NULL, 0 is + * returned. Note that this is different from OpenSSL, which prompts for a + * password. */ +OPENSSL_EXPORT int PEM_def_callback(char *buf, int size, int rwflag, void *userdata); +OPENSSL_EXPORT void PEM_proc_type(char *buf, int type); +OPENSSL_EXPORT void PEM_dek_info(char *buf, const char *type, int len, char *str); + + +DECLARE_PEM_rw(X509, X509) + +DECLARE_PEM_rw(X509_AUX, X509) + +DECLARE_PEM_rw(X509_CERT_PAIR, X509_CERT_PAIR) + +DECLARE_PEM_rw(X509_REQ, X509_REQ) +DECLARE_PEM_write(X509_REQ_NEW, X509_REQ) + +DECLARE_PEM_rw(X509_CRL, X509_CRL) + +/* DECLARE_PEM_rw(PKCS7, PKCS7) */ + +DECLARE_PEM_rw(NETSCAPE_CERT_SEQUENCE, NETSCAPE_CERT_SEQUENCE) + +DECLARE_PEM_rw(PKCS8, X509_SIG) + +DECLARE_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO) + +DECLARE_PEM_rw_cb(RSAPrivateKey, RSA) + +DECLARE_PEM_rw_const(RSAPublicKey, RSA) +DECLARE_PEM_rw(RSA_PUBKEY, RSA) + +#ifndef OPENSSL_NO_DSA + +DECLARE_PEM_rw_cb(DSAPrivateKey, DSA) + +DECLARE_PEM_rw(DSA_PUBKEY, DSA) + +DECLARE_PEM_rw_const(DSAparams, DSA) + +#endif + +DECLARE_PEM_rw_cb(ECPrivateKey, EC_KEY) +DECLARE_PEM_rw(EC_PUBKEY, EC_KEY) + + +DECLARE_PEM_rw_const(DHparams, DH) + + +DECLARE_PEM_rw_cb(PrivateKey, EVP_PKEY) + +DECLARE_PEM_rw(PUBKEY, EVP_PKEY) + +OPENSSL_EXPORT int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid, char *kstr, int klen, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *, char *, int, pem_password_cb *, void *); +OPENSSL_EXPORT int i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, char *kstr, int klen, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid, char *kstr, int klen, pem_password_cb *cb, void *u); +OPENSSL_EXPORT EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u); + +OPENSSL_EXPORT int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, char *kstr, int klen, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid, char *kstr, int klen, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int PEM_write_PKCS8PrivateKey_nid(FILE *fp, EVP_PKEY *x, int nid, char *kstr, int klen, pem_password_cb *cb, void *u); + +OPENSSL_EXPORT EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u); + +OPENSSL_EXPORT int PEM_write_PKCS8PrivateKey(FILE *fp,EVP_PKEY *x,const EVP_CIPHER *enc, char *kstr,int klen, pem_password_cb *cd, void *u); + +OPENSSL_EXPORT EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x); +OPENSSL_EXPORT int PEM_write_bio_Parameters(BIO *bp, EVP_PKEY *x); + + +OPENSSL_EXPORT EVP_PKEY *b2i_PrivateKey(const unsigned char **in, long length); +OPENSSL_EXPORT EVP_PKEY *b2i_PublicKey(const unsigned char **in, long length); +OPENSSL_EXPORT EVP_PKEY *b2i_PrivateKey_bio(BIO *in); +OPENSSL_EXPORT EVP_PKEY *b2i_PublicKey_bio(BIO *in); +OPENSSL_EXPORT int i2b_PrivateKey_bio(BIO *out, EVP_PKEY *pk); +OPENSSL_EXPORT int i2b_PublicKey_bio(BIO *out, EVP_PKEY *pk); +OPENSSL_EXPORT EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int i2b_PVK_bio(BIO *out, EVP_PKEY *pk, int enclevel, pem_password_cb *cb, void *u); + + +void ERR_load_PEM_strings(void); + + +#ifdef __cplusplus +} +#endif + +#define PEM_R_BAD_BASE64_DECODE 100 +#define PEM_R_BAD_DECRYPT 101 +#define PEM_R_BAD_END_LINE 102 +#define PEM_R_BAD_IV_CHARS 103 +#define PEM_R_BAD_PASSWORD_READ 104 +#define PEM_R_CIPHER_IS_NULL 105 +#define PEM_R_ERROR_CONVERTING_PRIVATE_KEY 106 +#define PEM_R_NOT_DEK_INFO 107 +#define PEM_R_NOT_ENCRYPTED 108 +#define PEM_R_NOT_PROC_TYPE 109 +#define PEM_R_NO_START_LINE 110 +#define PEM_R_READ_KEY 111 +#define PEM_R_SHORT_HEADER 112 +#define PEM_R_UNSUPPORTED_CIPHER 113 +#define PEM_R_UNSUPPORTED_ENCRYPTION 114 + +#endif /* OPENSSL_HEADER_PEM_H */ diff --git a/project/jni/boringssl/include/openssl/pkcs12.h b/project/jni/boringssl/include/openssl/pkcs12.h new file mode 100644 index 000000000..b5e951638 --- /dev/null +++ b/project/jni/boringssl/include/openssl/pkcs12.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "pkcs8.h" diff --git a/project/jni/boringssl/include/openssl/pkcs7.h b/project/jni/boringssl/include/openssl/pkcs7.h new file mode 100644 index 000000000..6e5e43307 --- /dev/null +++ b/project/jni/boringssl/include/openssl/pkcs7.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ diff --git a/project/jni/boringssl/include/openssl/pkcs8.h b/project/jni/boringssl/include/openssl/pkcs8.h new file mode 100644 index 000000000..6b51f8550 --- /dev/null +++ b/project/jni/boringssl/include/openssl/pkcs8.h @@ -0,0 +1,220 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#ifndef OPENSSL_HEADER_PKCS8_H +#define OPENSSL_HEADER_PKCS8_H + +#include +#include + + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* PKCS8_encrypt_pbe serializes and encrypts a PKCS8_PRIV_KEY_INFO with PBES1 or + * PBES2 as defined in PKCS #5. Only pbeWithSHAAnd128BitRC4, + * pbeWithSHAAnd3-KeyTripleDES-CBC and pbeWithSHA1And40BitRC2, defined in PKCS + * #12, and PBES2, are supported. PBES2 is selected by setting |cipher| and + * passing -1 for |pbe_nid|. Otherwise, PBES1 is used and |cipher| is ignored. + * + * The |pass_raw_len| bytes pointed to by |pass_raw| are used as the password. + * Note that any conversions from the password as supplied in a text string + * (such as those specified in B.1 of PKCS #12) must be performed by the caller. + * + * If |salt| is NULL, a random salt of |salt_len| bytes is generated. If + * |salt_len| is zero, a default salt length is used instead. + * + * The resulting structure is stored in an X509_SIG which must be freed by the + * caller. + * + * TODO(davidben): Really? An X509_SIG? OpenSSL probably did that because it has + * the same structure as EncryptedPrivateKeyInfo. */ +OPENSSL_EXPORT X509_SIG *PKCS8_encrypt_pbe(int pbe_nid, + const EVP_CIPHER *cipher, + const uint8_t *pass_raw, + size_t pass_raw_len, + uint8_t *salt, size_t salt_len, + int iterations, + PKCS8_PRIV_KEY_INFO *p8inf); + +/* PKCS8_decrypt_pbe decrypts and decodes a PKCS8_PRIV_KEY_INFO with PBES1 or + * PBES2 as defined in PKCS #5. Only pbeWithSHAAnd128BitRC4, + * pbeWithSHAAnd3-KeyTripleDES-CBC and pbeWithSHA1And40BitRC2, and PBES2, + * defined in PKCS #12, are supported. + * + * The |pass_raw_len| bytes pointed to by |pass_raw| are used as the password. + * Note that any conversions from the password as supplied in a text string + * (such as those specified in B.1 of PKCS #12) must be performed by the caller. + * + * The resulting structure must be freed by the caller. */ +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_decrypt_pbe(X509_SIG *pkcs8, + const uint8_t *pass_raw, + size_t pass_raw_len); + +/* PKCS12_get_key_and_certs parses a PKCS#12 structure from |in|, authenticates + * and decrypts it using |password|, sets |*out_key| to the included private + * key and appends the included certificates to |out_certs|. It returns one on + * success and zero on error. The caller takes ownership of the outputs. */ +OPENSSL_EXPORT int PKCS12_get_key_and_certs(EVP_PKEY **out_key, + STACK_OF(X509) *out_certs, + CBS *in, const char *password); + + +/* Deprecated functions. */ + +/* PKCS8_encrypt calls |PKCS8_encrypt_pbe| after (in the PKCS#12 case) treating + * |pass| as an ASCII string, appending U+0000, and converting to UCS-2. (So the + * empty password encodes as two NUL bytes.) In the PBES2 case, the password is + * unchanged. */ +OPENSSL_EXPORT X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, + const char *pass, int pass_len, + uint8_t *salt, size_t salt_len, + int iterations, + PKCS8_PRIV_KEY_INFO *p8inf); + +/* PKCS8_decrypt calls PKCS8_decrypt_pbe after (in the PKCS#12 case) treating + * |pass| as an ASCII string, appending U+0000, and converting to UCS-2. (So the + * empty password encodes as two NUL bytes.) In the PBES2 case, the password is + * unchanged. */ +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, + const char *pass, + int pass_len); + +/* PKCS12_PBE_add does nothing. It exists for compatibility with OpenSSL. */ +OPENSSL_EXPORT void PKCS12_PBE_add(void); + +/* d2i_PKCS12 is a dummy function that copies |*ber_bytes| into a + * |PKCS12| structure. The |out_p12| argument must be NULL. On exit, + * |*ber_bytes| will be advanced by |ber_len|. It returns a fresh |PKCS12| + * structure or NULL on error. + * + * Note: unlike other d2i functions, |d2i_PKCS12| will always consume |ber_len| + * bytes.*/ +OPENSSL_EXPORT PKCS12 *d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes, + size_t ber_len); + +/* d2i_PKCS12_bio acts like |d2i_PKCS12| but reads from a |BIO|. */ +OPENSSL_EXPORT PKCS12* d2i_PKCS12_bio(BIO *bio, PKCS12 **out_p12); + +/* d2i_PKCS12_fp acts like |d2i_PKCS12| but reads from a |FILE|. */ +OPENSSL_EXPORT PKCS12* d2i_PKCS12_fp(FILE *fp, PKCS12 **out_p12); + +/* PKCS12_parse calls |PKCS12_get_key_and_certs| on the ASN.1 data stored in + * |p12|. The |out_pkey| and |out_cert| arguments must not be NULL and, on + * successful exit, the private key and first certificate will be stored in + * them. The |out_ca_certs| argument may be NULL but, if not, then any extra + * certificates will be appended to |*out_ca_certs|. If |*out_ca_certs| is NULL + * then it will be set to a freshly allocated stack containing the extra certs. + * + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS12_parse(const PKCS12 *p12, const char *password, + EVP_PKEY **out_pkey, X509 **out_cert, + STACK_OF(X509) **out_ca_certs); + +/* PKCS12_verify_mac returns one if |password| is a valid password for |p12| + * and zero otherwise. Since |PKCS12_parse| doesn't take a length parameter, + * it's not actually possible to use a non-NUL-terminated password to actually + * get anything from a |PKCS12|. Thus |password| and |password_len| may be + * |NULL| and zero, respectively, or else |password_len| may be -1, or else + * |password[password_len]| must be zero and no other NUL bytes may appear in + * |password|. If the |password_len| checks fail, zero is returned + * immediately. */ +OPENSSL_EXPORT int PKCS12_verify_mac(const PKCS12 *p12, const char *password, + int password_len); + +/* PKCS12_free frees |p12| and its contents. */ +OPENSSL_EXPORT void PKCS12_free(PKCS12 *p12); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define PKCS8_R_BAD_PKCS12_DATA 100 +#define PKCS8_R_BAD_PKCS12_VERSION 101 +#define PKCS8_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 102 +#define PKCS8_R_CRYPT_ERROR 103 +#define PKCS8_R_DECODE_ERROR 104 +#define PKCS8_R_ENCODE_ERROR 105 +#define PKCS8_R_ENCRYPT_ERROR 106 +#define PKCS8_R_ERROR_SETTING_CIPHER_PARAMS 107 +#define PKCS8_R_INCORRECT_PASSWORD 108 +#define PKCS8_R_KEYGEN_FAILURE 109 +#define PKCS8_R_KEY_GEN_ERROR 110 +#define PKCS8_R_METHOD_NOT_SUPPORTED 111 +#define PKCS8_R_MISSING_MAC 112 +#define PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12 113 +#define PKCS8_R_PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED 114 +#define PKCS8_R_PKCS12_TOO_DEEPLY_NESTED 115 +#define PKCS8_R_PRIVATE_KEY_DECODE_ERROR 116 +#define PKCS8_R_PRIVATE_KEY_ENCODE_ERROR 117 +#define PKCS8_R_TOO_LONG 118 +#define PKCS8_R_UNKNOWN_ALGORITHM 119 +#define PKCS8_R_UNKNOWN_CIPHER 120 +#define PKCS8_R_UNKNOWN_CIPHER_ALGORITHM 121 +#define PKCS8_R_UNKNOWN_DIGEST 122 +#define PKCS8_R_UNKNOWN_HASH 123 +#define PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM 124 +#define PKCS8_R_UNSUPPORTED_KEYLENGTH 125 +#define PKCS8_R_UNSUPPORTED_SALT_TYPE 126 +#define PKCS8_R_UNSUPPORTED_CIPHER 127 +#define PKCS8_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION 128 +#define PKCS8_R_BAD_ITERATION_COUNT 129 +#define PKCS8_R_UNSUPPORTED_PRF 130 + +#endif /* OPENSSL_HEADER_PKCS8_H */ diff --git a/project/jni/boringssl/include/openssl/poly1305.h b/project/jni/boringssl/include/openssl/poly1305.h new file mode 100644 index 000000000..b4e23e298 --- /dev/null +++ b/project/jni/boringssl/include/openssl/poly1305.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_POLY1305_H +#define OPENSSL_HEADER_POLY1305_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef uint8_t poly1305_state[512]; + +/* CRYPTO_poly1305_init sets up |state| so that it can be used to calculate an + * authentication tag with the one-time key |key|. Note that |key| is a + * one-time key and therefore there is no `reset' method because that would + * enable several messages to be authenticated with the same key. */ +OPENSSL_EXPORT void CRYPTO_poly1305_init(poly1305_state* state, + const uint8_t key[32]); + +/* CRYPTO_poly1305_update processes |in_len| bytes from |in|. It can be called + * zero or more times after poly1305_init. */ +OPENSSL_EXPORT void CRYPTO_poly1305_update(poly1305_state* state, + const uint8_t* in, + size_t in_len); + +/* CRYPTO_poly1305_finish completes the poly1305 calculation and writes a 16 + * byte authentication tag to |mac|. The |mac| address must be 16-byte + * aligned. */ +OPENSSL_EXPORT void CRYPTO_poly1305_finish(poly1305_state* state, + uint8_t mac[16]); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_POLY1305_H */ diff --git a/project/jni/boringssl/include/openssl/pqueue.h b/project/jni/boringssl/include/openssl/pqueue.h new file mode 100644 index 000000000..ceb1fa2a7 --- /dev/null +++ b/project/jni/boringssl/include/openssl/pqueue.h @@ -0,0 +1,146 @@ +/* + * DTLS implementation written by Nagendra Modadugu + * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. + */ +/* ==================================================================== + * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_PQUEUE_H +#define OPENSSL_HEADER_PQUEUE_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Priority queue. + * + * The priority queue maintains a linked-list of nodes, each with a unique, + * 64-bit priority, in ascending priority order. */ + +typedef struct _pqueue *pqueue; + +typedef struct _pitem { + uint8_t priority[8]; /* 64-bit value in big-endian encoding */ + void *data; + struct _pitem *next; +} pitem; + +typedef struct _pitem *piterator; + + +/* Creating and freeing queues. */ + +/* pqueue_new allocates a fresh, empty priority queue object and returns it, or + * NULL on error. */ +OPENSSL_EXPORT pqueue pqueue_new(void); + +/* pqueue_free frees |pq| but not any of the items it points to. Thus |pq| must + * be empty or a memory leak will occur. */ +OPENSSL_EXPORT void pqueue_free(pqueue pq); + + +/* Creating and freeing items. */ + +/* pitem_new allocates a fresh priority queue item that points at |data| and + * has a priority given by |prio64be|, which is a 64-bit, unsigned number + * expressed in big-endian form. It returns the fresh item, or NULL on + * error. */ +OPENSSL_EXPORT pitem *pitem_new(uint8_t prio64be[8], void *data); + +/* pitem_free frees |item|, but not any data that it points to. */ +OPENSSL_EXPORT void pitem_free(pitem *item); + + +/* Queue accessor functions */ + +/* pqueue_peek returns the item with the smallest priority from |pq|, or NULL + * if empty. */ +OPENSSL_EXPORT pitem *pqueue_peek(pqueue pq); + +/* pqueue_find returns the item whose priority matches |prio64be| or NULL if no + * such item exists. */ +OPENSSL_EXPORT pitem *pqueue_find(pqueue pq, uint8_t *prio64be); + + +/* Queue mutation functions */ + +/* pqueue_insert inserts |item| into |pq| and returns item. */ +OPENSSL_EXPORT pitem *pqueue_insert(pqueue pq, pitem *item); + +/* pqueue_pop takes the item with the least priority from |pq| and returns it, + * or NULL if |pq| is empty. */ +OPENSSL_EXPORT pitem *pqueue_pop(pqueue pq); + +/* pqueue_size returns the number of items in |pq|. */ +OPENSSL_EXPORT size_t pqueue_size(pqueue pq); + + +/* Iterating */ + +/* pqueue_iterator returns an iterator that can be used to iterate over the + * contents of the queue. */ +OPENSSL_EXPORT piterator pqueue_iterator(pqueue pq); + +/* pqueue_next returns the current value of |iter| and advances it to the next + * position. If the iterator has advanced over all the elements, it returns + * NULL. */ +OPENSSL_EXPORT pitem *pqueue_next(piterator *iter); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_PQUEUE_H */ diff --git a/project/jni/boringssl/include/openssl/rand.h b/project/jni/boringssl/include/openssl/rand.h new file mode 100644 index 000000000..3a8e357cc --- /dev/null +++ b/project/jni/boringssl/include/openssl/rand.h @@ -0,0 +1,113 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_RAND_H +#define OPENSSL_HEADER_RAND_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Random number generation. */ + + +/* RAND_bytes writes |len| bytes of random data to |buf| and returns one. */ +OPENSSL_EXPORT int RAND_bytes(uint8_t *buf, size_t len); + +/* RAND_cleanup frees any resources used by the RNG. This is not safe if other + * threads might still be calling |RAND_bytes|. */ +OPENSSL_EXPORT void RAND_cleanup(void); + + +/* Obscure functions. */ + +#if !defined(OPENSSL_WINDOWS) +/* RAND_set_urandom_fd causes the module to use a copy of |fd| for system + * randomness rather opening /dev/urandom internally. The caller retains + * ownership of |fd| and is at liberty to close it at any time. This is useful + * if, due to a sandbox, /dev/urandom isn't available. If used, it must be + * called before the first call to |RAND_bytes|, and it is mutually exclusive + * with |RAND_enable_fork_unsafe_buffering|. + * + * |RAND_set_urandom_fd| does not buffer any entropy, so it is safe to call + * |fork| at any time after calling |RAND_set_urandom_fd|. */ +OPENSSL_EXPORT void RAND_set_urandom_fd(int fd); + +/* RAND_enable_fork_unsafe_buffering enables efficient buffered reading of + * /dev/urandom. It adds an overhead of a few KB of memory per thread. It must + * be called before the first call to |RAND_bytes| and it is mutually exclusive + * with calls to |RAND_set_urandom_fd|. + * + * If |fd| is non-negative then a copy of |fd| will be used rather than opening + * /dev/urandom internally. Like |RAND_set_urandom_fd|, the caller retains + * ownership of |fd|. If |fd| is negative then /dev/urandom will be opened and + * any error from open(2) crashes the address space. + * + * It has an unusual name because the buffer is unsafe across calls to |fork|. + * Hence, this function should never be called by libraries. */ +OPENSSL_EXPORT void RAND_enable_fork_unsafe_buffering(int fd); +#endif + + +/* Deprecated functions */ + +/* RAND_pseudo_bytes is a wrapper around |RAND_bytes|. */ +OPENSSL_EXPORT int RAND_pseudo_bytes(uint8_t *buf, size_t len); + +/* RAND_seed reads a single byte of random data to ensure that any file + * descriptors etc are opened. */ +OPENSSL_EXPORT void RAND_seed(const void *buf, int num); + +/* RAND_load_file returns a nonnegative number. */ +OPENSSL_EXPORT int RAND_load_file(const char *path, long num); + +/* RAND_add does nothing. */ +OPENSSL_EXPORT void RAND_add(const void *buf, int num, double entropy); + +/* RAND_egd returns 255. */ +OPENSSL_EXPORT int RAND_egd(const char *); + +/* RAND_poll returns one. */ +OPENSSL_EXPORT int RAND_poll(void); + +/* RAND_status returns one. */ +OPENSSL_EXPORT int RAND_status(void); + +/* rand_meth_st is typedefed to |RAND_METHOD| in base.h. It isn't used; it + * exists only to be the return type of |RAND_SSLeay|. It's + * external so that variables of this type can be initialized. */ +struct rand_meth_st { + void (*seed) (const void *buf, int num); + int (*bytes) (uint8_t *buf, size_t num); + void (*cleanup) (void); + void (*add) (const void *buf, int num, double entropy); + int (*pseudorand) (uint8_t *buf, size_t num); + int (*status) (void); +}; + +/* RAND_SSLeay returns a pointer to a dummy |RAND_METHOD|. */ +OPENSSL_EXPORT RAND_METHOD *RAND_SSLeay(void); + +/* RAND_set_rand_method does nothing. */ +OPENSSL_EXPORT void RAND_set_rand_method(const RAND_METHOD *); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_RAND_H */ diff --git a/project/jni/boringssl/include/openssl/rc4.h b/project/jni/boringssl/include/openssl/rc4.h new file mode 100644 index 000000000..0619cac35 --- /dev/null +++ b/project/jni/boringssl/include/openssl/rc4.h @@ -0,0 +1,90 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_RC4_H +#define OPENSSL_HEADER_RC4_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* RC4. */ + + +struct rc4_key_st { + uint32_t x, y; + uint32_t data[256]; +} /* RC4_KEY */; + +/* RC4_set_key performs an RC4 key schedule and initialises |rc4key| with |len| + * bytes of key material from |key|. */ +OPENSSL_EXPORT void RC4_set_key(RC4_KEY *rc4key, unsigned len, + const uint8_t *key); + +/* RC4 encrypts (or decrypts, it's the same with RC4) |len| bytes from |in| to + * |out|. */ +OPENSSL_EXPORT void RC4(RC4_KEY *key, size_t len, const uint8_t *in, + uint8_t *out); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_RC4_H */ diff --git a/project/jni/boringssl/include/openssl/rsa.h b/project/jni/boringssl/include/openssl/rsa.h new file mode 100644 index 000000000..304c5558c --- /dev/null +++ b/project/jni/boringssl/include/openssl/rsa.h @@ -0,0 +1,637 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_RSA_H +#define OPENSSL_HEADER_RSA_H + +#include + +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* rsa.h contains functions for handling encryption and signature using RSA. */ + + +/* Allocation and destruction. */ + +/* RSA_new returns a new, empty RSA object or NULL on error. */ +OPENSSL_EXPORT RSA *RSA_new(void); + +/* RSA_new_method acts the same as |RSA_new| but takes an explicit |ENGINE|. */ +OPENSSL_EXPORT RSA *RSA_new_method(const ENGINE *engine); + +/* RSA_free decrements the reference count of |rsa| and frees it if the + * reference count drops to zero. */ +OPENSSL_EXPORT void RSA_free(RSA *rsa); + +/* RSA_up_ref increments the reference count of |rsa|. */ +OPENSSL_EXPORT int RSA_up_ref(RSA *rsa); + + +/* Key generation. */ + +/* RSA_generate_key_ex generates a new RSA key where the modulus has size + * |bits| and the public exponent is |e|. If unsure, |RSA_F4| is a good value + * for |e|. If |cb| is not NULL then it is called during the key generation + * process. In addition to the calls documented for |BN_generate_prime_ex|, it + * is called with event=2 when the n'th prime is rejected as unsuitable and + * with event=3 when a suitable value for |p| is found. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, + BN_GENCB *cb); + +/* RSA_generate_multi_prime_key acts like |RSA_generate_key_ex| but can + * generate an RSA private key with more than two primes. */ +OPENSSL_EXPORT int RSA_generate_multi_prime_key(RSA *rsa, int bits, + int num_primes, BIGNUM *e, + BN_GENCB *cb); + + +/* Encryption / Decryption */ + +/* Padding types for encryption. */ +#define RSA_PKCS1_PADDING 1 +#define RSA_NO_PADDING 3 +#define RSA_PKCS1_OAEP_PADDING 4 +/* RSA_PKCS1_PSS_PADDING can only be used via the EVP interface. */ +#define RSA_PKCS1_PSS_PADDING 6 + +/* RSA_encrypt encrypts |in_len| bytes from |in| to the public key from |rsa| + * and writes, at most, |max_out| bytes of encrypted data to |out|. The + * |max_out| argument must be, at least, |RSA_size| in order to ensure success. + * + * It returns 1 on success or zero on error. + * + * The |padding| argument must be one of the |RSA_*_PADDING| values. If in + * doubt, use |RSA_PKCS1_OAEP_PADDING| for new protocols but + * |RSA_PKCS1_PADDING| is most common. */ +OPENSSL_EXPORT int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, + size_t max_out, const uint8_t *in, size_t in_len, + int padding); + +/* RSA_decrypt decrypts |in_len| bytes from |in| with the private key from + * |rsa| and writes, at most, |max_out| bytes of plaintext to |out|. The + * |max_out| argument must be, at least, |RSA_size| in order to ensure success. + * + * It returns 1 on success or zero on error. + * + * The |padding| argument must be one of the |RSA_*_PADDING| values. If in + * doubt, use |RSA_PKCS1_OAEP_PADDING| for new protocols. + * + * Passing |RSA_PKCS1_PADDING| into this function is deprecated and insecure. If + * implementing a protocol using RSAES-PKCS1-V1_5, use |RSA_NO_PADDING| and then + * check padding in constant-time combined with a swap to a random session key + * or other mitigation. See "Chosen Ciphertext Attacks Against Protocols Based + * on the RSA Encryption Standard PKCS #1", Daniel Bleichenbacher, Advances in + * Cryptology (Crypto '98). */ +OPENSSL_EXPORT int RSA_decrypt(RSA *rsa, size_t *out_len, uint8_t *out, + size_t max_out, const uint8_t *in, size_t in_len, + int padding); + +/* RSA_public_encrypt encrypts |flen| bytes from |from| to the public key in + * |rsa| and writes the encrypted data to |to|. The |to| buffer must have at + * least |RSA_size| bytes of space. It returns the number of bytes written, or + * -1 on error. The |padding| argument must be one of the |RSA_*_PADDING| + * values. If in doubt, use |RSA_PKCS1_OAEP_PADDING| for new protocols but + * |RSA_PKCS1_PADDING| is most common. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use |RSA_encrypt| instead. */ +OPENSSL_EXPORT int RSA_public_encrypt(size_t flen, const uint8_t *from, + uint8_t *to, RSA *rsa, int padding); + +/* RSA_private_decrypt decrypts |flen| bytes from |from| with the public key in + * |rsa| and writes the plaintext to |to|. The |to| buffer must have at least + * |RSA_size| bytes of space. It returns the number of bytes written, or -1 on + * error. The |padding| argument must be one of the |RSA_*_PADDING| values. If + * in doubt, use |RSA_PKCS1_OAEP_PADDING| for new protocols. Passing + * |RSA_PKCS1_PADDING| into this function is deprecated and insecure. See + * |RSA_decrypt|. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use |RSA_decrypt| instead. */ +OPENSSL_EXPORT int RSA_private_decrypt(size_t flen, const uint8_t *from, + uint8_t *to, RSA *rsa, int padding); + + +/* Signing / Verification */ + +/* RSA_sign signs |in_len| bytes of digest from |in| with |rsa| using + * RSASSA-PKCS1-v1_5. It writes, at most, |RSA_size(rsa)| bytes to |out|. On + * successful return, the actual number of bytes written is written to + * |*out_len|. + * + * The |hash_nid| argument identifies the hash function used to calculate |in| + * and is embedded in the resulting signature. For example, it might be + * |NID_sha256|. + * + * It returns 1 on success and zero on error. */ +OPENSSL_EXPORT int RSA_sign(int hash_nid, const uint8_t *in, + unsigned int in_len, uint8_t *out, + unsigned int *out_len, RSA *rsa); + +/* RSA_sign_raw signs |in_len| bytes from |in| with the public key from |rsa| + * and writes, at most, |max_out| bytes of signature data to |out|. The + * |max_out| argument must be, at least, |RSA_size| in order to ensure success. + * + * It returns 1 on success or zero on error. + * + * The |padding| argument must be one of the |RSA_*_PADDING| values. If in + * doubt, |RSA_PKCS1_PADDING| is the most common but |RSA_PKCS1_PSS_PADDING| + * (via the |EVP_PKEY| interface) is preferred for new protocols. */ +OPENSSL_EXPORT int RSA_sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, + size_t max_out, const uint8_t *in, + size_t in_len, int padding); + +/* RSA_verify verifies that |sig_len| bytes from |sig| are a valid, + * RSASSA-PKCS1-v1_5 signature of |msg_len| bytes at |msg| by |rsa|. + * + * The |hash_nid| argument identifies the hash function used to calculate |in| + * and is embedded in the resulting signature in order to prevent hash + * confusion attacks. For example, it might be |NID_sha256|. + * + * It returns one if the signature is valid and zero otherwise. + * + * WARNING: this differs from the original, OpenSSL function which additionally + * returned -1 on error. */ +OPENSSL_EXPORT int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len, + const uint8_t *sig, size_t sig_len, RSA *rsa); + +/* RSA_verify_raw verifies |in_len| bytes of signature from |in| using the + * public key from |rsa| and writes, at most, |max_out| bytes of plaintext to + * |out|. The |max_out| argument must be, at least, |RSA_size| in order to + * ensure success. + * + * It returns 1 on success or zero on error. + * + * The |padding| argument must be one of the |RSA_*_PADDING| values. If in + * doubt, |RSA_PKCS1_PADDING| is the most common but |RSA_PKCS1_PSS_PADDING| + * (via the |EVP_PKEY| interface) is preferred for new protocols. */ +OPENSSL_EXPORT int RSA_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, + size_t max_out, const uint8_t *in, + size_t in_len, int padding); + +/* RSA_private_encrypt encrypts |flen| bytes from |from| with the private key in + * |rsa| and writes the encrypted data to |to|. The |to| buffer must have at + * least |RSA_size| bytes of space. It returns the number of bytes written, or + * -1 on error. The |padding| argument must be one of the |RSA_*_PADDING| + * values. If in doubt, |RSA_PKCS1_PADDING| is the most common but + * |RSA_PKCS1_PSS_PADDING| (via the |EVP_PKEY| interface) is preferred for new + * protocols. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use |RSA_sign_raw| instead. */ +OPENSSL_EXPORT int RSA_private_encrypt(size_t flen, const uint8_t *from, + uint8_t *to, RSA *rsa, int padding); + +/* RSA_public_decrypt verifies |flen| bytes of signature from |from| using the + * public key in |rsa| and writes the plaintext to |to|. The |to| buffer must + * have at least |RSA_size| bytes of space. It returns the number of bytes + * written, or -1 on error. The |padding| argument must be one of the + * |RSA_*_PADDING| values. If in doubt, |RSA_PKCS1_PADDING| is the most common + * but |RSA_PKCS1_PSS_PADDING| (via the |EVP_PKEY| interface) is preferred for + * new protocols. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use |RSA_verify_raw| instead. */ +OPENSSL_EXPORT int RSA_public_decrypt(size_t flen, const uint8_t *from, + uint8_t *to, RSA *rsa, int padding); + + +/* Utility functions. */ + +/* RSA_size returns the number of bytes in the modulus, which is also the size + * of a signature or encrypted value using |rsa|. */ +OPENSSL_EXPORT unsigned RSA_size(const RSA *rsa); + +/* RSA_is_opaque returns one if |rsa| is opaque and doesn't expose its key + * material. Otherwise it returns zero. */ +OPENSSL_EXPORT int RSA_is_opaque(const RSA *rsa); + +/* RSA_supports_digest returns one if |rsa| supports signing digests + * of type |md|. Otherwise it returns zero. */ +OPENSSL_EXPORT int RSA_supports_digest(const RSA *rsa, const EVP_MD *md); + +/* RSAPublicKey_dup allocates a fresh |RSA| and copies the public key from + * |rsa| into it. It returns the fresh |RSA| object, or NULL on error. */ +OPENSSL_EXPORT RSA *RSAPublicKey_dup(const RSA *rsa); + +/* RSAPrivateKey_dup allocates a fresh |RSA| and copies the private key from + * |rsa| into it. It returns the fresh |RSA| object, or NULL on error. */ +OPENSSL_EXPORT RSA *RSAPrivateKey_dup(const RSA *rsa); + +/* RSA_check_key performs basic validatity tests on |rsa|. It returns one if + * they pass and zero otherwise. Opaque keys and public keys always pass. If it + * returns zero then a more detailed error is available on the error queue. */ +OPENSSL_EXPORT int RSA_check_key(const RSA *rsa); + +/* RSA_recover_crt_params uses |rsa->n|, |rsa->d| and |rsa->e| in order to + * calculate the two primes used and thus the precomputed, CRT values. These + * values are set in the |p|, |q|, |dmp1|, |dmq1| and |iqmp| members of |rsa|, + * which must be |NULL| on entry. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int RSA_recover_crt_params(RSA *rsa); + +/* RSA_verify_PKCS1_PSS_mgf1 verifies that |EM| is a correct PSS padding of + * |mHash|, where |mHash| is a digest produced by |Hash|. |EM| must point to + * exactly |RSA_size(rsa)| bytes of data. The |mgf1Hash| argument specifies the + * hash function for generating the mask. If NULL, |Hash| is used. The |sLen| + * argument specifies the expected salt length in bytes. If |sLen| is -1 then + * the salt length is the same as the hash length. If -2, then the salt length + * is maximal and is taken from the size of |EM|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash, + const EVP_MD *Hash, + const EVP_MD *mgf1Hash, + const uint8_t *EM, int sLen); + +/* RSA_padding_add_PKCS1_PSS_mgf1 writes a PSS padding of |mHash| to |EM|, + * where |mHash| is a digest produced by |Hash|. |RSA_size(rsa)| bytes of + * output will be written to |EM|. The |mgf1Hash| argument specifies the hash + * function for generating the mask. If NULL, |Hash| is used. The |sLen| + * argument specifies the expected salt length in bytes. If |sLen| is -1 then + * the salt length is the same as the hash length. If -2, then the salt length + * is maximal given the space in |EM|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, uint8_t *EM, + const uint8_t *mHash, + const EVP_MD *Hash, + const EVP_MD *mgf1Hash, + int sLen); + +/* RSA_add_pkcs1_prefix builds a version of |msg| prefixed with the DigestInfo + * header for the given hash function and sets |out_msg| to point to it. On + * successful return, |*out_msg| may be allocated memory and, if so, + * |*is_alloced| will be 1. */ +OPENSSL_EXPORT int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len, + int *is_alloced, int hash_nid, + const uint8_t *msg, size_t msg_len); + + +/* ASN.1 functions. */ + +/* RSA_parse_public_key parses a DER-encoded RSAPublicKey structure (RFC 3447) + * from |cbs| and advances |cbs|. It returns a newly-allocated |RSA| or NULL on + * error. */ +OPENSSL_EXPORT RSA *RSA_parse_public_key(CBS *cbs); + +/* RSA_parse_public_key_buggy behaves like |RSA_parse_public_key|, but it + * tolerates some invalid encodings. Do not use this function. */ +OPENSSL_EXPORT RSA *RSA_parse_public_key_buggy(CBS *cbs); + +/* RSA_public_key_from_bytes parses |in| as a DER-encoded RSAPublicKey structure + * (RFC 3447). It returns a newly-allocated |RSA| or NULL on error. */ +OPENSSL_EXPORT RSA *RSA_public_key_from_bytes(const uint8_t *in, size_t in_len); + +/* RSA_marshal_public_key marshals |rsa| as a DER-encoded RSAPublicKey structure + * (RFC 3447) and appends the result to |cbb|. It returns one on success and + * zero on failure. */ +OPENSSL_EXPORT int RSA_marshal_public_key(CBB *cbb, const RSA *rsa); + +/* RSA_public_key_to_bytes marshals |rsa| as a DER-encoded RSAPublicKey + * structure (RFC 3447) and, on success, sets |*out_bytes| to a newly allocated + * buffer containing the result and returns one. Otherwise, it returns zero. The + * result should be freed with |OPENSSL_free|. */ +OPENSSL_EXPORT int RSA_public_key_to_bytes(uint8_t **out_bytes, size_t *out_len, + const RSA *rsa); + +/* RSA_parse_private_key parses a DER-encoded RSAPrivateKey structure (RFC 3447) + * from |cbs| and advances |cbs|. It returns a newly-allocated |RSA| or NULL on + * error. */ +OPENSSL_EXPORT RSA *RSA_parse_private_key(CBS *cbs); + +/* RSA_private_key_from_bytes parses |in| as a DER-encoded RSAPrivateKey + * structure (RFC 3447). It returns a newly-allocated |RSA| or NULL on error. */ +OPENSSL_EXPORT RSA *RSA_private_key_from_bytes(const uint8_t *in, + size_t in_len); + +/* RSA_marshal_private_key marshals |rsa| as a DER-encoded RSAPrivateKey + * structure (RFC 3447) and appends the result to |cbb|. It returns one on + * success and zero on failure. */ +OPENSSL_EXPORT int RSA_marshal_private_key(CBB *cbb, const RSA *rsa); + +/* RSA_private_key_to_bytes marshals |rsa| as a DER-encoded RSAPrivateKey + * structure (RFC 3447) and, on success, sets |*out_bytes| to a newly allocated + * buffer containing the result and returns one. Otherwise, it returns zero. The + * result should be freed with |OPENSSL_free|. */ +OPENSSL_EXPORT int RSA_private_key_to_bytes(uint8_t **out_bytes, + size_t *out_len, const RSA *rsa); + + +/* ex_data functions. + * + * See |ex_data.h| for details. */ + +OPENSSL_EXPORT int RSA_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_unused *unused, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int RSA_set_ex_data(RSA *r, int idx, void *arg); +OPENSSL_EXPORT void *RSA_get_ex_data(const RSA *r, int idx); + + +/* Flags. */ + +/* RSA_FLAG_OPAQUE specifies that this RSA_METHOD does not expose its key + * material. This may be set if, for instance, it is wrapping some other crypto + * API, like a platform key store. */ +#define RSA_FLAG_OPAQUE 1 + +/* RSA_FLAG_CACHE_PUBLIC causes a precomputed Montgomery context to be created, + * on demand, for the public key operations. */ +#define RSA_FLAG_CACHE_PUBLIC 2 + +/* RSA_FLAG_CACHE_PRIVATE causes a precomputed Montgomery context to be + * created, on demand, for the private key operations. */ +#define RSA_FLAG_CACHE_PRIVATE 4 + +/* RSA_FLAG_NO_BLINDING disables blinding of private operations. */ +#define RSA_FLAG_NO_BLINDING 8 + +/* RSA_FLAG_EXT_PKEY means that private key operations will be handled by + * |mod_exp| and that they do not depend on the private key components being + * present: for example a key stored in external hardware. */ +#define RSA_FLAG_EXT_PKEY 0x20 + +/* RSA_FLAG_SIGN_VER causes the |sign| and |verify| functions of |rsa_meth_st| + * to be called when set. */ +#define RSA_FLAG_SIGN_VER 0x40 + + +/* RSA public exponent values. */ + +#define RSA_3 0x3 +#define RSA_F4 0x10001 + + +/* Deprecated functions. */ + +/* RSA_blinding_on returns one. */ +OPENSSL_EXPORT int RSA_blinding_on(RSA *rsa, BN_CTX *ctx); + +/* RSA_generate_key behaves like |RSA_generate_key_ex|, which is what you + * should use instead. It returns NULL on error, or a newly-allocated |RSA| on + * success. This function is provided for compatibility only. The |callback| + * and |cb_arg| parameters must be NULL. */ +OPENSSL_EXPORT RSA *RSA_generate_key(int bits, unsigned long e, void *callback, + void *cb_arg); + +/* d2i_RSAPublicKey parses an ASN.1, DER-encoded, RSA public key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. If |*out| is already non-NULL on entry then the result is + * written directly into |*out|, otherwise a fresh |RSA| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT RSA *d2i_RSAPublicKey(RSA **out, const uint8_t **inp, long len); + +/* i2d_RSAPublicKey marshals |in| to an ASN.1, DER structure. If |outp| is not + * NULL then the result is written to |*outp| and |*outp| is advanced just past + * the output. It returns the number of bytes in the result, whether written or + * not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_RSAPublicKey(const RSA *in, uint8_t **outp); + +/* d2i_RSAPrivateKey parses an ASN.1, DER-encoded, RSA private key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. If |*out| is already non-NULL on entry then the result is + * written directly into |*out|, otherwise a fresh |RSA| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT RSA *d2i_RSAPrivateKey(RSA **out, const uint8_t **inp, long len); + +/* i2d_RSAPrivateKey marshals |in| to an ASN.1, DER structure. If |outp| is not + * NULL then the result is written to |*outp| and |*outp| is advanced just past + * the output. It returns the number of bytes in the result, whether written or + * not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_RSAPrivateKey(const RSA *in, uint8_t **outp); + +typedef struct rsa_pss_params_st { + X509_ALGOR *hashAlgorithm; + X509_ALGOR *maskGenAlgorithm; + ASN1_INTEGER *saltLength; + ASN1_INTEGER *trailerField; +} RSA_PSS_PARAMS; + +DECLARE_ASN1_FUNCTIONS(RSA_PSS_PARAMS) + + +struct rsa_meth_st { + struct openssl_method_common_st common; + + void *app_data; + + int (*init)(RSA *rsa); + int (*finish)(RSA *rsa); + + /* size returns the size of the RSA modulus in bytes. */ + size_t (*size)(const RSA *rsa); + + int (*sign)(int type, const uint8_t *m, unsigned int m_length, + uint8_t *sigret, unsigned int *siglen, const RSA *rsa); + + int (*verify)(int dtype, const uint8_t *m, unsigned int m_length, + const uint8_t *sigbuf, unsigned int siglen, const RSA *rsa); + + + /* These functions mirror the |RSA_*| functions of the same name. */ + int (*encrypt)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding); + int (*sign_raw)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding); + + int (*decrypt)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding); + int (*verify_raw)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding); + + /* private_transform takes a big-endian integer from |in|, calculates the + * d'th power of it, modulo the RSA modulus and writes the result as a + * big-endian integer to |out|. Both |in| and |out| are |len| bytes long and + * |len| is always equal to |RSA_size(rsa)|. If the result of the transform + * can be represented in fewer than |len| bytes, then |out| must be zero + * padded on the left. + * + * It returns one on success and zero otherwise. + * + * RSA decrypt and sign operations will call this, thus an ENGINE might wish + * to override it in order to avoid having to implement the padding + * functionality demanded by those, higher level, operations. */ + int (*private_transform)(RSA *rsa, uint8_t *out, const uint8_t *in, + size_t len); + + int (*mod_exp)(BIGNUM *r0, const BIGNUM *I, RSA *rsa, + BN_CTX *ctx); /* Can be null */ + int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + const BN_MONT_CTX *mont); + + int flags; + + int (*keygen)(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb); + + int (*multi_prime_keygen)(RSA *rsa, int bits, int num_primes, BIGNUM *e, + BN_GENCB *cb); + + /* supports_digest returns one if |rsa| supports digests of type + * |md|. If null, it is assumed that all digests are supported. */ + int (*supports_digest)(const RSA *rsa, const EVP_MD *md); +}; + + +/* Private functions. */ + +typedef struct bn_blinding_st BN_BLINDING; + +struct rsa_st { + RSA_METHOD *meth; + + BIGNUM *n; + BIGNUM *e; + BIGNUM *d; + BIGNUM *p; + BIGNUM *q; + BIGNUM *dmp1; + BIGNUM *dmq1; + BIGNUM *iqmp; + + STACK_OF(RSA_additional_prime) *additional_primes; + + /* be careful using this if the RSA structure is shared */ + CRYPTO_EX_DATA ex_data; + CRYPTO_refcount_t references; + int flags; + + CRYPTO_MUTEX lock; + + /* Used to cache montgomery values. The creation of these values is protected + * by |lock|. */ + BN_MONT_CTX *mont_n; + BN_MONT_CTX *mont_p; + BN_MONT_CTX *mont_q; + + /* num_blindings contains the size of the |blindings| and |blindings_inuse| + * arrays. This member and the |blindings_inuse| array are protected by + * |lock|. */ + unsigned num_blindings; + /* blindings is an array of BN_BLINDING structures that can be reserved by a + * thread by locking |lock| and changing the corresponding element in + * |blindings_inuse| from 0 to 1. */ + BN_BLINDING **blindings; + unsigned char *blindings_inuse; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define RSA_R_BAD_E_VALUE 100 +#define RSA_R_BAD_FIXED_HEADER_DECRYPT 101 +#define RSA_R_BAD_PAD_BYTE_COUNT 102 +#define RSA_R_BAD_RSA_PARAMETERS 103 +#define RSA_R_BAD_SIGNATURE 104 +#define RSA_R_BLOCK_TYPE_IS_NOT_01 105 +#define RSA_R_BN_NOT_INITIALIZED 106 +#define RSA_R_CRT_PARAMS_ALREADY_GIVEN 107 +#define RSA_R_CRT_VALUES_INCORRECT 108 +#define RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN 109 +#define RSA_R_DATA_TOO_LARGE 110 +#define RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE 111 +#define RSA_R_DATA_TOO_LARGE_FOR_MODULUS 112 +#define RSA_R_DATA_TOO_SMALL 113 +#define RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE 114 +#define RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY 115 +#define RSA_R_D_E_NOT_CONGRUENT_TO_1 116 +#define RSA_R_EMPTY_PUBLIC_KEY 117 +#define RSA_R_FIRST_OCTET_INVALID 118 +#define RSA_R_INCONSISTENT_SET_OF_CRT_VALUES 119 +#define RSA_R_INTERNAL_ERROR 120 +#define RSA_R_INVALID_MESSAGE_LENGTH 121 +#define RSA_R_KEY_SIZE_TOO_SMALL 122 +#define RSA_R_LAST_OCTET_INVALID 123 +#define RSA_R_MODULUS_TOO_LARGE 124 +#define RSA_R_NO_PUBLIC_EXPONENT 125 +#define RSA_R_NULL_BEFORE_BLOCK_MISSING 126 +#define RSA_R_N_NOT_EQUAL_P_Q 127 +#define RSA_R_OAEP_DECODING_ERROR 128 +#define RSA_R_ONLY_ONE_OF_P_Q_GIVEN 129 +#define RSA_R_OUTPUT_BUFFER_TOO_SMALL 130 +#define RSA_R_PADDING_CHECK_FAILED 131 +#define RSA_R_PKCS_DECODING_ERROR 132 +#define RSA_R_SLEN_CHECK_FAILED 133 +#define RSA_R_SLEN_RECOVERY_FAILED 134 +#define RSA_R_TOO_LONG 135 +#define RSA_R_TOO_MANY_ITERATIONS 136 +#define RSA_R_UNKNOWN_ALGORITHM_TYPE 137 +#define RSA_R_UNKNOWN_PADDING_TYPE 138 +#define RSA_R_VALUE_MISSING 139 +#define RSA_R_WRONG_SIGNATURE_LENGTH 140 +#define RSA_R_MUST_HAVE_AT_LEAST_TWO_PRIMES 141 +#define RSA_R_CANNOT_RECOVER_MULTI_PRIME_KEY 142 +#define RSA_R_BAD_ENCODING 143 +#define RSA_R_ENCODE_ERROR 144 +#define RSA_R_BAD_VERSION 145 + +#endif /* OPENSSL_HEADER_RSA_H */ diff --git a/project/jni/boringssl/include/openssl/safestack.h b/project/jni/boringssl/include/openssl/safestack.h new file mode 100644 index 000000000..6e5e43307 --- /dev/null +++ b/project/jni/boringssl/include/openssl/safestack.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ diff --git a/project/jni/boringssl/include/openssl/sha.h b/project/jni/boringssl/include/openssl/sha.h new file mode 100644 index 000000000..48a52e8f0 --- /dev/null +++ b/project/jni/boringssl/include/openssl/sha.h @@ -0,0 +1,256 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_SHA_H +#define OPENSSL_HEADER_SHA_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* The SHA family of hash functions (SHA-1 and SHA-2). */ + + +/* SHA_CBLOCK is the block size of SHA-1. */ +#define SHA_CBLOCK 64 + +/* SHA_DIGEST_LENGTH is the length of a SHA-1 digest. */ +#define SHA_DIGEST_LENGTH 20 + +/* TODO(fork): remove */ +#define SHA_LBLOCK 16 +#define SHA_LONG uint32_t + +/* SHA1_Init initialises |sha| and returns one. */ +OPENSSL_EXPORT int SHA1_Init(SHA_CTX *sha); + +/* SHA1_Update adds |len| bytes from |data| to |sha| and returns one. */ +OPENSSL_EXPORT int SHA1_Update(SHA_CTX *sha, const void *data, size_t len); + +/* SHA1_Final adds the final padding to |sha| and writes the resulting digest + * to |md|, which must have at least |SHA_DIGEST_LENGTH| bytes of space. It + * returns one. */ +OPENSSL_EXPORT int SHA1_Final(uint8_t *md, SHA_CTX *sha); + +/* SHA1 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |SHA_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *SHA1(const uint8_t *data, size_t len, uint8_t *out); + +/* SHA1_Transform is a low-level function that performs a single, SHA-1 block + * transformation using the state from |sha| and 64 bytes from |block|. */ +OPENSSL_EXPORT void SHA1_Transform(SHA_CTX *sha, const uint8_t *block); + +struct sha_state_st { +#if defined(OPENSSL_WINDOWS) + uint32_t h[5]; +#else + /* wpa_supplicant accesses |h0|..|h4| so we must support those names + * for compatibility with it until it can be updated. */ + union { + uint32_t h[5]; + struct { + uint32_t h0; + uint32_t h1; + uint32_t h2; + uint32_t h3; + uint32_t h4; + }; + }; +#endif + uint32_t Nl, Nh; + uint8_t data[SHA_CBLOCK]; + unsigned num; +}; + + +/* SHA-224. */ + +/* SHA224_CBLOCK is the block size of SHA-224. */ +#define SHA224_CBLOCK 64 + +/* SHA224_DIGEST_LENGTH is the length of a SHA-224 digest. */ +#define SHA224_DIGEST_LENGTH 28 + +/* SHA224_Init initialises |sha| and returns 1. */ +OPENSSL_EXPORT int SHA224_Init(SHA256_CTX *sha); + +/* SHA224_Update adds |len| bytes from |data| to |sha| and returns 1. */ +OPENSSL_EXPORT int SHA224_Update(SHA256_CTX *sha, const void *data, size_t len); + +/* SHA224_Final adds the final padding to |sha| and writes the resulting digest + * to |md|, which must have at least |SHA224_DIGEST_LENGTH| bytes of space. It + * returns one on success and zero on programmer error. */ +OPENSSL_EXPORT int SHA224_Final(uint8_t *md, SHA256_CTX *sha); + +/* SHA224 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |SHA224_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *SHA224(const uint8_t *data, size_t len, uint8_t *out); + + +/* SHA-256. */ + +/* SHA256_CBLOCK is the block size of SHA-256. */ +#define SHA256_CBLOCK 64 + +/* SHA256_DIGEST_LENGTH is the length of a SHA-256 digest. */ +#define SHA256_DIGEST_LENGTH 32 + +/* SHA256_Init initialises |sha| and returns 1. */ +OPENSSL_EXPORT int SHA256_Init(SHA256_CTX *sha); + +/* SHA256_Update adds |len| bytes from |data| to |sha| and returns 1. */ +OPENSSL_EXPORT int SHA256_Update(SHA256_CTX *sha, const void *data, size_t len); + +/* SHA256_Final adds the final padding to |sha| and writes the resulting digest + * to |md|, which must have at least |SHA256_DIGEST_LENGTH| bytes of space. It + * returns one on success and zero on programmer error. */ +OPENSSL_EXPORT int SHA256_Final(uint8_t *md, SHA256_CTX *sha); + +/* SHA256 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |SHA256_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *SHA256(const uint8_t *data, size_t len, uint8_t *out); + +/* SHA256_Transform is a low-level function that performs a single, SHA-1 block + * transformation using the state from |sha| and 64 bytes from |block|. */ +OPENSSL_EXPORT void SHA256_Transform(SHA256_CTX *sha, const uint8_t *data); + +struct sha256_state_st { + uint32_t h[8]; + uint32_t Nl, Nh; + uint8_t data[SHA256_CBLOCK]; + unsigned num, md_len; +}; + + +/* SHA-384. */ + +/* SHA384_CBLOCK is the block size of SHA-384. */ +#define SHA384_CBLOCK 128 + +/* SHA384_DIGEST_LENGTH is the length of a SHA-384 digest. */ +#define SHA384_DIGEST_LENGTH 48 + +/* SHA384_Init initialises |sha| and returns 1. */ +OPENSSL_EXPORT int SHA384_Init(SHA512_CTX *sha); + +/* SHA384_Update adds |len| bytes from |data| to |sha| and returns 1. */ +OPENSSL_EXPORT int SHA384_Update(SHA512_CTX *sha, const void *data, size_t len); + +/* SHA384_Final adds the final padding to |sha| and writes the resulting digest + * to |md|, which must have at least |SHA384_DIGEST_LENGTH| bytes of space. It + * returns one on success and zero on programmer error. */ +OPENSSL_EXPORT int SHA384_Final(uint8_t *md, SHA512_CTX *sha); + +/* SHA384 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |SHA384_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *SHA384(const uint8_t *data, size_t len, uint8_t *out); + +/* SHA384_Transform is a low-level function that performs a single, SHA-1 block + * transformation using the state from |sha| and 64 bytes from |block|. */ +OPENSSL_EXPORT void SHA384_Transform(SHA512_CTX *sha, const uint8_t *data); + + +/* SHA-512. */ + +/* SHA512_CBLOCK is the block size of SHA-512. */ +#define SHA512_CBLOCK 128 + +/* SHA512_DIGEST_LENGTH is the length of a SHA-512 digest. */ +#define SHA512_DIGEST_LENGTH 64 + +/* SHA512_Init initialises |sha| and returns 1. */ +OPENSSL_EXPORT int SHA512_Init(SHA512_CTX *sha); + +/* SHA512_Update adds |len| bytes from |data| to |sha| and returns 1. */ +OPENSSL_EXPORT int SHA512_Update(SHA512_CTX *sha, const void *data, size_t len); + +/* SHA512_Final adds the final padding to |sha| and writes the resulting digest + * to |md|, which must have at least |SHA512_DIGEST_LENGTH| bytes of space. It + * returns one on success and zero on programmer error. */ +OPENSSL_EXPORT int SHA512_Final(uint8_t *md, SHA512_CTX *sha); + +/* SHA512 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |SHA512_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *SHA512(const uint8_t *data, size_t len, uint8_t *out); + +/* SHA512_Transform is a low-level function that performs a single, SHA-1 block + * transformation using the state from |sha| and 64 bytes from |block|. */ +OPENSSL_EXPORT void SHA512_Transform(SHA512_CTX *sha, const uint8_t *data); + +struct sha512_state_st { + uint64_t h[8]; + uint64_t Nl, Nh; + union { + uint64_t d[16]; + uint8_t p[128]; + } u; + unsigned num, md_len; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_SHA_H */ diff --git a/project/jni/boringssl/include/openssl/srtp.h b/project/jni/boringssl/include/openssl/srtp.h new file mode 100644 index 000000000..39f6a8552 --- /dev/null +++ b/project/jni/boringssl/include/openssl/srtp.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "ssl.h" diff --git a/project/jni/boringssl/include/openssl/ssl.h b/project/jni/boringssl/include/openssl/ssl.h new file mode 100644 index 000000000..dcfee915d --- /dev/null +++ b/project/jni/boringssl/include/openssl/ssl.h @@ -0,0 +1,4472 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#ifndef OPENSSL_HEADER_SSL_H +#define OPENSSL_HEADER_SSL_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(OPENSSL_WINDOWS) +#include +#endif + +/* wpa_supplicant expects to get the version functions from ssl.h */ +#include + +/* Forward-declare struct timeval. On Windows, it is defined in winsock2.h and + * Windows headers define too many macros to be included in public headers. + * However, only a forward declaration is needed. */ +struct timeval; + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* SSL implementation. */ + + +/* SSL contexts. + * + * |SSL_CTX| objects manage shared state and configuration between multiple TLS + * or DTLS connections. Whether the connections are TLS or DTLS is selected by + * an |SSL_METHOD| on creation. + * + * |SSL_CTX| are reference-counted and may be shared by connections across + * multiple threads. Once shared, functions which change the |SSL_CTX|'s + * configuration may not be used. */ + +/* TLS_method is the |SSL_METHOD| used for TLS (and SSLv3) connections. */ +OPENSSL_EXPORT const SSL_METHOD *TLS_method(void); + +/* DTLS_method is the |SSL_METHOD| used for DTLS connections. */ +OPENSSL_EXPORT const SSL_METHOD *DTLS_method(void); + +/* SSL_CTX_new returns a newly-allocated |SSL_CTX| with default settings or NULL + * on error. */ +OPENSSL_EXPORT SSL_CTX *SSL_CTX_new(const SSL_METHOD *method); + +/* SSL_CTX_free releases memory associated with |ctx|. */ +OPENSSL_EXPORT void SSL_CTX_free(SSL_CTX *ctx); + + +/* SSL connections. + * + * An |SSL| object represents a single TLS or DTLS connection. Although the + * shared |SSL_CTX| is thread-safe, an |SSL| is not thread-safe and may only be + * used on one thread at a time. */ + +/* SSL_new returns a newly-allocated |SSL| using |ctx| or NULL on error. The new + * connection inherits settings from |ctx| at the time of creation. Settings may + * also be individually configured on the connection. + * + * On creation, an |SSL| is not configured to be either a client or server. Call + * |SSL_set_connect_state| or |SSL_set_accept_state| to set this. */ +OPENSSL_EXPORT SSL *SSL_new(SSL_CTX *ctx); + +/* SSL_free releases memory associated with |ssl|. */ +OPENSSL_EXPORT void SSL_free(SSL *ssl); + +/* SSL_get_SSL_CTX returns the |SSL_CTX| associated with |ssl|. If + * |SSL_set_SSL_CTX| is called, it returns the new |SSL_CTX|, not the initial + * one. */ +OPENSSL_EXPORT SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); + +/* SSL_set_connect_state configures |ssl| to be a client. */ +OPENSSL_EXPORT void SSL_set_connect_state(SSL *ssl); + +/* SSL_set_accept_state configures |ssl| to be a server. */ +OPENSSL_EXPORT void SSL_set_accept_state(SSL *ssl); + +/* SSL_is_server returns one if |ssl| is configured as a server and zero + * otherwise. */ +OPENSSL_EXPORT int SSL_is_server(SSL *ssl); + +/* SSL_set_bio configures |ssl| to read from |rbio| and write to |wbio|. |ssl| + * takes ownership of the two |BIO|s. If |rbio| and |wbio| are the same, |ssl| + * only takes ownership of one reference. + * + * In DTLS, if |rbio| is blocking, it must handle + * |BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT| control requests to set read timeouts. + * + * Calling this function on an already-configured |ssl| is deprecated. */ +OPENSSL_EXPORT void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio); + +/* SSL_get_rbio returns the |BIO| that |ssl| reads from. */ +OPENSSL_EXPORT BIO *SSL_get_rbio(const SSL *ssl); + +/* SSL_get_wbio returns the |BIO| that |ssl| writes to. */ +OPENSSL_EXPORT BIO *SSL_get_wbio(const SSL *ssl); + +/* SSL_get_fd calls |SSL_get_rfd|. */ +OPENSSL_EXPORT int SSL_get_fd(const SSL *ssl); + +/* SSL_get_rfd returns the file descriptor that |ssl| is configured to read + * from. If |ssl|'s read |BIO| is not configured or doesn't wrap a file + * descriptor then it returns -1. */ +OPENSSL_EXPORT int SSL_get_rfd(const SSL *ssl); + +/* SSL_get_wfd returns the file descriptor that |ssl| is configured to write + * to. If |ssl|'s write |BIO| is not configured or doesn't wrap a file + * descriptor then it returns -1. */ +OPENSSL_EXPORT int SSL_get_wfd(const SSL *ssl); + +/* SSL_set_fd configures |ssl| to read from and write to |fd|. It returns one + * on success and zero on allocation error. The caller retains ownership of + * |fd|. */ +OPENSSL_EXPORT int SSL_set_fd(SSL *ssl, int fd); + +/* SSL_set_rfd configures |ssl| to read from |fd|. It returns one on success and + * zero on allocation error. The caller retains ownership of |fd|. */ +OPENSSL_EXPORT int SSL_set_rfd(SSL *ssl, int fd); + +/* SSL_set_wfd configures |ssl| to write to |fd|. It returns one on success and + * zero on allocation error. The caller retains ownership of |fd|. */ +OPENSSL_EXPORT int SSL_set_wfd(SSL *ssl, int fd); + +/* SSL_do_handshake continues the current handshake. If there is none or the + * handshake has completed or False Started, it returns one. Otherwise, it + * returns <= 0. The caller should pass the value into |SSL_get_error| to + * determine how to proceed. + * + * In DTLS, if the read |BIO| is non-blocking, the caller must drive + * retransmissions. Whenever |SSL_get_error| signals |SSL_ERROR_WANT_READ|, use + * |DTLSv1_get_timeout| to determine the current timeout. If it expires before + * the next retry, call |DTLSv1_handle_timeout|. Note that DTLS handshake + * retransmissions use fresh sequence numbers, so it is not sufficient to replay + * packets at the transport. + * + * TODO(davidben): Ensure 0 is only returned on transport EOF. + * https://crbug.com/466303. */ +OPENSSL_EXPORT int SSL_do_handshake(SSL *ssl); + +/* SSL_connect configures |ssl| as a client, if unconfigured, and calls + * |SSL_do_handshake|. */ +OPENSSL_EXPORT int SSL_connect(SSL *ssl); + +/* SSL_accept configures |ssl| as a server, if unconfigured, and calls + * |SSL_do_handshake|. */ +OPENSSL_EXPORT int SSL_accept(SSL *ssl); + +/* SSL_read reads up to |num| bytes from |ssl| into |buf|. It implicitly runs + * any pending handshakes, including renegotiations when enabled. On success, it + * returns the number of bytes read. Otherwise, it returns <= 0. The caller + * should pass the value into |SSL_get_error| to determine how to proceed. + * + * TODO(davidben): Ensure 0 is only returned on transport EOF. + * https://crbug.com/466303. */ +OPENSSL_EXPORT int SSL_read(SSL *ssl, void *buf, int num); + +/* SSL_peek behaves like |SSL_read| but does not consume any bytes returned. */ +OPENSSL_EXPORT int SSL_peek(SSL *ssl, void *buf, int num); + +/* SSL_pending returns the number of bytes available in |ssl|. It does not read + * from the transport. */ +OPENSSL_EXPORT int SSL_pending(const SSL *ssl); + +/* SSL_write writes up to |num| bytes from |buf| into |ssl|. It implicitly runs + * any pending handshakes, including renegotiations when enabled. On success, it + * returns the number of bytes read. Otherwise, it returns <= 0. The caller + * should pass the value into |SSL_get_error| to determine how to proceed. + * + * In TLS, a non-blocking |SSL_write| differs from non-blocking |write| in that + * a failed |SSL_write| still commits to the data passed in. When retrying, the + * caller must supply the original write buffer (or a larger one containing the + * original as a prefix). By default, retries will fail if they also do not + * reuse the same |buf| pointer. This may be relaxed with + * |SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER|, but the buffer contents still must be + * unchanged. + * + * By default, in TLS, |SSL_write| will not return success until all |num| bytes + * are written. This may be relaxed with |SSL_MODE_ENABLE_PARTIAL_WRITE|. It + * allows |SSL_write| to complete with a partial result when only part of the + * input was written in a single record. + * + * In DTLS, neither |SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER| and + * |SSL_MODE_ENABLE_PARTIAL_WRITE| do anything. The caller may retry with a + * different buffer freely. A single call to |SSL_write| only ever writes a + * single record in a single packet, so |num| must be at most + * |SSL3_RT_MAX_PLAIN_LENGTH|. + * + * TODO(davidben): Ensure 0 is only returned on transport EOF. + * https://crbug.com/466303. */ +OPENSSL_EXPORT int SSL_write(SSL *ssl, const void *buf, int num); + +/* SSL_shutdown shuts down |ssl|. On success, it completes in two stages. First, + * it returns 0 if |ssl| completed uni-directional shutdown; close_notify has + * been sent, but the peer's close_notify has not been received. Most callers + * may stop at this point. For bi-directional shutdown, call |SSL_shutdown| + * again. It returns 1 if close_notify has been both sent and received. + * + * If the peer's close_notify arrived first, the first stage is skipped. + * |SSL_shutdown| will return 1 once close_notify is sent and skip 0. Callers + * only interested in uni-directional shutdown must therefore allow for the + * first stage returning either 0 or 1. + * + * |SSL_shutdown| returns -1 on failure. The caller should pass the return value + * into |SSL_get_error| to determine how to proceed. If the underlying |BIO| is + * non-blocking, both stages may require retry. + * + * |SSL_shutdown| must be called to retain |ssl|'s session in the session + * cache. Use |SSL_CTX_set_quiet_shutdown| to configure |SSL_shutdown| to + * neither send nor wait for close_notify but still retain the session. + * + * TODO(davidben): Is there any point in the session cache interaction? Remove + * it? */ +OPENSSL_EXPORT int SSL_shutdown(SSL *ssl); + +/* SSL_CTX_set_quiet_shutdown sets quiet shutdown on |ctx| to |mode|. If + * enabled, |SSL_shutdown| will not send a close_notify alert or wait for one + * from the peer. It will instead synchronously return one. */ +OPENSSL_EXPORT void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx, int mode); + +/* SSL_CTX_get_quiet_shutdown returns whether quiet shutdown is enabled for + * |ctx|. */ +OPENSSL_EXPORT int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx); + +/* SSL_set_quiet_shutdown sets quiet shutdown on |ssl| to |mode|. If enabled, + * |SSL_shutdown| will not send a close_notify alert or wait for one from the + * peer. It will instead synchronously return one. */ +OPENSSL_EXPORT void SSL_set_quiet_shutdown(SSL *ssl, int mode); + +/* SSL_get_quiet_shutdown returns whether quiet shutdown is enabled for + * |ssl|. */ +OPENSSL_EXPORT int SSL_get_quiet_shutdown(const SSL *ssl); + +/* SSL_get_error returns a |SSL_ERROR_*| value for the most recent operation on + * |ssl|. It should be called after an operation failed to determine whether the + * error was fatal and, if not, when to retry. */ +OPENSSL_EXPORT int SSL_get_error(const SSL *ssl, int ret_code); + +/* SSL_ERROR_NONE indicates the operation succeeded. */ +#define SSL_ERROR_NONE 0 + +/* SSL_ERROR_SSL indicates the operation failed within the library. The caller + * may inspect the error queue for more information. */ +#define SSL_ERROR_SSL 1 + +/* SSL_ERROR_WANT_READ indicates the operation failed attempting to read from + * the transport. The caller may retry the operation when the transport is ready + * for reading. + * + * If signaled by a DTLS handshake, the caller must also call + * |DTLSv1_get_timeout| and |DTLSv1_handle_timeout| as appropriate. See + * |SSL_do_handshake|. */ +#define SSL_ERROR_WANT_READ 2 + +/* SSL_ERROR_WANT_WRITE indicates the operation failed attempting to write to + * the transport. The caller may retry the operation when the transport is ready + * for writing. */ +#define SSL_ERROR_WANT_WRITE 3 + +/* SSL_ERROR_WANT_X509_LOOKUP indicates the operation failed in calling the + * |cert_cb| or |client_cert_cb|. The caller may retry the operation when the + * callback is ready to return a certificate or one has been configured + * externally. + * + * See also |SSL_CTX_set_cert_cb| and |SSL_CTX_set_client_cert_cb|. */ +#define SSL_ERROR_WANT_X509_LOOKUP 4 + +/* SSL_ERROR_WANT_SYSCALL indicates the operation failed externally to the + * library. The caller should consult the system-specific error mechanism. This + * is typically |errno| but may be something custom if using a custom |BIO|. It + * may also be signaled if the transport returned EOF, in which case the + * operation's return value will be zero. */ +#define SSL_ERROR_SYSCALL 5 + +/* SSL_ERROR_ZERO_RETURN indicates the operation failed because the connection + * was cleanly shut down with a close_notify alert. */ +#define SSL_ERROR_ZERO_RETURN 6 + +/* SSL_ERROR_WANT_CONNECT indicates the operation failed attempting to connect + * the transport (the |BIO| signaled |BIO_RR_CONNECT|). The caller may retry the + * operation when the transport is ready. */ +#define SSL_ERROR_WANT_CONNECT 7 + +/* SSL_ERROR_WANT_ACCEPT indicates the operation failed attempting to accept a + * connection from the transport (the |BIO| signaled |BIO_RR_ACCEPT|). The + * caller may retry the operation when the transport is ready. + * + * TODO(davidben): Remove this. It's used by accept BIOs which are bizarre. */ +#define SSL_ERROR_WANT_ACCEPT 8 + +/* SSL_ERROR_WANT_CHANNEL_ID_LOOKUP indicates the operation failed looking up + * the Channel ID key. The caller may retry the operation when |channel_id_cb| + * is ready to return a key or one has been configured with + * |SSL_set1_tls_channel_id|. + * + * See also |SSL_CTX_set_channel_id_cb|. */ +#define SSL_ERROR_WANT_CHANNEL_ID_LOOKUP 9 + +/* SSL_ERROR_PENDING_SESSION indicates the operation failed because the session + * lookup callback indicated the session was unavailable. The caller may retry + * the operation when lookup has completed. + * + * See also |SSL_CTX_sess_set_get_cb| and |SSL_magic_pending_session_ptr|. */ +#define SSL_ERROR_PENDING_SESSION 11 + +/* SSL_ERROR_PENDING_CERTIFICATE indicates the operation failed because the + * early callback indicated certificate lookup was incomplete. The caller may + * retry the operation when lookup has completed. Note: when the operation is + * retried, the early callback will not be called a second time. + * + * See also |SSL_CTX_set_select_certificate_cb|. */ +#define SSL_ERROR_PENDING_CERTIFICATE 12 + +/* SSL_ERROR_WANT_PRIVATE_KEY_OPERATION indicates the operation failed because + * a private key operation was unfinished. The caller may retry the operation + * when the private key operation is complete. + * + * See also |SSL_set_private_key_method|. */ +#define SSL_ERROR_WANT_PRIVATE_KEY_OPERATION 13 + +/* SSL_set_mtu sets the |ssl|'s MTU in DTLS to |mtu|. It returns one on success + * and zero on failure. */ +OPENSSL_EXPORT int SSL_set_mtu(SSL *ssl, unsigned mtu); + +/* DTLSv1_get_timeout queries the next DTLS handshake timeout. If there is a + * timeout in progress, it sets |*out| to the time remaining and returns one. + * Otherwise, it returns zero. + * + * When the timeout expires, call |DTLSv1_handle_timeout| to handle the + * retransmit behavior. + * + * NOTE: This function must be queried again whenever the handshake state + * machine changes, including when |DTLSv1_handle_timeout| is called. */ +OPENSSL_EXPORT int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out); + +/* DTLSv1_handle_timeout is called when a DTLS handshake timeout expires. If no + * timeout had expired, it returns 0. Otherwise, it retransmits the previous + * flight of handshake messages and returns 1. If too many timeouts had expired + * without progress or an error occurs, it returns -1. + * + * The caller's external timer should be compatible with the one |ssl| queries + * within some fudge factor. Otherwise, the call will be a no-op, but + * |DTLSv1_get_timeout| will return an updated timeout. + * + * If the function returns -1, checking if |SSL_get_error| returns + * |SSL_ERROR_WANT_WRITE| may be used to determine if the retransmit failed due + * to a non-fatal error at the write |BIO|. However, the operation may not be + * retried until the next timeout fires. + * + * WARNING: This function breaks the usual return value convention. + * + * TODO(davidben): This |SSL_ERROR_WANT_WRITE| behavior is kind of bizarre. */ +OPENSSL_EXPORT int DTLSv1_handle_timeout(SSL *ssl); + + +/* Protocol versions. */ + +#define DTLS1_VERSION_MAJOR 0xfe +#define SSL3_VERSION_MAJOR 0x03 + +#define SSL3_VERSION 0x0300 +#define TLS1_VERSION 0x0301 +#define TLS1_1_VERSION 0x0302 +#define TLS1_2_VERSION 0x0303 + +#define DTLS1_VERSION 0xfeff +#define DTLS1_2_VERSION 0xfefd + +/* SSL_CTX_set_min_version sets the minimum protocol version for |ctx| to + * |version|. */ +OPENSSL_EXPORT void SSL_CTX_set_min_version(SSL_CTX *ctx, uint16_t version); + +/* SSL_CTX_set_max_version sets the maximum protocol version for |ctx| to + * |version|. */ +OPENSSL_EXPORT void SSL_CTX_set_max_version(SSL_CTX *ctx, uint16_t version); + +/* SSL_set_min_version sets the minimum protocol version for |ssl| to + * |version|. */ +OPENSSL_EXPORT void SSL_set_min_version(SSL *ssl, uint16_t version); + +/* SSL_set_max_version sets the maximum protocol version for |ssl| to + * |version|. */ +OPENSSL_EXPORT void SSL_set_max_version(SSL *ssl, uint16_t version); + +/* SSL_version returns the TLS or DTLS protocol version used by |ssl|, which is + * one of the |*_VERSION| values. (E.g. |TLS1_2_VERSION|.) Before the version + * is negotiated, the result is undefined. */ +OPENSSL_EXPORT int SSL_version(const SSL *ssl); + + +/* Options. + * + * Options configure protocol behavior. */ + +/* SSL_OP_NO_QUERY_MTU, in DTLS, disables querying the MTU from the underlying + * |BIO|. Instead, the MTU is configured with |SSL_set_mtu|. */ +#define SSL_OP_NO_QUERY_MTU 0x00001000L + +/* SSL_OP_NO_TICKET disables session ticket support (RFC 5077). */ +#define SSL_OP_NO_TICKET 0x00004000L + +/* SSL_OP_CIPHER_SERVER_PREFERENCE configures servers to select ciphers and + * ECDHE curves according to the server's preferences instead of the + * client's. */ +#define SSL_OP_CIPHER_SERVER_PREFERENCE 0x00400000L + +/* SSL_OP_DISABLE_NPN configures an individual |SSL| to not advertise NPN, + * despite |SSL_CTX_set_next_proto_select_cb| being configured on the + * |SSL_CTX|. */ +#define SSL_OP_DISABLE_NPN 0x00800000L + +/* SSL_CTX_set_options enables all options set in |options| (which should be one + * or more of the |SSL_OP_*| values, ORed together) in |ctx|. It returns a + * bitmask representing the resulting enabled options. */ +OPENSSL_EXPORT uint32_t SSL_CTX_set_options(SSL_CTX *ctx, uint32_t options); + +/* SSL_CTX_clear_options disables all options set in |options| (which should be + * one or more of the |SSL_OP_*| values, ORed together) in |ctx|. It returns a + * bitmask representing the resulting enabled options. */ +OPENSSL_EXPORT uint32_t SSL_CTX_clear_options(SSL_CTX *ctx, uint32_t options); + +/* SSL_CTX_get_options returns a bitmask of |SSL_OP_*| values that represent all + * the options enabled for |ctx|. */ +OPENSSL_EXPORT uint32_t SSL_CTX_get_options(const SSL_CTX *ctx); + +/* SSL_set_options enables all options set in |options| (which should be one or + * more of the |SSL_OP_*| values, ORed together) in |ssl|. It returns a bitmask + * representing the resulting enabled options. */ +OPENSSL_EXPORT uint32_t SSL_set_options(SSL *ssl, uint32_t options); + +/* SSL_clear_options disables all options set in |options| (which should be one + * or more of the |SSL_OP_*| values, ORed together) in |ssl|. It returns a + * bitmask representing the resulting enabled options. */ +OPENSSL_EXPORT uint32_t SSL_clear_options(SSL *ssl, uint32_t options); + +/* SSL_get_options returns a bitmask of |SSL_OP_*| values that represent all the + * options enabled for |ssl|. */ +OPENSSL_EXPORT uint32_t SSL_get_options(const SSL *ssl); + + +/* Modes. + * + * Modes configure API behavior. */ + +/* SSL_MODE_ENABLE_PARTIAL_WRITE, in TLS, allows |SSL_write| to complete with a + * partial result when the only part of the input was written in a single + * record. In DTLS, it does nothing. */ +#define SSL_MODE_ENABLE_PARTIAL_WRITE 0x00000001L + +/* SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER, in TLS, allows retrying an incomplete + * |SSL_write| with a different buffer. However, |SSL_write| still assumes the + * buffer contents are unchanged. This is not the default to avoid the + * misconception that non-blocking |SSL_write| behaves like non-blocking + * |write|. In DTLS, it does nothing. */ +#define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L + +/* SSL_MODE_NO_AUTO_CHAIN disables automatically building a certificate chain + * before sending certificates to the peer. + * TODO(davidben): Remove this behavior. https://crbug.com/486295. */ +#define SSL_MODE_NO_AUTO_CHAIN 0x00000008L + +/* SSL_MODE_ENABLE_FALSE_START allows clients to send application data before + * receipt of ChangeCipherSpec and Finished. This mode enables full-handshakes + * to 'complete' in one RTT. See draft-bmoeller-tls-falsestart-01. + * + * When False Start is enabled, |SSL_do_handshake| may succeed before the + * handshake has completely finished. |SSL_write| will function at this point, + * and |SSL_read| will transparently wait for the final handshake leg before + * returning application data. To determine if False Start occurred or when the + * handshake is completely finished, see |SSL_in_false_start|, |SSL_in_init|, + * and |SSL_CB_HANDSHAKE_DONE| from |SSL_CTX_set_info_callback|. */ +#define SSL_MODE_ENABLE_FALSE_START 0x00000080L + +/* SSL_MODE_CBC_RECORD_SPLITTING causes multi-byte CBC records in SSL 3.0 and + * TLS 1.0 to be split in two: the first record will contain a single byte and + * the second will contain the remainder. This effectively randomises the IV and + * prevents BEAST attacks. */ +#define SSL_MODE_CBC_RECORD_SPLITTING 0x00000100L + +/* SSL_MODE_NO_SESSION_CREATION will cause any attempts to create a session to + * fail with SSL_R_SESSION_MAY_NOT_BE_CREATED. This can be used to enforce that + * session resumption is used for a given SSL*. */ +#define SSL_MODE_NO_SESSION_CREATION 0x00000200L + +/* SSL_MODE_SEND_FALLBACK_SCSV sends TLS_FALLBACK_SCSV in the ClientHello. + * To be set only by applications that reconnect with a downgraded protocol + * version; see RFC 7507 for details. + * + * DO NOT ENABLE THIS if your application attempts a normal handshake. Only use + * this in explicit fallback retries, following the guidance in RFC 7507. */ +#define SSL_MODE_SEND_FALLBACK_SCSV 0x00000400L + +/* SSL_CTX_set_mode enables all modes set in |mode| (which should be one or more + * of the |SSL_MODE_*| values, ORed together) in |ctx|. It returns a bitmask + * representing the resulting enabled modes. */ +OPENSSL_EXPORT uint32_t SSL_CTX_set_mode(SSL_CTX *ctx, uint32_t mode); + +/* SSL_CTX_clear_mode disables all modes set in |mode| (which should be one or + * more of the |SSL_MODE_*| values, ORed together) in |ctx|. It returns a + * bitmask representing the resulting enabled modes. */ +OPENSSL_EXPORT uint32_t SSL_CTX_clear_mode(SSL_CTX *ctx, uint32_t mode); + +/* SSL_CTX_get_mode returns a bitmask of |SSL_MODE_*| values that represent all + * the modes enabled for |ssl|. */ +OPENSSL_EXPORT uint32_t SSL_CTX_get_mode(const SSL_CTX *ctx); + +/* SSL_set_mode enables all modes set in |mode| (which should be one or more of + * the |SSL_MODE_*| values, ORed together) in |ssl|. It returns a bitmask + * representing the resulting enabled modes. */ +OPENSSL_EXPORT uint32_t SSL_set_mode(SSL *ssl, uint32_t mode); + +/* SSL_clear_mode disables all modes set in |mode| (which should be one or more + * of the |SSL_MODE_*| values, ORed together) in |ssl|. It returns a bitmask + * representing the resulting enabled modes. */ +OPENSSL_EXPORT uint32_t SSL_clear_mode(SSL *ssl, uint32_t mode); + +/* SSL_get_mode returns a bitmask of |SSL_MODE_*| values that represent all the + * modes enabled for |ssl|. */ +OPENSSL_EXPORT uint32_t SSL_get_mode(const SSL *ssl); + + +/* Configuring certificates and private keys. + * + * These functions configure the connection's leaf certificate, private key, and + * certificate chain. The certificate chain is ordered leaf to root (as sent on + * the wire) but does not include the leaf. Both client and server certificates + * use these functions. + * + * Certificates and keys may be configured before the handshake or dynamically + * in the early callback and certificate callback. */ + +/* SSL_CTX_use_certificate sets |ctx|'s leaf certificate to |x509|. It returns + * one on success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x509); + +/* SSL_use_certificate sets |ssl|'s leaf certificate to |x509|. It returns one + * on success and zero on failure. */ +OPENSSL_EXPORT int SSL_use_certificate(SSL *ssl, X509 *x509); + +/* SSL_CTX_use_PrivateKey sets |ctx|'s private key to |pkey|. It returns one on + * success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); + +/* SSL_use_PrivateKey sets |ssl|'s private key to |pkey|. It returns one on + * success and zero on failure. */ +OPENSSL_EXPORT int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey); + +/* SSL_CTX_set0_chain sets |ctx|'s certificate chain, excluding the leaf, to + * |chain|. On success, it returns one and takes ownership of |chain|. + * Otherwise, it returns zero. */ +OPENSSL_EXPORT int SSL_CTX_set0_chain(SSL_CTX *ctx, STACK_OF(X509) *chain); + +/* SSL_CTX_set1_chain sets |ctx|'s certificate chain, excluding the leaf, to + * |chain|. It returns one on success and zero on failure. The caller retains + * ownership of |chain| and may release it freely. */ +OPENSSL_EXPORT int SSL_CTX_set1_chain(SSL_CTX *ctx, STACK_OF(X509) *chain); + +/* SSL_set0_chain sets |ssl|'s certificate chain, excluding the leaf, to + * |chain|. On success, it returns one and takes ownership of |chain|. + * Otherwise, it returns zero. */ +OPENSSL_EXPORT int SSL_set0_chain(SSL *ssl, STACK_OF(X509) *chain); + +/* SSL_set1_chain sets |ssl|'s certificate chain, excluding the leaf, to + * |chain|. It returns one on success and zero on failure. The caller retains + * ownership of |chain| and may release it freely. */ +OPENSSL_EXPORT int SSL_set1_chain(SSL *ssl, STACK_OF(X509) *chain); + +/* SSL_CTX_add0_chain_cert appends |x509| to |ctx|'s certificate chain. On + * success, it returns one and takes ownership of |x509|. Otherwise, it returns + * zero. */ +OPENSSL_EXPORT int SSL_CTX_add0_chain_cert(SSL_CTX *ctx, X509 *x509); + +/* SSL_CTX_add1_chain_cert appends |x509| to |ctx|'s certificate chain. It + * returns one on success and zero on failure. The caller retains ownership of + * |x509| and may release it freely. */ +OPENSSL_EXPORT int SSL_CTX_add1_chain_cert(SSL_CTX *ctx, X509 *x509); + +/* SSL_add0_chain_cert appends |x509| to |ctx|'s certificate chain. On success, + * it returns one and takes ownership of |x509|. Otherwise, it returns zero. */ +OPENSSL_EXPORT int SSL_add0_chain_cert(SSL *ssl, X509 *x509); + +/* SSL_CTX_add_extra_chain_cert calls |SSL_CTX_add0_chain_cert|. */ +OPENSSL_EXPORT int SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x509); + +/* SSL_add1_chain_cert appends |x509| to |ctx|'s certificate chain. It returns + * one on success and zero on failure. The caller retains ownership of |x509| + * and may release it freely. */ +OPENSSL_EXPORT int SSL_add1_chain_cert(SSL *ssl, X509 *x509); + +/* SSL_CTX_clear_chain_certs clears |ctx|'s certificate chain and returns + * one. */ +OPENSSL_EXPORT int SSL_CTX_clear_chain_certs(SSL_CTX *ctx); + +/* SSL_CTX_clear_extra_chain_certs calls |SSL_CTX_clear_chain_certs|. */ +OPENSSL_EXPORT int SSL_CTX_clear_extra_chain_certs(SSL_CTX *ctx); + +/* SSL_clear_chain_certs clears |ssl|'s certificate chain and returns one. */ +OPENSSL_EXPORT int SSL_clear_chain_certs(SSL *ssl); + +/* SSL_CTX_set_cert_cb sets a callback that is called to select a certificate. + * The callback returns one on success, zero on internal error, and a negative + * number on failure or to pause the handshake. If the handshake is paused, + * |SSL_get_error| will return |SSL_ERROR_WANT_X509_LOOKUP|. + * + * On the client, the callback may call |SSL_get0_certificate_types| and + * |SSL_get_client_CA_list| for information on the server's certificate + * request. */ +OPENSSL_EXPORT void SSL_CTX_set_cert_cb(SSL_CTX *ctx, + int (*cb)(SSL *ssl, void *arg), + void *arg); + +/* SSL_set_cert_cb sets a callback that is called to select a certificate. The + * callback returns one on success, zero on internal error, and a negative + * number on failure or to pause the handshake. If the handshake is paused, + * |SSL_get_error| will return |SSL_ERROR_WANT_X509_LOOKUP|. + * + * On the client, the callback may call |SSL_get0_certificate_types| and + * |SSL_get_client_CA_list| for information on the server's certificate + * request. */ +OPENSSL_EXPORT void SSL_set_cert_cb(SSL *ssl, int (*cb)(SSL *ssl, void *arg), + void *arg); + +/* SSL_get0_certificate_types, for a client, sets |*out_types| to an array + * containing the client certificate types requested by a server. It returns the + * length of the array. + * + * The behavior of this function is undefined except during the callbacks set by + * by |SSL_CTX_set_cert_cb| and |SSL_CTX_set_client_cert_cb| or when the + * handshake is paused because of them. */ +OPENSSL_EXPORT size_t SSL_get0_certificate_types(SSL *ssl, + const uint8_t **out_types); + +/* SSL_certs_clear resets the private key, leaf certificate, and certificate + * chain of |ssl|. */ +OPENSSL_EXPORT void SSL_certs_clear(SSL *ssl); + +/* SSL_CTX_check_private_key returns one if the certificate and private key + * configured in |ctx| are consistent and zero otherwise. */ +OPENSSL_EXPORT int SSL_CTX_check_private_key(const SSL_CTX *ctx); + +/* SSL_check_private_key returns one if the certificate and private key + * configured in |ssl| are consistent and zero otherwise. */ +OPENSSL_EXPORT int SSL_check_private_key(const SSL *ssl); + +/* SSL_CTX_get0_certificate returns |ctx|'s leaf certificate. */ +OPENSSL_EXPORT X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx); + +/* SSL_get_certificate returns |ssl|'s leaf certificate. */ +OPENSSL_EXPORT X509 *SSL_get_certificate(const SSL *ssl); + +/* SSL_CTX_get0_privatekey returns |ctx|'s private key. */ +OPENSSL_EXPORT EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx); + +/* SSL_get_privatekey returns |ssl|'s private key. */ +OPENSSL_EXPORT EVP_PKEY *SSL_get_privatekey(const SSL *ssl); + +/* SSL_CTX_get0_chain_certs sets |*out_chain| to |ctx|'s certificate chain and + * returns one. */ +OPENSSL_EXPORT int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, + STACK_OF(X509) **out_chain); + +/* SSL_CTX_get_extra_chain_certs calls |SSL_CTX_get0_chain_certs|. */ +OPENSSL_EXPORT int SSL_CTX_get_extra_chain_certs(const SSL_CTX *ctx, + STACK_OF(X509) **out_chain); + +/* SSL_get0_chain_certs sets |*out_chain| to |ssl|'s certificate chain and + * returns one. */ +OPENSSL_EXPORT int SSL_get0_chain_certs(const SSL *ssl, + STACK_OF(X509) **out_chain); + +/* SSL_CTX_set_signed_cert_timestamp_list sets the list of signed certificate + * timestamps that is sent to clients that request it. The |list| argument must + * contain one or more SCT structures serialised as a SignedCertificateTimestamp + * List (see https://tools.ietf.org/html/rfc6962#section-3.3) – i.e. each SCT + * is prefixed by a big-endian, uint16 length and the concatenation of one or + * more such prefixed SCTs are themselves also prefixed by a uint16 length. It + * returns one on success and zero on error. The caller retains ownership of + * |list|. */ +OPENSSL_EXPORT int SSL_CTX_set_signed_cert_timestamp_list(SSL_CTX *ctx, + const uint8_t *list, + size_t list_len); + +/* SSL_CTX_set_ocsp_response sets the OCSP reponse that is sent to clients + * which request it. It returns one on success and zero on error. The caller + * retains ownership of |response|. */ +OPENSSL_EXPORT int SSL_CTX_set_ocsp_response(SSL_CTX *ctx, + const uint8_t *response, + size_t response_len); + +/* SSL_set_private_key_digest_prefs copies |num_digests| NIDs from |digest_nids| + * into |ssl|. These digests will be used, in decreasing order of preference, + * when signing with |ssl|'s private key. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int SSL_set_private_key_digest_prefs(SSL *ssl, + const int *digest_nids, + size_t num_digests); + + +/* Certificate and private key convenience functions. */ + +/* SSL_CTX_use_RSAPrivateKey sets |ctx|'s private key to |rsa|. It returns one + * on success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa); + +/* SSL_use_RSAPrivateKey sets |ctx|'s private key to |rsa|. It returns one on + * success and zero on failure. */ +OPENSSL_EXPORT int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa); + +/* The following functions configure certificates or private keys but take as + * input DER-encoded structures. They return one on success and zero on + * failure. */ + +OPENSSL_EXPORT int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, size_t der_len, + const uint8_t *der); +OPENSSL_EXPORT int SSL_use_certificate_ASN1(SSL *ssl, const uint8_t *der, + size_t der_len); + +OPENSSL_EXPORT int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, + const uint8_t *der, + size_t der_len); +OPENSSL_EXPORT int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, + const uint8_t *der, size_t der_len); + +OPENSSL_EXPORT int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, + const uint8_t *der, + size_t der_len); +OPENSSL_EXPORT int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, const uint8_t *der, + size_t der_len); + +/* The following functions configure certificates or private keys but take as + * input files to read from. They return one on success and zero on failure. The + * |type| parameter is one of the |SSL_FILETYPE_*| values and determines whether + * the file's contents are read as PEM or DER. */ + +#define SSL_FILETYPE_ASN1 X509_FILETYPE_ASN1 +#define SSL_FILETYPE_PEM X509_FILETYPE_PEM + +OPENSSL_EXPORT int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, + const char *file, + int type); +OPENSSL_EXPORT int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, + int type); + +OPENSSL_EXPORT int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, + int type); +OPENSSL_EXPORT int SSL_use_certificate_file(SSL *ssl, const char *file, + int type); + +OPENSSL_EXPORT int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, + int type); +OPENSSL_EXPORT int SSL_use_PrivateKey_file(SSL *ssl, const char *file, + int type); + +/* SSL_CTX_use_certificate_chain_file configures certificates for |ctx|. It + * reads the contents of |file| as a PEM-encoded leaf certificate followed + * optionally by the certificate chain to send to the peer. It returns one on + * success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, + const char *file); + +/* SSL_CTX_set_default_passwd_cb sets the password callback for PEM-based + * convenience functions called on |ctx|. */ +OPENSSL_EXPORT void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, + pem_password_cb *cb); + +/* SSL_CTX_set_default_passwd_cb_userdata sets the userdata parameter for + * |ctx|'s password callback. */ +OPENSSL_EXPORT void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, + void *data); + + +/* Custom private keys. */ + +enum ssl_private_key_result_t { + ssl_private_key_success, + ssl_private_key_retry, + ssl_private_key_failure, +}; + +/* SSL_PRIVATE_KEY_METHOD describes private key hooks. This is used to off-load + * signing operations to a custom, potentially asynchronous, backend. */ +typedef struct ssl_private_key_method_st { + /* type returns either |EVP_PKEY_RSA| or |EVP_PKEY_EC| to denote the type of + * key used by |ssl|. */ + int (*type)(SSL *ssl); + + /* max_signature_len returns the maximum length of a signature signed by the + * key used by |ssl|. This must be a constant value for a given |ssl|. */ + size_t (*max_signature_len)(SSL *ssl); + + /* sign signs |in_len| bytes of digest from |in|. |md| is the hash function + * used to calculate |in|. On success, it returns |ssl_private_key_success| + * and writes at most |max_out| bytes of signature data to |out|. On failure, + * it returns |ssl_private_key_failure|. If the operation has not completed, + * it returns |ssl_private_key_retry|. |sign| should arrange for the + * high-level operation on |ssl| to be retried when the operation is + * completed. This will result in a call to |sign_complete|. + * + * If the key is an RSA key, implementations must use PKCS#1 padding. |in| is + * the digest itself, so the DigestInfo prefix, if any, must be prepended by + * |sign|. If |md| is |EVP_md5_sha1|, there is no prefix. + * + * It is an error to call |sign| while another private key operation is in + * progress on |ssl|. */ + enum ssl_private_key_result_t (*sign)(SSL *ssl, uint8_t *out, size_t *out_len, + size_t max_out, const EVP_MD *md, + const uint8_t *in, size_t in_len); + + /* sign_complete completes a pending |sign| operation. If the operation has + * completed, it returns |ssl_private_key_success| and writes the result to + * |out| as in |sign|. Otherwise, it returns |ssl_private_key_failure| on + * failure and |ssl_private_key_retry| if the operation is still in progress. + * + * |sign_complete| may be called arbitrarily many times before completion, but + * it is an error to call |sign_complete| if there is no pending |sign| + * operation in progress on |ssl|. */ + enum ssl_private_key_result_t (*sign_complete)(SSL *ssl, uint8_t *out, + size_t *out_len, + size_t max_out); + + /* decrypt decrypts |in_len| bytes of encrypted data from |in|. On success it + * returns |ssl_private_key_success|, writes at most |max_out| bytes of + * decrypted data to |out| and sets |*out_len| to the actual number of bytes + * written. On failure it returns |ssl_private_key_failure|. If the operation + * has not completed, it returns |ssl_private_key_retry|. The caller should + * arrange for the high-level operation on |ssl| to be retried when the + * operation is completed, which will result in a call to |decrypt_complete|. + * This function only works with RSA keys and should perform a raw RSA + * decryption operation with no padding. + * + * It is an error to call |decrypt| while another private key operation is in + * progress on |ssl|. */ + enum ssl_private_key_result_t (*decrypt)(SSL *ssl, uint8_t *out, + size_t *out_len, size_t max_out, + const uint8_t *in, size_t in_len); + + /* decrypt_complete completes a pending |decrypt| operation. If the operation + * has completed, it returns |ssl_private_key_success| and writes the result + * to |out| as in |decrypt|. Otherwise, it returns |ssl_private_key_failure| + * on failure and |ssl_private_key_retry| if the operation is still in + * progress. + * + * |decrypt_complete| may be called arbitrarily many times before completion, + * but it is an error to call |decrypt_complete| if there is no pending + * |decrypt| operation in progress on |ssl|. */ + enum ssl_private_key_result_t (*decrypt_complete)(SSL *ssl, uint8_t *out, + size_t *out_len, + size_t max_out); +} SSL_PRIVATE_KEY_METHOD; + +/* SSL_set_private_key_method configures a custom private key on |ssl|. + * |key_method| must remain valid for the lifetime of |ssl|. */ +OPENSSL_EXPORT void SSL_set_private_key_method( + SSL *ssl, const SSL_PRIVATE_KEY_METHOD *key_method); + + +/* Cipher suites. + * + * |SSL_CIPHER| objects represent cipher suites. */ + +DECLARE_STACK_OF(SSL_CIPHER) + +/* SSL_get_cipher_by_value returns the structure representing a TLS cipher + * suite based on its assigned number, or NULL if unknown. See + * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4. */ +OPENSSL_EXPORT const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value); + +/* SSL_CIPHER_get_id returns |cipher|'s id. It may be cast to a |uint16_t| to + * get the cipher suite value. */ +OPENSSL_EXPORT uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_AES returns one if |cipher| uses AES (either GCM or CBC + * mode). */ +OPENSSL_EXPORT int SSL_CIPHER_is_AES(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_has_MD5_HMAC returns one if |cipher| uses HMAC-MD5. */ +OPENSSL_EXPORT int SSL_CIPHER_has_MD5_HMAC(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_has_SHA1_HMAC returns one if |cipher| uses HMAC-SHA1. */ +OPENSSL_EXPORT int SSL_CIPHER_has_SHA1_HMAC(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_AESGCM returns one if |cipher| uses AES-GCM. */ +OPENSSL_EXPORT int SSL_CIPHER_is_AESGCM(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_AES128GCM returns one if |cipher| uses 128-bit AES-GCM. */ +OPENSSL_EXPORT int SSL_CIPHER_is_AES128GCM(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_AES128CBC returns one if |cipher| uses 128-bit AES in CBC + * mode. */ +OPENSSL_EXPORT int SSL_CIPHER_is_AES128CBC(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_AES256CBC returns one if |cipher| uses 256-bit AES in CBC + * mode. */ +OPENSSL_EXPORT int SSL_CIPHER_is_AES256CBC(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_CHACHA20POLY1305 returns one if |cipher| uses + * CHACHA20_POLY1305. Note this includes both the + * draft-ietf-tls-chacha20-poly1305-04 and draft-agl-tls-chacha20poly1305-04 + * versions. */ +OPENSSL_EXPORT int SSL_CIPHER_is_CHACHA20POLY1305(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_NULL returns one if |cipher| does not encrypt. */ +OPENSSL_EXPORT int SSL_CIPHER_is_NULL(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_RC4 returns one if |cipher| uses RC4. */ +OPENSSL_EXPORT int SSL_CIPHER_is_RC4(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_block_cipher returns one if |cipher| is a block cipher. */ +OPENSSL_EXPORT int SSL_CIPHER_is_block_cipher(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_ECDSA returns one if |cipher| uses ECDSA. */ +OPENSSL_EXPORT int SSL_CIPHER_is_ECDSA(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_ECDHE returns one if |cipher| uses ECDHE. */ +OPENSSL_EXPORT int SSL_CIPHER_is_ECDHE(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_get_min_version returns the minimum protocol version required + * for |cipher|. */ +OPENSSL_EXPORT uint16_t SSL_CIPHER_get_min_version(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_get_name returns the OpenSSL name of |cipher|. */ +OPENSSL_EXPORT const char *SSL_CIPHER_get_name(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_get_kx_name returns a string that describes the key-exchange + * method used by |cipher|. For example, "ECDHE_ECDSA". */ +OPENSSL_EXPORT const char *SSL_CIPHER_get_kx_name(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_get_rfc_name returns a newly-allocated string with the standard + * name for |cipher| or NULL on error. For example, + * "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256". The caller is responsible for + * calling |OPENSSL_free| on the result. */ +OPENSSL_EXPORT char *SSL_CIPHER_get_rfc_name(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_get_bits returns the strength, in bits, of |cipher|. If + * |out_alg_bits| is not NULL, it writes the number of bits consumed by the + * symmetric algorithm to |*out_alg_bits|. */ +OPENSSL_EXPORT int SSL_CIPHER_get_bits(const SSL_CIPHER *cipher, + int *out_alg_bits); + + +/* Cipher suite configuration. + * + * OpenSSL uses a mini-language to configure cipher suites. The language + * maintains an ordered list of enabled ciphers, along with an ordered list of + * disabled but available ciphers. Initially, all ciphers are disabled with a + * default ordering. The cipher string is then interpreted as a sequence of + * directives, separated by colons, each of which modifies this state. + * + * Most directives consist of a one character or empty opcode followed by a + * selector which matches a subset of available ciphers. + * + * Available opcodes are: + * + * The empty opcode enables and appends all matching disabled ciphers to the + * end of the enabled list. The newly appended ciphers are ordered relative to + * each other matching their order in the disabled list. + * + * |-| disables all matching enabled ciphers and prepends them to the disabled + * list, with relative order from the enabled list preserved. This means the + * most recently disabled ciphers get highest preference relative to other + * disabled ciphers if re-enabled. + * + * |+| moves all matching enabled ciphers to the end of the enabled list, with + * relative order preserved. + * + * |!| deletes all matching ciphers, enabled or not, from either list. Deleted + * ciphers will not matched by future operations. + * + * A selector may be a specific cipher (using the OpenSSL name for the cipher) + * or one or more rules separated by |+|. The final selector matches the + * intersection of each rule. For instance, |AESGCM+aECDSA| matches + * ECDSA-authenticated AES-GCM ciphers. + * + * Available cipher rules are: + * + * |ALL| matches all ciphers. + * + * |kRSA|, |kDHE|, |kECDHE|, and |kPSK| match ciphers using plain RSA, DHE, + * ECDHE, and plain PSK key exchanges, respectively. Note that ECDHE_PSK is + * matched by |kECDHE| and not |kPSK|. + * + * |aRSA|, |aECDSA|, and |aPSK| match ciphers authenticated by RSA, ECDSA, and + * a pre-shared key, respectively. + * + * |RSA|, |DHE|, |ECDHE|, |PSK|, |ECDSA|, and |PSK| are aliases for the + * corresponding |k*| or |a*| cipher rule. |RSA| is an alias for |kRSA|, not + * |aRSA|. + * + * |3DES|, |RC4|, |AES128|, |AES256|, |AES|, |AESGCM|, |CHACHA20| match + * ciphers whose bulk cipher use the corresponding encryption scheme. Note + * that |AES|, |AES128|, and |AES256| match both CBC and GCM ciphers. + * + * |MD5|, |SHA1|, |SHA256|, and |SHA384| match legacy cipher suites using the + * corresponding hash function in their MAC. AEADs are matched by none of + * these. + * + * |SHA| is an alias for |SHA1|. + * + * Although implemented, authentication-only ciphers match no rules and must be + * explicitly selected by name. + * + * Deprecated cipher rules: + * + * |kEDH|, |EDH|, |kEECDH|, and |EECDH| are legacy aliases for |kDHE|, |DHE|, + * |kECDHE|, and |ECDHE|, respectively. + * + * |MEDIUM| and |HIGH| match RC4-based ciphers and all others, respectively. + * + * |FIPS| is an alias for |HIGH|. + * + * |SSLv3| and |TLSv1| match ciphers available in TLS 1.1 or earlier. + * |TLSv1_2| matches ciphers new in TLS 1.2. This is confusing and should not + * be used. + * + * Unknown rules silently match nothing. + * + * The special |@STRENGTH| directive will sort all enabled ciphers by strength. + * + * The |DEFAULT| directive, when appearing at the front of the string, expands + * to the default ordering of available ciphers. + * + * If configuring a server, one may also configure equal-preference groups to + * partially respect the client's preferences when + * |SSL_OP_CIPHER_SERVER_PREFERENCE| is enabled. Ciphers in an equal-preference + * group have equal priority and use the client order. This may be used to + * enforce that AEADs are preferred but select AES-GCM vs. ChaCha20-Poly1305 + * based on client preferences. An equal-preference is specified with square + * brackets, combining multiple selectors separated by |. For example: + * + * [ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256] + * + * Once an equal-preference group is used, future directives must be + * opcode-less. */ + +/* SSL_DEFAULT_CIPHER_LIST is the default cipher suite configuration. It is + * substituted when a cipher string starts with 'DEFAULT'. */ +#define SSL_DEFAULT_CIPHER_LIST "ALL" + +/* SSL_CTX_set_cipher_list configures the cipher list for |ctx|, evaluating + * |str| as a cipher string. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str); + +/* SSL_CTX_set_cipher_list_tls10 configures the TLS 1.0+ cipher list for |ctx|, + * evaluating |str| as a cipher string. It returns one on success and zero on + * failure. If set, servers will use this cipher suite list for TLS 1.0 or + * higher. */ +OPENSSL_EXPORT int SSL_CTX_set_cipher_list_tls10(SSL_CTX *ctx, const char *str); + +/* SSL_CTX_set_cipher_list_tls11 configures the TLS 1.1+ cipher list for |ctx|, + * evaluating |str| as a cipher string. It returns one on success and zero on + * failure. If set, servers will use this cipher suite list for TLS 1.1 or + * higher. */ +OPENSSL_EXPORT int SSL_CTX_set_cipher_list_tls11(SSL_CTX *ctx, const char *str); + +/* SSL_set_cipher_list configures the cipher list for |ssl|, evaluating |str| as + * a cipher string. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int SSL_set_cipher_list(SSL *ssl, const char *str); + +/* SSL_get_ciphers returns the cipher list for |ssl|, in order of preference. If + * |SSL_CTX_set_cipher_list_tls10| or |SSL_CTX_set_cipher_list_tls11| has been + * used, the corresponding list for the current version is returned. */ +OPENSSL_EXPORT STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl); + + +/* Connection information. */ + +/* SSL_is_init_finished returns one if |ssl| has completed its initial handshake + * and has no pending handshake. It returns zero otherwise. */ +OPENSSL_EXPORT int SSL_is_init_finished(const SSL *ssl); + +/* SSL_in_init returns one if |ssl| has a pending handshake and zero + * otherwise. */ +OPENSSL_EXPORT int SSL_in_init(const SSL *ssl); + +/* SSL_in_false_start returns one if |ssl| has a pending handshake that is in + * False Start. |SSL_write| may be called at this point without waiting for the + * peer, but |SSL_read| will complete the handshake before accepting application + * data. + * + * See also |SSL_MODE_ENABLE_FALSE_START|. */ +OPENSSL_EXPORT int SSL_in_false_start(const SSL *ssl); + +/* SSL_get_peer_certificate returns the peer's leaf certificate or NULL if the + * peer did not use certificates. The caller must call |X509_free| on the + * result to release it. */ +OPENSSL_EXPORT X509 *SSL_get_peer_certificate(const SSL *ssl); + +/* SSL_get_peer_cert_chain returns the peer's certificate chain or NULL if + * unavailable or the peer did not use certificates. This is the unverified + * list of certificates as sent by the peer, not the final chain built during + * verification. For historical reasons, this value may not be available if + * resuming a serialized |SSL_SESSION|. The caller does not take ownership of + * the result. + * + * WARNING: This function behaves differently between client and server. If + * |ssl| is a server, the returned chain does not include the leaf certificate. + * If a client, it does. */ +OPENSSL_EXPORT STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *ssl); + +/* SSL_get0_signed_cert_timestamp_list sets |*out| and |*out_len| to point to + * |*out_len| bytes of SCT information from the server. This is only valid if + * |ssl| is a client. The SCT information is a SignedCertificateTimestampList + * (including the two leading length bytes). + * See https://tools.ietf.org/html/rfc6962#section-3.3 + * If no SCT was received then |*out_len| will be zero on return. + * + * WARNING: the returned data is not guaranteed to be well formed. */ +OPENSSL_EXPORT void SSL_get0_signed_cert_timestamp_list(const SSL *ssl, + const uint8_t **out, + size_t *out_len); + +/* SSL_get0_ocsp_response sets |*out| and |*out_len| to point to |*out_len| + * bytes of an OCSP response from the server. This is the DER encoding of an + * OCSPResponse type as defined in RFC 2560. + * + * WARNING: the returned data is not guaranteed to be well formed. */ +OPENSSL_EXPORT void SSL_get0_ocsp_response(const SSL *ssl, const uint8_t **out, + size_t *out_len); + +/* SSL_get_tls_unique writes at most |max_out| bytes of the tls-unique value + * for |ssl| to |out| and sets |*out_len| to the number of bytes written. It + * returns one on success or zero on error. In general |max_out| should be at + * least 12. + * + * This function will always fail if the initial handshake has not completed. + * The tls-unique value will change after a renegotiation but, since + * renegotiations can be initiated by the server at any point, the higher-level + * protocol must either leave them disabled or define states in which the + * tls-unique value can be read. + * + * The tls-unique value is defined by + * https://tools.ietf.org/html/rfc5929#section-3.1. Due to a weakness in the + * TLS protocol, tls-unique is broken for resumed connections unless the + * Extended Master Secret extension is negotiated. Thus this function will + * return zero if |ssl| performed session resumption unless EMS was used when + * negotiating the original session. */ +OPENSSL_EXPORT int SSL_get_tls_unique(const SSL *ssl, uint8_t *out, + size_t *out_len, size_t max_out); + +/* SSL_get_extms_support returns one if the Extended Master Secret + * extension was negotiated. Otherwise, it returns zero. */ +OPENSSL_EXPORT int SSL_get_extms_support(const SSL *ssl); + +/* SSL_get_current_cipher returns the cipher used in the current outgoing + * connection state, or NULL if the null cipher is active. */ +OPENSSL_EXPORT const SSL_CIPHER *SSL_get_current_cipher(const SSL *ssl); + +/* SSL_session_reused returns one if |ssl| performed an abbreviated handshake + * and zero otherwise. + * + * TODO(davidben): Hammer down the semantics of this API while a handshake, + * initial or renego, is in progress. */ +OPENSSL_EXPORT int SSL_session_reused(const SSL *ssl); + +/* SSL_get_secure_renegotiation_support returns one if the peer supports secure + * renegotiation (RFC 5746) and zero otherwise. */ +OPENSSL_EXPORT int SSL_get_secure_renegotiation_support(const SSL *ssl); + +/* SSL_export_keying_material exports a value derived from the master secret, as + * specified in RFC 5705. It writes |out_len| bytes to |out| given a label and + * optional context. (Since a zero length context is allowed, the |use_context| + * flag controls whether a context is included.) + * + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int SSL_export_keying_material( + SSL *ssl, uint8_t *out, size_t out_len, const char *label, size_t label_len, + const uint8_t *context, size_t context_len, int use_context); + + +/* Custom extensions. + * + * The custom extension functions allow TLS extensions to be added to + * ClientHello and ServerHello messages. */ + +/* SSL_custom_ext_add_cb is a callback function that is called when the + * ClientHello (for clients) or ServerHello (for servers) is constructed. In + * the case of a server, this callback will only be called for a given + * extension if the ClientHello contained that extension – it's not possible to + * inject extensions into a ServerHello that the client didn't request. + * + * When called, |extension_value| will contain the extension number that is + * being considered for addition (so that a single callback can handle multiple + * extensions). If the callback wishes to include the extension, it must set + * |*out| to point to |*out_len| bytes of extension contents and return one. In + * this case, the corresponding |SSL_custom_ext_free_cb| callback will later be + * called with the value of |*out| once that data has been copied. + * + * If the callback does not wish to add an extension it must return zero. + * + * Alternatively, the callback can abort the connection by setting + * |*out_alert_value| to a TLS alert number and returning -1. */ +typedef int (*SSL_custom_ext_add_cb)(SSL *ssl, unsigned extension_value, + const uint8_t **out, size_t *out_len, + int *out_alert_value, void *add_arg); + +/* SSL_custom_ext_free_cb is a callback function that is called by OpenSSL iff + * an |SSL_custom_ext_add_cb| callback previously returned one. In that case, + * this callback is called and passed the |out| pointer that was returned by + * the add callback. This is to free any dynamically allocated data created by + * the add callback. */ +typedef void (*SSL_custom_ext_free_cb)(SSL *ssl, unsigned extension_value, + const uint8_t *out, void *add_arg); + +/* SSL_custom_ext_parse_cb is a callback function that is called by OpenSSL to + * parse an extension from the peer: that is from the ServerHello for a client + * and from the ClientHello for a server. + * + * When called, |extension_value| will contain the extension number and the + * contents of the extension are |contents_len| bytes at |contents|. + * + * The callback must return one to continue the handshake. Otherwise, if it + * returns zero, a fatal alert with value |*out_alert_value| is sent and the + * handshake is aborted. */ +typedef int (*SSL_custom_ext_parse_cb)(SSL *ssl, unsigned extension_value, + const uint8_t *contents, + size_t contents_len, + int *out_alert_value, void *parse_arg); + +/* SSL_extension_supported returns one iff OpenSSL internally handles + * extensions of type |extension_value|. This can be used to avoid registering + * custom extension handlers for extensions that a future version of OpenSSL + * may handle internally. */ +OPENSSL_EXPORT int SSL_extension_supported(unsigned extension_value); + +/* SSL_CTX_add_client_custom_ext registers callback functions for handling + * custom TLS extensions for client connections. + * + * If |add_cb| is NULL then an empty extension will be added in each + * ClientHello. Otherwise, see the comment for |SSL_custom_ext_add_cb| about + * this callback. + * + * The |free_cb| may be NULL if |add_cb| doesn't dynamically allocate data that + * needs to be freed. + * + * It returns one on success or zero on error. It's always an error to register + * callbacks for the same extension twice, or to register callbacks for an + * extension that OpenSSL handles internally. See |SSL_extension_supported| to + * discover, at runtime, which extensions OpenSSL handles internally. */ +OPENSSL_EXPORT int SSL_CTX_add_client_custom_ext( + SSL_CTX *ctx, unsigned extension_value, SSL_custom_ext_add_cb add_cb, + SSL_custom_ext_free_cb free_cb, void *add_arg, + SSL_custom_ext_parse_cb parse_cb, void *parse_arg); + +/* SSL_CTX_add_server_custom_ext is the same as + * |SSL_CTX_add_client_custom_ext|, but for server connections. + * + * Unlike on the client side, if |add_cb| is NULL no extension will be added. + * The |add_cb|, if any, will only be called if the ClientHello contained a + * matching extension. */ +OPENSSL_EXPORT int SSL_CTX_add_server_custom_ext( + SSL_CTX *ctx, unsigned extension_value, SSL_custom_ext_add_cb add_cb, + SSL_custom_ext_free_cb free_cb, void *add_arg, + SSL_custom_ext_parse_cb parse_cb, void *parse_arg); + + +/* Sessions. + * + * An |SSL_SESSION| represents an SSL session that may be resumed in an + * abbreviated handshake. It is reference-counted and immutable. Once + * established, an |SSL_SESSION| may be shared by multiple |SSL| objects on + * different threads and must not be modified. */ + +DECLARE_LHASH_OF(SSL_SESSION) +DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) + +/* SSL_SESSION_new returns a newly-allocated blank |SSL_SESSION| or NULL on + * error. This may be useful in writing tests but otherwise should not be + * used outside the library. */ +OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_new(void); + +/* SSL_SESSION_up_ref, if |session| is not NULL, increments the reference count + * of |session|. It then returns |session|. */ +OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_up_ref(SSL_SESSION *session); + +/* SSL_SESSION_free decrements the reference count of |session|. If it reaches + * zero, all data referenced by |session| and |session| itself are released. */ +OPENSSL_EXPORT void SSL_SESSION_free(SSL_SESSION *session); + +/* SSL_SESSION_to_bytes serializes |in| into a newly allocated buffer and sets + * |*out_data| to that buffer and |*out_len| to its length. The caller takes + * ownership of the buffer and must call |OPENSSL_free| when done. It returns + * one on success and zero on error. */ +OPENSSL_EXPORT int SSL_SESSION_to_bytes(const SSL_SESSION *in, + uint8_t **out_data, size_t *out_len); + +/* SSL_SESSION_to_bytes_for_ticket serializes |in|, but excludes the session + * identification information, namely the session ID and ticket. */ +OPENSSL_EXPORT int SSL_SESSION_to_bytes_for_ticket(const SSL_SESSION *in, + uint8_t **out_data, + size_t *out_len); + +/* SSL_SESSION_from_bytes parses |in_len| bytes from |in| as an SSL_SESSION. It + * returns a newly-allocated |SSL_SESSION| on success or NULL on error. */ +OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, + size_t in_len); + +/* SSL_SESSION_get_version returns a string describing the TLS version |session| + * was established at. For example, "TLSv1.2" or "SSLv3". */ +OPENSSL_EXPORT const char *SSL_SESSION_get_version(const SSL_SESSION *session); + +/* SSL_SESSION_get_id returns a pointer to a buffer containg |session|'s session + * ID and sets |*out_len| to its length. */ +OPENSSL_EXPORT const uint8_t *SSL_SESSION_get_id(const SSL_SESSION *session, + unsigned *out_len); + +/* SSL_SESSION_get_time returns the time at which |session| was established in + * seconds since the UNIX epoch. */ +OPENSSL_EXPORT long SSL_SESSION_get_time(const SSL_SESSION *session); + +/* SSL_SESSION_get_timeout returns the lifetime of |session| in seconds. */ +OPENSSL_EXPORT long SSL_SESSION_get_timeout(const SSL_SESSION *session); + +/* SSL_SESSION_get_key_exchange_info returns a value that describes the + * strength of the asymmetric operation that provides confidentiality to + * |session|. Its interpretation depends on the operation used. See the + * documentation for this value in the |SSL_SESSION| structure. */ +OPENSSL_EXPORT uint32_t SSL_SESSION_get_key_exchange_info( + const SSL_SESSION *session); + +/* SSL_SESSION_get0_peer return's the peer leaf certificate stored in + * |session|. + * + * TODO(davidben): This should return a const X509 *. */ +OPENSSL_EXPORT X509 *SSL_SESSION_get0_peer(const SSL_SESSION *session); + +/* SSL_SESSION_set_time sets |session|'s creation time to |time| and returns + * |time|. This function may be useful in writing tests but otherwise should not + * be used. */ +OPENSSL_EXPORT long SSL_SESSION_set_time(SSL_SESSION *session, long time); + +/* SSL_SESSION_set_timeout sets |session|'s timeout to |timeout| and returns + * one. This function may be useful in writing tests but otherwise should not + * be used. */ +OPENSSL_EXPORT long SSL_SESSION_set_timeout(SSL_SESSION *session, long timeout); + +/* SSL_SESSION_set1_id_context sets |session|'s session ID context (see + * |SSL_CTX_set_session_id_context|) to |sid_ctx|. It returns one on success and + * zero on error. This function may be useful in writing tests but otherwise + * should not be used. */ +OPENSSL_EXPORT int SSL_SESSION_set1_id_context(SSL_SESSION *session, + const uint8_t *sid_ctx, + unsigned sid_ctx_len); + + +/* Session caching. + * + * Session caching allows clients to reconnect to a server based on saved + * parameters from a previous connection. + * + * For a server, the library implements a built-in internal session cache as an + * in-memory hash table. One may also register callbacks to implement a custom + * external session cache. An external cache may be used in addition to or + * instead of the internal one. Use |SSL_CTX_set_session_cache_mode| to toggle + * the internal cache. + * + * For a client, the only option is an external session cache. Prior to + * handshaking, the consumer should look up a session externally (keyed, for + * instance, by hostname) and use |SSL_set_session| to configure which session + * to offer. The callbacks may be used to determine when new sessions are + * available. + * + * Note that offering or accepting a session short-circuits most parameter + * negotiation. Resuming sessions across different configurations may result in + * surprising behavor. So, for instance, a client implementing a version + * fallback should shard its session cache by maximum protocol version. */ + +/* SSL_SESS_CACHE_OFF disables all session caching. */ +#define SSL_SESS_CACHE_OFF 0x0000 + +/* SSL_SESS_CACHE_CLIENT enables session caching for a client. The internal + * cache is never used on a client, so this only enables the callbacks. */ +#define SSL_SESS_CACHE_CLIENT 0x0001 + +/* SSL_SESS_CACHE_SERVER enables session caching for a server. */ +#define SSL_SESS_CACHE_SERVER 0x0002 + +/* SSL_SESS_CACHE_SERVER enables session caching for both client and server. */ +#define SSL_SESS_CACHE_BOTH (SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_SERVER) + +/* SSL_SESS_CACHE_NO_AUTO_CLEAR disables automatically calling + * |SSL_CTX_flush_sessions| every 255 connections. */ +#define SSL_SESS_CACHE_NO_AUTO_CLEAR 0x0080 + +/* SSL_SESS_CACHE_NO_INTERNAL_LOOKUP, on a server, disables looking up a session + * from the internal session cache. */ +#define SSL_SESS_CACHE_NO_INTERNAL_LOOKUP 0x0100 + +/* SSL_SESS_CACHE_NO_INTERNAL_STORE, on a server, disables storing sessions in + * the internal session cache. */ +#define SSL_SESS_CACHE_NO_INTERNAL_STORE 0x0200 + +/* SSL_SESS_CACHE_NO_INTERNAL, on a server, disables the internal session + * cache. */ +#define SSL_SESS_CACHE_NO_INTERNAL \ + (SSL_SESS_CACHE_NO_INTERNAL_LOOKUP | SSL_SESS_CACHE_NO_INTERNAL_STORE) + +/* SSL_CTX_set_session_cache_mode sets the session cache mode bits for |ctx| to + * |mode|. It returns the previous value. */ +OPENSSL_EXPORT int SSL_CTX_set_session_cache_mode(SSL_CTX *ctx, int mode); + +/* SSL_CTX_get_session_cache_mode returns the session cache mode bits for + * |ctx| */ +OPENSSL_EXPORT int SSL_CTX_get_session_cache_mode(const SSL_CTX *ctx); + +/* SSL_set_session, for a client, configures |ssl| to offer to resume |session| + * in the initial handshake and returns one. The caller retains ownership of + * |session|. */ +OPENSSL_EXPORT int SSL_set_session(SSL *ssl, SSL_SESSION *session); + +/* SSL_get_session returns a non-owning pointer to |ssl|'s session. Prior to the + * initial handshake beginning, this is the session to be offered, set by + * |SSL_set_session|. After a handshake has finished, this is the currently + * active session. Its behavior is undefined while a handshake is progress. */ +OPENSSL_EXPORT SSL_SESSION *SSL_get_session(const SSL *ssl); + +/* SSL_get0_session is an alias for |SSL_get_session|. */ +#define SSL_get0_session SSL_get_session + +/* SSL_get1_session acts like |SSL_get_session| but returns a new reference to + * the session. */ +OPENSSL_EXPORT SSL_SESSION *SSL_get1_session(SSL *ssl); + +/* SSL_DEFAULT_SESSION_TIMEOUT is the default lifetime, in seconds, of a + * session. */ +#define SSL_DEFAULT_SESSION_TIMEOUT (2 * 60 * 60) + +/* SSL_CTX_set_timeout sets the lifetime, in seconds, of sessions created in + * |ctx| to |timeout|. */ +OPENSSL_EXPORT long SSL_CTX_set_timeout(SSL_CTX *ctx, long timeout); + +/* SSL_CTX_get_timeout returns the lifetime, in seconds, of sessions created in + * |ctx|. */ +OPENSSL_EXPORT long SSL_CTX_get_timeout(const SSL_CTX *ctx); + +/* SSL_CTX_set_session_id_context sets |ctx|'s session ID context to |sid_ctx|. + * It returns one on success and zero on error. The session ID context is an + * application-defined opaque byte string. A session will not be used in a + * connection without a matching session ID context. + * + * For a server, if |SSL_VERIFY_PEER| is enabled, it is an error to not set a + * session ID context. + * + * TODO(davidben): Is that check needed? That seems a special case of taking + * care not to cross-resume across configuration changes, and this is only + * relevant if a server requires client auth. */ +OPENSSL_EXPORT int SSL_CTX_set_session_id_context(SSL_CTX *ctx, + const uint8_t *sid_ctx, + unsigned sid_ctx_len); + +/* SSL_set_session_id_context sets |ssl|'s session ID context to |sid_ctx|. It + * returns one on success and zero on error. See also + * |SSL_CTX_set_session_id_context|. */ +OPENSSL_EXPORT int SSL_set_session_id_context(SSL *ssl, const uint8_t *sid_ctx, + unsigned sid_ctx_len); + +/* SSL_SESSION_CACHE_MAX_SIZE_DEFAULT is the default maximum size of a session + * cache. */ +#define SSL_SESSION_CACHE_MAX_SIZE_DEFAULT (1024 * 20) + +/* SSL_CTX_sess_set_cache_size sets the maximum size of |ctx|'s internal session + * cache to |size|. It returns the previous value. */ +OPENSSL_EXPORT unsigned long SSL_CTX_sess_set_cache_size(SSL_CTX *ctx, + unsigned long size); + +/* SSL_CTX_sess_get_cache_size returns the maximum size of |ctx|'s internal + * session cache. */ +OPENSSL_EXPORT unsigned long SSL_CTX_sess_get_cache_size(const SSL_CTX *ctx); + +/* SSL_CTX_sessions returns |ctx|'s internal session cache. */ +OPENSSL_EXPORT LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx); + +/* SSL_CTX_sess_number returns the number of sessions in |ctx|'s internal + * session cache. */ +OPENSSL_EXPORT size_t SSL_CTX_sess_number(const SSL_CTX *ctx); + +/* SSL_CTX_add_session inserts |session| into |ctx|'s internal session cache. It + * returns one on success and zero on error or if |session| is already in the + * cache. The caller retains its reference to |session|. */ +OPENSSL_EXPORT int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *session); + +/* SSL_CTX_remove_session removes |session| from |ctx|'s internal session cache. + * It returns one on success and zero if |session| was not in the cache. */ +OPENSSL_EXPORT int SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *session); + +/* SSL_CTX_flush_sessions removes all sessions from |ctx| which have expired as + * of time |time|. If |time| is zero, all sessions are removed. */ +OPENSSL_EXPORT void SSL_CTX_flush_sessions(SSL_CTX *ctx, long time); + +/* SSL_CTX_sess_set_new_cb sets the callback to be called when a new session is + * established and ready to be cached. If the session cache is disabled (the + * appropriate one of |SSL_SESS_CACHE_CLIENT| or |SSL_SESS_CACHE_SERVER| is + * unset), the callback is not called. + * + * The callback is passed a reference to |session|. It returns one if it takes + * ownership and zero otherwise. + * + * Note: For a client, the callback may be called on abbreviated handshakes if a + * ticket is renewed. Further, it may not be called until some time after + * |SSL_do_handshake| or |SSL_connect| completes if False Start is enabled. Thus + * it's recommended to use this callback over checking |SSL_session_reused| on + * handshake completion. + * + * TODO(davidben): Conditioning callbacks on |SSL_SESS_CACHE_CLIENT| or + * |SSL_SESS_CACHE_SERVER| doesn't make any sense when one could just as easily + * not supply the callbacks. Removing that condition and the client internal + * cache would simplify things. */ +OPENSSL_EXPORT void SSL_CTX_sess_set_new_cb( + SSL_CTX *ctx, int (*new_session_cb)(SSL *ssl, SSL_SESSION *session)); + +/* SSL_CTX_sess_get_new_cb returns the callback set by + * |SSL_CTX_sess_set_new_cb|. */ +OPENSSL_EXPORT int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))( + SSL *ssl, SSL_SESSION *session); + +/* SSL_CTX_sess_set_remove_cb sets a callback which is called when a session is + * removed from the internal session cache. + * + * TODO(davidben): What is the point of this callback? It seems useless since it + * only fires on sessions in the internal cache. */ +OPENSSL_EXPORT void SSL_CTX_sess_set_remove_cb( + SSL_CTX *ctx, + void (*remove_session_cb)(SSL_CTX *ctx, SSL_SESSION *session)); + +/* SSL_CTX_sess_get_remove_cb returns the callback set by + * |SSL_CTX_sess_set_remove_cb|. */ +OPENSSL_EXPORT void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))( + SSL_CTX *ctx, SSL_SESSION *session); + +/* SSL_CTX_sess_set_get_cb sets a callback to look up a session by ID for a + * server. The callback is passed the session ID and should return a matching + * |SSL_SESSION| or NULL if not found. It should set |*out_copy| to zero and + * return a new reference to the session. This callback is not used for a + * client. + * + * For historical reasons, if |*out_copy| is set to one (default), the SSL + * library will take a new reference to the returned |SSL_SESSION|, expecting + * the callback to return a non-owning pointer. This is not recommended. If + * |ctx| and thus the callback is used on multiple threads, the session may be + * removed and invalidated before the SSL library calls |SSL_SESSION_up_ref|, + * whereas the callback may synchronize internally. + * + * To look up a session asynchronously, the callback may return + * |SSL_magic_pending_session_ptr|. See the documentation for that function and + * |SSL_ERROR_PENDING_SESSION|. + * + * If the internal session cache is enabled, the callback is only consulted if + * the internal cache does not return a match. + * + * The callback's |id| parameter is not const for historical reasons, but the + * contents may not be modified. */ +OPENSSL_EXPORT void SSL_CTX_sess_set_get_cb( + SSL_CTX *ctx, + SSL_SESSION *(*get_session_cb)(SSL *ssl, uint8_t *id, int id_len, + int *out_copy)); + +/* SSL_CTX_sess_get_get_cb returns the callback set by + * |SSL_CTX_sess_set_get_cb|. */ +OPENSSL_EXPORT SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))( + SSL *ssl, uint8_t *id, int id_len, int *out_copy); + +/* SSL_magic_pending_session_ptr returns a magic |SSL_SESSION|* which indicates + * that the session isn't currently unavailable. |SSL_get_error| will then + * return |SSL_ERROR_PENDING_SESSION| and the handshake can be retried later + * when the lookup has completed. */ +OPENSSL_EXPORT SSL_SESSION *SSL_magic_pending_session_ptr(void); + + +/* Session tickets. + * + * Session tickets, from RFC 5077, allow session resumption without server-side + * state. Session tickets are supported in by default but may be disabled with + * |SSL_OP_NO_TICKET|. + * + * On the client, ticket-based sessions use the same APIs as ID-based tickets. + * Callers do not need to handle them differently. + * + * On the server, tickets are encrypted and authenticated with a secret key. By + * default, an |SSL_CTX| generates a key on creation. Tickets are minted and + * processed transparently. The following functions may be used to configure a + * persistent key or implement more custom behavior. */ + +/* SSL_CTX_get_tlsext_ticket_keys writes |ctx|'s session ticket key material to + * |len| bytes of |out|. It returns one on success and zero if |len| is not + * 48. If |out| is NULL, it returns 48 instead. */ +OPENSSL_EXPORT int SSL_CTX_get_tlsext_ticket_keys(SSL_CTX *ctx, void *out, + size_t len); + +/* SSL_CTX_set_tlsext_ticket_keys sets |ctx|'s session ticket key material to + * |len| bytes of |in|. It returns one on success and zero if |len| is not + * 48. If |in| is NULL, it returns 48 instead. */ +OPENSSL_EXPORT int SSL_CTX_set_tlsext_ticket_keys(SSL_CTX *ctx, const void *in, + size_t len); + +/* SSL_TICKET_KEY_NAME_LEN is the length of the key name prefix of a session + * ticket. */ +#define SSL_TICKET_KEY_NAME_LEN 16 + +/* SSL_CTX_set_tlsext_ticket_key_cb sets the ticket callback to |callback| and + * returns one. |callback| will be called when encrypting a new ticket and when + * decrypting a ticket from the client. + * + * In both modes, |ctx| and |hmac_ctx| will already have been initialized with + * |EVP_CIPHER_CTX_init| and |HMAC_CTX_init|, respectively. |callback| + * configures |hmac_ctx| with an HMAC digest and key, and configures |ctx| + * for encryption or decryption, based on the mode. + * + * When encrypting a new ticket, |encrypt| will be one. It writes a public + * 16-byte key name to |key_name| and a fresh IV to |iv|. The output IV length + * must match |EVP_CIPHER_CTX_iv_length| of the cipher selected. In this mode, + * |callback| returns 1 on success and -1 on error. + * + * When decrypting a ticket, |encrypt| will be zero. |key_name| will point to a + * 16-byte key name and |iv| points to an IV. The length of the IV consumed must + * match |EVP_CIPHER_CTX_iv_length| of the cipher selected. In this mode, + * |callback| returns -1 to abort the handshake, 0 if decrypting the ticket + * failed, and 1 or 2 on success. If it returns 2, the ticket will be renewed. + * This may be used to re-key the ticket. + * + * WARNING: |callback| wildly breaks the usual return value convention and is + * called in two different modes. */ +OPENSSL_EXPORT int SSL_CTX_set_tlsext_ticket_key_cb( + SSL_CTX *ctx, int (*callback)(SSL *ssl, uint8_t *key_name, uint8_t *iv, + EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx, + int encrypt)); + + +/* Elliptic curve Diffie-Hellman. + * + * Cipher suites using an ECDHE key exchange perform Diffie-Hellman over an + * elliptic curve negotiated by both endpoints. See RFC 4492. Only named curves + * are supported. ECDHE is always enabled, but the curve preferences may be + * configured with these functions. + * + * A client may use |SSL_SESSION_get_key_exchange_info| to determine the curve + * selected. */ + +/* SSL_CTX_set1_curves sets the preferred curves for |ctx| to be |curves|. Each + * element of |curves| should be a curve nid. It returns one on success and + * zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_set1_curves(SSL_CTX *ctx, const int *curves, + size_t curves_len); + +/* SSL_set1_curves sets the preferred curves for |ssl| to be |curves|. Each + * element of |curves| should be a curve nid. It returns one on success and + * zero on failure. */ +OPENSSL_EXPORT int SSL_set1_curves(SSL *ssl, const int *curves, + size_t curves_len); + +/* SSL_get_curve_name returns a human-readable name for the elliptic curve + * specified by the given TLS curve id, or NULL if the curve if unknown. */ +OPENSSL_EXPORT const char *SSL_get_curve_name(uint16_t curve_id); + + +/* Multiplicative Diffie-Hellman. + * + * Cipher suites using a DHE key exchange perform Diffie-Hellman over a + * multiplicative group selected by the server. These ciphers are disabled for a + * server unless a group is chosen with one of these functions. + * + * A client may use |SSL_SESSION_get_key_exchange_info| to determine the size of + * the selected group's prime, but note that servers may select degenerate + * groups. */ + +/* SSL_CTX_set_tmp_dh configures |ctx| to use the group from |dh| as the group + * for DHE. Only the group is used, so |dh| needn't have a keypair. It returns + * one on success and zero on error. */ +OPENSSL_EXPORT int SSL_CTX_set_tmp_dh(SSL_CTX *ctx, const DH *dh); + +/* SSL_set_tmp_dh configures |ssl| to use the group from |dh| as the group for + * DHE. Only the group is used, so |dh| needn't have a keypair. It returns one + * on success and zero on error. */ +OPENSSL_EXPORT int SSL_set_tmp_dh(SSL *ssl, const DH *dh); + +/* SSL_CTX_set_tmp_dh_callback configures |ctx| to use |callback| to determine + * the group for DHE ciphers. |callback| should ignore |is_export| and + * |keylength| and return a |DH| of the selected group or NULL on error. Only + * the parameters are used, so the |DH| needn't have a generated keypair. + * + * WARNING: The caller does not take ownership of the resulting |DH|, so + * |callback| must save and release the object elsewhere. */ +OPENSSL_EXPORT void SSL_CTX_set_tmp_dh_callback( + SSL_CTX *ctx, DH *(*callback)(SSL *ssl, int is_export, int keylength)); + +/* SSL_set_tmp_dh_callback configures |ssl| to use |callback| to determine the + * group for DHE ciphers. |callback| should ignore |is_export| and |keylength| + * and return a |DH| of the selected group or NULL on error. Only the + * parameters are used, so the |DH| needn't have a generated keypair. + * + * WARNING: The caller does not take ownership of the resulting |DH|, so + * |callback| must save and release the object elsewhere. */ +OPENSSL_EXPORT void SSL_set_tmp_dh_callback(SSL *ssl, + DH *(*dh)(SSL *ssl, int is_export, + int keylength)); + + +/* Certificate verification. + * + * SSL may authenticate either endpoint with an X.509 certificate. Typically + * this is used to authenticate the server to the client. These functions + * configure certificate verification. + * + * WARNING: By default, certificate verification errors on a client are not + * fatal. See |SSL_VERIFY_NONE| This may be configured with + * |SSL_CTX_set_verify|. + * + * By default clients are anonymous but a server may request a certificate from + * the client by setting |SSL_VERIFY_PEER|. + * + * Many of these functions use OpenSSL's legacy X.509 stack which is + * underdocumented and deprecated, but the replacement isn't ready yet. For + * now, consumers may use the existing stack or bypass it by performing + * certificate verification externally. This may be done with + * |SSL_CTX_set_cert_verify_callback| or by extracting the chain with + * |SSL_get_peer_cert_chain| after the handshake. In the future, functions will + * be added to use the SSL stack without dependency on any part of the legacy + * X.509 and ASN.1 stack. + * + * To augment certificate verification, a client may also enable OCSP stapling + * (RFC 6066) and Certificate Transparency (RFC 6962) extensions. */ + +/* SSL_VERIFY_NONE, on a client, verifies the server certificate but does not + * make errors fatal. The result may be checked with |SSL_get_verify_result|. On + * a server it does not request a client certificate. This is the default. */ +#define SSL_VERIFY_NONE 0x00 + +/* SSL_VERIFY_PEER, on a client, makes server certificate errors fatal. On a + * server it requests a client certificate and makes errors fatal. However, + * anonymous clients are still allowed. See + * |SSL_VERIFY_FAIL_IF_NO_PEER_CERT|. */ +#define SSL_VERIFY_PEER 0x01 + +/* SSL_VERIFY_FAIL_IF_NO_PEER_CERT configures a server to reject connections if + * the client declines to send a certificate. Otherwise |SSL_VERIFY_PEER| still + * allows anonymous clients. */ +#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 + +/* SSL_VERIFY_PEER_IF_NO_OBC configures a server to request a client certificate + * if and only if Channel ID is not negotiated. */ +#define SSL_VERIFY_PEER_IF_NO_OBC 0x04 + +/* SSL_CTX_set_verify configures certificate verification behavior. |mode| is + * one of the |SSL_VERIFY_*| values defined above. |callback|, if not NULL, is + * used to customize certificate verification. See the behavior of + * |X509_STORE_CTX_set_verify_cb|. + * + * The callback may use |SSL_get_ex_data_X509_STORE_CTX_idx| with + * |X509_STORE_CTX_get_ex_data| to look up the |SSL| from |store_ctx|. */ +OPENSSL_EXPORT void SSL_CTX_set_verify( + SSL_CTX *ctx, int mode, int (*callback)(int ok, X509_STORE_CTX *store_ctx)); + +/* SSL_set_verify configures certificate verification behavior. |mode| is one of + * the |SSL_VERIFY_*| values defined above. |callback|, if not NULL, is used to + * customize certificate verification. See the behavior of + * |X509_STORE_CTX_set_verify_cb|. + * + * The callback may use |SSL_get_ex_data_X509_STORE_CTX_idx| with + * |X509_STORE_CTX_get_ex_data| to look up the |SSL| from |store_ctx|. */ +OPENSSL_EXPORT void SSL_set_verify(SSL *ssl, int mode, + int (*callback)(int ok, + X509_STORE_CTX *store_ctx)); + +/* SSL_CTX_get_verify_mode returns |ctx|'s verify mode, set by + * |SSL_CTX_set_verify|. */ +OPENSSL_EXPORT int SSL_CTX_get_verify_mode(const SSL_CTX *ctx); + +/* SSL_get_verify_mode returns |ssl|'s verify mode, set by |SSL_CTX_set_verify| + * or |SSL_set_verify|. */ +OPENSSL_EXPORT int SSL_get_verify_mode(const SSL *ssl); + +/* SSL_CTX_get_verify_callback returns the callback set by + * |SSL_CTX_set_verify|. */ +OPENSSL_EXPORT int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))( + int ok, X509_STORE_CTX *store_ctx); + +/* SSL_get_verify_callback returns the callback set by |SSL_CTX_set_verify| or + * |SSL_set_verify|. */ +OPENSSL_EXPORT int (*SSL_get_verify_callback(const SSL *ssl))( + int ok, X509_STORE_CTX *store_ctx); + +/* SSL_CTX_set_verify_depth sets the maximum depth of a certificate chain + * accepted in verification. This number does not include the leaf, so a depth + * of 1 allows the leaf and one CA certificate. */ +OPENSSL_EXPORT void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth); + +/* SSL_set_verify_depth sets the maximum depth of a certificate chain accepted + * in verification. This number does not include the leaf, so a depth of 1 + * allows the leaf and one CA certificate. */ +OPENSSL_EXPORT void SSL_set_verify_depth(SSL *ssl, int depth); + +/* SSL_CTX_get_verify_depth returns the maximum depth of a certificate accepted + * in verification. */ +OPENSSL_EXPORT int SSL_CTX_get_verify_depth(const SSL_CTX *ctx); + +/* SSL_get_verify_depth returns the maximum depth of a certificate accepted in + * verification. */ +OPENSSL_EXPORT int SSL_get_verify_depth(const SSL *ssl); + +/* SSL_CTX_set1_param sets verification parameters from |param|. It returns one + * on success and zero on failure. The caller retains ownership of |param|. */ +OPENSSL_EXPORT int SSL_CTX_set1_param(SSL_CTX *ctx, + const X509_VERIFY_PARAM *param); + +/* SSL_set1_param sets verification parameters from |param|. It returns one on + * success and zero on failure. The caller retains ownership of |param|. */ +OPENSSL_EXPORT int SSL_set1_param(SSL *ssl, + const X509_VERIFY_PARAM *param); + +/* SSL_CTX_get0_param returns |ctx|'s |X509_VERIFY_PARAM| for certificate + * verification. The caller must not release the returned pointer but may call + * functions on it to configure it. */ +OPENSSL_EXPORT X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx); + +/* SSL_get0_param returns |ssl|'s |X509_VERIFY_PARAM| for certificate + * verification. The caller must not release the returned pointer but may call + * functions on it to configure it. */ +OPENSSL_EXPORT X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl); + +/* SSL_CTX_set_purpose sets |ctx|'s |X509_VERIFY_PARAM|'s 'purpose' parameter to + * |purpose|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int SSL_CTX_set_purpose(SSL_CTX *ctx, int purpose); + +/* SSL_set_purpose sets |ssl|'s |X509_VERIFY_PARAM|'s 'purpose' parameter to + * |purpose|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int SSL_set_purpose(SSL *ssl, int purpose); + +/* SSL_CTX_set_trust sets |ctx|'s |X509_VERIFY_PARAM|'s 'trust' parameter to + * |trust|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int SSL_CTX_set_trust(SSL_CTX *ctx, int trust); + +/* SSL_set_trust sets |ssl|'s |X509_VERIFY_PARAM|'s 'trust' parameter to + * |trust|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int SSL_set_trust(SSL *ssl, int trust); + +/* SSL_CTX_set_cert_store sets |ctx|'s certificate store to |store|. It takes + * ownership of |store|. The store is used for certificate verification. + * + * The store is also used for the auto-chaining feature, but this is deprecated. + * See also |SSL_MODE_NO_AUTO_CHAIN|. */ +OPENSSL_EXPORT void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store); + +/* SSL_CTX_get_cert_store returns |ctx|'s certificate store. */ +OPENSSL_EXPORT X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx); + +/* SSL_CTX_set_default_verify_paths loads the OpenSSL system-default trust + * anchors into |ctx|'s store. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); + +/* SSL_CTX_load_verify_locations loads trust anchors into |ctx|'s store from + * |ca_file| and |ca_dir|, either of which may be NULL. If |ca_file| is passed, + * it is opened and PEM-encoded CA certificates are read. If |ca_dir| is passed, + * it is treated as a directory in OpenSSL's hashed directory format. It returns + * one on success and zero on failure. + * + * See + * https://www.openssl.org/docs/manmaster/ssl/SSL_CTX_load_verify_locations.html + * for documentation on the directory format. */ +OPENSSL_EXPORT int SSL_CTX_load_verify_locations(SSL_CTX *ctx, + const char *ca_file, + const char *ca_dir); + +/* SSL_get_verify_result returns the result of certificate verification. It is + * either |X509_V_OK| or a |X509_V_ERR_*| value. */ +OPENSSL_EXPORT long SSL_get_verify_result(const SSL *ssl); + +/* SSL_set_verify_result overrides the result of certificate verification. */ +OPENSSL_EXPORT void SSL_set_verify_result(SSL *ssl, long result); + +/* SSL_get_ex_data_X509_STORE_CTX_idx returns the ex_data index used to look up + * the |SSL| associated with an |X509_STORE_CTX| in the verify callback. */ +OPENSSL_EXPORT int SSL_get_ex_data_X509_STORE_CTX_idx(void); + +/* SSL_CTX_set_cert_verify_callback sets a custom callback to be called on + * certificate verification rather than |X509_verify_cert|. |store_ctx| contains + * the verification parameters. The callback should return one on success and + * zero on fatal error. It may use |X509_STORE_CTX_set_error| to set a + * verification result. + * + * The callback may use either the |arg| parameter or + * |SSL_get_ex_data_X509_STORE_CTX_idx| to recover the associated |SSL| + * object. */ +OPENSSL_EXPORT void SSL_CTX_set_cert_verify_callback( + SSL_CTX *ctx, int (*callback)(X509_STORE_CTX *store_ctx, void *arg), + void *arg); + +/* SSL_enable_signed_cert_timestamps causes |ssl| (which must be the client end + * of a connection) to request SCTs from the server. See + * https://tools.ietf.org/html/rfc6962. It returns one. + * + * Call |SSL_get0_signed_cert_timestamp_list| to recover the SCT after the + * handshake. */ +OPENSSL_EXPORT int SSL_enable_signed_cert_timestamps(SSL *ssl); + +/* SSL_CTX_enable_signed_cert_timestamps enables SCT requests on all client SSL + * objects created from |ctx|. + * + * Call |SSL_get0_signed_cert_timestamp_list| to recover the SCT after the + * handshake. */ +OPENSSL_EXPORT void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx); + +/* SSL_enable_ocsp_stapling causes |ssl| (which must be the client end of a + * connection) to request a stapled OCSP response from the server. It returns + * one. + * + * Call |SSL_get0_ocsp_response| to recover the OCSP response after the + * handshake. */ +OPENSSL_EXPORT int SSL_enable_ocsp_stapling(SSL *ssl); + +/* SSL_CTX_enable_ocsp_stapling enables OCSP stapling on all client SSL objects + * created from |ctx|. + * + * Call |SSL_get0_ocsp_response| to recover the OCSP response after the + * handshake. */ +OPENSSL_EXPORT void SSL_CTX_enable_ocsp_stapling(SSL_CTX *ctx); + + +/* Client certificate CA list. + * + * When requesting a client certificate, a server may advertise a list of + * certificate authorities which are accepted. These functions may be used to + * configure this list. */ + +/* SSL_set_client_CA_list sets |ssl|'s client certificate CA list to + * |name_list|. It takes ownership of |name_list|. */ +OPENSSL_EXPORT void SSL_set_client_CA_list(SSL *ssl, + STACK_OF(X509_NAME) *name_list); + +/* SSL_CTX_set_client_CA_list sets |ctx|'s client certificate CA list to + * |name_list|. It takes ownership of |name_list|. */ +OPENSSL_EXPORT void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, + STACK_OF(X509_NAME) *name_list); + +/* SSL_get_client_CA_list returns |ssl|'s client certificate CA list. If |ssl| + * has not been configured as a client, this is the list configured by + * |SSL_CTX_set_client_CA_list|. + * + * If configured as a client, it returns the client certificate CA list sent by + * the server. In this mode, the behavior is undefined except during the + * callbacks set by |SSL_CTX_set_cert_cb| and |SSL_CTX_set_client_cert_cb| or + * when the handshake is paused because of them. */ +OPENSSL_EXPORT STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl); + +/* SSL_CTX_get_client_CA_list returns |ctx|'s client certificate CA list. */ +OPENSSL_EXPORT STACK_OF(X509_NAME) * + SSL_CTX_get_client_CA_list(const SSL_CTX *ctx); + +/* SSL_add_client_CA appends |x509|'s subject to the client certificate CA list. + * It returns one on success or zero on error. The caller retains ownership of + * |x509|. */ +OPENSSL_EXPORT int SSL_add_client_CA(SSL *ssl, X509 *x509); + +/* SSL_CTX_add_client_CA appends |x509|'s subject to the client certificate CA + * list. It returns one on success or zero on error. The caller retains + * ownership of |x509|. */ +OPENSSL_EXPORT int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x509); + +/* SSL_load_client_CA_file opens |file| and reads PEM-encoded certificates from + * it. It returns a newly-allocated stack of the certificate subjects or NULL + * on error. */ +OPENSSL_EXPORT STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file); + +/* SSL_dup_CA_list makes a deep copy of |list|. It returns the new list on + * success or NULL on allocation error. */ +OPENSSL_EXPORT STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list); + +/* SSL_add_file_cert_subjects_to_stack behaves like |SSL_load_client_CA_file| + * but appends the result to |out|. It returns one on success or zero on + * error. */ +OPENSSL_EXPORT int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *out, + const char *file); + +/* SSL_add_dir_cert_subjects_to_stack lists files in directory |dir|. It calls + * |SSL_add_file_cert_subjects_to_stack| on each file and returns one on success + * or zero on error. */ +OPENSSL_EXPORT int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *out, + const char *dir); + + +/* Server name indication. + * + * The server_name extension (RFC 3546) allows the client to advertise the name + * of the server it is connecting to. This is used in virtual hosting + * deployments to select one of a several certificates on a single IP. Only the + * host_name name type is supported. */ + +#define TLSEXT_NAMETYPE_host_name 0 + +/* SSL_set_tlsext_host_name, for a client, configures |ssl| to advertise |name| + * in the server_name extension. It returns one on success and zero on error. */ +OPENSSL_EXPORT int SSL_set_tlsext_host_name(SSL *ssl, const char *name); + +/* SSL_get_servername, for a server, returns the hostname supplied by the + * client or NULL if there was none. The |type| argument must be + * |TLSEXT_NAMETYPE_host_name|. */ +OPENSSL_EXPORT const char *SSL_get_servername(const SSL *ssl, const int type); + +/* SSL_get_servername_type, for a server, returns |TLSEXT_NAMETYPE_host_name| + * if the client sent a hostname and -1 otherwise. */ +OPENSSL_EXPORT int SSL_get_servername_type(const SSL *ssl); + +/* SSL_CTX_set_tlsext_servername_callback configures |callback| to be called on + * the server after ClientHello extensions have been parsed and returns one. + * The callback may use |SSL_get_servername| to examine the server_name extension + * and returns a |SSL_TLSEXT_ERR_*| value. The value of |arg| may be set by + * calling |SSL_CTX_set_tlsext_servername_arg|. + * + * If the callback returns |SSL_TLSEXT_ERR_NOACK|, the server_name extension is + * not acknowledged in the ServerHello. If the return value is + * |SSL_TLSEXT_ERR_ALERT_FATAL| or |SSL_TLSEXT_ERR_ALERT_WARNING| then + * |*out_alert| must be set to the alert value to send. */ +OPENSSL_EXPORT int SSL_CTX_set_tlsext_servername_callback( + SSL_CTX *ctx, int (*callback)(SSL *ssl, int *out_alert, void *arg)); + +/* SSL_CTX_set_tlsext_servername_arg sets the argument to the servername + * callback and returns one. See |SSL_CTX_set_tlsext_servername_callback|. */ +OPENSSL_EXPORT int SSL_CTX_set_tlsext_servername_arg(SSL_CTX *ctx, void *arg); + +/* SSL_TLSEXT_ERR_* are values returned by some extension-related callbacks. */ +#define SSL_TLSEXT_ERR_OK 0 +#define SSL_TLSEXT_ERR_ALERT_WARNING 1 +#define SSL_TLSEXT_ERR_ALERT_FATAL 2 +#define SSL_TLSEXT_ERR_NOACK 3 + + +/* Application-layer protocol negotation. + * + * The ALPN extension (RFC 7301) allows negotiating different application-layer + * protocols over a single port. This is used, for example, to negotiate + * HTTP/2. */ + +/* SSL_CTX_set_alpn_protos sets the client ALPN protocol list on |ctx| to + * |protos|. |protos| must be in wire-format (i.e. a series of non-empty, 8-bit + * length-prefixed strings). It returns zero on success and one on failure. + * Configuring this list enables ALPN on a client. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. */ +OPENSSL_EXPORT int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const uint8_t *protos, + unsigned protos_len); + +/* SSL_set_alpn_protos sets the client ALPN protocol list on |ssl| to |protos|. + * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit + * length-prefixed strings). It returns zero on success and one on failure. + * Configuring this list enables ALPN on a client. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. */ +OPENSSL_EXPORT int SSL_set_alpn_protos(SSL *ssl, const uint8_t *protos, + unsigned protos_len); + +/* SSL_CTX_set_alpn_select_cb sets a callback function on |ctx| that is called + * during ClientHello processing in order to select an ALPN protocol from the + * client's list of offered protocols. Configuring this callback enables ALPN on + * a server. + * + * The callback is passed a wire-format (i.e. a series of non-empty, 8-bit + * length-prefixed strings) ALPN protocol list in |in|. It should set |*out| and + * |*out_len| to the selected protocol and return |SSL_TLSEXT_ERR_OK| on + * success. It does not pass ownership of the buffer. Otherwise, it should + * return |SSL_TLSEXT_ERR_NOACK|. Other |SSL_TLSEXT_ERR_*| values are + * unimplemented and will be treated as |SSL_TLSEXT_ERR_NOACK|. */ +OPENSSL_EXPORT void SSL_CTX_set_alpn_select_cb( + SSL_CTX *ctx, int (*cb)(SSL *ssl, const uint8_t **out, uint8_t *out_len, + const uint8_t *in, unsigned in_len, void *arg), + void *arg); + +/* SSL_get0_alpn_selected gets the selected ALPN protocol (if any) from |ssl|. + * On return it sets |*out_data| to point to |*out_len| bytes of protocol name + * (not including the leading length-prefix byte). If the server didn't respond + * with a negotiated protocol then |*out_len| will be zero. */ +OPENSSL_EXPORT void SSL_get0_alpn_selected(const SSL *ssl, + const uint8_t **out_data, + unsigned *out_len); + + +/* Next protocol negotiation. + * + * The NPN extension (draft-agl-tls-nextprotoneg-03) is the predecessor to ALPN + * and deprecated in favor of it. */ + +/* SSL_CTX_set_next_protos_advertised_cb sets a callback that is called when a + * TLS server needs a list of supported protocols for Next Protocol + * Negotiation. The returned list must be in wire format. The list is returned + * by setting |*out| to point to it and |*out_len| to its length. This memory + * will not be modified, but one should assume that |ssl| keeps a reference to + * it. + * + * The callback should return |SSL_TLSEXT_ERR_OK| if it wishes to advertise. + * Otherwise, no such extension will be included in the ServerHello. */ +OPENSSL_EXPORT void SSL_CTX_set_next_protos_advertised_cb( + SSL_CTX *ctx, + int (*cb)(SSL *ssl, const uint8_t **out, unsigned *out_len, void *arg), + void *arg); + +/* SSL_CTX_set_next_proto_select_cb sets a callback that is called when a client + * needs to select a protocol from the server's provided list. |*out| must be + * set to point to the selected protocol (which may be within |in|). The length + * of the protocol name must be written into |*out_len|. The server's advertised + * protocols are provided in |in| and |in_len|. The callback can assume that + * |in| is syntactically valid. + * + * The client must select a protocol. It is fatal to the connection if this + * callback returns a value other than |SSL_TLSEXT_ERR_OK|. + * + * Configuring this callback enables NPN on a client. */ +OPENSSL_EXPORT void SSL_CTX_set_next_proto_select_cb( + SSL_CTX *ctx, int (*cb)(SSL *ssl, uint8_t **out, uint8_t *out_len, + const uint8_t *in, unsigned in_len, void *arg), + void *arg); + +/* SSL_get0_next_proto_negotiated sets |*out_data| and |*out_len| to point to + * the client's requested protocol for this connection. If the client didn't + * request any protocol, then |*out_data| is set to NULL. + * + * Note that the client can request any protocol it chooses. The value returned + * from this function need not be a member of the list of supported protocols + * provided by the server. */ +OPENSSL_EXPORT void SSL_get0_next_proto_negotiated(const SSL *ssl, + const uint8_t **out_data, + unsigned *out_len); + +/* SSL_select_next_proto implements the standard protocol selection. It is + * expected that this function is called from the callback set by + * |SSL_CTX_set_next_proto_select_cb|. + * + * The protocol data is assumed to be a vector of 8-bit, length prefixed byte + * strings. The length byte itself is not included in the length. A byte + * string of length 0 is invalid. No byte string may be truncated. + * + * The current, but experimental algorithm for selecting the protocol is: + * + * 1) If the server doesn't support NPN then this is indicated to the + * callback. In this case, the client application has to abort the connection + * or have a default application level protocol. + * + * 2) If the server supports NPN, but advertises an empty list then the + * client selects the first protcol in its list, but indicates via the + * API that this fallback case was enacted. + * + * 3) Otherwise, the client finds the first protocol in the server's list + * that it supports and selects this protocol. This is because it's + * assumed that the server has better information about which protocol + * a client should use. + * + * 4) If the client doesn't support any of the server's advertised + * protocols, then this is treated the same as case 2. + * + * It returns either |OPENSSL_NPN_NEGOTIATED| if a common protocol was found, or + * |OPENSSL_NPN_NO_OVERLAP| if the fallback case was reached. */ +OPENSSL_EXPORT int SSL_select_next_proto(uint8_t **out, uint8_t *out_len, + const uint8_t *server, + unsigned server_len, + const uint8_t *client, + unsigned client_len); + +#define OPENSSL_NPN_UNSUPPORTED 0 +#define OPENSSL_NPN_NEGOTIATED 1 +#define OPENSSL_NPN_NO_OVERLAP 2 + + +/* Channel ID. + * + * See draft-balfanz-tls-channelid-01. */ + +/* SSL_CTX_enable_tls_channel_id either configures a TLS server to accept TLS + * Channel IDs from clients, or configures a client to send TLS Channel IDs to + * a server. It returns one. */ +OPENSSL_EXPORT int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx); + +/* SSL_enable_tls_channel_id either configures a TLS server to accept TLS + * Channel IDs from clients, or configures a client to send TLS Channel IDs to + * server. It returns one. */ +OPENSSL_EXPORT int SSL_enable_tls_channel_id(SSL *ssl); + +/* SSL_CTX_set1_tls_channel_id configures a TLS client to send a TLS Channel ID + * to compatible servers. |private_key| must be a P-256 EC key. It returns one + * on success and zero on error. */ +OPENSSL_EXPORT int SSL_CTX_set1_tls_channel_id(SSL_CTX *ctx, + EVP_PKEY *private_key); + +/* SSL_set1_tls_channel_id configures a TLS client to send a TLS Channel ID to + * compatible servers. |private_key| must be a P-256 EC key. It returns one on + * success and zero on error. */ +OPENSSL_EXPORT int SSL_set1_tls_channel_id(SSL *ssl, EVP_PKEY *private_key); + +/* SSL_get_tls_channel_id gets the client's TLS Channel ID from a server |SSL*| + * and copies up to the first |max_out| bytes into |out|. The Channel ID + * consists of the client's P-256 public key as an (x,y) pair where each is a + * 32-byte, big-endian field element. It returns 0 if the client didn't offer a + * Channel ID and the length of the complete Channel ID otherwise. */ +OPENSSL_EXPORT size_t SSL_get_tls_channel_id(SSL *ssl, uint8_t *out, + size_t max_out); + +/* SSL_CTX_set_channel_id_cb sets a callback to be called when a TLS Channel ID + * is requested. The callback may set |*out_pkey| to a key, passing a reference + * to the caller. If none is returned, the handshake will pause and + * |SSL_get_error| will return |SSL_ERROR_WANT_CHANNEL_ID_LOOKUP|. + * + * See also |SSL_ERROR_WANT_CHANNEL_ID_LOOKUP|. */ +OPENSSL_EXPORT void SSL_CTX_set_channel_id_cb( + SSL_CTX *ctx, void (*channel_id_cb)(SSL *ssl, EVP_PKEY **out_pkey)); + +/* SSL_CTX_get_channel_id_cb returns the callback set by + * |SSL_CTX_set_channel_id_cb|. */ +OPENSSL_EXPORT void (*SSL_CTX_get_channel_id_cb(SSL_CTX *ctx))( + SSL *ssl, EVP_PKEY **out_pkey); + + +/* DTLS-SRTP. + * + * See RFC 5764. */ + +/* An SRTP_PROTECTION_PROFILE is an SRTP profile for use with the use_srtp + * extension. */ +struct srtp_protection_profile_st { + const char *name; + unsigned long id; +} /* SRTP_PROTECTION_PROFILE */; + +DECLARE_STACK_OF(SRTP_PROTECTION_PROFILE) + +/* SRTP_* define constants for SRTP profiles. */ +#define SRTP_AES128_CM_SHA1_80 0x0001 +#define SRTP_AES128_CM_SHA1_32 0x0002 +#define SRTP_AES128_F8_SHA1_80 0x0003 +#define SRTP_AES128_F8_SHA1_32 0x0004 +#define SRTP_NULL_SHA1_80 0x0005 +#define SRTP_NULL_SHA1_32 0x0006 +#define SRTP_AEAD_AES_128_GCM 0x0007 +#define SRTP_AEAD_AES_256_GCM 0x0008 + +/* SSL_CTX_set_srtp_profiles enables SRTP for all SSL objects created from + * |ctx|. |profile| contains a colon-separated list of profile names. It returns + * one on success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_set_srtp_profiles(SSL_CTX *ctx, + const char *profiles); + +/* SSL_set_srtp_profiles enables SRTP for |ssl|. |profile| contains a + * colon-separated list of profile names. It returns one on success and zero on + * failure. */ +OPENSSL_EXPORT int SSL_set_srtp_profiles(SSL *ssl, const char *profiles); + +/* SSL_get_srtp_profiles returns the SRTP profiles supported by |ssl|. */ +OPENSSL_EXPORT STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles( + SSL *ssl); + +/* SSL_get_selected_srtp_profile returns the selected SRTP profile, or NULL if + * SRTP was not negotiated. */ +OPENSSL_EXPORT const SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile( + SSL *ssl); + + +/* Pre-shared keys. + * + * Connections may be configured with PSK (Pre-Shared Key) cipher suites. These + * authenticate using out-of-band pre-shared keys rather than certificates. See + * RFC 4279. + * + * This implementation uses NUL-terminated C strings for identities and identity + * hints, so values with a NUL character are not supported. (RFC 4279 does not + * specify the format of an identity.) */ + +/* PSK_MAX_IDENTITY_LEN is the maximum supported length of a PSK identity, + * excluding the NUL terminator. */ +#define PSK_MAX_IDENTITY_LEN 128 + +/* PSK_MAX_PSK_LEN is the maximum supported length of a pre-shared key. */ +#define PSK_MAX_PSK_LEN 256 + +/* SSL_CTX_set_psk_client_callback sets the callback to be called when PSK is + * negotiated on the client. This callback must be set to enable PSK cipher + * suites on the client. + * + * The callback is passed the identity hint in |hint| or NULL if none was + * provided. It should select a PSK identity and write the identity and the + * corresponding PSK to |identity| and |psk|, respectively. The identity is + * written as a NUL-terminated C string of length (excluding the NUL terminator) + * at most |max_identity_len|. The PSK's length must be at most |max_psk_len|. + * The callback returns the length of the PSK or 0 if no suitable identity was + * found. */ +OPENSSL_EXPORT void SSL_CTX_set_psk_client_callback( + SSL_CTX *ctx, + unsigned (*psk_client_callback)( + SSL *ssl, const char *hint, char *identity, + unsigned max_identity_len, uint8_t *psk, unsigned max_psk_len)); + +/* SSL_set_psk_client_callback sets the callback to be called when PSK is + * negotiated on the client. This callback must be set to enable PSK cipher + * suites on the client. See also |SSL_CTX_set_psk_client_callback|. */ +OPENSSL_EXPORT void SSL_set_psk_client_callback( + SSL *ssl, unsigned (*psk_client_callback)(SSL *ssl, const char *hint, + char *identity, + unsigned max_identity_len, + uint8_t *psk, + unsigned max_psk_len)); + +/* SSL_CTX_set_psk_server_callback sets the callback to be called when PSK is + * negotiated on the server. This callback must be set to enable PSK cipher + * suites on the server. + * + * The callback is passed the identity in |identity|. It should write a PSK of + * length at most |max_psk_len| to |psk| and return the number of bytes written + * or zero if the PSK identity is unknown. */ +OPENSSL_EXPORT void SSL_CTX_set_psk_server_callback( + SSL_CTX *ctx, + unsigned (*psk_server_callback)(SSL *ssl, const char *identity, + uint8_t *psk, + unsigned max_psk_len)); + +/* SSL_set_psk_server_callback sets the callback to be called when PSK is + * negotiated on the server. This callback must be set to enable PSK cipher + * suites on the server. See also |SSL_CTX_set_psk_server_callback|. */ +OPENSSL_EXPORT void SSL_set_psk_server_callback( + SSL *ssl, + unsigned (*psk_server_callback)(SSL *ssl, const char *identity, + uint8_t *psk, + unsigned max_psk_len)); + +/* SSL_CTX_use_psk_identity_hint configures server connections to advertise an + * identity hint of |identity_hint|. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, + const char *identity_hint); + +/* SSL_use_psk_identity_hint configures server connections to advertise an + * identity hint of |identity_hint|. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int SSL_use_psk_identity_hint(SSL *ssl, + const char *identity_hint); + +/* SSL_get_psk_identity_hint returns the PSK identity hint advertised for |ssl| + * or NULL if there is none. */ +OPENSSL_EXPORT const char *SSL_get_psk_identity_hint(const SSL *ssl); + +/* SSL_get_psk_identity, after the handshake completes, returns the PSK identity + * that was negotiated by |ssl| or NULL if PSK was not used. */ +OPENSSL_EXPORT const char *SSL_get_psk_identity(const SSL *ssl); + + +/* Alerts. + * + * TLS and SSL 3.0 use alerts to signal error conditions. Alerts have a type + * (warning or fatal) and description. OpenSSL internally handles fatal alerts + * with dedicated error codes (see |SSL_AD_REASON_OFFSET|). Except for + * close_notify, warning alerts are silently ignored and may only be surfaced + * with |SSL_CTX_set_info_callback|. */ + +/* SSL_AD_REASON_OFFSET is the offset between error reasons and |SSL_AD_*| + * values. Any error code under |ERR_LIB_SSL| with an error reason above this + * value corresponds to an alert description. Consumers may add or subtract + * |SSL_AD_REASON_OFFSET| to convert between them. + * + * make_errors.go reserves error codes above 1000 for manually-assigned errors. + * This value must be kept in sync with reservedReasonCode in make_errors.h */ +#define SSL_AD_REASON_OFFSET 1000 + +/* SSL_AD_* are alert descriptions for SSL 3.0 and TLS. */ +#define SSL_AD_CLOSE_NOTIFY SSL3_AD_CLOSE_NOTIFY +#define SSL_AD_UNEXPECTED_MESSAGE SSL3_AD_UNEXPECTED_MESSAGE +#define SSL_AD_BAD_RECORD_MAC SSL3_AD_BAD_RECORD_MAC +#define SSL_AD_DECRYPTION_FAILED TLS1_AD_DECRYPTION_FAILED +#define SSL_AD_RECORD_OVERFLOW TLS1_AD_RECORD_OVERFLOW +#define SSL_AD_DECOMPRESSION_FAILURE SSL3_AD_DECOMPRESSION_FAILURE +#define SSL_AD_HANDSHAKE_FAILURE SSL3_AD_HANDSHAKE_FAILURE +#define SSL_AD_NO_CERTIFICATE SSL3_AD_NO_CERTIFICATE /* Not used in TLS */ +#define SSL_AD_BAD_CERTIFICATE SSL3_AD_BAD_CERTIFICATE +#define SSL_AD_UNSUPPORTED_CERTIFICATE SSL3_AD_UNSUPPORTED_CERTIFICATE +#define SSL_AD_CERTIFICATE_REVOKED SSL3_AD_CERTIFICATE_REVOKED +#define SSL_AD_CERTIFICATE_EXPIRED SSL3_AD_CERTIFICATE_EXPIRED +#define SSL_AD_CERTIFICATE_UNKNOWN SSL3_AD_CERTIFICATE_UNKNOWN +#define SSL_AD_ILLEGAL_PARAMETER SSL3_AD_ILLEGAL_PARAMETER +#define SSL_AD_UNKNOWN_CA TLS1_AD_UNKNOWN_CA +#define SSL_AD_ACCESS_DENIED TLS1_AD_ACCESS_DENIED +#define SSL_AD_DECODE_ERROR TLS1_AD_DECODE_ERROR +#define SSL_AD_DECRYPT_ERROR TLS1_AD_DECRYPT_ERROR +#define SSL_AD_EXPORT_RESTRICTION TLS1_AD_EXPORT_RESTRICTION +#define SSL_AD_PROTOCOL_VERSION TLS1_AD_PROTOCOL_VERSION +#define SSL_AD_INSUFFICIENT_SECURITY TLS1_AD_INSUFFICIENT_SECURITY +#define SSL_AD_INTERNAL_ERROR TLS1_AD_INTERNAL_ERROR +#define SSL_AD_USER_CANCELLED TLS1_AD_USER_CANCELLED +#define SSL_AD_NO_RENEGOTIATION TLS1_AD_NO_RENEGOTIATION +#define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION +#define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE +#define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME +#define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE \ + TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE +#define SSL_AD_BAD_CERTIFICATE_HASH_VALUE TLS1_AD_BAD_CERTIFICATE_HASH_VALUE +#define SSL_AD_UNKNOWN_PSK_IDENTITY TLS1_AD_UNKNOWN_PSK_IDENTITY +#define SSL_AD_INAPPROPRIATE_FALLBACK SSL3_AD_INAPPROPRIATE_FALLBACK + +/* SSL_alert_type_string_long returns a string description of |value| as an + * alert type (warning or fatal). */ +OPENSSL_EXPORT const char *SSL_alert_type_string_long(int value); + +/* SSL_alert_desc_string_long returns a string description of |value| as an + * alert description or "unknown" if unknown. */ +OPENSSL_EXPORT const char *SSL_alert_desc_string_long(int value); + + +/* ex_data functions. + * + * See |ex_data.h| for details. */ + +OPENSSL_EXPORT int SSL_set_ex_data(SSL *ssl, int idx, void *data); +OPENSSL_EXPORT void *SSL_get_ex_data(const SSL *ssl, int idx); +OPENSSL_EXPORT int SSL_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_unused *unused, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); + +OPENSSL_EXPORT int SSL_SESSION_set_ex_data(SSL_SESSION *session, int idx, + void *data); +OPENSSL_EXPORT void *SSL_SESSION_get_ex_data(const SSL_SESSION *session, + int idx); +OPENSSL_EXPORT int SSL_SESSION_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_unused *unused, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); + +OPENSSL_EXPORT int SSL_CTX_set_ex_data(SSL_CTX *ctx, int idx, void *data); +OPENSSL_EXPORT void *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx); +OPENSSL_EXPORT int SSL_CTX_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_unused *unused, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); + + +/* Obscure functions. */ + +/* SSL_get_rc4_state sets |*read_key| and |*write_key| to the RC4 states for + * the read and write directions. It returns one on success or zero if |ssl| + * isn't using an RC4-based cipher suite. */ +OPENSSL_EXPORT int SSL_get_rc4_state(const SSL *ssl, const RC4_KEY **read_key, + const RC4_KEY **write_key); + +/* SSL_get_ivs sets |*out_iv_len| to the length of the IVs for the ciphers + * underlying |ssl| and sets |*out_read_iv| and |*out_write_iv| to point to the + * current IVs for the read and write directions. This is only meaningful for + * connections with implicit IVs (i.e. CBC mode with SSLv3 or TLS 1.0). + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int SSL_get_ivs(const SSL *ssl, const uint8_t **out_read_iv, + const uint8_t **out_write_iv, + size_t *out_iv_len); + +/* SSL_get_structure_sizes returns the sizes of the SSL, SSL_CTX and + * SSL_SESSION structures so that a test can ensure that outside code agrees on + * these values. */ +OPENSSL_EXPORT void SSL_get_structure_sizes(size_t *ssl_size, + size_t *ssl_ctx_size, + size_t *ssl_session_size); + +/* SSL_CTX_set_msg_callback installs |cb| as the message callback for |ctx|. + * This callback will be called when sending or receiving low-level record + * headers, complete handshake messages, ChangeCipherSpec, and alerts. + * |write_p| is one for outgoing messages and zero for incoming messages. + * + * For each record header, |cb| is called with |version| = 0 and |content_type| + * = |SSL3_RT_HEADER|. The |len| bytes from |buf| contain the header. Note that + * this does not include the record body. If the record is sealed, the length + * in the header is the length of the ciphertext. + * + * For each handshake message, ChangeCipherSpec, and alert, |version| is the + * protocol version and |content_type| is the corresponding record type. The + * |len| bytes from |buf| contain the handshake message, one-byte + * ChangeCipherSpec body, and two-byte alert, respectively. */ +OPENSSL_EXPORT void SSL_CTX_set_msg_callback( + SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg)); + +/* SSL_CTX_set_msg_callback_arg sets the |arg| parameter of the message + * callback. */ +OPENSSL_EXPORT void SSL_CTX_set_msg_callback_arg(SSL_CTX *ctx, void *arg); + +/* SSL_set_msg_callback installs |cb| as the message callback of |ssl|. See + * |SSL_CTX_set_msg_callback| for when this callback is called. */ +OPENSSL_EXPORT void SSL_set_msg_callback( + SSL *ssl, void (*cb)(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg)); + +/* SSL_set_msg_callback_arg sets the |arg| parameter of the message callback. */ +OPENSSL_EXPORT void SSL_set_msg_callback_arg(SSL *ssl, void *arg); + +/* SSL_CTX_set_keylog_callback configures a callback to log key material. This + * is intended for debugging use with tools like Wireshark. The |cb| function + * should log |line| followed by a newline, synchronizing with any concurrent + * access to the log. + * + * The format is described in + * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format. */ +OPENSSL_EXPORT void SSL_CTX_set_keylog_callback( + SSL_CTX *ctx, void (*cb)(const SSL *ssl, const char *line)); + +enum ssl_renegotiate_mode_t { + ssl_renegotiate_never = 0, + ssl_renegotiate_once, + ssl_renegotiate_freely, + ssl_renegotiate_ignore, +}; + +/* SSL_set_renegotiate_mode configures how |ssl|, a client, reacts to + * renegotiation attempts by a server. If |ssl| is a server, peer-initiated + * renegotiations are *always* rejected and this function does nothing. + * + * The renegotiation mode defaults to |ssl_renegotiate_never|, but may be set + * at any point in a connection's lifetime. Set it to |ssl_renegotiate_once| to + * allow one renegotiation, |ssl_renegotiate_freely| to allow all + * renegotiations or |ssl_renegotiate_ignore| to ignore HelloRequest messages. + * Note that ignoring HelloRequest messages may cause the connection to stall + * if the server waits for the renegotiation to complete. + * + * There is no support in BoringSSL for initiating renegotiations as a client + * or server. */ +OPENSSL_EXPORT void SSL_set_renegotiate_mode(SSL *ssl, + enum ssl_renegotiate_mode_t mode); + +/* SSL_renegotiate_pending returns one if |ssl| is in the middle of a + * renegotiation. */ +OPENSSL_EXPORT int SSL_renegotiate_pending(SSL *ssl); + +/* SSL_total_renegotiations returns the total number of renegotiation handshakes + * peformed by |ssl|. This includes the pending renegotiation, if any. */ +OPENSSL_EXPORT int SSL_total_renegotiations(const SSL *ssl); + +/* SSL_MAX_CERT_LIST_DEFAULT is the default maximum length, in bytes, of a peer + * certificate chain. */ +#define SSL_MAX_CERT_LIST_DEFAULT 1024 * 100 + +/* SSL_CTX_get_max_cert_list returns the maximum length, in bytes, of a peer + * certificate chain accepted by |ctx|. */ +OPENSSL_EXPORT size_t SSL_CTX_get_max_cert_list(const SSL_CTX *ctx); + +/* SSL_CTX_set_max_cert_list sets the maximum length, in bytes, of a peer + * certificate chain to |max_cert_list|. This affects how much memory may be + * consumed during the handshake. */ +OPENSSL_EXPORT void SSL_CTX_set_max_cert_list(SSL_CTX *ctx, + size_t max_cert_list); + +/* SSL_get_max_cert_list returns the maximum length, in bytes, of a peer + * certificate chain accepted by |ssl|. */ +OPENSSL_EXPORT size_t SSL_get_max_cert_list(const SSL *ssl); + +/* SSL_set_max_cert_list sets the maximum length, in bytes, of a peer + * certificate chain to |max_cert_list|. This affects how much memory may be + * consumed during the handshake. */ +OPENSSL_EXPORT void SSL_set_max_cert_list(SSL *ssl, size_t max_cert_list); + +/* SSL_CTX_set_max_send_fragment sets the maximum length, in bytes, of records + * sent by |ctx|. Beyond this length, handshake messages and application data + * will be split into multiple records. */ +OPENSSL_EXPORT void SSL_CTX_set_max_send_fragment(SSL_CTX *ctx, + size_t max_send_fragment); + +/* SSL_set_max_send_fragment sets the maximum length, in bytes, of records + * sent by |ssl|. Beyond this length, handshake messages and application data + * will be split into multiple records. */ +OPENSSL_EXPORT void SSL_set_max_send_fragment(SSL *ssl, + size_t max_send_fragment); + +/* ssl_early_callback_ctx is passed to certain callbacks that are called very + * early on during the server handshake. At this point, much of the SSL* hasn't + * been filled out and only the ClientHello can be depended on. */ +struct ssl_early_callback_ctx { + SSL *ssl; + const uint8_t *client_hello; + size_t client_hello_len; + const uint8_t *session_id; + size_t session_id_len; + const uint8_t *cipher_suites; + size_t cipher_suites_len; + const uint8_t *compression_methods; + size_t compression_methods_len; + const uint8_t *extensions; + size_t extensions_len; +}; + +/* SSL_early_callback_ctx_extension_get searches the extensions in |ctx| for an + * extension of the given type. If not found, it returns zero. Otherwise it + * sets |out_data| to point to the extension contents (not including the type + * and length bytes), sets |out_len| to the length of the extension contents + * and returns one. */ +OPENSSL_EXPORT int SSL_early_callback_ctx_extension_get( + const struct ssl_early_callback_ctx *ctx, uint16_t extension_type, + const uint8_t **out_data, size_t *out_len); + +/* SSL_CTX_set_select_certificate_cb sets a callback that is called before most + * ClientHello processing and before the decision whether to resume a session + * is made. The callback may inspect the ClientHello and configure the + * connection. It may then return one to continue the handshake or zero to + * pause the handshake to perform an asynchronous operation. If paused, + * |SSL_get_error| will return |SSL_ERROR_PENDING_CERTIFICATE|. + * + * Note: The |ssl_early_callback_ctx| is only valid for the duration of the + * callback and is not valid while the handshake is paused. Further, unlike with + * most callbacks, when the handshake loop is resumed, it will not call the + * callback a second time. The caller must finish reconfiguring the connection + * before resuming the handshake. */ +OPENSSL_EXPORT void SSL_CTX_set_select_certificate_cb( + SSL_CTX *ctx, int (*cb)(const struct ssl_early_callback_ctx *)); + +/* SSL_CTX_set_dos_protection_cb sets a callback that is called once the + * resumption decision for a ClientHello has been made. It can return one to + * allow the handshake to continue or zero to cause the handshake to abort. */ +OPENSSL_EXPORT void SSL_CTX_set_dos_protection_cb( + SSL_CTX *ctx, int (*cb)(const struct ssl_early_callback_ctx *)); + +/* SSL_ST_* are possible values for |SSL_state| and the bitmasks that make them + * up. */ +#define SSL_ST_CONNECT 0x1000 +#define SSL_ST_ACCEPT 0x2000 +#define SSL_ST_MASK 0x0FFF +#define SSL_ST_INIT (SSL_ST_CONNECT | SSL_ST_ACCEPT) +#define SSL_ST_OK 0x03 +#define SSL_ST_RENEGOTIATE (0x04 | SSL_ST_INIT) + +/* SSL_CB_* are possible values for the |type| parameter in the info + * callback and the bitmasks that make them up. */ +#define SSL_CB_LOOP 0x01 +#define SSL_CB_EXIT 0x02 +#define SSL_CB_READ 0x04 +#define SSL_CB_WRITE 0x08 +#define SSL_CB_ALERT 0x4000 +#define SSL_CB_READ_ALERT (SSL_CB_ALERT | SSL_CB_READ) +#define SSL_CB_WRITE_ALERT (SSL_CB_ALERT | SSL_CB_WRITE) +#define SSL_CB_ACCEPT_LOOP (SSL_ST_ACCEPT | SSL_CB_LOOP) +#define SSL_CB_ACCEPT_EXIT (SSL_ST_ACCEPT | SSL_CB_EXIT) +#define SSL_CB_CONNECT_LOOP (SSL_ST_CONNECT | SSL_CB_LOOP) +#define SSL_CB_CONNECT_EXIT (SSL_ST_CONNECT | SSL_CB_EXIT) +#define SSL_CB_HANDSHAKE_START 0x10 +#define SSL_CB_HANDSHAKE_DONE 0x20 + +/* SSL_CTX_set_info_callback configures a callback to be run when various + * events occur during a connection's lifetime. The |type| argumentj determines + * the type of event and the meaning of the |value| argument. Callbacks must + * ignore unexpected |type| values. + * + * |SSL_CB_READ_ALERT| is signaled for each alert received, warning or fatal. + * The |value| argument is a 16-bit value where the alert level (either + * |SSL3_AL_WARNING| or |SSL3_AL_FATAL|) is in the most-significant eight bits and + * the alert type (one of |SSL_AD_*|) is in the least-significant eight. + * + * |SSL_CB_WRITE_ALERT| is signaled for each alert sent. The |value| argument + * is constructed as with |SSL_CB_READ_ALERT|. + * + * |SSL_CB_HANDSHAKE_START| is signaled when a handshake begins. The |value| + * argument is always one. + * + * |SSL_CB_HANDSHAKE_DONE| is signaled when a handshake completes successfully. + * The |value| argument is always one. If a handshake False Starts, this event + * may be used to determine when the Finished message is received. + * + * The following event types expose implementation details of the handshake + * state machine. Consuming them is deprecated. + * + * |SSL_CB_ACCEPT_LOOP| (respectively, |SSL_CB_CONNECT_LOOP|) is signaled when + * a server (respectively, client) handshake progresses. The |value| argument + * is always one. For the duration of the callback, |SSL_state| will return the + * previous state. + * + * |SSL_CB_ACCEPT_EXIT| (respectively, |SSL_CB_CONNECT_EXIT|) is signaled when + * a server (respectively, client) handshake completes, fails, or is paused. + * The |value| argument is one if the handshake succeeded and <= 0 + * otherwise. */ +OPENSSL_EXPORT void SSL_CTX_set_info_callback( + SSL_CTX *ctx, void (*cb)(const SSL *ssl, int type, int value)); + +/* SSL_CTX_get_info_callback returns the callback set by + * |SSL_CTX_set_info_callback|. */ +OPENSSL_EXPORT void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl, + int type, + int value); + +/* SSL_set_info_callback configures a callback to be run at various events + * during a connection's lifetime. See |SSL_CTX_set_info_callback|. */ +OPENSSL_EXPORT void SSL_set_info_callback( + SSL *ssl, void (*cb)(const SSL *ssl, int type, int value)); + +/* SSL_get_info_callback returns the callback set by |SSL_set_info_callback|. */ +OPENSSL_EXPORT void (*SSL_get_info_callback(const SSL *ssl))(const SSL *ssl, + int type, + int value); + +/* SSL_state_string_long returns the current state of the handshake state + * machine as a string. This may be useful for debugging and logging. */ +OPENSSL_EXPORT const char *SSL_state_string_long(const SSL *ssl); + +/* SSL_set_SSL_CTX partially changes |ssl|'s |SSL_CTX|. |ssl| will use the + * certificate and session_id_context from |ctx|, and |SSL_get_SSL_CTX| will + * report |ctx|. However most settings and the session cache itself will + * continue to use the initial |SSL_CTX|. It is often used as part of SNI. + * + * TODO(davidben): Make a better story here and get rid of this API. Also + * determine if there's anything else affected by |SSL_set_SSL_CTX| that + * matters. Not as many values are affected as one might initially think. The + * session cache explicitly selects the initial |SSL_CTX|. Most settings are + * copied at |SSL_new| so |ctx|'s versions don't apply. This, notably, has some + * consequences for any plans to make |SSL| copy-on-write most of its + * configuration. */ +OPENSSL_EXPORT SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx); + +#define SSL_SENT_SHUTDOWN 1 +#define SSL_RECEIVED_SHUTDOWN 2 + +/* SSL_get_shutdown returns a bitmask with a subset of |SSL_SENT_SHUTDOWN| and + * |SSL_RECEIVED_SHUTDOWN| to query whether close_notify was sent or received, + * respectively. */ +OPENSSL_EXPORT int SSL_get_shutdown(const SSL *ssl); + +/* SSL_get_server_key_exchange_hash, on a client, returns the hash the server + * used to sign the ServerKeyExchange in TLS 1.2. If not applicable, it returns + * |TLSEXT_hash_none|. */ +OPENSSL_EXPORT uint8_t SSL_get_server_key_exchange_hash(const SSL *ssl); + + +/* Deprecated functions. */ + +/* SSL_library_init calls |CRYPTO_library_init| and returns one. */ +OPENSSL_EXPORT int SSL_library_init(void); + +/* SSL_set_reject_peer_renegotiations calls |SSL_set_renegotiate_mode| with + * |ssl_never_renegotiate| if |reject| is one and |ssl_renegotiate_freely| if + * zero. */ +OPENSSL_EXPORT void SSL_set_reject_peer_renegotiations(SSL *ssl, int reject); + +/* SSL_CIPHER_description writes a description of |cipher| into |buf| and + * returns |buf|. If |buf| is NULL, it returns a newly allocated string, to be + * freed with |OPENSSL_free|, or NULL on error. + * + * The description includes a trailing newline and has the form: + * AES128-SHA Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1 + * + * Consider |SSL_CIPHER_get_name| or |SSL_CIPHER_get_rfc_name| instead. */ +OPENSSL_EXPORT const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, + char *buf, int len); + +/* SSL_CIPHER_get_version returns the string "TLSv1/SSLv3". */ +OPENSSL_EXPORT const char *SSL_CIPHER_get_version(const SSL_CIPHER *cipher); + +typedef void COMP_METHOD; + +/* SSL_COMP_get_compression_methods returns NULL. */ +OPENSSL_EXPORT COMP_METHOD *SSL_COMP_get_compression_methods(void); + +/* SSL_COMP_add_compression_method returns one. */ +OPENSSL_EXPORT int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm); + +/* SSL_COMP_get_name returns NULL. */ +OPENSSL_EXPORT const char *SSL_COMP_get_name(const COMP_METHOD *comp); + +/* SSLv23_method calls |TLS_method|. */ +OPENSSL_EXPORT const SSL_METHOD *SSLv23_method(void); + +/* These version-specific methods behave exactly like |TLS_method| and + * |DTLS_method| except they also call |SSL_CTX_set_min_version| and + * |SSL_CTX_set_max_version| to lock connections to that protocol version. */ +OPENSSL_EXPORT const SSL_METHOD *SSLv3_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_1_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_2_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_2_method(void); + +/* These client- and server-specific methods call their corresponding generic + * methods. */ +OPENSSL_EXPORT const SSL_METHOD *SSLv23_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *SSLv23_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *SSLv3_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *SSLv3_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_1_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_1_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_2_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_2_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLS_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLS_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_2_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_2_client_method(void); + +/* SSL_clear resets |ssl| to allow another connection and returns one on success + * or zero on failure. It returns most configuration state but releases memory + * associated with the current connection. + * + * Free |ssl| and create a new one instead. */ +OPENSSL_EXPORT int SSL_clear(SSL *ssl); + +/* SSL_CTX_set_tmp_rsa_callback does nothing. */ +OPENSSL_EXPORT void SSL_CTX_set_tmp_rsa_callback( + SSL_CTX *ctx, RSA *(*cb)(SSL *ssl, int is_export, int keylength)); + +/* SSL_set_tmp_rsa_callback does nothing. */ +OPENSSL_EXPORT void SSL_set_tmp_rsa_callback(SSL *ssl, + RSA *(*cb)(SSL *ssl, int is_export, + int keylength)); + +/* SSL_CTX_sess_connect returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_connect(const SSL_CTX *ctx); + +/* SSL_CTX_sess_connect_good returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_connect_good(const SSL_CTX *ctx); + +/* SSL_CTX_sess_connect_renegotiate returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_connect_renegotiate(const SSL_CTX *ctx); + +/* SSL_CTX_sess_accept returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_accept(const SSL_CTX *ctx); + +/* SSL_CTX_sess_accept_renegotiate returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_accept_renegotiate(const SSL_CTX *ctx); + +/* SSL_CTX_sess_accept_good returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_accept_good(const SSL_CTX *ctx); + +/* SSL_CTX_sess_hits returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_hits(const SSL_CTX *ctx); + +/* SSL_CTX_sess_cb_hits returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_cb_hits(const SSL_CTX *ctx); + +/* SSL_CTX_sess_misses returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_misses(const SSL_CTX *ctx); + +/* SSL_CTX_sess_timeouts returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_timeouts(const SSL_CTX *ctx); + +/* SSL_CTX_sess_cache_full returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_cache_full(const SSL_CTX *ctx); + +/* SSL_cutthrough_complete calls |SSL_in_false_start|. */ +OPENSSL_EXPORT int SSL_cutthrough_complete(const SSL *s); + +/* SSL_num_renegotiations calls |SSL_total_renegotiations|. */ +OPENSSL_EXPORT int SSL_num_renegotiations(const SSL *ssl); + +/* SSL_CTX_need_tmp_RSA returns zero. */ +OPENSSL_EXPORT int SSL_CTX_need_tmp_RSA(const SSL_CTX *ctx); + +/* SSL_need_tmp_RSA returns zero. */ +OPENSSL_EXPORT int SSL_need_tmp_RSA(const SSL *ssl); + +/* SSL_CTX_set_tmp_rsa returns one. */ +OPENSSL_EXPORT int SSL_CTX_set_tmp_rsa(SSL_CTX *ctx, const RSA *rsa); + +/* SSL_set_tmp_rsa returns one. */ +OPENSSL_EXPORT int SSL_set_tmp_rsa(SSL *ssl, const RSA *rsa); + +/* SSL_CTX_get_read_ahead returns zero. */ +OPENSSL_EXPORT int SSL_CTX_get_read_ahead(const SSL_CTX *ctx); + +/* SSL_CTX_set_read_ahead does nothing. */ +OPENSSL_EXPORT void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes); + +/* SSL_get_read_ahead returns zero. */ +OPENSSL_EXPORT int SSL_get_read_ahead(const SSL *s); + +/* SSL_set_read_ahead does nothing. */ +OPENSSL_EXPORT void SSL_set_read_ahead(SSL *s, int yes); + +/* SSL_renegotiate put an error on the error queue and returns zero. */ +OPENSSL_EXPORT int SSL_renegotiate(SSL *ssl); + +/* SSL_set_state does nothing. */ +OPENSSL_EXPORT void SSL_set_state(SSL *ssl, int state); + +/* SSL_MODE_HANDSHAKE_CUTTHROUGH is the same as SSL_MODE_ENABLE_FALSE_START. */ +#define SSL_MODE_HANDSHAKE_CUTTHROUGH SSL_MODE_ENABLE_FALSE_START + +/* i2d_SSL_SESSION serializes |in| to the bytes pointed to by |*pp|. On success, + * it returns the number of bytes written and advances |*pp| by that many bytes. + * On failure, it returns -1. If |pp| is NULL, no bytes are written and only the + * length is returned. + * + * Use |SSL_SESSION_to_bytes| instead. */ +OPENSSL_EXPORT int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp); + +/* d2i_SSL_SESSION parses a serialized session from the |length| bytes pointed + * to by |*pp|. It returns the new |SSL_SESSION| and advances |*pp| by the + * number of bytes consumed on success and NULL on failure. The caller takes + * ownership of the new session and must call |SSL_SESSION_free| when done. + * + * If |a| is non-NULL, |*a| is released and set the new |SSL_SESSION|. + * + * Use |SSL_SESSION_from_bytes| instead. */ +OPENSSL_EXPORT SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, + long length); + +/* i2d_SSL_SESSION_bio serializes |session| and writes the result to |bio|. It + * returns the number of bytes written on success and <= 0 on error. */ +OPENSSL_EXPORT int i2d_SSL_SESSION_bio(BIO *bio, const SSL_SESSION *session); + +/* d2i_SSL_SESSION_bio reads a serialized |SSL_SESSION| from |bio| and returns a + * newly-allocated |SSL_SESSION| or NULL on error. If |out| is not NULL, it also + * frees |*out| and sets |*out| to the new |SSL_SESSION|. */ +OPENSSL_EXPORT SSL_SESSION *d2i_SSL_SESSION_bio(BIO *bio, SSL_SESSION **out); + +/* ERR_load_SSL_strings does nothing. */ +OPENSSL_EXPORT void ERR_load_SSL_strings(void); + +/* SSL_load_error_strings does nothing. */ +OPENSSL_EXPORT void SSL_load_error_strings(void); + +/* SSL_CTX_set_tlsext_use_srtp calls |SSL_CTX_set_srtp_profiles|. It returns + * zero on success and one on failure. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use |SSL_CTX_set_srtp_profiles| instead. */ +OPENSSL_EXPORT int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, + const char *profiles); + +/* SSL_set_tlsext_use_srtp calls |SSL_set_srtp_profiles|. It returns zero on + * success and one on failure. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use |SSL_set_srtp_profiles| instead. */ +OPENSSL_EXPORT int SSL_set_tlsext_use_srtp(SSL *ssl, const char *profiles); + +/* SSL_get_current_compression returns NULL. */ +OPENSSL_EXPORT const COMP_METHOD *SSL_get_current_compression(SSL *s); + +/* SSL_get_current_expansion returns NULL. */ +OPENSSL_EXPORT const COMP_METHOD *SSL_get_current_expansion(SSL *s); + +#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg)) +#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0)) +#define SSL_SESSION_set_app_data(s, a) \ + (SSL_SESSION_set_ex_data(s, 0, (char *)a)) +#define SSL_SESSION_get_app_data(s) (SSL_SESSION_get_ex_data(s, 0)) +#define SSL_CTX_get_app_data(ctx) (SSL_CTX_get_ex_data(ctx, 0)) +#define SSL_CTX_set_app_data(ctx, arg) \ + (SSL_CTX_set_ex_data(ctx, 0, (char *)arg)) + +#define OpenSSL_add_ssl_algorithms() SSL_library_init() +#define SSLeay_add_ssl_algorithms() SSL_library_init() + +#define SSL_get_cipher(ssl) SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)) +#define SSL_get_cipher_bits(ssl, out_alg_bits) \ + SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), out_alg_bits) +#define SSL_get_cipher_version(ssl) \ + SSL_CIPHER_get_version(SSL_get_current_cipher(ssl)) +#define SSL_get_cipher_name(ssl) \ + SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)) +#define SSL_get_time(session) SSL_SESSION_get_time(session) +#define SSL_set_time(session, time) SSL_SESSION_set_time((session), (time)) +#define SSL_get_timeout(session) SSL_SESSION_get_timeout(session) +#define SSL_set_timeout(session, timeout) \ + SSL_SESSION_set_timeout((session), (timeout)) + +typedef struct ssl_comp_st SSL_COMP; + +struct ssl_comp_st { + int id; + const char *name; + char *method; +}; + +DECLARE_STACK_OF(SSL_COMP) + +/* The following flags toggle individual protocol versions. This is deprecated. + * Use |SSL_CTX_set_min_version| and |SSL_CTX_set_max_version| instead. */ +#define SSL_OP_NO_SSLv3 0x02000000L +#define SSL_OP_NO_TLSv1 0x04000000L +#define SSL_OP_NO_TLSv1_2 0x08000000L +#define SSL_OP_NO_TLSv1_1 0x10000000L +#define SSL_OP_NO_DTLSv1 SSL_OP_NO_TLSv1 +#define SSL_OP_NO_DTLSv1_2 SSL_OP_NO_TLSv1_2 + +/* The following flags do nothing and are included only to make it easier to + * compile code with BoringSSL. */ +#define SSL_MODE_AUTO_RETRY 0 +#define SSL_MODE_RELEASE_BUFFERS 0 +#define SSL_MODE_SEND_CLIENTHELLO_TIME 0 +#define SSL_MODE_SEND_SERVERHELLO_TIME 0 +#define SSL_OP_ALL 0 +#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0 +#define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0 +#define SSL_OP_EPHEMERAL_RSA 0 +#define SSL_OP_LEGACY_SERVER_CONNECT 0 +#define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 0 +#define SSL_OP_MICROSOFT_SESS_ID_BUG 0 +#define SSL_OP_MSIE_SSLV2_RSA_PADDING 0 +#define SSL_OP_NETSCAPE_CA_DN_BUG 0 +#define SSL_OP_NETSCAPE_CHALLENGE_BUG 0 +#define SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG 0 +#define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0 +#define SSL_OP_NO_COMPRESSION 0 +#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0 +#define SSL_OP_NO_SSLv2 0 +#define SSL_OP_PKCS1_CHECK_1 0 +#define SSL_OP_PKCS1_CHECK_2 0 +#define SSL_OP_SINGLE_DH_USE 0 +#define SSL_OP_SINGLE_ECDH_USE 0 +#define SSL_OP_SSLEAY_080_CLIENT_DH_BUG 0 +#define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0 +#define SSL_OP_TLS_BLOCK_PADDING_BUG 0 +#define SSL_OP_TLS_D5_BUG 0 +#define SSL_OP_TLS_ROLLBACK_BUG 0 +#define SSL_VERIFY_CLIENT_ONCE 0 + +/* SSL_cache_hit calls |SSL_session_resumed|. */ +OPENSSL_EXPORT int SSL_cache_hit(SSL *ssl); + +/* SSL_get_default_timeout returns |SSL_DEFAULT_SESSION_TIMEOUT|. */ +OPENSSL_EXPORT long SSL_get_default_timeout(const SSL *ssl); + +/* SSL_get_version returns a string describing the TLS version used by |ssl|. + * For example, "TLSv1.2" or "SSLv3". */ +OPENSSL_EXPORT const char *SSL_get_version(const SSL *ssl); + +/* SSL_get_cipher_list returns the name of the |n|th cipher in the output of + * |SSL_get_ciphers| or NULL if out of range. Use |SSL_get_ciphers| insteads. */ +OPENSSL_EXPORT const char *SSL_get_cipher_list(const SSL *ssl, int n); + +/* SSL_CTX_set_client_cert_cb sets a callback which is called on the client if + * the server requests a client certificate and none is configured. On success, + * the callback should return one and set |*out_x509| to |*out_pkey| to a leaf + * certificate and private key, respectively, passing ownership. It should + * return zero to send no certificate and -1 to fail or pause the handshake. If + * the handshake is paused, |SSL_get_error| will return + * |SSL_ERROR_WANT_X509_LOOKUP|. + * + * The callback may call |SSL_get0_certificate_types| and + * |SSL_get_client_CA_list| for information on the server's certificate request. + * + * Use |SSL_CTX_set_cert_cb| instead. Configuring intermediate certificates with + * this function is confusing. */ +OPENSSL_EXPORT void SSL_CTX_set_client_cert_cb( + SSL_CTX *ctx, + int (*client_cert_cb)(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey)); + +/* SSL_CTX_get_client_cert_cb returns the callback set by + * |SSL_CTX_set_client_cert_cb|. */ +OPENSSL_EXPORT int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))( + SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey); + +#define SSL_NOTHING 1 +#define SSL_WRITING 2 +#define SSL_READING 3 +#define SSL_X509_LOOKUP 4 +#define SSL_CHANNEL_ID_LOOKUP 5 +#define SSL_PENDING_SESSION 7 +#define SSL_CERTIFICATE_SELECTION_PENDING 8 +#define SSL_PRIVATE_KEY_OPERATION 9 + +/* SSL_want returns one of the above values to determine what the most recent + * operation on |ssl| was blocked on. Use |SSL_get_error| instead. */ +OPENSSL_EXPORT int SSL_want(const SSL *ssl); + +#define SSL_want_nothing(ssl) (SSL_want(ssl) == SSL_NOTHING) +#define SSL_want_read(ssl) (SSL_want(ssl) == SSL_READING) +#define SSL_want_write(ssl) (SSL_want(ssl) == SSL_WRITING) +#define SSL_want_x509_lookup(ssl) (SSL_want(ssl) == SSL_X509_LOOKUP) +#define SSL_want_channel_id_lookup(ssl) (SSL_want(ssl) == SSL_CHANNEL_ID_LOOKUP) +#define SSL_want_session(ssl) (SSL_want(ssl) == SSL_PENDING_SESSION) +#define SSL_want_certificate(ssl) \ + (SSL_want(ssl) == SSL_CERTIFICATE_SELECTION_PENDING) +#define SSL_want_private_key_operation(ssl) \ + (SSL_want(ssl) == SSL_PRIVATE_KEY_OPERATION) + + /* SSL_get_finished writes up to |count| bytes of the Finished message sent by + * |ssl| to |buf|. It returns the total untruncated length or zero if none has + * been sent yet. + * + * Use |SSL_get_tls_unique| instead. */ +OPENSSL_EXPORT size_t SSL_get_finished(const SSL *ssl, void *buf, size_t count); + + /* SSL_get_peer_finished writes up to |count| bytes of the Finished message + * received from |ssl|'s peer to |buf|. It returns the total untruncated length + * or zero if none has been received yet. + * + * Use |SSL_get_tls_unique| instead. */ +OPENSSL_EXPORT size_t SSL_get_peer_finished(const SSL *ssl, void *buf, + size_t count); + +/* SSL_alert_type_string returns "!". Use |SSL_alert_type_string_long| + * instead. */ +OPENSSL_EXPORT const char *SSL_alert_type_string(int value); + +/* SSL_alert_desc_string returns "!!". Use |SSL_alert_desc_string_long| + * instead. */ +OPENSSL_EXPORT const char *SSL_alert_desc_string(int value); + +/* SSL_TXT_* expand to strings. */ +#define SSL_TXT_MEDIUM "MEDIUM" +#define SSL_TXT_HIGH "HIGH" +#define SSL_TXT_FIPS "FIPS" +#define SSL_TXT_kRSA "kRSA" +#define SSL_TXT_kDHE "kDHE" +#define SSL_TXT_kEDH "kEDH" +#define SSL_TXT_kECDHE "kECDHE" +#define SSL_TXT_kEECDH "kEECDH" +#define SSL_TXT_kPSK "kPSK" +#define SSL_TXT_aRSA "aRSA" +#define SSL_TXT_aECDSA "aECDSA" +#define SSL_TXT_aPSK "aPSK" +#define SSL_TXT_DH "DH" +#define SSL_TXT_DHE "DHE" +#define SSL_TXT_EDH "EDH" +#define SSL_TXT_RSA "RSA" +#define SSL_TXT_ECDH "ECDH" +#define SSL_TXT_ECDHE "ECDHE" +#define SSL_TXT_EECDH "EECDH" +#define SSL_TXT_ECDSA "ECDSA" +#define SSL_TXT_PSK "PSK" +#define SSL_TXT_3DES "3DES" +#define SSL_TXT_RC4 "RC4" +#define SSL_TXT_AES128 "AES128" +#define SSL_TXT_AES256 "AES256" +#define SSL_TXT_AES "AES" +#define SSL_TXT_AES_GCM "AESGCM" +#define SSL_TXT_CHACHA20 "CHACHA20" +#define SSL_TXT_MD5 "MD5" +#define SSL_TXT_SHA1 "SHA1" +#define SSL_TXT_SHA "SHA" +#define SSL_TXT_SHA256 "SHA256" +#define SSL_TXT_SHA384 "SHA384" +#define SSL_TXT_SSLV3 "SSLv3" +#define SSL_TXT_TLSV1 "TLSv1" +#define SSL_TXT_TLSV1_1 "TLSv1.1" +#define SSL_TXT_TLSV1_2 "TLSv1.2" +#define SSL_TXT_ALL "ALL" +#define SSL_TXT_CMPDEF "COMPLEMENTOFDEFAULT" + +typedef struct ssl_conf_ctx_st SSL_CONF_CTX; + +/* SSL_state returns the current state of the handshake state machine. */ +OPENSSL_EXPORT int SSL_state(const SSL *ssl); + +#define SSL_get_state(ssl) SSL_state(ssl) + +/* SSL_state_string returns the current state of the handshake state machine as + * a six-letter string. Use |SSL_state_string_long| for a more intelligible + * string. */ +OPENSSL_EXPORT const char *SSL_state_string(const SSL *ssl); + +/* SSL_set_shutdown causes |ssl| to behave as if the shutdown bitmask (see + * |SSL_get_shutdown|) were |mode|. This may be used to skip sending or + * receiving close_notify in |SSL_shutdown| by causing the implementation to + * believe the events already happened. + * + * It is an error to use |SSL_set_shutdown| to unset a bit that has already been + * set. Doing so will trigger an |assert| in debug builds and otherwise be + * ignored. + * + * Use |SSL_CTX_set_quiet_shutdown| instead. */ +OPENSSL_EXPORT void SSL_set_shutdown(SSL *ssl, int mode); + +/* SSL_CTX_set_tmp_ecdh calls |SSL_CTX_set1_curves| with a one-element list + * containing |ec_key|'s curve. */ +OPENSSL_EXPORT int SSL_CTX_set_tmp_ecdh(SSL_CTX *ctx, const EC_KEY *ec_key); + +/* SSL_set_tmp_ecdh calls |SSL_set1_curves| with a one-element list containing + * |ec_key|'s curve. */ +OPENSSL_EXPORT int SSL_set_tmp_ecdh(SSL *ssl, const EC_KEY *ec_key); + + +/* Private structures. + * + * This structures are exposed for historical reasons, but access to them is + * deprecated. */ + +typedef struct ssl_protocol_method_st SSL_PROTOCOL_METHOD; +typedef struct ssl3_enc_method SSL3_ENC_METHOD; +typedef struct ssl_aead_ctx_st SSL_AEAD_CTX; + +struct ssl_cipher_st { + /* name is the OpenSSL name for the cipher. */ + const char *name; + /* id is the cipher suite value bitwise OR-d with 0x03000000. */ + uint32_t id; + + /* algorithm_* are internal fields. See ssl/internal.h for their values. */ + uint32_t algorithm_mkey; + uint32_t algorithm_auth; + uint32_t algorithm_enc; + uint32_t algorithm_mac; + uint32_t algorithm_prf; +}; + +typedef struct ssl_ecdh_method_st SSL_ECDH_METHOD; +typedef struct ssl_ecdh_ctx_st { + const SSL_ECDH_METHOD *method; + void *data; +} SSL_ECDH_CTX; + +#define SSL_MAX_SSL_SESSION_ID_LENGTH 32 +#define SSL_MAX_SID_CTX_LENGTH 32 +#define SSL_MAX_MASTER_KEY_LENGTH 48 + +struct ssl_session_st { + CRYPTO_refcount_t references; + int ssl_version; /* what ssl version session info is being kept in here? */ + + /* key_exchange_info contains an indication of the size of the asymmetric + * primitive used in the handshake that created this session. In the event + * that two asymmetric operations are used, this value applies to the one + * that controls the confidentiality of the connection. Its interpretation + * depends on the primitive that was used; as specified by the cipher suite: + * DHE: the size, in bits, of the multiplicative group. + * RSA: the size, in bits, of the modulus. + * ECDHE: the TLS id for the curve. + * + * A zero indicates that the value is unknown. */ + uint32_t key_exchange_info; + + int master_key_length; + uint8_t master_key[SSL_MAX_MASTER_KEY_LENGTH]; + + /* session_id - valid? */ + unsigned int session_id_length; + uint8_t session_id[SSL_MAX_SSL_SESSION_ID_LENGTH]; + /* this is used to determine whether the session is being reused in + * the appropriate context. It is up to the application to set this, + * via SSL_new */ + unsigned int sid_ctx_length; + uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; + + char *psk_identity; + /* peer is the peer's certificate. */ + X509 *peer; + + /* cert_chain is the certificate chain sent by the peer. NOTE: for historical + * reasons, when a client (so the peer is a server), the chain includes + * |peer|, but when a server it does not. */ + STACK_OF(X509) *cert_chain; + + /* when app_verify_callback accepts a session where the peer's certificate is + * not ok, we must remember the error for session reuse: */ + long verify_result; /* only for servers */ + + long timeout; + long time; + + const SSL_CIPHER *cipher; + + CRYPTO_EX_DATA ex_data; /* application specific data */ + + /* These are used to make removal of session-ids more efficient and to + * implement a maximum cache size. */ + SSL_SESSION *prev, *next; + char *tlsext_hostname; + + /* RFC4507 info */ + uint8_t *tlsext_tick; /* Session ticket */ + size_t tlsext_ticklen; /* Session ticket length */ + + size_t tlsext_signed_cert_timestamp_list_length; + uint8_t *tlsext_signed_cert_timestamp_list; /* Server's list. */ + + /* The OCSP response that came with the session. */ + size_t ocsp_response_length; + uint8_t *ocsp_response; + + /* peer_sha256 contains the SHA-256 hash of the peer's certificate if + * |peer_sha256_valid| is true. */ + uint8_t peer_sha256[SHA256_DIGEST_LENGTH]; + + /* original_handshake_hash contains the handshake hash (either SHA-1+MD5 or + * SHA-2, depending on TLS version) for the original, full handshake that + * created a session. This is used by Channel IDs during resumption. */ + uint8_t original_handshake_hash[EVP_MAX_MD_SIZE]; + unsigned original_handshake_hash_len; + + uint32_t tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */ + + /* extended_master_secret is true if the master secret in this session was + * generated using EMS and thus isn't vulnerable to the Triple Handshake + * attack. */ + unsigned extended_master_secret:1; + + /* peer_sha256_valid is non-zero if |peer_sha256| is valid. */ + unsigned peer_sha256_valid:1; /* Non-zero if peer_sha256 is valid */ + + /* not_resumable is used to indicate that session resumption is not allowed. + * Applications can also set this bit for a new session via + * not_resumable_session_cb to disable session caching and tickets. */ + unsigned not_resumable:1; +}; + +/* ssl_cipher_preference_list_st contains a list of SSL_CIPHERs with + * equal-preference groups. For TLS clients, the groups are moot because the + * server picks the cipher and groups cannot be expressed on the wire. However, + * for servers, the equal-preference groups allow the client's preferences to + * be partially respected. (This only has an effect with + * SSL_OP_CIPHER_SERVER_PREFERENCE). + * + * The equal-preference groups are expressed by grouping SSL_CIPHERs together. + * All elements of a group have the same priority: no ordering is expressed + * within a group. + * + * The values in |ciphers| are in one-to-one correspondence with + * |in_group_flags|. (That is, sk_SSL_CIPHER_num(ciphers) is the number of + * bytes in |in_group_flags|.) The bytes in |in_group_flags| are either 1, to + * indicate that the corresponding SSL_CIPHER is not the last element of a + * group, or 0 to indicate that it is. + * + * For example, if |in_group_flags| contains all zeros then that indicates a + * traditional, fully-ordered preference. Every SSL_CIPHER is the last element + * of the group (i.e. they are all in a one-element group). + * + * For a more complex example, consider: + * ciphers: A B C D E F + * in_group_flags: 1 1 0 0 1 0 + * + * That would express the following, order: + * + * A E + * B -> D -> F + * C + */ +struct ssl_cipher_preference_list_st { + STACK_OF(SSL_CIPHER) *ciphers; + uint8_t *in_group_flags; +}; + +struct ssl_ctx_st { + const SSL_PROTOCOL_METHOD *method; + + /* lock is used to protect various operations on this object. */ + CRYPTO_MUTEX lock; + + /* max_version is the maximum acceptable protocol version. If zero, the + * maximum supported version, currently (D)TLS 1.2, is used. */ + uint16_t max_version; + + /* min_version is the minimum acceptable protocl version. If zero, the + * minimum supported version, currently SSL 3.0 and DTLS 1.0, is used */ + uint16_t min_version; + + struct ssl_cipher_preference_list_st *cipher_list; + /* same as above but sorted for lookup */ + STACK_OF(SSL_CIPHER) *cipher_list_by_id; + + /* cipher_list_tls10 is the list of ciphers when TLS 1.0 or greater is in + * use. This only applies to server connections as, for clients, the version + * number is known at connect time and so the cipher list can be set then. If + * |cipher_list_tls11| is non-NULL then this applies only to TLS 1.0 + * connections. + * + * TODO(agl): this exists to assist in the death of SSLv3. It can hopefully + * be removed after that. */ + struct ssl_cipher_preference_list_st *cipher_list_tls10; + + /* cipher_list_tls11 is the list of ciphers when TLS 1.1 or greater is in + * use. This only applies to server connections as, for clients, the version + * number is known at connect time and so the cipher list can be set then. */ + struct ssl_cipher_preference_list_st *cipher_list_tls11; + + X509_STORE *cert_store; + LHASH_OF(SSL_SESSION) *sessions; + /* Most session-ids that will be cached, default is + * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited. */ + unsigned long session_cache_size; + SSL_SESSION *session_cache_head; + SSL_SESSION *session_cache_tail; + + /* handshakes_since_cache_flush is the number of successful handshakes since + * the last cache flush. */ + int handshakes_since_cache_flush; + + /* This can have one of 2 values, ored together, + * SSL_SESS_CACHE_CLIENT, + * SSL_SESS_CACHE_SERVER, + * Default is SSL_SESSION_CACHE_SERVER, which means only + * SSL_accept which cache SSL_SESSIONS. */ + int session_cache_mode; + + /* If timeout is not 0, it is the default timeout value set when SSL_new() is + * called. This has been put in to make life easier to set things up */ + long session_timeout; + + /* If this callback is not null, it will be called each time a session id is + * added to the cache. If this function returns 1, it means that the + * callback will do a SSL_SESSION_free() when it has finished using it. + * Otherwise, on 0, it means the callback has finished with it. If + * remove_session_cb is not null, it will be called when a session-id is + * removed from the cache. After the call, OpenSSL will SSL_SESSION_free() + * it. */ + int (*new_session_cb)(SSL *ssl, SSL_SESSION *sess); + void (*remove_session_cb)(SSL_CTX *ctx, SSL_SESSION *sess); + SSL_SESSION *(*get_session_cb)(SSL *ssl, uint8_t *data, int len, + int *copy); + + CRYPTO_refcount_t references; + + /* if defined, these override the X509_verify_cert() calls */ + int (*app_verify_callback)(X509_STORE_CTX *store_ctx, void *arg); + void *app_verify_arg; + + /* Default password callback. */ + pem_password_cb *default_passwd_callback; + + /* Default password callback user data. */ + void *default_passwd_callback_userdata; + + /* get client cert callback */ + int (*client_cert_cb)(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey); + + /* get channel id callback */ + void (*channel_id_cb)(SSL *ssl, EVP_PKEY **out_pkey); + + CRYPTO_EX_DATA ex_data; + + /* custom_*_extensions stores any callback sets for custom extensions. Note + * that these pointers will be NULL if the stack would otherwise be empty. */ + STACK_OF(SSL_CUSTOM_EXTENSION) *client_custom_extensions; + STACK_OF(SSL_CUSTOM_EXTENSION) *server_custom_extensions; + + /* Default values used when no per-SSL value is defined follow */ + + void (*info_callback)(const SSL *ssl, int type, int value); + + /* what we put in client cert requests */ + STACK_OF(X509_NAME) *client_CA; + + + /* Default values to use in SSL structures follow (these are copied by + * SSL_new) */ + + uint32_t options; + uint32_t mode; + uint32_t max_cert_list; + + struct cert_st /* CERT */ *cert; + + /* callback that allows applications to peek at protocol messages */ + void (*msg_callback)(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg); + void *msg_callback_arg; + + int verify_mode; + unsigned int sid_ctx_length; + uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; + int (*default_verify_callback)( + int ok, X509_STORE_CTX *ctx); /* called 'verify_callback' in the SSL */ + + X509_VERIFY_PARAM *param; + + /* select_certificate_cb is called before most ClientHello processing and + * before the decision whether to resume a session is made. It may return one + * to continue the handshake or zero to cause the handshake loop to return + * with an error and cause SSL_get_error to return + * SSL_ERROR_PENDING_CERTIFICATE. Note: when the handshake loop is resumed, it + * will not call the callback a second time. */ + int (*select_certificate_cb)(const struct ssl_early_callback_ctx *); + + /* dos_protection_cb is called once the resumption decision for a ClientHello + * has been made. It returns one to continue the handshake or zero to + * abort. */ + int (*dos_protection_cb) (const struct ssl_early_callback_ctx *); + + /* Maximum amount of data to send in one fragment. actual record size can be + * more than this due to padding and MAC overheads. */ + uint16_t max_send_fragment; + + /* TLS extensions servername callback */ + int (*tlsext_servername_callback)(SSL *, int *, void *); + void *tlsext_servername_arg; + /* RFC 4507 session ticket keys */ + uint8_t tlsext_tick_key_name[SSL_TICKET_KEY_NAME_LEN]; + uint8_t tlsext_tick_hmac_key[16]; + uint8_t tlsext_tick_aes_key[16]; + /* Callback to support customisation of ticket key setting */ + int (*tlsext_ticket_key_cb)(SSL *ssl, uint8_t *name, uint8_t *iv, + EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc); + + /* Server-only: psk_identity_hint is the default identity hint to send in + * PSK-based key exchanges. */ + char *psk_identity_hint; + + unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, + char *identity, + unsigned int max_identity_len, + uint8_t *psk, unsigned int max_psk_len); + unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, + uint8_t *psk, unsigned int max_psk_len); + + + /* retain_only_sha256_of_client_certs is true if we should compute the SHA256 + * hash of the peer's certifiate and then discard it to save memory and + * session space. Only effective on the server side. */ + char retain_only_sha256_of_client_certs; + + /* Next protocol negotiation information */ + /* (for experimental NPN extension). */ + + /* For a server, this contains a callback function by which the set of + * advertised protocols can be provided. */ + int (*next_protos_advertised_cb)(SSL *ssl, const uint8_t **out, + unsigned *out_len, void *arg); + void *next_protos_advertised_cb_arg; + /* For a client, this contains a callback function that selects the + * next protocol from the list provided by the server. */ + int (*next_proto_select_cb)(SSL *ssl, uint8_t **out, uint8_t *out_len, + const uint8_t *in, unsigned in_len, void *arg); + void *next_proto_select_cb_arg; + + /* ALPN information + * (we are in the process of transitioning from NPN to ALPN.) */ + + /* For a server, this contains a callback function that allows the + * server to select the protocol for the connection. + * out: on successful return, this must point to the raw protocol + * name (without the length prefix). + * outlen: on successful return, this contains the length of |*out|. + * in: points to the client's list of supported protocols in + * wire-format. + * inlen: the length of |in|. */ + int (*alpn_select_cb)(SSL *s, const uint8_t **out, uint8_t *out_len, + const uint8_t *in, unsigned in_len, void *arg); + void *alpn_select_cb_arg; + + /* For a client, this contains the list of supported protocols in wire + * format. */ + uint8_t *alpn_client_proto_list; + unsigned alpn_client_proto_list_len; + + /* SRTP profiles we are willing to do from RFC 5764 */ + STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; + + /* EC extension values inherited by SSL structure */ + size_t tlsext_ellipticcurvelist_length; + uint16_t *tlsext_ellipticcurvelist; + + /* The client's Channel ID private key. */ + EVP_PKEY *tlsext_channel_id_private; + + /* Signed certificate timestamp list to be sent to the client, if requested */ + uint8_t *signed_cert_timestamp_list; + size_t signed_cert_timestamp_list_length; + + /* OCSP response to be sent to the client, if requested. */ + uint8_t *ocsp_response; + size_t ocsp_response_length; + + /* keylog_callback, if not NULL, is the key logging callback. See + * |SSL_CTX_set_keylog_callback|. */ + void (*keylog_callback)(const SSL *ssl, const char *line); + + /* current_time_cb, if not NULL, is the function to use to get the current + * time. It sets |*out_clock| to the current time. */ + void (*current_time_cb)(const SSL *ssl, struct timeval *out_clock); + + /* quiet_shutdown is true if the connection should not send a close_notify on + * shutdown. */ + unsigned quiet_shutdown:1; + + /* ocsp_stapling_enabled is only used by client connections and indicates + * whether OCSP stapling will be requested. */ + unsigned ocsp_stapling_enabled:1; + + /* If true, a client will request certificate timestamps. */ + unsigned signed_cert_timestamps_enabled:1; + + /* tlsext_channel_id_enabled is copied from the |SSL_CTX|. For a server, + * means that we'll accept Channel IDs from clients. For a client, means that + * we'll advertise support. */ + unsigned tlsext_channel_id_enabled:1; +}; + +struct ssl_st { + /* version is the protocol version. */ + int version; + + /* max_version is the maximum acceptable protocol version. If zero, the + * maximum supported version, currently (D)TLS 1.2, is used. */ + uint16_t max_version; + + /* min_version is the minimum acceptable protocl version. If zero, the + * minimum supported version, currently SSL 3.0 and DTLS 1.0, is used */ + uint16_t min_version; + + /* method is the method table corresponding to the current protocol (DTLS or + * TLS). */ + const SSL_PROTOCOL_METHOD *method; + + /* enc_method is the method table corresponding to the current protocol + * version. */ + const SSL3_ENC_METHOD *enc_method; + + /* There are 2 BIO's even though they are normally both the same. This is so + * data can be read and written to different handlers */ + + BIO *rbio; /* used by SSL_read */ + BIO *wbio; /* used by SSL_write */ + + /* bbio, if non-NULL, is a buffer placed in front of |wbio| to pack handshake + * messages within one flight into a single |BIO_write|. + * + * TODO(davidben): This does not work right for DTLS. It assumes the MTU is + * smaller than the buffer size so that the buffer's internal flushing never + * kicks in. It also doesn't kick in for DTLS retransmission. Replace this + * with a better mechanism. */ + BIO *bbio; + + int (*handshake_func)(SSL *); + + /* Imagine that here's a boolean member "init" that is switched as soon as + * SSL_set_{accept/connect}_state is called for the first time, so that + * "state" and "handshake_func" are properly initialized. But as + * handshake_func is == 0 until then, we use this test instead of an "init" + * member. */ + + int shutdown; /* we have shut things down, 0x01 sent, 0x02 + * for received */ + int state; /* where we are */ + + BUF_MEM *init_buf; /* buffer used during init */ + uint8_t *init_msg; /* pointer to handshake message body, set by + ssl3_get_message() */ + int init_num; /* amount read/written */ + int init_off; /* amount read/written */ + + struct ssl3_state_st *s3; /* SSLv3 variables */ + struct dtls1_state_st *d1; /* DTLSv1 variables */ + + /* callback that allows applications to peek at protocol messages */ + void (*msg_callback)(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg); + void *msg_callback_arg; + + X509_VERIFY_PARAM *param; + + /* crypto */ + struct ssl_cipher_preference_list_st *cipher_list; + STACK_OF(SSL_CIPHER) *cipher_list_by_id; + + SSL_AEAD_CTX *aead_read_ctx; + SSL_AEAD_CTX *aead_write_ctx; + + /* session info */ + + /* client cert? */ + /* This is used to hold the server certificate used */ + struct cert_st /* CERT */ *cert; + + /* This holds a variable that indicates what we were doing when a 0 or -1 is + * returned. This is needed for non-blocking IO so we know what request + * needs re-doing when in SSL_accept or SSL_connect */ + int rwstate; + + /* the session_id_context is used to ensure sessions are only reused + * in the appropriate context */ + unsigned int sid_ctx_length; + uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; + + /* This can also be in the session once a session is established */ + SSL_SESSION *session; + + int (*verify_callback)(int ok, + X509_STORE_CTX *ctx); /* fail if callback returns 0 */ + + void (*info_callback)(const SSL *ssl, int type, int value); + + /* Server-only: psk_identity_hint is the identity hint to send in + * PSK-based key exchanges. */ + char *psk_identity_hint; + + unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, + char *identity, + unsigned int max_identity_len, + uint8_t *psk, unsigned int max_psk_len); + unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, + uint8_t *psk, unsigned int max_psk_len); + + SSL_CTX *ctx; + + /* extra application data */ + long verify_result; + CRYPTO_EX_DATA ex_data; + + /* for server side, keep the list of CA_dn we can use */ + STACK_OF(X509_NAME) *client_CA; + + uint32_t options; /* protocol behaviour */ + uint32_t mode; /* API behaviour */ + uint32_t max_cert_list; + int client_version; /* what was passed, used for + * SSLv3/TLS rollback check */ + uint16_t max_send_fragment; + char *tlsext_hostname; + /* RFC4507 session ticket expected to be received or sent */ + int tlsext_ticket_expected; + size_t tlsext_ellipticcurvelist_length; + uint16_t *tlsext_ellipticcurvelist; /* our list */ + + SSL_CTX *initial_ctx; /* initial ctx, used to store sessions */ + + /* Next protocol negotiation. For the client, this is the protocol that we + * sent in NextProtocol and is set when handling ServerHello extensions. + * + * For a server, this is the client's selected_protocol from NextProtocol and + * is set when handling the NextProtocol message, before the Finished + * message. */ + uint8_t *next_proto_negotiated; + size_t next_proto_negotiated_len; + + /* srtp_profiles is the list of configured SRTP protection profiles for + * DTLS-SRTP. */ + STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; + + /* srtp_profile is the selected SRTP protection profile for + * DTLS-SRTP. */ + const SRTP_PROTECTION_PROFILE *srtp_profile; + + /* The client's Channel ID private key. */ + EVP_PKEY *tlsext_channel_id_private; + + /* For a client, this contains the list of supported protocols in wire + * format. */ + uint8_t *alpn_client_proto_list; + unsigned alpn_client_proto_list_len; + + /* renegotiate_mode controls how peer renegotiation attempts are handled. */ + enum ssl_renegotiate_mode_t renegotiate_mode; + + /* These fields are always NULL and exist only to keep wpa_supplicant happy + * about the change to EVP_AEAD. They are only needed for EAP-FAST, which we + * don't support. */ + EVP_CIPHER_CTX *enc_read_ctx; + EVP_MD_CTX *read_hash; + + /* in_handshake is non-zero when we are actually in SSL_accept() or + * SSL_connect() */ + int in_handshake; + + /* verify_mode is a bitmask of |SSL_VERIFY_*| values. */ + uint8_t verify_mode; + + /* hit is true if this connection is resuming a previous session. */ + unsigned hit:1; + + /* server is true iff the this SSL* is the server half. Note: before the SSL* + * is initialized by either SSL_set_accept_state or SSL_set_connect_state, + * the side is not determined. In this state, server is always false. */ + unsigned server:1; + + /* quiet_shutdown is true if the connection should not send a close_notify on + * shutdown. */ + unsigned quiet_shutdown:1; + + /* Enable signed certificate time stamps. Currently client only. */ + unsigned signed_cert_timestamps_enabled:1; + + /* ocsp_stapling_enabled is only used by client connections and indicates + * whether OCSP stapling will be requested. */ + unsigned ocsp_stapling_enabled:1; + + /* tlsext_channel_id_enabled is copied from the |SSL_CTX|. For a server, + * means that we'll accept Channel IDs from clients. For a client, means that + * we'll advertise support. */ + unsigned tlsext_channel_id_enabled:1; +}; + +typedef struct ssl3_record_st { + /* type is the record type. */ + uint8_t type; + /* length is the number of unconsumed bytes in the record. */ + uint16_t length; + /* data is a non-owning pointer to the first unconsumed byte of the record. */ + uint8_t *data; +} SSL3_RECORD; + +typedef struct ssl3_buffer_st { + /* buf is the memory allocated for this buffer. */ + uint8_t *buf; + /* offset is the offset into |buf| which the buffer contents start at. */ + uint16_t offset; + /* len is the length of the buffer contents from |buf| + |offset|. */ + uint16_t len; + /* cap is how much memory beyond |buf| + |offset| is available. */ + uint16_t cap; +} SSL3_BUFFER; + +typedef struct ssl3_state_st { + uint8_t read_sequence[8]; + uint8_t write_sequence[8]; + + uint8_t server_random[SSL3_RANDOM_SIZE]; + uint8_t client_random[SSL3_RANDOM_SIZE]; + + /* have_version is true if the connection's final version is known. Otherwise + * the version has not been negotiated yet. */ + char have_version; + + /* initial_handshake_complete is true if the initial handshake has + * completed. */ + char initial_handshake_complete; + + /* read_buffer holds data from the transport to be processed. */ + SSL3_BUFFER read_buffer; + /* write_buffer holds data to be written to the transport. */ + SSL3_BUFFER write_buffer; + + SSL3_RECORD rrec; /* each decoded record goes in here */ + + /* hello_request_len is the number of bytes of HelloRequest received, possibly + * split over multiple records. */ + uint8_t hello_request_len; + + /* partial write - check the numbers match */ + unsigned int wnum; /* number of bytes sent so far */ + int wpend_tot; /* number bytes written */ + int wpend_type; + int wpend_ret; /* number of bytes submitted */ + const uint8_t *wpend_buf; + + /* handshake_buffer, if non-NULL, contains the handshake transcript. */ + BUF_MEM *handshake_buffer; + /* handshake_hash, if initialized with an |EVP_MD|, maintains the handshake + * hash. For TLS 1.1 and below, it is the SHA-1 half. */ + EVP_MD_CTX handshake_hash; + /* handshake_md5, if initialized with an |EVP_MD|, maintains the MD5 half of + * the handshake hash for TLS 1.1 and below. */ + EVP_MD_CTX handshake_md5; + + int warn_alert; + int fatal_alert; + /* we allow one fatal and one warning alert to be outstanding, send close + * alert via the warning alert */ + int alert_dispatch; + uint8_t send_alert[2]; + + int total_renegotiations; + + /* empty_record_count is the number of consecutive empty records received. */ + uint8_t empty_record_count; + + /* warning_alert_count is the number of consecutive warning alerts + * received. */ + uint8_t warning_alert_count; + + /* State pertaining to the pending handshake. + * + * TODO(davidben): State is current spread all over the place. Move + * pending handshake state here so it can be managed separately from + * established connection state in case of renegotiations. */ + struct { + uint8_t finish_md[EVP_MAX_MD_SIZE]; + int finish_md_len; + uint8_t peer_finish_md[EVP_MAX_MD_SIZE]; + int peer_finish_md_len; + + unsigned long message_size; + int message_type; + + /* used to hold the new cipher we are going to use */ + const SSL_CIPHER *new_cipher; + + /* used when SSL_ST_FLUSH_DATA is entered */ + int next_state; + + int reuse_message; + + union { + /* sent is a bitset where the bits correspond to elements of kExtensions + * in t1_lib.c. Each bit is set if that extension was sent in a + * ClientHello. It's not used by servers. */ + uint32_t sent; + /* received is a bitset, like |sent|, but is used by servers to record + * which extensions were received from a client. */ + uint32_t received; + } extensions; + + union { + /* sent is a bitset where the bits correspond to elements of + * |client_custom_extensions| in the |SSL_CTX|. Each bit is set if that + * extension was sent in a ClientHello. It's not used by servers. */ + uint16_t sent; + /* received is a bitset, like |sent|, but is used by servers to record + * which custom extensions were received from a client. The bits here + * correspond to |server_custom_extensions|. */ + uint16_t received; + } custom_extensions; + + /* SNI extension */ + + /* should_ack_sni is used by a server and indicates that the SNI extension + * should be echoed in the ServerHello. */ + unsigned should_ack_sni:1; + + + /* Client-only: cert_req determines if a client certificate is to be sent. + * This is 0 if no client Certificate message is to be sent, 1 if there is + * a client certificate, and 2 to send an empty client Certificate + * message. */ + int cert_req; + + /* Client-only: ca_names contains the list of CAs received in a + * CertificateRequest message. */ + STACK_OF(X509_NAME) *ca_names; + + /* Client-only: certificate_types contains the set of certificate types + * received in a CertificateRequest message. */ + uint8_t *certificate_types; + size_t num_certificate_types; + + int key_block_length; + uint8_t *key_block; + + const EVP_AEAD *new_aead; + uint8_t new_mac_secret_len; + uint8_t new_fixed_iv_len; + uint8_t new_variable_iv_len; + + /* Server-only: cert_request is true if a client certificate was + * requested. */ + int cert_request; + + /* certificate_status_expected is true if OCSP stapling was negotiated and + * the server is expected to send a CertificateStatus message. (This is + * used on both the client and server sides.) */ + unsigned certificate_status_expected:1; + + /* ocsp_stapling_requested is true if a client requested OCSP stapling. */ + unsigned ocsp_stapling_requested:1; + + /* Server-only: peer_ellipticcurvelist contains the EC curve IDs advertised + * by the peer. This is only set on the server's end. The server does not + * advertise this extension to the client. */ + uint16_t *peer_ellipticcurvelist; + size_t peer_ellipticcurvelist_length; + + /* extended_master_secret indicates whether the extended master secret + * computation is used in this handshake. Note that this is different from + * whether it was used for the current session. If this is a resumption + * handshake then EMS might be negotiated in the client and server hello + * messages, but it doesn't matter if the session that's being resumed + * didn't use it to create the master secret initially. */ + char extended_master_secret; + + /* Client-only: peer_psk_identity_hint is the psk_identity_hint sent by the + * server when using a PSK key exchange. */ + char *peer_psk_identity_hint; + + /* new_mac_secret_size is unused and exists only until wpa_supplicant can + * be updated. It is only needed for EAP-FAST, which we don't support. */ + uint8_t new_mac_secret_size; + + /* Client-only: in_false_start is one if there is a pending handshake in + * False Start. The client may write data at this point. */ + char in_false_start; + + /* server_key_exchange_hash, on a client, is the hash the server used to + * sign the ServerKeyExchange in TLS 1.2. If not applicable, it is + * |TLSEXT_hash_none|. */ + uint8_t server_key_exchange_hash; + + /* ecdh_ctx is the current ECDH instance. */ + SSL_ECDH_CTX ecdh_ctx; + + /* peer_key is the peer's ECDH key. */ + uint8_t *peer_key; + uint16_t peer_key_len; + } tmp; + + /* Connection binding to prevent renegotiation attacks */ + uint8_t previous_client_finished[EVP_MAX_MD_SIZE]; + uint8_t previous_client_finished_len; + uint8_t previous_server_finished[EVP_MAX_MD_SIZE]; + uint8_t previous_server_finished_len; + int send_connection_binding; /* TODOEKR */ + + /* Set if we saw the Next Protocol Negotiation extension from our peer. */ + int next_proto_neg_seen; + + /* ALPN information + * (we are in the process of transitioning from NPN to ALPN.) */ + + /* In a server these point to the selected ALPN protocol after the + * ClientHello has been processed. In a client these contain the protocol + * that the server selected once the ServerHello has been processed. */ + uint8_t *alpn_selected; + size_t alpn_selected_len; + + /* In a client, this means that the server supported Channel ID and that a + * Channel ID was sent. In a server it means that we echoed support for + * Channel IDs and that tlsext_channel_id will be valid after the + * handshake. */ + char tlsext_channel_id_valid; + /* For a server: + * If |tlsext_channel_id_valid| is true, then this contains the + * verified Channel ID from the client: a P256 point, (x,y), where + * each are big-endian values. */ + uint8_t tlsext_channel_id[64]; +} SSL3_STATE; + + +/* Android compatibility section (hidden). + * + * These functions are declared, temporarily, for Android because + * wpa_supplicant will take a little time to sync with upstream. Outside of + * Android they'll have no definition. */ + +#define SSL_F_SSL_SET_SESSION_TICKET_EXT doesnt_exist + +OPENSSL_EXPORT int SSL_set_session_ticket_ext(SSL *s, void *ext_data, + int ext_len); +OPENSSL_EXPORT int SSL_set_session_secret_cb(SSL *s, void *cb, void *arg); +OPENSSL_EXPORT int SSL_set_session_ticket_ext_cb(SSL *s, void *cb, void *arg); +OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); + + +/* Preprocessor compatibility section (hidden). + * + * Historically, a number of APIs were implemented in OpenSSL as macros and + * constants to 'ctrl' functions. To avoid breaking #ifdefs in consumers, this + * section defines a number of legacy macros. + * + * Although using either the CTRL values or their wrapper macros in #ifdefs is + * still supported, the CTRL values may not be passed to |SSL_ctrl| and + * |SSL_CTX_ctrl|. Call the functions (previously wrapper macros) instead. */ + +#define DTLS_CTRL_GET_TIMEOUT doesnt_exist +#define DTLS_CTRL_HANDLE_TIMEOUT doesnt_exist +#define SSL_CTRL_CHAIN doesnt_exist +#define SSL_CTRL_CHAIN_CERT doesnt_exist +#define SSL_CTRL_CHANNEL_ID doesnt_exist +#define SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS doesnt_exist +#define SSL_CTRL_CLEAR_MODE doesnt_exist +#define SSL_CTRL_CLEAR_OPTIONS doesnt_exist +#define SSL_CTRL_EXTRA_CHAIN_CERT doesnt_exist +#define SSL_CTRL_GET_CHAIN_CERTS doesnt_exist +#define SSL_CTRL_GET_CHANNEL_ID doesnt_exist +#define SSL_CTRL_GET_CLIENT_CERT_TYPES doesnt_exist +#define SSL_CTRL_GET_EXTRA_CHAIN_CERTS doesnt_exist +#define SSL_CTRL_GET_MAX_CERT_LIST doesnt_exist +#define SSL_CTRL_GET_NUM_RENEGOTIATIONS doesnt_exist +#define SSL_CTRL_GET_READ_AHEAD doesnt_exist +#define SSL_CTRL_GET_RI_SUPPORT doesnt_exist +#define SSL_CTRL_GET_SESSION_REUSED doesnt_exist +#define SSL_CTRL_GET_SESS_CACHE_MODE doesnt_exist +#define SSL_CTRL_GET_SESS_CACHE_SIZE doesnt_exist +#define SSL_CTRL_GET_TLSEXT_TICKET_KEYS doesnt_exist +#define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS doesnt_exist +#define SSL_CTRL_MODE doesnt_exist +#define SSL_CTRL_NEED_TMP_RSA doesnt_exist +#define SSL_CTRL_OPTIONS doesnt_exist +#define SSL_CTRL_SESS_NUMBER doesnt_exist +#define SSL_CTRL_SET_CHANNEL_ID doesnt_exist +#define SSL_CTRL_SET_CURVES doesnt_exist +#define SSL_CTRL_SET_MAX_CERT_LIST doesnt_exist +#define SSL_CTRL_SET_MAX_SEND_FRAGMENT doesnt_exist +#define SSL_CTRL_SET_MSG_CALLBACK doesnt_exist +#define SSL_CTRL_SET_MSG_CALLBACK_ARG doesnt_exist +#define SSL_CTRL_SET_MTU doesnt_exist +#define SSL_CTRL_SET_READ_AHEAD doesnt_exist +#define SSL_CTRL_SET_SESS_CACHE_MODE doesnt_exist +#define SSL_CTRL_SET_SESS_CACHE_SIZE doesnt_exist +#define SSL_CTRL_SET_TLSEXT_HOSTNAME doesnt_exist +#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG doesnt_exist +#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB doesnt_exist +#define SSL_CTRL_SET_TLSEXT_TICKET_KEYS doesnt_exist +#define SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB doesnt_exist +#define SSL_CTRL_SET_TMP_DH doesnt_exist +#define SSL_CTRL_SET_TMP_DH_CB doesnt_exist +#define SSL_CTRL_SET_TMP_ECDH doesnt_exist +#define SSL_CTRL_SET_TMP_ECDH_CB doesnt_exist +#define SSL_CTRL_SET_TMP_RSA doesnt_exist +#define SSL_CTRL_SET_TMP_RSA_CB doesnt_exist + +#define DTLSv1_get_timeout DTLSv1_get_timeout +#define DTLSv1_handle_timeout DTLSv1_handle_timeout +#define SSL_CTX_add0_chain_cert SSL_CTX_add0_chain_cert +#define SSL_CTX_add1_chain_cert SSL_CTX_add1_chain_cert +#define SSL_CTX_add_extra_chain_cert SSL_CTX_add_extra_chain_cert +#define SSL_CTX_clear_extra_chain_certs SSL_CTX_clear_extra_chain_certs +#define SSL_CTX_clear_chain_certs SSL_CTX_clear_chain_certs +#define SSL_CTX_clear_mode SSL_CTX_clear_mode +#define SSL_CTX_clear_options SSL_CTX_clear_options +#define SSL_CTX_enable_tls_channel_id SSL_CTX_enable_tls_channel_id +#define SSL_CTX_get0_chain_certs SSL_CTX_get0_chain_certs +#define SSL_CTX_get_extra_chain_certs SSL_CTX_get_extra_chain_certs +#define SSL_CTX_get_max_cert_list SSL_CTX_get_max_cert_list +#define SSL_CTX_get_mode SSL_CTX_get_mode +#define SSL_CTX_get_options SSL_CTX_get_options +#define SSL_CTX_get_read_ahead SSL_CTX_get_read_ahead +#define SSL_CTX_get_session_cache_mode SSL_CTX_get_session_cache_mode +#define SSL_CTX_get_tlsext_ticket_keys SSL_CTX_get_tlsext_ticket_keys +#define SSL_CTX_need_tmp_RSA SSL_CTX_need_tmp_RSA +#define SSL_CTX_sess_get_cache_size SSL_CTX_sess_get_cache_size +#define SSL_CTX_sess_number SSL_CTX_sess_number +#define SSL_CTX_sess_set_cache_size SSL_CTX_sess_set_cache_size +#define SSL_CTX_set0_chain SSL_CTX_set0_chain +#define SSL_CTX_set1_chain SSL_CTX_set1_chain +#define SSL_CTX_set1_curves SSL_CTX_set1_curves +#define SSL_CTX_set1_tls_channel_id SSL_CTX_set1_tls_channel_id +#define SSL_CTX_set_max_cert_list SSL_CTX_set_max_cert_list +#define SSL_CTX_set_max_send_fragment SSL_CTX_set_max_send_fragment +#define SSL_CTX_set_mode SSL_CTX_set_mode +#define SSL_CTX_set_msg_callback_arg SSL_CTX_set_msg_callback_arg +#define SSL_CTX_set_options SSL_CTX_set_options +#define SSL_CTX_set_read_ahead SSL_CTX_set_read_ahead +#define SSL_CTX_set_session_cache_mode SSL_CTX_set_session_cache_mode +#define SSL_CTX_set_tlsext_servername_arg SSL_CTX_set_tlsext_servername_arg +#define SSL_CTX_set_tlsext_servername_callback \ + SSL_CTX_set_tlsext_servername_callback +#define SSL_CTX_set_tlsext_ticket_key_cb SSL_CTX_set_tlsext_ticket_key_cb +#define SSL_CTX_set_tlsext_ticket_keys SSL_CTX_set_tlsext_ticket_keys +#define SSL_CTX_set_tmp_dh SSL_CTX_set_tmp_dh +#define SSL_CTX_set_tmp_ecdh SSL_CTX_set_tmp_ecdh +#define SSL_CTX_set_tmp_rsa SSL_CTX_set_tmp_rsa +#define SSL_add0_chain_cert SSL_add0_chain_cert +#define SSL_add1_chain_cert SSL_add1_chain_cert +#define SSL_clear_chain_certs SSL_clear_chain_certs +#define SSL_clear_mode SSL_clear_mode +#define SSL_clear_options SSL_clear_options +#define SSL_enable_tls_channel_id SSL_enable_tls_channel_id +#define SSL_get0_certificate_types SSL_get0_certificate_types +#define SSL_get0_chain_certs SSL_get0_chain_certs +#define SSL_get_max_cert_list SSL_get_max_cert_list +#define SSL_get_mode SSL_get_mode +#define SSL_get_options SSL_get_options +#define SSL_get_secure_renegotiation_support \ + SSL_get_secure_renegotiation_support +#define SSL_get_tls_channel_id SSL_get_tls_channel_id +#define SSL_need_tmp_RSA SSL_need_tmp_RSA +#define SSL_num_renegotiations SSL_num_renegotiations +#define SSL_session_reused SSL_session_reused +#define SSL_set0_chain SSL_set0_chain +#define SSL_set1_chain SSL_set1_chain +#define SSL_set1_curves SSL_set1_curves +#define SSL_set1_tls_channel_id SSL_set1_tls_channel_id +#define SSL_set_max_cert_list SSL_set_max_cert_list +#define SSL_set_max_send_fragment SSL_set_max_send_fragment +#define SSL_set_mode SSL_set_mode +#define SSL_set_msg_callback_arg SSL_set_msg_callback_arg +#define SSL_set_mtu SSL_set_mtu +#define SSL_set_options SSL_set_options +#define SSL_set_tlsext_host_name SSL_set_tlsext_host_name +#define SSL_set_tmp_dh SSL_set_tmp_dh +#define SSL_set_tmp_ecdh SSL_set_tmp_ecdh +#define SSL_set_tmp_rsa SSL_set_tmp_rsa +#define SSL_total_renegotiations SSL_total_renegotiations + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define SSL_R_APP_DATA_IN_HANDSHAKE 100 +#define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 101 +#define SSL_R_BAD_ALERT 102 +#define SSL_R_BAD_CHANGE_CIPHER_SPEC 103 +#define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 104 +#define SSL_R_BAD_DH_P_LENGTH 105 +#define SSL_R_BAD_DIGEST_LENGTH 106 +#define SSL_R_BAD_ECC_CERT 107 +#define SSL_R_BAD_ECPOINT 108 +#define SSL_R_BAD_HANDSHAKE_RECORD 109 +#define SSL_R_BAD_HELLO_REQUEST 110 +#define SSL_R_BAD_LENGTH 111 +#define SSL_R_BAD_PACKET_LENGTH 112 +#define SSL_R_BAD_RSA_ENCRYPT 113 +#define SSL_R_BAD_SIGNATURE 114 +#define SSL_R_BAD_SRTP_MKI_VALUE 115 +#define SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST 116 +#define SSL_R_BAD_SSL_FILETYPE 117 +#define SSL_R_BAD_WRITE_RETRY 118 +#define SSL_R_BIO_NOT_SET 119 +#define SSL_R_BN_LIB 120 +#define SSL_R_BUFFER_TOO_SMALL 121 +#define SSL_R_CA_DN_LENGTH_MISMATCH 122 +#define SSL_R_CA_DN_TOO_LONG 123 +#define SSL_R_CCS_RECEIVED_EARLY 124 +#define SSL_R_CERTIFICATE_VERIFY_FAILED 125 +#define SSL_R_CERT_CB_ERROR 126 +#define SSL_R_CERT_LENGTH_MISMATCH 127 +#define SSL_R_CHANNEL_ID_NOT_P256 128 +#define SSL_R_CHANNEL_ID_SIGNATURE_INVALID 129 +#define SSL_R_CIPHER_OR_HASH_UNAVAILABLE 130 +#define SSL_R_CLIENTHELLO_PARSE_FAILED 131 +#define SSL_R_CLIENTHELLO_TLSEXT 132 +#define SSL_R_CONNECTION_REJECTED 133 +#define SSL_R_CONNECTION_TYPE_NOT_SET 134 +#define SSL_R_CUSTOM_EXTENSION_ERROR 135 +#define SSL_R_DATA_LENGTH_TOO_LONG 136 +#define SSL_R_DECODE_ERROR 137 +#define SSL_R_DECRYPTION_FAILED 138 +#define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 139 +#define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG 140 +#define SSL_R_DH_P_TOO_LONG 141 +#define SSL_R_DIGEST_CHECK_FAILED 142 +#define SSL_R_DTLS_MESSAGE_TOO_BIG 143 +#define SSL_R_ECC_CERT_NOT_FOR_SIGNING 144 +#define SSL_R_EMS_STATE_INCONSISTENT 145 +#define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 146 +#define SSL_R_ERROR_ADDING_EXTENSION 147 +#define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 148 +#define SSL_R_ERROR_PARSING_EXTENSION 149 +#define SSL_R_EXCESSIVE_MESSAGE_SIZE 150 +#define SSL_R_EXTRA_DATA_IN_MESSAGE 151 +#define SSL_R_FRAGMENT_MISMATCH 152 +#define SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION 153 +#define SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO 154 +#define SSL_R_HTTPS_PROXY_REQUEST 155 +#define SSL_R_HTTP_REQUEST 156 +#define SSL_R_INAPPROPRIATE_FALLBACK 157 +#define SSL_R_INVALID_COMMAND 158 +#define SSL_R_INVALID_MESSAGE 159 +#define SSL_R_INVALID_SSL_SESSION 160 +#define SSL_R_INVALID_TICKET_KEYS_LENGTH 161 +#define SSL_R_LENGTH_MISMATCH 162 +#define SSL_R_LIBRARY_HAS_NO_CIPHERS 163 +#define SSL_R_MISSING_EXTENSION 164 +#define SSL_R_MISSING_RSA_CERTIFICATE 165 +#define SSL_R_MISSING_TMP_DH_KEY 166 +#define SSL_R_MISSING_TMP_ECDH_KEY 167 +#define SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS 168 +#define SSL_R_MTU_TOO_SMALL 169 +#define SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN 170 +#define SSL_R_NESTED_GROUP 171 +#define SSL_R_NO_CERTIFICATES_RETURNED 172 +#define SSL_R_NO_CERTIFICATE_ASSIGNED 173 +#define SSL_R_NO_CERTIFICATE_SET 174 +#define SSL_R_NO_CIPHERS_AVAILABLE 175 +#define SSL_R_NO_CIPHERS_PASSED 176 +#define SSL_R_NO_CIPHER_MATCH 177 +#define SSL_R_NO_COMPRESSION_SPECIFIED 178 +#define SSL_R_NO_METHOD_SPECIFIED 179 +#define SSL_R_NO_P256_SUPPORT 180 +#define SSL_R_NO_PRIVATE_KEY_ASSIGNED 181 +#define SSL_R_NO_RENEGOTIATION 182 +#define SSL_R_NO_REQUIRED_DIGEST 183 +#define SSL_R_NO_SHARED_CIPHER 184 +#define SSL_R_NULL_SSL_CTX 185 +#define SSL_R_NULL_SSL_METHOD_PASSED 186 +#define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 187 +#define SSL_R_OLD_SESSION_VERSION_NOT_RETURNED 188 +#define SSL_R_OUTPUT_ALIASES_INPUT 189 +#define SSL_R_PARSE_TLSEXT 190 +#define SSL_R_PATH_TOO_LONG 191 +#define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE 192 +#define SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE 193 +#define SSL_R_PROTOCOL_IS_SHUTDOWN 194 +#define SSL_R_PSK_IDENTITY_NOT_FOUND 195 +#define SSL_R_PSK_NO_CLIENT_CB 196 +#define SSL_R_PSK_NO_SERVER_CB 197 +#define SSL_R_READ_TIMEOUT_EXPIRED 198 +#define SSL_R_RECORD_LENGTH_MISMATCH 199 +#define SSL_R_RECORD_TOO_LARGE 200 +#define SSL_R_RENEGOTIATION_ENCODING_ERR 201 +#define SSL_R_RENEGOTIATION_MISMATCH 202 +#define SSL_R_REQUIRED_CIPHER_MISSING 203 +#define SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION 204 +#define SSL_R_RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION 205 +#define SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 206 +#define SSL_R_SERVERHELLO_TLSEXT 207 +#define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED 208 +#define SSL_R_SESSION_MAY_NOT_BE_CREATED 209 +#define SSL_R_SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER 210 +#define SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES 211 +#define SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE 212 +#define SSL_R_SSL3_EXT_INVALID_SERVERNAME 213 +#define SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION 214 +#define SSL_R_SSL_HANDSHAKE_FAILURE 215 +#define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG 216 +#define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 217 +#define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG 218 +#define SSL_R_TOO_MANY_EMPTY_FRAGMENTS 219 +#define SSL_R_TOO_MANY_WARNING_ALERTS 220 +#define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 221 +#define SSL_R_UNEXPECTED_EXTENSION 222 +#define SSL_R_UNEXPECTED_MESSAGE 223 +#define SSL_R_UNEXPECTED_OPERATOR_IN_GROUP 224 +#define SSL_R_UNEXPECTED_RECORD 225 +#define SSL_R_UNINITIALIZED 226 +#define SSL_R_UNKNOWN_ALERT_TYPE 227 +#define SSL_R_UNKNOWN_CERTIFICATE_TYPE 228 +#define SSL_R_UNKNOWN_CIPHER_RETURNED 229 +#define SSL_R_UNKNOWN_CIPHER_TYPE 230 +#define SSL_R_UNKNOWN_DIGEST 231 +#define SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE 232 +#define SSL_R_UNKNOWN_PROTOCOL 233 +#define SSL_R_UNKNOWN_SSL_VERSION 234 +#define SSL_R_UNKNOWN_STATE 235 +#define SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 236 +#define SSL_R_UNSUPPORTED_CIPHER 237 +#define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM 238 +#define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 239 +#define SSL_R_UNSUPPORTED_PROTOCOL 240 +#define SSL_R_WRONG_CERTIFICATE_TYPE 241 +#define SSL_R_WRONG_CIPHER_RETURNED 242 +#define SSL_R_WRONG_CURVE 243 +#define SSL_R_WRONG_MESSAGE_TYPE 244 +#define SSL_R_WRONG_SIGNATURE_TYPE 245 +#define SSL_R_WRONG_SSL_VERSION 246 +#define SSL_R_WRONG_VERSION_NUMBER 247 +#define SSL_R_X509_LIB 248 +#define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS 249 +#define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000 +#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010 +#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020 +#define SSL_R_TLSV1_ALERT_DECRYPTION_FAILED 1021 +#define SSL_R_TLSV1_ALERT_RECORD_OVERFLOW 1022 +#define SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE 1030 +#define SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE 1040 +#define SSL_R_SSLV3_ALERT_NO_CERTIFICATE 1041 +#define SSL_R_SSLV3_ALERT_BAD_CERTIFICATE 1042 +#define SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE 1043 +#define SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED 1044 +#define SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED 1045 +#define SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN 1046 +#define SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER 1047 +#define SSL_R_TLSV1_ALERT_UNKNOWN_CA 1048 +#define SSL_R_TLSV1_ALERT_ACCESS_DENIED 1049 +#define SSL_R_TLSV1_ALERT_DECODE_ERROR 1050 +#define SSL_R_TLSV1_ALERT_DECRYPT_ERROR 1051 +#define SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION 1060 +#define SSL_R_TLSV1_ALERT_PROTOCOL_VERSION 1070 +#define SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY 1071 +#define SSL_R_TLSV1_ALERT_INTERNAL_ERROR 1080 +#define SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK 1086 +#define SSL_R_TLSV1_ALERT_USER_CANCELLED 1090 +#define SSL_R_TLSV1_ALERT_NO_RENEGOTIATION 1100 +#define SSL_R_TLSV1_UNSUPPORTED_EXTENSION 1110 +#define SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE 1111 +#define SSL_R_TLSV1_UNRECOGNIZED_NAME 1112 +#define SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE 1113 +#define SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE 1114 + +#endif /* OPENSSL_HEADER_SSL_H */ diff --git a/project/jni/boringssl/include/openssl/ssl3.h b/project/jni/boringssl/include/openssl/ssl3.h new file mode 100644 index 000000000..957b740e9 --- /dev/null +++ b/project/jni/boringssl/include/openssl/ssl3.h @@ -0,0 +1,441 @@ +/* ssl/ssl3.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#ifndef OPENSSL_HEADER_SSL3_H +#define OPENSSL_HEADER_SSL3_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* These are kept to support clients that negotiates higher protocol versions + * using SSLv2 client hello records. */ +#define SSL2_MT_CLIENT_HELLO 1 +#define SSL2_VERSION 0x0002 + +/* Signalling cipher suite value from RFC 5746. */ +#define SSL3_CK_SCSV 0x030000FF +/* Fallback signalling cipher suite value from RFC 7507. */ +#define SSL3_CK_FALLBACK_SCSV 0x03005600 + +#define SSL3_CK_RSA_NULL_MD5 0x03000001 +#define SSL3_CK_RSA_NULL_SHA 0x03000002 +#define SSL3_CK_RSA_RC4_40_MD5 0x03000003 +#define SSL3_CK_RSA_RC4_128_MD5 0x03000004 +#define SSL3_CK_RSA_RC4_128_SHA 0x03000005 +#define SSL3_CK_RSA_RC2_40_MD5 0x03000006 +#define SSL3_CK_RSA_IDEA_128_SHA 0x03000007 +#define SSL3_CK_RSA_DES_40_CBC_SHA 0x03000008 +#define SSL3_CK_RSA_DES_64_CBC_SHA 0x03000009 +#define SSL3_CK_RSA_DES_192_CBC3_SHA 0x0300000A + +#define SSL3_CK_DH_DSS_DES_40_CBC_SHA 0x0300000B +#define SSL3_CK_DH_DSS_DES_64_CBC_SHA 0x0300000C +#define SSL3_CK_DH_DSS_DES_192_CBC3_SHA 0x0300000D +#define SSL3_CK_DH_RSA_DES_40_CBC_SHA 0x0300000E +#define SSL3_CK_DH_RSA_DES_64_CBC_SHA 0x0300000F +#define SSL3_CK_DH_RSA_DES_192_CBC3_SHA 0x03000010 + +#define SSL3_CK_EDH_DSS_DES_40_CBC_SHA 0x03000011 +#define SSL3_CK_EDH_DSS_DES_64_CBC_SHA 0x03000012 +#define SSL3_CK_EDH_DSS_DES_192_CBC3_SHA 0x03000013 +#define SSL3_CK_EDH_RSA_DES_40_CBC_SHA 0x03000014 +#define SSL3_CK_EDH_RSA_DES_64_CBC_SHA 0x03000015 +#define SSL3_CK_EDH_RSA_DES_192_CBC3_SHA 0x03000016 + +#define SSL3_CK_ADH_RC4_40_MD5 0x03000017 +#define SSL3_CK_ADH_RC4_128_MD5 0x03000018 +#define SSL3_CK_ADH_DES_40_CBC_SHA 0x03000019 +#define SSL3_CK_ADH_DES_64_CBC_SHA 0x0300001A +#define SSL3_CK_ADH_DES_192_CBC_SHA 0x0300001B + +#define SSL3_TXT_RSA_NULL_MD5 "NULL-MD5" +#define SSL3_TXT_RSA_NULL_SHA "NULL-SHA" +#define SSL3_TXT_RSA_RC4_40_MD5 "EXP-RC4-MD5" +#define SSL3_TXT_RSA_RC4_128_MD5 "RC4-MD5" +#define SSL3_TXT_RSA_RC4_128_SHA "RC4-SHA" +#define SSL3_TXT_RSA_RC2_40_MD5 "EXP-RC2-CBC-MD5" +#define SSL3_TXT_RSA_IDEA_128_SHA "IDEA-CBC-SHA" +#define SSL3_TXT_RSA_DES_40_CBC_SHA "EXP-DES-CBC-SHA" +#define SSL3_TXT_RSA_DES_64_CBC_SHA "DES-CBC-SHA" +#define SSL3_TXT_RSA_DES_192_CBC3_SHA "DES-CBC3-SHA" + +#define SSL3_TXT_DH_DSS_DES_40_CBC_SHA "EXP-DH-DSS-DES-CBC-SHA" +#define SSL3_TXT_DH_DSS_DES_64_CBC_SHA "DH-DSS-DES-CBC-SHA" +#define SSL3_TXT_DH_DSS_DES_192_CBC3_SHA "DH-DSS-DES-CBC3-SHA" +#define SSL3_TXT_DH_RSA_DES_40_CBC_SHA "EXP-DH-RSA-DES-CBC-SHA" +#define SSL3_TXT_DH_RSA_DES_64_CBC_SHA "DH-RSA-DES-CBC-SHA" +#define SSL3_TXT_DH_RSA_DES_192_CBC3_SHA "DH-RSA-DES-CBC3-SHA" + +#define SSL3_TXT_EDH_DSS_DES_40_CBC_SHA "EXP-EDH-DSS-DES-CBC-SHA" +#define SSL3_TXT_EDH_DSS_DES_64_CBC_SHA "EDH-DSS-DES-CBC-SHA" +#define SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA "EDH-DSS-DES-CBC3-SHA" +#define SSL3_TXT_EDH_RSA_DES_40_CBC_SHA "EXP-EDH-RSA-DES-CBC-SHA" +#define SSL3_TXT_EDH_RSA_DES_64_CBC_SHA "EDH-RSA-DES-CBC-SHA" +#define SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA "EDH-RSA-DES-CBC3-SHA" + +#define SSL3_TXT_ADH_RC4_40_MD5 "EXP-ADH-RC4-MD5" +#define SSL3_TXT_ADH_RC4_128_MD5 "ADH-RC4-MD5" +#define SSL3_TXT_ADH_DES_40_CBC_SHA "EXP-ADH-DES-CBC-SHA" +#define SSL3_TXT_ADH_DES_64_CBC_SHA "ADH-DES-CBC-SHA" +#define SSL3_TXT_ADH_DES_192_CBC_SHA "ADH-DES-CBC3-SHA" + +#define SSL3_SSL_SESSION_ID_LENGTH 32 +#define SSL3_MAX_SSL_SESSION_ID_LENGTH 32 + +#define SSL3_MASTER_SECRET_SIZE 48 +#define SSL3_RANDOM_SIZE 32 +#define SSL3_SESSION_ID_SIZE 32 +#define SSL3_RT_HEADER_LENGTH 5 + +#define SSL3_HM_HEADER_LENGTH 4 + +#ifndef SSL3_ALIGN_PAYLOAD +/* Some will argue that this increases memory footprint, but it's not actually + * true. Point is that malloc has to return at least 64-bit aligned pointers, + * meaning that allocating 5 bytes wastes 3 bytes in either case. Suggested + * pre-gaping simply moves these wasted bytes from the end of allocated region + * to its front, but makes data payload aligned, which improves performance. */ +#define SSL3_ALIGN_PAYLOAD 8 +#else +#if (SSL3_ALIGN_PAYLOAD & (SSL3_ALIGN_PAYLOAD - 1)) != 0 +#error "insane SSL3_ALIGN_PAYLOAD" +#undef SSL3_ALIGN_PAYLOAD +#endif +#endif + +/* This is the maximum MAC (digest) size used by the SSL library. Currently + * maximum of 20 is used by SHA1, but we reserve for future extension for + * 512-bit hashes. */ + +#define SSL3_RT_MAX_MD_SIZE 64 + +/* Maximum block size used in all ciphersuites. Currently 16 for AES. */ + +#define SSL_RT_MAX_CIPHER_BLOCK_SIZE 16 + +/* Maximum plaintext length: defined by SSL/TLS standards */ +#define SSL3_RT_MAX_PLAIN_LENGTH 16384 +/* Maximum compression overhead: defined by SSL/TLS standards */ +#define SSL3_RT_MAX_COMPRESSED_OVERHEAD 1024 + +/* The standards give a maximum encryption overhead of 1024 bytes. In practice + * the value is lower than this. The overhead is the maximum number of padding + * bytes (256) plus the mac size. + * + * TODO(davidben): This derivation doesn't take AEADs into account, or TLS 1.1 + * explicit nonces. It happens to work because |SSL3_RT_MAX_MD_SIZE| is larger + * than necessary and no true AEAD has variable overhead in TLS 1.2. */ +#define SSL3_RT_MAX_ENCRYPTED_OVERHEAD (256 + SSL3_RT_MAX_MD_SIZE) + +/* SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD is the maximum overhead in encrypting a + * record. This does not include the record header. Some ciphers use explicit + * nonces, so it includes both the AEAD overhead as well as the nonce. */ +#define SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD \ + (EVP_AEAD_MAX_OVERHEAD + EVP_AEAD_MAX_NONCE_LENGTH) + +OPENSSL_COMPILE_ASSERT( + SSL3_RT_MAX_ENCRYPTED_OVERHEAD >= SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD, + max_overheads_are_consistent); + +/* SSL3_RT_MAX_COMPRESSED_LENGTH is an alias for + * |SSL3_RT_MAX_PLAIN_LENGTH|. Compression is gone, so don't include the + * compression overhead. */ +#define SSL3_RT_MAX_COMPRESSED_LENGTH SSL3_RT_MAX_PLAIN_LENGTH + +#define SSL3_RT_MAX_ENCRYPTED_LENGTH \ + (SSL3_RT_MAX_ENCRYPTED_OVERHEAD + SSL3_RT_MAX_COMPRESSED_LENGTH) +#define SSL3_RT_MAX_PACKET_SIZE \ + (SSL3_RT_MAX_ENCRYPTED_LENGTH + SSL3_RT_HEADER_LENGTH) + +#define SSL3_MD_CLIENT_FINISHED_CONST "\x43\x4C\x4E\x54" +#define SSL3_MD_SERVER_FINISHED_CONST "\x53\x52\x56\x52" + +#define SSL3_RT_CHANGE_CIPHER_SPEC 20 +#define SSL3_RT_ALERT 21 +#define SSL3_RT_HANDSHAKE 22 +#define SSL3_RT_APPLICATION_DATA 23 + +/* Pseudo content type for SSL/TLS header info */ +#define SSL3_RT_HEADER 0x100 + +#define SSL3_AL_WARNING 1 +#define SSL3_AL_FATAL 2 + +#define SSL3_AD_CLOSE_NOTIFY 0 +#define SSL3_AD_UNEXPECTED_MESSAGE 10 /* fatal */ +#define SSL3_AD_BAD_RECORD_MAC 20 /* fatal */ +#define SSL3_AD_DECOMPRESSION_FAILURE 30 /* fatal */ +#define SSL3_AD_HANDSHAKE_FAILURE 40 /* fatal */ +#define SSL3_AD_NO_CERTIFICATE 41 +#define SSL3_AD_BAD_CERTIFICATE 42 +#define SSL3_AD_UNSUPPORTED_CERTIFICATE 43 +#define SSL3_AD_CERTIFICATE_REVOKED 44 +#define SSL3_AD_CERTIFICATE_EXPIRED 45 +#define SSL3_AD_CERTIFICATE_UNKNOWN 46 +#define SSL3_AD_ILLEGAL_PARAMETER 47 /* fatal */ +#define SSL3_AD_INAPPROPRIATE_FALLBACK 86 /* fatal */ + +#define SSL3_CT_RSA_SIGN 1 +#define SSL3_CT_DSS_SIGN 2 +#define SSL3_CT_RSA_FIXED_DH 3 +#define SSL3_CT_DSS_FIXED_DH 4 +#define SSL3_CT_RSA_EPHEMERAL_DH 5 +#define SSL3_CT_DSS_EPHEMERAL_DH 6 +#define SSL3_CT_FORTEZZA_DMS 20 + +/* SSLv3 */ +/* client */ +/* extra state */ +#define SSL3_ST_CW_FLUSH (0x100 | SSL_ST_CONNECT) +#define SSL3_ST_FALSE_START (0x101 | SSL_ST_CONNECT) +#define SSL3_ST_VERIFY_SERVER_CERT (0x102 | SSL_ST_CONNECT) +/* write to server */ +#define SSL3_ST_CW_CLNT_HELLO_A (0x110 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CLNT_HELLO_B (0x111 | SSL_ST_CONNECT) +/* read from server */ +#define SSL3_ST_CR_SRVR_HELLO_A (0x120 | SSL_ST_CONNECT) +#define SSL3_ST_CR_SRVR_HELLO_B (0x121 | SSL_ST_CONNECT) +#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126 | SSL_ST_CONNECT) +#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B (0x127 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_A (0x130 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_B (0x131 | SSL_ST_CONNECT) +#define SSL3_ST_CR_KEY_EXCH_A (0x140 | SSL_ST_CONNECT) +#define SSL3_ST_CR_KEY_EXCH_B (0x141 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_REQ_A (0x150 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_REQ_B (0x151 | SSL_ST_CONNECT) +#define SSL3_ST_CR_SRVR_DONE_A (0x160 | SSL_ST_CONNECT) +#define SSL3_ST_CR_SRVR_DONE_B (0x161 | SSL_ST_CONNECT) +/* write to server */ +#define SSL3_ST_CW_CERT_A (0x170 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_B (0x171 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_C (0x172 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_D (0x173 | SSL_ST_CONNECT) +#define SSL3_ST_CW_KEY_EXCH_A (0x180 | SSL_ST_CONNECT) +#define SSL3_ST_CW_KEY_EXCH_B (0x181 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_VRFY_A (0x190 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_VRFY_B (0x191 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_VRFY_C (0x192 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANGE_A (0x1A0 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANGE_B (0x1A1 | SSL_ST_CONNECT) +#define SSL3_ST_CW_NEXT_PROTO_A (0x200 | SSL_ST_CONNECT) +#define SSL3_ST_CW_NEXT_PROTO_B (0x201 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANNEL_ID_A (0x220 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANNEL_ID_B (0x221 | SSL_ST_CONNECT) +#define SSL3_ST_CW_FINISHED_A (0x1B0 | SSL_ST_CONNECT) +#define SSL3_ST_CW_FINISHED_B (0x1B1 | SSL_ST_CONNECT) +/* read from server */ +#define SSL3_ST_CR_CHANGE (0x1C0 | SSL_ST_CONNECT) +#define SSL3_ST_CR_FINISHED_A (0x1D0 | SSL_ST_CONNECT) +#define SSL3_ST_CR_FINISHED_B (0x1D1 | SSL_ST_CONNECT) +#define SSL3_ST_CR_SESSION_TICKET_A (0x1E0 | SSL_ST_CONNECT) +#define SSL3_ST_CR_SESSION_TICKET_B (0x1E1 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_STATUS_A (0x1F0 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_STATUS_B (0x1F1 | SSL_ST_CONNECT) + +/* server */ +/* extra state */ +#define SSL3_ST_SW_FLUSH (0x100 | SSL_ST_ACCEPT) +/* read from client */ +#define SSL3_ST_SR_INITIAL_BYTES (0x240 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_V2_CLIENT_HELLO (0x241 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CLNT_HELLO_A (0x110 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CLNT_HELLO_B (0x111 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CLNT_HELLO_C (0x112 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CLNT_HELLO_D (0x115 | SSL_ST_ACCEPT) +/* write to client */ +#define SSL3_ST_SW_HELLO_REQ_A (0x120 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_HELLO_REQ_B (0x121 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_HELLO_REQ_C (0x122 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_HELLO_A (0x130 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_HELLO_B (0x131 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_A (0x140 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_B (0x141 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_KEY_EXCH_A (0x150 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_KEY_EXCH_B (0x151 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_KEY_EXCH_C (0x152 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_REQ_A (0x160 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_REQ_B (0x161 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_DONE_A (0x170 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_DONE_B (0x171 | SSL_ST_ACCEPT) +/* read from client */ +#define SSL3_ST_SR_CERT_A (0x180 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CERT_B (0x181 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_KEY_EXCH_A (0x190 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_KEY_EXCH_B (0x191 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_KEY_EXCH_C (0x192 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CERT_VRFY_A (0x1A0 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CERT_VRFY_B (0x1A1 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CHANGE (0x1B0 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_NEXT_PROTO_A (0x210 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_NEXT_PROTO_B (0x211 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CHANNEL_ID_A (0x230 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CHANNEL_ID_B (0x231 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_FINISHED_A (0x1C0 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_FINISHED_B (0x1C1 | SSL_ST_ACCEPT) + +/* write to client */ +#define SSL3_ST_SW_CHANGE_A (0x1D0 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CHANGE_B (0x1D1 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_FINISHED_A (0x1E0 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_FINISHED_B (0x1E1 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SESSION_TICKET_A (0x1F0 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SESSION_TICKET_B (0x1F1 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_STATUS_A (0x200 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_STATUS_B (0x201 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SUPPLEMENTAL_DATA_A (0x220 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SUPPLEMENTAL_DATA_B (0x221 | SSL_ST_ACCEPT) + +#define SSL3_MT_HELLO_REQUEST 0 +#define SSL3_MT_CLIENT_HELLO 1 +#define SSL3_MT_SERVER_HELLO 2 +#define SSL3_MT_NEWSESSION_TICKET 4 +#define SSL3_MT_CERTIFICATE 11 +#define SSL3_MT_SERVER_KEY_EXCHANGE 12 +#define SSL3_MT_CERTIFICATE_REQUEST 13 +#define SSL3_MT_SERVER_DONE 14 +#define SSL3_MT_CERTIFICATE_VERIFY 15 +#define SSL3_MT_CLIENT_KEY_EXCHANGE 16 +#define SSL3_MT_FINISHED 20 +#define SSL3_MT_CERTIFICATE_STATUS 22 +#define SSL3_MT_SUPPLEMENTAL_DATA 23 +#define SSL3_MT_NEXT_PROTO 67 +#define SSL3_MT_ENCRYPTED_EXTENSIONS 203 +#define DTLS1_MT_HELLO_VERIFY_REQUEST 3 + + +#define SSL3_MT_CCS 1 + +/* These are used when changing over to a new cipher */ +#define SSL3_CC_READ 0x01 +#define SSL3_CC_WRITE 0x02 +#define SSL3_CC_CLIENT 0x10 +#define SSL3_CC_SERVER 0x20 +#define SSL3_CHANGE_CIPHER_CLIENT_WRITE (SSL3_CC_CLIENT | SSL3_CC_WRITE) +#define SSL3_CHANGE_CIPHER_SERVER_READ (SSL3_CC_SERVER | SSL3_CC_READ) +#define SSL3_CHANGE_CIPHER_CLIENT_READ (SSL3_CC_CLIENT | SSL3_CC_READ) +#define SSL3_CHANGE_CIPHER_SERVER_WRITE (SSL3_CC_SERVER | SSL3_CC_WRITE) + + +#ifdef __cplusplus +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_SSL3_H */ diff --git a/project/jni/boringssl/include/openssl/stack.h b/project/jni/boringssl/include/openssl/stack.h new file mode 100644 index 000000000..16b9f4f66 --- /dev/null +++ b/project/jni/boringssl/include/openssl/stack.h @@ -0,0 +1,295 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_STACK_H +#define OPENSSL_HEADER_STACK_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* A stack, in OpenSSL, is an array of pointers. They are the most commonly + * used collection object. + * + * This file defines macros for type safe use of the stack functions. A stack + * of a specific type of object has type |STACK_OF(type)|. This can be defined + * (once) with |DEFINE_STACK_OF(type)| and declared where needed with + * |DECLARE_STACK_OF(type)|. For example: + * + * struct foo { + * int bar; + * }; + * + * DEFINE_STACK_OF(struct foo); + * + * Although note that the stack will contain /pointers/ to |foo|. + * + * A macro will be defined for each of the sk_* functions below. For + * STACK_OF(foo), the macros would be sk_foo_new, sk_foo_pop etc. */ + + +/* stack_cmp_func is a comparison function that returns a value < 0, 0 or > 0 + * if |*a| is less than, equal to or greater than |*b|, respectively. Note the + * extra indirection - the function is given a pointer to a pointer to the + * element. This differs from the usual qsort/bsearch comparison function. */ +typedef int (*stack_cmp_func)(const void **a, const void **b); + +/* stack_st contains an array of pointers. It is not designed to be used + * directly, rather the wrapper macros should be used. */ +typedef struct stack_st { + /* num contains the number of valid pointers in |data|. */ + size_t num; + void **data; + /* sorted is non-zero if the values pointed to by |data| are in ascending + * order, based on |comp|. */ + size_t sorted; + /* num_alloc contains the number of pointers allocated in the buffer pointed + * to by |data|, which may be larger than |num|. */ + size_t num_alloc; + /* comp is an optional comparison function. */ + stack_cmp_func comp; +} _STACK; + + +#define STACK_OF(type) struct stack_st_##type + +#define DECLARE_STACK_OF(type) STACK_OF(type); + +/* The make_macros.sh script in this directory parses the following lines and + * generates the stack_macros.h file that contains macros for the following + * types of stacks: + * + * STACK_OF:ACCESS_DESCRIPTION + * STACK_OF:ASN1_ADB_TABLE + * STACK_OF:ASN1_GENERALSTRING + * STACK_OF:ASN1_INTEGER + * STACK_OF:ASN1_OBJECT + * STACK_OF:ASN1_STRING_TABLE + * STACK_OF:ASN1_TYPE + * STACK_OF:ASN1_VALUE + * STACK_OF:BIO + * STACK_OF:BY_DIR_ENTRY + * STACK_OF:BY_DIR_HASH + * STACK_OF:CONF_VALUE + * STACK_OF:CRYPTO_EX_DATA_FUNCS + * STACK_OF:DIST_POINT + * STACK_OF:GENERAL_NAME + * STACK_OF:GENERAL_NAMES + * STACK_OF:GENERAL_SUBTREE + * STACK_OF:POLICYINFO + * STACK_OF:POLICYQUALINFO + * STACK_OF:POLICY_MAPPING + * STACK_OF:RSA_additional_prime + * STACK_OF:SSL_COMP + * STACK_OF:SSL_CUSTOM_EXTENSION + * STACK_OF:STACK_OF_X509_NAME_ENTRY + * STACK_OF:SXNETID + * STACK_OF:X509 + * STACK_OF:X509V3_EXT_METHOD + * STACK_OF:X509_ALGOR + * STACK_OF:X509_ATTRIBUTE + * STACK_OF:X509_CRL + * STACK_OF:X509_EXTENSION + * STACK_OF:X509_INFO + * STACK_OF:X509_LOOKUP + * STACK_OF:X509_NAME + * STACK_OF:X509_NAME_ENTRY + * STACK_OF:X509_OBJECT + * STACK_OF:X509_POLICY_DATA + * STACK_OF:X509_POLICY_NODE + * STACK_OF:X509_PURPOSE + * STACK_OF:X509_REVOKED + * STACK_OF:X509_TRUST + * STACK_OF:X509_VERIFY_PARAM + * STACK_OF:void + * + * Some stacks contain only const structures, so the stack should return const + * pointers to retain type-checking. + * + * CONST_STACK_OF:SRTP_PROTECTION_PROFILE + * CONST_STACK_OF:SSL_CIPHER */ + + +/* Some stacks are special because, although we would like STACK_OF(char *), + * that would actually be a stack of pointers to char*, but we just want to + * point to the string directly. In this case we call them "special" and use + * |DEFINE_SPECIAL_STACK_OF(type)| */ +#define DEFINE_SPECIAL_STACK_OF(type, inner) \ + STACK_OF(type) { _STACK special_stack; }; \ + OPENSSL_COMPILE_ASSERT(sizeof(type) == sizeof(void *), \ + special_stack_of_non_pointer_##type); + +typedef char *OPENSSL_STRING; + +DEFINE_SPECIAL_STACK_OF(OPENSSL_STRING, char) +DEFINE_SPECIAL_STACK_OF(OPENSSL_BLOCK, uint8_t) + +/* The make_macros.sh script in this directory parses the following lines and + * generates the stack_macros.h file that contains macros for the following + * types of stacks: + * + * SPECIAL_STACK_OF:OPENSSL_STRING + * SPECIAL_STACK_OF:OPENSSL_BLOCK */ + +#define IN_STACK_H +#include +#undef IN_STACK_H + + +/* These are the raw stack functions, you shouldn't be using them. Rather you + * should be using the type stack macros implemented above. */ + +/* sk_new creates a new, empty stack with the given comparison function, which + * may be zero. It returns the new stack or NULL on allocation failure. */ +OPENSSL_EXPORT _STACK *sk_new(stack_cmp_func comp); + +/* sk_new_null creates a new, empty stack. It returns the new stack or NULL on + * allocation failure. */ +OPENSSL_EXPORT _STACK *sk_new_null(void); + +/* sk_num returns the number of elements in |s|. */ +OPENSSL_EXPORT size_t sk_num(const _STACK *sk); + +/* sk_zero resets |sk| to the empty state but does nothing to free the + * individual elements themselves. */ +OPENSSL_EXPORT void sk_zero(_STACK *sk); + +/* sk_value returns the |i|th pointer in |sk|, or NULL if |i| is out of + * range. */ +OPENSSL_EXPORT void *sk_value(const _STACK *sk, size_t i); + +/* sk_set sets the |i|th pointer in |sk| to |p| and returns |p|. If |i| is out + * of range, it returns NULL. */ +OPENSSL_EXPORT void *sk_set(_STACK *sk, size_t i, void *p); + +/* sk_free frees the given stack and array of pointers, but does nothing to + * free the individual elements. Also see |sk_pop_free|. */ +OPENSSL_EXPORT void sk_free(_STACK *sk); + +/* sk_pop_free calls |free_func| on each element in the stack and then frees + * the stack itself. */ +OPENSSL_EXPORT void sk_pop_free(_STACK *sk, void (*free_func)(void *)); + +/* sk_insert inserts |p| into the stack at index |where|, moving existing + * elements if needed. It returns the length of the new stack, or zero on + * error. */ +OPENSSL_EXPORT size_t sk_insert(_STACK *sk, void *p, size_t where); + +/* sk_delete removes the pointer at index |where|, moving other elements down + * if needed. It returns the removed pointer, or NULL if |where| is out of + * range. */ +OPENSSL_EXPORT void *sk_delete(_STACK *sk, size_t where); + +/* sk_delete_ptr removes, at most, one instance of |p| from the stack based on + * pointer equality. If an instance of |p| is found then |p| is returned, + * otherwise it returns NULL. */ +OPENSSL_EXPORT void *sk_delete_ptr(_STACK *sk, void *p); + +/* sk_find returns the first value in the stack equal to |p|. If a comparison + * function has been set on the stack, then equality is defined by it and the + * stack will be sorted if need be so that a binary search can be used. + * Otherwise pointer equality is used. If a matching element is found, its + * index is written to |*out_index| (if |out_index| is not NULL) and one is + * returned. Otherwise zero is returned. */ +OPENSSL_EXPORT int sk_find(_STACK *sk, size_t *out_index, void *p); + +/* sk_shift removes and returns the first element in the stack, or returns NULL + * if the stack is empty. */ +OPENSSL_EXPORT void *sk_shift(_STACK *sk); + +/* sk_push appends |p| to the stack and returns the length of the new stack, or + * 0 on allocation failure. */ +OPENSSL_EXPORT size_t sk_push(_STACK *sk, void *p); + +/* sk_pop returns and removes the last element on the stack, or NULL if the + * stack is empty. */ +OPENSSL_EXPORT void *sk_pop(_STACK *sk); + +/* sk_dup performs a shallow copy of a stack and returns the new stack, or NULL + * on error. */ +OPENSSL_EXPORT _STACK *sk_dup(const _STACK *sk); + +/* sk_sort sorts the elements of |sk| into ascending order based on the + * comparison function. The stack maintains a |sorted| flag and sorting an + * already sorted stack is a no-op. */ +OPENSSL_EXPORT void sk_sort(_STACK *sk); + +/* sk_is_sorted returns one if |sk| is known to be sorted and zero + * otherwise. */ +OPENSSL_EXPORT int sk_is_sorted(const _STACK *sk); + +/* sk_set_cmp_func sets the comparison function to be used by |sk| and returns + * the previous one. */ +OPENSSL_EXPORT stack_cmp_func sk_set_cmp_func(_STACK *sk, stack_cmp_func comp); + +/* sk_deep_copy performs a copy of |sk| and of each of the non-NULL elements in + * |sk| by using |copy_func|. If an error occurs, |free_func| is used to free + * any copies already made and NULL is returned. */ +OPENSSL_EXPORT _STACK *sk_deep_copy(const _STACK *sk, + void *(*copy_func)(void *), + void (*free_func)(void *)); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_STACK_H */ diff --git a/project/jni/boringssl/include/openssl/stack_macros.h b/project/jni/boringssl/include/openssl/stack_macros.h new file mode 100644 index 000000000..809424c72 --- /dev/null +++ b/project/jni/boringssl/include/openssl/stack_macros.h @@ -0,0 +1,3934 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#if !defined(IN_STACK_H) +#error "Don't include this file directly. Include stack.h." +#endif + +/* ACCESS_DESCRIPTION */ +#define sk_ACCESS_DESCRIPTION_new(comp) \ + ((STACK_OF(ACCESS_DESCRIPTION) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const ACCESS_DESCRIPTION **a, const ACCESS_DESCRIPTION **b), \ + comp))) + +#define sk_ACCESS_DESCRIPTION_new_null() \ + ((STACK_OF(ACCESS_DESCRIPTION) *)sk_new_null()) + +#define sk_ACCESS_DESCRIPTION_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)) + +#define sk_ACCESS_DESCRIPTION_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)); + +#define sk_ACCESS_DESCRIPTION_value(sk, i) \ + ((ACCESS_DESCRIPTION *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk), (i))) + +#define sk_ACCESS_DESCRIPTION_set(sk, i, p) \ + ((ACCESS_DESCRIPTION *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), (i), \ + CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p))) + +#define sk_ACCESS_DESCRIPTION_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)) + +#define sk_ACCESS_DESCRIPTION_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ACCESS_DESCRIPTION *), \ + free_func)) + +#define sk_ACCESS_DESCRIPTION_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p), (where)) + +#define sk_ACCESS_DESCRIPTION_delete(sk, where) \ + ((ACCESS_DESCRIPTION *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), (where))) + +#define sk_ACCESS_DESCRIPTION_delete_ptr(sk, p) \ + ((ACCESS_DESCRIPTION *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p))) + +#define sk_ACCESS_DESCRIPTION_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + (out_index), CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p)) + +#define sk_ACCESS_DESCRIPTION_shift(sk) \ + ((ACCESS_DESCRIPTION *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk))) + +#define sk_ACCESS_DESCRIPTION_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p)) + +#define sk_ACCESS_DESCRIPTION_pop(sk) \ + ((ACCESS_DESCRIPTION *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk))) + +#define sk_ACCESS_DESCRIPTION_dup(sk) \ + ((STACK_OF(ACCESS_DESCRIPTION) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk))) + +#define sk_ACCESS_DESCRIPTION_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)) + +#define sk_ACCESS_DESCRIPTION_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk)) + +#define sk_ACCESS_DESCRIPTION_set_cmp_func(sk, comp) \ + ((int (*)(const ACCESS_DESCRIPTION **a, const ACCESS_DESCRIPTION **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const ACCESS_DESCRIPTION **a, \ + const ACCESS_DESCRIPTION **b), \ + comp))) + +#define sk_ACCESS_DESCRIPTION_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ACCESS_DESCRIPTION) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + ACCESS_DESCRIPTION *(*)(ACCESS_DESCRIPTION *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ACCESS_DESCRIPTION *), \ + free_func))) + +/* ASN1_ADB_TABLE */ +#define sk_ASN1_ADB_TABLE_new(comp) \ + ((STACK_OF(ASN1_ADB_TABLE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const ASN1_ADB_TABLE **a, const ASN1_ADB_TABLE **b), comp))) + +#define sk_ASN1_ADB_TABLE_new_null() ((STACK_OF(ASN1_ADB_TABLE) *)sk_new_null()) + +#define sk_ASN1_ADB_TABLE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)) + +#define sk_ASN1_ADB_TABLE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)); + +#define sk_ASN1_ADB_TABLE_value(sk, i) \ + ((ASN1_ADB_TABLE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk), (i))) + +#define sk_ASN1_ADB_TABLE_set(sk, i, p) \ + ((ASN1_ADB_TABLE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), (i), \ + CHECKED_CAST(void *, ASN1_ADB_TABLE *, p))) + +#define sk_ASN1_ADB_TABLE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)) + +#define sk_ASN1_ADB_TABLE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_ADB_TABLE *), free_func)) + +#define sk_ASN1_ADB_TABLE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_ADB_TABLE *, p), (where)) + +#define sk_ASN1_ADB_TABLE_delete(sk, where) \ + ((ASN1_ADB_TABLE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), (where))) + +#define sk_ASN1_ADB_TABLE_delete_ptr(sk, p) \ + ((ASN1_ADB_TABLE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_ADB_TABLE *, p))) + +#define sk_ASN1_ADB_TABLE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), (out_index), \ + CHECKED_CAST(void *, ASN1_ADB_TABLE *, p)) + +#define sk_ASN1_ADB_TABLE_shift(sk) \ + ((ASN1_ADB_TABLE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk))) + +#define sk_ASN1_ADB_TABLE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_ADB_TABLE *, p)) + +#define sk_ASN1_ADB_TABLE_pop(sk) \ + ((ASN1_ADB_TABLE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk))) + +#define sk_ASN1_ADB_TABLE_dup(sk) \ + ((STACK_OF(ASN1_ADB_TABLE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk))) + +#define sk_ASN1_ADB_TABLE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)) + +#define sk_ASN1_ADB_TABLE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk)) + +#define sk_ASN1_ADB_TABLE_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_ADB_TABLE **a, const ASN1_ADB_TABLE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const ASN1_ADB_TABLE **a, \ + const ASN1_ADB_TABLE **b), \ + comp))) + +#define sk_ASN1_ADB_TABLE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_ADB_TABLE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(void *(*)(void *), ASN1_ADB_TABLE *(*)(ASN1_ADB_TABLE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_ADB_TABLE *), free_func))) + +/* ASN1_GENERALSTRING */ +#define sk_ASN1_GENERALSTRING_new(comp) \ + ((STACK_OF(ASN1_GENERALSTRING) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const ASN1_GENERALSTRING **a, const ASN1_GENERALSTRING **b), \ + comp))) + +#define sk_ASN1_GENERALSTRING_new_null() \ + ((STACK_OF(ASN1_GENERALSTRING) *)sk_new_null()) + +#define sk_ASN1_GENERALSTRING_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)) + +#define sk_ASN1_GENERALSTRING_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)); + +#define sk_ASN1_GENERALSTRING_value(sk, i) \ + ((ASN1_GENERALSTRING *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk), (i))) + +#define sk_ASN1_GENERALSTRING_set(sk, i, p) \ + ((ASN1_GENERALSTRING *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), (i), \ + CHECKED_CAST(void *, ASN1_GENERALSTRING *, p))) + +#define sk_ASN1_GENERALSTRING_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)) + +#define sk_ASN1_GENERALSTRING_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_GENERALSTRING *), \ + free_func)) + +#define sk_ASN1_GENERALSTRING_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(void *, ASN1_GENERALSTRING *, p), (where)) + +#define sk_ASN1_GENERALSTRING_delete(sk, where) \ + ((ASN1_GENERALSTRING *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), (where))) + +#define sk_ASN1_GENERALSTRING_delete_ptr(sk, p) \ + ((ASN1_GENERALSTRING *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(void *, ASN1_GENERALSTRING *, p))) + +#define sk_ASN1_GENERALSTRING_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + (out_index), CHECKED_CAST(void *, ASN1_GENERALSTRING *, p)) + +#define sk_ASN1_GENERALSTRING_shift(sk) \ + ((ASN1_GENERALSTRING *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk))) + +#define sk_ASN1_GENERALSTRING_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(void *, ASN1_GENERALSTRING *, p)) + +#define sk_ASN1_GENERALSTRING_pop(sk) \ + ((ASN1_GENERALSTRING *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk))) + +#define sk_ASN1_GENERALSTRING_dup(sk) \ + ((STACK_OF(ASN1_GENERALSTRING) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk))) + +#define sk_ASN1_GENERALSTRING_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)) + +#define sk_ASN1_GENERALSTRING_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk)) + +#define sk_ASN1_GENERALSTRING_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_GENERALSTRING **a, const ASN1_GENERALSTRING **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const ASN1_GENERALSTRING **a, \ + const ASN1_GENERALSTRING **b), \ + comp))) + +#define sk_ASN1_GENERALSTRING_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_GENERALSTRING) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + ASN1_GENERALSTRING *(*)(ASN1_GENERALSTRING *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_GENERALSTRING *), \ + free_func))) + +/* ASN1_INTEGER */ +#define sk_ASN1_INTEGER_new(comp) \ + ((STACK_OF(ASN1_INTEGER) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const ASN1_INTEGER **a, const ASN1_INTEGER **b), \ + comp))) + +#define sk_ASN1_INTEGER_new_null() ((STACK_OF(ASN1_INTEGER) *)sk_new_null()) + +#define sk_ASN1_INTEGER_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)) + +#define sk_ASN1_INTEGER_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)); + +#define sk_ASN1_INTEGER_value(sk, i) \ + ((ASN1_INTEGER *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_INTEGER) *, sk), (i))) + +#define sk_ASN1_INTEGER_set(sk, i, p) \ + ((ASN1_INTEGER *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), (i), \ + CHECKED_CAST(void *, ASN1_INTEGER *, p))) + +#define sk_ASN1_INTEGER_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)) + +#define sk_ASN1_INTEGER_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_INTEGER *), free_func)) + +#define sk_ASN1_INTEGER_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(void *, ASN1_INTEGER *, p), (where)) + +#define sk_ASN1_INTEGER_delete(sk, where) \ + ((ASN1_INTEGER *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), (where))) + +#define sk_ASN1_INTEGER_delete_ptr(sk, p) \ + ((ASN1_INTEGER *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(void *, ASN1_INTEGER *, p))) + +#define sk_ASN1_INTEGER_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), (out_index), \ + CHECKED_CAST(void *, ASN1_INTEGER *, p)) + +#define sk_ASN1_INTEGER_shift(sk) \ + ((ASN1_INTEGER *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk))) + +#define sk_ASN1_INTEGER_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(void *, ASN1_INTEGER *, p)) + +#define sk_ASN1_INTEGER_pop(sk) \ + ((ASN1_INTEGER *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk))) + +#define sk_ASN1_INTEGER_dup(sk) \ + ((STACK_OF(ASN1_INTEGER) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_INTEGER) *, sk))) + +#define sk_ASN1_INTEGER_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)) + +#define sk_ASN1_INTEGER_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_INTEGER) *, sk)) + +#define sk_ASN1_INTEGER_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_INTEGER **a, const ASN1_INTEGER **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const ASN1_INTEGER **a, const ASN1_INTEGER **b), \ + comp))) + +#define sk_ASN1_INTEGER_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_INTEGER) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(void *(*)(void *), ASN1_INTEGER *(*)(ASN1_INTEGER *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_INTEGER *), free_func))) + +/* ASN1_OBJECT */ +#define sk_ASN1_OBJECT_new(comp) \ + ((STACK_OF(ASN1_OBJECT) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const ASN1_OBJECT **a, const ASN1_OBJECT **b), \ + comp))) + +#define sk_ASN1_OBJECT_new_null() ((STACK_OF(ASN1_OBJECT) *)sk_new_null()) + +#define sk_ASN1_OBJECT_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)) + +#define sk_ASN1_OBJECT_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)); + +#define sk_ASN1_OBJECT_value(sk, i) \ + ((ASN1_OBJECT *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_OBJECT) *, sk), (i))) + +#define sk_ASN1_OBJECT_set(sk, i, p) \ + ((ASN1_OBJECT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + (i), CHECKED_CAST(void *, ASN1_OBJECT *, p))) + +#define sk_ASN1_OBJECT_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)) + +#define sk_ASN1_OBJECT_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_OBJECT *), free_func)) + +#define sk_ASN1_OBJECT_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(void *, ASN1_OBJECT *, p), (where)) + +#define sk_ASN1_OBJECT_delete(sk, where) \ + ((ASN1_OBJECT *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), (where))) + +#define sk_ASN1_OBJECT_delete_ptr(sk, p) \ + ((ASN1_OBJECT *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(void *, ASN1_OBJECT *, p))) + +#define sk_ASN1_OBJECT_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), (out_index), \ + CHECKED_CAST(void *, ASN1_OBJECT *, p)) + +#define sk_ASN1_OBJECT_shift(sk) \ + ((ASN1_OBJECT *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk))) + +#define sk_ASN1_OBJECT_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(void *, ASN1_OBJECT *, p)) + +#define sk_ASN1_OBJECT_pop(sk) \ + ((ASN1_OBJECT *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk))) + +#define sk_ASN1_OBJECT_dup(sk) \ + ((STACK_OF(ASN1_OBJECT) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_OBJECT) *, sk))) + +#define sk_ASN1_OBJECT_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)) + +#define sk_ASN1_OBJECT_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_OBJECT) *, sk)) + +#define sk_ASN1_OBJECT_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_OBJECT **a, const ASN1_OBJECT **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const ASN1_OBJECT **a, const ASN1_OBJECT **b), \ + comp))) + +#define sk_ASN1_OBJECT_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_OBJECT) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(void *(*)(void *), ASN1_OBJECT *(*)(ASN1_OBJECT *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_OBJECT *), free_func))) + +/* ASN1_STRING_TABLE */ +#define sk_ASN1_STRING_TABLE_new(comp) \ + ((STACK_OF(ASN1_STRING_TABLE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const ASN1_STRING_TABLE **a, const ASN1_STRING_TABLE **b), \ + comp))) + +#define sk_ASN1_STRING_TABLE_new_null() \ + ((STACK_OF(ASN1_STRING_TABLE) *)sk_new_null()) + +#define sk_ASN1_STRING_TABLE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)) + +#define sk_ASN1_STRING_TABLE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)); + +#define sk_ASN1_STRING_TABLE_value(sk, i) \ + ((ASN1_STRING_TABLE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk), (i))) + +#define sk_ASN1_STRING_TABLE_set(sk, i, p) \ + ((ASN1_STRING_TABLE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), (i), \ + CHECKED_CAST(void *, ASN1_STRING_TABLE *, p))) + +#define sk_ASN1_STRING_TABLE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)) + +#define sk_ASN1_STRING_TABLE_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_STRING_TABLE *), \ + free_func)) + +#define sk_ASN1_STRING_TABLE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_STRING_TABLE *, p), (where)) + +#define sk_ASN1_STRING_TABLE_delete(sk, where) \ + ((ASN1_STRING_TABLE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), (where))) + +#define sk_ASN1_STRING_TABLE_delete_ptr(sk, p) \ + ((ASN1_STRING_TABLE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_STRING_TABLE *, p))) + +#define sk_ASN1_STRING_TABLE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + (out_index), CHECKED_CAST(void *, ASN1_STRING_TABLE *, p)) + +#define sk_ASN1_STRING_TABLE_shift(sk) \ + ((ASN1_STRING_TABLE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk))) + +#define sk_ASN1_STRING_TABLE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_STRING_TABLE *, p)) + +#define sk_ASN1_STRING_TABLE_pop(sk) \ + ((ASN1_STRING_TABLE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk))) + +#define sk_ASN1_STRING_TABLE_dup(sk) \ + ((STACK_OF(ASN1_STRING_TABLE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk))) + +#define sk_ASN1_STRING_TABLE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)) + +#define sk_ASN1_STRING_TABLE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk)) + +#define sk_ASN1_STRING_TABLE_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_STRING_TABLE **a, const ASN1_STRING_TABLE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const ASN1_STRING_TABLE **a, \ + const ASN1_STRING_TABLE **b), \ + comp))) + +#define sk_ASN1_STRING_TABLE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_STRING_TABLE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + ASN1_STRING_TABLE *(*)(ASN1_STRING_TABLE *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_STRING_TABLE *), \ + free_func))) + +/* ASN1_TYPE */ +#define sk_ASN1_TYPE_new(comp) \ + ((STACK_OF(ASN1_TYPE) *)sk_new( \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const ASN1_TYPE **a, const ASN1_TYPE **b), comp))) + +#define sk_ASN1_TYPE_new_null() ((STACK_OF(ASN1_TYPE) *)sk_new_null()) + +#define sk_ASN1_TYPE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)) + +#define sk_ASN1_TYPE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)); + +#define sk_ASN1_TYPE_value(sk, i) \ + ((ASN1_TYPE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_TYPE) *, sk), (i))) + +#define sk_ASN1_TYPE_set(sk, i, p) \ + ((ASN1_TYPE *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), (i), \ + CHECKED_CAST(void *, ASN1_TYPE *, p))) + +#define sk_ASN1_TYPE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)) + +#define sk_ASN1_TYPE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_TYPE *), free_func)) + +#define sk_ASN1_TYPE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(void *, ASN1_TYPE *, p), (where)) + +#define sk_ASN1_TYPE_delete(sk, where) \ + ((ASN1_TYPE *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + (where))) + +#define sk_ASN1_TYPE_delete_ptr(sk, p) \ + ((ASN1_TYPE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(void *, ASN1_TYPE *, p))) + +#define sk_ASN1_TYPE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), (out_index), \ + CHECKED_CAST(void *, ASN1_TYPE *, p)) + +#define sk_ASN1_TYPE_shift(sk) \ + ((ASN1_TYPE *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk))) + +#define sk_ASN1_TYPE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(void *, ASN1_TYPE *, p)) + +#define sk_ASN1_TYPE_pop(sk) \ + ((ASN1_TYPE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk))) + +#define sk_ASN1_TYPE_dup(sk) \ + ((STACK_OF(ASN1_TYPE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_TYPE) *, sk))) + +#define sk_ASN1_TYPE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)) + +#define sk_ASN1_TYPE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_TYPE) *, sk)) + +#define sk_ASN1_TYPE_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_TYPE **a, const ASN1_TYPE **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const ASN1_TYPE **a, const ASN1_TYPE **b), comp))) + +#define sk_ASN1_TYPE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_TYPE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(void *(*)(void *), ASN1_TYPE *(*)(ASN1_TYPE *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_TYPE *), free_func))) + +/* ASN1_VALUE */ +#define sk_ASN1_VALUE_new(comp) \ + ((STACK_OF(ASN1_VALUE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const ASN1_VALUE **a, const ASN1_VALUE **b), \ + comp))) + +#define sk_ASN1_VALUE_new_null() ((STACK_OF(ASN1_VALUE) *)sk_new_null()) + +#define sk_ASN1_VALUE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)) + +#define sk_ASN1_VALUE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)); + +#define sk_ASN1_VALUE_value(sk, i) \ + ((ASN1_VALUE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_VALUE) *, sk), (i))) + +#define sk_ASN1_VALUE_set(sk, i, p) \ + ((ASN1_VALUE *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + (i), CHECKED_CAST(void *, ASN1_VALUE *, p))) + +#define sk_ASN1_VALUE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)) + +#define sk_ASN1_VALUE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_VALUE *), free_func)) + +#define sk_ASN1_VALUE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(void *, ASN1_VALUE *, p), (where)) + +#define sk_ASN1_VALUE_delete(sk, where) \ + ((ASN1_VALUE *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + (where))) + +#define sk_ASN1_VALUE_delete_ptr(sk, p) \ + ((ASN1_VALUE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(void *, ASN1_VALUE *, p))) + +#define sk_ASN1_VALUE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), (out_index), \ + CHECKED_CAST(void *, ASN1_VALUE *, p)) + +#define sk_ASN1_VALUE_shift(sk) \ + ((ASN1_VALUE *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk))) + +#define sk_ASN1_VALUE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(void *, ASN1_VALUE *, p)) + +#define sk_ASN1_VALUE_pop(sk) \ + ((ASN1_VALUE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk))) + +#define sk_ASN1_VALUE_dup(sk) \ + ((STACK_OF(ASN1_VALUE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_VALUE) *, sk))) + +#define sk_ASN1_VALUE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)) + +#define sk_ASN1_VALUE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_VALUE) *, sk)) + +#define sk_ASN1_VALUE_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_VALUE **a, const ASN1_VALUE **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const ASN1_VALUE **a, const ASN1_VALUE **b), \ + comp))) + +#define sk_ASN1_VALUE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_VALUE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(void *(*)(void *), ASN1_VALUE *(*)(ASN1_VALUE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_VALUE *), free_func))) + +/* BIO */ +#define sk_BIO_new(comp) \ + ((STACK_OF(BIO) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const BIO **a, const BIO **b), comp))) + +#define sk_BIO_new_null() ((STACK_OF(BIO) *)sk_new_null()) + +#define sk_BIO_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)) + +#define sk_BIO_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)); + +#define sk_BIO_value(sk, i) \ + ((BIO *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(BIO) *, sk), (i))) + +#define sk_BIO_set(sk, i, p) \ + ((BIO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), (i), \ + CHECKED_CAST(void *, BIO *, p))) + +#define sk_BIO_free(sk) sk_free(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)) + +#define sk_BIO_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(BIO *), free_func)) + +#define sk_BIO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \ + CHECKED_CAST(void *, BIO *, p), (where)) + +#define sk_BIO_delete(sk, where) \ + ((BIO *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), (where))) + +#define sk_BIO_delete_ptr(sk, p) \ + ((BIO *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \ + CHECKED_CAST(void *, BIO *, p))) + +#define sk_BIO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), (out_index), \ + CHECKED_CAST(void *, BIO *, p)) + +#define sk_BIO_shift(sk) \ + ((BIO *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk))) + +#define sk_BIO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \ + CHECKED_CAST(void *, BIO *, p)) + +#define sk_BIO_pop(sk) \ + ((BIO *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk))) + +#define sk_BIO_dup(sk) \ + ((STACK_OF(BIO) *)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(BIO) *, sk))) + +#define sk_BIO_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)) + +#define sk_BIO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(BIO) *, sk)) + +#define sk_BIO_set_cmp_func(sk, comp) \ + ((int (*)(const BIO **a, const BIO **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const BIO **a, const BIO **b), \ + comp))) + +#define sk_BIO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(BIO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(BIO) *, sk), \ + CHECKED_CAST(void *(*)(void *), BIO *(*)(BIO *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(BIO *), free_func))) + +/* BY_DIR_ENTRY */ +#define sk_BY_DIR_ENTRY_new(comp) \ + ((STACK_OF(BY_DIR_ENTRY) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const BY_DIR_ENTRY **a, const BY_DIR_ENTRY **b), \ + comp))) + +#define sk_BY_DIR_ENTRY_new_null() ((STACK_OF(BY_DIR_ENTRY) *)sk_new_null()) + +#define sk_BY_DIR_ENTRY_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)) + +#define sk_BY_DIR_ENTRY_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)); + +#define sk_BY_DIR_ENTRY_value(sk, i) \ + ((BY_DIR_ENTRY *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk), (i))) + +#define sk_BY_DIR_ENTRY_set(sk, i, p) \ + ((BY_DIR_ENTRY *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), (i), \ + CHECKED_CAST(void *, BY_DIR_ENTRY *, p))) + +#define sk_BY_DIR_ENTRY_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)) + +#define sk_BY_DIR_ENTRY_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_ENTRY *), free_func)) + +#define sk_BY_DIR_ENTRY_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(void *, BY_DIR_ENTRY *, p), (where)) + +#define sk_BY_DIR_ENTRY_delete(sk, where) \ + ((BY_DIR_ENTRY *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), (where))) + +#define sk_BY_DIR_ENTRY_delete_ptr(sk, p) \ + ((BY_DIR_ENTRY *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(void *, BY_DIR_ENTRY *, p))) + +#define sk_BY_DIR_ENTRY_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), (out_index), \ + CHECKED_CAST(void *, BY_DIR_ENTRY *, p)) + +#define sk_BY_DIR_ENTRY_shift(sk) \ + ((BY_DIR_ENTRY *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk))) + +#define sk_BY_DIR_ENTRY_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(void *, BY_DIR_ENTRY *, p)) + +#define sk_BY_DIR_ENTRY_pop(sk) \ + ((BY_DIR_ENTRY *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk))) + +#define sk_BY_DIR_ENTRY_dup(sk) \ + ((STACK_OF(BY_DIR_ENTRY) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk))) + +#define sk_BY_DIR_ENTRY_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)) + +#define sk_BY_DIR_ENTRY_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk)) + +#define sk_BY_DIR_ENTRY_set_cmp_func(sk, comp) \ + ((int (*)(const BY_DIR_ENTRY **a, const BY_DIR_ENTRY **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const BY_DIR_ENTRY **a, const BY_DIR_ENTRY **b), \ + comp))) + +#define sk_BY_DIR_ENTRY_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(BY_DIR_ENTRY) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(void *(*)(void *), BY_DIR_ENTRY *(*)(BY_DIR_ENTRY *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_ENTRY *), free_func))) + +/* BY_DIR_HASH */ +#define sk_BY_DIR_HASH_new(comp) \ + ((STACK_OF(BY_DIR_HASH) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const BY_DIR_HASH **a, const BY_DIR_HASH **b), \ + comp))) + +#define sk_BY_DIR_HASH_new_null() ((STACK_OF(BY_DIR_HASH) *)sk_new_null()) + +#define sk_BY_DIR_HASH_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)) + +#define sk_BY_DIR_HASH_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)); + +#define sk_BY_DIR_HASH_value(sk, i) \ + ((BY_DIR_HASH *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_HASH) *, sk), (i))) + +#define sk_BY_DIR_HASH_set(sk, i, p) \ + ((BY_DIR_HASH *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + (i), CHECKED_CAST(void *, BY_DIR_HASH *, p))) + +#define sk_BY_DIR_HASH_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)) + +#define sk_BY_DIR_HASH_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_HASH *), free_func)) + +#define sk_BY_DIR_HASH_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(void *, BY_DIR_HASH *, p), (where)) + +#define sk_BY_DIR_HASH_delete(sk, where) \ + ((BY_DIR_HASH *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), (where))) + +#define sk_BY_DIR_HASH_delete_ptr(sk, p) \ + ((BY_DIR_HASH *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(void *, BY_DIR_HASH *, p))) + +#define sk_BY_DIR_HASH_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), (out_index), \ + CHECKED_CAST(void *, BY_DIR_HASH *, p)) + +#define sk_BY_DIR_HASH_shift(sk) \ + ((BY_DIR_HASH *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk))) + +#define sk_BY_DIR_HASH_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(void *, BY_DIR_HASH *, p)) + +#define sk_BY_DIR_HASH_pop(sk) \ + ((BY_DIR_HASH *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk))) + +#define sk_BY_DIR_HASH_dup(sk) \ + ((STACK_OF(BY_DIR_HASH) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_HASH) *, sk))) + +#define sk_BY_DIR_HASH_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)) + +#define sk_BY_DIR_HASH_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_HASH) *, sk)) + +#define sk_BY_DIR_HASH_set_cmp_func(sk, comp) \ + ((int (*)(const BY_DIR_HASH **a, const BY_DIR_HASH **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const BY_DIR_HASH **a, const BY_DIR_HASH **b), \ + comp))) + +#define sk_BY_DIR_HASH_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(BY_DIR_HASH) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(void *(*)(void *), BY_DIR_HASH *(*)(BY_DIR_HASH *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_HASH *), free_func))) + +/* CONF_VALUE */ +#define sk_CONF_VALUE_new(comp) \ + ((STACK_OF(CONF_VALUE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const CONF_VALUE **a, const CONF_VALUE **b), \ + comp))) + +#define sk_CONF_VALUE_new_null() ((STACK_OF(CONF_VALUE) *)sk_new_null()) + +#define sk_CONF_VALUE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)) + +#define sk_CONF_VALUE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)); + +#define sk_CONF_VALUE_value(sk, i) \ + ((CONF_VALUE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(CONF_VALUE) *, sk), (i))) + +#define sk_CONF_VALUE_set(sk, i, p) \ + ((CONF_VALUE *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + (i), CHECKED_CAST(void *, CONF_VALUE *, p))) + +#define sk_CONF_VALUE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)) + +#define sk_CONF_VALUE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(CONF_VALUE *), free_func)) + +#define sk_CONF_VALUE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(void *, CONF_VALUE *, p), (where)) + +#define sk_CONF_VALUE_delete(sk, where) \ + ((CONF_VALUE *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + (where))) + +#define sk_CONF_VALUE_delete_ptr(sk, p) \ + ((CONF_VALUE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(void *, CONF_VALUE *, p))) + +#define sk_CONF_VALUE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), (out_index), \ + CHECKED_CAST(void *, CONF_VALUE *, p)) + +#define sk_CONF_VALUE_shift(sk) \ + ((CONF_VALUE *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk))) + +#define sk_CONF_VALUE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(void *, CONF_VALUE *, p)) + +#define sk_CONF_VALUE_pop(sk) \ + ((CONF_VALUE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk))) + +#define sk_CONF_VALUE_dup(sk) \ + ((STACK_OF(CONF_VALUE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(CONF_VALUE) *, sk))) + +#define sk_CONF_VALUE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)) + +#define sk_CONF_VALUE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(CONF_VALUE) *, sk)) + +#define sk_CONF_VALUE_set_cmp_func(sk, comp) \ + ((int (*)(const CONF_VALUE **a, const CONF_VALUE **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const CONF_VALUE **a, const CONF_VALUE **b), \ + comp))) + +#define sk_CONF_VALUE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(CONF_VALUE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(void *(*)(void *), CONF_VALUE *(*)(CONF_VALUE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(CONF_VALUE *), free_func))) + +/* CRYPTO_EX_DATA_FUNCS */ +#define sk_CRYPTO_EX_DATA_FUNCS_new(comp) \ + ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const CRYPTO_EX_DATA_FUNCS **a, const CRYPTO_EX_DATA_FUNCS **b), \ + comp))) + +#define sk_CRYPTO_EX_DATA_FUNCS_new_null() \ + ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_new_null()) + +#define sk_CRYPTO_EX_DATA_FUNCS_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) + +#define sk_CRYPTO_EX_DATA_FUNCS_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)); + +#define sk_CRYPTO_EX_DATA_FUNCS_value(sk, i) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + (i))) + +#define sk_CRYPTO_EX_DATA_FUNCS_set(sk, i, p) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), (i), \ + CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p))) + +#define sk_CRYPTO_EX_DATA_FUNCS_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) + +#define sk_CRYPTO_EX_DATA_FUNCS_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_EX_DATA_FUNCS *), \ + free_func)) + +#define sk_CRYPTO_EX_DATA_FUNCS_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p), (where)) + +#define sk_CRYPTO_EX_DATA_FUNCS_delete(sk, where) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), (where))) + +#define sk_CRYPTO_EX_DATA_FUNCS_delete_ptr(sk, p) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p))) + +#define sk_CRYPTO_EX_DATA_FUNCS_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + (out_index), CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p)) + +#define sk_CRYPTO_EX_DATA_FUNCS_shift(sk) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))) + +#define sk_CRYPTO_EX_DATA_FUNCS_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p)) + +#define sk_CRYPTO_EX_DATA_FUNCS_pop(sk) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))) + +#define sk_CRYPTO_EX_DATA_FUNCS_dup(sk) \ + ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))) + +#define sk_CRYPTO_EX_DATA_FUNCS_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) + +#define sk_CRYPTO_EX_DATA_FUNCS_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(_STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) + +#define sk_CRYPTO_EX_DATA_FUNCS_set_cmp_func(sk, comp) \ + ((int (*)(const CRYPTO_EX_DATA_FUNCS **a, const CRYPTO_EX_DATA_FUNCS **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const CRYPTO_EX_DATA_FUNCS **a, \ + const CRYPTO_EX_DATA_FUNCS **b), \ + comp))) + +#define sk_CRYPTO_EX_DATA_FUNCS_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, \ + sk), \ + CHECKED_CAST(void *(*)(void *), \ + CRYPTO_EX_DATA_FUNCS *(*)(CRYPTO_EX_DATA_FUNCS *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_EX_DATA_FUNCS *), \ + free_func))) + +/* DIST_POINT */ +#define sk_DIST_POINT_new(comp) \ + ((STACK_OF(DIST_POINT) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const DIST_POINT **a, const DIST_POINT **b), \ + comp))) + +#define sk_DIST_POINT_new_null() ((STACK_OF(DIST_POINT) *)sk_new_null()) + +#define sk_DIST_POINT_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)) + +#define sk_DIST_POINT_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)); + +#define sk_DIST_POINT_value(sk, i) \ + ((DIST_POINT *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(DIST_POINT) *, sk), (i))) + +#define sk_DIST_POINT_set(sk, i, p) \ + ((DIST_POINT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + (i), CHECKED_CAST(void *, DIST_POINT *, p))) + +#define sk_DIST_POINT_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)) + +#define sk_DIST_POINT_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(DIST_POINT *), free_func)) + +#define sk_DIST_POINT_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(void *, DIST_POINT *, p), (where)) + +#define sk_DIST_POINT_delete(sk, where) \ + ((DIST_POINT *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + (where))) + +#define sk_DIST_POINT_delete_ptr(sk, p) \ + ((DIST_POINT *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(void *, DIST_POINT *, p))) + +#define sk_DIST_POINT_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), (out_index), \ + CHECKED_CAST(void *, DIST_POINT *, p)) + +#define sk_DIST_POINT_shift(sk) \ + ((DIST_POINT *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk))) + +#define sk_DIST_POINT_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(void *, DIST_POINT *, p)) + +#define sk_DIST_POINT_pop(sk) \ + ((DIST_POINT *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk))) + +#define sk_DIST_POINT_dup(sk) \ + ((STACK_OF(DIST_POINT) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(DIST_POINT) *, sk))) + +#define sk_DIST_POINT_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)) + +#define sk_DIST_POINT_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(DIST_POINT) *, sk)) + +#define sk_DIST_POINT_set_cmp_func(sk, comp) \ + ((int (*)(const DIST_POINT **a, const DIST_POINT **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const DIST_POINT **a, const DIST_POINT **b), \ + comp))) + +#define sk_DIST_POINT_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(DIST_POINT) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(void *(*)(void *), DIST_POINT *(*)(DIST_POINT *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(DIST_POINT *), free_func))) + +/* GENERAL_NAME */ +#define sk_GENERAL_NAME_new(comp) \ + ((STACK_OF(GENERAL_NAME) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const GENERAL_NAME **a, const GENERAL_NAME **b), \ + comp))) + +#define sk_GENERAL_NAME_new_null() ((STACK_OF(GENERAL_NAME) *)sk_new_null()) + +#define sk_GENERAL_NAME_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)) + +#define sk_GENERAL_NAME_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)); + +#define sk_GENERAL_NAME_value(sk, i) \ + ((GENERAL_NAME *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAME) *, sk), (i))) + +#define sk_GENERAL_NAME_set(sk, i, p) \ + ((GENERAL_NAME *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), (i), \ + CHECKED_CAST(void *, GENERAL_NAME *, p))) + +#define sk_GENERAL_NAME_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)) + +#define sk_GENERAL_NAME_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAME *), free_func)) + +#define sk_GENERAL_NAME_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAME *, p), (where)) + +#define sk_GENERAL_NAME_delete(sk, where) \ + ((GENERAL_NAME *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), (where))) + +#define sk_GENERAL_NAME_delete_ptr(sk, p) \ + ((GENERAL_NAME *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAME *, p))) + +#define sk_GENERAL_NAME_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), (out_index), \ + CHECKED_CAST(void *, GENERAL_NAME *, p)) + +#define sk_GENERAL_NAME_shift(sk) \ + ((GENERAL_NAME *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk))) + +#define sk_GENERAL_NAME_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAME *, p)) + +#define sk_GENERAL_NAME_pop(sk) \ + ((GENERAL_NAME *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk))) + +#define sk_GENERAL_NAME_dup(sk) \ + ((STACK_OF(GENERAL_NAME) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAME) *, sk))) + +#define sk_GENERAL_NAME_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)) + +#define sk_GENERAL_NAME_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAME) *, sk)) + +#define sk_GENERAL_NAME_set_cmp_func(sk, comp) \ + ((int (*)(const GENERAL_NAME **a, const GENERAL_NAME **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const GENERAL_NAME **a, const GENERAL_NAME **b), \ + comp))) + +#define sk_GENERAL_NAME_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(GENERAL_NAME) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(void *(*)(void *), GENERAL_NAME *(*)(GENERAL_NAME *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAME *), free_func))) + +/* GENERAL_NAMES */ +#define sk_GENERAL_NAMES_new(comp) \ + ((STACK_OF(GENERAL_NAMES) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const GENERAL_NAMES **a, const GENERAL_NAMES **b), comp))) + +#define sk_GENERAL_NAMES_new_null() ((STACK_OF(GENERAL_NAMES) *)sk_new_null()) + +#define sk_GENERAL_NAMES_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)) + +#define sk_GENERAL_NAMES_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)); + +#define sk_GENERAL_NAMES_value(sk, i) \ + ((GENERAL_NAMES *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAMES) *, sk), (i))) + +#define sk_GENERAL_NAMES_set(sk, i, p) \ + ((GENERAL_NAMES *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), (i), \ + CHECKED_CAST(void *, GENERAL_NAMES *, p))) + +#define sk_GENERAL_NAMES_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)) + +#define sk_GENERAL_NAMES_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAMES *), free_func)) + +#define sk_GENERAL_NAMES_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAMES *, p), (where)) + +#define sk_GENERAL_NAMES_delete(sk, where) \ + ((GENERAL_NAMES *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), (where))) + +#define sk_GENERAL_NAMES_delete_ptr(sk, p) \ + ((GENERAL_NAMES *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAMES *, p))) + +#define sk_GENERAL_NAMES_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), (out_index), \ + CHECKED_CAST(void *, GENERAL_NAMES *, p)) + +#define sk_GENERAL_NAMES_shift(sk) \ + ((GENERAL_NAMES *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk))) + +#define sk_GENERAL_NAMES_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAMES *, p)) + +#define sk_GENERAL_NAMES_pop(sk) \ + ((GENERAL_NAMES *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk))) + +#define sk_GENERAL_NAMES_dup(sk) \ + ((STACK_OF(GENERAL_NAMES) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAMES) *, sk))) + +#define sk_GENERAL_NAMES_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)) + +#define sk_GENERAL_NAMES_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAMES) *, sk)) + +#define sk_GENERAL_NAMES_set_cmp_func(sk, comp) \ + ((int (*)(const GENERAL_NAMES **a, const GENERAL_NAMES **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const GENERAL_NAMES **a, const GENERAL_NAMES **b), \ + comp))) + +#define sk_GENERAL_NAMES_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(GENERAL_NAMES) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(void *(*)(void *), GENERAL_NAMES *(*)(GENERAL_NAMES *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAMES *), free_func))) + +/* GENERAL_SUBTREE */ +#define sk_GENERAL_SUBTREE_new(comp) \ + ((STACK_OF(GENERAL_SUBTREE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const GENERAL_SUBTREE **a, const GENERAL_SUBTREE **b), comp))) + +#define sk_GENERAL_SUBTREE_new_null() \ + ((STACK_OF(GENERAL_SUBTREE) *)sk_new_null()) + +#define sk_GENERAL_SUBTREE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)) + +#define sk_GENERAL_SUBTREE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)); + +#define sk_GENERAL_SUBTREE_value(sk, i) \ + ((GENERAL_SUBTREE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk), (i))) + +#define sk_GENERAL_SUBTREE_set(sk, i, p) \ + ((GENERAL_SUBTREE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), (i), \ + CHECKED_CAST(void *, GENERAL_SUBTREE *, p))) + +#define sk_GENERAL_SUBTREE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)) + +#define sk_GENERAL_SUBTREE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_SUBTREE *), free_func)) + +#define sk_GENERAL_SUBTREE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(void *, GENERAL_SUBTREE *, p), (where)) + +#define sk_GENERAL_SUBTREE_delete(sk, where) \ + ((GENERAL_SUBTREE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), (where))) + +#define sk_GENERAL_SUBTREE_delete_ptr(sk, p) \ + ((GENERAL_SUBTREE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(void *, GENERAL_SUBTREE *, p))) + +#define sk_GENERAL_SUBTREE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + (out_index), CHECKED_CAST(void *, GENERAL_SUBTREE *, p)) + +#define sk_GENERAL_SUBTREE_shift(sk) \ + ((GENERAL_SUBTREE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk))) + +#define sk_GENERAL_SUBTREE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(void *, GENERAL_SUBTREE *, p)) + +#define sk_GENERAL_SUBTREE_pop(sk) \ + ((GENERAL_SUBTREE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk))) + +#define sk_GENERAL_SUBTREE_dup(sk) \ + ((STACK_OF(GENERAL_SUBTREE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk))) + +#define sk_GENERAL_SUBTREE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)) + +#define sk_GENERAL_SUBTREE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk)) + +#define sk_GENERAL_SUBTREE_set_cmp_func(sk, comp) \ + ((int (*)(const GENERAL_SUBTREE **a, const GENERAL_SUBTREE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const GENERAL_SUBTREE **a, \ + const GENERAL_SUBTREE **b), \ + comp))) + +#define sk_GENERAL_SUBTREE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(GENERAL_SUBTREE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(void *(*)(void *), GENERAL_SUBTREE *(*)(GENERAL_SUBTREE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_SUBTREE *), free_func))) + +/* POLICYINFO */ +#define sk_POLICYINFO_new(comp) \ + ((STACK_OF(POLICYINFO) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const POLICYINFO **a, const POLICYINFO **b), \ + comp))) + +#define sk_POLICYINFO_new_null() ((STACK_OF(POLICYINFO) *)sk_new_null()) + +#define sk_POLICYINFO_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)) + +#define sk_POLICYINFO_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)); + +#define sk_POLICYINFO_value(sk, i) \ + ((POLICYINFO *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICYINFO) *, sk), (i))) + +#define sk_POLICYINFO_set(sk, i, p) \ + ((POLICYINFO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + (i), CHECKED_CAST(void *, POLICYINFO *, p))) + +#define sk_POLICYINFO_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)) + +#define sk_POLICYINFO_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICYINFO *), free_func)) + +#define sk_POLICYINFO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(void *, POLICYINFO *, p), (where)) + +#define sk_POLICYINFO_delete(sk, where) \ + ((POLICYINFO *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + (where))) + +#define sk_POLICYINFO_delete_ptr(sk, p) \ + ((POLICYINFO *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(void *, POLICYINFO *, p))) + +#define sk_POLICYINFO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), (out_index), \ + CHECKED_CAST(void *, POLICYINFO *, p)) + +#define sk_POLICYINFO_shift(sk) \ + ((POLICYINFO *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk))) + +#define sk_POLICYINFO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(void *, POLICYINFO *, p)) + +#define sk_POLICYINFO_pop(sk) \ + ((POLICYINFO *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk))) + +#define sk_POLICYINFO_dup(sk) \ + ((STACK_OF(POLICYINFO) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICYINFO) *, sk))) + +#define sk_POLICYINFO_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)) + +#define sk_POLICYINFO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICYINFO) *, sk)) + +#define sk_POLICYINFO_set_cmp_func(sk, comp) \ + ((int (*)(const POLICYINFO **a, const POLICYINFO **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const POLICYINFO **a, const POLICYINFO **b), \ + comp))) + +#define sk_POLICYINFO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(POLICYINFO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(void *(*)(void *), POLICYINFO *(*)(POLICYINFO *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICYINFO *), free_func))) + +/* POLICYQUALINFO */ +#define sk_POLICYQUALINFO_new(comp) \ + ((STACK_OF(POLICYQUALINFO) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const POLICYQUALINFO **a, const POLICYQUALINFO **b), comp))) + +#define sk_POLICYQUALINFO_new_null() ((STACK_OF(POLICYQUALINFO) *)sk_new_null()) + +#define sk_POLICYQUALINFO_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)) + +#define sk_POLICYQUALINFO_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)); + +#define sk_POLICYQUALINFO_value(sk, i) \ + ((POLICYQUALINFO *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk), (i))) + +#define sk_POLICYQUALINFO_set(sk, i, p) \ + ((POLICYQUALINFO *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (i), \ + CHECKED_CAST(void *, POLICYQUALINFO *, p))) + +#define sk_POLICYQUALINFO_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)) + +#define sk_POLICYQUALINFO_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICYQUALINFO *), free_func)) + +#define sk_POLICYQUALINFO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(void *, POLICYQUALINFO *, p), (where)) + +#define sk_POLICYQUALINFO_delete(sk, where) \ + ((POLICYQUALINFO *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (where))) + +#define sk_POLICYQUALINFO_delete_ptr(sk, p) \ + ((POLICYQUALINFO *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(void *, POLICYQUALINFO *, p))) + +#define sk_POLICYQUALINFO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (out_index), \ + CHECKED_CAST(void *, POLICYQUALINFO *, p)) + +#define sk_POLICYQUALINFO_shift(sk) \ + ((POLICYQUALINFO *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk))) + +#define sk_POLICYQUALINFO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(void *, POLICYQUALINFO *, p)) + +#define sk_POLICYQUALINFO_pop(sk) \ + ((POLICYQUALINFO *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk))) + +#define sk_POLICYQUALINFO_dup(sk) \ + ((STACK_OF(POLICYQUALINFO) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk))) + +#define sk_POLICYQUALINFO_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)) + +#define sk_POLICYQUALINFO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk)) + +#define sk_POLICYQUALINFO_set_cmp_func(sk, comp) \ + ((int (*)(const POLICYQUALINFO **a, const POLICYQUALINFO **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const POLICYQUALINFO **a, \ + const POLICYQUALINFO **b), \ + comp))) + +#define sk_POLICYQUALINFO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(POLICYQUALINFO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(void *(*)(void *), POLICYQUALINFO *(*)(POLICYQUALINFO *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICYQUALINFO *), free_func))) + +/* POLICY_MAPPING */ +#define sk_POLICY_MAPPING_new(comp) \ + ((STACK_OF(POLICY_MAPPING) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const POLICY_MAPPING **a, const POLICY_MAPPING **b), comp))) + +#define sk_POLICY_MAPPING_new_null() ((STACK_OF(POLICY_MAPPING) *)sk_new_null()) + +#define sk_POLICY_MAPPING_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)) + +#define sk_POLICY_MAPPING_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)); + +#define sk_POLICY_MAPPING_value(sk, i) \ + ((POLICY_MAPPING *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICY_MAPPING) *, sk), (i))) + +#define sk_POLICY_MAPPING_set(sk, i, p) \ + ((POLICY_MAPPING *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), (i), \ + CHECKED_CAST(void *, POLICY_MAPPING *, p))) + +#define sk_POLICY_MAPPING_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)) + +#define sk_POLICY_MAPPING_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICY_MAPPING *), free_func)) + +#define sk_POLICY_MAPPING_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(void *, POLICY_MAPPING *, p), (where)) + +#define sk_POLICY_MAPPING_delete(sk, where) \ + ((POLICY_MAPPING *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), (where))) + +#define sk_POLICY_MAPPING_delete_ptr(sk, p) \ + ((POLICY_MAPPING *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(void *, POLICY_MAPPING *, p))) + +#define sk_POLICY_MAPPING_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), (out_index), \ + CHECKED_CAST(void *, POLICY_MAPPING *, p)) + +#define sk_POLICY_MAPPING_shift(sk) \ + ((POLICY_MAPPING *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk))) + +#define sk_POLICY_MAPPING_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(void *, POLICY_MAPPING *, p)) + +#define sk_POLICY_MAPPING_pop(sk) \ + ((POLICY_MAPPING *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk))) + +#define sk_POLICY_MAPPING_dup(sk) \ + ((STACK_OF(POLICY_MAPPING) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICY_MAPPING) *, sk))) + +#define sk_POLICY_MAPPING_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)) + +#define sk_POLICY_MAPPING_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICY_MAPPING) *, sk)) + +#define sk_POLICY_MAPPING_set_cmp_func(sk, comp) \ + ((int (*)(const POLICY_MAPPING **a, const POLICY_MAPPING **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const POLICY_MAPPING **a, \ + const POLICY_MAPPING **b), \ + comp))) + +#define sk_POLICY_MAPPING_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(POLICY_MAPPING) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(void *(*)(void *), POLICY_MAPPING *(*)(POLICY_MAPPING *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICY_MAPPING *), free_func))) + +/* RSA_additional_prime */ +#define sk_RSA_additional_prime_new(comp) \ + ((STACK_OF(RSA_additional_prime) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const RSA_additional_prime **a, const RSA_additional_prime **b), \ + comp))) + +#define sk_RSA_additional_prime_new_null() \ + ((STACK_OF(RSA_additional_prime) *)sk_new_null()) + +#define sk_RSA_additional_prime_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)) + +#define sk_RSA_additional_prime_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)); + +#define sk_RSA_additional_prime_value(sk, i) \ + ((RSA_additional_prime *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(RSA_additional_prime) *, sk), \ + (i))) + +#define sk_RSA_additional_prime_set(sk, i, p) \ + ((RSA_additional_prime *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), (i), \ + CHECKED_CAST(void *, RSA_additional_prime *, p))) + +#define sk_RSA_additional_prime_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)) + +#define sk_RSA_additional_prime_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(RSA_additional_prime *), \ + free_func)) + +#define sk_RSA_additional_prime_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + CHECKED_CAST(void *, RSA_additional_prime *, p), (where)) + +#define sk_RSA_additional_prime_delete(sk, where) \ + ((RSA_additional_prime *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), (where))) + +#define sk_RSA_additional_prime_delete_ptr(sk, p) \ + ((RSA_additional_prime *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + CHECKED_CAST(void *, RSA_additional_prime *, p))) + +#define sk_RSA_additional_prime_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + (out_index), CHECKED_CAST(void *, RSA_additional_prime *, p)) + +#define sk_RSA_additional_prime_shift(sk) \ + ((RSA_additional_prime *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk))) + +#define sk_RSA_additional_prime_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + CHECKED_CAST(void *, RSA_additional_prime *, p)) + +#define sk_RSA_additional_prime_pop(sk) \ + ((RSA_additional_prime *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk))) + +#define sk_RSA_additional_prime_dup(sk) \ + ((STACK_OF(RSA_additional_prime) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(RSA_additional_prime) *, sk))) + +#define sk_RSA_additional_prime_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)) + +#define sk_RSA_additional_prime_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(_STACK *, const STACK_OF(RSA_additional_prime) *, sk)) + +#define sk_RSA_additional_prime_set_cmp_func(sk, comp) \ + ((int (*)(const RSA_additional_prime **a, const RSA_additional_prime **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const RSA_additional_prime **a, \ + const RSA_additional_prime **b), \ + comp))) + +#define sk_RSA_additional_prime_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(RSA_additional_prime) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(RSA_additional_prime) *, \ + sk), \ + CHECKED_CAST(void *(*)(void *), \ + RSA_additional_prime *(*)(RSA_additional_prime *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(RSA_additional_prime *), \ + free_func))) + +/* SSL_COMP */ +#define sk_SSL_COMP_new(comp) \ + ((STACK_OF(SSL_COMP) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const SSL_COMP **a, const SSL_COMP **b), comp))) + +#define sk_SSL_COMP_new_null() ((STACK_OF(SSL_COMP) *)sk_new_null()) + +#define sk_SSL_COMP_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)) + +#define sk_SSL_COMP_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)); + +#define sk_SSL_COMP_value(sk, i) \ + ((SSL_COMP *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_COMP) *, sk), (i))) + +#define sk_SSL_COMP_set(sk, i, p) \ + ((SSL_COMP *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), (i), \ + CHECKED_CAST(void *, SSL_COMP *, p))) + +#define sk_SSL_COMP_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)) + +#define sk_SSL_COMP_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(SSL_COMP *), free_func)) + +#define sk_SSL_COMP_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(void *, SSL_COMP *, p), (where)) + +#define sk_SSL_COMP_delete(sk, where) \ + ((SSL_COMP *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + (where))) + +#define sk_SSL_COMP_delete_ptr(sk, p) \ + ((SSL_COMP *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(void *, SSL_COMP *, p))) + +#define sk_SSL_COMP_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), (out_index), \ + CHECKED_CAST(void *, SSL_COMP *, p)) + +#define sk_SSL_COMP_shift(sk) \ + ((SSL_COMP *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk))) + +#define sk_SSL_COMP_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(void *, SSL_COMP *, p)) + +#define sk_SSL_COMP_pop(sk) \ + ((SSL_COMP *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk))) + +#define sk_SSL_COMP_dup(sk) \ + ((STACK_OF(SSL_COMP) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_COMP) *, sk))) + +#define sk_SSL_COMP_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)) + +#define sk_SSL_COMP_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(SSL_COMP) *, sk)) + +#define sk_SSL_COMP_set_cmp_func(sk, comp) \ + ((int (*)(const SSL_COMP **a, const SSL_COMP **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const SSL_COMP **a, const SSL_COMP **b), comp))) + +#define sk_SSL_COMP_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SSL_COMP) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(void *(*)(void *), SSL_COMP *(*)(SSL_COMP *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(SSL_COMP *), free_func))) + +/* SSL_CUSTOM_EXTENSION */ +#define sk_SSL_CUSTOM_EXTENSION_new(comp) \ + ((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const SSL_CUSTOM_EXTENSION **a, const SSL_CUSTOM_EXTENSION **b), \ + comp))) + +#define sk_SSL_CUSTOM_EXTENSION_new_null() \ + ((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_new_null()) + +#define sk_SSL_CUSTOM_EXTENSION_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) + +#define sk_SSL_CUSTOM_EXTENSION_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)); + +#define sk_SSL_CUSTOM_EXTENSION_value(sk, i) \ + ((SSL_CUSTOM_EXTENSION *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + (i))) + +#define sk_SSL_CUSTOM_EXTENSION_set(sk, i, p) \ + ((SSL_CUSTOM_EXTENSION *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), (i), \ + CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p))) + +#define sk_SSL_CUSTOM_EXTENSION_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) + +#define sk_SSL_CUSTOM_EXTENSION_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(SSL_CUSTOM_EXTENSION *), \ + free_func)) + +#define sk_SSL_CUSTOM_EXTENSION_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p), (where)) + +#define sk_SSL_CUSTOM_EXTENSION_delete(sk, where) \ + ((SSL_CUSTOM_EXTENSION *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), (where))) + +#define sk_SSL_CUSTOM_EXTENSION_delete_ptr(sk, p) \ + ((SSL_CUSTOM_EXTENSION *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p))) + +#define sk_SSL_CUSTOM_EXTENSION_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + (out_index), CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p)) + +#define sk_SSL_CUSTOM_EXTENSION_shift(sk) \ + ((SSL_CUSTOM_EXTENSION *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))) + +#define sk_SSL_CUSTOM_EXTENSION_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p)) + +#define sk_SSL_CUSTOM_EXTENSION_pop(sk) \ + ((SSL_CUSTOM_EXTENSION *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))) + +#define sk_SSL_CUSTOM_EXTENSION_dup(sk) \ + ((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))) + +#define sk_SSL_CUSTOM_EXTENSION_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) + +#define sk_SSL_CUSTOM_EXTENSION_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) + +#define sk_SSL_CUSTOM_EXTENSION_set_cmp_func(sk, comp) \ + ((int (*)(const SSL_CUSTOM_EXTENSION **a, const SSL_CUSTOM_EXTENSION **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const SSL_CUSTOM_EXTENSION **a, \ + const SSL_CUSTOM_EXTENSION **b), \ + comp))) + +#define sk_SSL_CUSTOM_EXTENSION_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, \ + sk), \ + CHECKED_CAST(void *(*)(void *), \ + SSL_CUSTOM_EXTENSION *(*)(SSL_CUSTOM_EXTENSION *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(SSL_CUSTOM_EXTENSION *), \ + free_func))) + +/* STACK_OF_X509_NAME_ENTRY */ +#define sk_STACK_OF_X509_NAME_ENTRY_new(comp) \ + ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const STACK_OF_X509_NAME_ENTRY **a, \ + const STACK_OF_X509_NAME_ENTRY **b), \ + comp))) + +#define sk_STACK_OF_X509_NAME_ENTRY_new_null() \ + ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_new_null()) + +#define sk_STACK_OF_X509_NAME_ENTRY_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) + +#define sk_STACK_OF_X509_NAME_ENTRY_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)); + +#define sk_STACK_OF_X509_NAME_ENTRY_value(sk, i) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + (i))) + +#define sk_STACK_OF_X509_NAME_ENTRY_set(sk, i, p) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), (i), \ + CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p))) + +#define sk_STACK_OF_X509_NAME_ENTRY_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) + +#define sk_STACK_OF_X509_NAME_ENTRY_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(STACK_OF_X509_NAME_ENTRY *), \ + free_func)) + +#define sk_STACK_OF_X509_NAME_ENTRY_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p), (where)) + +#define sk_STACK_OF_X509_NAME_ENTRY_delete(sk, where) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + (where))) + +#define sk_STACK_OF_X509_NAME_ENTRY_delete_ptr(sk, p) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p))) + +#define sk_STACK_OF_X509_NAME_ENTRY_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + (out_index), CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p)) + +#define sk_STACK_OF_X509_NAME_ENTRY_shift(sk) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))) + +#define sk_STACK_OF_X509_NAME_ENTRY_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p)) + +#define sk_STACK_OF_X509_NAME_ENTRY_pop(sk) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))) + +#define sk_STACK_OF_X509_NAME_ENTRY_dup(sk) \ + ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))) + +#define sk_STACK_OF_X509_NAME_ENTRY_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) + +#define sk_STACK_OF_X509_NAME_ENTRY_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(_STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) + +#define sk_STACK_OF_X509_NAME_ENTRY_set_cmp_func(sk, comp) \ + ((int (*)(const STACK_OF_X509_NAME_ENTRY **a, \ + const STACK_OF_X509_NAME_ENTRY **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const STACK_OF_X509_NAME_ENTRY **a, \ + const STACK_OF_X509_NAME_ENTRY **b), \ + comp))) + +#define sk_STACK_OF_X509_NAME_ENTRY_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, \ + sk), \ + CHECKED_CAST(void *(*)(void *), \ + STACK_OF_X509_NAME_ENTRY *(*)(STACK_OF_X509_NAME_ENTRY *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(STACK_OF_X509_NAME_ENTRY *), \ + free_func))) + +/* SXNETID */ +#define sk_SXNETID_new(comp) \ + ((STACK_OF(SXNETID) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const SXNETID **a, const SXNETID **b), comp))) + +#define sk_SXNETID_new_null() ((STACK_OF(SXNETID) *)sk_new_null()) + +#define sk_SXNETID_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)) + +#define sk_SXNETID_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)); + +#define sk_SXNETID_value(sk, i) \ + ((SXNETID *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(SXNETID) *, sk), \ + (i))) + +#define sk_SXNETID_set(sk, i, p) \ + ((SXNETID *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), (i), \ + CHECKED_CAST(void *, SXNETID *, p))) + +#define sk_SXNETID_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)) + +#define sk_SXNETID_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(SXNETID *), free_func)) + +#define sk_SXNETID_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(void *, SXNETID *, p), (where)) + +#define sk_SXNETID_delete(sk, where) \ + ((SXNETID *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + (where))) + +#define sk_SXNETID_delete_ptr(sk, p) \ + ((SXNETID *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(void *, SXNETID *, p))) + +#define sk_SXNETID_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), (out_index), \ + CHECKED_CAST(void *, SXNETID *, p)) + +#define sk_SXNETID_shift(sk) \ + ((SXNETID *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk))) + +#define sk_SXNETID_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(void *, SXNETID *, p)) + +#define sk_SXNETID_pop(sk) \ + ((SXNETID *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk))) + +#define sk_SXNETID_dup(sk) \ + ((STACK_OF(SXNETID) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(SXNETID) *, sk))) + +#define sk_SXNETID_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)) + +#define sk_SXNETID_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(SXNETID) *, sk)) + +#define sk_SXNETID_set_cmp_func(sk, comp) \ + ((int (*)(const SXNETID **a, const SXNETID **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const SXNETID **a, const SXNETID **b), comp))) + +#define sk_SXNETID_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SXNETID) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(void *(*)(void *), SXNETID *(*)(SXNETID *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(SXNETID *), free_func))) + +/* X509 */ +#define sk_X509_new(comp) \ + ((STACK_OF(X509) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509 **a, const X509 **b), comp))) + +#define sk_X509_new_null() ((STACK_OF(X509) *)sk_new_null()) + +#define sk_X509_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)) + +#define sk_X509_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)); + +#define sk_X509_value(sk, i) \ + ((X509 *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(X509) *, sk), (i))) + +#define sk_X509_set(sk, i, p) \ + ((X509 *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), (i), \ + CHECKED_CAST(void *, X509 *, p))) + +#define sk_X509_free(sk) sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)) + +#define sk_X509_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509 *), free_func)) + +#define sk_X509_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \ + CHECKED_CAST(void *, X509 *, p), (where)) + +#define sk_X509_delete(sk, where) \ + ((X509 *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), (where))) + +#define sk_X509_delete_ptr(sk, p) \ + ((X509 *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \ + CHECKED_CAST(void *, X509 *, p))) + +#define sk_X509_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), (out_index), \ + CHECKED_CAST(void *, X509 *, p)) + +#define sk_X509_shift(sk) \ + ((X509 *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk))) + +#define sk_X509_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \ + CHECKED_CAST(void *, X509 *, p)) + +#define sk_X509_pop(sk) \ + ((X509 *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk))) + +#define sk_X509_dup(sk) \ + ((STACK_OF(X509) *)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(X509) *, sk))) + +#define sk_X509_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)) + +#define sk_X509_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509) *, sk)) + +#define sk_X509_set_cmp_func(sk, comp) \ + ((int (*)(const X509 **a, const X509 **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509 **a, const X509 **b), \ + comp))) + +#define sk_X509_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509 *(*)(X509 *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509 *), free_func))) + +/* X509V3_EXT_METHOD */ +#define sk_X509V3_EXT_METHOD_new(comp) \ + ((STACK_OF(X509V3_EXT_METHOD) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509V3_EXT_METHOD **a, const X509V3_EXT_METHOD **b), \ + comp))) + +#define sk_X509V3_EXT_METHOD_new_null() \ + ((STACK_OF(X509V3_EXT_METHOD) *)sk_new_null()) + +#define sk_X509V3_EXT_METHOD_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)) + +#define sk_X509V3_EXT_METHOD_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)); + +#define sk_X509V3_EXT_METHOD_value(sk, i) \ + ((X509V3_EXT_METHOD *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk), (i))) + +#define sk_X509V3_EXT_METHOD_set(sk, i, p) \ + ((X509V3_EXT_METHOD *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), (i), \ + CHECKED_CAST(void *, X509V3_EXT_METHOD *, p))) + +#define sk_X509V3_EXT_METHOD_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)) + +#define sk_X509V3_EXT_METHOD_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509V3_EXT_METHOD *), \ + free_func)) + +#define sk_X509V3_EXT_METHOD_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(void *, X509V3_EXT_METHOD *, p), (where)) + +#define sk_X509V3_EXT_METHOD_delete(sk, where) \ + ((X509V3_EXT_METHOD *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), (where))) + +#define sk_X509V3_EXT_METHOD_delete_ptr(sk, p) \ + ((X509V3_EXT_METHOD *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(void *, X509V3_EXT_METHOD *, p))) + +#define sk_X509V3_EXT_METHOD_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + (out_index), CHECKED_CAST(void *, X509V3_EXT_METHOD *, p)) + +#define sk_X509V3_EXT_METHOD_shift(sk) \ + ((X509V3_EXT_METHOD *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk))) + +#define sk_X509V3_EXT_METHOD_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(void *, X509V3_EXT_METHOD *, p)) + +#define sk_X509V3_EXT_METHOD_pop(sk) \ + ((X509V3_EXT_METHOD *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk))) + +#define sk_X509V3_EXT_METHOD_dup(sk) \ + ((STACK_OF(X509V3_EXT_METHOD) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk))) + +#define sk_X509V3_EXT_METHOD_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)) + +#define sk_X509V3_EXT_METHOD_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk)) + +#define sk_X509V3_EXT_METHOD_set_cmp_func(sk, comp) \ + ((int (*)(const X509V3_EXT_METHOD **a, const X509V3_EXT_METHOD **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509V3_EXT_METHOD **a, \ + const X509V3_EXT_METHOD **b), \ + comp))) + +#define sk_X509V3_EXT_METHOD_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509V3_EXT_METHOD) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + X509V3_EXT_METHOD *(*)(X509V3_EXT_METHOD *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509V3_EXT_METHOD *), \ + free_func))) + +/* X509_ALGOR */ +#define sk_X509_ALGOR_new(comp) \ + ((STACK_OF(X509_ALGOR) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_ALGOR **a, const X509_ALGOR **b), \ + comp))) + +#define sk_X509_ALGOR_new_null() ((STACK_OF(X509_ALGOR) *)sk_new_null()) + +#define sk_X509_ALGOR_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)) + +#define sk_X509_ALGOR_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)); + +#define sk_X509_ALGOR_value(sk, i) \ + ((X509_ALGOR *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk), (i))) + +#define sk_X509_ALGOR_set(sk, i, p) \ + ((X509_ALGOR *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + (i), CHECKED_CAST(void *, X509_ALGOR *, p))) + +#define sk_X509_ALGOR_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)) + +#define sk_X509_ALGOR_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_ALGOR *), free_func)) + +#define sk_X509_ALGOR_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(void *, X509_ALGOR *, p), (where)) + +#define sk_X509_ALGOR_delete(sk, where) \ + ((X509_ALGOR *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + (where))) + +#define sk_X509_ALGOR_delete_ptr(sk, p) \ + ((X509_ALGOR *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(void *, X509_ALGOR *, p))) + +#define sk_X509_ALGOR_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_ALGOR *, p)) + +#define sk_X509_ALGOR_shift(sk) \ + ((X509_ALGOR *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk))) + +#define sk_X509_ALGOR_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(void *, X509_ALGOR *, p)) + +#define sk_X509_ALGOR_pop(sk) \ + ((X509_ALGOR *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk))) + +#define sk_X509_ALGOR_dup(sk) \ + ((STACK_OF(X509_ALGOR) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk))) + +#define sk_X509_ALGOR_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)) + +#define sk_X509_ALGOR_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk)) + +#define sk_X509_ALGOR_set_cmp_func(sk, comp) \ + ((int (*)(const X509_ALGOR **a, const X509_ALGOR **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_ALGOR **a, const X509_ALGOR **b), \ + comp))) + +#define sk_X509_ALGOR_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_ALGOR) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_ALGOR *(*)(X509_ALGOR *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_ALGOR *), free_func))) + +/* X509_ATTRIBUTE */ +#define sk_X509_ATTRIBUTE_new(comp) \ + ((STACK_OF(X509_ATTRIBUTE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_ATTRIBUTE **a, const X509_ATTRIBUTE **b), comp))) + +#define sk_X509_ATTRIBUTE_new_null() ((STACK_OF(X509_ATTRIBUTE) *)sk_new_null()) + +#define sk_X509_ATTRIBUTE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)) + +#define sk_X509_ATTRIBUTE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)); + +#define sk_X509_ATTRIBUTE_value(sk, i) \ + ((X509_ATTRIBUTE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk), (i))) + +#define sk_X509_ATTRIBUTE_set(sk, i, p) \ + ((X509_ATTRIBUTE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (i), \ + CHECKED_CAST(void *, X509_ATTRIBUTE *, p))) + +#define sk_X509_ATTRIBUTE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)) + +#define sk_X509_ATTRIBUTE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_ATTRIBUTE *), free_func)) + +#define sk_X509_ATTRIBUTE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(void *, X509_ATTRIBUTE *, p), (where)) + +#define sk_X509_ATTRIBUTE_delete(sk, where) \ + ((X509_ATTRIBUTE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (where))) + +#define sk_X509_ATTRIBUTE_delete_ptr(sk, p) \ + ((X509_ATTRIBUTE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(void *, X509_ATTRIBUTE *, p))) + +#define sk_X509_ATTRIBUTE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_ATTRIBUTE *, p)) + +#define sk_X509_ATTRIBUTE_shift(sk) \ + ((X509_ATTRIBUTE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk))) + +#define sk_X509_ATTRIBUTE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(void *, X509_ATTRIBUTE *, p)) + +#define sk_X509_ATTRIBUTE_pop(sk) \ + ((X509_ATTRIBUTE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk))) + +#define sk_X509_ATTRIBUTE_dup(sk) \ + ((STACK_OF(X509_ATTRIBUTE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk))) + +#define sk_X509_ATTRIBUTE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)) + +#define sk_X509_ATTRIBUTE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk)) + +#define sk_X509_ATTRIBUTE_set_cmp_func(sk, comp) \ + ((int (*)(const X509_ATTRIBUTE **a, const X509_ATTRIBUTE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_ATTRIBUTE **a, \ + const X509_ATTRIBUTE **b), \ + comp))) + +#define sk_X509_ATTRIBUTE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_ATTRIBUTE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_ATTRIBUTE *(*)(X509_ATTRIBUTE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_ATTRIBUTE *), free_func))) + +/* X509_CRL */ +#define sk_X509_CRL_new(comp) \ + ((STACK_OF(X509_CRL) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_CRL **a, const X509_CRL **b), comp))) + +#define sk_X509_CRL_new_null() ((STACK_OF(X509_CRL) *)sk_new_null()) + +#define sk_X509_CRL_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)) + +#define sk_X509_CRL_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)); + +#define sk_X509_CRL_value(sk, i) \ + ((X509_CRL *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk), (i))) + +#define sk_X509_CRL_set(sk, i, p) \ + ((X509_CRL *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), (i), \ + CHECKED_CAST(void *, X509_CRL *, p))) + +#define sk_X509_CRL_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)) + +#define sk_X509_CRL_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_CRL *), free_func)) + +#define sk_X509_CRL_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(void *, X509_CRL *, p), (where)) + +#define sk_X509_CRL_delete(sk, where) \ + ((X509_CRL *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + (where))) + +#define sk_X509_CRL_delete_ptr(sk, p) \ + ((X509_CRL *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(void *, X509_CRL *, p))) + +#define sk_X509_CRL_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_CRL *, p)) + +#define sk_X509_CRL_shift(sk) \ + ((X509_CRL *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk))) + +#define sk_X509_CRL_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(void *, X509_CRL *, p)) + +#define sk_X509_CRL_pop(sk) \ + ((X509_CRL *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk))) + +#define sk_X509_CRL_dup(sk) \ + ((STACK_OF(X509_CRL) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk))) + +#define sk_X509_CRL_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)) + +#define sk_X509_CRL_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk)) + +#define sk_X509_CRL_set_cmp_func(sk, comp) \ + ((int (*)(const X509_CRL **a, const X509_CRL **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_CRL **a, const X509_CRL **b), comp))) + +#define sk_X509_CRL_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_CRL) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_CRL *(*)(X509_CRL *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_CRL *), free_func))) + +/* X509_EXTENSION */ +#define sk_X509_EXTENSION_new(comp) \ + ((STACK_OF(X509_EXTENSION) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_EXTENSION **a, const X509_EXTENSION **b), comp))) + +#define sk_X509_EXTENSION_new_null() ((STACK_OF(X509_EXTENSION) *)sk_new_null()) + +#define sk_X509_EXTENSION_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)) + +#define sk_X509_EXTENSION_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)); + +#define sk_X509_EXTENSION_value(sk, i) \ + ((X509_EXTENSION *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk), (i))) + +#define sk_X509_EXTENSION_set(sk, i, p) \ + ((X509_EXTENSION *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (i), \ + CHECKED_CAST(void *, X509_EXTENSION *, p))) + +#define sk_X509_EXTENSION_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)) + +#define sk_X509_EXTENSION_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_EXTENSION *), free_func)) + +#define sk_X509_EXTENSION_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(void *, X509_EXTENSION *, p), (where)) + +#define sk_X509_EXTENSION_delete(sk, where) \ + ((X509_EXTENSION *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (where))) + +#define sk_X509_EXTENSION_delete_ptr(sk, p) \ + ((X509_EXTENSION *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(void *, X509_EXTENSION *, p))) + +#define sk_X509_EXTENSION_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_EXTENSION *, p)) + +#define sk_X509_EXTENSION_shift(sk) \ + ((X509_EXTENSION *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk))) + +#define sk_X509_EXTENSION_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(void *, X509_EXTENSION *, p)) + +#define sk_X509_EXTENSION_pop(sk) \ + ((X509_EXTENSION *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk))) + +#define sk_X509_EXTENSION_dup(sk) \ + ((STACK_OF(X509_EXTENSION) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk))) + +#define sk_X509_EXTENSION_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)) + +#define sk_X509_EXTENSION_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk)) + +#define sk_X509_EXTENSION_set_cmp_func(sk, comp) \ + ((int (*)(const X509_EXTENSION **a, const X509_EXTENSION **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_EXTENSION **a, \ + const X509_EXTENSION **b), \ + comp))) + +#define sk_X509_EXTENSION_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_EXTENSION) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_EXTENSION *(*)(X509_EXTENSION *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_EXTENSION *), free_func))) + +/* X509_INFO */ +#define sk_X509_INFO_new(comp) \ + ((STACK_OF(X509_INFO) *)sk_new( \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_INFO **a, const X509_INFO **b), comp))) + +#define sk_X509_INFO_new_null() ((STACK_OF(X509_INFO) *)sk_new_null()) + +#define sk_X509_INFO_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)) + +#define sk_X509_INFO_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)); + +#define sk_X509_INFO_value(sk, i) \ + ((X509_INFO *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk), (i))) + +#define sk_X509_INFO_set(sk, i, p) \ + ((X509_INFO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), (i), \ + CHECKED_CAST(void *, X509_INFO *, p))) + +#define sk_X509_INFO_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)) + +#define sk_X509_INFO_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_INFO *), free_func)) + +#define sk_X509_INFO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(void *, X509_INFO *, p), (where)) + +#define sk_X509_INFO_delete(sk, where) \ + ((X509_INFO *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + (where))) + +#define sk_X509_INFO_delete_ptr(sk, p) \ + ((X509_INFO *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(void *, X509_INFO *, p))) + +#define sk_X509_INFO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_INFO *, p)) + +#define sk_X509_INFO_shift(sk) \ + ((X509_INFO *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk))) + +#define sk_X509_INFO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(void *, X509_INFO *, p)) + +#define sk_X509_INFO_pop(sk) \ + ((X509_INFO *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk))) + +#define sk_X509_INFO_dup(sk) \ + ((STACK_OF(X509_INFO) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk))) + +#define sk_X509_INFO_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)) + +#define sk_X509_INFO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk)) + +#define sk_X509_INFO_set_cmp_func(sk, comp) \ + ((int (*)(const X509_INFO **a, const X509_INFO **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_INFO **a, const X509_INFO **b), comp))) + +#define sk_X509_INFO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_INFO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_INFO *(*)(X509_INFO *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_INFO *), free_func))) + +/* X509_LOOKUP */ +#define sk_X509_LOOKUP_new(comp) \ + ((STACK_OF(X509_LOOKUP) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b), \ + comp))) + +#define sk_X509_LOOKUP_new_null() ((STACK_OF(X509_LOOKUP) *)sk_new_null()) + +#define sk_X509_LOOKUP_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)) + +#define sk_X509_LOOKUP_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)); + +#define sk_X509_LOOKUP_value(sk, i) \ + ((X509_LOOKUP *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk), (i))) + +#define sk_X509_LOOKUP_set(sk, i, p) \ + ((X509_LOOKUP *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + (i), CHECKED_CAST(void *, X509_LOOKUP *, p))) + +#define sk_X509_LOOKUP_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)) + +#define sk_X509_LOOKUP_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_LOOKUP *), free_func)) + +#define sk_X509_LOOKUP_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(void *, X509_LOOKUP *, p), (where)) + +#define sk_X509_LOOKUP_delete(sk, where) \ + ((X509_LOOKUP *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), (where))) + +#define sk_X509_LOOKUP_delete_ptr(sk, p) \ + ((X509_LOOKUP *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(void *, X509_LOOKUP *, p))) + +#define sk_X509_LOOKUP_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_LOOKUP *, p)) + +#define sk_X509_LOOKUP_shift(sk) \ + ((X509_LOOKUP *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk))) + +#define sk_X509_LOOKUP_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(void *, X509_LOOKUP *, p)) + +#define sk_X509_LOOKUP_pop(sk) \ + ((X509_LOOKUP *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk))) + +#define sk_X509_LOOKUP_dup(sk) \ + ((STACK_OF(X509_LOOKUP) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk))) + +#define sk_X509_LOOKUP_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)) + +#define sk_X509_LOOKUP_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk)) + +#define sk_X509_LOOKUP_set_cmp_func(sk, comp) \ + ((int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b), \ + comp))) + +#define sk_X509_LOOKUP_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_LOOKUP) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_LOOKUP *(*)(X509_LOOKUP *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_LOOKUP *), free_func))) + +/* X509_NAME */ +#define sk_X509_NAME_new(comp) \ + ((STACK_OF(X509_NAME) *)sk_new( \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_NAME **a, const X509_NAME **b), comp))) + +#define sk_X509_NAME_new_null() ((STACK_OF(X509_NAME) *)sk_new_null()) + +#define sk_X509_NAME_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)) + +#define sk_X509_NAME_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)); + +#define sk_X509_NAME_value(sk, i) \ + ((X509_NAME *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk), (i))) + +#define sk_X509_NAME_set(sk, i, p) \ + ((X509_NAME *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), (i), \ + CHECKED_CAST(void *, X509_NAME *, p))) + +#define sk_X509_NAME_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)) + +#define sk_X509_NAME_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_NAME *), free_func)) + +#define sk_X509_NAME_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(void *, X509_NAME *, p), (where)) + +#define sk_X509_NAME_delete(sk, where) \ + ((X509_NAME *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + (where))) + +#define sk_X509_NAME_delete_ptr(sk, p) \ + ((X509_NAME *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(void *, X509_NAME *, p))) + +#define sk_X509_NAME_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_NAME *, p)) + +#define sk_X509_NAME_shift(sk) \ + ((X509_NAME *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk))) + +#define sk_X509_NAME_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(void *, X509_NAME *, p)) + +#define sk_X509_NAME_pop(sk) \ + ((X509_NAME *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk))) + +#define sk_X509_NAME_dup(sk) \ + ((STACK_OF(X509_NAME) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk))) + +#define sk_X509_NAME_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)) + +#define sk_X509_NAME_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk)) + +#define sk_X509_NAME_set_cmp_func(sk, comp) \ + ((int (*)(const X509_NAME **a, const X509_NAME **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_NAME **a, const X509_NAME **b), comp))) + +#define sk_X509_NAME_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_NAME) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_NAME *(*)(X509_NAME *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_NAME *), free_func))) + +/* X509_NAME_ENTRY */ +#define sk_X509_NAME_ENTRY_new(comp) \ + ((STACK_OF(X509_NAME_ENTRY) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b), comp))) + +#define sk_X509_NAME_ENTRY_new_null() \ + ((STACK_OF(X509_NAME_ENTRY) *)sk_new_null()) + +#define sk_X509_NAME_ENTRY_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)) + +#define sk_X509_NAME_ENTRY_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)); + +#define sk_X509_NAME_ENTRY_value(sk, i) \ + ((X509_NAME_ENTRY *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk), (i))) + +#define sk_X509_NAME_ENTRY_set(sk, i, p) \ + ((X509_NAME_ENTRY *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), (i), \ + CHECKED_CAST(void *, X509_NAME_ENTRY *, p))) + +#define sk_X509_NAME_ENTRY_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)) + +#define sk_X509_NAME_ENTRY_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_NAME_ENTRY *), free_func)) + +#define sk_X509_NAME_ENTRY_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, X509_NAME_ENTRY *, p), (where)) + +#define sk_X509_NAME_ENTRY_delete(sk, where) \ + ((X509_NAME_ENTRY *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), (where))) + +#define sk_X509_NAME_ENTRY_delete_ptr(sk, p) \ + ((X509_NAME_ENTRY *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, X509_NAME_ENTRY *, p))) + +#define sk_X509_NAME_ENTRY_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + (out_index), CHECKED_CAST(void *, X509_NAME_ENTRY *, p)) + +#define sk_X509_NAME_ENTRY_shift(sk) \ + ((X509_NAME_ENTRY *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))) + +#define sk_X509_NAME_ENTRY_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, X509_NAME_ENTRY *, p)) + +#define sk_X509_NAME_ENTRY_pop(sk) \ + ((X509_NAME_ENTRY *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))) + +#define sk_X509_NAME_ENTRY_dup(sk) \ + ((STACK_OF(X509_NAME_ENTRY) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk))) + +#define sk_X509_NAME_ENTRY_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)) + +#define sk_X509_NAME_ENTRY_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk)) + +#define sk_X509_NAME_ENTRY_set_cmp_func(sk, comp) \ + ((int (*)(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_NAME_ENTRY **a, \ + const X509_NAME_ENTRY **b), \ + comp))) + +#define sk_X509_NAME_ENTRY_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_NAME_ENTRY) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_NAME_ENTRY *(*)(X509_NAME_ENTRY *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_NAME_ENTRY *), free_func))) + +/* X509_OBJECT */ +#define sk_X509_OBJECT_new(comp) \ + ((STACK_OF(X509_OBJECT) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_OBJECT **a, const X509_OBJECT **b), \ + comp))) + +#define sk_X509_OBJECT_new_null() ((STACK_OF(X509_OBJECT) *)sk_new_null()) + +#define sk_X509_OBJECT_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)) + +#define sk_X509_OBJECT_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)); + +#define sk_X509_OBJECT_value(sk, i) \ + ((X509_OBJECT *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk), (i))) + +#define sk_X509_OBJECT_set(sk, i, p) \ + ((X509_OBJECT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + (i), CHECKED_CAST(void *, X509_OBJECT *, p))) + +#define sk_X509_OBJECT_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)) + +#define sk_X509_OBJECT_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_OBJECT *), free_func)) + +#define sk_X509_OBJECT_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(void *, X509_OBJECT *, p), (where)) + +#define sk_X509_OBJECT_delete(sk, where) \ + ((X509_OBJECT *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), (where))) + +#define sk_X509_OBJECT_delete_ptr(sk, p) \ + ((X509_OBJECT *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(void *, X509_OBJECT *, p))) + +#define sk_X509_OBJECT_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_OBJECT *, p)) + +#define sk_X509_OBJECT_shift(sk) \ + ((X509_OBJECT *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk))) + +#define sk_X509_OBJECT_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(void *, X509_OBJECT *, p)) + +#define sk_X509_OBJECT_pop(sk) \ + ((X509_OBJECT *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk))) + +#define sk_X509_OBJECT_dup(sk) \ + ((STACK_OF(X509_OBJECT) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk))) + +#define sk_X509_OBJECT_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)) + +#define sk_X509_OBJECT_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk)) + +#define sk_X509_OBJECT_set_cmp_func(sk, comp) \ + ((int (*)(const X509_OBJECT **a, const X509_OBJECT **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_OBJECT **a, const X509_OBJECT **b), \ + comp))) + +#define sk_X509_OBJECT_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_OBJECT) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_OBJECT *(*)(X509_OBJECT *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_OBJECT *), free_func))) + +/* X509_POLICY_DATA */ +#define sk_X509_POLICY_DATA_new(comp) \ + ((STACK_OF(X509_POLICY_DATA) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_POLICY_DATA **a, const X509_POLICY_DATA **b), comp))) + +#define sk_X509_POLICY_DATA_new_null() \ + ((STACK_OF(X509_POLICY_DATA) *)sk_new_null()) + +#define sk_X509_POLICY_DATA_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)) + +#define sk_X509_POLICY_DATA_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)); + +#define sk_X509_POLICY_DATA_value(sk, i) \ + ((X509_POLICY_DATA *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk), (i))) + +#define sk_X509_POLICY_DATA_set(sk, i, p) \ + ((X509_POLICY_DATA *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), (i), \ + CHECKED_CAST(void *, X509_POLICY_DATA *, p))) + +#define sk_X509_POLICY_DATA_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)) + +#define sk_X509_POLICY_DATA_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_DATA *), free_func)) + +#define sk_X509_POLICY_DATA_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_DATA *, p), (where)) + +#define sk_X509_POLICY_DATA_delete(sk, where) \ + ((X509_POLICY_DATA *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), (where))) + +#define sk_X509_POLICY_DATA_delete_ptr(sk, p) \ + ((X509_POLICY_DATA *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_DATA *, p))) + +#define sk_X509_POLICY_DATA_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + (out_index), CHECKED_CAST(void *, X509_POLICY_DATA *, p)) + +#define sk_X509_POLICY_DATA_shift(sk) \ + ((X509_POLICY_DATA *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk))) + +#define sk_X509_POLICY_DATA_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_DATA *, p)) + +#define sk_X509_POLICY_DATA_pop(sk) \ + ((X509_POLICY_DATA *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk))) + +#define sk_X509_POLICY_DATA_dup(sk) \ + ((STACK_OF(X509_POLICY_DATA) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk))) + +#define sk_X509_POLICY_DATA_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)) + +#define sk_X509_POLICY_DATA_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk)) + +#define sk_X509_POLICY_DATA_set_cmp_func(sk, comp) \ + ((int (*)(const X509_POLICY_DATA **a, const X509_POLICY_DATA **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_POLICY_DATA **a, \ + const X509_POLICY_DATA **b), \ + comp))) + +#define sk_X509_POLICY_DATA_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_POLICY_DATA) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + X509_POLICY_DATA *(*)(X509_POLICY_DATA *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_DATA *), \ + free_func))) + +/* X509_POLICY_NODE */ +#define sk_X509_POLICY_NODE_new(comp) \ + ((STACK_OF(X509_POLICY_NODE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_POLICY_NODE **a, const X509_POLICY_NODE **b), comp))) + +#define sk_X509_POLICY_NODE_new_null() \ + ((STACK_OF(X509_POLICY_NODE) *)sk_new_null()) + +#define sk_X509_POLICY_NODE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)) + +#define sk_X509_POLICY_NODE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)); + +#define sk_X509_POLICY_NODE_value(sk, i) \ + ((X509_POLICY_NODE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk), (i))) + +#define sk_X509_POLICY_NODE_set(sk, i, p) \ + ((X509_POLICY_NODE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), (i), \ + CHECKED_CAST(void *, X509_POLICY_NODE *, p))) + +#define sk_X509_POLICY_NODE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)) + +#define sk_X509_POLICY_NODE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_NODE *), free_func)) + +#define sk_X509_POLICY_NODE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_NODE *, p), (where)) + +#define sk_X509_POLICY_NODE_delete(sk, where) \ + ((X509_POLICY_NODE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), (where))) + +#define sk_X509_POLICY_NODE_delete_ptr(sk, p) \ + ((X509_POLICY_NODE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_NODE *, p))) + +#define sk_X509_POLICY_NODE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + (out_index), CHECKED_CAST(void *, X509_POLICY_NODE *, p)) + +#define sk_X509_POLICY_NODE_shift(sk) \ + ((X509_POLICY_NODE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk))) + +#define sk_X509_POLICY_NODE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_NODE *, p)) + +#define sk_X509_POLICY_NODE_pop(sk) \ + ((X509_POLICY_NODE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk))) + +#define sk_X509_POLICY_NODE_dup(sk) \ + ((STACK_OF(X509_POLICY_NODE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk))) + +#define sk_X509_POLICY_NODE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)) + +#define sk_X509_POLICY_NODE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk)) + +#define sk_X509_POLICY_NODE_set_cmp_func(sk, comp) \ + ((int (*)(const X509_POLICY_NODE **a, const X509_POLICY_NODE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_POLICY_NODE **a, \ + const X509_POLICY_NODE **b), \ + comp))) + +#define sk_X509_POLICY_NODE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_POLICY_NODE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + X509_POLICY_NODE *(*)(X509_POLICY_NODE *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_NODE *), \ + free_func))) + +/* X509_PURPOSE */ +#define sk_X509_PURPOSE_new(comp) \ + ((STACK_OF(X509_PURPOSE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b), \ + comp))) + +#define sk_X509_PURPOSE_new_null() ((STACK_OF(X509_PURPOSE) *)sk_new_null()) + +#define sk_X509_PURPOSE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)) + +#define sk_X509_PURPOSE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)); + +#define sk_X509_PURPOSE_value(sk, i) \ + ((X509_PURPOSE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk), (i))) + +#define sk_X509_PURPOSE_set(sk, i, p) \ + ((X509_PURPOSE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (i), \ + CHECKED_CAST(void *, X509_PURPOSE *, p))) + +#define sk_X509_PURPOSE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)) + +#define sk_X509_PURPOSE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_PURPOSE *), free_func)) + +#define sk_X509_PURPOSE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(void *, X509_PURPOSE *, p), (where)) + +#define sk_X509_PURPOSE_delete(sk, where) \ + ((X509_PURPOSE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (where))) + +#define sk_X509_PURPOSE_delete_ptr(sk, p) \ + ((X509_PURPOSE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(void *, X509_PURPOSE *, p))) + +#define sk_X509_PURPOSE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_PURPOSE *, p)) + +#define sk_X509_PURPOSE_shift(sk) \ + ((X509_PURPOSE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk))) + +#define sk_X509_PURPOSE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(void *, X509_PURPOSE *, p)) + +#define sk_X509_PURPOSE_pop(sk) \ + ((X509_PURPOSE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk))) + +#define sk_X509_PURPOSE_dup(sk) \ + ((STACK_OF(X509_PURPOSE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk))) + +#define sk_X509_PURPOSE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)) + +#define sk_X509_PURPOSE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk)) + +#define sk_X509_PURPOSE_set_cmp_func(sk, comp) \ + ((int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b), \ + comp))) + +#define sk_X509_PURPOSE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_PURPOSE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_PURPOSE *(*)(X509_PURPOSE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_PURPOSE *), free_func))) + +/* X509_REVOKED */ +#define sk_X509_REVOKED_new(comp) \ + ((STACK_OF(X509_REVOKED) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_REVOKED **a, const X509_REVOKED **b), \ + comp))) + +#define sk_X509_REVOKED_new_null() ((STACK_OF(X509_REVOKED) *)sk_new_null()) + +#define sk_X509_REVOKED_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)) + +#define sk_X509_REVOKED_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)); + +#define sk_X509_REVOKED_value(sk, i) \ + ((X509_REVOKED *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk), (i))) + +#define sk_X509_REVOKED_set(sk, i, p) \ + ((X509_REVOKED *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (i), \ + CHECKED_CAST(void *, X509_REVOKED *, p))) + +#define sk_X509_REVOKED_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)) + +#define sk_X509_REVOKED_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_REVOKED *), free_func)) + +#define sk_X509_REVOKED_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(void *, X509_REVOKED *, p), (where)) + +#define sk_X509_REVOKED_delete(sk, where) \ + ((X509_REVOKED *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (where))) + +#define sk_X509_REVOKED_delete_ptr(sk, p) \ + ((X509_REVOKED *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(void *, X509_REVOKED *, p))) + +#define sk_X509_REVOKED_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_REVOKED *, p)) + +#define sk_X509_REVOKED_shift(sk) \ + ((X509_REVOKED *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk))) + +#define sk_X509_REVOKED_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(void *, X509_REVOKED *, p)) + +#define sk_X509_REVOKED_pop(sk) \ + ((X509_REVOKED *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk))) + +#define sk_X509_REVOKED_dup(sk) \ + ((STACK_OF(X509_REVOKED) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk))) + +#define sk_X509_REVOKED_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)) + +#define sk_X509_REVOKED_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk)) + +#define sk_X509_REVOKED_set_cmp_func(sk, comp) \ + ((int (*)(const X509_REVOKED **a, const X509_REVOKED **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_REVOKED **a, const X509_REVOKED **b), \ + comp))) + +#define sk_X509_REVOKED_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_REVOKED) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_REVOKED *(*)(X509_REVOKED *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_REVOKED *), free_func))) + +/* X509_TRUST */ +#define sk_X509_TRUST_new(comp) \ + ((STACK_OF(X509_TRUST) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_TRUST **a, const X509_TRUST **b), \ + comp))) + +#define sk_X509_TRUST_new_null() ((STACK_OF(X509_TRUST) *)sk_new_null()) + +#define sk_X509_TRUST_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)) + +#define sk_X509_TRUST_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)); + +#define sk_X509_TRUST_value(sk, i) \ + ((X509_TRUST *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk), (i))) + +#define sk_X509_TRUST_set(sk, i, p) \ + ((X509_TRUST *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + (i), CHECKED_CAST(void *, X509_TRUST *, p))) + +#define sk_X509_TRUST_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)) + +#define sk_X509_TRUST_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_TRUST *), free_func)) + +#define sk_X509_TRUST_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(void *, X509_TRUST *, p), (where)) + +#define sk_X509_TRUST_delete(sk, where) \ + ((X509_TRUST *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + (where))) + +#define sk_X509_TRUST_delete_ptr(sk, p) \ + ((X509_TRUST *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(void *, X509_TRUST *, p))) + +#define sk_X509_TRUST_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_TRUST *, p)) + +#define sk_X509_TRUST_shift(sk) \ + ((X509_TRUST *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk))) + +#define sk_X509_TRUST_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(void *, X509_TRUST *, p)) + +#define sk_X509_TRUST_pop(sk) \ + ((X509_TRUST *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk))) + +#define sk_X509_TRUST_dup(sk) \ + ((STACK_OF(X509_TRUST) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk))) + +#define sk_X509_TRUST_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)) + +#define sk_X509_TRUST_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk)) + +#define sk_X509_TRUST_set_cmp_func(sk, comp) \ + ((int (*)(const X509_TRUST **a, const X509_TRUST **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_TRUST **a, const X509_TRUST **b), \ + comp))) + +#define sk_X509_TRUST_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_TRUST) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_TRUST *(*)(X509_TRUST *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_TRUST *), free_func))) + +/* X509_VERIFY_PARAM */ +#define sk_X509_VERIFY_PARAM_new(comp) \ + ((STACK_OF(X509_VERIFY_PARAM) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_VERIFY_PARAM **a, const X509_VERIFY_PARAM **b), \ + comp))) + +#define sk_X509_VERIFY_PARAM_new_null() \ + ((STACK_OF(X509_VERIFY_PARAM) *)sk_new_null()) + +#define sk_X509_VERIFY_PARAM_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)) + +#define sk_X509_VERIFY_PARAM_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)); + +#define sk_X509_VERIFY_PARAM_value(sk, i) \ + ((X509_VERIFY_PARAM *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk), (i))) + +#define sk_X509_VERIFY_PARAM_set(sk, i, p) \ + ((X509_VERIFY_PARAM *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), (i), \ + CHECKED_CAST(void *, X509_VERIFY_PARAM *, p))) + +#define sk_X509_VERIFY_PARAM_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)) + +#define sk_X509_VERIFY_PARAM_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_VERIFY_PARAM *), \ + free_func)) + +#define sk_X509_VERIFY_PARAM_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(void *, X509_VERIFY_PARAM *, p), (where)) + +#define sk_X509_VERIFY_PARAM_delete(sk, where) \ + ((X509_VERIFY_PARAM *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), (where))) + +#define sk_X509_VERIFY_PARAM_delete_ptr(sk, p) \ + ((X509_VERIFY_PARAM *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(void *, X509_VERIFY_PARAM *, p))) + +#define sk_X509_VERIFY_PARAM_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + (out_index), CHECKED_CAST(void *, X509_VERIFY_PARAM *, p)) + +#define sk_X509_VERIFY_PARAM_shift(sk) \ + ((X509_VERIFY_PARAM *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk))) + +#define sk_X509_VERIFY_PARAM_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(void *, X509_VERIFY_PARAM *, p)) + +#define sk_X509_VERIFY_PARAM_pop(sk) \ + ((X509_VERIFY_PARAM *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk))) + +#define sk_X509_VERIFY_PARAM_dup(sk) \ + ((STACK_OF(X509_VERIFY_PARAM) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk))) + +#define sk_X509_VERIFY_PARAM_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)) + +#define sk_X509_VERIFY_PARAM_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk)) + +#define sk_X509_VERIFY_PARAM_set_cmp_func(sk, comp) \ + ((int (*)(const X509_VERIFY_PARAM **a, const X509_VERIFY_PARAM **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_VERIFY_PARAM **a, \ + const X509_VERIFY_PARAM **b), \ + comp))) + +#define sk_X509_VERIFY_PARAM_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_VERIFY_PARAM) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + X509_VERIFY_PARAM *(*)(X509_VERIFY_PARAM *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_VERIFY_PARAM *), \ + free_func))) + +/* void */ +#define sk_void_new(comp) \ + ((STACK_OF(void)*)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const void **a, const void **b), comp))) + +#define sk_void_new_null() ((STACK_OF(void)*)sk_new_null()) + +#define sk_void_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)) + +#define sk_void_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)); + +#define sk_void_value(sk, i) \ + ((void *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(void) *, sk), (i))) + +#define sk_void_set(sk, i, p) \ + ((void *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (i), \ + CHECKED_CAST(void *, void *, p))) + +#define sk_void_free(sk) sk_free(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)) + +#define sk_void_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(void *), free_func)) + +#define sk_void_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), \ + CHECKED_CAST(void *, void *, p), (where)) + +#define sk_void_delete(sk, where) \ + ((void *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (where))) + +#define sk_void_delete_ptr(sk, p) \ + ((void *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \ + CHECKED_CAST(void *, void *, p))) + +#define sk_void_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), (out_index), \ + CHECKED_CAST(void *, void *, p)) + +#define sk_void_shift(sk) \ + ((void *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))) + +#define sk_void_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), \ + CHECKED_CAST(void *, void *, p)) + +#define sk_void_pop(sk) \ + ((void *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))) + +#define sk_void_dup(sk) \ + ((STACK_OF(void)*)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(void) *, sk))) + +#define sk_void_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)) + +#define sk_void_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(void) *, sk)) + +#define sk_void_set_cmp_func(sk, comp) \ + ((int (*)(const void **a, const void **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const void **a, const void **b), \ + comp))) + +#define sk_void_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(void)*)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(void) *, sk), \ + CHECKED_CAST(void *(*)(void *), void *(*)(void *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(void *), free_func))) + +/* SRTP_PROTECTION_PROFILE */ +#define sk_SRTP_PROTECTION_PROFILE_new(comp) \ + ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const const SRTP_PROTECTION_PROFILE **a, \ + const const SRTP_PROTECTION_PROFILE **b), \ + comp))) + +#define sk_SRTP_PROTECTION_PROFILE_new_null() \ + ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_new_null()) + +#define sk_SRTP_PROTECTION_PROFILE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) + +#define sk_SRTP_PROTECTION_PROFILE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)); + +#define sk_SRTP_PROTECTION_PROFILE_value(sk, i) \ + ((const SRTP_PROTECTION_PROFILE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + (i))) + +#define sk_SRTP_PROTECTION_PROFILE_set(sk, i, p) \ + ((const SRTP_PROTECTION_PROFILE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), (i), \ + CHECKED_CAST(void *, const SRTP_PROTECTION_PROFILE *, p))) + +#define sk_SRTP_PROTECTION_PROFILE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) + +#define sk_SRTP_PROTECTION_PROFILE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + CHECKED_CAST(void (*)(void *), \ + void (*)(const SRTP_PROTECTION_PROFILE *), free_func)) + +#define sk_SRTP_PROTECTION_PROFILE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + CHECKED_CAST(void *, const SRTP_PROTECTION_PROFILE *, p), (where)) + +#define sk_SRTP_PROTECTION_PROFILE_delete(sk, where) \ + ((const SRTP_PROTECTION_PROFILE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + (where))) + +#define sk_SRTP_PROTECTION_PROFILE_delete_ptr(sk, p) \ + ((const SRTP_PROTECTION_PROFILE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + CHECKED_CAST(void *, const SRTP_PROTECTION_PROFILE *, p))) + +#define sk_SRTP_PROTECTION_PROFILE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + (out_index), \ + CHECKED_CAST(void *, const SRTP_PROTECTION_PROFILE *, p)) + +#define sk_SRTP_PROTECTION_PROFILE_shift(sk) \ + ((const SRTP_PROTECTION_PROFILE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))) + +#define sk_SRTP_PROTECTION_PROFILE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + CHECKED_CAST(void *, const SRTP_PROTECTION_PROFILE *, p)) + +#define sk_SRTP_PROTECTION_PROFILE_pop(sk) \ + ((const SRTP_PROTECTION_PROFILE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))) + +#define sk_SRTP_PROTECTION_PROFILE_dup(sk) \ + ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))) + +#define sk_SRTP_PROTECTION_PROFILE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) + +#define sk_SRTP_PROTECTION_PROFILE_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(_STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) + +#define sk_SRTP_PROTECTION_PROFILE_set_cmp_func(sk, comp) \ + ((int (*)(const SRTP_PROTECTION_PROFILE **a, \ + const SRTP_PROTECTION_PROFILE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const SRTP_PROTECTION_PROFILE **a, \ + const SRTP_PROTECTION_PROFILE **b), \ + comp))) + +#define sk_SRTP_PROTECTION_PROFILE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, \ + sk), \ + CHECKED_CAST(void *(*)(void *), const SRTP_PROTECTION_PROFILE *(*)( \ + const SRTP_PROTECTION_PROFILE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), \ + void (*)(const SRTP_PROTECTION_PROFILE *), free_func))) + +/* SSL_CIPHER */ +#define sk_SSL_CIPHER_new(comp) \ + ((STACK_OF(SSL_CIPHER) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const const SSL_CIPHER **a, const const SSL_CIPHER **b), comp))) + +#define sk_SSL_CIPHER_new_null() ((STACK_OF(SSL_CIPHER) *)sk_new_null()) + +#define sk_SSL_CIPHER_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)) + +#define sk_SSL_CIPHER_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)); + +#define sk_SSL_CIPHER_value(sk, i) \ + ((const SSL_CIPHER *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_CIPHER) *, sk), (i))) + +#define sk_SSL_CIPHER_set(sk, i, p) \ + ((const SSL_CIPHER *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), (i), \ + CHECKED_CAST(void *, const SSL_CIPHER *, p))) + +#define sk_SSL_CIPHER_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)) + +#define sk_SSL_CIPHER_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(const SSL_CIPHER *), free_func)) + +#define sk_SSL_CIPHER_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(void *, const SSL_CIPHER *, p), (where)) + +#define sk_SSL_CIPHER_delete(sk, where) \ + ((const SSL_CIPHER *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), (where))) + +#define sk_SSL_CIPHER_delete_ptr(sk, p) \ + ((const SSL_CIPHER *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(void *, const SSL_CIPHER *, p))) + +#define sk_SSL_CIPHER_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), (out_index), \ + CHECKED_CAST(void *, const SSL_CIPHER *, p)) + +#define sk_SSL_CIPHER_shift(sk) \ + ((const SSL_CIPHER *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk))) + +#define sk_SSL_CIPHER_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(void *, const SSL_CIPHER *, p)) + +#define sk_SSL_CIPHER_pop(sk) \ + ((const SSL_CIPHER *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk))) + +#define sk_SSL_CIPHER_dup(sk) \ + ((STACK_OF(SSL_CIPHER) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_CIPHER) *, sk))) + +#define sk_SSL_CIPHER_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)) + +#define sk_SSL_CIPHER_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(SSL_CIPHER) *, sk)) + +#define sk_SSL_CIPHER_set_cmp_func(sk, comp) \ + ((int (*)(const SSL_CIPHER **a, const SSL_CIPHER **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const SSL_CIPHER **a, const SSL_CIPHER **b), \ + comp))) + +#define sk_SSL_CIPHER_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SSL_CIPHER) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + const SSL_CIPHER *(*)(const SSL_CIPHER *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(const SSL_CIPHER *), \ + free_func))) + +/* OPENSSL_STRING */ +#define sk_OPENSSL_STRING_new(comp) \ + ((STACK_OF(OPENSSL_STRING) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const OPENSSL_STRING *a, const OPENSSL_STRING *b), comp))) + +#define sk_OPENSSL_STRING_new_null() ((STACK_OF(OPENSSL_STRING) *)sk_new_null()) + +#define sk_OPENSSL_STRING_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)) + +#define sk_OPENSSL_STRING_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)); + +#define sk_OPENSSL_STRING_value(sk, i) \ + ((OPENSSL_STRING)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_STRING) *, sk), (i))) + +#define sk_OPENSSL_STRING_set(sk, i, p) \ + ((OPENSSL_STRING)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), (i), \ + CHECKED_CAST(void *, OPENSSL_STRING, p))) + +#define sk_OPENSSL_STRING_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)) + +#define sk_OPENSSL_STRING_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_STRING), free_func)) + +#define sk_OPENSSL_STRING_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(void *, OPENSSL_STRING, p), (where)) + +#define sk_OPENSSL_STRING_delete(sk, where) \ + ((OPENSSL_STRING)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), (where))) + +#define sk_OPENSSL_STRING_delete_ptr(sk, p) \ + ((OPENSSL_STRING)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(void *, OPENSSL_STRING, p))) + +#define sk_OPENSSL_STRING_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), (out_index), \ + CHECKED_CAST(void *, OPENSSL_STRING, p)) + +#define sk_OPENSSL_STRING_shift(sk) \ + ((OPENSSL_STRING)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk))) + +#define sk_OPENSSL_STRING_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(void *, OPENSSL_STRING, p)) + +#define sk_OPENSSL_STRING_pop(sk) \ + ((OPENSSL_STRING)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk))) + +#define sk_OPENSSL_STRING_dup(sk) \ + ((STACK_OF(OPENSSL_STRING) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_STRING) *, sk))) + +#define sk_OPENSSL_STRING_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)) + +#define sk_OPENSSL_STRING_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_STRING) *, sk)) + +#define sk_OPENSSL_STRING_set_cmp_func(sk, comp) \ + ((int (*)(const OPENSSL_STRING **a, const OPENSSL_STRING **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const OPENSSL_STRING **a, \ + const OPENSSL_STRING **b), \ + comp))) + +#define sk_OPENSSL_STRING_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(OPENSSL_STRING) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(void *(*)(void *), OPENSSL_STRING (*)(OPENSSL_STRING), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_STRING), free_func))) + +/* OPENSSL_BLOCK */ +#define sk_OPENSSL_BLOCK_new(comp) \ + ((STACK_OF(OPENSSL_BLOCK) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const OPENSSL_BLOCK *a, const OPENSSL_BLOCK *b), \ + comp))) + +#define sk_OPENSSL_BLOCK_new_null() ((STACK_OF(OPENSSL_BLOCK) *)sk_new_null()) + +#define sk_OPENSSL_BLOCK_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)) + +#define sk_OPENSSL_BLOCK_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)); + +#define sk_OPENSSL_BLOCK_value(sk, i) \ + ((OPENSSL_BLOCK)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk), (i))) + +#define sk_OPENSSL_BLOCK_set(sk, i, p) \ + ((OPENSSL_BLOCK)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), (i), \ + CHECKED_CAST(void *, OPENSSL_BLOCK, p))) + +#define sk_OPENSSL_BLOCK_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)) + +#define sk_OPENSSL_BLOCK_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_BLOCK), free_func)) + +#define sk_OPENSSL_BLOCK_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(void *, OPENSSL_BLOCK, p), (where)) + +#define sk_OPENSSL_BLOCK_delete(sk, where) \ + ((OPENSSL_BLOCK)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), (where))) + +#define sk_OPENSSL_BLOCK_delete_ptr(sk, p) \ + ((OPENSSL_BLOCK)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(void *, OPENSSL_BLOCK, p))) + +#define sk_OPENSSL_BLOCK_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), (out_index), \ + CHECKED_CAST(void *, OPENSSL_BLOCK, p)) + +#define sk_OPENSSL_BLOCK_shift(sk) \ + ((OPENSSL_BLOCK)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk))) + +#define sk_OPENSSL_BLOCK_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(void *, OPENSSL_BLOCK, p)) + +#define sk_OPENSSL_BLOCK_pop(sk) \ + ((OPENSSL_BLOCK)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk))) + +#define sk_OPENSSL_BLOCK_dup(sk) \ + ((STACK_OF(OPENSSL_BLOCK) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk))) + +#define sk_OPENSSL_BLOCK_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)) + +#define sk_OPENSSL_BLOCK_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk)) + +#define sk_OPENSSL_BLOCK_set_cmp_func(sk, comp) \ + ((int (*)(const OPENSSL_BLOCK **a, const OPENSSL_BLOCK **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const OPENSSL_BLOCK **a, const OPENSSL_BLOCK **b), \ + comp))) + +#define sk_OPENSSL_BLOCK_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(OPENSSL_BLOCK) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(void *(*)(void *), OPENSSL_BLOCK (*)(OPENSSL_BLOCK), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_BLOCK), free_func))) diff --git a/project/jni/boringssl/include/openssl/thread.h b/project/jni/boringssl/include/openssl/thread.h new file mode 100644 index 000000000..568a85833 --- /dev/null +++ b/project/jni/boringssl/include/openssl/thread.h @@ -0,0 +1,173 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_THREAD_H +#define OPENSSL_HEADER_THREAD_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#if defined(OPENSSL_NO_THREADS) +typedef struct crypto_mutex_st {} CRYPTO_MUTEX; +#elif defined(OPENSSL_WINDOWS) +/* CRYPTO_MUTEX can appear in public header files so we really don't want to + * pull in windows.h. It's statically asserted that this structure is large + * enough to contain a Windows CRITICAL_SECTION by thread_win.c. */ +typedef union crypto_mutex_st { + double alignment; + uint8_t padding[4*sizeof(void*) + 2*sizeof(int)]; +} CRYPTO_MUTEX; +#elif defined(__MACH__) && defined(__APPLE__) +typedef pthread_rwlock_t CRYPTO_MUTEX; +#else +/* It is reasonable to include pthread.h on non-Windows systems, however the + * |pthread_rwlock_t| that we need is hidden under feature flags, and we can't + * ensure that we'll be able to get it. It's statically asserted that this + * structure is large enough to contain a |pthread_rwlock_t| by + * thread_pthread.c. */ +typedef union crypto_mutex_st { + double alignment; + uint8_t padding[3*sizeof(int) + 5*sizeof(unsigned) + 16 + 8]; +} CRYPTO_MUTEX; +#endif + +/* CRYPTO_refcount_t is the type of a reference count. + * + * Since some platforms use C11 atomics to access this, it should have the + * _Atomic qualifier. However, this header is included by C++ programs as well + * as C code that might not set -std=c11. So, in practice, it's not possible to + * do that. Instead we statically assert that the size and native alignment of + * a plain uint32_t and an _Atomic uint32_t are equal in refcount_c11.c. */ +typedef uint32_t CRYPTO_refcount_t; + + +/* Deprecated functions */ + +/* These defines do nothing but are provided to make old code easier to + * compile. */ +#define CRYPTO_LOCK 1 +#define CRYPTO_UNLOCK 2 +#define CRYPTO_READ 4 +#define CRYPTO_WRITE 8 + +/* CRYPTO_num_locks returns one. (This is non-zero that callers who allocate + * sizeof(lock) times this value don't get zero and then fail because malloc(0) + * returned NULL.) */ +OPENSSL_EXPORT int CRYPTO_num_locks(void); + +/* CRYPTO_set_locking_callback does nothing. */ +OPENSSL_EXPORT void CRYPTO_set_locking_callback( + void (*func)(int mode, int lock_num, const char *file, int line)); + +/* CRYPTO_set_add_lock_callback does nothing. */ +OPENSSL_EXPORT void CRYPTO_set_add_lock_callback(int (*func)( + int *num, int amount, int lock_num, const char *file, int line)); + +/* CRYPTO_get_lock_name returns a fixed, dummy string. */ +OPENSSL_EXPORT const char *CRYPTO_get_lock_name(int lock_num); + +/* CRYPTO_THREADID_set_callback returns one. */ +OPENSSL_EXPORT int CRYPTO_THREADID_set_callback( + void (*threadid_func)(CRYPTO_THREADID *threadid)); + +/* CRYPTO_THREADID_set_numeric does nothing. */ +OPENSSL_EXPORT void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, + unsigned long val); + +/* CRYPTO_THREADID_set_pointer does nothing. */ +OPENSSL_EXPORT void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr); + +/* CRYPTO_THREADID_current does nothing. */ +OPENSSL_EXPORT void CRYPTO_THREADID_current(CRYPTO_THREADID *id); + + +/* Private functions. + * + * Some old code calls these functions and so no-op implementations are + * provided. + * + * TODO(fork): cleanup callers and remove. */ + +OPENSSL_EXPORT void CRYPTO_set_id_callback(unsigned long (*func)(void)); + +typedef struct { + int references; + struct CRYPTO_dynlock_value *data; +} CRYPTO_dynlock; + +OPENSSL_EXPORT void CRYPTO_set_dynlock_create_callback( + struct CRYPTO_dynlock_value *(*dyn_create_function)(const char *file, + int line)); + +OPENSSL_EXPORT void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)( + int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)); + +OPENSSL_EXPORT void CRYPTO_set_dynlock_destroy_callback( + void (*dyn_destroy_function)(struct CRYPTO_dynlock_value *l, + const char *file, int line)); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_THREAD_H */ diff --git a/project/jni/boringssl/include/openssl/time_support.h b/project/jni/boringssl/include/openssl/time_support.h new file mode 100644 index 000000000..cec430d32 --- /dev/null +++ b/project/jni/boringssl/include/openssl/time_support.h @@ -0,0 +1,90 @@ +/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL + * project 2001. + * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2008. + */ +/* ==================================================================== + * Copyright (c) 2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_TIME_SUPPORT_H +#define OPENSSL_HEADER_TIME_SUPPORT_H + +#include + + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Wrapper functions for time functions. */ + + +/* OPENSSL_gmtime wraps |gmtime_r|. See the manual page for that function. */ +struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result); + +/* OPENSSL_gmtime_adj updates |tm| by adding |offset_day| days and |offset_sec| + * seconds. */ +int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, long offset_sec); + +/* OPENSSL_gmtime_diff calculates the difference between |from| and |to| and + * outputs the difference as a number of days and seconds in |*out_days| and + * |*out_secs|. */ +int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from, + const struct tm *to); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_TIME_SUPPORT_H */ diff --git a/project/jni/boringssl/include/openssl/tls1.h b/project/jni/boringssl/include/openssl/tls1.h new file mode 100644 index 000000000..92d275224 --- /dev/null +++ b/project/jni/boringssl/include/openssl/tls1.h @@ -0,0 +1,653 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * ECC cipher suite support in OpenSSL originally written by + * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#ifndef OPENSSL_HEADER_TLS1_H +#define OPENSSL_HEADER_TLS1_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES 0 + +#define TLS1_AD_DECRYPTION_FAILED 21 +#define TLS1_AD_RECORD_OVERFLOW 22 +#define TLS1_AD_UNKNOWN_CA 48 /* fatal */ +#define TLS1_AD_ACCESS_DENIED 49 /* fatal */ +#define TLS1_AD_DECODE_ERROR 50 /* fatal */ +#define TLS1_AD_DECRYPT_ERROR 51 +#define TLS1_AD_EXPORT_RESTRICTION 60 /* fatal */ +#define TLS1_AD_PROTOCOL_VERSION 70 /* fatal */ +#define TLS1_AD_INSUFFICIENT_SECURITY 71 /* fatal */ +#define TLS1_AD_INTERNAL_ERROR 80 /* fatal */ +#define TLS1_AD_USER_CANCELLED 90 +#define TLS1_AD_NO_RENEGOTIATION 100 +/* codes 110-114 are from RFC3546 */ +#define TLS1_AD_UNSUPPORTED_EXTENSION 110 +#define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111 +#define TLS1_AD_UNRECOGNIZED_NAME 112 +#define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113 +#define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114 +#define TLS1_AD_UNKNOWN_PSK_IDENTITY 115 /* fatal */ + +/* ExtensionType values from RFC3546 / RFC4366 / RFC6066 */ +#define TLSEXT_TYPE_server_name 0 +#define TLSEXT_TYPE_max_fragment_length 1 +#define TLSEXT_TYPE_client_certificate_url 2 +#define TLSEXT_TYPE_trusted_ca_keys 3 +#define TLSEXT_TYPE_truncated_hmac 4 +#define TLSEXT_TYPE_status_request 5 +/* ExtensionType values from RFC4681 */ +#define TLSEXT_TYPE_user_mapping 6 + +/* ExtensionType values from RFC5878 */ +#define TLSEXT_TYPE_client_authz 7 +#define TLSEXT_TYPE_server_authz 8 + +/* ExtensionType values from RFC6091 */ +#define TLSEXT_TYPE_cert_type 9 + +/* ExtensionType values from RFC4492 */ +#define TLSEXT_TYPE_elliptic_curves 10 +#define TLSEXT_TYPE_ec_point_formats 11 + +/* ExtensionType value from RFC5054 */ +#define TLSEXT_TYPE_srp 12 + +/* ExtensionType values from RFC5246 */ +#define TLSEXT_TYPE_signature_algorithms 13 + +/* ExtensionType value from RFC5764 */ +#define TLSEXT_TYPE_srtp 14 + +/* ExtensionType value from RFC5620 */ +#define TLSEXT_TYPE_heartbeat 15 + +/* ExtensionType value from RFC7301 */ +#define TLSEXT_TYPE_application_layer_protocol_negotiation 16 + +/* ExtensionType value from RFC7685 */ +#define TLSEXT_TYPE_padding 21 + +/* https://tools.ietf.org/html/draft-ietf-tls-session-hash-01 */ +#define TLSEXT_TYPE_extended_master_secret 23 + +/* ExtensionType value from RFC4507 */ +#define TLSEXT_TYPE_session_ticket 35 + +/* ExtensionType value from RFC5746 */ +#define TLSEXT_TYPE_renegotiate 0xff01 + +/* ExtensionType value from RFC6962 */ +#define TLSEXT_TYPE_certificate_timestamp 18 + +/* This is not an IANA defined extension number */ +#define TLSEXT_TYPE_next_proto_neg 13172 + +/* This is not an IANA defined extension number */ +#define TLSEXT_TYPE_channel_id 30032 + +/* status request value from RFC 3546 */ +#define TLSEXT_STATUSTYPE_ocsp 1 + +/* ECPointFormat values from RFC 4492 */ +#define TLSEXT_ECPOINTFORMAT_uncompressed 0 +#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime 1 +#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2 2 + +/* Signature and hash algorithms from RFC 5246 */ + +#define TLSEXT_signature_anonymous 0 +#define TLSEXT_signature_rsa 1 +#define TLSEXT_signature_dsa 2 +#define TLSEXT_signature_ecdsa 3 + +#define TLSEXT_hash_none 0 +#define TLSEXT_hash_md5 1 +#define TLSEXT_hash_sha1 2 +#define TLSEXT_hash_sha224 3 +#define TLSEXT_hash_sha256 4 +#define TLSEXT_hash_sha384 5 +#define TLSEXT_hash_sha512 6 + +/* Flag set for unrecognised algorithms */ +#define TLSEXT_nid_unknown 0x1000000 + +/* ECC curves */ + +#define TLSEXT_curve_P_256 23 +#define TLSEXT_curve_P_384 24 + + +#define TLSEXT_MAXLEN_host_name 255 + +/* PSK ciphersuites from 4279 */ +#define TLS1_CK_PSK_WITH_RC4_128_SHA 0x0300008A +#define TLS1_CK_PSK_WITH_3DES_EDE_CBC_SHA 0x0300008B +#define TLS1_CK_PSK_WITH_AES_128_CBC_SHA 0x0300008C +#define TLS1_CK_PSK_WITH_AES_256_CBC_SHA 0x0300008D + +/* PSK ciphersuites from RFC 5489 */ +#define TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA 0x0300C035 +#define TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA 0x0300C036 + +/* Additional TLS ciphersuites from expired Internet Draft + * draft-ietf-tls-56-bit-ciphersuites-01.txt + * (available if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES is defined, see + * s3_lib.c). We actually treat them like SSL 3.0 ciphers, which we probably + * shouldn't. Note that the first two are actually not in the IDs. */ +#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_MD5 0x03000060 /* not in ID */ +#define TLS1_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 0x03000061 /* not in ID */ +#define TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA 0x03000062 +#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA 0x03000063 +#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_SHA 0x03000064 +#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA 0x03000065 +#define TLS1_CK_DHE_DSS_WITH_RC4_128_SHA 0x03000066 + +/* AES ciphersuites from RFC3268 */ + +#define TLS1_CK_RSA_WITH_AES_128_SHA 0x0300002F +#define TLS1_CK_DH_DSS_WITH_AES_128_SHA 0x03000030 +#define TLS1_CK_DH_RSA_WITH_AES_128_SHA 0x03000031 +#define TLS1_CK_DHE_DSS_WITH_AES_128_SHA 0x03000032 +#define TLS1_CK_DHE_RSA_WITH_AES_128_SHA 0x03000033 +#define TLS1_CK_ADH_WITH_AES_128_SHA 0x03000034 + +#define TLS1_CK_RSA_WITH_AES_256_SHA 0x03000035 +#define TLS1_CK_DH_DSS_WITH_AES_256_SHA 0x03000036 +#define TLS1_CK_DH_RSA_WITH_AES_256_SHA 0x03000037 +#define TLS1_CK_DHE_DSS_WITH_AES_256_SHA 0x03000038 +#define TLS1_CK_DHE_RSA_WITH_AES_256_SHA 0x03000039 +#define TLS1_CK_ADH_WITH_AES_256_SHA 0x0300003A + +/* TLS v1.2 ciphersuites */ +#define TLS1_CK_RSA_WITH_NULL_SHA256 0x0300003B +#define TLS1_CK_RSA_WITH_AES_128_SHA256 0x0300003C +#define TLS1_CK_RSA_WITH_AES_256_SHA256 0x0300003D +#define TLS1_CK_DH_DSS_WITH_AES_128_SHA256 0x0300003E +#define TLS1_CK_DH_RSA_WITH_AES_128_SHA256 0x0300003F +#define TLS1_CK_DHE_DSS_WITH_AES_128_SHA256 0x03000040 + +/* Camellia ciphersuites from RFC4132 */ +#define TLS1_CK_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000041 +#define TLS1_CK_DH_DSS_WITH_CAMELLIA_128_CBC_SHA 0x03000042 +#define TLS1_CK_DH_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000043 +#define TLS1_CK_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA 0x03000044 +#define TLS1_CK_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000045 +#define TLS1_CK_ADH_WITH_CAMELLIA_128_CBC_SHA 0x03000046 + +/* TLS v1.2 ciphersuites */ +#define TLS1_CK_DHE_RSA_WITH_AES_128_SHA256 0x03000067 +#define TLS1_CK_DH_DSS_WITH_AES_256_SHA256 0x03000068 +#define TLS1_CK_DH_RSA_WITH_AES_256_SHA256 0x03000069 +#define TLS1_CK_DHE_DSS_WITH_AES_256_SHA256 0x0300006A +#define TLS1_CK_DHE_RSA_WITH_AES_256_SHA256 0x0300006B +#define TLS1_CK_ADH_WITH_AES_128_SHA256 0x0300006C +#define TLS1_CK_ADH_WITH_AES_256_SHA256 0x0300006D + +/* Camellia ciphersuites from RFC4132 */ +#define TLS1_CK_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000084 +#define TLS1_CK_DH_DSS_WITH_CAMELLIA_256_CBC_SHA 0x03000085 +#define TLS1_CK_DH_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000086 +#define TLS1_CK_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA 0x03000087 +#define TLS1_CK_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000088 +#define TLS1_CK_ADH_WITH_CAMELLIA_256_CBC_SHA 0x03000089 + +/* SEED ciphersuites from RFC4162 */ +#define TLS1_CK_RSA_WITH_SEED_SHA 0x03000096 +#define TLS1_CK_DH_DSS_WITH_SEED_SHA 0x03000097 +#define TLS1_CK_DH_RSA_WITH_SEED_SHA 0x03000098 +#define TLS1_CK_DHE_DSS_WITH_SEED_SHA 0x03000099 +#define TLS1_CK_DHE_RSA_WITH_SEED_SHA 0x0300009A +#define TLS1_CK_ADH_WITH_SEED_SHA 0x0300009B + +/* TLS v1.2 GCM ciphersuites from RFC5288 */ +#define TLS1_CK_RSA_WITH_AES_128_GCM_SHA256 0x0300009C +#define TLS1_CK_RSA_WITH_AES_256_GCM_SHA384 0x0300009D +#define TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256 0x0300009E +#define TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384 0x0300009F +#define TLS1_CK_DH_RSA_WITH_AES_128_GCM_SHA256 0x030000A0 +#define TLS1_CK_DH_RSA_WITH_AES_256_GCM_SHA384 0x030000A1 +#define TLS1_CK_DHE_DSS_WITH_AES_128_GCM_SHA256 0x030000A2 +#define TLS1_CK_DHE_DSS_WITH_AES_256_GCM_SHA384 0x030000A3 +#define TLS1_CK_DH_DSS_WITH_AES_128_GCM_SHA256 0x030000A4 +#define TLS1_CK_DH_DSS_WITH_AES_256_GCM_SHA384 0x030000A5 +#define TLS1_CK_ADH_WITH_AES_128_GCM_SHA256 0x030000A6 +#define TLS1_CK_ADH_WITH_AES_256_GCM_SHA384 0x030000A7 + +/* ECC ciphersuites from RFC4492 */ +#define TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA 0x0300C001 +#define TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA 0x0300C002 +#define TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA 0x0300C003 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0x0300C004 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0x0300C005 + +#define TLS1_CK_ECDHE_ECDSA_WITH_NULL_SHA 0x0300C006 +#define TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA 0x0300C007 +#define TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA 0x0300C008 +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0x0300C009 +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0x0300C00A + +#define TLS1_CK_ECDH_RSA_WITH_NULL_SHA 0x0300C00B +#define TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA 0x0300C00C +#define TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA 0x0300C00D +#define TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA 0x0300C00E +#define TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA 0x0300C00F + +#define TLS1_CK_ECDHE_RSA_WITH_NULL_SHA 0x0300C010 +#define TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA 0x0300C011 +#define TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA 0x0300C012 +#define TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA 0x0300C013 +#define TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA 0x0300C014 + +#define TLS1_CK_ECDH_anon_WITH_NULL_SHA 0x0300C015 +#define TLS1_CK_ECDH_anon_WITH_RC4_128_SHA 0x0300C016 +#define TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA 0x0300C017 +#define TLS1_CK_ECDH_anon_WITH_AES_128_CBC_SHA 0x0300C018 +#define TLS1_CK_ECDH_anon_WITH_AES_256_CBC_SHA 0x0300C019 + +/* SRP ciphersuites from RFC 5054 */ +#define TLS1_CK_SRP_SHA_WITH_3DES_EDE_CBC_SHA 0x0300C01A +#define TLS1_CK_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA 0x0300C01B +#define TLS1_CK_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA 0x0300C01C +#define TLS1_CK_SRP_SHA_WITH_AES_128_CBC_SHA 0x0300C01D +#define TLS1_CK_SRP_SHA_RSA_WITH_AES_128_CBC_SHA 0x0300C01E +#define TLS1_CK_SRP_SHA_DSS_WITH_AES_128_CBC_SHA 0x0300C01F +#define TLS1_CK_SRP_SHA_WITH_AES_256_CBC_SHA 0x0300C020 +#define TLS1_CK_SRP_SHA_RSA_WITH_AES_256_CBC_SHA 0x0300C021 +#define TLS1_CK_SRP_SHA_DSS_WITH_AES_256_CBC_SHA 0x0300C022 + +/* ECDH HMAC based ciphersuites from RFC5289 */ + +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256 0x0300C023 +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384 0x0300C024 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_SHA256 0x0300C025 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_SHA384 0x0300C026 +#define TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256 0x0300C027 +#define TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384 0x0300C028 +#define TLS1_CK_ECDH_RSA_WITH_AES_128_SHA256 0x0300C029 +#define TLS1_CK_ECDH_RSA_WITH_AES_256_SHA384 0x0300C02A + +/* ECDH GCM based ciphersuites from RFC5289 */ +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0x0300C02B +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0x0300C02C +#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0x0300C02D +#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 0x0300C02E +#define TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0x0300C02F +#define TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0x0300C030 +#define TLS1_CK_ECDH_RSA_WITH_AES_128_GCM_SHA256 0x0300C031 +#define TLS1_CK_ECDH_RSA_WITH_AES_256_GCM_SHA384 0x0300C032 + +#define TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD 0x0300CC13 +#define TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD 0x0300CC14 + +#define TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0x0300CCA8 +#define TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0x0300CCA9 +#define TLS1_CK_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0x0300CCAC + +/* TODO(davidben): Remove this. Historically, the CK names for CHACHA20_POLY1305 + * were missing 'WITH' and 'SHA256'. */ +#define TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305 \ + TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + +/* XXX + * Inconsistency alert: + * The OpenSSL names of ciphers with ephemeral DH here include the string + * "DHE", while elsewhere it has always been "EDH". + * (The alias for the list of all such ciphers also is "EDH".) + * The specifications speak of "EDH"; maybe we should allow both forms + * for everything. */ +#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_MD5 "EXP1024-RC4-MD5" +#define TLS1_TXT_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 "EXP1024-RC2-CBC-MD5" +#define TLS1_TXT_RSA_EXPORT1024_WITH_DES_CBC_SHA "EXP1024-DES-CBC-SHA" +#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA \ + "EXP1024-DHE-DSS-DES-CBC-SHA" +#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_SHA "EXP1024-RC4-SHA" +#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA "EXP1024-DHE-DSS-RC4-SHA" +#define TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA "DHE-DSS-RC4-SHA" + +/* AES ciphersuites from RFC3268 */ +#define TLS1_TXT_RSA_WITH_AES_128_SHA "AES128-SHA" +#define TLS1_TXT_DH_DSS_WITH_AES_128_SHA "DH-DSS-AES128-SHA" +#define TLS1_TXT_DH_RSA_WITH_AES_128_SHA "DH-RSA-AES128-SHA" +#define TLS1_TXT_DHE_DSS_WITH_AES_128_SHA "DHE-DSS-AES128-SHA" +#define TLS1_TXT_DHE_RSA_WITH_AES_128_SHA "DHE-RSA-AES128-SHA" +#define TLS1_TXT_ADH_WITH_AES_128_SHA "ADH-AES128-SHA" + +#define TLS1_TXT_RSA_WITH_AES_256_SHA "AES256-SHA" +#define TLS1_TXT_DH_DSS_WITH_AES_256_SHA "DH-DSS-AES256-SHA" +#define TLS1_TXT_DH_RSA_WITH_AES_256_SHA "DH-RSA-AES256-SHA" +#define TLS1_TXT_DHE_DSS_WITH_AES_256_SHA "DHE-DSS-AES256-SHA" +#define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA "DHE-RSA-AES256-SHA" +#define TLS1_TXT_ADH_WITH_AES_256_SHA "ADH-AES256-SHA" + +/* ECC ciphersuites from RFC4492 */ +#define TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA "ECDH-ECDSA-NULL-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA "ECDH-ECDSA-RC4-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA "ECDH-ECDSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA "ECDH-ECDSA-AES128-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA "ECDH-ECDSA-AES256-SHA" + +#define TLS1_TXT_ECDHE_ECDSA_WITH_NULL_SHA "ECDHE-ECDSA-NULL-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA "ECDHE-ECDSA-RC4-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA "ECDHE-ECDSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA "ECDHE-ECDSA-AES128-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA "ECDHE-ECDSA-AES256-SHA" + +#define TLS1_TXT_ECDH_RSA_WITH_NULL_SHA "ECDH-RSA-NULL-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA "ECDH-RSA-RC4-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA "ECDH-RSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA "ECDH-RSA-AES128-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA "ECDH-RSA-AES256-SHA" + +#define TLS1_TXT_ECDHE_RSA_WITH_NULL_SHA "ECDHE-RSA-NULL-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA "ECDHE-RSA-RC4-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA "ECDHE-RSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA "ECDHE-RSA-AES128-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA "ECDHE-RSA-AES256-SHA" + +#define TLS1_TXT_ECDH_anon_WITH_NULL_SHA "AECDH-NULL-SHA" +#define TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA "AECDH-RC4-SHA" +#define TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA "AECDH-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_anon_WITH_AES_128_CBC_SHA "AECDH-AES128-SHA" +#define TLS1_TXT_ECDH_anon_WITH_AES_256_CBC_SHA "AECDH-AES256-SHA" + +/* PSK ciphersuites from RFC 4279 */ +#define TLS1_TXT_PSK_WITH_RC4_128_SHA "PSK-RC4-SHA" +#define TLS1_TXT_PSK_WITH_3DES_EDE_CBC_SHA "PSK-3DES-EDE-CBC-SHA" +#define TLS1_TXT_PSK_WITH_AES_128_CBC_SHA "PSK-AES128-CBC-SHA" +#define TLS1_TXT_PSK_WITH_AES_256_CBC_SHA "PSK-AES256-CBC-SHA" + +/* PSK ciphersuites from RFC 5489 */ +#define TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA "ECDHE-PSK-AES128-CBC-SHA" +#define TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA "ECDHE-PSK-AES256-CBC-SHA" + +/* SRP ciphersuite from RFC 5054 */ +#define TLS1_TXT_SRP_SHA_WITH_3DES_EDE_CBC_SHA "SRP-3DES-EDE-CBC-SHA" +#define TLS1_TXT_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA "SRP-RSA-3DES-EDE-CBC-SHA" +#define TLS1_TXT_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA "SRP-DSS-3DES-EDE-CBC-SHA" +#define TLS1_TXT_SRP_SHA_WITH_AES_128_CBC_SHA "SRP-AES-128-CBC-SHA" +#define TLS1_TXT_SRP_SHA_RSA_WITH_AES_128_CBC_SHA "SRP-RSA-AES-128-CBC-SHA" +#define TLS1_TXT_SRP_SHA_DSS_WITH_AES_128_CBC_SHA "SRP-DSS-AES-128-CBC-SHA" +#define TLS1_TXT_SRP_SHA_WITH_AES_256_CBC_SHA "SRP-AES-256-CBC-SHA" +#define TLS1_TXT_SRP_SHA_RSA_WITH_AES_256_CBC_SHA "SRP-RSA-AES-256-CBC-SHA" +#define TLS1_TXT_SRP_SHA_DSS_WITH_AES_256_CBC_SHA "SRP-DSS-AES-256-CBC-SHA" + +/* Camellia ciphersuites from RFC4132 */ +#define TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA "CAMELLIA128-SHA" +#define TLS1_TXT_DH_DSS_WITH_CAMELLIA_128_CBC_SHA "DH-DSS-CAMELLIA128-SHA" +#define TLS1_TXT_DH_RSA_WITH_CAMELLIA_128_CBC_SHA "DH-RSA-CAMELLIA128-SHA" +#define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA "DHE-DSS-CAMELLIA128-SHA" +#define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA "DHE-RSA-CAMELLIA128-SHA" +#define TLS1_TXT_ADH_WITH_CAMELLIA_128_CBC_SHA "ADH-CAMELLIA128-SHA" + +#define TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA "CAMELLIA256-SHA" +#define TLS1_TXT_DH_DSS_WITH_CAMELLIA_256_CBC_SHA "DH-DSS-CAMELLIA256-SHA" +#define TLS1_TXT_DH_RSA_WITH_CAMELLIA_256_CBC_SHA "DH-RSA-CAMELLIA256-SHA" +#define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA "DHE-DSS-CAMELLIA256-SHA" +#define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA "DHE-RSA-CAMELLIA256-SHA" +#define TLS1_TXT_ADH_WITH_CAMELLIA_256_CBC_SHA "ADH-CAMELLIA256-SHA" + +/* SEED ciphersuites from RFC4162 */ +#define TLS1_TXT_RSA_WITH_SEED_SHA "SEED-SHA" +#define TLS1_TXT_DH_DSS_WITH_SEED_SHA "DH-DSS-SEED-SHA" +#define TLS1_TXT_DH_RSA_WITH_SEED_SHA "DH-RSA-SEED-SHA" +#define TLS1_TXT_DHE_DSS_WITH_SEED_SHA "DHE-DSS-SEED-SHA" +#define TLS1_TXT_DHE_RSA_WITH_SEED_SHA "DHE-RSA-SEED-SHA" +#define TLS1_TXT_ADH_WITH_SEED_SHA "ADH-SEED-SHA" + +/* TLS v1.2 ciphersuites */ +#define TLS1_TXT_RSA_WITH_NULL_SHA256 "NULL-SHA256" +#define TLS1_TXT_RSA_WITH_AES_128_SHA256 "AES128-SHA256" +#define TLS1_TXT_RSA_WITH_AES_256_SHA256 "AES256-SHA256" +#define TLS1_TXT_DH_DSS_WITH_AES_128_SHA256 "DH-DSS-AES128-SHA256" +#define TLS1_TXT_DH_RSA_WITH_AES_128_SHA256 "DH-RSA-AES128-SHA256" +#define TLS1_TXT_DHE_DSS_WITH_AES_128_SHA256 "DHE-DSS-AES128-SHA256" +#define TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 "DHE-RSA-AES128-SHA256" +#define TLS1_TXT_DH_DSS_WITH_AES_256_SHA256 "DH-DSS-AES256-SHA256" +#define TLS1_TXT_DH_RSA_WITH_AES_256_SHA256 "DH-RSA-AES256-SHA256" +#define TLS1_TXT_DHE_DSS_WITH_AES_256_SHA256 "DHE-DSS-AES256-SHA256" +#define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 "DHE-RSA-AES256-SHA256" +#define TLS1_TXT_ADH_WITH_AES_128_SHA256 "ADH-AES128-SHA256" +#define TLS1_TXT_ADH_WITH_AES_256_SHA256 "ADH-AES256-SHA256" + +/* TLS v1.2 GCM ciphersuites from RFC5288 */ +#define TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256 "AES128-GCM-SHA256" +#define TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384 "AES256-GCM-SHA384" +#define TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 "DHE-RSA-AES128-GCM-SHA256" +#define TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 "DHE-RSA-AES256-GCM-SHA384" +#define TLS1_TXT_DH_RSA_WITH_AES_128_GCM_SHA256 "DH-RSA-AES128-GCM-SHA256" +#define TLS1_TXT_DH_RSA_WITH_AES_256_GCM_SHA384 "DH-RSA-AES256-GCM-SHA384" +#define TLS1_TXT_DHE_DSS_WITH_AES_128_GCM_SHA256 "DHE-DSS-AES128-GCM-SHA256" +#define TLS1_TXT_DHE_DSS_WITH_AES_256_GCM_SHA384 "DHE-DSS-AES256-GCM-SHA384" +#define TLS1_TXT_DH_DSS_WITH_AES_128_GCM_SHA256 "DH-DSS-AES128-GCM-SHA256" +#define TLS1_TXT_DH_DSS_WITH_AES_256_GCM_SHA384 "DH-DSS-AES256-GCM-SHA384" +#define TLS1_TXT_ADH_WITH_AES_128_GCM_SHA256 "ADH-AES128-GCM-SHA256" +#define TLS1_TXT_ADH_WITH_AES_256_GCM_SHA384 "ADH-AES256-GCM-SHA384" + +/* ECDH HMAC based ciphersuites from RFC5289 */ + +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256 "ECDHE-ECDSA-AES128-SHA256" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384 "ECDHE-ECDSA-AES256-SHA384" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_SHA256 "ECDH-ECDSA-AES128-SHA256" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_SHA384 "ECDH-ECDSA-AES256-SHA384" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 "ECDHE-RSA-AES128-SHA256" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 "ECDHE-RSA-AES256-SHA384" +#define TLS1_TXT_ECDH_RSA_WITH_AES_128_SHA256 "ECDH-RSA-AES128-SHA256" +#define TLS1_TXT_ECDH_RSA_WITH_AES_256_SHA384 "ECDH-RSA-AES256-SHA384" + +/* ECDH GCM based ciphersuites from RFC5289 */ +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 \ + "ECDHE-ECDSA-AES128-GCM-SHA256" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 \ + "ECDHE-ECDSA-AES256-GCM-SHA384" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 \ + "ECDH-ECDSA-AES128-GCM-SHA256" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 \ + "ECDH-ECDSA-AES256-GCM-SHA384" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 "ECDHE-RSA-AES128-GCM-SHA256" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 "ECDHE-RSA-AES256-GCM-SHA384" +#define TLS1_TXT_ECDH_RSA_WITH_AES_128_GCM_SHA256 "ECDH-RSA-AES128-GCM-SHA256" +#define TLS1_TXT_ECDH_RSA_WITH_AES_256_GCM_SHA384 "ECDH-RSA-AES256-GCM-SHA384" + +/* For convenience, the old and new CHACHA20_POLY1305 ciphers have the same + * name. In cipher strings, both will be selected. This is temporary and will be + * removed when the pre-standard construction is removed. */ +#define TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305_OLD \ + "ECDHE-RSA-CHACHA20-POLY1305" +#define TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_OLD \ + "ECDHE-ECDSA-CHACHA20-POLY1305" + +#define TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 \ + "ECDHE-RSA-CHACHA20-POLY1305" +#define TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 \ + "ECDHE-ECDSA-CHACHA20-POLY1305" +#define TLS1_TXT_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 \ + "ECDHE-PSK-CHACHA20-POLY1305" + +/* TODO(davidben): Remove this. Historically, the TXT names for CHACHA20_POLY1305 + * were missing 'SHA256'. */ +#define TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 \ + TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + +#define TLS_CT_RSA_SIGN 1 +#define TLS_CT_DSS_SIGN 2 +#define TLS_CT_RSA_FIXED_DH 3 +#define TLS_CT_DSS_FIXED_DH 4 +#define TLS_CT_ECDSA_SIGN 64 +#define TLS_CT_RSA_FIXED_ECDH 65 +#define TLS_CT_ECDSA_FIXED_ECDH 66 + +#define TLS_MD_MAX_CONST_SIZE 20 +#define TLS_MD_CLIENT_FINISH_CONST "client finished" +#define TLS_MD_CLIENT_FINISH_CONST_SIZE 15 +#define TLS_MD_SERVER_FINISH_CONST "server finished" +#define TLS_MD_SERVER_FINISH_CONST_SIZE 15 +#define TLS_MD_KEY_EXPANSION_CONST "key expansion" +#define TLS_MD_KEY_EXPANSION_CONST_SIZE 13 +#define TLS_MD_CLIENT_WRITE_KEY_CONST "client write key" +#define TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE 16 +#define TLS_MD_SERVER_WRITE_KEY_CONST "server write key" +#define TLS_MD_SERVER_WRITE_KEY_CONST_SIZE 16 +#define TLS_MD_IV_BLOCK_CONST "IV block" +#define TLS_MD_IV_BLOCK_CONST_SIZE 8 +#define TLS_MD_MASTER_SECRET_CONST "master secret" +#define TLS_MD_MASTER_SECRET_CONST_SIZE 13 +#define TLS_MD_EXTENDED_MASTER_SECRET_CONST "extended master secret" +#define TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE 22 + + +#ifdef __cplusplus +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_TLS1_H */ diff --git a/project/jni/boringssl/include/openssl/type_check.h b/project/jni/boringssl/include/openssl/type_check.h new file mode 100644 index 000000000..674913a35 --- /dev/null +++ b/project/jni/boringssl/include/openssl/type_check.h @@ -0,0 +1,91 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_TYPE_CHECK_H +#define OPENSSL_HEADER_TYPE_CHECK_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* This header file contains some common macros for enforcing type checking. + * Several, common OpenSSL structures (i.e. stack and lhash) operate on void + * pointers, but we wish to have type checking when they are used with a + * specific type. */ + +/* CHECKED_CAST casts |p| from type |from| to type |to|. */ +#define CHECKED_CAST(to, from, p) ((to) (1 ? (p) : (from)0)) + +/* CHECKED_PTR_OF casts a given pointer to void* and statically checks that it + * was a pointer to |type|. */ +#define CHECKED_PTR_OF(type, p) CHECKED_CAST(void*, type*, (p)) + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#define OPENSSL_COMPILE_ASSERT(cond, msg) _Static_assert(cond, #msg) +#else +#define OPENSSL_COMPILE_ASSERT(cond, msg) \ + typedef char OPENSSL_COMPILE_ASSERT_##msg[((cond) ? 1 : -1)] +#endif + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_TYPE_CHECK_H */ diff --git a/project/jni/boringssl/include/openssl/x509.h b/project/jni/boringssl/include/openssl/x509.h new file mode 100644 index 000000000..a5aaf31b9 --- /dev/null +++ b/project/jni/boringssl/include/openssl/x509.h @@ -0,0 +1,1256 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECDH support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#ifndef HEADER_X509_H +#define HEADER_X509_H + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define X509_FILETYPE_PEM 1 +#define X509_FILETYPE_ASN1 2 +#define X509_FILETYPE_DEFAULT 3 + +#define X509v3_KU_DIGITAL_SIGNATURE 0x0080 +#define X509v3_KU_NON_REPUDIATION 0x0040 +#define X509v3_KU_KEY_ENCIPHERMENT 0x0020 +#define X509v3_KU_DATA_ENCIPHERMENT 0x0010 +#define X509v3_KU_KEY_AGREEMENT 0x0008 +#define X509v3_KU_KEY_CERT_SIGN 0x0004 +#define X509v3_KU_CRL_SIGN 0x0002 +#define X509v3_KU_ENCIPHER_ONLY 0x0001 +#define X509v3_KU_DECIPHER_ONLY 0x8000 +#define X509v3_KU_UNDEF 0xffff + +struct X509_objects_st + { + int nid; + int (*a2i)(void); + int (*i2a)(void); + } /* X509_OBJECTS */; + +DECLARE_ASN1_SET_OF(X509_ALGOR) + +typedef STACK_OF(X509_ALGOR) X509_ALGORS; + +struct X509_val_st + { + ASN1_TIME *notBefore; + ASN1_TIME *notAfter; + } /* X509_VAL */; + +struct X509_pubkey_st + { + X509_ALGOR *algor; + ASN1_BIT_STRING *public_key; + EVP_PKEY *pkey; + }; + +struct X509_sig_st + { + X509_ALGOR *algor; + ASN1_OCTET_STRING *digest; + } /* X509_SIG */; + +struct X509_name_entry_st + { + ASN1_OBJECT *object; + ASN1_STRING *value; + int set; + int size; /* temp variable */ + } /* X509_NAME_ENTRY */; + +DECLARE_STACK_OF(X509_NAME_ENTRY) +DECLARE_ASN1_SET_OF(X509_NAME_ENTRY) + +/* we always keep X509_NAMEs in 2 forms. */ +struct X509_name_st + { + STACK_OF(X509_NAME_ENTRY) *entries; + int modified; /* true if 'bytes' needs to be built */ +#ifndef OPENSSL_NO_BUFFER + BUF_MEM *bytes; +#else + char *bytes; +#endif +/* unsigned long hash; Keep the hash around for lookups */ + unsigned char *canon_enc; + int canon_enclen; + } /* X509_NAME */; + +DECLARE_STACK_OF(X509_NAME) + +#define X509_EX_V_NETSCAPE_HACK 0x8000 +#define X509_EX_V_INIT 0x0001 +struct X509_extension_st + { + ASN1_OBJECT *object; + ASN1_BOOLEAN critical; + ASN1_OCTET_STRING *value; + } /* X509_EXTENSION */; + +typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS; + +DECLARE_STACK_OF(X509_EXTENSION) +DECLARE_ASN1_SET_OF(X509_EXTENSION) + +/* a sequence of these are used */ +struct x509_attributes_st + { + ASN1_OBJECT *object; + int single; /* 0 for a set, 1 for a single item (which is wrong) */ + union { + char *ptr; +/* 0 */ STACK_OF(ASN1_TYPE) *set; +/* 1 */ ASN1_TYPE *single; + } value; + } /* X509_ATTRIBUTE */; + +DECLARE_STACK_OF(X509_ATTRIBUTE) +DECLARE_ASN1_SET_OF(X509_ATTRIBUTE) + + +struct X509_req_info_st + { + ASN1_ENCODING enc; + ASN1_INTEGER *version; + X509_NAME *subject; + X509_PUBKEY *pubkey; + /* d=2 hl=2 l= 0 cons: cont: 00 */ + STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */ + } /* X509_REQ_INFO */; + +struct X509_req_st + { + X509_REQ_INFO *req_info; + X509_ALGOR *sig_alg; + ASN1_BIT_STRING *signature; + CRYPTO_refcount_t references; + } /* X509_REQ */; + +struct x509_cinf_st + { + ASN1_INTEGER *version; /* [ 0 ] default of v1 */ + ASN1_INTEGER *serialNumber; + X509_ALGOR *signature; + X509_NAME *issuer; + X509_VAL *validity; + X509_NAME *subject; + X509_PUBKEY *key; + ASN1_BIT_STRING *issuerUID; /* [ 1 ] optional in v2 */ + ASN1_BIT_STRING *subjectUID; /* [ 2 ] optional in v2 */ + STACK_OF(X509_EXTENSION) *extensions; /* [ 3 ] optional in v3 */ + ASN1_ENCODING enc; + } /* X509_CINF */; + +/* This stuff is certificate "auxiliary info" + * it contains details which are useful in certificate + * stores and databases. When used this is tagged onto + * the end of the certificate itself + */ + +struct x509_cert_aux_st + { + STACK_OF(ASN1_OBJECT) *trust; /* trusted uses */ + STACK_OF(ASN1_OBJECT) *reject; /* rejected uses */ + ASN1_UTF8STRING *alias; /* "friendly name" */ + ASN1_OCTET_STRING *keyid; /* key id of private key */ + STACK_OF(X509_ALGOR) *other; /* other unspecified info */ + } /* X509_CERT_AUX */; + +struct x509_st + { + X509_CINF *cert_info; + X509_ALGOR *sig_alg; + ASN1_BIT_STRING *signature; + int valid; + CRYPTO_refcount_t references; + char *name; + CRYPTO_EX_DATA ex_data; + /* These contain copies of various extension values */ + long ex_pathlen; + long ex_pcpathlen; + unsigned long ex_flags; + unsigned long ex_kusage; + unsigned long ex_xkusage; + unsigned long ex_nscert; + ASN1_OCTET_STRING *skid; + AUTHORITY_KEYID *akid; + X509_POLICY_CACHE *policy_cache; + STACK_OF(DIST_POINT) *crldp; + STACK_OF(GENERAL_NAME) *altname; + NAME_CONSTRAINTS *nc; + unsigned char sha1_hash[SHA_DIGEST_LENGTH]; + X509_CERT_AUX *aux; + } /* X509 */; + +DECLARE_STACK_OF(X509) +DECLARE_ASN1_SET_OF(X509) + +/* This is used for a table of trust checking functions */ + +struct x509_trust_st { + int trust; + int flags; + int (*check_trust)(struct x509_trust_st *, X509 *, int); + char *name; + int arg1; + void *arg2; +} /* X509_TRUST */; + +DECLARE_STACK_OF(X509_TRUST) + +struct x509_cert_pair_st { + X509 *forward; + X509 *reverse; +} /* X509_CERT_PAIR */; + +/* standard trust ids */ + +#define X509_TRUST_DEFAULT -1 /* Only valid in purpose settings */ + +#define X509_TRUST_COMPAT 1 +#define X509_TRUST_SSL_CLIENT 2 +#define X509_TRUST_SSL_SERVER 3 +#define X509_TRUST_EMAIL 4 +#define X509_TRUST_OBJECT_SIGN 5 +#define X509_TRUST_OCSP_SIGN 6 +#define X509_TRUST_OCSP_REQUEST 7 +#define X509_TRUST_TSA 8 + +/* Keep these up to date! */ +#define X509_TRUST_MIN 1 +#define X509_TRUST_MAX 8 + + +/* trust_flags values */ +#define X509_TRUST_DYNAMIC 1 +#define X509_TRUST_DYNAMIC_NAME 2 + +/* check_trust return codes */ + +#define X509_TRUST_TRUSTED 1 +#define X509_TRUST_REJECTED 2 +#define X509_TRUST_UNTRUSTED 3 + +/* Flags for X509_print_ex() */ + +#define X509_FLAG_COMPAT 0 +#define X509_FLAG_NO_HEADER 1L +#define X509_FLAG_NO_VERSION (1L << 1) +#define X509_FLAG_NO_SERIAL (1L << 2) +#define X509_FLAG_NO_SIGNAME (1L << 3) +#define X509_FLAG_NO_ISSUER (1L << 4) +#define X509_FLAG_NO_VALIDITY (1L << 5) +#define X509_FLAG_NO_SUBJECT (1L << 6) +#define X509_FLAG_NO_PUBKEY (1L << 7) +#define X509_FLAG_NO_EXTENSIONS (1L << 8) +#define X509_FLAG_NO_SIGDUMP (1L << 9) +#define X509_FLAG_NO_AUX (1L << 10) +#define X509_FLAG_NO_ATTRIBUTES (1L << 11) +#define X509_FLAG_NO_IDS (1L << 12) + +/* Flags specific to X509_NAME_print_ex() */ + +/* The field separator information */ + +#define XN_FLAG_SEP_MASK (0xf << 16) + +#define XN_FLAG_COMPAT 0 /* Traditional SSLeay: use old X509_NAME_print */ +#define XN_FLAG_SEP_COMMA_PLUS (1 << 16) /* RFC2253 ,+ */ +#define XN_FLAG_SEP_CPLUS_SPC (2 << 16) /* ,+ spaced: more readable */ +#define XN_FLAG_SEP_SPLUS_SPC (3 << 16) /* ;+ spaced */ +#define XN_FLAG_SEP_MULTILINE (4 << 16) /* One line per field */ + +#define XN_FLAG_DN_REV (1 << 20) /* Reverse DN order */ + +/* How the field name is shown */ + +#define XN_FLAG_FN_MASK (0x3 << 21) + +#define XN_FLAG_FN_SN 0 /* Object short name */ +#define XN_FLAG_FN_LN (1 << 21) /* Object long name */ +#define XN_FLAG_FN_OID (2 << 21) /* Always use OIDs */ +#define XN_FLAG_FN_NONE (3 << 21) /* No field names */ + +#define XN_FLAG_SPC_EQ (1 << 23) /* Put spaces round '=' */ + +/* This determines if we dump fields we don't recognise: + * RFC2253 requires this. + */ + +#define XN_FLAG_DUMP_UNKNOWN_FIELDS (1 << 24) + +#define XN_FLAG_FN_ALIGN (1 << 25) /* Align field names to 20 characters */ + +/* Complete set of RFC2253 flags */ + +#define XN_FLAG_RFC2253 (ASN1_STRFLGS_RFC2253 | \ + XN_FLAG_SEP_COMMA_PLUS | \ + XN_FLAG_DN_REV | \ + XN_FLAG_FN_SN | \ + XN_FLAG_DUMP_UNKNOWN_FIELDS) + +/* readable oneline form */ + +#define XN_FLAG_ONELINE (ASN1_STRFLGS_RFC2253 | \ + ASN1_STRFLGS_ESC_QUOTE | \ + XN_FLAG_SEP_CPLUS_SPC | \ + XN_FLAG_SPC_EQ | \ + XN_FLAG_FN_SN) + +/* readable multiline form */ + +#define XN_FLAG_MULTILINE (ASN1_STRFLGS_ESC_CTRL | \ + ASN1_STRFLGS_ESC_MSB | \ + XN_FLAG_SEP_MULTILINE | \ + XN_FLAG_SPC_EQ | \ + XN_FLAG_FN_LN | \ + XN_FLAG_FN_ALIGN) + +struct x509_revoked_st + { + ASN1_INTEGER *serialNumber; + ASN1_TIME *revocationDate; + STACK_OF(X509_EXTENSION) /* optional */ *extensions; + /* Set up if indirect CRL */ + STACK_OF(GENERAL_NAME) *issuer; + /* Revocation reason */ + int reason; + int sequence; /* load sequence */ + }; + +DECLARE_STACK_OF(X509_REVOKED) +DECLARE_ASN1_SET_OF(X509_REVOKED) + +struct X509_crl_info_st + { + ASN1_INTEGER *version; + X509_ALGOR *sig_alg; + X509_NAME *issuer; + ASN1_TIME *lastUpdate; + ASN1_TIME *nextUpdate; + STACK_OF(X509_REVOKED) *revoked; + STACK_OF(X509_EXTENSION) /* [0] */ *extensions; + ASN1_ENCODING enc; + } /* X509_CRL_INFO */; + +struct X509_crl_st + { + /* actual signature */ + X509_CRL_INFO *crl; + X509_ALGOR *sig_alg; + ASN1_BIT_STRING *signature; + CRYPTO_refcount_t references; + int flags; + /* Copies of various extensions */ + AUTHORITY_KEYID *akid; + ISSUING_DIST_POINT *idp; + /* Convenient breakdown of IDP */ + int idp_flags; + int idp_reasons; + /* CRL and base CRL numbers for delta processing */ + ASN1_INTEGER *crl_number; + ASN1_INTEGER *base_crl_number; + unsigned char sha1_hash[SHA_DIGEST_LENGTH]; + STACK_OF(GENERAL_NAMES) *issuers; + const X509_CRL_METHOD *meth; + void *meth_data; + } /* X509_CRL */; + +DECLARE_STACK_OF(X509_CRL) +DECLARE_ASN1_SET_OF(X509_CRL) + +struct private_key_st + { + int version; + /* The PKCS#8 data types */ + X509_ALGOR *enc_algor; + ASN1_OCTET_STRING *enc_pkey; /* encrypted pub key */ + + /* When decrypted, the following will not be NULL */ + EVP_PKEY *dec_pkey; + + /* used to encrypt and decrypt */ + int key_length; + char *key_data; + int key_free; /* true if we should auto free key_data */ + + /* expanded version of 'enc_algor' */ + EVP_CIPHER_INFO cipher; + } /* X509_PKEY */; + +#ifndef OPENSSL_NO_EVP +struct X509_info_st + { + X509 *x509; + X509_CRL *crl; + X509_PKEY *x_pkey; + + EVP_CIPHER_INFO enc_cipher; + int enc_len; + char *enc_data; + + } /* X509_INFO */; + +DECLARE_STACK_OF(X509_INFO) +#endif + +/* The next 2 structures and their 8 routines were sent to me by + * Pat Richard and are used to manipulate + * Netscapes spki structures - useful if you are writing a CA web page + */ +struct Netscape_spkac_st + { + X509_PUBKEY *pubkey; + ASN1_IA5STRING *challenge; /* challenge sent in atlas >= PR2 */ + } /* NETSCAPE_SPKAC */; + +struct Netscape_spki_st + { + NETSCAPE_SPKAC *spkac; /* signed public key and challenge */ + X509_ALGOR *sig_algor; + ASN1_BIT_STRING *signature; + } /* NETSCAPE_SPKI */; + +/* Netscape certificate sequence structure */ +struct Netscape_certificate_sequence + { + ASN1_OBJECT *type; + STACK_OF(X509) *certs; + } /* NETSCAPE_CERT_SEQUENCE */; + +/* Unused (and iv length is wrong) +typedef struct CBCParameter_st + { + unsigned char iv[8]; + } CBC_PARAM; +*/ + +/* Password based encryption structure */ + +struct PBEPARAM_st { +ASN1_OCTET_STRING *salt; +ASN1_INTEGER *iter; +} /* PBEPARAM */; + +/* Password based encryption V2 structures */ + +struct PBE2PARAM_st { +X509_ALGOR *keyfunc; +X509_ALGOR *encryption; +} /* PBE2PARAM */; + +struct PBKDF2PARAM_st { +ASN1_TYPE *salt; /* Usually OCTET STRING but could be anything */ +ASN1_INTEGER *iter; +ASN1_INTEGER *keylength; +X509_ALGOR *prf; +} /* PBKDF2PARAM */; + + +/* PKCS#8 private key info structure */ + +struct pkcs8_priv_key_info_st + { + int broken; /* Flag for various broken formats */ +#define PKCS8_OK 0 +#define PKCS8_NO_OCTET 1 +#define PKCS8_EMBEDDED_PARAM 2 +#define PKCS8_NS_DB 3 +#define PKCS8_NEG_PRIVKEY 4 + ASN1_INTEGER *version; + X509_ALGOR *pkeyalg; + ASN1_TYPE *pkey; /* Should be OCTET STRING but some are broken */ + STACK_OF(X509_ATTRIBUTE) *attributes; + }; + +#ifdef __cplusplus +} +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define X509_EXT_PACK_UNKNOWN 1 +#define X509_EXT_PACK_STRING 2 + +#define X509_get_version(x) ASN1_INTEGER_get((x)->cert_info->version) +/* #define X509_get_serialNumber(x) ((x)->cert_info->serialNumber) */ +#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore) +#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter) +#define X509_get_cert_info(x) ((x)->cert_info) +#define X509_extract_key(x) X509_get_pubkey(x) /*****/ +#define X509_REQ_get_version(x) ASN1_INTEGER_get((x)->req_info->version) +#define X509_REQ_get_subject_name(x) ((x)->req_info->subject) +#define X509_REQ_extract_key(a) X509_REQ_get_pubkey(a) +#define X509_name_cmp(a,b) X509_NAME_cmp((a),(b)) +#define X509_get_signature_type(x) EVP_PKEY_type(OBJ_obj2nid((x)->sig_alg->algorithm)) + +#define X509_CRL_get_version(x) ASN1_INTEGER_get((x)->crl->version) +#define X509_CRL_get_lastUpdate(x) ((x)->crl->lastUpdate) +#define X509_CRL_get_nextUpdate(x) ((x)->crl->nextUpdate) +#define X509_CRL_get_issuer(x) ((x)->crl->issuer) +#define X509_CRL_get_REVOKED(x) ((x)->crl->revoked) + +#define X509_CINF_set_modified(c) ((c)->enc.modified = 1) +#define X509_CINF_get_issuer(c) (&(c)->issuer) +#define X509_CINF_get_extensions(c) ((c)->extensions) +#define X509_CINF_get_signature(c) ((c)->signature) + +OPENSSL_EXPORT void X509_CRL_set_default_method(const X509_CRL_METHOD *meth); +OPENSSL_EXPORT X509_CRL_METHOD *X509_CRL_METHOD_new( + int (*crl_init)(X509_CRL *crl), + int (*crl_free)(X509_CRL *crl), + int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret, + ASN1_INTEGER *ser, X509_NAME *issuer), + int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk)); +OPENSSL_EXPORT void X509_CRL_METHOD_free(X509_CRL_METHOD *m); + +OPENSSL_EXPORT void X509_CRL_set_meth_data(X509_CRL *crl, void *dat); +OPENSSL_EXPORT void *X509_CRL_get_meth_data(X509_CRL *crl); + +/* This one is only used so that a binary form can output, as in + * i2d_X509_NAME(X509_get_X509_PUBKEY(x),&buf) */ +#define X509_get_X509_PUBKEY(x) ((x)->cert_info->key) + + +OPENSSL_EXPORT const char *X509_verify_cert_error_string(long n); + +#ifndef OPENSSL_NO_EVP +OPENSSL_EXPORT int X509_verify(X509 *a, EVP_PKEY *r); + +OPENSSL_EXPORT int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r); +OPENSSL_EXPORT int X509_CRL_verify(X509_CRL *a, EVP_PKEY *r); +OPENSSL_EXPORT int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *a, EVP_PKEY *r); + +OPENSSL_EXPORT NETSCAPE_SPKI * NETSCAPE_SPKI_b64_decode(const char *str, int len); +OPENSSL_EXPORT char * NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *x); +OPENSSL_EXPORT EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *x); +OPENSSL_EXPORT int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *x, EVP_PKEY *pkey); + +OPENSSL_EXPORT int NETSCAPE_SPKI_print(BIO *out, NETSCAPE_SPKI *spki); + +OPENSSL_EXPORT int X509_signature_dump(BIO *bp,const ASN1_STRING *sig, int indent); +OPENSSL_EXPORT int X509_signature_print(BIO *bp,X509_ALGOR *alg, ASN1_STRING *sig); + +OPENSSL_EXPORT int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md); +OPENSSL_EXPORT int X509_sign_ctx(X509 *x, EVP_MD_CTX *ctx); +OPENSSL_EXPORT int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md); +OPENSSL_EXPORT int X509_REQ_sign_ctx(X509_REQ *x, EVP_MD_CTX *ctx); +OPENSSL_EXPORT int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md); +OPENSSL_EXPORT int X509_CRL_sign_ctx(X509_CRL *x, EVP_MD_CTX *ctx); +OPENSSL_EXPORT int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *x, EVP_PKEY *pkey, const EVP_MD *md); + +OPENSSL_EXPORT int X509_pubkey_digest(const X509 *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +OPENSSL_EXPORT int X509_digest(const X509 *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +OPENSSL_EXPORT int X509_CRL_digest(const X509_CRL *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +OPENSSL_EXPORT int X509_REQ_digest(const X509_REQ *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +OPENSSL_EXPORT int X509_NAME_digest(const X509_NAME *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +#endif + +#ifndef OPENSSL_NO_FP_API +OPENSSL_EXPORT X509 *d2i_X509_fp(FILE *fp, X509 **x509); +OPENSSL_EXPORT int i2d_X509_fp(FILE *fp,X509 *x509); +OPENSSL_EXPORT X509_CRL *d2i_X509_CRL_fp(FILE *fp,X509_CRL **crl); +OPENSSL_EXPORT int i2d_X509_CRL_fp(FILE *fp,X509_CRL *crl); +OPENSSL_EXPORT X509_REQ *d2i_X509_REQ_fp(FILE *fp,X509_REQ **req); +OPENSSL_EXPORT int i2d_X509_REQ_fp(FILE *fp,X509_REQ *req); +OPENSSL_EXPORT RSA *d2i_RSAPrivateKey_fp(FILE *fp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSAPrivateKey_fp(FILE *fp,RSA *rsa); +OPENSSL_EXPORT RSA *d2i_RSAPublicKey_fp(FILE *fp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSAPublicKey_fp(FILE *fp,RSA *rsa); +OPENSSL_EXPORT RSA *d2i_RSA_PUBKEY_fp(FILE *fp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSA_PUBKEY_fp(FILE *fp,RSA *rsa); +#ifndef OPENSSL_NO_DSA +OPENSSL_EXPORT DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa); +OPENSSL_EXPORT int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa); +OPENSSL_EXPORT DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa); +OPENSSL_EXPORT int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa); +#endif +OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey); +OPENSSL_EXPORT int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey); +OPENSSL_EXPORT EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey); +OPENSSL_EXPORT int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey); +OPENSSL_EXPORT X509_SIG *d2i_PKCS8_fp(FILE *fp,X509_SIG **p8); +OPENSSL_EXPORT int i2d_PKCS8_fp(FILE *fp,X509_SIG *p8); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, + PKCS8_PRIV_KEY_INFO **p8inf); +OPENSSL_EXPORT int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,PKCS8_PRIV_KEY_INFO *p8inf); +OPENSSL_EXPORT int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key); +OPENSSL_EXPORT int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a); +OPENSSL_EXPORT int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a); +#endif + +OPENSSL_EXPORT X509 *d2i_X509_bio(BIO *bp,X509 **x509); +OPENSSL_EXPORT int i2d_X509_bio(BIO *bp,X509 *x509); +OPENSSL_EXPORT X509_CRL *d2i_X509_CRL_bio(BIO *bp,X509_CRL **crl); +OPENSSL_EXPORT int i2d_X509_CRL_bio(BIO *bp,X509_CRL *crl); +OPENSSL_EXPORT X509_REQ *d2i_X509_REQ_bio(BIO *bp,X509_REQ **req); +OPENSSL_EXPORT int i2d_X509_REQ_bio(BIO *bp,X509_REQ *req); +OPENSSL_EXPORT RSA *d2i_RSAPrivateKey_bio(BIO *bp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSAPrivateKey_bio(BIO *bp,RSA *rsa); +OPENSSL_EXPORT RSA *d2i_RSAPublicKey_bio(BIO *bp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSAPublicKey_bio(BIO *bp,RSA *rsa); +OPENSSL_EXPORT RSA *d2i_RSA_PUBKEY_bio(BIO *bp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSA_PUBKEY_bio(BIO *bp,RSA *rsa); +#ifndef OPENSSL_NO_DSA +OPENSSL_EXPORT DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa); +OPENSSL_EXPORT int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa); +OPENSSL_EXPORT DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa); +OPENSSL_EXPORT int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa); +#endif +OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey); +OPENSSL_EXPORT int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *eckey); +OPENSSL_EXPORT EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey); +OPENSSL_EXPORT int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey); +OPENSSL_EXPORT X509_SIG *d2i_PKCS8_bio(BIO *bp,X509_SIG **p8); +OPENSSL_EXPORT int i2d_PKCS8_bio(BIO *bp,X509_SIG *p8); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, + PKCS8_PRIV_KEY_INFO **p8inf); +OPENSSL_EXPORT int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,PKCS8_PRIV_KEY_INFO *p8inf); +OPENSSL_EXPORT int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key); +OPENSSL_EXPORT int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a); +OPENSSL_EXPORT int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a); + +OPENSSL_EXPORT X509 *X509_dup(X509 *x509); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_dup(X509_ATTRIBUTE *xa); +OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *ex); +OPENSSL_EXPORT X509_CRL *X509_CRL_dup(X509_CRL *crl); +OPENSSL_EXPORT X509_REVOKED *X509_REVOKED_dup(X509_REVOKED *rev); +OPENSSL_EXPORT X509_REQ *X509_REQ_dup(X509_REQ *req); +OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_dup(X509_ALGOR *xn); +OPENSSL_EXPORT int X509_ALGOR_set0(X509_ALGOR *alg, const ASN1_OBJECT *aobj, int ptype, void *pval); +OPENSSL_EXPORT void X509_ALGOR_get0(ASN1_OBJECT **paobj, int *pptype, void **ppval, + X509_ALGOR *algor); +OPENSSL_EXPORT void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md); +OPENSSL_EXPORT int X509_ALGOR_cmp(const X509_ALGOR *a, const X509_ALGOR *b); + +OPENSSL_EXPORT X509_NAME *X509_NAME_dup(X509_NAME *xn); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_dup(X509_NAME_ENTRY *ne); + +OPENSSL_EXPORT int X509_cmp_time(const ASN1_TIME *s, time_t *t); +OPENSSL_EXPORT int X509_cmp_current_time(const ASN1_TIME *s); +OPENSSL_EXPORT ASN1_TIME * X509_time_adj(ASN1_TIME *s, long adj, time_t *t); +OPENSSL_EXPORT ASN1_TIME * X509_time_adj_ex(ASN1_TIME *s, int offset_day, long offset_sec, time_t *t); +OPENSSL_EXPORT ASN1_TIME * X509_gmtime_adj(ASN1_TIME *s, long adj); + +OPENSSL_EXPORT const char * X509_get_default_cert_area(void ); +OPENSSL_EXPORT const char * X509_get_default_cert_dir(void ); +OPENSSL_EXPORT const char * X509_get_default_cert_file(void ); +OPENSSL_EXPORT const char * X509_get_default_cert_dir_env(void ); +OPENSSL_EXPORT const char * X509_get_default_cert_file_env(void ); +OPENSSL_EXPORT const char * X509_get_default_private_dir(void ); + +OPENSSL_EXPORT X509_REQ * X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md); +OPENSSL_EXPORT X509 * X509_REQ_to_X509(X509_REQ *r, int days,EVP_PKEY *pkey); + +DECLARE_ASN1_ENCODE_FUNCTIONS(X509_ALGORS, X509_ALGORS, X509_ALGORS) +DECLARE_ASN1_FUNCTIONS(X509_VAL) + +DECLARE_ASN1_FUNCTIONS(X509_PUBKEY) + +OPENSSL_EXPORT int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY * X509_PUBKEY_get(X509_PUBKEY *key); +OPENSSL_EXPORT int i2d_PUBKEY(const EVP_PKEY *a,unsigned char **pp); +OPENSSL_EXPORT EVP_PKEY * d2i_PUBKEY(EVP_PKEY **a,const unsigned char **pp, + long length); +OPENSSL_EXPORT int i2d_RSA_PUBKEY(const RSA *a,unsigned char **pp); +OPENSSL_EXPORT RSA * d2i_RSA_PUBKEY(RSA **a,const unsigned char **pp, + long length); +#ifndef OPENSSL_NO_DSA +OPENSSL_EXPORT int i2d_DSA_PUBKEY(const DSA *a,unsigned char **pp); +OPENSSL_EXPORT DSA * d2i_DSA_PUBKEY(DSA **a,const unsigned char **pp, + long length); +#endif +OPENSSL_EXPORT int i2d_EC_PUBKEY(const EC_KEY *a, unsigned char **pp); +OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, + long length); + +DECLARE_ASN1_FUNCTIONS(X509_SIG) +DECLARE_ASN1_FUNCTIONS(X509_REQ_INFO) +DECLARE_ASN1_FUNCTIONS(X509_REQ) + +DECLARE_ASN1_FUNCTIONS(X509_ATTRIBUTE) +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value); + +DECLARE_ASN1_FUNCTIONS(X509_EXTENSION) +DECLARE_ASN1_ENCODE_FUNCTIONS(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS) + +DECLARE_ASN1_FUNCTIONS(X509_NAME_ENTRY) + +DECLARE_ASN1_FUNCTIONS(X509_NAME) + +OPENSSL_EXPORT int X509_NAME_set(X509_NAME **xn, X509_NAME *name); + +DECLARE_ASN1_FUNCTIONS(X509_CINF) + +DECLARE_ASN1_FUNCTIONS(X509) +DECLARE_ASN1_FUNCTIONS(X509_CERT_AUX) + +DECLARE_ASN1_FUNCTIONS(X509_CERT_PAIR) + +/* X509_up_ref adds one to the reference count of |x| and returns + * |x|. */ +OPENSSL_EXPORT X509 *X509_up_ref(X509 *x); + +OPENSSL_EXPORT int X509_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int X509_set_ex_data(X509 *r, int idx, void *arg); +OPENSSL_EXPORT void *X509_get_ex_data(X509 *r, int idx); +OPENSSL_EXPORT int i2d_X509_AUX(X509 *a,unsigned char **pp); +OPENSSL_EXPORT X509 * d2i_X509_AUX(X509 **a,const unsigned char **pp,long length); + +OPENSSL_EXPORT void X509_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, + const X509 *x); +OPENSSL_EXPORT int X509_get_signature_nid(const X509 *x); + +OPENSSL_EXPORT int X509_alias_set1(X509 *x, unsigned char *name, int len); +OPENSSL_EXPORT int X509_keyid_set1(X509 *x, unsigned char *id, int len); +OPENSSL_EXPORT unsigned char * X509_alias_get0(X509 *x, int *len); +OPENSSL_EXPORT unsigned char * X509_keyid_get0(X509 *x, int *len); +OPENSSL_EXPORT int (*X509_TRUST_set_default(int (*trust)(int , X509 *, int)))(int, X509 *, int); +OPENSSL_EXPORT int X509_TRUST_set(int *t, int trust); +OPENSSL_EXPORT int X509_add1_trust_object(X509 *x, ASN1_OBJECT *obj); +OPENSSL_EXPORT int X509_add1_reject_object(X509 *x, ASN1_OBJECT *obj); +OPENSSL_EXPORT void X509_trust_clear(X509 *x); +OPENSSL_EXPORT void X509_reject_clear(X509 *x); + +DECLARE_ASN1_FUNCTIONS(X509_REVOKED) +DECLARE_ASN1_FUNCTIONS(X509_CRL_INFO) +DECLARE_ASN1_FUNCTIONS(X509_CRL) + +OPENSSL_EXPORT int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev); +OPENSSL_EXPORT int X509_CRL_get0_by_serial(X509_CRL *crl, + X509_REVOKED **ret, ASN1_INTEGER *serial); +OPENSSL_EXPORT int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, X509 *x); + +OPENSSL_EXPORT X509_PKEY * X509_PKEY_new(void ); +OPENSSL_EXPORT void X509_PKEY_free(X509_PKEY *a); + +DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKI) +DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKAC) +DECLARE_ASN1_FUNCTIONS(NETSCAPE_CERT_SEQUENCE) + +#ifndef OPENSSL_NO_EVP +OPENSSL_EXPORT X509_INFO * X509_INFO_new(void); +OPENSSL_EXPORT void X509_INFO_free(X509_INFO *a); +OPENSSL_EXPORT char * X509_NAME_oneline(X509_NAME *a,char *buf,int size); + +OPENSSL_EXPORT int ASN1_digest(i2d_of_void *i2d,const EVP_MD *type,char *data, + unsigned char *md,unsigned int *len); + +OPENSSL_EXPORT int ASN1_item_digest(const ASN1_ITEM *it,const EVP_MD *type,void *data, + unsigned char *md,unsigned int *len); + +OPENSSL_EXPORT int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *algor1, + ASN1_BIT_STRING *signature,void *data,EVP_PKEY *pkey); + +OPENSSL_EXPORT int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2, + ASN1_BIT_STRING *signature, + void *data, EVP_PKEY *pkey, const EVP_MD *type); +OPENSSL_EXPORT int ASN1_item_sign_ctx(const ASN1_ITEM *it, + X509_ALGOR *algor1, X509_ALGOR *algor2, + ASN1_BIT_STRING *signature, void *asn, EVP_MD_CTX *ctx); +#endif + +OPENSSL_EXPORT int X509_set_version(X509 *x,long version); +OPENSSL_EXPORT int X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial); +OPENSSL_EXPORT ASN1_INTEGER * X509_get_serialNumber(X509 *x); +OPENSSL_EXPORT int X509_set_issuer_name(X509 *x, X509_NAME *name); +OPENSSL_EXPORT X509_NAME * X509_get_issuer_name(X509 *a); +OPENSSL_EXPORT int X509_set_subject_name(X509 *x, X509_NAME *name); +OPENSSL_EXPORT X509_NAME * X509_get_subject_name(X509 *a); +OPENSSL_EXPORT int X509_set_notBefore(X509 *x, const ASN1_TIME *tm); +OPENSSL_EXPORT int X509_set_notAfter(X509 *x, const ASN1_TIME *tm); +OPENSSL_EXPORT int X509_set_pubkey(X509 *x, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY * X509_get_pubkey(X509 *x); +OPENSSL_EXPORT ASN1_BIT_STRING * X509_get0_pubkey_bitstr(const X509 *x); +OPENSSL_EXPORT int X509_certificate_type(X509 *x,EVP_PKEY *pubkey /* optional */); + +OPENSSL_EXPORT int X509_REQ_set_version(X509_REQ *x,long version); +OPENSSL_EXPORT int X509_REQ_set_subject_name(X509_REQ *req,X509_NAME *name); +OPENSSL_EXPORT int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY * X509_REQ_get_pubkey(X509_REQ *req); +OPENSSL_EXPORT int X509_REQ_extension_nid(int nid); +OPENSSL_EXPORT const int * X509_REQ_get_extension_nids(void); +OPENSSL_EXPORT void X509_REQ_set_extension_nids(const int *nids); +OPENSSL_EXPORT STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req); +OPENSSL_EXPORT int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts, + int nid); +OPENSSL_EXPORT int X509_REQ_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts); +OPENSSL_EXPORT int X509_REQ_get_attr_count(const X509_REQ *req); +OPENSSL_EXPORT int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid, + int lastpos); +OPENSSL_EXPORT int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, ASN1_OBJECT *obj, + int lastpos); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc); +OPENSSL_EXPORT int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr); +OPENSSL_EXPORT int X509_REQ_add1_attr_by_OBJ(X509_REQ *req, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT int X509_REQ_add1_attr_by_NID(X509_REQ *req, + int nid, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT int X509_REQ_add1_attr_by_txt(X509_REQ *req, + const char *attrname, int type, + const unsigned char *bytes, int len); + +OPENSSL_EXPORT int X509_CRL_set_version(X509_CRL *x, long version); +OPENSSL_EXPORT int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name); +OPENSSL_EXPORT int X509_CRL_set_lastUpdate(X509_CRL *x, const ASN1_TIME *tm); +OPENSSL_EXPORT int X509_CRL_set_nextUpdate(X509_CRL *x, const ASN1_TIME *tm); +OPENSSL_EXPORT int X509_CRL_sort(X509_CRL *crl); +OPENSSL_EXPORT void X509_CRL_up_ref(X509_CRL *crl); + +OPENSSL_EXPORT int X509_REVOKED_set_serialNumber(X509_REVOKED *x, ASN1_INTEGER *serial); +OPENSSL_EXPORT int X509_REVOKED_set_revocationDate(X509_REVOKED *r, ASN1_TIME *tm); + +OPENSSL_EXPORT X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer, + EVP_PKEY *skey, const EVP_MD *md, unsigned int flags); + +OPENSSL_EXPORT int X509_REQ_check_private_key(X509_REQ *x509,EVP_PKEY *pkey); + +OPENSSL_EXPORT int X509_check_private_key(X509 *x509,EVP_PKEY *pkey); +OPENSSL_EXPORT int X509_chain_check_suiteb(int *perror_depth, + X509 *x, STACK_OF(X509) *chain, + unsigned long flags); +OPENSSL_EXPORT int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, + unsigned long flags); +OPENSSL_EXPORT STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain); + +OPENSSL_EXPORT int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b); +OPENSSL_EXPORT unsigned long X509_issuer_and_serial_hash(X509 *a); + +OPENSSL_EXPORT int X509_issuer_name_cmp(const X509 *a, const X509 *b); +OPENSSL_EXPORT unsigned long X509_issuer_name_hash(X509 *a); + +OPENSSL_EXPORT int X509_subject_name_cmp(const X509 *a, const X509 *b); +OPENSSL_EXPORT unsigned long X509_subject_name_hash(X509 *x); + +OPENSSL_EXPORT unsigned long X509_issuer_name_hash_old(X509 *a); +OPENSSL_EXPORT unsigned long X509_subject_name_hash_old(X509 *x); + +OPENSSL_EXPORT int X509_cmp(const X509 *a, const X509 *b); +OPENSSL_EXPORT int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b); +OPENSSL_EXPORT unsigned long X509_NAME_hash(X509_NAME *x); +OPENSSL_EXPORT unsigned long X509_NAME_hash_old(X509_NAME *x); + +OPENSSL_EXPORT int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b); +OPENSSL_EXPORT int X509_CRL_match(const X509_CRL *a, const X509_CRL *b); +#ifndef OPENSSL_NO_FP_API +OPENSSL_EXPORT int X509_print_ex_fp(FILE *bp,X509 *x, unsigned long nmflag, unsigned long cflag); +OPENSSL_EXPORT int X509_print_fp(FILE *bp,X509 *x); +OPENSSL_EXPORT int X509_CRL_print_fp(FILE *bp,X509_CRL *x); +OPENSSL_EXPORT int X509_REQ_print_fp(FILE *bp,X509_REQ *req); +OPENSSL_EXPORT int X509_NAME_print_ex_fp(FILE *fp, X509_NAME *nm, int indent, unsigned long flags); +#endif + +OPENSSL_EXPORT int X509_NAME_print(BIO *bp, X509_NAME *name, int obase); +OPENSSL_EXPORT int X509_NAME_print_ex(BIO *out, X509_NAME *nm, int indent, unsigned long flags); +OPENSSL_EXPORT int X509_print_ex(BIO *bp,X509 *x, unsigned long nmflag, unsigned long cflag); +OPENSSL_EXPORT int X509_print(BIO *bp,X509 *x); +OPENSSL_EXPORT int X509_ocspid_print(BIO *bp,X509 *x); +OPENSSL_EXPORT int X509_CERT_AUX_print(BIO *bp,X509_CERT_AUX *x, int indent); +OPENSSL_EXPORT int X509_CRL_print(BIO *bp,X509_CRL *x); +OPENSSL_EXPORT int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflag, unsigned long cflag); +OPENSSL_EXPORT int X509_REQ_print(BIO *bp,X509_REQ *req); + +OPENSSL_EXPORT int X509_NAME_entry_count(X509_NAME *name); +OPENSSL_EXPORT int X509_NAME_get_text_by_NID(X509_NAME *name, int nid, + char *buf,int len); +OPENSSL_EXPORT int X509_NAME_get_text_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, + char *buf,int len); + +/* NOTE: you should be passsing -1, not 0 as lastpos. The functions that use + * lastpos, search after that position on. */ +OPENSSL_EXPORT int X509_NAME_get_index_by_NID(X509_NAME *name,int nid,int lastpos); +OPENSSL_EXPORT int X509_NAME_get_index_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, + int lastpos); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *name, int loc); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc); +OPENSSL_EXPORT int X509_NAME_add_entry(X509_NAME *name,X509_NAME_ENTRY *ne, + int loc, int set); +OPENSSL_EXPORT int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type, + unsigned char *bytes, int len, int loc, int set); +OPENSSL_EXPORT int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type, + unsigned char *bytes, int len, int loc, int set); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne, + const char *field, int type, const unsigned char *bytes, int len); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid, + int type,unsigned char *bytes, int len); +OPENSSL_EXPORT int X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type, + const unsigned char *bytes, int len, int loc, int set); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **ne, + const ASN1_OBJECT *obj, int type,const unsigned char *bytes, + int len); +OPENSSL_EXPORT int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne, + const ASN1_OBJECT *obj); +OPENSSL_EXPORT int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT ASN1_OBJECT * X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *ne); +OPENSSL_EXPORT ASN1_STRING * X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *ne); + +OPENSSL_EXPORT int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x); +OPENSSL_EXPORT int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x, + int nid, int lastpos); +OPENSSL_EXPORT int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *x, + const ASN1_OBJECT *obj,int lastpos); +OPENSSL_EXPORT int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *x, + int crit, int lastpos); +OPENSSL_EXPORT X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, int loc); +OPENSSL_EXPORT X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, int loc); +OPENSSL_EXPORT STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x, + X509_EXTENSION *ex, int loc); + +OPENSSL_EXPORT int X509_get_ext_count(X509 *x); +OPENSSL_EXPORT int X509_get_ext_by_NID(X509 *x, int nid, int lastpos); +OPENSSL_EXPORT int X509_get_ext_by_OBJ(X509 *x,ASN1_OBJECT *obj,int lastpos); +OPENSSL_EXPORT int X509_get_ext_by_critical(X509 *x, int crit, int lastpos); +OPENSSL_EXPORT X509_EXTENSION *X509_get_ext(X509 *x, int loc); +OPENSSL_EXPORT X509_EXTENSION *X509_delete_ext(X509 *x, int loc); +OPENSSL_EXPORT int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc); +OPENSSL_EXPORT void * X509_get_ext_d2i(X509 *x, int nid, int *crit, int *idx); +OPENSSL_EXPORT int X509_add1_ext_i2d(X509 *x, int nid, void *value, int crit, + unsigned long flags); + +OPENSSL_EXPORT int X509_CRL_get_ext_count(X509_CRL *x); +OPENSSL_EXPORT int X509_CRL_get_ext_by_NID(X509_CRL *x, int nid, int lastpos); +OPENSSL_EXPORT int X509_CRL_get_ext_by_OBJ(X509_CRL *x,ASN1_OBJECT *obj,int lastpos); +OPENSSL_EXPORT int X509_CRL_get_ext_by_critical(X509_CRL *x, int crit, int lastpos); +OPENSSL_EXPORT X509_EXTENSION *X509_CRL_get_ext(X509_CRL *x, int loc); +OPENSSL_EXPORT X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc); +OPENSSL_EXPORT int X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc); +OPENSSL_EXPORT void * X509_CRL_get_ext_d2i(X509_CRL *x, int nid, int *crit, int *idx); +OPENSSL_EXPORT int X509_CRL_add1_ext_i2d(X509_CRL *x, int nid, void *value, int crit, + unsigned long flags); + +OPENSSL_EXPORT int X509_REVOKED_get_ext_count(X509_REVOKED *x); +OPENSSL_EXPORT int X509_REVOKED_get_ext_by_NID(X509_REVOKED *x, int nid, int lastpos); +OPENSSL_EXPORT int X509_REVOKED_get_ext_by_OBJ(X509_REVOKED *x,ASN1_OBJECT *obj,int lastpos); +OPENSSL_EXPORT int X509_REVOKED_get_ext_by_critical(X509_REVOKED *x, int crit, int lastpos); +OPENSSL_EXPORT X509_EXTENSION *X509_REVOKED_get_ext(X509_REVOKED *x, int loc); +OPENSSL_EXPORT X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x, int loc); +OPENSSL_EXPORT int X509_REVOKED_add_ext(X509_REVOKED *x, X509_EXTENSION *ex, int loc); +OPENSSL_EXPORT void * X509_REVOKED_get_ext_d2i(X509_REVOKED *x, int nid, int *crit, int *idx); +OPENSSL_EXPORT int X509_REVOKED_add1_ext_i2d(X509_REVOKED *x, int nid, void *value, int crit, + unsigned long flags); + +OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex, + int nid, int crit, ASN1_OCTET_STRING *data); +OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **ex, + const ASN1_OBJECT *obj,int crit,ASN1_OCTET_STRING *data); +OPENSSL_EXPORT int X509_EXTENSION_set_object(X509_EXTENSION *ex,const ASN1_OBJECT *obj); +OPENSSL_EXPORT int X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit); +OPENSSL_EXPORT int X509_EXTENSION_set_data(X509_EXTENSION *ex, + ASN1_OCTET_STRING *data); +OPENSSL_EXPORT ASN1_OBJECT * X509_EXTENSION_get_object(X509_EXTENSION *ex); +OPENSSL_EXPORT ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ne); +OPENSSL_EXPORT int X509_EXTENSION_get_critical(X509_EXTENSION *ex); + +OPENSSL_EXPORT int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x); +OPENSSL_EXPORT int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid, + int lastpos); +OPENSSL_EXPORT int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, const ASN1_OBJECT *obj, + int lastpos); +OPENSSL_EXPORT X509_ATTRIBUTE *X509at_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc); +OPENSSL_EXPORT X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc); +OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, + X509_ATTRIBUTE *attr); +OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) **x, + int nid, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) **x, + const char *attrname, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x, + ASN1_OBJECT *obj, int lastpos, int type); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid, + int atrtype, const void *data, int len); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr, + const ASN1_OBJECT *obj, int atrtype, const void *data, int len); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr, + const char *atrname, int type, const unsigned char *bytes, int len); +OPENSSL_EXPORT int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj); +OPENSSL_EXPORT int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, const void *data, int len); +OPENSSL_EXPORT void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx, + int atrtype, void *data); +OPENSSL_EXPORT int X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr); +OPENSSL_EXPORT ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr); +OPENSSL_EXPORT ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx); + +OPENSSL_EXPORT int EVP_PKEY_get_attr_count(const EVP_PKEY *key); +OPENSSL_EXPORT int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *key, int nid, + int lastpos); +OPENSSL_EXPORT int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *key, ASN1_OBJECT *obj, + int lastpos); +OPENSSL_EXPORT X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *key, int loc); +OPENSSL_EXPORT X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *key, int loc); +OPENSSL_EXPORT int EVP_PKEY_add1_attr(EVP_PKEY *key, X509_ATTRIBUTE *attr); +OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *key, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *key, + int nid, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key, + const char *attrname, int type, + const unsigned char *bytes, int len); + +OPENSSL_EXPORT int X509_verify_cert(X509_STORE_CTX *ctx); + +/* lookup a cert from a X509 STACK */ +OPENSSL_EXPORT X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk,X509_NAME *name, + ASN1_INTEGER *serial); +OPENSSL_EXPORT X509 *X509_find_by_subject(STACK_OF(X509) *sk,X509_NAME *name); + +DECLARE_ASN1_FUNCTIONS(PBEPARAM) +DECLARE_ASN1_FUNCTIONS(PBE2PARAM) +DECLARE_ASN1_FUNCTIONS(PBKDF2PARAM) + +OPENSSL_EXPORT int PKCS5_pbe_set0_algor(X509_ALGOR *algor, int alg, int iter, + const unsigned char *salt, int saltlen); + +OPENSSL_EXPORT X509_ALGOR *PKCS5_pbe_set(int alg, int iter, + const unsigned char *salt, int saltlen); +OPENSSL_EXPORT X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter, + unsigned char *salt, int saltlen); +OPENSSL_EXPORT X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter, + unsigned char *salt, int saltlen, + unsigned char *aiv, int prf_nid); + +OPENSSL_EXPORT X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen, + int prf_nid, int keylen); + +/* PKCS#8 utilities */ + +DECLARE_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO) + +OPENSSL_EXPORT EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8_broken(EVP_PKEY *pkey, int broken); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_set_broken(PKCS8_PRIV_KEY_INFO *p8, int broken); + +OPENSSL_EXPORT int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj, + int version, int ptype, void *pval, + unsigned char *penc, int penclen); +OPENSSL_EXPORT int PKCS8_pkey_get0(ASN1_OBJECT **ppkalg, + const unsigned char **pk, int *ppklen, + X509_ALGOR **pa, + PKCS8_PRIV_KEY_INFO *p8); + +OPENSSL_EXPORT int X509_PUBKEY_set0_param(X509_PUBKEY *pub, const ASN1_OBJECT *aobj, + int ptype, void *pval, + unsigned char *penc, int penclen); +OPENSSL_EXPORT int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg, + const unsigned char **pk, int *ppklen, + X509_ALGOR **pa, + X509_PUBKEY *pub); + +OPENSSL_EXPORT int X509_check_trust(X509 *x, int id, int flags); +OPENSSL_EXPORT int X509_TRUST_get_count(void); +OPENSSL_EXPORT X509_TRUST * X509_TRUST_get0(int idx); +OPENSSL_EXPORT int X509_TRUST_get_by_id(int id); +OPENSSL_EXPORT int X509_TRUST_add(int id, int flags, int (*ck)(X509_TRUST *, X509 *, int), + char *name, int arg1, void *arg2); +OPENSSL_EXPORT void X509_TRUST_cleanup(void); +OPENSSL_EXPORT int X509_TRUST_get_flags(X509_TRUST *xp); +OPENSSL_EXPORT char *X509_TRUST_get0_name(X509_TRUST *xp); +OPENSSL_EXPORT int X509_TRUST_get_trust(X509_TRUST *xp); + +/* PKCS7_get_certificates parses a PKCS#7, SignedData structure from |cbs| and + * appends the included certificates to |out_certs|. It returns one on success + * and zero on error. */ +OPENSSL_EXPORT int PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs); + +/* PKCS7_bundle_certificates appends a PKCS#7, SignedData structure containing + * |certs| to |out|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS7_bundle_certificates( + CBB *out, const STACK_OF(X509) *certs); + +/* PKCS7_get_CRLs parses a PKCS#7, SignedData structure from |cbs| and appends + * the included CRLs to |out_crls|. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int PKCS7_get_CRLs(STACK_OF(X509_CRL) *out_crls, CBS *cbs); + +/* PKCS7_bundle_CRLs appends a PKCS#7, SignedData structure containing + * |crls| to |out|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS7_bundle_CRLs(CBB *out, const STACK_OF(X509_CRL) *crls); + +/* PKCS7_get_PEM_certificates reads a PEM-encoded, PKCS#7, SignedData structure + * from |pem_bio| and appends the included certificates to |out_certs|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS7_get_PEM_certificates(STACK_OF(X509) *out_certs, + BIO *pem_bio); + +/* PKCS7_get_PEM_CRLs reads a PEM-encoded, PKCS#7, SignedData structure from + * |pem_bio| and appends the included CRLs to |out_crls|. It returns one on + * success and zero on error. */ +OPENSSL_EXPORT int PKCS7_get_PEM_CRLs(STACK_OF(X509_CRL) *out_crls, + BIO *pem_bio); + +/* EVP_PK values indicate the algorithm of the public key in a certificate. */ + +#define EVP_PK_RSA 0x0001 +#define EVP_PK_DSA 0x0002 +#define EVP_PK_DH 0x0004 +#define EVP_PK_EC 0x0008 + +/* EVP_PKS values indicate the algorithm used to sign a certificate. */ + +#define EVP_PKS_RSA 0x0100 +#define EVP_PKS_DSA 0x0200 +#define EVP_PKS_EC 0x0400 + +/* EVP_PKT values are flags that define what public-key operations can be + * performed with the public key from a certificate. */ + +/* EVP_PKT_SIGN indicates that the public key can be used for signing. */ +#define EVP_PKT_SIGN 0x0010 +/* EVP_PKT_ENC indicates that a session key can be encrypted to the public + * key. */ +#define EVP_PKT_ENC 0x0020 +/* EVP_PKT_EXCH indicates that key-agreement can be performed. */ +#define EVP_PKT_EXCH 0x0040 +/* EVP_PKT_EXP indicates that key is weak (i.e. "export"). */ +#define EVP_PKT_EXP 0x1000 + + +#ifdef __cplusplus +} +#endif + +#define X509_R_AKID_MISMATCH 100 +#define X509_R_BAD_PKCS7_VERSION 101 +#define X509_R_BAD_X509_FILETYPE 102 +#define X509_R_BASE64_DECODE_ERROR 103 +#define X509_R_CANT_CHECK_DH_KEY 104 +#define X509_R_CERT_ALREADY_IN_HASH_TABLE 105 +#define X509_R_CRL_ALREADY_DELTA 106 +#define X509_R_CRL_VERIFY_FAILURE 107 +#define X509_R_IDP_MISMATCH 108 +#define X509_R_INVALID_BIT_STRING_BITS_LEFT 109 +#define X509_R_INVALID_DIRECTORY 110 +#define X509_R_INVALID_FIELD_NAME 111 +#define X509_R_INVALID_TRUST 112 +#define X509_R_ISSUER_MISMATCH 113 +#define X509_R_KEY_TYPE_MISMATCH 114 +#define X509_R_KEY_VALUES_MISMATCH 115 +#define X509_R_LOADING_CERT_DIR 116 +#define X509_R_LOADING_DEFAULTS 117 +#define X509_R_METHOD_NOT_SUPPORTED 118 +#define X509_R_NEWER_CRL_NOT_NEWER 119 +#define X509_R_NOT_PKCS7_SIGNED_DATA 120 +#define X509_R_NO_CERTIFICATES_INCLUDED 121 +#define X509_R_NO_CERT_SET_FOR_US_TO_VERIFY 122 +#define X509_R_NO_CRL_NUMBER 123 +#define X509_R_PUBLIC_KEY_DECODE_ERROR 124 +#define X509_R_PUBLIC_KEY_ENCODE_ERROR 125 +#define X509_R_SHOULD_RETRY 126 +#define X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN 127 +#define X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY 128 +#define X509_R_UNKNOWN_KEY_TYPE 129 +#define X509_R_UNKNOWN_NID 130 +#define X509_R_UNKNOWN_PURPOSE_ID 131 +#define X509_R_UNKNOWN_TRUST_ID 132 +#define X509_R_UNSUPPORTED_ALGORITHM 133 +#define X509_R_WRONG_LOOKUP_TYPE 134 +#define X509_R_WRONG_TYPE 135 +#define X509_R_NO_CRLS_INCLUDED 136 + +#endif diff --git a/project/jni/boringssl/include/openssl/x509_vfy.h b/project/jni/boringssl/include/openssl/x509_vfy.h new file mode 100644 index 000000000..b39ef49c9 --- /dev/null +++ b/project/jni/boringssl/include/openssl/x509_vfy.h @@ -0,0 +1,611 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_X509_H +#include +/* openssl/x509.h ends up #include-ing this file at about the only + * appropriate moment. */ +#endif + +#ifndef HEADER_X509_VFY_H +#define HEADER_X509_VFY_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if 0 +/* Outer object */ +typedef struct x509_hash_dir_st + { + int num_dirs; + char **dirs; + int *dirs_type; + int num_dirs_alloced; + } X509_HASH_DIR_CTX; +#endif + +typedef struct x509_file_st + { + int num_paths; /* number of paths to files or directories */ + int num_alloced; + char **paths; /* the list of paths or directories */ + int *path_type; + } X509_CERT_FILE_CTX; + +/*******************************/ +/* +SSL_CTX -> X509_STORE + -> X509_LOOKUP + ->X509_LOOKUP_METHOD + -> X509_LOOKUP + ->X509_LOOKUP_METHOD + +SSL -> X509_STORE_CTX + ->X509_STORE + +The X509_STORE holds the tables etc for verification stuff. +A X509_STORE_CTX is used while validating a single certificate. +The X509_STORE has X509_LOOKUPs for looking up certs. +The X509_STORE then calls a function to actually verify the +certificate chain. +*/ + +#define X509_LU_RETRY -1 +#define X509_LU_FAIL 0 +#define X509_LU_X509 1 +#define X509_LU_CRL 2 +#define X509_LU_PKEY 3 + +typedef struct x509_object_st + { + /* one of the above types */ + int type; + union { + char *ptr; + X509 *x509; + X509_CRL *crl; + EVP_PKEY *pkey; + } data; + } X509_OBJECT; + +typedef struct x509_lookup_st X509_LOOKUP; + +DECLARE_STACK_OF(X509_LOOKUP) +DECLARE_STACK_OF(X509_OBJECT) + +/* This is a static that defines the function interface */ +typedef struct x509_lookup_method_st + { + const char *name; + int (*new_item)(X509_LOOKUP *ctx); + void (*free)(X509_LOOKUP *ctx); + int (*init)(X509_LOOKUP *ctx); + int (*shutdown)(X509_LOOKUP *ctx); + int (*ctrl)(X509_LOOKUP *ctx,int cmd,const char *argc,long argl, + char **ret); + int (*get_by_subject)(X509_LOOKUP *ctx,int type,X509_NAME *name, + X509_OBJECT *ret); + int (*get_by_issuer_serial)(X509_LOOKUP *ctx,int type,X509_NAME *name, + ASN1_INTEGER *serial,X509_OBJECT *ret); + int (*get_by_fingerprint)(X509_LOOKUP *ctx,int type, + unsigned char *bytes,int len, + X509_OBJECT *ret); + int (*get_by_alias)(X509_LOOKUP *ctx,int type,char *str,int len, + X509_OBJECT *ret); + } X509_LOOKUP_METHOD; + +typedef struct X509_VERIFY_PARAM_ID_st X509_VERIFY_PARAM_ID; + +/* This structure hold all parameters associated with a verify operation + * by including an X509_VERIFY_PARAM structure in related structures the + * parameters used can be customized + */ + +typedef struct X509_VERIFY_PARAM_st + { + char *name; + time_t check_time; /* Time to use */ + unsigned long inh_flags; /* Inheritance flags */ + unsigned long flags; /* Various verify flags */ + int purpose; /* purpose to check untrusted certificates */ + int trust; /* trust setting to check */ + int depth; /* Verify depth */ + STACK_OF(ASN1_OBJECT) *policies; /* Permissible policies */ + X509_VERIFY_PARAM_ID *id; /* opaque ID data */ + } X509_VERIFY_PARAM; + +DECLARE_STACK_OF(X509_VERIFY_PARAM) + +/* This is used to hold everything. It is used for all certificate + * validation. Once we have a certificate chain, the 'verify' + * function is then called to actually check the cert chain. */ +struct x509_store_st + { + /* The following is a cache of trusted certs */ + int cache; /* if true, stash any hits */ + STACK_OF(X509_OBJECT) *objs; /* Cache of all objects */ + CRYPTO_MUTEX objs_lock; + + /* These are external lookup methods */ + STACK_OF(X509_LOOKUP) *get_cert_methods; + + X509_VERIFY_PARAM *param; + + /* Callbacks for various operations */ + int (*verify)(X509_STORE_CTX *ctx); /* called to verify a certificate */ + int (*verify_cb)(int ok,X509_STORE_CTX *ctx); /* error callback */ + int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* get issuers cert from ctx */ + int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */ + int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */ + int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */ + int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */ + int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */ + STACK_OF(X509) * (*lookup_certs)(X509_STORE_CTX *ctx, X509_NAME *nm); + STACK_OF(X509_CRL) * (*lookup_crls)(X509_STORE_CTX *ctx, X509_NAME *nm); + int (*cleanup)(X509_STORE_CTX *ctx); + + CRYPTO_refcount_t references; + } /* X509_STORE */; + +OPENSSL_EXPORT int X509_STORE_set_depth(X509_STORE *store, int depth); + +#define X509_STORE_set_verify_cb_func(ctx,func) ((ctx)->verify_cb=(func)) +#define X509_STORE_set_verify_func(ctx,func) ((ctx)->verify=(func)) + +/* This is the functions plus an instance of the local variables. */ +struct x509_lookup_st + { + int init; /* have we been started */ + int skip; /* don't use us. */ + X509_LOOKUP_METHOD *method; /* the functions */ + char *method_data; /* method data */ + + X509_STORE *store_ctx; /* who owns us */ + } /* X509_LOOKUP */; + +/* This is a used when verifying cert chains. Since the + * gathering of the cert chain can take some time (and have to be + * 'retried', this needs to be kept and passed around. */ +struct x509_store_ctx_st /* X509_STORE_CTX */ + { + X509_STORE *ctx; + int current_method; /* used when looking up certs */ + + /* The following are set by the caller */ + X509 *cert; /* The cert to check */ + STACK_OF(X509) *untrusted; /* chain of X509s - untrusted - passed in */ + STACK_OF(X509_CRL) *crls; /* set of CRLs passed in */ + + X509_VERIFY_PARAM *param; + void *other_ctx; /* Other info for use with get_issuer() */ + + /* Callbacks for various operations */ + int (*verify)(X509_STORE_CTX *ctx); /* called to verify a certificate */ + int (*verify_cb)(int ok,X509_STORE_CTX *ctx); /* error callback */ + int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* get issuers cert from ctx */ + int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */ + int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */ + int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */ + int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */ + int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */ + int (*check_policy)(X509_STORE_CTX *ctx); + STACK_OF(X509) * (*lookup_certs)(X509_STORE_CTX *ctx, X509_NAME *nm); + STACK_OF(X509_CRL) * (*lookup_crls)(X509_STORE_CTX *ctx, X509_NAME *nm); + int (*cleanup)(X509_STORE_CTX *ctx); + + /* The following is built up */ + int valid; /* if 0, rebuild chain */ + int last_untrusted; /* index of last untrusted cert */ + STACK_OF(X509) *chain; /* chain of X509s - built up and trusted */ + X509_POLICY_TREE *tree; /* Valid policy tree */ + + int explicit_policy; /* Require explicit policy value */ + + /* When something goes wrong, this is why */ + int error_depth; + int error; + X509 *current_cert; + X509 *current_issuer; /* cert currently being tested as valid issuer */ + X509_CRL *current_crl; /* current CRL */ + + int current_crl_score; /* score of current CRL */ + unsigned int current_reasons; /* Reason mask */ + + X509_STORE_CTX *parent; /* For CRL path validation: parent context */ + + CRYPTO_EX_DATA ex_data; + } /* X509_STORE_CTX */; + +OPENSSL_EXPORT void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); + +#define X509_STORE_CTX_set_app_data(ctx,data) \ + X509_STORE_CTX_set_ex_data(ctx,0,data) +#define X509_STORE_CTX_get_app_data(ctx) \ + X509_STORE_CTX_get_ex_data(ctx,0) + +#define X509_L_FILE_LOAD 1 +#define X509_L_ADD_DIR 2 + +#define X509_LOOKUP_load_file(x,name,type) \ + X509_LOOKUP_ctrl((x),X509_L_FILE_LOAD,(name),(long)(type),NULL) + +#define X509_LOOKUP_add_dir(x,name,type) \ + X509_LOOKUP_ctrl((x),X509_L_ADD_DIR,(name),(long)(type),NULL) + +#define X509_V_OK 0 +/* illegal error (for uninitialized values, to avoid X509_V_OK): 1 */ + +#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2 +#define X509_V_ERR_UNABLE_TO_GET_CRL 3 +#define X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE 4 +#define X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE 5 +#define X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY 6 +#define X509_V_ERR_CERT_SIGNATURE_FAILURE 7 +#define X509_V_ERR_CRL_SIGNATURE_FAILURE 8 +#define X509_V_ERR_CERT_NOT_YET_VALID 9 +#define X509_V_ERR_CERT_HAS_EXPIRED 10 +#define X509_V_ERR_CRL_NOT_YET_VALID 11 +#define X509_V_ERR_CRL_HAS_EXPIRED 12 +#define X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD 13 +#define X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD 14 +#define X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD 15 +#define X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD 16 +#define X509_V_ERR_OUT_OF_MEM 17 +#define X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT 18 +#define X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN 19 +#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY 20 +#define X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE 21 +#define X509_V_ERR_CERT_CHAIN_TOO_LONG 22 +#define X509_V_ERR_CERT_REVOKED 23 +#define X509_V_ERR_INVALID_CA 24 +#define X509_V_ERR_PATH_LENGTH_EXCEEDED 25 +#define X509_V_ERR_INVALID_PURPOSE 26 +#define X509_V_ERR_CERT_UNTRUSTED 27 +#define X509_V_ERR_CERT_REJECTED 28 +/* These are 'informational' when looking for issuer cert */ +#define X509_V_ERR_SUBJECT_ISSUER_MISMATCH 29 +#define X509_V_ERR_AKID_SKID_MISMATCH 30 +#define X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH 31 +#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32 + +#define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33 +#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34 +#define X509_V_ERR_KEYUSAGE_NO_CRL_SIGN 35 +#define X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION 36 +#define X509_V_ERR_INVALID_NON_CA 37 +#define X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED 38 +#define X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE 39 +#define X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED 40 + +#define X509_V_ERR_INVALID_EXTENSION 41 +#define X509_V_ERR_INVALID_POLICY_EXTENSION 42 +#define X509_V_ERR_NO_EXPLICIT_POLICY 43 +#define X509_V_ERR_DIFFERENT_CRL_SCOPE 44 +#define X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE 45 + +#define X509_V_ERR_UNNESTED_RESOURCE 46 + +#define X509_V_ERR_PERMITTED_VIOLATION 47 +#define X509_V_ERR_EXCLUDED_VIOLATION 48 +#define X509_V_ERR_SUBTREE_MINMAX 49 +#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE 51 +#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX 52 +#define X509_V_ERR_UNSUPPORTED_NAME_SYNTAX 53 +#define X509_V_ERR_CRL_PATH_VALIDATION_ERROR 54 + +/* Suite B mode algorithm violation */ +#define X509_V_ERR_SUITE_B_INVALID_VERSION 56 +#define X509_V_ERR_SUITE_B_INVALID_ALGORITHM 57 +#define X509_V_ERR_SUITE_B_INVALID_CURVE 58 +#define X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM 59 +#define X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED 60 +#define X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 61 + +/* Host, email and IP check errors */ +#define X509_V_ERR_HOSTNAME_MISMATCH 62 +#define X509_V_ERR_EMAIL_MISMATCH 63 +#define X509_V_ERR_IP_ADDRESS_MISMATCH 64 + +/* The application is not happy */ +#define X509_V_ERR_APPLICATION_VERIFICATION 50 + +/* Certificate verify flags */ + +/* Send issuer+subject checks to verify_cb */ +#define X509_V_FLAG_CB_ISSUER_CHECK 0x1 +/* Use check time instead of current time */ +#define X509_V_FLAG_USE_CHECK_TIME 0x2 +/* Lookup CRLs */ +#define X509_V_FLAG_CRL_CHECK 0x4 +/* Lookup CRLs for whole chain */ +#define X509_V_FLAG_CRL_CHECK_ALL 0x8 +/* Ignore unhandled critical extensions */ +#define X509_V_FLAG_IGNORE_CRITICAL 0x10 +/* Disable workarounds for broken certificates */ +#define X509_V_FLAG_X509_STRICT 0x20 +/* Enable proxy certificate validation */ +#define X509_V_FLAG_ALLOW_PROXY_CERTS 0x40 +/* Enable policy checking */ +#define X509_V_FLAG_POLICY_CHECK 0x80 +/* Policy variable require-explicit-policy */ +#define X509_V_FLAG_EXPLICIT_POLICY 0x100 +/* Policy variable inhibit-any-policy */ +#define X509_V_FLAG_INHIBIT_ANY 0x200 +/* Policy variable inhibit-policy-mapping */ +#define X509_V_FLAG_INHIBIT_MAP 0x400 +/* Notify callback that policy is OK */ +#define X509_V_FLAG_NOTIFY_POLICY 0x800 +/* Extended CRL features such as indirect CRLs, alternate CRL signing keys */ +#define X509_V_FLAG_EXTENDED_CRL_SUPPORT 0x1000 +/* Delta CRL support */ +#define X509_V_FLAG_USE_DELTAS 0x2000 +/* Check selfsigned CA signature */ +#define X509_V_FLAG_CHECK_SS_SIGNATURE 0x4000 +/* Use trusted store first */ +#define X509_V_FLAG_TRUSTED_FIRST 0x8000 +/* Suite B 128 bit only mode: not normally used */ +#define X509_V_FLAG_SUITEB_128_LOS_ONLY 0x10000 +/* Suite B 192 bit only mode */ +#define X509_V_FLAG_SUITEB_192_LOS 0x20000 +/* Suite B 128 bit mode allowing 192 bit algorithms */ +#define X509_V_FLAG_SUITEB_128_LOS 0x30000 + +/* Allow partial chains if at least one certificate is in trusted store */ +#define X509_V_FLAG_PARTIAL_CHAIN 0x80000 + +#define X509_VP_FLAG_DEFAULT 0x1 +#define X509_VP_FLAG_OVERWRITE 0x2 +#define X509_VP_FLAG_RESET_FLAGS 0x4 +#define X509_VP_FLAG_LOCKED 0x8 +#define X509_VP_FLAG_ONCE 0x10 + +/* Internal use: mask of policy related options */ +#define X509_V_FLAG_POLICY_MASK (X509_V_FLAG_POLICY_CHECK \ + | X509_V_FLAG_EXPLICIT_POLICY \ + | X509_V_FLAG_INHIBIT_ANY \ + | X509_V_FLAG_INHIBIT_MAP) + +OPENSSL_EXPORT int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type, + X509_NAME *name); +OPENSSL_EXPORT X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h,int type,X509_NAME *name); +OPENSSL_EXPORT X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x); +OPENSSL_EXPORT void X509_OBJECT_up_ref_count(X509_OBJECT *a); +OPENSSL_EXPORT void X509_OBJECT_free_contents(X509_OBJECT *a); +OPENSSL_EXPORT X509_STORE *X509_STORE_new(void ); +OPENSSL_EXPORT void X509_STORE_free(X509_STORE *v); + +OPENSSL_EXPORT STACK_OF(X509)* X509_STORE_get1_certs(X509_STORE_CTX *st, X509_NAME *nm); +OPENSSL_EXPORT STACK_OF(X509_CRL)* X509_STORE_get1_crls(X509_STORE_CTX *st, X509_NAME *nm); +OPENSSL_EXPORT int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags); +OPENSSL_EXPORT int X509_STORE_set_purpose(X509_STORE *ctx, int purpose); +OPENSSL_EXPORT int X509_STORE_set_trust(X509_STORE *ctx, int trust); +OPENSSL_EXPORT int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *pm); + +OPENSSL_EXPORT void X509_STORE_set_verify_cb(X509_STORE *ctx, + int (*verify_cb)(int, X509_STORE_CTX *)); + +OPENSSL_EXPORT void X509_STORE_set_lookup_crls_cb(X509_STORE *ctx, + STACK_OF(X509_CRL)* (*cb)(X509_STORE_CTX *ctx, X509_NAME *nm)); + +OPENSSL_EXPORT X509_STORE_CTX *X509_STORE_CTX_new(void); + +OPENSSL_EXPORT int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); + +OPENSSL_EXPORT void X509_STORE_CTX_free(X509_STORE_CTX *ctx); +OPENSSL_EXPORT int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, + X509 *x509, STACK_OF(X509) *chain); +OPENSSL_EXPORT void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk); +OPENSSL_EXPORT void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx); + +OPENSSL_EXPORT X509_STORE *X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx); + +OPENSSL_EXPORT X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m); + +OPENSSL_EXPORT X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void); +OPENSSL_EXPORT X509_LOOKUP_METHOD *X509_LOOKUP_file(void); + +OPENSSL_EXPORT int X509_STORE_add_cert(X509_STORE *ctx, X509 *x); +OPENSSL_EXPORT int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x); + +OPENSSL_EXPORT int X509_STORE_get_by_subject(X509_STORE_CTX *vs,int type,X509_NAME *name, + X509_OBJECT *ret); + +OPENSSL_EXPORT int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, + long argl, char **ret); + +#ifndef OPENSSL_NO_STDIO +OPENSSL_EXPORT int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type); +OPENSSL_EXPORT int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type); +OPENSSL_EXPORT int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type); +#endif + + +OPENSSL_EXPORT X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method); +OPENSSL_EXPORT void X509_LOOKUP_free(X509_LOOKUP *ctx); +OPENSSL_EXPORT int X509_LOOKUP_init(X509_LOOKUP *ctx); +OPENSSL_EXPORT int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, int type, X509_NAME *name, + X509_OBJECT *ret); +OPENSSL_EXPORT int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, int type, X509_NAME *name, + ASN1_INTEGER *serial, X509_OBJECT *ret); +OPENSSL_EXPORT int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, int type, + unsigned char *bytes, int len, X509_OBJECT *ret); +OPENSSL_EXPORT int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, int type, char *str, + int len, X509_OBJECT *ret); +OPENSSL_EXPORT int X509_LOOKUP_shutdown(X509_LOOKUP *ctx); + +#ifndef OPENSSL_NO_STDIO +OPENSSL_EXPORT int X509_STORE_load_locations (X509_STORE *ctx, + const char *file, const char *dir); +OPENSSL_EXPORT int X509_STORE_set_default_paths(X509_STORE *ctx); +#endif + +OPENSSL_EXPORT int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx,int idx,void *data); +OPENSSL_EXPORT void * X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx,int idx); +OPENSSL_EXPORT int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx); +OPENSSL_EXPORT void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx,int s); +OPENSSL_EXPORT int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx); +OPENSSL_EXPORT X509 * X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx); +OPENSSL_EXPORT X509 *X509_STORE_CTX_get0_current_issuer(X509_STORE_CTX *ctx); +OPENSSL_EXPORT X509_CRL *X509_STORE_CTX_get0_current_crl(X509_STORE_CTX *ctx); +OPENSSL_EXPORT X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(X509_STORE_CTX *ctx); +OPENSSL_EXPORT STACK_OF(X509) *X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx); +OPENSSL_EXPORT STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx); +OPENSSL_EXPORT void X509_STORE_CTX_set_cert(X509_STORE_CTX *c,X509 *x); +OPENSSL_EXPORT void X509_STORE_CTX_set_chain(X509_STORE_CTX *c,STACK_OF(X509) *sk); +OPENSSL_EXPORT void X509_STORE_CTX_set0_crls(X509_STORE_CTX *c,STACK_OF(X509_CRL) *sk); +OPENSSL_EXPORT int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose); +OPENSSL_EXPORT int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust); +OPENSSL_EXPORT int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, + int purpose, int trust); +OPENSSL_EXPORT void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags); +OPENSSL_EXPORT void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags, + time_t t); +OPENSSL_EXPORT void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx, + int (*verify_cb)(int, X509_STORE_CTX *)); + +OPENSSL_EXPORT X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx); +OPENSSL_EXPORT int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx); + +OPENSSL_EXPORT X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx); +OPENSSL_EXPORT void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param); +OPENSSL_EXPORT int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name); + +/* X509_VERIFY_PARAM functions */ + +OPENSSL_EXPORT X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void); +OPENSSL_EXPORT void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param); +OPENSSL_EXPORT int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *to, + const X509_VERIFY_PARAM *from); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to, + const X509_VERIFY_PARAM *from); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags); +OPENSSL_EXPORT int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, + unsigned long flags); +OPENSSL_EXPORT unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust); +OPENSSL_EXPORT void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth); +OPENSSL_EXPORT void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t); +OPENSSL_EXPORT int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param, + ASN1_OBJECT *policy); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param, + STACK_OF(ASN1_OBJECT) *policies); + +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param, + const char *name, size_t namelen); +OPENSSL_EXPORT int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param, + const char *name, + size_t namelen); +OPENSSL_EXPORT void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param, + unsigned int flags); +OPENSSL_EXPORT char *X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, + const char *email, size_t emaillen); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, + const unsigned char *ip, size_t iplen); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc); + +OPENSSL_EXPORT int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param); +OPENSSL_EXPORT const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param); + +OPENSSL_EXPORT int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param); +OPENSSL_EXPORT int X509_VERIFY_PARAM_get_count(void); +OPENSSL_EXPORT const X509_VERIFY_PARAM *X509_VERIFY_PARAM_get0(int id); +OPENSSL_EXPORT const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name); +OPENSSL_EXPORT void X509_VERIFY_PARAM_table_cleanup(void); + +OPENSSL_EXPORT int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy, + STACK_OF(X509) *certs, + STACK_OF(ASN1_OBJECT) *policy_oids, + unsigned int flags); + +OPENSSL_EXPORT void X509_policy_tree_free(X509_POLICY_TREE *tree); + +OPENSSL_EXPORT int X509_policy_tree_level_count(const X509_POLICY_TREE *tree); +OPENSSL_EXPORT X509_POLICY_LEVEL * + X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, int i); + +OPENSSL_EXPORT STACK_OF(X509_POLICY_NODE) * + X509_policy_tree_get0_policies(const X509_POLICY_TREE *tree); + +OPENSSL_EXPORT STACK_OF(X509_POLICY_NODE) * + X509_policy_tree_get0_user_policies(const X509_POLICY_TREE *tree); + +OPENSSL_EXPORT int X509_policy_level_node_count(X509_POLICY_LEVEL *level); + +OPENSSL_EXPORT X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, int i); + +OPENSSL_EXPORT const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node); + +OPENSSL_EXPORT STACK_OF(POLICYQUALINFO) * + X509_policy_node_get0_qualifiers(const X509_POLICY_NODE *node); +OPENSSL_EXPORT const X509_POLICY_NODE * + X509_policy_node_get0_parent(const X509_POLICY_NODE *node); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/project/jni/boringssl/include/openssl/x509v3.h b/project/jni/boringssl/include/openssl/x509v3.h new file mode 100644 index 000000000..b7b8ba716 --- /dev/null +++ b/project/jni/boringssl/include/openssl/x509v3.h @@ -0,0 +1,798 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. */ +/* ==================================================================== + * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef HEADER_X509V3_H +#define HEADER_X509V3_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward reference */ +struct v3_ext_method; +struct v3_ext_ctx; + +/* Useful typedefs */ + +typedef void * (*X509V3_EXT_NEW)(void); +typedef void (*X509V3_EXT_FREE)(void *); +typedef void * (*X509V3_EXT_D2I)(void *, const unsigned char ** , long); +typedef int (*X509V3_EXT_I2D)(void *, unsigned char **); +typedef STACK_OF(CONF_VALUE) * + (*X509V3_EXT_I2V)(const struct v3_ext_method *method, void *ext, + STACK_OF(CONF_VALUE) *extlist); +typedef void * (*X509V3_EXT_V2I)(const struct v3_ext_method *method, + struct v3_ext_ctx *ctx, + STACK_OF(CONF_VALUE) *values); +typedef char * (*X509V3_EXT_I2S)(const struct v3_ext_method *method, void *ext); +typedef void * (*X509V3_EXT_S2I)(const struct v3_ext_method *method, + struct v3_ext_ctx *ctx, const char *str); +typedef int (*X509V3_EXT_I2R)(const struct v3_ext_method *method, void *ext, + BIO *out, int indent); +typedef void * (*X509V3_EXT_R2I)(const struct v3_ext_method *method, + struct v3_ext_ctx *ctx, const char *str); + +/* V3 extension structure */ + +struct v3_ext_method { +int ext_nid; +int ext_flags; +/* If this is set the following four fields are ignored */ +ASN1_ITEM_EXP *it; +/* Old style ASN1 calls */ +X509V3_EXT_NEW ext_new; +X509V3_EXT_FREE ext_free; +X509V3_EXT_D2I d2i; +X509V3_EXT_I2D i2d; + +/* The following pair is used for string extensions */ +X509V3_EXT_I2S i2s; +X509V3_EXT_S2I s2i; + +/* The following pair is used for multi-valued extensions */ +X509V3_EXT_I2V i2v; +X509V3_EXT_V2I v2i; + +/* The following are used for raw extensions */ +X509V3_EXT_I2R i2r; +X509V3_EXT_R2I r2i; + +void *usr_data; /* Any extension specific data */ +}; + +typedef struct X509V3_CONF_METHOD_st { +char * (*get_string)(void *db, char *section, char *value); +STACK_OF(CONF_VALUE) * (*get_section)(void *db, char *section); +void (*free_string)(void *db, char * string); +void (*free_section)(void *db, STACK_OF(CONF_VALUE) *section); +} X509V3_CONF_METHOD; + +/* Context specific info */ +struct v3_ext_ctx { +#define CTX_TEST 0x1 +int flags; +X509 *issuer_cert; +X509 *subject_cert; +X509_REQ *subject_req; +X509_CRL *crl; +const X509V3_CONF_METHOD *db_meth; +void *db; +/* Maybe more here */ +}; + +typedef struct v3_ext_method X509V3_EXT_METHOD; + +DECLARE_STACK_OF(X509V3_EXT_METHOD) + +/* ext_flags values */ +#define X509V3_EXT_DYNAMIC 0x1 +#define X509V3_EXT_CTX_DEP 0x2 +#define X509V3_EXT_MULTILINE 0x4 + +typedef BIT_STRING_BITNAME ENUMERATED_NAMES; + +typedef struct BASIC_CONSTRAINTS_st { +int ca; +ASN1_INTEGER *pathlen; +} BASIC_CONSTRAINTS; + + +typedef struct PKEY_USAGE_PERIOD_st { +ASN1_GENERALIZEDTIME *notBefore; +ASN1_GENERALIZEDTIME *notAfter; +} PKEY_USAGE_PERIOD; + +typedef struct otherName_st { +ASN1_OBJECT *type_id; +ASN1_TYPE *value; +} OTHERNAME; + +typedef struct EDIPartyName_st { + ASN1_STRING *nameAssigner; + ASN1_STRING *partyName; +} EDIPARTYNAME; + +typedef struct GENERAL_NAME_st { + +#define GEN_OTHERNAME 0 +#define GEN_EMAIL 1 +#define GEN_DNS 2 +#define GEN_X400 3 +#define GEN_DIRNAME 4 +#define GEN_EDIPARTY 5 +#define GEN_URI 6 +#define GEN_IPADD 7 +#define GEN_RID 8 + +int type; +union { + char *ptr; + OTHERNAME *otherName; /* otherName */ + ASN1_IA5STRING *rfc822Name; + ASN1_IA5STRING *dNSName; + ASN1_TYPE *x400Address; + X509_NAME *directoryName; + EDIPARTYNAME *ediPartyName; + ASN1_IA5STRING *uniformResourceIdentifier; + ASN1_OCTET_STRING *iPAddress; + ASN1_OBJECT *registeredID; + + /* Old names */ + ASN1_OCTET_STRING *ip; /* iPAddress */ + X509_NAME *dirn; /* dirn */ + ASN1_IA5STRING *ia5;/* rfc822Name, dNSName, uniformResourceIdentifier */ + ASN1_OBJECT *rid; /* registeredID */ + ASN1_TYPE *other; /* x400Address */ +} d; +} GENERAL_NAME; + +typedef STACK_OF(GENERAL_NAME) GENERAL_NAMES; + +typedef struct ACCESS_DESCRIPTION_st { + ASN1_OBJECT *method; + GENERAL_NAME *location; +} ACCESS_DESCRIPTION; + +typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; + +typedef STACK_OF(ASN1_OBJECT) EXTENDED_KEY_USAGE; + +DECLARE_STACK_OF(GENERAL_NAME) +DECLARE_ASN1_SET_OF(GENERAL_NAME) + +DECLARE_STACK_OF(ACCESS_DESCRIPTION) +DECLARE_ASN1_SET_OF(ACCESS_DESCRIPTION) + +typedef struct DIST_POINT_NAME_st { +int type; +union { + GENERAL_NAMES *fullname; + STACK_OF(X509_NAME_ENTRY) *relativename; +} name; +/* If relativename then this contains the full distribution point name */ +X509_NAME *dpname; +} DIST_POINT_NAME; +/* All existing reasons */ +#define CRLDP_ALL_REASONS 0x807f + +#define CRL_REASON_NONE -1 +#define CRL_REASON_UNSPECIFIED 0 +#define CRL_REASON_KEY_COMPROMISE 1 +#define CRL_REASON_CA_COMPROMISE 2 +#define CRL_REASON_AFFILIATION_CHANGED 3 +#define CRL_REASON_SUPERSEDED 4 +#define CRL_REASON_CESSATION_OF_OPERATION 5 +#define CRL_REASON_CERTIFICATE_HOLD 6 +#define CRL_REASON_REMOVE_FROM_CRL 8 +#define CRL_REASON_PRIVILEGE_WITHDRAWN 9 +#define CRL_REASON_AA_COMPROMISE 10 + +struct DIST_POINT_st { +DIST_POINT_NAME *distpoint; +ASN1_BIT_STRING *reasons; +GENERAL_NAMES *CRLissuer; +int dp_reasons; +}; + +typedef STACK_OF(DIST_POINT) CRL_DIST_POINTS; + +DECLARE_STACK_OF(DIST_POINT) +DECLARE_ASN1_SET_OF(DIST_POINT) + +struct AUTHORITY_KEYID_st { +ASN1_OCTET_STRING *keyid; +GENERAL_NAMES *issuer; +ASN1_INTEGER *serial; +}; + +/* Strong extranet structures */ + +typedef struct SXNET_ID_st { + ASN1_INTEGER *zone; + ASN1_OCTET_STRING *user; +} SXNETID; + +DECLARE_STACK_OF(SXNETID) +DECLARE_ASN1_SET_OF(SXNETID) + +typedef struct SXNET_st { + ASN1_INTEGER *version; + STACK_OF(SXNETID) *ids; +} SXNET; + +typedef struct NOTICEREF_st { + ASN1_STRING *organization; + STACK_OF(ASN1_INTEGER) *noticenos; +} NOTICEREF; + +typedef struct USERNOTICE_st { + NOTICEREF *noticeref; + ASN1_STRING *exptext; +} USERNOTICE; + +typedef struct POLICYQUALINFO_st { + ASN1_OBJECT *pqualid; + union { + ASN1_IA5STRING *cpsuri; + USERNOTICE *usernotice; + ASN1_TYPE *other; + } d; +} POLICYQUALINFO; + +DECLARE_STACK_OF(POLICYQUALINFO) +DECLARE_ASN1_SET_OF(POLICYQUALINFO) + +typedef struct POLICYINFO_st { + ASN1_OBJECT *policyid; + STACK_OF(POLICYQUALINFO) *qualifiers; +} POLICYINFO; + +typedef STACK_OF(POLICYINFO) CERTIFICATEPOLICIES; + +DECLARE_STACK_OF(POLICYINFO) +DECLARE_ASN1_SET_OF(POLICYINFO) + +typedef struct POLICY_MAPPING_st { + ASN1_OBJECT *issuerDomainPolicy; + ASN1_OBJECT *subjectDomainPolicy; +} POLICY_MAPPING; + +DECLARE_STACK_OF(POLICY_MAPPING) + +typedef STACK_OF(POLICY_MAPPING) POLICY_MAPPINGS; + +typedef struct GENERAL_SUBTREE_st { + GENERAL_NAME *base; + ASN1_INTEGER *minimum; + ASN1_INTEGER *maximum; +} GENERAL_SUBTREE; + +DECLARE_STACK_OF(GENERAL_SUBTREE) + +struct NAME_CONSTRAINTS_st { + STACK_OF(GENERAL_SUBTREE) *permittedSubtrees; + STACK_OF(GENERAL_SUBTREE) *excludedSubtrees; +}; + +typedef struct POLICY_CONSTRAINTS_st { + ASN1_INTEGER *requireExplicitPolicy; + ASN1_INTEGER *inhibitPolicyMapping; +} POLICY_CONSTRAINTS; + +/* Proxy certificate structures, see RFC 3820 */ +typedef struct PROXY_POLICY_st + { + ASN1_OBJECT *policyLanguage; + ASN1_OCTET_STRING *policy; + } PROXY_POLICY; + +typedef struct PROXY_CERT_INFO_EXTENSION_st + { + ASN1_INTEGER *pcPathLengthConstraint; + PROXY_POLICY *proxyPolicy; + } PROXY_CERT_INFO_EXTENSION; + +DECLARE_ASN1_FUNCTIONS(PROXY_POLICY) +DECLARE_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION) + +struct ISSUING_DIST_POINT_st + { + DIST_POINT_NAME *distpoint; + int onlyuser; + int onlyCA; + ASN1_BIT_STRING *onlysomereasons; + int indirectCRL; + int onlyattr; + }; + +/* Values in idp_flags field */ +/* IDP present */ +#define IDP_PRESENT 0x1 +/* IDP values inconsistent */ +#define IDP_INVALID 0x2 +/* onlyuser true */ +#define IDP_ONLYUSER 0x4 +/* onlyCA true */ +#define IDP_ONLYCA 0x8 +/* onlyattr true */ +#define IDP_ONLYATTR 0x10 +/* indirectCRL true */ +#define IDP_INDIRECT 0x20 +/* onlysomereasons present */ +#define IDP_REASONS 0x40 + +#define X509V3_conf_err(val) ERR_add_error_data(6, "section:", val->section, \ +",name:", val->name, ",value:", val->value); + +#define X509V3_set_ctx_test(ctx) \ + X509V3_set_ctx(ctx, NULL, NULL, NULL, NULL, CTX_TEST) +#define X509V3_set_ctx_nodb(ctx) (ctx)->db = NULL; + +#define EXT_BITSTRING(nid, table) { nid, 0, ASN1_ITEM_ref(ASN1_BIT_STRING), \ + 0,0,0,0, \ + 0,0, \ + (X509V3_EXT_I2V)i2v_ASN1_BIT_STRING, \ + (X509V3_EXT_V2I)v2i_ASN1_BIT_STRING, \ + NULL, NULL, \ + (void *)table} + +#define EXT_IA5STRING(nid) { nid, 0, ASN1_ITEM_ref(ASN1_IA5STRING), \ + 0,0,0,0, \ + (X509V3_EXT_I2S)i2s_ASN1_IA5STRING, \ + (X509V3_EXT_S2I)s2i_ASN1_IA5STRING, \ + 0,0,0,0, \ + NULL} + +#define EXT_END { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + + +/* X509_PURPOSE stuff */ + +#define EXFLAG_BCONS 0x1 +#define EXFLAG_KUSAGE 0x2 +#define EXFLAG_XKUSAGE 0x4 +#define EXFLAG_NSCERT 0x8 + +#define EXFLAG_CA 0x10 +/* Really self issued not necessarily self signed */ +#define EXFLAG_SI 0x20 +#define EXFLAG_V1 0x40 +#define EXFLAG_INVALID 0x80 +#define EXFLAG_SET 0x100 +#define EXFLAG_CRITICAL 0x200 +#define EXFLAG_PROXY 0x400 + +#define EXFLAG_INVALID_POLICY 0x800 +#define EXFLAG_FRESHEST 0x1000 +/* Self signed */ +#define EXFLAG_SS 0x2000 + +#define KU_DIGITAL_SIGNATURE 0x0080 +#define KU_NON_REPUDIATION 0x0040 +#define KU_KEY_ENCIPHERMENT 0x0020 +#define KU_DATA_ENCIPHERMENT 0x0010 +#define KU_KEY_AGREEMENT 0x0008 +#define KU_KEY_CERT_SIGN 0x0004 +#define KU_CRL_SIGN 0x0002 +#define KU_ENCIPHER_ONLY 0x0001 +#define KU_DECIPHER_ONLY 0x8000 + +#define NS_SSL_CLIENT 0x80 +#define NS_SSL_SERVER 0x40 +#define NS_SMIME 0x20 +#define NS_OBJSIGN 0x10 +#define NS_SSL_CA 0x04 +#define NS_SMIME_CA 0x02 +#define NS_OBJSIGN_CA 0x01 +#define NS_ANY_CA (NS_SSL_CA|NS_SMIME_CA|NS_OBJSIGN_CA) + +#define XKU_SSL_SERVER 0x1 +#define XKU_SSL_CLIENT 0x2 +#define XKU_SMIME 0x4 +#define XKU_CODE_SIGN 0x8 +#define XKU_SGC 0x10 +#define XKU_OCSP_SIGN 0x20 +#define XKU_TIMESTAMP 0x40 +#define XKU_DVCS 0x80 +#define XKU_ANYEKU 0x100 + +#define X509_PURPOSE_DYNAMIC 0x1 +#define X509_PURPOSE_DYNAMIC_NAME 0x2 + +typedef struct x509_purpose_st { + int purpose; + int trust; /* Default trust ID */ + int flags; + int (*check_purpose)(const struct x509_purpose_st *, + const X509 *, int); + char *name; + char *sname; + void *usr_data; +} X509_PURPOSE; + +#define X509_PURPOSE_SSL_CLIENT 1 +#define X509_PURPOSE_SSL_SERVER 2 +#define X509_PURPOSE_NS_SSL_SERVER 3 +#define X509_PURPOSE_SMIME_SIGN 4 +#define X509_PURPOSE_SMIME_ENCRYPT 5 +#define X509_PURPOSE_CRL_SIGN 6 +#define X509_PURPOSE_ANY 7 +#define X509_PURPOSE_OCSP_HELPER 8 +#define X509_PURPOSE_TIMESTAMP_SIGN 9 + +#define X509_PURPOSE_MIN 1 +#define X509_PURPOSE_MAX 9 + +/* Flags for X509V3_EXT_print() */ + +#define X509V3_EXT_UNKNOWN_MASK (0xfL << 16) +/* Return error for unknown extensions */ +#define X509V3_EXT_DEFAULT 0 +/* Print error for unknown extensions */ +#define X509V3_EXT_ERROR_UNKNOWN (1L << 16) +/* ASN1 parse unknown extensions */ +#define X509V3_EXT_PARSE_UNKNOWN (2L << 16) +/* BIO_dump unknown extensions */ +#define X509V3_EXT_DUMP_UNKNOWN (3L << 16) + +/* Flags for X509V3_add1_i2d */ + +#define X509V3_ADD_OP_MASK 0xfL +#define X509V3_ADD_DEFAULT 0L +#define X509V3_ADD_APPEND 1L +#define X509V3_ADD_REPLACE 2L +#define X509V3_ADD_REPLACE_EXISTING 3L +#define X509V3_ADD_KEEP_EXISTING 4L +#define X509V3_ADD_DELETE 5L +#define X509V3_ADD_SILENT 0x10 + +DECLARE_STACK_OF(X509_PURPOSE) + +DECLARE_ASN1_FUNCTIONS(BASIC_CONSTRAINTS) + +DECLARE_ASN1_FUNCTIONS(SXNET) +DECLARE_ASN1_FUNCTIONS(SXNETID) + +int SXNET_add_id_asc(SXNET **psx, char *zone, char *user, int userlen); +int SXNET_add_id_ulong(SXNET **psx, unsigned long lzone, char *user, int userlen); +int SXNET_add_id_INTEGER(SXNET **psx, ASN1_INTEGER *izone, char *user, int userlen); + +ASN1_OCTET_STRING *SXNET_get_id_asc(SXNET *sx, char *zone); +ASN1_OCTET_STRING *SXNET_get_id_ulong(SXNET *sx, unsigned long lzone); +ASN1_OCTET_STRING *SXNET_get_id_INTEGER(SXNET *sx, ASN1_INTEGER *zone); + +DECLARE_ASN1_FUNCTIONS(AUTHORITY_KEYID) + +DECLARE_ASN1_FUNCTIONS(PKEY_USAGE_PERIOD) + +DECLARE_ASN1_FUNCTIONS(GENERAL_NAME) +OPENSSL_EXPORT GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a); +OPENSSL_EXPORT int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b); + + + +OPENSSL_EXPORT ASN1_BIT_STRING *v2i_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); +OPENSSL_EXPORT STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, + ASN1_BIT_STRING *bits, + STACK_OF(CONF_VALUE) *extlist); + +OPENSSL_EXPORT STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret); +OPENSSL_EXPORT int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen); + +DECLARE_ASN1_FUNCTIONS(GENERAL_NAMES) + +OPENSSL_EXPORT STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method, + GENERAL_NAMES *gen, STACK_OF(CONF_VALUE) *extlist); +OPENSSL_EXPORT GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); + +DECLARE_ASN1_FUNCTIONS(OTHERNAME) +DECLARE_ASN1_FUNCTIONS(EDIPARTYNAME) +OPENSSL_EXPORT int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b); +OPENSSL_EXPORT void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value); +OPENSSL_EXPORT void *GENERAL_NAME_get0_value(GENERAL_NAME *a, int *ptype); +OPENSSL_EXPORT int GENERAL_NAME_set0_othername(GENERAL_NAME *gen, + ASN1_OBJECT *oid, ASN1_TYPE *value); +OPENSSL_EXPORT int GENERAL_NAME_get0_otherName(GENERAL_NAME *gen, + ASN1_OBJECT **poid, ASN1_TYPE **pvalue); + +OPENSSL_EXPORT char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *ia5); +OPENSSL_EXPORT ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str); + +DECLARE_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE) +OPENSSL_EXPORT int i2a_ACCESS_DESCRIPTION(BIO *bp, ACCESS_DESCRIPTION* a); + +DECLARE_ASN1_FUNCTIONS(CERTIFICATEPOLICIES) +DECLARE_ASN1_FUNCTIONS(POLICYINFO) +DECLARE_ASN1_FUNCTIONS(POLICYQUALINFO) +DECLARE_ASN1_FUNCTIONS(USERNOTICE) +DECLARE_ASN1_FUNCTIONS(NOTICEREF) + +DECLARE_ASN1_FUNCTIONS(CRL_DIST_POINTS) +DECLARE_ASN1_FUNCTIONS(DIST_POINT) +DECLARE_ASN1_FUNCTIONS(DIST_POINT_NAME) +DECLARE_ASN1_FUNCTIONS(ISSUING_DIST_POINT) + +OPENSSL_EXPORT int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, X509_NAME *iname); + +OPENSSL_EXPORT int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc); + +DECLARE_ASN1_FUNCTIONS(ACCESS_DESCRIPTION) +DECLARE_ASN1_FUNCTIONS(AUTHORITY_INFO_ACCESS) + +DECLARE_ASN1_ITEM(POLICY_MAPPING) +DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_MAPPING) +DECLARE_ASN1_ITEM(POLICY_MAPPINGS) + +DECLARE_ASN1_ITEM(GENERAL_SUBTREE) +DECLARE_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE) + +DECLARE_ASN1_ITEM(NAME_CONSTRAINTS) +DECLARE_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS) + +DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_CONSTRAINTS) +DECLARE_ASN1_ITEM(POLICY_CONSTRAINTS) + +OPENSSL_EXPORT GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out, + const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + int gen_type, char *value, int is_nc); + +OPENSSL_EXPORT GENERAL_NAME *v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + CONF_VALUE *cnf); +OPENSSL_EXPORT GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out, + const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc); +OPENSSL_EXPORT void X509V3_conf_free(CONF_VALUE *val); + +OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid, char *value); +OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, char *name, char *value); +OPENSSL_EXPORT int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, char *section, STACK_OF(X509_EXTENSION) **sk); +OPENSSL_EXPORT int X509V3_EXT_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509 *cert); +OPENSSL_EXPORT int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_REQ *req); +OPENSSL_EXPORT int X509V3_EXT_CRL_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_CRL *crl); + +OPENSSL_EXPORT int X509V3_EXT_CRL_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, + char *section, X509_CRL *crl); + +OPENSSL_EXPORT int X509V3_add_value_bool_nf(char *name, int asn1_bool, + STACK_OF(CONF_VALUE) **extlist); +OPENSSL_EXPORT int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool); +OPENSSL_EXPORT int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint); +OPENSSL_EXPORT void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf); + +OPENSSL_EXPORT char * X509V3_get_string(X509V3_CTX *ctx, char *name, char *section); +OPENSSL_EXPORT STACK_OF(CONF_VALUE) * X509V3_get_section(X509V3_CTX *ctx, char *section); +OPENSSL_EXPORT void X509V3_string_free(X509V3_CTX *ctx, char *str); +OPENSSL_EXPORT void X509V3_section_free( X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section); +OPENSSL_EXPORT void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject, + X509_REQ *req, X509_CRL *crl, int flags); + +OPENSSL_EXPORT int X509V3_add_value(const char *name, const char *value, + STACK_OF(CONF_VALUE) **extlist); +OPENSSL_EXPORT int X509V3_add_value_uchar(const char *name, const unsigned char *value, + STACK_OF(CONF_VALUE) **extlist); +OPENSSL_EXPORT int X509V3_add_value_bool(const char *name, int asn1_bool, + STACK_OF(CONF_VALUE) **extlist); +OPENSSL_EXPORT int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint, + STACK_OF(CONF_VALUE) **extlist); +OPENSSL_EXPORT char * i2s_ASN1_INTEGER(X509V3_EXT_METHOD *meth, ASN1_INTEGER *aint); +OPENSSL_EXPORT ASN1_INTEGER * s2i_ASN1_INTEGER(X509V3_EXT_METHOD *meth, char *value); +OPENSSL_EXPORT char * i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *meth, ASN1_ENUMERATED *aint); +OPENSSL_EXPORT char * i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *meth, ASN1_ENUMERATED *aint); +OPENSSL_EXPORT int X509V3_EXT_add(X509V3_EXT_METHOD *ext); +OPENSSL_EXPORT int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist); +OPENSSL_EXPORT int X509V3_EXT_add_alias(int nid_to, int nid_from); +OPENSSL_EXPORT void X509V3_EXT_cleanup(void); + +OPENSSL_EXPORT const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext); +OPENSSL_EXPORT const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid); +OPENSSL_EXPORT int X509V3_add_standard_extensions(void); +OPENSSL_EXPORT STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line); +OPENSSL_EXPORT void *X509V3_EXT_d2i(X509_EXTENSION *ext); +OPENSSL_EXPORT void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx); + + +OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc); +OPENSSL_EXPORT int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, int crit, unsigned long flags); + +char *hex_to_string(const unsigned char *buffer, long len); +unsigned char *string_to_hex(const char *str, long *len); +int name_cmp(const char *name, const char *cmp); + +OPENSSL_EXPORT void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent, + int ml); +OPENSSL_EXPORT int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent); +OPENSSL_EXPORT int X509V3_EXT_print_fp(FILE *out, X509_EXTENSION *ext, int flag, int indent); + +OPENSSL_EXPORT int X509V3_extensions_print(BIO *out, const char *title, STACK_OF(X509_EXTENSION) *exts, unsigned long flag, int indent); + +OPENSSL_EXPORT int X509_check_ca(X509 *x); +OPENSSL_EXPORT int X509_check_purpose(X509 *x, int id, int ca); +OPENSSL_EXPORT int X509_supported_extension(X509_EXTENSION *ex); +OPENSSL_EXPORT int X509_PURPOSE_set(int *p, int purpose); +OPENSSL_EXPORT int X509_check_issued(X509 *issuer, X509 *subject); +OPENSSL_EXPORT int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid); +OPENSSL_EXPORT int X509_PURPOSE_get_count(void); +OPENSSL_EXPORT X509_PURPOSE * X509_PURPOSE_get0(int idx); +OPENSSL_EXPORT int X509_PURPOSE_get_by_sname(char *sname); +OPENSSL_EXPORT int X509_PURPOSE_get_by_id(int id); +OPENSSL_EXPORT int X509_PURPOSE_add(int id, int trust, int flags, + int (*ck)(const X509_PURPOSE *, const X509 *, int), + char *name, char *sname, void *arg); +OPENSSL_EXPORT char *X509_PURPOSE_get0_name(X509_PURPOSE *xp); +OPENSSL_EXPORT char *X509_PURPOSE_get0_sname(X509_PURPOSE *xp); +OPENSSL_EXPORT int X509_PURPOSE_get_trust(X509_PURPOSE *xp); +OPENSSL_EXPORT void X509_PURPOSE_cleanup(void); +OPENSSL_EXPORT int X509_PURPOSE_get_id(X509_PURPOSE *); + +OPENSSL_EXPORT STACK_OF(OPENSSL_STRING) *X509_get1_email(X509 *x); +OPENSSL_EXPORT STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x); +OPENSSL_EXPORT void X509_email_free(STACK_OF(OPENSSL_STRING) *sk); +OPENSSL_EXPORT STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x); +/* Flags for X509_check_* functions */ + +/* Always check subject name for host match even if subject alt names present */ +#define X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT 0x1 +/* Disable wildcard matching for dnsName fields and common name. */ +#define X509_CHECK_FLAG_NO_WILDCARDS 0x2 +/* Wildcards must not match a partial label. */ +#define X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 0x4 +/* Allow (non-partial) wildcards to match multiple labels. */ +#define X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS 0x8 +/* Constraint verifier subdomain patterns to match a single labels. */ +#define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0x10 +/* + * Match reference identifiers starting with "." to any sub-domain. + * This is a non-public flag, turned on implicitly when the subject + * reference identity is a DNS name. + */ +#define _X509_CHECK_FLAG_DOT_SUBDOMAINS 0x8000 + +OPENSSL_EXPORT int X509_check_host(X509 *x, const char *chk, size_t chklen, + unsigned int flags, char **peername); +OPENSSL_EXPORT int X509_check_email(X509 *x, const char *chk, size_t chklen, + unsigned int flags); +OPENSSL_EXPORT int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen, + unsigned int flags); +OPENSSL_EXPORT int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags); + +OPENSSL_EXPORT ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc); +OPENSSL_EXPORT ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc); +OPENSSL_EXPORT int a2i_ipadd(unsigned char *ipout, const char *ipasc); +OPENSSL_EXPORT int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE)*dn_sk, + unsigned long chtype); + +OPENSSL_EXPORT void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent); +DECLARE_STACK_OF(X509_POLICY_NODE) + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_X509V3_strings(void); + + +#ifdef __cplusplus +} +#endif +#define X509V3_R_BAD_IP_ADDRESS 100 +#define X509V3_R_BAD_OBJECT 101 +#define X509V3_R_BN_DEC2BN_ERROR 102 +#define X509V3_R_BN_TO_ASN1_INTEGER_ERROR 103 +#define X509V3_R_CANNOT_FIND_FREE_FUNCTION 104 +#define X509V3_R_DIRNAME_ERROR 105 +#define X509V3_R_DISTPOINT_ALREADY_SET 106 +#define X509V3_R_DUPLICATE_ZONE_ID 107 +#define X509V3_R_ERROR_CONVERTING_ZONE 108 +#define X509V3_R_ERROR_CREATING_EXTENSION 109 +#define X509V3_R_ERROR_IN_EXTENSION 110 +#define X509V3_R_EXPECTED_A_SECTION_NAME 111 +#define X509V3_R_EXTENSION_EXISTS 112 +#define X509V3_R_EXTENSION_NAME_ERROR 113 +#define X509V3_R_EXTENSION_NOT_FOUND 114 +#define X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED 115 +#define X509V3_R_EXTENSION_VALUE_ERROR 116 +#define X509V3_R_ILLEGAL_EMPTY_EXTENSION 117 +#define X509V3_R_ILLEGAL_HEX_DIGIT 118 +#define X509V3_R_INCORRECT_POLICY_SYNTAX_TAG 119 +#define X509V3_R_INVALID_BOOLEAN_STRING 120 +#define X509V3_R_INVALID_EXTENSION_STRING 121 +#define X509V3_R_INVALID_MULTIPLE_RDNS 122 +#define X509V3_R_INVALID_NAME 123 +#define X509V3_R_INVALID_NULL_ARGUMENT 124 +#define X509V3_R_INVALID_NULL_NAME 125 +#define X509V3_R_INVALID_NULL_VALUE 126 +#define X509V3_R_INVALID_NUMBER 127 +#define X509V3_R_INVALID_NUMBERS 128 +#define X509V3_R_INVALID_OBJECT_IDENTIFIER 129 +#define X509V3_R_INVALID_OPTION 130 +#define X509V3_R_INVALID_POLICY_IDENTIFIER 131 +#define X509V3_R_INVALID_PROXY_POLICY_SETTING 132 +#define X509V3_R_INVALID_PURPOSE 133 +#define X509V3_R_INVALID_SECTION 134 +#define X509V3_R_INVALID_SYNTAX 135 +#define X509V3_R_ISSUER_DECODE_ERROR 136 +#define X509V3_R_MISSING_VALUE 137 +#define X509V3_R_NEED_ORGANIZATION_AND_NUMBERS 138 +#define X509V3_R_NO_CONFIG_DATABASE 139 +#define X509V3_R_NO_ISSUER_CERTIFICATE 140 +#define X509V3_R_NO_ISSUER_DETAILS 141 +#define X509V3_R_NO_POLICY_IDENTIFIER 142 +#define X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED 143 +#define X509V3_R_NO_PUBLIC_KEY 144 +#define X509V3_R_NO_SUBJECT_DETAILS 145 +#define X509V3_R_ODD_NUMBER_OF_DIGITS 146 +#define X509V3_R_OPERATION_NOT_DEFINED 147 +#define X509V3_R_OTHERNAME_ERROR 148 +#define X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED 149 +#define X509V3_R_POLICY_PATH_LENGTH 150 +#define X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED 151 +#define X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY 152 +#define X509V3_R_SECTION_NOT_FOUND 153 +#define X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS 154 +#define X509V3_R_UNABLE_TO_GET_ISSUER_KEYID 155 +#define X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT 156 +#define X509V3_R_UNKNOWN_EXTENSION 157 +#define X509V3_R_UNKNOWN_EXTENSION_NAME 158 +#define X509V3_R_UNKNOWN_OPTION 159 +#define X509V3_R_UNSUPPORTED_OPTION 160 +#define X509V3_R_UNSUPPORTED_TYPE 161 +#define X509V3_R_USER_TOO_LONG 162 + +#endif diff --git a/project/jni/boringssl/lib-arm64-v8a/libcrypto.a b/project/jni/boringssl/lib-arm64-v8a/libcrypto.a new file mode 100644 index 000000000..e932627fd Binary files /dev/null and b/project/jni/boringssl/lib-arm64-v8a/libcrypto.a differ diff --git a/project/jni/boringssl/lib-arm64-v8a/libssl.a b/project/jni/boringssl/lib-arm64-v8a/libssl.a new file mode 100644 index 000000000..588fe2610 Binary files /dev/null and b/project/jni/boringssl/lib-arm64-v8a/libssl.a differ diff --git a/project/jni/boringssl/lib-armeabi-v7a/libcrypto.a b/project/jni/boringssl/lib-armeabi-v7a/libcrypto.a new file mode 100644 index 000000000..cb5075525 Binary files /dev/null and b/project/jni/boringssl/lib-armeabi-v7a/libcrypto.a differ diff --git a/project/jni/boringssl/lib-armeabi-v7a/libssl.a b/project/jni/boringssl/lib-armeabi-v7a/libssl.a new file mode 100644 index 000000000..f8a94970c Binary files /dev/null and b/project/jni/boringssl/lib-armeabi-v7a/libssl.a differ diff --git a/project/jni/boringssl/lib-x86/libcrypto.a b/project/jni/boringssl/lib-x86/libcrypto.a new file mode 100644 index 000000000..19a47f5a3 Binary files /dev/null and b/project/jni/boringssl/lib-x86/libcrypto.a differ diff --git a/project/jni/boringssl/lib-x86/libssl.a b/project/jni/boringssl/lib-x86/libssl.a new file mode 100644 index 000000000..e6b7e3a91 Binary files /dev/null and b/project/jni/boringssl/lib-x86/libssl.a differ diff --git a/project/jni/boringssl/lib-x86_64/libcrypto.a b/project/jni/boringssl/lib-x86_64/libcrypto.a new file mode 100644 index 000000000..d485ea73a Binary files /dev/null and b/project/jni/boringssl/lib-x86_64/libcrypto.a differ diff --git a/project/jni/boringssl/lib-x86_64/libssl.a b/project/jni/boringssl/lib-x86_64/libssl.a new file mode 100644 index 000000000..abd8e1830 Binary files /dev/null and b/project/jni/boringssl/lib-x86_64/libssl.a differ diff --git a/project/jni/crypto b/project/jni/crypto index fc538edfe..4eadeea9a 120000 --- a/project/jni/crypto +++ b/project/jni/crypto @@ -1 +1 @@ -openssl \ No newline at end of file +boringssl \ No newline at end of file diff --git a/project/jni/curl/Android.mk b/project/jni/curl/Android.mk index a07338bcd..1fe42b5a5 100644 --- a/project/jni/curl/Android.mk +++ b/project/jni/curl/Android.mk @@ -66,11 +66,10 @@ CURL_HEADERS := \ mprintf.h \ multi.h \ stdcheaders.h \ - typecheck-gcc.h \ - types.h + typecheck-gcc.h LOCAL_SRC_FILES := $(addprefix lib/,$(CSOURCES)) -LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/include/curl $(LOCAL_PATH)/lib $(LOCAL_PATH)/../openssl/include +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/include/curl $(LOCAL_PATH)/lib $(LOCAL_PATH)/../boringssl/include LOCAL_CFLAGS += $(common_CFLAGS) LOCAL_MODULE:= libcurl diff --git a/project/jni/curl/CHANGES b/project/jni/curl/CHANGES index 1b8e3ece5..da5ded9d4 100644 --- a/project/jni/curl/CHANGES +++ b/project/jni/curl/CHANGES @@ -6,4708 +6,5470 @@ Changelog -Daniel Stenberg (15 Dec 2010) -- RELEASE-NOTES: synced with a865bd9fbaaa43e5c +Version 7.48.0 (23 Mar 2016) -- IsPipeliningPossible: only for HTTP +Daniel Stenberg (23 Mar 2016) +- RELEASE-NOTES: curl 7.48.0 + +- THANKS: 15 new contributors from 7.48.0 release + +Jay Satiro (23 Mar 2016) +- CURLINFO_TLS_SSL_PTR.3: Warn about limitations - The function that checks if pipelining is possible now requires the HTTP - bit to be set so that it doesn't mistakenly tries to do it for other - protocols. + Bug: https://github.com/curl/curl/issues/685 + +Daniel Stenberg (22 Mar 2016) +- Revert "sshserver: remove use of AuthorizedKeysFile2" - Bug: http://curl.haxx.se/mail/lib-2010-12/0152.html - Reported by: Dmitri Shubin - -- multi_runsingle: don't timeout completed handles + It seems we may have some autobuild problems after this commit went + in. Trying to see if a revert helps to get them back. - The generic timeout code must not check easy handles that are already - completed. Going to completed (again) within there risked decreasing the - number of alive handles again and thus it could go negative. + This reverts commit 2716350d1f3edc8e929f6ceeee05051090f6d642. + +- maketgz: add -j to make dist - This regression bug was added in 7.21.2 in commit ca10e28f06f1 + ... makes it a lot faster -- symbols-in-versions: CURLOPT_KEYPASSWD fixed +- libcurl-thread.3: minor nroff format fix + +- CURLINFO_TLS_SSL_PTR.3: minor nroff format fix + +- CODE_STYLE: indend example code - It was added in 7.17.0 and is not deprecated + ... to make it look nicer in markdown outputa -- RELEASE-NOTES: synced with c28443c551825 - -Dan Fandrich (8 Dec 2010) -- Mention that using other libraries can affect app licensing - -Yang Tse (7 Dec 2010) -- easy: fix compiler warning: end-of-loop code not reached - -Daniel Stenberg (6 Dec 2010) -- disconnect: pass on the dead_connection argument +Jay Satiro (22 Mar 2016) +- build-wolfssl: Update VS properties for wolfSSL v3.9.0 - Cleanup fix after Kamil's commit 5c7c9a768d0093 - -Yang Tse (6 Dec 2010) -- sws: fix compier warning: external definition with no prior declaration - -Daniel Stenberg (6 Dec 2010) -- [Heinrich Ko brought this change] - - ossl_connect_common: detect connection re-use + - Do not use wolfSSL's sample user-setting files. - ossl_connect_common() now checks whether or not 'struct - connectdata->state' is equal 'ssl_connection_complete' and if so, will - return CURLE_OK with 'done' set to 'TRUE'. This check prevents - ossl_connect_common() from creating a new ssl connection on an existing - ssl session which causes openssl to fail when it tries to parse an - encrypted TLS packet since the cipher data was effectively thrown away - when the new ssl connection was created. + wolfSSL starting in v3.9.0 has added their own sample user settings that + are applied by default, but we don't use them because we have our own + settings. - Bug: http://curl.haxx.se/mail/lib-2010-11/0169.html - -Kamil Dudka (6 Dec 2010) -- url: provide dead_connection flag in Curl_handler::disconnect + - Do not use wolfSSL's Visual Studio Unicode character setting. - It helps to prevent a hangup with some FTP servers in case idle session - timeout has exceeded. But it may be useful also for other protocols - that send any quit message on disconnect. Currently used by FTP, POP3, - IMAP and SMTP. - -Yang Tse (6 Dec 2010) -- ssh: fix a download resume point calculation - -Daniel Stenberg (5 Dec 2010) -- Curl_wait_for_resolv: correct timeout + wolfSSL Visual Studio projects use the Unicode character set however our + settings and options imitate mingw build which does not use the Unicode + character set. This does not appear to have any effect at the moment but + better safe than sorry. - When looping in this function and checking for the timeout being - expired, it was not updating the reference time when calculating the - timediff since previous round which made it think each subsequent loop - to have taken longer than it actually did. - I also modified the function to use the generic Curl_timeleft() function - instead of the custom logic. + These changes are backwards compatible with earlier versions. + +Steve Holme (22 Mar 2016) +- hostip6: Fixed compilation warnings when verbose strings disabled - Bug: http://curl.haxx.se/bug/view.cgi?id=3112579 - -- Curl_send/recv_plain: return errno on failure + warning C4189: 'data': local variable is initialized but not referenced - When send() and recv() fail, we now store the errno value to allow the - app to access it. + ...and some minor formatting/spacing changes. + +Daniel Stenberg (21 Mar 2016) +- sshserver: remove use of AuthorizedKeysFile2 - Bug: http://curl.haxx.se/bug/view.cgi?id=3128121 - Reported by: Yuri - -Guenter Knauf (5 Dec 2010) -- Updated OpenSSL version. - -Yang Tse (4 Dec 2010) -- fix compiler warning: conversion may lose significant bits - -- fix compiler warning: assignment within conditional expression - -- fix getinfo CURLINFO_LOCAL* for reused connections (take 2) follow-up + Support for the (undocumented) AuthorizedKeysFile2 was removed in + OpenSSH 5.9, released in September 2011 - - Show address string from proper buffer in case of connection failure. + Closes #715 + +Steve Holme (20 Mar 2016) +- connect/ntlm/http: Fixed compilation warnings when verbose strings disabled - - Try next address when inet_ntop() fails. + warning C4189: 'data': local variable is initialized but not referenced -Daniel Stenberg (3 Dec 2010) -- version-check: added brief documentation +- openssl: Fixed compilation warning when /Wall enabled - and the traditional source header + warning C4706: assignment within conditional expression -Yang Tse (3 Dec 2010) -- build: provide SIZEOF_SIZE_T DOS definition - -- build: lib/config.dos renamed to lib/config-dos.h - -- build: provide SIZEOF_SIZE_T VMS definition - -- build: move config-vms.h from subdir 'packages/vms' into 'lib' - -- build: provide SIZEOF_SIZE_T definition for non-configure builds - -- build: provide SIZEOF_SIZE_T netware definition - -- configure: undo using autobuilds to temporarily verify strict aliasing warnings. - -- fix compiler warning: rounding, sign extension, or loss of accuracy may result - -- fix compiler warning: statement is not reachable - -- fix compiler warning: conversion may lose significant bits - -- connect: fix compiler warning: unused variable - -- fix getinfo CURLINFO_LOCAL* for reused connections (take 2) - -- fix getinfo CURLINFO_LOCAL* for reused connections follow-up +- CODE_STYLE: Use boolean conditions - Reinstate IPV6 build variable that got removed. - -- fix getinfo CURLINFO_LOCAL* for reused connections + Rather than use TRUE, FALSE, NULL, 0 or != 0 in if/while conditions. - Failed to commit this file changes along with the others. + Additionally, corrected some example code to adhere to the recommended + coding style. -- fix getinfo CURLINFO_LOCAL* for reused connections - -- atoi: remove atoi usage - -- multi: fix compiler warning: conversion may lose significant bits follow-up - -- ftp: fix 'bool' data type implementation dependant usage - -- multi: fix compiler warning: conversion may lose significant bits - -- multi: fix compiler warning: enumerated type mixed with another type - -- hostip: edit comment - -- xattr: fix compiler warning: enumerated type mixed with another type - -- s/isspace/ISSPACE - -- symbol-scan: use configure script knowledge about how to run the C preprocessor - -- ignore file generated by configure - -- curl_multi_info_read: fix compiler warning: conversion may lose significant bits - -- inet_pton: fix compiler warning +- inet_pton.c: Fixed compilation warnings - warning C4146: unary minus operator applied to unsigned type, result still unsigned + warning: conversion to 'unsigned char' from 'int' may alter its value -- Curl_getaddrinfo_ex: sanitize function results follow-up. +Daniel Stenberg (19 Mar 2016) +- RELEASE-NOTES: synced with 80851028efc2fa9 -- Curl_getaddrinfo_ex: sanitize function results. +- mbedtls: fix compiler warning - Ensure that spurious results from system's getaddrinfo() ares not propagated - by Curl_getaddrinfo_ex() into the library. + vtls/mbedtls.h:67:36: warning: implicit declaration of function + ‘mbedtls_sha256’ [-Wimplicit-function-declaration] + +Steve Holme (19 Mar 2016) +- easy: Minor coding standard and style updates - Also ensure that the ai_addrlen member of Curl_getaddrinfo_ex()'s output linked - list of Curl_addrinfo structures has appropriate family-specific address size. + Following commit c5744340db. Additionally removes the need for a second + 'result code' variable as well. -Kamil Dudka (22 Nov 2010) -- openldap: use remote port in URL passed to ldap_init_fd() +Jay Satiro (19 Mar 2016) +- easy: Remove poll failure check in easy_transfer - ... not the proxy port. It makes no difference unless a proxy is used. - -Yang Tse (20 Nov 2010) -- gtls: define and use gtls_EAGAIN, gtls_EINTR and gtls_EIO. + .. because curl_multi_wait can no longer signal poll failure. - Winsock builds clobber some errno.h defines in setup_once. - -Dan Fandrich (19 Nov 2010) -- Added a couple examples that were missing from the tar ball - -- Check for errors while preprocessing curl.h in test 1119 + follow-up to 77e1726 - This showed a problem when running the test out-of-tree, so - an include path is now being added to pick up the generated - curlbuild.h file. + Bug: https://github.com/curl/curl/issues/707 -- Use the 3-argument open for compatibility with older perls - -- [Matthias Bolte brought this change] - - Detect socket errors in GnuTLS on Windows +Steve Holme (19 Mar 2016) +- build: Added missing Visual Studio filter files for VC10 onwards - On Windows, translate WSAGetLastError() to errno values as GNU - TLS does it internally, too. This is necessary because send() and - recv() on Windows don't set errno when they fail but GNU TLS - expects a proper errno value. + As these files don't need to contain references to the source files, + although typically do, added basic files which only include three + filters and don't require the project file generator to be modified. - Bug: http://curl.haxx.se/bug/view.cgi?id=3110991 + These files allow the source code to be viewed in the Solution Explorer + in versions of Visual Studio from 2010 onwards in the same manner as + previous versions did rather than one large view of files. -Yang Tse (19 Nov 2010) -- test servers: fix strict aliasing compiler warnings +- ftp/imap/pop3/smtp: Fixed compilation warning when /Wall enabled + + warning C4706: assignment within conditional expression -- configure: use autobuilds to temporarily verify strict aliasing warnings. +- config-w32.h: Fixed compilation warning when /Wall enabled - Temporarily, When cross-compiling with gcc 3.0 or later, enable strict aliasing - rules and warnings. Given that cross-compiled targets autobuilds do not run the + warning C4668: 'USE_IPV6' is not defined as a preprocessor macro, + replacing with '0' for '#if/#elif' -Julien Chaffraix (17 Nov 2010) -- configure: Prevent link errors with --librtmp. +- imap.c: Fixed compilation warning with /Wall enabled - If --librtmp was specified but pkg-config could not find the librtmp - file, we would have undefined symbols when linking curl. + warning C4701: potentially uninitialized local variable 'size' used - We prevent this error by disabling this case as suggested on the mailing + Technically this can't happen, as the usage of 'size' is protected by + 'if(parsed)' and 'parsed' is only set after 'size' has been parsed. + + Anyway, lets keep the compiler happy. + +- KNOWN_BUGS: #93 Issue with CURLFORM_CONTENTLEN in arrays on 32-bit platforms + +Daniel Stenberg (18 Mar 2016) +- bump: the coming release is 7.48.0 + +- configure: use cpp -P when needed + + Since gcc 5, the processor output can get split up on multiple lines + that made the configure script fail to figure out values from + definitions. The fix is to use cpp -P, and this fix now first checks if + cpp -P is necessary and then if cpp -P works before it uses that to + extract defined values. + + Fixes #719 + +Steve Holme (18 Mar 2016) +- formdata.c: Fixed compilation warning + + formdata.c:390: warning: cast from pointer to integer of different size + + Introduced in commit ca5f9341ef this happens because a char*, which is + 32-bits wide in 32-bit land, is being cast to a curl_off_t which is + 64-bits wide where 64-bit integers are supported by the compiler. + + This doesn't happen in 64-bit land as a pointer is the same size as a + curl_off_t. + + This fix doesn't address the fact that a 64-bit value cannot be used + for CURLFORM_CONTENTLEN when set in a form array and compiled on a + 32-bit platforms, it does at least suppress the compilation warning. + +Daniel Stenberg (18 Mar 2016) +- FAQ: 2.5 Install libcurl for both 32bit and 64bit? + +- [Gisle Vanem brought this change] + + openssl: adapt to API breakage in ERR_remove_thread_state() + + The OpenSSL API change that broke this is "Convert ERR_STATE to new + multi-threading API": openssl commit 8509dcc. + + Closes #713 + +- version: init moved to private name space, added protos + + follow-up to 80015cdd52145 + +- openssl: verbose: show matching SAN pattern + + ... to allow users to see which specfic wildcard that matched when such + is used. + + Also minor logic cleanup to simplify the code, and I removed all tabs + from verbose strings. + +Jay Satiro (16 Mar 2016) +- version: thread safety + +Steve Holme (16 Mar 2016) +- transfer: Removed redundant HTTP authentication include files + + It would also seem that share.h is not required here either as there + are no references to the Curl_share structure or functions. + +- easy: Removed redundant HTTP authentication include files + +Jay Satiro (15 Mar 2016) +- CURLOPT_SSLENGINE.3: Only for OpenSSL built with engine support + + Bug: https://curl.haxx.se/mail/lib-2016-03/0150.html + Reported-by: Oliver Graute + +Steve Holme (15 Mar 2016) +- curl_sasl: Minor code indent fixes + +Daniel Stenberg (14 Mar 2016) +- runtests: mention when run event-based + +- easy: add check to malloc() when running event-based + + ... to allow torture tests then too. + +- memdebug: skip logging the limit countdown, fflush when reached + +- CODE_STYLE: Space around operators + + As just discussed on the mailing list, also document how we prefer + spacing in expressions. + +- curl: glob_range: no need to check unsigned variable for negative + + cppcheck warned: + + [src/tool_urlglob.c:283]: (style) Checking if unsigned variable 'step_n' + is less than zero. + +- CODE_STYLE: add example for indent style as well + +- CODE_STYLE: mention braces for functions too + +- docs/Makefile.am: include CODE_STYLE in tarball too + +- CONTRIBUTE: moved out code style to a separate document + +- CODE_STYLE: initial version + + Ripped out from CONTRIBUTE into its own document, but also extended from + there. + +- curl_sasl.c: minor code indent fixes + +- multi: simplified singlesocket + + Since sh_getentry() now checks for invalid sockets itself and by + narrowing the scope of the remove_sock_from_hash variable. + +- multi: introduce sh_getentry() for looking up sockets in the sockhash + + Simplify the code by using a single entry that looks for a socket in the + socket hash. As indicated in #712, the code looked for CURL_SOCKET_BAD + at some point and that is ineffective/wrong and this makes it easier to + avoid that. + +- [Jaime Fullaondo brought this change] + + multi hash: ensure modulo performed on curl_socket_t + + Closes #712 + +Steve Holme (13 Mar 2016) +- base64: Minor coding standard and style updates + +- base64: Use 'CURLcode result' for curl result codes + +- negotiate: Use 'CURLcode result' for curl result codes + +Daniel Stenberg (13 Mar 2016) +- [Maksim Kuzevanov brought this change] + + multi_runsingle: avoid loop in CURLM_STATE_WAITPROXYCONNECT + + Closes #703 + +- TODO: Use the RFC6265 test suite + +Steve Holme (13 Mar 2016) +- checksrc.bat: Added the ability to scan src and lib source independently + +- digest: Use boolean based success code for Curl_sasl_digest_get_pair() + + Rather than use a 0 and 1 integer base result code use a TRUE / FALSE + based success code. + +- digest: Corrected some typos in comments + +- krb5: Corrected some typos in function descriptions + +- ntlm: Corrected some typos in function descriptions + +- url: Corrected indentation when calling idna_to_ascii_lz() + +- idn_win32: Use boolean based success codes + + Rather than use 0 and 1 integer base result codes use a FALSE / TRUE + based success code. + +Daniel Stenberg (10 Mar 2016) +- idn_win32.c: warning: Trailing whitespace + +Steve Holme (10 Mar 2016) +- idn_win32.c: Fixed compilation warning from commit 9e7fcd4291 + + warning C4267: 'function': conversion from 'size_t' to 'int', + possible loss of data + +Daniel Stenberg (10 Mar 2016) +- THANKS-filter: unify Michael König + +- RELEASE-NOTES: synced with 863c5766dd + +- ftp: remove a check for NULL(!) + + ... as it implies we need to check for that on all the other variable + references as well (as Coverity otherwise warns us for missing NULL + checks), and we're alredy making sure that the pointer is never NULL. + +- cookies: first n/v pair in Set-Cookie: is the cookie, then parameters + + RFC 6265 section 4.1.1 spells out that the first name/value pair in the + header is the actual cookie name and content, while the following are + the parameters. + + libcurl previously had a more liberal approach which causes significant + problems when introducing new cookie parameters, like the suggested new + cookie priority draft. + + The previous logic read all n/v pairs from left-to-right and the first + name used that wassn't a known parameter name would be used as the + cookie name, thus accepting "Set-Cookie: Max-Age=2; person=daniel" to be + a cookie named 'person' while an RFC 6265 compliant parser should + consider that to be a cookie named 'Max-Age' with an (unknown) parameter + 'person'. + + Fixes #709 + +- krb5: improved type handling to avoid clang compiler warnings + +- url.c: fix clang warning: no newline at end of file + +- curl_multi_wait: never return -1 in 'numfds' + + Such a return value isn't documented but could still happen, and the + curl tool code checks for it. It would happen when the underlying + Curl_poll() function returns an error. Starting now we mask that error + as a user of curl_multi_wait() would have no way to handle it anyway. + + Reported-by: Jay Satiro + Closes #707 + +- HTTP2.md: add CURL_HTTP_VERSION_2TLS and updated alt-svc link + +- curl_multi_wait.3: add example + +Steve Holme (8 Mar 2016) +- imap/pop3/smtp: Fixed connections upgraded with TLS are not reused + + Regression since commit 710f14edba. + + Bug: https://github.com/curl/curl/issues/422 + Reported-by: Justin Ehlert + +Jay Satiro (8 Mar 2016) +- opt-docs: fix heading macros + + ..SH should be .SH + + Bug: https://github.com/curl/curl/issues/705 + Reported-by: Eric S. Raymond + +Kamil Dudka (8 Mar 2016) +- [Tim Rühsen brought this change] + + cookie: do not refuse cookies for localhost + + Closes #658 + +Daniel Stenberg (8 Mar 2016) +- ftp_done: clear tunnel_state when secondary socket closes + + Introducing a function for closing the secondary connection to make this + bug less likely to happen again. + + Reported-by: daboul + Closes #701 + +- [Gisle Vanem brought this change] + + openssl: use the correct OpenSSL/BoringSSL/LibreSSL in messages + +- HTTP2.md: HTTP/2 by default for curl's HTTPS connections + +- [Anders Bakken brought this change] + + pipeline: Sanity check pipeline pointer before accessing it. + + I got a crash with this stack: + + curl/lib/url.c:2873 (Curl_removeHandleFromPipeline) + curl/lib/url.c:2919 (Curl_getoff_all_pipelines) + curl/lib/multi.c:561 (curl_multi_remove_handle) + curl/lib/url.c:415 (Curl_close) + curl/lib/easy.c:859 (curl_easy_cleanup) + + Closes #704 + +- HTTP2.md: mention the disable ALPN and NPN options + +- TODO: 17.12 keep running, read instructions from pipe/socket + + And delete trailing whitespace + And rename section 17 to "command line tool" from "client" + + Closes #702 + +- README.md: linkified + + It also makes it less readable as plain text, so let's keep this + primarily for github use. + + Removed the top ascii art logo, as it looks weird when markdownified. + +- README.md: markdown version of README + + Attempt to make it look more appealing on github + +Jay Satiro (6 Mar 2016) +- mprintf: update trio project link + +Daniel Stenberg (6 Mar 2016) +- CURLOPT_ACCEPTTIMEOUT_MS.3: added example + +- CURLOPT_ACCEPT_ENCODING.3: added example + +- CURLOPT_APPEND.3: added example + +- CURLOPT_NOPROGRESS.3: added example, conform to stardard style + +Steve Holme (6 Mar 2016) +- build-openssl/checksrc.bat: Fixed prepend vs append of Perl path + + Fixed inconsistency from commit 1eae114065 and 0ad6c72227 of the order + in which Perl was added to the PATH. + +Daniel Stenberg (6 Mar 2016) +- opts: added two examples + +- CURLOPT_SSL_CTX_FUNCTION.3: use .NF for example + +- CURLOPT_SSL_CTX_FUNCTION.3: added example + + and removed erroneous reference to test case lib509 + +- curlx.c: use more curl style code + +- test46: change cookie expiry date + + Since two of the cookies would now otherwise expire and cause the test + to fail after commit 20de9b4f09 + + Discussed in #697 + +Jay Satiro (5 Mar 2016) +- [Viktor Szakats brought this change] + + makefile.m32: add missing libs for static -winssl-ssh2 builds + + Bug: https://github.com/curl/curl/pull/693 + +- mbedtls: fix user-specified SSL protocol version + + Prior to this change when a single protocol CURL_SSLVERSION_ was + specified by the user that version was set only as the minimum version + but not as the maximum version as well. + +Steve Holme (5 Mar 2016) +- .gitignore: Added *.VC.opendb and *.vcxproj.user files for VC14 + +- build-openssl.bat: Fixed cannot find perl if installed but not in path + +- checksrc.bat: Fixed cannot find perl if installed but not in path + +Jay Satiro (5 Mar 2016) +- [Viktor Szakats brought this change] + + makefile.m32: fix to allow -ssh2-winssl combination + + In makefile.m32, option -ssh2 (libssh2) automatically implied -ssl + (OpenSSL) option, with no way to override it with -winssl. Since both + libssh2 and curl support using Windows's built-in SSL backend, modify + the logic to allow that combination. + +- cookie: Don't expire session cookies in remove_expired + + Prior to this change cookies with an expiry date that failed parsing + and were converted to session cookies could be purged in remove_expired. + + Bug: https://github.com/curl/curl/issues/697 + Reported-by: Seth Mos + +Daniel Stenberg (3 Mar 2016) +- cookie: remove redundant check + + ... as it was already checked previously within the function. + + Reported-by: Dmitry-Me + Closes #695 + +Jay Satiro (1 Mar 2016) +- [Anders Bakken brought this change] + + url: if Curl_done is premature then pipeline not in use + + Prevent a crash if 2 (or more) requests are made to the same host and + pipelining is enabled and the connection does not complete. + + Bug: https://github.com/curl/curl/pull/690 + +- [Viktor Szakats brought this change] + + makefile.m32: allow to pass .dll/.exe-specific LDFLAGS + + using envvars `CURL_LDFLAG_EXTRAS_DLL` and + `CURL_LDFLAG_EXTRAS_EXE` respectively. This + is useful f.e. to pass ASLR-related extra + options, that are required to make this + feature work when using the mingw toolchain. + + Ref: https://github.com/curl/curl/pull/670#issuecomment-190863985 + + Closes https://github.com/curl/curl/pull/689 + +Daniel Stenberg (29 Feb 2016) +- formpost: fix memory leaks in AddFormData error branches + + Reported-by: Dmitry-Me + Fixes #688 + +Jay Satiro (28 Feb 2016) +- getinfo: Fix syntax error when mbedTLS + + The assignment of the mbedTLS TLS session info in the parent commit was + incorrect. Change the assignment to a pointer to the session structure. + +- getinfo: Add support for mbedTLS TLS session info + + .. and preprocessor check TLS session info is defined for all backends. + +Daniel Stenberg (26 Feb 2016) +- ROADMAP: clarify on the TLS proxy, mention HTTP cookies to work on + +- file: try reading from files with no size + + Some systems have special files that report as 0 bytes big, but still + contain data that can be read (for example /proc/cpuinfo on + Linux). Starting now, a zero byte size is considered "unknown" size and + will be read as far as possible anyway. + + Reported-by: Jesse Tan + + Closes #681 + +Jay Satiro (25 Feb 2016) +- configure: warn on invalid ca bundle or path + + - Warn if --with-ca-bundle file does not exist. + + - Warn if --with-ca-path directory does not contain certificates. + + - Improve help messages for both. + + Example configure output: + + ca cert bundle: /some/file (warning: certs not found) + ca cert path: /some/dir (warning: certs not found) + + Bug: https://github.com/curl/curl/issues/404 + Reported-by: Jeffrey Walton + +Daniel Stenberg (24 Feb 2016) +- Curl_read: check for activated HTTP/1 pipelining, not only requested + + ... as when pipelining is used, we read things into a unified buffer and + we don't do that with HTTP/2. This could then easily make programs that + set CURLMOPT_PIPELINING = CURLPIPE_HTTP1|CURLPIPE_MULTIPLEX to get data + intermixed or plain broken between HTTP/2 streams. + + Reported-by: Anders Bakken + +Patrick Monnerat (24 Feb 2016) +- os400: Fix ILE/RPG definition of CURLOPT_TFTP_NO_OPTIONS + +Jay Satiro (23 Feb 2016) +- getinfo: CURLINFO_TLS_SSL_PTR supersedes CURLINFO_TLS_SESSION + + The two options are almost the same, except in the case of OpenSSL: + + CURLINFO_TLS_SESSION OpenSSL session internals is SSL_CTX *. + + CURLINFO_TLS_SSL_PTR OpenSSL session internals is SSL *. + + For backwards compatibility we couldn't modify CURLINFO_TLS_SESSION to + return an SSL pointer for OpenSSL. + + Also, add support for the 'internals' member to point to SSL object for + the other backends axTLS, PolarSSL, Secure Channel, Secure Transport and + wolfSSL. + + Bug: https://github.com/curl/curl/issues/234 + Reported-by: dkjjr89@users.noreply.github.com + + Bug: https://curl.haxx.se/mail/lib-2015-09/0127.html + Reported-by: Michael König + +Daniel Stenberg (23 Feb 2016) +- multi_remove_handle: keep the timeout list until after disconnect + + The internal Curl_done() function uses Curl_expire() at times and that + uses the timeout list. Better clean up the list once we're done using + it. This caused a segfault. + + Reported-by: 蔡文凱 + Bug: https://curl.haxx.se/mail/lib-2016-02/0097.html + +Kamil Dudka (23 Feb 2016) +- tests/sshserver.pl: use RSA instead of DSA for host auth + + DSA is no longer supported by OpenSSH 7.0, which causes all SCP/SFTP + test cases to be skipped. Using RSA for host authentication works with + both old and new versions of OpenSSH. + + Reported-by: Karlson2k + + Closes #676 + +Jay Satiro (23 Feb 2016) +- TFTP: add option to suppress TFTP option requests (Part 2) + + - Add tests. + + - Add an example to CURLOPT_TFTP_NO_OPTIONS.3. + + - Add --tftp-no-options to expose CURLOPT_TFTP_NO_OPTIONS. + + Bug: https://github.com/curl/curl/issues/481 + +- [Michael Koenig brought this change] + + TFTP: add option to suppress TFTP option requests (Part 1) + + Some TFTP server implementations ignore the "TFTP Option extension" + (RFC 1782-1784, 2347-2349), or implement it in a flawed way, causing + problems with libcurl. Another switch for curl_easy_setopt + "CURLOPT_TFTP_NO_OPTIONS" is introduced which prevents libcurl from + sending TFTP option requests to a server, avoiding many problems caused + by faulty implementations. + + Bug: https://github.com/curl/curl/issues/481 + +Daniel Stenberg (22 Feb 2016) +- [Karlson2k brought this change] + + runtests: Fixed usage of %PWD on MinGW64 + + Closes #672 + +Jay Satiro (20 Feb 2016) +- CURLOPT_DEBUGFUNCTION.3: Fix example + +- [Viktor Szakats brought this change] + + src/Makefile.m32: add CURL_{LD,C}FLAGS_EXTRAS support + + Sync with lib/Makefile.m32 which already uses those variables. + + Bug: https://github.com/curl/curl/pull/670 + +Dan Fandrich (20 Feb 2016) +- Enabled test 1437 after the bug fix in commit 3fa220a6 + +Jay Satiro (19 Feb 2016) +- [Emil Lerner brought this change] + + curl_sasl: Fix memory leak in digest parser + + If any parameter in a HTTP DIGEST challenge message is present multiple + times, memory allocated for all but the last entry should be freed. + + Bug: https://github.com/curl/curl/pull/667 + +Dan Fandrich (19 Feb 2016) +- Added test 1437 to verify a memory leak + + Reported-by: neex@users.noreply.github.com + +Jay Satiro (18 Feb 2016) +- CURLOPT_COOKIEFILE.3: HTTP headers must be Set-Cookie style + + Bug: https://github.com/curl/curl/issues/666 + Reported-by: baumanj@users.noreply.github.com + +- curl.1: HTTP headers for --cookie must be Set-Cookie style + + Bug: https://github.com/curl/curl/issues/666 + Reported-by: baumanj@users.noreply.github.com + +Daniel Stenberg (18 Feb 2016) +- curl.1: add a missing dash + +- CONTRIBUTING.md: fix links + +- ISSUE_TEMPLATE: github issue template + + First version, try this out! + +- CONTRIBUTING.md: move into .github + + To hide github specific files somewhat from the rest. + +- opts: add references + +- examples/make: add 'checksrc' target + +- 10-at-a-time: typecast the argument passed to sleep() + +- externalsocket.c: fix compiler warning for fwrite return type + +- anyauthput.c: fix compiler warnings + +- simplessl.c: warning: while with space + +- curlx.c: i2s_ASN1_IA5STRING() clashes with an openssl function + + Reported-By: Gisle Vanem + +- http2: don't decompress gzip decoding automatically + + At one point during the development of HTTP/2, the commit 133cdd29ea0 + introduced automatic decompression of Content-Encoding as that was what + the spec said then. Now however, HTTP/2 should work the same way as + HTTP/1 in this regard. + + Reported-by: Kazuho Oku + + Closes #661 + +Jay Satiro (16 Feb 2016) +- [Tatsuhiro Tsujikawa brought this change] + + http: Don't break the header into chunks if HTTP/2 + + nghttp2 callback deals with TLS layer and therefore the header does not + need to be broken into chunks. + + Bug: https://github.com/curl/curl/issues/659 + Reported-by: Kazuho Oku + +Daniel Stenberg (16 Feb 2016) +- [Viktor Szakats brought this change] + + openssl: use macro to guard the opaque EVP_PKEY branch + +- [Viktor Szakats brought this change] + + openssl: avoid direct PKEY access with OpenSSL 1.1.0 + + by using API instead of accessing an internal structure. + This is required starting OpenSSL 1.1.0-pre3. + + Closes #650 + +- RELEASE-NOTES: synced with ede0bfc079da + +- [Clint Clayton brought this change] + + CURLOPT_CONNECTTIMEOUT_MS.3: Fix example to use milliseconds option + + Change the example in the docs for CURLOPT_CONNECTTIMEOUT_MS to use + CURLOPT_CONNECTTIMEOUT_MS instead of CURLOPT_CONNECTTIMEOUT. + + Closes #653 + +- opt-docs: add more references + +- [David Byron brought this change] + + SCP: use libssh2_scp_recv2 to support > 2GB files on windows + + libssh2_scp_recv2 is introduced in libssh2 1.7.0 - to be released "any + day now. + + Closes #451 + +Jay Satiro (13 Feb 2016) +- [Shine Fan brought this change] + + gtls: fix for builds lacking encrypted key file support + + Bug: https://github.com/curl/curl/pull/651 + +Dan Fandrich (13 Feb 2016) +- test1604: Add to Makefile.inc so it gets run + +Jay Satiro (12 Feb 2016) +- generate.bat: Fix comment bug by removing old comments + + Remove NOTES section, it's no longer needed since we aren't setting the + errorlevel and more importantly the recently updated URL in the comments + is causing some unusual behavior that breaks the script. + + Closes https://github.com/curl/curl/issues/649 + +Kamil Dudka (12 Feb 2016) +- curl.1: --disable-{eprt,epsv} are ignored for IPv6 hosts + + The behavior has been clarified in CURLOPT_FTP_USE_{EPRT,EPSV}.3 man + pages since curl-7_12_3~131. This patch makes it clear in the curl.1 + man page, too. + + Bug: https://bugzilla.redhat.com/1305970 + +Daniel Stenberg (12 Feb 2016) +- dist: ship buildconf.bat too + + As the winbuild/* stuff uses it! + +- curlx_tvdiff: handle 32bit time_t overflows + + On 32bit systems, make sure we don't overflow and return funky values + for very large time differences. + + Reported-by: Anders Bakken + + Closes #646 + +- examples: fix some compiler warnings + +- simplessl.c: fix my breakage + +- examples: adhere to curl code style + + All plain C examples now (mostly) adhere to the curl code style. While + they are only examples, they had diverted so much and contained all + sorts of different mixed code styles by now. Having them use a unified + style helps users and readability. Also, as they get copy-and-pasted + widely by users, making sure they're clean and nice is a good idea. + + 573 checksrc warnings were addressed. + +- examples/cookie_interface.c: add cleanup call + + cleaning up handles is a good idea as we leak memory otherwise + + Also, line wrapped before 80 columns. + +Kamil Dudka (10 Feb 2016) +- nss: search slash in forward direction in dup_nickname() + + It is wasteful to search it backwards if we look for _any_ slash. + +- nss: do not count enabled cipher-suites + + We only care if at least one cipher-suite is enabled, so it does + not make any sense to iterate till the end and count all enabled + cipher-suites. + +Daniel Stenberg (10 Feb 2016) +- contributors.sh: make 79 the max column width (from 80) + +- RELEASE-NOTES: synced with c276aefee3995 + +- mbedtls.c: re-indent to better match curl standards + +- [Rafael Antonio brought this change] + + mbedtls: fix memory leak when destroying SSL connection data + + Closes #626 + +- mbedtls: fix ALPN usage segfault + + Since we didn't keep the input argument around after having called + mbedtls, it could end up accessing the wrong memory when figuring out + the ALPN protocols. + + Closes #642 + +Jay Satiro (9 Feb 2016) +- [Timotej Lazar brought this change] + + opts: update references to renamed options + +- KNOWN_BUGS: Update #92 - Windows device prefix + +- tool_doswin: Support for literal path prefix \\?\ + + For example something like --output \\?\C:\foo + +Daniel Stenberg (9 Feb 2016) +- configure: state "BoringSSL" in summary when that was detected + +- [David Benjamin brought this change] + + openssl: remove most BoringSSL #ifdefs. + + As of https://boringssl-review.googlesource.com/#/c/6980/, almost all of + BoringSSL #ifdefs in cURL should be unnecessary: + + - BoringSSL provides no-op stubs for compatibility which replaces most + #ifdefs. + + - DES_set_odd_parity has been in BoringSSL for nearly a year now. Remove + the compatibility codepath. + + - With a small tweak to an extend_key_56_to_64 call, the NTLM code + builds fine. + + - Switch OCSP-related #ifdefs to the more generally useful + OPENSSL_NO_OCSP. + + The only #ifdefs which remain are Curl_ossl_version and the #undefs to + work around OpenSSL and wincrypt.h name conflicts. (BoringSSL leaves + that to the consumer. The in-header workaround makes things sensitive to + include order.) + + This change errs on the side of removing conditionals despite many of + the restored codepaths being no-ops. (BoringSSL generally adds no-op + compatibility stubs when possible. OPENSSL_VERSION_NUMBER #ifdefs are + bad enough!) + + Closes #640 + +Jay Satiro (8 Feb 2016) +- KNOWN_BUGS: Windows device prefix is required for devices + +- tool_urlglob: Allow reserved dos device names (Windows) + + Allow --output to reserved dos device names without the device prefix + for backwards compatibility. + + Example: --output NUL can be used instead of --output \\.\NUL + + Bug: https://github.com/curl/curl/commit/4520534#commitcomment-15954863 + Reported-by: Gisle Vanem + +Daniel Stenberg (8 Feb 2016) +- cookies: allow spaces in cookie names, cut of trailing spaces + + It turns out Firefox and Chrome both allow spaces in cookie names and + there are sites out there using that. + + Turned out the code meant to strip off trailing space from cookie names + didn't work. Fixed now. + + Test case 8 modified to verify both these changes. + + Closes #639 + +Patrick Monnerat (8 Feb 2016) +- Merge branch 'master' of github.com:curl/curl + +- os400: sync ILE/RPG definitions with latest public header files. + +Daniel Stenberg (8 Feb 2016) +- [Ludwig Nussel brought this change] + + SSLCERTS: update wrt SSL CA certificate store + +- [Ludwig Nussel brought this change] + + configure: --with-ca-fallback: use built-in TLS CA fallback + + When trying to verify a peer without having any root CA certificates + set, this makes libcurl use the TLS library's built in default as + fallback. + + Closes #569 + +- Proxy-Connection: stop sending this header by default + + RFC 7230 says we should stop. Firefox already stopped. + + Bug: https://github.com/curl/curl/issues/633 + Reported-By: Brad Fitzpatrick + + Closes #633 + +- bump: work toward the next release + +- THANKS: 2 contributors from the 7.47.1 release + +- RELEASE-PROCEDURE: remove the github upload part + + ... as we're HTTPS on the main site now, there's no point in that + extra step + +Version 7.47.1 (8 Feb 2016) + +Daniel Stenberg (8 Feb 2016) +- RELEASE-NOTES: curl 7.47.1 time! + +Jay Satiro (8 Feb 2016) +- tool_operhlp: Check for backslashes in get_url_file_name + + Extract the filename from the last slash or backslash. Prior to this + change backslashes could be part of the filename. + + This change needed for the curl tool built for Cygwin. Refer to the + CYGWIN addendum in advisory 20160127B. + + Bug: https://curl.haxx.se/docs/adv_20160127B.html + +Daniel Stenberg (7 Feb 2016) +- RELEASE-NOTES: synced with d6a8869ea34 + +Jay Satiro (6 Feb 2016) +- openssl: Fix signed/unsigned mismatch warning in X509V3_ext + + sk_X509_EXTENSION_num may return an unsigned integer, however the value + will fit in an int. + + Bug: https://github.com/curl/curl/commit/dd1b44c#commitcomment-15913896 + Reported-by: Gisle Vanem + +Daniel Stenberg (7 Feb 2016) +- TODO: 17.11 -w output to stderr + +Jay Satiro (6 Feb 2016) +- [Michael Kaufmann brought this change] + + idn_win32: Better error checking + + .. also fix a conversion bug in the unused function + curl_win32_ascii_to_idn(). + + And remove wprintfs on error (Jay). + + Bug: https://github.com/curl/curl/pull/637 + +- [Gisle Vanem brought this change] + + examples/asiohiper: Avoid function name collision on Windows + + closesocket => close_socket + Winsock already has the former. + + Bug: https://curl.haxx.se/mail/lib-2016-02/0016.html + +- [Gisle Vanem brought this change] + + examples/htmltitle: Use _stricmp on Windows + + Bug: https://curl.haxx.se/mail/lib-2016-02/0017.html + +Daniel Stenberg (6 Feb 2016) +- COPYING: clarify that Daniel is not the sole author + + ... done on request and as it is a fair point. + +Jay Satiro (5 Feb 2016) +- unit1604: Fix unit setup return code + +- tool_doswin: Use type SANITIZEcode in sanitize_file_name + +- tool_doswin: Improve sanitization processing + + - Add unit test 1604 to test the sanitize_file_name function. + + - Use -DCURL_STATICLIB when building libcurltool for unit testing. + + - Better detection of reserved DOS device names. + + - New flags to modify sanitize behavior: + + SANITIZE_ALLOW_COLONS: Allow colons + SANITIZE_ALLOW_PATH: Allow path separators and colons + SANITIZE_ALLOW_RESERVED: Allow reserved device names + SANITIZE_ALLOW_TRUNCATE: Allow truncating a long filename + + - Restore sanitization of banned characters from user-specified outfile. + + Prior to this commit sanitization of a user-specified outfile was + temporarily disabled in 2b6dadc because there was no way to allow path + separators and colons through while replacing other banned characters. + Now in such a case we call the sanitize function with + SANITIZE_ALLOW_PATH which allows path separators and colons to pass + through. + + + Closes https://github.com/curl/curl/issues/624 + Reported-by: Octavio Schroeder + +- [Viktor Szakats brought this change] + + URLs: change more http to https + +- sasl_sspi: Fix memory leak in domain populate + + Free an existing domain before replacing it. + + Bug: https://github.com/curl/curl/issues/635 + Reported-by: silveja1@users.noreply.github.com + +Daniel Stenberg (4 Feb 2016) +- [Viktor Szakats brought this change] + + URLs: follow GitHub project rename (also Travis CI) + + Closes #632 + +- CHANGES.o: fix references to curl.haxx.nu + + I removed the scheme prefix from the URLs references this host name, as + we don't own/run that anymore but the name is kept for historic reasons. + +- HISTORY: add some info about when we used which host names + +Jay Satiro (2 Feb 2016) +- [Viktor Szakats brought this change] + + URLs: change more http to https + +Dan Fandrich (3 Feb 2016) +- URLs: Change more haxx.se URLs from http: to https: + +Daniel Stenberg (3 Feb 2016) +- RELEASE-NOTES: synced with 4af40b364 + +- URLs: change all http:// URLs to https:// + +- configure: update the copyright year range in output + +- dotdot: allow an empty input string too + + It isn't used by the code in current conditions but for safety it seems + sensible to at least not crash on such input. + + Extended unit test 1395 to verify this too as well as a plain "/" input. + +- HTTPS: update a bunch of URLs from HTTP to HTTPS + +- [Sergei Nikulov brought this change] + + AppVeyor: updated to handle OpenSSL/WinSSL builds + + Closes #621 + +Jay Satiro (1 Feb 2016) +- tool_operate: Don't sanitize --output path (Windows) + + Due to path separators being incorrectly sanitized in --output + pathnames, eg -o c:\foo => c__foo + + This is a partial revert of 3017d8a until I write a proper fix. The + remote-name will continue to be sanitized, but if the user specified an + --output with string replacement (#1, #2, etc) that data is unsanitized + until I finish a fix. + + Bug: https://github.com/bagder/curl/issues/624 + Reported-by: Octavio Schroeder + +- curl.1: Explain remote-name behavior if file already exists + + .. also warn about letting the server pick the filename. + +- [Gisle Vanem brought this change] + + urldata: Error on missing SSL backend-specific connect info + +Daniel Stenberg (28 Jan 2016) +- bump: towards the next (7.47.1 ?) + +- [Sergei Nikulov brought this change] + + cmake: fixed when OpenSSL enabled on Windows and schannel detected + + Closes #617 + +Jay Satiro (28 Jan 2016) +- [Sergei Nikulov brought this change] + + urldata: moved common variable out of ifdef + + Closes https://github.com/bagder/curl/pull/618 + +- [Viktor Szakats brought this change] + + tool_doswin: silence unused function warning + + tool_doswin.c:185:14: warning: 'msdosify' defined but not used + [-Wunused-function] + + Closes https://github.com/bagder/curl/pull/616 + +Daniel Stenberg (27 Jan 2016) +- getredirect.c: fix variable name + + Reported-by: Bernard Spil + +Version 7.47.0 (27 Jan 2016) + +Daniel Stenberg (27 Jan 2016) +- examples/Makefile.inc: specify programs without .c! + +- THANKS: 6 new contributors from 7.47.0 release notes + +- [Isaac Boukris brought this change] + + NTLM: Fix ConnectionExists to compare Proxy credentials + + Proxy NTLM authentication should compare credentials when + re-using a connection similar to host authentication, as it + authenticate the connection. + + Example: + curl -v -x http://proxy:port http://host/ -U good_user:good_pwd + --proxy-ntlm --next -x http://proxy:port http://host/ + [-U fake_user:fake_pwd --proxy-ntlm] + + CVE-2016-0755 + + Bug: http://curl.haxx.se/docs/adv_20160127A.html + +- [Ray Satiro brought this change] + + curl: avoid local drive traversal when saving file (Windows) + + curl does not sanitize colons in a remote file name that is used as the + local file name. This may lead to a vulnerability on systems where the + colon is a special path character. Currently Windows/DOS is the only OS + where this vulnerability applies. + + CVE-2016-0754 + + Bug: http://curl.haxx.se/docs/adv_20160127B.html + +- RELEASE-NOTES: 7.47.0 + +- FAQ: language fix in 4.19 + +- [paulehoffman brought this change] + + FAQ: Update to point to GitHub + + Current FAQ didn't make it clear where the main repo is. + + Closes #612 + +- maketgz: generate date stamp with LC_TIME=C + + bug: http://curl.haxx.se/mail/lib-2016-01/0123.html + +- curl_multi_socket_action.3: line wrap + +- RELEASE-NOTES: synced with d58ba66eeceb + +Steve Holme (21 Jan 2016) +- TODO: "Create remote directories" for SMB + +Jay Satiro (18 Jan 2016) +- mbedtls: Fix pinned key return value on fail + + - Switch from verifying a pinned public key in a callback during the + certificate verification to inline after the certificate verification. + + The callback method had three problems: + + 1. If a pinned public key didn't match, CURLE_SSL_PINNEDPUBKEYNOTMATCH + was not returned. + + 2. If peer certificate verification was disabled the pinned key + verification did not take place as it should. + + 3. (related to #2) If there was no certificate of depth 0 the callback + would not have checked the pinned public key. + + Though all those problems could have been fixed it would have made the + code more complex. Instead we now verify inline after the certificate + verification in mbedtls_connect_step2. + + Ref: http://curl.haxx.se/mail/lib-2016-01/0047.html + Ref: https://github.com/bagder/curl/pull/601 + +- tests: Add a test for pinnedpubkey fail even when insecure + + Because disabling the peer verification (--insecure) must not disable + the public key pinning check (--pinnedpubkey). + +- [Daniel Schauenberg brought this change] + + CURLINFO_RESPONSE_CODE.3: add example + +Kamil Dudka (15 Jan 2016) +- ssh: make CURLOPT_SSH_PUBLIC_KEYFILE treat "" as NULL + + The CURLOPT_SSH_PUBLIC_KEYFILE option has been documented to handle + empty strings specially since curl-7_25_0-31-g05a443a but the behavior + was unintentionally removed in curl-7_38_0-47-gfa7d04f. + + This commit restores the original behavior and clarifies it in the + documentation that NULL and "" have both the same meaning when passed + to CURLOPT_SSH_PUBLIC_KEYFILE. + + Bug: http://curl.haxx.se/mail/lib-2016-01/0072.html + +Daniel Stenberg (14 Jan 2016) +- RELEASE-NOTES: synced with 35083ca60ed035a + +- openssl: improved error detection/reporting + + ... by extracting the LIB + REASON from the OpenSSL error code. OpenSSL + 1.1.0+ returned a new func number of another cerfificate fail so this + required a fix and this is the better way to catch this error anyway. + +- openssl: for 1.1.0+ they now provide a SSLeay() macro of their own + +- CURLOPT_RESOLVE.3: minor language polish + +- configure: assume IPv6 works when cross-compiled + + The configure test uses AC_TRY_RUN to figure out if an ipv6 socket + works, and testing like that doesn't work for cross-compiles. These days + IPv6 support is widespread so a blind guess is probably more likely to + be 'yes' than 'no' now. + + Further: anyone who cross-compiles can use configure's --disable-ipv6 to + explicitly disable IPv6 and that also works for cross-compiles. + + Made happen after discussions in issue #594 + +- TODO: "Try to URL encode given URL" + + Closes #514 + +- ConnectionExists: only do pipelining/multiplexing when asked + + When an HTTP/2 upgrade request fails (no protocol switch), it would + previously detect that as still possible to pipeline on (which is + acorrect) and do that when PIPEWAIT was enabled even if pipelining was + not explictily enabled. + + It should only pipelined if explicitly asked to. + + Closes #584 + +- [Mohammad AlSaleh brought this change] + + lib: Prefix URLs with lower-case protocol names/schemes + + Before this patch, if a URL does not start with the protocol + name/scheme, effective URLs would be prefixed with upper-case protocol + names/schemes. This behavior might not be expected by library users or + end users. + + For example, if `CURLOPT_DEFAULT_PROTOCOL` is set to "https". And the + URL is "hostname/path". The effective URL would be + "HTTPS://hostname/path" instead of "https://hostname/path". + + After this patch, effective URLs would be prefixed with a lower-case + protocol name/scheme. + + Closes #597 + + Signed-off-by: Mohammad AlSaleh + +- [Alessandro Ghedini brought this change] + + scripts: don't generate and install zsh completion when cross-compiling + +- [Alessandro Ghedini brought this change] + + scripts: fix zsh completion generation + + The script should use the just-built curl, not the system one. This fixes + zsh completion generation when no system curl is installed. + +- [Alessandro Ghedini brought this change] + + zsh.pl: fail if no curl is found + + Instead of generation a broken completion file. + +- [Michael Kaufmann brought this change] + + IDN host names: Remove the port number before converting to ACE + + Closes #596 + +Jay Satiro (10 Jan 2016) +- runtests: Add mbedTLS to the SSL backends + + .. and enable SSLpinning tests for mbedTLS, BoringSSL and LibreSSL. + +Daniel Stenberg (10 Jan 2016) +- [Thomas Glanzmann brought this change] + + mbedtls: implement CURLOPT_PINNEDPUBLICKEY + +Jay Satiro (9 Jan 2016) +- [Tatsuhiro Tsujikawa brought this change] + + url: Fix compile error with --enable-werror + +- [Tatsuhiro Tsujikawa brought this change] + + http2: Ensure that http2_handle_stream_close is called + + Previously, when HTTP/2 is enabled and used, and stream has content + length known, Curl_read was not called when there was no bytes left to + read. Because of this, we could not make sure that + http2_handle_stream_close was called for every stream. Since we use + http2_handle_stream_close to emit trailer fields, they were + effectively ignored. This commit changes the code so that Curl_read is + called even if no bytes left to read, to ensure that + http2_handle_stream_close is called for every stream. + + Discussed in https://github.com/bagder/curl/pull/564 + +Daniel Stenberg (8 Jan 2016) +- http2: handle the received SETTINGS frame + + This regression landed in 5778e6f5 and made libcurl not act on received + settings and instead stayed with its internal defaults. + + Bug: http://curl.haxx.se/mail/lib-2016-01/0031.html + Reported-by: Bankde + +- Revert "multiplex: allow only once HTTP/2 is actually used" + + This reverts commit 46cb70e9fa81c9a56de484cdd7c5d9d0d9fbec36. + + Bug: http://curl.haxx.se/mail/lib-2016-01/0031.html + +Jay Satiro (8 Jan 2016) +- [Tatsuhiro Tsujikawa brought this change] + + http2: Fix PUSH_PROMISE headers being treated as trailers + + Discussed in https://github.com/bagder/curl/pull/564 + +Daniel Stenberg (8 Jan 2016) +- [Michael Kaufmann brought this change] + + connection reuse: IDN host names fixed + + Use the ACE form of IDN hostnames as key in the connection cache. Add + new tests. + + Closes #592 + +- tests: mark IPv6 FTP and FTPS tests with the FTP keyword + +Jay Satiro (7 Jan 2016) +- mbedtls: Fix ALPN support + + - Fix ALPN reply detection. + + - Wrap nghttp2 code in ifdef USE_NGHTTP2. + + + Prior to this change ALPN and HTTP/2 did not work properly in mbedTLS. + +- http2: Fix client write for trailers on stream close + + Check that the trailer buffer exists before attempting a client write + for trailers on stream close. + + Refer to comments in https://github.com/bagder/curl/pull/564 + +Daniel Stenberg (7 Jan 2016) +- COPYING: update general copyright year range + +- ConnectionExists: add missing newline in infof() call + + Mistake from commit a464f33843ee1 + +- multiplex: allow only once HTTP/2 is actually used + + To make sure curl doesn't allow multiplexing before a connection is + upgraded to HTTP/2 (like when Upgrade: h2c fails), we must make sure the + connection uses HTTP/2 as well and not only check what's wanted. + + Closes #584 + + Patch-by: c0ff + +Jay Satiro (4 Jan 2016) +- curl_global_init.3: Add Windows-specific info for init via DLL + + - Add to both curl_global_init.3 and libcurl.3 the caveat for Windows + that initializing libcurl via a DLL's DllMain or static initializer + could cause a deadlock. + + Bug: https://github.com/bagder/curl/issues/586 + Reported-by: marc-groundctl@users.noreply.github.com + +Daniel Stenberg (4 Jan 2016) +- FAQ: clarify who to mail about ECCN clarifications + +- progressfunc.c: spellfix description + +- docs/examples/multi-app.c: fix bad desc formatting + +- examples: added descriptions + +- example/simple.c: add description + +- getredirect.c: a new example + +Marc Hoersken (27 Dec 2015) +- RELEASE-NOTES: add 5e0e81a9c4e35f04ca + +Daniel Stenberg (26 Dec 2015) +- RELEASE-NOTES: synced with 2aec4359db1088b10d + +Marc Hoersken (26 Dec 2015) +- test 1515: add data check + +- test 1515: add MSYS support by passing a relative path + + MSYS would otherwise turn a /-style path into a C:\-style path. + +- test 539: use datacheck mode text for ASCII-mode LISTings + + While still using datacheck mode binary for the inline reply data. + +- runtests.pl: check up to 5 data parts with different text modes + + Move the text-mode conversion for reply/replycheck from the verify + section into the load section and add support for 4 more check parts. + +Daniel Stenberg (24 Dec 2015) +- CURLOPT_RANGE: for HTTP servers, range support is optional + +Marc Hoersken (24 Dec 2015) +- tests 1048 and 1050: use datacheck mode text for ASCII-mode LISTings + +- tests 706 and 707: use datacheck mode text for ASCII-mode LISTings + +- tests 400,403,406: use datacheck mode text for ASCII-mode LISTings + +- sockfilt.c: fix calculation of sleep timeout on Windows + + Not converting to double caused small timeouts to be skipped. + +- tests first.c: fix calculation of sleep timeout on Windows + + Not converting to double caused small timeouts to be skipped. + +- test 573: add more debug output + +- ftplistparser.c: fix handling of file LISTings using Windows EOL + + Previously file.txt[CR][LF] would have been returned as file.tx + (without the last t) if filetype is symlink. Now the t is + included and the internal item_length includes the zero byte. + + Spotted using test 576 on Windows. + +- test 16: fix on Linux (and Windows) by using plain ASCII characters + + Follow up on b064ff0c351bb287557228575ef4c1d079b866fb, thanks Daniel. + +- tftpd server: add Windows support by writing files in binary mode + +- tests 252-255: use datacheck mode text for ASCII-mode LISTings + +- test 16: fix on Windows by converting data file from ANSI to UTF-8 + +Daniel Stenberg (23 Dec 2015) +- Makefile.inc: s/curl_SOURCES/CURL_FILES + + This allows the root Makefile.am to include the Makefile.inc without + causing automake to warn on it (variables named *_SOURCES are + magic). curl_SOURCES is then instead assigned properly in + src/Makefile.am only. + + Closes #577 + +- [Anders Bakken brought this change] + + ConnectionExists: with *PIPEWAIT, wait for connections + + Try harder to prevent libcurl from opening up an additional socket when + CURLOPT_PIPEWAIT is set. Accomplished by letting ongoing TCP and TLS + handshakes complete first before the decision is made. + + Closes #575 + +- [Anders Bakken brought this change] + + Add .dir-locals and set c-basic-offset to 2. + + This makes it easier for emacs users to automatically get the right + 2-space indentation when they edit curl source files. + + c++-mode is in there as well because Emacs can't easily know if + something is a C or C++ header. + + Closes #574 + +- [Johannes Schindelin brought this change] + + configure: detect IPv6 support on Windows + + This patch was "nicked" from the MINGW-packages project by Daniel. + + https://github.com/Alexpux/MINGW-packages/commit/9253d0bf58a1486e91f7efb5316e7fdb48fa4007 + Signed-off-by: Johannes Schindelin + +- configure: allow static builds on mingw + + This patch is adopted from the MINGW-packages project. It makes it + possible to build curl both shared and static again. + + URL: https://github.com/Alexpux/MINGW-packages/tree/master/mingw-w64-curl + +Marc Hoersken (17 Dec 2015) +- test 1326: fix file check since curl is outputting binary data + +- test 1326: fix getting stuck on Windows due to incomplete request + + The request needs to be read and send in binary mode in order to use + CRLF instead of LF. Adding --upload-file - causes curl to read stdin + in binary mode. + +Daniel Stenberg (17 Dec 2015) +- RELEASE-NOTES: command line option recount + +Dan Fandrich (16 Dec 2015) +- scripts/Makefile: build zsh script even in an out-of-tree build + +Marc Hoersken (16 Dec 2015) +- sockfilt.c: added some debug output to select_ws + +- sockfilt.c: keep lines shorter than 80 chars + +- sockfilt.c: do not wait on unreliable file or pipe handle + + The previous implementation caused issues on modern MSYS2 runtimes. + +Daniel Stenberg (16 Dec 2015) +- cyassl: deal with lack of *get_peer_certificate + + The function is only present in wolfssl/cyassl if it was built with + --enable-opensslextra. With these checks added, pinning support is disabled + unless the TLS lib has that function available. + + Also fix the mistake in configure that checks for the wrong lib name. + + Closes #566 + +- wolfssl: handle builds without SSLv3 support + +- [Tatsuhiro Tsujikawa brought this change] + + http2: Support trailer fields + + This commit adds trailer support in HTTP/2. In HTTP/1.1, chunked + encoding must be used to send trialer fields. HTTP/2 deprecated any + trandfer-encoding, including chunked. But trailer fields are now + always available. + + Since trailer fields are relatively rare these days (gRPC uses them + extensively though), allocating buffer for trailer fields is done when + we detect that HEADERS frame containing trailer fields is started. We + use Curl_add_buffer_* functions to buffer all trailers, just like we + do for regular header fields. And then deliver them when stream is + closed. We have to be careful here so that all data are delivered to + upper layer before sending trailers to the application. + + We can deliver trailer field one by one using NGHTTP2_ERR_PAUSE + mechanism, but current method is far more simple. + + Another possibility is use chunked encoding internally for HTTP/2 + traffic. I have not tested it, but it could add another overhead. + + Closes #564 + +- RELEASE-NOTES: synced with 6c2c019654e658a + +Jay Satiro (15 Dec 2015) +- x509asn1: Fix host altname verification + + - In Curl_verifyhost check all altnames in the certificate. + + Prior to this change only the first altname was checked. Only the GSKit + SSL backend was affected by this bug. + + Bug: http://curl.haxx.se/mail/lib-2015-12/0062.html + Reported-by: John Kohl + +Daniel Stenberg (15 Dec 2015) +- curl --expect100-timeout: added + + This is the new command line option to set the value for the existing + libcurl option CURLOPT_EXPECT_100_TIMEOUT_MS + +- cyassl: fix compiler warning on type conversion + +- curlver: the pending release will become 7.47.0 + +- [Anders Bakken brought this change] + + setstropt: const-correctness + + Closes #565 + +- ROADMAP: implemented HTTP2 for HTTPS-only + +- HTTP2.md: spell fix and remove TODO now implemented + +- libressl: the latest openssl x509 funcs are not in libressl + +- curl: use 2TLS by default + + Make this the default for the curl tool (if built with HTTP/2 powers + enabled) unless a specific HTTP version is requested on the command + line. + + This should allow more users to get HTTP/2 powers without having to + change anything. + +- http: add libcurl option to allow HTTP/2 for HTTPS only + + ... and stick to 1.1 for HTTP. This is in line with what browsers do and + should have very little risk. + +- openssl: adapt to openssl >= 1.1.0 X509 opaque structs + + Closes #491 + +- openssl: avoid BIO_reset() warnings since it returns a value + +- openssl: adapt to 1.1.0+ name changes + +- scripts/makefile: add standard header + +- scripts/Makefile: fix GNUism and survive no perl + + Closes #555 + + Reported-by: Thomas Klausner + +- fix b6d5cb40d7038fe + +- [Tatsuhiro Tsujikawa brought this change] + + http2: Fix hanging paused stream + + When NGHTTP2_ERR_PAUSE is returned from data_source_read_callback, we + might not process DATA frame fully. Calling nghttp2_session_mem_recv() + again will continue to process DATA frame, but if there is no incoming + frames, then we have to call it again with 0-length data. Without this, + on_stream_close callback will not be called, and stream could be hanged. + + Bug: http://curl.haxx.se/mail/lib-2015-11/0103.html + Reported-by: Francisco Moraes + +- [Christian Stewart brought this change] + + build: fix compilation error with CURL_DISABLE_VERBOSE_STRINGS + + With curl disable verbose strings in http.c the compilation fails due to + the data variable being undefined later on in the function. + + Closes #558 + +Jay Satiro (7 Dec 2015) +- [Gisle Vanem brought this change] + + config-win32: Fix warning HAVE_WINSOCK2_H undefined + +- [Gisle Vanem brought this change] + + openssl: BoringSSL doesn't have CONF_modules_free + +- [Gisle Vanem brought this change] + + lwip: Fix compatibility issues with later versions + + The name of the header guard in lwIP's has changed from + '__LWIP_OPT_H__' to 'LWIP_HDR_OPT_H' (bug #35874 in May 2015). + + Other fixes: + + - In curl_setup.h, the problem with an old PSDK doesn't apply if lwIP is + used. + + - In memdebug.h, the 'socket' should be undefined first due to lwIP's + lwip_socket() macro. + + - In curl_addrinfo.c lwIP's getaddrinfo() + freeaddrinfo() macros need + special handling because they were undef'ed in memdebug.h. + + - In select.c we can't use preprocessor conditionals inside select if + MSVC and select is a macro, as it is with lwIP. + + http://curl.haxx.se/mail/lib-2015-12/0023.html + http://curl.haxx.se/mail/lib-2015-12/0024.html + +Patrick Monnerat (7 Dec 2015) +- os400: define CURL_VERSION_PSL in ILE/RPG binding + +Jay Satiro (7 Dec 2015) +- [Gisle Vanem brought this change] + + version: Add flag CURL_VERSION_PSL for libpsl + +- formdata: Check if length is too large for memory + + - If the size of the length type (curl_off_t) is greater than the size + of the size_t type then check before allocating memory to make sure the + value of length will fit in a size_t without overflow. If it doesn't + then return CURLE_BAD_FUNCTION_ARGUMENT. + + Bug: https://github.com/bagder/curl/issues/425#issuecomment-154518679 + Reported-by: Steve Holme + +Steve Holme (3 Dec 2015) +- tests: Corrected copy and pasted comments from commit e643c5c908 + +Daniel Stenberg (3 Dec 2015) +- curl: remove keepalive #ifdef checks done on libcurl's behalf + + They didn't match the ifdef logic used within libcurl anyway so they + could indeed warn for the wrong case - plus the tool cannot know how the + lib actually performs at that level. + +Steve Holme (2 Dec 2015) +- test947: Corrected typo in test name + +- tests: Disable the OAUTHBEARER tests when using a non-default port number + + Tests 842, 843, 844, 845, 887, 888, 889, 890, 946, 947, 948 and 949 fail + if a custom port number is specified via the -b option of runtests.pl. + + Suggested by: Kamil Dudka + Bug: http://curl.haxx.se/mail/lib-2015-12/0003.html + +Daniel Stenberg (2 Dec 2015) +- bump: towards next release + + for all we know now, it might be called 7.46.1 + +Version 7.46.0 (1 Dec 2015) + +Daniel Stenberg (1 Dec 2015) +- RELEASE-NOTES: updated contributor count for 7.46.0 + +- THANKS: new contributors from the 7.46.0 release + +- THANKS-filter: single Tim Rühsen spelling + +- docs/examples: gitignore some more built examples + +- RELEASE-NOTES; this bug was never released + +- RELEASE-NOTES: synced with e55f15454efacb0 + +- [Flavio Medeiros brought this change] + + Curl_read_plain: clean up ifdefs that break statements + + Closes #546 + +- http2: convert some verbose output into debug-only output + +- http2 push: add missing inits of new stream + + - set the correct stream_id for pushed streams + - init maxdownload and size properly + +- http2 push: set weight for new stream + + give the new stream the old one's stream_weight internally to avoid + sending a PRIORITY frame unless asked for it + +- curl_setup.h: undef freeaddrinfo in c-ares block to fix build + + Fixes warnings 78c25c854a added. + +- nonblock: fix setting non-blocking mode for Amiga + + IoctlSocket() apparently wants a pointer to a long, passed as a char * + in its third parameter. This bug was introduced already back in commit + c5fdeef41d from October 1 2001! + + Bug: http://curl.haxx.se/mail/lib-2015-11/0088.html + Reported-by: Norbert Kett + +- zsh install: fix DESTDIR support + + Reported-by: Mohammad AlSaleh + +Dan Fandrich (27 Nov 2015) +- lib: Only define curl_dofreeaddrinfo if struct addrinfo is available + +Steve Holme (27 Nov 2015) +- tool_paramhlp: Fixed display of URL index in password prompt for --next + + Commit f3bae6ed73 added the URL index to the password prompt when using + --next. Unfortunately, because the size_t specifier (%zu) is not + supported by all sprintf() implementations we use the curl_off_t format + specifier instead. The display of an incorrect value arises on platforms + where size_t and curl_off_t are of a different size. + +Daniel Stenberg (25 Nov 2015) +- timecond: do not add if-modified-since without timecondition + + The RTSP code path didn't skip adding the if-modified-since for certain + RTSP code paths, even if CURLOPT_TIMECONDITION was set to + CURL_TIMECOND_NONE. + + Also, an unknown non-zero CURLOPT_TIMECONDITION value no longer equals + CURL_TIMECOND_IFMODSINCE. + + Bug: http://stackoverflow.com/questions/33903982/curl-timecond-none-doesnt-work-how-to-remove-if-modified-since-header + +- RELEASE-NOTES: synced with 99d17a5e2ba77e58 + +- examples/README: cut out the incomplete list + + ... and add a generic explanation for them instead. Each example file + should contain its own description these days. + +- test1513: make sure the callback is only called once + +- [Daniel Shahaf brought this change] + + build: Install zsh completion + + Fixes #534 + Closes #537 + +- done: make sure the final progress update is made + + It would previously be skipped if an existing error was returned, but + would lead to a previous value being left there and later used. + CURLINFO_TOTAL_TIME for example. + + Still it avoids that final progress update if we reached DONE as the + result of a callback abort to avoid another callback to be called after + an abort-by-callback. + + Reported-by: Lukas Ruzicka + + Closes #538 + +- curl: expanded the -XHEAD warning text + + ... to also mention the specific options used. + +- Revert "cleanup: general removal of TODO (and similar) comments" + + This reverts commit 64e959ffe37c436503f9fed1ce2d6ee6ae50bd9a. + + Feedback-by: Dan Fandrich + URL: http://curl.haxx.se/mail/lib-2015-11/0062.html + +- CURLOPT_HEADERFUNCTION.3: fix typo + + Refer to _HEADERDATA not _WRITEDATA. + + Reported-by: Michał Piechowski + +- TODO: TCP Fast Open + +Steve Holme (22 Nov 2015) +- examples: Added website parse-able descriptions to the e-mail examples + +- TODO: Added another 'multi-interface' idea + +- smb.c: Fixed compilation warnings + + smb.c:134:3: warning: conversion to 'short unsigned int' from 'int' may + alter its value + smb.c:146:42: warning: conversion to 'unsigned int' from 'long long + unsigned int' may alter its value + smb.c:146:65: warning: conversion to 'unsigned int' from 'long long + unsigned int' may alter its value + +- schannel: Corrected copy/paste error in commit 8d17117683 + +- schannel: Use GetVersionEx() when VerifyVersionInfo() isn't available + + Regression from commit 7a8e861a5 as highlighted in the msys autobuilds. + +- examples: Fixed compilation warnings + + pop3-multi.c:96:5: warning: implicit declaration of function 'memset' + imap-multi.c:96:5: warning: implicit declaration of function 'memset' + http2-download.c:226:5: warning: implicit declaration of function 'memset' + http2-upload.c:290:5: warning: implicit declaration of function 'memset' + http2-upload.c:290:5: warning: implicit declaration of function 'memset' + +- Makefile.inc: Fixed test run error + + test845 not present in tests/data/Makefile.inc + +Daniel Stenberg (20 Nov 2015) +- TODO: remove duplicated title + +- TODO: added two more libcurl ideas + + Moved some ideas from "next major" to just ordinary ideas since we can + always add new things while keeping the old without doing a "next + major". + +Steve Holme (20 Nov 2015) +- tests: Re-enabled tests 889 and 890 following POP3 fix + +- pop3: Differentiate between success and continuation responses + +- pop3: Added clarity on some server response codes + +Daniel Stenberg (20 Nov 2015) +- [Daniel Shahaf brought this change] + + build: Fix theoretical infinite loops + + Add error-checking to 'cd' in a few cases where omitting the checks + might result in an infinite loop. + + Closes #535 + +Patrick Monnerat (19 Nov 2015) +- curl.h: s/#defien/#define/ + +- os400: synchronize ILE/RPG header file + +- os400: Provide options for libssh2 use in compile scripts. Adjust README. + +Daniel Stenberg (19 Nov 2015) +- [danielsh@apache.org brought this change] + + zsh completion: Preserve single quotes in output + + When an option's help string contains literal single quotes, those + single quotes would be stripped from the option's description in the + completion output (unless the zsh RC_QUOTES option were set while the + completion function was being sourced, which is not the default). This + patch makes the completion output contain single quotes where the --help + output does. + + Closes #532 + +Jay Satiro (18 Nov 2015) +- [MaxGiting brought this change] + + FAQ: Grammar changes + + Closes https://github.com/bagder/curl/pull/533 + +Daniel Stenberg (17 Nov 2015) +- http2: http_done: don't free already-freed push headers + + The push headers are freed after the push callback has been invoked, + meaning this code should only free the headers if the callback was never + invoked and thus the headers weren't freed at that time. + + Reported-by: Davey Shafik + +- [Anders Bakken brought this change] + + getconnectinfo: Don't call recv(2) if socket == -1 + + Closes #528 + +- CURLMOPT_PUSHFUNCTION.3: *_byname() returns only the first header + + ... if there are more than one using the same name + +- http2: minor comment typo + +- sasl; fix checksrc warnings + +Steve Holme (15 Nov 2015) +- RELEASE-NOTES: Adjusted for the recent OAuth 2.0 activity + +- tests: Disabled 889 and 890 until we support POP3 continuation responses + + As POP3 final and continuation responses both begin with a + character, + and both the finalcode and contcode variables in SASLprotoc are set as + such, we cannot tell the difference between them when we are expecting + an optional continuation from the server such as the following: + + + something else from the server + +OK final response + + Disabled these tests until such a time we can tell the responses apart. + +- tests: Corrected typos from commit ba4d8f7eba + +- tests: Added OAUTHBEARER failure response tests + +- oauth2: Support OAUTHBEARER failures sent as continuation responses + + According to RFC7628 a failure message may be sent by the server in a + base64 encoded JSON string as a continuation response. + + Currently only implemented for OAUTHBEARER and not XAUTH2. + +Daniel Stenberg (15 Nov 2015) +- RELEASE-NOTES: synced with 808a17ee675 + +Steve Holme (14 Nov 2015) +- tests: Renamed existing OAuth 2.0 (XOAUTH) tests + +- tests: Added OAuth 2.0 (OAUTHBEARER) tests + +- oauth2: Added support for OAUTHBEARER SASL mechanism to IMAP, POP3 and SNMP + + OAUTHBEARER is now the official "registered" SASL mechanism name for + OAuth 2.0. However, we don't want to drop support for XOAUTH2 as some + servers won't support the new mechanism yet. + +Daniel Stenberg (13 Nov 2015) +- RELEASE-NOTES: recounted curl_easy_setopt() options + +- typecheck-gcc.h: add missing slist-using options + + CURLOPT_RESOLVE and CURLOPT_PROXYHEADER were missing + + Also sorted the list. + +- typecheck-gcc.h: added CURLOPT_CLOSESOCKETDATA + + ... and sorted curl_is_cb_data_option alphabetically + +Jay Satiro (13 Nov 2015) +- [Sebastian Pohlschmidt brought this change] + + openssl: Free modules on cleanup + + Curl_ossl_init calls OPENSSL_load_builtin_modules() but + Curl_ossl_cleanup doesn't make a call to free these modules. + + Bug: https://github.com/bagder/curl/issues/526 + +Steve Holme (13 Nov 2015) +- symbols-in-versions: Added new CURLOPTTYPE_STRINGPOINT alias + + ...following commit aba281e762 to fix test 1119. + +Daniel Stenberg (13 Nov 2015) +- curl: mark two more options strings for --libcurl output + +- typecheck-gcc.h: add some missing string types + + Also sorted that list alphabetically + +- curl.h: introducing the STRINGPOINT alias + + As an alias for OBJECTPOINT. Provided to allow us to grep for all string + options easier. + +- cleanup: general removal of TODO (and similar) comments + + They tend to never get updated anyway so they're frequently inaccurate + and we never go back to revisit them anyway. We document issues to work + on properly in KNOWN_BUGS and TODO instead. + +- ftplistparser: remove empty function + +- openssl: remove #if check for 0.9.7 for ENGINE_load_private_key + +- openssl: all supported versions have X509_STORE_set_flags + + Simplify by removing #ifdefs and macros + +- openssl: remove 0.9.3 check + +- openssl: remove #ifdefs for < 0.9.5 support + + We only support >= 0.9.7 + +- lib/vtls/openssl: remove unused traces of yassl ifdefs + +Dan Fandrich (12 Nov 2015) +- [dfandrich brought this change] + + unit1603: Demote hash mismatch failure to a warning + + The hashes can vary between architectures (e.g. Sparc differs from x86_64). + This is not a fatal problem but just reduces the coverage of these white-box + tests, as the assumptions about into which hash bucket each key falls are no + longer valid. + +- [dfandrich brought this change] + + unit1603: Added unit tests for hash functions + +- [dfandrich brought this change] + + unit1602: Fixed failure in torture test + +Steve Holme (12 Nov 2015) +- sasl: Re-introduced XOAUTH2 in the default enabled authentication mechanism + + Following the fix in commit d6d58dd558 it is necessary to re-introduce + XOAUTH2 in the default enabled authentication mechanism, which was + removed in commit 7b2012f262, otherwise users will have to specify + AUTH=XOAUTH2 in the URL. + + Note: OAuth 2.0 will only be used when the bearer is specified. + +- [Stefan Bühler brought this change] + + sasl_sspi: fix identity memory leak in digest authentication + +- [Stefan Bühler brought this change] + + sasl_sspi: fixed unicode build for digest authentication + + Closes #525 + +- oauth2: Re-factored OAuth 2.0 state variable + +- sasl: Don't choose OAuth 2.0 if mechanism not advertised + + Regression from commit 9e8ced9890 which meant if --oauth2-bearer was + specified but the SASL mechanism wasn't supported by the server then + the mechanism would be chosen. + +Daniel Stenberg (12 Nov 2015) +- runtests: more compact "System characteristics" output + + - no point in repeating curl features that is already listed as features + from the curl -V output + + - remove the port numbers/unix domain path from the output unless + verbose is used, as that is rarely interesting to users. + +- runtests: rename conditional curl-features to $has_[name] + +Steve Holme (11 Nov 2015) +- oauth2: Introduced support for host and port details + + Added support to the OAuth 2.0 message function for host and port, in + order to accommodate the official OAUTHBEARER SASL mechanism which is + to be added shortly. + +- curl_setup.h: Removed duplicate CURL_DISABLE_RTSP when HTTP_ONLY defined + +- cmake: Add missing feature macros in config header (Part 2) + + In addition to commit a215381c94 added the RTSP, RTMP and SMB protocols. + +Daniel Stenberg (10 Nov 2015) +- [Douglas Creager brought this change] + + cmake: Add missing feature macros in config header + + The curl_config.h file can be generated either from curl_config.h.cmake + or curl_config.h.in, depending on whether you're building using CMake or + the autotools. The CMake template header doesn't include entries for + all of the protocols that you can disable, which (I think) means that + you can't actually disable those protocols when building via CMake. + + Closes #523 + +- [Douglas Creager brought this change] + + BoringSSL: Work with stricter BIO_get_mem_data() + + BoringSSL implements `BIO_get_mem_data` as a function, instead of a + macro, and expects the output pointer to be a `char **`. We have to add + an explicit cast to grab the pointer as a `const char **`. + + Closes #524 + +- http2: rectify the http2 version #if check + + We need 1.0.0 or later. Also verified by configure. + +Steve Holme (9 Nov 2015) +- oauth2: Don't use XAUTH2 in OAuth 2.0 function name + +- oauth2: Don't use XOAUTH2 in OAuth 2.0 variables + +- oauth2: Use OAuth 2.0 rather than XOAUTH2 in comments + + When referring to OAuth 2.0 we should use the official name rather the + SASL mechanism name. + +Daniel Stenberg (9 Nov 2015) +- imap: avoid freeing constant string + + The fix in 1a614c6c3 was wrong and would leed to free() of a fixed + string. + + Pointed-out-by: Kamil Dudka + +- ROADMAP: remove two items already done + +- RELEASE-NOTES: synced with 2200bf62054 + +Jay Satiro (9 Nov 2015) +- acinclude: Remove check for 16-bit curl_off_t + + Because it's illogical to check for a 16-bit curl_off_t. + + Ref: https://github.com/bagder/curl/issues/425#issuecomment-154964205 + +Dan Fandrich (8 Nov 2015) +- tool: Fixed a memory leak on OOM introduced in 19cb0c4a + +Steve Holme (8 Nov 2015) +- [Justin Ehlert brought this change] + + imap: Don't check for continuation when executing a CUSTOMREQUEST + + Bug: https://github.com/bagder/curl/issues/486 + Closes https://github.com/bagder/curl/pull/487 + +Daniel Stenberg (7 Nov 2015) +- imap: checksrc: remove space after while before paren + +- checksrc.whitelist: "missing space after close paren" + + ... when it was within a string! + +Steve Holme (7 Nov 2015) +- opts: Corrected TLS protocols list to include POP3S rather than POP3 + +- imap: Quote other 'atom-specials' and not just the space character + + Closes #517 + +- imap: Fixed double quote in LIST command when mailbox contains spaces + +Daniel Stenberg (6 Nov 2015) +- imap: fix compiler warning + + imap.c:657:13: error: assignment discards 'const' qualifier from pointer + target type [-Werror=discarded-qualifiers] + +Steve Holme (6 Nov 2015) +- imap: Don't call imap_atom() when no mailbox specified in LIST command + +Daniel Stenberg (6 Nov 2015) +- curl.1: remove the overlap --range example + + ... it is just weird to include by default even if it still works. + +- tftp tests: verify sent options too + + The tftpd test server now logs all received options and thus all TFTP + test cases need to match them exactly. + + Extended test 283 to use and verify --tftp-blksize. + +Jay Satiro (6 Nov 2015) +- getinfo: CURLINFO_ACTIVESOCKET: fix bad socket value + + - Set user info param to the socket returned by Curl_getconnectinfo, + regardless of if the socket is bad. Effectively this means the user info + param now will receive CURL_SOCKET_BAD instead of -1 on bad socket. + + - Remove incorrect comments. + + CURLINFO_ACTIVESOCKET is documented to write CURL_SOCKET_BAD to user + info param but prior to this change it wrote -1. + + Bug: https://github.com/bagder/curl/pull/518 + Reported-by: Marcel Raad + +Patrick Monnerat (5 Nov 2015) +- curl_ntlm_core: fix 2 curl_off_t constant overflows. + +- os400: adjust specific code to support new options. + +Daniel Stenberg (2 Nov 2015) +- [Lauri Kasanen brought this change] + + rawstr: Speed up Curl_raw_toupper by 40% + + Rationale: when starting up a curl-using app, all cookies from the jar + are checked against each other. This was causing a startup delay in the + Fifth browser. + + All tests pass. + + Signed-off-by: Lauri Kasanen + +- http redirects: %-encode bytes outside of ascii range + + Apparently there are sites out there that do redirects to URLs they + provide in plain UTF-8 or similar. Browsers and wget %-encode such + headers when doing a subsequent request. Now libcurl does too. + + Added test 1138 to verify. + + Closes #473 + +- RELEASE-NOTES: synced with cba5bc585410 + +- symbols-in-version: add all CURL_HTTPPOST_* symbols + +- formadd: support >2GB files on windows + + Closes #425 + +- curl.h: s/HTTPPOST_/CURL_HTTPOST_ + + Fixes a name space pollution at the cost of programs using one of these + defines will no longer compile. However, the vast majority of libcurl + programs that do multipart formposts use curl_formadd() to build this list. + + Closes #506 -Daniel Stenberg (15 Nov 2010) -- RELEASE-NOTES: synced with cbf4961bf3e4 +- mbedtls: fix "Structurally dead code" + + CID 1332129 -- gnutls->handshake: improved timeout handling +- mbedtls: fix "Logically dead code" - When no timeout is set, we call the socket_ready function with a timeout - value of 0 during handshake, which makes it loop too much/fast in this - function. It also made this function return CURLE_OPERATION_TIMEDOUT - wrongly on a slow handshake. + CID 1332128 + +- Revert "openssl: engine: remove double-free" - However, the particular bug report that highlighted this problem is not - solved by this fix, as this fix only makes the more proper error get - reported instead. + This reverts commit 370ee919b37cc9a46c36428b2bb1527eae5db2bd. - Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=594150 - Reported by: Johannes Ernst + Issue #509 has all the details but it was confirmed that the crash was + not due to this, so the previous commit was wrong. -Julien Chaffraix (13 Nov 2010) -- urldata: Capitalize enum protect_level values. +- curl.1: -E: s/private certificate/client certificate - This makes it easier to spot the enum values from the variables. - Removed some unneeded DEBUGASSERT added in the previous commit. + ... as the certificate is strictly speaking not private. + + Reported-by: John Levon -- security: tighten enum protection_level usage. +- openssl: engine: remove double-free - While changing Curl_sec_read_msg to accept an enum protection_level - instead of an int, I went ahead and fixed the usage of the associated - fields. + After a successful call to SSL_CTX_use_PrivateKey(), we must not call + EVP_PKEY_free() on the key. - Some code was assuming that prot_clear == 0. Fixed those to use the - proper value. Added assertions prior to any code that would set the - protection level. - -Yang Tse (13 Nov 2010) -- configure: fix autoconf 2.68 warning: no AC_LANG_SOURCE call detected in body + Reported-by: nased0 + Closes #509 -Daniel Stenberg (12 Nov 2010) -- curl.1: "a file", not an +Jay Satiro (27 Oct 2015) +- socks: Fix incorrect port numbers in failed connect messages -- version-check.pl: display version number for symbols +Daniel Stenberg (26 Oct 2015) +- DISTRO-DILEMMA: removed - This script is the start of a helper tool that scans a source code and - outputs the most recent libcurl version it finds symbols for. Meaning - that if there's no conditions in the code, that's the earliest libcurl - version the scanned code requires. - - It is not added to the Makefile.am yet as it is still a bit crude, but - I'm committing it to keep it and allow us to work on it. - -- [Adam Light brought this change] + Out of date and not kept accurate. It was sort of a problem of the past + anyway. - Makefile.vc6: fixed the xattr.c compile +- [xiangbin li brought this change] -Julien Chaffraix (12 Nov 2010) -- krb5: Use GSS_ERROR to check for error. + MacOSX-Framework: sdk regex fix for sdk 10.10 and later - This is the advised way of checking for errors in the GSS-API RFC. - Also added some '\n' to the error message so that they are not mixed - with other outputs. + closes #507 -- security: Pass the right parameter to init. +Jay Satiro (24 Oct 2015) +- build: Fix support for PKG_CONFIG - init is expecting app_data. Passing it the struct connecdata would make - us crash later. - -Daniel Stenberg (11 Nov 2010) -- HTTP Auth: Add CURLAUTH_ONLY + - Allow the user to use PKG_CONFIG but not PKGCONFIG. - This is a meta symbol. OR this value together with a single specific - auth value to force libcurl to probe for un-restricted auth and if not, - only that single auth algorithm is acceptable. + Background: - For example you can use CURLAUTH_DIGEST|CURLAUTH_ONLY to make libcurl - first probe for what method to use, but yet only consider Digest to be - acceptable. + Last week in 14d5a86 a change was made to allow the user to set the + PKGCONFIG variable. Today in 72d99f2 I supplemented that to allow the + more common PKG_CONFIG as an alternative if PKGCONFIG is not set. - Using _only_ CURLAUTH_DIGEST without the CURLAUTH_ONLY field, will make - libcurl explicitly use Digest right away and not do any probing. + Neither of those changes worked as expected because PKGCONFIG is + occasionally reset in configure and by the CURL_CHECK_PKGCONFIG macro. + Instead in this commit I take the approach that the user may set + PKG_CONFIG only. -- ip_version: moved to connection struct +- build: Fix mingw ssl gdi32 order - The IP version choice was previously only in the UserDefined struct - within the SessionHandle, but since we sometimes alter that option - during a request we need to have it on a per-connection basis. + - If mingw ssl make sure -lgdi32 comes after ssl libs - I also moved more "init conn" code into the allocate_conn() function - which is designed for that purpose more or less. - -Yang Tse (11 Nov 2010) -- buildconf: MAC OS X requires libtool version 1.5.26 or newer + - Allow PKG_CONFIG to set pkg-config location and options - MAC OS X requires libtool version 1.5.26 or newer, otherwise - configure will mishandle *.dSYM directories when it runs. + Bug: https://github.com/bagder/curl/pull/501 + Reported-by: Kang Lin -- configure: remove temporary autobuilds exercising of xattr function tests +Daniel Stenberg (23 Oct 2015) +- RELEASE-NOTES: synced with 03b6e078163f -- configure: use autobuilds to temporarily exercise xattr function tests - -- xattr: portability fix +- polarssl/mbedtls: fix name space pollution + + Global private symbols MUST start with Curl_! -- curl-functions: provide xattr function tests that also check number of arguments +- [Dmitry S. Baikov brought this change] -Daniel Stenberg (10 Nov 2010) -- test1120: verify FTP response 421 + mbedTLS: THREADING_SUPPORT compilation fix - curl mustn't try to use the control connection after the 421 is received + Closes #505 -- ftpserver.pl: spellfix comment +- test1137: verify --ignore-content-length for FTP -- [Rutger Hofman brought this change] +- curl.1: --ignore-content-length now works for FTP too - TFTP: resend the correct data - - I found a bug in tftp_tx() in tftp.c. If a data resend is done after - reception of an ACK/OACK, the call to sendto is wrong. +- [Kurt Fankhauser brought this change] -- [Stefan Tomanek brought this change] + ftp: allow CURLOPT_IGNORE_CONTENT_LENGTH to ignore size + + This allows FTP transfers with growing (or shrinking) files without + causing a transfer error. + + Closes #480 - write extended attributes by using fsetxattr +- CURLOPT_STREAM_WEIGHT.3: call argument 'weight' too - Instead of reopening the downloaded file, fsetxattr uses the (already - open) file descriptor to attach extended attributes. This makes the - procedure more robust against errors caused by moved or deleted files. + ... and add a little example of what the weight actually means. "Relative + proportion of bandwidth". -Dan Fandrich (9 Nov 2010) -- Check for getinfo errors before setting attributes +- http2: add stream options to dist and curl_easy_setopt.3 -Kamil Dudka (9 Nov 2010) -- ftp: treat server's response 421 as CURLE_OPERATION_TIMEDOUT - - Bug: https://bugzilla.redhat.com/650255 - Reported by: Simon H. +- http2: s/priority/weight -Daniel Stenberg (9 Nov 2010) -- symbols-in-version: add CURL_SOCKET_BAD +- http2: on_frame_recv: trust the conn/data input - I also documented the filtering logic in the symbol-scan.pl function to - clarify why not all CURL_* symbols are included. - -Yang Tse (9 Nov 2010) -- serial number bump + Removed wrong assert()s + + The 'conn' passed in as userdata can be used and there can be other + sessionhandles ('data') than the single one this checked for. -Kamil Dudka (8 Nov 2010) -- ftp: close connection as soon as ABOR has been sent +- http2: added three stream prio/deps options + + CURLOPT_STREAM_DEPENDS - ... and do not send ABOR unless really necessary. + CURLOPT_STREAM_DEPENDS_E - Bug: https://bugzilla.redhat.com/649347 - Reported by: Simon H. + CURLOPT_STREAM_PRIORITY -Daniel Stenberg (8 Nov 2010) -- RELEASE-NOTES: synced with fc6c4c10f9faab08 +- RELEASE-NOTES: synced with ace68fdc0cfed83d + +- [m-gardet brought this change] + + mbedtls:new profile with RSA min key len = 1024. - I also recounted and updated the command line and libcurl options. + Closes #502 -- help: indent the --xattr option like the others +- checksrc: add crude // detection -- curl.1: --resolve documented +Jay Satiro (21 Oct 2015) +- [Gisle Vanem brought this change] -- CURLOPT_RESOLVE: documented + build: fix for MSDOS/djgpp + + - Add a VPATH-statement for the vtls/*.c files. + + - Due to 'vtls/*.c', remove that subdir part from $(OBJECTS). -- CURLOPT_USE_SSL: move from FTP options to connection options +Daniel Stenberg (20 Oct 2015) +- copyrights: update Gisle Vanem's email -- xattr-check: correct the comment as well +- vtls: fix compiler warning for TLS backends without sha256 + + ... noticed with mbedTLS. -- xattr: use const char * for const strings +- [Jonas Minnberg brought this change] -- setxattr: fix the checks + vtls: added support for mbedTLS - My copy and paste job was a little too much copy and I missed to adjust - it properly to sys/xattr.h all over and this is a fix to cure that. + closes #496 -- CURLOPT_RESOLVE: added +Jay Satiro (19 Oct 2015) +- [Javier G. Sogo brought this change] + + cmake: Fix for add_subdirectory(curl) use-case + + - Use CURL_BINARY_DIR instead of CMAKE_BINARY_DIR. - CURLOPT_RESOLVE is a new option that sends along a curl_slist with - name:port:address sets that will populate the DNS cache with entries so - that request can be "fooled" to use another host than what otherwise - would've been used. Previously we've encouraged the use of Host: for - that when dealing with HTTP, but this new feature has the added bonus - that it allows the name from the URL to be used for TLS SNI and server - certificate name checks as well. + When including CURL using add_subdirectory the variables + CMAKE_BINARY_DIR and CURL_BINARY_DIR hold different paths. - This is a first change. Surely more will follow to make it decent. + Closes https://github.com/bagder/curl/pull/488 + Closes https://github.com/bagder/curl/pull/498 -Yang Tse (8 Nov 2010) -- fix compiler warning +Daniel Stenberg (18 Oct 2015) +- RELEASE-NOTES: synced with 4c773bcb474e -Dan Fandrich (7 Nov 2010) -- Added os-specific.c and xattr.c to the Symbian build files +- tests/FILEFORMAT: mention PSL as a valid feture to check for + + For example in test 1136 -Yang Tse (7 Nov 2010) -- xattr: fix VisualStudio builds +- teste1136: only run when PSL is enabled -- fix snapshot generation +- curl: slist_wc: remove curl_memory.h inclusion + + ... that's for the library only. -Daniel Stenberg (5 Nov 2010) -- --libcurl: simplify output +- configure: add PSL to the list of features - Removed the code that was needed for libcurl before 7.19.0 which now is - more than two years old. + ... to make test 1014 work again after e77b5b7453. + +- [Daniel Hwang brought this change] + + tool: Generate easysrc with last cache linked-list + + Using a last cache linked-list improves the performance of easysrc + generation. + + Bug: https://github.com/bagder/curl/issues/444 + Ref: https://github.com/bagder/curl/issues/429 - Simplified the top comment and corrected the URL. + Closes #452 -- [Alfred Gebert brought this change] +- [Tim Rühsen brought this change] - LDAP: detect non-binary attributes properly + cookies: Add support for Mozilla's Publix Suffix List - If the query result has a binary attribute, the binary attribute is - base64 encoded. But all following non binary attributes are also base64 - encoded which is wrong. + Use libpsl to check the domain value of Set-Cookie headers (and cookie + jar entries) for not being a Publix Suffix. - This is a test (LDAP server is public). + The configure script checks for "libpsl" by default. Disable the check + with --without-libpsl. - curl - ldap://x500.bund.de:389/o=Bund,c=DE?userCertificate,certificateSerialNumber?sub - ?cn=*Woehleke* + Ref: https://publicsuffix.org/ + Ref: https://github.com/publicsuffix/list + Ref: https://github.com/rockdaboot/libpsl -- xattr: add configure check and #ifdefs +- [Richard Hosking brought this change] + + curlbuild.h: Fix non-configure compiling to mips and sh4 targets + +- [Anders Bakken brought this change] + + http2: Don't pass unitialized name+len pairs to nghttp2_submit_request + + bug introduced by 18691642931e5c7ac8af83ac3a84fbcb36000f96. - setxattr is a glibc call to set extended attributes, so configure now - checks for it and the code is adapted to only build when the - functionality is present. + Closes #493 -- [Stefan Tomanek brought this change] +Dan Fandrich (16 Oct 2015) +- test1601: fix compilation with --enable-debug and --disable-crypto-auth - save metadata to extended file attributes +Daniel Stenberg (16 Oct 2015) +- multi: fix off-by-one finit[] array size - It is often convinient to track back the source of a once downloaded - file; this patch makes curl store the source URL and other metadata - alongside the retrieved file by using the extended attributes (if - supported by the file system and enabled by --xattr). + introduced in c6aedf680f6. It needs to be CURLM_STATE_LAST big since it + must hande the range 0 .. CURLM_STATE_MSGSENT (18) and CURLM_STATE_LAST + is 19 right now. + + Reported-by: Dan Fandrich + Bug: http://curl.haxx.se/mail/lib-2015-10/0069.html -- test: remove test 580 +- fread_func: move callback pointer from set to state struct - Test 580 is removed again for two reasons: + ... and assign it from the set.fread_func_set pointer in the + Curl_init_CONNECT function. This A) avoids that we have code that + assigns fields in the 'set' struct (which we always knew was bad) and + more importantly B) it makes it impossibly to accidentally leave the + wrong value for when the handle is re-used etc. - 1) Some compilers aren't satisfied by just a data variable called 'test' - when first.o wants a function called 'test'. The Solaris compiler says - "ld: warning: symbol `test' has differing types:" while the AIX compiler - downright rejects it. + Introducing a state-init functionality in multi.c, so that we can set a + specific function to get called when we enter a state. The + Curl_init_CONNECT is thus called when switching to the CONNECT state. - 2) Test case 1119 that was added after this test is way more complete - and cover everything test 580 does and more without introducing the same - problems. - -- Revert: use Host: name for SNI and cert name checks + Bug: https://github.com/bagder/curl/issues/346 - This reverts commit b0fd03f5b8d4520dd232a9d13567d16bd0ad8951, - 4b2fbe1e97891f, afecd1aa13b4f, 68cde058f66b3 + Closes #346 + +Dan Fandrich (14 Oct 2015) +- test1531: case the size to fix the test on non-largefile builds -- TODO-RELEASE: "TLS SNI use Host:" is done +Daniel Stenberg (13 Oct 2015) +- acinclude: remove PKGCONFIG override - 262 - Manual setting of TLS Server Name Indication - use Host: + ... and allow it to get set by a caller easier. + + Reported-by: Rainer Jung + Bug: http://curl.haxx.se/mail/lib-2015-10/0035.html -- RELEASE-NOTES: synced with 7b823badbcab9d330 +Dan Fandrich (12 Oct 2015) +- docs/INSTALL: Updated example minimal binary sizes -- curl.1: added a few missing exit codes +Daniel Stenberg (11 Oct 2015) +- [Erik Johansson brought this change] -- certcheck: use the custom Host: name for checks + openssl: Fix set up of pkcs12 certificate verification chain - If you use a custom Host: name in a request to a SSL server, libcurl - will now use that given name when it verifies the server certificate to - be correct rather than using the host name used in the actual URL. - -- SNI: simplify the custom host name use + sk_X509_pop will decrease the size of the stack which means that the loop would + end after having added only half of the certificates. - The redirect check is already done at the position where the customhost - field is assigned so there's no point in doing that a second time. + Also make sure that the X509 certificate is freed in case + SSL_CTX_add_extra_chain_cert fails. -- host: get the custom Host: name more genericly +- ntlm: error out without 64bit support as the code needs it - When given a custom host name in a Host: header, we can use it for - several different purposes other than just cookies, so we rename it and - use it for SSL SNI etc. - -- [Hongli Lai (Phusion) brought this change] + It makes it a clearer message for developers reaching that point without + the necessary support. + + Thanks-by: Jay Satiro + + Closes #78 - SNI: set name to custom Host header +- curl_global_init: set the memory function pointers correct - OpenSSL SNI host name should be set to the custom Host header, if the - user provided one. + follow-up from 6f8ecea0 -- fopen.c: re-indented, fixed previous mistake +- curl_global_init_mem: set function pointers before doing init - I've made the code intended using curl-style now to look more like other - examples. + ... as in the polarssl TLS backend for example it uses memory functions. + +Jay Satiro (9 Oct 2015) +- http2: Fix http2_recv to return -1 if recv returned -1 - My previous "fix" was a bit too invasive but is now fixed again. + If the underlying recv called by http2_recv returns -1 then that is the + value http2_recv returns to the caller. -- multi use: call multi_perform even on select() timeouts +Daniel Stenberg (8 Oct 2015) +- [Svyatoslav Mishyn brought this change] -- example: add smtp-multi.c + curl_easy_recv.3: CURLINFO_LASTSOCKET => CURLINFO_ACTIVESOCKET - An example application source code sending SMTP mail with the multi - interface. It is based on the code Alona Rossen provided, which in turn - is based on existing example/test code, and I converted it even more - into a decent example with a fair multi API use, put the info required - to edit at the top and I added some comments. + Closes #479 -- CURLOPT_NOSIGNAL: add blurb about SIGPIPE +- [Svyatoslav Mishyn brought this change] -Dan Fandrich (3 Nov 2010) -- Allow building test 580 out of tree + curl_easy_send.3: CURLINFO_LASTSOCKET => CURLINFO_ACTIVESOCKET -Daniel Stenberg (3 Nov 2010) -- dist: add symbol-scan.pl to the tarball +- [Svyatoslav Mishyn brought this change] -- test1119: verify symbols-in-versions + CURLOPT_CONNECT_ONLY.3: CURLINFO_LASTSOCKET => CURLINFO_ACTIVESOCKET -- runtests: allow tests written as perl scripts - - If a command is set type="perl", it can now specify a perl program that will - be run instead of an ordinary curl or built tool. - - A perl test automatically disables memory and valgrind debugging. +- CURLOPT_CERTINFO.3: fix reference to CURLINFO_CERTINFO -- symbol-scan: verifies symbols-in-versions +- ntlm: get rid of unconditional use of long long - This new script scans for all enums and #defines used by the curl/curl.h - and curl/multi.h headers. Then it reads all symbols mentioned in - symbols-in-vesions and make sure that there's no entries missing in - there. It then proceeds to verify that the entries that - symbols-in-vesions mentions but aren't found in the sources are truly - documented as removed. + ... since some compilers don't have it and instead use other types, such + as __int64. - This script is used in the new test case 1119 + Reported by: gkinseyhpw + Closes #478 + +Jay Satiro (8 Oct 2015) +- [Anders Bakken brought this change] -- symbols-in-versions: added 119 missing symbols + des: Fix header conditional for Curl_des_set_odd_parity - I've developed a script I call symbol-scan.pl that scans the curl.h and - multi.h header files and compare the symbols it finds in there with the - symbols symbols-in-versions documents and outputs a report on the - differences. Using this I've dug through the history to fill up - symbols-in-versions with all the symbols my script found mismatches for. + Follow up to 613e502. + +Daniel Stenberg (7 Oct 2015) +- configure: build silently by default - I will commit symbol-scan.pl separatly and think of a way to put it to - use in the build/tests so that we from now on will get this in-sync - check automatically. + 'make V=1' will make the build verbose like before -Dan Fandrich (2 Nov 2010) -- Added mk580.pl to the tar ball +- bump: start climbing toward 7.46.0 -Daniel Stenberg (2 Nov 2010) -- symbols-in-versions: added missing symbols +- RELEASE-PROCEDURE: add the github HTTPS download step -- ignore: lib580.c is generated by mk580.pl +Version 7.45.0 (7 Oct 2015) -- test: added test 580 - verifies symbols-in-versions - - The new perl script mk580.pl generates a C table in a fresh source file - named lib580.c and if that compiles fine we know that the file - docs/libcurl/symbols-in-versions at least doesn't include any symbols - that are misspelled. - - An additional feature would be to somehow scan curl/curl.h and compare - with symbols-in-versions to see if there are symbols missing. +Daniel Stenberg (7 Oct 2015) +- THANKS: 19 new contributors from the 7.45.0 announcement -- spellfix: CURLOPT_TFTP_BLKSIZE it is +- RELEASE-NOTES: synced with 69ea57970080 -Kamil Dudka (29 Oct 2010) -- ftp: prevent server from hanging on closed data connection +Jay Satiro (4 Oct 2015) +- getinfo: Fix return code for unknown CURLINFO options - Some FTP servers (e.g. Pure-ftpd) end up hanging if we close the data - connection before transferring all the requested data. If we send ABOR - in that case, it prevents the server from hanging. + - If a CURLINFO option is unknown return CURLE_UNKNOWN_OPTION. - Bug: https://bugzilla.redhat.com/643656 - Reported by: Pasi Karkkainen, Patrick Monnerat + Prior to this change CURLE_BAD_FUNCTION_ARGUMENT was returned on + unknown. That return value is contradicted by the CURLINFO option + documentation which specifies a return of CURLE_UNKNOWN_OPTION on + unknown. -Dan Fandrich (28 Oct 2010) -- Removed a leftover mention of FTP in an error message +- [rouzier brought this change] -- Removed the native Makefile.riscos files + hiperfifo: fix the pointer passed to WRITEDATA - These haven't worked in at least 8 years due to missing source - files, and most active RiscOS developers these days apparently - cross-compile anyway. + Closes https://github.com/bagder/curl/pull/471 + +- [Maksim Stsepanenka brought this change] + + tool_setopt: fix c_escape truncated octal - Signed-off-by: James Bursa + Closes https://github.com/bagder/curl/pull/469 + +Daniel Stenberg (1 Oct 2015) +- [Orange Tsai brought this change] -- Lightened the stack in wc_statemach to permit deeper recursion + gopher: don't send NUL byte - Also, added a few hints to help compilers to perform tail call - recursion optimization. + Closes #466 -Daniel Stenberg (20 Oct 2010) -- SSH: use libssh2_session_handshake() +Jay Satiro (29 Sep 2015) +- runtests: Fix pid check in checkdied - In libssh2 1.2.8, libssh2_session_handshake() replaces - libssh2_session_startup() to fix the previous portability problem with - the socket type that was too small for win64 and thus easily could cause - crashes and more. + Because the 'not' operator has a very low precedence and as a result the + entire statement was erroneously negated and could never be true. -- SSH: avoid using the libssh2_ prefix +Daniel Stenberg (30 Sep 2015) +- [Thorsten Schöning brought this change] + + win32: make recent Borland compilers use long long + +- RELEASE-NOTES: synced with 69b89050d4 + +Jay Satiro (28 Sep 2015) +- [Michael Kalinin brought this change] + + openssl: Fix algorithm init + + - Change algorithm init to happen after OpenSSL config load. - It is a bad idea to use the public prefix used by another library and - now we realize that libssh2 introduces a symbol in the upcoming version - 1.2.8 that conflicts with our static function named libssh2_free. + Additional algorithms may be available due to the user's config so we + initialize the algorithms after the user's config is loaded. + + Bug: https://github.com/bagder/curl/issues/447 + Reported-by: Denis Feklushkin + +- [Svyatoslav Mishyn brought this change] -- formdata: provide error message + docs: fix unescaped '\n' in man pages - When failing to build form post due to an error, the code now does a - proper failf(). Previously libcurl would report an error like "failed - creating formpost data" when a file wasn't possible to open which was - not easy for users to figure out. + Closes https://github.com/bagder/curl/pull/459 + +Daniel Stenberg (27 Sep 2015) +- http2: set TCP_NODELAY unconditionally - I also lower cased a function name to be named more curl-style and - removed some unnecessary code. + For a single-stream download from localhost, we managed to increase + transfer speed from 1.6MB/sec to around 400MB/sec, mostly because of + this single fix. -- URL-parsing: consider ? a divider +- http2: avoid superfluous Curl_expire() calls - The URL parser got a little stricter as it now considers a ? to be a - host name divider so that the slightly sloppier URLs work too. The - problem that made me do this change was the reported problem with an URL - like: www.example.com?email=name@example.com This form of URL is not - really a legal URL (due to the missing slash after the host name) but is - widely accepted by all major browsers and libcurl also already accepted - it, it was just the '@' letter that triggered the problem now. + ... only call it when there is data arriving for another handle than the + one that is currently driving it. - The side-effect of this change is that now libcurl no longer accepts the - ? letter as part of user-name or password when given in the URL, which - it used to accept (and is tested in test 191). That letter is however - mentioned in RFC3986 to be required to be percent encoded since it is - used as a divider. + Improves single-stream download performance quite a lot. - Bug: http://curl.haxx.se/bug/view.cgi?id=3090268 - -- curl_easy_setopt.3: spellfix + Thanks-to: Tatsuhiro Tsujikawa + Bug: http://curl.haxx.se/mail/lib-2015-09/0097.html -- curl_easy_setopt.3: CURLOPT_USE_SSL is not just for FTP +- readwrite_data: set a max number of loops - It is for FTP, SMTP, POP3, IMAP at least. + ... as otherwise a really fast pipe can "lock" one transfer for some + protocols, like with HTTP/2. -- krb4.h: removed unused prototypes +- [Sergei Nikulov brought this change] -- krb4: make a few functions static + CI: Added AppVeyor-CI for curl + + Closes #439 -- TODO-RELEASE: cleanup for 7.21.3 works +- FTP: fix uploading ASCII with unknown size - "SFTP resume with 4GB file does not work" is now removed as I'm sure - this is really a libssh2 bug and not a libcurl bug. + ... don't try to increase the supposed file size on newlines if we don't + know what file size it is! - 7.21.2 is released already + Patch-by: lzsiga -- RELEASE-NOTES: sync with 09a2d93a0f17ca +- [Tatsuhiro Tsujikawa brought this change] -- http_chunks: remove debug output + build: fix failures with -Wcast-align and -Werror - Accidentally left in there during my previous debugging of this + Closes #457 + +- [Tatsuhiro Tsujikawa brought this change] -- Curl_setopt: disallow CURLOPT_USE_SSL without SSL support + curl-confopts.m4: Add missing ')' - In order to avoid for example the pingpong protocols to issue STARTTLS - (or equivalent) even though there's no SSL support built-in. + ... for CURL_CHECK_OPTION_RT - Reported by: Sune Ahlgren - Bug: http://curl.haxx.se/mail/archive-2010-10/0045.html + Closes #456 -- options: check for features for some options - - Some options, such as the automatic decompression and some SSL related - ones now will bail out if the underlying libcurl doesn't have support - for the particular feature needed. +Jay Satiro (25 Sep 2015) +- curl_easy_getinfo.3: Add brief description for each CURLINFO -Dan Fandrich (14 Oct 2010) -- Fixed the IPv6 host address in test1203 - - Reported by: Christian Weisgerber - Bug: http://curl.haxx.se/bug/view.cgi?id=3087479 +Daniel Stenberg (23 Sep 2015) +- [Jakub Zakrzewski brought this change] -Daniel Stenberg (14 Oct 2010) -- curl_easy_setopt.3: clarify CURLOPT_CRLF + CMake: Ensure discovered include dirs are considered - The option takes a parameter that should be 1 or 0 to enable or disable - the feature. + ...during header checks. Otherwise some following header tests + (incorrectly) fail. - URL: http://curl.haxx.se/bug/view.cgi?id=3086428 + Closes #436 -Guenter Knauf (14 Oct 2010) -- Some more small Watcom makefile fixes. +- [Jakub Zakrzewski brought this change] -- Added --noconfigure switch to testcurl.pl. + CMake: Put "winsock2.h" before "windows.h" during configure checks + + "windows.h" includes "winsock.h" what causes many redefinition errors + if "winsock2.h" is included afterwards and can cause build to fail. + +- tests: disable 1510 due to CI-problems on github -- Modified Watcom makefiles to work on Linux too. +- [Mike Crowe brought this change] -- Added MingW32 rtmp target; changed Watcom targets. + gnutls: Report actual GnuTLS error message for certificate errors - Modified Watcom targets to avoid backslashs so that they can - work on Linux too. + If GnuTLS fails to read the certificate then include whatever reason it + provides in the failure message reported to the client. + + Signed-off-by: Mike Crowe -Daniel Stenberg (13 Oct 2010) -- gitignore: ignore Makefile.vc10.dist made by maketgz +- RELEASE-NOTES: synced with 6b56901b56e -- curlver.h: start over at 7.21.3 +- [Mike Crowe brought this change] -- RELEASE-NOTES: start over towards 7.21.3 + gnutls: Support CURLOPT_KEYPASSWD + + The gnutls vtls back-end was previously ignoring any password set via + CURLOPT_KEYPASSWD. Presumably this was because + gnutls_certificate_set_x509_key_file did not support encrypted keys. + + gnutls now has a gnutls_certificate_set_x509_key_file2 function that + does support encrypted keys. Let's determine at compile time whether the + available gnutls supports this new function. If it does then use it to + pass the password. If it does not then emit a helpful diagnostic if a + password is set. This is preferable to the previous behaviour of just + failing to read the certificate without giving a reason in that case. + + Signed-off-by: Mike Crowe -- THANKS: added contributors from 7.21.2 +- CURLINFO_TLS_SESSION: always return backend info + + ... even for those that don't support providing anything in the + 'internals' struct member since it offers a convenient way for + applications to figure this out. -Version 7.21.2 (12 Oct 2010) +- [Daniel Hwang brought this change] -Daniel Stenberg (12 Oct 2010) -- RELEASE-NOTES: synced with ecd624b8e774a85 + tool: remove redundant libcurl check + + The easysrc generation is run only when --libcurl is initialized. + + Ref: https://github.com/bagder/curl/issues/429 + + Closes #448 -- [Julien Chaffraix brought this change] +- [Richard van den Berg brought this change] - CMake: Build fix. + CURLOPT_PROXY.3: A proxy given as env variable gets no special treatment - Do not match the trailing '\n' in the regular expression as this would - make us dump a ) parenthesis on a new line. + Closes #449 + +- TODO: 5.7 More compressions - This fixes the following error: + Like for example brotli, as being implemented in Firefox now. + +Jay Satiro (21 Sep 2015) +- tool_operate: Don't call easysrc cleanup unless --libcurl - would get transformed into: + - Review of 4d95491. - ) + The author changed it so easysrc only initializes when --libcurl but did + not do the same for the call to easysrc cleanup. - Bug: http://curl.haxx.se/mail/lib-2010-10/0065.html - Reported by: Dimitre Dimitrov + Ref: https://github.com/bagder/curl/issues/429 -- header_callback: strip off file path separated with backslashes - - If the filename contains a backslash, only use filename portion. The - idea is that even systems that don't handle backslashes as path - separators probably want that path removed for convenience. +Daniel Stenberg (20 Sep 2015) +- [Viktor Szakats brought this change] + + CURLOPT_PINNEDPUBLICKEY.3: replace test.com with example.com - This flaw is considered a security problem, see the curl security - vulnerability http://curl.haxx.se/docs/adv_20101013.html + closes #443 -Dan Fandrich (12 Oct 2010) -- Get the curl source files for Amiga from Makefile.inc +- KNOWN_BUGS: 91 "curl_easy_perform hangs with imap and PolarSSL" - This is similar to how it's done in the lib directory. - The Amiga build appears to have been broken for a year because - of a missing homedir.c + Closes #334 -- Added section on server-supplied names to security considerations +- KNOWN_BUGS: add link to #85 -Guenter Knauf (12 Oct 2010) -- Fixed Watcom makefile. +- tests: disable 1801 until fixed + + It is unreliable and causes CI problems on github + + Closes #380 -- Added build bits for librtmp / libssh2 to Watcom makefiles. +- RELEASE-NOTES: synced with 4d95491636ee -- Added build bits for librtmp to NetWare makefiles. +- [Daniel Lee Hwang brought this change] -Daniel Stenberg (12 Oct 2010) -- SFTP: more ignoring negative file sizes + tool: generate easysrc only on --libcurl - As the change in 5f0ae7a0626cbe709 added a precaution against negative - file sizes that for some reason managed to get returned, this change now - introduces the same check at the second place in the code where the file - size from the libssh2 stat call is used. + Code should only be generated when --libcurl is used. - This check might not be suitable for a 32 bit curl_off_t, but libssh2.h - assumes long long to work and to be 64 bit so I believe such a small - curl_off_t will be very unlikely to occur in the wild. + Bug: https://github.com/bagder/curl/issues/429 + Reported-by: @greafhe, Jay Satiro + + Closes #429 + Closes #442 -- SMTP: debug output for no known auth mechanisms supported +Jay Satiro (19 Sep 2015) +- vtls: Change designator name for server's pubkey hash + + - Change the designator name we use to show the base64 encoded sha256 + hash of the server's public key from 'pinnedpubkey' to + 'public key hash'. - ... and some minor source code whitespace edits + Though the server's public key hash is only shown when comparing pinned + public key hashes, the server's hash may not match one of the pinned. -- test: urlglob error messages have no extra newline anymore +Daniel Stenberg (19 Sep 2015) +- [Isaac Boukris brought this change] -Guenter Knauf (11 Oct 2010) -- Added build bits for librtmp to MingW32 makefiles. + NTLM: Reset auth-done when using a fresh connection + + With NTLM a new connection will always require authentication. + Fixes #435 -Daniel Stenberg (8 Oct 2010) -- RELEASE-NOTES: synced with 61f4cdb73ae4 +- [Daniel Hwang brought this change] -- globbing: fix crash on unballanced open brace - - Having an open brace without a closing brace caused a segfault. + ssl: add server cert's "sha256//" hash to verbose - Having a closing brace too many caused a silent error to occur, which - caused curl to bail out and return an error code but no error message - was shown. It does now! + Add a "pinnedpubkey" section to the "Server Certificate" verbose - All error message outputs no longer wrongly get _two_ newlines written - after the error message. + Bug: https://github.com/bagder/curl/issues/410 + Reported-by: W. Mark Kubacki - Reported by: Vlad Ureche - Bug: http://curl.haxx.se/bug/view.cgi?id=3083942 + Closes #430 + Closes #410 -- [Dan Locks brought this change] +- [Jakub Zakrzewski brought this change] - libcurl.m4: AC_PATH_PROG fixes + openldap: only part of LDAP query results received - The invocation of autoconf's AC_PATH_PROG( ) is not quite right for - finding curl-config. This fix corrects the negative case (where - curl-config is not found). + Introduced with commit 65d141e6da5c6003a1592bbc87ee550b0ad75c2f + + Closes #440 -- FAQ: added "How do I submit my patch?" +- [Alessandro Ghedini brought this change] -- examples: use example.com in example URLs + openssl: don't output certinfo data -- TODO-RELEASE: libidn problem not repeatable - - "261 - configure and libidn" is removed from the list since Julien - Chaffraix tried to repeat it but failed and the reporter did not return - to provide further details. +- [Alessandro Ghedini brought this change] + + openssl: refactor certificate parsing to use OpenSSL memory BIO - Reported by: Lyndon Hill - Bug: http://curl.haxx.se/mail/lib-2010-07/0029.html + Fixes #427 -- libcurl.m4: mention argument is PREFIX +Kamil Dudka (18 Sep 2015) +- nss: prevent NSS from incorrectly re-using a session - The macro provides a --with-libcurl option that expects a PREFIX to be - specified and not actually a "directory" in which libcurl will be found. - This now spells that out more clearly. + Without this workaround, NSS re-uses a session cache entry despite the + server name does not match. This causes SNI host name to differ from + the actual host name. Consequently, certain servers (e.g. github.com) + respond by 400 to such requests. - Reported by: Dan Locks - Bug: http://curl.haxx.se/bug/view.cgi?id=3079891 + Bug: https://bugzilla.mozilla.org/1202264 -Guenter Knauf (3 Oct 2010) -- Some NetWare makefile tweaks. - - Renamed SDK_* to NDK_*; made NDK_* defines overwriteable from - environment; removed now obsolete YACC macro; - moved some curl_config.h defines to IPv6 section since they - are only needed when IPv6 is enabled - this makes libcurl compile - with older NDKs too which were not IPv6-aware. +- nss: check return values of NSS functions -Daniel Stenberg (2 Oct 2010) -- TODO-RELEASE: 416 error fixed - - "3076808 Requests fail silently following a 416 error" done +Daniel Stenberg (17 Sep 2015) +- CURLOPT_PINNEDPUBLICKEY.3: mention error code -Julien Chaffraix (2 Oct 2010) -- krb5-gssapi: Removed a memory leak in krb5_auth. +- openssl: build with < 0.9.8 - We forgot to release the buffer passed to gss_init_sec_context. + ... without sha256 support and no define saying so. - The previous logic was difficult to read as we were reusing the same - variable (gssbuf) for both input buffer and output buffer. Splitted the - logic in 2 variables to better underline who needs to be released. - Also made the code break at 80 lines. + Reported-by: Rajkumar Mandal -- krb5-gssapi: Made the function always return a value. +- libcurl-errors.3: add two missing error codes - kr5_auth missed a final 'return' statement. This is not an error in - gcc but can lead to potential bugs. + CURLE_SSL_PINNEDPUBKEYNOTMATCH and CURLE_SSL_INVALIDCERTSTATUS -- krb5-gssapi: Delete the GSS-API context. +Jay Satiro (14 Sep 2015) +- CURLOPT_PINNEDPUBLICKEY.3: Improve pubkey extraction example - This fixes a memory leak related to the GSS-API code. + - Show how a certificate can be obtained using OpenSSL. - Added a krb5_init and krb5_end functions. Also removed a work-around - the lack of proper initialization of the GSS-API context. + Bug: https://github.com/bagder/curl/pull/430 + Reported-by: Daniel Hwang -Daniel Stenberg (2 Oct 2010) -- HTTP: remove special case for 416 - - It was pointed out that the special case libcurl did for 416 was - incorrect and wrong. 416 is not really different to other errors so the - response body must be handled like for other errors/http responses. - - Reported by: Chris Smowton - Bug: http://curl.haxx.se/bug/view.cgi?id=3076808 +Daniel Stenberg (13 Sep 2015) +- http2: removed unused function + +- CURLINFO_ACTIVESOCKET.3: mention it replaces *LASTSOCKET + +- opts: add CURLINFO_* man pages to dist + +- opts: 19 more CURLINFO_* options made into stand-alone man pages + +- RELEASE-NOTES: synced with fad9604613 -- [Dan Fandrich brought this change] +- curl: customrequest_helper: deal with NULL custom method - sws: Added writedelay HTTP server command +- [Svyatoslav Mishyn brought this change] + + CURLOPT_FNMATCH_FUNCTION.3: fix typo + + s => is - This delays between write operations, hopefully making it easier - to spot problems where libcurl doesn't flush the socket properly - before waiting for the next response. + Closes #428 -- TODO-RELEASE: no bug in ftp_nextconnect +- curl: point out unnecessary uses of -X in verbose mode - The issue named "266 - Bug in ftp_nextconnect?" was deemed to not be a - bug and instead resulted in clarified docs. + It uses 'Note:' as a prefix as opposed to the common 'Warning:' to take + down the tone a bit. + + It adds a warning for using -XHEAD on other methods becasue that may + lead to a hanging connection. -- curl_easy_setopt.3: CURLOPT_DIRLISTONLY implies dir list +Jay Satiro (10 Sep 2015) +- curl_sspi: fix possibly undefined CRYPT_E_REVOKED - Make it explicit that setting CURLOPT_DIRLISTONLY to 1 will make libcurl - to list the directory. + Bug: https://github.com/bagder/curl/pull/411 + Reported-by: Viktor Szakats -- RELEASE-NOTES: synced up to 588402585bae +- buildconf.bat: fix syntax error -- TODO-RELEASE: move new features to next release +- [Benjamin Kircher brought this change] -- README.ares: we know require c-ares 1.6.0 + winbuild: run buildconf.bat if necessary -- SFTP: avoid downloading negative sizes! - - It is still not clarified exactly why this happens, but libssh2 - sometimes report a negative file size for the remote SFTP file and that - deeply confuses libcurl (or crashes it) so this precaution is added to - avoid badness. - - Reported by: Ernest Beinrohr - Bug: http://curl.haxx.se/bug/view.cgi?id=3076430 +- [Svyatoslav Mishyn brought this change] -- TODO-RELEASE: drop curl_easy_setoptv + docs: fix argument type for CURLINFO_SPEED_*, CURLINFO_SIZE_* - I haven't read any really convincing arguments for adding it + long => double -- [Dirk Manske brought this change] +Daniel Stenberg (8 Sep 2015) +- [Sergei Nikulov brought this change] - multi & hiper examples: updates and cleanups + cmake: IPv6 : disable Unix header check on Windows platform - all multi and hiper examples: + Closes #409 + +- parse_proxy: reject illegal port numbers - * don't loop curl_multi_perform calls, that was <7.20.0 style, currently - the exported multi functions will not return CURLM_CALL_MULTI_PERFORM + If the port number in the proxy string ended weirdly or the number is + too large, skip it. Mostly as a means to bail out early if a "bare" IPv6 + numerical address is used without enclosing brackets. - all hiper examples: - * renamed check_run_count to check_multi_info - * don't compare current running handle count with previous value, this - was the wrong way to check for finished requests, simply call - curl_multi_info_read - * it's also safe to call curl_multi_remove_handle inside the - curl_multi_info_read loop. + Also mention the bracket requirement for IPv6 numerical addresses to the + man page for CURLOPT_PROXY. - ghiper.c: - * replaced curl_multi_socket (that function is marked as obsolete) calls - with curl_multi_socket_action calls (as in hiperfifo.c and - evhiperfifo.c) + Closes #415 - ghiper.c and evhiperfifo.c: - * be smart as hiperfifo.c, don't do uncessary curl_multi_* calls in - new_conn and main + Reported-by: Marcel Raad -- TODO-RELEASE: one fixed, one postponed, one added +- FTP: do_more: add check for wait_data_conn in upload case - As we're already in feature freeze, I pushed the feature onwards. - -Dan Fandrich (29 Sep 2010) -- Renamed test1204 to test1117 to move it into the normal range + In some timing-dependnt cases when a 4xx response immediately followed + after a 150 when a STOR was issued, this function would wrongly return + 'complete == true' while 'wait_data_conn' was still set. + + Closes #405 + + Reported-by: Patricia Muscalu -Patrick Monnerat (29 Sep 2010) -- Add gopher protocol definition to ILE/RPG binding. - OS400 compile script in test dir updated for chkhostname. +- [Svyatoslav Mishyn brought this change] -Julien Chaffraix (28 Sep 2010) -- krb5-gssapi: Remove several memory leaks. + CURLOPT_TLSAUTH_TYPE.3: update description - Remove a leak seen on Kerberos/MIT (gss_OID is copied internally and - we were leaking it). Now we just pass NULL as advised in RFC2744. + Closes #414 + Closes #413 + +- [Svyatoslav Mishyn brought this change] + + CURLOPT_PATH_AS_IS.3: fix typo - |tmp| was never set back to buf->data. + leavit => leaveit - Cleaned up Curl_sec_end to take into account failure in Curl_sec_login - (where conn->mech would be NULL but not conn->app_data or - conn->in_buffer->data). + closes #412 + +- [Svyatoslav Mishyn brought this change] + + CURLINFO_SSL_VERIFYRESULT.3: add short description + +- [Svyatoslav Mishyn brought this change] + + CURLINFO_SSL_ENGINES.3: add short description + +- [Svyatoslav Mishyn brought this change] + + CURLINFO_CONTENT_LENGTH_UPLOAD.3: replace "receive" with "get" for consistency -- security.c: Remove Curl_sec_fflush_fd. +- [Svyatoslav Mishyn brought this change] + + CURLINFO_REDIRECT_TIME.3: remove redundant '!' + +Kamil Dudka (4 Sep 2015) +- Revert "has: generate the curl/has.h header" - The current implementation would make us send wrong data on a closed - socket. We don't buffer our data so the method can be safely removed. + This reverts commit a60bde79f9adeb135d5c642a07f0d783fbfbbc25 I have + pushed by mistake. Apologies for my incompetent use of the git repo! -- security.c: We should always register the socket handler. +- nss: do not directly access SSL_ImplementedCiphers[] - Following a change in the way socket handler are registered, the custom - recv and send method were conditionaly registered. - We need to register them everytime to handle the ftp security - extensions. + It causes dynamic linking issues at run-time after an update of NSS. - Re-added the clear text handling in sec_recv. + Bug: https://lists.fedoraproject.org/pipermail/devel/2015-September/214117.html + +- [Daniel Stenberg brought this change] -- security.c: Fix Curl_sec_login after rewrite. + has: generate the curl/has.h header - Curl_sec_login was returning the opposite result that the code in ftp.c - was expecting. Simplified the return code (using a CURLcode) so to see - more clearly what is going on. + changed macro name, moved and renamed script to become docs/libcurl/has.pl, + generate code that is checksrc compliant + +Daniel Stenberg (3 Sep 2015) +- gitignore: ignore more generated VC Makefiles + +- projects/Windows/.gitignore: ignore generated files for release -- security.c: Readd the '\n' to the infof() calls. +- http2: don't pass on Connection: headers - They are not automatically added and make the output of the verbose - mode a lot more readable. + RFC 7540 section 8.1.2.2 states: "An endpoint MUST NOT generate an + HTTP/2 message containing connection-specific header fields; any message + containing connection-specific header fields MUST be treated as + malformed" + + Closes #401 + +- curl.1: update RFC references -- security.c: Fix typo (PSBZ -> PBSZ) +- CURLOPT_POSTREDIR.3: update RFC number and section -- security.c: Fix ftp_send_command. +- CURLOPT_FOLLOWLOCATION.3: mention methods for redirects - My use of va_args was completely wrong. Fixed the usage so that - we send the right commands! + and some general cleaning up -Daniel Stenberg (28 Sep 2010) -- curl_easy_escape: don't escape "unreserved" characters +- [Marcel Raad brought this change] + + inet_pton.c: Fix MSVC run-time check failure (2) - According to RFC3986 section 2.3 the letters -, ., _ and ~ should not be - percent-encoded. + This fixes another run-time check failure because of a narrowing cast on + Visual C++. - Reported by: Miguel Diaz - Bug: http://curl.haxx.se/mail/lib-2010-09/0227.html + Closes #408 -- multi: don't expire timeouts at disonnect or done +Jay Satiro (3 Sep 2015) +- docs: Warn about any-domain cookies and multiple transfers - The functions Curl_disconnect() and Curl_done() are both used within the - scope of a single request so they cannot be allowed to use - Curl_expire(... 0) to kill all timeouts as there are some timeouts that - are set before a request that are supposed to remain until the request - is done. + - Warn that cookies without a domain are sent to any domain: + CURLOPT_COOKIELIST, CURLOPT_COOKIEFILE, --cookie - The timeouts are now instead cleared at curl_easy_cleanup() and when the - multi state machine changes a handle to the complete state. + - Note that imported Set-Cookie cookies without a domain are no longer + exported: + CURLINFO_COOKIELIST, CURLOPT_COOKIEJAR, --cookie-jar -Dan Fandrich (27 Sep 2010) -- Changed the TPF make file to get source files from Makefile.inc +Steve Holme (2 Sep 2015) +- tool_sdecls.h: Fixed compilation warning from commit 4a889441d3 - Patch was fixed and validated by David McCreedy. + tool_sdecls.h:139 warning: comma at end of enumerator list -- Added test case 1204 to test HTTP range failure - - This is an attempt to reproduce bug #3076808 +Daniel Stenberg (2 Sep 2015) +- opts: 8 more CURLINFO* options as stand-alone man pages -Daniel Stenberg (27 Sep 2010) -- [Dirk Manske brought this change] +- RELEASE-NOTES: synced with c764cb4add1a8 - multi_runsingle: set timeout error messages - - With the latest changes to fix the timeout handling with multi interface - we lost the timeout error messages. This patch brings them back. +- man-pages: more SEE ALSO links -- TODO-RELEASE: updated list of issues to work on +- opts: more CURLINFO_* options as stand-alone man pages -- parsedate: allow time specified without seconds - - The date format in RFC822 allows that the seconds part of HH:MM:SS is - left out, but this function didn't allow it. This change also includes a - modified test case that makes sure that this now works. +Steve Holme (31 Aug 2015) +- sasl: Only define Curl_sasl_digest_get_pair() when CRYPTO_AUTH enabled - Reported by: Matt Ford - Bug: http://curl.haxx.se/bug/view.cgi?id=3076529 + Introduced in commit 59f3f92ba6 this function is only implemented when + CURL_DISABLE_CRYPTO_AUTH is not defined. As such we shouldn't define + the function in the header file either. -- TFTP: re-indented the source code +- sasl: Updated SPN variables and comments for consistency - Just made sure that the good old curl indentation style is used all over - this file. - -- [Tim Newsome brought this change] + In places the "host name" and "realm" variable was referred to as + "instance" whilst in others it was referred to as "host". - TFTP: Work around tftpd-hpa upload bug +Daniel Stenberg (30 Aug 2015) +- configure: check for HMAC_Update in openssl - tftpd-hpa has a bug where it will send an incorrect ack when the block - counter wraps and tftp options have been sent. Work around that by - accepting an ack for 65535 when we're expecting one for 0. + Turns out HMAC_Init is now deprecated in openssl master (and I spelled + HMAC_Init_ex wrong in previous commit) -- Revert "security.c: buffer_read various fixes." +Steve Holme (30 Aug 2015) +- win32: Use DES_set_odd_parity() from OpenSSL/BoringSSL by default - This reverts commit fbb38de415b7bb7d743e53a7b4b887ffb12b3e5b. + Set HAVE_DES_SET_ODD_PARITY when using OpenSSL/BoringSSL as native + Windows builds don't use the autoconf tools. -- security.c: removed superfluous parentheses +- des: Fixed compilation warning from commit 613e5022fe - And also removed the FIXME where memory was zeroed just before freed, - and some other minor whitespace changes. + curl_ntlm_core.c:150: warning 'Curl_des_set_odd_parity' undefined; + assuming extern returning int -- [Julien Chaffraix brought this change] +- buildconf.bat: Fixed double blank line in 'curl manual' warning output - security.c: Update the #include statements after the rewrite. +- makefiles: Added our standard copyright header + + But kept the original author, when they were specified in a comment, as + the initial copyright holder. -- [Julien Chaffraix brought this change] +Jay Satiro (29 Aug 2015) +- CURLOPT_FILETIME.3: CURLINFO_FILETIME has its own manpage now - security.c: sec_write tweaks - - - |fd| is now a curl_socket_t and |len| a size_t to avoid conversions. - - Added 2 FIXMEs about the 2 unsigned -> signed conversions. - - Included 2 minor changes to Curl_sec_end. +Daniel Stenberg (29 Aug 2015) +- CURLINFO_RESPONSE_CODE.3: added short description -- [Julien Chaffraix brought this change] +- opts: 7 initial CURLINFO_* options as stand-alone man pages - security.c: _sec_send tweaks +- [Nikolai Kondrashov brought this change] + + libcurl.m4: Put braces around empty if body + + Put braces around empty "if" body in libcurl.m4 check to avoid warning: + + suggest braces around empty body in an 'if' statement + + and make it work with -Werror builds. - - Renamed the method to sec_send now that we - renamed sec_send to do_sec_send. - - Some more variable renaming. + Closes #402 -- [Julien Chaffraix brought this change] +- [Svyatoslav Mishyn brought this change] - security.c: sec_read tweaks + curl_easy_escape.3: escape '\n' - - Renamed the function to sec_recv. - - Renamed the parameters and variable to match the rest of the code. + Closes #398 -- [Julien Chaffraix brought this change] +- [Svyatoslav Mishyn brought this change] - security.c: Curl_sec_fflush_fd tweaks + curl_easy_{escape,setopt}.3: fix example - - Use an early return as it makes the code more readable. - - Added a FIXME about a conversion. + remove redundant '}' -- [Julien Chaffraix brought this change] +- [Sergei Nikulov brought this change] - security.c: sec_send tweaks + cmake: added Windows SSL support - - Renamed it to do_sec_send as it is the function doing the actual - transfer. - - Do not return any values as no one was checking it and it never - reported a failure (added a FIXME about checking for errors). - - Renamed the variables to make their use more specific. - - Removed some casts (int -> curl_socket_t, ...) - - Avoid doing the htnl <-> nthl twice by caching the 2 results. + Closes #399 -- [Julien Chaffraix brought this change] - - security.c: Curl_sec_read_msg tweaks +- curl: point out the conflicting HTTP methods if used - - Renamed the variables name to better match their intend. - - Unified the |decoded_len| checks. - - Added some FIXMEs to flag some improvement that did not go in this - change. + It isn't always clear to the user which options that cause the HTTP + methods to conflict so by spelling them out it should hopefully be + easier to understand why curl complains. + +- curl: clarify that users can only specify one _METHOD_ -- [Julien Chaffraix brought this change] +- [Svyatoslav Mishyn brought this change] - security.c: Curl_sec_set_protection_level tweaking + curl_easy_{escape,unescape}.3: "char *" vs. "const char *" - - Removed sec_prot_internal as it is now inlined in the function (this removed - a redundant check). - - Changed the prototype to return an error code. - - Updated the method to use the new ftp_send_command function. - - Added a level_to_char helper method to avoid relying on the compiler's - bound checks. This default to the maximum security we have in case of a - wrong input. + Closes #395 -- [Julien Chaffraix brought this change] +Patrick Monnerat (24 Aug 2015) +- os400: include new options in wrappers and update ILE/RPG binding. - security.c: factored the logic from Curl_sec_login into a dedicated method that better reflect its intent. +Daniel Stenberg (24 Aug 2015) +- KNOWN_BUGS: #2, not reading a HEAD response-body is not a bug - Introduced a helper method ftp_send_command that synchronously send - an FTP query. + ... since HTTP is forbidden to return any such. -- [Julien Chaffraix brought this change] +- KNOWN_BUGS: #78 zero-length files is already fixed! - security.c: Remove out_buffer as it was never written into. +- [Razvan Cojocaru brought this change] -- [Julien Chaffraix brought this change] - - security.c: buffer_read various fixes. + getinfo: added CURLINFO_ACTIVESOCKET - Tighten the type of the |data| parameter to avoid a cast. Also made - it const as we should not modify it. + This patch addresses known bug #76, where on 64-bit Windows SOCKET is 64 + bits wide, but long is only 32, making CURLINFO_LASTSOCKET unreliable. - Added a DEBUGASSERT on the size to be written while changing it. - -- [Julien Chaffraix brought this change] + Signed-off-by: Razvan Cojocaru - security.c: Made block_write return a CURLcode. +- http2: remove dead code - While doing so, renamed it to socket_write to better match its - function. - -- [Julien Chaffraix brought this change] + Leftovers from when we removed the private socket hash. + + Coverity CID 1317365, "Logically dead code" - security.c: Made block_read and sec_get_data return CURLcode. +- ntlm: mark deliberate switch case fall-through - To do so, made block_read call Curl_read_plain instead of read. + Coverity CID 1317367, "Missing break in switch" + +- http2: on_frame_recv: get a proper 'conn' for the debug logging - While changing them renamed block_read to socket_read and sec_get_data - to read_data to better match their function. + "Explicit null dereferenced (FORWARD_NULL)" - Also fixed a potential memory leak in block_read. + Coverity CID 1317366 -- [Julien Chaffraix brought this change] +- RELEASE-NOTES: synced with 2acaf3c804 - Security.c: Fix headers guard to match the rest of the code. +Dan Fandrich (23 Aug 2015) +- tool: fix memory leak with --proto-default option -- [Julien Chaffraix brought this change] +Jay Satiro (22 Aug 2015) +- [Nathaniel Waisbrot brought this change] - configure: Fix the LDAPS disable message + CURLOPT_DEFAULT_PROTOCOL: added - ... for example when LDAP is not compiled. + - Add new option CURLOPT_DEFAULT_PROTOCOL to allow specifying a default + protocol for schemeless URLs. - Fixed the logic to match the rest of the options' message that is we - update the default message only if the option is not disabled after the - different checks. + - Add new tool option --proto-default to expose + CURLOPT_DEFAULT_PROTOCOL. - Reported by: Guenter Knauf - -- RELEASE-NOTES: sync with 8665d4e5 and c-ares >= 1.6.0 note - -- parse_remote_port: ignore colons without port number + In the case of schemeless URLs libcurl will behave in this way: - Obviously, browsers ignore a colon without a following port number. Both - Firefox and Chrome just removes the colon for such URLs. This change - does not remove the colon for URLs sent over a HTTP proxy, so we should - consider doing that change as well. + When the option is used libcurl will use the supplied default. - Reported by: github user 'kreshano' + When the option is not used, libcurl will follow its usual plan of + guessing from the hostname and falling back to 'http'. -- RELEASE-NOTES: in sync with 19f45eaa799 +- runtests: Allow for spaces in server-verify curl custom path -- duphandle: use ares_dup() - - curl_easy_duphandle() was not properly duping the ares channel. The - ares_dup() function was introduced in c-ares 1.6.0 so by starting to use - this function we also raise the bar and require c-ares >= 1.6.0 - (released Dec 9, 2008) for such builds. +Daniel Stenberg (22 Aug 2015) +- NTLM: recent boringssl brought DES_set_odd_parity back - Reported by: Ning Dong - Bug: http://curl.haxx.se/mail/lib-2010-08/0318.html - -- [Hendrik Visage brought this change] + ... so improve the #ifdefs for using our local implementation. - MacOSX-Framework: updates for Snowleopard +- configure: detect latest boringssl - 1) PPC64 appears to be an 10.5 only supported architecture, so I - forced 10.5 for 64bit if there is a need for PPC64, else 64bit only - does x86_64 + Since boringssl brought back DES_set_odd_parity again, it cannot be used + to differentiate from boringssl. Using the OPENSSL_IS_BORINGSSL define + seems better anyway. - 2) proper "make clean" after every ./configure. fixes a bug where - subsequent runs the 32bit do not get compiled + URL: https://android.googlesource.com/platform/external/curl/+/f551028d5caab29d4b4a4ae8c159c76c3cfd4887%5E!/ + Original-patch-by: Bertrand Simonnet - 3) Added a version numbering curl-$VERSION} rather than the "stock standard" A + Closes #393 -- RELEASE-NOTES: synced with 5fcc4332d62fe +- configure: change functions to detect openssl (clones) - Removed the duplicate entry of Kamil in the credits. - -- configure: don't enable RTMP if the lib detect fails + ... since boringssl moved the former ones and the check started to fail. - librtmp is often statically linked and using sub dependencies like - OpenSSL, so we need to make sure we can actually link with it properly - before enabling it. Otherwise we easily end up trying to link with a - RTMP lib that fails. + URL: https://android.googlesource.com/platform/external/curl/+/f551028d5caab29d4b4a4ae8c159c76c3cfd4887%5E!/ + Original-patch-by: Bertrand Simonnet -- TODO: added 8.4 non-gcrypt under GnuTLS - - We must not assume gcrypt just because of GnuTLS +- [Alessandro Ghedini brought this change] -- configure: check for gcrypt if using GnuTLS + openssl: handle lack of server cert when strict checking disabled - 1 - libcurl assumes that there are gcrypt functions available when - GnuTLS is. + If strict certificate checking is disabled (CURLOPT_SSL_VERIFYPEER + and CURLOPT_SSL_VERIFYHOST are disabled) do not fail if the server + doesn't present a certificate at all. - 2 - GnuTLS can be built to use libnettle instead as crypto library, - which breaks assumption (1) + Closes #392 + +- ftp: clear the do_more bit when the server has connected - This change makes configure make sure that if GnuTLS is requested and - detected, it also makes sure that gcrypt is present or it errors - out. This is mostly a way to make the user more aware of this flaw, the - correct fix would be to detect which crypto layer that is in use and - adapt our code to use that instead of blindly assuming gcrypt. + The multi state machine would otherwise go into the DO_MORE state after + DO, even for the case when the FTP state machine had already performed + those duties, which caused libcurl to get stuck in that state and fail + miserably. This occured for for active ftp uploads. - Reported by: Michal Gorny - Bug: http://curl.haxx.se/bug/view.cgi?id=3071038 + Reported-by: Patricia Muscalu -- RELEASE-NOTES: sync from d2a7fd2fe65b to HEAD +- [Jactry Zeng brought this change] -- FTP: fix bad check of Curl_timeleft() return code - - When it returns 0 it means no timeout. Only a negative value means that - we're out of time. + travis.yml: Add OS X testbot. -- LDAP: moved variable declaration to avoid compiler warn - - If built without HTTP or proxy support it would cause a compiler warning - due to the unused variable. I moved the declaration of it into the only - scope it is used. +- [Rémy Léone brought this change] -Tor Arntsen (18 Sep 2010) -- LDAP: Use FALSE instead of bool_false when setting bits.close + travis: Upgrading to container based build - bool_false is the internal name used in the setup_once.h definition - we fall back to for non-C99 non-stdbool systems, it's not the actual - name to use in assignments (we use bool_false, bool_true there to - avoid global namespace problems, see comment in setup_once.h). - The correct C99 value to use is 'false', but let's use FALSE as - used elsewhere when assigning to bits.close. FALSE is set equal - to 'false' in setup_once.h when possible. + http://docs.travis-ci.com/user/migrating-from-legacy - This fixes a build problem on C99 targets. + Closes #388 -- LDAP: Add missing declaration for 'result' +- RELEASE-NOTES: synced with 14ff86256b13e -Daniel Stenberg (18 Sep 2010) -- [Mauro Iorio brought this change] +- [Erik Janssen brought this change] - LDAP: Support for tunnelling queries through HTTP proxy - - As of curl-7.21.1 tunnelling ldap queries through HTTP Proxies is not - supported. Actually if --proxytunnel command-line option (or equivalent - CURLOPT_HTTPPROXYTUNNEL) is used for ldap queries like - ldap://ldap.my.server.com/... You are unable to successfully execute the - query. In facts ldap_*_bind is executed directly against the ldap server - and proxy is totally ignored. This is true for both openLDAP and - Microsoft LDAP API. + rtsp: stop reading empty DESCRIBE responses - Step to reproduce the error: - Just launch "curl --proxytunnel --proxy 192.168.1.1:8080 - ldap://ldap.my.server.com/dc=... " + Based-on-patch-by: Jim Hollinger + +- [Erik Janssen brought this change] + + rtsp: support basic/digest authentication + +- [Sam Roth brought this change] + + CURLMOPT_PUSHFUNCTION.3: fix argument types - This fix adds an invocation to Curl_proxyCONNECT against the provided - proxy address and on successful "CONNECT" it tunnels ldap query to the - final ldap server through the HTTP proxy. As far as I know Microsoft - LDAP APIs don't permit tunnelling in any way so the patch provided is - for OpenLDAP only. The patch has been developed against OpenLDAP 2.4.23 - and has been tested with Microsoft ISA Server 2006 and works properly - with basic, digest and NTLM authentication. + Closes #389 + Closes #386 + +- [Marcel Raad brought this change] -- timeout: use the correct start value as offset + inet_pton.c: Fix MSVC run-time check failure + + Visual Studio complains with a message box: + + "Run-Time Check Failure #1 - A cast to a smaller data type has caused a + loss of data. If this was intentional, you should mask the source of + the cast with the appropriate bitmask. + + For example: + char c = (i & 0xFF); + + Changing the code in this way will not affect the quality of the + resulting optimized code." - Rodric provide an awesome recipe that proved libcurl didn't timeout at - the requested time - it instead often timed out at [connect time] + - [timeout time] instead of the documented and intended [timeout time] - only. This bug was due to the code using the wrong base offset when - comparing against "now". I could also take the oppurtinity to simplify - the code by properly using of the generic help function for this: - Curl_timeleft. + This is because only 'val' is cast to unsigned char, so the "& 0xff" has + no effect. - Reported by: Rodric Glaser - Bug: http://curl.haxx.se/bug/view.cgi?id=3061535 + Closes #387 -- Curl_timeleft: avoid returning "no timeout" by mistake +Jay Satiro (18 Aug 2015) +- docs: Update the redirect protocols disabled by default - As this function uses return code 0 to mean that there is no timeout, it - needs to check that it doesn't return a time left value that is exactly - zero. It could lead to libcurl doing an extra 1000 ms select() call and - thus not timing out as accurately as it should. + - Clarify that FILE and SCP are disabled by default since 7.19.4 + - Add that SMB and SMBS are disabled by default since 7.40.0 + - Add CURLPROTO_SMBS to the list of protocols + +- gitignore: Sort for readability + + find . -name .gitignore -print0 | xargs -i -0 sort -o '{}' '{}' + +Daniel Stenberg (15 Aug 2015) +- curl_easy_getinfo.3: fix superfluous space - I fell over this bug when working on the bug 3061535 but this fix does - not correct that problem alone, although this is a problem that needs to - be fixed. + ... and changed "oriented" to "related" - Reported by: Rodric Glaser - Bug: http://curl.haxx.se/bug/view.cgi?id=3061535 + Closes #378 + +- CURLOPT_HTTP_VERSION.3: connection re-use goes before version + +- [Daniel Kahn Gillmor brought this change] -- whitespace: unified source + curl.1: Document weaknesses in SSLv2 and SSLv3 - if ( => if( - while ( => while( + Acknowledge that SSLv3 is also widely considered to be insecure. - and some other changes in the similar spirit, trying to make the - whole file use the same style + Also, provide references for people who want to know more about why it's + insecure. -- remote-header-name: don't output filename when NULL +Steve Holme (14 Aug 2015) +- generate.bat: Added support for generating only the prerequisite files -- [James Bursa brought this change] +- generate.bat: Only call buildconf.bat if it exists - TheArtOfHttpScripting: use long options +- generate.bat: Fixed issues when ran in directories with special chars -- [James Bursa brought this change] +Daniel Stenberg (14 Aug 2015) +- [Brad King brought this change] - getinmemory: make the example easier to follow + cmake: Fix CurlTests check for gethostbyname_r with 5 arguments - 1. Remove the comment warning that it's "not been verified to work". It - works with no problems in my testing. + Fix the check code to pass 5 arguments instead of 6. This typo was + introduced by commit aebfd4cfbf (cmake: fix gethostby{addr,name}_r in + CurlTests, 2014-10-31). + +Steve Holme (14 Aug 2015) +- * buildconf.bat: Fixed issues when ran in directories with special chars - 2. Remove 2 unnecessary includes. + Bug: https://github.com/bagder/curl/pull/379 + Reported-by: Daniel Seither + +Jay Satiro (13 Aug 2015) +- curl_global_init_mem.3: Stronger thread safety warning - 3. Remove the myrealloc(). Initialize chunk.memory with malloc() instead - of NULL. The comments for these two parts contradicted each other. + Bug: http://curl.haxx.se/mail/lib-2015-08/0016.html + Reported-by: Eric Ridge + +Daniel Stenberg (12 Aug 2015) +- [Svyatoslav Mishyn brought this change] + + curl_multi_add_handle.3: fix a typo - 4. Handle out of memory from realloc() instead of continuing. + "can not" => "cannot" - 5. Print a brief status message at the end. + closes #377 -- multi: don't do extra expire calls for the connection +- [Alessandro Ghedini brought this change] + + docs: fix typos - The timeout is set for the connect phase already at the start of the - request so we should not add a new one, and we MUST not set expire to 0 - as that will remove any other potentially existing timeouts. + closes #376 -- [Peter Pentchev brought this change] +- bump: start working toward 7.45.0 - Fix a bashism: test a = b is more portable than ==. +- THANKS: remove duplicate name -- glob_word: remove a check that is always false +- THANKS-filter: merge Todd's names -- inflate_stream: remove redundant check that is always true +- THANKS: 13 new contributors from the 7.44.0 RELEASE-NOTES -- digest: make it clear the condition is always true +Version 7.44.0 (11 Aug 2015) -- ssluse: removed redundant check that is always true +Daniel Stenberg (11 Aug 2015) +- RELEASE-NOTES: synced with c75a1e775061 -Dan Fandrich (11 Sep 2010) -- Link curl and the test apps with -lrt explicitly when necessary - - When curl calls a function from that library then it needs to - explicitly link to the library instead of piggybacking on - libcurl's own dependency. Without this, GNU ld with the - --no-add-needed flag fails when linking (which Fedora now does - by default). +- [Svyatoslav Mishyn brought this change] + + curl_formget.3: correct return code - Reported by: Quanah Gibson-Mount - Bug: http://curl.haxx.se/mail/lib-2010-09/0085.html + Closes #375 -- Mention the Debian Popularity Contest +- [Svyatoslav Mishyn brought this change] -Tor Arntsen (9 Sep 2010) -- test565: Don't hardcode IP:PORT + libcurl-tutorial.3: fix formatting - Use %HOSTIP:%HTTPPORT instead of 127.0.0.1:8990 so that - verification works if the baseport change option is used - when executing runtests.pl. + Closes #374 -Daniel Stenberg (9 Sep 2010) -- curl.1: updated protocols and polished language +- [Svyatoslav Mishyn brought this change] -- FAQ: CURL_STATICLIB for visual studio users - - Clarified as it isn't used with a -D option for them. - - Reported by: Artfunkel - Bug: http://curl.haxx.se/bug/view.cgi?id=3060381 + curl_easy_recv.3: fix formatting -- FAQ: updated and added host with custom IP question - - Added "3.19 How do I get HTTP from a host using a specific IP address?" - and updated some stuff about certs etc. +- [Anders Bakken brought this change] -- chunky parser: only rewind if needed + http2: discard frames with no SessionHandle - The code reading chunked encoding attempts to rewind the code if it had - read more data than the chunky parser consumes. The rewinding can fail - and it will then cause an error. This change now makes the rewinding - only happen if pipelining is in use - as that's the only time it really - needs to be done. + Return 0 instead of NGHTTP2_ERR_CALLBACK_FAILURE if we can't locate the + SessionHandle. Apparently mod_h2 will sometimes send a frame for a + stream_id we're finished with. - Bug: http://curl.haxx.se/mail/lib-2010-08/0297.html - Reported by: Ron Parker + Use nghttp2_session_get_stream_user_data and + nghttp2_session_set_stream_user_data to identify SessionHandles instead + of a hash. + + Closes #372 -Kamil Dudka (6 Sep 2010) -- rtsp: avoid SIGSEGV on malformed header +- RELEASE-NOTES: synced with 9ee40ce2aba -- rtsp: avoid SIGSEGV on malformed header +- [Viktor Szakats brought this change] -Daniel Stenberg (6 Sep 2010) -- warning: fix conversion to 'int' from 'size_t' + build: refer to fixed libidn versions + + closes #371 -- portabilty: use proper variable type to hold sockets +- Revert "configure: disable libidn by default" - Curl_getconnectinfo() is changed to return a proper curl_socket_t for - the last socket so that it'll work more portably (and cause less - compiler warnings). + This reverts commit e6749055d65398315fd77f5b5b8234c5552ac2d3. + + ... since libidn has since been fixed. -Guenter Knauf (3 Sep 2010) -- Trial to fix another compiler warning with braces. +- [Jakub Zakrzewski brought this change] -Dan Fandrich (2 Sep 2010) -- Use checkprefix() to compare protocol-specific strings + CMake: s/HAVE_GSS_API/HAVE_GSSAPI/ to match header define - Otherwise, there could be problems running in certain locales. - -Guenter Knauf (2 Sep 2010) -- Moved S_ISREG define to setup as suggested by Dan. + Otherwise the build only pretended to use GSS-API + + Closes #370 -- Use own typedef as workaround for broken sspi.h header (f.e. Watcom). +- SFTP: fix range request off-by-one in size check + + Reported-by: Tim Stack + + Closes #359 -- Added some hacks in order to build with VC from git. +- test46: update cookie expire time - Adam Light posted this patch to the list which enables builds from - git with VC versions other than vc6; also he added a vc10 target. + ... since it went old and thus was expired and caused the test to fail! -- Added S_ISREG define for Win32. +Steve Holme (9 Aug 2015) +- generate.bat: Use buildconf.bat for prerequisite file generation -Daniel Stenberg (1 Sep 2010) -- multi: fixes for timing out handles +- buildconf.bat: Tidy up of comments after recent commits + +- buildconf.bat: Added full generation of src\tool_hugehelp.c - Add a timeout check for handles in the state machine so that they will - timeout in all states disregarding what actions that may or may not - happen. + Added support for generating the full man page based on code from + generate.bat. + +- buildconf.bat: Added detection of groff, nroff, perl and gzip - Fixed a bug in socket_action introduced recently when looping over timed - out handles: it wouldn't assign the 'data' variable and thus it wouldn't - properly take care of handles. + To allow for the full generation of tool_hugehelp.c added detection of + the required programs - based on code from generate.bat. + +- buildconf.bat: Move DOS variable clean-up code to separate function - In the update_timer function, the code now checks if the timeout has - been removed and then it tells the application. Previously it would - always let the remaining timeout(s) just linger to expire later on. + Rather than duplicate future variables, during clean-up of both success + and error conditions, use a common function that can be called by both. + +- RELEASE-NOTES: Synced with 39dcf352d2 -- threaded resolver: no more expire 0 calls +- buildconf.bat: Added error messages on failure + +- buildconf.bat: Generate and clean files in the same order + +- buildconf.bat: Maintain compatibility with DOS based systems - Curl_expire() set to 0 expires ALL timeouts so it should only be called - if we truly and really want to remove all timeouts for the handle. + Commit f08e30d7bc broke compatibility with DOS and non Windows NT based + versions of Windows due to the use of the setlocal command. -- resolve_server: simplify code +Jay Satiro (9 Aug 2015) +- CURLOPT_RESOLVE.3: Note removal support was added in 7.42 - Make use of the helper function Curl_timeleft() instead of duplicating - code. + Bug: http://curl.haxx.se/mail/lib-2015-08/0019.html + Reported-by: Inca R -- multi: make sure the next timeout is used when one expires +Steve Holme (8 Aug 2015) +- checksrc.bat: Fixed error when missing *.c and *.h files - Each easy handle has a list of timeouts, so as soon as the main timeout - for a handle expires, we must make sure to get the next entry from the - list and re-add the handle to the splay tree. + File Not Found + +- checksrc.bat: Fixed incorrect 'lib\vtls' path check in commit 333c36b276 + +- checksrc.bat: Fixed error when [directory] isn't a curl source directory - This was attempted previously but was done poorly in my commit - 232ad6549a68450. + The system cannot find the file specified. + +- checksrc.bat: Added check for unknown arguments -Dan Fandrich (30 Aug 2010) -- Added proxy keyword to allow skipping test in proxyless configs +- scripts: Added missing comments -Daniel Stenberg (29 Aug 2010) -- multi: set timeouts when transfer begins +- scripts: Always perform setlocal and endlocal calls in pairs - When a new transfer is about to start we now set the proper timeouts to - expire for the multi interface if they are set for the handle. This is a - follow-up bugfix to make sure that easy handles timeout properly when - the times expire and the multi interface is used. This also improves - curl_multi_timeout(). + Ensure that there isn't a mismatch between setlocal and endlocal calls, + which could have happened due to setlocal being called after certain + error conditions were checked for. -- CURLOPT_DIRLISTONLY: don't use with CURLOPT_WILDCARDMATCH +- scripts: Allow -help to be specified in any argument + + Allow the -help command line argument to be specified in any argument + and not just as the first. -- FAQ: update list of supported protocols +Daniel Stenberg (6 Aug 2015) +- [juef brought this change] -- [Fabian Keil brought this change] + curl_multi_remove_handle.3: fix formatting + + closes #366 - In the m4 detection line, factor out the 2>dev/null +Steve Holme (6 Aug 2015) +- README: Added notes about 'Running DLL based configurations' + + ...as well as a TODO for a future enhancement to the project files. + + Thanks-to: Jay Satiro -- [Fabian Keil brought this change] +- RELEASE-NOTES: Synced with cf8975387f - If m4 doesn't support --version, try if gm4 does. +- buildconf.bat: Synchronise no repository error with generate.bat -- [Fabian Keil brought this change] +- generate.bat: Added a check for the presence of a git repository - If the m4 version isn't recognized at all, just say so +- [Jay Satiro brought this change] + + build: Added wolfSSL configurations to VC10+ project files - 'm4 version found. You need a GNU m4 installed!' is a bit confusing. + URL: https://github.com/bagder/curl/pull/174 -- HISTORY: mention the gopher story +- [Jay Satiro brought this change] -Dan Fandrich (25 Aug 2010) -- Tweaked some test data files + build: Added wolfSSL build script for Visual Studio projects - Fixed some issues that caused xmllint failures, added features - and keywords, fixed some quotes and removed some sections - that unnecessarily limited test checking. + Added the wolfSSL build script, based on build-openssl.bat, as well as + the property sheet and header file required for the upcoming additions + to the Visual Studio project files. -- Added new source files to Symbian and TPF makefiles +Daniel Stenberg (6 Aug 2015) +- CHANGES: refer to the online changelog + + Suggested-by: mc0e -Daniel Stenberg (25 Aug 2010) -- RELEASE-NOTES: sync from b980c9a02 to HEAD +- [Isaac Boukris brought this change] -- Makefile: add gopher.c file to build + NTLM: handle auth for only a single request + + Currently when the server responds with 401 on NTLM authenticated + connection (re-used) we consider it to have failed. However this is + legitimate and may happen when for example IIS is set configured to + 'authPersistSingleRequest' or when the request goes thru a proxy (with + 'via' header). - As the VC and RISCOS makefiles don't use the .inc file + Implemented by imploying an additional state once a connection is + re-used to indicate that if we receive 401 we need to restart + authentication. + + Closes #363 -- runtests: fix uninitialized variable warning +Steve Holme (5 Aug 2015) +- RELEASE-NOTES: Synced with 473807b95f -- gopher tests: revert parts of gopher in the pingpong server - - Introduced in the initial gopher commits, there was added logic to do - GOPHER test serving in the pingpong server but as it resembles HTTP much - more than FTP or SMTP, the gopher testing has been moved over to instead - use the sws (HTTP) server. This change simply removes unused code. +- generate.bat: Use buildconf.bat for prerequisite file clean-up -- gopher tests: use sws and adjusted to more standard style +- buildconf.bat: Added support for file clean-up via -clean -- sws: added basic gopher support +- buildconf.bat: Added progress output -- gopher: enable the header callback/verbosity +- buildconf.bat: Avoid using goto for file not in repository -- gopher: fix test case line endings - - Patches over email very easily lose CRLF line endings in files otherwise - LF-only so I had to put them back where needed. +Daniel Stenberg (5 Aug 2015) +- curl_slist_append.3: add error checking to the example -- gopher: fix memory leak and busyloop - - The fix for the busyloop really only is a temporary work-around. It - causes a BLOCKING behavior which is a NO-NO. This function should rather - be split up in a do and a doing piece where the pieces that aren't - possible to send now will be sent in the doing function repeatedly until - the entire request is sent. +Steve Holme (5 Aug 2015) +- buildconf.bat: Added display of usage text with -help -- [Cameron Kaiser brought this change] +- buildconf.bat: Added exit codes for error handling - Gopher using Curl_write; test suite (4 tests) +- buildconf.bat: Added our standard copyright header -- [Cameron Kaiser brought this change] +- buildconf.bat: Use lower-case for commands and reserved keywords - Remove url.c test +- generate.bat: Only clean prerequisite files when in ALL mode -- [Cameron Kaiser brought this change] +- generate.bat: Moved error messages out of sub-routines - Forgot gopher.h in Makefile.inc +- generate.bat: More use of lower-case for commands and reserved keywords -- [Cameron Kaiser brought this change] +Daniel Stenberg (3 Aug 2015) +- libcurl.3: fix a single typo + + Closes #361 - Gopher protocol support (initial release) +- RELEASE-NOTES: synced with c4eb10e2f06f -- http: handle trailer headers in all chunked responses +- SSH: three state machine fixups - HTTP allows that a server sends trailing headers after all the chunks - have been sent WITHOUT signalling their presence in the first response - headers. The "Trailer:" header is only a SHOULD there and as we need to - handle the situation even without that header I made libcurl ignore - Trailer: completely. + The SSH state machine didn't clear the 'rc' variable appropriately in a + two places which prevented it from looping the way it should. And it + lacked an 'else' statement that made it possible to erroneously get + stuck in the SSH_AUTH_AGENT state. - Test case 1116 was added to verify this and to make sure we handle more - than one trailer header properly. + Reported-by: Tim Stack - Reported by: Patrick McManus - Bug: http://curl.haxx.se/bug/view.cgi?id=3052450 - -- TODO: we now support RTMP + Closes #357 -- TODO: done "NTLM with other crypto functions" +- curl_gssapi: remove 'const' to fix compiler warnings - Since NTLM was made to work with the NSS API as well, the primary SSL - alternatives will be built with NTLM support in libcurl. + initialization discards 'const' qualifier from pointer target type -- TODO: fixed "Make curl_multi_info_read faster" +- docs: formpost needs the full size at start of upload - It is really fast now + Closes #360 -Dan Fandrich (24 Aug 2010) -- Fixed a NULL pointer dereference in form posting +Steve Holme (1 Aug 2015) +- sspi: Fix typo from left over from old code which referenced NTLM - It was introduced in commit eeb2cb05 along with the -F type= - change. Also fixed a typo in the name of the magic filename= - parameter. Tweaked tests 39 and 173 to better test this path. + References to NTLM in the identity generation should have been removed + in commit c469941293 but not all were. -Daniel Stenberg (24 Aug 2010) -- [Ben Greear brought this change] +- win32: Fix compilation warnings from commit 40c921f8b8 + + connect.c:953:5: warning: initializer element is not computable at load + time + connect.c:953:5: warning: missing initializer for field 'dwMinorVersion' + of 'OSVERSIONINFOEX' + curl_sspi.c:97:5: warning: initializer element is not computable at load + time + curl_sspi.c:97:5: warning: missing initializer for field 'szCSDVersion' + of 'OSVERSIONINFOEX' - multi: Fix compile warning on 64-bit systems +- schannel: Fix compilation warning from commit 7a8e861a56 + + schannel.c:1125:5: warning: missing initializer for field 'dwMinorVersion' + of 'OSVERSIONINFOEX' [-Wmissing-field-initializers -Dan Fandrich (23 Aug 2010) -- Mention PolarSSL in tutorial & add some URLs to INSTALL +Daniel Stenberg (31 Jul 2015) +- libcurl-thread.3: minor reformatting -Daniel Stenberg (23 Aug 2010) -- RESUME_FROM: clarify what ftp uploads do +Jay Satiro (31 Jul 2015) +- curl_global_init_mem.3: Warn threaded resolver needs thread safe funcs - The numerical value passed to CURLOPT_RESUME_FROM for FTP uploads is - interpreted and used as position where to resume the _reading_ of the - local file and it will "blindly" append that data on the remote - file. This was certainly not clear in the docs previously. + Bug: http://curl.haxx.se/mail/lib-2015-07/0149.html + Reported-by: Eric Ridge + +- libcurl-thread.3: Warn memory functions must be thread safe - Reported by: catalin - Bug: http://curl.haxx.se/bug/view.cgi?id=3048174 + Bug: http://curl.haxx.se/mail/lib-2015-07/0149.html + Reported-by: Eric Ridge -- [Dirk Manske brought this change] +Steve Holme (31 Jul 2015) +- RELEASE-NOTES: Synced with 8b1d00ac1a - Curl_is_connected: use correct errno - - The correctly extracted errno contents were mistakenly overwritten by a newer - value that wasn't the correct error value. +- INSTALL: Minor formatting correction in 'Legacy Windows and SSL' section - Bug: http://curl.haxx.se/mail/lib-2010-08/0242.html + ...as well as some rewording. -- cmdline: make -F type= accept ;charset= +Kamil Dudka (30 Jul 2015) +- http: move HTTP/2 cleanup code off http_disconnect() - The -F option allows some custom parameters within the given string, and - those strings are separated with semicolons. You can for example specify - "name=daniel;type=text/plain" to set content-type for the - field. However, the use of semicolons like that made it not work fine if - you specified one within the content-type, like for: - "name=daniel;type=text/plain;charset=UTF-8" - ... as the second one would be seen as a separator and "charset" is no - parameter curl knows anything about so it was just silently discarded. + Otherwise it would never be called for an HTTP/2 connection, which has + its own disconnect handler. - The new logic now checks if the semicolon and following keyword looks - like a parameter it knows about and if it isn't it is assumed to be - meant to be used within the content-type string itself. + I spotted this while debugging + where the http_disconnect() handler was called on an FTP session handle + causing 'dnf' to crash. conn->data->req.protop of type (struct FTP *) + was reinterpreted as type (struct HTTP *) which resulted in SIGSEGV in + Curl_add_buffer_free() after printing the "Connection cache is full, + closing the oldest one." message. - I modified test case 186 to verify that this works as intended. + A previously working version of libcurl started to crash after it was + recompiled with the HTTP/2 support despite the HTTP/2 protocol was not + actually used. This commit makes it work again although I suspect the + root cause (reinterpreting session handle data of incompatible protocol) + still has to be fixed. Otherwise the same will happen when mixing FTP + and HTTP/2 connections and exceeding the connection cache limit. - Reported by: Larry Stone - Bug: http://curl.haxx.se/bug/view.cgi?id=3048988 + Reported-by: Tomas Tomecek + Bug: https://bugzilla.redhat.com/1248389 -Guenter Knauf (20 Aug 2010) -- Added mk-ca-bundle.vbs script. - - The script works exactly same as the Perl one except for one thing: - when the text descriptions generated with openssl are included then - the md5 fingerprints are missing; seems openssl has either a bug or - a feature which prints the md5 fingerprint output to stdout instead - of writing them to specified file; this script could here do the same - as what the Perl scripr does (redirect stdout into file) but this - makes the script take up double the time because it needs to launch - cmd.exe 140 times (fo each openssl call). So I think for now we just - ommit the md5 fingerprints, and see if openssl will be fixed. +Daniel Stenberg (30 Jul 2015) +- [Viktor Szakats brought this change] + + ABI doc: use secure URL -- Trial to fix win32 autobuilds. +- ABI: remove the ascii logo - It seems that its time to look at some better ideas for the win32 - non-configure builds; probably a prebuild target which copies - config-win32.h to curl_config.h and appends also then feature - defines like USE_ARES. + and made the indent level to 1 -Dan Fandrich (19 Aug 2010) -- Use the S_ISREG macro to determine what is a regular file +- libcurl-multi.3: mention curl_multi_wait + + ... and some general rewordings to improve this docs. + + Reported-by: Tim Stack + + Closes #356 -Kamil Dudka (19 Aug 2010) -- AC_INIT: avoid a warning with autoconf 2.66 +Steve Holme (30 Jul 2015) +- maketgz: Fixed some VC makefiles missing from the release tarball - It was complaining about the '=>' operator, introduced in e3fc0d5. + VC7, VC11, VC12 and VC14 makefiles were missing from the release + tarball. + +- RELEASE-NOTES: Synced with 2d7e165761 -Dan Fandrich (18 Aug 2010) -- Fixed a memory leak during OOM in the multi timeout code +- build: Added VC14 project files to Makefile.am -- Removed a C99ism & made an array const +- build: Added VC14 project files + + Updates to Makefile.am for the generation of the project files in + the tarball to follow. -Daniel Stenberg (19 Aug 2010) -- [Julien Chaffraix brought this change] +Jay Satiro (29 Jul 2015) +- libcurl-thread.3: Clarify CURLOPT_NOSIGNAL takes long value 1L - test: added test 579 to verify progress callback for chunked post +Steve Holme (28 Jul 2015) +- generate.bat: Use lower-case for commands and reserved keywords - The 66 bytes checked are those 38 bytes with the chunked encoding - headers added: 8+8+10+35+5 = 66 + Whilst there are no coding standards for the batch files used in curl, + most tend to use lower-case for keywords and upper-case for variables. + +- build: Added initial VC14 support to generate.bat - The three-letter words become 8 bytes on the wire because they are sent - like: "3\r\none\r\n" + Visual Studio project files and updates to makefile.am to follow. + +- build: Fixed missing .opensdf files from VC10+ .gitignore files + +- build: Use $(ProjectName) macro for curl.exe and curld.exe filenames - ... and there's the trailing 5 bytes write after the four lines since - the final chunk is sent (which is "0\r\n\r\n"). + This wasn't possible with the old curlsrc project filenames, but like + commit 2a615a2b64 and 11397eb6dd for libcurl use the built in Visual + Studio macros for the output filenames. -- multi: avoid sending multiple complete messages +- build: Renamed curl src Visual Studio project files - I fell over this bug report that mentioned that libcurl could wrongly - send more than one complete messages at the end of a transfer. Reading - the code confirmed this, so I've added a new multi state to make it not - happen. The mentioned bug report was made by Brad Jorsch but is (oddly - enough) filed in Debian's bug tracker for the "wmweather+" tool. + Following commit 957fcd9049 and in preparation for adding the VC14 + project files renamed the curl source project files. + +Daniel Stenberg (28 Jul 2015) +- [Jay Satiro brought this change] + + libcurl-thread.3: Revert to stricter handle wording - Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=593390 + .. also update formatting and add WinSSL and wolfSSL to the SSL/TLS + handlers list. -- FAQ: update the list of supported protocols +- [Jay Satiro brought this change] -- FAQ: added blurb about ECCN + libcurl-thread.3: Consolidate thread safety info - "1.13 curl's ECCN number" is a new section mostly made up from - Alessandro Vesely's very informative ML post on the subject: - http://curl.haxx.se/mail/lib-2008-03/0251.html + This is a new document to consolidate our thread safety information from + several documents (curl-www:features, libcurl.3, libcurl-tutorial.3). + Each document's section on multi-threading will now point to this one. -Guenter Knauf (18 Aug 2010) -- It is sufficient to pipe stderr to NUL to get rid of the nasty messages. +Steve Holme (27 Jul 2015) +- README: Corrected formatting for 'Legacy Windows and SSL' section + + ...as well as some wording. -- Added SSPI build to Watcom makefile. +- build-openssl.bat: Added support for VC14 -Daniel Stenberg (16 Aug 2010) -- [Julien Chaffraix brought this change] +Daniel Stenberg (26 Jul 2015) +- RELEASE-NOTES: synced with 0f645adc95390e8 - progress: callback for POSTs less than MAX_INITIAL_POST_SIZE +- test1902: attempt to make the test more reliable - Add a call to Curl_pgrsSetUploadSize in this case valided by a test - case. + Closes #355 + +- comment: fix comment about adding new option support + +Jay Satiro (25 Jul 2015) +- build-openssl.bat: Show syntax if required args are missing + +Daniel Stenberg (26 Jul 2015) +- TODO: improve how curl works in a windows console window - Reported by: Никита Дорохин. - Bug: http://curl.haxx.se/mail/lib-2010-04/0173.html + Closes #322 for now -Dan Fandrich (16 Aug 2010) -- Make the LD_PRELOAD path absolute in the tests that use it +- 1.11 minimize dependencies with dynamicly loaded modules - In some situations, libtool will change directories and perform - a link step before executing the libtest test app. Since - LD_PRELOAD is in effect for this entire process, the path to the - binary must be absolute so it will be valid no matter in which - directory the app is running. + Closes #349 for now -Daniel Stenberg (16 Aug 2010) -- negotiation: Wrong proxy authorization +Jay Satiro (25 Jul 2015) +- tool_operate: Fix CURLOPT_SSL_OPTIONS for builds without HTTPS - There's an error in http_negotiation.c where a mistake is using only - userpwd even for proxy requests. Ludek provided a patch, but I decided - to write the fix slightly different using his patch as inspiration. + - Set CURLOPT_SSL_OPTIONS only if the tool enabled an SSL option. - Reported by: Ludek Finstrle - Bug: http://curl.haxx.se/bug/view.cgi?id=3046066 + Broken by me several days ago in 172b2be. + https://github.com/bagder/curl/commit/172b2be#diff-70b44ee478e58d4e1ddcf9c9a73d257b + + Bug: http://curl.haxx.se/mail/lib-2015-07/0119.html + Reported-by: Dan Fandrich -Dan Fandrich (16 Aug 2010) -- Clear stdout and stderr files on each test run +Daniel Stenberg (25 Jul 2015) +- configure: check if OpenSSL linking wants -ldl + + To make it easier to link with static versions of OpenSSL, the configure + script now checks if -ldl is needed for linking. - This allows a test to be run several times in the same test - session even when the -k option is given. + Help-by: TJ Saunders -Guenter Knauf (15 Aug 2010) -- Syncroniszed vclean target; fixed some comments. +- [Michael Kaufmann brought this change] -Daniel Stenberg (15 Aug 2010) -- THANKS: added contributors from 7.21.1 + HTTP: ignore "Content-Encoding: compress" + + Currently, libcurl rejects responses with "Content-Encoding: compress" + when CURLOPT_ACCEPT_ENCODING is set to "". I think that libcurl should + treat the Content-Encoding "compress" the same as other + Content-Encodings that it does not support, e.g. "bzip2". That means + just ignoring it. -- multi: two fixes done +- [Marcel Raad brought this change] -- multi: use timeouts properly for MAX_RECV/SEND_SPEED + openssl: work around MSVC warning + + MSVC 12 complains: - When detecting that the send or recv speed, the multi interface changes - state to TOOFAST and previously there was no timeout set that would - force a recheck but it would rely on the application to somehow call - libcurl anyway. This now sets a timeout for a suitable future time to - check again if the average transfer speed is then below the threshold - again. + lib\vtls\openssl.c(1554): warning C4701: potentially uninitialized local + variable 'verstr' used It's a false positive, but as it's normally not, + I have enabled warning-as-error for that warning. -- multi: support timeouts +- [Michał Fita brought this change] + + configure: add --disable-rt option - Curl_expire() is now expanded to hold a list of timeouts for each easy - handle. Only the closest in time will be the one used as the primary - timeout for the handle and will be used for the splay tree (which sorts - and lists all handles within the multi handle). + This option disables any attempts in configure to create dependency on + stuff requiring linking to librt.so and libpthread.so, in this case this + means clock_gettime(CLOCK_MONOTONIC, &mt). - When the main timeout has triggered/expired, the next timeout in time - that is kept in the list will be moved to the main timeout position and - used as the key to splay with. This way, all timeouts that are set with - Curl_expire() internally will end up as a proper timeout. Previously any - Curl_expire() that set a _later_ timeout than what was already set was - just silently ignored and thus missed. + We were in need to build curl which doesn't link libpthread.so to avoid + the following bug: + https://sourceware.org/bugzilla/show_bug.cgi?id=16628. + +Kamil Dudka (23 Jul 2015) +- http2: verify success of strchr() in http2_send() - Setting Curl_expire() with timeout 0 (zero) will cancel all previously - added timeouts. + Detected by Coverity. - Corrects known bug #62. + Error: NULL_RETURNS: + lib/http2.c:1301: returned_null: "strchr" returns null (checked 103 out of 109 times). + lib/http2.c:1301: var_assigned: Assigning: "hdbuf" = null return value from "strchr". + lib/http2.c:1302: dereference: Incrementing a pointer which might be null: "hdbuf". + 1300| + 1301| hdbuf = strchr(hdbuf, 0x0a); + 1302|-> ++hdbuf; + 1303| + 1304| authority_idx = 0; -- Curl_llist_insert_next: allow insertion first in the list +Jay Satiro (22 Jul 2015) +- Windows: Fix VerifyVersionInfo calls - When we specify the "insert after" entry as NULL, this function now - inserts the new entry first in the list. + - Fix the VerifyVersionInfo calls, which we use to test for the OS major + version, to also test for the minor version as well as the service pack + major and minor versions. + + MSDN: "If you are testing the major version, you must also test the + minor version and the service pack major and minor versions." + + https://msdn.microsoft.com/en-us/library/windows/desktop/ms725492.aspx + + Bug: https://github.com/bagder/curl/pull/353#issuecomment-123493098 + Reported-by: Marcel Raad + +- [Marcel Raad brought this change] + + schannel: Replace deprecated GetVersion with VerifyVersionInfo + +Steve Holme (21 Jul 2015) +- makefile: Added support for VC14 + +Patrick Monnerat (21 Jul 2015) +- os400: ebcdic wrappers for new functions. Upgrade ILE/RPG bindings. + +- libcurl: VERSIONINFO update + Addition of new procedures curl_pushheader_bynum and curl_pushheader_byname + requires VERSIONINFO updating. + +- http2: satisfy external references even if http2 is not compiled in. -- multi: make curl_multi_info_read perform O(1) +Daniel Stenberg (20 Jul 2015) +- http2: add stream != NULL checks for reliability - Instead of looping over all attached easy handles, this now keeps a list - of messages in the multi handle. It allows curl_multi_info_read() to - perform O(1) no matter how many easy handles that are handled. This is - of importance since this function may be polled very frequently by apps - using the multi interface. + They should not trigger, but in case of internal problems we at least + avoid crashes this way. -Kamil Dudka (15 Aug 2010) -- curl -T: ignore file size of special files +Jay Satiro (18 Jul 2015) +- symbols-in-versions: Add new CURLSSLOPT_NO_REVOKE symbol + +- SSL: Add an option to disable certificate revocation checks + + New tool option --ssl-no-revoke. + New value CURLSSLOPT_NO_REVOKE for CURLOPT_SSL_OPTIONS. - original bug report at https://bugzilla.redhat.com/622520 + Currently this option applies only to WinSSL where we have automatic + certificate revocation checking by default. According to the + ssl-compared chart there are other backends that have automatic checking + (NSS, wolfSSL and DarwinSSL) so we could possibly accommodate them at + some later point. + + Bug: https://github.com/bagder/curl/issues/264 + Reported-by: zenden2k -Dan Fandrich (13 Aug 2010) -- Reset environment variables before starting servers +- runtests: Allow for spaces in curl custom path - Otherwise, variables from tests could affect the servers - themselves. + .. also fix some typos in test's FILEFORMAT spec. + +- [David Woodhouse brought this change] -Kamil Dudka (12 Aug 2010) -- typecheck-gcc: work around gcc upstream bug #32061 + ntlm_wb: Fix theoretical memory leak - original bug report at https://bugzilla.redhat.com/617757 + Static analysis indicated that my commit 9008f3d564 ("ntlm_wb: Fix + hard-coded limit on NTLM auth packet size") introduced a potential + memory leak on an error path, because we forget to free the buffer + before returning an error. + + Fix this. + + Although actually, it never happens in practice because we never *get* + here with state == NTLMSTATE_TYPE1. The state is always zero. That + might want cleaning up in a separate patch. + + Reported-by: Terri Oda -Daniel Stenberg (11 Aug 2010) -- release cycle loop: start over toward 7.21.2 +- strerror: Add CRYPT_E_REVOKED to SSPI error strings -Version 7.21.1 (11 Aug 2010) +Kamil Dudka (14 Jul 2015) +- libtest: call PR_Cleanup() on exit if NSPR is used + + This prevents valgrind from reporting possibly lost memory that NSPR + uses for file descriptor cache and other globally allocated internal + data structures. + + Reported-by: Štefan Kremeň -Daniel Stenberg (11 Aug 2010) -- RELEASE-NOTES: mention the runtests fix as well +Jay Satiro (14 Jul 2015) +- [John Malmberg brought this change] -- runtests: clear old setenv remainders before test + openssl: VMS support for SHA256 - Due to the layout of the singletest function there are situations where - it returns before it clears the environment variables that were - especially set for the single specific test case. That could lead to - subsequent tests getting executed with environment variables sticking - around from a previous test which could lead to badness. + setup-vms.h: More symbols for SHA256, hacks for older VAX - This change makes sure to clear all custom variables that may be laying - around from a previous round, before running a test case. + openssl.h: Use OpenSSL OPENSSL_NO_SHA256 macro to allow building on VAX. - Reported by: Kamil Dudka - Bug: http://curl.haxx.se/mail/lib-2010-08/0141.html + openssl.c: Use OpenSSL version checks and OPENSSL_NO_SHA256 macro to + allow building on VAX and 64 bit VMS. -Guenter Knauf (11 Aug 2010) -- Added OpenSSL builds to Watcom makefiles. +- examples: Fix typo in multi-single.c -Yang Tse (11 Aug 2010) -- configure: werror related adjustments +Daniel Stenberg (7 Jul 2015) +- [Tatsuhiro Tsujikawa brought this change] -Daniel Stenberg (11 Aug 2010) -- FAQ: s/libcurl.so.3/libcurl.so.X + http2: Fix memory leak in push header array -Dan Fandrich (10 Aug 2010) -- KNOWN_BUG #59 is fixed. Clarify support of IPv6 zone IDs. +Dan Fandrich (2 Jul 2015) +- test2041: fixed line endings in protocol part -- Fixed typo in Android configure command +- cyassl: fixed mismatched sha256sum function prototype -Daniel Stenberg (11 Aug 2010) -- HISTORY: added stuff from recent years +Daniel Stenberg (1 Jul 2015) +- [moparisthebest brought this change] -- warning: silence the compiler - - warning: conversion to 'long int' from 'time_t' may alter its value - - ... on win64 when time_t is 64bit and long is 32bit. + SSL: Pinned public key hash support -- RELEASE-NOTES: synced, 3 additional bugfixes +- examples: provide sections -- multi_socket_action: clarify how to kickstart it - - The callbacks are called when curl_multi_socket_action() is called, not - when handles are added. This is now mentioned in the "TYPICAL USAGE" - section. +- [John Malmberg brought this change] -- callbacks: acknowledge progress callback error returns + OpenVMS: VMS Software, Inc now the supplier. - When the progress callback is called during the TCP connection, an error - return would accidentally not abort the operation as intended but would - instead be counted as a failure to connect to that particular IP and - libcurl would just continue to try the next. I made singleipconnect() - and trynextip() return CURLcode properly. + setup-vms.h: Symbol case fixups submitted by Michael Steve - Added bonus: it corrected the error code for bad --interface usages, - like tested in test 1084 and test 1085. + build_gnv_curl_pcsi_desc.com: VSI aka as VMS Software, is now the + supplier of new versions of VMS. The install kit needs to accept + VSI as a producer. + +Jay Satiro (30 Jun 2015) +- multi: Move http2 push function declarations to header end - Reported by: Adam Light - Bug: http://curl.haxx.se/mail/lib-2010-08/0105.html + This change necessary for binary compatibility. + + Prior to this change test 1135 failed due to the order of functions. -Guenter Knauf (10 Aug 2010) -- More Watcom makefile fixes ... +- symbols-in-versions: Add new http2 push symbols - Final fix (hopefully!) for dll wlink loader; - prefer faster internal rm if available. + Prior to this change test 1119 failed due to the missing symbols. -- Fixed my wrong edit. +Daniel Stenberg (30 Jun 2015) +- RELEASE-NOTES: synced with e6749055d653 -- More Watcom makefile fixes. +- configure: disable libidn by default - Added the -br switch to dynamic builds which fixes the issue I saw - with curl's --version output. Added debug info and symfile for debug - builds to linker opts. Added DLL loader for wlink back, but this time - dependend on wlink version. - Patch posted to the list by malak.jiri AT gmail.com. - -- Changed test for -u switch in order to enable other wmake switches. + For security reasons, until there is a fix. - The var %MAKEFLAGS is only set in 3 cases: if set as environment - var or as macro definition from commandline, and either with the - -u or -ms switch. Since all these cases are unlikely for the average - user it should be safe to only test if %MAKEFLAGS is defined; this - has the benefit that now all other switches can be used again in - addition to the -u which was formerly not possible. + Bug: http://curl.haxx.se/mail/lib-2015-06/0143.html + Reported-by: Gustavo Grieco, Feist Josselin -Daniel Stenberg (10 Aug 2010) -- llist: hide Curl_llist_init +- SSL-PROBLEMS: mention WinSSL problems in WinXP + +- CODE_OF_CONDUCT.md: added - Curl_llist_init is never used outside of llist.c and thus it should be - static. I also removed the protos for Curl_llist_insert_prev and - Curl_llist_remove_next which are functions we removed from llist.c ages - ago. + Just to underscore how we treat each other in this project. Nothing new + really, but could be useful for newcomers and outsiders to see our + values. -Guenter Knauf (10 Aug 2010) -- Added msys Perl since git for Win32 comes with own Perl which identifies as msys. +- tool_header_cb: fflush the header stream + + Flush the header stream when -D is used so that they are sent off + earlier. + + Bug: https://github.com/bagder/curl/issues/324 + Reported-by: Cédric Connes -- Updated lib dependency versions. +- [Roger Leigh brought this change] -- Make testcurl.pl Watcom-aware. + tests: Distribute CMakeLists.txt files in subdirectories -Daniel Stenberg (10 Aug 2010) -- parse_remote_port: fix ;type= URL suffix over HTTP proxy +- CURLOPT_FAILONERROR.3: mention that it closes the connection - Test 563 is enabled now and verifies that the combo FTP type=A URL, - CURLOPT_PORT set and proxy work fine. As a bonus I managed to remove the - somewhat odd FTP check in parse_remote_port() and instead converted it - to a better and more generic 'slash_removed' struct field. Checking the - ->protocol field isn't right since when an FTP:// URL is sent over a - HTTP proxy, the protocol is HTTP but the URL was handled by the FTP code - and thus slash_removed is set TRUE for this case. + Reported-by: bemoody + Bug: https://github.com/bagder/curl/issues/325 -- indent: white space fixes only +- curl_multi_setopt.3: alpha sort the options -Yang Tse (9 Aug 2010) -- build: fix previous push +- curl_multi_setopt.3: add the new push options -- build: don't build libhostname unless shared libcurl is built +- [Tatsuhiro Tsujikawa brought this change] -- build: libhostname and chkhostname linkage adjustments followup + http2: Use nghttp2 library error code for error return value -Daniel Stenberg (8 Aug 2010) -- typo: remove duplicate semicolon +- [Tatsuhiro Tsujikawa brought this change] -- multi: avoid a malloc() when a transfer is complete + http2: Harden header validation for curl_pushheader_byname - The struct used for storing the message for a completed transfer is now - no longer allocated separatly but is kept within the main struct kept - for each easy handle so that we avoid one malloc (and the subsequent - free). + Since we do prefix match using given header by application code + against header name pair in format "NAME:VALUE", and VALUE part can + contain ":", we have to careful about existence of ":" in header + parameter. ":" should be allowed to match HTTP/2 pseudo-header field, + and other use of ":" in header must be treated as error, and + curl_pushheader_byname should return NULL. This commit implements + this behaviour. -Yang Tse (8 Aug 2010) -- build: libhostname linkage adjustments followup +- [Tatsuhiro Tsujikawa brought this change] -Guenter Knauf (7 Aug 2010) -- Fix to overwrite libcurl name. + CURLMOPT_PUSHFUNCTION.3: Remove unused variable -Yang Tse (7 Aug 2010) -- build: chkhostname build adjustments followup +- CURLMOPT_PUSHFUNCTION.3: added example -U-D5B1PQ1J\Administrador (7 Aug 2010) -- build: allow NTLM tests to run on more build configurations +- http2: curl_pushheader_byname now takes a const char * -Daniel Stenberg (7 Aug 2010) -- curl_easy_setopt.3: rename stream to userdata - - In some places where the name 'stream' has been used for naming a - function argument that is in fact settable with a setopt() option we now - call that argument 'userdata' to make it more obvious that it is in fact - possible to set by the application. - - Suggested by: Jeff Pohlmeyer +- http2-serverpush.c: example code -Guenter Knauf (7 Aug 2010) -- Block created curlbuild.h for NetWare to avoid usage from other platforms. +- http2: free all header memory after the push callback -Daniel Stenberg (7 Aug 2010) -- RELEASE-NOTES: synced with recent changes +- http2: init the pushed transfer properly -Yang Tse (6 Aug 2010) -- build: ensure that libhostname doesn't get installed +- http2: fixed the header accessor functions for the push callback -Daniel Stenberg (6 Aug 2010) -- multi_socket: set timeout for 100-continue - - When libcurl internally decided to wait for a 100-continue header, there - was no call to the timeout function so there was no timeout callback - called when the multi_socket API was used and thus applications became - either completely wrong or at least ineffecient depending on how they - handled the situation. We now set a timeout to get triggered. - - Reported by: Ben Darnell - Bug: http://curl.haxx.se/bug/view.cgi?id=3039744 +- http2: setup the new pushed stream properly -Guenter Knauf (6 Aug 2010) -- Some more Watcom makefile massage ... +- http2: initial implementation of the push callback + +- http2: initial HTTP/2 server push types/docs + +- test1531: verify POSTFIELDSIZE set after add_handle - For now removed the .autodepend directive until I've figured out - which of my changes broke it again. + Following the fix made in 903b6e05565bf. -Yang Tse (5 Aug 2010) -- build: fix libssh2_scp_send64() availability +- pretransfer: init state.infilesize here, not in add_handle + + ... to properly support that options are set to the handle after it is + added to the multi handle. + + Bug: http://curl.haxx.se/mail/lib-2015-06/0122.html + Reported-by: Stefan Bühler -- build: remove unneeded cast to (void *) +Jay Satiro (21 Jun 2015) +- [Lior Kaplan brought this change] -- build: remove unused file + tool_help: fix --tlsv1 help text to use >= for TLSv1 -Daniel Stenberg (4 Aug 2010) -- SCP: send large files properly with new enough libssh2 +- INSTALL: Advise use of non-native SSL for Windows <= XP - libssh2 1.2.6 and later handle >32bit file sizes properly even on 32bit - architectures and we make sure to use that ability. + Advise that WinSSL in versions <= XP will not be able to connect to + servers that no longer support the legacy handshakes and algorithms used + by those versions, and to use an alternate backend like OpenSSL instead. - Reported by: Mikael Johansson - Bug: http://curl.haxx.se/mail/lib-2010-08/0052.html + Bug: https://github.com/bagder/curl/issues/253 + Reported-by: zenden2k -Yang Tse (3 Aug 2010) -- build: add missing new files to non-configure target build files +Kamil Dudka (19 Jun 2015) +- curl_easy_setopt.3: restore contents removed by mistake + + ... in commit curl-7_43_0-18-g570076e -- md4: replace bcopy usage with memcpy +Daniel Stenberg (19 Jun 2015) +- curl_easy_setopt.3: mention CURLOPT_PIPEWAIT -Daniel Stenberg (3 Aug 2010) -- RELEASE-NOTES: synced with recent changes +Jay Satiro (18 Jun 2015) +- cookie: Fix bug in export if any-domain cookie is present + + In 3013bb6 I had changed cookie export to ignore any-domain cookies, + however the logic I used to do so was incorrect, and would lead to a + busy loop in the case of exporting a cookie list that contained + any-domain cookies. The result of that is worse though, because in that + case the other cookies would not be written resulting in an empty file + once the application is terminated to stop the busy loop. -- TODO-RELEASE: clear, file not really used ATM +Dan Fandrich (18 Jun 2015) +- FTP: fixed compiling with --disable-proxy, broken in b88f980a -- typecheck-gcc: add checks for recently added options - - I added all OBJECTPOINT curl_easy_setopt() options from 178 to 202. Left - to add: the five FUNCTIONPOINT (callbacks) options added since: +Daniel Stenberg (18 Jun 2015) +- tool: always provide negotiate/kerberos options - SSH_KEYFUNCTION - INTERLEAVEFUNCTION - CHUNK_BGN_FUNCTION - CHUNK_END_FUNCTION - FNMATCH_FUNCTION + libcurl can still be built with it, even if the tool is not. Maintain + independence! -- .gitignore: ignore all built examples +- TODO: Support IDNA2008 -- example: fix code to build warning-free +- [Viktor Szakats brought this change] -- Curl_connected_proxy: skip the bits.tcpconnect check - - Simply because the TCP might be connected already we cannot skip the - proxy connect procedure. We need to be careful to not overload more - meaning to the bits.tcpconnect field like this. - - With this fix, SOCKS proxies work again when the multi interface is - used. I believe this regression was added with commit 4b351d018e, - released as 7.20.1. + Makefile.m32: add support for CURL_LDFLAG_EXTRAS - Left todo: add a test case that verifies this functionality that - prevents us from breaking it again in the future! - - Reported by: Robin Cornelius - Bug: http://curl.haxx.se/bug/view.cgi?id=3033966 + It is similar to existing CURL_CFLAG_EXTRAS, but for + extra linker option. -- sethostname: provide local prototype for gethostname +- RTSP: removed another piece of dead code - This is only to avoid warnings on some systems. + Coverity CID 1306668 -- build: add typecast to avoid warning +- openssl: fix use of uninitialized buffer + + Make sure that the error buffer is always initialized and simplify the + use of it to make the logic easier. - There is an implicit conversion from "unsigned long" to "long"; - rounding, sign extension, or loss of accuracy may result. + Bug: https://github.com/bagder/curl/issues/318 + Reported-by: sneis -Guenter Knauf (2 Aug 2010) -- Rename CURL_SOURCES macro; revert previous rename of curl_SOURCES macro. +- examples: more descriptions -- Removed ugly dependency lists since wmake knows the .autodepend directive. +- examples: add descriptions with + + Using this fixed format for example descriptions, we can generate a + better list on the web site. -- Use suffix search path for sources in lib folder. +- libcurl-errors.3: fix typo -- Changed src/Makefile.Watcom to use CURL_SOURCES from src/Makefile.inc. +- curl_easy_setopt.3: option order doesn't matter -- Renamed curl_SOURCES to CURL_ALLFILES to overcome wmake's case-insensitivity. +- openssl: fix build with BoringSSL + + OPENSSL_load_builtin_modules does not exist in BoringSSL. Regression + from cae43a1 -- Removed wlink from DLL loader list because it doesnt work with Watcom < 1.8. +- [Paul Howarth brought this change] -- Moved the LDAP API defines from Makefile.Watcom to config-win32.h. + openssl: Fix build with openssl < ~ 0.9.8f - These defines are only needed for older Watcom versions (< 1280). + The symbol SSL3_MT_NEWSESSION_TICKET appears to have been introduced at + around openssl 0.9.8f, and the use of it in lib/vtls/openssl.c breaks + builds with older openssls (certainly with 0.9.8b, which is the latest + older version I have to try with). -Daniel Stenberg (2 Aug 2010) -- retry: consider retrying even if -f is used +- FTP: do the HTTP CONNECT for data connection blocking - The --retry logic does retry HTTP when some specific response codes are - returned, but because the -f option sets the CURLOPT_FAILONERROR to - libcurl, the return codes are different for such situations and then the - curl tool failed to consider it for retrying. + ** WORK-AROUND ** - Reported by: Mike Power - Bug: http://curl.haxx.se/bug/view.cgi?id=3037362 - -- multi: fix FTPS connecting the data connection with OpenSSL + The introduced non-blocking general behaviour for Curl_proxyCONNECT() + didn't work for the data connection establishment unless it was very + fast. The newly introduced function argument makes it operate in a more + blocking manner, more like it used to work in the past. This blocking + approach is only used when the FTP data connecting through HTTP proxy. - Commit 496002ea1cd76af7f (released in 7.20.1) broke FTPS when using the - multi interface and OpenSSL was used. The condition for the non-blocking - connect was incorrect. + Blocking like this is bad. A better fix would make it work more + asynchronously. - Reported by: Georg Lippitsch - Bug: http://curl.haxx.se/mail/lib-2010-07/0270.html - -Guenter Knauf (1 Aug 2010) -- Fixed curlbuild.h rule. - -- Added rule to create curlbuild.h if not present (for builds from git). - -- Added dependend libs for curl static linking. + Bug: https://github.com/bagder/curl/issues/278 -- Fixed curl.exe static linking. +- bump: start the journey toward 7.44.0 -Daniel Stenberg (30 Jul 2010) -- warning: silence a win64 compiler warning - - conversion from 'size_t' to 'curl_socklen_t', possible loss of data - - Reported by: Adam Light +Jay Satiro (17 Jun 2015) +- CURLOPT_ERRORBUFFER.3: Fix example, escape backslashes -- KNOWN_BUG: The SOCKET type in Win64 is 64 bits - - The SOCKET type in Win64 is 64 bits large (and thus so is curl_socket_t - on that platform), and long is only 32 bits. It makes it impossible for - curl_easy_getinfo() to return a socket properly with the - CURLINFO_LASTSOCKET option as for all other operating systems. +- CURLOPT_ERRORBUFFER.3: Improve example -- smtp_connect: always provide host name buffer - - Previously the host name buffer was only used if gethostname() exists, - but since we converted that into a curl private function that function - always exists and will be used so the buffer needs to exist for all - cases/systems. +Version 7.43.0 (17 Jun 2015) -- sethostname: avoid including unistd.h to duck for warnings +Daniel Stenberg (17 Jun 2015) +- RELEASE-NOTES: 7.43.0 release -- sethostname: ISO C does not allow extra `;' outside of a function +- THANKS: updated with 7.43.0 names - [Kamil Dudka brought this change] - NTLM tests: boost coverage by forcing the hostname + http: do not leak basic auth credentials on re-used connections - A shared library tests/libtest/.libs/lihostname.so is preloaded in NTLM - test-cases to override the system implementation of gethostname(). It - makes it possible to test the NTLM authentication for exact match, and - this way test the implementation of MD4 and DES. + CVE-2015-3236 - If LD_PRELOAD doesn't work, a debug build willl also workk as debug - builds are now made to prefer a specific environment variable and will - then return that content as host name instead of the actual one. + This partially reverts commit curl-7_39_0-237-g87c4abb - Kamil wrote the bulk of this, Daniel Stenberg polished it. + Reported-by: Tomas Tomecek, Kamil Dudka + Bug: http://curl.haxx.se/docs/adv_20150617A.html -Guenter Knauf (29 Jul 2010) -- Added a comment with an alternate idea to avoid the backslash line contination character. +- [Kamil Dudka brought this change] -- Changed comparison to match size_t var type. + test2040: verify basic auth on re-used connections -- Removed unused vars to avoid compiler warnings. - -- Make Watcom makefiles use Makefile.inc to reduce future maintainance. +- SMB: rangecheck values read off incoming packet - lib/Makefile.Watcom works fine already, for src/Makefile.Watcom we - need first to tweak src/Makefile.inc a bit - therefore the handtweaked - list still exists for now. - -- Watcom makefiles overhaul. + CVE-2015-3237 - - make both libcurl and curl makefiles use register calling convention - (previously libcurl had stack calling convention). - - added include paths to the Watcom headers so its no longer required - to set the environment vars for this. - - added -wcd=201 to supress compiler warning about unreachable code. - - use macros for all tools, and removed dependency on GNU tools like rm. - - make ipv6 and debug builds controlable via env vars and so make them - optional instead of default. - - commented WINLDAPAPI and WINBERAPI since they broke with OW 1.8, and - it seems they're not needed (anymore?). - - added rule for hugehelp.c.cvs so that it will be created when not - already exist - this is required for building from a release tarball - since there we have no hugehelp.c.cvs, thus compilation broke. - - removed C_ARG creation from lib/Makefile.Watcom and use CFLAGS - directly as done too in src/Makefile.Watcom - this has the benefit - that we will see all active cflags and defines during compile. - - added LINK-ARG to src/Makefile.Watcom in order to better control - linker input. - - a couple of other minor makefile tweaks here and there ... - - added largefile support for Watcom builds to config-win32.h. Not yet - tested if it really works, but should since Win32 supports it. - - added loaddll stuff to speed up builds if supported. - -- some cosmetic changes. - -Dan Fandrich (26 Jul 2010) -- Added md4.c to the Watcom makefile - -- Added PolarSSL to the docs + Detected by Coverity. CID 1299430. + + Bug: http://curl.haxx.se/docs/adv_20150617B.html -Daniel Stenberg (25 Jul 2010) -- curl-config: --built-shared returns shared info +Jay Satiro (17 Jun 2015) +- schannel: schannel_recv overhaul - The curl-config now features a --built-shared command line option that - will output 'yes' or 'no' depending if the build process was asked to - build shared library/libraries or not. + This commit is several drafts squashed together. The changes from each + draft are noted below. If any changes are similar and possibly + contradictory the change in the latest draft takes precedence. - It is primarily made to offer more details to the test suite to know - what kind of stunts it can expect to work. - -- add_buffer_send: fix compiler warning + Bug: https://github.com/bagder/curl/issues/244 + Reported-by: Chris Araman - Win64's 32 bit long but 64 bit size_t caused a warning that we avoid - with a typecast. A small whitespace indent fix was also applied. + %% + %% Draft 1 + %% + - return 0 if len == 0. that will have to be documented. + - continue on and process the caches regardless of raw recv + - if decrypted data will be returned then set the error code to CURLE_OK + and return its count + - if decrypted data will not be returned and the connection has closed + (eg nread == 0) then return 0 and CURLE_OK + - if decrypted data will not be returned and the connection *hasn't* + closed then set the error code to CURLE_AGAIN --only if an error code + isn't already set-- and return -1 + - narrow the Win2k workaround to only Win2k - Reported by: Adam Light - -Guenter Knauf (22 Jul 2010) -- Updated library versions. - -- Fixed script version which was still based on CVS Revision tag. - -Dan Fandrich (21 Jul 2010) -- FAQ: Why doesn't cURL error out when the cable is unplugged? + %% + %% Draft 2 + %% + - Trying out a change in flow to handle corner cases. - This one was long overdue to be mentioned in the FAQ. Also, mention the - new ftp wildcard downloading feature. - -Daniel Stenberg (21 Jul 2010) -- [Ben Greear brought this change] - - ssh: Fix compile error on 64-bit systems. + %% + %% Draft 3 + %% + - Back out the lazier decryption change made in draft2. - Signed-off-by: Ben Greear - -- [Ben Greear brought this change] - - build: Enable configure --enable-werror + %% + %% Draft 4 + %% + - Some formatting and branching changes + - Decrypt all encrypted cached data when len == 0 + - Save connection closed state + - Change special Win2k check to use connection closed state - This passes -Werror to gcc when building curl and libcurl, - allowing easy dection of compile warnings. + %% + %% Draft 5 + %% + - Default to CURLE_AGAIN in cleanup if an error code wasn't set and the + connection isn't closed. - Signed-off-by: Ben Greear - -- [Ben Greear brought this change] - - pingpong: Fix indentation (whitespace change only) + %% + %% Draft 6 + %% + - Save the last error only if it is an unrecoverable error. - Signed-off-by: Ben Greear - -- [Jan Van Boghout brought this change] - - CUSTOMREQUEST: shouldn't be disabled when HTTP is disabled + Prior to this I saved the last error state in all cases; unfortunately + the logic to cover that in all cases would lead to some muddle and I'm + concerned that could then lead to a bug in the future so I've replaced + it by only recording an unrecoverable error and that state will persist. - ... since FTP is using it as well, and potentially other protocols! + - Do not recurse on renegotiation. - Also, an #endif CURL_DISABLE_HTTP was incorrectly marked, as it seems to - end the proxy block instead. - -- [Jan Van Boghout brought this change] - - pingpong: response_time is milliseconds + Instead we'll continue on to process any trailing encrypted data + received during the renegotiation only. - Fixed the comment/document for the response_time struct member. - -- [Jan Van Boghout brought this change] - - ftp: response timeout bug in "quote" sending + - Move the err checks in cleanup after the check for decrypted data. - The FTP implementation was missing a timestamp reset point, making the - waiting for responses after sending a post-transfer "QUOTE" command not - working as supposedly. This bug was introduced in 7.20.0 - -- [Jeff Pohlmeyer brought this change] - - remote-header-name: chop filename at next semicolon + In either case decrypted data is always returned but I think it's easier + to understand when those err checks come after the decrypted data check. - The --remote-header-name option for the command-line tool assumes that - everything beyond the filename= field is part of the filename, but that - might not always be the case, for example: + %% + %% Draft 7 + %% + - Regardless of len value go directly to cleanup if there is an + unrecoverable error or a close_notify was already received. Prior to + this change we only acknowledged those two states if len != 0. - Content-Disposition: attachment; filename=file.txt; modification-date=... + - Fix a bug in connection closed behavior: Set the error state in the + cleanup, because we don't know for sure it's an error until that time. - This fix chops the filename off at the next semicolon, if there is one. - -- --retry: access violation with URL part sets continued + - (Related to above) In the case the connection is closed go "greedy" + with the decryption to make sure all remaining encrypted data has been + decrypted even if it is not needed at that time by the caller. This is + necessary because we can only tell if the connection closed gracefully + (close_notify) once all encrypted data has been decrypted. - When getting multiple URLs, curl didn't properly reset the byte counter - after a successful transfer so if the subsequent transfer failed it - would wrongly use the previous byte counter and behave badly (segfault) - because of that. The code assumes that the byte counter and the 'stream' - pointer is well in synch. + - Do not renegotiate when an unrecoverable error is pending. - Reported by: Jon Sargeant - Bug: http://curl.haxx.se/bug/view.cgi?id=3028241 - -- releasnote: synch up with commit f3b77e5611d + %% + %% Draft 8 + %% + - Don't show 'server closed the connection' info message twice. + + - Show an info message if server closed abruptly (missing close_notify). -- [Constantine Sapuntzakis brought this change] +Daniel Stenberg (16 Jun 2015) +- [Paul Oliver brought this change] - examples: add curl_multi_timeout + Fix typo in docs - Make the multi-interface using examples use curl_multi_timeout to - properly educate users how to do things. + s/curret/current/ -- configure: document the STATICLIB variable +- [Viktor Szakats brought this change] -- [Constantine Sapuntzakis brought this change] + docs: update URLs - multi: fix condition that remove timers before trigger - - curl_multi perform has two phases: run through every easy handle calling - multi_runsingle and remove expired timers (timer removal). - - If a small timer (e.g. 1-10ms) is set during multi_runsingle, then it's - possible that the timer has passed by when the timer removal runs. The - timer which was just added is then removed. This will potentially cause - the timer list to be empty and cause the next call to curl_multi_timeout - to return -1. Ideally, curl_multi_timeout should return 0 in this case. - - One way to fix this is to move the struct timeval now = Curl_tvnow(); to - the top of curl_multi_perform. The change does that. +- RELEASE-NOTES: synced with f29f2cbd00dbe5f -- [Constantine Sapuntzakis brought this change] +- [Viktor Szakats brought this change] - threaded resolver: fix timeout issue - - Reset old timer first so we can set a new one further in the future. + README: use secure protocol for Git repository -- configure: allow environments variable to override internals - - configure checks for grep, egrep, sed and ar and set the variables GREP, - EGREP, SED and AR accordingly. We now let already set variables override - the internal choices to let users make decisions when they know the - right choice already. This is a regression as our configure script used - to allow this back before commit 0b57c475 (up to 7.18.2). - - Reported by: "kdekker" - Bug: http://curl.haxx.se/bug/view.cgi?id=3028318 +- [Viktor Szakats brought this change] -Dan Fandrich (9 Jul 2010) -- Improved the Android build instructions + HTTP2.md: use SSL/TLS IETF URLs -Daniel Stenberg (7 Jul 2010) -- [Tor Arntsen brought this change] +- [Viktor Szakats brought this change] - upload: Avoid infinite loop when checking for auth bits + LICENSE-MIXING: update URLs - The test would loop forever if authtype bit 0 wasn't set. + * use SSL/TLS where available + * follow permanent redirects -- upload: warn users trying to upload from stdin with anyauth - - Since uploading from stdin is very likely to not work with anyauth and - its multi-phase probing for what authentication to actually use, alert - the user about it. Multi-phase negotiate almost certainly will involve - sending data and thus libcurl will need to rewind the stream to send - again, and it cannot do that with stdin. +- LICENSE-MIXING: refreshed -- http: don't enable chunked during authentication negotiations +- curl_easy_duphandle: see also *reset + +- rtsp_do: fix DEAD CODE - As mentioned in bug report #2956968, the HTTP code wouldn't send the - first empty chunk during the auth negotiation phase of the HTTP request - sending, so the server would wait for data to come and libcurl would - wait for data to arrive... I've made the code not enable chunked - encoding until the auth negotiation is done and thus this scenario - doesn't occur anymore. + "At condition p_request, the value of p_request cannot be NULL." - Reported by: Sidney San Martn - Bug: http://curl.haxx.se/bug/view.cgi?id=2956968 + Coverity CID 1306668. -- --libcurl: list the tricky options instead of using [REMARK] +- security:choose_mech fix DEAD CODE warning - I think the [REMARK] and commented function calls cluttered the code a - bit too much and made the generated code ugly to read. Now we instead - track the remarks one specially and just lists them at the end of the - generated code more as additional information. - -- curl: avoid setting libcurl options to its default + ... by removing the "do {} while (0)" block. - it makes the --libcurl output easier to follow. + Coverity CID 1306669 -- --libcurl: hide setopt() calls setting default options - - And additionally, don't show function or object pointers actual value - since they make no sense to anyone. Show 'functionpointer' and - 'objectpointer' instead. +- curl.1: netrc is in man section 5 -- --libcurl: use *_LARGE options with typecasted constants +- curl.1: small format fix - In the generated code --libcurl makes, all calls to curl_easy_setopt() - that use *_LARGE options now have the value typecasted to curl_off_t, so - that it works correctly for 32bit systems with 64bit curl_off_t type. + use \fI-style instead of .BR for references -- multi: CURLINFO_LASTSOCKET doesn't work after remove_handle - - When curl_multi_remove_handle() is called and an easy handle is returned - to the connection cache held in the multi handle, then we cannot allow - CURLINFO_LASTSOCKET to extract it since that will more or less encourage - that the user uses the socket while it can get used by libcurl again. +- urldata: store POST size in state.infilesize too - Without this fix, we'd get a segfault in Curl_getconnectinfo() trying to - dereference the NULL pointer in 'data->state.connc'. + ... to simplify checking when PUT _or_ POST have completed. - Bug: http://curl.haxx.se/bug/view.cgi?id=3023840 + Reported-by: Frank Meier + Bug: http://curl.haxx.se/mail/lib-2015-06/0019.html -- [Pierre Joye brought this change] +Dan Fandrich (14 Jun 2015) +- test1530: added http to required features - build: add enable IPV6 option for the VC makefiles +Jay Satiro (14 Jun 2015) +- [Drake Arconis brought this change] -- FAQ: the threaded resolver works universally now + build: Fix typo from OpenSSL 1.0.2 version detection fix -Kamil Dudka (30 Jun 2010) -- http_ntlm: add support for NSS - - When configured with '--without-ssl --with-nss', NTLM authentication - now uses NSS crypto library for MD5 and DES. For MD4 we have a local - implementation in that case. More details are available at - https://bugzilla.redhat.com/603783 - - In order to get it working, curl_global_init() must be called with - CURL_GLOBAL_SSL or CURL_GLOBAL_ALL. That's necessary because NSS needs - to be initialized globally and we do so only when the NSS library is - actually required by protocol. The mentioned call of curl_global_init() - is responsible for creating of the initialization mutex. - - There was also slightly changed the NSS initialization scenario, in - particular, loading of the NSS PEM module. It used to be loaded always - right after the NSS library was initialized. Now the library is - initialized as soon as any SSL or NTLM is required, while the PEM module - is prevented from being loaded until the SSL is actually required. +- [Drake Arconis brought this change] -Daniel Stenberg (29 Jun 2010) -- glob: backslash escaping bug - - curl didn't properly handle escaping characters in a URL with the use of - backslash. It did an attempt, but that failed as reported in bug - 3022551. The described example was using the URL - "http://example.com?{AB,C\,D}". - - I've now removed the special-handling of letters following the backslash - and I also removed the bad extra check that triggered this particular - bug. - - Bug: http://curl.haxx.se/bug/view.cgi?id=3022551 - Reported by: Jon Sargeant + build: Properly detect OpenSSL 1.0.2 when using configure -- release-notes: sync up with recent commits +- curl_multi_info_read.3: fix example formatting -- CONTRIBUTE: the git commit message line length is 72 columns +Daniel Stenberg (13 Jun 2015) +- BINDINGS: there's a new R binding in town! -- [Pavel Raiskup brought this change] +- BINDINGS: added the Xojo binding - ftp wildcard: FTP LIST parser FIX +Jay Satiro (11 Jun 2015) +- [Joel Depooter brought this change] + + schannel: Add support for optional client certificates - There was a problem when a UNIX-like server returned information - about directory size (total NNNNNN) at the first line of - response. + Some servers will request a client certificate, but not require one. + This change allows libcurl to connect to such servers when using + schannel as its ssl/tls backend. When a server requests a client + certificate, libcurl will now continue the handshake without one, + rather than terminating the handshake. The server can then decide + if that is acceptable or not. Prior to this change, libcurl would + terminate the handshake, reporting a SEC_I_INCOMPLETE_CREDENTIALS + error. -- [Pavel Raiskup brought this change] +Daniel Stenberg (11 Jun 2015) +- curl_easy_cleanup.3: provide more SEE ALSO - examples: new FTP wildcard showcase +- debug: remove http2 debug leftovers -- multi_socket: re-use of same socket without notifying app - - When a hostname resolves to multiple IP addresses and the first one - tried doesn't work, the socket for the second attempt may get dropped on - the floor, causing the request to eventually time out. The issue is that - when using kqueue (as on mac and bsd platforms) instead of select, the - kernel removes the first fd from kqueue when it is closed (in trynextip, - connect.c:503). Trynextip() then goes on to open a new socket, which - gets assigned the same number as the one it just closed. Later in - multi.c, socket_cb is not called because the fd is already in - multi->sockhash, so the new socket is never added to kqueue. - - The correct fix is to ensure that socket_cb is called to remove the fd - when trynextip() closes the socket, and again to re-add it after - singleipsocket(). I'm not sure how to cleanly do that, but the attached - patch works around the problem in an admittedly kludgy way by delaying - the close to ensure that the newly-opened socket gets a different fd. - - Daniel's added comment: I didn't spot a way to easily do a nicer fix so - I've proceeded with Ben's patch. - - Bug: http://curl.haxx.se/bug/view.cgi?id=3017819 - Patch by: Ben Darnell +- VERSIONS: now using markdown -Kamil Dudka (24 Jun 2010) -- [Pavel Raiskup brought this change] +- RELEASE-PROCEDURE: remove ascii logo at the top of file - ftp-wildcard: avoid tight loop when used without any pattern - - It was broken for URLs like "ftp://example.com/". +- INTERNALS: absorbed docs/LIBCURL-STRUCTS -Daniel Stenberg (21 Jun 2010) -- maketgz: produce CHANGES automatically with the 1000 most recent commits +- INTERNALS: cat lib/README* >> INTERNALS - It passes the git log output through 'log2changes.pl' to produce - the lot. - -- ignore: CHANGES.dist gets generated by maketgz - -- CHANGES: move all contents from CHANGES to CHANGES.0 + and a conversion to markdown. Removed the lib/README.* files. The idea + being to move toward having INTERNALS as the one and only "book" of + internals documentation. - CHANGES is no longer used for manually edited content. It is to - be generated automatically by maketgz when we make release - tarballs. + Added a TOC to top of the document. -- log2changes: correct command line, fix tag usage, change Version output +Jay Satiro (8 Jun 2015) +- openssl: LibreSSL and BoringSSL do not use TLS_client_method - --decorate=full is needed with my git 1.7.1 to get the necessary - output so that the previous edit would work to extract the - Version stuff. + Although OpenSSL 1.1.0+ deprecated SSLv23_client_method in favor of + TLS_client_method LibreSSL and BoringSSL didn't and still use + SSLv23_client_method. - ... but I had to edit how the refs/tags was extracted since it - had a little flaw that made it miss the 7.20.1 output. - - Finally, I changed so that Version is outputted even more similar - to how CHANGES does it. + Bug: https://github.com/bagder/curl/commit/49a6642#commitcomment-11578009 + Reported-by: asavah@users.noreply.github.com -Dan Fandrich (21 Jun 2010) -- Make the output of log2changes.pl even more closely match CHANGES - - Add the ASCII art header, and list version commits by decoding - the ref tag names, when available (using the git log --decorate - option). +Daniel Stenberg (9 Jun 2015) +- RELEASE-NOTES: synced with 20ac3458068 -Daniel Stenberg (19 Jun 2010) -- log2changes: first version of the git log to CHANGES conversion script +- CURLOPT_OPENSOCKETFUNCTION: return error at once - $ git log --pretty=fuller --no-color --date=short | ./log2changes.pl - - Of course, limiting the log output with a range like with - "[tag]..HEAD" appended can be very useful too. - -- sendrecv: treat all negative values from send/recv as errors + When CURL_SOCKET_BAD is returned in the callback, it should be treated + as an error (CURLE_COULDNT_CONNECT) if no other socket is subsequently + created when trying to connect to a server. - For example the libssh2 based functions return other negative - values than -1 to signal errors and it is important that we catch - them properly. Right before this, various failures from libssh2 - were treated as negative download amounts which caused havoc. + Bug: http://curl.haxx.se/mail/lib-2015-06/0047.html -- multi: prevent NULL pointer dereference - - My additional call to Curl_pgrsUpdate() would sometimes get - called even though there's no connection (left) so a NULL pointer - would get passed, causing a segfault. +- fopen.c: fix a few compiler warnings -- smtp: fixed a few uses of size_t that seemed to believe it was signed - - Reported-by: Steven M. Schweda +- [Ville Skyttä brought this change] -Dan Fandrich (17 Jun 2010) -- Fixed an OOM memory leak in the FTP wildcard code + docs: Spelling fixes -Kamil Dudka (17 Jun 2010) -- test575: do not fail with threaded DNS resolver +- [Ville Skyttä brought this change] -Daniel Stenberg (17 Jun 2010) -- [Krister Johansen brought this change] + docs: man page indentation and syntax fixes - multi: unmark handle as used when no longer head of pipeline +Linus Nielsen (8 Jun 2015) +- help: Add --proxy-service-name and --service-name to the --help output -- multi: call the progress function only once and allow abort +Jay Satiro (7 Jun 2015) +- openssl: Fix verification of server-sent legacy intermediates - 1) no need to call the progress function twice when in the - CURLM_STATE_TOOFAST state. + - Try building a chain using issuers in the trusted store first to avoid + problems with server-sent legacy intermediates. - 2) Make sure that the progress callback's return code is - acknowledged when used - -- multi: call the progress callback in all states + Prior to this change server-sent legacy intermediates with missing + legacy issuers would cause verification to fail even if the client's CA + bundle contained a valid replacement for the intermediate and an + alternate chain could be constructed that would verify successfully. - As long as no error is reported, the progress function can get - called. This may be a little TOO often so we should keep an eye - on this and possibly make this conditional somehow. + https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest -- configure: spell --disable-threaded-resolver correctly - - Previously we only accepted the option when named - --disable-threaded-resover, which wasn't quite intended. +Daniel Stenberg (5 Jun 2015) +- BINDINGS: update several URLs - Reported by: Helwing Lutz - -- release: start on 7.21.1, bump contributor count - -- version: start working on the 7.21.1-dev version - -- THANKS: added contributors from the 7.21.0 release - -Version 7.21.0 (16 Jun 2010) + Stop linking to the curl.haxx.se anchor pages, they are usually only + themselves pointers to the real page so better point there directly + instead. -Daniel Stenberg (16 Jun 2010) -- release: 7.21.0 +- BINDINGS: the curl-rust binding -Yang Tse (10 Jun 2010) -- remove unused 'tmpdata' and 'backup' ftp_parselist_data struct members - -- replace isprint() with ISPRINT() - -- ensure that Curl_wildcard_dtor() leaves WildcardData struct zero initialized - -Patrick Monnerat (9 Jun 2010) -- ILE/RPG binding updated to current curl.h definitions. - -Yang Tse (9 Jun 2010) -- code simplification - -- add Curl_ prefix to conform with cURL naming standards - -- Merge branch 'master' of git@github.com:bagder/curl - -- fix compiler warning using curl_socket_t to store socket descriptor - -Daniel Stenberg (8 Jun 2010) -- inet_pton: warnings: use size_t to store pointer deltas - -Yang Tse (8 Jun 2010) -- avoid redundant work when reusing same connection - -- fix function result checking - -Daniel Stenberg (8 Jun 2010) -- transfer: warning: implicit conversion - - There is an implicit conversion from "unsigned long" to "long"; - rounding, sign extension, or loss of accuracy may result. +- curl.h: add CURL_HTTP_VERSION_2 - Fixed by an added typecast. + The protocol is named "HTTP/2" after all. It is an alias for the + existing CURL_HTTP_VERSION_2_0 enum. -- TFTP: fix compiler warning +- openssl: removed error string #ifdef - Curl_fillreadbuffer()'s second argument takes an int, so - typecasting to another is a bad idea. + ERR_error_string_n() was introduced in 0.9.6, no need to #ifdef anymore -- TFTP: fix warning for sendto() usage on non-POSIX systems +- openssl: removed USERDATA_IN_PWD_CALLBACK kludge - Older unixes want an 'int' instead of 'size_t' as the 3rd - argumment so before this change it would cause warnings such as: - - There is an implicit conversion from "unsigned long" to "int"; - rounding, sign extension, or loss of accuracy may result. + Code for OpenSSL 0.9.4 serves no purpose anymore! -Dan Fandrich (7 Jun 2010) -- Include Makefile.inc to get the list of source files for Amiga +- openssl: remove SSL_get_session()-using code - Signed-off-by: Diego Casorran + It was present for OpenSSL 0.9.5 code but we only support 0.9.7 or + later. -Yang Tse (7 Jun 2010) -- Curl_updateconninfo() error handling fix +- openssl: remove dummy callback use from SSL_CTX_set_verify() + + The existing callback served no purpose. -Daniel Stenberg (5 Jun 2010) -- [Constantine Sapuntzakis brought this change] +- LIBCURL-STRUCTS: clarify for multiplexing - OpenSSL: fix spurious SSL connection aborts - - Was seeing spurious SSL connection aborts using libcurl and - OpenSSL. I tracked it down to uncleared error state on the - OpenSSL error stack - patch attached deals with that. - - Rough idea of problem: +Jay Satiro (3 Jun 2015) +- cookie: Stop exporting any-domain cookies - Code that uses libcurl calls some library that uses OpenSSL but - don't clear the OpenSSL error stack after an error. + Prior to this change any-domain cookies (cookies without a domain that + are sent to any domain) were exported with domain name "unknown". - ssluse.c calls SSL_read which eventually gets an EWOULDBLOCK from - the OS. Returns -1 to indicate an error - - ssluse.c calls SSL_get_error. First thing, SSL_get_error calls - ERR_get_error to check the OpenSSL error stack, finds an old - error and returns SSL_ERROR_SSL instead of SSL_ERROR_WANT_READ or - SSL_ERROR_WANT_WRITE. - - ssluse.c returns an error and aborts the connection - - Solution: - - Clear the openssl error stack before calling SSL_* operation if - we're going to call SSL_get_error afterwards. - - Notes: - - This is much more likely to happen with multi because it's easier - to intersperse other calls to the OpenSSL library in the same - thread. + Bug: https://github.com/bagder/curl/issues/292 -Yang Tse (5 Jun 2010) -- replace socklen_t with curl_socklen_t +Daniel Stenberg (3 Jun 2015) +- RELEASE-PROCEDURE: refreshed 'coming dates' + +Jay Satiro (2 Jun 2015) +- curl_setup: Change fopen text macros to use 't' for MSDOS + + Bug: https://github.com/bagder/curl/pull/258#issuecomment-107915198 + Reported-by: Gisle Vanem -Daniel Stenberg (5 Jun 2010) -- [Frank Meier brought this change] +Daniel Stenberg (2 Jun 2015) +- curl_multi_timeout.3: added example - getinfo: added *_PRIMARY_PORT, *_LOCAL_IP and *_LOCAL_PORT +- curl_multi_perform.3: added example -- RELEASE-NOTES: add contributors not mentioned +- curl_multi_info_read.3: added example -Yang Tse (4 Jun 2010) -- Enable OpenLDAP support for cygwin builds. +- checksrc: detect fopen() for text without the FOPEN_* macros - Enable OpenLDAP support for cygwin builds. This support was disabled back - in 2008 due to incompatibilities between OpenSSL and OpenLDAP headers. - cygwin's OpenSSL 0.9.8l and OpenLDAP 2.3.43 versions on cygwin 1.5.25 - allow building an OpenLDAP enabled libcurl supporting back to Windows 95. + Follow-up to e8423f9ce150 with discussionis in + https://github.com/bagder/curl/pull/258 - Remove non-functional CURL_LDAP_HYBRID code and references. + This check scans for fopen() with a mode string without 'b' present, as + it may indicate that an FOPEN_* define should rather be used. -Kamil Dudka (2 Jun 2010) -- ftplistparser.c: oops, fix typo in the last commit +- curl_getdate.3: update RFC reference -- ftplistparser.c: avoid some invalid dereferences - -- lib: eliminate some dead code - -Daniel Stenberg (2 Jun 2010) -- SSH: corrected the inability to respect the timeout +Jay Satiro (1 Jun 2015) +- curl_setup: Add macros for FOPEN_READTEXT, FOPEN_WRITETEXT - Jason McDonald posted bug report #3006786 when he found that the - SFTP code didn't timeout properly in several places in the code - even if a timeout was set properly. + - Change fopen calls to use FOPEN_READTEXT instead of "r" or "rt" + - Change fopen calls to use FOPEN_WRITETEXT instead of "w" or "wt" - Based on his suggested patch, I wrote a different implementation - that I think addressed the issue better and also uses the connect - timeout for the initial part of the SSH/SFTP done during the - "protocol connect" phase. + This change is to explicitly specify when we need to read/write text. + Unfortunately 't' is not part of POSIX fopen so we can't specify it + directly. Instead we now have FOPEN_READTEXT, FOPEN_WRITETEXT. - (http://curl.haxx.se/bug/view.cgi?id=3006786) - -Yang Tse (2 Jun 2010) -- mention last changes - -- add missing new files to non-configure target build files - -- include libcurl standard internal headers - -Daniel Stenberg (2 Jun 2010) -- TODO: add multi interface improvement remove ldap select + Prior to this change we had an issue on Windows if an application that + uses libcurl overrides the default file mode to binary. The default file + mode in Windows is normally text mode (translation mode) and that's what + libcurl expects. + + Bug: https://github.com/bagder/curl/pull/258#issuecomment-107093055 + Reported-by: Orgad Shaneh -Yang Tse (2 Jun 2010) -- make setup.h first included file +Daniel Stenberg (1 Jun 2015) +- http2-upload.c: use PIPEWAIT for playing HTTP/2 better -- fix spnego memory leak +- http2-download: check for CURLPIPE_MULTIPLEX properly + + Bug: http://curl.haxx.se/mail/lib-2015-06/0001.html + Reported-by: Rafayel Mkrtchyan -- openldap header inclusions fix +- [Isaac Boukris brought this change] -Daniel Stenberg (1 Jun 2010) -- multi_socket: handles timer inaccuracy better for timeouts + HTTP-NTLM: fail auth on connection close instead of looping - Igor Novoseltsev reported a problem with the multi socket API and - using timeouts and timers. It boiled down to a problem with - libcurl's use of GetTickCount() interally to figure out the - current time, while Igor's own application code used another - function call. - - It made his app call the socket API timeout function a bit - _before_ libcurl would consider the timeout to trigger, and that - could easily lead to timeouts or stalls in the app. It seems - GetTickCount() in general often has no better resolution than - 16ms and switching to the alternative function - QueryPerformanceCounter has its share of problems: - http://www.virtualdub.org/blog/pivot/entry.php?id=106 - - We address this problem by simply having libcurl treat timers - that already has occured or will occur within 40ms subject for - treatment. I'm confident that there are other implementations and - operating systems with similarly in accurate timer functions so - it makes sense to have applied generically and I don't believe we - sacrifice much by adding a 40ms inaccuracy on these timeouts. + Bug: https://github.com/bagder/curl/issues/256 -Yang Tse (1 Jun 2010) -- fix ldaps option issue +- 5.6 Refuse "downgrade" redirects -- fix ldap related compilation issues +- README.pingpong: removed -- fix compiler warning: enumerated type mixed with another type +- ROADMAP: remove HTTP/2 multiplexing - its here now -- fix compiler warning: enumerated type mixed with another type +- HTTP2.md: formatted properly -Patrick Monnerat (31 May 2010) -- smtp_authenticate: avoid compiler warnings +- HTTP2: moved docs into docs/ and make it markdown -Yang Tse (31 May 2010) -- fix compiler warning: enumerated type mixed with another type +- README.http2: refreshed and added multiplexing info -- fix compiler warning: enumerated type mixed with another type +- dist: add the http2 examples -- fix compiler warning: enumerated type mixed with another type +- http2 examples: clean up some comments -- fix compiler warning: external declaration in primary source file +- examples: added two programs doing multiplexed HTTP/2 -- fix compiler warning: variable was set but never used +- scripts: moved contributors.sh and contrithanks.sh into subdir -- fix compiler warning: enumerated type mixed with another type +- RELEASE-NOTES: synced with c005790ff1c0a -- fix compiler warning: external declaration in primary source file +- [Daniel Melani brought this change] -- update year in copyright notice + openssl: typo in comment -Kamil Dudka (29 May 2010) -- strtoofft: rename CURL_LLONG_MIN -> CURL_OFF_T_MIN +Jay Satiro (27 May 2015) +- openssl: Use TLS_client_method for OpenSSL 1.1.0+ - ... and CURL_LLONG_MAX -> CURL_OFF_T_MAX - -- CURL_LLONG_MAX: avoid constant overflow + SSLv23_client_method is deprecated starting in OpenSSL 1.1.0. The + equivalent is TLS_client_method. - ... when (CURL_SIZEOF_CURL_OFF_T == 4) - -Daniel Stenberg (28 May 2010) -- [Howard Chu brought this change] + https://github.com/openssl/openssl/commit/13c9bb3#diff-708d3ae0f2c2973b272b811315381557 - LDAPS: list availability depending on SSL's presence +Daniel Stenberg (26 May 2015) +- FAQ: How do I port libcurl to my OS? -- [Howard Chu brought this change] - - LDAP: make it build without SSL if no such support is available - - of course it also goes for the case where SSL is explicitly - disabled - -- TODO: removed fixed items +Jay Satiro (25 May 2015) +- CURLOPT_COOKIELIST.3: Explain Set-Cookie without a domain - These two items are now actually implemented: + Document that if Set-Cookie is used without a domain then the cookie is + sent for any domain and will not be modified. - 11.1 Content-Disposition - 11.5 ftp wildcard download - -Kamil Dudka (28 May 2010) -- lib: eliminate 'statement not reached' warnings + Bug: http://curl.haxx.se/mail/lib-2015-05/0137.html + Reported-by: Alexander Dyagilev -Daniel Stenberg (28 May 2010) -- test1115: verify that unexpected 1xx responses work fine +Daniel Stenberg (25 May 2015) +- [Tatsuhiro Tsujikawa brought this change] -Kamil Dudka (28 May 2010) -- lib577: avoid redefinition of ERROR - -- test313: a new test for CRL support - -- tests/certs: re-generated because of lost pass-phrase - -- tests/certs/scripts: generate also CRL + http2: Copy data passed in Curl_http2_switched into HTTP/2 connection buffer - ... and make it possible to do so without any user interaction - -Daniel Stenberg (27 May 2010) -- [Howard Chu brought this change] - - openldap: fix compiler warnings - -- indent: some whitespace edits - -Kamil Dudka (27 May 2010) -- wildcard.c: add missing include of "setup.h" - -- [Tor Arntsen brought this change] + Previously, after seeing upgrade to HTTP/2, we feed data followed by + upgrade response headers directly to nghttp2_session_mem_recv() in + Curl_http2_switched(). But it turns out that passed buffer, mem, is + part of stream->mem, and callbacks called by + nghttp2_session_mem_recv() will write stream specific data into + stream->mem, overwriting input data. This will corrupt input, and + most likely frame length error is detected by nghttp2 library. The + fix is first copy the passed data to HTTP/2 connection buffer, + httpc->inbuf, and call nghttp2_session_mem_recv(). - lib573: do not compare double for exact match - -- [Pavel Raiskup brought this change] - - wildcard.c: add missing include of "curl_memory.h" - -- [Tor Arntsen brought this change] - - setup_once: use enum type for 'bool' on non-C99 platforms +Jay Satiro (24 May 2015) +- CURLOPT_COOKIE.3: Explain that the cookies won't be modified - An enum will catch non-bool assignments to bool on platforms with - a strict compiler, e.g MIPSPro. + The CURLOPT_COOKIE doc says it "sets the cookie header explicitly in the + outgoing request(s)." However there seems to be some user confusion + about cookie modification. Document that the cookies set by this option + are not modified by the cookie engine. - Signed-off-by: Kamil Dudka + Bug: http://curl.haxx.se/mail/lib-2015-05/0115.html + Reported-by: Alexander Dyagilev -- url.c: avoid implied cast to bool +- CURLOPT_COOKIELIST.3: Add example -- [Tor Arntsen brought this change] - - curl_fnmatch: remove use of register keyword +Dan Fandrich (24 May 2015) +- testcurl.pl: use rel2abs to make the source directory absolute - Using the 'register' keyword rarely improves anything with modern - compilers and architectures. - -Daniel Stenberg (26 May 2010) -- [Julien Chaffraix brought this change] + This function makes a platform-specific absolute path which uses + backslashes on Windows. This form works when passing it on the + command-line, as well as if the source is on another drive. - RTMP: Fix compiler warnings +- conncache: fixed memory leak on OOM (torture tests) -- [Julien Chaffraix brought this change] +Daniel Stenberg (24 May 2015) +- perl: remove subdir, not touched in 9 years - OOM fixes in http_negociate.c and lib/splay.c - - Fix 2 OOM errors: a missing NULL-check in lib/http_negociate.c - and a potential NULL dereferencing in lib/splay.c +- log2changes.pl: moved to scripts/ -- [Howard Chu brought this change] +- [Alessandro Ghedini brought this change] - LDAP: properly implemented as a curl_handler - - makes the LDAP code much cleaner, nicer and in general being a - better libcurl citizen. If a new enough OpenLDAP version is - detect, the new and shiny lib/openldap.c code is then used - instead of the old cruft - - Code by Howard, minor cleanups by Daniel. + scripts: add zsh.pl for generating zsh completion -- [Tor Arntsen brought this change] +Dan Fandrich (23 May 2015) +- test1510: another flaky test - curl_fnmatch: Use int not bool when function returns int +Daniel Stenberg (22 May 2015) +- security: fix "Unchecked return value" from sscanf() + + By (void) prefixing it and adding a comment. Did some minor related + cleanups. - bool in curl internals is unsigned char and should not be used - to receive return value from functions returning int - this fails - when using IBM VisualAge and Tru64 compilers. + Coverity CID 1299423. -- TFTP: send legal timeout value +- security: simplify choose_mech - Eric Mertens posted bug #3003705: when we made TFTP use the - correct timeout option when sent to the server (fixed May 18th - 2010) it became obvious that libcurl used invalid timeout values - (300 by default while the RFC allows nothing above 255). While of - course it is obvious that as TFTP has worked thus far without - being able to set timeout at all, just removing the setting - wouldn't make any difference in behavior. I decided to still keep - it (but fix the problem) as it now actually allows for easier - (future) customization of the timeout. + Coverity CID 1299424 identified dead code because of checks that could + never equal true (if the mechanism's name was NULL). - (http://curl.haxx.se/bug/view.cgi?id=3003705) + Simplified the function by removing a level of pointers and removing the + loop and array that weren't used. -- TFTP: don't ack if wrong block num is received +- RTSP: catch attempted unsupported requests better - If an unexpected block number was received, break out of the - switch loop. + Replace use of assert with code that properly catches bad input at + run-time even in non-debug builds. + + This flaw was sort of detected by Coverity CID 1299425 which claimed the + "case RTSPREQ_NONE" was dead code. -- TFTP: block id wrap bug fix +- share_init: fix OOM crash - In a normal expression, doing [unsigned short] + 1 will not wrap - at 16 bits so the comparisons and outputs were done wrong. I - added a macro do make sure it gets done right. + A failed calloc() would lead to NULL pointer use. - Douglas Kilpatrick filed bug report #3004787 about it: - http://curl.haxx.se/bug/view.cgi?id=3004787 - -- [Ben Greear brought this change] + Coverity CID 1299427. - Fix build warnings. +- parse_proxy: switch off tunneling if non-HTTP proxy - Signed-off-by: Ben Greear - -- [Ben Greear brought this change] - - setopt: Fix setting of set.is_fwrite_set + non-HTTP proxy implies not using CURLOPT_HTTPPROXYTUNNEL - Signed-off-by: Ben Greear + Bug: http://curl.haxx.se/mail/lib-2015-05/0056.html + Reported-by: Sean Boudreau -- [Tanguy Fautre brought this change] - - build: allow curl to build with Microsoft VC10 +- curl: fix potential NULL dereference - By undefing a bunch of E* defines that VC10 has started to define - but that we redefine internally to their WSA* alternatives when - building for Windows. - -Kamil Dudka (20 May 2010) -- [Tor Arntsen brought this change] + Coverity CID 1299428: Dereference after null check (FORWARD_NULL) - Test 573: Use correct type for CURLINFO_CONNECT_TIME +- http2: on_frame_recv: return early on stream 0 - curl_easy_getinfo() called with a pointer to long instead of double - would sigbus on RISC processors (e.g. MIPS) due to wrong alignment - of pointer address. + Coverity CID 1299426 warned about possible NULL dereference otherwise, + but that would only ever happen if we get invalid HTTP/2 data with + frames for stream 0. Avoid this risk by returning early when stream 0 is + used. -- [Tor Arntsen brought this change] - - lib: Fix AIX build failure - -Dan Fandrich (19 May 2010) -- Fixed some memory leaks in the POP3 torture tests - -- Fixed a memory leak in the SMTP torture tests - -Daniel Stenberg (18 May 2010) -- TFTP: send timeout option correctly +- http: removed self assignment - Eric Mertens posted bug report #3003005 pointing out that the - libcurl TFTP code was not sending the timeout option properly to - the server, and suggested a fix. + Follow-up fix from b0143a2a33f0 - (http://curl.haxx.se/bug/view.cgi?id=3003005) + Detected by coverity. CID 1299429 -Kamil Dudka (16 May 2010) -- [Tor Arntsen brought this change] +- [Tatsuhiro Tsujikawa brought this change] - lib: Change some CRLF line endings to LF + http2: Make HTTP Upgrade work - An update had added a couple of lines with DOS line endings, - and some compilers will choke on that (e.g. the Tru64 compiler). - -- ftp wildcard: a new option CURLOPT_FNMATCH_DATA - -Daniel Stenberg (15 May 2010) -- [Howard Chu brought this change] - - RMTP: the version code is now rtmp aware - -- [Howard Chu brought this change] + This commit just add implicitly opened stream 1 to streams hash. - RTMP: fix wrong #ifdef - -- [Pavel Raiskup brought this change] - - ftp wildcard: fix int32_t and size/group mixups - -Dan Fandrich (14 May 2010) -- Fixed test 577 to work when --enable-hidden-symbols is configured - -Daniel Stenberg (14 May 2010) -- OpenSSL: multi interface handshake could hang +Jay Satiro (22 May 2015) +- strerror: Change SEC_E_ILLEGAL_MESSAGE description - John-Mark Bell filed bug #3000052 that identified a problem (with - an associated patch) with the OpenSSL handshake state machine - when the multi interface is used: + Prior to this change the description for SEC_E_ILLEGAL_MESSAGE was OS + and language specific, and invariably translated to something not very + helpful like: "The message received was unexpected or badly formatted." - Performing an https request using a curl multi handle and using - select or epoll to wait for events results in a hang. It appears - that the cause is the fix for bug #2958179, which makes - ossl_connect_common unconditionally return from the step 2 loop - when fetching from a multi handle. - - When ossl_connect_step2 has completed, it updates - connssl->connecting_state to ssl_connect_3. ossl_connect_common - will then return to the caller, as a multi handle is in - use. Eventually, the client code will call curl_multi_fdset to - obtain an updated fdset to select or epoll on. For https - requests, curl_multi_fdset will cause https_getsock to be called. - https_getsock will only return a socket handle if the - connecting_state is ssl_connect_2_reading or - ssl_connect_2_writing. Therefore, the client will never obtain a - valid fdset, and thus not drive the multi handle, resulting in a - hang. - - (http://curl.haxx.se/bug/view.cgi?id=3000052) - -- changelog: add link to bug report - -Dan Fandrich (14 May 2010) -- Added directories.pm to the source tar ball + Bug: https://github.com/bagder/curl/issues/267 + Reported-by: Michael Osipov -Daniel Stenberg (14 May 2010) -- follow redirect: ignore response-body on redirect even if compressed +- telnet: Fix read-callback change for Windows builds - Sebastian V reported bug #3000056 identifying a problem with - redirect following. It showed that when curl followed redirects - it didn't properly ignore the response body of the 30X response - if that response was using compressed Content-Encoding! - - (http://curl.haxx.se/bug/view.cgi?id=3000056) - -- version: we're now going for 7.21.0 + Refer to b0143a2 for more information on the read-callback change. -- [Hoi-Ho Chan brought this change] +Daniel Stenberg (21 May 2015) +- CURLOPT_HTTPPROXYTUNNEL.3: only works with a HTTP proxy! - Remove support for BSD version of PolarSSL +Dan Fandrich (21 May 2015) +- testcurl.pl: allow source to be in an arbitrary directory - "The BSD version of PolarSSL was made for migratory purposes only and is not - maintained. The GPL version of PolarSSL is actually the only actively - developed version, so I would be very reluctant to use the BSD version." / - Paul Bakker, PolarSSL hacker. - - Signed-off-by: Hoi-Ho Chan + This way, the build directory can be located on an entirely different + filesystem from the source code (e.g. a tmpfs). -Dan Fandrich (12 May 2010) -- Added Polar SSL and RTMP files to the non-autoconf build files +Daniel Stenberg (20 May 2015) +- read_callback: move to SessionHandle from connectdata - I didn't bother with a few that have little hope of running the required - dependent libraries. - -- Added the new ftp source files to the non-autoconf build files - -- Copy the license file so it's seen by the Android build system - -Daniel Stenberg (13 May 2010) -- updated with symbols added in recent commits for 7.21.0 - -- changelogs: mention RTMP and the FTP wildcard support - -- ftp wildcards: mention they're added in 7.21.0 + With many easy handles using the same connection for multiplexing, it is + important we store and keep the transfer-oriented stuff in the + SessionHandle so that callbacks and callback data work fine even when + many easy handles share the same physical connection. -- style: minor whitespace change - -- syntax: cleanups - -- [Pavel Raiskup brought this change] - - FTP: WILDCARDMATCH/CHUNKING/FNMATCH added - -- [Howard Chu brought this change] - - RTMP: initial support added, powered by librtmp +- http2: show stream IDs in decimal - librtmp is found at http://rtmpdump.mplayerhq.hu/ + It makes them easier to match output from the nghttpd test server. -- [Howard Chu brought this change] +- [Tatsuhiro Tsujikawa brought this change] - sendrecv: make them two pairs of send/recv to properly deal with FTPS - - FTP(S) use two connections that can be set to different recv and - send functions independently, so by introducing recv+send pairs - in the same manner we already have sockets/connections we can - work with FTPS fine. + http2: Faster http2 upload - This commit fixes the FTPS regression introduced in change d64bd82. + Previously, when we send all given buffer in data_source_callback, we + return NGHTTP2_ERR_DEFERRED, and nghttp2 library removes this stream + temporarily for writing. This itself is good. If this is the sole + stream in the session, nghttp2_session_want_write() returns zero, + which means that libcurl does not check writeability of the underlying + socket. This leads to very slow upload, because it seems curl only + upload 16k something per 1 second. To fix this, if we still have data + to send, call nghttp2_session_resume_data after nghttp2_session_send. + This makes nghttp2_session_want_write() returns nonzero (if connection + window still opens), and as a result, socket writeability is checked, + and upload speed becomes normal. -Kamil Dudka (11 May 2010) -- changelog: fixed CRL support in libcurl-NSS +- [Dmitry Eremin-Solenikov brought this change] -- nss: make it possible to read ASCII and DER CRL - -- nss: add CRL to cache instead of read-only NSS db + gtls: don't fail on non-fatal alerts during handshake + + Stop curl from failing when non-fatal alert is received during + handshake. This e.g. fixes lots of problems when working with https + sites through proxies. -Daniel Stenberg (10 May 2010) -- git: how to write a fine commit message +- curl_easy_unescape.3: update RFC reference + + Reported-by: bsammon + Bug: https://github.com/bagder/curl/issues/282 -- findtool: file name as a full path requires a slash +Jay Satiro (20 May 2015) +- CURLOPT_POSTFIELDS.3: Mention curl_easy_escape - Kalle Vahlman's patch applied a while ago broke how the findtool - function searches for tools, as it would always check if "$file" - was present first, which thus made the bad assumption that a file - in the current directory would be a match. + .. also correct some variable naming in curl_easy_escape.3 - I noticed when it found 'libtool' in the current directory but - libtoolize is not there, which confused the script. + Bug: https://github.com/bagder/curl/issues/281 + Reported-by: bsammon@users.noreply.github.com -Hacki (8 May 2010) -- moved vars into conditional since seems that winsock implementation doesnt use them. +Daniel Stenberg (19 May 2015) +- [Brian Prodoehl brought this change] -Daniel Stenberg (7 May 2010) -- multi interface: missed storing connection time - - Dirk Manske reported a regression. When connecting with the multi - interface, there were situations where libcurl wouldn't store - connect time correctly as it used to (and is documented to) do. + openssl: Use SSL_CTX_set_msg_callback and SSL_CTX_set_msg_callback_arg - Using his fine sample program we could repeat it, and I wrote up - test case 573 using that code. The problem does not easily show - itself using the local test suite though. - - The fix, also as suggested by Dirk, is a bit on the ugly side as - it adds yet another call to Curl_verboseconnect() and setting the - TIMER_CONNECT time. That situation is subject for some closer - inspection in the future. - -- verboseconnect: so the verbose checking within the function + BoringSSL removed support for direct callers of SSL_CTX_callback_ctrl + and SSL_CTX_ctrl, so move to a way that should work on BoringSSL and + OpenSSL. - As the function is used more than once and libcurl can be built - without it, do the conditional check within the verboseconnect() - function itself. + re #275 -- changelogs: split the I/O handling +Jay Satiro (19 May 2015) +- curl.1: fix missing space in section --data -- [Howard Chu brought this change] +Daniel Stenberg (19 May 2015) +- transfer: remove erroneous and misleading comment - sendrecv: split the I/O handling into private handler +Kamil Dudka (19 May 2015) +- http: silence compile-time warnings without USE_NGHTTP2 - Howard Chu brought the bulk work of this patch that properly - moves out the sending and recving of data to the parts of the - code that are properly responsible for the various ways of doing - so. + Error: CLANG_WARNING: + lib/http.c:173:16: warning: Value stored to 'http' during its initialization is never read - Daniel Stenberg assisted with polishing a few bits and fixed some - minor flaws in the original patch. - - Another upside of this patch is that we now abuse CURLcodes less - with the "magic" -1 return codes and instead use CURLE_AGAIN more - consistently. - -- changelog: PolarSSL + Error: COMPILER_WARNING: + lib/http.c: scope_hint: In function ‘http_disconnect’ + lib/http.c:173:16: warning: unused variable ‘http’ [-Wunused-variable] -- [Hoi-Ho Chan brought this change] - - PolarSSL: initial support added +Jay Satiro (19 May 2015) +- transfer: Replace __func__ instances with function name - This is Hoi-Ho Chan's patch with some minor fixes by me. There - are some potential issues in this, but none worse than we can - sort out on the list and over time. - -- TODO: we've done PRET already, consider HOST for the future + .. also make __func__ replacement in multi. - ... and GnuTLS connects are non-blocking, TFTP is better - integrated as a "real" protocol and RTSP is supported. + Prior to this change debug builds would fail to build if the compiler + was building pre-c99 and didn't support __func__. -- TODO: GnuTLS connects are now non-blocking - - Since commit c288860 by Jerome Vouillon +Daniel Stenberg (19 May 2015) +- [Viktor Szakats brought this change] -- INTERNALS: tftp is decent now, ldap is not - - It's not quite fair to list TFTP is a "crappy" member of the - libcurl family so I removed its mentioning. + build: bump version in default nghttp2 paths -- changelog: mention Ben Greear's telnet work +- INTERNALS: we require nghttp2 1.0.0+ now -- [Ben Greear brought this change] +Jay Satiro (18 May 2015) +- http: Add some include guards for the new HTTP/2 stuff - telnet: Allow programatic use of telnet. - - The main change is to allow input from user-specified methods, - when they are specified with CURLOPT_READFUNCTION. - All calls to fflush(stdout) in telnet.c were removed, which makes - using 'curl telnet://foo.com' painful since prompts and other data - are not always returned to the user promptly. Use - 'curl --no-buffer telnet://foo.com' instead. In general, - the user should have their CURLOPT_WRITEFUNCTION do a fflush - for interactive use. - - Also fix assumption that reading from stdin never returns < 0. - Old code could crash in that case. +Daniel Stenberg (18 May 2015) +- http2: store upload state per stream - Call progress functions in telnet main loop. - - Signed-off-by: Ben Greear - -- test: enable valgrind for 604, seems to work + Use a curl_off_t for upload left -Kamil Dudka (28 Apr 2010) -- [Paul Howarth brought this change] +- http2: fix build when NOT h2-enabled - add 1s post-command delay to tests 513 and 514 +- http2: switch to use Curl_hash_destroy() - addressing http://curl.haxx.se/mail/lib-2009-12/0031.html + as after 4883f7019d3, the *_clean() function only flushes the hash. -Daniel Stenberg (26 Apr 2010) -- [Kalle Vahlman brought this change] - - Allow tools to be defined with full path in buildconf +- curlver: restore LIBCURL_VERSION_NUM defined as a full number - This is required in Scratchbox where - LIBTOOL=/targets/links/arch_tools/bin/libtool - is set in the environment. + As it breaks configure, curl-config and test 1023 if not. -- progress callback: can be called more than once per sec +- [Anthony Avina brought this change] -- SSH: init and cleanup libssh2 in global_init/cleanup + hostip: fix unintended destruction of hash table - The necessary libssh2 functions require libssh2 1.2.5 or later. - -- new configure option --enable-threaded-resolver + .. and added unit1602 for hash.c -- configure: check for libssh2_init and libssh2_exit +- curlver: introducing new version number (checking) macros -Kamil Dudka (24 Apr 2010) -- nss: fix SSL handshake timeout underflow +- runtests.pl: use 'h2c' now, no -14 anymore -Guenter Knauf (24 Apr 2010) -- encourage users to take latest lib dependencies. +- [Tatsuhiro Tsujikawa brought this change] -Daniel Stenberg (24 Apr 2010) -- socks5: please static code analyzer + http2: Ignore if we have stream ID not in hash in on_stream_close - Make sure we don't call memcpy() if the argument is NULL even - though we also passed a zero length then, as the clang analyzer - whined and we want to limit warnings (even false positives) when - they're this easy to fix. - - The change of (char) to (unsigned char) will fix long user names - and passwords on systems that have the char type signed by - default. - -- gzip: Value stored to 'data' is never read - -- RELEASE-NOTES: update top numbers - -- changelog: added the --proto and -proto-redir options + We could get stream ID not in the hash in on_stream_close. For + example, if we decided to reject stream (e.g., PUSH_PROMISE), then we + don't create stream and store it in hash with its stream ID. -- [Alex Bligh brought this change] +- [Tatsuhiro Tsujikawa brought this change] - curl: added --proto and --proto-redir + Require nghttp2 v1.0.0 - --proto tells curl to use the listed protocols for its initial - retrieval + This commit requires nghttp2 v1.0.0 to compile, and migrate to v1.0.0, + and utilize recent version of nghttp2 to simplify the code, - --proto-redir tells curl to use the listed protocols after a - redirect - -Kamil Dudka (24 Apr 2010) -- test536: do not fail with threaded DNS resolver + First we use nghttp2_option_set_no_recv_client_magic function to + detect nghttp2 v1.0.0. That function only exists since v1.0.0. - Also tweaked comments in certain examples using curl_multi_fdset(). - -Daniel Stenberg (21 Apr 2010) -- curl: -O crash on windows + Since nghttp2 v0.7.5, nghttp2 ensures header field ordering, and + validates received header field. If it found error, RST_STREAM with + PROTOCOL_ERROR is issued. Since we require v1.0.0, we can utilize + this feature to simplify libcurl code. This commit does this. - The -O option caused curl to crash on windows and DOS due to the - tool writing out of boundary memory. + Migration from 0.7 series are done based on nghttp2 migration + document. For libcurl, we removed the code sending first 24 bytes + client magic. It is now done by nghttp2 library. + on_invalid_frame_recv callback signature changed, and is updated + accordingly. -Yang Tse (20 Apr 2010) -- hmac.c related compilation adjustment +- http2: infof length in on_frame_send() -- hmac.c related compilation adjustment - -monnerat (20 Apr 2010) -- Add compilation directives for hmac in Watcom,riscos and vc6 platform-specific makefiles. +- pipeline: switch some code over to functions + + ... to "compartmentalize" a bit and make it easier to change behavior + when multiplexing is used instead of good old pipelining. -Yang Tse (20 Apr 2010) -- [Ruslan Gazizov brought this change] +- symbols-in-versions: add CURLOPT_PIPEWAIT - replaced wsock32.lib usage with ws2_32.lib in MSVC makefiles +- CURLOPT_PIPEWAIT: added + + By setting this option to 1 libcurl will wait for a connection to reveal + if it is possible to pipeline/multiplex on before it continues. -monnerat (19 Apr 2010) -- Merge branch 'master' of github.com:bagder/curl +- Curl_http_readwrite_headers: minor code simplification -- Remove null-effect leftover code. +- IsPipeliningPossible: fixed for http2 -Daniel Stenberg (19 Apr 2010) -- changelog: -J/--remote-header-name strips CRLF +- http2: bump the h2 buffer size to 32K for speed -- parse_filename: strip trailing CRs and LFs +- http2: remove the stream from the hash in stream_close callback - The feature that uses the file name given in a - Content-disposition: header didn't properly skip trailing - carriage returns and linefeed characters from the end of the file - name when it was given without quotes. - -- Curl_HMAC_MD5: fix the array init to not warn with picky compilers + ... and suddenly things work much better! -monnerat (19 Apr 2010) -- Fix GnuTLS compilation problem in md5.c +- http2: if there is paused data, do not clear the drain field -- Fix compilation problem: declare Curl_HMAC_MD5 as extern in include file. +- http2: rename s/data/pausedata -- Merge branch 'master' of github.com:bagder/curl +- http2: "stream %x" in all outputs to make it easier to search for -- Implement SMTP authentication - -Daniel Stenberg (17 Apr 2010) -- parseconfig: Value stored to 'line' is never read +- http2: Curl_expire() all handles with incoming traffic - Make the function call with (void) as we don't care about the - return code. - -- parsedate: Value stored to 'found' is never read + ... so that they'll get handled next in the multi loop. -- check_gzip_header: Value stored to 'data' is never read +- http2: don't signal settings change for same values -- dprintf_formatf: Value stored to 'left' is never read +- http2: set default concurrency, fix ConnectionExists for multiplex -- curl_version: remove superfluous assignments - -- FTP PORT: Value stored to 'rc' is never read +- bundles: store no/default/pipeline/multiplex + + to allow code to act differently on the situation. + + Also added some more info message for the connection re-use function to + make it clearer when connections are not re-used. -- Curl_setup_transfer: no longer returns anything +- http2: lazy init header_recvbuf - This function could only return CURLE_OK and by changing it to - a void instead, we can simplify code all over. + It makes us use less memory when not doing HTTP/2 and subsequently also + makes us not have to cleanup HTTP/2 related data when not using HTTP/2! -- PASV response: Value stored to 'rc' is never read +- http2: separate multiplex/pipelining + cleanup memory leaks -- Curl_perform: Value stored to 'res2' is never read +- CURLMOPT_PIPELINE: bit 1 is for multiplexing -- sftp range: remove unnecessary check for NULL pointer +- [Tatsuhiro Tsujikawa brought this change] -- ftp_range: remove unnecessary check for NULL pointer + http2: Fix bug that data to be drained are overwritten by pending "paused" data -- file_range: remove unnecessary check for NULL pointer +- [Tatsuhiro Tsujikawa brought this change] -- SOCKS4: Value stored to 'rc' is never read + http2: Don't call nghttp2_session_mem_recv while it is paused by a stream -- FTP PASV: Value stored to 'rc' is never read +- [Tatsuhiro Tsujikawa brought this change] -- ftp_range: Value stored to 'totalsize' is never read + http2: Read data left in connection buffer after pause - Simplified the code by removing a local variable completely. + Previously when we do pause because of out of buffer, we just throw + away unread data in connection buffer. This just broke protocol + framing, and I saw occasional FRAME_SIZE_ERROR. This commit fix this + issue by remembering how much data read, and in the next iteration, we + process remaining data. -- SOCKS5: when name resolves fail return immediately - - This makes the code flow more obvious and reacts on the return - code properly, even if the code acted the same way before. +- [Tatsuhiro Tsujikawa brought this change] -- POP3: when USER command fails, don't even try PASS + http2: Fix streams get stuck + + This commit fixes the bug that streams get stuck if stream gets some + DATA, and stream->closed becomes true at the same time. Previously, + in this condition, after we processed DATA, we are going to try to + read data from underlying transport, but there is no data, and gets + EAGAIN. There was no code path to evaludate stream->closed. -- tftp_rx: Value stored to 'sbytes' is never read +- http2: store incoming h2 SETTINGS -- file_range: Value stored to 'totalsize' is never read +- pipeline: move function to pipeline.c and make static + + ... as it was only used from there. -- changelog: GnuTLS: SSL handshake phase is non-blocking +- IsPipeliningPossible: http2 can always "pipeline" (multiplex) -- [Jerome Vouillon brought this change] +- http2: remove debug logging from on_frame_recv - GnuTLS: make the connection phase non-blocking +- http2: remove the closed check in http2_recv - When multi interface is used, the SSL handshake is no longer - blocking when GnuTLS is used. - -- krb5_auth: fix my previous change to compile - -unknown (16 Apr 2010) -- OS400 version V5R2M0 not supported anymore by IBM: default target release changed to V5R3M0. + With the "drained" functionality we can get here slightly asynchronously + so the stream have have been closed but there is pending data left to + read. -Daniel Stenberg (16 Apr 2010) -- changelog: GnuTLS fix, no reverse loopkups and fixed GSS detection +- http2: bump the h2 buffer to 8K -- SSL_RECV: EOF is not an error here +- http2: Curl_read should not use the single buffer - The recent overhaul of the SSL recv function made this treat a - zero returned from gnutls_record_recv() as an error, and this - caused our HTTPS test cases to fail. We leave it to upper layer - code to detect if an EOF is a problem or not. + ... as it does for pipelining when we're multiplexing, as we need the + different buffers to store incoming data correctly for all streams. -- [Paul Howarth brought this change] +- http2: more debug outputs - configure: GSSAPI detection on ancient Linux distros +- http2: leave WAITPERFORM when conn is multiplexed - On some ancient distributions such as RHEL-3, needs - to be processed after , but does not include it itself. - This patch checks for first and then includes it - in the test for , resolving the problem. - - Without the patch, is "present but cannot be - compiled". + No need to wait for our "spot" like for pipelining -- resolvers: no more using AI_CANONNAME +- http2: force "drainage" of streams - No resolver anymore needs to use AI_CANONNAME and do reverse - lookups. We should work hard to avoid having code that relies on - it. + ... which is necessary since the socket won't be readable but there is + data waiting in the buffer. -- KRB5: use given host name instead of reverse lookup'ed name - - This code would previously use dns_entry->addr->ai_canonname - instead of the given host name, which caused us grief and - problems since not all our resolver options do the reverse lookup - and I would also guess that it caused problems with KRB5/GSS with - virtual name-based hosts. Now the host name from the URL is used. +- http2: move the mem+len pair to the stream struct -Dan Fandrich (15 Apr 2010) -- Remove redundant conditional +- http2: more stream-oriented data, stream ID 0 is for connections -- Eliminated an unlikely race condition in some tests. +- http2: move lots of state data to the 'stream' struct - Based on a patch from the FreeBSD ports by Peter Pentchev. - -Daniel Stenberg (15 Apr 2010) -- changelog: prevent needless reverse name lookups - -- Curl_ipv4_resolve_r: only set AI_CANONNAME when needed + ... from the connection struct. The stream one being the 'struct HTTP' + which is kept in the SessionHandle struct (easy handle). - As reported in bug report #2987196, the code for ipv6 already did - the setting of this bit correctly so we copied that logic into - the Curl_ipv4_resolve_r() function as well. KRB code is the only - code we know that might need the cannonical name so only resolve - it for such requests! - -- IGNORE: files generated by maketgz - -- bumped to start the journey towards 7.20.2 - -- added contributors from the 7.20.1 RELEASE-NOTES - -- ignore files generated by 'maketgz' - -Version 7.20.1 (14 Apr 2010) - -Daniel Stenberg (14 Apr 2010) -- 7.20.1: 14 April 2010 - -Guenter Knauf (13 Apr 2010) -- Use correct directory for c-ares git pull - Signed-off-by: Tor Arntsen - -Yang Tse (13 Apr 2010) -- fix compiler warning: variable might be clobbered by longjmp or vfork + lookup streams for incoming frames in the stream hash, hashing is based + on the stream id and we get the SessionHandle for the incoming stream + that way. -Guenter Knauf (13 Apr 2010) -- added last git commit output for c-ares too. +- HTTP: partial start at fixing up hash-lookups on http2 frame receival -- changed the git update block to take care of c-ares repo if detected. +- http: a stream hash for h2 multiplexing -- updated timestamp of the script. +- http: a stream hash for h2 multiplexing -- removed obsolete var in gitpull() function - no need to create a var - lets just return the status var itself. +- http2: debug log when receiving unexpected stream_id -- added a cast to silent compiler warning with 64bit systems. +- http2: move stream_id to the HTTP struct (per-stream) -- fixed a path typo in src/Makefile.netware. - -Daniel Stenberg (12 Apr 2010) -- Added text for How To Make a Patch with git - -- update the section on timeouts +- Curl_http2_setup: only do it once and enable multiplex on the server - The section that describes how to work with timeouts was - misleading and could easily trick users to use the wrong API. + Once we know we are HTTP/2 enabled we know the server can multiplex. -- update URL and cut out wrong info on ipv6 +- http: switch on "pipelining" (multiplexing) for HTTP/2 servers - c-ares has had its own URL for a while and we should point - people to that. It also works with IPv6 since a long time. + ... and do not blacklist any. -- refer to CURLMOPT_TIMERFUNCTION for multi_socket users +- README.pipelining: removed - curl_multi_timeout(3) is simply the wrong function to use - if you're using the multi_socket API and this document now - states this pretty clearly to help guiding users. + All the details mentioned here are better documented in man pages -- s/CVS/git - -- modified to use the git file, not cvs +Dan Fandrich (14 May 2015) +- build: removed bundles.c from make files - I've done this blindly, and the last piece that works with ares - should possibly be done differently now that c-ares isn't a - subtree within the curl tree anymore... + This file was removed in commit fd137786 -- mention missing test servers for +Daniel Stenberg (14 May 2015) +- Curl_conncache_add_conn: fix memory leak on OOM -- FTP quote commands prefixed with '*' now can fail without aborting - - Prefixing the FTP quote commands with an asterisk really only - worked for the postquote actions. This is now fixed and test case - 227 has been extended to verify. +- CURLMOPT_MAX_HOST_CONNECTIONS: host = host name + port number -Kamil Dudka (7 Apr 2010) -- qssl: reflect recent code changes in SSL interface +- conncache: keep bundles on host+port bases, not only host names - Reported by Guenter Knauf. + Previously we counted all connections to a specific host name and that + would be used for the CURLMOPT_MAX_HOST_CONNECTIONS check for example, + while servers on different port numbers are normally considered + different "origins" on the web and should thus be considered different + hosts. -- nss: handle client certificate related errors - -- [Ben Greear brought this change] - - ssl: Fix build when SSL isn't enabled +- bundles: merged into conncache.c - Signed-off-by: Ben Greear - -- refactorize interface of Curl_ssl_recv/Curl_ssl_send - -- simplify code of Curl_resolv_timeout() + All the existing Curl_bundle* functions were only ever used from within + the conncache.c file, so I moved them over and made them static (and + removed the Curl_ prefix). -- eliminate a race condition in Curl_resolv_timeout() - -Daniel Stenberg (2 Apr 2010) -- [Ben Greear brought this change] - - fixed compiler warnings - -- updated contributor count - -- add contributors from the 7.20.0 release notes +- hostcache: made all host caches use structs, not pointers + + This avoids unnecessary dynamic allocs and as this also removed the last + users of *hash_alloc() and *hash_destroy(), those two functions are now + removed. -- fix SFTP download hang +- multi: converted socket hash into non-allocated struct - Matt Wixson found and fixed a bug in the SCP/SFTP area where the - code treated a 0 return code from libssh2 to be the same as - EAGAIN while in reality it isn't. The problem caused a hang in - SFTP transfers from a MessageWay server. + avoids extra dynamic allocation -Dan Fandrich (31 Mar 2010) -- Fixed misleading test message +- connection cache: avoid Curl_hash_alloc() + + ... by using plain structs instead of pointers for the connection cache, + we can avoid several dynamic allocations that weren't necessary. -Daniel Stenberg (31 Mar 2010) -- update the generic copyright year range +- proxy: add newline to info message -- removed README.cmake due to the improved situation +Patrick Monnerat (8 May 2015) +- FTP: fix dangling conn->ip_addr dereference on verbose EPSV. -Guenter Knauf (31 Mar 2010) -- fix compiler warning with a cast. +- FTP: Make EPSV use the control IP address rather than the original host. + This ensures an alternate address is not used. + Does not apply to proxy tunnel. -- make folks use latest available dependent libraries. +Daniel Stenberg (8 May 2015) +- [Alessandro Ghedini brought this change] -Dan Fandrich (30 Mar 2010) -- Call curl_global_cleanup() in test 560 to avoid a memory leak + tool_help: fix formatting for --next option -- Allow test 538 to run even when proxy support is disabled +- [Egon Eckert brought this change] -Daniel Stenberg (29 Mar 2010) -- use (s)size_t for string lengths to fix compiler warns + opts: improved the TCP keepalive examples -- use size_t to hold string length +Jay Satiro (8 May 2015) +- winbuild: Document the option used to statically link the CRT - using int is not fine on 64bit systems + - Document option RTLIBCFG (runtime library configuration). + + Bug: https://github.com/bagder/curl/issues/254 + Reported-by: Bert Huijben -- [Ben Greear brought this change] +- [Orgad Shaneh brought this change] - Fix compile warnings in ssh.c + netrc: Read in text mode when cygwin - strlen() returns size_t, but ssh libraries are wanting 'unsigned int'. Add - explicit casts and use _ex versions of the ssh library calls. + Use text mode when cygwin to eliminate trailing carriage returns. - Signed-off-by: Ben Greear + Bug: https://github.com/bagder/curl/pull/258 -- [Ben Greear brought this change] +Patrick Monnerat (5 May 2015) +- OS400: Add SPNEGO service name options to ILE/RPG binding. - fix smtp compile warning +Daniel Stenberg (4 May 2015) +- curl_multi_info_read.3: fix typo - Use ssize_t instead of int for the Curl_smtp_escape_eob nread - argument. + Reported-by: Liviu Chircu + +- MANUAL: language fix - Signed-off-by: Ben Greear + Reported-by: Fred Stluka + Bug: https://github.com/bagder/curl/issues/255 -- Ben's POP3 change +- [Alessandro Ghedini brought this change] -- [Ben Greear brought this change] + gtls: properly retrieve certificate status + + Also print the revocation reason if appropriate. - pop3: Get message listing if no mailbox in URL +- OpenSSL: conditional check for SSL3_RT_HEADER - If you pass a URL to pop3 that does not contain a message ID as - part of the URL, it will currently ask for 'INBOX' which just - causes the pop3 server to return an error. + The symbol is fairly new. - The change makes libcurl treat en empty message ID as a request - for LIST (list of pop3 message IDs). User's code could then - parse this and download individual messages as desired. - -- [Ben Greear brought this change] + Reported-by: Kamil Dudka - Allow running ./tests/testcurl.pl from within git repo. +- openssl: skip trace outputs for ssl_ver == 0 - My first instinct was to run the test script within the checked out - repository. This small change to the script allows that to work as - expected. + The OpenSSL trace callback is wonderfully undocumented but given a + journey in the source code, it seems the cases were ssl_ver is zero + doesn't follow the same pattern and thus turned out confusing and + misleading. For now, we skip doing any CURLINFO_TEXT logging on those + but keep sending them as CURLINFO_SSL_DATA_OUT/IN. - Signed-off-by: Ben Greear - -- minor language fix - -- [Ben Greear brought this change] - - allow user+password in the URL for all protocols + Also, I added direction to the text info and I edited some functions + slightly. - Ben Greear brought a patch that from now on allows all protocols - to specify name and user within the URL, in the same manner HTTP - and FTP have been allowed to in the past - although far from all - of the libcurl supported protocols actually have that feature in - their URL definition spec. + Bug: https://github.com/bagder/curl/issues/219 + Reported-by: Jay Satiro, Ashish Shukla -- ignore pid files and stunnel.conf - - all used while running tests +Marc Hoersken (2 May 2015) +- schannel.c: Small changes -- make sure git pull is actually done! +- schannel.c: Improve code path and readability -- changelogged: smoother rate limiting +- schannel.c: Improve error and return code handling upon aa99a63f03 -- [Ben Greear brought this change] +- [Chris Araman brought this change] - Make rate-limitation logic smoother + schannel: fix regression in schannel_recv - This gives a smoother rate limitation performance by using - sub-second pauses and also taking the buffer sizes into - account. - -- remove all .cvsignore files - -- PROT_CLOSEACTION should not include TFTP + https://github.com/bagder/curl/issues/244 - TFTP is not a protocol that uses close actions so it should - not be set in that bitmask! + Commit 145c263 changed the behavior when Curl_read_plain returns + CURLE_AGAIN. We now handle CURLE_AGAIN and SEC_I_CONTEXT_EXPIRED + correctly. -- [Tor Arntsen brought this change] - - Avoid double newline for the 'last commits' log in testcurl.pl +- Bug born in changes made several days ago 9a91e80. - The backtick command which extracts 'git log' lines come with a - newline, so chomp the newline before calling logit(), as the logit - function adds a newline by itself. + Commit: https://github.com/bagder/curl/commit/926cb9f + Reported-by: Ray Satiro -- [Tor Arntsen brought this change] +Daniel Stenberg (30 Apr 2015) +- [Michael Osipov brought this change] - Change to version-independent git option for 'git log --oneline' + configure: remove missing and make it autogenerate - 'git log --oneline' is a relatively recent Git function. It is - documented to be the same as 'git log --pretty=oneline --abbrev-commit', - so use that instead. It works all the way back to Git 1.5.0. + The missing file has not been autogenerated because a temporary fix was + employed in acinclude.m4 which blocked update. Removed that fix and a recent + version of missing is copied to build root. -- show 5 commits even if no git pull was made +- [Michael Osipov brought this change] -- don't touch ares/aclocal.m4 and show recent git commits - - since c-ares no longer embedded, we must not touch such files - anymore + acinclude.m4: fix test for default CA cert bundle/path - we show the 5 last git commits if git was proven in use, to help - us see exactly what's being tested + test(1) on HP-UX requires a single equals sign and fails with two. + Let's use one and make every OS happy. -- use CURL_SIZEOF_LONG instead of SIZEOF_LONG +- CONTRIBUTING.md: remove the sourceforge mention - That's the symbol we have or generate in include/curl/curlbuild.h + Reported-By: Michael Osipov -- s/CVS/DEV in the version string from the git repo +Dan Fandrich (30 Apr 2015) +- http_negotiate_sspi: added missing data variable -Bill Hoffman (24 Mar 2010) -- Merge branch 'master' of github.com:bagder/curl +Daniel Stenberg (30 Apr 2015) +- [Michael Osipov brought this change] -- Add .gitattributes files to turn off CRLF translation for some files - -Daniel Stenberg (24 Mar 2010) -- provide a version number as today's date + configure: remove --automake from libtoolize call - It should at least help visualize which autobuilds that are - using this script. - -- testcurl now uses git instead of CVS - -Bill Hoffman (24 Mar 2010) -- Merge branch 'master' of github.com:bagder/curl - -- Enable LDAP by default since it is now disabled when ldap.h is not found, - -- CMake fixes for Linux. + That option is not mentioned in the man page of libtoolize 2.4.4.19-fda4. + Moveover, a comment in line 2623 says "--automake is for 1.5 compatibility". - Make sure is included if around when testing/using - socklen_t. Also, disable LDAP if LDAP_H is not found on the system. + This option is redundant now. -Daniel Stenberg (24 Mar 2010) -- [Bob Richmond brought this change] +- [Viktor Szakats brought this change] - fix: timeout after last data chunk was handled - - Bob Richmond: There's an annoying situation where libcurl will - read new HTTP response data from a socket, then check if it's a - timeout if one is set. If the last packet received constitutes - the end of the response body, libcurl still treats it as a - timeout condition and reports a message like: + build: update depedency versions, urls, example makefiles - "Operation timed out after 3000 milliseconds with 876 out of 876 - bytes received" - - It should only a timeout if the timer lapsed and we DIDN'T - receive the end of the response body yet. + - update default versions of dependencies (except for rare/old platforms) + - update urls + - sync examples makefiles with main ones + - remove line ending space -- avoid compiler warning without USE_ALARM_TIMEOUT +- [Michael Osipov brought this change] -Bill Hoffman (24 Mar 2010) -- Fix curl CMake build. + configure: remove autogenerated files by autoconf - This commit fixes the cmake build of curl, and cleans up the - cmake code a little. It removes some commented out code and - some trailing whitespace. To get curl to build the binary - tree include/curl directory needed to be added to the include - path. Also, SIZEOF_SHORT needed to be added. A check for the - lack of defines of SIZEOF_* for warnless.c was added. + * install-sh is always regenerated + * mkinstalldirs was already redudant years ago. Automake uses install for + that. See: http://lists.gnu.org/archive/html/automake/2007-03/msg00015.html -Daniel Stenberg (24 Mar 2010) -- [Chris Conroy brought this change] +- [Anders Bakken brought this change] - remove debug printfs + curl_multi_add_handle: next is already NULL -- RTSP GET_PARAMETER fix +Jay Satiro (30 Apr 2015) +- schannel: Fix out of bounds array - Christopher Conroy fixed a problem with RTSP and GET_PARAMETER - reported to us by Massimo Callegari. There's a new test case 572 - that verifies this now. - -- remove trace of CVS - -- [Chris Conroy brought this change] - - Fix RTSP GET_PARAMETER empty and non-empty operation. + Bug born in changes made several days ago 9a91e80. - Test coverage included. Thanks to Massimo Callegari for the bug report + Bug: http://curl.haxx.se/mail/lib-2015-04/0199.html + Reported-by: Brian Chrisman -- s/CVS/DEV/ in the version string for repo versions - -- scrapped all left-over TODOs - - In order to get back on track, I've removed all the plans for - stuff I had in the queue. I will instead focus on fixing bugs and - relying on that people who truly want things added will come back - on the mailing list and nag and provide patches. +- docs/libcurl: gitignore libcurl-symbols.3 - 7.20.1 should be possible to release in April 2010 - -- restore executable bits on some files - -- remove the CVSish $Id$ lines + Bug: http://curl.haxx.se/mail/lib-2015-04/0191.html + Reported-by: Michael Osipov -- The 'ares' subtree has been removed from the source repository +- [Viktor Szakats brought this change] -- s/CVS/git - -- update to current state - -- remove the ares subtree - - c-ares is now hosted entirely separate from the curl project - see http://c-ares.haxx.se/ for all details concerning c-ares, - its source repository and more. - -- mark connection as connected + lib/makefile.m32: add arch -m32/-m64 to LDFLAGS - Kenny To filed the bug report #2963679 with patch to fix a - problem he experienced with doing multi interface HTTP POST over - a proxy using PROXYTUNNEL. He found a case where it would connect - fine but bits.tcpconnect was not set correct so libcurl didn't - work properly. - - (http://curl.haxx.se/bug/view.cgi?id=2963679) + This fixes using a multi-target mingw distro to build curl .dll for the + non-default target. + (mirroring the same patch present in src/makefile.m32) -- enabled valgrind +Daniel Stenberg (29 Apr 2015) +- RELEASE-NOTES: synced with cd39b944afc - I ran it now successfully and it helped to pinpoint a libssh2 - memory leak! - -Dan Fandrich (23 Mar 2010) -- Updated Symbian notes + I've not mentioned the bug fixes that were shipped in 7.42.1 from the + 7_42 branch. -Daniel Stenberg (23 Mar 2010) -- chunked-encoding with Content-Length: header problem - - Akos Pasztory filed debian bug report #572276 - http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=572276 - mentioning a problem with a resource that returns chunked-encoded - _and_ with a Content-Length and libcurl failed to properly ignore - the latter information. +- THANKS: merged from the 7.42.1 release -- delayed easy handle kill caused double Curl_close() call +- CURLOPT_HEADEROPT: default to separate - Hauke Duden provided an example program that made the multi - interface crash. His example simply used the multi interface and - did first one FTP transfer and after completion it used a second - easy handle and did another FTP transfer on the same FTP server. + Make the HTTP headers separated by default for improved security and + reduced risk for information leakage. - This triggered a bug in the "delayed easy handle kill" system - that curl uses: when an FTP connection is left alive it must keep - an easy handle around internally - only for the purpose of having - an easy handle when it later disconnects it. The code assumed - that when the easy handle was removed and an internal reference - was made, that version could be killed later on when a new easy - handle came using the same connection. This was wrong as Hauke's - example showed that the removed handle wasn't killed for real - until later. This caused a double close attempt => segfault. - -- ignore more files generated when tests run in the source tree - -- Thomas Lopatic fixed the alarm()-based DNS timeout - -- [Thomas Lopatic brought this change] - - fix the alarm()-based DNS timeout - - Looking at the code of Curl_resolv_timeout() in hostip.c, I think - that in case of a timeout, the signal handler for SIGALRM never - gets removed. I think that in my case it gets executed at some - point later on when execution has long left Curl_resolv_timeout() - or even the cURL library. - - The code that is jumped to with siglongjmp() simply sets the - error message to "name lookup timed out" and then returns with - CURLRESOLV_ERROR. I guess that instead of simply returning - without cleaning up, the code should have a goto that jumps to - the spot right after the call to Curl_resolv(). - -- [Daniel Johnson brought this change] - - Fix warnings for clang - -- Merge branch 'master' of github.com:bagder/curl - -Kamil Dudka (22 Mar 2010) -- [douglas steinwand brought this change] - - Fix insufficient initialization in Curl_clone_ssl_config() - - which could have caused a double free when reusing curl handle. - -Daniel Stenberg (22 Mar 2010) -- we never used this file anyway - -- s/CVS/git - -- various changes of CVS to git - -- remove references to CVS in the code and use DEV instead - -- Ben Greear's two fixes explained - -- [Ben Greear brought this change] - - Fix tftp return codes and tsize upload handling - - Error codes were not properly returned to the main curl code (and on to apps - using libcurl). - - tftp was crapping out when tsize == 0 on upload, but I see no reason to fail - to upload just because the remote file is zero-length. Ignore tsize option on - upload. - -- more files to ignore - -- provide an initial set of .gitignore files - -Kamil Dudka (19 Mar 2010) -- - Improved Curl_read() to not ignore the error returned from Curl_ssl_recv(). - -Daniel Stenberg (18 Mar 2010) -- fix warning about conversions between curl_off_t and long - -Yang Tse (18 Mar 2010) -- another shot at the ftp_init() icc 9.1 optimizer issue - -- replaced intel compiler option -no-ansi-alias with -fno-strict-aliasing - -- update outdated serial number - -Dan Fandrich (16 Mar 2010) -- Factored out some code into a few independent functions - -Daniel Stenberg (15 Mar 2010) -- - Constantine Sapuntzakis brought a patch: - - The problem mentioned on Dec 10 2009 - (http://curl.haxx.se/bug/view.cgi?id=2905220) was only partially fixed. - Partially because an easy handle can be associated with many connections in - the cache (e.g. if there is a redirect during the lifetime of the easy - handle). The previous patch only cleaned up the first one. The new fix now - removes the easy handle from all connections, not just the first one. - -Yang Tse (11 Mar 2010) -- fix compiler warning - -Dan Fandrich (11 Mar 2010) -- SSL should now be working out-of-the-box on Symbian S60. - -- Enable Symbian zlib support by default. - -- Allow compilation even when OpenSSL has been configured without MD4 support. - -- A few Symbian build changes - -Yang Tse (9 Mar 2010) -- watt32 compilation fix - -Daniel Stenberg (6 Mar 2010) -- - Ben Greear brought a patch that fixed the rate limiting logic for TFTP when - the easy interface was used. - -- indent fix by Ben Greear, I removed some braces for single-line conditional - expressions - -Yang Tse (6 Mar 2010) -- Added another VS10 version string - -- fix line break - -- removed usage of 's6_addr', fixing compilation issue triggered with no - longer using 'in6_addr' but only our 'ares_in6_addr' struct - -Daniel Stenberg (5 Mar 2010) -- Daniel Johnson provided fixes for building with the clang compiler - -Yang Tse (5 Mar 2010) -- Added IPv6 name servers support - -Gisle Vanem (5 Mar 2010) -- Ops!. Readded ares_nowarn.h. - -- Added ares_nowarn.c. - -Yang Tse (5 Mar 2010) -- Constantine Sapuntzakis detected and fixed a double free in builds done - with threaded resolver enabled (Windows default configuration) that would - get triggered when a curl handle is closed while doing DNS resolution. - -- Added SIZEOF_INT and SIZEOF_SHORT definitions for VMS configuration file - -Daniel Stenberg (4 Mar 2010) -- Julien Chaffraix clarified CURLOPT_HEADERFUNCTION and made - CURLOPT_HEADERFUNCTION and CURLOPT_WRITEFUNCTION more consistent - -- - [Daniel Johnson] I've been trying to build libcurl with clang on Darwin and - ran into some issues with the GSSAPI tests in configure.ac. The tests first - try to determine the include dirs and libs and set CPPFLAGS and LIBS - accordingly. It then checks for the headers and finally sets LIBS a second - time, causing the libs to be included twice. The first setting of LIBS seems - redundant and should be left out, since the first part is otherwise just - about finding headers. - - My second issue is that 'krb5-config --libs gssapi' on Darwin is less than - useless and returns junk that, while it happens to work with gcc, causes - clang to choke. For example, --libs returns $CFLAGS along with the libs, - which is really retarded. Simply setting 'LIBS="$LIBS -lgssapi_krb5 - -lresolv"' on Darwin is sufficient. - -- - Based on patch provided by Jacob Moshenko, the transfer logic now properly - makes sure that when using sub-second timeouts, there's no final bad 1000ms - wait. Previously, a sub-second timeout would often make the elapsed time end - up the time rounded up to the nearest second (e.g. 1s for 200ms timeout) - -- update the generic copyright year range to include 2010 - -- - Andrei Benea filed bug report #2956698 and pointed out that the - CURLOPT_CERTINFO feature leaked memory due to a missing OpenSSL function - call. He provided the patch to fix it too. - - http://curl.haxx.se/bug/view.cgi?id=2956698 - -- - Markus Duft pointed out in bug #2961796 that even though Interix has a - poll() function it doesn't quite work the way we want it so we must disable - it, and he also provided a patch for it. - - http://curl.haxx.se/bug/view.cgi?id=2961796 - -- - Made the pingpong timeout code properly deal with the response timeout AND - the global timeout if set. Also, as was reported in the bug report #2956437 - by Ryan Chan, the time stamp to use as basis for the per command timeout was - not set properly in the DONE phase for FTP (and not for SMTP) so I fixed - that just now. This was a regression compared to 7.19.7 due to the - conversion of FTP code over to the generic pingpong concepts. - - http://curl.haxx.se/bug/view.cgi?id=2956437 - -- remove assignment never used - -- - Ben Greear provided an update for TFTP that fixes upload. - -- SSL, not SSH, SSL - -- - Wesley Miaw reported bug #2958179 which identified a case of looping during - OpenSSL based SSL handshaking even though the multi interface was used and - there was no good reason for it. - - http://curl.haxx.se/bug/view.cgi?id=2958179 - -Yang Tse (28 Feb 2010) -- Added SIZEOF_INT and SIZEOF_SHORT definitions for non-configure systems - -- Added ares_nowarn.* to VC6 project file - -Daniel Stenberg (26 Feb 2010) -- spellchecked by Stphane Fillod - -- - Pat Ray in bug #2958474 pointed out an off-by-one case when receiving a - chunked-encoding trailer. - - http://curl.haxx.se/bug/view.cgi?id=2958474 - -Dan Fandrich (26 Feb 2010) -- Fixed a couple of out of memory leaks and a segfault in the IMAP code. - -Yang Tse (26 Feb 2010) -- fix sizeof short - -- Added SIZEOF_INT and SIZEOF_SHORT definitions for non-configure systems - -- Added SIZEOF_INT definition - -- fix compiler warning - -- fix compiler warning - -- fix compiler warning - -Dan Fandrich (25 Feb 2010) -- Fixed a couple of out of memory leaks and a segfault in the SMTP code. - -Yang Tse (25 Feb 2010) -- fix file name - -- Fixed bug report #2958074 indicating - (http://curl.haxx.se/bug/view.cgi?id=2958074) that curl on Windows with - option --trace-time did not use local time when timestamping trace lines. - This could also happen on other systems depending on time souurce. - -- enable 802 and 803 - -- fix compiler warning - -- fix compiler warning - -- fix compiler warning - -- fix socket data type - -- fix socket data type and logging format in debug tracking socket functions - -- convert Curl_ultous() and Curl_ultouc() functions to curlx_ultous() and - curlx_ultouc(), exposing them through curlx.h to allow proper code reuse - later in our test harness. - -- updated sources - -Patrick Monnerat (22 Feb 2010) -- _ Adjusted RFC821 HELO fallback and enabled test804 - -- - Proper handling of STARTTLS on SMTP, taking CURLUSESSL_TRY into account. - - SMTP falls back to RFC821 HELO when EHLO fails (and SSL is not required). - - Use of true local host name (i.e.: via gethostname()) when available, as default argument to SMTP HELO/EHLO. - - Test case 804 for HELO fallback. - -Yang Tse (22 Feb 2010) -- add header inclusion - -- fix compiler warning - -- fix compiler warning - -Daniel Stenberg (21 Feb 2010) -- clarify more details on section "2.1 More non-blocking" - -- TFTP transfers are not blocking since 7.20.0 - -- - Fixed the SMTP compliance by making sure RCPT TO addresses are specified - properly in angle brackets. Recipients provided with CURLOPT_MAIL_RCPT now - get angle bracket wrapping automatically by libcurl unless the recipient - starts with an angle bracket as then the app is assumed to deal with that - properly on its own. - -- - I made the SMTP code expect a 250 response back from the server after the - full DATA has been sent, and I modified the test SMTP server to also send - that response. As usual, the DONE operation that is made after a completed - transfer is still not doable in a non-blocking way so this waiting for 250 - is unfortunately made blockingly. - -- corected a comment and wrapped a few longish lines - -Yang Tse (20 Feb 2010) -- fix compiler warning - -- fix compiler warning - -- fix compiler warning - -- fix compiler warning - -- fix compiler warning - -Daniel Stenberg (17 Feb 2010) -- ares_reinit() - - - To allow an app to force a re-read of /etc/resolv.conf etc, pretty much - like the res_init() resolver function offers - -- use curl standard indentation and line lengths - -Yang Tse (16 Feb 2010) -- replaced tabs with spaces - -- fix Content-Length validation - -Daniel Stenberg (15 Feb 2010) -- use (void) in front of fwrite() calls that ignore the return code - -Yang Tse (15 Feb 2010) -- fix compiler warning: conversion from "long" to "size_t" may lose sign - -- fix compiler warning: conversion from "long" to "size_t" may lose sign - -Daniel Stenberg (15 Feb 2010) -- -w speed_download and speed_upload are measured in bytes per second - -- 75. NTLM authentication involving unicode user name or password. - http://curl.haxx.se/mail/lib-2009-10/0024.html - http://curl.haxx.se/bug/view.cgi?id=2944325 - -Yang Tse (14 Feb 2010) -- removed trailing whitespace - -- fix compiler warning - -- Overhauled test suite getpart() function. Fixing potential out of bounds - stack and memory overwrites triggered with huge test case definitions. - -Daniel Stenberg (13 Feb 2010) -- - Martin Hager reported and fixed a problem with a missing quote in libcurl.m4 - - (http://curl.haxx.se/bug/view.cgi?id=2951319) - -Gunter Knauf (13 Feb 2010) -- used allways #ifdef / #ifndef; - moved gethostbyname_thread() to #else case to avoid 'not used' compiler warning. - -- replaced tabs by spaces, removed trailing tabs/spaces. - -Daniel Stenberg (13 Feb 2010) -- - Tom Donovan fixed the CURL_FORMAT_* defines when building with cmake. - -- - Jack Zhang reported a problem with SMTP: we wrongly used multiple addresses - in the same RCPT TO line, when they should be sent in separate single - commands. I updated test case 802 to verify this. - - - I also fixed a bad use of my_setopt_str() of CURLOPT_MAIL_RCPT in the curl - tool which made it try to output it as string for the --libcurl feature - which could lead to crashes. - -- CURLOPT_MAIL_RCPT is *not* a string so we must not try to printf() it - -- free --mail-from strings properly - -Patrick Monnerat (11 Feb 2010) -- _ Make it compilable again on OS400. - _ Upgrade OS400 EBCDIC wrappers for new options. - _ Upgrade ILE/RPG bindings to current state. - -Yang Tse (11 Feb 2010) -- mention last changes - -- Steven M. Schweda updated VMS readme file - -- Steven M. Schweda removed batch_compile.com and defines.com - -- Steven M. Schweda fixed: - - VMS builder bad behavior when used in a batch job. - - Various ".LIS" and ".MAP" files created without being requested - by a "LIST" command-line option, and in the wrong place, too. - - Some minor typographical changes. - -Dan Fandrich (10 Feb 2010) -- Mention the minimum size of CURL_MAX_WRITE_SIZE - -Yang Tse (10 Feb 2010) -- - remove extra "\r\n" from doc404_RTSP - - - avoid memory alignment issue when setting RTSP packet length - -Dan Fandrich (9 Feb 2010) -- Removed some erroneous "compressed" key words - -Daniel Stenberg (9 Feb 2010) -- start working on 7.20.1 - -Version 7.20.0 (9 Feb 2010) - -Daniel Stenberg (9 Feb 2010) -- spell and 7.20.0 - -- - When downloading compressed content over HTTP and the app as asked libcurl - to automatically uncompress it with the CURLOPT_ENCODING option, libcurl - could wrongly provide the callback with more data than what the maximum - documented amount. An application could thus get tricked into badness if the - maximum limit was trusted to be enforced by libcurl itself (as it is - documented). - - This is further detailed and explained in the libcurl security advisory - 20100209 at - - http://curl.haxx.se/docs/adv_20100209.html - -- set VERSIONINFO accordingly for the 7.20.0 release - -Yang Tse (6 Feb 2010) -- warning fix - -- OOM handling fix - -- OOM handling fix - -- fix compiler warning - -- fix compiler warning - -- fix compiler warning - -- Addes OOM handling for curl_easy_setopt() calls in test - -- - avoid OpenSSL 0.9.8 ENGINE_by_id memory leak - - - cleanup parenthesis usage in return statements - -- - attempt to workaround icc 9.1 optimizer issue - -- fix printf-style format strings - -- Validate server port argument - -- Fix variable initialization - -- Modified test case 557 to additionally verify libcurl's internal curl_m*printf() - functions formatting functionality when handling signed and unsigned shorts. - -- Added size check for 'short' data type - -- Fix compiler warning: unused variable - -- added an additional second to allow test to pass on heavily loaded servers - -Dan Fandrich (3 Feb 2010) -- Changed the Watcom makefiles to make them easier to keep in sync with - Makefile.inc since that can't be included directly. - -Daniel Stenberg (3 Feb 2010) -- more symbols added in 7.20.0 - -Yang Tse (3 Feb 2010) -- Fix OOM handling - -- Fix progressmode Configurable struct member data type. Changed to - 'int' which fits better with existing CURL_PROGRESS_* definitions. - -- Fix portability issue related with unaligned memory access - -- Fix compiler warnings: conversion from 'const int ' to 'unsigned char ', possible loss of data - -- cookies with same path length might get sorted in different order when - using different qsort implementations. In order to make this test give - same results on different systems, paths now have different lengths. - -- added an additional second to allow test to pass on heavily loaded servers - -- Fix compiler warning: conditional expression is constant - -- Fix compiler warning: local variable may be used without having been initialized. - -- Fix compiler warnings: conversion from 'const int ' to 'unsigned char ', possible loss of data - -- Fix compiler warnings: - - (1) conversion from 'const int ' to 'unsigned char ', possible loss of data - (2) conditional expression is constant - -- mention a couple of changes back from November - -- mention run time statistics options - -- - Symbol CURL_FORMAT_OFF_T now obsoleted, will be removed in a future release, - symbol will not be available when building with CURL_NO_OLDIES defined. Use - of CURL_FORMAT_CURL_OFF_T is preferred since 7.19.0 - -- avoid possibility of using obsoleted stuff - -- remove setup.h inclusion which is already done from test.h inclusion - -Kamil Dudka (2 Feb 2010) -- mention SOCKS related problems in the curl(1) man page - -Yang Tse (2 Feb 2010) -- Fix compiler warning: variable was set but never used - - Simplify preprocessor symbol checking - -Daniel Stenberg (2 Feb 2010) -- Julien Chaffraix pointed out a comment mistake, and I re-indented the code - slightly while editing - -Yang Tse (2 Feb 2010) -- include headers - -- Conroy added a check to the coded message size since the docs stipulate - that each call will contain a full protocol packet. - -- Conroy's fix to make the code match with the RTP documentation regarding - writing out the whole header. The docs say it writes the whole header, - but the code (before this patch) did not write out the leading $. - -Daniel Stenberg (1 Feb 2010) -- We introduce a loop in lib/multi.c around all calls to multi_runsingle() and - simply check for CURLM_CALL_MULTI_PERFORM internally. This has the added - benefit that this goes in line with my long-term wishes to get rid of the - CURLM_CALL_MULTI_PERFORM all together from the public API. - -Yang Tse (1 Feb 2010) -- update rtsp server header field from SWS to RTSPD - -- Test suite support for RTSP - -- Make Curl_pop3_write() additionally truncate trailing POP3_EOB from received - string buffer, otherwise Curl_client_write() call with zero size would write - to the end of string buffer including matched POP3_EOB. - -- WIN32 fix, _beginthreadex() may return either 0 or -1L upon failure - -- fix errno usage for WIN32 builds - -- fix printf-style format strings - -- Chris Conroy fixed test #568 issues with carriage returns - -- RTSP followup fix. Both the pipelined and non-pipelined case need to - check for (excess > 0 && !k->ignorebody). - -Daniel Stenberg (28 Jan 2010) -- - Tommie Gannert pointed out a silly bug in ares_process_fd() since it didn't - check for broken connections like ares_process() did. Based on that, I - merged the two functions into a single generic one with two front-ends. - -Yang Tse (28 Jan 2010) -- fix printf-style format strings - -- Use 'size_t' for GETNAMEINFO_TYPE_ARG2 definition for VMS. - - http://curl.haxx.se/mail/lib-2009-12/0293.html - -- portability fix - -- fix printf-style format strings - -- Known bug #64 fixed by Constantine Sapuntzakis and Joshua Kwan in 7.20.0 - -- Chris Conroy provided first RTSP tests - -- RTSP tests disabled until test harness RTSP support is updated - -- Chris Conroy's RTSP followup fixes - -- mention asynchronous DNS lookups enhancements - -- Restore normal operation: - - c-ares is only enabled when specifically requested. - - Consequently, c-ares default setting is disabled. - -- fix c-ares assumed check being skipped - -- fix compiler warning - -- fix LDFLAGS preservation in CURL_CHECK_LIB_ARES - -Daniel Stenberg (26 Jan 2010) -- no need to take precautiono for how things were before 7.16.0 since that - is now a very long time ago - -- - Mike Crowe made libcurl return CURLE_COULDNT_RESOLVE_PROXY when it is the - proxy that cannot be resolved when using c-ares. This matches the behaviour - when not using c-ares. - -Dan Fandrich (26 Jan 2010) -- Added curl_threads.c to a few more non-configure build files - -Yang Tse (26 Jan 2010) -- minor fixes for --enable-ares configure option - -Daniel Stenberg (26 Jan 2010) -- Andre Guibert de Bruet improved the libssh2 error code translation - -Yang Tse (26 Jan 2010) -- resolver selection for non-configure Windows builds, default is threaded DNS - -- add curl_threads.c to non-configure target build files - -- onstantine Sapuntzakis threaded resolver enhancements - -- Constantine Sapuntzakis threaded resolver enhancements - -- Constantine Sapuntzakis provided initial thread abstraction layer - -- make Curl_handler_*_proxy definition static - -Dan Fandrich (25 Jan 2010) -- Updated minimum library sizes - -Yang Tse (25 Jan 2010) -- fix compiler warning - -Daniel Stenberg (24 Jan 2010) -- Julien Chaffraix corrected bad #elif lines to silence warnings - -Yang Tse (24 Jan 2010) -- HAVE_GETADDRINFO_THREADSAFE definition for non-configure win32 builds - -Bjorn Stenberg (23 Jan 2010) -- Mention -J change - -- Added -J/--remote-header-name. - -Daniel Stenberg (23 Jan 2010) -- "remove progress meter from libcurl" at next API break - -Yang Tse (23 Jan 2010) -- add inclusion of curl_memory.h - -- adjust preprocessor symbol definition check relative to resolver specialty - -- PKTSIZE might have been already defined in arpa/tftp.h - -Dan Fandrich (23 Jan 2010) -- Include "curl_memory.h" to get the strdup replacement when necessary - -Daniel Stenberg (22 Jan 2010) -- wrap long lines and do some indent policing - -Yang Tse (22 Jan 2010) -- Definitions of resolver specialty compile-time defines CURLRES_* moved - from hostip.h to setup.h in order to allow proper inclusion in any file. - - This represents no functional change at all in which resolver is used, - everything still works as usual, internally and externally there is no - difference in behavior. - -- adjust rtsp protocol support in curl-config and libcurl.pc when http is disabled - -- deal with the possibility that CURL_DISABLE_RTSP may already be defined - -- fix compiler warning: statement is unreachable - -- fix compilation when http is disabled - -- disabling of rtsp when http isn't enabled required here for non-configure systems - -Daniel Stenberg (22 Jan 2010) -- wrap long lines, remove (very old) attribution from code - -- cleanups by Julien Chaffraix - -- alphabetically sort the list of supported protocols - -- In spite claiming to tbe disabled by default, RTSP is enabled and it now - also says so. I also made the list of protocols get sorted. - -- expanded to provide info about the newer protocols too - -- s/RTPFUNCTION/INTERLEAVEFUNCTION/ - s/RTPDATA/INTERLEAVEDATA/ - -- keep lines shorter than 80 columns, and reduce/remove the use of the word - 'note' in most description as it is mostly useless. - -Yang Tse (22 Jan 2010) -- Julien Chaffraix adjusted " section" line length - -- Constantine Sapuntzakis refactoring of async callbacks, allowing - removal of Curl_addrinfo_copy(), Curl_addrinfo6_callback(), and - Curl_addrinfo4_callback() - -Dan Fandrich (21 Jan 2010) -- Added rtsp.c to the non-configure target build files - -Yang Tse (21 Jan 2010) -- fix compiler warning - -- make tftp_translate_code() static, it is only used from within tftp.c - -- fix warning triggered when debugging on cygwin - -- allow exporting of exe_ext() sub - -- improve displaylogcontent() sub fixing a warning - -Daniel Stenberg (21 Jan 2010) -- remove typedef we ended up not using - -- Chris Conroy brought support for RTSP transfers, and with it comes 8(!) new - libcurl options for controlling what to get and how to receive posssibly - interleaved RTP data. Initial commit. - -- Julien Chaffraix fixed line lengths - -- Julien Chaffraix removed an old obsolete typedef - -- Yun Fu pointed out a flaw in the loop that checks handles, and I indented - the code more curl-style - -- "5.3 Sort outgoing cookies" removed, we now sort them - -Yang Tse (20 Jan 2010) -- SIGTERM is the signal to trap here, SIGKILL can't be caught. - -- Use killsockfilters() to kill sockfilter processes, this ensures that when - killing a sockfilter process the actual PID from the pid file is used and - not the one returned by open2() which might be different. - -- Allow killsockfilters() to take a 5th optional parameter that when provided - indicates that only one of the two possible sockfilter processes should be - killed. Valid values for this parameter are 'main' and 'data'. - -- Use delete() to unset environment variables instead of assigning undef which - generates warning 'Use of uninitialized value in scalar assignment' with perl - versions older than 5.10 - -- Adjust valgrind logs file name detection. - - Adjust environment vars setting and restoring from test definition. - - Avoid using strftime in torture sub. - -Daniel Stenberg (20 Jan 2010) -- modified test case 8 to also make sure that we deal with cookies using - identical names but different paths properly - -- - As was pointed out on the http-state mailing list, the order of cookies in a - HTTP Cookie: header _needs_ to be sorted on the path length in the cases - where two cookies using the same name are set more than once using - (overlapping) paths. Realizing this, identically named cookies must be - sorted correctly. But detecting only identically named cookies and take care - of them individually is harder than just to blindly and unconditionally sort - all cookies based on their path lengths. All major browsers also already do - this, so this makes our behavior one step closer to them in the cookie area. - - Test case 8 was the only one that broke due to this change and I updated it - accordingly. - -- oops, I forgot to cvs add this before my previous commit (Dan Fandrich - pointed it out to me) - -- - David McCreedy brought a fix and a new test case (129) to make libcurl work - again when downloading files over FTP using ASCII and it turns out that the - final size of the file is not the same as the initial size the server - reported. This is very common since servers don't take the newline - conversions into account. - -- "260 - IMAP, POP3 and SMTP support" done! - -- avoid "Use of uninitialized value $l in concatenation" - -Yang Tse (19 Jan 2010) -- Fail harder when curl coredumps trying to verify http and ftp servers. - - Add some debug messages to see what's going on with valgrind logs. - -- prevent %runcert hash growth when clearing items - -- update copyright year notice - -- Constantine Sapuntzakis enhancements to make memory tracking log file writing - of messages atomic, on systems where an fwrite of a memory buffer is atomic. - -Dan Fandrich (18 Jan 2010) -- Added PEM certificate keyword - -Yang Tse (18 Jan 2010) -- fix warnings - -- Stop ssl running server when cert file currently used by server is - different than the one specified in test definition for same server - -- fix warnings - -- - Remove QD restarting of https servers. Proper fixing required. - This will make tests 310 311 and 312 fail while fixing. - - - Remove some debug messages - -- make verifyhttp use different file names depending on server characteristics - -- add serverfactors() sub which returns server characterization factors - -- fix warnings - -- fix warnings - -- fix warnings - -- add some debug messages - -- use servername_id() from serverhelp.pm - -- refactored stopping of test harness servers - -- Store now this file in CVS with unix line endings. - - maketgz already converts this file to DOS style with an awk filter. - -- Declaration of $sshdlog is done in sshhelp.pm - -- Start using the centralized pidfile and logfile name generation - subroutines for ssh and socks test suite servers. - -Dan Fandrich (15 Jan 2010) -- Added the new protocol source files to the non-autoconf build files - -Yang Tse (14 Jan 2010) -- Squeeze slack time when killing more than one server from - the section of test harness definition files. - -Kamil Dudka (14 Jan 2010) -- - Suppressed side effect of OpenSSL configure checks, which prevented NSS from - being properly detected under certain circumstances. It had been caused by - strange behavior of pkg-config when handling PKG_CONFIG_LIBDIR. pkg-config - distinguishes among empty and non-existent environment variable in that case. - -Yang Tse (13 Jan 2010) -- Give the test a bit mote time to run so it passes on slow machines - -Kamil Dudka (13 Jan 2010) -- remove trailing spaces from configure.ac - -Yang Tse (12 Jan 2010) -- Added test case #1112 which does an FTPS download with strict timeout - and slow data transfer in a similar way as test case #1086 does for FTP. - - This also exercises section for the FTPS server. - -- Make runtests.pl actually support any (valid) server specification - for the section of test harness definition files. - -- Fix tftp and sftp supported protocols in servername_str() - -- Make sockfilter kill messages look alike server ones + Bug: http://curl.haxx.se/docs/adv_20150429.html + Reported-by: Yehezkel Horowitz, Oren Souroujon diff --git a/project/jni/curl/COPYING b/project/jni/curl/COPYING index 163b299ae..a98663e94 100644 --- a/project/jni/curl/COPYING +++ b/project/jni/curl/COPYING @@ -1,6 +1,7 @@ COPYRIGHT AND PERMISSION NOTICE -Copyright (c) 1996 - 2010, Daniel Stenberg, . +Copyright (c) 1996 - 2016, Daniel Stenberg, , and many +contributors, see the THANKS file. All rights reserved. diff --git a/project/jni/curl/README b/project/jni/curl/README index 2ffacc32c..f0b3b9393 100644 --- a/project/jni/curl/README +++ b/project/jni/curl/README @@ -24,7 +24,7 @@ README CONTACT If you have problems, questions, ideas or suggestions, please contact us - by posting to a suitable mailing list. See http://curl.haxx.se/mail/ + by posting to a suitable mailing list. See https://curl.haxx.se/mail/ All contributors to the project are listed in the THANKS document. @@ -32,18 +32,18 @@ WEB SITE Visit the curl web site for the latest news and downloads: - http://curl.haxx.se/ + https://curl.haxx.se/ GIT To download the very latest source off the GIT server do this: - git clone git://github.com/bagder/curl.git + git clone https://github.com/curl/curl.git (you'll get a directory named curl created, filled with the source code) NOTICE Curl contains pieces of source code that is Copyright (c) 1998, 1999 - Kungliga Tekniska Hgskolan. This notice is included here to comply with the + Kungliga Tekniska Högskolan. This notice is included here to comply with the distribution terms. diff --git a/project/jni/curl/RELEASE-NOTES b/project/jni/curl/RELEASE-NOTES index 70ac0dc95..54029dbce 100644 --- a/project/jni/curl/RELEASE-NOTES +++ b/project/jni/curl/RELEASE-NOTES @@ -1,61 +1,159 @@ -Curl and libcurl 7.21.3 +Curl and libcurl 7.48.0 - Public curl releases: 119 - Command line options: 143 - curl_easy_setopt() options: 185 - Public functions in libcurl: 58 - Known libcurl bindings: 39 - Contributors: 827 + Public curl releases: 153 + Command line options: 179 + curl_easy_setopt() options: 221 + Public functions in libcurl: 61 + Contributors: 1364 This release includes the following changes: - o Added --noconfigure switch to testcurl.pl - o Added --xattr option - o Added CURLOPT_RESOLVE and --resolve - o Added CURLAUTH_ONLY - o Added version-check.pl to the examples dir + o configure: --with-ca-fallback: use built-in TLS CA fallback [2] + o TFTP: add --tftp-no-options to expose CURLOPT_TFTP_NO_OPTIONS [22] + o getinfo: CURLINFO_TLS_SSL_PTR supersedes CURLINFO_TLS_SESSION [25] + o added CODE_STYLE.md [47] This release includes the following bugfixes: - o check for libcurl features for some command line options - o Curl_setopt: disallow CURLOPT_USE_SSL without SSL support - o http_chunks: remove debug output - o URL-parsing: consider ? a divider - o SSH: avoid using the libssh2_ prefix - o SSH: use libssh2_session_handshake() to work on win64 - o ftp: prevent server from hanging on closed data connection when stopping - a transfer before the end of the full transfer (ranges) - o LDAP: detect non-binary attributes properly - o ftp: treat server's response 421 as CURLE_OPERATION_TIMEDOUT - o gnutls->handshake: improved timeout handling - o security: Pass the right parameter to init - o krb5: Use GSS_ERROR to check for error - o TFTP: resend the correct data - o configure: fix autoconf 2.68 warning: no AC_LANG_SOURCE call detected - o GnuTLS: now detects socket errors on Windows - o symbols-in-versions: updated en masse - o added a couple examples that were missing from the tar ball - o Curl_send/recv_plain: return errno on failure - o Curl_wait_for_resolv (for c-ares): correct timeout - o ossl_connect_common: detect connection re-use - o configure: Prevent link errors with --librtmp - o openldap: use remote port in URL passed to ldap_init_fd() - o url: provide dead_connection flag in Curl_handler::disconnect - o lots of compiler warning fixes - o ssh: fix a download resume point calculation - o fix getinfo CURLINFO_LOCAL* for reused connections - o multi: the returned running handles conuter could turn negative - o multi: only ever consider pipelining for connections doing HTTP(S) + o Proxy-Connection: stop sending this header by default [1] + o os400: sync ILE/RPG definitions with latest public header files + o cookies: allow spaces in cookie names, cut of trailing spaces [3] + o tool_urlglob: Allow reserved dos device names (Windows) [4] + o openssl: remove most BoringSSL #ifdefs [5] + o tool_doswin: Support for literal path prefix \\?\ + o mbedtls: fix ALPN usage segfault [6] + o mbedtls: fix memory leak when destroying SSL connection data [7] + o nss: do not count enabled cipher-suites + o examples/cookie_interface.c: add cleanup call + o examples: adhere to curl code style + o curlx_tvdiff: handle 32bit time_t overflows [8] + o dist: ship buildconf.bat too + o curl.1: --disable-{eprt,epsv} are ignored for IPv6 hosts [9] + o generate.bat: Fix comment bug by removing old comments [10] + o test1604: Add to Makefile.inc so it gets run + o gtls: fix for builds lacking encrypted key file support [11] + o SCP: use libssh2_scp_recv2 to support > 2GB files on windows [12] + o CURLOPT_CONNECTTIMEOUT_MS.3: Fix example to use milliseconds option [13] + o cookie: do not refuse cookies to localhost [14] + o openssl: avoid direct PKEY access with OpenSSL 1.1.0 [15] + o http: Don't break the header into chunks if HTTP/2 [16] + o http2: don't decompress gzip decoding automatically [17] + o curlx.c: i2s_ASN1_IA5STRING() clashes with an openssl function + o curl.1: add a missing dash + o curl.1: HTTP headers for --cookie must be Set-Cookie style [18] + o CURLOPT_COOKIEFILE.3: HTTP headers must be Set-Cookie style [18] + o curl_sasl: Fix memory leak in digest parser [19] + o src/Makefile.m32: add CURL_{LD,C}FLAGS_EXTRAS support [20] + o CURLOPT_DEBUGFUNCTION.3: Fix example + o runtests: Fixed usage of %PWD on MinGW64 [21] + o tests/sshserver.pl: use RSA instead of DSA for host auth [23] + o multi_remove_handle: keep the timeout list until after disconnect [24] + o Curl_read: check for activated HTTP/1 pipelining, not only requested + o configure: warn on invalid ca bundle or path [26] + o file: try reading from files with no size [27] + o getinfo: Add support for mbedTLS TLS session info + o formpost: fix memory leaks in AddFormData error branches [28] + o makefile.m32: allow to pass .dll/.exe-specific LDFLAGS [29] + o url: if Curl_done is premature then pipeline not in use [30] + o cookie: remove redundant check [31] + o cookie: Don't expire session cookies in remove_expired [32] + o makefile.m32: fix to allow -ssh2-winssl combination [33] + o checksrc.bat: Fixed cannot find perl if installed but not in path + o build-openssl.bat: Fixed cannot find perl if installed but not in path + o mbedtls: fix user-specified SSL protocol version + o makefile.m32: add missing libs for static -winssl-ssh2 builds [34] + o test46: change cookie expiry date [35] + o pipeline: Sanity check pipeline pointer before accessing it [36] + o openssl: use the correct OpenSSL/BoringSSL/LibreSSL in messages + o ftp_done: clear tunnel_state when secondary socket closes [37] + o opt-docs: fix heading macros [38] + o imap/pop3/smtp: Fixed connections upgraded with TLS are not reused [39] + o curl_multi_wait: never return -1 in 'numfds' [40] + o url.c: fix clang warning: no newline at end of file + o krb5: improved type handling to avoid clang compiler warnings + o cookies: first n/v pair in Set-Cookie: is the cookie, then parameters [41] + o multi: avoid blocking during CURLM_STATE_WAITPROXYCONNECT [42] + o multi hash: ensure modulo performed on curl_socket_t [43] + o curl: glob_range: no need to check unsigned variable for negative + o easy: add check to malloc() when running event-based + o CURLOPT_SSLENGINE.3: Only for OpenSSL built with engine support [44] + o version: thread safety + o openssl: verbose: show matching SAN pattern + o openssl: adapt to OpenSSL 1.1.0 API breakage in ERR_remove_thread_state() + o formdata.c: Fixed compilation warning + o configure: use cpp -P when needed [45] + o imap.c: Fixed compilation warning with /Wall enabled + o config-w32.h: Fixed compilation warning when /Wall enabled + o ftp/imap/pop3/smtp: Fixed compilation warning when /Wall enabled + o build: Added missing Visual Studio filter files for VC10 onwards + o easy: Remove poll failure check in easy_transfer + o mbedtls: fix compiler warning + o build-wolfssl: Update VS properties for wolfSSL v3.9.0 + o Fixed various compilation warnings when verbose strings disabled This release includes the following known bugs: - o see docs/KNOWN_BUGS (http://curl.haxx.se/docs/knownbugs.html) + o see docs/KNOWN_BUGS (https://curl.haxx.se/docs/knownbugs.html) This release would not have looked like this without help, code, reports and advice from friends like these: - Dan Fandrich, Guenter Knauf, Pat Ray, Hongli Lai, Kamil Dudka, - Stefan Tomanek, Alfred Gebert, Yang Tse, Julien Chaffraix, Adam Light, - Rutger Hofman, Matthias Bolte, Heinrich Ko, Dmitri Shubin + Anders Bakken, Brad Fitzpatrick, Clint Clayton, Dan Fandrich, + Daniel Stenberg, David Benjamin, David Byron, Emil Lerner, Eric S. Raymond, + Gisle Vanem, Jaime Fullaondo, Jeffrey Walton, Jesse Tan, Justin Ehlert, + Kamil Dudka, Kazuho Oku, Ludwig Nussel, Maksim Kuzevanov, Michael König, + Oliver Graute, Patrick Monnerat, Rafael Antonio, Ray Satiro, Seth Mos, + Shine Fan, Steve Holme, Tatsuhiro Tsujikawa, Timotej Lazar, Tim Rühsen, + Viktor Szakáts, + (30 contributors) Thanks! (and sorry if I forgot to mention someone) + +References to bug reports and discussions on issues: + + [1] = https://curl.haxx.se/bug/?i=633 + [2] = https://curl.haxx.se/bug/?i=569 + [3] = https://curl.haxx.se/bug/?i=639 + [4] = https://github.com/curl/curl/commit/4520534#commitcomment-15954863 + [5] = https://curl.haxx.se/bug/?i=640 + [6] = https://curl.haxx.se/bug/?i=642 + [7] = https://curl.haxx.se/bug/?i=626 + [8] = https://curl.haxx.se/bug/?i=646 + [9] = https://bugzilla.redhat.com/1305970 + [10] = https://curl.haxx.se/bug/?i=649 + [11] = https://curl.haxx.se/bug/?i=651 + [12] = https://curl.haxx.se/bug/?i=451 + [13] = https://curl.haxx.se/bug/?i=653 + [14] = https://curl.haxx.se/bug/?i=658 + [15] = https://curl.haxx.se/bug/?i=650 + [16] = https://curl.haxx.se/bug/?i=659 + [17] = https://curl.haxx.se/bug/?i=661 + [18] = https://curl.haxx.se/bug/?i=666 + [19] = https://curl.haxx.se/bug/?i=667 + [20] = https://curl.haxx.se/bug/?i=670 + [21] = https://curl.haxx.se/bug/?i=672 + [22] = https://curl.haxx.se/bug/?i=481 + [23] = https://curl.haxx.se/bug/?i=676 + [24] = https://curl.haxx.se/mail/lib-2016-02/0097.html + [25] = https://curl.haxx.se/libcurl/c/CURLINFO_TLS_SSL_PTR.html + [26] = https://curl.haxx.se/bug/?i=404 + [27] = https://curl.haxx.se/bug/?i=681 + [28] = https://curl.haxx.se/bug/?i=688 + [29] = https://curl.haxx.se/bug/?i=689 + [30] = https://curl.haxx.se/bug/?i=690 + [31] = https://curl.haxx.se/bug/?i=695 + [32] = https://curl.haxx.se/bug/?i=697 + [33] = https://curl.haxx.se/bug/?i=692 + [34] = https://curl.haxx.se/bug/?i=693 + [35] = https://curl.haxx.se/bug/?i=697 + [36] = https://curl.haxx.se/bug/?i=704 + [37] = https://curl.haxx.se/bug/?i=701 + [38] = https://curl.haxx.se/bug/?i=705 + [39] = https://curl.haxx.se/bug/?i=422 + [40] = https://curl.haxx.se/bug/?i=707 + [41] = https://curl.haxx.se/bug/?i=709 + [42] = https://curl.haxx.se/bug/?i=703 + [43] = https://curl.haxx.se/bug/?i=712 + [44] = https://curl.haxx.se/mail/lib-2016-03/0150.html + [45] = https://curl.haxx.se/bug/?i=719 + [47] = https://curl.haxx.se/dev/code-style.html diff --git a/project/jni/curl/include/README b/project/jni/curl/include/README index 205f9f7dd..3e52a1d0a 100644 --- a/project/jni/curl/include/README +++ b/project/jni/curl/include/README @@ -36,7 +36,7 @@ The following notes apply to libcurl version 7.19.0 and later. * If you intend to distribute an already compiled libcurl library you _MUST_ also distribute along with it the generated curl/curlbuild.h which has been used to compile it. Otherwise the library will be of no use for the users of - the library that you have built. It is _your_ responsability to provide this + the library that you have built. It is _your_ responsibility to provide this file. No one at the cURL project can know how you have built the library. * File curl/curlbuild.h includes platform and configuration dependent info, diff --git a/project/jni/curl/include/curl/curl.h b/project/jni/curl/include/curl/curl.h index fbd0d9b01..e0d5c0f4e 100644 --- a/project/jni/curl/include/curl/curl.h +++ b/project/jni/curl/include/curl/curl.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -24,10 +24,10 @@ /* * If you have libcurl problems, all docs and details are found here: - * http://curl.haxx.se/libcurl/ + * https://curl.haxx.se/libcurl/ * * curl-library mailing list subscription and unsubscription web interface: - * http://cool.haxx.se/mailman/listinfo/curl-library/ + * https://cool.haxx.se/mailman/listinfo/curl-library/ */ #include "curlver.h" /* libcurl version defines */ @@ -55,34 +55,33 @@ #include #include -#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__GNUC__) && \ - !defined(__CYGWIN__) || defined(__MINGW32__) -#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H)) +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ + defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) /* The check above prevents the winsock2 inclusion if winsock.h already was included, since they can't co-exist without problems */ #include #include #endif -#else +#endif /* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish - libc5-based Linux systems. Only include it on system that are known to + libc5-based Linux systems. Only include it on systems that are known to require it! */ #if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ - defined(ANDROID) || \ + defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) #include #endif -#ifndef _WIN32_WCE +#if !defined(WIN32) && !defined(_WIN32_WCE) #include #endif + #if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) #include #endif -#include -#endif #ifdef __BEOS__ #include @@ -95,34 +94,26 @@ extern "C" { typedef void CURL; /* - * Decorate exportable functions for Win32 and Symbian OS DLL linking. - * This avoids using a .def file for building libcurl.dll. + * libcurl external API function linkage decorations. */ -#if (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) && \ - !defined(CURL_STATICLIB) -#if defined(BUILDING_LIBCURL) -#define CURL_EXTERN __declspec(dllexport) -#else -#define CURL_EXTERN __declspec(dllimport) -#endif -#else -#ifdef CURL_HIDDEN_SYMBOLS -/* - * This definition is used to make external definitions visible in the - * shared library when symbols are hidden by default. It makes no - * difference when compiling applications whether this is set or not, - * only when compiling the library. - */ -#define CURL_EXTERN CURL_EXTERN_SYMBOL +#ifdef CURL_STATICLIB +# define CURL_EXTERN +#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__) +# if defined(BUILDING_LIBCURL) +# define CURL_EXTERN __declspec(dllexport) +# else +# define CURL_EXTERN __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) +# define CURL_EXTERN CURL_EXTERN_SYMBOL #else -#define CURL_EXTERN -#endif +# define CURL_EXTERN #endif #ifndef curl_socket_typedef /* socket typedef */ -#ifdef WIN32 +#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) typedef SOCKET curl_socket_t; #define CURL_SOCKET_BAD INVALID_SOCKET #else @@ -137,7 +128,8 @@ struct curl_httppost { char *name; /* pointer to allocated name */ long namelength; /* length of name length */ char *contents; /* pointer to allocated data contents */ - long contentslength; /* length of contents field */ + long contentslength; /* length of contents field, see also + CURL_HTTPPOST_LARGE */ char *buffer; /* pointer to allocated buffer contents */ long bufferlength; /* length of buffer field */ char *contenttype; /* Content-Type */ @@ -146,32 +138,51 @@ struct curl_httppost { file, this link should link to following files */ long flags; /* as defined below */ -#define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */ -#define HTTPPOST_READFILE (1<<1) /* specified content is a file name */ -#define HTTPPOST_PTRNAME (1<<2) /* name is only stored pointer - do not free in formfree */ -#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer - do not free in formfree */ -#define HTTPPOST_BUFFER (1<<4) /* upload file from buffer */ -#define HTTPPOST_PTRBUFFER (1<<5) /* upload file from pointer contents */ -#define HTTPPOST_CALLBACK (1<<6) /* upload file contents by using the - regular read callback to get the data - and pass the given pointer as custom - pointer */ + +/* specified content is a file name */ +#define CURL_HTTPPOST_FILENAME (1<<0) +/* specified content is a file name */ +#define CURL_HTTPPOST_READFILE (1<<1) +/* name is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRNAME (1<<2) +/* contents is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRCONTENTS (1<<3) +/* upload file from buffer */ +#define CURL_HTTPPOST_BUFFER (1<<4) +/* upload file from pointer contents */ +#define CURL_HTTPPOST_PTRBUFFER (1<<5) +/* upload file contents by using the regular read callback to get the data and + pass the given pointer as custom pointer */ +#define CURL_HTTPPOST_CALLBACK (1<<6) +/* use size in 'contentlen', added in 7.46.0 */ +#define CURL_HTTPPOST_LARGE (1<<7) char *showfilename; /* The file name to show. If not set, the actual file name will be used (if this is a file part) */ void *userp; /* custom pointer used for HTTPPOST_CALLBACK posts */ + curl_off_t contentlen; /* alternative length of contents + field. Used if CURL_HTTPPOST_LARGE is + set. Added in 7.46.0 */ }; +/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered + deprecated but was the only choice up until 7.31.0 */ typedef int (*curl_progress_callback)(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow); +/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in + 7.32.0, it avoids floating point and provides more detailed information. */ +typedef int (*curl_xferinfo_callback)(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + #ifndef CURL_MAX_WRITE_SIZE /* Tests have proven that 20K is a very bad buffer size for uploads on Windows, while 16K for some odd reason performed a lot better. @@ -189,10 +200,10 @@ typedef int (*curl_progress_callback)(void *clientp, #define CURL_MAX_HTTP_HEADER (100*1024) #endif - /* This is a magic return code for the write callback that, when returned, will signal libcurl to pause receiving on the current transfer. */ #define CURL_WRITEFUNC_PAUSE 0x10000001 + typedef size_t (*curl_write_callback)(char *buffer, size_t size, size_t nitems, @@ -311,10 +322,18 @@ typedef size_t (*curl_read_callback)(char *buffer, void *instream); typedef enum { - CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ - CURLSOCKTYPE_LAST /* never use */ + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ + CURLSOCKTYPE_LAST /* never use */ } curlsocktype; +/* The return code from the sockopt_callback can signal information back + to libcurl: */ +#define CURL_SOCKOPT_OK 0 +#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return + CURLE_ABORTED_BY_CALLBACK */ +#define CURL_SOCKOPT_ALREADY_CONNECTED 2 + typedef int (*curl_sockopt_callback)(void *clientp, curl_socket_t curlfd, curlsocktype purpose); @@ -334,6 +353,9 @@ typedef curl_socket_t curlsocktype purpose, struct curl_sockaddr *address); +typedef int +(*curl_closesocket_callback)(void *clientp, curl_socket_t item); + typedef enum { CURLIOE_OK, /* I/O operation successful */ CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ @@ -394,7 +416,8 @@ typedef enum { CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ CURLE_FAILED_INIT, /* 2 */ CURLE_URL_MALFORMAT, /* 3 */ - CURLE_OBSOLETE4, /* 4 - NOT USED */ + CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for + 7.17.0, reused in April 2011 for 7.21.5] */ CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ CURLE_COULDNT_RESOLVE_HOST, /* 6 */ CURLE_COULDNT_CONNECT, /* 7 */ @@ -402,13 +425,18 @@ typedef enum { CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server due to lack of access - when login fails this is not returned. */ - CURLE_OBSOLETE10, /* 10 - NOT USED */ + CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for + 7.15.4, reused in Dec 2011 for 7.24.0]*/ CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ - CURLE_OBSOLETE12, /* 12 - NOT USED */ + CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server + [was obsoleted in August 2007 for 7.17.0, + reused in Dec 2011 for 7.24.0]*/ CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ CURLE_FTP_CANT_GET_HOST, /* 15 */ - CURLE_OBSOLETE16, /* 16 - NOT USED */ + CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. + [was obsoleted in August 2007 for 7.17.0, + reused in July 2014 for 7.38.0] */ CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ CURLE_PARTIAL_FILE, /* 18 */ CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ @@ -444,7 +472,7 @@ typedef enum { CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ CURLE_OBSOLETE46, /* 46 - NOT USED */ CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */ - CURLE_UNKNOWN_TELNET_OPTION, /* 48 - User specified an unknown option */ + CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */ CURLE_OBSOLETE50, /* 50 - NOT USED */ CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint @@ -459,7 +487,7 @@ typedef enum { CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */ - CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized transfer encoding */ + CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ @@ -499,17 +527,32 @@ typedef enum { 7.19.0) */ CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ - CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Identifiers */ + CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ - + CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the + session will be queued */ + CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not + match */ + CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ CURL_LAST /* never use! */ } CURLcode; #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all the obsolete stuff removed! */ -/* Backwards compatibility with older names */ +/* Previously obsolete error code re-used in 7.38.0 */ +#define CURLE_OBSOLETE16 CURLE_HTTP2 + +/* Previously obsolete error codes re-used in 7.24.0 */ +#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED +#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT + +/* compatibility with older names */ +#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING + +/* The following were added in 7.21.5, April 2011 */ +#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION /* The following were added in 7.17.1 */ /* These are scheduled to disappear by 2009 */ @@ -517,7 +560,7 @@ typedef enum { /* The following were added in 7.17.0 */ /* These are scheduled to disappear by 2009 */ -#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* noone should be using this! */ +#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ #define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 #define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 #define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 @@ -529,7 +572,7 @@ typedef enum { #define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 #define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 #define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 -#define CURLE_URL_MALFORMAT_USER CURLE_OBSOLETE4 +#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN #define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED #define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE @@ -555,6 +598,16 @@ typedef enum { make programs break */ #define CURLE_ALREADY_COMPLETE 99999 +/* Provide defines for really old option names */ +#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ +#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ +#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA + +/* Since long deprecated options with no code in the lib that does anything + with them. */ +#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 +#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 + #endif /*!CURL_NO_OLDIES*/ /* This prototype applies to all conversion callbacks */ @@ -579,17 +632,35 @@ typedef enum { in 7.18.0 */ } curl_proxytype; /* this enum was added in 7.10 */ -#define CURLAUTH_NONE 0 /* nothing */ -#define CURLAUTH_BASIC (1<<0) /* Basic (default) */ -#define CURLAUTH_DIGEST (1<<1) /* Digest */ -#define CURLAUTH_GSSNEGOTIATE (1<<2) /* GSS-Negotiate */ -#define CURLAUTH_NTLM (1<<3) /* NTLM */ -#define CURLAUTH_DIGEST_IE (1<<4) /* Digest with IE flavour */ -#define CURLAUTH_ONLY (1<<31) /* used together with a single other - type to force no auth or just that - single type */ -#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) /* all fine types set */ -#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) +/* + * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: + * + * CURLAUTH_NONE - No HTTP authentication + * CURLAUTH_BASIC - HTTP Basic authentication (default) + * CURLAUTH_DIGEST - HTTP Digest authentication + * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication + * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) + * CURLAUTH_NTLM - HTTP NTLM authentication + * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour + * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper + * CURLAUTH_ONLY - Use together with a single other type to force no + * authentication or just that single type + * CURLAUTH_ANY - All fine types set + * CURLAUTH_ANYSAFE - All fine types except Basic + */ + +#define CURLAUTH_NONE ((unsigned long)0) +#define CURLAUTH_BASIC (((unsigned long)1)<<0) +#define CURLAUTH_DIGEST (((unsigned long)1)<<1) +#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) +/* Deprecated since the advent of CURLAUTH_NEGOTIATE */ +#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE +#define CURLAUTH_NTLM (((unsigned long)1)<<3) +#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) +#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) +#define CURLAUTH_ONLY (((unsigned long)1)<<31) +#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) +#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) #define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ #define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ @@ -597,20 +668,27 @@ typedef enum { #define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ #define CURLSSH_AUTH_HOST (1<<2) /* host key files */ #define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ +#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ #define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY +#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ +#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ +#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ + #define CURL_ERROR_SIZE 256 +enum curl_khtype { + CURLKHTYPE_UNKNOWN, + CURLKHTYPE_RSA1, + CURLKHTYPE_RSA, + CURLKHTYPE_DSS +}; + struct curl_khkey { const char *key; /* points to a zero-terminated string encoded with base64 if len is zero, otherwise to the "raw" data */ size_t len; - enum type { - CURLKHTYPE_UNKNOWN, - CURLKHTYPE_RSA1, - CURLKHTYPE_RSA, - CURLKHTYPE_DSS - } keytype; + enum curl_khtype keytype; }; /* this is the set of return values expected from the curl_sshkeycallback @@ -649,6 +727,19 @@ typedef enum { CURLUSESSL_LAST /* not an option, never use */ } curl_usessl; +/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ + +/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the + name of improving interoperability with older servers. Some SSL libraries + have introduced work-arounds for this flaw but those work-arounds sometimes + make the SSL communication fail. To regain functionality with those broken + servers, a user can this way allow the vulnerability back. */ +#define CURLSSLOPT_ALLOW_BEAST (1<<0) + +/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those + SSL backends where such behavior is present. */ +#define CURLSSLOPT_NO_REVOKE (1<<1) + #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all the obsolete stuff removed! */ @@ -699,6 +790,10 @@ typedef enum { CURLFTPMETHOD_LAST /* not an option, never use */ } curl_ftpmethod; +/* bitmask defines for CURLOPT_HEADEROPT */ +#define CURLHEADER_UNIFIED 0 +#define CURLHEADER_SEPARATE (1<<0) + /* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ #define CURLPROTO_HTTP (1<<0) #define CURLPROTO_HTTPS (1<<1) @@ -726,15 +821,21 @@ typedef enum { #define CURLPROTO_RTMPS (1<<23) #define CURLPROTO_RTMPTS (1<<24) #define CURLPROTO_GOPHER (1<<25) +#define CURLPROTO_SMB (1<<26) +#define CURLPROTO_SMBS (1<<27) #define CURLPROTO_ALL (~0) /* enable everything */ /* long may be 32 or 64 bits, but we should never depend on anything else but 32 */ #define CURLOPTTYPE_LONG 0 #define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_STRINGPOINT 10000 #define CURLOPTTYPE_FUNCTIONPOINT 20000 #define CURLOPTTYPE_OFF_T 30000 +/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the + string options from the header file */ + /* name is uppercase CURLOPT_, type is one of the defined CURLOPTTYPE_ number is unique identifier */ @@ -743,11 +844,12 @@ typedef enum { #endif #ifdef CURL_ISOCPP -#define CINIT(name,type,number) CURLOPT_ ## name = CURLOPTTYPE_ ## type + number +#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu #else /* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ #define LONG CURLOPTTYPE_LONG #define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define STRINGPOINT CURLOPTTYPE_OBJECTPOINT #define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT #define OFF_T CURLOPTTYPE_OFF_T #define CINIT(name,type,number) CURLOPT_/**/name = type + number @@ -761,30 +863,30 @@ typedef enum { typedef enum { /* This is the FILE * or void * the regular output should be written to. */ - CINIT(FILE, OBJECTPOINT, 1), + CINIT(WRITEDATA, OBJECTPOINT, 1), /* The full URL to get/put */ - CINIT(URL, OBJECTPOINT, 2), + CINIT(URL, STRINGPOINT, 2), /* Port number to connect to, if other than default. */ CINIT(PORT, LONG, 3), /* Name of proxy to use. */ - CINIT(PROXY, OBJECTPOINT, 4), + CINIT(PROXY, STRINGPOINT, 4), - /* "name:password" to use when fetching. */ - CINIT(USERPWD, OBJECTPOINT, 5), + /* "user:password;options" to use when fetching. */ + CINIT(USERPWD, STRINGPOINT, 5), - /* "name:password" to use with proxy. */ - CINIT(PROXYUSERPWD, OBJECTPOINT, 6), + /* "user:password" to use with proxy. */ + CINIT(PROXYUSERPWD, STRINGPOINT, 6), /* Range to get, specified as an ASCII string. */ - CINIT(RANGE, OBJECTPOINT, 7), + CINIT(RANGE, STRINGPOINT, 7), /* not used */ /* Specified file stream to upload from (use as input): */ - CINIT(INFILE, OBJECTPOINT, 9), + CINIT(READDATA, OBJECTPOINT, 9), /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE * bytes big. If this is not used, error messages go to stderr instead: */ @@ -816,14 +918,14 @@ typedef enum { CINIT(POSTFIELDS, OBJECTPOINT, 15), /* Set the referrer page (needed by some CGIs) */ - CINIT(REFERER, OBJECTPOINT, 16), + CINIT(REFERER, STRINGPOINT, 16), /* Set the FTP PORT string (interface name, named or numerical IP address) Use i.e '-' to use default address. */ - CINIT(FTPPORT, OBJECTPOINT, 17), + CINIT(FTPPORT, STRINGPOINT, 17), /* Set the User-Agent string (examined by some CGIs) */ - CINIT(USERAGENT, OBJECTPOINT, 18), + CINIT(USERAGENT, STRINGPOINT, 18), /* If the download receives less than "low speed limit" bytes/second * during "low speed time" seconds, the operations is aborted. @@ -846,19 +948,20 @@ typedef enum { CINIT(RESUME_FROM, LONG, 21), /* Set cookie in request: */ - CINIT(COOKIE, OBJECTPOINT, 22), + CINIT(COOKIE, STRINGPOINT, 22), - /* This points to a linked list of headers, struct curl_slist kind */ + /* This points to a linked list of headers, struct curl_slist kind. This + list is also used for RTSP (in spite of its name) */ CINIT(HTTPHEADER, OBJECTPOINT, 23), /* This points to a linked list of post entries, struct curl_httppost */ CINIT(HTTPPOST, OBJECTPOINT, 24), /* name of the file keeping your private SSL-certificate */ - CINIT(SSLCERT, OBJECTPOINT, 25), + CINIT(SSLCERT, STRINGPOINT, 25), /* password for the SSL or SSH private key */ - CINIT(KEYPASSWD, OBJECTPOINT, 26), + CINIT(KEYPASSWD, STRINGPOINT, 26), /* send TYPE parameter? */ CINIT(CRLF, LONG, 27), @@ -868,11 +971,11 @@ typedef enum { /* send FILE * or void * to store headers to, if you use a callback it is simply passed to the callback unmodified */ - CINIT(WRITEHEADER, OBJECTPOINT, 29), + CINIT(HEADERDATA, OBJECTPOINT, 29), /* point to a file to read the initial cookies from, also enables "cookie awareness" */ - CINIT(COOKIEFILE, OBJECTPOINT, 31), + CINIT(COOKIEFILE, STRINGPOINT, 31), /* What version to specifically try to use. See CURL_SSLVERSION defines below. */ @@ -891,9 +994,9 @@ typedef enum { HTTP: DELETE, TRACE and others FTP: to use a different list command */ - CINIT(CUSTOMREQUEST, OBJECTPOINT, 36), + CINIT(CUSTOMREQUEST, STRINGPOINT, 36), - /* HTTP request, for odd commands like DELETE, TRACE and others */ + /* FILE handle to use instead of stderr */ CINIT(STDERR, OBJECTPOINT, 37), /* 38 is not used */ @@ -901,18 +1004,16 @@ typedef enum { /* send linked-list of post-transfer QUOTE commands */ CINIT(POSTQUOTE, OBJECTPOINT, 39), - /* Pass a pointer to string of the output using full variable-replacement - as described elsewhere. */ - CINIT(WRITEINFO, OBJECTPOINT, 40), + CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */ CINIT(VERBOSE, LONG, 41), /* talk a lot */ CINIT(HEADER, LONG, 42), /* throw the header out too */ CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ - CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 300 */ + CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */ CINIT(UPLOAD, LONG, 46), /* this is an upload */ CINIT(POST, LONG, 47), /* HTTP POST method */ - CINIT(DIRLISTONLY, LONG, 48), /* return bare names when listing directories */ + CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */ @@ -927,13 +1028,16 @@ typedef enum { /* 55 = OBSOLETE */ - /* Function that will be called instead of the internal progress display + /* DEPRECATED + * Function that will be called instead of the internal progress display * function. This function should be defined as the curl_progress_callback * prototype defines. */ CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), - /* Data passed to the progress callback */ + /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION + callbacks */ CINIT(PROGRESSDATA, OBJECTPOINT, 57), +#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA /* We want the referrer field set automatically when following locations */ CINIT(AUTOREFERER, LONG, 58), @@ -949,19 +1053,19 @@ typedef enum { CINIT(HTTPPROXYTUNNEL, LONG, 61), /* Set the interface string to use as outgoing network interface */ - CINIT(INTERFACE, OBJECTPOINT, 62), + CINIT(INTERFACE, STRINGPOINT, 62), /* Set the krb4/5 security level, this also enables krb4/5 awareness. This * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string * is set but doesn't match one of these, 'private' will be used. */ - CINIT(KRBLEVEL, OBJECTPOINT, 63), + CINIT(KRBLEVEL, STRINGPOINT, 63), /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ CINIT(SSL_VERIFYPEER, LONG, 64), /* The CApath or CAfile used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ - CINIT(CAINFO, OBJECTPOINT, 65), + CINIT(CAINFO, STRINGPOINT, 65), /* 66 = OBSOLETE */ /* 67 = OBSOLETE */ @@ -979,9 +1083,7 @@ typedef enum { /* Max amount of cached alive connections */ CINIT(MAXCONNECTS, LONG, 71), - /* What policy to use when closing connections when the cache is filled - up */ - CINIT(CLOSEPOLICY, LONG, 72), + CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */ /* 73 = OBSOLETE */ @@ -997,14 +1099,13 @@ typedef enum { /* Set to a file name that contains random data for libcurl to use to seed the random engine when doing SSL connects. */ - CINIT(RANDOM_FILE, OBJECTPOINT, 76), + CINIT(RANDOM_FILE, STRINGPOINT, 76), /* Set to the Entropy Gathering Daemon socket pathname */ - CINIT(EGDSOCKET, OBJECTPOINT, 77), + CINIT(EGDSOCKET, STRINGPOINT, 77), - /* Time-out connect operations after this amount of seconds, if connects - are OK within this time, then fine... This only aborts the connect - phase. [Only works on unix-style/SIGALRM operating systems] */ + /* Time-out connect operations after this amount of seconds, if connects are + OK within this time, then fine... This only aborts the connect phase. */ CINIT(CONNECTTIMEOUT, LONG, 78), /* Function that will be called to store headers (instead of fwrite). The @@ -1023,10 +1124,10 @@ typedef enum { /* Specify which file name to write all known cookies in after completed operation. Set file name to "-" (dash) to make it go to stdout. */ - CINIT(COOKIEJAR, OBJECTPOINT, 82), + CINIT(COOKIEJAR, STRINGPOINT, 82), /* Specify which SSL ciphers to use */ - CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83), + CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83), /* Specify which HTTP version to use! This must be set to one of the CURL_HTTP_VERSION* enums set below. */ @@ -1038,16 +1139,16 @@ typedef enum { CINIT(FTP_USE_EPSV, LONG, 85), /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ - CINIT(SSLCERTTYPE, OBJECTPOINT, 86), + CINIT(SSLCERTTYPE, STRINGPOINT, 86), /* name of the file keeping your private SSL-key */ - CINIT(SSLKEY, OBJECTPOINT, 87), + CINIT(SSLKEY, STRINGPOINT, 87), /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ - CINIT(SSLKEYTYPE, OBJECTPOINT, 88), + CINIT(SSLKEYTYPE, STRINGPOINT, 88), /* crypto engine for the SSL-sub system */ - CINIT(SSLENGINE, OBJECTPOINT, 89), + CINIT(SSLENGINE, STRINGPOINT, 89), /* set the crypto engine for the SSL-sub system as default the param has no meaning... @@ -1055,7 +1156,7 @@ typedef enum { CINIT(SSLENGINE_DEFAULT, LONG, 90), /* Non-zero value means to use the global dns cache */ - CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* To become OBSOLETE soon */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ /* DNS cache timeout */ CINIT(DNS_CACHE_TIMEOUT, LONG, 92), @@ -1074,7 +1175,7 @@ typedef enum { /* The CApath directory used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ - CINIT(CAPATH, OBJECTPOINT, 97), + CINIT(CAPATH, STRINGPOINT, 97), /* Instruct libcurl to use a smaller receive buffer */ CINIT(BUFFERSIZE, LONG, 98), @@ -1092,8 +1193,9 @@ typedef enum { CINIT(PROXYTYPE, LONG, 101), /* Set the Accept-Encoding string. Use this to tell a server you would like - the response to be compressed. */ - CINIT(ENCODING, OBJECTPOINT, 102), + the response to be compressed. Before 7.21.6, this was known as + CURLOPT_ENCODING */ + CINIT(ACCEPT_ENCODING, STRINGPOINT, 102), /* Set pointer to private data */ CINIT(PRIVATE, OBJECTPOINT, 103), @@ -1106,8 +1208,8 @@ typedef enum { and password to whatever host the server decides. */ CINIT(UNRESTRICTED_AUTH, LONG, 105), - /* Specifically switch on or off the FTP engine's use of the EPRT command ( it - also disables the LPRT attempt). By default, those ones will always be + /* Specifically switch on or off the FTP engine's use of the EPRT command ( + it also disables the LPRT attempt). By default, those ones will always be attempted before the good old traditional PORT command. */ CINIT(FTP_USE_EPRT, LONG, 106), @@ -1174,12 +1276,12 @@ typedef enum { to parse (using the CURLOPT_NETRC option). If not set, libcurl will do a poor attempt to find the user's home directory and check for a .netrc file in there. */ - CINIT(NETRC_FILE, OBJECTPOINT, 118), + CINIT(NETRC_FILE, STRINGPOINT, 118), /* Enable SSL/TLS for FTP, pick one of: - CURLFTPSSL_TRY - try using SSL, proceed anyway otherwise - CURLFTPSSL_CONTROL - SSL for the control connection or fail - CURLFTPSSL_ALL - SSL for all communication or fail + CURLUSESSL_TRY - try using SSL, proceed anyway otherwise + CURLUSESSL_CONTROL - SSL for the control connection or fail + CURLUSESSL_ALL - SSL for all communication or fail */ CINIT(USE_SSL, LONG, 119), @@ -1217,10 +1319,10 @@ typedef enum { /* zero terminated string for pass on to the FTP server when asked for "account" info */ - CINIT(FTP_ACCOUNT, OBJECTPOINT, 134), + CINIT(FTP_ACCOUNT, STRINGPOINT, 134), - /* feed cookies into cookie engine */ - CINIT(COOKIELIST, OBJECTPOINT, 135), + /* feed cookie into cookie engine */ + CINIT(COOKIELIST, STRINGPOINT, 135), /* ignore Content-Length */ CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), @@ -1266,7 +1368,7 @@ typedef enum { CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), /* Pointer to command string to send if USER/PASS fails. */ - CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147), + CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147), /* callback function for setting socket options */ CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), @@ -1280,8 +1382,8 @@ typedef enum { CINIT(SSH_AUTH_TYPES, LONG, 151), /* Used by scp/sftp to do public/private key authentication */ - CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152), - CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153), + CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152), + CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153), /* Send CCC (Clear Command Channel) after authentication */ CINIT(FTP_SSL_CCC, LONG, 154), @@ -1305,7 +1407,7 @@ typedef enum { CINIT(POSTREDIR, LONG, 161), /* used by scp/sftp to verify the host's public key */ - CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162), + CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162), /* Callback function for opening socket (instead of socket(2)). Optionally, callback is able change the address or refuse to connect returning @@ -1325,26 +1427,25 @@ typedef enum { CINIT(SEEKDATA, OBJECTPOINT, 168), /* CRL file */ - CINIT(CRLFILE, OBJECTPOINT, 169), + CINIT(CRLFILE, STRINGPOINT, 169), /* Issuer certificate */ - CINIT(ISSUERCERT, OBJECTPOINT, 170), + CINIT(ISSUERCERT, STRINGPOINT, 170), /* (IPv6) Address scope */ CINIT(ADDRESS_SCOPE, LONG, 171), /* Collect certificate chain info and allow it to get retrievable with - CURLINFO_CERTINFO after the transfer is complete. (Unfortunately) only - working with OpenSSL-powered builds. */ + CURLINFO_CERTINFO after the transfer is complete. */ CINIT(CERTINFO, LONG, 172), /* "name" and "pwd" to use when fetching. */ - CINIT(USERNAME, OBJECTPOINT, 173), - CINIT(PASSWORD, OBJECTPOINT, 174), + CINIT(USERNAME, STRINGPOINT, 173), + CINIT(PASSWORD, STRINGPOINT, 174), /* "name" and "pwd" to use with Proxy when fetching. */ - CINIT(PROXYUSERNAME, OBJECTPOINT, 175), - CINIT(PROXYPASSWORD, OBJECTPOINT, 176), + CINIT(PROXYUSERNAME, STRINGPOINT, 175), + CINIT(PROXYPASSWORD, STRINGPOINT, 176), /* Comma separated list of hostnames defining no-proxy zones. These should match both hostnames directly, and hostnames within a domain. For @@ -1353,13 +1454,13 @@ typedef enum { implementations of this, .local.com will be considered to be the same as local.com. A single * is the only valid wildcard, and effectively disables the use of proxy. */ - CINIT(NOPROXY, OBJECTPOINT, 177), + CINIT(NOPROXY, STRINGPOINT, 177), /* block size for TFTP transfers */ CINIT(TFTP_BLKSIZE, LONG, 178), /* Socks Service */ - CINIT(SOCKS5_GSSAPI_SERVICE, OBJECTPOINT, 179), + CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* Socks Service */ CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), @@ -1377,7 +1478,7 @@ typedef enum { CINIT(REDIR_PROTOCOLS, LONG, 182), /* set the SSH knownhost file name to use */ - CINIT(SSH_KNOWNHOSTS, OBJECTPOINT, 183), + CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183), /* set the SSH host key callback, must point to a curl_sshkeycallback function */ @@ -1387,9 +1488,9 @@ typedef enum { CINIT(SSH_KEYDATA, OBJECTPOINT, 185), /* set the SMTP mail originator */ - CINIT(MAIL_FROM, OBJECTPOINT, 186), + CINIT(MAIL_FROM, STRINGPOINT, 186), - /* set the SMTP mail receiver(s) */ + /* set the list of SMTP mail receiver(s) */ CINIT(MAIL_RCPT, OBJECTPOINT, 187), /* FTP: send PRET before PASV */ @@ -1399,13 +1500,13 @@ typedef enum { CINIT(RTSP_REQUEST, LONG, 189), /* The RTSP session identifier */ - CINIT(RTSP_SESSION_ID, OBJECTPOINT, 190), + CINIT(RTSP_SESSION_ID, STRINGPOINT, 190), /* The RTSP stream URI */ - CINIT(RTSP_STREAM_URI, OBJECTPOINT, 191), + CINIT(RTSP_STREAM_URI, STRINGPOINT, 191), /* The Transport: header to use in RTSP requests */ - CINIT(RTSP_TRANSPORT, OBJECTPOINT, 192), + CINIT(RTSP_TRANSPORT, STRINGPOINT, 192), /* Manually initialize the client RTSP CSeq for this handle */ CINIT(RTSP_CLIENT_CSEQ, LONG, 193), @@ -1442,6 +1543,139 @@ typedef enum { /* send linked-list of name:port:address sets */ CINIT(RESOLVE, OBJECTPOINT, 203), + /* Set a username for authenticated TLS */ + CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204), + + /* Set a password for authenticated TLS */ + CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205), + + /* Set authentication type for authenticated TLS */ + CINIT(TLSAUTH_TYPE, STRINGPOINT, 206), + + /* Set to 1 to enable the "TE:" header in HTTP requests to ask for + compressed transfer-encoded responses. Set to 0 to disable the use of TE: + in outgoing requests. The current default is 0, but it might change in a + future libcurl release. + + libcurl will ask for the compressed methods it knows of, and if that + isn't any, it will not ask for transfer-encoding at all even if this + option is set to 1. + + */ + CINIT(TRANSFER_ENCODING, LONG, 207), + + /* Callback function for closing socket (instead of close(2)). The callback + should have type curl_closesocket_callback */ + CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), + CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), + + /* allow GSSAPI credential delegation */ + CINIT(GSSAPI_DELEGATION, LONG, 210), + + /* Set the name servers to use for DNS resolution */ + CINIT(DNS_SERVERS, STRINGPOINT, 211), + + /* Time-out accept operations (currently for FTP only) after this amount + of miliseconds. */ + CINIT(ACCEPTTIMEOUT_MS, LONG, 212), + + /* Set TCP keepalive */ + CINIT(TCP_KEEPALIVE, LONG, 213), + + /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ + CINIT(TCP_KEEPIDLE, LONG, 214), + CINIT(TCP_KEEPINTVL, LONG, 215), + + /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ + CINIT(SSL_OPTIONS, LONG, 216), + + /* Set the SMTP auth originator */ + CINIT(MAIL_AUTH, STRINGPOINT, 217), + + /* Enable/disable SASL initial response */ + CINIT(SASL_IR, LONG, 218), + + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_xferinfo_callback + * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ + CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), + + /* The XOAUTH2 bearer token */ + CINIT(XOAUTH2_BEARER, STRINGPOINT, 220), + + /* Set the interface string to use as outgoing network + * interface for DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_INTERFACE, STRINGPOINT, 221), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223), + + /* Set authentication options directly */ + CINIT(LOGIN_OPTIONS, STRINGPOINT, 224), + + /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_NPN, LONG, 225), + + /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_ALPN, LONG, 226), + + /* Time to wait for a response to a HTTP request containing an + * Expect: 100-continue header before sending the data anyway. */ + CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227), + + /* This points to a linked list of headers used for proxy requests only, + struct curl_slist kind */ + CINIT(PROXYHEADER, OBJECTPOINT, 228), + + /* Pass in a bitmask of "header options" */ + CINIT(HEADEROPT, LONG, 229), + + /* The public key in DER form used to validate the peer public key + this option is used only if SSL_VERIFYPEER is true */ + CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230), + + /* Path to Unix domain socket */ + CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231), + + /* Set if we should verify the certificate status. */ + CINIT(SSL_VERIFYSTATUS, LONG, 232), + + /* Set if we should enable TLS false start. */ + CINIT(SSL_FALSESTART, LONG, 233), + + /* Do not squash dot-dot sequences */ + CINIT(PATH_AS_IS, LONG, 234), + + /* Proxy Service Name */ + CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235), + + /* Service Name */ + CINIT(SERVICE_NAME, STRINGPOINT, 236), + + /* Wait/don't wait for pipe/mutex to clarify */ + CINIT(PIPEWAIT, LONG, 237), + + /* Set the protocol used when curl is given a URL without a protocol */ + CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238), + + /* Set stream weight, 1 - 256 (default is 16) */ + CINIT(STREAM_WEIGHT, LONG, 239), + + /* Set stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS, OBJECTPOINT, 240), + + /* Set E-xclusive stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241), + + /* Do not send any tftp option requests to the server */ + CINIT(TFTP_NO_OPTIONS, LONG, 242), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -1478,13 +1712,10 @@ typedef enum { option might be handy to force libcurl to use a specific IP version. */ #define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP versions that your system allows */ -#define CURL_IPRESOLVE_V4 1 /* resolve to ipv4 addresses */ -#define CURL_IPRESOLVE_V6 2 /* resolve to ipv6 addresses */ +#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */ +#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */ /* three convenient "aliases" that follow the name scheme better */ -#define CURLOPT_WRITEDATA CURLOPT_FILE -#define CURLOPT_READDATA CURLOPT_INFILE -#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER #define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ @@ -1494,10 +1725,17 @@ enum { for us! */ CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ + CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ + CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ }; +/* Convenience definition simple because the name of the version is HTTP/2 and + not 2.0. The 2_0 version of the enum name was set while the version was + still planned to be 2.0 and we stick to it for compatibility. */ +#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 + /* * Public API enums for RTSP requests */ @@ -1531,21 +1769,33 @@ enum CURL_NETRC_OPTION { enum { CURL_SSLVERSION_DEFAULT, - CURL_SSLVERSION_TLSv1, + CURL_SSLVERSION_TLSv1, /* TLS 1.x */ CURL_SSLVERSION_SSLv2, CURL_SSLVERSION_SSLv3, + CURL_SSLVERSION_TLSv1_0, + CURL_SSLVERSION_TLSv1_1, + CURL_SSLVERSION_TLSv1_2, CURL_SSLVERSION_LAST /* never use, keep last */ }; +enum CURL_TLSAUTH { + CURL_TLSAUTH_NONE, + CURL_TLSAUTH_SRP, + CURL_TLSAUTH_LAST /* never use, keep last */ +}; + /* symbols to use with CURLOPT_POSTREDIR. - CURL_REDIR_POST_301 and CURL_REDIR_POST_302 can be bitwise ORed so that - CURL_REDIR_POST_301 | CURL_REDIR_POST_302 == CURL_REDIR_POST_ALL */ + CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 + can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 + | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ #define CURL_REDIR_GET_ALL 0 #define CURL_REDIR_POST_301 1 #define CURL_REDIR_POST_302 2 -#define CURL_REDIR_POST_ALL (CURL_REDIR_POST_301|CURL_REDIR_POST_302) +#define CURL_REDIR_POST_303 4 +#define CURL_REDIR_POST_ALL \ + (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) typedef enum { CURL_TIMECOND_NONE, @@ -1601,6 +1851,7 @@ typedef enum { CFINIT(OBSOLETE2), CFINIT(STREAM), + CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */ CURLFORM_LASTENTRY /* the last unused */ } CURLformoption; @@ -1664,7 +1915,8 @@ CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, * Should return the buffer length passed to it as the argument "len" on * success. */ -typedef size_t (*curl_formget_callback)(void *arg, const char *buf, size_t len); +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, + size_t len); /* * NAME curl_formget() @@ -1842,10 +2094,35 @@ struct curl_certinfo { format "name: value" */ }; +/* enum for the different supported SSL backends */ +typedef enum { + CURLSSLBACKEND_NONE = 0, + CURLSSLBACKEND_OPENSSL = 1, + CURLSSLBACKEND_GNUTLS = 2, + CURLSSLBACKEND_NSS = 3, + CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ + CURLSSLBACKEND_GSKIT = 5, + CURLSSLBACKEND_POLARSSL = 6, + CURLSSLBACKEND_CYASSL = 7, + CURLSSLBACKEND_SCHANNEL = 8, + CURLSSLBACKEND_DARWINSSL = 9, + CURLSSLBACKEND_AXTLS = 10, + CURLSSLBACKEND_MBEDTLS = 11 +} curl_sslbackend; + +/* Information about the SSL library used and the respective internal SSL + handle, which can be used to obtain further information regarding the + connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ +struct curl_tlssessioninfo { + curl_sslbackend backend; + void *internals; +}; + #define CURLINFO_STRING 0x100000 #define CURLINFO_LONG 0x200000 #define CURLINFO_DOUBLE 0x300000 #define CURLINFO_SLIST 0x400000 +#define CURLINFO_SOCKET 0x500000 #define CURLINFO_MASK 0x0fffff #define CURLINFO_TYPEMASK 0xf00000 @@ -1893,9 +2170,12 @@ typedef enum { CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, + CURLINFO_TLS_SESSION = CURLINFO_SLIST + 43, + CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, + CURLINFO_TLS_SSL_PTR = CURLINFO_SLIST + 45, /* Fill in new entries below here! */ - CURLINFO_LASTONE = 42 + CURLINFO_LASTONE = 45 } CURLINFO; /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as @@ -1919,6 +2199,7 @@ typedef enum { #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) #define CURL_GLOBAL_NOTHING 0 #define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL +#define CURL_GLOBAL_ACK_EINTR (1<<2) /***************************************************************************** @@ -1963,8 +2244,9 @@ typedef enum { CURLSHE_BAD_OPTION, /* 1 */ CURLSHE_IN_USE, /* 2 */ CURLSHE_INVALID, /* 3 */ - CURLSHE_NOMEM, /* out of memory */ - CURLSHE_LAST /* never use */ + CURLSHE_NOMEM, /* 4 out of memory */ + CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ + CURLSHE_LAST /* never use */ } CURLSHcode; typedef enum { @@ -2029,22 +2311,34 @@ typedef struct { } curl_version_info_data; -#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ -#define CURL_VERSION_KERBEROS4 (1<<1) /* kerberos auth is supported */ -#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ -#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ -#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ -#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth support */ -#define CURL_VERSION_DEBUG (1<<6) /* built with debug capabilities */ -#define CURL_VERSION_ASYNCHDNS (1<<7) /* asynchronous dns resolves */ -#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth */ -#define CURL_VERSION_LARGEFILE (1<<9) /* supports files bigger than 2GB */ -#define CURL_VERSION_IDN (1<<10) /* International Domain Names support */ -#define CURL_VERSION_SSPI (1<<11) /* SSPI is supported */ -#define CURL_VERSION_CONV (1<<12) /* character conversions supported */ -#define CURL_VERSION_CURLDEBUG (1<<13) /* debug memory tracking supported */ +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported + (deprecated) */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported + (deprecated) */ +#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ +#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are + supported */ +#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ +#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ +#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ +#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ +#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper + is suported */ +#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ +#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ +#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ +#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ +#define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used + for cookie domain verification */ -/* + /* * NAME curl_version_info() * * DESCRIPTION diff --git a/project/jni/curl/include/curl/curlbuild.h b/project/jni/curl/include/curl/curlbuild.h index 81f4a2854..d7ab0be3e 100644 --- a/project/jni/curl/include/curl/curlbuild.h +++ b/project/jni/curl/include/curl/curlbuild.h @@ -153,7 +153,11 @@ #endif /* The size of `long', as computed by sizeof. */ +#ifdef __LP64__ +#define CURL_SIZEOF_LONG 8 +#else #define CURL_SIZEOF_LONG 4 +#endif /* Integral data type used for curl_socklen_t. */ #define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t diff --git a/project/jni/curl/include/curl/curlrules.h b/project/jni/curl/include/curl/curlrules.h index 8aad1df67..55d21f68f 100644 --- a/project/jni/curl/include/curl/curlrules.h +++ b/project/jni/curl/include/curl/curlrules.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -47,7 +47,7 @@ * library is properly built and used. * * You can find further help on the libcurl development mailing list: - * http://cool.haxx.se/mailman/listinfo/curl-library/ + * https://cool.haxx.se/mailman/listinfo/curl-library/ * * NOTE 2 * ------ @@ -190,7 +190,7 @@ typedef char * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow * these to be visible and exported by the external libcurl interface API, * while also making them visible to the library internals, simply including - * setup.h, without actually needing to include curl.h internally. + * curl_setup.h, without actually needing to include curl.h internally. * If some day this section would grow big enough, all this should be moved * to its own header file. */ @@ -216,14 +216,23 @@ typedef char * Macros for minimum-width signed and unsigned curl_off_t integer constants. */ -#ifdef CURL_ISOCPP -# define __CURL_OFF_T_C_HELPER2(Val,Suffix) Val ## Suffix +#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) +# define __CURL_OFF_T_C_HLPR2(x) x +# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) #else -# define __CURL_OFF_T_C_HELPER2(Val,Suffix) Val/**/Suffix +# ifdef CURL_ISOCPP +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix +# else +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix +# endif +# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) #endif -#define __CURL_OFF_T_C_HELPER1(Val,Suffix) __CURL_OFF_T_C_HELPER2(Val,Suffix) -#define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HELPER1(Val,CURL_SUFFIX_CURL_OFF_T) -#define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HELPER1(Val,CURL_SUFFIX_CURL_OFF_TU) /* * Get rid of macros private to this header file. @@ -239,6 +248,7 @@ typedef char #undef CURL_PULL_WS2TCPIP_H #undef CURL_PULL_SYS_TYPES_H #undef CURL_PULL_SYS_SOCKET_H +#undef CURL_PULL_SYS_POLL_H #undef CURL_PULL_STDINT_H #undef CURL_PULL_INTTYPES_H diff --git a/project/jni/curl/include/curl/curlver.h b/project/jni/curl/include/curl/curlver.h index 7c3ccc905..18c10fe1e 100644 --- a/project/jni/curl/include/curl/curlver.h +++ b/project/jni/curl/include/curl/curlver.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,17 +26,17 @@ a script at release-time. This was made its own header file in 7.11.2 */ /* This is the global package copyright */ -#define LIBCURL_COPYRIGHT "1996 - 2010 Daniel Stenberg, ." +#define LIBCURL_COPYRIGHT "1996 - 2016 Daniel Stenberg, ." /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.21.3" +#define LIBCURL_VERSION "7.48.0" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 21 -#define LIBCURL_VERSION_PATCH 3 +#define LIBCURL_VERSION_MINOR 48 +#define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier parsing and comparions by programs. The LIBCURL_VERSION_NUM define will @@ -52,8 +52,12 @@ This 6-digit (24 bits) hexadecimal number does not show pre-release number, and it is always a greater number in a more recent release. It makes comparisons with greater than and less than work. + + Note: This define is the full hex number and _does not_ use the + CURL_VERSION_BITS() macro since curl's own configure script greps for it + and needs it to contain the full number. */ -#define LIBCURL_VERSION_NUM 0x071503 +#define LIBCURL_VERSION_NUM 0x073000 /* * This is the date and time when the full source package was created. The @@ -64,6 +68,10 @@ * * "Mon Feb 12 11:35:33 UTC 2007" */ -#define LIBCURL_TIMESTAMP "Wed Dec 15 14:07:08 UTC 2010" +#define LIBCURL_TIMESTAMP "Wed Mar 23 06:57:50 UTC 2016" + +#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) +#define CURL_AT_LEAST_VERSION(x,y,z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) #endif /* __CURL_CURLVER_H */ diff --git a/project/jni/curl/include/curl/easy.h b/project/jni/curl/include/curl/easy.h index 1ddb4fe5a..afc766cd2 100644 --- a/project/jni/curl/include/curl/easy.h +++ b/project/jni/curl/include/curl/easy.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -53,8 +53,8 @@ CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); * * Creates a new curl session handle with the same options set for the handle * passed in. Duplicating a handle could only be a matter of cloning data and - * options, internal state info and things like persistant connections cannot - * be transfered. It is useful in multithreaded applications when you can run + * options, internal state info and things like persistent connections cannot + * be transferred. It is useful in multithreaded applications when you can run * curl_easy_duphandle() for each new thread to avoid a series of identical * curl_easy_setopt() invokes in every thread. */ diff --git a/project/jni/curl/include/curl/mprintf.h b/project/jni/curl/include/curl/mprintf.h index de7dd2f3c..de8c96248 100644 --- a/project/jni/curl/include/curl/mprintf.h +++ b/project/jni/curl/include/curl/mprintf.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -57,15 +57,8 @@ CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); # undef vaprintf # define printf curl_mprintf # define fprintf curl_mfprintf -#ifdef CURLDEBUG -/* When built with CURLDEBUG we define away the sprintf() functions since we - don't want internal code to be using them */ -# define sprintf sprintf_was_used -# define vsprintf vsprintf_was_used -#else # define sprintf curl_msprintf # define vsprintf curl_mvsprintf -#endif # define snprintf curl_msnprintf # define vprintf curl_mvprintf # define vfprintf curl_mvfprintf diff --git a/project/jni/curl/include/curl/multi.h b/project/jni/curl/include/curl/multi.h index f96566669..0fbbd96f0 100644 --- a/project/jni/curl/include/curl/multi.h +++ b/project/jni/curl/include/curl/multi.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -64,6 +64,8 @@ typedef enum { CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ + CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was + attempted to get added - again */ CURLM_LAST } CURLMcode; @@ -72,6 +74,11 @@ typedef enum { curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ #define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM +/* bitmask bits for CURLMOPT_PIPELINING */ +#define CURLPIPE_NOTHING 0L +#define CURLPIPE_HTTP1 1L +#define CURLPIPE_MULTIPLEX 2L + typedef enum { CURLMSG_NONE, /* first, not used */ CURLMSG_DONE, /* This easy handle has completed. 'result' contains @@ -89,6 +96,19 @@ struct CURLMsg { }; typedef struct CURLMsg CURLMsg; +/* Based on poll(2) structure and values. + * We don't use pollfd and POLL* constants explicitly + * to cover platforms without poll(). */ +#define CURL_WAIT_POLLIN 0x0001 +#define CURL_WAIT_POLLPRI 0x0002 +#define CURL_WAIT_POLLOUT 0x0004 + +struct curl_waitfd { + curl_socket_t fd; + short events; + short revents; /* not supported yet */ +}; + /* * Name: curl_multi_init() * @@ -133,6 +153,20 @@ CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, fd_set *exc_fd_set, int *max_fd); +/* + * Name: curl_multi_wait() + * + * Desc: Poll on all fds within a CURLM set as well as any + * additional fds passed to the function. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret); + /* * Name: curl_multi_perform() * @@ -311,6 +345,37 @@ typedef enum { /* maximum number of entries in the connection cache */ CINIT(MAXCONNECTS, LONG, 6), + /* maximum number of (pipelining) connections to one host */ + CINIT(MAX_HOST_CONNECTIONS, LONG, 7), + + /* maximum number of requests in a pipeline */ + CINIT(MAX_PIPELINE_LENGTH, LONG, 8), + + /* a connection with a content-length longer than this + will not be considered for pipelining */ + CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9), + + /* a connection with a chunk length longer than this + will not be considered for pipelining */ + CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10), + + /* a list of site names(+port) that are blacklisted from + pipelining */ + CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11), + + /* a list of server types that are blacklisted from + pipelining */ + CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12), + + /* maximum number of open connections in total */ + CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), + + /* This is the server push callback function pointer */ + CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14), + + /* This is the argument passed to the server push callback */ + CINIT(PUSHDATA, OBJECTPOINT, 15), + CURLMOPT_LASTENTRY /* the last unused */ } CURLMoption; @@ -338,6 +403,31 @@ CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, curl_socket_t sockfd, void *sockp); + +/* + * Name: curl_push_callback + * + * Desc: This callback gets called when a new stream is being pushed by the + * server. It approves or denies the new stream. + * + * Returns: CURL_PUSH_OK or CURL_PUSH_DENY. + */ +#define CURL_PUSH_OK 0 +#define CURL_PUSH_DENY 1 + +struct curl_pushheaders; /* forward declaration only */ + +CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, + size_t num); +CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, + const char *name); + +typedef int (*curl_push_callback)(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *userp); + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/project/jni/curl/include/curl/stdcheaders.h b/project/jni/curl/include/curl/stdcheaders.h index ad82ef633..6f0f7f343 100644 --- a/project/jni/curl/include/curl/stdcheaders.h +++ b/project/jni/curl/include/curl/stdcheaders.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/project/jni/curl/include/curl/typecheck-gcc.h b/project/jni/curl/include/curl/typecheck-gcc.h index e6f74a958..6ec8bcfd4 100644 --- a/project/jni/curl/include/curl/typecheck-gcc.h +++ b/project/jni/curl/include/curl/typecheck-gcc.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -41,66 +41,66 @@ #define curl_easy_setopt(handle, option, value) \ __extension__ ({ \ __typeof__ (option) _curl_opt = option; \ - if (__builtin_constant_p(_curl_opt)) { \ - if (_curl_is_long_option(_curl_opt)) \ - if (!_curl_is_long(value)) \ + if(__builtin_constant_p(_curl_opt)) { \ + if(_curl_is_long_option(_curl_opt)) \ + if(!_curl_is_long(value)) \ _curl_easy_setopt_err_long(); \ - if (_curl_is_off_t_option(_curl_opt)) \ - if (!_curl_is_off_t(value)) \ + if(_curl_is_off_t_option(_curl_opt)) \ + if(!_curl_is_off_t(value)) \ _curl_easy_setopt_err_curl_off_t(); \ - if (_curl_is_string_option(_curl_opt)) \ - if (!_curl_is_string(value)) \ + if(_curl_is_string_option(_curl_opt)) \ + if(!_curl_is_string(value)) \ _curl_easy_setopt_err_string(); \ - if (_curl_is_write_cb_option(_curl_opt)) \ - if (!_curl_is_write_cb(value)) \ + if(_curl_is_write_cb_option(_curl_opt)) \ + if(!_curl_is_write_cb(value)) \ _curl_easy_setopt_err_write_callback(); \ - if ((_curl_opt) == CURLOPT_READFUNCTION) \ - if (!_curl_is_read_cb(value)) \ + if((_curl_opt) == CURLOPT_READFUNCTION) \ + if(!_curl_is_read_cb(value)) \ _curl_easy_setopt_err_read_cb(); \ - if ((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ - if (!_curl_is_ioctl_cb(value)) \ + if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ + if(!_curl_is_ioctl_cb(value)) \ _curl_easy_setopt_err_ioctl_cb(); \ - if ((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ - if (!_curl_is_sockopt_cb(value)) \ + if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ + if(!_curl_is_sockopt_cb(value)) \ _curl_easy_setopt_err_sockopt_cb(); \ - if ((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ - if (!_curl_is_opensocket_cb(value)) \ + if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ + if(!_curl_is_opensocket_cb(value)) \ _curl_easy_setopt_err_opensocket_cb(); \ - if ((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ - if (!_curl_is_progress_cb(value)) \ + if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ + if(!_curl_is_progress_cb(value)) \ _curl_easy_setopt_err_progress_cb(); \ - if ((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ - if (!_curl_is_debug_cb(value)) \ + if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ + if(!_curl_is_debug_cb(value)) \ _curl_easy_setopt_err_debug_cb(); \ - if ((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ - if (!_curl_is_ssl_ctx_cb(value)) \ + if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ + if(!_curl_is_ssl_ctx_cb(value)) \ _curl_easy_setopt_err_ssl_ctx_cb(); \ - if (_curl_is_conv_cb_option(_curl_opt)) \ - if (!_curl_is_conv_cb(value)) \ + if(_curl_is_conv_cb_option(_curl_opt)) \ + if(!_curl_is_conv_cb(value)) \ _curl_easy_setopt_err_conv_cb(); \ - if ((_curl_opt) == CURLOPT_SEEKFUNCTION) \ - if (!_curl_is_seek_cb(value)) \ + if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ + if(!_curl_is_seek_cb(value)) \ _curl_easy_setopt_err_seek_cb(); \ - if (_curl_is_cb_data_option(_curl_opt)) \ - if (!_curl_is_cb_data(value)) \ + if(_curl_is_cb_data_option(_curl_opt)) \ + if(!_curl_is_cb_data(value)) \ _curl_easy_setopt_err_cb_data(); \ - if ((_curl_opt) == CURLOPT_ERRORBUFFER) \ - if (!_curl_is_error_buffer(value)) \ + if((_curl_opt) == CURLOPT_ERRORBUFFER) \ + if(!_curl_is_error_buffer(value)) \ _curl_easy_setopt_err_error_buffer(); \ - if ((_curl_opt) == CURLOPT_STDERR) \ - if (!_curl_is_FILE(value)) \ + if((_curl_opt) == CURLOPT_STDERR) \ + if(!_curl_is_FILE(value)) \ _curl_easy_setopt_err_FILE(); \ - if (_curl_is_postfields_option(_curl_opt)) \ - if (!_curl_is_postfields(value)) \ + if(_curl_is_postfields_option(_curl_opt)) \ + if(!_curl_is_postfields(value)) \ _curl_easy_setopt_err_postfields(); \ - if ((_curl_opt) == CURLOPT_HTTPPOST) \ - if (!_curl_is_arr((value), struct curl_httppost)) \ + if((_curl_opt) == CURLOPT_HTTPPOST) \ + if(!_curl_is_arr((value), struct curl_httppost)) \ _curl_easy_setopt_err_curl_httpost(); \ - if (_curl_is_slist_option(_curl_opt)) \ - if (!_curl_is_arr((value), struct curl_slist)) \ + if(_curl_is_slist_option(_curl_opt)) \ + if(!_curl_is_arr((value), struct curl_slist)) \ _curl_easy_setopt_err_curl_slist(); \ - if ((_curl_opt) == CURLOPT_SHARE) \ - if (!_curl_is_ptr((value), CURLSH)) \ + if((_curl_opt) == CURLOPT_SHARE) \ + if(!_curl_is_ptr((value), CURLSH)) \ _curl_easy_setopt_err_CURLSH(); \ } \ curl_easy_setopt(handle, _curl_opt, value); \ @@ -111,18 +111,18 @@ __extension__ ({ \ #define curl_easy_getinfo(handle, info, arg) \ __extension__ ({ \ __typeof__ (info) _curl_info = info; \ - if (__builtin_constant_p(_curl_info)) { \ - if (_curl_is_string_info(_curl_info)) \ - if (!_curl_is_arr((arg), char *)) \ + if(__builtin_constant_p(_curl_info)) { \ + if(_curl_is_string_info(_curl_info)) \ + if(!_curl_is_arr((arg), char *)) \ _curl_easy_getinfo_err_string(); \ - if (_curl_is_long_info(_curl_info)) \ - if (!_curl_is_arr((arg), long)) \ + if(_curl_is_long_info(_curl_info)) \ + if(!_curl_is_arr((arg), long)) \ _curl_easy_getinfo_err_long(); \ - if (_curl_is_double_info(_curl_info)) \ - if (!_curl_is_arr((arg), double)) \ + if(_curl_is_double_info(_curl_info)) \ + if(!_curl_is_arr((arg), double)) \ _curl_easy_getinfo_err_double(); \ - if (_curl_is_slist_info(_curl_info)) \ - if (!_curl_is_arr((arg), struct curl_slist *)) \ + if(_curl_is_slist_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_slist *)) \ _curl_easy_getinfo_err_curl_slist(); \ } \ curl_easy_getinfo(handle, _curl_info, arg); \ @@ -141,15 +141,17 @@ __extension__ ({ \ /* To define a new warning, use _CURL_WARNING(identifier, "message") */ #define _CURL_WARNING(id, message) \ - static void __attribute__((warning(message))) __attribute__((unused)) \ - __attribute__((noinline)) id(void) { __asm__(""); } + static void __attribute__((__warning__(message))) \ + __attribute__((__unused__)) __attribute__((__noinline__)) \ + id(void) { __asm__(""); } _CURL_WARNING(_curl_easy_setopt_err_long, "curl_easy_setopt expects a long argument for this option") _CURL_WARNING(_curl_easy_setopt_err_curl_off_t, "curl_easy_setopt expects a curl_off_t argument for this option") _CURL_WARNING(_curl_easy_setopt_err_string, - "curl_easy_setopt expects a string (char* or char[]) argument for this option" + "curl_easy_setopt expects a " + "string (char* or char[]) argument for this option" ) _CURL_WARNING(_curl_easy_setopt_err_write_callback, "curl_easy_setopt expects a curl_write_callback argument for this option") @@ -160,7 +162,8 @@ _CURL_WARNING(_curl_easy_setopt_err_ioctl_cb, _CURL_WARNING(_curl_easy_setopt_err_sockopt_cb, "curl_easy_setopt expects a curl_sockopt_callback argument for this option") _CURL_WARNING(_curl_easy_setopt_err_opensocket_cb, - "curl_easy_setopt expects a curl_opensocket_callback argument for this option" + "curl_easy_setopt expects a " + "curl_opensocket_callback argument for this option" ) _CURL_WARNING(_curl_easy_setopt_err_progress_cb, "curl_easy_setopt expects a curl_progress_callback argument for this option") @@ -173,9 +176,11 @@ _CURL_WARNING(_curl_easy_setopt_err_conv_cb, _CURL_WARNING(_curl_easy_setopt_err_seek_cb, "curl_easy_setopt expects a curl_seek_callback argument for this option") _CURL_WARNING(_curl_easy_setopt_err_cb_data, - "curl_easy_setopt expects a private data pointer as argument for this option") + "curl_easy_setopt expects a " + "private data pointer as argument for this option") _CURL_WARNING(_curl_easy_setopt_err_error_buffer, - "curl_easy_setopt expects a char buffer of CURL_ERROR_SIZE as argument for this option") + "curl_easy_setopt expects a " + "char buffer of CURL_ERROR_SIZE as argument for this option") _CURL_WARNING(_curl_easy_setopt_err_FILE, "curl_easy_setopt expects a FILE* argument for this option") _CURL_WARNING(_curl_easy_setopt_err_postfields, @@ -213,52 +218,67 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, /* evaluates to true if option takes a char* argument */ #define _curl_is_string_option(option) \ - ((option) == CURLOPT_URL || \ - (option) == CURLOPT_PROXY || \ - (option) == CURLOPT_INTERFACE || \ - (option) == CURLOPT_NETRC_FILE || \ - (option) == CURLOPT_USERPWD || \ - (option) == CURLOPT_USERNAME || \ - (option) == CURLOPT_PASSWORD || \ - (option) == CURLOPT_PROXYUSERPWD || \ - (option) == CURLOPT_PROXYUSERNAME || \ - (option) == CURLOPT_PROXYPASSWORD || \ - (option) == CURLOPT_NOPROXY || \ - (option) == CURLOPT_ENCODING || \ - (option) == CURLOPT_REFERER || \ - (option) == CURLOPT_USERAGENT || \ + ((option) == CURLOPT_ACCEPT_ENCODING || \ + (option) == CURLOPT_CAINFO || \ + (option) == CURLOPT_CAPATH || \ (option) == CURLOPT_COOKIE || \ (option) == CURLOPT_COOKIEFILE || \ (option) == CURLOPT_COOKIEJAR || \ (option) == CURLOPT_COOKIELIST || \ - (option) == CURLOPT_FTPPORT || \ - (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ - (option) == CURLOPT_FTP_ACCOUNT || \ - (option) == CURLOPT_RANGE || \ - (option) == CURLOPT_CUSTOMREQUEST || \ - (option) == CURLOPT_SSLCERT || \ - (option) == CURLOPT_SSLCERTTYPE || \ - (option) == CURLOPT_SSLKEY || \ - (option) == CURLOPT_SSLKEYTYPE || \ - (option) == CURLOPT_KEYPASSWD || \ - (option) == CURLOPT_SSLENGINE || \ - (option) == CURLOPT_CAINFO || \ - (option) == CURLOPT_CAPATH || \ - (option) == CURLOPT_RANDOM_FILE || \ - (option) == CURLOPT_EGDSOCKET || \ - (option) == CURLOPT_SSL_CIPHER_LIST || \ - (option) == CURLOPT_KRBLEVEL || \ - (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ - (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ - (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ (option) == CURLOPT_CRLFILE || \ + (option) == CURLOPT_CUSTOMREQUEST || \ + (option) == CURLOPT_DEFAULT_PROTOCOL || \ + (option) == CURLOPT_DNS_INTERFACE || \ + (option) == CURLOPT_DNS_LOCAL_IP4 || \ + (option) == CURLOPT_DNS_LOCAL_IP6 || \ + (option) == CURLOPT_DNS_SERVERS || \ + (option) == CURLOPT_EGDSOCKET || \ + (option) == CURLOPT_FTPPORT || \ + (option) == CURLOPT_FTP_ACCOUNT || \ + (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ + (option) == CURLOPT_INTERFACE || \ (option) == CURLOPT_ISSUERCERT || \ - (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ - (option) == CURLOPT_SSH_KNOWNHOSTS || \ + (option) == CURLOPT_KEYPASSWD || \ + (option) == CURLOPT_KRBLEVEL || \ + (option) == CURLOPT_LOGIN_OPTIONS || \ + (option) == CURLOPT_MAIL_AUTH || \ (option) == CURLOPT_MAIL_FROM || \ + (option) == CURLOPT_NETRC_FILE || \ + (option) == CURLOPT_NOPROXY || \ + (option) == CURLOPT_PASSWORD || \ + (option) == CURLOPT_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PROXY || \ + (option) == CURLOPT_PROXYPASSWORD || \ + (option) == CURLOPT_PROXYUSERNAME || \ + (option) == CURLOPT_PROXYUSERPWD || \ + (option) == CURLOPT_PROXY_SERVICE_NAME || \ + (option) == CURLOPT_RANDOM_FILE || \ + (option) == CURLOPT_RANGE || \ + (option) == CURLOPT_REFERER || \ (option) == CURLOPT_RTSP_SESSION_ID || \ (option) == CURLOPT_RTSP_STREAM_URI || \ (option) == CURLOPT_RTSP_TRANSPORT || \ + (option) == CURLOPT_SERVICE_NAME || \ + (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ + (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ + (option) == CURLOPT_SSH_KNOWNHOSTS || \ + (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ + (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ + (option) == CURLOPT_SSLCERT || \ + (option) == CURLOPT_SSLCERTTYPE || \ + (option) == CURLOPT_SSLENGINE || \ + (option) == CURLOPT_SSLKEY || \ + (option) == CURLOPT_SSLKEYTYPE || \ + (option) == CURLOPT_SSL_CIPHER_LIST || \ + (option) == CURLOPT_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_TLSAUTH_TYPE || \ + (option) == CURLOPT_TLSAUTH_USERNAME || \ + (option) == CURLOPT_UNIX_SOCKET_PATH || \ + (option) == CURLOPT_URL || \ + (option) == CURLOPT_USERAGENT || \ + (option) == CURLOPT_USERNAME || \ + (option) == CURLOPT_USERPWD || \ + (option) == CURLOPT_XOAUTH2_BEARER || \ 0) /* evaluates to true if option takes a curl_write_callback argument */ @@ -274,21 +294,22 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, /* evaluates to true if option takes a data argument to pass to a callback */ #define _curl_is_cb_data_option(option) \ - ((option) == CURLOPT_WRITEDATA || \ - (option) == CURLOPT_READDATA || \ - (option) == CURLOPT_IOCTLDATA || \ - (option) == CURLOPT_SOCKOPTDATA || \ - (option) == CURLOPT_OPENSOCKETDATA || \ - (option) == CURLOPT_PROGRESSDATA || \ - (option) == CURLOPT_WRITEHEADER || \ + ((option) == CURLOPT_CHUNK_DATA || \ + (option) == CURLOPT_CLOSESOCKETDATA || \ (option) == CURLOPT_DEBUGDATA || \ - (option) == CURLOPT_SSL_CTX_DATA || \ - (option) == CURLOPT_SEEKDATA || \ - (option) == CURLOPT_PRIVATE || \ - (option) == CURLOPT_SSH_KEYDATA || \ - (option) == CURLOPT_INTERLEAVEDATA || \ - (option) == CURLOPT_CHUNK_DATA || \ (option) == CURLOPT_FNMATCH_DATA || \ + (option) == CURLOPT_HEADERDATA || \ + (option) == CURLOPT_INTERLEAVEDATA || \ + (option) == CURLOPT_IOCTLDATA || \ + (option) == CURLOPT_OPENSOCKETDATA || \ + (option) == CURLOPT_PRIVATE || \ + (option) == CURLOPT_PROGRESSDATA || \ + (option) == CURLOPT_READDATA || \ + (option) == CURLOPT_SEEKDATA || \ + (option) == CURLOPT_SOCKOPTDATA || \ + (option) == CURLOPT_SSH_KEYDATA || \ + (option) == CURLOPT_SSL_CTX_DATA || \ + (option) == CURLOPT_WRITEDATA || \ 0) /* evaluates to true if option takes a POST data argument (void* or char*) */ @@ -299,13 +320,15 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, /* evaluates to true if option takes a struct curl_slist * argument */ #define _curl_is_slist_option(option) \ - ((option) == CURLOPT_HTTPHEADER || \ - (option) == CURLOPT_HTTP200ALIASES || \ - (option) == CURLOPT_QUOTE || \ + ((option) == CURLOPT_HTTP200ALIASES || \ + (option) == CURLOPT_HTTPHEADER || \ + (option) == CURLOPT_MAIL_RCPT || \ (option) == CURLOPT_POSTQUOTE || \ (option) == CURLOPT_PREQUOTE || \ + (option) == CURLOPT_PROXYHEADER || \ + (option) == CURLOPT_QUOTE || \ + (option) == CURLOPT_RESOLVE || \ (option) == CURLOPT_TELNETOPTIONS || \ - (option) == CURLOPT_MAIL_RCPT || \ 0) /* groups of curl_easy_getinfo infos that take the same type of argument */ @@ -388,7 +411,8 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, /* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ /* XXX: also check size of an char[] array? */ #define _curl_is_error_buffer(expr) \ - (__builtin_types_compatible_p(__typeof__(expr), char *) || \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), char *) || \ __builtin_types_compatible_p(__typeof__(expr), char[])) /* evaluates to true if expr is of type (const) void* or (const) FILE* */ @@ -481,7 +505,8 @@ typedef int (_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); typedef int (_curl_sockopt_callback2)(const void *, curl_socket_t, curlsocktype); -/* evaluates to true if expr is of type curl_opensocket_callback or "similar" */ +/* evaluates to true if expr is of type curl_opensocket_callback or + "similar" */ #define _curl_is_opensocket_cb(expr) \ (_curl_is_NULL(expr) || \ __builtin_types_compatible_p(__typeof__(expr), curl_opensocket_callback) ||\ @@ -516,7 +541,11 @@ typedef int (_curl_progress_callback2)(const void *, _curl_callback_compatible((expr), _curl_debug_callback1) || \ _curl_callback_compatible((expr), _curl_debug_callback2) || \ _curl_callback_compatible((expr), _curl_debug_callback3) || \ - _curl_callback_compatible((expr), _curl_debug_callback4)) + _curl_callback_compatible((expr), _curl_debug_callback4) || \ + _curl_callback_compatible((expr), _curl_debug_callback5) || \ + _curl_callback_compatible((expr), _curl_debug_callback6) || \ + _curl_callback_compatible((expr), _curl_debug_callback7) || \ + _curl_callback_compatible((expr), _curl_debug_callback8)) typedef int (_curl_debug_callback1) (CURL *, curl_infotype, char *, size_t, void *); typedef int (_curl_debug_callback2) (CURL *, @@ -525,6 +554,14 @@ typedef int (_curl_debug_callback3) (CURL *, curl_infotype, const char *, size_t, void *); typedef int (_curl_debug_callback4) (CURL *, curl_infotype, const char *, size_t, const void *); +typedef int (_curl_debug_callback5) (CURL *, + curl_infotype, unsigned char *, size_t, void *); +typedef int (_curl_debug_callback6) (CURL *, + curl_infotype, unsigned char *, size_t, const void *); +typedef int (_curl_debug_callback7) (CURL *, + curl_infotype, const unsigned char *, size_t, void *); +typedef int (_curl_debug_callback8) (CURL *, + curl_infotype, const unsigned char *, size_t, const void *); /* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ /* this is getting even messier... */ @@ -550,7 +587,8 @@ typedef CURLcode (_curl_ssl_ctx_callback4)(CURL *, const void *, const void *); typedef CURLcode (_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *); typedef CURLcode (_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *); typedef CURLcode (_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *); -typedef CURLcode (_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, const void *); +typedef CURLcode (_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, + const void *); #else typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; diff --git a/project/jni/curl/include/curl/types.h b/project/jni/curl/include/curl/types.h deleted file mode 100644 index d37d6ae9e..000000000 --- a/project/jni/curl/include/curl/types.h +++ /dev/null @@ -1 +0,0 @@ -/* not used */ diff --git a/project/jni/curl/lib/Makefile.inc b/project/jni/curl/lib/Makefile.inc index 41ab8277d..39884d0b1 100644 --- a/project/jni/curl/lib/Makefile.inc +++ b/project/jni/curl/lib/Makefile.inc @@ -1,40 +1,75 @@ -# ./lib/Makefile.inc -# Using the backslash as line continuation character might be problematic -# with some make flavours, as Watcom's wmake showed us already. If we -# ever want to change this in a portable manner then we should consider -# this idea (posted to the libcurl list by Adam Kellas): -# CSRC1 = file1.c file2.c file3.c -# CSRC2 = file4.c file5.c file6.c -# CSOURCES = $(CSRC1) $(CSRC2) +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### -CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ - cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ - ldap.c ssluse.c version.c getenv.c escape.c mprintf.c telnet.c \ - netrc.c getinfo.c transfer.c strequal.c easy.c security.c krb4.c \ - curl_fnmatch.c fileinfo.c ftplistparser.c wildcard.c krb5.c \ - memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c multi.c \ - content_encoding.c share.c http_digest.c md4.c md5.c curl_rand.c \ - http_negotiate.c http_ntlm.c inet_pton.c strtoofft.c strerror.c \ - hostares.c hostasyn.c hostip4.c hostip6.c hostsyn.c hostthre.c \ - inet_ntop.c parsedate.c select.c gtls.c sslgen.c tftp.c splay.c \ - strdup.c socks.c ssh.c nss.c qssl.c rawstr.c curl_addrinfo.c \ - socks_gssapi.c socks_sspi.c curl_sspi.c slist.c nonblock.c \ - curl_memrchr.c imap.c pop3.c smtp.c pingpong.c rtsp.c curl_threads.c \ - warnless.c hmac.c polarssl.c curl_rtmp.c openldap.c curl_gethostname.c\ - gopher.c +LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ + vtls/polarssl.c vtls/polarssl_threadlock.c vtls/axtls.c \ + vtls/cyassl.c vtls/schannel.c vtls/darwinssl.c vtls/gskit.c \ + vtls/mbedtls.c -HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \ - progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h \ - if2ip.h speedcheck.h urldata.h curl_ldap.h ssluse.h escape.h telnet.h \ - getinfo.h strequal.h krb4.h memdebug.h http_chunks.h curl_rand.h \ - curl_fnmatch.h wildcard.h fileinfo.h ftplistparser.h strtok.h \ - connect.h llist.h hash.h content_encoding.h share.h curl_md4.h \ - curl_md5.h http_digest.h http_negotiate.h http_ntlm.h inet_pton.h \ - strtoofft.h strerror.h inet_ntop.h curlx.h curl_memory.h setup.h \ - transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h gtls.h \ - tftp.h sockaddr.h splay.h strdup.h setup_once.h socks.h ssh.h nssg.h \ - curl_base64.h rawstr.h curl_addrinfo.h curl_sspi.h slist.h nonblock.h \ - curl_memrchr.h imap.h pop3.h smtp.h pingpong.h rtsp.h curl_threads.h \ - warnless.h curl_hmac.h polarssl.h curl_rtmp.h curl_gethostname.h \ - gopher.h +LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \ + vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h vtls/axtls.h \ + vtls/cyassl.h vtls/schannel.h vtls/darwinssl.h vtls/gskit.h \ + vtls/mbedtls.h +LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ + cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ + ldap.c version.c getenv.c escape.c mprintf.c telnet.c netrc.c \ + getinfo.c transfer.c strequal.c easy.c security.c curl_fnmatch.c \ + fileinfo.c ftplistparser.c wildcard.c krb5.c memdebug.c http_chunks.c \ + strtok.c connect.c llist.c hash.c multi.c content_encoding.c share.c \ + http_digest.c md4.c md5.c http_negotiate.c inet_pton.c strtoofft.c \ + strerror.c amigaos.c hostasyn.c hostip4.c hostip6.c hostsyn.c \ + inet_ntop.c parsedate.c select.c tftp.c splay.c strdup.c socks.c \ + ssh.c rawstr.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \ + curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c \ + pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \ + openldap.c curl_gethostname.c gopher.c idn_win32.c \ + http_negotiate_sspi.c http_proxy.c non-ascii.c asyn-ares.c \ + asyn-thread.c curl_gssapi.c curl_ntlm.c curl_ntlm_wb.c \ + curl_ntlm_core.c curl_ntlm_msgs.c curl_sasl.c curl_multibyte.c \ + hostcheck.c conncache.c pipeline.c dotdot.c x509asn1.c \ + http2.c curl_sasl_sspi.c smb.c curl_sasl_gssapi.c curl_endian.c \ + curl_des.c + +LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ + formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ + speedcheck.h urldata.h curl_ldap.h escape.h telnet.h getinfo.h \ + strequal.h curl_sec.h memdebug.h http_chunks.h curl_fnmatch.h \ + wildcard.h fileinfo.h ftplistparser.h strtok.h connect.h llist.h \ + hash.h content_encoding.h share.h curl_md4.h curl_md5.h http_digest.h \ + http_negotiate.h inet_pton.h amigaos.h strtoofft.h strerror.h \ + inet_ntop.h curlx.h curl_memory.h curl_setup.h transfer.h select.h \ + easyif.h multiif.h parsedate.h tftp.h sockaddr.h splay.h strdup.h \ + socks.h ssh.h curl_base64.h rawstr.h curl_addrinfo.h curl_sspi.h \ + slist.h nonblock.h curl_memrchr.h imap.h pop3.h smtp.h pingpong.h \ + rtsp.h curl_threads.h warnless.h curl_hmac.h curl_rtmp.h \ + curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \ + curl_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \ + curl_ntlm_msgs.h curl_sasl.h curl_multibyte.h hostcheck.h \ + conncache.h curl_setup_once.h multihandle.h setup-vms.h pipeline.h \ + dotdot.h x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ + curl_printf.h + +LIB_RCFILES = libcurl.rc + +CSOURCES = $(LIB_CFILES) $(LIB_VTLS_CFILES) +HHEADERS = $(LIB_HFILES) $(LIB_VTLS_HFILES) diff --git a/project/jni/curl/lib/amigaos.c b/project/jni/curl/lib/amigaos.c index 2055126fe..e2fe35d1f 100644 --- a/project/jni/curl/lib/amigaos.c +++ b/project/jni/curl/lib/amigaos.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,10 +20,13 @@ * ***************************************************************************/ -#ifdef __AMIGA__ /* Any AmigaOS flavour */ +#include "curl_setup.h" + +#if defined(__AMIGA__) && !defined(__ixemul__) + +#include #include "amigaos.h" -#include struct Library *SocketBase = NULL; extern int errno, h_errno; @@ -35,7 +38,7 @@ void __request(const char *msg); # define __request( msg ) Printf( msg "\n\a") #endif -void amiga_cleanup() +void Curl_amiga_cleanup() { if(SocketBase) { CloseLibrary(SocketBase); @@ -43,7 +46,7 @@ void amiga_cleanup() } } -BOOL amiga_init() +bool Curl_amiga_init() { if(!SocketBase) SocketBase = OpenLibrary("bsdsocket.library", 4); @@ -61,20 +64,14 @@ BOOL amiga_init() } #ifndef __libnix__ - atexit(amiga_cleanup); + atexit(Curl_amiga_cleanup); #endif return TRUE; } #ifdef __libnix__ -ADD2EXIT(amiga_cleanup,-50); +ADD2EXIT(Curl_amiga_cleanup, -50); #endif -#else /* __AMIGA__ */ - -#ifdef __POCC__ -# pragma warn(disable:2024) /* Disable warning #2024: Empty input file */ -#endif - -#endif /* __AMIGA__ */ +#endif /* __AMIGA__ && ! __ixemul__ */ diff --git a/project/jni/curl/lib/amigaos.h b/project/jni/curl/lib/amigaos.h index d6ff0646a..02bee1610 100644 --- a/project/jni/curl/lib/amigaos.h +++ b/project/jni/curl/lib/amigaos.h @@ -1,5 +1,5 @@ -#ifndef LIBCURL_AMIGAOS_H -#define LIBCURL_AMIGAOS_H +#ifndef HEADER_CURL_AMIGAOS_H +#define HEADER_CURL_AMIGAOS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,37 +21,19 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "curl_setup.h" -#ifdef __AMIGA__ /* Any AmigaOS flavour */ +#if defined(__AMIGA__) && !defined(__ixemul__) -#ifndef __ixemul__ +bool Curl_amiga_init(); +void Curl_amiga_cleanup(); -#include -#include +#else -#include -#include +#define Curl_amiga_init() 1 +#define Curl_amiga_cleanup() Curl_nop_stmt -#include - -#include "config-amigaos.h" - -#ifndef select -# define select(args...) WaitSelect( args, NULL) #endif -#ifndef ioctl -# define ioctl(a,b,c,d) IoctlSocket( (LONG)a, (ULONG)b, (char*)c) -#endif -#define _AMIGASF 1 -extern void amiga_cleanup(); -extern BOOL amiga_init(); - -#else /* __ixemul__ */ - -#warning compiling with ixemul... - -#endif /* __ixemul__ */ -#endif /* __AMIGA__ */ -#endif /* LIBCURL_AMIGAOS_H */ +#endif /* HEADER_CURL_AMIGAOS_H */ diff --git a/project/jni/curl/lib/arpa_telnet.h b/project/jni/curl/lib/arpa_telnet.h index ddb14f6fe..ec238729d 100644 --- a/project/jni/curl/lib/arpa_telnet.h +++ b/project/jni/curl/lib/arpa_telnet.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,9 +26,11 @@ * Telnet option defines. Add more here if in need. */ #define CURL_TELOPT_BINARY 0 /* binary 8bit data */ -#define CURL_TELOPT_SGA 3 /* Supress Go Ahead */ +#define CURL_TELOPT_ECHO 1 /* just echo! */ +#define CURL_TELOPT_SGA 3 /* Suppress Go Ahead */ #define CURL_TELOPT_EXOPL 255 /* EXtended OPtions List */ #define CURL_TELOPT_TTYPE 24 /* Terminal TYPE */ +#define CURL_TELOPT_NAWS 31 /* Negotiate About Window Size */ #define CURL_TELOPT_XDISPLOC 35 /* X DISPlay LOCation */ #define CURL_TELOPT_NEW_ENVIRON 39 /* NEW ENVIRONment variables */ diff --git a/project/jni/curl/lib/asyn-ares.c b/project/jni/curl/lib/asyn-ares.c new file mode 100644 index 000000000..adb1a238a --- /dev/null +++ b/project/jni/curl/lib/asyn-ares.c @@ -0,0 +1,691 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef __VMS +#include +#include +#endif + +#ifdef HAVE_PROCESS_H +#include +#endif + +#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) +#undef in_addr_t +#define in_addr_t unsigned long +#endif + +/*********************************************************************** + * Only for ares-enabled builds + * And only for functions that fulfill the asynch resolver backend API + * as defined in asyn.h, nothing else belongs in this file! + **********************************************************************/ + +#ifdef CURLRES_ARES + +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "share.h" +#include "strerror.h" +#include "url.h" +#include "multiif.h" +#include "inet_pton.h" +#include "connect.h" +#include "select.h" +#include "progress.h" +#include "curl_printf.h" + +# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ + (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) +# define CARES_STATICLIB +# endif +# include +# include /* really old c-ares didn't include this by + itself */ + +#if ARES_VERSION >= 0x010500 +/* c-ares 1.5.0 or later, the callback proto is modified */ +#define HAVE_CARES_CALLBACK_TIMEOUTS 1 +#endif + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +struct ResolverResults { + int num_pending; /* number of ares_gethostbyname() requests */ + Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */ + int last_status; +}; + +/* + * Curl_resolver_global_init() - the generic low-level asynchronous name + * resolve API. Called from curl_global_init() to initialize global resolver + * environment. Initializes ares library. + */ +int Curl_resolver_global_init(void) +{ +#ifdef CARES_HAVE_ARES_LIBRARY_INIT + if(ares_library_init(ARES_LIB_INIT_ALL)) { + return CURLE_FAILED_INIT; + } +#endif + return CURLE_OK; +} + +/* + * Curl_resolver_global_cleanup() + * + * Called from curl_global_cleanup() to destroy global resolver environment. + * Deinitializes ares library. + */ +void Curl_resolver_global_cleanup(void) +{ +#ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP + ares_library_cleanup(); +#endif +} + +/* + * Curl_resolver_init() + * + * Called from curl_easy_init() -> Curl_open() to initialize resolver + * URL-state specific environment ('resolver' member of the UrlState + * structure). Fills the passed pointer by the initialized ares_channel. + */ +CURLcode Curl_resolver_init(void **resolver) +{ + int status = ares_init((ares_channel*)resolver); + if(status != ARES_SUCCESS) { + if(status == ARES_ENOMEM) + return CURLE_OUT_OF_MEMORY; + else + return CURLE_FAILED_INIT; + } + return CURLE_OK; + /* make sure that all other returns from this function should destroy the + ares channel before returning error! */ +} + +/* + * Curl_resolver_cleanup() + * + * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver + * URL-state specific environment ('resolver' member of the UrlState + * structure). Destroys the ares channel. + */ +void Curl_resolver_cleanup(void *resolver) +{ + ares_destroy((ares_channel)resolver); +} + +/* + * Curl_resolver_duphandle() + * + * Called from curl_easy_duphandle() to duplicate resolver URL-state specific + * environment ('resolver' member of the UrlState structure). Duplicates the + * 'from' ares channel and passes the resulting channel to the 'to' pointer. + */ +int Curl_resolver_duphandle(void **to, void *from) +{ + /* Clone the ares channel for the new handle */ + if(ARES_SUCCESS != ares_dup((ares_channel*)to, (ares_channel)from)) + return CURLE_FAILED_INIT; + return CURLE_OK; +} + +static void destroy_async_data (struct Curl_async *async); + +/* + * Cancel all possibly still on-going resolves for this connection. + */ +void Curl_resolver_cancel(struct connectdata *conn) +{ + if(conn->data && conn->data->state.resolver) + ares_cancel((ares_channel)conn->data->state.resolver); + destroy_async_data(&conn->async); +} + +/* + * destroy_async_data() cleans up async resolver data. + */ +static void destroy_async_data (struct Curl_async *async) +{ + free(async->hostname); + + if(async->os_specific) { + struct ResolverResults *res = (struct ResolverResults *)async->os_specific; + if(res) { + if(res->temp_ai) { + Curl_freeaddrinfo(res->temp_ai); + res->temp_ai = NULL; + } + free(res); + } + async->os_specific = NULL; + } + + async->hostname = NULL; +} + +/* + * Curl_resolver_getsock() is called when someone from the outside world + * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking + * with ares. The caller must make sure that this function is only called when + * we have a working ares channel. + * + * Returns: sockets-in-use-bitmap + */ + +int Curl_resolver_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) + +{ + struct timeval maxtime; + struct timeval timebuf; + struct timeval *timeout; + long milli; + int max = ares_getsock((ares_channel)conn->data->state.resolver, + (ares_socket_t *)socks, numsocks); + + maxtime.tv_sec = CURL_TIMEOUT_RESOLVE; + maxtime.tv_usec = 0; + + timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime, + &timebuf); + milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000); + if(milli == 0) + milli += 10; + Curl_expire_latest(conn->data, milli); + + return max; +} + +/* + * waitperform() + * + * 1) Ask ares what sockets it currently plays with, then + * 2) wait for the timeout period to check for action on ares' sockets. + * 3) tell ares to act on all the sockets marked as "with action" + * + * return number of sockets it worked on + */ + +static int waitperform(struct connectdata *conn, int timeout_ms) +{ + struct SessionHandle *data = conn->data; + int nfds; + int bitmask; + ares_socket_t socks[ARES_GETSOCK_MAXNUM]; + struct pollfd pfd[ARES_GETSOCK_MAXNUM]; + int i; + int num = 0; + + bitmask = ares_getsock((ares_channel)data->state.resolver, socks, + ARES_GETSOCK_MAXNUM); + + for(i=0; i < ARES_GETSOCK_MAXNUM; i++) { + pfd[i].events = 0; + pfd[i].revents = 0; + if(ARES_GETSOCK_READABLE(bitmask, i)) { + pfd[i].fd = socks[i]; + pfd[i].events |= POLLRDNORM|POLLIN; + } + if(ARES_GETSOCK_WRITABLE(bitmask, i)) { + pfd[i].fd = socks[i]; + pfd[i].events |= POLLWRNORM|POLLOUT; + } + if(pfd[i].events != 0) + num++; + else + break; + } + + if(num) + nfds = Curl_poll(pfd, num, timeout_ms); + else + nfds = 0; + + if(!nfds) + /* Call ares_process() unconditonally here, even if we simply timed out + above, as otherwise the ares name resolve won't timeout! */ + ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD, + ARES_SOCKET_BAD); + else { + /* move through the descriptors and ask for processing on them */ + for(i=0; i < num; i++) + ares_process_fd((ares_channel)data->state.resolver, + pfd[i].revents & (POLLRDNORM|POLLIN)? + pfd[i].fd:ARES_SOCKET_BAD, + pfd[i].revents & (POLLWRNORM|POLLOUT)? + pfd[i].fd:ARES_SOCKET_BAD); + } + return nfds; +} + +/* + * Curl_resolver_is_resolved() is called repeatedly to check if a previous + * name resolve request has completed. It should also make sure to time-out if + * the operation seems to take too long. + * + * Returns normal CURLcode errors. + */ +CURLcode Curl_resolver_is_resolved(struct connectdata *conn, + struct Curl_dns_entry **dns) +{ + struct SessionHandle *data = conn->data; + struct ResolverResults *res = (struct ResolverResults *) + conn->async.os_specific; + CURLcode result = CURLE_OK; + + *dns = NULL; + + waitperform(conn, 0); + + if(res && !res->num_pending) { + (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai); + /* temp_ai ownership is moved to the connection, so we need not free-up + them */ + res->temp_ai = NULL; + if(!conn->async.dns) { + failf(data, "Could not resolve: %s (%s)", + conn->async.hostname, ares_strerror(conn->async.status)); + result = conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY: + CURLE_COULDNT_RESOLVE_HOST; + } + else + *dns = conn->async.dns; + + destroy_async_data(&conn->async); + } + + return result; +} + +/* + * Curl_resolver_wait_resolv() + * + * waits for a resolve to finish. This function should be avoided since using + * this risk getting the multi interface to "hang". + * + * If 'entry' is non-NULL, make it point to the resolved dns entry + * + * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and + * CURLE_OPERATION_TIMEDOUT if a time-out occurred. + */ +CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, + struct Curl_dns_entry **entry) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + long timeout; + struct timeval now = Curl_tvnow(); + struct Curl_dns_entry *temp_entry; + + timeout = Curl_timeleft(data, &now, TRUE); + if(!timeout) + timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */ + + /* Wait for the name resolve query to complete. */ + for(;;) { + struct timeval *tvp, tv, store; + long timediff; + int itimeout; + int timeout_ms; + + itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout; + + store.tv_sec = itimeout/1000; + store.tv_usec = (itimeout%1000)*1000; + + tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv); + + /* use the timeout period ares returned to us above if less than one + second is left, otherwise just use 1000ms to make sure the progress + callback gets called frequent enough */ + if(!tvp->tv_sec) + timeout_ms = (int)(tvp->tv_usec/1000); + else + timeout_ms = 1000; + + waitperform(conn, timeout_ms); + Curl_resolver_is_resolved(conn, &temp_entry); + + if(conn->async.done) + break; + + if(Curl_pgrsUpdate(conn)) { + result = CURLE_ABORTED_BY_CALLBACK; + timeout = -1; /* trigger the cancel below */ + } + else { + struct timeval now2 = Curl_tvnow(); + timediff = Curl_tvdiff(now2, now); /* spent time */ + timeout -= timediff?timediff:1; /* always deduct at least 1 */ + now = now2; /* for next loop */ + } + + if(timeout < 0) { + /* our timeout, so we cancel the ares operation */ + ares_cancel((ares_channel)data->state.resolver); + break; + } + } + + /* Operation complete, if the lookup was successful we now have the entry + in the cache. */ + if(entry) + *entry = conn->async.dns; + + if(result) + /* close the connection, since we can't return failure here without + cleaning up this connection properly. + TODO: remove this action from here, it is not a name resolver decision. + */ + connclose(conn, "c-ares resolve failed"); + + return result; +} + +/* Connects results to the list */ +static void compound_results(struct ResolverResults *res, + Curl_addrinfo *ai) +{ + Curl_addrinfo *ai_tail; + if(!ai) + return; + ai_tail = ai; + + while(ai_tail->ai_next) + ai_tail = ai_tail->ai_next; + + /* Add the new results to the list of old results. */ + ai_tail->ai_next = res->temp_ai; + res->temp_ai = ai; +} + +/* + * ares_query_completed_cb() is the callback that ares will call when + * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(), + * when using ares, is completed either successfully or with failure. + */ +static void query_completed_cb(void *arg, /* (struct connectdata *) */ + int status, +#ifdef HAVE_CARES_CALLBACK_TIMEOUTS + int timeouts, +#endif + struct hostent *hostent) +{ + struct connectdata *conn = (struct connectdata *)arg; + struct ResolverResults *res; + +#ifdef HAVE_CARES_CALLBACK_TIMEOUTS + (void)timeouts; /* ignored */ +#endif + + if(ARES_EDESTRUCTION == status) + /* when this ares handle is getting destroyed, the 'arg' pointer may not + be valid so only defer it when we know the 'status' says its fine! */ + return; + + res = (struct ResolverResults *)conn->async.os_specific; + res->num_pending--; + + if(CURL_ASYNC_SUCCESS == status) { + Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port); + if(ai) { + compound_results(res, ai); + } + } + /* A successful result overwrites any previous error */ + if(res->last_status != ARES_SUCCESS) + res->last_status = status; +} + +/* + * Curl_resolver_getaddrinfo() - when using ares + * + * Returns name information about the given hostname and port number. If + * successful, the 'hostent' is returned and the forth argument will point to + * memory we need to free after use. That memory *MUST* be freed with + * Curl_freeaddrinfo(), nothing else. + */ +Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) +{ + char *bufp; + struct SessionHandle *data = conn->data; + struct in_addr in; + int family = PF_INET; +#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ + struct in6_addr in6; +#endif /* CURLRES_IPV6 */ + + *waitp = 0; /* default to synchronous response */ + + /* First check if this is an IPv4 address string */ + if(Curl_inet_pton(AF_INET, hostname, &in) > 0) { + /* This is a dotted IP address 123.123.123.123-style */ + return Curl_ip2addr(AF_INET, &in, hostname, port); + } + +#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ + /* Otherwise, check if this is an IPv6 address string */ + if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0) + /* This must be an IPv6 address literal. */ + return Curl_ip2addr(AF_INET6, &in6, hostname, port); + + switch(conn->ip_version) { + default: +#if ARES_VERSION >= 0x010601 + family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older + c-ares versions this just falls through and defaults + to PF_INET */ + break; +#endif + case CURL_IPRESOLVE_V4: + family = PF_INET; + break; + case CURL_IPRESOLVE_V6: + family = PF_INET6; + break; + } +#endif /* CURLRES_IPV6 */ + + bufp = strdup(hostname); + if(bufp) { + struct ResolverResults *res = NULL; + free(conn->async.hostname); + conn->async.hostname = bufp; + conn->async.port = port; + conn->async.done = FALSE; /* not done */ + conn->async.status = 0; /* clear */ + conn->async.dns = NULL; /* clear */ + res = calloc(sizeof(struct ResolverResults), 1); + if(!res) { + free(conn->async.hostname); + conn->async.hostname = NULL; + return NULL; + } + conn->async.os_specific = res; + + /* initial status - failed */ + res->last_status = ARES_ENOTFOUND; +#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ + if(family == PF_UNSPEC) { + if(Curl_ipv6works()) { + res->num_pending = 2; + + /* areschannel is already setup in the Curl_open() function */ + ares_gethostbyname((ares_channel)data->state.resolver, hostname, + PF_INET, query_completed_cb, conn); + ares_gethostbyname((ares_channel)data->state.resolver, hostname, + PF_INET6, query_completed_cb, conn); + } + else { + res->num_pending = 1; + + /* areschannel is already setup in the Curl_open() function */ + ares_gethostbyname((ares_channel)data->state.resolver, hostname, + PF_INET, query_completed_cb, conn); + } + } + else +#endif /* CURLRES_IPV6 */ + { + res->num_pending = 1; + + /* areschannel is already setup in the Curl_open() function */ + ares_gethostbyname((ares_channel)data->state.resolver, hostname, family, + query_completed_cb, conn); + } + + *waitp = 1; /* expect asynchronous response */ + } + return NULL; /* no struct yet */ +} + +CURLcode Curl_set_dns_servers(struct SessionHandle *data, + char *servers) +{ + CURLcode result = CURLE_NOT_BUILT_IN; + int ares_result; + + /* If server is NULL or empty, this would purge all DNS servers + * from ares library, which will cause any and all queries to fail. + * So, just return OK if none are configured and don't actually make + * any changes to c-ares. This lets c-ares use it's defaults, which + * it gets from the OS (for instance from /etc/resolv.conf on Linux). + */ + if(!(servers && servers[0])) + return CURLE_OK; + +#if (ARES_VERSION >= 0x010704) + ares_result = ares_set_servers_csv(data->state.resolver, servers); + switch(ares_result) { + case ARES_SUCCESS: + result = CURLE_OK; + break; + case ARES_ENOMEM: + result = CURLE_OUT_OF_MEMORY; + break; + case ARES_ENOTINITIALIZED: + case ARES_ENODATA: + case ARES_EBADSTR: + default: + result = CURLE_BAD_FUNCTION_ARGUMENT; + break; + } +#else /* too old c-ares version! */ + (void)data; + (void)(ares_result); +#endif + return result; +} + +CURLcode Curl_set_dns_interface(struct SessionHandle *data, + const char *interf) +{ +#if (ARES_VERSION >= 0x010704) + if(!interf) + interf = ""; + + ares_set_local_dev((ares_channel)data->state.resolver, interf); + + return CURLE_OK; +#else /* c-ares version too old! */ + (void)data; + (void)interf; + return CURLE_NOT_BUILT_IN; +#endif +} + +CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, + const char *local_ip4) +{ +#if (ARES_VERSION >= 0x010704) + struct in_addr a4; + + if((!local_ip4) || (local_ip4[0] == 0)) { + a4.s_addr = 0; /* disabled: do not bind to a specific address */ + } + else { + if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) { + return CURLE_BAD_FUNCTION_ARGUMENT; + } + } + + ares_set_local_ip4((ares_channel)data->state.resolver, ntohl(a4.s_addr)); + + return CURLE_OK; +#else /* c-ares version too old! */ + (void)data; + (void)local_ip4; + return CURLE_NOT_BUILT_IN; +#endif +} + +CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, + const char *local_ip6) +{ +#if (ARES_VERSION >= 0x010704) && defined(ENABLE_IPV6) + unsigned char a6[INET6_ADDRSTRLEN]; + + if((!local_ip6) || (local_ip6[0] == 0)) { + /* disabled: do not bind to a specific address */ + memset(a6, 0, sizeof(a6)); + } + else { + if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) { + return CURLE_BAD_FUNCTION_ARGUMENT; + } + } + + ares_set_local_ip6((ares_channel)data->state.resolver, a6); + + return CURLE_OK; +#else /* c-ares version too old! */ + (void)data; + (void)local_ip6; + return CURLE_NOT_BUILT_IN; +#endif +} +#endif /* CURLRES_ARES */ diff --git a/project/jni/curl/lib/hostthre.c b/project/jni/curl/lib/asyn-thread.c similarity index 54% rename from project/jni/curl/lib/hostthre.c rename to project/jni/curl/lib/asyn-thread.c index d45a8993c..83ce0ce4e 100644 --- a/project/jni/curl/lib/hostthre.c +++ b/project/jni/curl/lib/asyn-thread.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,14 +20,8 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#include -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif @@ -37,16 +31,9 @@ #ifdef HAVE_ARPA_INET_H #include #endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototypes */ -#endif -#ifdef HAVE_UNISTD_H -#include /* for the close() proto */ -#endif #ifdef __VMS #include #include -#include #endif #if defined(USE_THREADS_POSIX) @@ -64,6 +51,12 @@ #define in_addr_t unsigned long #endif +#ifdef HAVE_GETADDRINFO +# define RESOLVER_ENOMEM EAI_MEMORY +#else +# define RESOLVER_ENOMEM ENOMEM +#endif + #include "urldata.h" #include "sendf.h" #include "hostip.h" @@ -75,11 +68,10 @@ #include "inet_pton.h" #include "inet_ntop.h" #include "curl_threads.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "connect.h" +#include "curl_printf.h" #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" @@ -88,6 +80,71 @@ **********************************************************************/ #ifdef CURLRES_THREADED +/* + * Curl_resolver_global_init() + * Called from curl_global_init() to initialize global resolver environment. + * Does nothing here. + */ +int Curl_resolver_global_init(void) +{ + return CURLE_OK; +} + +/* + * Curl_resolver_global_cleanup() + * Called from curl_global_cleanup() to destroy global resolver environment. + * Does nothing here. + */ +void Curl_resolver_global_cleanup(void) +{ +} + +/* + * Curl_resolver_init() + * Called from curl_easy_init() -> Curl_open() to initialize resolver + * URL-state specific environment ('resolver' member of the UrlState + * structure). Does nothing here. + */ +CURLcode Curl_resolver_init(void **resolver) +{ + (void)resolver; + return CURLE_OK; +} + +/* + * Curl_resolver_cleanup() + * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver + * URL-state specific environment ('resolver' member of the UrlState + * structure). Does nothing here. + */ +void Curl_resolver_cleanup(void *resolver) +{ + (void)resolver; +} + +/* + * Curl_resolver_duphandle() + * Called from curl_easy_duphandle() to duplicate resolver URL state-specific + * environment ('resolver' member of the UrlState structure). Does nothing + * here. + */ +int Curl_resolver_duphandle(void **to, void *from) +{ + (void)to; + (void)from; + return CURLE_OK; +} + +static void destroy_async_data(struct Curl_async *); + +/* + * Cancel all possibly still on-going resolves for this connection. + */ +void Curl_resolver_cancel(struct connectdata *conn) +{ + destroy_async_data(&conn->async); +} + /* This function is used to init a threaded resolve */ static bool init_resolve_thread(struct connectdata *conn, const char *hostname, int port, @@ -107,17 +164,17 @@ struct thread_sync_data { #ifdef HAVE_GETADDRINFO struct addrinfo hints; #endif + struct thread_data *td; /* for thread-self cleanup */ }; struct thread_data { curl_thread_t thread_hnd; - curl_socket_t dummy_sock; unsigned int poll_interval; - int interval_end; + long interval_end; struct thread_sync_data tsd; }; -static struct thread_sync_data * conn_thread_sync_data(struct connectdata *conn) +static struct thread_sync_data *conn_thread_sync_data(struct connectdata *conn) { return &(((struct thread_data *)conn->async.os_specific)->tsd); } @@ -128,31 +185,33 @@ static struct thread_sync_data * conn_thread_sync_data(struct connectdata *conn) static void destroy_thread_sync_data(struct thread_sync_data * tsd) { - if (tsd->mtx) { + if(tsd->mtx) { Curl_mutex_destroy(tsd->mtx); free(tsd->mtx); } - if(tsd->hostname) - free(tsd->hostname); + free(tsd->hostname); - if (tsd->res) + if(tsd->res) Curl_freeaddrinfo(tsd->res); - memset(tsd,0,sizeof(*tsd)); + memset(tsd, 0, sizeof(*tsd)); } /* Initialize resolver thread synchronization data */ static -int init_thread_sync_data(struct thread_sync_data * tsd, +int init_thread_sync_data(struct thread_data * td, const char * hostname, int port, const struct addrinfo *hints) { + struct thread_sync_data *tsd = &td->tsd; + memset(tsd, 0, sizeof(*tsd)); + tsd->td = td; tsd->port = port; -#ifdef CURLRES_IPV6 +#ifdef HAVE_GETADDRINFO DEBUGASSERT(hints); tsd->hints = *hints; #else @@ -160,7 +219,8 @@ int init_thread_sync_data(struct thread_sync_data * tsd, #endif tsd->mtx = malloc(sizeof(curl_mutex_t)); - if (tsd->mtx == NULL) goto err_exit; + if(tsd->mtx == NULL) + goto err_exit; Curl_mutex_init(tsd->mtx); @@ -170,7 +230,8 @@ int init_thread_sync_data(struct thread_sync_data * tsd, * thread during gethostbyname execution. */ tsd->hostname = strdup(hostname); - if (!tsd->hostname) goto err_exit; + if(!tsd->hostname) + goto err_exit; return 1; @@ -186,9 +247,9 @@ static int getaddrinfo_complete(struct connectdata *conn) int rc; rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res); - /* The tsd->res structure has been copied to async.dns and perhaps the DNS cache. - Set our copy to NULL so destroy_thread_sync_data doesn't free it. - */ + /* The tsd->res structure has been copied to async.dns and perhaps the DNS + cache. Set our copy to NULL so destroy_thread_sync_data doesn't free it. + */ tsd->res = NULL; return rc; @@ -206,22 +267,31 @@ static int getaddrinfo_complete(struct connectdata *conn) static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg) { struct thread_sync_data *tsd = (struct thread_sync_data*)arg; - char service [NI_MAXSERV]; + struct thread_data *td = tsd->td; + char service[12]; int rc; snprintf(service, sizeof(service), "%d", tsd->port); rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res); - if (rc != 0) { - tsd->sock_error = SOCKERRNO; - if (tsd->sock_error == 0) - tsd->sock_error = ENOMEM; + if(rc != 0) { + tsd->sock_error = SOCKERRNO?SOCKERRNO:rc; + if(tsd->sock_error == 0) + tsd->sock_error = RESOLVER_ENOMEM; } Curl_mutex_acquire(tsd->mtx); - tsd->done = 1; - Curl_mutex_release(tsd->mtx); + if(tsd->done) { + /* too late, gotta clean up the mess */ + Curl_mutex_release(tsd->mtx); + destroy_thread_sync_data(tsd); + free(td); + } + else { + tsd->done = 1; + Curl_mutex_release(tsd->mtx); + } return 0; } @@ -234,18 +304,27 @@ static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg) static unsigned int CURL_STDCALL gethostbyname_thread (void *arg) { struct thread_sync_data *tsd = (struct thread_sync_data *)arg; + struct thread_data *td = tsd->td; tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port); - if (!tsd->res) { + if(!tsd->res) { tsd->sock_error = SOCKERRNO; - if (tsd->sock_error == 0) - tsd->sock_error = ENOMEM; + if(tsd->sock_error == 0) + tsd->sock_error = RESOLVER_ENOMEM; } Curl_mutex_acquire(tsd->mtx); - tsd->done = 1; - Curl_mutex_release(tsd->mtx); + if(tsd->done) { + /* too late, gotta clean up the mess */ + Curl_mutex_release(tsd->mtx); + destroy_thread_sync_data(tsd); + free(td); + } + else { + tsd->done = 1; + Curl_mutex_release(tsd->mtx); + } return 0; } @@ -253,29 +332,39 @@ static unsigned int CURL_STDCALL gethostbyname_thread (void *arg) #endif /* HAVE_GETADDRINFO */ /* - * Curl_destroy_thread_data() cleans up async resolver data and thread handle. - * Complementary of ares_destroy. + * destroy_async_data() cleans up async resolver data and thread handle. */ -void Curl_destroy_thread_data (struct Curl_async *async) +static void destroy_async_data (struct Curl_async *async) { - if(async->hostname) - free(async->hostname); - if(async->os_specific) { struct thread_data *td = (struct thread_data*) async->os_specific; + int done; - if (td->dummy_sock != CURL_SOCKET_BAD) - sclose(td->dummy_sock); + /* + * if the thread is still blocking in the resolve syscall, detach it and + * let the thread do the cleanup... + */ + Curl_mutex_acquire(td->tsd.mtx); + done = td->tsd.done; + td->tsd.done = 1; + Curl_mutex_release(td->tsd.mtx); - if (td->thread_hnd != curl_thread_t_null) - Curl_thread_join(&td->thread_hnd); + if(!done) { + Curl_thread_destroy(td->thread_hnd); + } + else { + if(td->thread_hnd != curl_thread_t_null) + Curl_thread_join(&td->thread_hnd); - destroy_thread_sync_data(&td->tsd); + destroy_thread_sync_data(&td->tsd); - free(async->os_specific); + free(async->os_specific); + } } - async->hostname = NULL; async->os_specific = NULL; + + free(async->hostname); + async->hostname = NULL; } /* @@ -289,7 +378,7 @@ static bool init_resolve_thread (struct connectdata *conn, const struct addrinfo *hints) { struct thread_data *td = calloc(1, sizeof(struct thread_data)); - int err = ENOMEM; + int err = RESOLVER_ENOMEM; conn->async.os_specific = (void*) td; if(!td) @@ -299,27 +388,16 @@ static bool init_resolve_thread (struct connectdata *conn, conn->async.done = FALSE; conn->async.status = 0; conn->async.dns = NULL; - td->dummy_sock = CURL_SOCKET_BAD; td->thread_hnd = curl_thread_t_null; - if (!init_thread_sync_data(&td->tsd, hostname, port, hints)) + if(!init_thread_sync_data(td, hostname, port, hints)) goto err_exit; - Curl_safefree(conn->async.hostname); + free(conn->async.hostname); conn->async.hostname = strdup(hostname); if(!conn->async.hostname) goto err_exit; -#ifdef WIN32 - /* This socket is only to keep Curl_resolv_fdset() and select() happy; - * should never become signalled for read since it's unbound but - * Windows needs at least 1 socket in select(). - */ - td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0); - if (td->dummy_sock == CURL_SOCKET_BAD) - goto err_exit; -#endif - #ifdef HAVE_GETADDRINFO td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd); #else @@ -336,71 +414,86 @@ static bool init_resolve_thread (struct connectdata *conn, return TRUE; err_exit: - Curl_destroy_thread_data(&conn->async); + destroy_async_data(&conn->async); SET_ERRNO(err); return FALSE; } +/* + * resolver_error() calls failf() with the appropriate message after a resolve + * error + */ + +static CURLcode resolver_error(struct connectdata *conn) +{ + const char *host_or_proxy; + CURLcode result; + + if(conn->bits.httpproxy) { + host_or_proxy = "proxy"; + result = CURLE_COULDNT_RESOLVE_PROXY; + } + else { + host_or_proxy = "host"; + result = CURLE_COULDNT_RESOLVE_HOST; + } + + failf(conn->data, "Could not resolve %s: %s", host_or_proxy, + conn->async.hostname); + + return result; +} /* - * Curl_wait_for_resolv() waits for a resolve to finish. This function should - * be avoided since using this risk getting the multi interface to "hang". + * Curl_resolver_wait_resolv() + * + * waits for a resolve to finish. This function should be avoided since using + * this risk getting the multi interface to "hang". * * If 'entry' is non-NULL, make it point to the resolved dns entry * * This is the version for resolves-in-a-thread. */ -CURLcode Curl_wait_for_resolv(struct connectdata *conn, - struct Curl_dns_entry **entry) +CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, + struct Curl_dns_entry **entry) { struct thread_data *td = (struct thread_data*) conn->async.os_specific; - struct SessionHandle *data = conn->data; - CURLcode rc = CURLE_OK; + CURLcode result = CURLE_OK; DEBUGASSERT(conn && td); /* wait for the thread to resolve the name */ - if (Curl_thread_join(&td->thread_hnd)) { - rc = getaddrinfo_complete(conn); - } else { + if(Curl_thread_join(&td->thread_hnd)) + result = getaddrinfo_complete(conn); + else DEBUGASSERT(0); - } conn->async.done = TRUE; if(entry) *entry = conn->async.dns; - if(!conn->async.dns) { - /* a name was not resolved */ - if (conn->bits.httpproxy) { - failf(data, "Could not resolve proxy: %s; %s", - conn->async.hostname, Curl_strerror(conn, conn->async.status)); - rc = CURLE_COULDNT_RESOLVE_PROXY; - } else { - failf(data, "Could not resolve host: %s; %s", - conn->async.hostname, Curl_strerror(conn, conn->async.status)); - rc = CURLE_COULDNT_RESOLVE_HOST; - } - } + if(!conn->async.dns) + /* a name was not resolved, report error */ + result = resolver_error(conn); - Curl_destroy_thread_data(&conn->async); + destroy_async_data(&conn->async); if(!conn->async.dns) - conn->bits.close = TRUE; + connclose(conn, "asynch resolve failed"); - return (rc); + return result; } /* - * Curl_is_resolved() is called repeatedly to check if a previous name resolve - * request has completed. It should also make sure to time-out if the - * operation seems to take too long. + * Curl_resolver_is_resolved() is called repeatedly to check if a previous + * name resolve request has completed. It should also make sure to time-out if + * the operation seems to take too long. */ -CURLcode Curl_is_resolved(struct connectdata *conn, - struct Curl_dns_entry **entry) +CURLcode Curl_resolver_is_resolved(struct connectdata *conn, + struct Curl_dns_entry **entry) { struct SessionHandle *data = conn->data; struct thread_data *td = (struct thread_data*) conn->async.os_specific; @@ -408,7 +501,7 @@ CURLcode Curl_is_resolved(struct connectdata *conn, *entry = NULL; - if (!td) { + if(!td) { DEBUGASSERT(td); return CURLE_COULDNT_RESOLVE_HOST; } @@ -417,30 +510,31 @@ CURLcode Curl_is_resolved(struct connectdata *conn, done = td->tsd.done; Curl_mutex_release(td->tsd.mtx); - if (done) { + if(done) { getaddrinfo_complete(conn); - Curl_destroy_thread_data(&conn->async); if(!conn->async.dns) { - failf(data, "Could not resolve host: %s; %s", - conn->host.name, Curl_strerror(conn, conn->async.status)); - return CURLE_COULDNT_RESOLVE_HOST; + CURLcode result = resolver_error(conn); + destroy_async_data(&conn->async); + return result; } + destroy_async_data(&conn->async); *entry = conn->async.dns; - } else { + } + else { /* poll for name lookup done with exponential backoff up to 250ms */ - int elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); - if (elapsed < 0) + long elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); + if(elapsed < 0) elapsed = 0; - if (td->poll_interval == 0) + if(td->poll_interval == 0) /* Start at 1ms poll interval */ td->poll_interval = 1; - else if (elapsed >= td->interval_end) + else if(elapsed >= td->interval_end) /* Back-off exponentially if last interval expired */ td->poll_interval *= 2; - if (td->poll_interval > 250) + if(td->poll_interval > 250) td->poll_interval = 250; td->interval_end = elapsed + td->poll_interval; @@ -450,21 +544,13 @@ CURLcode Curl_is_resolved(struct connectdata *conn, return CURLE_OK; } -int Curl_resolv_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) +int Curl_resolver_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) { - const struct thread_data *td = - (const struct thread_data *) conn->async.os_specific; - - if(td && td->dummy_sock != CURL_SOCKET_BAD) { - if(numsocks) { - /* return one socket waiting for readable, even though this is just - a dummy */ - socks[0] = td->dummy_sock; - return GETSOCK_READSOCK(0); - } - } + (void)conn; + (void)socks; + (void)numsocks; return 0; } @@ -472,10 +558,10 @@ int Curl_resolv_getsock(struct connectdata *conn, /* * Curl_getaddrinfo() - for platforms without getaddrinfo */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) +Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) { struct in_addr in; @@ -498,23 +584,36 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, #else /* !HAVE_GETADDRINFO */ /* - * Curl_getaddrinfo() - for getaddrinfo + * Curl_resolver_getaddrinfo() - for getaddrinfo */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) +Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) { struct addrinfo hints; + struct in_addr in; Curl_addrinfo *res; int error; - char sbuf[NI_MAXSERV]; + char sbuf[12]; int pf = PF_INET; - struct SessionHandle *data = conn->data; +#ifdef CURLRES_IPV6 + struct in6_addr in6; +#endif /* CURLRES_IPV6 */ *waitp = 0; /* default to synchronous response */ -#ifndef CURLRES_IPV4 + /* First check if this is an IPv4 address string */ + if(Curl_inet_pton(AF_INET, hostname, &in) > 0) + /* This is a dotted IP address 123.123.123.123-style */ + return Curl_ip2addr(AF_INET, &in, hostname, port); + +#ifdef CURLRES_IPV6 + /* check if this is an IPv6 address string */ + if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0) + /* This is an IPv6 address literal */ + return Curl_ip2addr(AF_INET6, &in6, hostname, port); + /* * Check if a limited name resolve has been requested. */ @@ -530,24 +629,11 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, break; } - if (pf != PF_INET) { - /* see if we have an IPv6 stack */ - curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); - if(s == CURL_SOCKET_BAD) { - /* Some non-IPv6 stacks have been found to make very slow name resolves - * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if - * the stack seems to be a non-ipv6 one. */ + if((pf != PF_INET) && !Curl_ipv6works()) + /* The stack seems to be a non-IPv6 one */ + pf = PF_INET; - pf = PF_INET; - } - else { - /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest - * possible checks. And close the socket again. - */ - sclose(s); - } - } -#endif /* !CURLRES_IPV4 */ +#endif /* CURLRES_IPV6 */ memset(&hints, 0, sizeof(hints)); hints.ai_family = pf; @@ -562,12 +648,12 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, } /* fall-back to blocking version */ - infof(data, "init_resolve_thread() failed for %s; %s\n", + infof(conn->data, "init_resolve_thread() failed for %s; %s\n", hostname, Curl_strerror(conn, ERRNO)); error = Curl_getaddrinfo_ex(hostname, sbuf, &hints, &res); if(error) { - infof(data, "getaddrinfo() failed for %s:%d; %s\n", + infof(conn->data, "getaddrinfo() failed for %s:%d; %s\n", hostname, port, Curl_strerror(conn, SOCKERRNO)); return NULL; } @@ -576,4 +662,37 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, #endif /* !HAVE_GETADDRINFO */ +CURLcode Curl_set_dns_servers(struct SessionHandle *data, + char *servers) +{ + (void)data; + (void)servers; + return CURLE_NOT_BUILT_IN; + +} + +CURLcode Curl_set_dns_interface(struct SessionHandle *data, + const char *interf) +{ + (void)data; + (void)interf; + return CURLE_NOT_BUILT_IN; +} + +CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, + const char *local_ip4) +{ + (void)data; + (void)local_ip4; + return CURLE_NOT_BUILT_IN; +} + +CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, + const char *local_ip6) +{ + (void)data; + (void)local_ip6; + return CURLE_NOT_BUILT_IN; +} + #endif /* CURLRES_THREADED */ diff --git a/project/jni/curl/lib/asyn.h b/project/jni/curl/lib/asyn.h new file mode 100644 index 000000000..416510f95 --- /dev/null +++ b/project/jni/curl/lib/asyn.h @@ -0,0 +1,168 @@ +#ifndef HEADER_CURL_ASYN_H +#define HEADER_CURL_ASYN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "curl_addrinfo.h" + +struct addrinfo; +struct hostent; +struct SessionHandle; +struct connectdata; +struct Curl_dns_entry; + +/* + * This header defines all functions in the internal asynch resolver interface. + * All asynch resolvers need to provide these functions. + * asyn-ares.c and asyn-thread.c are the current implementations of asynch + * resolver backends. + */ + +/* + * Curl_resolver_global_init() + * + * Called from curl_global_init() to initialize global resolver environment. + * Returning anything else than CURLE_OK fails curl_global_init(). + */ +int Curl_resolver_global_init(void); + +/* + * Curl_resolver_global_cleanup() + * Called from curl_global_cleanup() to destroy global resolver environment. + */ +void Curl_resolver_global_cleanup(void); + +/* + * Curl_resolver_init() + * Called from curl_easy_init() -> Curl_open() to initialize resolver + * URL-state specific environment ('resolver' member of the UrlState + * structure). Should fill the passed pointer by the initialized handler. + * Returning anything else than CURLE_OK fails curl_easy_init() with the + * correspondent code. + */ +CURLcode Curl_resolver_init(void **resolver); + +/* + * Curl_resolver_cleanup() + * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver + * URL-state specific environment ('resolver' member of the UrlState + * structure). Should destroy the handler and free all resources connected to + * it. + */ +void Curl_resolver_cleanup(void *resolver); + +/* + * Curl_resolver_duphandle() + * Called from curl_easy_duphandle() to duplicate resolver URL-state specific + * environment ('resolver' member of the UrlState structure). Should + * duplicate the 'from' handle and pass the resulting handle to the 'to' + * pointer. Returning anything else than CURLE_OK causes failed + * curl_easy_duphandle() call. + */ +int Curl_resolver_duphandle(void **to, void *from); + +/* + * Curl_resolver_cancel(). + * + * It is called from inside other functions to cancel currently performing + * resolver request. Should also free any temporary resources allocated to + * perform a request. + */ +void Curl_resolver_cancel(struct connectdata *conn); + +/* Curl_resolver_getsock() + * + * This function is called from the multi_getsock() function. 'sock' is a + * pointer to an array to hold the file descriptors, with 'numsock' being the + * size of that array (in number of entries). This function is supposed to + * return bitmask indicating what file descriptors (referring to array indexes + * in the 'sock' array) to wait for, read/write. + */ +int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *sock, + int numsocks); + +/* + * Curl_resolver_is_resolved() + * + * Called repeatedly to check if a previous name resolve request has + * completed. It should also make sure to time-out if the operation seems to + * take too long. + * + * Returns normal CURLcode errors. + */ +CURLcode Curl_resolver_is_resolved(struct connectdata *conn, + struct Curl_dns_entry **dns); + +/* + * Curl_resolver_wait_resolv() + * + * waits for a resolve to finish. This function should be avoided since using + * this risk getting the multi interface to "hang". + * + * If 'entry' is non-NULL, make it point to the resolved dns entry + * + * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and + * CURLE_OPERATION_TIMEDOUT if a time-out occurred. + + */ +CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, + struct Curl_dns_entry **dnsentry); + +/* + * Curl_resolver_getaddrinfo() - when using this resolver + * + * Returns name information about the given hostname and port number. If + * successful, the 'hostent' is returned and the forth argument will point to + * memory we need to free after use. That memory *MUST* be freed with + * Curl_freeaddrinfo(), nothing else. + * + * Each resolver backend must of course make sure to return data in the + * correct format to comply with this. + */ +Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp); + +#ifndef CURLRES_ASYNCH +/* convert these functions if an asynch resolver isn't used */ +#define Curl_resolver_cancel(x) Curl_nop_stmt +#define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST +#define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST +#define Curl_resolver_getsock(x,y,z) 0 +#define Curl_resolver_duphandle(x,y) CURLE_OK +#define Curl_resolver_init(x) CURLE_OK +#define Curl_resolver_global_init() CURLE_OK +#define Curl_resolver_global_cleanup() Curl_nop_stmt +#define Curl_resolver_cleanup(x) Curl_nop_stmt +#endif + +#ifdef CURLRES_ASYNCH +#define Curl_resolver_asynch() 1 +#else +#define Curl_resolver_asynch() 0 +#endif + + +/********** end of generic resolver interface functions *****************/ +#endif /* HEADER_CURL_ASYN_H */ diff --git a/project/jni/curl/lib/base64.c b/project/jni/curl/lib/base64.c index edccf5402..9bb7de495 100644 --- a/project/jni/curl/lib/base64.c +++ b/project/jni/curl/lib/base64.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,182 +20,196 @@ * ***************************************************************************/ -/* Base64 encoding/decoding - * - * Test harnesses down the bottom - compile with -DTEST_ENCODE for - * a program that will read in raw data from stdin and write out - * a base64-encoded version to stdout, and the length returned by the - * encoding function to stderr. Compile with -DTEST_DECODE for a program that - * will go the other way. - * - * This code will break if int is smaller than 32 bits - */ - -#include "setup.h" - -#include -#include - -#define _MPRINTF_REPLACE /* use our functions only */ -#include +/* Base64 encoding/decoding */ +#include "curl_setup.h" +#include "curl_printf.h" #include "urldata.h" /* for the SessionHandle definition */ -#include "easyif.h" /* for Curl_convert_... prototypes */ #include "warnless.h" #include "curl_base64.h" -#include "curl_memory.h" +#include "non-ascii.h" -/* include memdebug.h last */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* ---- Base64 Encoding/Decoding Table --- */ -static const char table64[]= +static const char base64[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static void decodeQuantum(unsigned char *dest, const char *src) +/* The Base 64 encoding with an URL and filename safe alphabet, RFC 4648 + section 5 */ +static const char base64url[]= + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +static size_t decodeQuantum(unsigned char *dest, const char *src) { + size_t padding = 0; const char *s, *p; - unsigned long i, v, x = 0; + unsigned long i, x = 0; for(i = 0, s = src; i < 4; i++, s++) { - v = 0; - p = table64; - while(*p && (*p != *s)) { - v++; - p++; - } - if(*p == *s) - x = (x << 6) + v; - else if(*s == '=') + unsigned long v = 0; + + if(*s == '=') { x = (x << 6); + padding++; + } + else { + p = base64; + + while(*p && (*p != *s)) { + v++; + p++; + } + + if(*p == *s) + x = (x << 6) + v; + else + return 0; + } } - dest[2] = curlx_ultouc(x); + if(padding < 1) + dest[2] = curlx_ultouc(x & 0xFFUL); + x >>= 8; - dest[1] = curlx_ultouc(x); + if(padding < 2) + dest[1] = curlx_ultouc(x & 0xFFUL); + x >>= 8; - dest[0] = curlx_ultouc(x); + dest[0] = curlx_ultouc(x & 0xFFUL); + + return 3 - padding; } /* * Curl_base64_decode() * - * Given a base64 string at src, decode it and return an allocated memory in - * the *outptr. Returns the length of the decoded data. + * Given a base64 NUL-terminated string at src, decode it and return a + * pointer in *outptr to a newly allocated memory area holding decoded + * data. Size of decoded data is returned in variable pointed by outlen. + * + * Returns CURLE_OK on success, otherwise specific error code. Function + * output shall not be considered valid unless CURLE_OK is returned. + * + * When decoded data length is 0, returns NULL in *outptr. + * + * @unittest: 1302 */ -size_t Curl_base64_decode(const char *src, unsigned char **outptr) +CURLcode Curl_base64_decode(const char *src, + unsigned char **outptr, size_t *outlen) { + size_t srclen = 0; size_t length = 0; - size_t equalsTerm = 0; + size_t padding = 0; size_t i; size_t numQuantums; - unsigned char lastQuantum[3]; size_t rawlen = 0; + unsigned char *pos; unsigned char *newstr; *outptr = NULL; + *outlen = 0; + srclen = strlen(src); + /* Check the length of the input string is valid */ + if(!srclen || srclen % 4) + return CURLE_BAD_CONTENT_ENCODING; + + /* Find the position of any = padding characters */ while((src[length] != '=') && src[length]) length++; + /* A maximum of two = padding characters is allowed */ if(src[length] == '=') { - equalsTerm++; - if(src[length+equalsTerm] == '=') - equalsTerm++; + padding++; + if(src[length + 1] == '=') + padding++; } - numQuantums = (length + equalsTerm) / 4; - /* Don't allocate a buffer if the decoded length is 0 */ - if(numQuantums == 0) - return 0; + /* Check the = padding characters weren't part way through the input */ + if(length + padding != srclen) + return CURLE_BAD_CONTENT_ENCODING; - rawlen = (numQuantums * 3) - equalsTerm; + /* Calculate the number of quantums */ + numQuantums = srclen / 4; - /* The buffer must be large enough to make room for the last quantum - (which may be partially thrown out) and the zero terminator. */ - newstr = malloc(rawlen+4); + /* Calculate the size of the decoded string */ + rawlen = (numQuantums * 3) - padding; + + /* Allocate our buffer including room for a zero terminator */ + newstr = malloc(rawlen + 1); if(!newstr) - return 0; + return CURLE_OUT_OF_MEMORY; - *outptr = newstr; + pos = newstr; - /* Decode all but the last quantum (which may not decode to a - multiple of 3 bytes) */ - for(i = 0; i < numQuantums - 1; i++) { - decodeQuantum(newstr, src); - newstr += 3; src += 4; + /* Decode the quantums */ + for(i = 0; i < numQuantums; i++) { + size_t result = decodeQuantum(pos, src); + if(!result) { + free(newstr); + + return CURLE_BAD_CONTENT_ENCODING; + } + + pos += result; + src += 4; } - /* This final decode may actually read slightly past the end of the buffer - if the input string is missing pad bytes. This will almost always be - harmless. */ - decodeQuantum(lastQuantum, src); - for(i = 0; i < 3 - equalsTerm; i++) - newstr[i] = lastQuantum[i]; + /* Zero terminate */ + *pos = '\0'; - newstr[i] = '\0'; /* zero terminate */ - return rawlen; + /* Return the decoded data */ + *outptr = newstr; + *outlen = rawlen; + + return CURLE_OK; } -/* - * Curl_base64_encode() - * - * Returns the length of the newly created base64 string. The third argument - * is a pointer to an allocated area holding the base64 data. If something - * went wrong, 0 is returned. - * - */ -size_t Curl_base64_encode(struct SessionHandle *data, - const char *inputbuff, size_t insize, - char **outptr) +static CURLcode base64_encode(const char *table64, + struct SessionHandle *data, + const char *inputbuff, size_t insize, + char **outptr, size_t *outlen) { + CURLcode result; unsigned char ibuf[3]; unsigned char obuf[4]; int i; int inputparts; char *output; char *base64data; -#ifdef CURL_DOES_CONVERSIONS char *convbuf = NULL; -#endif const char *indata = inputbuff; - *outptr = NULL; /* set to NULL in case of failure before we reach the end */ + *outptr = NULL; + *outlen = 0; - if(0 == insize) + if(!insize) insize = strlen(indata); - base64data = output = malloc(insize*4/3+4); - if(NULL == output) - return 0; + base64data = output = malloc(insize * 4 / 3 + 4); + if(!output) + return CURLE_OUT_OF_MEMORY; -#ifdef CURL_DOES_CONVERSIONS /* * The base64 data needs to be created using the network encoding * not the host encoding. And we can't change the actual input * so we copy it to a buffer, translate it, and use that instead. */ - if(data) { - convbuf = malloc(insize); - if(!convbuf) { - free(output); - return 0; - } - memcpy(convbuf, indata, insize); - if(CURLE_OK != Curl_convert_to_network(data, convbuf, insize)) { - free(convbuf); - free(output); - return 0; - } - indata = convbuf; /* switch to the converted buffer */ + result = Curl_convert_clone(data, indata, insize, &convbuf); + if(result) { + free(output); + return result; } -#else - (void)data; -#endif + + if(convbuf) + indata = (char *)convbuf; while(insize > 0) { - for (i = inputparts = 0; i < 3; i++) { + for(i = inputparts = 0; i < 3; i++) { if(insize > 0) { inputparts++; ibuf[i] = (unsigned char) *indata; @@ -219,12 +233,14 @@ size_t Curl_base64_encode(struct SessionHandle *data, table64[obuf[0]], table64[obuf[1]]); break; + case 2: /* two bytes read */ snprintf(output, 5, "%c%c%c=", table64[obuf[0]], table64[obuf[1]], table64[obuf[2]]); break; + default: snprintf(output, 5, "%c%c%c%c", table64[obuf[0]], @@ -235,13 +251,65 @@ size_t Curl_base64_encode(struct SessionHandle *data, } output += 4; } - *output=0; - *outptr = base64data; /* make it return the actual data memory */ -#ifdef CURL_DOES_CONVERSIONS - if(data) - free(convbuf); -#endif - return strlen(base64data); /* return the length of the new data */ + /* Zero terminate */ + *output = '\0'; + + /* Return the pointer to the new data (allocated memory) */ + *outptr = base64data; + + free(convbuf); + + /* Return the length of the new data */ + *outlen = strlen(base64data); + + return CURLE_OK; +} + +/* + * Curl_base64_encode() + * + * Given a pointer to an input buffer and an input size, encode it and + * return a pointer in *outptr to a newly allocated memory area holding + * encoded data. Size of encoded data is returned in variable pointed by + * outlen. + * + * Input length of 0 indicates input buffer holds a NUL-terminated string. + * + * Returns CURLE_OK on success, otherwise specific error code. Function + * output shall not be considered valid unless CURLE_OK is returned. + * + * When encoded data length is 0, returns NULL in *outptr. + * + * @unittest: 1302 + */ +CURLcode Curl_base64_encode(struct SessionHandle *data, + const char *inputbuff, size_t insize, + char **outptr, size_t *outlen) +{ + return base64_encode(base64, data, inputbuff, insize, outptr, outlen); +} + +/* + * Curl_base64url_encode() + * + * Given a pointer to an input buffer and an input size, encode it and + * return a pointer in *outptr to a newly allocated memory area holding + * encoded data. Size of encoded data is returned in variable pointed by + * outlen. + * + * Input length of 0 indicates input buffer holds a NUL-terminated string. + * + * Returns CURLE_OK on success, otherwise specific error code. Function + * output shall not be considered valid unless CURLE_OK is returned. + * + * When encoded data length is 0, returns NULL in *outptr. + * + * @unittest: 1302 + */ +CURLcode Curl_base64url_encode(struct SessionHandle *data, + const char *inputbuff, size_t insize, + char **outptr, size_t *outlen) +{ + return base64_encode(base64url, data, inputbuff, insize, outptr, outlen); } -/* ---- End of Base64 Encoding ---- */ diff --git a/project/jni/curl/lib/config-amigaos.h b/project/jni/curl/lib/config-amigaos.h index 99b96d656..74f5f5278 100644 --- a/project/jni/curl/lib/config-amigaos.h +++ b/project/jni/curl/lib/config-amigaos.h @@ -1,5 +1,5 @@ -#ifndef LIBCURL_CONFIG_AMIGAOS_H -#define LIBCURL_CONFIG_AMIGAOS_H +#ifndef HEADER_CURL_CONFIG_AMIGAOS_H +#define HEADER_CURL_CONFIG_AMIGAOS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,10 +22,15 @@ * ***************************************************************************/ +/* ================================================================ */ +/* Hand crafted config file for AmigaOS */ +/* ================================================================ */ + #ifdef __AMIGA__ /* Any AmigaOS flavour */ #define HAVE_ARPA_INET_H 1 #define HAVE_CLOSESOCKET_CAMEL 1 +#define HAVE_ERRNO_H 1 #define HAVE_GETHOSTBYADDR 1 #define HAVE_INET_ADDR 1 #define HAVE_INTTYPES_H 1 @@ -71,8 +76,6 @@ #define HAVE_SYS_STAT_H 1 #define HAVE_SYS_TIME_H 1 #define HAVE_SYS_TYPES_H 1 -#define HAVE_TERMIOS_H 1 -#define HAVE_TERMIO_H 1 #define HAVE_TIME_H 1 #define HAVE_UNAME 1 #define HAVE_UNISTD_H 1 @@ -88,11 +91,10 @@ #define SIZEOF_SHORT 2 #define SIZEOF_SIZE_T 4 +#define USE_MANUAL 1 #define USE_OPENSSL 1 -#define USE_SSLEAY 1 #define CURL_DISABLE_LDAP 1 - #define OS "AmigaOS" #define PACKAGE "curl" @@ -113,8 +115,20 @@ #define in_addr_t int +#ifndef F_OK +# define F_OK 0 +#endif + #ifndef O_RDONLY -# define O_RDONLY 0x0000 +# define O_RDONLY 0x0000 +#endif + +#ifndef LONG_MAX +# define LONG_MAX 0x7fffffffL +#endif + +#ifndef LONG_MIN +# define LONG_MIN (-0x7fffffffL-1) #endif #define HAVE_GETNAMEINFO 1 @@ -149,4 +163,4 @@ #define SEND_TYPE_RETV int #endif /* __AMIGA__ */ -#endif /* LIBCURL_CONFIG_AMIGAOS_H */ +#endif /* HEADER_CURL_CONFIG_AMIGAOS_H */ diff --git a/project/jni/curl/lib/config-dos.h b/project/jni/curl/lib/config-dos.h index bb0315e2c..f2c9ff403 100644 --- a/project/jni/curl/lib/config-dos.h +++ b/project/jni/curl/lib/config-dos.h @@ -1,5 +1,26 @@ -#ifndef HEADER_CONFIG_DOS_H -#define HEADER_CONFIG_DOS_H +#ifndef HEADER_CURL_CONFIG_DOS_H +#define HEADER_CURL_CONFIG_DOS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ /* ================================================================ */ @@ -19,6 +40,7 @@ #define PACKAGE "curl" #define HAVE_ARPA_INET_H 1 +#define HAVE_ERRNO_H 1 #define HAVE_FCNTL_H 1 #define HAVE_GETADDRINFO 1 #define HAVE_GETNAMEINFO 1 @@ -47,7 +69,6 @@ #define HAVE_SETMODE 1 #define HAVE_SIGNAL 1 #define HAVE_SOCKET 1 -#define HAVE_SPNEGO 1 #define HAVE_STRDUP 1 #define HAVE_STRICMP 1 #define HAVE_STRTOLL 1 @@ -57,7 +78,6 @@ #define HAVE_SYS_SOCKET_H 1 #define HAVE_SYS_STAT_H 1 #define HAVE_SYS_TYPES_H 1 -#define HAVE_TERMIOS_H 1 #define HAVE_TIME_H 1 #define HAVE_UNISTD_H 1 @@ -112,12 +132,11 @@ #define HAVE_LIBZ 1 #endif -/* USE_SSLEAY on cmd-line */ -#ifdef USE_SSLEAY +/* USE_OPENSSL on cmd-line */ +#ifdef USE_OPENSSL #define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 #define HAVE_OPENSSL_ENGINE_H 1 #define OPENSSL_NO_KRB5 1 - #define USE_OPENSSL 1 #endif /* to disable LDAP */ @@ -127,7 +146,7 @@ #if defined(__HIGHC__) || \ (defined(__GNUC__) && (__GNUC__ < 4)) -#define ssize_t int + #define ssize_t int #endif #define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE") @@ -140,31 +159,23 @@ #define HAVE_SIGACTION 1 #define HAVE_SIGSETJMP 1 #define HAVE_SYS_TIME_H 1 + #define HAVE_TERMIOS_H 1 #define HAVE_VARIADIC_MACROS_GCC 1 - #if (DJGPP_MINOR >= 4) - #define HAVE_STRLCAT 1 - #endif - - /* Because djgpp <= 2.03 doesn't have snprintf() etc. */ - #if (DJGPP_MINOR < 4) - #define _MPRINTF_REPLACE - #endif - #elif defined(__WATCOMC__) #define HAVE_STRCASECMP 1 #elif defined(__HIGHC__) #define HAVE_SYS_TIME_H 1 + #define strerror(e) strerror_s_((e)) #endif #ifdef MSDOS /* Watt-32 */ - #define HAVE_CLOSESOCKET_CAMEL 1 - #define CloseSocket(s) close_s((s)) + #define HAVE_CLOSE_S 1 #endif #undef word #undef byte -#endif /* HEADER_CONFIG_DOS_H */ +#endif /* HEADER_CURL_CONFIG_DOS_H */ diff --git a/project/jni/curl/lib/config-mac.h b/project/jni/curl/lib/config-mac.h index 1f7950ab1..3c12bdfac 100644 --- a/project/jni/curl/lib/config-mac.h +++ b/project/jni/curl/lib/config-mac.h @@ -1,14 +1,39 @@ -#ifndef __LIB_CONFIG_MAC_H -#define __LIB_CONFIG_MAC_H +#ifndef HEADER_CURL_CONFIG_MAC_H +#define HEADER_CURL_CONFIG_MAC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ /* =================================================================== */ -/* lib/config-mac.h - Hand crafted config file for Mac OS 9 */ +/* Hand crafted config file for Mac OS 9 */ /* =================================================================== */ /* On Mac OS X you must run configure to generate curl_config.h file */ /* =================================================================== */ #define OS "mac" +/* Define if you want the built-in manual */ +#define USE_MANUAL 1 + +#define HAVE_ERRNO_H 1 #define HAVE_NETINET_IN_H 1 #define HAVE_SYS_SOCKET_H 1 #define HAVE_SYS_SELECT_H 1 @@ -21,15 +46,16 @@ #define HAVE_FCNTL_H 1 #define HAVE_SYS_STAT_H 1 #define HAVE_ALLOCA_H 1 -#define HAVE_TIME_H 1 #define HAVE_STDLIB_H 1 +#define HAVE_TIME_H 1 #define HAVE_UTIME_H 1 #define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_UTIME_H 1 #define TIME_WITH_SYS_TIME 1 #define HAVE_ALARM 1 -#define HAVE_STRDUP 1 +#define HAVE_FTRUNCATE 1 #define HAVE_UTIME 1 #define HAVE_SETVBUF 1 #define HAVE_STRFTIME 1 @@ -39,14 +65,12 @@ #define HAVE_SOCKET 1 #define HAVE_STRUCT_TIMEVAL 1 -//#define HAVE_STRICMP 1 #define HAVE_SIGACTION 1 #define HAVE_SIGNAL_H 1 #define HAVE_SIG_ATOMIC_T 1 #ifdef MACOS_SSL_SUPPORT -# define USE_SSLEAY 1 -# define USE_OPENSSL 1 +# define USE_OPENSSL 1 #endif #define CURL_DISABLE_LDAP 1 @@ -98,4 +122,4 @@ #define HAVE_EXTRA_STRICMP_H 1 #define HAVE_EXTRA_STRDUP_H 1 -#endif /* __LIB_CONFIG_MAC_H */ +#endif /* HEADER_CURL_CONFIG_MAC_H */ diff --git a/project/jni/curl/lib/config-os400.h b/project/jni/curl/lib/config-os400.h index 370fc1138..fe5b864d6 100644 --- a/project/jni/curl/lib/config-os400.h +++ b/project/jni/curl/lib/config-os400.h @@ -1,5 +1,29 @@ +#ifndef HEADER_CURL_CONFIG_OS400_H +#define HEADER_CURL_CONFIG_OS400_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + /* ================================================================ */ -/* lib/config-os400.h - Hand crafted config file for OS/400 */ +/* Hand crafted config file for OS/400 */ /* ================================================================ */ #pragma enum(int) @@ -76,6 +100,9 @@ /* Define if you have the header file. */ #undef HAVE_DES_H +/* Define if you have the header file. */ +#define HAVE_ERRNO_H + /* Define if you have the header file. */ #undef HAVE_ERR_H @@ -148,6 +175,15 @@ /* Define if you have GSS API. */ #define HAVE_GSSAPI +/* Define if you have the GNU gssapi libraries */ +#undef HAVE_GSSGNU + +/* Define if you have the Heimdal gssapi libraries */ +#define HAVE_GSSHEIMDAL + +/* Define if you have the MIT gssapi libraries */ +#undef HAVE_GSSMIT + /* Define if you have the `ucb' library (-lucb). */ #undef HAVE_LIBUCB @@ -250,30 +286,33 @@ /* Define if you have the header file. */ #define HAVE_STDLIB_H + +/* The following define is needed on OS400 to enable strcmpi(), stricmp() and + strdup(). */ +#define __cplusplus__strings__ + /* Define if you have the `strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define if you have the `strcmpi' function. */ -#undef HAVE_STRCMPI +#define HAVE_STRCMPI + +/* Define if you have the `stricmp' function. */ +#define HAVE_STRICMP /* Define if you have the `strdup' function. */ -#undef HAVE_STRDUP +#define HAVE_STRDUP + /* Define if you have the `strftime' function. */ #define HAVE_STRFTIME -/* Define if you have the `stricmp' function. */ -#undef HAVE_STRICMP - /* Define if you have the header file. */ #define HAVE_STRINGS_H /* Define if you have the header file. */ #define HAVE_STRING_H -/* Define if you have the `strlcat' function. */ -#undef HAVE_STRLCAT - /* Define if you have the `strlcpy' function. */ #undef HAVE_STRLCPY @@ -410,10 +449,7 @@ /* To disable LDAP */ #undef CURL_DISABLE_LDAP -/* To avoid external use of library hidden symbols */ -#define CURL_HIDDEN_SYMBOLS - -/* External symbols need no special keyword. */ +/* Definition to make a library symbol externally visible. */ #define CURL_EXTERN_SYMBOL /* Define if you have the ldap_url_parse procedure. */ @@ -501,8 +537,14 @@ /* Define to the function return type for send. */ #define SEND_TYPE_RETV int -/* Define to use the QsoSSL package. */ -#define USE_QSOSSL +/* Define to use the GSKit package. */ +#define USE_GSKIT + +/* Define to use the OS/400 crypto library. */ +#define USE_OS400CRYPTO + +/* Define to use Unix sockets. */ +#define USE_UNIX_SOCKETS /* Use the system keyring as the default CA bundle. */ #define CURL_CA_BUNDLE "/QIBM/UserData/ICSS/Cert/Server/DEFAULT.KDB" @@ -518,3 +560,4 @@ #define qadrt_use_fread_inline /* Generate fread() wrapper inline. */ #define qadrt_use_fwrite_inline /* Generate fwrite() wrapper inline. */ +#endif /* HEADER_CURL_CONFIG_OS400_H */ diff --git a/project/jni/curl/lib/config-riscos.h b/project/jni/curl/lib/config-riscos.h index 84683aa26..0379524fb 100644 --- a/project/jni/curl/lib/config-riscos.h +++ b/project/jni/curl/lib/config-riscos.h @@ -1,4 +1,31 @@ -/* curl_config.h.in. Generated automatically from configure.in by autoheader. */ +#ifndef HEADER_CURL_CONFIG_RISCOS_H +#define HEADER_CURL_CONFIG_RISCOS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* Hand crafted config file for RISC OS */ +/* ================================================================ */ + /* Name of this package! */ #undef PACKAGE @@ -11,6 +38,9 @@ /* Define cpu-machine-OS */ #define OS "ARM-RISC OS" +/* Define if you want the built-in manual */ +#define USE_MANUAL + /* Define if you have the gethostbyaddr_r() function with 5 arguments */ #undef HAVE_GETHOSTBYADDR_R_5 @@ -53,8 +83,8 @@ /* Define if you want to enable IPv6 support */ #undef ENABLE_IPV6 -/* Define to 1 if you have the alarm function. */ -#define HAVE_ALARM 1 +/* Define if you have the alarm function. */ +#define HAVE_ALARM /* Define if you have the header file. */ #define HAVE_ALLOCA_H @@ -71,12 +101,18 @@ /* Define if you have the header file. */ #undef HAVE_DES_H +/* Define if you have the header file. */ +#define HAVE_ERRNO_H + /* Define if you have the header file. */ #undef HAVE_ERR_H /* Define if you have the header file. */ #define HAVE_FCNTL_H +/* Define if you have the `ftruncate' function. */ +#define HAVE_FTRUNCATE + /* Define if getaddrinfo exists and works */ #define HAVE_GETADDRINFO @@ -120,7 +156,7 @@ #define HAVE_INTTYPES_H /* Define if you have the header file. */ -#define HAVE_IO_H +#undef HAVE_IO_H /* Define if you have the `krb_get_our_ip_for_realm' function. */ #undef HAVE_KRB_GET_OUR_IP_FOR_REALM @@ -269,9 +305,6 @@ /* Define if you have the header file. */ #define HAVE_STRING_H -/* Define if you have the `strlcat' function. */ -#undef HAVE_STRLCAT - /* Define if you have the `strlcpy' function. */ #undef HAVE_STRLCPY @@ -438,8 +471,8 @@ /* Define to the type pointed by arg 2 for recvfrom. */ #define RECVFROM_TYPE_ARG2 void -/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */ -#define RECVFROM_TYPE_ARG2_IS_VOID 1 +/* Define if the type pointed by arg 2 for recvfrom is void. */ +#define RECVFROM_TYPE_ARG2_IS_VOID /* Define to the type of arg 3 for recvfrom. */ #define RECVFROM_TYPE_ARG3 size_t @@ -476,3 +509,5 @@ /* Define to the function return type for send. */ #define SEND_TYPE_RETV ssize_t + +#endif /* HEADER_CURL_CONFIG_RISCOS_H */ diff --git a/project/jni/curl/lib/config-symbian.h b/project/jni/curl/lib/config-symbian.h index 9f8b74a57..2603a46b4 100644 --- a/project/jni/curl/lib/config-symbian.h +++ b/project/jni/curl/lib/config-symbian.h @@ -1,7 +1,30 @@ -/* config-symbian.h. Manually generated. */ +#ifndef HEADER_CURL_CONFIG_SYMBIAN_H +#define HEADER_CURL_CONFIG_SYMBIAN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ -/* when building libcurl itself */ -/* #undef BUILDING_LIBCURL */ +/* ================================================================ */ +/* Hand crafted config file for Symbian */ +/* ================================================================ */ /* Location of default ca bundle */ /* #define CURL_CA_BUNDLE "/etc/pki/tls/certs/ca-bundle.crt"*/ @@ -42,17 +65,11 @@ /* to disable verbose strings */ /* #define CURL_DISABLE_VERBOSE_STRINGS 1*/ -/* to make a symbol visible */ -/*#define CURL_EXTERN_SYMBOL __declspec(dllexport)*/ - -/* to enable hidden symbols */ -/*#define CURL_HIDDEN_SYMBOLS 1*/ +/* Definition to make a library symbol externally visible. */ +/* #undef CURL_EXTERN_SYMBOL */ /* Use Windows LDAP implementation */ -/* #undef CURL_LDAP_WIN */ - -/* when not building a shared library */ -/* #undef CURL_STATICLIB */ +/* #undef USE_WIN32_LDAP */ /* your Entropy Gathering Daemon socket pathname */ /* #undef EGD_SOCKET */ @@ -243,7 +260,8 @@ /* Define to 1 if you have the IoctlSocket camel case function. */ /* #undef HAVE_IOCTLSOCKET_CAMEL */ -/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. */ +/* Define to 1 if you have a working IoctlSocket camel case FIONBIO + function. */ /* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */ /* Define to 1 if you have the header file. */ @@ -379,9 +397,6 @@ /* Define to 1 if you have the `pipe' function. */ #define HAVE_PIPE 1 -/* if you have the function PK11_CreateGenericObject */ -/* #undef HAVE_PK11_CREATEGENERICOBJECT */ - /* Define to 1 if you have the `poll' function. */ /*#define HAVE_POLL 1*/ @@ -466,9 +481,6 @@ /* Define to 1 if you have the `socket' function. */ #define HAVE_SOCKET 1 -/* Define this if you have the SPNEGO library fbopenssl */ -/* #undef HAVE_SPNEGO */ - /* Define to 1 if you have the `SSL_get_shutdown' function. */ /*#define HAVE_SSL_GET_SHUTDOWN 1*/ @@ -490,9 +502,6 @@ /* Define to 1 if you have the `strcasecmp' function. */ #define HAVE_STRCASECMP 1 -/* Define to 1 if you have the `strcasestr' function. */ -#define HAVE_STRCASESTR 1 - /* Define to 1 if you have the `strcmpi' function. */ /* #undef HAVE_STRCMPI */ @@ -511,9 +520,6 @@ /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 -/* Define to 1 if you have the `strlcat' function. */ -#define HAVE_STRLCAT 1 - /* Define to 1 if you have the `strlcpy' function. */ #define HAVE_STRLCPY 1 @@ -625,9 +631,6 @@ /* Define to 1 if you have the header file. */ /* #undef HAVE_X509_H */ -/* Define to 1 if you are building a native Windows target. */ -/* #undef NATIVE_WINDOWS */ - /* Define to 1 if you need the lber.h header file even with ldap.h */ /* #undef NEED_LBER_H */ @@ -654,7 +657,8 @@ /*#define PACKAGE "curl"*/ /* Define to the address where bug reports for this package should be sent. */ -/*#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"*/ +/*#define PACKAGE_BUGREPORT \ + "a suitable curl mailing list => https://curl.haxx.se/mail/"*/ /* Define to the full name of this package. */ /*#define PACKAGE_NAME "curl"*/ @@ -804,8 +808,4 @@ #define HAVE_ZLIB_H 1 #endif -/* Enable appropriate definitions only when OpenSSL support is enabled */ -#ifdef USE_SSLEAY -/* if OpenSSL is in use */ -#define USE_OPENSSL -#endif +#endif /* HEADER_CURL_CONFIG_SYMBIAN_H */ diff --git a/project/jni/curl/lib/config-tpf.h b/project/jni/curl/lib/config-tpf.h index 3e494f7c9..d1714fdfc 100644 --- a/project/jni/curl/lib/config-tpf.h +++ b/project/jni/curl/lib/config-tpf.h @@ -1,8 +1,29 @@ -#ifndef __LIBCONFIGTPF_H -#define __LIBCONFIGTPF_H +#ifndef HEADER_CURL_CONFIG_TPF_H +#define HEADER_CURL_CONFIG_TPF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ /* ================================================================ */ -/* lib/config-tpf.h - Hand crafted config file for TPF */ +/* Hand crafted config file for TPF */ /* ================================================================ */ /* ---------------------------------------------------------------- */ @@ -11,9 +32,6 @@ /* NOTE: Refer also to the .mak file for some of the flags below */ -/* when building libcurl itself */ -/* #undef BUILDING_LIBCURL */ - /* to disable cookies support */ /* #undef CURL_DISABLE_COOKIES */ @@ -44,9 +62,6 @@ /* to disable verbose strings */ /* #undef CURL_DISABLE_VERBOSE_STRINGS */ -/* when not building a shared library */ -/* #undef CURL_STATICLIB */ - /* lber dynamic library file */ /* #undef DL_LBER_FILE */ @@ -231,7 +246,8 @@ /* Define to 1 if you have the IoctlSocket camel case function. */ /* #undef HAVE_IOCTLSOCKET_CAMEL */ -/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. */ +/* Define to 1 if you have a working IoctlSocket camel case FIONBIO + function. */ /* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */ /* Define to 1 if you have the header file. */ @@ -421,9 +437,6 @@ /* Define to 1 if you have the `socket' function. */ #define HAVE_SOCKET 1 -/* Define this if you have the SPNEGO library fbopenssl */ -/* #undef HAVE_SPNEGO */ - /* Define to 1 if you have the header file. */ /* #undef HAVE_SSL_H */ #define HAVE_SSL_H 1 @@ -456,9 +469,6 @@ /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 -/* Define to 1 if you have the `strlcat' function. */ -/* #undef HAVE_STRLCAT */ - /* Define to 1 if you have the `strlcpy' function. */ /* #undef HAVE_STRLCPY */ @@ -569,7 +579,8 @@ #define PACKAGE "curl" /* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/" +#define PACKAGE_BUGREPORT \ + "a suitable curl mailing list => https://curl.haxx.se/mail/" /* Define to the full name of this package. */ #define PACKAGE_NAME "curl" @@ -635,7 +646,7 @@ /* #undef USE_OPENSSL */ /* if SSL is enabled */ -/* #undef USE_SSLEAY */ +/* #undef USE_OPENSSL */ /* to enable SSPI support */ /* #undef USE_WINDOWS_SSPI */ @@ -758,4 +769,4 @@ #endif -#endif /* __LIBCONFIGTPF_H */ +#endif /* HEADER_CURL_CONFIG_TPF_H */ diff --git a/project/jni/curl/lib/config-vms.h b/project/jni/curl/lib/config-vms.h deleted file mode 100644 index 73ef5c026..000000000 --- a/project/jni/curl/lib/config-vms.h +++ /dev/null @@ -1,374 +0,0 @@ -#ifndef HEADER_CONFIG_VMS_H -#define HEADER_CONFIG_VMS_H - -/* */ -/* MSK, 02/05/04, Hand edited for trail build on Alpha V7.3, DEC C 6.5-003 */ -/* MSK, 03/09/04, Seems to work for all platforms I've built on so far. */ -/* Added HAVE_SYS_IOCTL_H define */ -/* TES, 10/06/04, Added MAX_INITIAL_POST_SIZE, HAVE_BASENAME */ -/* MSK, 02/02/05, Changed HAVE_TERMIOS_H to an undef since the change in */ -/* getpass.c no longer undef'd it during compile. */ -/* MSK, 02/08/05, turned two config-vms files into one by using USE_SSLEAY */ -/* MPZ, 12/28/05, changed HAVE_STRTOK_R define to use CRTL_VER */ -/* MSK, 01/27/07, needed to add HAVE_STRUCT_TIMEVAL define */ - -/* Define cpu-machine-OS */ -#if defined(__alpha) -# define OS "ALPHA-HP-VMS" -#elif defined(__vax) -# define OS "VAX-HP-VMS" -#elif defined(__ia64) -# define OS "IA64-HP-VMS" -#else -# define OS "UNKNOWN-HP-VMS" -#endif - -/* Define if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define if you can safely include both and . */ -#define TIME_WITH_SYS_TIME 1 - -/* The size of `int', as computed by sizeof. */ -#define SIZEOF_INT 4 - -/* The size of `long double', as computed by sizeof. */ -#define SIZEOF_LONG_DOUBLE 8 - -/* The size of `long long', as computed by sizeof. */ -#define SIZEOF_LONG_LONG 8 - -/* The size of `short', as computed by sizeof. */ -#define SIZEOF_SHORT 2 - -/* The size of `size_t', as computed by sizeof. */ -#define SIZEOF_SIZE_T 4 - -/* Define if you have the alarm function. */ -#define HAVE_ALARM 1 - -/* Define if you have the geteuid function. */ -#define HAVE_GETEUID 1 - -/* Define if you have the basename function. */ -#define HAVE_BASENAME 1 - -/* Define if you have the gethostbyaddr function. */ -#define HAVE_GETHOSTBYADDR 1 - -/* Define if you have the gethostname function. */ -#define HAVE_GETHOSTNAME 1 - -/* Define if you have the getpwuid function. */ -#define HAVE_GETPWUID 1 - -/* Define if you have the getservbyname function. */ -#define HAVE_GETSERVBYNAME 1 - -/* Define if you have the gettimeofday function. */ -#define HAVE_GETTIMEOFDAY 1 - -/* Define if you have the inet_addr function. */ -#define HAVE_INET_ADDR 1 - -/* Define if you have the ioctl function. */ -#define HAVE_IOCTL 1 - -/* Define if you have a working ioctl FIONBIO function. */ -#define HAVE_IOCTL_FIONBIO 1 - -/* Define if you have a working ioctl SIOCGIFADDR function. */ -#define HAVE_IOCTL_SIOCGIFADDR 1 - -/* Define if you have the perror function. */ -#define HAVE_PERROR 1 - -/* Define if you have the select function. */ -#define HAVE_SELECT 1 - -/* Define if you have the setvbuf function. */ -#define HAVE_SETVBUF 1 - -/* Define if you have the sigaction function. */ -#define HAVE_SIGACTION 1 - -/* Define if you have the signal function. */ -#define HAVE_SIGNAL 1 - -/* Define if you have the socket function. */ -#define HAVE_SOCKET 1 - -/* Define if you have the strcasecmp function. */ -#define HAVE_STRCASECMP 1 - -/* Define if you have the strcmpi function. */ -/* #define HAVE_STRCMPI 1 */ - -/* Define if you have the strdup function. */ -#define HAVE_STRDUP 1 - -/* Define if you have the strftime function. */ -#define HAVE_STRFTIME 1 - -/* Define if you have the stricmp function. */ -/* #define HAVE_STRICMP 1 */ - -/* Define if you have the strstr function. */ -#define HAVE_STRSTR 1 - -/* Define if you have the ftruncate function. */ -#define HAVE_FTRUNCATE 1 - -/* Define if you have the uname function. */ -#define HAVE_UNAME 1 - -/* Define if you have the header file. */ -#define HAVE_ERR_H 1 - -/* Define if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define if you have the header file. */ -#define HAVE_GETOPT_H 1 - -/* Define if you have the header file. */ -#define HAVE_MALLOC_H 1 - -/* Define if you need the malloc.h header header file even with stdlib.h */ -/* #define NEED_MALLOC_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_NET_IF_H 1 - -/* Define if you have the header file. */ -#define HAVE_NETDB_H 1 - -/* Define if you have the header file. */ -#define HAVE_NETINET_IF_ETHER_H 1 - -/* Define if you have the header file. */ -#define HAVE_NETINET_IN_H 1 - -/* OpenSSL section starts here */ - -/* Define if you have a working OpenSSL installation */ -#ifdef USE_SSLEAY - -/* if OpenSSL is in use */ -#define USE_OPENSSL 1 - -/* Define if you have the crypto library (-lcrypto). */ -#define HAVE_LIBCRYPTO 1 - -/* Define if you have the ssl library (-lssl). */ -#define HAVE_LIBSSL 1 - -/* Define if you have the header file. */ -#define HAVE_OPENSSL_CRYPTO_H 1 - -/* Define if you have the header file. */ -#define HAVE_OPENSSL_ERR_H 1 - -/* Define if you have the header file. */ -#define HAVE_OPENSSL_PEM_H 1 - -/* Define if you have the header file. */ -#define HAVE_OPENSSL_RSA_H 1 - -/* Define if you have the header file. */ -#define HAVE_OPENSSL_SSL_H 1 - -/* Define if you have the header file. */ -#define HAVE_OPENSSL_X509_H 1 - -/* - * This needs to be defined for OpenSSL 0.9.7 and other versions that have the - * ENGINE stuff supported. If an include of "openssl/engine.h" fails, then - * undefine the define below. -*/ -#define HAVE_OPENSSL_ENGINE_H 1 - -#endif /* USE_SSLEAY */ -/* OpenSSL section ends here */ - -/* Define if you have the header file. */ -#define HAVE_PWD_H 1 - -/* Define if you have the header file. */ -#define HAVE_SGTTY_H 1 - -/* Define if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define if you have the header file. */ -#define HAVE_SYS_SOCKET_H 1 - -/* Define if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define if you have the header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define if you have the header file. */ -#undef HAVE_TERMIOS_H - -/* Define if you have the header file. */ -#define HAVE_TIME_H 1 - -/* Define if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define if you have the resolv library (-lresolv). */ -#define HAVE_LIBRESOLV 1 - -/* Define if you have the socket library (-lsocket). */ -#define HAVE_LIBSOCKET 1 - -/* Define if getaddrinfo exists and works */ -#define HAVE_GETADDRINFO 1 - -/* Define if you have the header file. */ -#define HAVE_TIMEVAL_H 1 - -/* Define if you have the timeval struct. */ -#define HAVE_STRUCT_TIMEVAL 1 - -/* Name of this package! */ -#define PACKAGE "not-used" - -/* Version number of this archive. */ -#define VERSION "not-used" - -/* Define if you have the getpass function. */ -#undef HAVE_GETPASS - -/* Define if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define if you have the `strtok_r' function. */ -/* Condition lifted from */ -#if __CRTL_VER >= 70301000 -# define HAVE_STRTOK_R 1 -#endif - -/* Define if you have the `strtoll' function. */ -#define HAVE_STRTOLL 1 - -/* Define if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you need the memory.h header file even with stdlib.h */ -#define NEED_MEMORY_H 1 - -/* Define if you have the `sigsetjmp' function. */ -#define HAVE_SIGSETJMP 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SETJMP_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LIMITS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_IOCTL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STROPTS_H 1 - -/* Define if you have the getnameinfo function. */ -#define HAVE_GETNAMEINFO 1 - -/* Define to the type qualifier of arg 1 for getnameinfo. */ -#define GETNAMEINFO_QUAL_ARG1 const - -/* Define to the type of arg 1 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * - -/* Define to the type of arg 2 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG2 size_t - -/* Define to the type of args 4 and 6 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG46 size_t - -/* Define to the type of arg 7 for getnameinfo. */ -#define GETNAMEINFO_TYPE_ARG7 int - -/* Define if you have the recv function. */ -#define HAVE_RECV 1 - -/* Define to the type of arg 1 for recv. */ -#define RECV_TYPE_ARG1 int - -/* Define to the type of arg 2 for recv. */ -#define RECV_TYPE_ARG2 void * - -/* Define to the type of arg 3 for recv. */ -#define RECV_TYPE_ARG3 int - -/* Define to the type of arg 4 for recv. */ -#define RECV_TYPE_ARG4 int - -/* Define to the function return type for recv. */ -#define RECV_TYPE_RETV int - -/* Define if you have the recvfrom function. */ -#define HAVE_RECVFROM 1 - -/* Define to the type of arg 1 for recvfrom. */ -#define RECVFROM_TYPE_ARG1 int - -/* Define to the type pointed by arg 2 for recvfrom. */ -#define RECVFROM_TYPE_ARG2 void - -/* Define if the type pointed by arg 2 for recvfrom is void. */ -#define RECVFROM_TYPE_ARG2_IS_VOID 1 - -/* Define to the type of arg 3 for recvfrom. */ -#define RECVFROM_TYPE_ARG3 int - -/* Define to the type of arg 4 for recvfrom. */ -#define RECVFROM_TYPE_ARG4 int - -/* Define to the type pointed by arg 5 for recvfrom. */ -#define RECVFROM_TYPE_ARG5 struct sockaddr - -/* Define to the type pointed by arg 6 for recvfrom. */ -#define RECVFROM_TYPE_ARG6 int - -/* Define to the function return type for recvfrom. */ -#define RECVFROM_TYPE_RETV int - -/* Define if you have the send function. */ -#define HAVE_SEND 1 - -/* Define to the type of arg 1 for send. */ -#define SEND_TYPE_ARG1 int - -/* Define to the type qualifier of arg 2 for send. */ -#define SEND_QUAL_ARG2 const - -/* Define to the type of arg 2 for send. */ -#define SEND_TYPE_ARG2 void * - -/* Define to the type of arg 3 for send. */ -#define SEND_TYPE_ARG3 int - -/* Define to the type of arg 4 for send. */ -#define SEND_TYPE_ARG4 int - -/* Define to the function return type for send. */ -#define SEND_TYPE_RETV int - -/* Define to hide dollar sign from compilers in strict ansi mode. */ -#define decc_translate_vms(__s) decc$translate_vms(__s) - -#endif /* HEADER_CONFIG_VMS_H */ diff --git a/project/jni/curl/lib/config-vxworks.h b/project/jni/curl/lib/config-vxworks.h index f7797fd0e..780a4a225 100644 --- a/project/jni/curl/lib/config-vxworks.h +++ b/project/jni/curl/lib/config-vxworks.h @@ -1,13 +1,31 @@ -#ifndef __LIB_CONFIG_VXWORKS_H -#define __LIB_CONFIG_VXWORKS_H +#ifndef HEADER_CURL_CONFIG_VXWORKS_H +#define HEADER_CURL_CONFIG_VXWORKS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ /* =============================================================== */ -/* lib/config-vxworks.h - Hand crafted config file for VxWorks */ +/* Hand crafted config file for VxWorks */ /* =============================================================== */ -/* when building libcurl itself */ -/* #undef BUILDING_LIBCURL */ - /* Location of default ca bundle */ /* #undef CURL_CA_BUNDLE */ @@ -53,17 +71,11 @@ /* to disable verbose strings */ /* #undef CURL_DISABLE_VERBOSE_STRINGS */ -/* to make a symbol visible */ +/* Definition to make a library symbol externally visible. */ /* #undef CURL_EXTERN_SYMBOL */ -/* to enable hidden symbols */ -/* #undef CURL_HIDDEN_SYMBOLS */ - /* Use Windows LDAP implementation */ -/* #undef CURL_LDAP_WIN */ - -/* when not building a shared library */ -/* #undef CURL_STATICLIB */ +/* #undef USE_WIN32_LDAP */ /* your Entropy Gathering Daemon socket pathname */ /* #undef EGD_SOCKET */ @@ -448,9 +460,6 @@ /* Define to 1 if you have the `pipe' function. */ #define HAVE_PIPE 1 -/* if you have the function PK11_CreateGenericObject */ -/* #undef HAVE_PK11_CREATEGENERICOBJECT */ - /* Define to 1 if you have a working poll function. */ /* #undef HAVE_POLL */ @@ -538,9 +547,6 @@ /* Define to 1 if you have the `socket' function. */ #define HAVE_SOCKET 1 -/* Define this if you have the SPNEGO library fbopenssl */ -/* #undef HAVE_SPNEGO */ - /* Define to 1 if you have the `SSL_get_shutdown' function. */ #define HAVE_SSL_GET_SHUTDOWN 1 @@ -562,9 +568,6 @@ /* Define to 1 if you have the strcasecmp function. */ #define HAVE_STRCASECMP 1 -/* Define to 1 if you have the strcasestr function. */ -/* #undef HAVE_STRCASESTR */ - /* Define to 1 if you have the strcmpi function. */ /* #undef HAVE_STRCMPI */ @@ -583,9 +586,6 @@ /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 -/* Define to 1 if you have the strlcat function. */ -/* #undef HAVE_STRLCAT */ - /* Define to 1 if you have the `strlcpy' function. */ /* #undef HAVE_STRLCPY */ @@ -724,9 +724,6 @@ /* if you have the zlib.h header file */ #define HAVE_ZLIB_H 1 -/* Define to 1 if you are building a native Windows target. */ -/* #undef NATIVE_WINDOWS */ - /* Define to 1 if you need the lber.h header file even with ldap.h */ /* #undef NEED_LBER_H */ @@ -886,9 +883,6 @@ /* if OpenSSL is in use */ #define USE_OPENSSL 1 -/* if SSL is enabled */ -#define USE_SSLEAY 1 - /* Define to 1 if you are building a Windows target without large file support. */ /* #undef USE_WIN32_LARGE_FILES */ @@ -931,4 +925,4 @@ /* the signed version of size_t */ /* #undef ssize_t */ -#endif /* __LIB_CONFIG_VXWORKS_H */ +#endif /* HEADER_CURL_CONFIG_VXWORKS_H */ diff --git a/project/jni/curl/lib/config-win32.h b/project/jni/curl/lib/config-win32.h index 67bfec3c0..af7bb1fb0 100644 --- a/project/jni/curl/lib/config-win32.h +++ b/project/jni/curl/lib/config-win32.h @@ -1,50 +1,84 @@ -#ifndef __LIB_CONFIG_WIN32_H -#define __LIB_CONFIG_WIN32_H +#ifndef HEADER_CURL_CONFIG_WIN32_H +#define HEADER_CURL_CONFIG_WIN32_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ /* ================================================================ */ -/* lib/config-win32.h - Hand crafted config file for Windows */ +/* Hand crafted config file for Windows */ /* ================================================================ */ /* ---------------------------------------------------------------- */ /* HEADER FILES */ /* ---------------------------------------------------------------- */ -/* Define if you have the header file. */ +/* Define if you have the header file. */ /* #define HAVE_ARPA_INET_H 1 */ -/* Define if you have the header file. */ +/* Define if you have the header file. */ #define HAVE_ASSERT_H 1 -/* Define if you have the header file. */ +/* Define if you have the header file. */ /* #define HAVE_CRYPTO_H 1 */ -/* Define if you have the header file. */ +/* Define if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define if you have the header file. */ /* #define HAVE_ERR_H 1 */ -/* Define if you have the header file. */ +/* Define if you have the header file. */ #define HAVE_FCNTL_H 1 -/* Define if you have the header file. */ -/* #define HAVE_GETOPT_H 1 */ +/* Define if you have the header file. */ +#if defined(__MINGW32__) || defined(__POCC__) +#define HAVE_GETOPT_H 1 +#endif -/* Define if you have the header file. */ +/* Define to 1 if you have the header file. */ +#if defined(_MSC_VER) && (_MSC_VER >= 1800) +#define HAVE_INTTYPES_H 1 +#endif + +/* Define if you have the header file. */ #define HAVE_IO_H 1 -/* Define if you have the header file. */ +/* Define if you have the header file. */ #define HAVE_LIMITS_H 1 -/* Define if you need the malloc.h header file even with stdlib.h */ +/* Define if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define if you need header even with header file. */ #if !defined(__SALFORDC__) && !defined(__POCC__) #define NEED_MALLOC_H 1 #endif -/* Define if you have the header file. */ +/* Define if you have the header file. */ /* #define HAVE_NETDB_H 1 */ -/* Define if you have the header file. */ +/* Define if you have the header file. */ /* #define HAVE_NETINET_IN_H 1 */ -/* Define if you have the header file. */ +/* Define if you have the header file. */ #ifndef __SALFORDC__ #define HAVE_PROCESS_H 1 #endif @@ -52,68 +86,73 @@ /* Define if you have the header file. */ #define HAVE_SIGNAL_H 1 -/* Define if you have the header file. */ +/* Define if you have the header file. */ /* #define HAVE_SGTTY_H 1 */ -/* Define if you have the header file. */ +/* Define if you have the header file. */ /* #define HAVE_SSL_H 1 */ -/* Define if you have the header file. */ +/* Define to 1 if you have the header file. */ +#if defined(_MSC_VER) && (_MSC_VER >= 1800) +#define HAVE_STDBOOL_H 1 +#endif + +/* Define if you have the header file. */ #define HAVE_STDLIB_H 1 -/* Define if you have the header file. */ +/* Define if you have the header file. */ /* #define HAVE_SYS_PARAM_H 1 */ -/* Define if you have the header file. */ +/* Define if you have the header file. */ /* #define HAVE_SYS_SELECT_H 1 */ -/* Define if you have the header file. */ +/* Define if you have the header file. */ /* #define HAVE_SYS_SOCKET_H 1 */ -/* Define if you have the header file. */ +/* Define if you have the header file. */ /* #define HAVE_SYS_SOCKIO_H 1 */ -/* Define if you have the header file. */ +/* Define if you have the header file. */ #define HAVE_SYS_STAT_H 1 -/* Define if you have the header file */ +/* Define if you have the header file. */ /* #define HAVE_SYS_TIME_H 1 */ -/* Define if you have the header file. */ +/* Define if you have the header file. */ #define HAVE_SYS_TYPES_H 1 -/* Define if you have the header file. */ +/* Define if you have the header file. */ #ifndef __BORLANDC__ #define HAVE_SYS_UTIME_H 1 #endif -/* Define if you have the header file. */ +/* Define if you have the header file. */ /* #define HAVE_TERMIO_H 1 */ -/* Define if you have the header file. */ +/* Define if you have the header file. */ /* #define HAVE_TERMIOS_H 1 */ -/* Define if you have the header file. */ +/* Define if you have the header file. */ #define HAVE_TIME_H 1 -/* Define if you have the header file. */ +/* Define if you have the header file. */ #if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__LCC__) || \ defined(__POCC__) #define HAVE_UNISTD_H 1 #endif -/* Define if you have the header file. */ +/* Define if you have the header file. */ #define HAVE_WINDOWS_H 1 -/* Define if you have the header file. */ +/* Define if you have the header file. */ #define HAVE_WINSOCK_H 1 -/* Define if you have the header file. */ +/* Define if you have the header file. */ #ifndef __SALFORDC__ #define HAVE_WINSOCK2_H 1 #endif -/* Define if you have the header file. */ +/* Define if you have the header file. */ #ifndef __SALFORDC__ #define HAVE_WS2TCPIP_H 1 #endif @@ -125,41 +164,49 @@ /* Define if sig_atomic_t is an available typedef. */ #define HAVE_SIG_ATOMIC_T 1 -/* Define if you have the ANSI C header files. */ +/* Define if you have the ANSI C header files. */ #define STDC_HEADERS 1 -/* Define if you can safely include both and . */ +/* Define if you can safely include both and . */ /* #define TIME_WITH_SYS_TIME 1 */ +/* Define to 1 if bool is an available type. */ +#if defined(_MSC_VER) && (_MSC_VER >= 1800) +#define HAVE_BOOL_T 1 +#endif + /* ---------------------------------------------------------------- */ /* FUNCTIONS */ /* ---------------------------------------------------------------- */ -/* Define if you have the closesocket function. */ +/* Define if you have the closesocket function. */ #define HAVE_CLOSESOCKET 1 -/* Define if you don't have vprintf but do have _doprnt. */ +/* Define if you don't have vprintf but do have _doprnt. */ /* #define HAVE_DOPRNT 1 */ -/* Define if you have the gethostbyaddr function. */ +/* Define if you have the ftruncate function. */ +#define HAVE_FTRUNCATE 1 + +/* Define if you have the gethostbyaddr function. */ #define HAVE_GETHOSTBYADDR 1 -/* Define if you have the gethostname function. */ +/* Define if you have the gethostname function. */ #define HAVE_GETHOSTNAME 1 -/* Define if you have the getpass function. */ +/* Define if you have the getpass function. */ /* #define HAVE_GETPASS 1 */ -/* Define if you have the getservbyname function. */ +/* Define if you have the getservbyname function. */ #define HAVE_GETSERVBYNAME 1 -/* Define if you have the getprotobyname function. */ +/* Define if you have the getprotobyname function. */ #define HAVE_GETPROTOBYNAME -/* Define if you have the gettimeofday function. */ +/* Define if you have the gettimeofday function. */ /* #define HAVE_GETTIMEOFDAY 1 */ -/* Define if you have the inet_addr function. */ +/* Define if you have the inet_addr function. */ #define HAVE_INET_ADDR 1 /* Define if you have the ioctlsocket function. */ @@ -168,35 +215,41 @@ /* Define if you have a working ioctlsocket FIONBIO function. */ #define HAVE_IOCTLSOCKET_FIONBIO 1 -/* Define if you have the perror function. */ +/* Define if you have the perror function. */ #define HAVE_PERROR 1 -/* Define if you have the RAND_screen function when using SSL */ +/* Define if you have the RAND_screen function when using SSL. */ #define HAVE_RAND_SCREEN 1 /* Define if you have the `RAND_status' function when using SSL. */ #define HAVE_RAND_STATUS 1 -/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. +/* Define if you have the `CRYPTO_cleanup_all_ex_data' function. This is present in OpenSSL versions after 0.9.6b */ #define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 -/* Define if you have the select function. */ +/* Define if you have the select function. */ #define HAVE_SELECT 1 -/* Define if you have the setvbuf function. */ +/* Define if you have the setlocale function. */ +#define HAVE_SETLOCALE 1 + +/* Define if you have the setmode function. */ +#define HAVE_SETMODE 1 + +/* Define if you have the setvbuf function. */ #define HAVE_SETVBUF 1 -/* Define if you have the socket function. */ +/* Define if you have the socket function. */ #define HAVE_SOCKET 1 -/* Define if you have the strcasecmp function. */ +/* Define if you have the strcasecmp function. */ /* #define HAVE_STRCASECMP 1 */ -/* Define if you have the strdup function. */ +/* Define if you have the strdup function. */ #define HAVE_STRDUP 1 -/* Define if you have the strftime function. */ +/* Define if you have the strftime function. */ #define HAVE_STRFTIME 1 /* Define if you have the stricmp function. */ @@ -208,21 +261,22 @@ /* Define if you have the strnicmp function. */ #define HAVE_STRNICMP 1 -/* Define if you have the strstr function. */ +/* Define if you have the strstr function. */ #define HAVE_STRSTR 1 -/* Define if you have the strtoll function. */ -#if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__POCC__) +/* Define if you have the strtoll function. */ +#if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__POCC__) || \ + (defined(_MSC_VER) && (_MSC_VER >= 1800)) #define HAVE_STRTOLL 1 #endif -/* Define if you have the tcgetattr function. */ +/* Define if you have the tcgetattr function. */ /* #define HAVE_TCGETATTR 1 */ -/* Define if you have the tcsetattr function. */ +/* Define if you have the tcsetattr function. */ /* #define HAVE_TCSETATTR 1 */ -/* Define if you have the utime function */ +/* Define if you have the utime function. */ #ifndef __BORLANDC__ #define HAVE_UTIME 1 #endif @@ -309,13 +363,13 @@ /* TYPEDEF REPLACEMENTS */ /* ---------------------------------------------------------------- */ -/* Define this if in_addr_t is not an available 'typedefed' type */ +/* Define if in_addr_t is not an available 'typedefed' type. */ #define in_addr_t unsigned long -/* Define as the return type of signal handlers (int or void). */ +/* Define to the return type of signal handlers (int or void). */ #define RETSIGTYPE void -/* Define ssize_t if it is not an available 'typedefed' type */ +/* Define if ssize_t is not an available 'typedefed' type. */ #ifndef _SSIZE_T_DEFINED # if (defined(__WATCOMC__) && (__WATCOMC__ >= 1240)) || \ defined(__POCC__) || \ @@ -333,19 +387,19 @@ /* TYPE SIZES */ /* ---------------------------------------------------------------- */ -/* The size of `int', as computed by sizeof. */ +/* Define to the size of `int', as computed by sizeof. */ #define SIZEOF_INT 4 -/* The size of `long double', as computed by sizeof. */ +/* Define to the size of `long double', as computed by sizeof. */ #define SIZEOF_LONG_DOUBLE 16 -/* The size of `long long', as computed by sizeof. */ +/* Define to the size of `long long', as computed by sizeof. */ /* #define SIZEOF_LONG_LONG 8 */ -/* The size of `short', as computed by sizeof. */ +/* Define to the size of `short', as computed by sizeof. */ #define SIZEOF_SHORT 2 -/* The size of `size_t', as computed by sizeof. */ +/* Define to the size of `size_t', as computed by sizeof. */ #if defined(_WIN64) # define SIZEOF_SIZE_T 8 #else @@ -353,16 +407,36 @@ #endif /* ---------------------------------------------------------------- */ -/* STRUCT RELATED */ +/* BSD-style lwIP TCP/IP stack SPECIFIC */ /* ---------------------------------------------------------------- */ -/* Define this if you have struct sockaddr_storage */ -#ifndef __SALFORDC__ -#define HAVE_STRUCT_SOCKADDR_STORAGE 1 -#endif +/* Define to use BSD-style lwIP TCP/IP stack. */ +/* #define USE_LWIPSOCK 1 */ -/* Define this if you have struct timeval */ -#define HAVE_STRUCT_TIMEVAL 1 +#ifdef USE_LWIPSOCK +# undef USE_WINSOCK +# undef HAVE_WINSOCK_H +# undef HAVE_WINSOCK2_H +# undef HAVE_WS2TCPIP_H +# undef HAVE_ERRNO_H +# undef HAVE_GETHOSTNAME +# undef HAVE_GETNAMEINFO +# undef LWIP_POSIX_SOCKETS_IO_NAMES +# undef RECV_TYPE_ARG1 +# undef RECV_TYPE_ARG3 +# undef SEND_TYPE_ARG1 +# undef SEND_TYPE_ARG3 +# define HAVE_FREEADDRINFO +# define HAVE_GETADDRINFO +# define HAVE_GETHOSTBYNAME +# define HAVE_GETHOSTBYNAME_R +# define HAVE_GETHOSTBYNAME_R_6 +# define LWIP_POSIX_SOCKETS_IO_NAMES 0 +# define RECV_TYPE_ARG1 int +# define RECV_TYPE_ARG3 size_t +# define SEND_TYPE_ARG1 int +# define SEND_TYPE_ARG3 size_t +#endif /* ---------------------------------------------------------------- */ /* Watt-32 tcp/ip SPECIFIC */ @@ -392,8 +466,11 @@ /* COMPILER SPECIFIC */ /* ---------------------------------------------------------------- */ -/* Undef keyword 'const' if it does not work. */ -/* #undef const */ +/* Define to nothing if compiler does not support 'const' qualifier. */ +/* #define const */ + +/* Define to nothing if compiler does not support 'volatile' qualifier. */ +/* #define volatile */ /* Windows should not have HAVE_GMTIME_R defined */ /* #undef HAVE_GMTIME_R */ @@ -404,18 +481,20 @@ #endif /* Define if the compiler supports the 'long long' data type. */ -#if defined(__MINGW32__) || defined(__WATCOMC__) +#if defined(__MINGW32__) || defined(__WATCOMC__) || \ + (defined(_MSC_VER) && (_MSC_VER >= 1310)) || \ + (defined(__BORLANDC__) && (__BORLANDC__ >= 0x561)) #define HAVE_LONGLONG 1 #endif -/* Define to avoid VS2005 complaining about portable C functions */ +/* Define to avoid VS2005 complaining about portable C functions. */ #if defined(_MSC_VER) && (_MSC_VER >= 1400) #define _CRT_SECURE_NO_DEPRECATE 1 #define _CRT_NONSTDC_NO_DEPRECATE 1 #endif -/* VS2005 and later dafault size for time_t is 64-bit, unless */ -/* _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */ +/* VS2005 and later dafault size for time_t is 64-bit, unless + _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */ #if defined(_MSC_VER) && (_MSC_VER >= 1400) # ifndef _USE_32BIT_TIME_T # define SIZEOF_TIME_T 8 @@ -424,36 +503,68 @@ # endif #endif -/* Officially, Microsoft's Windows SDK versions 6.X do not support Windows - 2000 as a supported build target. VS2008 default installations provide an - embedded Windows SDK v6.0A along with the claim that Windows 2000 is a - valid build target for VS2008. Popular belief is that binaries built using - Windows SDK versions 6.X and Windows 2000 as a build target are functional */ -#if defined(_MSC_VER) && (_MSC_VER >= 1500) -# define VS2008_MINIMUM_TARGET 0x0500 +/* Define some minimum and default build targets for Visual Studio */ +#if defined(_MSC_VER) + /* Officially, Microsoft's Windows SDK versions 6.X does not support Windows + 2000 as a supported build target. VS2008 default installations provides + an embedded Windows SDK v6.0A along with the claim that Windows 2000 is a + valid build target for VS2008. Popular belief is that binaries built with + VS2008 using Windows SDK versions v6.X and Windows 2000 as a build target + are functional. */ +# define VS2008_MIN_TARGET 0x0500 + + /* The minimum build target for VS2012 is Vista unless Update 1 is installed + and the v110_xp toolset is choosen. */ +# if defined(_USING_V110_SDK71_) +# define VS2012_MIN_TARGET 0x0501 +# else +# define VS2012_MIN_TARGET 0x0600 +# endif + + /* VS2008 default build target is Windows Vista. We override default target + to be Windows XP. */ +# define VS2008_DEF_TARGET 0x0501 + + /* VS2012 default build target is Windows Vista unless Update 1 is installed + and the v110_xp toolset is choosen. */ +# if defined(_USING_V110_SDK71_) +# define VS2012_DEF_TARGET 0x0501 +# else +# define VS2012_DEF_TARGET 0x0600 +# endif #endif -/* When no build target is specified VS2008 default build target is Windows - Vista, which leaves out even Winsows XP. If no build target has been given - for VS2008 we will target the minimum Officially supported build target, - which happens to be Windows XP. */ -#if defined(_MSC_VER) && (_MSC_VER >= 1500) -# define VS2008_DEFAULT_TARGET 0x0501 -#endif - -/* VS2008 default target settings and minimum build target check */ -#if defined(_MSC_VER) && (_MSC_VER >= 1500) +/* VS2008 default target settings and minimum build target check. */ +#if defined(_MSC_VER) && (_MSC_VER >= 1500) && (_MSC_VER <= 1600) # ifndef _WIN32_WINNT -# define _WIN32_WINNT VS2008_DEFAULT_TARGET +# define _WIN32_WINNT VS2008_DEF_TARGET # endif # ifndef WINVER -# define WINVER VS2008_DEFAULT_TARGET +# define WINVER VS2008_DEF_TARGET # endif -# if (_WIN32_WINNT < VS2008_MINIMUM_TARGET) || (WINVER < VS2008_MINIMUM_TARGET) +# if (_WIN32_WINNT < VS2008_MIN_TARGET) || (WINVER < VS2008_MIN_TARGET) # error VS2008 does not support Windows build targets prior to Windows 2000 # endif #endif +/* VS2012 default target settings and minimum build target check. */ +#if defined(_MSC_VER) && (_MSC_VER >= 1700) +# ifndef _WIN32_WINNT +# define _WIN32_WINNT VS2012_DEF_TARGET +# endif +# ifndef WINVER +# define WINVER VS2012_DEF_TARGET +# endif +# if (_WIN32_WINNT < VS2012_MIN_TARGET) || (WINVER < VS2012_MIN_TARGET) +# if defined(_USING_V110_SDK71_) +# error VS2012 does not support Windows build targets prior to Windows XP +# else +# error VS2012 does not support Windows build targets prior to Windows \ +Vista +# endif +# endif +#endif + /* When no build target is specified Pelles C 5.00 and later default build target is Windows Vista. We override default target to be Windows 2000. */ #if defined(__POCC__) && (__POCC__ >= 500) @@ -495,6 +606,26 @@ # endif #endif +/* ---------------------------------------------------------------- */ +/* STRUCT RELATED */ +/* ---------------------------------------------------------------- */ + +/* Define if you have struct sockaddr_storage. */ +#if !defined(__SALFORDC__) && !defined(__BORLANDC__) +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 +#endif + +/* Define if you have struct timeval. */ +#define HAVE_STRUCT_TIMEVAL 1 + +/* Define if struct sockaddr_in6 has the sin6_scope_id member. */ +#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +#if defined(HAVE_WINSOCK2_H) && defined(_WIN32_WINNT) && \ + (_WIN32_WINNT >= 0x0600) +#define HAVE_STRUCT_POLLFD 1 +#endif + /* ---------------------------------------------------------------- */ /* LARGE FILE SUPPORT */ /* ---------------------------------------------------------------- */ @@ -528,14 +659,17 @@ /* ---------------------------------------------------------------- */ /* - * Undefine both USE_ARES and USE_THREADS_WIN32 for synchronous DNS + * Undefine both USE_ARES and USE_THREADS_WIN32 for synchronous DNS. */ -/* Define USE_ARES to enable c-ares asynchronous DNS lookups */ +/* Define to enable c-ares asynchronous DNS lookups. */ /* #define USE_ARES 1 */ -/* Define USE_THREADS_WIN32 to enable threaded asynchronous DNS lookups */ -#define USE_THREADS_WIN32 1 +/* Default define to enable threaded asynchronous DNS lookups. */ +#if !defined(USE_SYNC_DNS) && !defined(USE_ARES) && \ + !defined(USE_THREADS_WIN32) +# define USE_THREADS_WIN32 1 +#endif #if defined(USE_ARES) && defined(USE_THREADS_WIN32) # error "Only one DNS lookup specialty may be defined at most" @@ -546,28 +680,33 @@ /* ---------------------------------------------------------------- */ #if defined(CURL_HAS_NOVELL_LDAPSDK) || defined(CURL_HAS_MOZILLA_LDAPSDK) -#undef CURL_LDAP_WIN +#undef USE_WIN32_LDAP #define HAVE_LDAP_SSL_H 1 #define HAVE_LDAP_URL_PARSE 1 #elif defined(CURL_HAS_OPENLDAP_LDAPSDK) -#undef CURL_LDAP_WIN +#undef USE_WIN32_LDAP #define HAVE_LDAP_URL_PARSE 1 #else #undef HAVE_LDAP_URL_PARSE -#define CURL_LDAP_WIN 1 +#define USE_WIN32_LDAP 1 #endif -#if defined(__WATCOMC__) && defined(CURL_LDAP_WIN) +#if defined(__WATCOMC__) && defined(USE_WIN32_LDAP) #if __WATCOMC__ < 1280 #define WINBERAPI __declspec(cdecl) #define WINLDAPAPI __declspec(cdecl) #endif #endif -#if defined(__POCC__) && defined(CURL_LDAP_WIN) +#if defined(__POCC__) && defined(USE_WIN32_LDAP) # define CURL_DISABLE_LDAP 1 #endif +/* Define to use the Windows crypto library. */ +#if !defined(USE_OPENSSL) && !defined(USE_NSS) +#define USE_WIN32_CRYPTO +#endif + /* ---------------------------------------------------------------- */ /* ADDITIONAL DEFINITIONS */ /* ---------------------------------------------------------------- */ @@ -576,10 +715,10 @@ #undef OS #if defined(_M_IX86) || defined(__i386__) /* x86 (MSVC or gcc) */ #define OS "i386-pc-win32" +#elif defined(_M_X64) || defined(__x86_64__) /* x86_64 (MSVC >=2005 or gcc) */ +#define OS "x86_64-pc-win32" #elif defined(_M_IA64) /* Itanium */ #define OS "ia64-pc-win32" -#elif defined(_M_X64) /* AMD64/EM64T - Not defined until MSVC 2005 */ -#define OS "amd64-pc-win32" #else #define OS "unknown-pc-win32" #endif @@ -587,8 +726,11 @@ /* Name of package */ #define PACKAGE "curl" -#if defined(__POCC__) || (USE_IPV6) +/* If you want to build curl with the built-in manual */ +#define USE_MANUAL 1 + +#if defined(__POCC__) || defined(USE_IPV6) # define ENABLE_IPV6 1 #endif -#endif /* __LIB_CONFIG_WIN32_H */ +#endif /* HEADER_CURL_CONFIG_WIN32_H */ diff --git a/project/jni/curl/lib/config-win32ce.h b/project/jni/curl/lib/config-win32ce.h index 3a5913e99..383948576 100644 --- a/project/jni/curl/lib/config-win32ce.h +++ b/project/jni/curl/lib/config-win32ce.h @@ -1,5 +1,26 @@ -#ifndef __LIB_CONFIG_WIN32CE_H -#define __LIB_CONFIG_WIN32CE_H +#ifndef HEADER_CURL_CONFIG_WIN32CE_H +#define HEADER_CURL_CONFIG_WIN32CE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ /* ================================================================ */ /* lib/config-win32ce.h - Hand crafted config file for windows ce */ @@ -18,6 +39,9 @@ /* Define if you have the header file. */ /* #define HAVE_CRYPTO_H 1 */ +/* Define if you have the header file. */ +/* #define HAVE_ERRNO_H 1 */ + /* Define if you have the header file. */ /* #define HAVE_ERR_H 1 */ @@ -55,7 +79,7 @@ #define HAVE_STDLIB_H 1 /* Define if you have the header file. */ -#define HAVE_PROCESS_H 1 +/* #define HAVE_PROCESS_H 1 */ /* Define if you have the header file. */ /* #define HAVE_SYS_PARAM_H 1 */ @@ -385,7 +409,7 @@ /* LDAP SUPPORT */ /* ---------------------------------------------------------------- */ -#define CURL_LDAP_WIN 1 +#define USE_WIN32_LDAP 1 #undef HAVE_LDAP_URL_PARSE /* ---------------------------------------------------------------- */ @@ -403,6 +427,14 @@ /* WinCE */ /* ---------------------------------------------------------------- */ +#ifndef UNICODE +# define UNICODE +#endif + +#ifndef _UNICODE +# define _UNICODE +#endif + #define CURL_DISABLE_FILE 1 #define CURL_DISABLE_TELNET 1 #define CURL_DISABLE_LDAP 1 @@ -411,6 +443,6 @@ #define ENOMEM 2 #define EAGAIN 3 -extern int stat(const char *path,struct stat *buffer ); +extern int stat(const char *path, struct stat *buffer); -#endif /* __LIB_CONFIG_WIN32CE_H */ +#endif /* HEADER_CURL_CONFIG_WIN32CE_H */ diff --git a/project/jni/curl/lib/conncache.c b/project/jni/curl/lib/conncache.c new file mode 100644 index 000000000..6e03caf3c --- /dev/null +++ b/project/jni/curl/lib/conncache.c @@ -0,0 +1,364 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2012, Linus Nielsen Feltzing, + * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "urldata.h" +#include "url.h" +#include "progress.h" +#include "multiif.h" +#include "sendf.h" +#include "rawstr.h" +#include "conncache.h" +#include "curl_printf.h" + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +static void conn_llist_dtor(void *user, void *element) +{ + struct connectdata *data = element; + (void)user; + + data->bundle = NULL; +} + +static CURLcode bundle_create(struct SessionHandle *data, + struct connectbundle **cb_ptr) +{ + (void)data; + DEBUGASSERT(*cb_ptr == NULL); + *cb_ptr = malloc(sizeof(struct connectbundle)); + if(!*cb_ptr) + return CURLE_OUT_OF_MEMORY; + + (*cb_ptr)->num_connections = 0; + (*cb_ptr)->multiuse = BUNDLE_UNKNOWN; + + (*cb_ptr)->conn_list = Curl_llist_alloc((curl_llist_dtor) conn_llist_dtor); + if(!(*cb_ptr)->conn_list) { + Curl_safefree(*cb_ptr); + return CURLE_OUT_OF_MEMORY; + } + return CURLE_OK; +} + +static void bundle_destroy(struct connectbundle *cb_ptr) +{ + if(!cb_ptr) + return; + + if(cb_ptr->conn_list) { + Curl_llist_destroy(cb_ptr->conn_list, NULL); + cb_ptr->conn_list = NULL; + } + free(cb_ptr); +} + +/* Add a connection to a bundle */ +static CURLcode bundle_add_conn(struct connectbundle *cb_ptr, + struct connectdata *conn) +{ + if(!Curl_llist_insert_next(cb_ptr->conn_list, cb_ptr->conn_list->tail, conn)) + return CURLE_OUT_OF_MEMORY; + + conn->bundle = cb_ptr; + + cb_ptr->num_connections++; + return CURLE_OK; +} + +/* Remove a connection from a bundle */ +static int bundle_remove_conn(struct connectbundle *cb_ptr, + struct connectdata *conn) +{ + struct curl_llist_element *curr; + + curr = cb_ptr->conn_list->head; + while(curr) { + if(curr->ptr == conn) { + Curl_llist_remove(cb_ptr->conn_list, curr, NULL); + cb_ptr->num_connections--; + conn->bundle = NULL; + return 1; /* we removed a handle */ + } + curr = curr->next; + } + return 0; +} + +static void free_bundle_hash_entry(void *freethis) +{ + struct connectbundle *b = (struct connectbundle *) freethis; + + bundle_destroy(b); +} + +int Curl_conncache_init(struct conncache *connc, int size) +{ + return Curl_hash_init(&connc->hash, size, Curl_hash_str, + Curl_str_key_compare, free_bundle_hash_entry); +} + +void Curl_conncache_destroy(struct conncache *connc) +{ + if(connc) + Curl_hash_destroy(&connc->hash); +} + +/* returns an allocated key to find a bundle for this connection */ +static char *hashkey(struct connectdata *conn) +{ + return aprintf("%s:%d", + conn->bits.proxy?conn->proxy.name:conn->host.name, + conn->localport); +} + +/* Look up the bundle with all the connections to the same host this + connectdata struct is setup to use. */ +struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn, + struct conncache *connc) +{ + struct connectbundle *bundle = NULL; + if(connc) { + char *key = hashkey(conn); + if(key) { + bundle = Curl_hash_pick(&connc->hash, key, strlen(key)); + free(key); + } + } + + return bundle; +} + +static bool conncache_add_bundle(struct conncache *connc, + char *key, + struct connectbundle *bundle) +{ + void *p = Curl_hash_add(&connc->hash, key, strlen(key), bundle); + + return p?TRUE:FALSE; +} + +static void conncache_remove_bundle(struct conncache *connc, + struct connectbundle *bundle) +{ + struct curl_hash_iterator iter; + struct curl_hash_element *he; + + if(!connc) + return; + + Curl_hash_start_iterate(&connc->hash, &iter); + + he = Curl_hash_next_element(&iter); + while(he) { + if(he->ptr == bundle) { + /* The bundle is destroyed by the hash destructor function, + free_bundle_hash_entry() */ + Curl_hash_delete(&connc->hash, he->key, he->key_len); + return; + } + + he = Curl_hash_next_element(&iter); + } +} + +CURLcode Curl_conncache_add_conn(struct conncache *connc, + struct connectdata *conn) +{ + CURLcode result; + struct connectbundle *bundle; + struct connectbundle *new_bundle = NULL; + struct SessionHandle *data = conn->data; + + bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache); + if(!bundle) { + char *key; + int rc; + + result = bundle_create(data, &new_bundle); + if(result) + return result; + + key = hashkey(conn); + if(!key) { + bundle_destroy(new_bundle); + return CURLE_OUT_OF_MEMORY; + } + + rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle); + free(key); + if(!rc) { + bundle_destroy(new_bundle); + return CURLE_OUT_OF_MEMORY; + } + bundle = new_bundle; + } + + result = bundle_add_conn(bundle, conn); + if(result) { + if(new_bundle) + conncache_remove_bundle(data->state.conn_cache, new_bundle); + return result; + } + + conn->connection_id = connc->next_connection_id++; + connc->num_connections++; + + DEBUGF(infof(conn->data, "Added connection %ld. " + "The cache now contains %" CURL_FORMAT_CURL_OFF_TU " members\n", + conn->connection_id, (curl_off_t) connc->num_connections)); + + return CURLE_OK; +} + +void Curl_conncache_remove_conn(struct conncache *connc, + struct connectdata *conn) +{ + struct connectbundle *bundle = conn->bundle; + + /* The bundle pointer can be NULL, since this function can be called + due to a failed connection attempt, before being added to a bundle */ + if(bundle) { + bundle_remove_conn(bundle, conn); + if(bundle->num_connections == 0) { + conncache_remove_bundle(connc, bundle); + } + + if(connc) { + connc->num_connections--; + + DEBUGF(infof(conn->data, "The cache now contains %" + CURL_FORMAT_CURL_OFF_TU " members\n", + (curl_off_t) connc->num_connections)); + } + } +} + +/* This function iterates the entire connection cache and calls the + function func() with the connection pointer as the first argument + and the supplied 'param' argument as the other, + + Return 0 from func() to continue the loop, return 1 to abort it. + */ +void Curl_conncache_foreach(struct conncache *connc, + void *param, + int (*func)(struct connectdata *conn, void *param)) +{ + struct curl_hash_iterator iter; + struct curl_llist_element *curr; + struct curl_hash_element *he; + + if(!connc) + return; + + Curl_hash_start_iterate(&connc->hash, &iter); + + he = Curl_hash_next_element(&iter); + while(he) { + struct connectbundle *bundle; + + bundle = he->ptr; + he = Curl_hash_next_element(&iter); + + curr = bundle->conn_list->head; + while(curr) { + /* Yes, we need to update curr before calling func(), because func() + might decide to remove the connection */ + struct connectdata *conn = curr->ptr; + curr = curr->next; + + if(1 == func(conn, param)) + return; + } + } +} + +/* Return the first connection found in the cache. Used when closing all + connections */ +struct connectdata * +Curl_conncache_find_first_connection(struct conncache *connc) +{ + struct curl_hash_iterator iter; + struct curl_hash_element *he; + struct connectbundle *bundle; + + Curl_hash_start_iterate(&connc->hash, &iter); + + he = Curl_hash_next_element(&iter); + while(he) { + struct curl_llist_element *curr; + bundle = he->ptr; + + curr = bundle->conn_list->head; + if(curr) { + return curr->ptr; + } + + he = Curl_hash_next_element(&iter); + } + + return NULL; +} + + +#if 0 +/* Useful for debugging the connection cache */ +void Curl_conncache_print(struct conncache *connc) +{ + struct curl_hash_iterator iter; + struct curl_llist_element *curr; + struct curl_hash_element *he; + + if(!connc) + return; + + fprintf(stderr, "=Bundle cache=\n"); + + Curl_hash_start_iterate(connc->hash, &iter); + + he = Curl_hash_next_element(&iter); + while(he) { + struct connectbundle *bundle; + struct connectdata *conn; + + bundle = he->ptr; + + fprintf(stderr, "%s -", he->key); + curr = bundle->conn_list->head; + while(curr) { + conn = curr->ptr; + + fprintf(stderr, " [%p %d]", (void *)conn, conn->inuse); + curr = curr->next; + } + fprintf(stderr, "\n"); + + he = Curl_hash_next_element(&iter); + } +} +#endif diff --git a/project/jni/curl/lib/conncache.h b/project/jni/curl/lib/conncache.h new file mode 100644 index 000000000..b1dadf990 --- /dev/null +++ b/project/jni/curl/lib/conncache.h @@ -0,0 +1,68 @@ +#ifndef HEADER_CURL_CONNCACHE_H +#define HEADER_CURL_CONNCACHE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2015, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2014, Linus Nielsen Feltzing, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +struct conncache { + struct curl_hash hash; + size_t num_connections; + long next_connection_id; + struct timeval last_cleanup; +}; + +#define BUNDLE_NO_MULTIUSE -1 +#define BUNDLE_UNKNOWN 0 /* initial value */ +#define BUNDLE_PIPELINING 1 +#define BUNDLE_MULTIPLEX 2 + +struct connectbundle { + int multiuse; /* supports multi-use */ + size_t num_connections; /* Number of connections in the bundle */ + struct curl_llist *conn_list; /* The connectdata members of the bundle */ +}; + +int Curl_conncache_init(struct conncache *, int size); + +void Curl_conncache_destroy(struct conncache *connc); + +/* return the correct bundle, to a host or a proxy */ +struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn, + struct conncache *connc); + +CURLcode Curl_conncache_add_conn(struct conncache *connc, + struct connectdata *conn); + +void Curl_conncache_remove_conn(struct conncache *connc, + struct connectdata *conn); + +void Curl_conncache_foreach(struct conncache *connc, + void *param, + int (*func)(struct connectdata *conn, + void *param)); + +struct connectdata * +Curl_conncache_find_first_connection(struct conncache *connc); + +void Curl_conncache_print(struct conncache *connc); + +#endif /* HEADER_CURL_CONNCACHE_H */ diff --git a/project/jni/curl/lib/connect.c b/project/jni/curl/lib/connect.c index 7638854b3..567186a69 100644 --- a/project/jni/curl/lib/connect.c +++ b/project/jni/curl/lib/connect.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,14 +20,8 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include /* may need it */ #endif @@ -40,9 +34,6 @@ #ifdef HAVE_SYS_IOCTL_H #include #endif -#ifdef HAVE_UNISTD_H -#include -#endif #ifdef HAVE_NETDB_H #include #endif @@ -52,9 +43,6 @@ #ifdef HAVE_ARPA_INET_H #include #endif -#ifdef HAVE_STDLIB_H -#include -#endif #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE)) #include @@ -68,29 +56,26 @@ #include #endif -#include -#include -#include - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "curl_printf.h" #include "urldata.h" #include "sendf.h" #include "if2ip.h" #include "strerror.h" #include "connect.h" -#include "curl_memory.h" #include "select.h" #include "url.h" /* for Curl_safefree() */ #include "multiif.h" #include "sockaddr.h" /* required for Curl_sockaddr_storage */ #include "inet_ntop.h" #include "inet_pton.h" -#include "sslgen.h" /* for Curl_ssl_check_cxn() */ +#include "vtls/vtls.h" /* for Curl_ssl_check_cxn() */ #include "progress.h" +#include "warnless.h" +#include "conncache.h" +#include "multihandle.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #ifdef __SYMBIAN32__ @@ -98,41 +83,105 @@ #undef SO_NOSIGPIPE #endif -struct Curl_sockaddr_ex { - int family; - int socktype; - int protocol; - unsigned int addrlen; - union { - struct sockaddr addr; - struct Curl_sockaddr_storage buff; - } _sa_ex_u; -}; -#define sa_addr _sa_ex_u.addr - static bool verifyconnect(curl_socket_t sockfd, int *error); +#if defined(__DragonFly__) || defined(HAVE_WINSOCK_H) +/* DragonFlyBSD and Windows use millisecond units */ +#define KEEPALIVE_FACTOR(x) (x *= 1000) +#else +#define KEEPALIVE_FACTOR(x) +#endif + +#if defined(HAVE_WINSOCK2_H) && !defined(SIO_KEEPALIVE_VALS) +#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) + +struct tcp_keepalive { + u_long onoff; + u_long keepalivetime; + u_long keepaliveinterval; +}; +#endif + +static void +tcpkeepalive(struct SessionHandle *data, + curl_socket_t sockfd) +{ + int optval = data->set.tcp_keepalive?1:0; + + /* only set IDLE and INTVL if setting KEEPALIVE is successful */ + if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, + (void *)&optval, sizeof(optval)) < 0) { + infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd); + } + else { +#if defined(SIO_KEEPALIVE_VALS) + struct tcp_keepalive vals; + DWORD dummy; + vals.onoff = 1; + optval = curlx_sltosi(data->set.tcp_keepidle); + KEEPALIVE_FACTOR(optval); + vals.keepalivetime = optval; + optval = curlx_sltosi(data->set.tcp_keepintvl); + KEEPALIVE_FACTOR(optval); + vals.keepaliveinterval = optval; + if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals), + NULL, 0, &dummy, NULL, NULL) != 0) { + infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d\n", + (int)sockfd, WSAGetLastError()); + } +#else +#ifdef TCP_KEEPIDLE + optval = curlx_sltosi(data->set.tcp_keepidle); + KEEPALIVE_FACTOR(optval); + if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, + (void *)&optval, sizeof(optval)) < 0) { + infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd); + } +#endif +#ifdef TCP_KEEPINTVL + optval = curlx_sltosi(data->set.tcp_keepintvl); + KEEPALIVE_FACTOR(optval); + if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, + (void *)&optval, sizeof(optval)) < 0) { + infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd); + } +#endif +#ifdef TCP_KEEPALIVE + /* Mac OS X style */ + optval = curlx_sltosi(data->set.tcp_keepidle); + KEEPALIVE_FACTOR(optval); + if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE, + (void *)&optval, sizeof(optval)) < 0) { + infof(data, "Failed to set TCP_KEEPALIVE on fd %d\n", sockfd); + } +#endif +#endif + } +} + static CURLcode singleipconnect(struct connectdata *conn, const Curl_addrinfo *ai, /* start connecting to this */ - long timeout_ms, - curl_socket_t *sock, - bool *connected); + curl_socket_t *sock); /* * Curl_timeleft() returns the amount of milliseconds left allowed for the * transfer/connection. If the value is negative, the timeout time has already * elapsed. * + * The start time is stored in progress.t_startsingle - as set with + * Curl_pgrsTime(..., TIMER_STARTSINGLE); + * * If 'nowp' is non-NULL, it points to the current time. * 'duringconnect' is FALSE if not during a connect, as then of course the * connect timeout is not taken into account! + * + * @unittest: 1303 */ -long Curl_timeleft(struct connectdata *conn, +long Curl_timeleft(struct SessionHandle *data, struct timeval *nowp, bool duringconnect) { - struct SessionHandle *data = conn->data; int timeout_set = 0; long timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0; struct timeval now; @@ -172,8 +221,13 @@ long Curl_timeleft(struct connectdata *conn, nowp = &now; } - /* substract elapsed time */ - timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle); + /* subtract elapsed time */ + if(duringconnect) + /* since this most recent connect started */ + timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle); + else + /* since the entire operation started */ + timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startop); if(!timeout_ms) /* avoid returning 0 as that means no timeout! */ return -1; @@ -181,62 +235,8 @@ long Curl_timeleft(struct connectdata *conn, return timeout_ms; } -/* - * waitconnect() waits for a TCP connect on the given socket for the specified - * number if milliseconds. It returns: - */ - -#define WAITCONN_CONNECTED 0 -#define WAITCONN_SELECT_ERROR -1 -#define WAITCONN_TIMEOUT 1 -#define WAITCONN_FDSET_ERROR 2 -#define WAITCONN_ABORTED 3 - -static -int waitconnect(struct connectdata *conn, - curl_socket_t sockfd, /* socket */ - long timeout_msec) -{ - int rc; -#ifdef mpeix - /* Call this function once now, and ignore the results. We do this to - "clear" the error state on the socket so that we can later read it - reliably. This is reported necessary on the MPE/iX operating system. */ - (void)verifyconnect(sockfd, NULL); -#endif - - for(;;) { - - /* now select() until we get connect or timeout */ - rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, (int)(timeout_msec>1000? - 1000:timeout_msec)); - if(Curl_pgrsUpdate(conn)) - return WAITCONN_ABORTED; - - if(-1 == rc) - /* error, no connect here, try next */ - return WAITCONN_SELECT_ERROR; - - else if(0 == rc) { - /* timeout */ - timeout_msec -= 1000; - if(timeout_msec <= 0) - return WAITCONN_TIMEOUT; - - continue; - } - - if(rc & CURL_CSELECT_ERR) - /* error condition caught */ - return WAITCONN_FDSET_ERROR; - - break; - } - return WAITCONN_CONNECTED; -} - static CURLcode bindlocal(struct connectdata *conn, - curl_socket_t sockfd, int af) + curl_socket_t sockfd, int af, unsigned int scope) { struct SessionHandle *data = conn->data; @@ -255,53 +255,83 @@ static CURLcode bindlocal(struct connectdata *conn, int portnum = data->set.localportrange; const char *dev = data->set.str[STRING_DEVICE]; int error; - char myhost[256] = ""; - int done = 0; /* -1 for error, 1 for address found */ /************************************************************* * Select device to bind socket to *************************************************************/ - if ( !dev && !port ) + if(!dev && !port) /* no local kind of binding was requested */ return CURLE_OK; memset(&sa, 0, sizeof(struct Curl_sockaddr_storage)); if(dev && (strlen(dev)<255) ) { + char myhost[256] = ""; + int done = 0; /* -1 for error, 1 for address found */ + bool is_interface = FALSE; + bool is_host = FALSE; + static const char *if_prefix = "if!"; + static const char *host_prefix = "host!"; + + if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) { + dev += strlen(if_prefix); + is_interface = TRUE; + } + else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) { + dev += strlen(host_prefix); + is_host = TRUE; + } /* interface */ - if(Curl_if2ip(af, dev, myhost, sizeof(myhost))) { - /* - * We now have the numerical IP address in the 'myhost' buffer - */ - infof(data, "Local Interface %s is ip %s using address family %i\n", - dev, myhost, af); - done = 1; + if(!is_host) { + switch(Curl_if2ip(af, scope, conn->scope_id, dev, + myhost, sizeof(myhost))) { + case IF2IP_NOT_FOUND: + if(is_interface) { + /* Do not fall back to treating it as a host name */ + failf(data, "Couldn't bind to interface '%s'", dev); + return CURLE_INTERFACE_FAILED; + } + break; + case IF2IP_AF_NOT_SUPPORTED: + /* Signal the caller to try another address family if available */ + return CURLE_UNSUPPORTED_PROTOCOL; + case IF2IP_FOUND: + is_interface = TRUE; + /* + * We now have the numerical IP address in the 'myhost' buffer + */ + infof(data, "Local Interface %s is ip %s using address family %i\n", + dev, myhost, af); + done = 1; #ifdef SO_BINDTODEVICE - /* I am not sure any other OSs than Linux that provide this feature, and - * at the least I cannot test. --Ben - * - * This feature allows one to tightly bind the local socket to a - * particular interface. This will force even requests to other local - * interfaces to go out the external interface. - * - * - * Only bind to the interface when specified as interface, not just as a - * hostname or ip address. - */ - if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, - dev, (curl_socklen_t)strlen(dev)+1) != 0) { - error = SOCKERRNO; - infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;" - " will do regular bind\n", - dev, error, Curl_strerror(conn, error)); - /* This is typically "errno 1, error: Operation not permitted" if - you're not running as root or another suitable privileged user */ - } + /* I am not sure any other OSs than Linux that provide this feature, + * and at the least I cannot test. --Ben + * + * This feature allows one to tightly bind the local socket to a + * particular interface. This will force even requests to other + * local interfaces to go out the external interface. + * + * + * Only bind to the interface when specified as interface, not just + * as a hostname or ip address. + */ + if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, + dev, (curl_socklen_t)strlen(dev)+1) != 0) { + error = SOCKERRNO; + infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;" + " will do regular bind\n", + dev, error, Curl_strerror(conn, error)); + /* This is typically "errno 1, error: Operation not permitted" if + you're not running as root or another suitable privileged + user */ + } #endif + break; + } } - else { + if(!is_interface) { /* * This was not an interface, resolve the name as a host name * or IP number @@ -313,16 +343,16 @@ static CURLcode bindlocal(struct connectdata *conn, long ipver = conn->ip_version; int rc; - if (af == AF_INET) + if(af == AF_INET) conn->ip_version = CURL_IPRESOLVE_V4; #ifdef ENABLE_IPV6 - else if (af == AF_INET6) + else if(af == AF_INET6) conn->ip_version = CURL_IPRESOLVE_V6; #endif rc = Curl_resolv(conn, dev, 0, &h); if(rc == CURLRESOLV_PENDING) - (void)Curl_wait_for_resolv(conn, &h); + (void)Curl_resolver_wait_resolv(conn, &h); conn->ip_version = ipver; if(h) { @@ -344,16 +374,30 @@ static CURLcode bindlocal(struct connectdata *conn, if(done > 0) { #ifdef ENABLE_IPV6 - /* ipv6 address */ - if((af == AF_INET6) && - (Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0)) { - si6->sin6_family = AF_INET6; - si6->sin6_port = htons(port); + /* IPv6 address */ + if(af == AF_INET6) { +#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID + char *scope_ptr = strchr(myhost, '%'); + if(scope_ptr) + *(scope_ptr++) = 0; +#endif + if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) { + si6->sin6_family = AF_INET6; + si6->sin6_port = htons(port); +#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID + if(scope_ptr) + /* The "myhost" string either comes from Curl_if2ip or from + Curl_printable_address. The latter returns only numeric scope + IDs and the former returns none at all. So the scope ID, if + present, is known to be numeric */ + si6->sin6_scope_id = atoi(scope_ptr); +#endif + } sizeof_sa = sizeof(struct sockaddr_in6); } else #endif - /* ipv4 address */ + /* IPv4 address */ if((af == AF_INET) && (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) { si4->sin_family = AF_INET; @@ -370,14 +414,14 @@ static CURLcode bindlocal(struct connectdata *conn, else { /* no device was given, prepare sa to match af's needs */ #ifdef ENABLE_IPV6 - if ( af == AF_INET6 ) { + if(af == AF_INET6) { si6->sin6_family = AF_INET6; si6->sin6_port = htons(port); sizeof_sa = sizeof(struct sockaddr_in6); } else #endif - if ( af == AF_INET ) { + if(af == AF_INET) { si4->sin_family = AF_INET; si4->sin_port = htons(port); sizeof_sa = sizeof(struct sockaddr_in); @@ -385,8 +429,8 @@ static CURLcode bindlocal(struct connectdata *conn, } for(;;) { - if( bind(sockfd, sock, sizeof_sa) >= 0) { - /* we succeeded to bind */ + if(bind(sockfd, sock, sizeof_sa) >= 0) { + /* we succeeded to bind */ struct Curl_sockaddr_storage add; curl_socklen_t size = sizeof(add); memset(&add, 0, sizeof(struct Curl_sockaddr_storage)); @@ -494,42 +538,60 @@ static bool verifyconnect(curl_socket_t sockfd, int *error) more address exists or error */ static CURLcode trynextip(struct connectdata *conn, int sockindex, - bool *connected) + int tempindex) { - curl_socket_t sockfd; - Curl_addrinfo *ai; + const int other = tempindex ^ 1; + CURLcode result = CURLE_COULDNT_CONNECT; /* First clean up after the failed socket. Don't close it yet to ensure that the next IP's socket gets a different file descriptor, which can prevent bugs when the curl_multi_socket_action interface is used with certain select() replacements such as kqueue. */ - curl_socket_t fd_to_close = conn->sock[sockindex]; - conn->sock[sockindex] = CURL_SOCKET_BAD; - *connected = FALSE; + curl_socket_t fd_to_close = conn->tempsock[tempindex]; + conn->tempsock[tempindex] = CURL_SOCKET_BAD; - if(sockindex != FIRSTSOCKET) { - sclose(fd_to_close); - return CURLE_COULDNT_CONNECT; /* no next */ - } + if(sockindex == FIRSTSOCKET) { + Curl_addrinfo *ai = NULL; + int family = AF_UNSPEC; - /* try the next address */ - ai = conn->ip_addr->ai_next; - - while(ai) { - CURLcode res = singleipconnect(conn, ai, 0L, &sockfd, connected); - if(res) - return res; - if(sockfd != CURL_SOCKET_BAD) { - /* store the new socket descriptor */ - conn->sock[sockindex] = sockfd; - conn->ip_addr = ai; - sclose(fd_to_close); - return CURLE_OK; + if(conn->tempaddr[tempindex]) { + /* find next address in the same protocol family */ + family = conn->tempaddr[tempindex]->ai_family; + ai = conn->tempaddr[tempindex]->ai_next; + } +#ifdef ENABLE_IPV6 + else if(conn->tempaddr[0]) { + /* happy eyeballs - try the other protocol family */ + int firstfamily = conn->tempaddr[0]->ai_family; + family = (firstfamily == AF_INET) ? AF_INET6 : AF_INET; + ai = conn->tempaddr[0]->ai_next; + } +#endif + + while(ai) { + if(conn->tempaddr[other]) { + /* we can safely skip addresses of the other protocol family */ + while(ai && ai->ai_family != family) + ai = ai->ai_next; + } + + if(ai) { + result = singleipconnect(conn, ai, &conn->tempsock[tempindex]); + if(result == CURLE_COULDNT_CONNECT) { + ai = ai->ai_next; + continue; + } + + conn->tempaddr[tempindex] = ai; + } + break; } - ai = ai->ai_next; } - sclose(fd_to_close); - return CURLE_COULDNT_CONNECT; + + if(fd_to_close != CURL_SOCKET_BAD) + Curl_closesocket(conn, fd_to_close); + + return result; } /* Copies connection info into the session handle to make it available @@ -557,7 +619,7 @@ static bool getaddressinfo(struct sockaddr* sa, char* addr, switch (sa->sa_family) { case AF_INET: - si = (struct sockaddr_in*) sa; + si = (struct sockaddr_in*)(void*) sa; if(Curl_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) { us_port = ntohs(si->sin_port); @@ -567,7 +629,7 @@ static bool getaddressinfo(struct sockaddr* sa, char* addr, break; #ifdef ENABLE_IPV6 case AF_INET6: - si6 = (struct sockaddr_in6*)sa; + si6 = (struct sockaddr_in6*)(void*) sa; if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr, addr, MAX_IPADR_LEN)) { us_port = ntohs(si6->sin6_port); @@ -597,13 +659,17 @@ static bool getaddressinfo(struct sockaddr* sa, char* addr, connection */ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) { - int error; curl_socklen_t len; struct Curl_sockaddr_storage ssrem; struct Curl_sockaddr_storage ssloc; struct SessionHandle *data = conn->data; + if(conn->socktype == SOCK_DGRAM) + /* there's no connection! */ + return; + if(!conn->bits.reuse) { + int error; len = sizeof(struct Curl_sockaddr_storage); if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) { @@ -614,6 +680,7 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) } len = sizeof(struct Curl_sockaddr_storage); + memset(&ssloc, 0, sizeof(ssloc)); if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) { error = SOCKERRNO; failf(data, "getsockname() failed with errno %d: %s", @@ -628,6 +695,7 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) error, Curl_strerror(conn, error)); return; } + memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN); if(!getaddressinfo((struct sockaddr*)&ssloc, conn->local_ip, &conn->local_port)) { @@ -644,33 +712,35 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) } /* - * Curl_is_connected() is used from the multi interface to check if the - * firstsocket has connected. + * Curl_is_connected() checks if the socket has connected. */ CURLcode Curl_is_connected(struct connectdata *conn, int sockindex, bool *connected) { - int rc; struct SessionHandle *data = conn->data; - CURLcode code = CURLE_OK; - curl_socket_t sockfd = conn->sock[sockindex]; - long allow = DEFAULT_CONNECT_TIMEOUT; + CURLcode result = CURLE_OK; + long allow; int error = 0; + struct timeval now; + int rc; + int i; DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET); *connected = FALSE; /* a very negative world view is best */ - if(conn->bits.tcpconnect) { + if(conn->bits.tcpconnect[sockindex]) { /* we are connected already! */ *connected = TRUE; return CURLE_OK; } + now = Curl_tvnow(); + /* figure out how long time we have left to connect */ - allow = Curl_timeleft(conn, NULL, TRUE); + allow = Curl_timeleft(data, &now, TRUE); if(allow < 0) { /* time-out, bail out, go home */ @@ -678,63 +748,123 @@ CURLcode Curl_is_connected(struct connectdata *conn, return CURLE_OPERATION_TIMEDOUT; } - /* check for connect without timeout as we want to return immediately */ - rc = waitconnect(conn, sockfd, 0); - if(WAITCONN_TIMEOUT == rc) - /* not an error, but also no connection yet */ - return code; + for(i=0; i<2; i++) { + const int other = i ^ 1; + if(conn->tempsock[i] == CURL_SOCKET_BAD) + continue; - if(WAITCONN_CONNECTED == rc) { - if(verifyconnect(sockfd, &error)) { - /* we are connected, awesome! */ - conn->bits.tcpconnect = TRUE; - *connected = TRUE; - Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ - Curl_verboseconnect(conn); - Curl_updateconninfo(conn, sockfd); +#ifdef mpeix + /* Call this function once now, and ignore the results. We do this to + "clear" the error state on the socket so that we can later read it + reliably. This is reported necessary on the MPE/iX operating system. */ + (void)verifyconnect(conn->tempsock[i], NULL); +#endif - return CURLE_OK; + /* check socket for connect */ + rc = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0); + + if(rc == 0) { /* no connection yet */ + if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) { + infof(data, "After %ldms connect time, move on!\n", + conn->timeoutms_per_addr); + error = ETIMEDOUT; + } + + /* should we try another protocol family? */ + if(i == 0 && conn->tempaddr[1] == NULL && + curlx_tvdiff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) { + trynextip(conn, sockindex, 1); + } } - /* nope, not connected for real */ - } - else { - /* nope, not connected */ - if(WAITCONN_FDSET_ERROR == rc) { - (void)verifyconnect(sockfd, &error); - infof(data, "%s\n",Curl_strerror(conn, error)); + else if(rc == CURL_CSELECT_OUT) { + if(verifyconnect(conn->tempsock[i], &error)) { + /* we are connected with TCP, awesome! */ + + /* use this socket from now on */ + conn->sock[sockindex] = conn->tempsock[i]; + conn->ip_addr = conn->tempaddr[i]; + conn->tempsock[i] = CURL_SOCKET_BAD; + + /* close the other socket, if open */ + if(conn->tempsock[other] != CURL_SOCKET_BAD) { + Curl_closesocket(conn, conn->tempsock[other]); + conn->tempsock[other] = CURL_SOCKET_BAD; + } + + /* see if we need to do any proxy magic first once we connected */ + result = Curl_connected_proxy(conn, sockindex); + if(result) + return result; + + conn->bits.tcpconnect[sockindex] = TRUE; + + *connected = TRUE; + if(sockindex == FIRSTSOCKET) + Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ + Curl_updateconninfo(conn, conn->sock[sockindex]); + Curl_verboseconnect(conn); + + return CURLE_OK; + } + else + infof(data, "Connection failed\n"); + } + else if(rc & CURL_CSELECT_ERR) + (void)verifyconnect(conn->tempsock[i], &error); + + /* + * The connection failed here, we should attempt to connect to the "next + * address" for the given host. But first remember the latest error. + */ + if(error) { + data->state.os_errno = error; + SET_SOCKERRNO(error); + if(conn->tempaddr[i]) { + CURLcode status; + char ipaddress[MAX_IPADR_LEN]; + Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN); + infof(data, "connect to %s port %ld failed: %s\n", + ipaddress, conn->port, Curl_strerror(conn, error)); + + conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ? + allow : allow / 2; + + status = trynextip(conn, sockindex, i); + if(status != CURLE_COULDNT_CONNECT + || conn->tempsock[other] == CURL_SOCKET_BAD) + /* the last attempt failed and no other sockets remain open */ + result = status; + } } - else - infof(data, "Connection failed\n"); } - /* - * The connection failed here, we should attempt to connect to the "next - * address" for the given host. But first remember the latest error. - */ - if(error) { - data->state.os_errno = error; - SET_SOCKERRNO(error); + if(result) { + /* no more addresses to try */ + + /* if the first address family runs out of addresses to try before + the happy eyeball timeout, go ahead and try the next family now */ + if(conn->tempaddr[1] == NULL) { + result = trynextip(conn, sockindex, 1); + if(!result) + return result; + } + + failf(data, "Failed to connect to %s port %ld: %s", + conn->bits.proxy?conn->proxy.name:conn->host.name, + conn->port, Curl_strerror(conn, error)); } - code = trynextip(conn, sockindex, connected); - - if(code) { - error = SOCKERRNO; - data->state.os_errno = error; - failf(data, "Failed connect to %s:%ld; %s", - conn->host.name, conn->port, Curl_strerror(conn, error)); - } - - return code; + return result; } -static void tcpnodelay(struct connectdata *conn, - curl_socket_t sockfd) +void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd) { -#ifdef TCP_NODELAY - struct SessionHandle *data= conn->data; - curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay; - int proto = IPPROTO_TCP; +#if defined(TCP_NODELAY) +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) + struct SessionHandle *data = conn->data; +#endif + curl_socklen_t onoff = (curl_socklen_t) 1; + int level = IPPROTO_TCP; #if 0 /* The use of getprotobyname() is disabled since it isn't thread-safe on @@ -746,15 +876,19 @@ static void tcpnodelay(struct connectdata *conn, detected. */ struct protoent *pe = getprotobyname("tcp"); if(pe) - proto = pe->p_proto; + level = pe->p_proto; #endif - if(setsockopt(sockfd, proto, TCP_NODELAY, (void *)&onoff, +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) conn; +#endif + + if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff, sizeof(onoff)) < 0) infof(data, "Could not set TCP_NODELAY: %s\n", Curl_strerror(conn, SOCKERRNO)); else - infof(data,"TCP_NODELAY set\n"); + infof(data, "TCP_NODELAY set\n"); #else (void)conn; (void)sockfd; @@ -777,34 +911,81 @@ static void nosigpipe(struct connectdata *conn, Curl_strerror(conn, SOCKERRNO)); } #else -#define nosigpipe(x,y) +#define nosigpipe(x,y) Curl_nop_stmt #endif -#ifdef WIN32 +#ifdef USE_WINSOCK /* When you run a program that uses the Windows Sockets API, you may experience slow performance when you copy data to a TCP server. - http://support.microsoft.com/kb/823764 + https://support.microsoft.com/kb/823764 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send Buffer Size + The problem described in this knowledge-base is applied only to pre-Vista + Windows. Following function trying to detect OS version and skips + SO_SNDBUF adjustment for Windows Vista and above. */ +#define DETECT_OS_NONE 0 +#define DETECT_OS_PREVISTA 1 +#define DETECT_OS_VISTA_OR_LATER 2 + void Curl_sndbufset(curl_socket_t sockfd) { int val = CURL_MAX_WRITE_SIZE + 32; int curval = 0; int curlen = sizeof(curval); + DWORD majorVersion = 6; - if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0) - if (curval > val) + static int detectOsState = DETECT_OS_NONE; + + if(detectOsState == DETECT_OS_NONE) { +#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ + (_WIN32_WINNT < _WIN32_WINNT_WIN2K) + OSVERSIONINFO osver; + + memset(&osver, 0, sizeof(osver)); + osver.dwOSVersionInfoSize = sizeof(osver); + + detectOsState = DETECT_OS_PREVISTA; + if(GetVersionEx(&osver)) { + if(osver.dwMajorVersion >= majorVersion) + detectOsState = DETECT_OS_VISTA_OR_LATER; + } +#else + ULONGLONG cm; + OSVERSIONINFOEX osver; + + memset(&osver, 0, sizeof(osver)); + osver.dwOSVersionInfoSize = sizeof(osver); + osver.dwMajorVersion = majorVersion; + + cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); + + if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), + cm)) + detectOsState = DETECT_OS_VISTA_OR_LATER; + else + detectOsState = DETECT_OS_PREVISTA; +#endif + } + + if(detectOsState == DETECT_OS_VISTA_OR_LATER) + return; + + if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0) + if(curval > val) return; setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val)); } #endif - /* * singleipconnect() * @@ -812,131 +993,117 @@ void Curl_sndbufset(curl_socket_t sockfd) * CURL_SOCKET_BAD. Other errors will however return proper errors. * * singleipconnect() connects to the given IP only, and it may return without - * having connected if used from the multi interface. + * having connected. */ -static CURLcode -singleipconnect(struct connectdata *conn, - const Curl_addrinfo *ai, - long timeout_ms, - curl_socket_t *sockp, - bool *connected) +static CURLcode singleipconnect(struct connectdata *conn, + const Curl_addrinfo *ai, + curl_socket_t *sockp) { struct Curl_sockaddr_ex addr; int rc; - int error; - bool isconnected; + int error = 0; + bool isconnected = FALSE; struct SessionHandle *data = conn->data; curl_socket_t sockfd; - CURLcode res = CURLE_OK; -#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) - struct sockaddr_in6 * const sa6 = (void *)&addr.sa_addr; -#endif + CURLcode result; + char ipaddress[MAX_IPADR_LEN]; + long port; + bool is_tcp; *sockp = CURL_SOCKET_BAD; - /* - * The Curl_sockaddr_ex structure is basically libcurl's external API - * curl_sockaddr structure with enough space available to directly hold - * any protocol-specific address structures. The variable declared here - * will be used to pass / receive data to/from the fopensocket callback - * if this has been set, before that, it is initialized from parameters. - */ - - addr.family = ai->ai_family; - addr.socktype = conn->socktype; - addr.protocol = ai->ai_protocol; - addr.addrlen = ai->ai_addrlen; - - if(addr.addrlen > sizeof(struct Curl_sockaddr_storage)) - addr.addrlen = sizeof(struct Curl_sockaddr_storage); - memcpy(&addr.sa_addr, ai->ai_addr, addr.addrlen); - - *connected = FALSE; /* default is not connected */ - - if(data->set.fopensocket) - /* - * If the opensocket callback is set, all the destination address - * information is passed to the callback. Depending on this information the - * callback may opt to abort the connection, this is indicated returning - * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When - * the callback returns a valid socket the destination address information - * might have been changed and this 'new' address will actually be used - * here to connect. - */ - sockfd = data->set.fopensocket(data->set.opensocket_client, - CURLSOCKTYPE_IPCXN, - (struct curl_sockaddr *)&addr); - else - /* opensocket callback not set, so simply create the socket now */ - sockfd = socket(addr.family, addr.socktype, addr.protocol); - - if(sockfd == CURL_SOCKET_BAD) - /* no socket, no connection */ + result = Curl_socket(conn, ai, &addr, &sockfd); + if(result) + /* Failed to create the socket, but still return OK since we signal the + lack of socket as well. This allows the parent function to keep looping + over alternative addresses/socket families etc. */ return CURLE_OK; -#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) - if (conn->scope && (addr.family == AF_INET6)) - sa6->sin6_scope_id = conn->scope; -#endif - /* store remote address and port used in this connection attempt */ if(!getaddressinfo((struct sockaddr*)&addr.sa_addr, - conn->primary_ip, &conn->primary_port)) { + ipaddress, &port)) { /* malformed address or bug in inet_ntop, try next address */ error = ERRNO; failf(data, "sa_addr inet_ntop() failed with errno %d: %s", error, Curl_strerror(conn, error)); - sclose(sockfd); + Curl_closesocket(conn, sockfd); return CURLE_OK; } - memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN); - infof(data, " Trying %s... ", conn->ip_addr_str); - - Curl_persistconninfo(conn); + infof(data, " Trying %s...\n", ipaddress); #ifdef ENABLE_IPV6 - if(addr.family == AF_INET6) - conn->bits.ipv6 = TRUE; + is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) && + addr.socktype == SOCK_STREAM; +#else + is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM; #endif - - if(data->set.tcp_nodelay) - tcpnodelay(conn, sockfd); + if(is_tcp && data->set.tcp_nodelay) + Curl_tcpnodelay(conn, sockfd); nosigpipe(conn, sockfd); Curl_sndbufset(sockfd); + if(is_tcp && data->set.tcp_keepalive) + tcpkeepalive(data, sockfd); + if(data->set.fsockopt) { /* activate callback for setting socket options */ error = data->set.fsockopt(data->set.sockopt_client, sockfd, CURLSOCKTYPE_IPCXN); - if(error) { - sclose(sockfd); /* close the socket and bail out */ - return res; + + if(error == CURL_SOCKOPT_ALREADY_CONNECTED) + isconnected = TRUE; + else if(error) { + Curl_closesocket(conn, sockfd); /* close the socket and bail out */ + return CURLE_ABORTED_BY_CALLBACK; } } /* possibly bind the local end to an IP, interface or port */ - res = bindlocal(conn, sockfd, addr.family); - if(res) { - sclose(sockfd); /* close socket and bail out */ - return res; + if(addr.family == AF_INET +#ifdef ENABLE_IPV6 + || addr.family == AF_INET6 +#endif + ) { + result = bindlocal(conn, sockfd, addr.family, + Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr)); + if(result) { + Curl_closesocket(conn, sockfd); /* close socket and bail out */ + if(result == CURLE_UNSUPPORTED_PROTOCOL) { + /* The address family is not supported on this interface. + We can continue trying addresses */ + return CURLE_COULDNT_CONNECT; + } + return result; + } } /* set socket non-blocking */ - curlx_nonblock(sockfd, TRUE); + (void)curlx_nonblock(sockfd, TRUE); + + conn->connecttime = Curl_tvnow(); + if(conn->num_addr > 1) + Curl_expire_latest(data, conn->timeoutms_per_addr); /* Connect TCP sockets, bind UDP */ - if(conn->socktype == SOCK_STREAM) + if(!isconnected && (conn->socktype == SOCK_STREAM)) { rc = connect(sockfd, &addr.sa_addr, addr.addrlen); - else - rc = 0; + if(-1 == rc) + error = SOCKERRNO; + } + else { + *sockp = sockfd; + return CURLE_OK; + } + +#ifdef ENABLE_IPV6 + conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE; +#endif if(-1 == rc) { - error = SOCKERRNO; - - switch (error) { + switch(error) { case EINPROGRESS: case EWOULDBLOCK: #if defined(EAGAIN) @@ -948,51 +1115,25 @@ singleipconnect(struct connectdata *conn, case EAGAIN: #endif #endif - rc = waitconnect(conn, sockfd, timeout_ms); - if(WAITCONN_ABORTED == rc) { - sclose(sockfd); - return CURLE_ABORTED_BY_CALLBACK; - } + result = CURLE_OK; break; + default: /* unknown error, fallthrough and try another address! */ - failf(data, "Failed to connect to %s: %s", - conn->ip_addr_str, Curl_strerror(conn,error)); + infof(data, "Immediate connect fail for %s: %s\n", + ipaddress, Curl_strerror(conn, error)); data->state.os_errno = error; - break; + + /* connect failed */ + Curl_closesocket(conn, sockfd); + result = CURLE_COULDNT_CONNECT; } } - /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from - connect(). We can be sure of this since connect() cannot return 1. */ - if((WAITCONN_TIMEOUT == rc) && - (data->state.used_interface == Curl_if_multi)) { - /* Timeout when running the multi interface */ + if(!result) *sockp = sockfd; - return CURLE_OK; - } - isconnected = verifyconnect(sockfd, &error); - - if(!rc && isconnected) { - /* we are connected, awesome! */ - *connected = TRUE; /* this is a true connect */ - infof(data, "connected\n"); - Curl_updateconninfo(conn, sockfd); - *sockp = sockfd; - return CURLE_OK; - } - else if(WAITCONN_TIMEOUT == rc) - infof(data, "Timeout\n"); - else { - data->state.os_errno = error; - infof(data, "%s\n", Curl_strerror(conn, error)); - } - - /* connect failed or timed out */ - sclose(sockfd); - - return CURLE_OK; + return result; } /* @@ -1002,32 +1143,13 @@ singleipconnect(struct connectdata *conn, */ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ - const struct Curl_dns_entry *remotehost, - curl_socket_t *sockconn, /* the connected socket */ - Curl_addrinfo **addr, /* the one we used */ - bool *connected) /* really connected? */ + const struct Curl_dns_entry *remotehost) { struct SessionHandle *data = conn->data; - curl_socket_t sockfd = CURL_SOCKET_BAD; - int aliasindex; - int num_addr; - Curl_addrinfo *ai; - Curl_addrinfo *curr_addr; - - struct timeval after; struct timeval before = Curl_tvnow(); + CURLcode result = CURLE_COULDNT_CONNECT; - /************************************************************* - * Figure out what maximum time we have left - *************************************************************/ - long timeout_ms; - long timeout_per_addr; - - DEBUGASSERT(sockconn); - *connected = FALSE; /* default to not connected */ - - /* get the timeout left */ - timeout_ms = Curl_timeleft(conn, &before, TRUE); + long timeout_ms = Curl_timeleft(data, &before, TRUE); if(timeout_ms < 0) { /* a precaution, no need to continue if time already is up */ @@ -1035,65 +1157,51 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ return CURLE_OPERATION_TIMEDOUT; } - /* Max time for each address */ - num_addr = Curl_num_addresses(remotehost->addr); - timeout_per_addr = timeout_ms / num_addr; + conn->num_addr = Curl_num_addresses(remotehost->addr); + conn->tempaddr[0] = remotehost->addr; + conn->tempaddr[1] = NULL; + conn->tempsock[0] = CURL_SOCKET_BAD; + conn->tempsock[1] = CURL_SOCKET_BAD; + Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT); - ai = remotehost->addr; + /* Max time for the next connection attempt */ + conn->timeoutms_per_addr = + conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2; - /* Below is the loop that attempts to connect to all IP-addresses we - * know for the given host. One by one until one IP succeeds. - */ - - if(data->state.used_interface == Curl_if_multi) - /* don't hang when doing multi */ - timeout_per_addr = 0; - - /* - * Connecting with a Curl_addrinfo chain - */ - for (curr_addr = ai, aliasindex=0; curr_addr; - curr_addr = curr_addr->ai_next, aliasindex++) { - - /* start connecting to the IP curr_addr points to */ - CURLcode res = - singleipconnect(conn, curr_addr, timeout_per_addr, &sockfd, connected); - - if(res) - return res; - - if(sockfd != CURL_SOCKET_BAD) + /* start connecting to first IP */ + while(conn->tempaddr[0]) { + result = singleipconnect(conn, conn->tempaddr[0], &(conn->tempsock[0])); + if(!result) break; - - /* get a new timeout for next attempt */ - after = Curl_tvnow(); - timeout_ms -= Curl_tvdiff(after, before); - if(timeout_ms < 0) { - failf(data, "connect() timed out!"); - return CURLE_OPERATION_TIMEDOUT; - } - before = after; - } /* end of connect-to-each-address loop */ - - *sockconn = sockfd; /* the socket descriptor we've connected */ - - if(sockfd == CURL_SOCKET_BAD) { - /* no good connect was made */ - failf(data, "couldn't connect to host"); - return CURLE_COULDNT_CONNECT; + conn->tempaddr[0] = conn->tempaddr[0]->ai_next; } - /* leave the socket in non-blocking mode */ - - /* store the address we use */ - if(addr) - *addr = curr_addr; + if(conn->tempsock[0] == CURL_SOCKET_BAD) { + if(!result) + result = CURLE_COULDNT_CONNECT; + return result; + } data->info.numconnects++; /* to track the number of connections made */ return CURLE_OK; } +struct connfind { + struct connectdata *tofind; + bool found; +}; + +static int conn_is_conn(struct connectdata *conn, void *param) +{ + struct connfind *f = (struct connfind *)param; + if(conn == f->tofind) { + f->found = TRUE; + return 1; + } + return 0; +} + /* * Used to extract socket and connectdata struct for the most recent * transfer on the given SessionHandle. @@ -1104,10 +1212,29 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, struct connectdata **connp) { curl_socket_t sockfd; - if((data->state.lastconnect != -1) && - (data->state.connc->connects[data->state.lastconnect] != NULL)) { - struct connectdata *c = - data->state.connc->connects[data->state.lastconnect]; + + DEBUGASSERT(data); + + /* this works for an easy handle: + * - that has been used for curl_easy_perform() + * - that is associated with a multi handle, and whose connection + * was detached with CURLOPT_CONNECT_ONLY + */ + if(data->state.lastconnect && (data->multi_easy || data->multi)) { + struct connectdata *c = data->state.lastconnect; + struct connfind find; + find.tofind = data->state.lastconnect; + find.found = FALSE; + + Curl_conncache_foreach(data->multi_easy? + &data->multi_easy->conn_cache: + &data->multi->conn_cache, &find, conn_is_conn); + + if(!find.found) { + data->state.lastconnect = NULL; + return CURL_SOCKET_BAD; + } + if(connp) /* only store this if the caller cares for it */ *connp = c; @@ -1121,10 +1248,10 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, } /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */ #ifdef MSG_PEEK - else { + else if(sockfd != CURL_SOCKET_BAD) { /* use the socket */ char buf; - if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf, + if(recv((RECV_TYPE_ARG1)sockfd, (RECV_TYPE_ARG2)&buf, (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) { return CURL_SOCKET_BAD; /* FIN received */ } @@ -1136,3 +1263,126 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, return sockfd; } + +/* + * Close a socket. + * + * 'conn' can be NULL, beware! + */ +int Curl_closesocket(struct connectdata *conn, + curl_socket_t sock) +{ + if(conn && conn->fclosesocket) { + if((sock == conn->sock[SECONDARYSOCKET]) && + conn->sock_accepted[SECONDARYSOCKET]) + /* if this socket matches the second socket, and that was created with + accept, then we MUST NOT call the callback but clear the accepted + status */ + conn->sock_accepted[SECONDARYSOCKET] = FALSE; + else { + Curl_multi_closed(conn, sock); + return conn->fclosesocket(conn->closesocket_client, sock); + } + } + + if(conn) + /* tell the multi-socket code about this */ + Curl_multi_closed(conn, sock); + + sclose(sock); + + return 0; +} + +/* + * Create a socket based on info from 'conn' and 'ai'. + * + * 'addr' should be a pointer to the correct struct to get data back, or NULL. + * 'sockfd' must be a pointer to a socket descriptor. + * + * If the open socket callback is set, used that! + * + */ +CURLcode Curl_socket(struct connectdata *conn, + const Curl_addrinfo *ai, + struct Curl_sockaddr_ex *addr, + curl_socket_t *sockfd) +{ + struct SessionHandle *data = conn->data; + struct Curl_sockaddr_ex dummy; + + if(!addr) + /* if the caller doesn't want info back, use a local temp copy */ + addr = &dummy; + + /* + * The Curl_sockaddr_ex structure is basically libcurl's external API + * curl_sockaddr structure with enough space available to directly hold + * any protocol-specific address structures. The variable declared here + * will be used to pass / receive data to/from the fopensocket callback + * if this has been set, before that, it is initialized from parameters. + */ + + addr->family = ai->ai_family; + addr->socktype = conn->socktype; + addr->protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol; + addr->addrlen = ai->ai_addrlen; + + if(addr->addrlen > sizeof(struct Curl_sockaddr_storage)) + addr->addrlen = sizeof(struct Curl_sockaddr_storage); + memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen); + + if(data->set.fopensocket) + /* + * If the opensocket callback is set, all the destination address + * information is passed to the callback. Depending on this information the + * callback may opt to abort the connection, this is indicated returning + * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When + * the callback returns a valid socket the destination address information + * might have been changed and this 'new' address will actually be used + * here to connect. + */ + *sockfd = data->set.fopensocket(data->set.opensocket_client, + CURLSOCKTYPE_IPCXN, + (struct curl_sockaddr *)addr); + else + /* opensocket callback not set, so simply create the socket now */ + *sockfd = socket(addr->family, addr->socktype, addr->protocol); + + if(*sockfd == CURL_SOCKET_BAD) + /* no socket, no connection */ + return CURLE_COULDNT_CONNECT; + +#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) + if(conn->scope_id && (addr->family == AF_INET6)) { + struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr; + sa6->sin6_scope_id = conn->scope_id; + } +#endif + + return CURLE_OK; + +} + +#ifdef CURLDEBUG +/* + * Curl_conncontrol() is used to set the conn->bits.close bit on or off. It + * MUST be called with the connclose() or connkeep() macros with a stated + * reason. The reason is only shown in debug builds but helps to figure out + * decision paths when connections are or aren't re-used as expected. + */ +void Curl_conncontrol(struct connectdata *conn, bool closeit, + const char *reason) +{ +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) reason; +#endif + if(closeit != conn->bits.close) { + infof(conn->data, "Marked for [%s]: %s\n", closeit?"closure":"keep alive", + reason); + + conn->bits.close = closeit; /* the only place in the source code that + should assign this bit */ + } +} +#endif diff --git a/project/jni/curl/lib/connect.h b/project/jni/curl/lib/connect.h index 6cc403d9f..f3d4ac747 100644 --- a/project/jni/curl/lib/connect.h +++ b/project/jni/curl/lib/connect.h @@ -1,5 +1,5 @@ -#ifndef __CONNECT_H -#define __CONNECT_H +#ifndef HEADER_CURL_CONNECT_H +#define HEADER_CURL_CONNECT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,27 +21,27 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "curl_setup.h" #include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */ +#include "sockaddr.h" CURLcode Curl_is_connected(struct connectdata *conn, int sockindex, bool *connected); CURLcode Curl_connecthost(struct connectdata *conn, - const struct Curl_dns_entry *host, /* connect to - this */ - curl_socket_t *sockconn, /* not set if error */ - Curl_addrinfo **addr, /* the one we used */ - bool *connected); /* truly connected? */ + const struct Curl_dns_entry *host); /* generic function that returns how much time there's left to run, according to the timeouts set */ -long Curl_timeleft(struct connectdata *conn, +long Curl_timeleft(struct SessionHandle *data, struct timeval *nowp, bool duringconnect); #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */ +#define HAPPY_EYEBALLS_TIMEOUT 200 /* milliseconds to wait between + IPv4/IPv6 connection attempts */ /* * Used to extract socket and connectdata struct for the most recent @@ -52,11 +52,11 @@ long Curl_timeleft(struct connectdata *conn, curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, struct connectdata **connp); -#ifdef WIN32 +#ifdef USE_WINSOCK /* When you run a program that uses the Windows Sockets API, you may experience slow performance when you copy data to a TCP server. - http://support.microsoft.com/kb/823764 + https://support.microsoft.com/kb/823764 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send Buffer Size @@ -64,11 +64,61 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, */ void Curl_sndbufset(curl_socket_t sockfd); #else -#define Curl_sndbufset(y) +#define Curl_sndbufset(y) Curl_nop_stmt #endif void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd); - void Curl_persistconninfo(struct connectdata *conn); +int Curl_closesocket(struct connectdata *conn, curl_socket_t sock); + +/* + * The Curl_sockaddr_ex structure is basically libcurl's external API + * curl_sockaddr structure with enough space available to directly hold any + * protocol-specific address structures. The variable declared here will be + * used to pass / receive data to/from the fopensocket callback if this has + * been set, before that, it is initialized from parameters. + */ +struct Curl_sockaddr_ex { + int family; + int socktype; + int protocol; + unsigned int addrlen; + union { + struct sockaddr addr; + struct Curl_sockaddr_storage buff; + } _sa_ex_u; +}; +#define sa_addr _sa_ex_u.addr + +/* + * Create a socket based on info from 'conn' and 'ai'. + * + * Fill in 'addr' and 'sockfd' accordingly if OK is returned. If the open + * socket callback is set, used that! + * + */ +CURLcode Curl_socket(struct connectdata *conn, + const Curl_addrinfo *ai, + struct Curl_sockaddr_ex *addr, + curl_socket_t *sockfd); + +void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd); + +#ifdef CURLDEBUG +/* + * Curl_connclose() sets the bit.close bit to TRUE with an explanation. + * Nothing else. + */ +void Curl_conncontrol(struct connectdata *conn, + bool closeit, + const char *reason); +#define connclose(x,y) Curl_conncontrol(x,TRUE, y) +#define connkeep(x,y) Curl_conncontrol(x, FALSE, y) +#else /* if !CURLDEBUG */ + +#define connclose(x,y) (x)->bits.close = TRUE +#define connkeep(x,y) (x)->bits.close = FALSE #endif + +#endif /* HEADER_CURL_CONNECT_H */ diff --git a/project/jni/curl/lib/content_encoding.c b/project/jni/curl/lib/content_encoding.c index 6fb7c8d3a..2d30816c1 100644 --- a/project/jni/curl/lib/content_encoding.c +++ b/project/jni/curl/lib/content_encoding.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,13 +20,10 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifdef HAVE_LIBZ -#include -#include - #include "urldata.h" #include #include "sendf.h" @@ -52,6 +49,21 @@ #define COMMENT 0x10 /* bit 4 set: file comment present */ #define RESERVED 0xE0 /* bits 5..7: reserved */ +static voidpf +zalloc_cb(voidpf opaque, unsigned int items, unsigned int size) +{ + (void) opaque; + /* not a typo, keep it calloc() */ + return (voidpf) calloc(items, size); +} + +static void +zfree_cb(voidpf opaque, voidpf ptr) +{ + (void) opaque; + free(ptr); +} + static CURLcode process_zlib_error(struct connectdata *conn, z_stream *z) { @@ -95,7 +107,7 @@ inflate_stream(struct connectdata *conn, /* because the buffer size is fixed, iteratively decompress and transfer to the client via client_write. */ - for (;;) { + for(;;) { /* (re)set buffer for decompressed output for every iteration */ z->next_out = (Bytef *)decomp; z->avail_out = DSIZ; @@ -161,11 +173,10 @@ Curl_unencode_deflate_write(struct connectdata *conn, /* Initialize zlib? */ if(k->zlib_init == ZLIB_UNINIT) { - z->zalloc = (alloc_func)Z_NULL; - z->zfree = (free_func)Z_NULL; - z->opaque = 0; - z->next_in = NULL; - z->avail_in = 0; + memset(z, 0, sizeof(z_stream)); + z->zalloc = (alloc_func)zalloc_cb; + z->zfree = (free_func)zfree_cb; + if(inflateInit(z) != Z_OK) return process_zlib_error(conn, z); k->zlib_init = ZLIB_INIT; @@ -272,11 +283,9 @@ Curl_unencode_gzip_write(struct connectdata *conn, /* Initialize zlib? */ if(k->zlib_init == ZLIB_UNINIT) { - z->zalloc = (alloc_func)Z_NULL; - z->zfree = (free_func)Z_NULL; - z->opaque = 0; - z->next_in = NULL; - z->avail_in = 0; + memset(z, 0, sizeof(z_stream)); + z->zalloc = (alloc_func)zalloc_cb; + z->zfree = (free_func)zfree_cb; if(strcmp(zlibVersion(), "1.2.0.4") >= 0) { /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */ diff --git a/project/jni/curl/lib/content_encoding.h b/project/jni/curl/lib/content_encoding.h index 3aff9d3c0..3fadd2899 100644 --- a/project/jni/curl/lib/content_encoding.h +++ b/project/jni/curl/lib/content_encoding.h @@ -1,5 +1,5 @@ -#ifndef __CURL_CONTENT_ENCODING_H -#define __CURL_CONTENT_ENCODING_H +#ifndef HEADER_CURL_CONTENT_ENCODING_H +#define HEADER_CURL_CONTENT_ENCODING_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,7 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" /* * Comma-separated list all supported Content-Encodings ('identity' is implied) @@ -32,7 +32,7 @@ void Curl_unencode_cleanup(struct connectdata *conn); #else #define ALL_CONTENT_ENCODINGS "identity" -#define Curl_unencode_cleanup(x) +#define Curl_unencode_cleanup(x) Curl_nop_stmt #endif CURLcode Curl_unencode_deflate_write(struct connectdata *conn, @@ -45,4 +45,4 @@ Curl_unencode_gzip_write(struct connectdata *conn, ssize_t nread); -#endif +#endif /* HEADER_CURL_CONTENT_ENCODING_H */ diff --git a/project/jni/curl/lib/cookie.c b/project/jni/curl/lib/cookie.c index c6460a100..1f2239242 100644 --- a/project/jni/curl/lib/cookie.c +++ b/project/jni/curl/lib/cookie.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,14 +26,17 @@ RECEIVING COOKIE INFORMATION ============================ -struct CookieInfo *cookie_init(char *file); +struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, + const char *file, struct CookieInfo *inc, bool newsession); Inits a cookie struct to store data in a local file. This is always called before any cookies are set. -int cookies_set(struct CookieInfo *cookie, char *cookie_line); +struct Cookie *Curl_cookie_add(struct SessionHandle *data, + struct CookieInfo *c, bool httpheader, char *lineptr, + const char *domain, const char *path); - The 'cookie_line' parameter is a full "Set-cookie:" line as + The 'lineptr' parameter is a full "Set-cookie:" line as received from a server. The function need to replace previously stored lines that this new @@ -47,8 +50,8 @@ int cookies_set(struct CookieInfo *cookie, char *cookie_line); SENDING COOKIE INFORMATION ========================== -struct Cookies *cookie_getlist(struct CookieInfo *cookie, - char *host, char *path, bool secure); +struct Cookies *Curl_cookie_getlist(struct CookieInfo *cookie, + char *host, char *path, bool secure); For a given host and path, return a linked list of cookies that the client should send to the server if used now. The secure @@ -77,64 +80,185 @@ Example set of cookies: ****/ -#include "setup.h" +#include "curl_setup.h" #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) -#include -#include - -#define _MPRINTF_REPLACE /* without this on windows OS we get undefined reference to snprintf */ -#include +#ifdef USE_LIBPSL +# include +#endif +#include "curl_printf.h" #include "urldata.h" #include "cookie.h" #include "strequal.h" #include "strtok.h" #include "sendf.h" -#include "curl_memory.h" +#include "slist.h" #include "share.h" #include "strtoofft.h" #include "rawstr.h" #include "curl_memrchr.h" +#include "inet_pton.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" - static void freecookie(struct Cookie *co) { - if(co->expirestr) - free(co->expirestr); - if(co->domain) - free(co->domain); - if(co->path) - free(co->path); - if(co->name) - free(co->name); - if(co->value) - free(co->value); - if(co->maxage) - free(co->maxage); - if(co->version) - free(co->version); - + free(co->expirestr); + free(co->domain); + free(co->path); + free(co->spath); + free(co->name); + free(co->value); + free(co->maxage); + free(co->version); free(co); } -static bool tailmatch(const char *little, const char *bigone) +static bool tailmatch(const char *cooke_domain, const char *hostname) { - size_t littlelen = strlen(little); - size_t biglen = strlen(bigone); + size_t cookie_domain_len = strlen(cooke_domain); + size_t hostname_len = strlen(hostname); - if(littlelen > biglen) + if(hostname_len < cookie_domain_len) return FALSE; - return (bool)Curl_raw_equal(little, bigone+biglen-littlelen); + if(!Curl_raw_equal(cooke_domain, hostname+hostname_len-cookie_domain_len)) + return FALSE; + + /* A lead char of cookie_domain is not '.'. + RFC6265 4.1.2.3. The Domain Attribute says: + For example, if the value of the Domain attribute is + "example.com", the user agent will include the cookie in the Cookie + header when making HTTP requests to example.com, www.example.com, and + www.corp.example.com. + */ + if(hostname_len == cookie_domain_len) + return TRUE; + if('.' == *(hostname + hostname_len - cookie_domain_len - 1)) + return TRUE; + return FALSE; +} + +/* + * matching cookie path and url path + * RFC6265 5.1.4 Paths and Path-Match + */ +static bool pathmatch(const char* cookie_path, const char* request_uri) +{ + size_t cookie_path_len; + size_t uri_path_len; + char* uri_path = NULL; + char* pos; + bool ret = FALSE; + + /* cookie_path must not have last '/' separator. ex: /sample */ + cookie_path_len = strlen(cookie_path); + if(1 == cookie_path_len) { + /* cookie_path must be '/' */ + return TRUE; + } + + uri_path = strdup(request_uri); + if(!uri_path) + return FALSE; + pos = strchr(uri_path, '?'); + if(pos) + *pos = 0x0; + + /* #-fragments are already cut off! */ + if(0 == strlen(uri_path) || uri_path[0] != '/') { + free(uri_path); + uri_path = strdup("/"); + if(!uri_path) + return FALSE; + } + + /* here, RFC6265 5.1.4 says + 4. Output the characters of the uri-path from the first character up + to, but not including, the right-most %x2F ("/"). + but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site + without redirect. + Ignore this algorithm because /hoge is uri path for this case + (uri path is not /). + */ + + uri_path_len = strlen(uri_path); + + if(uri_path_len < cookie_path_len) { + ret = FALSE; + goto pathmatched; + } + + /* not using checkprefix() because matching should be case-sensitive */ + if(strncmp(cookie_path, uri_path, cookie_path_len)) { + ret = FALSE; + goto pathmatched; + } + + /* The cookie-path and the uri-path are identical. */ + if(cookie_path_len == uri_path_len) { + ret = TRUE; + goto pathmatched; + } + + /* here, cookie_path_len < url_path_len */ + if(uri_path[cookie_path_len] == '/') { + ret = TRUE; + goto pathmatched; + } + + ret = FALSE; + +pathmatched: + free(uri_path); + return ret; +} + +/* + * cookie path sanitize + */ +static char *sanitize_cookie_path(const char *cookie_path) +{ + size_t len; + char *new_path = strdup(cookie_path); + if(!new_path) + return NULL; + + /* some stupid site sends path attribute with '"'. */ + len = strlen(new_path); + if(new_path[0] == '\"') { + memmove((void *)new_path, (const void *)(new_path + 1), len); + len--; + } + if(len && (new_path[len - 1] == '\"')) { + new_path[len - 1] = 0x0; + len--; + } + + /* RFC6265 5.2.4 The Path Attribute */ + if(new_path[0] != '/') { + /* Let cookie-path be the default-path. */ + free(new_path); + new_path = strdup("/"); + return new_path; + } + + /* convert /hoge/ to /hoge */ + if(len && new_path[len - 1] == '/') { + new_path[len - 1] = 0x0; + } + + return new_path; } /* * Load cookies from all given cookie files (CURLOPT_COOKIEFILE). + * + * NOTE: OOM or cookie parsing failures are ignored. */ void Curl_cookie_loadfiles(struct SessionHandle *data) { @@ -142,15 +266,22 @@ void Curl_cookie_loadfiles(struct SessionHandle *data) if(list) { Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); while(list) { - data->cookies = Curl_cookie_init(data, - list->data, - data->cookies, - data->set.cookiesession); + struct CookieInfo *newcookies = Curl_cookie_init(data, + list->data, + data->cookies, + data->set.cookiesession); + if(!newcookies) + /* Failure may be due to OOM or a bad cookie; both are ignored + * but only the first should be + */ + infof(data, "ignoring failed cookie_init for %s\n", list->data); + else + data->cookies = newcookies; list = list->next; } - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); curl_slist_free_all(data->change.cookielist); /* clean up list */ data->change.cookielist = NULL; /* don't do this again! */ + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } } @@ -162,11 +293,60 @@ void Curl_cookie_loadfiles(struct SessionHandle *data) */ static void strstore(char **str, const char *newstr) { - if(*str) - free(*str); + free(*str); *str = strdup(newstr); } +/* + * remove_expired() removes expired cookies. + */ +static void remove_expired(struct CookieInfo *cookies) +{ + struct Cookie *co, *nx, *pv; + curl_off_t now = (curl_off_t)time(NULL); + + co = cookies->cookies; + pv = NULL; + while(co) { + nx = co->next; + if(co->expires && co->expires < now) { + if(co == cookies->cookies) { + cookies->cookies = co->next; + } + else { + pv->next = co->next; + } + cookies->numcookies--; + freecookie(co); + } + else { + pv = co; + } + co = nx; + } +} + +/* + * Return true if the given string is an IP(v4|v6) address. + */ +static bool isip(const char *domain) +{ + struct in_addr addr; +#ifdef ENABLE_IPV6 + struct in6_addr addr6; +#endif + + if(Curl_inet_pton(AF_INET, domain, &addr) +#ifdef ENABLE_IPV6 + || Curl_inet_pton(AF_INET6, domain, &addr6) +#endif + ) { + /* domain name given as IP address */ + return TRUE; + } + + return FALSE; +} /**************************************************************************** * @@ -174,6 +354,11 @@ static void strstore(char **str, const char *newstr) * * Add a single cookie line to the cookie keeping object. * + * Be aware that sometimes we get an IP-only host name, and that might also be + * a numerical IPv6 address. + * + * Returns NULL on out of memory or invalid cookie. This is suboptimal, + * as they should be treated separately. ***************************************************************************/ struct Cookie * @@ -198,6 +383,10 @@ Curl_cookie_add(struct SessionHandle *data, bool replace_old = FALSE; bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */ +#ifdef USE_LIBPSL + const psl_ctx_t *psl; +#endif + #ifdef CURL_DISABLE_VERBOSE_STRINGS (void)data; #endif @@ -210,7 +399,6 @@ Curl_cookie_add(struct SessionHandle *data, if(httpheader) { /* This line was read off a HTTP-header */ const char *ptr; - const char *sep; const char *semiptr; char *what; @@ -227,183 +415,158 @@ Curl_cookie_add(struct SessionHandle *data, ptr = lineptr; do { - /* we have a = pair or a 'secure' word here */ - sep = strchr(ptr, '='); - if(sep && (!semiptr || (semiptr>sep)) ) { + /* we have a = pair or a stand-alone word here */ + name[0]=what[0]=0; /* init the buffers */ + if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%" + MAX_COOKIE_LINE_TXT "[^;\r\n]", + name, what)) { + /* Use strstore() below to properly deal with received cookie + headers that have the same string property set more than once, + and then we use the last one. */ + const char *whatptr; + bool done = FALSE; + bool sep; + size_t len=strlen(what); + size_t nlen = strlen(name); + const char *endofn = &ptr[ nlen ]; + + /* name ends with a '=' ? */ + sep = (*endofn == '=')?TRUE:FALSE; + + if(nlen) { + endofn--; /* move to the last character */ + if(ISBLANK(*endofn)) { + /* skip trailing spaces in name */ + while(*endofn && ISBLANK(*endofn) && nlen) { + endofn--; + nlen--; + } + name[nlen]=0; /* new end of name */ + } + } + + /* Strip off trailing whitespace from the 'what' */ + while(len && ISBLANK(what[len-1])) { + what[len-1]=0; + len--; + } + + /* Skip leading whitespace from the 'what' */ + whatptr=what; + while(*whatptr && ISBLANK(*whatptr)) + whatptr++; + + if(!co->name && sep) { + /* The very first name/value pair is the actual cookie name */ + co->name = strdup(name); + co->value = strdup(whatptr); + if(!co->name || !co->value) { + badcookie = TRUE; + break; + } + } + else if(!len) { + /* this was a "=" with no content, and we must allow + 'secure' and 'httponly' specified this weirdly */ + done = TRUE; + if(Curl_raw_equal("secure", name)) + co->secure = TRUE; + else if(Curl_raw_equal("httponly", name)) + co->httponly = TRUE; + else if(sep) + /* there was a '=' so we're not done parsing this field */ + done = FALSE; + } + if(done) + ; + else if(Curl_raw_equal("path", name)) { + strstore(&co->path, whatptr); + if(!co->path) { + badcookie = TRUE; /* out of memory bad */ + break; + } + co->spath = sanitize_cookie_path(co->path); + if(!co->spath) { + badcookie = TRUE; /* out of memory bad */ + break; + } + } + else if(Curl_raw_equal("domain", name)) { + bool is_ip; + const char *dotp; + + /* Now, we make sure that our host is within the given domain, + or the given domain is not valid and thus cannot be set. */ + + if('.' == whatptr[0]) + whatptr++; /* ignore preceding dot */ + + is_ip = isip(domain ? domain : whatptr); + + /* check for more dots */ + dotp = strchr(whatptr, '.'); + if(!dotp) + domain=":"; + + if(!domain + || (is_ip && !strcmp(whatptr, domain)) + || (!is_ip && tailmatch(whatptr, domain))) { + strstore(&co->domain, whatptr); + if(!co->domain) { + badcookie = TRUE; + break; + } + if(!is_ip) + co->tailmatch=TRUE; /* we always do that if the domain name was + given */ + } + else { + /* we did not get a tailmatch and then the attempted set domain + is not a domain to which the current host belongs. Mark as + bad. */ + badcookie=TRUE; + infof(data, "skipped cookie with bad tailmatch domain: %s\n", + whatptr); + } + } + else if(Curl_raw_equal("version", name)) { + strstore(&co->version, whatptr); + if(!co->version) { + badcookie = TRUE; + break; + } + } + else if(Curl_raw_equal("max-age", name)) { + /* Defined in RFC2109: + + Optional. The Max-Age attribute defines the lifetime of the + cookie, in seconds. The delta-seconds value is a decimal non- + negative integer. After delta-seconds seconds elapse, the + client should discard the cookie. A value of zero means the + cookie should be discarded immediately. + + */ + strstore(&co->maxage, whatptr); + if(!co->maxage) { + badcookie = TRUE; + break; + } + } + else if(Curl_raw_equal("expires", name)) { + strstore(&co->expirestr, whatptr); + if(!co->expirestr) { + badcookie = TRUE; + break; + } + } /* - * There is a = sign and if there was a semicolon too, which make sure - * that the semicolon comes _after_ the equal sign. - */ - - name[0]=what[0]=0; /* init the buffers */ - if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%" - MAX_COOKIE_LINE_TXT "[^;\r\n]", - name, what)) { - /* this is a = pair. We use strstore() below to properly - deal with received cookie headers that have the same string - property set more than once, and then we use the last one. */ - - const char *whatptr; - - /* Strip off trailing whitespace from the 'what' */ - size_t len=strlen(what); - while(len && ISBLANK(what[len-1])) { - what[len-1]=0; - len--; - } - - /* Skip leading whitespace from the 'what' */ - whatptr=what; - while(*whatptr && ISBLANK(*whatptr)) { - whatptr++; - } - - if(Curl_raw_equal("path", name)) { - strstore(&co->path, whatptr); - if(!co->path) { - badcookie = TRUE; /* out of memory bad */ - break; - } - } - else if(Curl_raw_equal("domain", name)) { - /* note that this name may or may not have a preceeding dot, but - we don't care about that, we treat the names the same anyway */ - - const char *domptr=whatptr; - int dotcount=1; - - /* Count the dots, we need to make sure that there are enough - of them. */ - - if('.' == whatptr[0]) - /* don't count the initial dot, assume it */ - domptr++; - - do { - domptr = strchr(domptr, '.'); - if(domptr) { - domptr++; - dotcount++; - } - } while(domptr); - - /* The original Netscape cookie spec defined that this domain name - MUST have three dots (or two if one of the seven holy TLDs), - but it seems that these kinds of cookies are in use "out there" - so we cannot be that strict. I've therefore lowered the check - to not allow less than two dots. */ - - if(dotcount < 2) { - /* Received and skipped a cookie with a domain using too few - dots. */ - badcookie=TRUE; /* mark this as a bad cookie */ - infof(data, "skipped cookie with illegal dotcount domain: %s\n", - whatptr); - } - else { - /* Now, we make sure that our host is within the given domain, - or the given domain is not valid and thus cannot be set. */ - - if('.' == whatptr[0]) - whatptr++; /* ignore preceeding dot */ - - if(!domain || tailmatch(whatptr, domain)) { - const char *tailptr=whatptr; - if(tailptr[0] == '.') - tailptr++; - strstore(&co->domain, tailptr); /* don't prefix w/dots - internally */ - if(!co->domain) { - badcookie = TRUE; - break; - } - co->tailmatch=TRUE; /* we always do that if the domain name was - given */ - } - else { - /* we did not get a tailmatch and then the attempted set domain - is not a domain to which the current host belongs. Mark as - bad. */ - badcookie=TRUE; - infof(data, "skipped cookie with bad tailmatch domain: %s\n", - whatptr); - } - } - } - else if(Curl_raw_equal("version", name)) { - strstore(&co->version, whatptr); - if(!co->version) { - badcookie = TRUE; - break; - } - } - else if(Curl_raw_equal("max-age", name)) { - /* Defined in RFC2109: - - Optional. The Max-Age attribute defines the lifetime of the - cookie, in seconds. The delta-seconds value is a decimal non- - negative integer. After delta-seconds seconds elapse, the - client should discard the cookie. A value of zero means the - cookie should be discarded immediately. - - */ - strstore(&co->maxage, whatptr); - if(!co->maxage) { - badcookie = TRUE; - break; - } - co->expires = - strtol((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0],NULL,10) - + (long)now; - } - else if(Curl_raw_equal("expires", name)) { - strstore(&co->expirestr, whatptr); - if(!co->expirestr) { - badcookie = TRUE; - break; - } - /* Note that if the date couldn't get parsed for whatever reason, - the cookie will be treated as a session cookie */ - co->expires = curl_getdate(what, &now); - - /* Session cookies have expires set to 0 so if we get that back - from the date parser let's add a second to make it a - non-session cookie */ - if (co->expires == 0) - co->expires = 1; - else if( co->expires < 0 ) - co->expires = 0; - } - else if(!co->name) { - co->name = strdup(name); - co->value = strdup(whatptr); - if(!co->name || !co->value) { - badcookie = TRUE; - break; - } - } - /* - else this is the second (or more) name we don't know - about! */ - } - else { - /* this is an "illegal" = pair */ - } + else this is the second (or more) name we don't know + about! */ } else { - if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]", - what)) { - if(Curl_raw_equal("secure", what)) { - co->secure = TRUE; - } - else if (Curl_raw_equal("httponly", what)) { - co->httponly = TRUE; - } - /* else, - unsupported keyword without assign! */ - - } + /* this is an "illegal" = pair */ } + if(!semiptr || !*semiptr) { /* we already know there are no more cookies */ semiptr = NULL; @@ -421,6 +584,30 @@ Curl_cookie_add(struct SessionHandle *data, semiptr=strchr(ptr, '\0'); } while(semiptr); + if(co->maxage) { + co->expires = + curlx_strtoofft((*co->maxage=='\"')? + &co->maxage[1]:&co->maxage[0], NULL, 10); + if(CURL_OFF_T_MAX - now < co->expires) + /* avoid overflow */ + co->expires = CURL_OFF_T_MAX; + else + co->expires += now; + } + else if(co->expirestr) { + /* Note that if the date couldn't get parsed for whatever reason, + the cookie will be treated as a session cookie */ + co->expires = curl_getdate(co->expirestr, NULL); + + /* Session cookies have expires set to 0 so if we get that back + from the date parser let's add a second to make it a + non-session cookie */ + if(co->expires == 0) + co->expires = 1; + else if(co->expires < 0) + co->expires = 0; + } + if(!badcookie && !co->domain) { if(domain) { /* no domain was given in the header line, set the default */ @@ -449,6 +636,9 @@ Curl_cookie_add(struct SessionHandle *data, if(co->path) { memcpy(co->path, path, pathlen); co->path[pathlen]=0; /* zero terminate */ + co->spath = sanitize_cookie_path(co->path); + if(!co->spath) + badcookie = TRUE; /* out of memory bad */ } else badcookie = TRUE; @@ -477,10 +667,10 @@ Curl_cookie_add(struct SessionHandle *data, marked with httpOnly after the domain name are not accessible from javascripts, but since curl does not operate at javascript level, we include them anyway. In Firefox's cookie files, these - lines are preceeded with #HttpOnly_ and then everything is + lines are preceded with #HttpOnly_ and then everything is as usual, so we skip 10 characters of the line.. */ - if (strncmp(lineptr, "#HttpOnly_", 10) == 0) { + if(strncmp(lineptr, "#HttpOnly_", 10) == 0) { lineptr += 10; co->httponly = TRUE; } @@ -500,19 +690,13 @@ Curl_cookie_add(struct SessionHandle *data, firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */ - /* Here's a quick check to eliminate normal HTTP-headers from this */ - if(!firstptr || strchr(firstptr, ':')) { - free(co); - return NULL; - } - /* Now loop through the fields and init the struct we already have allocated */ for(ptr=firstptr, fields=0; ptr && !badcookie; ptr=strtok_r(NULL, "\t", &tok_buf), fields++) { switch(fields) { case 0: - if(ptr[0]=='.') /* skip preceeding dots */ + if(ptr[0]=='.') /* skip preceding dots */ ptr++; co->domain = strdup(ptr); if(!co->domain) @@ -529,7 +713,7 @@ Curl_cookie_add(struct SessionHandle *data, As far as I can see, it is set to true when the cookie says .domain.com and to false when the domain is complete www.domain.com */ - co->tailmatch=(bool)Curl_raw_equal(ptr, "TRUE"); /* store information */ + co->tailmatch = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE; break; case 2: /* It turns out, that sometimes the file format allows the path @@ -540,16 +724,25 @@ Curl_cookie_add(struct SessionHandle *data, co->path = strdup(ptr); if(!co->path) badcookie = TRUE; + else { + co->spath = sanitize_cookie_path(co->path); + if(!co->spath) { + badcookie = TRUE; /* out of memory bad */ + } + } break; } /* this doesn't look like a path, make one up! */ co->path = strdup("/"); if(!co->path) badcookie = TRUE; + co->spath = strdup("/"); + if(!co->spath) + badcookie = TRUE; fields++; /* add a field and fall down to secure */ /* FALLTHROUGH */ case 3: - co->secure = (bool)Curl_raw_equal(ptr, "TRUE"); + co->secure = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE; break; case 4: co->expires = curlx_strtoofft(ptr, NULL, 10); @@ -599,6 +792,24 @@ Curl_cookie_add(struct SessionHandle *data, superceeds an already existing cookie, which it may if the previous have the same domain and path as this */ + /* at first, remove expired cookies */ + remove_expired(c); + +#ifdef USE_LIBPSL + /* Check if the domain is a Public Suffix and if yes, ignore the cookie. + This needs a libpsl compiled with builtin data. */ + if(domain && co->domain && !isip(co->domain)) { + if(((psl = psl_builtin()) != NULL) + && !psl_is_cookie_domain_acceptable(psl, domain, co->domain)) { + infof(data, + "cookie '%s' dropped, domain '%s' must not set cookies for '%s'\n", + co->name, domain, co->domain); + freecookie(co); + return NULL; + } + } +#endif + clist = c->cookies; replace_old = FALSE; while(clist) { @@ -616,14 +827,14 @@ Curl_cookie_add(struct SessionHandle *data, if(replace_old) { /* the domains were identical */ - if(clist->path && co->path) { - if(Curl_raw_equal(clist->path, co->path)) { + if(clist->spath && co->spath) { + if(Curl_raw_equal(clist->spath, co->spath)) { replace_old = TRUE; } else replace_old = FALSE; } - else if(!clist->path && !co->path) + else if(!clist->spath && !co->spath) replace_old = TRUE; else replace_old = FALSE; @@ -646,19 +857,13 @@ Curl_cookie_add(struct SessionHandle *data, /* then free all the old pointers */ free(clist->name); - if(clist->value) - free(clist->value); - if(clist->domain) - free(clist->domain); - if(clist->path) - free(clist->path); - if(clist->expirestr) - free(clist->expirestr); - - if(clist->version) - free(clist->version); - if(clist->maxage) - free(clist->maxage); + free(clist->value); + free(clist->domain); + free(clist->path); + free(clist->spath); + free(clist->expirestr); + free(clist->version); + free(clist->maxage); *clist = *co; /* then store all the new data */ @@ -681,7 +886,7 @@ Curl_cookie_add(struct SessionHandle *data, if(c->running) /* Only show this when NOT reading the cookies from a file */ infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, " - "expire %" FORMAT_OFF_T "\n", + "expire %" CURL_FORMAT_CURL_OFF_T "\n", replace_old?"Replaced":"Added", co->name, co->value, co->domain, co->path, co->expires); @@ -691,9 +896,9 @@ Curl_cookie_add(struct SessionHandle *data, lastc->next = co; else c->cookies = co; + c->numcookies++; /* one more cookie in the jar */ } - c->numcookies++; /* one more cookie in the jar */ return co; } @@ -706,6 +911,7 @@ Curl_cookie_add(struct SessionHandle *data, * * If 'newsession' is TRUE, discard all "session cookies" on read from file. * + * Returns NULL on out of memory. Invalid cookies are ignored. ****************************************************************************/ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, const char *file, @@ -713,8 +919,9 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, bool newsession) { struct CookieInfo *c; - FILE *fp; + FILE *fp = NULL; bool fromfile=TRUE; + char *line = NULL; if(NULL == inc) { /* we didn't get a struct, create one */ @@ -722,6 +929,8 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, if(!c) return NULL; /* failed to get memory */ c->filename = strdup(file?file:"none"); /* copy the name just in case */ + if(!c->filename) + goto fail; /* failed to get memory */ } else { /* we got an already existing one, use that */ @@ -738,7 +947,7 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, fp = NULL; } else - fp = file?fopen(file, "r"):NULL; + fp = file?fopen(file, FOPEN_READTEXT):NULL; c->newsession = newsession; /* new session? */ @@ -746,25 +955,26 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, char *lineptr; bool headerline; - char *line = malloc(MAX_COOKIE_LINE); - if(line) { - while(fgets(line, MAX_COOKIE_LINE, fp)) { - if(checkprefix("Set-Cookie:", line)) { - /* This is a cookie line, get it! */ - lineptr=&line[11]; - headerline=TRUE; - } - else { - lineptr=line; - headerline=FALSE; - } - while(*lineptr && ISBLANK(*lineptr)) - lineptr++; - - Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL); + line = malloc(MAX_COOKIE_LINE); + if(!line) + goto fail; + while(fgets(line, MAX_COOKIE_LINE, fp)) { + if(checkprefix("Set-Cookie:", line)) { + /* This is a cookie line, get it! */ + lineptr=&line[11]; + headerline=TRUE; } - free(line); /* free the line buffer */ + else { + lineptr=line; + headerline=FALSE; + } + while(*lineptr && ISBLANK(*lineptr)) + lineptr++; + + Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL); } + free(line); /* free the line buffer */ + if(fromfile) fclose(fp); } @@ -772,6 +982,16 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, c->running = TRUE; /* now, we're running */ return c; + +fail: + free(line); + if(!inc) + /* Only clean up if we allocated it here, as the original could still be in + * use by a share handle */ + Curl_cookie_cleanup(c); + if(fromfile && fp) + fclose(fp); + return NULL; /* out of memory */ } /* sort this so that the longest path gets before the shorter path */ @@ -779,11 +999,28 @@ static int cookie_sort(const void *p1, const void *p2) { struct Cookie *c1 = *(struct Cookie **)p1; struct Cookie *c2 = *(struct Cookie **)p2; + size_t l1, l2; - size_t l1 = c1->path?strlen(c1->path):0; - size_t l2 = c2->path?strlen(c2->path):0; + /* 1 - compare cookie path lengths */ + l1 = c1->path ? strlen(c1->path) : 0; + l2 = c2->path ? strlen(c2->path) : 0; - return (l2 > l1) ? 1 : (l2 < l1) ? -1 : 0 ; + if(l1 != l2) + return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */ + + /* 2 - compare cookie domain lengths */ + l1 = c1->domain ? strlen(c1->domain) : 0; + l2 = c2->domain ? strlen(c2->domain) : 0; + + if(l1 != l2) + return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */ + + /* 3 - compare cookie names */ + if(c1->name && c2->name) + return strcmp(c1->name, c2->name); + + /* sorry, can't be more deterministic */ + return 0; } /***************************************************************************** @@ -807,32 +1044,36 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, time_t now = time(NULL); struct Cookie *mainco=NULL; size_t matches = 0; + bool is_ip; if(!c || !c->cookies) return NULL; /* no cookie struct or no cookies in the struct */ + /* at first, remove expired cookies */ + remove_expired(c); + + /* check if host is an IP(v4|v6) address */ + is_ip = isip(host); + co = c->cookies; while(co) { /* only process this cookie if it is not expired or had no expire date AND that if the cookie requires we're secure we must only continue if we are! */ - if( (!co->expires || (co->expires > now)) && - (co->secure?secure:TRUE) ) { + if((!co->expires || (co->expires > now)) && + (co->secure?secure:TRUE)) { /* now check if the domain is correct */ if(!co->domain || - (co->tailmatch && tailmatch(co->domain, host)) || - (!co->tailmatch && Curl_raw_equal(host, co->domain)) ) { + (co->tailmatch && !is_ip && tailmatch(co->domain, host)) || + ((!co->tailmatch || is_ip) && Curl_raw_equal(host, co->domain)) ) { /* the right part of the host matches the domain stuff in the cookie data */ /* now check the left part of the path with the cookies path requirement */ - if(!co->path || - /* not using checkprefix() because matching should be - case-sensitive */ - !strncmp(co->path, path, strlen(co->path)) ) { + if(!co->spath || pathmatch(co->spath, path) ) { /* and now, we know this is a match and we should create an entry for the return-linked-list */ @@ -875,7 +1116,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, size_t i; /* alloc an array and store all cookie pointers */ - array = (struct Cookie **)malloc(sizeof(struct Cookie *) * matches); + array = malloc(sizeof(struct Cookie *) * matches); if(!array) goto fail; @@ -884,7 +1125,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, for(i=0; co; co = co->next) array[i++] = co; - /* now sort the cookie pointers in path lenth order */ + /* now sort the cookie pointers in path length order */ qsort(array, matches, sizeof(struct Cookie *), cookie_sort); /* remake the linked list order according to the new order */ @@ -930,16 +1171,14 @@ void Curl_cookie_clearall(struct CookieInfo *cookies) void Curl_cookie_freelist(struct Cookie *co, bool cookiestoo) { struct Cookie *next; - if(co) { - while(co) { - next = co->next; - if(cookiestoo) - freecookie(co); - else - free(co); /* we only free the struct since the "members" are all just - pointed out in the main cookie list! */ - co = next; - } + while(co) { + next = co->next; + if(cookiestoo) + freecookie(co); + else + free(co); /* we only free the struct since the "members" are all just + pointed out in the main cookie list! */ + co = next; } } @@ -986,23 +1225,14 @@ void Curl_cookie_clearsess(struct CookieInfo *cookies) * * Curl_cookie_cleanup() * - * Free a "cookie object" previous created with cookie_init(). + * Free a "cookie object" previous created with Curl_cookie_init(). * ****************************************************************************/ void Curl_cookie_cleanup(struct CookieInfo *c) { - struct Cookie *co; - struct Cookie *next; if(c) { - if(c->filename) - free(c->filename); - co = c->cookies; - - while(co) { - next = co->next; - freecookie(co); - co = next; - } + free(c->filename); + Curl_cookie_freelist(c->cookies, TRUE); free(c); /* free the base struct as well */ } } @@ -1021,7 +1251,7 @@ static char *get_netscape_format(const struct Cookie *co) "%s\t" /* tailmatch */ "%s\t" /* path */ "%s\t" /* secure */ - "%" FORMAT_OFF_T "\t" /* expires */ + "%" CURL_FORMAT_CURL_OFF_T "\t" /* expires */ "%s\t" /* name */ "%s", /* value */ co->httponly?"#HttpOnly_":"", @@ -1038,56 +1268,56 @@ static char *get_netscape_format(const struct Cookie *co) } /* - * Curl_cookie_output() + * cookie_output() * * Writes all internally known cookies to the specified file. Specify * "-" as file name to write to stdout. * * The function returns non-zero on write failure. */ -int Curl_cookie_output(struct CookieInfo *c, const char *dumphere) +static int cookie_output(struct CookieInfo *c, const char *dumphere) { struct Cookie *co; FILE *out; bool use_stdout=FALSE; + char *format_ptr; if((NULL == c) || (0 == c->numcookies)) /* If there are no known cookies, we don't write or even create any destination file */ return 0; + /* at first, remove expired cookies */ + remove_expired(c); + if(strequal("-", dumphere)) { /* use stdout */ out = stdout; use_stdout=TRUE; } else { - out = fopen(dumphere, "w"); + out = fopen(dumphere, FOPEN_WRITETEXT); if(!out) return 1; /* failure */ } - if(c) { - char *format_ptr; + fputs("# Netscape HTTP Cookie File\n" + "# https://curl.haxx.se/docs/http-cookies.html\n" + "# This file was generated by libcurl! Edit at your own risk.\n\n", + out); - fputs("# Netscape HTTP Cookie File\n" - "# http://curl.haxx.se/rfc/cookie_spec.html\n" - "# This file was generated by libcurl! Edit at your own risk.\n\n", - out); - co = c->cookies; - - while(co) { - format_ptr = get_netscape_format(co); - if(format_ptr == NULL) { - fprintf(out, "#\n# Fatal libcurl error\n"); - if(!use_stdout) - fclose(out); + for(co = c->cookies; co; co = co->next) { + if(!co->domain) + continue; + format_ptr = get_netscape_format(co); + if(format_ptr == NULL) { + fprintf(out, "#\n# Fatal libcurl error\n"); + if(!use_stdout) + fclose(out); return 1; - } - fprintf(out, "%s\n", format_ptr); - free(format_ptr); - co=co->next; } + fprintf(out, "%s\n", format_ptr); + free(format_ptr); } if(!use_stdout) @@ -1107,29 +1337,57 @@ struct curl_slist *Curl_cookie_list(struct SessionHandle *data) (data->cookies->numcookies == 0)) return NULL; - c = data->cookies->cookies; - - beg = list; - while(c) { - /* fill the list with _all_ the cookies we know */ + for(c = data->cookies->cookies; c; c = c->next) { + if(!c->domain) + continue; line = get_netscape_format(c); - if(line == NULL) { - curl_slist_free_all(beg); + if(!line) { + curl_slist_free_all(list); return NULL; } - list = curl_slist_append(list, line); - free(line); - if(list == NULL) { - curl_slist_free_all(beg); + beg = Curl_slist_append_nodup(list, line); + if(!beg) { + free(line); + curl_slist_free_all(list); return NULL; } - else if(beg == NULL) { - beg = list; - } - c = c->next; + list = beg; } return list; } +void Curl_flush_cookies(struct SessionHandle *data, int cleanup) +{ + if(data->set.str[STRING_COOKIEJAR]) { + if(data->change.cookielist) { + /* If there is a list of cookie files to read, do it first so that + we have all the told files read before we write the new jar. + Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */ + Curl_cookie_loadfiles(data); + } + + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + + /* if we have a destination file for all the cookies to get dumped to */ + if(cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR])) + infof(data, "WARNING: failed to save cookies in %s\n", + data->set.str[STRING_COOKIEJAR]); + } + else { + if(cleanup && data->change.cookielist) { + /* since nothing is written, we can just free the list of cookie file + names */ + curl_slist_free_all(data->change.cookielist); /* clean up list */ + data->change.cookielist = NULL; + } + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + } + + if(cleanup && (!data->share || (data->cookies != data->share->cookies))) { + Curl_cookie_cleanup(data->cookies); + } + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); +} + #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */ diff --git a/project/jni/curl/lib/cookie.h b/project/jni/curl/lib/cookie.h index e8c005f20..74a9224ec 100644 --- a/project/jni/curl/lib/cookie.h +++ b/project/jni/curl/lib/cookie.h @@ -1,5 +1,5 @@ -#ifndef __COOKIE_H -#define __COOKIE_H +#ifndef HEADER_CURL_COOKIE_H +#define HEADER_CURL_COOKIE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,15 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ - -#include -#if defined(WIN32) -#include -#else -#ifdef HAVE_SYS_TIME_H -#include -#endif -#endif +#include "curl_setup.h" #include @@ -37,7 +29,8 @@ struct Cookie { struct Cookie *next; /* next in the chain */ char *name; /* = value */ char *value; /* name = */ - char *path; /* path = */ + char *path; /* path = which is in Set-Cookie: */ + char *spath; /* sanitized cookie path */ char *domain; /* domain = */ curl_off_t expires; /* expires = */ char *expirestr; /* the plain text version */ @@ -87,22 +80,25 @@ struct Cookie *Curl_cookie_add(struct SessionHandle *data, struct CookieInfo *, bool header, char *lineptr, const char *domain, const char *path); -struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, - const char *, struct CookieInfo *, bool); struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *, const char *, bool); void Curl_cookie_freelist(struct Cookie *cookies, bool cookiestoo); void Curl_cookie_clearall(struct CookieInfo *cookies); void Curl_cookie_clearsess(struct CookieInfo *cookies); -void Curl_cookie_cleanup(struct CookieInfo *); -int Curl_cookie_output(struct CookieInfo *, const char *); #if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES) #define Curl_cookie_list(x) NULL -#define Curl_cookie_loadfiles(x) do { } while (0) +#define Curl_cookie_loadfiles(x) Curl_nop_stmt +#define Curl_cookie_init(x,y,z,w) NULL +#define Curl_cookie_cleanup(x) Curl_nop_stmt +#define Curl_flush_cookies(x,y) Curl_nop_stmt #else +void Curl_flush_cookies(struct SessionHandle *data, int cleanup); +void Curl_cookie_cleanup(struct CookieInfo *); +struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, + const char *, struct CookieInfo *, bool); struct curl_slist *Curl_cookie_list(struct SessionHandle *data); void Curl_cookie_loadfiles(struct SessionHandle *data); #endif -#endif +#endif /* HEADER_CURL_COOKIE_H */ diff --git a/project/jni/curl/lib/curl_addrinfo.c b/project/jni/curl/lib/curl_addrinfo.c index 6feccf2d0..cc60ddb66 100644 --- a/project/jni/curl/lib/curl_addrinfo.c +++ b/project/jni/curl/lib/curl_addrinfo.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,13 +20,10 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #include -#ifdef HAVE_SYS_SOCKET_H -# include -#endif #ifdef HAVE_NETINET_IN_H # include #endif @@ -36,11 +33,13 @@ #ifdef HAVE_ARPA_INET_H # include #endif +#ifdef HAVE_SYS_UN_H +# include +#endif #ifdef __VMS # include # include -# include #endif #if defined(NETWARE) && defined(__NOVELL_LIBC__) @@ -50,15 +49,13 @@ #include "curl_addrinfo.h" #include "inet_pton.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "warnless.h" +#include "curl_printf.h" #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" - /* * Curl_freeaddrinfo() * @@ -83,13 +80,8 @@ Curl_freeaddrinfo(Curl_addrinfo *cahead) Curl_addrinfo *ca; for(ca = cahead; ca != NULL; ca = canext) { - - if(ca->ai_addr) - free(ca->ai_addr); - - if(ca->ai_canonname) - free(ca->ai_canonname); - + free(ca->ai_addr); + free(ca->ai_canonname); canext = ca->ai_next; free(ca); @@ -294,7 +286,7 @@ Curl_he2ai(const struct hostent *he, int port) size_t ss_size; #ifdef ENABLE_IPV6 - if (he->h_addrtype == AF_INET6) + if(he->h_addrtype == AF_INET6) ss_size = sizeof (struct sockaddr_in6); else #endif @@ -357,7 +349,7 @@ Curl_he2ai(const struct hostent *he, int port) prevai = ai; } - if(result != CURLE_OK) { + if(result) { Curl_freeaddrinfo(firstai); firstai = NULL; } @@ -480,20 +472,60 @@ Curl_addrinfo *Curl_str2addr(char *address, int port) return NULL; /* bad input format */ } +#ifdef USE_UNIX_SOCKETS +/** + * Given a path to a Unix domain socket, return a newly allocated Curl_addrinfo + * struct initialized with this path. + */ +Curl_addrinfo *Curl_unix2addr(const char *path) +{ + Curl_addrinfo *ai; + struct sockaddr_un *sa_un; + size_t path_len; + + ai = calloc(1, sizeof(Curl_addrinfo)); + if(!ai) + return NULL; + if((ai->ai_addr = calloc(1, sizeof(struct sockaddr_un))) == NULL) { + free(ai); + return NULL; + } + /* sun_path must be able to store the NUL-terminated path */ + path_len = strlen(path); + if(path_len >= sizeof(sa_un->sun_path)) { + free(ai->ai_addr); + free(ai); + return NULL; + } + + ai->ai_family = AF_UNIX; + ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */ + ai->ai_addrlen = (curl_socklen_t) sizeof(struct sockaddr_un); + sa_un = (void *) ai->ai_addr; + sa_un->sun_family = AF_UNIX; + memcpy(sa_un->sun_path, path, path_len + 1); /* copy NUL byte */ + return ai; +} +#endif + #if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) /* * curl_dofreeaddrinfo() * * This is strictly for memory tracing and are using the same style as the * family otherwise present in memdebug.c. I put these ones here since they - * require a bunch of structs I didn't wanna include in memdebug.c + * require a bunch of structs I didn't want to include in memdebug.c */ void curl_dofreeaddrinfo(struct addrinfo *freethis, int line, const char *source) { +#ifdef USE_LWIPSOCK + lwip_freeaddrinfo(freethis); +#else (freeaddrinfo)(freethis); +#endif curl_memlog("ADDR %s:%d freeaddrinfo(%p)\n", source, line, (void *)freethis); } @@ -506,7 +538,7 @@ curl_dofreeaddrinfo(struct addrinfo *freethis, * * This is strictly for memory tracing and are using the same style as the * family otherwise present in memdebug.c. I put these ones here since they - * require a bunch of structs I didn't wanna include in memdebug.c + * require a bunch of structs I didn't want to include in memdebug.c */ int @@ -516,7 +548,11 @@ curl_dogetaddrinfo(const char *hostname, struct addrinfo **result, int line, const char *source) { +#ifdef USE_LWIPSOCK + int res=lwip_getaddrinfo(hostname, service, hints, result); +#else int res=(getaddrinfo)(hostname, service, hints, result); +#endif if(0 == res) /* success */ curl_memlog("ADDR %s:%d getaddrinfo() = %p\n", diff --git a/project/jni/curl/lib/curl_addrinfo.h b/project/jni/curl/lib/curl_addrinfo.h index 11c339474..01f286478 100644 --- a/project/jni/curl/lib/curl_addrinfo.h +++ b/project/jni/curl/lib/curl_addrinfo.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,11 +22,8 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#ifdef HAVE_SYS_SOCKET_H -# include -#endif #ifdef HAVE_NETINET_IN_H # include #endif @@ -82,7 +79,12 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port); Curl_addrinfo *Curl_str2addr(char *dotted, int port); -#if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) +#ifdef USE_UNIX_SOCKETS +Curl_addrinfo *Curl_unix2addr(const char *path); +#endif + +#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \ + defined(HAVE_FREEADDRINFO) void curl_dofreeaddrinfo(struct addrinfo *freethis, int line, const char *source); diff --git a/project/jni/curl/lib/curl_base64.h b/project/jni/curl/lib/curl_base64.h index 2498a0a22..c26241767 100644 --- a/project/jni/curl/lib/curl_base64.h +++ b/project/jni/curl/lib/curl_base64.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,10 +22,14 @@ * ***************************************************************************/ -size_t Curl_base64_encode(struct SessionHandle *data, - const char *inputbuff, size_t insize, - char **outptr); +CURLcode Curl_base64_encode(struct SessionHandle *data, + const char *inputbuff, size_t insize, + char **outptr, size_t *outlen); +CURLcode Curl_base64url_encode(struct SessionHandle *data, + const char *inputbuff, size_t insize, + char **outptr, size_t *outlen); -size_t Curl_base64_decode(const char *src, unsigned char **outptr); +CURLcode Curl_base64_decode(const char *src, + unsigned char **outptr, size_t *outlen); #endif /* HEADER_CURL_BASE64_H */ diff --git a/project/jni/curl/lib/curl_config.h b/project/jni/curl/lib/curl_config.h index 4952c4eec..20282d649 100644 --- a/project/jni/curl/lib/curl_config.h +++ b/project/jni/curl/lib/curl_config.h @@ -40,6 +40,9 @@ /* to disable LDAPS */ #define CURL_DISABLE_LDAPS 1 +/* to disable --libcurl C code generation option */ +#define CURL_DISABLE_LIBCURL_OPTION 1 + /* to disable POP3 */ #define CURL_DISABLE_POP3 1 @@ -62,7 +65,7 @@ /* #undef CURL_DISABLE_VERBOSE_STRINGS */ /* to make a symbol visible */ -/* #undef CURL_EXTERN_SYMBOL */ +#define CURL_EXTERN_SYMBOL __attribute__ ((__visibility__ ("default"))) /* to enable hidden symbols */ /* #undef CURL_HIDDEN_SYMBOLS */ @@ -77,7 +80,7 @@ /* #undef EGD_SOCKET */ /* Define if you want to enable IPv6 support */ -/* #undef ENABLE_IPV6 */ +#define ENABLE_IPV6 1 /* Define to the type qualifier of arg 1 for getnameinfo. */ #define GETNAMEINFO_QUAL_ARG1 const @@ -121,6 +124,9 @@ /* Define to 1 if bool is an available type. */ #define HAVE_BOOL_T 1 +/* Define to 1 if using BoringSSL. */ +#define HAVE_BORINGSSL 1 + /* Define to 1 if you have the clock_gettime function and monotonic timer. */ #define HAVE_CLOCK_GETTIME_MONOTONIC 1 @@ -134,7 +140,7 @@ #define HAVE_CONNECT 1 /* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */ -/* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */ +#define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_CRYPTO_H */ @@ -149,7 +155,7 @@ /* #undef HAVE_ENGINE_CLEANUP */ /* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */ -/* #undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES */ +#define HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1 /* Define to 1 if you have the header file. */ #define HAVE_ERRNO_H 1 @@ -190,6 +196,9 @@ /* Define to 1 if you have the ftruncate function. */ #define HAVE_FTRUNCATE 1 +/* Define to 1 if you have the gai_strerror function. */ +#define HAVE_GAI_STRERROR 1 + /* Define to 1 if you have a working getaddrinfo function. */ #define HAVE_GETADDRINFO 1 @@ -203,7 +212,7 @@ #define HAVE_GETHOSTBYADDR 1 /* Define to 1 if you have the gethostbyaddr_r function. */ -/* #undef HAVE_GETHOSTBYADDR_R */ +/* #define HAVE_GETHOSTBYADDR_R 1 */ /* gethostbyaddr_r() takes 5 args */ /* #undef HAVE_GETHOSTBYADDR_R_5 */ @@ -212,13 +221,13 @@ /* #undef HAVE_GETHOSTBYADDR_R_7 */ /* gethostbyaddr_r() takes 8 args */ -/* #undef HAVE_GETHOSTBYADDR_R_8 */ +/* #define HAVE_GETHOSTBYADDR_R_8 1 */ /* Define to 1 if you have the gethostbyname function. */ #define HAVE_GETHOSTBYNAME 1 /* Define to 1 if you have the gethostbyname_r function. */ -#define HAVE_GETHOSTBYNAME_R 1 +/* #define HAVE_GETHOSTBYNAME_R 1 */ /* gethostbyname_r() takes 3 args */ /* #undef HAVE_GETHOSTBYNAME_R_3 */ @@ -227,7 +236,7 @@ /* #undef HAVE_GETHOSTBYNAME_R_5 */ /* gethostbyname_r() takes 6 args */ -#define HAVE_GETHOSTBYNAME_R_6 1 +/* #define HAVE_GETHOSTBYNAME_R_6 1 */ /* Define to 1 if you have the gethostname function. */ #define HAVE_GETHOSTNAME 1 @@ -235,6 +244,9 @@ /* Define to 1 if you have a working getifaddrs function. */ /* #undef HAVE_GETIFADDRS */ +/* Define to 1 if you have the `if_nametoindex' function. */ +#define HAVE_IF_NAMETOINDEX 1 + /* Define to 1 if you have the getnameinfo function. */ #define HAVE_GETNAMEINFO 1 @@ -466,29 +478,31 @@ /* #undef HAVE_OLD_GSSMIT */ /* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_CRYPTO_H */ +#define HAVE_OPENSSL_CRYPTO_H 1 /* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_ENGINE_H */ +#define HAVE_OPENSSL_ENGINE_H 1 /* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_ERR_H */ +#define HAVE_OPENSSL_ERR_H 1 /* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_PEM_H */ +#define HAVE_OPENSSL_PEM_H 1 /* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_PKCS12_H */ +#define HAVE_OPENSSL_PKCS12_H 1 /* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_RSA_H */ +#define HAVE_OPENSSL_RSA_H 1 + +/* if you have the function SRP_Calc_client_key */ +/* #define HAVE_OPENSSL_SRP 1 */ /* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_SSL_H */ +#define HAVE_OPENSSL_SSL_H 1 /* Define to 1 if you have the header file. */ -/* #undef HAVE_OPENSSL_X509_H */ - +#define HAVE_OPENSSL_X509_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_PEM_H */ @@ -571,7 +585,7 @@ #define HAVE_SIGINTERRUPT 1 /* Define to 1 if you have the signal function. */ -/* #undef HAVE_SIGNAL */ +#define HAVE_SIGNAL 1 /* Define to 1 if you have the header file. */ #define HAVE_SIGNAL_H 1 @@ -591,6 +605,9 @@ /* Define to 1 if you have the socket function. */ #define HAVE_SOCKET 1 +/* Define to 1 if you have the socketpair function. */ +#define HAVE_SOCKETPAIR 1 + /* Define to 1 if you have the header file. */ /* #undef HAVE_SOCKET_H */ @@ -598,7 +615,7 @@ /* #undef HAVE_SPNEGO */ /* Define to 1 if you have the `SSL_get_shutdown' function. */ -/* #undef HAVE_SSL_GET_SHUTDOWN */ +#define HAVE_SSL_GET_SHUTDOWN 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SSL_H */ @@ -621,6 +638,9 @@ /* Define to 1 if you have the strcasestr function. */ #define HAVE_STRCASESTR 1 +/* Define to 1 if you have the strcasestr function. */ +#define HAVE_STRCASESTR 1 + /* Define to 1 if you have the strcmpi function. */ /* #undef HAVE_STRCMPI */ @@ -643,7 +663,7 @@ #define HAVE_STRLCAT 1 /* Define to 1 if you have the `strlcpy' function. */ -/* #undef HAVE_STRLCPY */ +#define HAVE_STRLCPY 1 /* Define to 1 if you have the strncasecmp function. */ #define HAVE_STRNCASECMP 1 @@ -714,6 +734,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_SYS_UTIME_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_WAIT_H 1 + /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_XATTR_H */ @@ -914,22 +937,38 @@ #define SIZEOF_INT 4 /* The size of `long', as computed by sizeof. */ +#ifdef __LP64__ +#define SIZEOF_LONG 8 +#else #define SIZEOF_LONG 4 +#endif /* The size of `off_t', as computed by sizeof. */ +#ifdef __LP64__ +#define SIZEOF_OFF_T 8 +#else #define SIZEOF_OFF_T 4 +#endif /* The size of `short', as computed by sizeof. */ #define SIZEOF_SHORT 2 /* The size of `size_t', as computed by sizeof. */ +#ifdef __LP64__ +#define SIZEOF_SIZE_T 8 +#else #define SIZEOF_SIZE_T 4 +#endif /* The size of `time_t', as computed by sizeof. */ #define SIZEOF_TIME_T 4 /* The size of `void*', as computed by sizeof. */ +#ifdef __LP64__ +#define SIZEOF_VOIDP 8 +#else #define SIZEOF_VOIDP 4 +#endif /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 @@ -965,14 +1004,11 @@ /* #undef USE_OPENLDAP */ /* if OpenSSL is in use */ -#define USE_OPENSSL 1 +/* #define USE_OPENSSL 1 */ /* if PolarSSL is enabled */ /* #undef USE_POLARSSL */ -/* if SSL is enabled */ -#define USE_SSLEAY 1 - /* if you want POSIX threaded DNS lookup */ /* #undef USE_THREADS_POSIX */ @@ -986,9 +1022,6 @@ /* Define to 1 if using yaSSL in OpenSSL compatibility mode. */ /* #undef USE_YASSLEMUL */ -/* Version number of package */ -#define VERSION "7.21.3" - /* Define to avoid automatic inclusion of winsock.h */ /* #undef WIN32_LEAN_AND_MEAN */ diff --git a/project/jni/curl/lib/curl_des.c b/project/jni/curl/lib/curl_des.c new file mode 100644 index 000000000..421c9f768 --- /dev/null +++ b/project/jni/curl/lib/curl_des.c @@ -0,0 +1,63 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2015, Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_NTLM) && !defined(USE_OPENSSL) + +#include "curl_des.h" + +/* + * Curl_des_set_odd_parity() + * + * This is used to apply odd parity to the given byte array. It is typically + * used by when a cryptography engines doesn't have it's own version. + * + * The function is a port of the Java based oddParity() function over at: + * + * http://davenport.sourceforge.net/ntlm.html + * + * Parameters: + * + * bytes [in/out] - The data whose parity bits are to be adjusted for + * odd parity. + * len [out] - The length of the data. + */ +void Curl_des_set_odd_parity(unsigned char *bytes, size_t len) +{ + size_t i; + + for(i = 0; i < len; i++) { + unsigned char b = bytes[i]; + + bool needs_parity = (((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ + (b >> 4) ^ (b >> 3) ^ (b >> 2) ^ + (b >> 1)) & 0x01) == 0; + + if(needs_parity) + bytes[i] |= 0x01; + else + bytes[i] &= 0xfe; + } +} + +#endif /* USE_NTLM && !USE_OPENSSL */ diff --git a/project/jni/curl/lib/curl_des.h b/project/jni/curl/lib/curl_des.h new file mode 100644 index 000000000..129060ff7 --- /dev/null +++ b/project/jni/curl/lib/curl_des.h @@ -0,0 +1,34 @@ +#ifndef HEADER_CURL_DES_H +#define HEADER_CURL_DES_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2015, Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_NTLM) && !defined(USE_OPENSSL) + +/* Applies odd parity to the given byte array */ +void Curl_des_set_odd_parity(unsigned char *bytes, size_t length); + +#endif /* USE_NTLM && !USE_OPENSSL */ + +#endif /* HEADER_CURL_DES_H */ diff --git a/project/jni/curl/lib/curl_endian.c b/project/jni/curl/lib/curl_endian.c new file mode 100644 index 000000000..76deca6aa --- /dev/null +++ b/project/jni/curl/lib/curl_endian.c @@ -0,0 +1,236 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "curl_endian.h" + +/* + * Curl_read16_le() + * + * This function converts a 16-bit integer from the little endian format, as + * used in the incoming package to whatever endian format we're using + * natively. + * + * Parameters: + * + * buf [in] - A pointer to a 2 byte buffer. + * + * Returns the integer. + */ +unsigned short Curl_read16_le(unsigned char *buf) +{ + return (unsigned short)(((unsigned short)buf[0]) | + ((unsigned short)buf[1] << 8)); +} + +/* + * Curl_read32_le() + * + * This function converts a 32-bit integer from the little endian format, as + * used in the incoming package to whatever endian format we're using + * natively. + * + * Parameters: + * + * buf [in] - A pointer to a 4 byte buffer. + * + * Returns the integer. + */ +unsigned int Curl_read32_le(unsigned char *buf) +{ + return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | + ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); +} + +#if (CURL_SIZEOF_CURL_OFF_T > 4) +/* + * Curl_read64_le() + * + * This function converts a 64-bit integer from the little endian format, as + * used in the incoming package to whatever endian format we're using + * natively. + * + * Parameters: + * + * buf [in] - A pointer to a 8 byte buffer. + * + * Returns the integer. + */ +#if defined(HAVE_LONGLONG) +unsigned long long Curl_read64_le(unsigned char *buf) +{ + return ((unsigned long long)buf[0]) | + ((unsigned long long)buf[1] << 8) | + ((unsigned long long)buf[2] << 16) | + ((unsigned long long)buf[3] << 24) | + ((unsigned long long)buf[4] << 32) | + ((unsigned long long)buf[5] << 40) | + ((unsigned long long)buf[6] << 48) | + ((unsigned long long)buf[7] << 56); +} +#else +unsigned __int64 Curl_read64_le(unsigned char *buf) +{ + return ((unsigned __int64)buf[0]) | ((unsigned __int64)buf[1] << 8) | + ((unsigned __int64)buf[2] << 16) | ((unsigned __int64)buf[3] << 24) | + ((unsigned __int64)buf[4] << 32) | ((unsigned __int64)buf[5] << 40) | + ((unsigned __int64)buf[6] << 48) | ((unsigned __int64)buf[7] << 56); +} +#endif + +#endif /* CURL_SIZEOF_CURL_OFF_T > 4 */ + +/* + * Curl_read16_be() + * + * This function converts a 16-bit integer from the big endian format, as + * used in the incoming package to whatever endian format we're using + * natively. + * + * Parameters: + * + * buf [in] - A pointer to a 2 byte buffer. + * + * Returns the integer. + */ +unsigned short Curl_read16_be(unsigned char *buf) +{ + return (unsigned short)(((unsigned short)buf[0] << 8) | + ((unsigned short)buf[1])); +} + +/* + * Curl_read32_be() + * + * This function converts a 32-bit integer from the big endian format, as + * used in the incoming package to whatever endian format we're using + * natively. + * + * Parameters: + * + * buf [in] - A pointer to a 4 byte buffer. + * + * Returns the integer. + */ +unsigned int Curl_read32_be(unsigned char *buf) +{ + return ((unsigned int)buf[0] << 24) | ((unsigned int)buf[1] << 16) | + ((unsigned int)buf[2] << 8) | ((unsigned int)buf[3]); +} + +#if (CURL_SIZEOF_CURL_OFF_T > 4) +/* + * Curl_read64_be() + * + * This function converts a 64-bit integer from the big endian format, as + * used in the incoming package to whatever endian format we're using + * natively. + * + * Parameters: + * + * buf [in] - A pointer to a 8 byte buffer. + * + * Returns the integer. + */ +#if defined(HAVE_LONGLONG) +unsigned long long Curl_read64_be(unsigned char *buf) +{ + return ((unsigned long long)buf[0] << 56) | + ((unsigned long long)buf[1] << 48) | + ((unsigned long long)buf[2] << 40) | + ((unsigned long long)buf[3] << 32) | + ((unsigned long long)buf[4] << 24) | + ((unsigned long long)buf[5] << 16) | + ((unsigned long long)buf[6] << 8) | + ((unsigned long long)buf[7]); +} +#else +unsigned __int64 Curl_read64_be(unsigned char *buf) +{ + return ((unsigned __int64)buf[0] << 56) | ((unsigned __int64)buf[1] << 48) | + ((unsigned __int64)buf[2] << 40) | ((unsigned __int64)buf[3] << 32) | + ((unsigned __int64)buf[4] << 24) | ((unsigned __int64)buf[5] << 16) | + ((unsigned __int64)buf[6] << 8) | ((unsigned __int64)buf[7]); +} +#endif + +#endif /* CURL_SIZEOF_CURL_OFF_T > 4 */ + +/* + * Curl_write16_le() + * + * This function converts a 16-bit integer from the native endian format, + * to little endian format ready for sending down the wire. + * + * Parameters: + * + * value [in] - The 16-bit integer value. + * buffer [in] - A pointer to the output buffer. + */ +void Curl_write16_le(const short value, unsigned char *buffer) +{ + buffer[0] = (char)(value & 0x00FF); + buffer[1] = (char)((value & 0xFF00) >> 8); +} + +/* + * Curl_write32_le() + * + * This function converts a 32-bit integer from the native endian format, + * to little endian format ready for sending down the wire. + * + * Parameters: + * + * value [in] - The 32-bit integer value. + * buffer [in] - A pointer to the output buffer. + */ +void Curl_write32_le(const int value, unsigned char *buffer) +{ + buffer[0] = (char)(value & 0x000000FF); + buffer[1] = (char)((value & 0x0000FF00) >> 8); + buffer[2] = (char)((value & 0x00FF0000) >> 16); + buffer[3] = (char)((value & 0xFF000000) >> 24); +} + +#if (CURL_SIZEOF_CURL_OFF_T > 4) +/* + * Curl_write64_le() + * + * This function converts a 64-bit integer from the native endian format, + * to little endian format ready for sending down the wire. + * + * Parameters: + * + * value [in] - The 64-bit integer value. + * buffer [in] - A pointer to the output buffer. + */ +#if defined(HAVE_LONGLONG) +void Curl_write64_le(const long long value, unsigned char *buffer) +#else +void Curl_write64_le(const __int64 value, unsigned char *buffer) +#endif +{ + Curl_write32_le((int)value, buffer); + Curl_write32_le((int)(value >> 32), buffer + 4); +} +#endif /* CURL_SIZEOF_CURL_OFF_T > 4 */ diff --git a/project/jni/curl/lib/curl_endian.h b/project/jni/curl/lib/curl_endian.h new file mode 100644 index 000000000..df8398c8c --- /dev/null +++ b/project/jni/curl/lib/curl_endian.h @@ -0,0 +1,70 @@ +#ifndef HEADER_CURL_ENDIAN_H +#define HEADER_CURL_ENDIAN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* Converts a 16-bit integer from little endian */ +unsigned short Curl_read16_le(unsigned char *buf); + +/* Converts a 32-bit integer from little endian */ +unsigned int Curl_read32_le(unsigned char *buf); + +#if (CURL_SIZEOF_CURL_OFF_T > 4) +/* Converts a 64-bit integer from little endian */ +#if defined(HAVE_LONGLONG) +unsigned long long Curl_read64_le(unsigned char *buf); +#else +unsigned __int64 Curl_read64_le(unsigned char *buf); +#endif +#endif + +/* Converts a 16-bit integer from big endian */ +unsigned short Curl_read16_be(unsigned char *buf); + +/* Converts a 32-bit integer from big endian */ +unsigned int Curl_read32_be(unsigned char *buf); + +#if (CURL_SIZEOF_CURL_OFF_T > 4) +/* Converts a 64-bit integer from big endian */ +#if defined(HAVE_LONGLONG) +unsigned long long Curl_read64_be(unsigned char *buf); +#else +unsigned __int64 Curl_read64_be(unsigned char *buf); +#endif +#endif + +/* Converts a 16-bit integer to little endian */ +void Curl_write16_le(const short value, unsigned char *buffer); + +/* Converts a 32-bit integer to little endian */ +void Curl_write32_le(const int value, unsigned char *buffer); + +#if (CURL_SIZEOF_CURL_OFF_T > 4) +/* Converts a 64-bit integer to little endian */ +#if defined(HAVE_LONGLONG) +void Curl_write64_le(const long long value, unsigned char *buffer); +#else +void Curl_write64_le(const __int64 value, unsigned char *buffer); +#endif +#endif + +#endif /* HEADER_CURL_ENDIAN_H */ diff --git a/project/jni/curl/lib/curl_fnmatch.c b/project/jni/curl/lib/curl_fnmatch.c index ad4ec1871..53240078a 100644 --- a/project/jni/curl/lib/curl_fnmatch.c +++ b/project/jni/curl/lib/curl_fnmatch.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,14 +20,11 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #include "curl_fnmatch.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" @@ -317,7 +314,7 @@ static int loop(const unsigned char *pattern, const unsigned char *string) unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 }; int rc = 0; - for (;;) { + for(;;) { switch(state) { case CURLFNM_LOOP_DEFAULT: if(*p == '*') { @@ -413,6 +410,9 @@ static int loop(const unsigned char *pattern, const unsigned char *string) } } +/* + * @unittest: 1307 + */ int Curl_fnmatch(void *ptr, const char *pattern, const char *string) { (void)ptr; /* the argument is specified by the curl_fnmatch_callback diff --git a/project/jni/curl/lib/curl_fnmatch.h b/project/jni/curl/lib/curl_fnmatch.h index 6335d0312..69ffe392f 100644 --- a/project/jni/curl/lib/curl_fnmatch.h +++ b/project/jni/curl/lib/curl_fnmatch.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/project/jni/curl/lib/curl_gethostname.c b/project/jni/curl/lib/curl_gethostname.c index 7f0bfed54..2591fd886 100644 --- a/project/jni/curl/lib/curl_gethostname.c +++ b/project/jni/curl/lib/curl_gethostname.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,11 +20,7 @@ * ***************************************************************************/ -#include "setup.h" - -#ifdef HAVE_UNISTD_H -# include -#endif +#include "curl_setup.h" #include "curl_gethostname.h" @@ -32,12 +28,16 @@ * Curl_gethostname() is a wrapper around gethostname() which allows * overriding the host name that the function would normally return. * This capability is used by the test suite to verify exact matching - * of NTLM authentication, which exercises libcurl's MD4 and DES code. + * of NTLM authentication, which exercises libcurl's MD4 and DES code + * as well as by the SMTP module when a hostname is not provided. * * For libcurl debug enabled builds host name overriding takes place * when environment variable CURL_GETHOSTNAME is set, using the value * held by the variable to override returned host name. * + * Note: The function always returns the un-qualified hostname rather + * than being provider dependent. + * * For libcurl shared library release builds the test suite preloads * another shared library named libhostname using the LD_PRELOAD * mechanism which intercepts, and might override, the gethostname() @@ -58,6 +58,8 @@ int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen) { return -1; #else + int err; + char* dot; #ifdef DEBUGBUILD @@ -65,17 +67,34 @@ int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen) { const char *force_hostname = getenv("CURL_GETHOSTNAME"); if(force_hostname) { strncpy(name, force_hostname, namelen); - name[namelen-1] = '\0'; - return 0; + err = 0; + } + else { + name[0] = '\0'; + err = gethostname(name, namelen); } -#endif /* DEBUGBUILD */ +#else /* DEBUGBUILD */ /* The call to system's gethostname() might get intercepted by the libhostname library when libcurl is built as a non-debug shared library when running the test suite. */ - return gethostname(name, namelen); + name[0] = '\0'; + err = gethostname(name, namelen); #endif + name[namelen - 1] = '\0'; + + if(err) + return err; + + /* Truncate domain, leave only machine name */ + dot = strchr(name, '.'); + if(dot) + *dot = '\0'; + + return 0; +#endif + } diff --git a/project/jni/curl/lib/curl_gethostname.h b/project/jni/curl/lib/curl_gethostname.h index b8ecf88d6..07517c535 100644 --- a/project/jni/curl/lib/curl_gethostname.h +++ b/project/jni/curl/lib/curl_gethostname.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,6 +22,10 @@ * ***************************************************************************/ +/* Hostname buffer size */ +#define HOSTNAME_MAX 1024 + +/* This returns the local machine's un-qualified hostname */ int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen); #endif /* HEADER_CURL_GETHOSTNAME_H */ diff --git a/project/jni/curl/lib/curl_gssapi.c b/project/jni/curl/lib/curl_gssapi.c new file mode 100644 index 000000000..75af67036 --- /dev/null +++ b/project/jni/curl/lib/curl_gssapi.c @@ -0,0 +1,120 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2011 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_GSSAPI + +#include "curl_gssapi.h" +#include "sendf.h" + +static char spnego_oid_bytes[] = "\x2b\x06\x01\x05\x05\x02"; +gss_OID_desc Curl_spnego_mech_oid = { 6, &spnego_oid_bytes }; +static char krb5_oid_bytes[] = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"; +gss_OID_desc Curl_krb5_mech_oid = { 9, &krb5_oid_bytes }; + +OM_uint32 Curl_gss_init_sec_context( + struct SessionHandle *data, + OM_uint32 *minor_status, + gss_ctx_id_t *context, + gss_name_t target_name, + gss_OID mech_type, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_buffer_t output_token, + const bool mutual_auth, + OM_uint32 *ret_flags) +{ + OM_uint32 req_flags = GSS_C_REPLAY_FLAG; + + if(mutual_auth) + req_flags |= GSS_C_MUTUAL_FLAG; + + if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_POLICY_FLAG) { +#ifdef GSS_C_DELEG_POLICY_FLAG + req_flags |= GSS_C_DELEG_POLICY_FLAG; +#else + infof(data, "warning: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not " + "compiled in\n"); +#endif + } + + if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_FLAG) + req_flags |= GSS_C_DELEG_FLAG; + + return gss_init_sec_context(minor_status, + GSS_C_NO_CREDENTIAL, /* cred_handle */ + context, + target_name, + mech_type, + req_flags, + 0, /* time_req */ + input_chan_bindings, + input_token, + NULL, /* actual_mech_type */ + output_token, + ret_flags, + NULL /* time_rec */); +} + +/* + * Curl_gss_log_error() + * + * This is used to log a GSS-API error status. + * + * Parameters: + * + * data [in] - The session handle. + * status [in] - The status code. + * prefix [in] - The prefix of the log message. + */ +void Curl_gss_log_error(struct SessionHandle *data, OM_uint32 status, + const char *prefix) +{ + OM_uint32 maj_stat; + OM_uint32 min_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc status_string; + char buf[1024]; + size_t len; + + snprintf(buf, sizeof(buf), "%s", prefix); + len = strlen(buf); + do { + maj_stat = gss_display_status(&min_stat, + status, + GSS_C_MECH_CODE, + GSS_C_NO_OID, + &msg_ctx, + &status_string); + if(sizeof(buf) > len + status_string.length + 1) { + snprintf(buf + len, sizeof(buf) - len, + ": %s", (char*)status_string.value); + len += status_string.length; + } + gss_release_buffer(&min_stat, &status_string); + } while(!GSS_ERROR(maj_stat) && msg_ctx != 0); + + infof(data, "%s\n", buf); +} + +#endif /* HAVE_GSSAPI */ diff --git a/project/jni/curl/lib/curl_gssapi.h b/project/jni/curl/lib/curl_gssapi.h new file mode 100644 index 000000000..c1642a8b6 --- /dev/null +++ b/project/jni/curl/lib/curl_gssapi.h @@ -0,0 +1,75 @@ +#ifndef HEADER_CURL_GSSAPI_H +#define HEADER_CURL_GSSAPI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2011 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "urldata.h" + +#ifdef HAVE_GSSAPI + +#ifdef HAVE_GSSGNU +# include +#elif defined HAVE_GSSMIT + /* MIT style */ +# include +# include +# include +#else + /* Heimdal-style */ +# include +#endif + +extern gss_OID_desc Curl_spnego_mech_oid; +extern gss_OID_desc Curl_krb5_mech_oid; + +/* Common method for using GSS-API */ +OM_uint32 Curl_gss_init_sec_context( + struct SessionHandle *data, + OM_uint32 *minor_status, + gss_ctx_id_t *context, + gss_name_t target_name, + gss_OID mech_type, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_buffer_t output_token, + const bool mutual_auth, + OM_uint32 *ret_flags); + +/* Helper to log a GSS-API error status */ +void Curl_gss_log_error(struct SessionHandle *data, OM_uint32 status, + const char *prefix); + +/* Provide some definitions missing in old headers */ +#ifdef HAVE_OLD_GSSMIT +#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name +#define NCOMPAT 1 +#endif + +/* Define our privacy and integrity protection values */ +#define GSSAUTH_P_NONE 1 +#define GSSAUTH_P_INTEGRITY 2 +#define GSSAUTH_P_PRIVACY 4 + +#endif /* HAVE_GSSAPI */ + +#endif /* HEADER_CURL_GSSAPI_H */ diff --git a/project/jni/curl/lib/curl_hmac.h b/project/jni/curl/lib/curl_hmac.h index 9b65c8c2a..41703b42f 100644 --- a/project/jni/curl/lib/curl_hmac.h +++ b/project/jni/curl/lib/curl_hmac.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/project/jni/curl/lib/curl_ldap.h b/project/jni/curl/lib/curl_ldap.h index 3cce4bf7b..27d03810f 100644 --- a/project/jni/curl/lib/curl_ldap.h +++ b/project/jni/curl/lib/curl_ldap.h @@ -1,6 +1,5 @@ -#ifndef __CURL_LDAP_H -#define __CURL_LDAP_H - +#ifndef HEADER_CURL_LDAP_H +#define HEADER_CURL_LDAP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -12,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -25,10 +24,12 @@ #ifndef CURL_DISABLE_LDAP extern const struct Curl_handler Curl_handler_ldap; -#if (defined(USE_OPENLDAP) && defined(USE_SSL)) || \ - (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)) +#if !defined(CURL_DISABLE_LDAPS) && \ + ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \ + (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL))) extern const struct Curl_handler Curl_handler_ldaps; #endif #endif -#endif /* __CURL_LDAP_H */ +#endif /* HEADER_CURL_LDAP_H */ + diff --git a/project/jni/curl/lib/curl_md4.h b/project/jni/curl/lib/curl_md4.h index 6b6c16e13..8c26d1222 100644 --- a/project/jni/curl/lib/curl_md4.h +++ b/project/jni/curl/lib/curl_md4.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,12 +22,14 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" + +/* NSS and OS/400 crypto library do not provide the MD4 hash algorithm, so + * that we have a local implementation of it */ +#if defined(USE_NSS) || defined(USE_OS400CRYPTO) -/* NSS crypto library does not provide the MD4 hash algorithm, so that we have - * a local implementation of it */ -#ifdef USE_NSS void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len); -#endif /* USE_NSS */ + +#endif /* defined(USE_NSS) || defined(USE_OS400CRYPTO) */ #endif /* HEADER_CURL_MD4_H */ diff --git a/project/jni/curl/lib/curl_md5.h b/project/jni/curl/lib/curl_md5.h index ddc61e3e5..5f70c9634 100644 --- a/project/jni/curl/lib/curl_md5.h +++ b/project/jni/curl/lib/curl_md5.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -25,10 +25,39 @@ #ifndef CURL_DISABLE_CRYPTO_AUTH #include "curl_hmac.h" +#define MD5_DIGEST_LEN 16 + +typedef void (* Curl_MD5_init_func)(void *context); +typedef void (* Curl_MD5_update_func)(void *context, + const unsigned char *data, + unsigned int len); +typedef void (* Curl_MD5_final_func)(unsigned char *result, void *context); + +typedef struct { + Curl_MD5_init_func md5_init_func; /* Initialize context procedure */ + Curl_MD5_update_func md5_update_func; /* Update context with data */ + Curl_MD5_final_func md5_final_func; /* Get final result procedure */ + unsigned int md5_ctxtsize; /* Context structure size */ + unsigned int md5_resultlen; /* Result length (bytes) */ +} MD5_params; + +typedef struct { + const MD5_params *md5_hash; /* Hash function definition */ + void *md5_hashctx; /* Hash function context */ +} MD5_context; + +extern const MD5_params Curl_DIGEST_MD5[1]; extern const HMAC_params Curl_HMAC_MD5[1]; void Curl_md5it(unsigned char *output, const unsigned char *input); + +MD5_context * Curl_MD5_init(const MD5_params *md5params); +int Curl_MD5_update(MD5_context *context, + const unsigned char *data, + unsigned int len); +int Curl_MD5_final(MD5_context *context, unsigned char *result); + #endif #endif /* HEADER_CURL_MD5_H */ diff --git a/project/jni/curl/lib/curl_memory.h b/project/jni/curl/lib/curl_memory.h index e11945823..fcd177cd5 100644 --- a/project/jni/curl/lib/curl_memory.h +++ b/project/jni/curl/lib/curl_memory.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,17 +22,89 @@ * ***************************************************************************/ -#include /* for the typedefs */ +/* + * Nasty internal details ahead... + * + * File curl_memory.h must be included by _all_ *.c source files + * that use memory related functions strdup, malloc, calloc, realloc + * or free, and given source file is used to build libcurl library. + * It should be included immediately before memdebug.h as the last files + * included to avoid undesired interaction with other memory function + * headers in dependent libraries. + * + * There is nearly no exception to above rule. All libcurl source + * files in 'lib' subdirectory as well as those living deep inside + * 'packages' subdirectories and linked together in order to build + * libcurl library shall follow it. + * + * File lib/strdup.c is an exception, given that it provides a strdup + * clone implementation while using malloc. Extra care needed inside + * this one. TODO: revisit this paragraph and related code. + * + * The need for curl_memory.h inclusion is due to libcurl's feature + * of allowing library user to provide memory replacement functions, + * memory callbacks, at runtime with curl_global_init_mem() + * + * Any *.c source file used to build libcurl library that does not + * include curl_memory.h and uses any memory function of the five + * mentioned above will compile without any indication, but it will + * trigger weird memory related issues at runtime. + * + * OTOH some source files from 'lib' subdirectory may additionally be + * used directly as source code when using some curlx_ functions by + * third party programs that don't even use libcurl at all. When using + * these source files in this way it is necessary these are compiled + * with CURLX_NO_MEMORY_CALLBACKS defined, in order to ensure that no + * attempt of calling libcurl's memory callbacks is done from code + * which can not use this machinery. + * + * Notice that libcurl's 'memory tracking' system works chaining into + * the memory callback machinery. This implies that when compiling + * 'lib' source files with CURLX_NO_MEMORY_CALLBACKS defined this file + * disengages usage of libcurl's 'memory tracking' system, defining + * MEMDEBUG_NODEFINES and overriding CURLDEBUG purpose. + * + * CURLX_NO_MEMORY_CALLBACKS takes precedence over CURLDEBUG. This is + * done in order to allow building a 'memory tracking' enabled libcurl + * and at the same time allow building programs which do not use it. + * + * Programs and libraries in 'tests' subdirectories have specific + * purposes and needs, and as such each one will use whatever fits + * best, depending additionally wether it links with libcurl or not. + * + * Caveat emptor. Proper curlx_* separation is a work in progress + * the same as CURLX_NO_MEMORY_CALLBACKS usage, some adjustments may + * still be required. IOW don't use them yet, there are sharp edges. + */ + +#ifdef HEADER_CURL_MEMDEBUG_H +#error "Header memdebug.h shall not be included before curl_memory.h" +#endif + +#ifndef CURLX_NO_MEMORY_CALLBACKS + +#include /* for the callback typedefs */ extern curl_malloc_callback Curl_cmalloc; extern curl_free_callback Curl_cfree; extern curl_realloc_callback Curl_crealloc; extern curl_strdup_callback Curl_cstrdup; extern curl_calloc_callback Curl_ccalloc; +#if defined(WIN32) && defined(UNICODE) +extern curl_wcsdup_callback Curl_cwcsdup; +#endif #ifndef CURLDEBUG -/* Only do this define-mania if we're not using the memdebug system, as that - has preference on this magic. */ + +/* + * libcurl's 'memory tracking' system defines strdup, malloc, calloc, + * realloc and free, along with others, in memdebug.h in a different + * way although still using memory callbacks forward declared above. + * When using the 'memory tracking' system (CURLDEBUG defined) we do + * not define here the five memory functions given that definitions + * from memdebug.h are the ones that shall be used. + */ + #undef strdup #define strdup(ptr) Curl_cstrdup(ptr) #undef malloc @@ -44,6 +116,28 @@ extern curl_calloc_callback Curl_ccalloc; #undef free #define free(ptr) Curl_cfree(ptr) +#ifdef WIN32 +# ifdef UNICODE +# undef wcsdup +# define wcsdup(ptr) Curl_cwcsdup(ptr) +# undef _wcsdup +# define _wcsdup(ptr) Curl_cwcsdup(ptr) +# undef _tcsdup +# define _tcsdup(ptr) Curl_cwcsdup(ptr) +# else +# undef _tcsdup +# define _tcsdup(ptr) Curl_cstrdup(ptr) +# endif #endif +#endif /* CURLDEBUG */ + +#else /* CURLX_NO_MEMORY_CALLBACKS */ + +#ifndef MEMDEBUG_NODEFINES +#define MEMDEBUG_NODEFINES +#endif + +#endif /* CURLX_NO_MEMORY_CALLBACKS */ + #endif /* HEADER_CURL_MEMORY_H */ diff --git a/project/jni/curl/lib/curl_memrchr.c b/project/jni/curl/lib/curl_memrchr.c index a1e2bf0e5..1be27e5c8 100644 --- a/project/jni/curl/lib/curl_memrchr.c +++ b/project/jni/curl/lib/curl_memrchr.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,14 +20,10 @@ * ***************************************************************************/ -#include "setup.h" - +#include "curl_setup.h" #include "curl_memrchr.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" @@ -50,8 +46,8 @@ Curl_memrchr(const void *s, int c, size_t n) p += n - 1; - while (p >= q) { - if (*p == (unsigned char)c) + while(p >= q) { + if(*p == (unsigned char)c) return (void *)p; p--; } diff --git a/project/jni/curl/lib/curl_memrchr.h b/project/jni/curl/lib/curl_memrchr.h index 37061b608..747509c45 100644 --- a/project/jni/curl/lib/curl_memrchr.h +++ b/project/jni/curl/lib/curl_memrchr.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,7 +22,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifdef HAVE_MEMRCHR diff --git a/project/jni/curl/lib/curl_multibyte.c b/project/jni/curl/lib/curl_multibyte.c new file mode 100644 index 000000000..e2078e05a --- /dev/null +++ b/project/jni/curl/lib/curl_multibyte.c @@ -0,0 +1,82 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \ + defined(USE_WIN32_LDAP)) && defined(UNICODE)) + + /* + * MultiByte conversions using Windows kernel32 library. + */ + +#include "curl_multibyte.h" +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8) +{ + wchar_t *str_w = NULL; + + if(str_utf8) { + int str_w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + str_utf8, -1, NULL, 0); + if(str_w_len > 0) { + str_w = malloc(str_w_len * sizeof(wchar_t)); + if(str_w) { + if(MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_w, + str_w_len) == 0) { + free(str_w); + return NULL; + } + } + } + } + + return str_w; +} + +char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w) +{ + char *str_utf8 = NULL; + + if(str_w) { + int str_utf8_len = WideCharToMultiByte(CP_UTF8, 0, str_w, -1, NULL, + 0, NULL, NULL); + if(str_utf8_len > 0) { + str_utf8 = malloc(str_utf8_len * sizeof(wchar_t)); + if(str_utf8) { + if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, str_utf8_len, + NULL, FALSE) == 0) { + free(str_utf8); + return NULL; + } + } + } + } + + return str_utf8; +} + +#endif /* USE_WIN32_IDN || ((USE_WINDOWS_SSPI || USE_WIN32_LDAP) && UNICODE) */ diff --git a/project/jni/curl/lib/curl_multibyte.h b/project/jni/curl/lib/curl_multibyte.h new file mode 100644 index 000000000..615f5c086 --- /dev/null +++ b/project/jni/curl/lib/curl_multibyte.h @@ -0,0 +1,92 @@ +#ifndef HEADER_CURL_MULTIBYTE_H +#define HEADER_CURL_MULTIBYTE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curl_setup.h" + +#if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \ + defined(USE_WIN32_LDAP)) && defined(UNICODE)) + + /* + * MultiByte conversions using Windows kernel32 library. + */ + +wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8); +char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w); + +#endif /* USE_WIN32_IDN || ((USE_WINDOWS_SSPI || USE_WIN32_LDAP) && UNICODE) */ + + +#if defined(USE_WIN32_IDN) || defined(USE_WINDOWS_SSPI) || \ + defined(USE_WIN32_LDAP) + +/* + * Macros Curl_convert_UTF8_to_tchar(), Curl_convert_tchar_to_UTF8() + * and Curl_unicodefree() main purpose is to minimize the number of + * preprocessor conditional directives needed by code using these + * to differentiate UNICODE from non-UNICODE builds. + * + * When building with UNICODE defined, this two macros + * Curl_convert_UTF8_to_tchar() and Curl_convert_tchar_to_UTF8() + * return a pointer to a newly allocated memory area holding result. + * When the result is no longer needed, allocated memory is intended + * to be free'ed with Curl_unicodefree(). + * + * When building without UNICODE defined, this macros + * Curl_convert_UTF8_to_tchar() and Curl_convert_tchar_to_UTF8() + * return the pointer received as argument. Curl_unicodefree() does + * no actual free'ing of this pointer it is simply set to NULL. + */ + +#ifdef UNICODE + +#define Curl_convert_UTF8_to_tchar(ptr) Curl_convert_UTF8_to_wchar((ptr)) +#define Curl_convert_tchar_to_UTF8(ptr) Curl_convert_wchar_to_UTF8((ptr)) +#define Curl_unicodefree(ptr) \ + do {if((ptr)) {free((ptr)); (ptr) = NULL;}} WHILE_FALSE + +typedef union { + unsigned short *tchar_ptr; + const unsigned short *const_tchar_ptr; + unsigned short *tbyte_ptr; + const unsigned short *const_tbyte_ptr; +} xcharp_u; + +#else + +#define Curl_convert_UTF8_to_tchar(ptr) (ptr) +#define Curl_convert_tchar_to_UTF8(ptr) (ptr) +#define Curl_unicodefree(ptr) \ + do {(ptr) = NULL;} WHILE_FALSE + +typedef union { + char *tchar_ptr; + const char *const_tchar_ptr; + unsigned char *tbyte_ptr; + const unsigned char *const_tbyte_ptr; +} xcharp_u; + +#endif /* UNICODE */ + +#endif /* USE_WIN32_IDN || USE_WINDOWS_SSPI || USE_WIN32_LDAP */ + +#endif /* HEADER_CURL_MULTIBYTE_H */ diff --git a/project/jni/curl/lib/curl_ntlm.c b/project/jni/curl/lib/curl_ntlm.c new file mode 100644 index 000000000..d4842e468 --- /dev/null +++ b/project/jni/curl/lib/curl_ntlm.c @@ -0,0 +1,239 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) + +/* + * NTLM details: + * + * http://davenport.sourceforge.net/ntlm.html + * http://www.innovation.ch/java/ntlm.html + */ + +#define DEBUG_ME 0 + +#include "urldata.h" +#include "sendf.h" +#include "rawstr.h" +#include "curl_ntlm.h" +#include "curl_ntlm_msgs.h" +#include "curl_ntlm_wb.h" +#include "curl_sasl.h" +#include "url.h" +#include "curl_printf.h" + +#if defined(USE_NSS) +#include "vtls/nssg.h" +#elif defined(USE_WINDOWS_SSPI) +#include "curl_sspi.h" +#endif + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#if DEBUG_ME +# define DEBUG_OUT(x) x +#else +# define DEBUG_OUT(x) Curl_nop_stmt +#endif + +CURLcode Curl_input_ntlm(struct connectdata *conn, + bool proxy, /* if proxy or not */ + const char *header) /* rest of the www-authenticate: + header */ +{ + /* point to the correct struct with this */ + struct ntlmdata *ntlm; + CURLcode result = CURLE_OK; + + ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; + + if(checkprefix("NTLM", header)) { + header += strlen("NTLM"); + + while(*header && ISSPACE(*header)) + header++; + + if(*header) { + result = Curl_sasl_decode_ntlm_type2_message(conn->data, header, ntlm); + if(result) + return result; + + ntlm->state = NTLMSTATE_TYPE2; /* We got a type-2 message */ + } + else { + if(ntlm->state == NTLMSTATE_LAST) { + infof(conn->data, "NTLM auth restarted\n"); + Curl_http_ntlm_cleanup(conn); + } + else if(ntlm->state == NTLMSTATE_TYPE3) { + infof(conn->data, "NTLM handshake rejected\n"); + Curl_http_ntlm_cleanup(conn); + ntlm->state = NTLMSTATE_NONE; + return CURLE_REMOTE_ACCESS_DENIED; + } + else if(ntlm->state >= NTLMSTATE_TYPE1) { + infof(conn->data, "NTLM handshake failure (internal error)\n"); + return CURLE_REMOTE_ACCESS_DENIED; + } + + ntlm->state = NTLMSTATE_TYPE1; /* We should send away a type-1 */ + } + } + + return result; +} + +/* + * This is for creating ntlm header output + */ +CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) +{ + char *base64 = NULL; + size_t len = 0; + CURLcode result; + + /* point to the address of the pointer that holds the string to send to the + server, which is for a plain host or for a HTTP proxy */ + char **allocuserpwd; + + /* point to the name and password for this */ + const char *userp; + const char *passwdp; + + /* point to the correct struct with this */ + struct ntlmdata *ntlm; + struct auth *authp; + + DEBUGASSERT(conn); + DEBUGASSERT(conn->data); + +#ifdef USE_NSS + if(CURLE_OK != Curl_nss_force_init(conn->data)) + return CURLE_OUT_OF_MEMORY; +#endif + + if(proxy) { + allocuserpwd = &conn->allocptr.proxyuserpwd; + userp = conn->proxyuser; + passwdp = conn->proxypasswd; + ntlm = &conn->proxyntlm; + authp = &conn->data->state.authproxy; + } + else { + allocuserpwd = &conn->allocptr.userpwd; + userp = conn->user; + passwdp = conn->passwd; + ntlm = &conn->ntlm; + authp = &conn->data->state.authhost; + } + authp->done = FALSE; + + /* not set means empty */ + if(!userp) + userp = ""; + + if(!passwdp) + passwdp = ""; + +#ifdef USE_WINDOWS_SSPI + if(s_hSecDll == NULL) { + /* not thread safe and leaks - use curl_global_init() to avoid */ + CURLcode err = Curl_sspi_global_init(); + if(s_hSecDll == NULL) + return err; + } +#endif + + switch(ntlm->state) { + case NTLMSTATE_TYPE1: + default: /* for the weird cases we (re)start here */ + /* Create a type-1 message */ + result = Curl_sasl_create_ntlm_type1_message(userp, passwdp, ntlm, &base64, + &len); + if(result) + return result; + + if(base64) { + free(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", + proxy ? "Proxy-" : "", + base64); + free(base64); + if(!*allocuserpwd) + return CURLE_OUT_OF_MEMORY; + + DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); + } + break; + + case NTLMSTATE_TYPE2: + /* We already received the type-2 message, create a type-3 message */ + result = Curl_sasl_create_ntlm_type3_message(conn->data, userp, passwdp, + ntlm, &base64, &len); + if(result) + return result; + + if(base64) { + free(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", + proxy ? "Proxy-" : "", + base64); + free(base64); + if(!*allocuserpwd) + return CURLE_OUT_OF_MEMORY; + + DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); + + ntlm->state = NTLMSTATE_TYPE3; /* we send a type-3 */ + authp->done = TRUE; + } + break; + + case NTLMSTATE_TYPE3: + /* connection is already authenticated, + * don't send a header in future requests */ + ntlm->state = NTLMSTATE_LAST; + /* fall-through */ + case NTLMSTATE_LAST: + Curl_safefree(*allocuserpwd); + authp->done = TRUE; + break; + } + + return CURLE_OK; +} + +void Curl_http_ntlm_cleanup(struct connectdata *conn) +{ + Curl_sasl_ntlm_cleanup(&conn->ntlm); + Curl_sasl_ntlm_cleanup(&conn->proxyntlm); + +#if defined(NTLM_WB_ENABLED) + Curl_ntlm_wb_cleanup(conn); +#endif +} + +#endif /* !CURL_DISABLE_HTTP && USE_NTLM */ diff --git a/project/jni/curl/lib/curl_ntlm.h b/project/jni/curl/lib/curl_ntlm.h new file mode 100644 index 000000000..d186bbe37 --- /dev/null +++ b/project/jni/curl/lib/curl_ntlm.h @@ -0,0 +1,40 @@ +#ifndef HEADER_CURL_NTLM_H +#define HEADER_CURL_NTLM_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) + +/* this is for ntlm header input */ +CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy, + const char *header); + +/* this is for creating ntlm header output */ +CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy); + +void Curl_http_ntlm_cleanup(struct connectdata *conn); + +#endif /* !CURL_DISABLE_HTTP && USE_NTLM */ + +#endif /* HEADER_CURL_NTLM_H */ diff --git a/project/jni/curl/lib/curl_ntlm_core.c b/project/jni/curl/lib/curl_ntlm_core.c new file mode 100644 index 000000000..e79d1f64f --- /dev/null +++ b/project/jni/curl/lib/curl_ntlm_core.c @@ -0,0 +1,762 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_NTLM) + +/* + * NTLM details: + * + * http://davenport.sourceforge.net/ntlm.html + * http://www.innovation.ch/java/ntlm.html + */ + +#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) + +#ifdef USE_OPENSSL + +# ifdef USE_OPENSSL +# include +# ifndef OPENSSL_NO_MD4 +# include +# endif +# include +# include +# include +# else +# include +# ifndef OPENSSL_NO_MD4 +# include +# endif +# include +# include +# include +# endif +# if (OPENSSL_VERSION_NUMBER < 0x00907001L) +# define DES_key_schedule des_key_schedule +# define DES_cblock des_cblock +# define DES_set_odd_parity des_set_odd_parity +# define DES_set_key des_set_key +# define DES_ecb_encrypt des_ecb_encrypt +# define DESKEY(x) x +# define DESKEYARG(x) x +# else +# define DESKEYARG(x) *x +# define DESKEY(x) &x +# endif + +#elif defined(USE_GNUTLS_NETTLE) + +# include +# include + +#elif defined(USE_GNUTLS) + +# include +# define MD5_DIGEST_LENGTH 16 +# define MD4_DIGEST_LENGTH 16 + +#elif defined(USE_NSS) + +# include +# include +# include +# include "curl_md4.h" +# define MD5_DIGEST_LENGTH MD5_LENGTH + +#elif defined(USE_DARWINSSL) + +# include +# include + +#elif defined(USE_OS400CRYPTO) +# include "cipher.mih" /* mih/cipher */ +# include "curl_md4.h" +#elif defined(USE_WIN32_CRYPTO) +# include +#else +# error "Can't compile NTLM support without a crypto library." +#endif + +#include "urldata.h" +#include "non-ascii.h" +#include "rawstr.h" +#include "curl_ntlm_core.h" +#include "curl_md5.h" +#include "curl_hmac.h" +#include "warnless.h" +#include "curl_endian.h" +#include "curl_des.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#define NTLM_HMAC_MD5_LEN (16) +#define NTLMv2_BLOB_SIGNATURE "\x01\x01\x00\x00" +#define NTLMv2_BLOB_LEN (44 -16 + ntlm->target_info_len + 4) + +/* +* Turns a 56-bit key into being 64-bit wide. +*/ +static void extend_key_56_to_64(const unsigned char *key_56, char *key) +{ + key[0] = key_56[0]; + key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1)); + key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2)); + key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3)); + key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4)); + key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5)); + key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6)); + key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF); +} + +#ifdef USE_OPENSSL +/* + * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The + * key schedule ks is also set. + */ +static void setup_des_key(const unsigned char *key_56, + DES_key_schedule DESKEYARG(ks)) +{ + DES_cblock key; + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, (char *) &key); + + /* Set the key parity to odd */ + DES_set_odd_parity(&key); + + /* Set the key */ + DES_set_key(&key, ks); +} + +#elif defined(USE_GNUTLS_NETTLE) + +static void setup_des_key(const unsigned char *key_56, + struct des_ctx *des) +{ + char key[8]; + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, key); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); + + /* Set the key */ + des_set_key(des, (const uint8_t *) key); +} + +#elif defined(USE_GNUTLS) + +/* + * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. + */ +static void setup_des_key(const unsigned char *key_56, + gcry_cipher_hd_t *des) +{ + char key[8]; + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, key); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); + + /* Set the key */ + gcry_cipher_setkey(*des, key, sizeof(key)); +} + +#elif defined(USE_NSS) + +/* + * Expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of data, using + * the expanded key. The caller is responsible for giving 64 bit of valid + * data is IN and (at least) 64 bit large buffer as OUT. + */ +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + const CK_MECHANISM_TYPE mech = CKM_DES_ECB; /* DES cipher in ECB mode */ + PK11SlotInfo *slot = NULL; + char key[8]; /* expanded 64 bit key */ + SECItem key_item; + PK11SymKey *symkey = NULL; + SECItem *param = NULL; + PK11Context *ctx = NULL; + int out_len; /* not used, required by NSS */ + bool rv = FALSE; + + /* use internal slot for DES encryption (requires NSS to be initialized) */ + slot = PK11_GetInternalKeySlot(); + if(!slot) + return FALSE; + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, key); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); + + /* Import the key */ + key_item.data = (unsigned char *)key; + key_item.len = sizeof(key); + symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_ENCRYPT, + &key_item, NULL); + if(!symkey) + goto fail; + + /* Create the DES encryption context */ + param = PK11_ParamFromIV(mech, /* no IV in ECB mode */ NULL); + if(!param) + goto fail; + ctx = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, symkey, param); + if(!ctx) + goto fail; + + /* Perform the encryption */ + if(SECSuccess == PK11_CipherOp(ctx, out, &out_len, /* outbuflen */ 8, + (unsigned char *)in, /* inbuflen */ 8) + && SECSuccess == PK11_Finalize(ctx)) + rv = /* all OK */ TRUE; + +fail: + /* cleanup */ + if(ctx) + PK11_DestroyContext(ctx, PR_TRUE); + if(symkey) + PK11_FreeSymKey(symkey); + if(param) + SECITEM_FreeItem(param, PR_TRUE); + PK11_FreeSlot(slot); + return rv; +} + +#elif defined(USE_DARWINSSL) + +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + char key[8]; + size_t out_len; + CCCryptorStatus err; + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, key); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); + + /* Perform the encryption */ + err = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key, + kCCKeySizeDES, NULL, in, 8 /* inbuflen */, out, + 8 /* outbuflen */, &out_len); + + return err == kCCSuccess; +} + +#elif defined(USE_OS400CRYPTO) + +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + char key[8]; + _CIPHER_Control_T ctl; + + /* Setup the cipher control structure */ + ctl.Func_ID = ENCRYPT_ONLY; + ctl.Data_Len = sizeof(key); + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, ctl.Crypto_Key); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) ctl.Crypto_Key, ctl.Data_Len); + + /* Perform the encryption */ + _CIPHER((_SPCPTR *) &out, &ctl, (_SPCPTR *) &in); + + return TRUE; +} + +#elif defined(USE_WIN32_CRYPTO) + +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + HCRYPTPROV hprov; + HCRYPTKEY hkey; + struct { + BLOBHEADER hdr; + unsigned int len; + char key[8]; + } blob; + DWORD len = 8; + + /* Acquire the crypto provider */ + if(!CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + return FALSE; + + /* Setup the key blob structure */ + memset(&blob, 0, sizeof(blob)); + blob.hdr.bType = PLAINTEXTKEYBLOB; + blob.hdr.bVersion = 2; + blob.hdr.aiKeyAlg = CALG_DES; + blob.len = sizeof(blob.key); + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, blob.key); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) blob.key, sizeof(blob.key)); + + /* Import the key */ + if(!CryptImportKey(hprov, (BYTE *) &blob, sizeof(blob), 0, 0, &hkey)) { + CryptReleaseContext(hprov, 0); + + return FALSE; + } + + memcpy(out, in, 8); + + /* Perform the encryption */ + CryptEncrypt(hkey, 0, FALSE, 0, out, &len, len); + + CryptDestroyKey(hkey); + CryptReleaseContext(hprov, 0); + + return TRUE; +} + +#endif /* defined(USE_WIN32_CRYPTO) */ + + /* + * takes a 21 byte array and treats it as 3 56-bit DES keys. The + * 8 byte plaintext is encrypted with each key and the resulting 24 + * bytes are stored in the results array. + */ +void Curl_ntlm_core_lm_resp(const unsigned char *keys, + const unsigned char *plaintext, + unsigned char *results) +{ +#ifdef USE_OPENSSL + DES_key_schedule ks; + + setup_des_key(keys, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results, + DESKEY(ks), DES_ENCRYPT); + + setup_des_key(keys + 7, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 8), + DESKEY(ks), DES_ENCRYPT); + + setup_des_key(keys + 14, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 16), + DESKEY(ks), DES_ENCRYPT); +#elif defined(USE_GNUTLS_NETTLE) + struct des_ctx des; + setup_des_key(keys, &des); + des_encrypt(&des, 8, results, plaintext); + setup_des_key(keys + 7, &des); + des_encrypt(&des, 8, results + 8, plaintext); + setup_des_key(keys + 14, &des); + des_encrypt(&des, 8, results + 16, plaintext); +#elif defined(USE_GNUTLS) + gcry_cipher_hd_t des; + + gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); + setup_des_key(keys, &des); + gcry_cipher_encrypt(des, results, 8, plaintext, 8); + gcry_cipher_close(des); + + gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); + setup_des_key(keys + 7, &des); + gcry_cipher_encrypt(des, results + 8, 8, plaintext, 8); + gcry_cipher_close(des); + + gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); + setup_des_key(keys + 14, &des); + gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8); + gcry_cipher_close(des); +#elif defined(USE_NSS) || defined(USE_DARWINSSL) || defined(USE_OS400CRYPTO) \ + || defined(USE_WIN32_CRYPTO) + encrypt_des(plaintext, results, keys); + encrypt_des(plaintext, results + 8, keys + 7); + encrypt_des(plaintext, results + 16, keys + 14); +#endif +} + +/* + * Set up lanmanager hashed password + */ +CURLcode Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, + const char *password, + unsigned char *lmbuffer /* 21 bytes */) +{ + CURLcode result; + unsigned char pw[14]; + static const unsigned char magic[] = { + 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */ + }; + size_t len = CURLMIN(strlen(password), 14); + + Curl_strntoupper((char *)pw, password, len); + memset(&pw[len], 0, 14 - len); + + /* + * The LanManager hashed password needs to be created using the + * password in the network encoding not the host encoding. + */ + result = Curl_convert_to_network(data, (char *)pw, 14); + if(result) + return result; + + { + /* Create LanManager hashed password. */ + +#ifdef USE_OPENSSL + DES_key_schedule ks; + + setup_des_key(pw, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer, + DESKEY(ks), DES_ENCRYPT); + + setup_des_key(pw + 7, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer + 8), + DESKEY(ks), DES_ENCRYPT); +#elif defined(USE_GNUTLS_NETTLE) + struct des_ctx des; + setup_des_key(pw, &des); + des_encrypt(&des, 8, lmbuffer, magic); + setup_des_key(pw + 7, &des); + des_encrypt(&des, 8, lmbuffer + 8, magic); +#elif defined(USE_GNUTLS) + gcry_cipher_hd_t des; + + gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); + setup_des_key(pw, &des); + gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8); + gcry_cipher_close(des); + + gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); + setup_des_key(pw + 7, &des); + gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8); + gcry_cipher_close(des); +#elif defined(USE_NSS) || defined(USE_DARWINSSL) || defined(USE_OS400CRYPTO) \ + || defined(USE_WIN32_CRYPTO) + encrypt_des(magic, lmbuffer, pw); + encrypt_des(magic, lmbuffer + 8, pw + 7); +#endif + + memset(lmbuffer + 16, 0, 21 - 16); + } + + return CURLE_OK; +} + +#if USE_NTRESPONSES +static void ascii_to_unicode_le(unsigned char *dest, const char *src, + size_t srclen) +{ + size_t i; + for(i = 0; i < srclen; i++) { + dest[2 * i] = (unsigned char)src[i]; + dest[2 * i + 1] = '\0'; + } +} + +#if USE_NTLM_V2 && !defined(USE_WINDOWS_SSPI) + +static void ascii_uppercase_to_unicode_le(unsigned char *dest, + const char *src, size_t srclen) +{ + size_t i; + for(i = 0; i < srclen; i++) { + dest[2 * i] = (unsigned char)(toupper(src[i])); + dest[2 * i + 1] = '\0'; + } +} + +#endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */ + +/* + * Set up nt hashed passwords + * @unittest: 1600 + */ +CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data, + const char *password, + unsigned char *ntbuffer /* 21 bytes */) +{ + size_t len = strlen(password); + unsigned char *pw = malloc(len * 2); + CURLcode result; + if(!pw) + return CURLE_OUT_OF_MEMORY; + + ascii_to_unicode_le(pw, password, len); + + /* + * The NT hashed password needs to be created using the password in the + * network encoding not the host encoding. + */ + result = Curl_convert_to_network(data, (char *)pw, len * 2); + if(result) + return result; + + { + /* Create NT hashed password. */ +#ifdef USE_OPENSSL + MD4_CTX MD4pw; + MD4_Init(&MD4pw); + MD4_Update(&MD4pw, pw, 2 * len); + MD4_Final(ntbuffer, &MD4pw); +#elif defined(USE_GNUTLS_NETTLE) + struct md4_ctx MD4pw; + md4_init(&MD4pw); + md4_update(&MD4pw, (unsigned int)(2 * len), pw); + md4_digest(&MD4pw, MD4_DIGEST_SIZE, ntbuffer); +#elif defined(USE_GNUTLS) + gcry_md_hd_t MD4pw; + gcry_md_open(&MD4pw, GCRY_MD_MD4, 0); + gcry_md_write(MD4pw, pw, 2 * len); + memcpy (ntbuffer, gcry_md_read (MD4pw, 0), MD4_DIGEST_LENGTH); + gcry_md_close(MD4pw); +#elif defined(USE_NSS) || defined(USE_OS400CRYPTO) + Curl_md4it(ntbuffer, pw, 2 * len); +#elif defined(USE_DARWINSSL) + (void)CC_MD4(pw, (CC_LONG)(2 * len), ntbuffer); +#elif defined(USE_WIN32_CRYPTO) + HCRYPTPROV hprov; + if(CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) { + HCRYPTHASH hhash; + if(CryptCreateHash(hprov, CALG_MD4, 0, 0, &hhash)) { + DWORD length = 16; + CryptHashData(hhash, pw, (unsigned int)len * 2, 0); + CryptGetHashParam(hhash, HP_HASHVAL, ntbuffer, &length, 0); + CryptDestroyHash(hhash); + } + CryptReleaseContext(hprov, 0); + } +#endif + + memset(ntbuffer + 16, 0, 21 - 16); + } + + free(pw); + + return CURLE_OK; +} + +#if USE_NTLM_V2 && !defined(USE_WINDOWS_SSPI) + +/* This returns the HMAC MD5 digest */ +CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen, + const unsigned char *data, unsigned int datalen, + unsigned char *output) +{ + HMAC_context *ctxt = Curl_HMAC_init(Curl_HMAC_MD5, key, keylen); + + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + /* Update the digest with the given challenge */ + Curl_HMAC_update(ctxt, data, datalen); + + /* Finalise the digest */ + Curl_HMAC_final(ctxt, output); + + return CURLE_OK; +} + +/* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode + * (uppercase UserName + Domain) as the data + */ +CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen, + const char *domain, size_t domlen, + unsigned char *ntlmhash, + unsigned char *ntlmv2hash) +{ + /* Unicode representation */ + size_t identity_len = (userlen + domlen) * 2; + unsigned char *identity = malloc(identity_len); + CURLcode result = CURLE_OK; + + if(!identity) + return CURLE_OUT_OF_MEMORY; + + ascii_uppercase_to_unicode_le(identity, user, userlen); + ascii_to_unicode_le(identity + (userlen << 1), domain, domlen); + + result = Curl_hmac_md5(ntlmhash, 16, identity, curlx_uztoui(identity_len), + ntlmv2hash); + + free(identity); + + return result; +} + +/* + * Curl_ntlm_core_mk_ntlmv2_resp() + * + * This creates the NTLMv2 response as set in the ntlm type-3 message. + * + * Parameters: + * + * ntlmv2hash [in] - The ntlmv2 hash (16 bytes) + * challenge_client [in] - The client nonce (8 bytes) + * ntlm [in] - The ntlm data struct being used to read TargetInfo + and Server challenge received in the type-2 message + * ntresp [out] - The address where a pointer to newly allocated + * memory holding the NTLMv2 response. + * ntresp_len [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, + unsigned char *challenge_client, + struct ntlmdata *ntlm, + unsigned char **ntresp, + unsigned int *ntresp_len) +{ +/* NTLMv2 response structure : +------------------------------------------------------------------------------ +0 HMAC MD5 16 bytes +------BLOB-------------------------------------------------------------------- +16 Signature 0x01010000 +20 Reserved long (0x00000000) +24 Timestamp LE, 64-bit signed value representing the number of + tenths of a microsecond since January 1, 1601. +32 Client Nonce 8 bytes +40 Unknown 4 bytes +44 Target Info N bytes (from the type-2 message) +44+N Unknown 4 bytes +------------------------------------------------------------------------------ +*/ + + unsigned int len = 0; + unsigned char *ptr = NULL; + unsigned char hmac_output[NTLM_HMAC_MD5_LEN]; + curl_off_t tw; + + CURLcode result = CURLE_OK; + +#if CURL_SIZEOF_CURL_OFF_T < 8 +#error "this section needs 64bit support to work" +#endif + + /* Calculate the timestamp */ +#ifdef DEBUGBUILD + char *force_timestamp = getenv("CURL_FORCETIME"); + if(force_timestamp) + tw = CURL_OFF_T_C(11644473600) * 10000000; + else +#endif + tw = ((curl_off_t)time(NULL) + CURL_OFF_T_C(11644473600)) * 10000000; + + /* Calculate the response len */ + len = NTLM_HMAC_MD5_LEN + NTLMv2_BLOB_LEN; + + /* Allocate the response */ + ptr = malloc(len); + if(!ptr) + return CURLE_OUT_OF_MEMORY; + + memset(ptr, 0, len); + + /* Create the BLOB structure */ + snprintf((char *)ptr + NTLM_HMAC_MD5_LEN, NTLMv2_BLOB_LEN, + NTLMv2_BLOB_SIGNATURE + "%c%c%c%c", /* Reserved = 0 */ + 0, 0, 0, 0); + + Curl_write64_le(tw, ptr + 24); + memcpy(ptr + 32, challenge_client, 8); + memcpy(ptr + 44, ntlm->target_info, ntlm->target_info_len); + + /* Concatenate the Type 2 challenge with the BLOB and do HMAC MD5 */ + memcpy(ptr + 8, &ntlm->nonce[0], 8); + result = Curl_hmac_md5(ntlmv2hash, NTLM_HMAC_MD5_LEN, ptr + 8, + NTLMv2_BLOB_LEN + 8, hmac_output); + if(result) { + free(ptr); + return result; + } + + /* Concatenate the HMAC MD5 output with the BLOB */ + memcpy(ptr, hmac_output, NTLM_HMAC_MD5_LEN); + + /* Return the response */ + *ntresp = ptr; + *ntresp_len = len; + + return result; +} + +/* + * Curl_ntlm_core_mk_lmv2_resp() + * + * This creates the LMv2 response as used in the ntlm type-3 message. + * + * Parameters: + * + * ntlmv2hash [in] - The ntlmv2 hash (16 bytes) + * challenge_client [in] - The client nonce (8 bytes) + * challenge_client [in] - The server challenge (8 bytes) + * lmresp [out] - The LMv2 response (24 bytes) + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash, + unsigned char *challenge_client, + unsigned char *challenge_server, + unsigned char *lmresp) +{ + unsigned char data[16]; + unsigned char hmac_output[16]; + CURLcode result = CURLE_OK; + + memcpy(&data[0], challenge_server, 8); + memcpy(&data[8], challenge_client, 8); + + result = Curl_hmac_md5(ntlmv2hash, 16, &data[0], 16, hmac_output); + if(result) + return result; + + /* Concatenate the HMAC MD5 output with the client nonce */ + memcpy(lmresp, hmac_output, 16); + memcpy(lmresp+16, challenge_client, 8); + + return result; +} + +#endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */ + +#endif /* USE_NTRESPONSES */ + +#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ + +#endif /* USE_NTLM */ diff --git a/project/jni/curl/lib/curl_ntlm_core.h b/project/jni/curl/lib/curl_ntlm_core.h new file mode 100644 index 000000000..cf37dc811 --- /dev/null +++ b/project/jni/curl/lib/curl_ntlm_core.h @@ -0,0 +1,106 @@ +#ifndef HEADER_CURL_NTLM_CORE_H +#define HEADER_CURL_NTLM_CORE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_NTLM) + +#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) + +#ifdef USE_OPENSSL +# if !defined(OPENSSL_VERSION_NUMBER) && \ + !defined(HEADER_SSL_H) && !defined(HEADER_MD5_H) +# error "curl_ntlm_core.h shall not be included before OpenSSL headers." +# endif +# ifdef OPENSSL_NO_MD4 +# define USE_NTRESPONSES 0 +# define USE_NTLM2SESSION 0 +# define USE_NTLM_V2 0 +# endif +#endif + +/* Define USE_NTRESPONSES to 1 in order to make the type-3 message include + * the NT response message. */ +#ifndef USE_NTRESPONSES +#define USE_NTRESPONSES 1 +#endif + +/* Define USE_NTLM2SESSION to 1 in order to make the type-3 message include the + NTLM2Session response message, requires USE_NTRESPONSES defined to 1 and a + Crypto engine that we have curl_ssl_md5sum() for. */ +#if !defined(USE_NTLM2SESSION) && USE_NTRESPONSES && !defined(USE_WIN32_CRYPTO) +#define USE_NTLM2SESSION 1 +#endif + +/* Define USE_NTLM_V2 to 1 in order to allow the type-3 message to include the + LMv2 and NTLMv2 response messages, requires USE_NTRESPONSES defined to 1 + and support for 64-bit integers. */ +#if !defined(USE_NTLM_V2) && USE_NTRESPONSES && (CURL_SIZEOF_CURL_OFF_T > 4) +#define USE_NTLM_V2 1 +#endif + +void Curl_ntlm_core_lm_resp(const unsigned char *keys, + const unsigned char *plaintext, + unsigned char *results); + +CURLcode Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, + const char *password, + unsigned char *lmbuffer /* 21 bytes */); + +#if USE_NTRESPONSES +CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data, + const char *password, + unsigned char *ntbuffer /* 21 bytes */); + +#if USE_NTLM_V2 && !defined(USE_WINDOWS_SSPI) + +CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen, + const unsigned char *data, unsigned int datalen, + unsigned char *output); + +CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen, + const char *domain, size_t domlen, + unsigned char *ntlmhash, + unsigned char *ntlmv2hash); + +CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, + unsigned char *challenge_client, + struct ntlmdata *ntlm, + unsigned char **ntresp, + unsigned int *ntresp_len); + +CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash, + unsigned char *challenge_client, + unsigned char *challenge_server, + unsigned char *lmresp); + +#endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */ + +#endif /* USE_NTRESPONSES */ + +#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ + +#endif /* USE_NTLM */ + +#endif /* HEADER_CURL_NTLM_CORE_H */ diff --git a/project/jni/curl/lib/curl_ntlm_msgs.c b/project/jni/curl/lib/curl_ntlm_msgs.c new file mode 100644 index 000000000..fc9547207 --- /dev/null +++ b/project/jni/curl/lib/curl_ntlm_msgs.c @@ -0,0 +1,821 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) + +/* + * NTLM details: + * + * http://davenport.sourceforge.net/ntlm.html + * http://www.innovation.ch/java/ntlm.html + */ + +#define DEBUG_ME 0 + +#include "urldata.h" +#include "non-ascii.h" +#include "sendf.h" +#include "curl_base64.h" +#include "curl_ntlm_core.h" +#include "curl_gethostname.h" +#include "curl_multibyte.h" +#include "warnless.h" + +#include "vtls/vtls.h" + +#ifdef USE_NSS +#include "vtls/nssg.h" /* for Curl_nss_force_init() */ +#endif + +#define BUILDING_CURL_NTLM_MSGS_C +#include "curl_ntlm_msgs.h" +#include "curl_sasl.h" +#include "curl_endian.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* "NTLMSSP" signature is always in ASCII regardless of the platform */ +#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" + +#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff) +#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \ + (((x) >> 16) & 0xff), (((x) >> 24) & 0xff) + +#if DEBUG_ME +# define DEBUG_OUT(x) x +static void ntlm_print_flags(FILE *handle, unsigned long flags) +{ + if(flags & NTLMFLAG_NEGOTIATE_UNICODE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE "); + if(flags & NTLMFLAG_NEGOTIATE_OEM) + fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM "); + if(flags & NTLMFLAG_REQUEST_TARGET) + fprintf(handle, "NTLMFLAG_REQUEST_TARGET "); + if(flags & (1<<3)) + fprintf(handle, "NTLMFLAG_UNKNOWN_3 "); + if(flags & NTLMFLAG_NEGOTIATE_SIGN) + fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN "); + if(flags & NTLMFLAG_NEGOTIATE_SEAL) + fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL "); + if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE "); + if(flags & NTLMFLAG_NEGOTIATE_LM_KEY) + fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY "); + if(flags & NTLMFLAG_NEGOTIATE_NETWARE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE "); + if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) + fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY "); + if(flags & (1<<10)) + fprintf(handle, "NTLMFLAG_UNKNOWN_10 "); + if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS) + fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS "); + if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED) + fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED "); + if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED) + fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED "); + if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL) + fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL "); + if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN) + fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN "); + if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN) + fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN "); + if(flags & NTLMFLAG_TARGET_TYPE_SERVER) + fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER "); + if(flags & NTLMFLAG_TARGET_TYPE_SHARE) + fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE "); + if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) + fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY "); + if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE) + fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE "); + if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE) + fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE "); + if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY) + fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY "); + if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) + fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO "); + if(flags & (1<<24)) + fprintf(handle, "NTLMFLAG_UNKNOWN_24 "); + if(flags & (1<<25)) + fprintf(handle, "NTLMFLAG_UNKNOWN_25 "); + if(flags & (1<<26)) + fprintf(handle, "NTLMFLAG_UNKNOWN_26 "); + if(flags & (1<<27)) + fprintf(handle, "NTLMFLAG_UNKNOWN_27 "); + if(flags & (1<<28)) + fprintf(handle, "NTLMFLAG_UNKNOWN_28 "); + if(flags & NTLMFLAG_NEGOTIATE_128) + fprintf(handle, "NTLMFLAG_NEGOTIATE_128 "); + if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE "); + if(flags & NTLMFLAG_NEGOTIATE_56) + fprintf(handle, "NTLMFLAG_NEGOTIATE_56 "); +} + +static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) +{ + const char *p = buf; + (void)handle; + fprintf(stderr, "0x"); + while(len-- > 0) + fprintf(stderr, "%02.2x", (unsigned int)*p++); +} +#else +# define DEBUG_OUT(x) Curl_nop_stmt +#endif + +/* + * ntlm_decode_type2_target() + * + * This is used to decode the "target info" in the NTLM type-2 message + * received. + * + * Parameters: + * + * data [in] - The session handle. + * buffer [in] - The decoded type-2 message. + * size [in] - The input buffer size, at least 32 bytes. + * ntlm [in/out] - The NTLM data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +static CURLcode ntlm_decode_type2_target(struct SessionHandle *data, + unsigned char *buffer, + size_t size, + struct ntlmdata *ntlm) +{ + unsigned short target_info_len = 0; + unsigned int target_info_offset = 0; + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + + if(size >= 48) { + target_info_len = Curl_read16_le(&buffer[40]); + target_info_offset = Curl_read32_le(&buffer[44]); + if(target_info_len > 0) { + if(((target_info_offset + target_info_len) > size) || + (target_info_offset < 48)) { + infof(data, "NTLM handshake failure (bad type-2 message). " + "Target Info Offset Len is set incorrect by the peer\n"); + return CURLE_BAD_CONTENT_ENCODING; + } + + ntlm->target_info = malloc(target_info_len); + if(!ntlm->target_info) + return CURLE_OUT_OF_MEMORY; + + memcpy(ntlm->target_info, &buffer[target_info_offset], target_info_len); + } + } + + ntlm->target_info_len = target_info_len; + + return CURLE_OK; +} + +/* + NTLM message structure notes: + + A 'short' is a 'network short', a little-endian 16-bit unsigned value. + + A 'long' is a 'network long', a little-endian, 32-bit unsigned value. + + A 'security buffer' represents a triplet used to point to a buffer, + consisting of two shorts and one long: + + 1. A 'short' containing the length of the buffer content in bytes. + 2. A 'short' containing the allocated space for the buffer in bytes. + 3. A 'long' containing the offset to the start of the buffer in bytes, + from the beginning of the NTLM message. +*/ + +/* + * Curl_sasl_decode_ntlm_type2_message() + * + * This is used to decode an already encoded NTLM type-2 message. The message + * is first decoded from a base64 string into a raw NTLM message and checked + * for validity before the appropriate data for creating a type-3 message is + * written to the given NTLM data structure. + * + * Parameters: + * + * data [in] - The session handle. + * type2msg [in] - The base64 encoded type-2 message. + * ntlm [in/out] - The NTLM data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data, + const char *type2msg, + struct ntlmdata *ntlm) +{ + static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; + + /* NTLM type-2 message structure: + + Index Description Content + 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" + (0x4e544c4d53535000) + 8 NTLM Message Type long (0x02000000) + 12 Target Name security buffer + 20 Flags long + 24 Challenge 8 bytes + (32) Context 8 bytes (two consecutive longs) (*) + (40) Target Information security buffer (*) + (48) OS Version Structure 8 bytes (*) + 32 (48) (56) Start of data block (*) + (*) -> Optional + */ + + CURLcode result = CURLE_OK; + unsigned char *type2 = NULL; + size_t type2_len = 0; + +#if defined(USE_NSS) + /* Make sure the crypto backend is initialized */ + result = Curl_nss_force_init(data); + if(result) + return result; +#elif defined(CURL_DISABLE_VERBOSE_STRINGS) + (void)data; +#endif + + /* Decode the base-64 encoded type-2 message */ + if(strlen(type2msg) && *type2msg != '=') { + result = Curl_base64_decode(type2msg, &type2, &type2_len); + if(result) + return result; + } + + /* Ensure we have a valid type-2 message */ + if(!type2) { + infof(data, "NTLM handshake failure (empty type-2 message)\n"); + return CURLE_BAD_CONTENT_ENCODING; + } + + ntlm->flags = 0; + + if((type2_len < 32) || + (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) || + (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) { + /* This was not a good enough type-2 message */ + free(type2); + infof(data, "NTLM handshake failure (bad type-2 message)\n"); + return CURLE_BAD_CONTENT_ENCODING; + } + + ntlm->flags = Curl_read32_le(&type2[20]); + memcpy(ntlm->nonce, &type2[24], 8); + + if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) { + result = ntlm_decode_type2_target(data, type2, type2_len, ntlm); + if(result) { + free(type2); + infof(data, "NTLM handshake failure (bad type-2 message)\n"); + return result; + } + } + + DEBUG_OUT({ + fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); + ntlm_print_flags(stderr, ntlm->flags); + fprintf(stderr, "\n nonce="); + ntlm_print_hex(stderr, (char *)ntlm->nonce, 8); + fprintf(stderr, "\n****\n"); + fprintf(stderr, "**** Header %s\n ", header); + }); + + free(type2); + + return result; +} + +/* copy the source to the destination and fill in zeroes in every + other destination byte! */ +static void unicodecpy(unsigned char *dest, const char *src, size_t length) +{ + size_t i; + for(i = 0; i < length; i++) { + dest[2 * i] = (unsigned char)src[i]; + dest[2 * i + 1] = '\0'; + } +} + +/* + * Curl_sasl_create_ntlm_type1_message() + * + * This is used to generate an already encoded NTLM type-1 message ready for + * sending to the recipient using the appropriate compile time crypto API. + * + * Parameters: + * + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * ntlm [in/out] - The NTLM data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, size_t *outlen) +{ + /* NTLM type-1 message structure: + + Index Description Content + 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" + (0x4e544c4d53535000) + 8 NTLM Message Type long (0x01000000) + 12 Flags long + (16) Supplied Domain security buffer (*) + (24) Supplied Workstation security buffer (*) + (32) OS Version Structure 8 bytes (*) + (32) (40) Start of data block (*) + (*) -> Optional + */ + + size_t size; + + unsigned char ntlmbuf[NTLM_BUFSIZE]; + const char *host = ""; /* empty */ + const char *domain = ""; /* empty */ + size_t hostlen = 0; + size_t domlen = 0; + size_t hostoff = 0; + size_t domoff = hostoff + hostlen; /* This is 0: remember that host and + domain are empty */ + (void)userp; + (void)passwdp; + + /* Clean up any former leftovers and initialise to defaults */ + Curl_sasl_ntlm_cleanup(ntlm); + +#if USE_NTRESPONSES && USE_NTLM2SESSION +#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY +#else +#define NTLM2FLAG 0 +#endif + snprintf((char *)ntlmbuf, NTLM_BUFSIZE, + NTLMSSP_SIGNATURE "%c" + "\x01%c%c%c" /* 32-bit type = 1 */ + "%c%c%c%c" /* 32-bit NTLM flag field */ + "%c%c" /* domain length */ + "%c%c" /* domain allocated space */ + "%c%c" /* domain name offset */ + "%c%c" /* 2 zeroes */ + "%c%c" /* host length */ + "%c%c" /* host allocated space */ + "%c%c" /* host name offset */ + "%c%c" /* 2 zeroes */ + "%s" /* host name */ + "%s", /* domain string */ + 0, /* trailing zero */ + 0, 0, 0, /* part of type-1 long */ + + LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLM2FLAG | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), + SHORTPAIR(domlen), + SHORTPAIR(domlen), + SHORTPAIR(domoff), + 0, 0, + SHORTPAIR(hostlen), + SHORTPAIR(hostlen), + SHORTPAIR(hostoff), + 0, 0, + host, /* this is empty */ + domain /* this is empty */); + + /* Initial packet length */ + size = 32 + hostlen + domlen; + + DEBUG_OUT({ + fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x " + "0x%08.8x ", + LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLM2FLAG | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), + NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLM2FLAG | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); + ntlm_print_flags(stderr, + NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLM2FLAG | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); + fprintf(stderr, "\n****\n"); + }); + + /* Return with binary blob encoded into base64 */ + return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); +} + +/* + * Curl_sasl_create_ntlm_type3_message() + * + * This is used to generate an already encoded NTLM type-3 message ready for + * sending to the recipient using the appropriate compile time crypto API. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * ntlm [in/out] - The NTLM data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, size_t *outlen) + +{ + /* NTLM type-3 message structure: + + Index Description Content + 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" + (0x4e544c4d53535000) + 8 NTLM Message Type long (0x03000000) + 12 LM/LMv2 Response security buffer + 20 NTLM/NTLMv2 Response security buffer + 28 Target Name security buffer + 36 User Name security buffer + 44 Workstation Name security buffer + (52) Session Key security buffer (*) + (60) Flags long (*) + (64) OS Version Structure 8 bytes (*) + 52 (64) (72) Start of data block + (*) -> Optional + */ + + CURLcode result = CURLE_OK; + size_t size; + unsigned char ntlmbuf[NTLM_BUFSIZE]; + int lmrespoff; + unsigned char lmresp[24]; /* fixed-size */ +#if USE_NTRESPONSES + int ntrespoff; + unsigned int ntresplen = 24; + unsigned char ntresp[24]; /* fixed-size */ + unsigned char *ptr_ntresp = &ntresp[0]; + unsigned char *ntlmv2resp = NULL; +#endif + bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE; + char host[HOSTNAME_MAX + 1] = ""; + const char *user; + const char *domain = ""; + size_t hostoff = 0; + size_t useroff = 0; + size_t domoff = 0; + size_t hostlen = 0; + size_t userlen = 0; + size_t domlen = 0; + + user = strchr(userp, '\\'); + if(!user) + user = strchr(userp, '/'); + + if(user) { + domain = userp; + domlen = (user - domain); + user++; + } + else + user = userp; + + if(user) + userlen = strlen(user); + + /* Get the machine's un-qualified host name as NTLM doesn't like the fully + qualified domain name */ + if(Curl_gethostname(host, sizeof(host))) { + infof(data, "gethostname() failed, continuing without!\n"); + hostlen = 0; + } + else { + hostlen = strlen(host); + } + +#if USE_NTRESPONSES && USE_NTLM_V2 + if(ntlm->target_info_len) { + unsigned char ntbuffer[0x18]; + unsigned int entropy[2]; + unsigned char ntlmv2hash[0x18]; + + entropy[0] = Curl_rand(data); + entropy[1] = Curl_rand(data); + + result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); + if(result) + return result; + + result = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen, + ntbuffer, ntlmv2hash); + if(result) + return result; + + /* LMv2 response */ + result = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, + (unsigned char *)&entropy[0], + &ntlm->nonce[0], lmresp); + if(result) + return result; + + /* NTLMv2 response */ + result = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, + (unsigned char *)&entropy[0], + ntlm, &ntlmv2resp, &ntresplen); + if(result) + return result; + + ptr_ntresp = ntlmv2resp; + } + else +#endif + +#if USE_NTRESPONSES && USE_NTLM2SESSION + /* We don't support NTLM2 if we don't have USE_NTRESPONSES */ + if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { + unsigned char ntbuffer[0x18]; + unsigned char tmp[0x18]; + unsigned char md5sum[MD5_DIGEST_LENGTH]; + unsigned int entropy[2]; + + /* Need to create 8 bytes random data */ + entropy[0] = Curl_rand(data); + entropy[1] = Curl_rand(data); + + /* 8 bytes random data as challenge in lmresp */ + memcpy(lmresp, entropy, 8); + + /* Pad with zeros */ + memset(lmresp + 8, 0, 0x10); + + /* Fill tmp with challenge(nonce?) + entropy */ + memcpy(tmp, &ntlm->nonce[0], 8); + memcpy(tmp + 8, entropy, 8); + + result = Curl_ssl_md5sum(tmp, 16, md5sum, MD5_DIGEST_LENGTH); + if(!result) + /* We shall only use the first 8 bytes of md5sum, but the des code in + Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */ + result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); + if(result) + return result; + + Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp); + + /* End of NTLM2 Session code */ + + } + else +#endif + { + +#if USE_NTRESPONSES + unsigned char ntbuffer[0x18]; +#endif + unsigned char lmbuffer[0x18]; + +#if USE_NTRESPONSES + result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); + if(result) + return result; + + Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); +#endif + + result = Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer); + if(result) + return result; + + Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); + + /* A safer but less compatible alternative is: + * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); + * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ + } + + if(unicode) { + domlen = domlen * 2; + userlen = userlen * 2; + hostlen = hostlen * 2; + } + + lmrespoff = 64; /* size of the message header */ +#if USE_NTRESPONSES + ntrespoff = lmrespoff + 0x18; + domoff = ntrespoff + ntresplen; +#else + domoff = lmrespoff + 0x18; +#endif + useroff = domoff + domlen; + hostoff = useroff + userlen; + + /* Create the big type-3 message binary blob */ + size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE, + NTLMSSP_SIGNATURE "%c" + "\x03%c%c%c" /* 32-bit type = 3 */ + + "%c%c" /* LanManager length */ + "%c%c" /* LanManager allocated space */ + "%c%c" /* LanManager offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* NT-response length */ + "%c%c" /* NT-response allocated space */ + "%c%c" /* NT-response offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* domain length */ + "%c%c" /* domain allocated space */ + "%c%c" /* domain name offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* user length */ + "%c%c" /* user allocated space */ + "%c%c" /* user offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* host length */ + "%c%c" /* host allocated space */ + "%c%c" /* host offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* session key length (unknown purpose) */ + "%c%c" /* session key allocated space (unknown purpose) */ + "%c%c" /* session key offset (unknown purpose) */ + "%c%c" /* 2 zeroes */ + + "%c%c%c%c", /* flags */ + + /* domain string */ + /* user string */ + /* host string */ + /* LanManager response */ + /* NT response */ + + 0, /* zero termination */ + 0, 0, 0, /* type-3 long, the 24 upper bits */ + + SHORTPAIR(0x18), /* LanManager response length, twice */ + SHORTPAIR(0x18), + SHORTPAIR(lmrespoff), + 0x0, 0x0, + +#if USE_NTRESPONSES + SHORTPAIR(ntresplen), /* NT-response length, twice */ + SHORTPAIR(ntresplen), + SHORTPAIR(ntrespoff), + 0x0, 0x0, +#else + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, +#endif + SHORTPAIR(domlen), + SHORTPAIR(domlen), + SHORTPAIR(domoff), + 0x0, 0x0, + + SHORTPAIR(userlen), + SHORTPAIR(userlen), + SHORTPAIR(useroff), + 0x0, 0x0, + + SHORTPAIR(hostlen), + SHORTPAIR(hostlen), + SHORTPAIR(hostoff), + 0x0, 0x0, + + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + + LONGQUARTET(ntlm->flags)); + + DEBUGASSERT(size == 64); + DEBUGASSERT(size == (size_t)lmrespoff); + + /* We append the binary hashes */ + if(size < (NTLM_BUFSIZE - 0x18)) { + memcpy(&ntlmbuf[size], lmresp, 0x18); + size += 0x18; + } + + DEBUG_OUT({ + fprintf(stderr, "**** TYPE3 header lmresp="); + ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18); + }); + +#if USE_NTRESPONSES + if(size < (NTLM_BUFSIZE - ntresplen)) { + DEBUGASSERT(size == (size_t)ntrespoff); + memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen); + size += ntresplen; + } + + DEBUG_OUT({ + fprintf(stderr, "\n ntresp="); + ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen); + }); + + free(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */ + +#endif + + DEBUG_OUT({ + fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", + LONGQUARTET(ntlm->flags), ntlm->flags); + ntlm_print_flags(stderr, ntlm->flags); + fprintf(stderr, "\n****\n"); + }); + + /* Make sure that the domain, user and host strings fit in the + buffer before we copy them there. */ + if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) { + failf(data, "user + domain + host name too big"); + return CURLE_OUT_OF_MEMORY; + } + + DEBUGASSERT(size == domoff); + if(unicode) + unicodecpy(&ntlmbuf[size], domain, domlen / 2); + else + memcpy(&ntlmbuf[size], domain, domlen); + + size += domlen; + + DEBUGASSERT(size == useroff); + if(unicode) + unicodecpy(&ntlmbuf[size], user, userlen / 2); + else + memcpy(&ntlmbuf[size], user, userlen); + + size += userlen; + + DEBUGASSERT(size == hostoff); + if(unicode) + unicodecpy(&ntlmbuf[size], host, hostlen / 2); + else + memcpy(&ntlmbuf[size], host, hostlen); + + size += hostlen; + + /* Convert domain, user, and host to ASCII but leave the rest as-is */ + result = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff], + size - domoff); + if(result) + return CURLE_CONV_FAILED; + + /* Return with binary blob encoded into base64 */ + result = Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); + + Curl_sasl_ntlm_cleanup(ntlm); + + return result; +} + +#endif /* USE_NTLM && !USE_WINDOWS_SSPI */ diff --git a/project/jni/curl/lib/http_ntlm.h b/project/jni/curl/lib/curl_ntlm_msgs.h similarity index 86% rename from project/jni/curl/lib/http_ntlm.h rename to project/jni/curl/lib/curl_ntlm_msgs.h index c7422d701..b9026f87c 100644 --- a/project/jni/curl/lib/http_ntlm.h +++ b/project/jni/curl/lib/curl_ntlm_msgs.h @@ -1,5 +1,5 @@ -#ifndef __HTTP_NTLM_H -#define __HTTP_NTLM_H +#ifndef HEADER_CURL_NTLM_MSGS_H +#define HEADER_CURL_NTLM_MSGS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,26 +22,15 @@ * ***************************************************************************/ -typedef enum { - CURLNTLM_NONE, /* not a ntlm */ - CURLNTLM_BAD, /* an ntlm, but one we don't like */ - CURLNTLM_FIRST, /* the first 401-reply we got with NTLM */ - CURLNTLM_FINE, /* an ntlm we act on */ +#include "curl_setup.h" - CURLNTLM_LAST /* last entry in this enum, don't use */ -} CURLntlm; +#ifdef USE_NTLM -/* this is for ntlm header input */ -CURLntlm Curl_input_ntlm(struct connectdata *conn, bool proxy, - const char *header); +/* NTLM buffer fixed size, large enough for long user + host + domain */ +#define NTLM_BUFSIZE 1024 -/* this is for creating ntlm header output */ -CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy); - -void Curl_ntlm_cleanup(struct connectdata *conn); -#ifndef USE_NTLM -#define Curl_ntlm_cleanup(x) -#endif +/* Stuff only required for curl_ntlm_msgs.c */ +#ifdef BUILDING_CURL_NTLM_MSGS_C /* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */ @@ -146,4 +135,9 @@ void Curl_ntlm_cleanup(struct connectdata *conn); #define NTLMFLAG_NEGOTIATE_56 (1<<31) /* Indicates that 56-bit encryption is supported. */ -#endif + +#endif /* BUILDING_CURL_NTLM_MSGS_C */ + +#endif /* USE_NTLM */ + +#endif /* HEADER_CURL_NTLM_MSGS_H */ diff --git a/project/jni/curl/lib/curl_ntlm_wb.c b/project/jni/curl/lib/curl_ntlm_wb.c new file mode 100644 index 000000000..06f66702d --- /dev/null +++ b/project/jni/curl/lib/curl_ntlm_wb.c @@ -0,0 +1,431 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ + defined(NTLM_WB_ENABLED) + +/* + * NTLM details: + * + * http://davenport.sourceforge.net/ntlm.html + * http://www.innovation.ch/java/ntlm.html + */ + +#define DEBUG_ME 0 + +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#ifdef HAVE_SIGNAL_H +#include +#endif +#ifdef HAVE_PWD_H +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "select.h" +#include "curl_ntlm_msgs.h" +#include "curl_ntlm_wb.h" +#include "url.h" +#include "strerror.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#if DEBUG_ME +# define DEBUG_OUT(x) x +#else +# define DEBUG_OUT(x) Curl_nop_stmt +#endif + +/* Portable 'sclose_nolog' used only in child process instead of 'sclose' + to avoid fooling the socket leak detector */ +#if defined(HAVE_CLOSESOCKET) +# define sclose_nolog(x) closesocket((x)) +#elif defined(HAVE_CLOSESOCKET_CAMEL) +# define sclose_nolog(x) CloseSocket((x)) +#else +# define sclose_nolog(x) close((x)) +#endif + +void Curl_ntlm_wb_cleanup(struct connectdata *conn) +{ + if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) { + sclose(conn->ntlm_auth_hlpr_socket); + conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; + } + + if(conn->ntlm_auth_hlpr_pid) { + int i; + for(i = 0; i < 4; i++) { + pid_t ret = waitpid(conn->ntlm_auth_hlpr_pid, NULL, WNOHANG); + if(ret == conn->ntlm_auth_hlpr_pid || errno == ECHILD) + break; + switch(i) { + case 0: + kill(conn->ntlm_auth_hlpr_pid, SIGTERM); + break; + case 1: + /* Give the process another moment to shut down cleanly before + bringing down the axe */ + Curl_wait_ms(1); + break; + case 2: + kill(conn->ntlm_auth_hlpr_pid, SIGKILL); + break; + case 3: + break; + } + } + conn->ntlm_auth_hlpr_pid = 0; + } + + free(conn->challenge_header); + conn->challenge_header = NULL; + free(conn->response_header); + conn->response_header = NULL; +} + +static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) +{ + curl_socket_t sockfds[2]; + pid_t child_pid; + const char *username; + char *slash, *domain = NULL; + const char *ntlm_auth = NULL; + char *ntlm_auth_alloc = NULL; +#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) + struct passwd pw, *pw_res; + char pwbuf[1024]; +#endif + int error; + + /* Return if communication with ntlm_auth already set up */ + if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD || + conn->ntlm_auth_hlpr_pid) + return CURLE_OK; + + username = userp; + /* The real ntlm_auth really doesn't like being invoked with an + empty username. It won't make inferences for itself, and expects + the client to do so (mostly because it's really designed for + servers like squid to use for auth, and client support is an + afterthought for it). So try hard to provide a suitable username + if we don't already have one. But if we can't, provide the + empty one anyway. Perhaps they have an implementation of the + ntlm_auth helper which *doesn't* need it so we might as well try */ + if(!username || !username[0]) { + username = getenv("NTLMUSER"); + if(!username || !username[0]) + username = getenv("LOGNAME"); + if(!username || !username[0]) + username = getenv("USER"); +#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) + if((!username || !username[0]) && + !getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) && + pw_res) { + username = pw.pw_name; + } +#endif + if(!username || !username[0]) + username = userp; + } + slash = strpbrk(username, "\\/"); + if(slash) { + if((domain = strdup(username)) == NULL) + return CURLE_OUT_OF_MEMORY; + slash = domain + (slash - username); + *slash = '\0'; + username = username + (slash - domain) + 1; + } + + /* For testing purposes, when DEBUGBUILD is defined and environment + variable CURL_NTLM_WB_FILE is set a fake_ntlm is used to perform + NTLM challenge/response which only accepts commands and output + strings pre-written in test case definitions */ +#ifdef DEBUGBUILD + ntlm_auth_alloc = curl_getenv("CURL_NTLM_WB_FILE"); + if(ntlm_auth_alloc) + ntlm_auth = ntlm_auth_alloc; + else +#endif + ntlm_auth = NTLM_WB_FILE; + + if(access(ntlm_auth, X_OK) != 0) { + error = ERRNO; + failf(conn->data, "Could not access ntlm_auth: %s errno %d: %s", + ntlm_auth, error, Curl_strerror(conn, error)); + goto done; + } + + if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) { + error = ERRNO; + failf(conn->data, "Could not open socket pair. errno %d: %s", + error, Curl_strerror(conn, error)); + goto done; + } + + child_pid = fork(); + if(child_pid == -1) { + error = ERRNO; + sclose(sockfds[0]); + sclose(sockfds[1]); + failf(conn->data, "Could not fork. errno %d: %s", + error, Curl_strerror(conn, error)); + goto done; + } + else if(!child_pid) { + /* + * child process + */ + + /* Don't use sclose in the child since it fools the socket leak detector */ + sclose_nolog(sockfds[0]); + if(dup2(sockfds[1], STDIN_FILENO) == -1) { + error = ERRNO; + failf(conn->data, "Could not redirect child stdin. errno %d: %s", + error, Curl_strerror(conn, error)); + exit(1); + } + + if(dup2(sockfds[1], STDOUT_FILENO) == -1) { + error = ERRNO; + failf(conn->data, "Could not redirect child stdout. errno %d: %s", + error, Curl_strerror(conn, error)); + exit(1); + } + + if(domain) + execl(ntlm_auth, ntlm_auth, + "--helper-protocol", "ntlmssp-client-1", + "--use-cached-creds", + "--username", username, + "--domain", domain, + NULL); + else + execl(ntlm_auth, ntlm_auth, + "--helper-protocol", "ntlmssp-client-1", + "--use-cached-creds", + "--username", username, + NULL); + + error = ERRNO; + sclose_nolog(sockfds[1]); + failf(conn->data, "Could not execl(). errno %d: %s", + error, Curl_strerror(conn, error)); + exit(1); + } + + sclose(sockfds[1]); + conn->ntlm_auth_hlpr_socket = sockfds[0]; + conn->ntlm_auth_hlpr_pid = child_pid; + free(domain); + free(ntlm_auth_alloc); + return CURLE_OK; + +done: + free(domain); + free(ntlm_auth_alloc); + return CURLE_REMOTE_ACCESS_DENIED; +} + +static CURLcode ntlm_wb_response(struct connectdata *conn, + const char *input, curlntlm state) +{ + char *buf = malloc(NTLM_BUFSIZE); + size_t len_in = strlen(input), len_out = 0; + + if(!buf) + return CURLE_OUT_OF_MEMORY; + + while(len_in > 0) { + ssize_t written = swrite(conn->ntlm_auth_hlpr_socket, input, len_in); + if(written == -1) { + /* Interrupted by a signal, retry it */ + if(errno == EINTR) + continue; + /* write failed if other errors happen */ + goto done; + } + input += written; + len_in -= written; + } + /* Read one line */ + while(1) { + ssize_t size; + char *newbuf; + + size = sread(conn->ntlm_auth_hlpr_socket, buf + len_out, NTLM_BUFSIZE); + if(size == -1) { + if(errno == EINTR) + continue; + goto done; + } + else if(size == 0) + goto done; + + len_out += size; + if(buf[len_out - 1] == '\n') { + buf[len_out - 1] = '\0'; + break; + } + newbuf = realloc(buf, len_out + NTLM_BUFSIZE); + if(!newbuf) { + free(buf); + return CURLE_OUT_OF_MEMORY; + } + buf = newbuf; + } + + /* Samba/winbind installed but not configured */ + if(state == NTLMSTATE_TYPE1 && + len_out == 3 && + buf[0] == 'P' && buf[1] == 'W') + goto done; + /* invalid response */ + if(len_out < 4) + goto done; + if(state == NTLMSTATE_TYPE1 && + (buf[0]!='Y' || buf[1]!='R' || buf[2]!=' ')) + goto done; + if(state == NTLMSTATE_TYPE2 && + (buf[0]!='K' || buf[1]!='K' || buf[2]!=' ') && + (buf[0]!='A' || buf[1]!='F' || buf[2]!=' ')) + goto done; + + conn->response_header = aprintf("NTLM %.*s", len_out - 4, buf + 3); + free(buf); + return CURLE_OK; +done: + free(buf); + return CURLE_REMOTE_ACCESS_DENIED; +} + +/* + * This is for creating ntlm header output by delegating challenge/response + * to Samba's winbind daemon helper ntlm_auth. + */ +CURLcode Curl_output_ntlm_wb(struct connectdata *conn, + bool proxy) +{ + /* point to the address of the pointer that holds the string to send to the + server, which is for a plain host or for a HTTP proxy */ + char **allocuserpwd; + /* point to the name and password for this */ + const char *userp; + /* point to the correct struct with this */ + struct ntlmdata *ntlm; + struct auth *authp; + + CURLcode res = CURLE_OK; + char *input; + + DEBUGASSERT(conn); + DEBUGASSERT(conn->data); + + if(proxy) { + allocuserpwd = &conn->allocptr.proxyuserpwd; + userp = conn->proxyuser; + ntlm = &conn->proxyntlm; + authp = &conn->data->state.authproxy; + } + else { + allocuserpwd = &conn->allocptr.userpwd; + userp = conn->user; + ntlm = &conn->ntlm; + authp = &conn->data->state.authhost; + } + authp->done = FALSE; + + /* not set means empty */ + if(!userp) + userp=""; + + switch(ntlm->state) { + case NTLMSTATE_TYPE1: + default: + /* Use Samba's 'winbind' daemon to support NTLM authentication, + * by delegating the NTLM challenge/response protocal to a helper + * in ntlm_auth. + * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html + * https://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html + * https://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html + * Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this + * feature is enabled and 'NTLM_WB_FILE' symbol holds absolute + * filename of ntlm_auth helper. + * If NTLM authentication using winbind fails, go back to original + * request handling process. + */ + /* Create communication with ntlm_auth */ + res = ntlm_wb_init(conn, userp); + if(res) + return res; + res = ntlm_wb_response(conn, "YR\n", ntlm->state); + if(res) + return res; + + free(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: %s\r\n", + proxy ? "Proxy-" : "", + conn->response_header); + DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); + free(conn->response_header); + conn->response_header = NULL; + break; + case NTLMSTATE_TYPE2: + input = aprintf("TT %s\n", conn->challenge_header); + if(!input) + return CURLE_OUT_OF_MEMORY; + res = ntlm_wb_response(conn, input, ntlm->state); + free(input); + input = NULL; + if(res) + return res; + + free(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: %s\r\n", + proxy ? "Proxy-" : "", + conn->response_header); + DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); + ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */ + authp->done = TRUE; + Curl_ntlm_wb_cleanup(conn); + break; + case NTLMSTATE_TYPE3: + /* connection is already authenticated, + * don't send a header in future requests */ + free(*allocuserpwd); + *allocuserpwd=NULL; + authp->done = TRUE; + break; + } + + return CURLE_OK; +} + +#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */ diff --git a/project/jni/curl/lib/curl_ntlm_wb.h b/project/jni/curl/lib/curl_ntlm_wb.h new file mode 100644 index 000000000..aba3d469c --- /dev/null +++ b/project/jni/curl/lib/curl_ntlm_wb.h @@ -0,0 +1,38 @@ +#ifndef HEADER_CURL_NTLM_WB_H +#define HEADER_CURL_NTLM_WB_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ + defined(NTLM_WB_ENABLED) + +/* this is for creating ntlm header output by delegating challenge/response + to Samba's winbind daemon helper ntlm_auth */ +CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy); + +void Curl_ntlm_wb_cleanup(struct connectdata *conn); + +#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */ + +#endif /* HEADER_CURL_NTLM_WB_H */ diff --git a/project/jni/curl/lib/curl_printf.h b/project/jni/curl/lib/curl_printf.h new file mode 100644 index 000000000..49857cdb0 --- /dev/null +++ b/project/jni/curl/lib/curl_printf.h @@ -0,0 +1,56 @@ +#ifndef HEADER_CURL_PRINTF_H +#define HEADER_CURL_PRINTF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * This header should be included by ALL code in libcurl that uses any + * *rintf() functions. + */ + +#include + +# undef printf +# undef fprintf +# undef snprintf +# undef vprintf +# undef vfprintf +# undef vsnprintf +# undef aprintf +# undef vaprintf +# define printf curl_mprintf +# define fprintf curl_mfprintf +# define snprintf curl_msnprintf +# define vprintf curl_mvprintf +# define vfprintf curl_mvfprintf +# define vsnprintf curl_mvsnprintf +# define aprintf curl_maprintf +# define vaprintf curl_mvaprintf + +/* We define away the sprintf functions unconditonally since we don't want + internal code to be using them, intentionally or by mistake!*/ +# undef sprintf +# undef vsprintf +# define sprintf sprintf_was_used +# define vsprintf vsprintf_was_used + +#endif /* HEADER_CURL_PRINTF_H */ diff --git a/project/jni/curl/lib/curl_rand.c b/project/jni/curl/lib/curl_rand.c deleted file mode 100644 index 047b7f345..000000000 --- a/project/jni/curl/lib/curl_rand.c +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "setup.h" - -#include - -#include "curl_rand.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/* Private pseudo-random number seed. Unsigned integer >= 32bit. Threads - mutual exclusion is not implemented to acess it since we do not require - high quality random numbers (only used in form boudary generation). */ - -static unsigned int randseed; - -/* Pseudo-random number support. */ - -unsigned int Curl_rand(void) -{ - unsigned int r; - /* Return an unsigned 32-bit pseudo-random number. */ - r = randseed = randseed * 1103515245 + 12345; - return (r << 16) | ((r >> 16) & 0xFFFF); -} - -void Curl_srand(void) -{ - /* Randomize pseudo-random number sequence. */ - - randseed = (unsigned int) time(NULL); - Curl_rand(); - Curl_rand(); - Curl_rand(); -} - diff --git a/project/jni/curl/lib/curl_rtmp.c b/project/jni/curl/lib/curl_rtmp.c index bc1769e67..06dd047a4 100644 --- a/project/jni/curl/lib/curl_rtmp.c +++ b/project/jni/curl/lib/curl_rtmp.c @@ -5,11 +5,12 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * + * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. * Copyright (C) 2010, Howard Chu, * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,7 +21,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifdef USE_LIBRTMP @@ -28,12 +29,9 @@ #include "nonblock.h" /* for curlx_nonblock */ #include "progress.h" /* for Curl_pgrsSetUploadSize */ #include "transfer.h" +#include "warnless.h" #include #include - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -47,22 +45,22 @@ #define DEF_BUFTIME (2*60*60*1000) /* 2 hours */ -static CURLcode rtmp_setup(struct connectdata *conn); +static CURLcode rtmp_setup_connection(struct connectdata *conn); static CURLcode rtmp_do(struct connectdata *conn, bool *done); static CURLcode rtmp_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode rtmp_connect(struct connectdata *conn, bool *done); -static CURLcode rtmp_disconnect(struct connectdata *conn, bool dead_connection); +static CURLcode rtmp_disconnect(struct connectdata *conn, bool dead); static Curl_recv rtmp_recv; static Curl_send rtmp_send; /* - * RTMP protocol handler.h, based on http://rtmpdump.mplayerhq.hu + * RTMP protocol handler.h, based on https://rtmpdump.mplayerhq.hu */ const struct Curl_handler Curl_handler_rtmp = { "RTMP", /* scheme */ - rtmp_setup, /* setup_connection */ + rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ @@ -71,15 +69,18 @@ const struct Curl_handler Curl_handler_rtmp = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_RTMP, /* defport */ - PROT_RTMP /* protocol */ + CURLPROTO_RTMP, /* protocol */ + PROTOPT_NONE /* flags*/ }; const struct Curl_handler Curl_handler_rtmpt = { "RTMPT", /* scheme */ - rtmp_setup, /* setup_connection */ + rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ @@ -88,15 +89,18 @@ const struct Curl_handler Curl_handler_rtmpt = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_RTMPT, /* defport */ - PROT_RTMPT /* protocol */ + CURLPROTO_RTMPT, /* protocol */ + PROTOPT_NONE /* flags*/ }; const struct Curl_handler Curl_handler_rtmpe = { "RTMPE", /* scheme */ - rtmp_setup, /* setup_connection */ + rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ @@ -105,15 +109,18 @@ const struct Curl_handler Curl_handler_rtmpe = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_RTMP, /* defport */ - PROT_RTMPE /* protocol */ + CURLPROTO_RTMPE, /* protocol */ + PROTOPT_NONE /* flags*/ }; const struct Curl_handler Curl_handler_rtmpte = { "RTMPTE", /* scheme */ - rtmp_setup, /* setup_connection */ + rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ @@ -122,15 +129,18 @@ const struct Curl_handler Curl_handler_rtmpte = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_RTMPT, /* defport */ - PROT_RTMPTE /* protocol */ + CURLPROTO_RTMPTE, /* protocol */ + PROTOPT_NONE /* flags*/ }; const struct Curl_handler Curl_handler_rtmps = { "RTMPS", /* scheme */ - rtmp_setup, /* setup_connection */ + rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ @@ -139,14 +149,18 @@ const struct Curl_handler Curl_handler_rtmps = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_RTMPS, /* defport */ - PROT_RTMPS /* protocol */ + CURLPROTO_RTMPS, /* protocol */ + PROTOPT_NONE /* flags*/ }; + const struct Curl_handler Curl_handler_rtmpts = { "RTMPTS", /* scheme */ - rtmp_setup, /* setup_connection */ + rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ @@ -155,22 +169,24 @@ const struct Curl_handler Curl_handler_rtmpts = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_RTMPS, /* defport */ - PROT_RTMPTS /* protocol */ + CURLPROTO_RTMPTS, /* protocol */ + PROTOPT_NONE /* flags*/ }; -static CURLcode rtmp_setup(struct connectdata *conn) +static CURLcode rtmp_setup_connection(struct connectdata *conn) { RTMP *r = RTMP_Alloc(); - - if (!r) + if(!r) return CURLE_OUT_OF_MEMORY; RTMP_Init(r); RTMP_SetBufferMS(r, DEF_BUFTIME); - if (!RTMP_SetupURL(r, conn->data->change.url)) { + if(!RTMP_SetupURL(r, conn->data->change.url)) { RTMP_Free(r); return CURLE_URL_MALFORMAT; } @@ -181,24 +197,26 @@ static CURLcode rtmp_setup(struct connectdata *conn) static CURLcode rtmp_connect(struct connectdata *conn, bool *done) { RTMP *r = conn->proto.generic; - SET_RCVTIMEO(tv,10); + SET_RCVTIMEO(tv, 10); r->m_sb.sb_socket = conn->sock[FIRSTSOCKET]; /* We have to know if it's a write before we send the * connect request packet */ - if (conn->data->set.upload) + if(conn->data->set.upload) r->Link.protocol |= RTMP_FEATURE_WRITE; /* For plain streams, use the buffer toggle trick to keep data flowing */ - if (!(r->Link.lFlags & RTMP_LF_LIVE) && !(r->Link.protocol & RTMP_FEATURE_HTTP)) + if(!(r->Link.lFlags & RTMP_LF_LIVE) && + !(r->Link.protocol & RTMP_FEATURE_HTTP)) r->Link.lFlags |= RTMP_LF_BUFX; - curlx_nonblock(r->m_sb.sb_socket, FALSE); - setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); + (void)curlx_nonblock(r->m_sb.sb_socket, FALSE); + setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, + (char *)&tv, sizeof(tv)); - if (!RTMP_Connect1(r, NULL)) + if(!RTMP_Connect1(r, NULL)) return CURLE_FAILED_INIT; /* Clients must send a periodic BytesReceived report to the server */ @@ -214,13 +232,14 @@ static CURLcode rtmp_do(struct connectdata *conn, bool *done) { RTMP *r = conn->proto.generic; - if (!RTMP_ConnectStream(r, 0)) + if(!RTMP_ConnectStream(r, 0)) return CURLE_FAILED_INIT; - if (conn->data->set.upload) { - Curl_pgrsSetUploadSize(conn->data, conn->data->set.infilesize); + if(conn->data->set.upload) { + Curl_pgrsSetUploadSize(conn->data, conn->data->state.infilesize); Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL); - } else + } + else Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL); *done = TRUE; return CURLE_OK; @@ -241,7 +260,7 @@ static CURLcode rtmp_disconnect(struct connectdata *conn, { RTMP *r = conn->proto.generic; (void)dead_connection; - if (r) { + if(r) { conn->proto.generic = NULL; RTMP_Close(r); RTMP_Free(r); @@ -257,13 +276,14 @@ static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf, (void)sockindex; /* unused */ - nread = RTMP_Read(r, buf, len); - if (nread < 0) { - if (r->m_read.status == RTMP_READ_COMPLETE || + nread = RTMP_Read(r, buf, curlx_uztosi(len)); + if(nread < 0) { + if(r->m_read.status == RTMP_READ_COMPLETE || r->m_read.status == RTMP_READ_EOF) { conn->data->req.size = conn->data->req.bytecount; nread = 0; - } else + } + else *err = CURLE_RECV_ERROR; } return nread; @@ -277,10 +297,10 @@ static ssize_t rtmp_send(struct connectdata *conn, int sockindex, (void)sockindex; /* unused */ - num = RTMP_Write(r, (char *)buf, len); - if (num < 0) { + num = RTMP_Write(r, (char *)buf, curlx_uztosi(len)); + if(num < 0) *err = CURLE_SEND_ERROR; - } + return num; } #endif /* USE_LIBRTMP */ diff --git a/project/jni/curl/lib/curl_rtmp.h b/project/jni/curl/lib/curl_rtmp.h index 4a9e9e60c..3306e2200 100644 --- a/project/jni/curl/lib/curl_rtmp.h +++ b/project/jni/curl/lib/curl_rtmp.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/project/jni/curl/lib/curl_sasl.c b/project/jni/curl/lib/curl_sasl.c new file mode 100644 index 000000000..945d75232 --- /dev/null +++ b/project/jni/curl/lib/curl_sasl.c @@ -0,0 +1,1742 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * RFC2195 CRAM-MD5 authentication + * RFC2617 Basic and Digest Access Authentication + * RFC2831 DIGEST-MD5 authentication + * RFC4422 Simple Authentication and Security Layer (SASL) + * RFC4616 PLAIN authentication + * RFC6749 OAuth 2.0 Authorization Framework + * RFC7628 A Set of SASL Mechanisms for OAuth + * Draft LOGIN SASL Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include +#include "urldata.h" + +#include "curl_base64.h" +#include "curl_md5.h" +#include "vtls/vtls.h" +#include "curl_hmac.h" +#include "curl_sasl.h" +#include "warnless.h" +#include "strtok.h" +#include "strequal.h" +#include "rawstr.h" +#include "sendf.h" +#include "non-ascii.h" /* included for Curl_convert_... prototypes */ +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* Supported mechanisms */ +const struct { + const char *name; /* Name */ + size_t len; /* Name length */ + unsigned int bit; /* Flag bit */ +} mechtable[] = { + { "LOGIN", 5, SASL_MECH_LOGIN }, + { "PLAIN", 5, SASL_MECH_PLAIN }, + { "CRAM-MD5", 8, SASL_MECH_CRAM_MD5 }, + { "DIGEST-MD5", 10, SASL_MECH_DIGEST_MD5 }, + { "GSSAPI", 6, SASL_MECH_GSSAPI }, + { "EXTERNAL", 8, SASL_MECH_EXTERNAL }, + { "NTLM", 4, SASL_MECH_NTLM }, + { "XOAUTH2", 7, SASL_MECH_XOAUTH2 }, + { "OAUTHBEARER", 11, SASL_MECH_OAUTHBEARER }, + { ZERO_NULL, 0, 0 } +}; + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) && !defined(USE_WINDOWS_SSPI) +#define DIGEST_QOP_VALUE_AUTH (1 << 0) +#define DIGEST_QOP_VALUE_AUTH_INT (1 << 1) +#define DIGEST_QOP_VALUE_AUTH_CONF (1 << 2) + +#define DIGEST_QOP_VALUE_STRING_AUTH "auth" +#define DIGEST_QOP_VALUE_STRING_AUTH_INT "auth-int" +#define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf" + +/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines. + It converts digest text to ASCII so the MD5 will be correct for + what ultimately goes over the network. +*/ +#define CURL_OUTPUT_DIGEST_CONV(a, b) \ + result = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \ + if(result) { \ + free(b); \ + return result; \ + } + +#endif + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) +bool Curl_sasl_digest_get_pair(const char *str, char *value, char *content, + const char **endptr) +{ + int c; + bool starts_with_quote = FALSE; + bool escape = FALSE; + + for(c = DIGEST_MAX_VALUE_LENGTH - 1; (*str && (*str != '=') && c--); ) + *value++ = *str++; + *value = 0; + + if('=' != *str++) + /* eek, no match */ + return FALSE; + + if('\"' == *str) { + /* this starts with a quote so it must end with one as well! */ + str++; + starts_with_quote = TRUE; + } + + for(c = DIGEST_MAX_CONTENT_LENGTH - 1; *str && c--; str++) { + switch(*str) { + case '\\': + if(!escape) { + /* possibly the start of an escaped quote */ + escape = TRUE; + *content++ = '\\'; /* even though this is an escape character, we still + store it as-is in the target buffer */ + continue; + } + break; + + case ',': + if(!starts_with_quote) { + /* this signals the end of the content if we didn't get a starting + quote and then we do "sloppy" parsing */ + c = 0; /* the end */ + continue; + } + break; + + case '\r': + case '\n': + /* end of string */ + c = 0; + continue; + + case '\"': + if(!escape && starts_with_quote) { + /* end of string */ + c = 0; + continue; + } + break; + } + + escape = FALSE; + *content++ = *str; + } + + *content = 0; + *endptr = str; + + return TRUE; +} +#endif + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) && !defined(USE_WINDOWS_SSPI) +/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/ +static void sasl_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */ + unsigned char *dest) /* 33 bytes */ +{ + int i; + for(i = 0; i < 16; i++) + snprintf((char *)&dest[i*2], 3, "%02x", source[i]); +} + +/* Perform quoted-string escaping as described in RFC2616 and its errata */ +static char *sasl_digest_string_quoted(const char *source) +{ + char *dest, *d; + const char *s = source; + size_t n = 1; /* null terminator */ + + /* Calculate size needed */ + while(*s) { + ++n; + if(*s == '"' || *s == '\\') { + ++n; + } + ++s; + } + + dest = malloc(n); + if(dest) { + s = source; + d = dest; + while(*s) { + if(*s == '"' || *s == '\\') { + *d++ = '\\'; + } + *d++ = *s++; + } + *d = 0; + } + + return dest; +} + +/* Retrieves the value for a corresponding key from the challenge string + * returns TRUE if the key could be found, FALSE if it does not exists + */ +static bool sasl_digest_get_key_value(const char *chlg, + const char *key, + char *value, + size_t max_val_len, + char end_char) +{ + char *find_pos; + size_t i; + + find_pos = strstr(chlg, key); + if(!find_pos) + return FALSE; + + find_pos += strlen(key); + + for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i) + value[i] = *find_pos++; + value[i] = '\0'; + + return TRUE; +} + +static CURLcode sasl_digest_get_qop_values(const char *options, int *value) +{ + char *tmp; + char *token; + char *tok_buf; + + /* Initialise the output */ + *value = 0; + + /* Tokenise the list of qop values. Use a temporary clone of the buffer since + strtok_r() ruins it. */ + tmp = strdup(options); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + token = strtok_r(tmp, ",", &tok_buf); + while(token != NULL) { + if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) + *value |= DIGEST_QOP_VALUE_AUTH; + else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) + *value |= DIGEST_QOP_VALUE_AUTH_INT; + else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF)) + *value |= DIGEST_QOP_VALUE_AUTH_CONF; + + token = strtok_r(NULL, ",", &tok_buf); + } + + free(tmp); + + return CURLE_OK; +} +#endif /* !CURL_DISABLE_CRYPTO_AUTH && !USE_WINDOWS_SSPI */ + +#if !defined(USE_WINDOWS_SSPI) +/* + * Curl_sasl_build_spn() + * + * This is used to build a SPN string in the format service/instance. + * + * Parameters: + * + * service [in] - The service type such as www, smtp, pop or imap. + * instance [in] - The host name or realm. + * + * Returns a pointer to the newly allocated SPN. + */ +char *Curl_sasl_build_spn(const char *service, const char *instance) +{ + /* Generate and return our SPN */ + return aprintf("%s/%s", service, instance); +} +#endif + +/* + * sasl_create_plain_message() + * + * This is used to generate an already encoded PLAIN message ready + * for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name. + * passdwp [in] - The user's password. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +static CURLcode sasl_create_plain_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + char **outptr, size_t *outlen) +{ + CURLcode result; + char *plainauth; + size_t ulen; + size_t plen; + + ulen = strlen(userp); + plen = strlen(passwdp); + + plainauth = malloc(2 * ulen + plen + 2); + if(!plainauth) { + *outlen = 0; + *outptr = NULL; + return CURLE_OUT_OF_MEMORY; + } + + /* Calculate the reply */ + memcpy(plainauth, userp, ulen); + plainauth[ulen] = '\0'; + memcpy(plainauth + ulen + 1, userp, ulen); + plainauth[2 * ulen + 1] = '\0'; + memcpy(plainauth + 2 * ulen + 2, passwdp, plen); + + /* Base64 encode the reply */ + result = Curl_base64_encode(data, plainauth, 2 * ulen + plen + 2, outptr, + outlen); + free(plainauth); + return result; +} + +/* + * sasl_create_login_message() + * + * This is used to generate an already encoded LOGIN message containing the + * user name or password ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * valuep [in] - The user name or user's password. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +static CURLcode sasl_create_login_message(struct SessionHandle *data, + const char *valuep, char **outptr, + size_t *outlen) +{ + size_t vlen = strlen(valuep); + + if(!vlen) { + /* Calculate an empty reply */ + *outptr = strdup("="); + if(*outptr) { + *outlen = (size_t) 1; + return CURLE_OK; + } + + *outlen = 0; + return CURLE_OUT_OF_MEMORY; + } + + /* Base64 encode the value */ + return Curl_base64_encode(data, valuep, vlen, outptr, outlen); +} + +/* + * sasl_create_external_message() + * + * This is used to generate an already encoded EXTERNAL message containing + * the user name ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * user [in] - The user name. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +static CURLcode sasl_create_external_message(struct SessionHandle *data, + const char *user, char **outptr, + size_t *outlen) +{ + /* This is the same formatting as the login message. */ + return sasl_create_login_message(data, user, outptr, outlen); +} + +#ifndef CURL_DISABLE_CRYPTO_AUTH +/* + * sasl_decode_cram_md5_message() + * + * This is used to decode an already encoded CRAM-MD5 challenge message. + * + * Parameters: + * + * chlg64 [in] - The base64 encoded challenge message. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +static CURLcode sasl_decode_cram_md5_message(const char *chlg64, char **outptr, + size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t chlg64len = strlen(chlg64); + + *outptr = NULL; + *outlen = 0; + + /* Decode the challenge if necessary */ + if(chlg64len && *chlg64 != '=') + result = Curl_base64_decode(chlg64, (unsigned char **) outptr, outlen); + + return result; +} + +/* + * sasl_create_cram_md5_message() + * + * This is used to generate an already encoded CRAM-MD5 response message ready + * for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg [in] - The challenge. + * userp [in] - The user name. + * passdwp [in] - The user's password. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +static CURLcode sasl_create_cram_md5_message(struct SessionHandle *data, + const char *chlg, + const char *userp, + const char *passwdp, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + HMAC_context *ctxt; + unsigned char digest[MD5_DIGEST_LEN]; + char *response; + + if(chlg) + chlglen = strlen(chlg); + + /* Compute the digest using the password as the key */ + ctxt = Curl_HMAC_init(Curl_HMAC_MD5, + (const unsigned char *) passwdp, + curlx_uztoui(strlen(passwdp))); + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + /* Update the digest with the given challenge */ + if(chlglen > 0) + Curl_HMAC_update(ctxt, (const unsigned char *) chlg, + curlx_uztoui(chlglen)); + + /* Finalise the digest */ + Curl_HMAC_final(ctxt, digest); + + /* Generate the response */ + response = aprintf( + "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + userp, digest[0], digest[1], digest[2], digest[3], digest[4], + digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], + digest[11], digest[12], digest[13], digest[14], digest[15]); + if(!response) + return CURLE_OUT_OF_MEMORY; + + /* Base64 encode the response */ + result = Curl_base64_encode(data, response, 0, outptr, outlen); + + free(response); + + return result; +} + +#ifndef USE_WINDOWS_SSPI +/* + * sasl_decode_digest_md5_message() + * + * This is used internally to decode an already encoded DIGEST-MD5 challenge + * message into the seperate attributes. + * + * Parameters: + * + * chlg64 [in] - The base64 encoded challenge message. + * nonce [in/out] - The buffer where the nonce will be stored. + * nlen [in] - The length of the nonce buffer. + * realm [in/out] - The buffer where the realm will be stored. + * rlen [in] - The length of the realm buffer. + * alg [in/out] - The buffer where the algorithm will be stored. + * alen [in] - The length of the algorithm buffer. + * qop [in/out] - The buffer where the qop-options will be stored. + * qlen [in] - The length of the qop buffer. + * + * Returns CURLE_OK on success. + */ +static CURLcode sasl_decode_digest_md5_message(const char *chlg64, + char *nonce, size_t nlen, + char *realm, size_t rlen, + char *alg, size_t alen, + char *qop, size_t qlen) +{ + CURLcode result = CURLE_OK; + unsigned char *chlg = NULL; + size_t chlglen = 0; + size_t chlg64len = strlen(chlg64); + + /* Decode the base-64 encoded challenge message */ + if(chlg64len && *chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) + return CURLE_BAD_CONTENT_ENCODING; + + /* Retrieve nonce string from the challenge */ + if(!sasl_digest_get_key_value((char *)chlg, "nonce=\"", nonce, nlen, '\"')) { + free(chlg); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Retrieve realm string from the challenge */ + if(!sasl_digest_get_key_value((char *)chlg, "realm=\"", realm, rlen, '\"')) { + /* Challenge does not have a realm, set empty string [RFC2831] page 6 */ + strcpy(realm, ""); + } + + /* Retrieve algorithm string from the challenge */ + if(!sasl_digest_get_key_value((char *)chlg, "algorithm=", alg, alen, ',')) { + free(chlg); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Retrieve qop-options string from the challenge */ + if(!sasl_digest_get_key_value((char *)chlg, "qop=\"", qop, qlen, '\"')) { + free(chlg); + return CURLE_BAD_CONTENT_ENCODING; + } + + free(chlg); + + return CURLE_OK; +} + +/* + * Curl_sasl_create_digest_md5_message() + * + * This is used to generate an already encoded DIGEST-MD5 response message + * ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg64 [in] - The base64 encoded challenge message. + * userp [in] - The user name. + * passdwp [in] - The user's password. + * service [in] - The service type such as www, smtp, pop or imap. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, + const char *chlg64, + const char *userp, + const char *passwdp, + const char *service, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t i; + MD5_context *ctxt; + char *response = NULL; + unsigned char digest[MD5_DIGEST_LEN]; + char HA1_hex[2 * MD5_DIGEST_LEN + 1]; + char HA2_hex[2 * MD5_DIGEST_LEN + 1]; + char resp_hash_hex[2 * MD5_DIGEST_LEN + 1]; + char nonce[64]; + char realm[128]; + char algorithm[64]; + char qop_options[64]; + int qop_values; + char cnonce[33]; + unsigned int entropy[4]; + char nonceCount[] = "00000001"; + char method[] = "AUTHENTICATE"; + char qop[] = DIGEST_QOP_VALUE_STRING_AUTH; + char *spn = NULL; + + /* Decode the challange message */ + result = sasl_decode_digest_md5_message(chlg64, nonce, sizeof(nonce), + realm, sizeof(realm), + algorithm, sizeof(algorithm), + qop_options, sizeof(qop_options)); + if(result) + return result; + + /* We only support md5 sessions */ + if(strcmp(algorithm, "md5-sess") != 0) + return CURLE_BAD_CONTENT_ENCODING; + + /* Get the qop-values from the qop-options */ + result = sasl_digest_get_qop_values(qop_options, &qop_values); + if(result) + return result; + + /* We only support auth quality-of-protection */ + if(!(qop_values & DIGEST_QOP_VALUE_AUTH)) + return CURLE_BAD_CONTENT_ENCODING; + + /* Generate 16 bytes of random data */ + entropy[0] = Curl_rand(data); + entropy[1] = Curl_rand(data); + entropy[2] = Curl_rand(data); + entropy[3] = Curl_rand(data); + + /* Convert the random data into a 32 byte hex string */ + snprintf(cnonce, sizeof(cnonce), "%08x%08x%08x%08x", + entropy[0], entropy[1], entropy[2], entropy[3]); + + /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */ + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + Curl_MD5_update(ctxt, (const unsigned char *) userp, + curlx_uztoui(strlen(userp))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) realm, + curlx_uztoui(strlen(realm))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) passwdp, + curlx_uztoui(strlen(passwdp))); + Curl_MD5_final(ctxt, digest); + + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) nonce, + curlx_uztoui(strlen(nonce))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) cnonce, + curlx_uztoui(strlen(cnonce))); + Curl_MD5_final(ctxt, digest); + + /* Convert calculated 16 octet hex into 32 bytes string */ + for(i = 0; i < MD5_DIGEST_LEN; i++) + snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]); + + /* Generate our SPN */ + spn = Curl_sasl_build_spn(service, realm); + if(!spn) + return CURLE_OUT_OF_MEMORY; + + /* Calculate H(A2) */ + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) { + free(spn); + + return CURLE_OUT_OF_MEMORY; + } + + Curl_MD5_update(ctxt, (const unsigned char *) method, + curlx_uztoui(strlen(method))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) spn, + curlx_uztoui(strlen(spn))); + Curl_MD5_final(ctxt, digest); + + for(i = 0; i < MD5_DIGEST_LEN; i++) + snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]); + + /* Now calculate the response hash */ + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) { + free(spn); + + return CURLE_OUT_OF_MEMORY; + } + + Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) nonce, + curlx_uztoui(strlen(nonce))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + + Curl_MD5_update(ctxt, (const unsigned char *) nonceCount, + curlx_uztoui(strlen(nonceCount))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) cnonce, + curlx_uztoui(strlen(cnonce))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) qop, + curlx_uztoui(strlen(qop))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + + Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN); + Curl_MD5_final(ctxt, digest); + + for(i = 0; i < MD5_DIGEST_LEN; i++) + snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]); + + /* Generate the response */ + response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\"," + "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s," + "qop=%s", + userp, realm, nonce, + cnonce, nonceCount, spn, resp_hash_hex, qop); + free(spn); + if(!response) + return CURLE_OUT_OF_MEMORY; + + /* Base64 encode the response */ + result = Curl_base64_encode(data, response, 0, outptr, outlen); + + free(response); + + return result; +} + +/* + * Curl_sasl_decode_digest_http_message() + * + * This is used to decode a HTTP DIGEST challenge message into the seperate + * attributes. + * + * Parameters: + * + * chlg [in] - The challenge message. + * digest [in/out] - The digest data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_decode_digest_http_message(const char *chlg, + struct digestdata *digest) +{ + bool before = FALSE; /* got a nonce before */ + bool foundAuth = FALSE; + bool foundAuthInt = FALSE; + char *token = NULL; + char *tmp = NULL; + + /* If we already have received a nonce, keep that in mind */ + if(digest->nonce) + before = TRUE; + + /* Clean up any former leftovers and initialise to defaults */ + Curl_sasl_digest_cleanup(digest); + + for(;;) { + char value[DIGEST_MAX_VALUE_LENGTH]; + char content[DIGEST_MAX_CONTENT_LENGTH]; + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Extract a value=content pair */ + if(Curl_sasl_digest_get_pair(chlg, value, content, &chlg)) { + if(Curl_raw_equal(value, "nonce")) { + free(digest->nonce); + digest->nonce = strdup(content); + if(!digest->nonce) + return CURLE_OUT_OF_MEMORY; + } + else if(Curl_raw_equal(value, "stale")) { + if(Curl_raw_equal(content, "true")) { + digest->stale = TRUE; + digest->nc = 1; /* we make a new nonce now */ + } + } + else if(Curl_raw_equal(value, "realm")) { + free(digest->realm); + digest->realm = strdup(content); + if(!digest->realm) + return CURLE_OUT_OF_MEMORY; + } + else if(Curl_raw_equal(value, "opaque")) { + free(digest->opaque); + digest->opaque = strdup(content); + if(!digest->opaque) + return CURLE_OUT_OF_MEMORY; + } + else if(Curl_raw_equal(value, "qop")) { + char *tok_buf; + /* Tokenize the list and choose auth if possible, use a temporary + clone of the buffer since strtok_r() ruins it */ + tmp = strdup(content); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + token = strtok_r(tmp, ",", &tok_buf); + while(token != NULL) { + if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) { + foundAuth = TRUE; + } + else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) { + foundAuthInt = TRUE; + } + token = strtok_r(NULL, ",", &tok_buf); + } + + free(tmp); + + /* Select only auth or auth-int. Otherwise, ignore */ + if(foundAuth) { + free(digest->qop); + digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH); + if(!digest->qop) + return CURLE_OUT_OF_MEMORY; + } + else if(foundAuthInt) { + free(digest->qop); + digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH_INT); + if(!digest->qop) + return CURLE_OUT_OF_MEMORY; + } + } + else if(Curl_raw_equal(value, "algorithm")) { + free(digest->algorithm); + digest->algorithm = strdup(content); + if(!digest->algorithm) + return CURLE_OUT_OF_MEMORY; + + if(Curl_raw_equal(content, "MD5-sess")) + digest->algo = CURLDIGESTALGO_MD5SESS; + else if(Curl_raw_equal(content, "MD5")) + digest->algo = CURLDIGESTALGO_MD5; + else + return CURLE_BAD_CONTENT_ENCODING; + } + else { + /* unknown specifier, ignore it! */ + } + } + else + break; /* we're done here */ + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Allow the list to be comma-separated */ + if(',' == *chlg) + chlg++; + } + + /* We had a nonce since before, and we got another one now without + 'stale=true'. This means we provided bad credentials in the previous + request */ + if(before && !digest->stale) + return CURLE_BAD_CONTENT_ENCODING; + + /* We got this header without a nonce, that's a bad Digest line! */ + if(!digest->nonce) + return CURLE_BAD_CONTENT_ENCODING; + + return CURLE_OK; +} + +/* + * Curl_sasl_create_digest_http_message() + * + * This is used to generate a HTTP DIGEST response message ready for sending + * to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name. + * passdwp [in] - The user's password. + * request [in] - The HTTP request. + * uripath [in] - The path of the HTTP uri. + * digest [in/out] - The digest data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uripath, + struct digestdata *digest, + char **outptr, size_t *outlen) +{ + CURLcode result; + unsigned char md5buf[16]; /* 16 bytes/128 bits */ + unsigned char request_digest[33]; + unsigned char *md5this; + unsigned char ha1[33];/* 32 digits and 1 zero byte */ + unsigned char ha2[33];/* 32 digits and 1 zero byte */ + char cnoncebuf[33]; + char *cnonce = NULL; + size_t cnonce_sz = 0; + char *userp_quoted; + char *response = NULL; + char *tmp = NULL; + + if(!digest->nc) + digest->nc = 1; + + if(!digest->cnonce) { + snprintf(cnoncebuf, sizeof(cnoncebuf), "%08x%08x%08x%08x", + Curl_rand(data), Curl_rand(data), + Curl_rand(data), Curl_rand(data)); + + result = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), + &cnonce, &cnonce_sz); + if(result) + return result; + + digest->cnonce = cnonce; + } + + /* + If the algorithm is "MD5" or unspecified (which then defaults to MD5): + + A1 = unq(username-value) ":" unq(realm-value) ":" passwd + + If the algorithm is "MD5-sess" then: + + A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd ) ":" + unq(nonce-value) ":" unq(cnonce-value) + */ + + md5this = (unsigned char *) + aprintf("%s:%s:%s", userp, digest->realm, passwdp); + if(!md5this) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, md5this); + free(md5this); + sasl_digest_md5_to_ascii(md5buf, ha1); + + if(digest->algo == CURLDIGESTALGO_MD5SESS) { + /* nonce and cnonce are OUTSIDE the hash */ + tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, tmp); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, (unsigned char *)tmp); + free(tmp); + sasl_digest_md5_to_ascii(md5buf, ha1); + } + + /* + If the "qop" directive's value is "auth" or is unspecified, then A2 is: + + A2 = Method ":" digest-uri-value + + If the "qop" value is "auth-int", then A2 is: + + A2 = Method ":" digest-uri-value ":" H(entity-body) + + (The "Method" value is the HTTP request method as specified in section + 5.1.1 of RFC 2616) + */ + + md5this = (unsigned char *)aprintf("%s:%s", request, uripath); + + if(digest->qop && Curl_raw_equal(digest->qop, "auth-int")) { + /* We don't support auth-int for PUT or POST at the moment. + TODO: replace md5 of empty string with entity-body for PUT/POST */ + unsigned char *md5this2 = (unsigned char *) + aprintf("%s:%s", md5this, "d41d8cd98f00b204e9800998ecf8427e"); + free(md5this); + md5this = md5this2; + } + + if(!md5this) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, md5this); + free(md5this); + sasl_digest_md5_to_ascii(md5buf, ha2); + + if(digest->qop) { + md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s", + ha1, + digest->nonce, + digest->nc, + digest->cnonce, + digest->qop, + ha2); + } + else { + md5this = (unsigned char *)aprintf("%s:%s:%s", + ha1, + digest->nonce, + ha2); + } + + if(!md5this) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, md5this); + free(md5this); + sasl_digest_md5_to_ascii(md5buf, request_digest); + + /* for test case 64 (snooped from a Mozilla 1.3a request) + + Authorization: Digest username="testuser", realm="testrealm", \ + nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca" + + Digest parameters are all quoted strings. Username which is provided by + the user will need double quotes and backslashes within it escaped. For + the other fields, this shouldn't be an issue. realm, nonce, and opaque + are copied as is from the server, escapes and all. cnonce is generated + with web-safe characters. uri is already percent encoded. nc is 8 hex + characters. algorithm and qop with standard values only contain web-safe + characters. + */ + userp_quoted = sasl_digest_string_quoted(userp); + if(!userp_quoted) + return CURLE_OUT_OF_MEMORY; + + if(digest->qop) { + response = aprintf("username=\"%s\", " + "realm=\"%s\", " + "nonce=\"%s\", " + "uri=\"%s\", " + "cnonce=\"%s\", " + "nc=%08x, " + "qop=%s, " + "response=\"%s\"", + userp_quoted, + digest->realm, + digest->nonce, + uripath, + digest->cnonce, + digest->nc, + digest->qop, + request_digest); + + if(Curl_raw_equal(digest->qop, "auth")) + digest->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 + padded which tells to the server how many times you are + using the same nonce in the qop=auth mode */ + } + else { + response = aprintf("username=\"%s\", " + "realm=\"%s\", " + "nonce=\"%s\", " + "uri=\"%s\", " + "response=\"%s\"", + userp_quoted, + digest->realm, + digest->nonce, + uripath, + request_digest); + } + free(userp_quoted); + if(!response) + return CURLE_OUT_OF_MEMORY; + + /* Add the optional fields */ + if(digest->opaque) { + /* Append the opaque */ + tmp = aprintf("%s, opaque=\"%s\"", response, digest->opaque); + free(response); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + response = tmp; + } + + if(digest->algorithm) { + /* Append the algorithm */ + tmp = aprintf("%s, algorithm=\"%s\"", response, digest->algorithm); + free(response); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + response = tmp; + } + + /* Return the output */ + *outptr = response; + *outlen = strlen(response); + + return CURLE_OK; +} + +/* + * Curl_sasl_digest_cleanup() + * + * This is used to clean up the digest specific data. + * + * Parameters: + * + * digest [in/out] - The digest data struct being cleaned up. + * + */ +void Curl_sasl_digest_cleanup(struct digestdata *digest) +{ + Curl_safefree(digest->nonce); + Curl_safefree(digest->cnonce); + Curl_safefree(digest->realm); + Curl_safefree(digest->opaque); + Curl_safefree(digest->qop); + Curl_safefree(digest->algorithm); + + digest->nc = 0; + digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */ + digest->stale = FALSE; /* default means normal, not stale */ +} +#endif /* !USE_WINDOWS_SSPI */ + +#endif /* CURL_DISABLE_CRYPTO_AUTH */ + +#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) +/* + * Curl_sasl_ntlm_cleanup() + * + * This is used to clean up the NTLM specific data. + * + * Parameters: + * + * ntlm [in/out] - The NTLM data struct being cleaned up. + * + */ +void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm) +{ + /* Free the target info */ + Curl_safefree(ntlm->target_info); + + /* Reset any variables */ + ntlm->target_info_len = 0; +} +#endif /* USE_NTLM && !USE_WINDOWS_SSPI*/ + +/* + * sasl_create_oauth_bearer_message() + * + * This is used to generate an already encoded OAuth 2.0 message ready for + * sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * user [in] - The user name. + * host [in] - The host name (for OAUTHBEARER). + * port [in] - The port (for OAUTHBEARER when not Port 80). + * bearer [in] - The bearer token. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +static CURLcode sasl_create_oauth_bearer_message(struct SessionHandle *data, + const char *user, + const char *host, + const long port, + const char *bearer, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + char *oauth = NULL; + + /* Generate the message */ + if(host == NULL && (port == 0 || port == 80)) + oauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer); + else if(port == 0 || port == 80) + oauth = aprintf("user=%s\1host=%s\1auth=Bearer %s\1\1", user, host, + bearer); + else + oauth = aprintf("user=%s\1host=%s\1port=%ld\1auth=Bearer %s\1\1", user, + host, port, bearer); + if(!oauth) + return CURLE_OUT_OF_MEMORY; + + /* Base64 encode the reply */ + result = Curl_base64_encode(data, oauth, strlen(oauth), outptr, outlen); + + free(oauth); + + return result; +} + +/* + * Curl_sasl_cleanup() + * + * This is used to cleanup any libraries or curl modules used by the sasl + * functions. + * + * Parameters: + * + * conn [in] - The connection data. + * authused [in] - The authentication mechanism used. + */ +void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused) +{ +#if defined(USE_KERBEROS5) + /* Cleanup the gssapi structure */ + if(authused == SASL_MECH_GSSAPI) { + Curl_sasl_gssapi_cleanup(&conn->krb5); + } +#endif + +#if defined(USE_NTLM) + /* Cleanup the NTLM structure */ + if(authused == SASL_MECH_NTLM) { + Curl_sasl_ntlm_cleanup(&conn->ntlm); + } +#endif + +#if !defined(USE_KERBEROS5) && !defined(USE_NTLM) + /* Reserved for future use */ + (void)conn; + (void)authused; +#endif +} + +/* + * Curl_sasl_decode_mech() + * + * Convert a SASL mechanism name into a token. + * + * Parameters: + * + * ptr [in] - The mechanism string. + * maxlen [in] - Maximum mechanism string length. + * len [out] - If not NULL, effective name length. + * + * Returns the SASL mechanism token or 0 if no match. + */ +unsigned int Curl_sasl_decode_mech(const char *ptr, size_t maxlen, size_t *len) +{ + unsigned int i; + char c; + + for(i = 0; mechtable[i].name; i++) { + if(maxlen >= mechtable[i].len && + !memcmp(ptr, mechtable[i].name, mechtable[i].len)) { + if(len) + *len = mechtable[i].len; + + if(maxlen == mechtable[i].len) + return mechtable[i].bit; + + c = ptr[mechtable[i].len]; + if(!ISUPPER(c) && !ISDIGIT(c) && c != '-' && c != '_') + return mechtable[i].bit; + } + } + + return 0; +} + +/* + * Curl_sasl_parse_url_auth_option() + * + * Parse the URL login options. + */ +CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, + const char *value, size_t len) +{ + CURLcode result = CURLE_OK; + unsigned int mechbit; + size_t mechlen; + + if(!len) + return CURLE_URL_MALFORMAT; + + if(sasl->resetprefs) { + sasl->resetprefs = FALSE; + sasl->prefmech = SASL_AUTH_NONE; + } + + if(strnequal(value, "*", len)) + sasl->prefmech = SASL_AUTH_DEFAULT; + else { + mechbit = Curl_sasl_decode_mech(value, len, &mechlen); + if(mechbit && mechlen == len) + sasl->prefmech |= mechbit; + else + result = CURLE_URL_MALFORMAT; + } + + return result; +} + +/* + * Curl_sasl_init() + * + * Initializes the SASL structure. + */ +void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params) +{ + sasl->params = params; /* Set protocol dependent parameters */ + sasl->state = SASL_STOP; /* Not yet running */ + sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */ + sasl->prefmech = SASL_AUTH_DEFAULT; /* Prefer all mechanisms */ + sasl->authused = SASL_AUTH_NONE; /* No the authentication mechanism used */ + sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */ + sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */ + sasl->force_ir = FALSE; /* Respect external option */ +} + +/* + * state() + * + * This is the ONLY way to change SASL state! + */ +static void state(struct SASL *sasl, struct connectdata *conn, + saslstate newstate) +{ +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ + static const char * const names[]={ + "STOP", + "PLAIN", + "LOGIN", + "LOGIN_PASSWD", + "EXTERNAL", + "CRAMMD5", + "DIGESTMD5", + "DIGESTMD5_RESP", + "NTLM", + "NTLM_TYPE2MSG", + "GSSAPI", + "GSSAPI_TOKEN", + "GSSAPI_NO_DATA", + "OAUTH2", + "OAUTH2_RESP", + "CANCEL", + "FINAL", + /* LAST */ + }; + + if(sasl->state != newstate) + infof(conn->data, "SASL %p state change from %s to %s\n", + (void *)sasl, names[sasl->state], names[newstate]); +#else + (void) conn; +#endif + + sasl->state = newstate; +} + +/* + * Curl_sasl_can_authenticate() + * + * Check if we have enough auth data and capabilities to authenticate. + */ +bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn) +{ + /* Have credentials been provided? */ + if(conn->bits.user_passwd) + return TRUE; + + /* EXTERNAL can authenticate without a user name and/or password */ + if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL) + return TRUE; + + return FALSE; +} + +/* + * Curl_sasl_start() + * + * Calculate the required login details for SASL authentication. + */ +CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, + bool force_ir, saslprogress *progress) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + unsigned int enabledmechs; + const char *mech = NULL; + char *resp = NULL; + size_t len = 0; + saslstate state1 = SASL_STOP; + saslstate state2 = SASL_FINAL; + + sasl->force_ir = force_ir; /* Latch for future use */ + sasl->authused = 0; /* No mechanism used yet */ + enabledmechs = sasl->authmechs & sasl->prefmech; + *progress = SASL_IDLE; + + /* Calculate the supported authentication mechanism, by decreasing order of + security, as well as the initial response where appropriate */ + if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) { + mech = SASL_MECH_STRING_EXTERNAL; + state1 = SASL_EXTERNAL; + sasl->authused = SASL_MECH_EXTERNAL; + + if(force_ir || data->set.sasl_ir) + result = sasl_create_external_message(data, conn->user, &resp, &len); + } + else if(conn->bits.user_passwd) { +#if defined(USE_KERBEROS5) + if(enabledmechs & SASL_MECH_GSSAPI) { + sasl->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */ + mech = SASL_MECH_STRING_GSSAPI; + state1 = SASL_GSSAPI; + state2 = SASL_GSSAPI_TOKEN; + sasl->authused = SASL_MECH_GSSAPI; + + if(force_ir || data->set.sasl_ir) + result = Curl_sasl_create_gssapi_user_message(data, conn->user, + conn->passwd, + sasl->params->service, + sasl->mutual_auth, + NULL, &conn->krb5, + &resp, &len); + } + else +#endif +#ifndef CURL_DISABLE_CRYPTO_AUTH + if(enabledmechs & SASL_MECH_DIGEST_MD5) { + mech = SASL_MECH_STRING_DIGEST_MD5; + state1 = SASL_DIGESTMD5; + sasl->authused = SASL_MECH_DIGEST_MD5; + } + else if(enabledmechs & SASL_MECH_CRAM_MD5) { + mech = SASL_MECH_STRING_CRAM_MD5; + state1 = SASL_CRAMMD5; + sasl->authused = SASL_MECH_CRAM_MD5; + } + else +#endif +#ifdef USE_NTLM + if(enabledmechs & SASL_MECH_NTLM) { + mech = SASL_MECH_STRING_NTLM; + state1 = SASL_NTLM; + state2 = SASL_NTLM_TYPE2MSG; + sasl->authused = SASL_MECH_NTLM; + + if(force_ir || data->set.sasl_ir) + result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, + &conn->ntlm, &resp, &len); + } + else +#endif + if((enabledmechs & SASL_MECH_OAUTHBEARER) && conn->oauth_bearer) { + mech = SASL_MECH_STRING_OAUTHBEARER; + state1 = SASL_OAUTH2; + state2 = SASL_OAUTH2_RESP; + sasl->authused = SASL_MECH_OAUTHBEARER; + + if(force_ir || data->set.sasl_ir) + result = sasl_create_oauth_bearer_message(data, conn->user, + conn->host.name, + conn->port, + conn->oauth_bearer, + &resp, &len); + } + else if((enabledmechs & SASL_MECH_XOAUTH2) && conn->oauth_bearer) { + mech = SASL_MECH_STRING_XOAUTH2; + state1 = SASL_OAUTH2; + sasl->authused = SASL_MECH_XOAUTH2; + + if(force_ir || data->set.sasl_ir) + result = sasl_create_oauth_bearer_message(data, conn->user, + NULL, 0, + conn->oauth_bearer, + &resp, &len); + } + else if(enabledmechs & SASL_MECH_LOGIN) { + mech = SASL_MECH_STRING_LOGIN; + state1 = SASL_LOGIN; + state2 = SASL_LOGIN_PASSWD; + sasl->authused = SASL_MECH_LOGIN; + + if(force_ir || data->set.sasl_ir) + result = sasl_create_login_message(data, conn->user, &resp, &len); + } + else if(enabledmechs & SASL_MECH_PLAIN) { + mech = SASL_MECH_STRING_PLAIN; + state1 = SASL_PLAIN; + sasl->authused = SASL_MECH_PLAIN; + + if(force_ir || data->set.sasl_ir) + result = sasl_create_plain_message(data, conn->user, conn->passwd, + &resp, &len); + } + } + + if(!result) { + if(resp && sasl->params->maxirlen && + strlen(mech) + len > sasl->params->maxirlen) { + free(resp); + resp = NULL; + } + + if(mech) { + result = sasl->params->sendauth(conn, mech, resp); + if(!result) { + *progress = SASL_INPROGRESS; + state(sasl, conn, resp? state2: state1); + } + } + } + + free(resp); + + return result; +} + +/* + * Curl_sasl_continue() + * + * Continue the authentication. + */ +CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, + int code, saslprogress *progress) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + saslstate newstate = SASL_FINAL; + char *resp = NULL; +#if !defined(CURL_DISABLE_CRYPTO_AUTH) + char *serverdata; + char *chlg = NULL; + size_t chlglen = 0; +#endif + size_t len = 0; + + *progress = SASL_INPROGRESS; + + if(sasl->state == SASL_FINAL) { + if(code != sasl->params->finalcode) + result = CURLE_LOGIN_DENIED; + *progress = SASL_DONE; + state(sasl, conn, SASL_STOP); + return result; + } + + if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP && + code != sasl->params->contcode) { + *progress = SASL_DONE; + state(sasl, conn, SASL_STOP); + return CURLE_LOGIN_DENIED; + } + + switch(sasl->state) { + case SASL_STOP: + *progress = SASL_DONE; + return result; + case SASL_PLAIN: + result = sasl_create_plain_message(data, conn->user, conn->passwd, &resp, + &len); + break; + case SASL_LOGIN: + result = sasl_create_login_message(data, conn->user, &resp, &len); + newstate = SASL_LOGIN_PASSWD; + break; + case SASL_LOGIN_PASSWD: + result = sasl_create_login_message(data, conn->passwd, &resp, &len); + break; + case SASL_EXTERNAL: + result = sasl_create_external_message(data, conn->user, &resp, &len); + break; + +#ifndef CURL_DISABLE_CRYPTO_AUTH + case SASL_CRAMMD5: + sasl->params->getmessage(data->state.buffer, &serverdata); + result = sasl_decode_cram_md5_message(serverdata, &chlg, &chlglen); + if(!result) + result = sasl_create_cram_md5_message(data, chlg, conn->user, + conn->passwd, &resp, &len); + free(chlg); + break; + case SASL_DIGESTMD5: + sasl->params->getmessage(data->state.buffer, &serverdata); + result = Curl_sasl_create_digest_md5_message(data, serverdata, + conn->user, conn->passwd, + sasl->params->service, + &resp, &len); + newstate = SASL_DIGESTMD5_RESP; + break; + case SASL_DIGESTMD5_RESP: + resp = strdup(""); + if(!resp) + result = CURLE_OUT_OF_MEMORY; + break; +#endif + +#ifdef USE_NTLM + case SASL_NTLM: + /* Create the type-1 message */ + result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, + &conn->ntlm, &resp, &len); + newstate = SASL_NTLM_TYPE2MSG; + break; + case SASL_NTLM_TYPE2MSG: + /* Decode the type-2 message */ + sasl->params->getmessage(data->state.buffer, &serverdata); + result = Curl_sasl_decode_ntlm_type2_message(data, serverdata, + &conn->ntlm); + if(!result) + result = Curl_sasl_create_ntlm_type3_message(data, conn->user, + conn->passwd, &conn->ntlm, + &resp, &len); + break; +#endif + +#if defined(USE_KERBEROS5) + case SASL_GSSAPI: + result = Curl_sasl_create_gssapi_user_message(data, conn->user, + conn->passwd, + sasl->params->service, + sasl->mutual_auth, NULL, + &conn->krb5, + &resp, &len); + newstate = SASL_GSSAPI_TOKEN; + break; + case SASL_GSSAPI_TOKEN: + sasl->params->getmessage(data->state.buffer, &serverdata); + if(sasl->mutual_auth) { + /* Decode the user token challenge and create the optional response + message */ + result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL, + sasl->mutual_auth, + serverdata, &conn->krb5, + &resp, &len); + newstate = SASL_GSSAPI_NO_DATA; + } + else + /* Decode the security challenge and create the response message */ + result = Curl_sasl_create_gssapi_security_message(data, serverdata, + &conn->krb5, + &resp, &len); + break; + case SASL_GSSAPI_NO_DATA: + sasl->params->getmessage(data->state.buffer, &serverdata); + /* Decode the security challenge and create the response message */ + result = Curl_sasl_create_gssapi_security_message(data, serverdata, + &conn->krb5, + &resp, &len); + break; +#endif + + case SASL_OAUTH2: + /* Create the authorisation message */ + if(sasl->authused == SASL_MECH_OAUTHBEARER) { + result = sasl_create_oauth_bearer_message(data, conn->user, + conn->host.name, + conn->port, + conn->oauth_bearer, + &resp, &len); + + /* Failures maybe sent by the server as continuations for OAUTHBEARER */ + newstate = SASL_OAUTH2_RESP; + } + else + result = sasl_create_oauth_bearer_message(data, conn->user, + NULL, 0, + conn->oauth_bearer, + &resp, &len); + break; + + case SASL_OAUTH2_RESP: + /* The continuation is optional so check the response code */ + if(code == sasl->params->finalcode) { + /* Final response was received so we are done */ + *progress = SASL_DONE; + state(sasl, conn, SASL_STOP); + return result; + } + else if(code == sasl->params->contcode) { + /* Acknowledge the continuation by sending a 0x01 response base64 + encoded */ + resp = strdup("AQ=="); + if(!resp) + result = CURLE_OUT_OF_MEMORY; + break; + } + else { + *progress = SASL_DONE; + state(sasl, conn, SASL_STOP); + return CURLE_LOGIN_DENIED; + } + + case SASL_CANCEL: + /* Remove the offending mechanism from the supported list */ + sasl->authmechs ^= sasl->authused; + + /* Start an alternative SASL authentication */ + result = Curl_sasl_start(sasl, conn, sasl->force_ir, progress); + newstate = sasl->state; /* Use state from Curl_sasl_start() */ + break; + default: + failf(data, "Unsupported SASL authentication mechanism"); + result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */ + break; + } + + switch(result) { + case CURLE_BAD_CONTENT_ENCODING: + /* Cancel dialog */ + result = sasl->params->sendcont(conn, "*"); + newstate = SASL_CANCEL; + break; + case CURLE_OK: + if(resp) + result = sasl->params->sendcont(conn, resp); + break; + default: + newstate = SASL_STOP; /* Stop on error */ + *progress = SASL_DONE; + break; + } + + free(resp); + + state(sasl, conn, newstate); + + return result; +} diff --git a/project/jni/curl/lib/curl_sasl.h b/project/jni/curl/lib/curl_sasl.h new file mode 100644 index 000000000..2175e03d4 --- /dev/null +++ b/project/jni/curl/lib/curl_sasl.h @@ -0,0 +1,255 @@ +#ifndef HEADER_CURL_SASL_H +#define HEADER_CURL_SASL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include + +struct SessionHandle; +struct connectdata; + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) +struct digestdata; +#endif + +#if defined(USE_NTLM) +struct ntlmdata; +#endif + +#if defined(USE_KERBEROS5) +struct kerberos5data; +#endif + +/* Authentication mechanism flags */ +#define SASL_MECH_LOGIN (1 << 0) +#define SASL_MECH_PLAIN (1 << 1) +#define SASL_MECH_CRAM_MD5 (1 << 2) +#define SASL_MECH_DIGEST_MD5 (1 << 3) +#define SASL_MECH_GSSAPI (1 << 4) +#define SASL_MECH_EXTERNAL (1 << 5) +#define SASL_MECH_NTLM (1 << 6) +#define SASL_MECH_XOAUTH2 (1 << 7) +#define SASL_MECH_OAUTHBEARER (1 << 8) + +/* Authentication mechanism values */ +#define SASL_AUTH_NONE 0 +#define SASL_AUTH_ANY ~0U +#define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL) + +/* Authentication mechanism strings */ +#define SASL_MECH_STRING_LOGIN "LOGIN" +#define SASL_MECH_STRING_PLAIN "PLAIN" +#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5" +#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5" +#define SASL_MECH_STRING_GSSAPI "GSSAPI" +#define SASL_MECH_STRING_EXTERNAL "EXTERNAL" +#define SASL_MECH_STRING_NTLM "NTLM" +#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2" +#define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER" + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) +#define DIGEST_MAX_VALUE_LENGTH 256 +#define DIGEST_MAX_CONTENT_LENGTH 1024 +#endif + +enum { + CURLDIGESTALGO_MD5, + CURLDIGESTALGO_MD5SESS +}; + +/* SASL machine states */ +typedef enum { + SASL_STOP, + SASL_PLAIN, + SASL_LOGIN, + SASL_LOGIN_PASSWD, + SASL_EXTERNAL, + SASL_CRAMMD5, + SASL_DIGESTMD5, + SASL_DIGESTMD5_RESP, + SASL_NTLM, + SASL_NTLM_TYPE2MSG, + SASL_GSSAPI, + SASL_GSSAPI_TOKEN, + SASL_GSSAPI_NO_DATA, + SASL_OAUTH2, + SASL_OAUTH2_RESP, + SASL_CANCEL, + SASL_FINAL +} saslstate; + +/* Progress indicator */ +typedef enum { + SASL_IDLE, + SASL_INPROGRESS, + SASL_DONE +} saslprogress; + +/* Protocol dependent SASL parameters */ +struct SASLproto { + const char *service; /* The service name */ + int contcode; /* Code to receive when continuation is expected */ + int finalcode; /* Code to receive upon authentication success */ + size_t maxirlen; /* Maximum initial response length */ + CURLcode (*sendauth)(struct connectdata *conn, + const char *mech, const char *ir); + /* Send authentication command */ + CURLcode (*sendcont)(struct connectdata *conn, const char *contauth); + /* Send authentication continuation */ + void (*getmessage)(char *buffer, char **outptr); + /* Get SASL response message */ +}; + +/* Per-connection parameters */ +struct SASL { + const struct SASLproto *params; /* Protocol dependent parameters */ + saslstate state; /* Current machine state */ + unsigned int authmechs; /* Accepted authentication mechanisms */ + unsigned int prefmech; /* Preferred authentication mechanism */ + unsigned int authused; /* Auth mechanism used for the connection */ + bool resetprefs; /* For URL auth option parsing. */ + bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */ + bool force_ir; /* Protocol always supports initial response */ +}; + +/* This is used to test whether the line starts with the given mechanism */ +#define sasl_mech_equal(line, wordlen, mech) \ + (wordlen == (sizeof(mech) - 1) / sizeof(char) && \ + !memcmp(line, mech, wordlen)) + +/* This is used to build a SPN string */ +#if !defined(USE_WINDOWS_SSPI) +char *Curl_sasl_build_spn(const char *service, const char *instance); +#else +TCHAR *Curl_sasl_build_spn(const char *service, const char *instance); +#endif + +#if defined(HAVE_GSSAPI) +char *Curl_sasl_build_gssapi_spn(const char *service, const char *instance); +#endif + +#ifndef CURL_DISABLE_CRYPTO_AUTH +/* This is used to extract the realm from a challenge message */ +bool Curl_sasl_digest_get_pair(const char *str, char *value, char *content, + const char **endptr); + +/* This is used to generate a base64 encoded DIGEST-MD5 response message */ +CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, + const char *chlg64, + const char *userp, + const char *passwdp, + const char *service, + char **outptr, size_t *outlen); + +/* This is used to decode a HTTP DIGEST challenge message */ +CURLcode Curl_sasl_decode_digest_http_message(const char *chlg, + struct digestdata *digest); + +/* This is used to generate a HTTP DIGEST response message */ +CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uri, + struct digestdata *digest, + char **outptr, size_t *outlen); + +/* This is used to clean up the digest specific data */ +void Curl_sasl_digest_cleanup(struct digestdata *digest); +#endif + +#ifdef USE_NTLM +/* This is used to generate a base64 encoded NTLM type-1 message */ +CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, + size_t *outlen); + +/* This is used to decode a base64 encoded NTLM type-2 message */ +CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data, + const char *type2msg, + struct ntlmdata *ntlm); + +/* This is used to generate a base64 encoded NTLM type-3 message */ +CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, size_t *outlen); + +/* This is used to clean up the ntlm specific data */ +void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm); + +#endif /* USE_NTLM */ + +#if defined(USE_KERBEROS5) +/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token + message */ +CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + const char *service, + const bool mutual, + const char *chlg64, + struct kerberos5data *krb5, + char **outptr, size_t *outlen); + +/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security + token message */ +CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, + const char *input, + struct kerberos5data *krb5, + char **outptr, + size_t *outlen); + +/* This is used to clean up the gssapi specific data */ +void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5); +#endif /* USE_KERBEROS5 */ + +/* This is used to cleanup any libraries or curl modules used by the sasl + functions */ +void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused); + +/* Convert a mechanism name to a token */ +unsigned int Curl_sasl_decode_mech(const char *ptr, + size_t maxlen, size_t *len); + +/* Parse the URL login options */ +CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, + const char *value, size_t len); + +/* Initializes an SASL structure */ +void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params); + +/* Check if we have enough auth data and capabilities to authenticate */ +bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn); + +/* Calculate the required login details for SASL authentication */ +CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, + bool force_ir, saslprogress *progress); + +/* Continue an SASL authentication */ +CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, + int code, saslprogress *progress); + +#endif /* HEADER_CURL_SASL_H */ diff --git a/project/jni/curl/lib/curl_sasl_gssapi.c b/project/jni/curl/lib/curl_sasl_gssapi.c new file mode 100644 index 000000000..dcc0498b9 --- /dev/null +++ b/project/jni/curl/lib/curl_sasl_gssapi.c @@ -0,0 +1,392 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2014 - 2016, Steve Holme, . + * Copyright (C) 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(HAVE_GSSAPI) && defined(USE_KERBEROS5) + +#include + +#include "curl_sasl.h" +#include "urldata.h" +#include "curl_base64.h" +#include "curl_gssapi.h" +#include "sendf.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* +* Curl_sasl_build_gssapi_spn() +* +* This is used to build a SPN string in the format service@instance. +* +* Parameters: +* +* service [in] - The service type such as www, smtp, pop or imap. +* instance [in] - The host name or realm. +* +* Returns a pointer to the newly allocated SPN. +*/ +char *Curl_sasl_build_gssapi_spn(const char *service, const char *instance) +{ + /* Generate and return our SPN */ + return aprintf("%s@%s", service, instance); +} + +/* + * Curl_sasl_create_gssapi_user_message() + * + * This is used to generate an already encoded GSSAPI (Kerberos V5) user token + * message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name. + * passdwp [in] - The user's password. + * service [in] - The service type such as www, smtp, pop or imap. + * mutual_auth [in] - Flag specifing whether or not mutual authentication + * is enabled. + * chlg64 [in] - Pointer to the optional base64 encoded challenge + * message. + * krb5 [in/out] - The Kerberos 5 data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + const char *service, + const bool mutual_auth, + const char *chlg64, + struct kerberos5data *krb5, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + unsigned char *chlg = NULL; + OM_uint32 gss_status; + OM_uint32 gss_major_status; + OM_uint32 gss_minor_status; + gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + + (void) userp; + (void) passwdp; + + if(krb5->context == GSS_C_NO_CONTEXT) { + /* Generate our SPN */ + char *spn = Curl_sasl_build_gssapi_spn(service, + data->easy_conn->host.name); + if(!spn) + return CURLE_OUT_OF_MEMORY; + + /* Populate the SPN structure */ + spn_token.value = spn; + spn_token.length = strlen(spn); + + /* Import the SPN */ + gss_major_status = gss_import_name(&gss_minor_status, &spn_token, + GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn); + if(GSS_ERROR(gss_major_status)) { + Curl_gss_log_error(data, gss_minor_status, "gss_import_name() failed: "); + + free(spn); + + return CURLE_OUT_OF_MEMORY; + } + + free(spn); + } + else { + /* Decode the base-64 encoded challenge message */ + if(strlen(chlg64) && *chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "GSSAPI handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Setup the challenge "input" security buffer */ + input_token.value = chlg; + input_token.length = chlglen; + } + + gss_major_status = Curl_gss_init_sec_context(data, + &gss_minor_status, + &krb5->context, + krb5->spn, + &Curl_krb5_mech_oid, + GSS_C_NO_CHANNEL_BINDINGS, + &input_token, + &output_token, + mutual_auth, + NULL); + + free(input_token.value); + + if(GSS_ERROR(gss_major_status)) { + if(output_token.value) + gss_release_buffer(&gss_status, &output_token); + + Curl_gss_log_error(data, gss_minor_status, + "gss_init_sec_context() failed: "); + + return CURLE_RECV_ERROR; + } + + if(output_token.value && output_token.length) { + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) output_token.value, + output_token.length, outptr, outlen); + + gss_release_buffer(&gss_status, &output_token); + } + + return result; +} + +/* + * Curl_sasl_create_gssapi_security_message() + * + * This is used to generate an already encoded GSSAPI (Kerberos V5) security + * token message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg64 [in] - Pointer to the optional base64 encoded challenge message. + * krb5 [in/out] - The Kerberos 5 data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, + const char *chlg64, + struct kerberos5data *krb5, + char **outptr, + size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + size_t messagelen = 0; + unsigned char *chlg = NULL; + unsigned char *message = NULL; + OM_uint32 gss_status; + OM_uint32 gss_major_status; + OM_uint32 gss_minor_status; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + unsigned int indata = 0; + unsigned int outdata = 0; + gss_qop_t qop = GSS_C_QOP_DEFAULT; + unsigned int sec_layer = 0; + unsigned int max_size = 0; + gss_name_t username = GSS_C_NO_NAME; + gss_buffer_desc username_token; + + /* Decode the base-64 encoded input message */ + if(strlen(chlg64) && *chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "GSSAPI handshake failure (empty security message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Get the fully qualified username back from the context */ + gss_major_status = gss_inquire_context(&gss_minor_status, krb5->context, + &username, NULL, NULL, NULL, NULL, + NULL, NULL); + if(GSS_ERROR(gss_major_status)) { + Curl_gss_log_error(data, gss_minor_status, + "gss_inquire_context() failed: "); + + free(chlg); + + return CURLE_OUT_OF_MEMORY; + } + + /* Convert the username from internal format to a displayable token */ + gss_major_status = gss_display_name(&gss_minor_status, username, + &username_token, NULL); + if(GSS_ERROR(gss_major_status)) { + Curl_gss_log_error(data, gss_minor_status, "gss_display_name() failed: "); + + free(chlg); + + return CURLE_OUT_OF_MEMORY; + } + + /* Setup the challenge "input" security buffer */ + input_token.value = chlg; + input_token.length = chlglen; + + /* Decrypt the inbound challenge and obtain the qop */ + gss_major_status = gss_unwrap(&gss_minor_status, krb5->context, &input_token, + &output_token, NULL, &qop); + if(GSS_ERROR(gss_major_status)) { + Curl_gss_log_error(data, gss_minor_status, "gss_unwrap() failed: "); + + gss_release_buffer(&gss_status, &username_token); + free(chlg); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ + if(output_token.length != 4) { + infof(data, "GSSAPI handshake failure (invalid security data)\n"); + + gss_release_buffer(&gss_status, &username_token); + free(chlg); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Copy the data out and free the challenge as it is not required anymore */ + memcpy(&indata, output_token.value, 4); + gss_release_buffer(&gss_status, &output_token); + free(chlg); + + /* Extract the security layer */ + sec_layer = indata & 0x000000FF; + if(!(sec_layer & GSSAUTH_P_NONE)) { + infof(data, "GSSAPI handshake failure (invalid security layer)\n"); + + gss_release_buffer(&gss_status, &username_token); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Extract the maximum message size the server can receive */ + max_size = ntohl(indata & 0xFFFFFF00); + if(max_size > 0) { + /* The server has told us it supports a maximum receive buffer, however, as + we don't require one unless we are encrypting data, we tell the server + our receive buffer is zero. */ + max_size = 0; + } + + /* Allocate our message */ + messagelen = sizeof(outdata) + username_token.length + 1; + message = malloc(messagelen); + if(!message) { + gss_release_buffer(&gss_status, &username_token); + + return CURLE_OUT_OF_MEMORY; + } + + /* Populate the message with the security layer, client supported receive + message size and authorization identity including the 0x00 based + terminator. Note: Dispite RFC4752 Section 3.1 stating "The authorization + identity is not terminated with the zero-valued (%x00) octet." it seems + necessary to include it. */ + outdata = htonl(max_size) | sec_layer; + memcpy(message, &outdata, sizeof(outdata)); + memcpy(message + sizeof(outdata), username_token.value, + username_token.length); + message[messagelen - 1] = '\0'; + + /* Free the username token as it is not required anymore */ + gss_release_buffer(&gss_status, &username_token); + + /* Setup the "authentication data" security buffer */ + input_token.value = message; + input_token.length = messagelen; + + /* Encrypt the data */ + gss_major_status = gss_wrap(&gss_minor_status, krb5->context, 0, + GSS_C_QOP_DEFAULT, &input_token, NULL, + &output_token); + if(GSS_ERROR(gss_major_status)) { + Curl_gss_log_error(data, gss_minor_status, "gss_wrap() failed: "); + + free(message); + + return CURLE_OUT_OF_MEMORY; + } + + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) output_token.value, + output_token.length, outptr, outlen); + + /* Free the output buffer */ + gss_release_buffer(&gss_status, &output_token); + + /* Free the message buffer */ + free(message); + + return result; +} + +/* + * Curl_sasl_gssapi_cleanup() + * + * This is used to clean up the GSSAPI (Kerberos V5) specific data. + * + * Parameters: + * + * krb5 [in/out] - The Kerberos 5 data struct being cleaned up. + * + */ +void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5) +{ + OM_uint32 minor_status; + + /* Free our security context */ + if(krb5->context != GSS_C_NO_CONTEXT) { + gss_delete_sec_context(&minor_status, &krb5->context, GSS_C_NO_BUFFER); + krb5->context = GSS_C_NO_CONTEXT; + } + + /* Free the SPN */ + if(krb5->spn != GSS_C_NO_NAME) { + gss_release_name(&minor_status, &krb5->spn); + krb5->spn = GSS_C_NO_NAME; + } +} + +#endif /* HAVE_GSSAPI && USE_KERBEROS5 */ diff --git a/project/jni/curl/lib/curl_sasl_sspi.c b/project/jni/curl/lib/curl_sasl_sspi.c new file mode 100644 index 000000000..f46376cc4 --- /dev/null +++ b/project/jni/curl/lib/curl_sasl_sspi.c @@ -0,0 +1,1295 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2014 - 2016 Daniel Stenberg, , et al. + * Copyright (C) 2014 - 2016, Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * RFC2617 Basic and Digest Access Authentication + * RFC2831 DIGEST-MD5 authentication + * RFC4422 Simple Authentication and Security Layer (SASL) + * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_WINDOWS_SSPI) + +#include + +#include "curl_sasl.h" +#include "urldata.h" +#include "curl_base64.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" +#include "strdup.h" +#include "curl_printf.h" +#include "rawstr.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_sasl_build_spn() + * + * This is used to build a SPN string in the format service/instance. + * + * Parameters: + * + * serivce [in] - The service type such as www, smtp, pop or imap. + * instance [in] - The host name or realm. + * + * Returns a pointer to the newly allocated SPN. + */ +TCHAR *Curl_sasl_build_spn(const char *service, const char *instance) +{ + char *utf8_spn = NULL; + TCHAR *tchar_spn = NULL; + + /* Note: We could use DsMakeSPN() or DsClientMakeSpnForTargetServer() rather + than doing this ourselves but the first is only available in Windows XP + and Windows Server 2003 and the latter is only available in Windows 2000 + but not Windows95/98/ME or Windows NT4.0 unless the Active Directory + Client Extensions are installed. As such it is far simpler for us to + formulate the SPN instead. */ + + /* Allocate our UTF8 based SPN */ + utf8_spn = aprintf("%s/%s", service, instance); + if(!utf8_spn) { + return NULL; + } + + /* Allocate our TCHAR based SPN */ + tchar_spn = Curl_convert_UTF8_to_tchar(utf8_spn); + if(!tchar_spn) { + free(utf8_spn); + + return NULL; + } + + /* Release the UTF8 variant when operating with Unicode */ + Curl_unicodefree(utf8_spn); + + /* Return our newly allocated SPN */ + return tchar_spn; +} + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) +/* + * Curl_sasl_create_digest_md5_message() + * + * This is used to generate an already encoded DIGEST-MD5 response message + * ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg64 [in] - The base64 encoded challenge message. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * service [in] - The service type such as www, smtp, pop or imap. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, + const char *chlg64, + const char *userp, + const char *passwdp, + const char *service, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + TCHAR *spn = NULL; + size_t chlglen = 0; + size_t token_max = 0; + unsigned char *input_token = NULL; + unsigned char *output_token = NULL; + CredHandle credentials; + CtxtHandle context; + PSecPkgInfo SecurityPackage; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + SecBuffer chlg_buf; + SecBuffer resp_buf; + SecBufferDesc chlg_desc; + SecBufferDesc resp_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + /* Decode the base-64 encoded challenge message */ + if(strlen(chlg64) && *chlg64 != '=') { + result = Curl_base64_decode(chlg64, &input_token, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!input_token) { + infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Query the security package for DigestSSP */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), + &SecurityPackage); + if(status != SEC_E_OK) { + free(input_token); + + return CURLE_NOT_BUILT_IN; + } + + token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our response buffer */ + output_token = malloc(token_max); + if(!output_token) { + free(input_token); + + return CURLE_OUT_OF_MEMORY; + } + + /* Generate our SPN */ + spn = Curl_sasl_build_spn(service, data->easy_conn->host.name); + if(!spn) { + free(output_token); + free(input_token); + + return CURLE_OUT_OF_MEMORY; + } + + if(userp && *userp) { + /* Populate our identity structure */ + result = Curl_create_sspi_identity(userp, passwdp, &identity); + if(result) { + free(spn); + free(output_token); + free(input_token); + + return result; + } + + /* Allow proper cleanup of the identity structure */ + p_identity = &identity; + } + else + /* Use the current Windows user */ + p_identity = NULL; + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_DIGEST), + SECPKG_CRED_OUTBOUND, NULL, + p_identity, NULL, NULL, + &credentials, &expiry); + + if(status != SEC_E_OK) { + Curl_sspi_free_identity(p_identity); + free(spn); + free(output_token); + free(input_token); + + return CURLE_LOGIN_DENIED; + } + + /* Setup the challenge "input" security buffer */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 1; + chlg_desc.pBuffers = &chlg_buf; + chlg_buf.BufferType = SECBUFFER_TOKEN; + chlg_buf.pvBuffer = input_token; + chlg_buf.cbBuffer = curlx_uztoul(chlglen); + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = output_token; + resp_buf.cbBuffer = curlx_uztoul(token_max); + + /* Generate our response message */ + status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, + 0, 0, 0, &chlg_desc, 0, + &context, &resp_desc, &attrs, + &expiry); + + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { + s_pSecFn->FreeCredentialsHandle(&credentials); + Curl_sspi_free_identity(p_identity); + free(spn); + free(output_token); + free(input_token); + + return CURLE_RECV_ERROR; + } + + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer, + outptr, outlen); + + /* Free our handles */ + s_pSecFn->DeleteSecurityContext(&context); + s_pSecFn->FreeCredentialsHandle(&credentials); + + /* Free the identity structure */ + Curl_sspi_free_identity(p_identity); + + /* Free the SPN */ + free(spn); + + /* Free the response buffer */ + free(output_token); + + /* Free the decoded challenge message */ + free(input_token); + + return result; +} + +/* + * Curl_override_sspi_http_realm() + * + * This is used to populate the domain in a SSPI identity structure + * The realm is extracted from the challenge message and used as the + * domain if it is not already explicitly set. + * + * Parameters: + * + * chlg [in] - The challenge message. + * identity [in/out] - The identity structure. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_override_sspi_http_realm(const char *chlg, + SEC_WINNT_AUTH_IDENTITY *identity) +{ + xcharp_u domain, dup_domain; + + /* If domain is blank or unset, check challenge message for realm */ + if(!identity->Domain || !identity->DomainLength) { + for(;;) { + char value[DIGEST_MAX_VALUE_LENGTH]; + char content[DIGEST_MAX_CONTENT_LENGTH]; + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Extract a value=content pair */ + if(Curl_sasl_digest_get_pair(chlg, value, content, &chlg)) { + if(Curl_raw_equal(value, "realm")) { + + /* Setup identity's domain and length */ + domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)content); + if(!domain.tchar_ptr) + return CURLE_OUT_OF_MEMORY; + dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr); + if(!dup_domain.tchar_ptr) { + Curl_unicodefree(domain.tchar_ptr); + return CURLE_OUT_OF_MEMORY; + } + free(identity->Domain); + identity->Domain = dup_domain.tbyte_ptr; + identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr)); + dup_domain.tchar_ptr = NULL; + + Curl_unicodefree(domain.tchar_ptr); + } + else { + /* unknown specifier, ignore it! */ + } + } + else + break; /* we're done here */ + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Allow the list to be comma-separated */ + if(',' == *chlg) + chlg++; + } + } + + return CURLE_OK; +} + +/* + * Curl_sasl_decode_digest_http_message() + * + * This is used to decode a HTTP DIGEST challenge message into the seperate + * attributes. + * + * Parameters: + * + * chlg [in] - The challenge message. + * digest [in/out] - The digest data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_decode_digest_http_message(const char *chlg, + struct digestdata *digest) +{ + size_t chlglen = strlen(chlg); + + /* We had an input token before and we got another one now. This means we + provided bad credentials in the previous request. */ + if(digest->input_token) + return CURLE_BAD_CONTENT_ENCODING; + + /* Simply store the challenge for use later */ + digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen); + if(!digest->input_token) + return CURLE_OUT_OF_MEMORY; + + digest->input_token_len = chlglen; + + return CURLE_OK; +} + +/* + * Curl_sasl_create_digest_http_message() + * + * This is used to generate a HTTP DIGEST response message ready for sending + * to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * request [in] - The HTTP request. + * uripath [in] - The path of the HTTP uri. + * digest [in/out] - The digest data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uripath, + struct digestdata *digest, + char **outptr, size_t *outlen) +{ + size_t token_max; + CredHandle credentials; + CtxtHandle context; + char *resp; + BYTE *output_token; + PSecPkgInfo SecurityPackage; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + SecBuffer chlg_buf[3]; + SecBuffer resp_buf; + SecBufferDesc chlg_desc; + SecBufferDesc resp_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + TCHAR *spn; + + (void) data; + + /* Query the security package for DigestSSP */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), + &SecurityPackage); + if(status != SEC_E_OK) + return CURLE_NOT_BUILT_IN; + + token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate the output buffer according to the max token size as indicated + by the security package */ + output_token = malloc(token_max); + if(!output_token) + return CURLE_OUT_OF_MEMORY; + + if(userp && *userp) { + /* Populate our identity structure */ + if(Curl_create_sspi_identity(userp, passwdp, &identity)) + return CURLE_OUT_OF_MEMORY; + + /* Populate our identity domain */ + if(Curl_override_sspi_http_realm((const char*)digest->input_token, + &identity)) + return CURLE_OUT_OF_MEMORY; + + /* Allow proper cleanup of the identity structure */ + p_identity = &identity; + } + else + /* Use the current Windows user */ + p_identity = NULL; + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_DIGEST), + SECPKG_CRED_OUTBOUND, NULL, + p_identity, NULL, NULL, + &credentials, &expiry); + if(status != SEC_E_OK) { + Curl_sspi_free_identity(p_identity); + free(output_token); + + return CURLE_LOGIN_DENIED; + } + + /* Setup the challenge "input" security buffer if present */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 3; + chlg_desc.pBuffers = chlg_buf; + chlg_buf[0].BufferType = SECBUFFER_TOKEN; + chlg_buf[0].pvBuffer = digest->input_token; + chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len); + chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[1].pvBuffer = (void *)request; + chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); + chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[2].pvBuffer = NULL; + chlg_buf[2].cbBuffer = 0; + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = output_token; + resp_buf.cbBuffer = curlx_uztoul(token_max); + + spn = Curl_convert_UTF8_to_tchar((char *) uripath); + if(!spn) { + Curl_sspi_free_identity(p_identity); + free(output_token); + + return CURLE_OUT_OF_MEMORY; + } + + /* Generate our reponse message */ + status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, + spn, + ISC_REQ_USE_HTTP_STYLE, 0, 0, + &chlg_desc, 0, &context, + &resp_desc, &attrs, &expiry); + Curl_unicodefree(spn); + + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { + s_pSecFn->FreeCredentialsHandle(&credentials); + + Curl_sspi_free_identity(p_identity); + free(output_token); + + return CURLE_OUT_OF_MEMORY; + } + + resp = malloc(resp_buf.cbBuffer + 1); + if(!resp) { + s_pSecFn->DeleteSecurityContext(&context); + s_pSecFn->FreeCredentialsHandle(&credentials); + + Curl_sspi_free_identity(p_identity); + free(output_token); + + return CURLE_OUT_OF_MEMORY; + } + + /* Copy the generated reponse */ + memcpy(resp, resp_buf.pvBuffer, resp_buf.cbBuffer); + resp[resp_buf.cbBuffer] = 0x00; + + /* Return the response */ + *outptr = resp; + *outlen = resp_buf.cbBuffer; + + /* Free our handles */ + s_pSecFn->DeleteSecurityContext(&context); + s_pSecFn->FreeCredentialsHandle(&credentials); + + /* Free the identity structure */ + Curl_sspi_free_identity(p_identity); + + /* Free the response buffer */ + free(output_token); + + return CURLE_OK; +} + +/* + * Curl_sasl_digest_cleanup() + * + * This is used to clean up the digest specific data. + * + * Parameters: + * + * digest [in/out] - The digest data struct being cleaned up. + * + */ +void Curl_sasl_digest_cleanup(struct digestdata *digest) +{ + /* Free the input token */ + Curl_safefree(digest->input_token); + + /* Reset any variables */ + digest->input_token_len = 0; +} +#endif /* !CURL_DISABLE_CRYPTO_AUTH */ + +#if defined USE_NTLM +/* + * Curl_sasl_create_ntlm_type1_message() + * + * This is used to generate an already encoded NTLM type-1 message ready for + * sending to the recipient. + * + * Parameters: + * + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * ntlm [in/out] - The NTLM data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, size_t *outlen) +{ + PSecPkgInfo SecurityPackage; + SecBuffer type_1_buf; + SecBufferDesc type_1_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + /* Clean up any former leftovers and initialise to defaults */ + Curl_sasl_ntlm_cleanup(ntlm); + + /* Query the security package for NTLM */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), + &SecurityPackage); + if(status != SEC_E_OK) + return CURLE_NOT_BUILT_IN; + + ntlm->token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our output buffer */ + ntlm->output_token = malloc(ntlm->token_max); + if(!ntlm->output_token) + return CURLE_OUT_OF_MEMORY; + + if(userp && *userp) { + CURLcode result; + + /* Populate our identity structure */ + result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity); + if(result) + return result; + + /* Allow proper cleanup of the identity structure */ + ntlm->p_identity = &ntlm->identity; + } + else + /* Use the current Windows user */ + ntlm->p_identity = NULL; + + /* Allocate our credentials handle */ + ntlm->credentials = malloc(sizeof(CredHandle)); + if(!ntlm->credentials) + return CURLE_OUT_OF_MEMORY; + + memset(ntlm->credentials, 0, sizeof(CredHandle)); + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_NTLM), + SECPKG_CRED_OUTBOUND, NULL, + ntlm->p_identity, NULL, NULL, + ntlm->credentials, &expiry); + if(status != SEC_E_OK) + return CURLE_LOGIN_DENIED; + + /* Allocate our new context handle */ + ntlm->context = malloc(sizeof(CtxtHandle)); + if(!ntlm->context) + return CURLE_OUT_OF_MEMORY; + + memset(ntlm->context, 0, sizeof(CtxtHandle)); + + /* Setup the type-1 "output" security buffer */ + type_1_desc.ulVersion = SECBUFFER_VERSION; + type_1_desc.cBuffers = 1; + type_1_desc.pBuffers = &type_1_buf; + type_1_buf.BufferType = SECBUFFER_TOKEN; + type_1_buf.pvBuffer = ntlm->output_token; + type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max); + + /* Generate our type-1 message */ + status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL, + (TCHAR *) TEXT(""), + 0, 0, SECURITY_NETWORK_DREP, + NULL, 0, + ntlm->context, &type_1_desc, + &attrs, &expiry); + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) + return CURLE_RECV_ERROR; + + /* Base64 encode the response */ + return Curl_base64_encode(NULL, (char *) ntlm->output_token, + type_1_buf.cbBuffer, outptr, outlen); +} + +/* + * Curl_sasl_decode_ntlm_type2_message() + * + * This is used to decode an already encoded NTLM type-2 message. + * + * Parameters: + * + * data [in] - The session handle. + * type2msg [in] - The base64 encoded type-2 message. + * ntlm [in/out] - The NTLM data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data, + const char *type2msg, + struct ntlmdata *ntlm) +{ + CURLcode result = CURLE_OK; + unsigned char *type2 = NULL; + size_t type2_len = 0; + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + + /* Decode the base-64 encoded type-2 message */ + if(strlen(type2msg) && *type2msg != '=') { + result = Curl_base64_decode(type2msg, &type2, &type2_len); + if(result) + return result; + } + + /* Ensure we have a valid type-2 message */ + if(!type2) { + infof(data, "NTLM handshake failure (empty type-2 message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Simply store the challenge for use later */ + ntlm->input_token = type2; + ntlm->input_token_len = type2_len; + + return result; +} + +/* + * Curl_sasl_create_ntlm_type3_message() + * + * This is used to generate an already encoded NTLM type-3 message ready for + * sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * ntlm [in/out] - The NTLM data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + SecBuffer type_2_buf; + SecBuffer type_3_buf; + SecBufferDesc type_2_desc; + SecBufferDesc type_3_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + (void) passwdp; + (void) userp; + + /* Setup the type-2 "input" security buffer */ + type_2_desc.ulVersion = SECBUFFER_VERSION; + type_2_desc.cBuffers = 1; + type_2_desc.pBuffers = &type_2_buf; + type_2_buf.BufferType = SECBUFFER_TOKEN; + type_2_buf.pvBuffer = ntlm->input_token; + type_2_buf.cbBuffer = curlx_uztoul(ntlm->input_token_len); + + /* Setup the type-3 "output" security buffer */ + type_3_desc.ulVersion = SECBUFFER_VERSION; + type_3_desc.cBuffers = 1; + type_3_desc.pBuffers = &type_3_buf; + type_3_buf.BufferType = SECBUFFER_TOKEN; + type_3_buf.pvBuffer = ntlm->output_token; + type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max); + + /* Generate our type-3 message */ + status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, + ntlm->context, + (TCHAR *) TEXT(""), + 0, 0, SECURITY_NETWORK_DREP, + &type_2_desc, + 0, ntlm->context, + &type_3_desc, + &attrs, &expiry); + if(status != SEC_E_OK) { + infof(data, "NTLM handshake failure (type-3 message): Status=%x\n", + status); + + return CURLE_RECV_ERROR; + } + + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) ntlm->output_token, + type_3_buf.cbBuffer, outptr, outlen); + + Curl_sasl_ntlm_cleanup(ntlm); + + return result; +} + +/* + * Curl_sasl_ntlm_cleanup() + * + * This is used to clean up the NTLM specific data. + * + * Parameters: + * + * ntlm [in/out] - The NTLM data struct being cleaned up. + * + */ +void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm) +{ + /* Free our security context */ + if(ntlm->context) { + s_pSecFn->DeleteSecurityContext(ntlm->context); + free(ntlm->context); + ntlm->context = NULL; + } + + /* Free our credentials handle */ + if(ntlm->credentials) { + s_pSecFn->FreeCredentialsHandle(ntlm->credentials); + free(ntlm->credentials); + ntlm->credentials = NULL; + } + + /* Free our identity */ + Curl_sspi_free_identity(ntlm->p_identity); + ntlm->p_identity = NULL; + + /* Free the input and output tokens */ + Curl_safefree(ntlm->input_token); + Curl_safefree(ntlm->output_token); + + /* Reset any variables */ + ntlm->token_max = 0; +} +#endif /* USE_NTLM */ + +#if defined(USE_KERBEROS5) +/* + * Curl_sasl_create_gssapi_user_message() + * + * This is used to generate an already encoded GSSAPI (Kerberos V5) user token + * message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * service [in] - The service type such as www, smtp, pop or imap. + * mutual_auth [in] - Flag specifing whether or not mutual authentication + * is enabled. + * chlg64 [in] - The optional base64 encoded challenge message. + * krb5 [in/out] - The Kerberos 5 data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + const char *service, + const bool mutual_auth, + const char *chlg64, + struct kerberos5data *krb5, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + unsigned char *chlg = NULL; + CtxtHandle context; + PSecPkgInfo SecurityPackage; + SecBuffer chlg_buf; + SecBuffer resp_buf; + SecBufferDesc chlg_desc; + SecBufferDesc resp_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + if(!krb5->credentials) { + /* Query the security package for Kerberos */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_KERBEROS), + &SecurityPackage); + if(status != SEC_E_OK) { + return CURLE_NOT_BUILT_IN; + } + + krb5->token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our response buffer */ + krb5->output_token = malloc(krb5->token_max); + if(!krb5->output_token) + return CURLE_OUT_OF_MEMORY; + + /* Generate our SPN */ + krb5->spn = Curl_sasl_build_spn(service, data->easy_conn->host.name); + if(!krb5->spn) + return CURLE_OUT_OF_MEMORY; + + if(userp && *userp) { + /* Populate our identity structure */ + result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity); + if(result) + return result; + + /* Allow proper cleanup of the identity structure */ + krb5->p_identity = &krb5->identity; + } + else + /* Use the current Windows user */ + krb5->p_identity = NULL; + + /* Allocate our credentials handle */ + krb5->credentials = malloc(sizeof(CredHandle)); + if(!krb5->credentials) + return CURLE_OUT_OF_MEMORY; + + memset(krb5->credentials, 0, sizeof(CredHandle)); + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) + TEXT(SP_NAME_KERBEROS), + SECPKG_CRED_OUTBOUND, NULL, + krb5->p_identity, NULL, NULL, + krb5->credentials, &expiry); + if(status != SEC_E_OK) + return CURLE_LOGIN_DENIED; + + /* Allocate our new context handle */ + krb5->context = malloc(sizeof(CtxtHandle)); + if(!krb5->context) + return CURLE_OUT_OF_MEMORY; + + memset(krb5->context, 0, sizeof(CtxtHandle)); + } + else { + /* Decode the base-64 encoded challenge message */ + if(strlen(chlg64) && *chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "GSSAPI handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Setup the challenge "input" security buffer */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 1; + chlg_desc.pBuffers = &chlg_buf; + chlg_buf.BufferType = SECBUFFER_TOKEN; + chlg_buf.pvBuffer = chlg; + chlg_buf.cbBuffer = curlx_uztoul(chlglen); + } + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = krb5->output_token; + resp_buf.cbBuffer = curlx_uztoul(krb5->token_max); + + /* Generate our challenge-response message */ + status = s_pSecFn->InitializeSecurityContext(krb5->credentials, + chlg ? krb5->context : NULL, + krb5->spn, + (mutual_auth ? + ISC_REQ_MUTUAL_AUTH : 0), + 0, SECURITY_NATIVE_DREP, + chlg ? &chlg_desc : NULL, 0, + &context, + &resp_desc, &attrs, + &expiry); + + if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { + free(chlg); + + return CURLE_RECV_ERROR; + } + + if(memcmp(&context, krb5->context, sizeof(context))) { + s_pSecFn->DeleteSecurityContext(krb5->context); + + memcpy(krb5->context, &context, sizeof(context)); + } + + if(resp_buf.cbBuffer) { + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *)resp_buf.pvBuffer, + resp_buf.cbBuffer, outptr, outlen); + } + + /* Free the decoded challenge */ + free(chlg); + + return result; +} + +/* + * Curl_sasl_create_gssapi_security_message() + * + * This is used to generate an already encoded GSSAPI (Kerberos V5) security + * token message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg64 [in] - The optional base64 encoded challenge message. + * krb5 [in/out] - The Kerberos 5 data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, + const char *chlg64, + struct kerberos5data *krb5, + char **outptr, + size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t offset = 0; + size_t chlglen = 0; + size_t messagelen = 0; + size_t appdatalen = 0; + unsigned char *chlg = NULL; + unsigned char *trailer = NULL; + unsigned char *message = NULL; + unsigned char *padding = NULL; + unsigned char *appdata = NULL; + SecBuffer input_buf[2]; + SecBuffer wrap_buf[3]; + SecBufferDesc input_desc; + SecBufferDesc wrap_desc; + unsigned long indata = 0; + unsigned long outdata = 0; + unsigned long qop = 0; + unsigned long sec_layer = 0; + unsigned long max_size = 0; + SecPkgContext_Sizes sizes; + SecPkgCredentials_Names names; + SECURITY_STATUS status; + char *user_name; + + /* Decode the base-64 encoded input message */ + if(strlen(chlg64) && *chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "GSSAPI handshake failure (empty security message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Get our response size information */ + status = s_pSecFn->QueryContextAttributes(krb5->context, + SECPKG_ATTR_SIZES, + &sizes); + if(status != SEC_E_OK) { + free(chlg); + + return CURLE_OUT_OF_MEMORY; + } + + /* Get the fully qualified username back from the context */ + status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials, + SECPKG_CRED_ATTR_NAMES, + &names); + if(status != SEC_E_OK) { + free(chlg); + + return CURLE_RECV_ERROR; + } + + /* Setup the "input" security buffer */ + input_desc.ulVersion = SECBUFFER_VERSION; + input_desc.cBuffers = 2; + input_desc.pBuffers = input_buf; + input_buf[0].BufferType = SECBUFFER_STREAM; + input_buf[0].pvBuffer = chlg; + input_buf[0].cbBuffer = curlx_uztoul(chlglen); + input_buf[1].BufferType = SECBUFFER_DATA; + input_buf[1].pvBuffer = NULL; + input_buf[1].cbBuffer = 0; + + /* Decrypt the inbound challenge and obtain the qop */ + status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop); + if(status != SEC_E_OK) { + infof(data, "GSSAPI handshake failure (empty security message)\n"); + + free(chlg); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ + if(input_buf[1].cbBuffer != 4) { + infof(data, "GSSAPI handshake failure (invalid security data)\n"); + + free(chlg); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Copy the data out and free the challenge as it is not required anymore */ + memcpy(&indata, input_buf[1].pvBuffer, 4); + s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer); + free(chlg); + + /* Extract the security layer */ + sec_layer = indata & 0x000000FF; + if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) { + infof(data, "GSSAPI handshake failure (invalid security layer)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Extract the maximum message size the server can receive */ + max_size = ntohl(indata & 0xFFFFFF00); + if(max_size > 0) { + /* The server has told us it supports a maximum receive buffer, however, as + we don't require one unless we are encrypting data, we tell the server + our receive buffer is zero. */ + max_size = 0; + } + + /* Allocate the trailer */ + trailer = malloc(sizes.cbSecurityTrailer); + if(!trailer) + return CURLE_OUT_OF_MEMORY; + + /* Convert the user name to UTF8 when operating with Unicode */ + user_name = Curl_convert_tchar_to_UTF8(names.sUserName); + if(!user_name) { + free(trailer); + + return CURLE_OUT_OF_MEMORY; + } + + /* Allocate our message */ + messagelen = sizeof(outdata) + strlen(user_name) + 1; + message = malloc(messagelen); + if(!message) { + free(trailer); + Curl_unicodefree(user_name); + + return CURLE_OUT_OF_MEMORY; + } + + /* Populate the message with the security layer, client supported receive + message size and authorization identity including the 0x00 based + terminator. Note: Dispite RFC4752 Section 3.1 stating "The authorization + identity is not terminated with the zero-valued (%x00) octet." it seems + necessary to include it. */ + outdata = htonl(max_size) | sec_layer; + memcpy(message, &outdata, sizeof(outdata)); + strcpy((char *) message + sizeof(outdata), user_name); + Curl_unicodefree(user_name); + + /* Allocate the padding */ + padding = malloc(sizes.cbBlockSize); + if(!padding) { + free(message); + free(trailer); + + return CURLE_OUT_OF_MEMORY; + } + + /* Setup the "authentication data" security buffer */ + wrap_desc.ulVersion = SECBUFFER_VERSION; + wrap_desc.cBuffers = 3; + wrap_desc.pBuffers = wrap_buf; + wrap_buf[0].BufferType = SECBUFFER_TOKEN; + wrap_buf[0].pvBuffer = trailer; + wrap_buf[0].cbBuffer = sizes.cbSecurityTrailer; + wrap_buf[1].BufferType = SECBUFFER_DATA; + wrap_buf[1].pvBuffer = message; + wrap_buf[1].cbBuffer = curlx_uztoul(messagelen); + wrap_buf[2].BufferType = SECBUFFER_PADDING; + wrap_buf[2].pvBuffer = padding; + wrap_buf[2].cbBuffer = sizes.cbBlockSize; + + /* Encrypt the data */ + status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT, + &wrap_desc, 0); + if(status != SEC_E_OK) { + free(padding); + free(message); + free(trailer); + + return CURLE_OUT_OF_MEMORY; + } + + /* Allocate the encryption (wrap) buffer */ + appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer + + wrap_buf[2].cbBuffer; + appdata = malloc(appdatalen); + if(!appdata) { + free(padding); + free(message); + free(trailer); + + return CURLE_OUT_OF_MEMORY; + } + + /* Populate the encryption buffer */ + memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer); + offset += wrap_buf[0].cbBuffer; + memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer); + offset += wrap_buf[1].cbBuffer; + memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer); + + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *)appdata, appdatalen, outptr, + outlen); + + /* Free all of our local buffers */ + free(appdata); + free(padding); + free(message); + free(trailer); + + return result; +} + +/* + * Curl_sasl_gssapi_cleanup() + * + * This is used to clean up the GSSAPI (Kerberos V5) specific data. + * + * Parameters: + * + * krb5 [in/out] - The Kerberos 5 data struct being cleaned up. + * + */ +void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5) +{ + /* Free our security context */ + if(krb5->context) { + s_pSecFn->DeleteSecurityContext(krb5->context); + free(krb5->context); + krb5->context = NULL; + } + + /* Free our credentials handle */ + if(krb5->credentials) { + s_pSecFn->FreeCredentialsHandle(krb5->credentials); + free(krb5->credentials); + krb5->credentials = NULL; + } + + /* Free our identity */ + Curl_sspi_free_identity(krb5->p_identity); + krb5->p_identity = NULL; + + /* Free the SPN and output token */ + Curl_safefree(krb5->spn); + Curl_safefree(krb5->output_token); + + /* Reset any variables */ + krb5->token_max = 0; +} +#endif /* USE_KERBEROS5 */ + +#endif /* USE_WINDOWS_SSPI */ diff --git a/project/jni/curl/lib/krb4.h b/project/jni/curl/lib/curl_sec.h similarity index 76% rename from project/jni/curl/lib/krb4.h rename to project/jni/curl/lib/curl_sec.h index b3b5ea763..3f94e1444 100644 --- a/project/jni/curl/lib/krb4.h +++ b/project/jni/curl/lib/curl_sec.h @@ -1,5 +1,5 @@ -#ifndef __KRB4_H -#define __KRB4_H +#ifndef HEADER_CURL_SECURITY_H +#define HEADER_CURL_SECURITY_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -30,26 +30,22 @@ struct Curl_sec_client_mech { void (*end)(void *); int (*check_prot)(void *, int); int (*overhead)(void *, int, int); - int (*encode)(void *, const void*, int, int, void**, struct connectdata *); + int (*encode)(void *, const void*, int, int, void**); int (*decode)(void *, void*, int, int, struct connectdata *); }; - #define AUTH_OK 0 #define AUTH_CONTINUE 1 #define AUTH_ERROR 2 -#ifdef HAVE_KRB4 -extern struct Curl_sec_client_mech Curl_krb4_client_mech; -#endif #ifdef HAVE_GSSAPI -extern struct Curl_sec_client_mech Curl_krb5_client_mech; -#endif - -CURLcode Curl_krb_kauth(struct connectdata *conn); -int Curl_sec_read_msg (struct connectdata *conn, char *, enum protection_level); +int Curl_sec_read_msg (struct connectdata *conn, char *, + enum protection_level); void Curl_sec_end (struct connectdata *); CURLcode Curl_sec_login (struct connectdata *); int Curl_sec_request_prot (struct connectdata *conn, const char *level); +extern struct Curl_sec_client_mech Curl_krb5_client_mech; #endif + +#endif /* HEADER_CURL_SECURITY_H */ diff --git a/project/jni/curl/lib/setup.h b/project/jni/curl/lib/curl_setup.h similarity index 69% rename from project/jni/curl/lib/setup.h rename to project/jni/curl/lib/curl_setup.h index cc016c9cd..516327345 100644 --- a/project/jni/curl/lib/setup.h +++ b/project/jni/curl/lib/curl_setup.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_LIB_SETUP_H -#define HEADER_CURL_LIB_SETUP_H +#ifndef HEADER_CURL_SETUP_H +#define HEADER_CURL_SETUP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,7 +26,8 @@ * Define WIN32 when build target is Win32 API */ -#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) && !defined(__SYMBIAN32__) +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) && \ + !defined(__SYMBIAN32__) #define WIN32 #endif @@ -53,8 +54,12 @@ # include "config-mac.h" #endif +#ifdef __riscos__ +# include "config-riscos.h" +#endif + #ifdef __AMIGA__ -# include "amigaos.h" +# include "config-amigaos.h" #endif #ifdef __SYMBIAN32__ @@ -107,6 +112,13 @@ # endif #endif +/* Solaris needs this to get a POSIX-conformant getpwuid_r */ +#if defined(sun) || defined(__sun) +# ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +# endif +#endif + /* ================================================================ */ /* If you need to include a system header file for your platform, */ /* please, do it beyond the point further indicated in this file. */ @@ -134,41 +146,50 @@ Error Compilation_aborted_SIZEOF_CURL_OFF_T_shall_not_be_defined #endif -/* - * Set up internal curl_off_t formatting string directives for - * exclusive use with libcurl's internal *printf functions. - */ - -#ifdef FORMAT_OFF_T -# error "FORMAT_OFF_T shall not be defined before this point!" - Error Compilation_aborted_FORMAT_OFF_T_already_defined -#endif - -#ifdef FORMAT_OFF_TU -# error "FORMAT_OFF_TU shall not be defined before this point!" - Error Compilation_aborted_FORMAT_OFF_TU_already_defined -#endif - -#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG) -# define FORMAT_OFF_T "lld" -# define FORMAT_OFF_TU "llu" -#else -# define FORMAT_OFF_T "ld" -# define FORMAT_OFF_TU "lu" -#endif - /* * Disable other protocols when http is the only one desired. */ #ifdef HTTP_ONLY -# define CURL_DISABLE_TFTP -# define CURL_DISABLE_FTP -# define CURL_DISABLE_LDAP -# define CURL_DISABLE_TELNET -# define CURL_DISABLE_DICT -# define CURL_DISABLE_FILE -# define CURL_DISABLE_RTSP +# ifndef CURL_DISABLE_TFTP +# define CURL_DISABLE_TFTP +# endif +# ifndef CURL_DISABLE_FTP +# define CURL_DISABLE_FTP +# endif +# ifndef CURL_DISABLE_LDAP +# define CURL_DISABLE_LDAP +# endif +# ifndef CURL_DISABLE_TELNET +# define CURL_DISABLE_TELNET +# endif +# ifndef CURL_DISABLE_DICT +# define CURL_DISABLE_DICT +# endif +# ifndef CURL_DISABLE_FILE +# define CURL_DISABLE_FILE +# endif +# ifndef CURL_DISABLE_RTSP +# define CURL_DISABLE_RTSP +# endif +# ifndef CURL_DISABLE_POP3 +# define CURL_DISABLE_POP3 +# endif +# ifndef CURL_DISABLE_IMAP +# define CURL_DISABLE_IMAP +# endif +# ifndef CURL_DISABLE_SMTP +# define CURL_DISABLE_SMTP +# endif +# ifndef CURL_DISABLE_RTMP +# define CURL_DISABLE_RTMP +# endif +# ifndef CURL_DISABLE_GOPHER +# define CURL_DISABLE_GOPHER +# endif +# ifndef CURL_DISABLE_SMB +# define CURL_DISABLE_SMB +# endif #endif /* @@ -192,6 +213,14 @@ # include "setup-os400.h" #endif +/* + * VMS setup file includes some system headers. + */ + +#ifdef __VMS +# include "setup-vms.h" +#endif + /* * Include header files for windows builds before redefining anything. * Use this preprocessor block only to include or exclude windows.h, @@ -204,6 +233,12 @@ */ #ifdef HAVE_WINDOWS_H +# if defined(UNICODE) && !defined(_UNICODE) +# define _UNICODE +# endif +# if defined(_UNICODE) && !defined(UNICODE) +# define UNICODE +# endif # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif @@ -211,13 +246,17 @@ # ifdef HAVE_WINSOCK2_H # include # ifdef HAVE_WS2TCPIP_H -# include +# include # endif # else # ifdef HAVE_WINSOCK_H # include # endif # endif +# include +# ifdef UNICODE + typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str); +# endif #endif /* @@ -236,6 +275,12 @@ # endif #endif +#ifdef USE_LWIPSOCK +# include +# include +# include +#endif + #ifdef HAVE_EXTRA_STRICMP_H # include #endif @@ -260,11 +305,20 @@ # include /* for basic I/O interface functions */ #endif +#ifdef __AMIGA__ +# ifndef __ixemul__ +# include +# include +# include +# include +# define select(a,b,c,d,e) WaitSelect(a,b,c,d,e,0) +# endif +#endif + #include #ifdef HAVE_ASSERT_H #include #endif -#include #ifdef __TANDEM /* for nsr-tandem-nsk systems */ #include @@ -299,8 +353,11 @@ # include # include # include +# undef lseek # define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence) +# undef fstat # define fstat(fdes,stp) _fstati64(fdes, stp) +# undef stat # define stat(fname,stp) _stati64(fname, stp) # define struct_stat struct _stati64 # define LSEEK_ERROR (__int64)-1 @@ -314,10 +371,13 @@ # include # include # include -# define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence) -# define fstat(fdes,stp) _fstat(fdes, stp) -# define stat(fname,stp) _stat(fname, stp) -# define struct_stat struct _stat +# ifndef _WIN32_WCE +# undef lseek +# define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence) +# define fstat(fdes,stp) _fstat(fdes, stp) +# define stat(fname,stp) _stat(fname, stp) +# define struct_stat struct _stat +# endif # define LSEEK_ERROR (long)-1 #endif @@ -421,9 +481,10 @@ /* * msvc 6.0 requires PSDK in order to have INET6_ADDRSTRLEN * defined in ws2tcpip.h as well as to provide IPv6 support. + * Does not apply if lwIP is used. */ -#if defined(_MSC_VER) && !defined(__POCC__) +#if defined(_MSC_VER) && !defined(__POCC__) && !defined(USE_LWIPSOCK) # if !defined(HAVE_WS2TCPIP_H) || \ ((_MSC_VER < 1300) && !defined(INET6_ADDRSTRLEN)) # undef HAVE_GETADDRINFO_THREADSAFE @@ -465,6 +526,10 @@ #ifdef USE_ARES # define CURLRES_ASYNCH # define CURLRES_ARES +/* now undef the stock libc functions just to avoid them being used */ +# undef HAVE_GETADDRINFO +# undef HAVE_FREEADDRINFO +# undef HAVE_GETHOSTBYNAME #elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) # define CURLRES_ASYNCH # define CURLRES_THREADED @@ -509,7 +574,8 @@ #if defined(_MSC_VER) && !defined(__POCC__) # if !defined(HAVE_WINDOWS_H) || ((_MSC_VER < 1300) && !defined(_FILETIME_)) # if !defined(ALLOW_MSVC6_WITHOUT_PSDK) -# error MSVC 6.0 requires "February 2003 Platform SDK" a.k.a. "Windows Server 2003 PSDK" +# error MSVC 6.0 requires "February 2003 Platform SDK" a.k.a. \ + "Windows Server 2003 PSDK" # else # define CURL_DISABLE_LDAP 1 # endif @@ -537,12 +603,31 @@ int netware_init(void); #define LIBIDN_REQUIRED_VERSION "0.4.1" -#if defined(USE_GNUTLS) || defined(USE_SSLEAY) || defined(USE_NSS) || defined(USE_QSOSSL) || defined(USE_POLARSSL) +#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \ + defined(USE_POLARSSL) || defined(USE_AXTLS) || defined(USE_MBEDTLS) || \ + defined(USE_CYASSL) || defined(USE_SCHANNEL) || \ + defined(USE_DARWINSSL) || defined(USE_GSKIT) #define USE_SSL /* SSL support has been enabled */ #endif -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_NTLM) -#if defined(USE_SSLEAY) || defined(USE_WINDOWS_SSPI) || defined(USE_GNUTLS) || defined(USE_NSS) +/* Single point where USE_SPNEGO definition might be defined */ +#if !defined(CURL_DISABLE_CRYPTO_AUTH) && \ + (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) +#define USE_SPNEGO +#endif + +/* Single point where USE_KERBEROS5 definition might be defined */ +#if !defined(CURL_DISABLE_CRYPTO_AUTH) && \ + (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) +#define USE_KERBEROS5 +#endif + +/* Single point where USE_NTLM definition might be defined */ +#if !defined(CURL_DISABLE_NTLM) && !defined(CURL_DISABLE_CRYPTO_AUTH) +#if defined(USE_OPENSSL) || defined(USE_WINDOWS_SSPI) || \ + defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) || \ + defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) + #define USE_NTLM #endif #endif @@ -552,17 +637,89 @@ int netware_init(void); #define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE") #endif -/* Define S_ISREG if not defined by system headers, f.e. MSVC */ -#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +/* + * Provide a mechanism to silence picky compilers, such as gcc 4.6+. + * Parameters should of course normally not be unused, but for example when + * we have multiple implementations of the same interface it may happen. + */ + +#if defined(__GNUC__) && ((__GNUC__ >= 3) || \ + ((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 7))) +# define UNUSED_PARAM __attribute__((__unused__)) +# define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +# define UNUSED_PARAM /*NOTHING*/ +# define WARN_UNUSED_RESULT #endif /* * Include macros and defines that should only be processed once. */ -#ifndef __SETUP_ONCE_H -#include "setup_once.h" +#ifndef HEADER_CURL_SETUP_ONCE_H +#include "curl_setup_once.h" #endif -#endif /* HEADER_CURL_LIB_SETUP_H */ +/* + * Definition of our NOP statement Object-like macro + */ + +#ifndef Curl_nop_stmt +# define Curl_nop_stmt do { } WHILE_FALSE +#endif + +/* + * Ensure that Winsock and lwIP TCP/IP stacks are not mixed. + */ + +#if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H) +# if defined(SOCKET) || \ + defined(USE_WINSOCK) || \ + defined(HAVE_WINSOCK_H) || \ + defined(HAVE_WINSOCK2_H) || \ + defined(HAVE_WS2TCPIP_H) +# error "Winsock and lwIP TCP/IP stack definitions shall not coexist!" +# endif +#endif + +/* + * Portable symbolic names for Winsock shutdown() mode flags. + */ + +#ifdef USE_WINSOCK +# define SHUT_RD 0x00 +# define SHUT_WR 0x01 +# define SHUT_RDWR 0x02 +#endif + +/* Define S_ISREG if not defined by system headers, f.e. MSVC */ +#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif + +/* Define S_ISDIR if not defined by system headers, f.e. MSVC */ +#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif + +/* In Windows the default file mode is text but an application can override it. +Therefore we specify it explicitly. https://github.com/curl/curl/pull/258 +*/ +#if defined(WIN32) || defined(MSDOS) +#define FOPEN_READTEXT "rt" +#define FOPEN_WRITETEXT "wt" +#elif defined(__CYGWIN__) +/* Cygwin has specific behavior we need to address when WIN32 is not defined. +https://cygwin.com/cygwin-ug-net/using-textbinary.html +For write we want our output to have line endings of LF and be compatible with +other Cygwin utilities. For read we want to handle input that may have line +endings either CRLF or LF so 't' is appropriate. +*/ +#define FOPEN_READTEXT "rt" +#define FOPEN_WRITETEXT "w" +#else +#define FOPEN_READTEXT "r" +#define FOPEN_WRITETEXT "w" +#endif + +#endif /* HEADER_CURL_SETUP_H */ diff --git a/project/jni/curl/lib/setup_once.h b/project/jni/curl/lib/curl_setup_once.h similarity index 86% rename from project/jni/curl/lib/setup_once.h rename to project/jni/curl/lib/curl_setup_once.h index 85e78e8d8..4da83499a 100644 --- a/project/jni/curl/lib/setup_once.h +++ b/project/jni/curl/lib/curl_setup_once.h @@ -1,5 +1,5 @@ -#ifndef __SETUP_ONCE_H -#define __SETUP_ONCE_H +#ifndef HEADER_CURL_SETUP_ONCE_H +#define HEADER_CURL_SETUP_ONCE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -23,16 +23,6 @@ ***************************************************************************/ -/******************************************************************** - * NOTICE * - * ======== * - * * - * Content of header files lib/setup_once.h and ares/setup_once.h * - * must be kept in sync. Modify the other one if you change this. * - * * - ********************************************************************/ - - /* * Inclusion of common header files. */ @@ -42,7 +32,10 @@ #include #include #include + +#ifdef HAVE_ERRNO_H #include +#endif #ifdef HAVE_SYS_TYPES_H #include @@ -76,10 +69,38 @@ #include #endif -#ifdef HAVE_STDBOOL_H +#if defined(HAVE_STDBOOL_H) && defined(HAVE_BOOL_T) #include #endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef __hpux +# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL) +# ifdef _APP32_64BIT_OFF_T +# define OLD_APP32_64BIT_OFF_T _APP32_64BIT_OFF_T +# undef _APP32_64BIT_OFF_T +# else +# undef OLD_APP32_64BIT_OFF_T +# endif +# endif +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef __hpux +# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL) +# ifdef OLD_APP32_64BIT_OFF_T +# define _APP32_64BIT_OFF_T OLD_APP32_64BIT_OFF_T +# undef OLD_APP32_64BIT_OFF_T +# endif +# endif +#endif + /* * Definition of timeval struct for platforms that don't have it. @@ -236,10 +257,22 @@ struct timeval { # define sclose(x) closesocket((x)) #elif defined(HAVE_CLOSESOCKET_CAMEL) # define sclose(x) CloseSocket((x)) +#elif defined(HAVE_CLOSE_S) +# define sclose(x) close_s((x)) +#elif defined(USE_LWIPSOCK) +# define sclose(x) lwip_close((x)) #else # define sclose(x) close((x)) #endif +/* + * Stack-independent version of fcntl() on sockets: + */ +#if defined(USE_LWIPSOCK) +# define sfcntl lwip_fcntl +#else +# define sfcntl fcntl +#endif /* * Uppercase macro versions of ANSI/ISO is*() functions/macros which @@ -255,10 +288,25 @@ struct timeval { #define ISPRINT(x) (isprint((int) ((unsigned char)x))) #define ISUPPER(x) (isupper((int) ((unsigned char)x))) #define ISLOWER(x) (islower((int) ((unsigned char)x))) +#define ISASCII(x) (isascii((int) ((unsigned char)x))) #define ISBLANK(x) (int)((((unsigned char)x) == ' ') || \ (((unsigned char)x) == '\t')) +#define TOLOWER(x) (tolower((int) ((unsigned char)x))) + + +/* + * 'bool' stuff compatible with HP-UX headers. + */ + +#if defined(__hpux) && !defined(HAVE_BOOL_T) + typedef int bool; +# define false 0 +# define true 1 +# define HAVE_BOOL_T +#endif + /* * 'bool' exists on platforms with , i.e. C99 platforms. @@ -300,6 +348,27 @@ struct timeval { #endif +/* + * Macro WHILE_FALSE may be used to build single-iteration do-while loops, + * avoiding compiler warnings. Mostly intended for other macro definitions. + */ + +#define WHILE_FALSE while(0) + +#if defined(_MSC_VER) && !defined(__POCC__) +# undef WHILE_FALSE +# if (_MSC_VER < 1500) +# define WHILE_FALSE while(1, 0) +# else +# define WHILE_FALSE \ +__pragma(warning(push)) \ +__pragma(warning(disable:4127)) \ +while(0) \ +__pragma(warning(pop)) +# endif +#endif + + /* * Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type. */ @@ -337,7 +406,7 @@ typedef int sig_atomic_t; #ifdef DEBUGBUILD #define DEBUGF(x) x #else -#define DEBUGF(x) do { } while (0) +#define DEBUGF(x) do { } WHILE_FALSE #endif @@ -348,7 +417,7 @@ typedef int sig_atomic_t; #if defined(DEBUGBUILD) && defined(HAVE_ASSERT_H) #define DEBUGASSERT(x) assert(x) #else -#define DEBUGASSERT(x) do { } while (0) +#define DEBUGASSERT(x) do { } WHILE_FALSE #endif @@ -371,7 +440,7 @@ typedef int sig_atomic_t; * (or equivalent) on this platform to hide platform details to code using it. */ -#ifdef WIN32 +#if defined(WIN32) && !defined(USE_LWIPSOCK) #define ERRNO ((int)GetLastError()) #define SET_ERRNO(x) (SetLastError((DWORD)(x))) #else @@ -459,17 +528,6 @@ typedef int sig_atomic_t; #define EREMOTE WSAEREMOTE #endif - -/* - * Actually use __32_getpwuid() on 64-bit VMS builds for getpwuid() - */ - -#if defined(__VMS) && \ - defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64) -#define getpwuid __32_getpwuid -#endif - - /* * Macro argv_item_t hides platform details to code using it. */ @@ -489,5 +547,5 @@ typedef int sig_atomic_t; #define ZERO_NULL 0 -#endif /* __SETUP_ONCE_H */ +#endif /* HEADER_CURL_SETUP_ONCE_H */ diff --git a/project/jni/curl/lib/curl_sspi.c b/project/jni/curl/lib/curl_sspi.c index b985dbceb..04eac489b 100644 --- a/project/jni/curl/lib/curl_sspi.c +++ b/project/jni/curl/lib/curl_sspi.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,31 +20,38 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifdef USE_WINDOWS_SSPI #include - #include "curl_sspi.h" +#include "curl_multibyte.h" +#include "warnless.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +/* The last #include files should be: */ #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" - /* We use our own typedef here since some headers might lack these */ -typedef PSecurityFunctionTableA (APIENTRY *INITSECURITYINTERFACE_FN_A)(VOID); +typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID); + +/* See definition of SECURITY_ENTRYPOINT in sspi.h */ +#ifdef UNICODE +# ifdef _WIN32_WCE +# define SECURITYENTRYPOINT L"InitSecurityInterfaceW" +# else +# define SECURITYENTRYPOINT "InitSecurityInterfaceW" +# endif +#else +# define SECURITYENTRYPOINT "InitSecurityInterfaceA" +#endif /* Handle of security.dll or secur32.dll, depending on Windows version */ HMODULE s_hSecDll = NULL; /* Pointer to SSPI dispatch table */ -PSecurityFunctionTableA s_pSecFn = NULL; - +PSecurityFunctionTable s_pSecFn = NULL; /* * Curl_sspi_global_init() @@ -57,59 +64,87 @@ PSecurityFunctionTableA s_pSecFn = NULL; * Once this function has been executed, Windows SSPI functions can be * called through the Security Service Provider Interface dispatch table. */ - -CURLcode -Curl_sspi_global_init(void) +CURLcode Curl_sspi_global_init(void) { - OSVERSIONINFO osver; - INITSECURITYINTERFACE_FN_A pInitSecurityInterface; + bool securityDll = FALSE; + INITSECURITYINTERFACE_FN pInitSecurityInterface; /* If security interface is not yet initialized try to do this */ - if(s_hSecDll == NULL) { - - /* Find out Windows version */ - memset(&osver, 0, sizeof(osver)); - osver.dwOSVersionInfoSize = sizeof(osver); - if(! GetVersionEx(&osver)) - return CURLE_FAILED_INIT; - + if(!s_hSecDll) { /* Security Service Provider Interface (SSPI) functions are located in * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP * have both these DLLs (security.dll forwards calls to secur32.dll) */ + DWORD majorVersion = 4; + DWORD platformId = VER_PLATFORM_WIN32_NT; + +#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ + (_WIN32_WINNT < _WIN32_WINNT_WIN2K) + OSVERSIONINFO osver; + + memset(&osver, 0, sizeof(osver)); + osver.dwOSVersionInfoSize = sizeof(osver); + + /* Find out Windows version */ + if(!GetVersionEx(&osver)) + return CURLE_FAILED_INIT; + + /* Verify the major version number == 4 and platform id == WIN_NT */ + if(osver.dwMajorVersion == majorVersion && + osver.dwPlatformId == platformId) + securityDll = TRUE; +#else + ULONGLONG cm; + OSVERSIONINFOEX osver; + + memset(&osver, 0, sizeof(osver)); + osver.dwOSVersionInfoSize = sizeof(osver); + osver.dwMajorVersion = majorVersion; + osver.dwPlatformId = platformId; + + cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); + cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL); + + /* Verify the major version number == 4 and platform id == WIN_NT */ + if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR | + VER_PLATFORMID), + cm)) + securityDll = TRUE; +#endif /* Load SSPI dll into the address space of the calling process */ - if(osver.dwPlatformId == VER_PLATFORM_WIN32_NT - && osver.dwMajorVersion == 4) - s_hSecDll = LoadLibrary("security.dll"); + if(securityDll) + s_hSecDll = LoadLibrary(TEXT("security.dll")); else - s_hSecDll = LoadLibrary("secur32.dll"); - if(! s_hSecDll) + s_hSecDll = LoadLibrary(TEXT("secur32.dll")); + if(!s_hSecDll) return CURLE_FAILED_INIT; /* Get address of the InitSecurityInterfaceA function from the SSPI dll */ - pInitSecurityInterface = (INITSECURITYINTERFACE_FN_A) - GetProcAddress(s_hSecDll, "InitSecurityInterfaceA"); - if(! pInitSecurityInterface) + pInitSecurityInterface = (INITSECURITYINTERFACE_FN) + GetProcAddress(s_hSecDll, SECURITYENTRYPOINT); + if(!pInitSecurityInterface) return CURLE_FAILED_INIT; /* Get pointer to Security Service Provider Interface dispatch table */ s_pSecFn = pInitSecurityInterface(); - if(! s_pSecFn) + if(!s_pSecFn) return CURLE_FAILED_INIT; - } + return CURLE_OK; } - /* * Curl_sspi_global_cleanup() * * This deinitializes the Security Service Provider Interface from libcurl. */ -void -Curl_sspi_global_cleanup(void) +void Curl_sspi_global_cleanup(void) { if(s_hSecDll) { FreeLibrary(s_hSecDll); @@ -118,4 +153,105 @@ Curl_sspi_global_cleanup(void) } } +/* + * Curl_create_sspi_identity() + * + * This is used to populate a SSPI identity structure based on the supplied + * username and password. + * + * Parameters: + * + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * identity [in/out] - The identity structure. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, + SEC_WINNT_AUTH_IDENTITY *identity) +{ + xcharp_u useranddomain; + xcharp_u user, dup_user; + xcharp_u domain, dup_domain; + xcharp_u passwd, dup_passwd; + size_t domlen = 0; + + domain.const_tchar_ptr = TEXT(""); + + /* Initialize the identity */ + memset(identity, 0, sizeof(*identity)); + + useranddomain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)userp); + if(!useranddomain.tchar_ptr) + return CURLE_OUT_OF_MEMORY; + + user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\')); + if(!user.const_tchar_ptr) + user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/')); + + if(user.tchar_ptr) { + domain.tchar_ptr = useranddomain.tchar_ptr; + domlen = user.tchar_ptr - useranddomain.tchar_ptr; + user.tchar_ptr++; + } + else { + user.tchar_ptr = useranddomain.tchar_ptr; + domain.const_tchar_ptr = TEXT(""); + domlen = 0; + } + + /* Setup the identity's user and length */ + dup_user.tchar_ptr = _tcsdup(user.tchar_ptr); + if(!dup_user.tchar_ptr) { + Curl_unicodefree(useranddomain.tchar_ptr); + return CURLE_OUT_OF_MEMORY; + } + identity->User = dup_user.tbyte_ptr; + identity->UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr)); + dup_user.tchar_ptr = NULL; + + /* Setup the identity's domain and length */ + dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1)); + if(!dup_domain.tchar_ptr) { + Curl_unicodefree(useranddomain.tchar_ptr); + return CURLE_OUT_OF_MEMORY; + } + _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen); + *(dup_domain.tchar_ptr + domlen) = TEXT('\0'); + identity->Domain = dup_domain.tbyte_ptr; + identity->DomainLength = curlx_uztoul(domlen); + dup_domain.tchar_ptr = NULL; + + Curl_unicodefree(useranddomain.tchar_ptr); + + /* Setup the identity's password and length */ + passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp); + if(!passwd.tchar_ptr) + return CURLE_OUT_OF_MEMORY; + dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr); + if(!dup_passwd.tchar_ptr) { + Curl_unicodefree(passwd.tchar_ptr); + return CURLE_OUT_OF_MEMORY; + } + identity->Password = dup_passwd.tbyte_ptr; + identity->PasswordLength = curlx_uztoul(_tcslen(dup_passwd.tchar_ptr)); + dup_passwd.tchar_ptr = NULL; + + Curl_unicodefree(passwd.tchar_ptr); + + /* Setup the identity's flags */ + identity->Flags = SECFLAG_WINNT_AUTH_IDENTITY; + + return CURLE_OK; +} + +void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity) +{ + if(identity) { + Curl_safefree(identity->User); + Curl_safefree(identity->Password); + Curl_safefree(identity->Domain); + } +} + #endif /* USE_WINDOWS_SSPI */ diff --git a/project/jni/curl/lib/curl_sspi.h b/project/jni/curl/lib/curl_sspi.h index 221bce128..2bbf9477b 100644 --- a/project/jni/curl/lib/curl_sspi.h +++ b/project/jni/curl/lib/curl_sspi.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,14 +22,14 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifdef USE_WINDOWS_SSPI #include /* - * When including the folowing three headers, it is mandatory to define either + * When including the following three headers, it is mandatory to define either * SECURITY_WIN32 or SECURITY_KERNEL, indicating who is compiling the code. */ @@ -40,34 +40,311 @@ #include #include -/* Provide some definitions missing in MinGW's headers */ - -#ifndef SEC_I_CONTEXT_EXPIRED -# define SEC_I_CONTEXT_EXPIRED ((HRESULT)0x00090317L) -#endif -#ifndef SEC_E_BUFFER_TOO_SMALL -# define SEC_E_BUFFER_TOO_SMALL ((HRESULT)0x80090321L) -#endif -#ifndef SEC_E_CONTEXT_EXPIRED -# define SEC_E_CONTEXT_EXPIRED ((HRESULT)0x80090317L) -#endif -#ifndef SEC_E_CRYPTO_SYSTEM_INVALID -# define SEC_E_CRYPTO_SYSTEM_INVALID ((HRESULT)0x80090337L) -#endif -#ifndef SEC_E_MESSAGE_ALTERED -# define SEC_E_MESSAGE_ALTERED ((HRESULT)0x8009030FL) -#endif -#ifndef SEC_E_OUT_OF_SEQUENCE -# define SEC_E_OUT_OF_SEQUENCE ((HRESULT)0x80090310L) -#endif - CURLcode Curl_sspi_global_init(void); void Curl_sspi_global_cleanup(void); -/* Forward-declaration of global variables defined in curl_sspi.c */ +/* This is used to populate the domain in a SSPI identity structure */ +CURLcode Curl_override_sspi_http_realm(const char *chlg, + SEC_WINNT_AUTH_IDENTITY *identity); +/* This is used to generate an SSPI identity structure */ +CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, + SEC_WINNT_AUTH_IDENTITY *identity); + +/* This is used to free an SSPI identity structure */ +void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity); + +/* Forward-declaration of global variables defined in curl_sspi.c */ extern HMODULE s_hSecDll; -extern PSecurityFunctionTableA s_pSecFn; +extern PSecurityFunctionTable s_pSecFn; + +/* Provide some definitions missing in old headers */ +#define SP_NAME_DIGEST "WDigest" +#define SP_NAME_NTLM "NTLM" +#define SP_NAME_NEGOTIATE "Negotiate" +#define SP_NAME_KERBEROS "Kerberos" + +#ifndef ISC_REQ_USE_HTTP_STYLE +#define ISC_REQ_USE_HTTP_STYLE 0x01000000 +#endif + +#ifndef ISC_RET_REPLAY_DETECT +#define ISC_RET_REPLAY_DETECT 0x00000004 +#endif + +#ifndef ISC_RET_SEQUENCE_DETECT +#define ISC_RET_SEQUENCE_DETECT 0x00000008 +#endif + +#ifndef ISC_RET_CONFIDENTIALITY +#define ISC_RET_CONFIDENTIALITY 0x00000010 +#endif + +#ifndef ISC_RET_ALLOCATED_MEMORY +#define ISC_RET_ALLOCATED_MEMORY 0x00000100 +#endif + +#ifndef ISC_RET_STREAM +#define ISC_RET_STREAM 0x00008000 +#endif + +#ifndef SEC_E_INSUFFICIENT_MEMORY +# define SEC_E_INSUFFICIENT_MEMORY ((HRESULT)0x80090300L) +#endif +#ifndef SEC_E_INVALID_HANDLE +# define SEC_E_INVALID_HANDLE ((HRESULT)0x80090301L) +#endif +#ifndef SEC_E_UNSUPPORTED_FUNCTION +# define SEC_E_UNSUPPORTED_FUNCTION ((HRESULT)0x80090302L) +#endif +#ifndef SEC_E_TARGET_UNKNOWN +# define SEC_E_TARGET_UNKNOWN ((HRESULT)0x80090303L) +#endif +#ifndef SEC_E_INTERNAL_ERROR +# define SEC_E_INTERNAL_ERROR ((HRESULT)0x80090304L) +#endif +#ifndef SEC_E_SECPKG_NOT_FOUND +# define SEC_E_SECPKG_NOT_FOUND ((HRESULT)0x80090305L) +#endif +#ifndef SEC_E_NOT_OWNER +# define SEC_E_NOT_OWNER ((HRESULT)0x80090306L) +#endif +#ifndef SEC_E_CANNOT_INSTALL +# define SEC_E_CANNOT_INSTALL ((HRESULT)0x80090307L) +#endif +#ifndef SEC_E_INVALID_TOKEN +# define SEC_E_INVALID_TOKEN ((HRESULT)0x80090308L) +#endif +#ifndef SEC_E_CANNOT_PACK +# define SEC_E_CANNOT_PACK ((HRESULT)0x80090309L) +#endif +#ifndef SEC_E_QOP_NOT_SUPPORTED +# define SEC_E_QOP_NOT_SUPPORTED ((HRESULT)0x8009030AL) +#endif +#ifndef SEC_E_NO_IMPERSONATION +# define SEC_E_NO_IMPERSONATION ((HRESULT)0x8009030BL) +#endif +#ifndef SEC_E_LOGON_DENIED +# define SEC_E_LOGON_DENIED ((HRESULT)0x8009030CL) +#endif +#ifndef SEC_E_UNKNOWN_CREDENTIALS +# define SEC_E_UNKNOWN_CREDENTIALS ((HRESULT)0x8009030DL) +#endif +#ifndef SEC_E_NO_CREDENTIALS +# define SEC_E_NO_CREDENTIALS ((HRESULT)0x8009030EL) +#endif +#ifndef SEC_E_MESSAGE_ALTERED +# define SEC_E_MESSAGE_ALTERED ((HRESULT)0x8009030FL) +#endif +#ifndef SEC_E_OUT_OF_SEQUENCE +# define SEC_E_OUT_OF_SEQUENCE ((HRESULT)0x80090310L) +#endif +#ifndef SEC_E_NO_AUTHENTICATING_AUTHORITY +# define SEC_E_NO_AUTHENTICATING_AUTHORITY ((HRESULT)0x80090311L) +#endif +#ifndef SEC_E_BAD_PKGID +# define SEC_E_BAD_PKGID ((HRESULT)0x80090316L) +#endif +#ifndef SEC_E_CONTEXT_EXPIRED +# define SEC_E_CONTEXT_EXPIRED ((HRESULT)0x80090317L) +#endif +#ifndef SEC_E_INCOMPLETE_MESSAGE +# define SEC_E_INCOMPLETE_MESSAGE ((HRESULT)0x80090318L) +#endif +#ifndef SEC_E_INCOMPLETE_CREDENTIALS +# define SEC_E_INCOMPLETE_CREDENTIALS ((HRESULT)0x80090320L) +#endif +#ifndef SEC_E_BUFFER_TOO_SMALL +# define SEC_E_BUFFER_TOO_SMALL ((HRESULT)0x80090321L) +#endif +#ifndef SEC_E_WRONG_PRINCIPAL +# define SEC_E_WRONG_PRINCIPAL ((HRESULT)0x80090322L) +#endif +#ifndef SEC_E_TIME_SKEW +# define SEC_E_TIME_SKEW ((HRESULT)0x80090324L) +#endif +#ifndef SEC_E_UNTRUSTED_ROOT +# define SEC_E_UNTRUSTED_ROOT ((HRESULT)0x80090325L) +#endif +#ifndef SEC_E_ILLEGAL_MESSAGE +# define SEC_E_ILLEGAL_MESSAGE ((HRESULT)0x80090326L) +#endif +#ifndef SEC_E_CERT_UNKNOWN +# define SEC_E_CERT_UNKNOWN ((HRESULT)0x80090327L) +#endif +#ifndef SEC_E_CERT_EXPIRED +# define SEC_E_CERT_EXPIRED ((HRESULT)0x80090328L) +#endif +#ifndef SEC_E_ENCRYPT_FAILURE +# define SEC_E_ENCRYPT_FAILURE ((HRESULT)0x80090329L) +#endif +#ifndef SEC_E_DECRYPT_FAILURE +# define SEC_E_DECRYPT_FAILURE ((HRESULT)0x80090330L) +#endif +#ifndef SEC_E_ALGORITHM_MISMATCH +# define SEC_E_ALGORITHM_MISMATCH ((HRESULT)0x80090331L) +#endif +#ifndef SEC_E_SECURITY_QOS_FAILED +# define SEC_E_SECURITY_QOS_FAILED ((HRESULT)0x80090332L) +#endif +#ifndef SEC_E_UNFINISHED_CONTEXT_DELETED +# define SEC_E_UNFINISHED_CONTEXT_DELETED ((HRESULT)0x80090333L) +#endif +#ifndef SEC_E_NO_TGT_REPLY +# define SEC_E_NO_TGT_REPLY ((HRESULT)0x80090334L) +#endif +#ifndef SEC_E_NO_IP_ADDRESSES +# define SEC_E_NO_IP_ADDRESSES ((HRESULT)0x80090335L) +#endif +#ifndef SEC_E_WRONG_CREDENTIAL_HANDLE +# define SEC_E_WRONG_CREDENTIAL_HANDLE ((HRESULT)0x80090336L) +#endif +#ifndef SEC_E_CRYPTO_SYSTEM_INVALID +# define SEC_E_CRYPTO_SYSTEM_INVALID ((HRESULT)0x80090337L) +#endif +#ifndef SEC_E_MAX_REFERRALS_EXCEEDED +# define SEC_E_MAX_REFERRALS_EXCEEDED ((HRESULT)0x80090338L) +#endif +#ifndef SEC_E_MUST_BE_KDC +# define SEC_E_MUST_BE_KDC ((HRESULT)0x80090339L) +#endif +#ifndef SEC_E_STRONG_CRYPTO_NOT_SUPPORTED +# define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED ((HRESULT)0x8009033AL) +#endif +#ifndef SEC_E_TOO_MANY_PRINCIPALS +# define SEC_E_TOO_MANY_PRINCIPALS ((HRESULT)0x8009033BL) +#endif +#ifndef SEC_E_NO_PA_DATA +# define SEC_E_NO_PA_DATA ((HRESULT)0x8009033CL) +#endif +#ifndef SEC_E_PKINIT_NAME_MISMATCH +# define SEC_E_PKINIT_NAME_MISMATCH ((HRESULT)0x8009033DL) +#endif +#ifndef SEC_E_SMARTCARD_LOGON_REQUIRED +# define SEC_E_SMARTCARD_LOGON_REQUIRED ((HRESULT)0x8009033EL) +#endif +#ifndef SEC_E_SHUTDOWN_IN_PROGRESS +# define SEC_E_SHUTDOWN_IN_PROGRESS ((HRESULT)0x8009033FL) +#endif +#ifndef SEC_E_KDC_INVALID_REQUEST +# define SEC_E_KDC_INVALID_REQUEST ((HRESULT)0x80090340L) +#endif +#ifndef SEC_E_KDC_UNABLE_TO_REFER +# define SEC_E_KDC_UNABLE_TO_REFER ((HRESULT)0x80090341L) +#endif +#ifndef SEC_E_KDC_UNKNOWN_ETYPE +# define SEC_E_KDC_UNKNOWN_ETYPE ((HRESULT)0x80090342L) +#endif +#ifndef SEC_E_UNSUPPORTED_PREAUTH +# define SEC_E_UNSUPPORTED_PREAUTH ((HRESULT)0x80090343L) +#endif +#ifndef SEC_E_DELEGATION_REQUIRED +# define SEC_E_DELEGATION_REQUIRED ((HRESULT)0x80090345L) +#endif +#ifndef SEC_E_BAD_BINDINGS +# define SEC_E_BAD_BINDINGS ((HRESULT)0x80090346L) +#endif +#ifndef SEC_E_MULTIPLE_ACCOUNTS +# define SEC_E_MULTIPLE_ACCOUNTS ((HRESULT)0x80090347L) +#endif +#ifndef SEC_E_NO_KERB_KEY +# define SEC_E_NO_KERB_KEY ((HRESULT)0x80090348L) +#endif +#ifndef SEC_E_CERT_WRONG_USAGE +# define SEC_E_CERT_WRONG_USAGE ((HRESULT)0x80090349L) +#endif +#ifndef SEC_E_DOWNGRADE_DETECTED +# define SEC_E_DOWNGRADE_DETECTED ((HRESULT)0x80090350L) +#endif +#ifndef SEC_E_SMARTCARD_CERT_REVOKED +# define SEC_E_SMARTCARD_CERT_REVOKED ((HRESULT)0x80090351L) +#endif +#ifndef SEC_E_ISSUING_CA_UNTRUSTED +# define SEC_E_ISSUING_CA_UNTRUSTED ((HRESULT)0x80090352L) +#endif +#ifndef SEC_E_REVOCATION_OFFLINE_C +# define SEC_E_REVOCATION_OFFLINE_C ((HRESULT)0x80090353L) +#endif +#ifndef SEC_E_PKINIT_CLIENT_FAILURE +# define SEC_E_PKINIT_CLIENT_FAILURE ((HRESULT)0x80090354L) +#endif +#ifndef SEC_E_SMARTCARD_CERT_EXPIRED +# define SEC_E_SMARTCARD_CERT_EXPIRED ((HRESULT)0x80090355L) +#endif +#ifndef SEC_E_NO_S4U_PROT_SUPPORT +# define SEC_E_NO_S4U_PROT_SUPPORT ((HRESULT)0x80090356L) +#endif +#ifndef SEC_E_CROSSREALM_DELEGATION_FAILURE +# define SEC_E_CROSSREALM_DELEGATION_FAILURE ((HRESULT)0x80090357L) +#endif +#ifndef SEC_E_REVOCATION_OFFLINE_KDC +# define SEC_E_REVOCATION_OFFLINE_KDC ((HRESULT)0x80090358L) +#endif +#ifndef SEC_E_ISSUING_CA_UNTRUSTED_KDC +# define SEC_E_ISSUING_CA_UNTRUSTED_KDC ((HRESULT)0x80090359L) +#endif +#ifndef SEC_E_KDC_CERT_EXPIRED +# define SEC_E_KDC_CERT_EXPIRED ((HRESULT)0x8009035AL) +#endif +#ifndef SEC_E_KDC_CERT_REVOKED +# define SEC_E_KDC_CERT_REVOKED ((HRESULT)0x8009035BL) +#endif +#ifndef SEC_E_INVALID_PARAMETER +# define SEC_E_INVALID_PARAMETER ((HRESULT)0x8009035DL) +#endif +#ifndef SEC_E_DELEGATION_POLICY +# define SEC_E_DELEGATION_POLICY ((HRESULT)0x8009035EL) +#endif +#ifndef SEC_E_POLICY_NLTM_ONLY +# define SEC_E_POLICY_NLTM_ONLY ((HRESULT)0x8009035FL) +#endif + +#ifndef SEC_I_CONTINUE_NEEDED +# define SEC_I_CONTINUE_NEEDED ((HRESULT)0x00090312L) +#endif +#ifndef SEC_I_COMPLETE_NEEDED +# define SEC_I_COMPLETE_NEEDED ((HRESULT)0x00090313L) +#endif +#ifndef SEC_I_COMPLETE_AND_CONTINUE +# define SEC_I_COMPLETE_AND_CONTINUE ((HRESULT)0x00090314L) +#endif +#ifndef SEC_I_LOCAL_LOGON +# define SEC_I_LOCAL_LOGON ((HRESULT)0x00090315L) +#endif +#ifndef SEC_I_CONTEXT_EXPIRED +# define SEC_I_CONTEXT_EXPIRED ((HRESULT)0x00090317L) +#endif +#ifndef SEC_I_INCOMPLETE_CREDENTIALS +# define SEC_I_INCOMPLETE_CREDENTIALS ((HRESULT)0x00090320L) +#endif +#ifndef SEC_I_RENEGOTIATE +# define SEC_I_RENEGOTIATE ((HRESULT)0x00090321L) +#endif +#ifndef SEC_I_NO_LSA_CONTEXT +# define SEC_I_NO_LSA_CONTEXT ((HRESULT)0x00090323L) +#endif +#ifndef SEC_I_SIGNATURE_NEEDED +# define SEC_I_SIGNATURE_NEEDED ((HRESULT)0x0009035CL) +#endif + +#ifndef CRYPT_E_REVOKED +# define CRYPT_E_REVOKED ((HRESULT)0x80092010L) +#endif + +#ifdef UNICODE +# define SECFLAG_WINNT_AUTH_IDENTITY \ + (unsigned long)SEC_WINNT_AUTH_IDENTITY_UNICODE +#else +# define SECFLAG_WINNT_AUTH_IDENTITY \ + (unsigned long)SEC_WINNT_AUTH_IDENTITY_ANSI +#endif + +/* + * Definitions required from ntsecapi.h are directly provided below this point + * to avoid including ntsecapi.h due to a conflict with OpenSSL's safestack.h + */ +#define KERB_WRAP_NO_ENCRYPT 0x80000001 #endif /* USE_WINDOWS_SSPI */ + #endif /* HEADER_CURL_SSPI_H */ diff --git a/project/jni/curl/lib/curl_threads.c b/project/jni/curl/lib/curl_threads.c index fd10bd487..59d881143 100644 --- a/project/jni/curl/lib/curl_threads.c +++ b/project/jni/curl/lib/curl_threads.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -19,7 +19,8 @@ * KIND, either express or implied. * ***************************************************************************/ -#include "setup.h" + +#include "curl_setup.h" #if defined(USE_THREADS_POSIX) # ifdef HAVE_PTHREAD_H @@ -32,10 +33,6 @@ #endif #include "curl_threads.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -62,32 +59,38 @@ static void *curl_thread_create_thunk(void *arg) curl_thread_t Curl_thread_create(unsigned int (*func) (void*), void *arg) { - curl_thread_t t; + curl_thread_t t = malloc(sizeof(pthread_t)); struct curl_actual_call *ac = malloc(sizeof(struct curl_actual_call)); - if(!ac) - return curl_thread_t_null; + if(!(ac && t)) + goto err; ac->func = func; ac->arg = arg; - if(pthread_create(&t, NULL, curl_thread_create_thunk, ac) != 0) { - free(ac); - return curl_thread_t_null; - } + if(pthread_create(t, NULL, curl_thread_create_thunk, ac) != 0) + goto err; return t; + +err: + free(t); + free(ac); + return curl_thread_t_null; } void Curl_thread_destroy(curl_thread_t hnd) { - if(hnd != curl_thread_t_null) - pthread_detach(hnd); + if(hnd != curl_thread_t_null) { + pthread_detach(*hnd); + free(hnd); + } } int Curl_thread_join(curl_thread_t *hnd) { - int ret = (pthread_join(*hnd, NULL) == 0); + int ret = (pthread_join(**hnd, NULL) == 0); + free(*hnd); *hnd = curl_thread_t_null; return ret; @@ -95,7 +98,8 @@ int Curl_thread_join(curl_thread_t *hnd) #elif defined(USE_THREADS_WIN32) -curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void*), void *arg) +curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void*), + void *arg) { #ifdef _WIN32_WCE return CreateThread(NULL, 0, func, arg, 0, NULL); @@ -115,7 +119,12 @@ void Curl_thread_destroy(curl_thread_t hnd) int Curl_thread_join(curl_thread_t *hnd) { +#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ + (_WIN32_WINNT < _WIN32_WINNT_VISTA) int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0); +#else + int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0); +#endif Curl_thread_destroy(*hnd); diff --git a/project/jni/curl/lib/curl_threads.h b/project/jni/curl/lib/curl_threads.h index ba81054a2..8cbac63a7 100644 --- a/project/jni/curl/lib/curl_threads.h +++ b/project/jni/curl/lib/curl_threads.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,13 +21,13 @@ * KIND, either express or implied. * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #if defined(USE_THREADS_POSIX) # define CURL_STDCALL # define curl_mutex_t pthread_mutex_t -# define curl_thread_t pthread_t -# define curl_thread_t_null (pthread_t)0 +# define curl_thread_t pthread_t * +# define curl_thread_t_null (pthread_t *)0 # define Curl_mutex_init(m) pthread_mutex_init(m, NULL) # define Curl_mutex_acquire(m) pthread_mutex_lock(m) # define Curl_mutex_release(m) pthread_mutex_unlock(m) @@ -37,7 +37,12 @@ # define curl_mutex_t CRITICAL_SECTION # define curl_thread_t HANDLE # define curl_thread_t_null (HANDLE)0 -# define Curl_mutex_init(m) InitializeCriticalSection(m) +# if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ + (_WIN32_WINNT < _WIN32_WINNT_VISTA) +# define Curl_mutex_init(m) InitializeCriticalSection(m) +# else +# define Curl_mutex_init(m) InitializeCriticalSectionEx(m, 0, 1) +# endif # define Curl_mutex_acquire(m) EnterCriticalSection(m) # define Curl_mutex_release(m) LeaveCriticalSection(m) # define Curl_mutex_destroy(m) DeleteCriticalSection(m) diff --git a/project/jni/curl/lib/curlx.h b/project/jni/curl/lib/curlx.h index 2b7fec58a..448a34ff3 100644 --- a/project/jni/curl/lib/curlx.h +++ b/project/jni/curl/lib/curlx.h @@ -1,5 +1,5 @@ -#ifndef __CURLX_H -#define __CURLX_H +#ifndef HEADER_CURL_CURLX_H +#define HEADER_CURL_CURLX_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -89,9 +89,8 @@ #ifdef ENABLE_CURLX_PRINTF /* If this define is set, we define all "standard" printf() functions to use - the curlx_* version instead. It makes the source code transparant and - easier to understand/patch. Undefine them first in case _MPRINTF_REPLACE - is set. */ + the curlx_* version instead. It makes the source code transparent and + easier to understand/patch. Undefine them first. */ # undef printf # undef fprintf # undef sprintf @@ -115,4 +114,5 @@ # define vaprintf curlx_mvaprintf #endif /* ENABLE_CURLX_PRINTF */ -#endif /* __CURLX_H */ +#endif /* HEADER_CURL_CURLX_H */ + diff --git a/project/jni/curl/lib/dict.c b/project/jni/curl/lib/dict.c index d86923a9f..2e7cb4778 100644 --- a/project/jni/curl/lib/dict.c +++ b/project/jni/curl/lib/dict.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,32 +20,16 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_DICT -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include - -#ifdef WIN32 -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif +#ifdef HAVE_NETINET_IN_H #include -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include #endif +#ifdef HAVE_NETDB_H #include +#endif #ifdef HAVE_ARPA_INET_H #include #endif @@ -64,9 +48,6 @@ #include #endif - -#endif - #include "urldata.h" #include #include "transfer.h" @@ -76,14 +57,10 @@ #include "strequal.h" #include "dict.h" #include "rawstr.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" - /* * Forward declarations. */ @@ -105,10 +82,13 @@ const struct Curl_handler Curl_handler_dict = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_DICT, /* defport */ - PROT_DICT /* protocol */ + CURLPROTO_DICT, /* protocol */ + PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ }; static char *unescape_word(struct SessionHandle *data, const char *inputbuff) @@ -117,7 +97,7 @@ static char *unescape_word(struct SessionHandle *data, const char *inputbuff) char *dictp; char *ptr; int len; - char byte; + char ch; int olen=0; newp = curl_easy_unescape(data, inputbuff, 0, &len); @@ -129,18 +109,17 @@ static char *unescape_word(struct SessionHandle *data, const char *inputbuff) /* According to RFC2229 section 2.2, these letters need to be escaped with \[letter] */ for(ptr = newp; - (byte = *ptr) != 0; + (ch = *ptr) != 0; ptr++) { - if((byte <= 32) || (byte == 127) || - (byte == '\'') || (byte == '\"') || (byte == '\\')) { + if((ch <= 32) || (ch == 127) || + (ch == '\'') || (ch == '\"') || (ch == '\\')) { dictp[olen++] = '\\'; } - dictp[olen++] = byte; + dictp[olen++] = ch; } dictp[olen]=0; - - free(newp); } + free(newp); return dictp; } @@ -188,7 +167,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done) } if((word == NULL) || (*word == (char)0)) { - infof(data, "lookup word is missing"); + infof(data, "lookup word is missing\n"); word=(char *)"default"; } if((database == NULL) || (*database == (char)0)) { @@ -242,7 +221,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done) } if((word == NULL) || (*word == (char)0)) { - infof(data, "lookup word is missing"); + infof(data, "lookup word is missing\n"); word=(char *)"default"; } if((database == NULL) || (*database == (char)0)) { @@ -278,7 +257,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done) int i; ppath++; - for (i = 0; ppath[i]; i++) { + for(i = 0; ppath[i]; i++) { if(ppath[i] == ':') ppath[i] = ' '; } diff --git a/project/jni/curl/lib/dict.h b/project/jni/curl/lib/dict.h index 44fd9d49d..12c0f3394 100644 --- a/project/jni/curl/lib/dict.h +++ b/project/jni/curl/lib/dict.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/project/jni/curl/lib/dotdot.c b/project/jni/curl/lib/dotdot.c new file mode 100644 index 000000000..99fac7f98 --- /dev/null +++ b/project/jni/curl/lib/dotdot.c @@ -0,0 +1,177 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include "dotdot.h" + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* + * "Remove Dot Segments" + * https://tools.ietf.org/html/rfc3986#section-5.2.4 + */ + +/* + * Curl_dedotdotify() + * @unittest: 1395 + * + * This function gets a zero-terminated path with dot and dotdot sequences + * passed in and strips them off according to the rules in RFC 3986 section + * 5.2.4. + * + * The function handles a query part ('?' + stuff) appended but it expects + * that fragments ('#' + stuff) have already been cut off. + * + * RETURNS + * + * an allocated dedotdotified output string + */ +char *Curl_dedotdotify(const char *input) +{ + size_t inlen = strlen(input); + char *clone; + size_t clen = inlen; /* the length of the cloned input */ + char *out = malloc(inlen+1); + char *outptr; + char *orgclone; + char *queryp; + if(!out) + return NULL; /* out of memory */ + + /* get a cloned copy of the input */ + clone = strdup(input); + if(!clone) { + free(out); + return NULL; + } + orgclone = clone; + outptr = out; + + if(!*clone) { + /* zero length string, return that */ + free(out); + return clone; + } + + /* + * To handle query-parts properly, we must find it and remove it during the + * dotdot-operation and then append it again at the end to the output + * string. + */ + queryp = strchr(clone, '?'); + if(queryp) + *queryp = 0; + + do { + + /* A. If the input buffer begins with a prefix of "../" or "./", then + remove that prefix from the input buffer; otherwise, */ + + if(!strncmp("./", clone, 2)) { + clone+=2; + clen-=2; + } + else if(!strncmp("../", clone, 3)) { + clone+=3; + clen-=3; + } + + /* B. if the input buffer begins with a prefix of "/./" or "/.", where + "." is a complete path segment, then replace that prefix with "/" in + the input buffer; otherwise, */ + else if(!strncmp("/./", clone, 3)) { + clone+=2; + clen-=2; + } + else if(!strcmp("/.", clone)) { + clone[1]='/'; + clone++; + clen-=1; + } + + /* C. if the input buffer begins with a prefix of "/../" or "/..", where + ".." is a complete path segment, then replace that prefix with "/" in + the input buffer and remove the last segment and its preceding "/" (if + any) from the output buffer; otherwise, */ + + else if(!strncmp("/../", clone, 4)) { + clone+=3; + clen-=3; + /* remove the last segment from the output buffer */ + while(outptr > out) { + outptr--; + if(*outptr == '/') + break; + } + *outptr = 0; /* zero-terminate where it stops */ + } + else if(!strcmp("/..", clone)) { + clone[2]='/'; + clone+=2; + clen-=2; + /* remove the last segment from the output buffer */ + while(outptr > out) { + outptr--; + if(*outptr == '/') + break; + } + *outptr = 0; /* zero-terminate where it stops */ + } + + /* D. if the input buffer consists only of "." or "..", then remove + that from the input buffer; otherwise, */ + + else if(!strcmp(".", clone) || !strcmp("..", clone)) { + *clone=0; + } + + else { + /* E. move the first path segment in the input buffer to the end of + the output buffer, including the initial "/" character (if any) and + any subsequent characters up to, but not including, the next "/" + character or the end of the input buffer. */ + + do { + *outptr++ = *clone++; + clen--; + } while(*clone && (*clone != '/')); + *outptr = 0; + } + + } while(*clone); + + if(queryp) { + size_t qlen; + /* There was a query part, append that to the output. The 'clone' string + may now have been altered so we copy from the original input string + from the correct index. */ + size_t oindex = queryp - orgclone; + qlen = strlen(&input[oindex]); + memcpy(outptr, &input[oindex], qlen+1); /* include the ending zero byte */ + } + + free(orgclone); + return out; +} diff --git a/project/jni/curl/lib/curl_rand.h b/project/jni/curl/lib/dotdot.h similarity index 76% rename from project/jni/curl/lib/curl_rand.h rename to project/jni/curl/lib/dotdot.h index 26cfb7f03..fac8e6f2a 100644 --- a/project/jni/curl/lib/curl_rand.h +++ b/project/jni/curl/lib/dotdot.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_RAND_H -#define HEADER_CURL_RAND_H +#ifndef HEADER_CURL_DOTDOT_H +#define HEADER_CURL_DOTDOT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,9 +21,5 @@ * KIND, either express or implied. * ***************************************************************************/ - -void Curl_srand(void); - -unsigned int Curl_rand(void); - -#endif /* HEADER_CURL_RAND_H */ +char *Curl_dedotdotify(const char *input); +#endif diff --git a/project/jni/curl/lib/easy.c b/project/jni/curl/lib/easy.c index 6f553475b..2bddbb22f 100644 --- a/project/jni/curl/lib/easy.c +++ b/project/jni/curl/lib/easy.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,34 +20,19 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include -#include +/* + * See comment in curl_memory.h for the explanation of this sanity check. + */ -#include "strequal.h" - -#ifdef WIN32 -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include +#ifdef CURLX_NO_MEMORY_CALLBACKS +#error "libcurl shall not ever be built with CURLX_NO_MEMORY_CALLBACKS defined" #endif + #ifdef HAVE_NETINET_IN_H #include #endif -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif #ifdef HAVE_NETDB_H #include #endif @@ -65,45 +50,37 @@ #include #endif -#endif /* WIN32 ... */ - +#include "strequal.h" #include "urldata.h" #include #include "transfer.h" -#include "sslgen.h" +#include "vtls/vtls.h" #include "url.h" #include "getinfo.h" #include "hostip.h" #include "share.h" #include "strdup.h" -#include "curl_memory.h" #include "progress.h" #include "easyif.h" #include "select.h" #include "sendf.h" /* for failf function prototype */ -#include "http_ntlm.h" #include "connect.h" /* for Curl_getconnectinfo */ #include "slist.h" -#include "curl_rand.h" +#include "amigaos.h" +#include "non-ascii.h" +#include "warnless.h" +#include "conncache.h" +#include "multiif.h" +#include "sigpipe.h" +#include "ssh.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) -#include -/* set default codesets for iconv */ -#ifndef CURL_ICONV_CODESET_OF_NETWORK -#define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1" -#endif -#ifndef CURL_ICONV_CODESET_FOR_UTF8 -#define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8" -#endif -#define ICONV_ERROR (size_t)-1 -#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" +void Curl_version_init(void); + /* win32_cleanup() is for win32 socket cleanup functionality, the opposite of win32_init() */ static void win32_cleanup(void) @@ -144,8 +121,8 @@ static CURLcode win32_init(void) /* wVersionRequested in wVersion. wHighVersion contains the */ /* highest supported version. */ - if( LOBYTE( wsaData.wVersion ) != LOBYTE(wVersionRequested) || - HIBYTE( wsaData.wVersion ) != HIBYTE(wVersionRequested) ) { + if(LOBYTE( wsaData.wVersion ) != LOBYTE(wVersionRequested) || + HIBYTE( wsaData.wVersion ) != HIBYTE(wVersionRequested) ) { /* Tell the user that we couldn't find a useable */ /* winsock.dll. */ @@ -153,13 +130,15 @@ static CURLcode win32_init(void) return CURLE_FAILED_INIT; } /* The Windows Sockets DLL is acceptable. Proceed. */ +#elif defined(USE_LWIPSOCK) + lwip_init(); #endif #ifdef USE_WINDOWS_SSPI { - CURLcode err = Curl_sspi_global_init(); - if (err != CURLE_OK) - return err; + CURLcode result = Curl_sspi_global_init(); + if(result) + return result; } #endif @@ -219,6 +198,9 @@ curl_free_callback Curl_cfree = (curl_free_callback)free; curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc; curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup; curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc; +#if defined(WIN32) && defined(UNICODE) +curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup; +#endif #else /* * Symbian OS doesn't support initialization to code in writeable static data. @@ -239,17 +221,22 @@ curl_calloc_callback Curl_ccalloc; * curl_global_init() globally initializes cURL given a bitwise set of the * different features of what to initialize. */ -CURLcode curl_global_init(long flags) +static CURLcode global_init(long flags, bool memoryfuncs) { if(initialized++) return CURLE_OK; - /* Setup the default memory functions here (again) */ - Curl_cmalloc = (curl_malloc_callback)malloc; - Curl_cfree = (curl_free_callback)free; - Curl_crealloc = (curl_realloc_callback)realloc; - Curl_cstrdup = (curl_strdup_callback)system_strdup; - Curl_ccalloc = (curl_calloc_callback)calloc; + if(memoryfuncs) { + /* Setup the default memory functions here (again) */ + Curl_cmalloc = (curl_malloc_callback)malloc; + Curl_cfree = (curl_free_callback)free; + Curl_crealloc = (curl_realloc_callback)realloc; + Curl_cstrdup = (curl_strdup_callback)system_strdup; + Curl_ccalloc = (curl_calloc_callback)calloc; +#if defined(WIN32) && defined(UNICODE) + Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup; +#endif + } if(flags & CURL_GLOBAL_SSL) if(!Curl_ssl_init()) { @@ -258,14 +245,14 @@ CURLcode curl_global_init(long flags) } if(flags & CURL_GLOBAL_WIN32) - if(win32_init() != CURLE_OK) { + if(win32_init()) { DEBUGF(fprintf(stderr, "Error: win32_init failed\n")); return CURLE_FAILED_INIT; } #ifdef __AMIGA__ - if(!amiga_init()) { - DEBUGF(fprintf(stderr, "Error: amiga_init failed\n")); + if(!Curl_amiga_init()) { + DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n")); return CURLE_FAILED_INIT; } #endif @@ -280,12 +267,10 @@ CURLcode curl_global_init(long flags) idna_init(); #endif -#ifdef CARES_HAVE_ARES_LIBRARY_INIT - if(ares_library_init(ARES_LIB_INIT_ALL)) { - DEBUGF(fprintf(stderr, "Error: ares_library_init failed\n")); + if(Curl_resolver_global_init()) { + DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n")); return CURLE_FAILED_INIT; } -#endif #if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_INIT) if(libssh2_init(0)) { @@ -294,15 +279,26 @@ CURLcode curl_global_init(long flags) } #endif - init_flags = flags; + if(flags & CURL_GLOBAL_ACK_EINTR) + Curl_ack_eintr = 1; - /* Preset pseudo-random number sequence. */ + init_flags = flags; - Curl_srand(); + Curl_version_init(); return CURLE_OK; } + +/** + * curl_global_init() globally initializes cURL given a bitwise set of the + * different features of what to initialize. + */ +CURLcode curl_global_init(long flags) +{ + return global_init(flags, TRUE); +} + /* * curl_global_init_mem() globally initializes cURL and also registers the * user provided callback routines. @@ -311,27 +307,28 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, curl_free_callback f, curl_realloc_callback r, curl_strdup_callback s, curl_calloc_callback c) { - CURLcode code = CURLE_OK; - /* Invalid input, return immediately */ if(!m || !f || !r || !s || !c) return CURLE_FAILED_INIT; - /* Already initialized, don't do it again */ - if( initialized ) + if(initialized) { + /* Already initialized, don't do it again, but bump the variable anyway to + work like curl_global_init() and require the same amount of cleanup + calls. */ + initialized++; return CURLE_OK; - - /* Call the actual init function first */ - code = curl_global_init(flags); - if(code == CURLE_OK) { - Curl_cmalloc = m; - Curl_cfree = f; - Curl_cstrdup = s; - Curl_crealloc = r; - Curl_ccalloc = c; } - return code; + /* set memory functions before global_init() in case it wants memory + functions */ + Curl_cmalloc = m; + Curl_cfree = f; + Curl_cstrdup = s; + Curl_crealloc = r; + Curl_ccalloc = c; + + /* Call the actual init function, but without setting */ + return global_init(flags, FALSE); } /** @@ -351,16 +348,12 @@ void curl_global_cleanup(void) if(init_flags & CURL_GLOBAL_SSL) Curl_ssl_cleanup(); -#ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP - ares_library_cleanup(); -#endif + Curl_resolver_global_cleanup(); if(init_flags & CURL_GLOBAL_WIN32) win32_cleanup(); -#ifdef __AMIGA__ - amiga_cleanup(); -#endif + Curl_amiga_cleanup(); #if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_EXIT) (void)libssh2_exit(); @@ -375,13 +368,13 @@ void curl_global_cleanup(void) */ CURL *curl_easy_init(void) { - CURLcode res; + CURLcode result; struct SessionHandle *data; /* Make sure we inited the global SSL stuff */ if(!initialized) { - res = curl_global_init(CURL_GLOBAL_DEFAULT); - if(res) { + result = curl_global_init(CURL_GLOBAL_DEFAULT); + if(result) { /* something in the global init failed, return nothing */ DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n")); return NULL; @@ -389,8 +382,8 @@ CURL *curl_easy_init(void) } /* We use curl_open() with undefined URL so far */ - res = Curl_open(&data); - if(res != CURLE_OK) { + result = Curl_open(&data); + if(result) { DEBUGF(fprintf(stderr, "Error: Curl_open failed\n")); return NULL; } @@ -408,55 +401,401 @@ CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...) { va_list arg; struct SessionHandle *data = curl; - CURLcode ret; + CURLcode result; if(!curl) return CURLE_BAD_FUNCTION_ARGUMENT; va_start(arg, tag); - ret = Curl_setopt(data, tag, arg); + result = Curl_setopt(data, tag, arg); va_end(arg); - return ret; + return result; } -#ifdef CURL_MULTIEASY -/*************************************************************************** - * This function is still only for testing purposes. It makes a great way - * to run the full test suite on the multi interface instead of the easy one. - *************************************************************************** +#ifdef CURLDEBUG + +struct socketmonitor { + struct socketmonitor *next; /* the next node in the list or NULL */ + struct pollfd socket; /* socket info of what to monitor */ +}; + +struct events { + long ms; /* timeout, run the timeout function when reached */ + bool msbump; /* set TRUE when timeout is set by callback */ + int num_sockets; /* number of nodes in the monitor list */ + struct socketmonitor *list; /* list of sockets to monitor */ + int running_handles; /* store the returned number */ +}; + +/* events_timer * - * The *new* curl_easy_perform() is the external interface that performs a - * transfer previously setup. + * Callback that gets called with a new value when the timeout should be + * updated. + */ + +static int events_timer(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp) /* private callback pointer */ +{ + struct events *ev = userp; + (void)multi; + if(timeout_ms == -1) + /* timeout removed */ + timeout_ms = 0; + else if(timeout_ms == 0) + /* timeout is already reached! */ + timeout_ms = 1; /* trigger asap */ + + ev->ms = timeout_ms; + ev->msbump = TRUE; + return 0; +} + + +/* poll2cselect * - * Wrapper-function that: creates a multi handle, adds the easy handle to it, + * convert from poll() bit definitions to libcurl's CURL_CSELECT_* ones + */ +static int poll2cselect(int pollmask) +{ + int omask=0; + if(pollmask & POLLIN) + omask |= CURL_CSELECT_IN; + if(pollmask & POLLOUT) + omask |= CURL_CSELECT_OUT; + if(pollmask & POLLERR) + omask |= CURL_CSELECT_ERR; + return omask; +} + + +/* socketcb2poll + * + * convert from libcurl' CURL_POLL_* bit definitions to poll()'s + */ +static short socketcb2poll(int pollmask) +{ + short omask=0; + if(pollmask & CURL_POLL_IN) + omask |= POLLIN; + if(pollmask & CURL_POLL_OUT) + omask |= POLLOUT; + return omask; +} + +/* events_socket + * + * Callback that gets called with information about socket activity to + * monitor. + */ +static int events_socket(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp) /* private socket + pointer */ +{ + struct events *ev = userp; + struct socketmonitor *m; + struct socketmonitor *prev=NULL; + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) easy; +#endif + (void)socketp; + + m = ev->list; + while(m) { + if(m->socket.fd == s) { + + if(what == CURL_POLL_REMOVE) { + struct socketmonitor *nxt = m->next; + /* remove this node from the list of monitored sockets */ + if(prev) + prev->next = nxt; + else + ev->list = nxt; + free(m); + m = nxt; + infof(easy, "socket cb: socket %d REMOVED\n", s); + } + else { + /* The socket 's' is already being monitored, update the activity + mask. Convert from libcurl bitmask to the poll one. */ + m->socket.events = socketcb2poll(what); + infof(easy, "socket cb: socket %d UPDATED as %s%s\n", s, + what&CURL_POLL_IN?"IN":"", + what&CURL_POLL_OUT?"OUT":""); + } + break; + } + prev = m; + m = m->next; /* move to next node */ + } + if(!m) { + if(what == CURL_POLL_REMOVE) { + /* this happens a bit too often, libcurl fix perhaps? */ + /* fprintf(stderr, + "%s: socket %d asked to be REMOVED but not present!\n", + __func__, s); */ + } + else { + m = malloc(sizeof(struct socketmonitor)); + if(m) { + m->next = ev->list; + m->socket.fd = s; + m->socket.events = socketcb2poll(what); + m->socket.revents = 0; + ev->list = m; + infof(easy, "socket cb: socket %d ADDED as %s%s\n", s, + what&CURL_POLL_IN?"IN":"", + what&CURL_POLL_OUT?"OUT":""); + } + else + return CURLE_OUT_OF_MEMORY; + } + } + + return 0; +} + + +/* + * events_setup() + * + * Do the multi handle setups that only event-based transfers need. + */ +static void events_setup(CURLM *multi, struct events *ev) +{ + /* timer callback */ + curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer); + curl_multi_setopt(multi, CURLMOPT_TIMERDATA, ev); + + /* socket callback */ + curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, events_socket); + curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, ev); +} + + +/* wait_or_timeout() + * + * waits for activity on any of the given sockets, or the timeout to trigger. + */ + +static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) +{ + bool done = FALSE; + CURLMcode mcode; + CURLcode result = CURLE_OK; + + while(!done) { + CURLMsg *msg; + struct socketmonitor *m; + struct pollfd *f; + struct pollfd fds[4]; + int numfds=0; + int pollrc; + int i; + struct timeval before; + struct timeval after; + + /* populate the fds[] array */ + for(m = ev->list, f=&fds[0]; m; m = m->next) { + f->fd = m->socket.fd; + f->events = m->socket.events; + f->revents = 0; + /* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */ + f++; + numfds++; + } + + /* get the time stamp to use to figure out how long poll takes */ + before = curlx_tvnow(); + + /* wait for activity or timeout */ + pollrc = Curl_poll(fds, numfds, (int)ev->ms); + + after = curlx_tvnow(); + + ev->msbump = FALSE; /* reset here */ + + if(0 == pollrc) { + /* timeout! */ + ev->ms = 0; + /* fprintf(stderr, "call curl_multi_socket_action( TIMEOUT )\n"); */ + mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, + &ev->running_handles); + } + else if(pollrc > 0) { + /* loop over the monitored sockets to see which ones had activity */ + for(i = 0; i< numfds; i++) { + if(fds[i].revents) { + /* socket activity, tell libcurl */ + int act = poll2cselect(fds[i].revents); /* convert */ + infof(multi->easyp, "call curl_multi_socket_action( socket %d )\n", + fds[i].fd); + mcode = curl_multi_socket_action(multi, fds[i].fd, act, + &ev->running_handles); + } + } + + if(!ev->msbump) + /* If nothing updated the timeout, we decrease it by the spent time. + * If it was updated, it has the new timeout time stored already. + */ + ev->ms += curlx_tvdiff(after, before); + + } + else + return CURLE_RECV_ERROR; + + if(mcode) + return CURLE_URL_MALFORMAT; /* TODO: return a proper error! */ + + /* we don't really care about the "msgs_in_queue" value returned in the + second argument */ + msg = curl_multi_info_read(multi, &pollrc); + if(msg) { + result = msg->data.result; + done = TRUE; + } + } + + return result; +} + + +/* easy_events() + * + * Runs a transfer in a blocking manner using the events-based API + */ +static CURLcode easy_events(CURLM *multi) +{ + struct events evs= {2, FALSE, 0, NULL, 0}; + + /* if running event-based, do some further multi inits */ + events_setup(multi, &evs); + + return wait_or_timeout(multi, &evs); +} +#else /* CURLDEBUG */ +/* when not built with debug, this function doesn't exist */ +#define easy_events(x) CURLE_NOT_BUILT_IN +#endif + +static CURLcode easy_transfer(CURLM *multi) +{ + bool done = FALSE; + CURLMcode mcode = CURLM_OK; + CURLcode result = CURLE_OK; + struct timeval before; + int without_fds = 0; /* count number of consecutive returns from + curl_multi_wait() without any filedescriptors */ + + while(!done && !mcode) { + int still_running = 0; + int rc; + + before = curlx_tvnow(); + mcode = curl_multi_wait(multi, NULL, 0, 1000, &rc); + + if(!mcode) { + if(!rc) { + struct timeval after = curlx_tvnow(); + + /* If it returns without any filedescriptor instantly, we need to + avoid busy-looping during periods where it has nothing particular + to wait for */ + if(curlx_tvdiff(after, before) <= 10) { + without_fds++; + if(without_fds > 2) { + int sleep_ms = without_fds < 10 ? (1 << (without_fds - 1)) : 1000; + Curl_wait_ms(sleep_ms); + } + } + else + /* it wasn't "instant", restart counter */ + without_fds = 0; + } + else + /* got file descriptor, restart counter */ + without_fds = 0; + + mcode = curl_multi_perform(multi, &still_running); + } + + /* only read 'still_running' if curl_multi_perform() return OK */ + if(!mcode && !still_running) { + CURLMsg *msg = curl_multi_info_read(multi, &rc); + if(msg) { + result = msg->data.result; + done = TRUE; + } + } + } + + /* Make sure to return some kind of error if there was a multi problem */ + if(mcode) { + result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY : + /* The other multi errors should never happen, so return + something suitably generic */ + CURLE_BAD_FUNCTION_ARGUMENT; + } + + return result; +} + + +/* + * easy_perform() is the external interface that performs a blocking + * transfer as previously setup. + * + * CONCEPT: This function creates a multi handle, adds the easy handle to it, * runs curl_multi_perform() until the transfer is done, then detaches the * easy handle, destroys the multi handle and returns the easy handle's return - * code. This will make everything internally use and assume multi interface. + * code. + * + * REALITY: it can't just create and destroy the multi handle that easily. It + * needs to keep it around since if this easy handle is used again by this + * function, the same multi handle must be re-used so that the same pools and + * caches can be used. + * + * DEBUG: if 'events' is set TRUE, this function will use a replacement engine + * instead of curl_multi_perform() and use curl_multi_socket_action(). */ -CURLcode curl_easy_perform(CURL *easy) +static CURLcode easy_perform(struct SessionHandle *data, bool events) { CURLM *multi; CURLMcode mcode; - CURLcode code = CURLE_OK; - int still_running; - struct timeval timeout; - int rc; - CURLMsg *msg; - fd_set fdread; - fd_set fdwrite; - fd_set fdexcep; - int maxfd; + CURLcode result = CURLE_OK; + SIGPIPE_VARIABLE(pipe_st); - if(!easy) + if(!data) return CURLE_BAD_FUNCTION_ARGUMENT; - multi = curl_multi_init(); - if(!multi) - return CURLE_OUT_OF_MEMORY; + if(data->multi) { + failf(data, "easy handle already used in multi handle"); + return CURLE_FAILED_INIT; + } - mcode = curl_multi_add_handle(multi, easy); + if(data->multi_easy) + multi = data->multi_easy; + else { + /* this multi handle will only ever have a single easy handled attached + to it, so make it use minimal hashes */ + multi = Curl_multi_handle(1, 3); + if(!multi) + return CURLE_OUT_OF_MEMORY; + data->multi_easy = multi; + } + + /* Copy the MAXCONNECTS option to the multi handle */ + curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, data->set.maxconnects); + + mcode = curl_multi_add_handle(multi, data); if(mcode) { curl_multi_cleanup(multi); if(mcode == CURLM_OUT_OF_MEMORY) @@ -465,107 +804,45 @@ CURLcode curl_easy_perform(CURL *easy) return CURLE_FAILED_INIT; } - /* we start some action by calling perform right away */ + sigpipe_ignore(data, &pipe_st); - do { - while(CURLM_CALL_MULTI_PERFORM == - curl_multi_perform(multi, &still_running)); + /* assign this after curl_multi_add_handle() since that function checks for + it and rejects this handle otherwise */ + data->multi = multi; - if(!still_running) - break; + /* run the transfer */ + result = events ? easy_events(multi) : easy_transfer(multi); - FD_ZERO(&fdread); - FD_ZERO(&fdwrite); - FD_ZERO(&fdexcep); + /* ignoring the return code isn't nice, but atm we can't really handle + a failure here, room for future improvement! */ + (void)curl_multi_remove_handle(multi, data); - /* timeout once per second */ - timeout.tv_sec = 1; - timeout.tv_usec = 0; + sigpipe_restore(&pipe_st); - /* Old deprecated style: get file descriptors from the transfers */ - curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd); - rc = Curl_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); - - /* The way is to extract the sockets and wait for them without using - select. This whole alternative version should probably rather use the - curl_multi_socket() approach. */ - - if(rc == -1) - /* select error */ - break; - - /* timeout or data to send/receive => loop! */ - } while(still_running); - - msg = curl_multi_info_read(multi, &rc); - if(msg) - code = msg->data.result; - - mcode = curl_multi_remove_handle(multi, easy); - /* what to do if it fails? */ - - mcode = curl_multi_cleanup(multi); - /* what to do if it fails? */ - - return code; + /* The multi handle is kept alive, owned by the easy handle */ + return result; } -#else + + /* - * curl_easy_perform() is the external interface that performs a transfer - * previously setup. + * curl_easy_perform() is the external interface that performs a blocking + * transfer as previously setup. */ -CURLcode curl_easy_perform(CURL *curl) +CURLcode curl_easy_perform(CURL *easy) { - struct SessionHandle *data = (struct SessionHandle *)curl; - - if(!data) - return CURLE_BAD_FUNCTION_ARGUMENT; - - if( ! (data->share && data->share->hostcache) ) { - /* this handle is not using a shared dns cache */ - - if(data->set.global_dns_cache && - (data->dns.hostcachetype != HCACHE_GLOBAL)) { - /* global dns cache was requested but still isn't */ - struct curl_hash *ptr; - - if(data->dns.hostcachetype == HCACHE_PRIVATE) { - /* if the current cache is private, kill it first */ - Curl_hash_destroy(data->dns.hostcache); - data->dns.hostcachetype = HCACHE_NONE; - data->dns.hostcache = NULL; - } - - ptr = Curl_global_host_cache_init(); - if(ptr) { - /* only do this if the global cache init works */ - data->dns.hostcache = ptr; - data->dns.hostcachetype = HCACHE_GLOBAL; - } - } - - if(!data->dns.hostcache) { - data->dns.hostcachetype = HCACHE_PRIVATE; - data->dns.hostcache = Curl_mk_dnscache(); - - if(!data->dns.hostcache) - /* While we possibly could survive and do good without a host cache, - the fact that creating it failed indicates that things are truly - screwed up and we should bail out! */ - return CURLE_OUT_OF_MEMORY; - } - - } - - if(!data->state.connc) { - /* oops, no connection cache, make one up */ - data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1L); - if(!data->state.connc) - return CURLE_OUT_OF_MEMORY; - } - - return Curl_perform(data); + return easy_perform(easy, FALSE); } + +#ifdef CURLDEBUG +/* + * curl_easy_perform_ev() is the external interface that performs a blocking + * transfer using the event-based API internally. + */ +CURLcode curl_easy_perform_ev(CURL *easy) +{ + return easy_perform(easy, TRUE); +} + #endif /* @@ -575,31 +852,14 @@ CURLcode curl_easy_perform(CURL *curl) void curl_easy_cleanup(CURL *curl) { struct SessionHandle *data = (struct SessionHandle *)curl; + SIGPIPE_VARIABLE(pipe_st); if(!data) return; + sigpipe_ignore(data, &pipe_st); Curl_close(data); -} - -/* - * Store a pointed to the multi handle within the easy handle's data struct. - */ -void Curl_easy_addmulti(struct SessionHandle *data, - void *multi) -{ - data->multi = multi; - if(multi == NULL) - /* the association is cleared, mark the easy handle as not used by an - interface */ - data->state.used_interface = Curl_if_none; -} - -void Curl_easy_initHandleData(struct SessionHandle *data) -{ - memset(&data->req, 0, sizeof(struct SingleRequest)); - - data->req.maxdownload = -1; + sigpipe_restore(&pipe_st); } /* @@ -611,12 +871,16 @@ CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...) { va_list arg; void *paramp; + CURLcode result; struct SessionHandle *data = (struct SessionHandle *)curl; va_start(arg, info); paramp = va_arg(arg, void *); - return Curl_getinfo(data, info, paramp); + result = Curl_getinfo(data, info, paramp); + + va_end(arg); + return result; } /* @@ -643,18 +907,17 @@ CURL *curl_easy_duphandle(CURL *incurl) outcurl->state.headersize = HEADERSIZE; /* copy all userdefined values */ - if(Curl_dupset(outcurl, data) != CURLE_OK) + if(Curl_dupset(outcurl, data)) goto fail; /* the connection cache is setup on demand */ - outcurl->state.connc = NULL; + outcurl->state.conn_cache = NULL; - outcurl->state.lastconnect = -1; + outcurl->state.lastconnect = NULL; outcurl->progress.flags = data->progress.flags; outcurl->progress.callback = data->progress.callback; -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) if(data->cookies) { /* If cookies are enabled in the parent handle, we enable them in the clone as well! */ @@ -665,18 +928,14 @@ CURL *curl_easy_duphandle(CURL *incurl) if(!outcurl->cookies) goto fail; } -#endif /* CURL_DISABLE_HTTP */ /* duplicate all values in 'change' */ - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) if(data->change.cookielist) { outcurl->change.cookielist = Curl_slist_duplicate(data->change.cookielist); if(!outcurl->change.cookielist) goto fail; } -#endif /* CURL_DISABLE_HTTP */ if(data->change.url) { outcurl->change.url = strdup(data->change.url); @@ -692,23 +951,12 @@ CURL *curl_easy_duphandle(CURL *incurl) outcurl->change.referer_alloc = TRUE; } -#ifdef USE_ARES - /* If we use ares, we clone the ares channel for the new handle */ - if(ARES_SUCCESS != ares_dup(&outcurl->state.areschannel, - data->state.areschannel)) + /* Clone the resolver handle, if present, for the new handle */ + if(Curl_resolver_duphandle(&outcurl->state.resolver, + data->state.resolver)) goto fail; -#endif -#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) - outcurl->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_OF_NETWORK); - outcurl->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, - CURL_ICONV_CODESET_OF_HOST); - outcurl->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_FOR_UTF8); -#endif - - Curl_easy_initHandleData(outcurl); + Curl_convert_setup(outcurl); outcurl->magic = CURLEASY_MAGIC_NUMBER; @@ -719,19 +967,11 @@ CURL *curl_easy_duphandle(CURL *incurl) fail: if(outcurl) { - if(outcurl->state.connc && - (outcurl->state.connc->type == CONNCACHE_PRIVATE)) - Curl_rm_connc(outcurl->state.connc); - if(outcurl->state.headerbuff) - free(outcurl->state.headerbuff); -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - if(outcurl->change.cookielist) - curl_slist_free_all(outcurl->change.cookielist); -#endif - if(outcurl->change.url) - free(outcurl->change.url); - if(outcurl->change.referer) - free(outcurl->change.referer); + curl_slist_free_all(outcurl->change.cookielist); + outcurl->change.cookielist = NULL; + Curl_safefree(outcurl->state.headerbuff); + Curl_safefree(outcurl->change.url); + Curl_safefree(outcurl->change.referer); Curl_freeset(outcurl); free(outcurl); } @@ -748,10 +988,10 @@ void curl_easy_reset(CURL *curl) struct SessionHandle *data = (struct SessionHandle *)curl; Curl_safefree(data->state.pathbuffer); - data->state.pathbuffer=NULL; - Curl_safefree(data->state.proto.generic); - data->state.proto.generic=NULL; + data->state.path = NULL; + + Curl_free_request_state(data); /* zero out UserDefined data: */ Curl_freeset(data); @@ -761,9 +1001,6 @@ void curl_easy_reset(CURL *curl) /* zero out Progress data: */ memset(&data->progress, 0, sizeof(struct Progress)); - /* init Handle data */ - Curl_easy_initHandleData(data); - data->progress.flags |= PGRS_HIDE; data->state.current_speed = -1; /* init to negative == impossible */ } @@ -795,271 +1032,30 @@ CURLcode curl_easy_pause(CURL *curl, int action) k->keepon = newstate; if(!(newstate & KEEP_RECV_PAUSE) && data->state.tempwrite) { - /* we have a buffer for sending that we now seem to be able to deliver since - the receive pausing is lifted! */ + /* we have a buffer for sending that we now seem to be able to deliver + since the receive pausing is lifted! */ - /* get the pointer, type and length in local copies since the function may - return PAUSE again and then we'll get a new copy allocted and stored in + /* get the pointer in local copy since the function may return PAUSE + again and then we'll get a new copy allocted and stored in the tempwrite variables */ char *tempwrite = data->state.tempwrite; - char *freewrite = tempwrite; /* store this pointer to free it later */ - size_t tempsize = data->state.tempwritesize; - int temptype = data->state.tempwritetype; - size_t chunklen; - /* clear tempwrite here just to make sure it gets cleared if there's no - further use of it, and make sure we don't clear it after the function - invoke as it may have been set to a new value by then */ data->state.tempwrite = NULL; - - /* since the write callback API is define to never exceed - CURL_MAX_WRITE_SIZE bytes in a single call, and since we may in fact - have more data than that in our buffer here, we must loop sending the - data in multiple calls until there's no data left or we get another - pause returned. - - A tricky part is that the function we call will "buffer" the data - itself when it pauses on a particular buffer, so we may need to do some - extra trickery if we get a pause return here. - */ - do { - chunklen = (tempsize > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:tempsize; - - result = Curl_client_write(data->state.current_conn, - temptype, tempwrite, chunklen); - if(result) - /* failures abort the loop at once */ - break; - - if(data->state.tempwrite && (tempsize - chunklen)) { - /* Ouch, the reading is again paused and the block we send is now - "cached". If this is the final chunk we can leave it like this, but - if we have more chunks that are cached after this, we need to free - the newly cached one and put back a version that is truly the entire - contents that is saved for later - */ - char *newptr; - - /* note that tempsize is still the size as before the callback was - used, and thus the whole piece of data to keep */ - newptr = realloc(data->state.tempwrite, tempsize); - - if(!newptr) { - free(data->state.tempwrite); /* free old area */ - data->state.tempwrite = NULL; - result = CURLE_OUT_OF_MEMORY; - /* tempwrite will be freed further down */ - break; - } - data->state.tempwrite = newptr; /* store new pointer */ - memcpy(newptr, tempwrite, tempsize); - data->state.tempwritesize = tempsize; /* store new size */ - /* tempwrite will be freed further down */ - break; /* go back to pausing until further notice */ - } - else { - tempsize -= chunklen; /* left after the call above */ - tempwrite += chunklen; /* advance the pointer */ - } - - } while((result == CURLE_OK) && tempsize); - - free(freewrite); /* this is unconditionally no longer used */ + result = Curl_client_chop_write(data->easy_conn, data->state.tempwritetype, + tempwrite, data->state.tempwritesize); + free(tempwrite); } + /* if there's no error and we're not pausing both directions, we want + to have this handle checked soon */ + if(!result && + ((newstate&(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != + (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) ) + Curl_expire(data, 1); /* get this handle going again */ + return result; } -#ifdef CURL_DOES_CONVERSIONS -/* - * Curl_convert_to_network() is an internal function - * for performing ASCII conversions on non-ASCII platforms. - */ -CURLcode Curl_convert_to_network(struct SessionHandle *data, - char *buffer, size_t length) -{ - CURLcode rc; - - if(data->set.convtonetwork) { - /* use translation callback */ - rc = data->set.convtonetwork(buffer, length); - if(rc != CURLE_OK) { - failf(data, - "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s", - (int)rc, curl_easy_strerror(rc)); - } - return(rc); - } - else { -#ifdef HAVE_ICONV - /* do the translation ourselves */ - char *input_ptr, *output_ptr; - size_t in_bytes, out_bytes, rc; - int error; - - /* open an iconv conversion descriptor if necessary */ - if(data->outbound_cd == (iconv_t)-1) { - data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, - CURL_ICONV_CODESET_OF_HOST); - if(data->outbound_cd == (iconv_t)-1) { - error = ERRNO; - failf(data, - "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", - CURL_ICONV_CODESET_OF_NETWORK, - CURL_ICONV_CODESET_OF_HOST, - error, strerror(error)); - return CURLE_CONV_FAILED; - } - } - /* call iconv */ - input_ptr = output_ptr = buffer; - in_bytes = out_bytes = length; - rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes, - &output_ptr, &out_bytes); - if((rc == ICONV_ERROR) || (in_bytes != 0)) { - error = ERRNO; - failf(data, - "The Curl_convert_to_network iconv call failed with errno %i: %s", - error, strerror(error)); - return CURLE_CONV_FAILED; - } -#else - failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required"); - return CURLE_CONV_REQD; -#endif /* HAVE_ICONV */ - } - - return CURLE_OK; -} - -/* - * Curl_convert_from_network() is an internal function - * for performing ASCII conversions on non-ASCII platforms. - */ -CURLcode Curl_convert_from_network(struct SessionHandle *data, - char *buffer, size_t length) -{ - CURLcode rc; - - if(data->set.convfromnetwork) { - /* use translation callback */ - rc = data->set.convfromnetwork(buffer, length); - if(rc != CURLE_OK) { - failf(data, - "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s", - (int)rc, curl_easy_strerror(rc)); - } - return(rc); - } - else { -#ifdef HAVE_ICONV - /* do the translation ourselves */ - char *input_ptr, *output_ptr; - size_t in_bytes, out_bytes, rc; - int error; - - /* open an iconv conversion descriptor if necessary */ - if(data->inbound_cd == (iconv_t)-1) { - data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_OF_NETWORK); - if(data->inbound_cd == (iconv_t)-1) { - error = ERRNO; - failf(data, - "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", - CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_OF_NETWORK, - error, strerror(error)); - return CURLE_CONV_FAILED; - } - } - /* call iconv */ - input_ptr = output_ptr = buffer; - in_bytes = out_bytes = length; - rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes, - &output_ptr, &out_bytes); - if((rc == ICONV_ERROR) || (in_bytes != 0)) { - error = ERRNO; - failf(data, - "The Curl_convert_from_network iconv call failed with errno %i: %s", - error, strerror(error)); - return CURLE_CONV_FAILED; - } -#else - failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required"); - return CURLE_CONV_REQD; -#endif /* HAVE_ICONV */ - } - - return CURLE_OK; -} - -/* - * Curl_convert_from_utf8() is an internal function - * for performing UTF-8 conversions on non-ASCII platforms. - */ -CURLcode Curl_convert_from_utf8(struct SessionHandle *data, - char *buffer, size_t length) -{ - CURLcode rc; - - if(data->set.convfromutf8) { - /* use translation callback */ - rc = data->set.convfromutf8(buffer, length); - if(rc != CURLE_OK) { - failf(data, - "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s", - (int)rc, curl_easy_strerror(rc)); - } - return(rc); - } - else { -#ifdef HAVE_ICONV - /* do the translation ourselves */ - const char *input_ptr; - char *output_ptr; - size_t in_bytes, out_bytes, rc; - int error; - - /* open an iconv conversion descriptor if necessary */ - if(data->utf8_cd == (iconv_t)-1) { - data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_FOR_UTF8); - if(data->utf8_cd == (iconv_t)-1) { - error = ERRNO; - failf(data, - "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", - CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_FOR_UTF8, - error, strerror(error)); - return CURLE_CONV_FAILED; - } - } - /* call iconv */ - input_ptr = output_ptr = buffer; - in_bytes = out_bytes = length; - rc = iconv(data->utf8_cd, &input_ptr, &in_bytes, - &output_ptr, &out_bytes); - if((rc == ICONV_ERROR) || (in_bytes != 0)) { - error = ERRNO; - failf(data, - "The Curl_convert_from_utf8 iconv call failed with errno %i: %s", - error, strerror(error)); - return CURLE_CONV_FAILED; - } - if(output_ptr < input_ptr) { - /* null terminate the now shorter output string */ - *output_ptr = 0x00; - } -#else - failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required"); - return CURLE_CONV_REQD; -#endif /* HAVE_ICONV */ - } - - return CURLE_OK; -} - -#endif /* CURL_DOES_CONVERSIONS */ static CURLcode easy_connection(struct SessionHandle *data, curl_socket_t *sfd, @@ -1092,20 +1088,20 @@ static CURLcode easy_connection(struct SessionHandle *data, CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n) { curl_socket_t sfd; - CURLcode ret; + CURLcode result; ssize_t n1; struct connectdata *c; struct SessionHandle *data = (struct SessionHandle *)curl; - ret = easy_connection(data, &sfd, &c); - if(ret) - return ret; + result = easy_connection(data, &sfd, &c); + if(result) + return result; *n = 0; - ret = Curl_read(c, sfd, buffer, buflen, &n1); + result = Curl_read(c, sfd, buffer, buflen, &n1); - if(ret != CURLE_OK) - return ret; + if(result) + return result; *n = (size_t)n1; @@ -1120,26 +1116,26 @@ CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen, size_t *n) { curl_socket_t sfd; - CURLcode ret; + CURLcode result; ssize_t n1; struct connectdata *c = NULL; struct SessionHandle *data = (struct SessionHandle *)curl; - ret = easy_connection(data, &sfd, &c); - if(ret) - return ret; + result = easy_connection(data, &sfd, &c); + if(result) + return result; *n = 0; - ret = Curl_write(c, sfd, buffer, buflen, &n1); + result = Curl_write(c, sfd, buffer, buflen, &n1); if(n1 == -1) return CURLE_SEND_ERROR; /* detect EAGAIN */ - if((CURLE_OK == ret) && (0 == n1)) + if(!result && !n1) return CURLE_AGAIN; *n = (size_t)n1; - return ret; + return result; } diff --git a/project/jni/curl/lib/easyif.h b/project/jni/curl/lib/easyif.h index 8a0a51cc1..65333494c 100644 --- a/project/jni/curl/lib/easyif.h +++ b/project/jni/curl/lib/easyif.h @@ -1,5 +1,5 @@ -#ifndef __EASYIF_H -#define __EASYIF_H +#ifndef HEADER_CURL_EASYIF_H +#define HEADER_CURL_EASYIF_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -25,15 +25,9 @@ /* * Prototypes for library-wide functions provided by easy.c */ -void Curl_easy_addmulti(struct SessionHandle *data, void *multi); +#ifdef CURLDEBUG +CURL_EXTERN CURLcode curl_easy_perform_ev(CURL *easy); +#endif -void Curl_easy_initHandleData(struct SessionHandle *data); +#endif /* HEADER_CURL_EASYIF_H */ -CURLcode Curl_convert_to_network(struct SessionHandle *data, - char *buffer, size_t length); -CURLcode Curl_convert_from_network(struct SessionHandle *data, - char *buffer, size_t length); -CURLcode Curl_convert_from_utf8(struct SessionHandle *data, - char *buffer, size_t length); - -#endif /* __EASYIF_H */ diff --git a/project/jni/curl/lib/escape.c b/project/jni/curl/lib/escape.c index 735e1d8a7..40338a904 100644 --- a/project/jni/curl/lib/escape.c +++ b/project/jni/curl/lib/escape.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -23,28 +23,23 @@ /* Escape and unescape URL encoding in strings. The functions return a new * allocated string or NULL if an error occurred. */ -#include "setup.h" -#include +#include "curl_setup.h" + #include -#include -#include -#include -#include "curl_memory.h" -/* urldata.h and easyif.h are included for Curl_convert_... prototypes */ #include "urldata.h" -#include "easyif.h" #include "warnless.h" +#include "non-ascii.h" +#include "escape.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* Portable character check (remember EBCDIC). Do not use isalnum() because its behavior is altered by the current locale. - See http://tools.ietf.org/html/rfc3986#section-2.3 + See https://tools.ietf.org/html/rfc3986#section-2.3 */ static bool Curl_isunreserved(unsigned char in) { @@ -88,13 +83,10 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength) char *testing_ptr = NULL; unsigned char in; /* we need to treat the characters unsigned */ size_t newlen = alloc; - int strindex=0; + size_t strindex=0; size_t length; + CURLcode result; -#ifndef CURL_DOES_CONVERSIONS - /* avoid compiler warnings */ - (void)handle; -#endif ns = malloc(alloc); if(!ns) return NULL; @@ -103,10 +95,9 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength) while(length--) { in = *string; - if (Curl_isunreserved(in)) { + if(Curl_isunreserved(in)) /* just copy this */ ns[strindex++]=in; - } else { /* encode it */ newlen += 2; /* the size grows with two, since this'll become a %XX */ @@ -122,15 +113,12 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength) } } -#ifdef CURL_DOES_CONVERSIONS -/* escape sequences are always in ASCII so convert them on non-ASCII hosts */ - if(!handle || - (Curl_convert_to_network(handle, &in, 1) != CURLE_OK)) { + result = Curl_convert_to_network(handle, &in, 1); + if(result) { /* Curl_convert_to_network calls failf if unsuccessful */ free(ns); return NULL; } -#endif /* CURL_DOES_CONVERSIONS */ snprintf(&ns[strindex], 4, "%%%02X", in); @@ -143,30 +131,34 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength) } /* - * Unescapes the given URL escaped string of given length. Returns a - * pointer to a malloced string with length given in *olen. - * If length == 0, the length is assumed to be strlen(string). - * If olen == NULL, no output length is stored. + * Curl_urldecode() URL decodes the given string. + * + * Optionally detects control characters (byte codes lower than 32) in the + * data and rejects such data. + * + * Returns a pointer to a malloced string in *ostring with length given in + * *olen. If length == 0, the length is assumed to be strlen(string). + * */ -char *curl_easy_unescape(CURL *handle, const char *string, int length, - int *olen) +CURLcode Curl_urldecode(struct SessionHandle *data, + const char *string, size_t length, + char **ostring, size_t *olen, + bool reject_ctrl) { - int alloc = (length?length:(int)strlen(string))+1; + size_t alloc = (length?length:strlen(string))+1; char *ns = malloc(alloc); unsigned char in; - int strindex=0; + size_t strindex=0; unsigned long hex; + CURLcode result; -#ifndef CURL_DOES_CONVERSIONS - /* avoid compiler warnings */ - (void)handle; -#endif - if( !ns ) - return NULL; + if(!ns) + return CURLE_OUT_OF_MEMORY; while(--alloc > 0) { in = *string; - if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) { + if(('%' == in) && (alloc > 2) && + ISXDIGIT(string[1]) && ISXDIGIT(string[2])) { /* this is two hexadecimal digits following a '%' */ char hexstr[3]; char *ptr; @@ -178,20 +170,22 @@ char *curl_easy_unescape(CURL *handle, const char *string, int length, in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */ -#ifdef CURL_DOES_CONVERSIONS -/* escape sequences are always in ASCII so convert them on non-ASCII hosts */ - if(!handle || - (Curl_convert_from_network(handle, &in, 1) != CURLE_OK)) { + result = Curl_convert_from_network(data, &in, 1); + if(result) { /* Curl_convert_from_network calls failf if unsuccessful */ free(ns); - return NULL; + return result; } -#endif /* CURL_DOES_CONVERSIONS */ string+=2; alloc-=2; } + if(reject_ctrl && (in < 0x20)) { + free(ns); + return CURLE_URL_MALFORMAT; + } + ns[strindex++] = in; string++; } @@ -200,7 +194,32 @@ char *curl_easy_unescape(CURL *handle, const char *string, int length, if(olen) /* store output size */ *olen = strindex; - return ns; + + /* store output string */ + *ostring = ns; + + return CURLE_OK; +} + +/* + * Unescapes the given URL escaped string of given length. Returns a + * pointer to a malloced string with length given in *olen. + * If length == 0, the length is assumed to be strlen(string). + * If olen == NULL, no output length is stored. + */ +char *curl_easy_unescape(CURL *handle, const char *string, int length, + int *olen) +{ + char *str = NULL; + size_t inputlen = length; + size_t outputlen; + CURLcode res = Curl_urldecode(handle, string, inputlen, &str, &outputlen, + FALSE); + if(res) + return NULL; + if(olen) + *olen = curlx_uztosi(outputlen); + return str; } /* For operating systems/environments that use different malloc/free @@ -208,6 +227,5 @@ char *curl_easy_unescape(CURL *handle, const char *string, int length, the library's memory system */ void curl_free(void *p) { - if(p) - free(p); + free(p); } diff --git a/project/jni/curl/lib/escape.h b/project/jni/curl/lib/escape.h index 04b06a973..a6e2967b3 100644 --- a/project/jni/curl/lib/escape.h +++ b/project/jni/curl/lib/escape.h @@ -1,6 +1,5 @@ -#ifndef __ESCAPE_H -#define __ESCAPE_H - +#ifndef HEADER_CURL_ESCAPE_H +#define HEADER_CURL_ESCAPE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -8,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -25,5 +24,10 @@ /* Escape and unescape URL encoding in strings. The functions return a new * allocated string or NULL if an error occurred. */ +CURLcode Curl_urldecode(struct SessionHandle *data, + const char *string, size_t length, + char **ostring, size_t *olen, + bool reject_crlf); + +#endif /* HEADER_CURL_ESCAPE_H */ -#endif diff --git a/project/jni/curl/lib/file.c b/project/jni/curl/lib/file.c index 8e4ee075f..5c31fc4f7 100644 --- a/project/jni/curl/lib/file.c +++ b/project/jni/curl/lib/file.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,33 +20,13 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_FILE -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include -#ifdef WIN32 -#include -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif #ifdef HAVE_NETDB_H #include #endif @@ -68,8 +48,6 @@ #include #endif -#endif /* WIN32 */ - #include "strtoofft.h" #include "urldata.h" #include @@ -81,16 +59,16 @@ #include "getinfo.h" #include "transfer.h" #include "url.h" -#include "curl_memory.h" #include "parsedate.h" /* for the week day and month names */ +#include "warnless.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" -#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) || defined(__SYMBIAN32__) +#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) || \ + defined(__SYMBIAN32__) #define DOS_FILESYSTEM 1 #endif @@ -108,6 +86,9 @@ static CURLcode file_do(struct connectdata *, bool *done); static CURLcode file_done(struct connectdata *conn, CURLcode status, bool premature); static CURLcode file_connect(struct connectdata *conn, bool *done); +static CURLcode file_disconnect(struct connectdata *conn, + bool dead_connection); +static CURLcode file_setup_connection(struct connectdata *conn); /* * FILE scheme handler. @@ -115,7 +96,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done); const struct Curl_handler Curl_handler_file = { "FILE", /* scheme */ - ZERO_NULL, /* setup_connection */ + file_setup_connection, /* setup_connection */ file_do, /* do_it */ file_done, /* done */ ZERO_NULL, /* do_more */ @@ -124,13 +105,26 @@ const struct Curl_handler Curl_handler_file = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ + file_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ 0, /* defport */ - PROT_FILE /* protocol */ + CURLPROTO_FILE, /* protocol */ + PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */ }; +static CURLcode file_setup_connection(struct connectdata *conn) +{ + /* allocate the FILE specific struct */ + conn->data->req.protop = calloc(1, sizeof(struct FILEPROTO)); + if(!conn->data->req.protop) + return CURLE_OUT_OF_MEMORY; + + return CURLE_OK; +} + /* Check if this is a range download, and if so, set the internal variables properly. This code is copied from the FTP implementation and might as @@ -156,14 +150,14 @@ static CURLcode file_range(struct connectdata *conn) if((-1 == to) && (from>=0)) { /* X - */ data->state.resume_from = from; - DEBUGF(infof(data, "RANGE %" FORMAT_OFF_T " to end of file\n", + DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n", from)); } else if(from < 0) { /* -Y */ data->req.maxdownload = -from; data->state.resume_from = from; - DEBUGF(infof(data, "RANGE the last %" FORMAT_OFF_T " bytes\n", + DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes\n", -from)); } else { @@ -171,12 +165,13 @@ static CURLcode file_range(struct connectdata *conn) totalsize = to-from; data->req.maxdownload = totalsize+1; /* include last byte */ data->state.resume_from = from; - DEBUGF(infof(data, "RANGE from %" FORMAT_OFF_T - " getting %" FORMAT_OFF_T " bytes\n", + DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T + " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n", from, data->req.maxdownload)); } - DEBUGF(infof(data, "range-download from %" FORMAT_OFF_T - " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n", + DEBUGF(infof(data, "range-download from %" CURL_FORMAT_CURL_OFF_T + " to %" CURL_FORMAT_CURL_OFF_T ", totally %" + CURL_FORMAT_CURL_OFF_T " bytes\n", from, to, data->req.maxdownload)); } else @@ -192,40 +187,19 @@ static CURLcode file_range(struct connectdata *conn) static CURLcode file_connect(struct connectdata *conn, bool *done) { struct SessionHandle *data = conn->data; - char *real_path = curl_easy_unescape(data, data->state.path, 0, NULL); - struct FILEPROTO *file; + char *real_path; + struct FILEPROTO *file = data->req.protop; int fd; #ifdef DOS_FILESYSTEM int i; char *actual_path; #endif + int real_path_len; + real_path = curl_easy_unescape(data, data->state.path, 0, &real_path_len); if(!real_path) return CURLE_OUT_OF_MEMORY; - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); - - if(!data->state.proto.file) { - file = calloc(1, sizeof(struct FILEPROTO)); - if(!file) { - free(real_path); - return CURLE_OUT_OF_MEMORY; - } - data->state.proto.file = file; - } - else { - /* file is not a protocol that can deal with "persistancy" */ - file = data->state.proto.file; - Curl_safefree(file->freepath); - if(file->fd != -1) - close(file->fd); - file->path = NULL; - file->freepath = NULL; - file->fd = -1; - } - #ifdef DOS_FILESYSTEM /* If the first character is a slash, and there's something that looks like a drive at the beginning of @@ -244,20 +218,26 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) actual_path = real_path; if((actual_path[0] == '/') && actual_path[1] && - (actual_path[2] == ':' || actual_path[2] == '|')) - { + (actual_path[2] == ':' || actual_path[2] == '|')) { actual_path[2] = ':'; actual_path++; + real_path_len--; } /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */ - for (i=0; actual_path[i] != '\0'; ++i) + for(i=0; i < real_path_len; ++i) if(actual_path[i] == '/') actual_path[i] = '\\'; + else if(!actual_path[i]) /* binary zero */ + return CURLE_URL_MALFORMAT; - fd = open_readonly(actual_path, O_RDONLY|O_BINARY); /* no CR/LF translation */ + fd = open_readonly(actual_path, O_RDONLY|O_BINARY); file->path = actual_path; #else + if(memchr(real_path, 0, real_path_len)) + /* binary zeroes indicate foul play */ + return CURLE_URL_MALFORMAT; + fd = open_readonly(real_path, O_RDONLY); file->path = real_path; #endif @@ -277,13 +257,34 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) static CURLcode file_done(struct connectdata *conn, CURLcode status, bool premature) { - struct FILEPROTO *file = conn->data->state.proto.file; + struct FILEPROTO *file = conn->data->req.protop; (void)status; /* not used */ (void)premature; /* not used */ - Curl_safefree(file->freepath); - if(file->fd != -1) - close(file->fd); + if(file) { + Curl_safefree(file->freepath); + file->path = NULL; + if(file->fd != -1) + close(file->fd); + file->fd = -1; + } + + return CURLE_OK; +} + +static CURLcode file_disconnect(struct connectdata *conn, + bool dead_connection) +{ + struct FILEPROTO *file = conn->data->req.protop; + (void)dead_connection; /* not used */ + + if(file) { + Curl_safefree(file->freepath); + file->path = NULL; + if(file->fd != -1) + close(file->fd); + file->fd = -1; + } return CURLE_OK; } @@ -296,10 +297,11 @@ static CURLcode file_done(struct connectdata *conn, static CURLcode file_upload(struct connectdata *conn) { - struct FILEPROTO *file = conn->data->state.proto.file; + struct FILEPROTO *file = conn->data->req.protop; const char *dir = strchr(file->path, DIRSEP); - FILE *fp; - CURLcode res=CURLE_OK; + int fd; + int mode; + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; char *buf = data->state.buffer; size_t nread; @@ -313,49 +315,39 @@ static CURLcode file_upload(struct connectdata *conn) * Since FILE: doesn't do the full init, we need to provide some extra * assignments here. */ - conn->fread_func = data->set.fread_func; - conn->fread_in = data->set.in; conn->data->req.upload_fromhere = buf; if(!dir) return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ if(!dir[1]) - return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ + return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ + +#ifdef O_BINARY +#define MODE_DEFAULT O_WRONLY|O_CREAT|O_BINARY +#else +#define MODE_DEFAULT O_WRONLY|O_CREAT +#endif if(data->state.resume_from) - fp = fopen( file->path, "ab" ); - else { - int fd; + mode = MODE_DEFAULT|O_APPEND; + else + mode = MODE_DEFAULT|O_TRUNC; -#ifdef DOS_FILESYSTEM - fd = open(file->path, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, - conn->data->set.new_file_perms); -#else - fd = open(file->path, O_WRONLY|O_CREAT|O_TRUNC, - conn->data->set.new_file_perms); -#endif - if(fd < 0) { - failf(data, "Can't open %s for writing", file->path); - return CURLE_WRITE_ERROR; - } - close(fd); - fp = fopen(file->path, "wb"); - } - - if(!fp) { + fd = open(file->path, mode, conn->data->set.new_file_perms); + if(fd < 0) { failf(data, "Can't open %s for writing", file->path); return CURLE_WRITE_ERROR; } - if(-1 != data->set.infilesize) + if(-1 != data->state.infilesize) /* known size of data to "upload" */ - Curl_pgrsSetUploadSize(data, data->set.infilesize); + Curl_pgrsSetUploadSize(data, data->state.infilesize); /* treat the negative resume offset value as the case of "-" */ if(data->state.resume_from < 0) { - if(fstat(fileno(fp), &file_stat)) { - fclose(fp); + if(fstat(fd, &file_stat)) { + close(fd); failf(data, "Can't get the size of %s", file->path); return CURLE_WRITE_ERROR; } @@ -363,10 +355,10 @@ static CURLcode file_upload(struct connectdata *conn) data->state.resume_from = (curl_off_t)file_stat.st_size; } - while(res == CURLE_OK) { + while(!result) { int readcount; - res = Curl_fillreadbuffer(conn, BUFSIZE, &readcount); - if(res) + result = Curl_fillreadbuffer(conn, BUFSIZE, &readcount); + if(result) break; if(readcount <= 0) /* fix questionable compare error. curlvms */ @@ -376,7 +368,7 @@ static CURLcode file_upload(struct connectdata *conn) /*skip bytes before resume point*/ if(data->state.resume_from) { - if( (curl_off_t)nread <= data->state.resume_from ) { + if((curl_off_t)nread <= data->state.resume_from ) { data->state.resume_from -= nread; nread = 0; buf2 = buf; @@ -391,9 +383,9 @@ static CURLcode file_upload(struct connectdata *conn) buf2 = buf; /* write the data to the target */ - nwrite = fwrite(buf2, 1, nread, fp); + nwrite = write(fd, buf2, nread); if(nwrite != nread) { - res = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; break; } @@ -402,16 +394,16 @@ static CURLcode file_upload(struct connectdata *conn) Curl_pgrsSetUploadCounter(data, bytecount); if(Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; else - res = Curl_speedcheck(data, now); + result = Curl_speedcheck(data, now); } - if(!res && Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; + if(!result && Curl_pgrsUpdate(conn)) + result = CURLE_ABORTED_BY_CALLBACK; - fclose(fp); + close(fd); - return res; + return result; } /* @@ -429,19 +421,20 @@ static CURLcode file_do(struct connectdata *conn, bool *done) are supported. This means that files on remotely mounted directories (via NFS, Samba, NT sharing) can be accessed through a file:// URL */ - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; struct_stat statbuf; /* struct_stat instead of struct stat just to allow the Windows version to have a different struct without having to redefine the simple word 'stat' */ curl_off_t expected_size=0; + bool size_known; bool fstated=FALSE; ssize_t nread; - size_t bytestoread; struct SessionHandle *data = conn->data; char *buf = data->state.buffer; curl_off_t bytecount = 0; int fd; struct timeval now = Curl_tvnow(); + struct FILEPROTO *file; *done = TRUE; /* unconditionally */ @@ -451,11 +444,13 @@ static CURLcode file_do(struct connectdata *conn, bool *done) if(data->set.upload) return file_upload(conn); + file = conn->data->req.protop; + /* get the fd from the connection phase */ - fd = conn->data->state.proto.file->fd; + fd = file->fd; /* VMS: This only works reliable for STREAMLF files */ - if( -1 != fstat(fd, &statbuf)) { + if(-1 != fstat(fd, &statbuf)) { /* we could stat it, then read out the size */ expected_size = statbuf.st_size; /* and store the modification time */ @@ -463,13 +458,19 @@ static CURLcode file_do(struct connectdata *conn, bool *done) fstated = TRUE; } + if(fstated && !data->state.range && data->set.timecondition) { + if(!Curl_meets_timecondition(data, (time_t)data->info.filetime)) { + *done = TRUE; + return CURLE_OK; + } + } + /* If we have selected NOBODY and HEADER, it means that we only want file information. Which for FILE can't be much more than the file size and date. */ if(data->set.opt_no_body && data->set.include_header && fstated) { - CURLcode result; snprintf(buf, sizeof(data->state.buffer), - "Content-Length: %" FORMAT_OFF_T "\r\n", expected_size); + "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size); result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); if(result) return result; @@ -480,14 +481,13 @@ static CURLcode file_do(struct connectdata *conn, bool *done) return result; if(fstated) { - const struct tm *tm; time_t filetime = (time_t)statbuf.st_mtime; -#ifdef HAVE_GMTIME_R struct tm buffer; - tm = (const struct tm *)gmtime_r(&filetime, &buffer); -#else - tm = gmtime(&filetime); -#endif + const struct tm *tm = &buffer; + result = Curl_gmtime(filetime, &buffer); + if(result) + return result; + /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ snprintf(buf, BUFSIZE-1, "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", @@ -529,11 +529,13 @@ static CURLcode file_do(struct connectdata *conn, bool *done) } /* A high water mark has been specified so we obey... */ - if (data->req.maxdownload > 0) + if(data->req.maxdownload > 0) expected_size = data->req.maxdownload; - if(fstated && (expected_size == 0)) - return CURLE_OK; + if(!fstated || (expected_size == 0)) + size_known = FALSE; + else + size_known = TRUE; /* The following is a shortcut implementation of file reading this is both more efficient than the former call to download() and @@ -550,35 +552,45 @@ static CURLcode file_do(struct connectdata *conn, bool *done) Curl_pgrsTime(data, TIMER_STARTTRANSFER); - while(res == CURLE_OK) { + while(!result) { /* Don't fill a whole buffer if we want less than all data */ - bytestoread = (expected_size < BUFSIZE-1)?(size_t)expected_size:BUFSIZE-1; + size_t bytestoread; + + if(size_known) { + bytestoread = + (expected_size < CURL_OFF_T_C(BUFSIZE) - CURL_OFF_T_C(1)) ? + curlx_sotouz(expected_size) : BUFSIZE - 1; + } + else + bytestoread = BUFSIZE-1; + nread = read(fd, buf, bytestoread); - if( nread > 0) + if(nread > 0) buf[nread] = 0; - if (nread <= 0 || expected_size == 0) + if(nread <= 0 || (size_known && (expected_size == 0))) break; bytecount += nread; - expected_size -= nread; + if(size_known) + expected_size -= nread; - res = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread); - if(res) - return res; + result = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread); + if(result) + return result; Curl_pgrsSetDownloadCounter(data, bytecount); if(Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; else - res = Curl_speedcheck(data, now); + result = Curl_speedcheck(data, now); } if(Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; - return res; + return result; } #endif diff --git a/project/jni/curl/lib/file.h b/project/jni/curl/lib/file.h index 5e3bd7564..c12ae0e09 100644 --- a/project/jni/curl/lib/file.h +++ b/project/jni/curl/lib/file.h @@ -1,6 +1,5 @@ -#ifndef __FILE_H -#define __FILE_H - +#ifndef HEADER_CURL_FILE_H +#define HEADER_CURL_FILE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -12,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -37,4 +36,6 @@ struct FILEPROTO { #ifndef CURL_DISABLE_FILE extern const struct Curl_handler Curl_handler_file; #endif -#endif + +#endif /* HEADER_CURL_FILE_H */ + diff --git a/project/jni/curl/lib/fileinfo.c b/project/jni/curl/lib/fileinfo.c index f5dbfce4b..144c65b1d 100644 --- a/project/jni/curl/lib/fileinfo.c +++ b/project/jni/curl/lib/fileinfo.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2010, Daniel Stenberg, , et al. + * Copyright (C) 2010 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,15 +20,10 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#include #include "strdup.h" #include "fileinfo.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -49,27 +44,7 @@ void Curl_fileinfo_dtor(void *user, void *element) if(!finfo) return; - if(finfo->b_data){ - free(finfo->b_data); - } + Curl_safefree(finfo->b_data); free(finfo); } - -struct curl_fileinfo *Curl_fileinfo_dup(const struct curl_fileinfo *src) -{ - struct curl_fileinfo *ptr = malloc(sizeof(struct curl_fileinfo)); - if(!ptr) - return NULL; - *ptr = *src; - - ptr->b_data = malloc(src->b_size); - if(!ptr->b_data) { - free(ptr); - return NULL; - } - else { - memcpy(ptr->b_data, src->b_data, src->b_size); - return ptr; - } -} diff --git a/project/jni/curl/lib/fileinfo.h b/project/jni/curl/lib/fileinfo.h index b0e5e59e1..5324f1a40 100644 --- a/project/jni/curl/lib/fileinfo.h +++ b/project/jni/curl/lib/fileinfo.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/project/jni/curl/lib/firefox-db2pem.sh b/project/jni/curl/lib/firefox-db2pem.sh deleted file mode 100644 index 14ac57606..000000000 --- a/project/jni/curl/lib/firefox-db2pem.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/sh -# *************************************************************************** -# * _ _ ____ _ -# * Project ___| | | | _ \| | -# * / __| | | | |_) | | -# * | (__| |_| | _ <| |___ -# * \___|\___/|_| \_\_____| -# * -# * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. -# * -# * This software is licensed as described in the file COPYING, which -# * you should have received as part of this distribution. The terms -# * are also available at http://curl.haxx.se/docs/copyright.html. -# * -# * You may opt to use, copy, modify, merge, publish, distribute and/or sell -# * copies of the Software, and permit persons to whom the Software is -# * furnished to do so, under the terms of the COPYING file. -# * -# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# * KIND, either express or implied. -# * -# *************************************************************************** -# This shell script creates a fresh ca-bundle.crt file for use with libcurl. -# It extracts all ca certs it finds in the local Firefox database and converts -# them all into PEM format. -# -db=`ls -1d $HOME/.mozilla/firefox/*default` -out=$1 - -if test -z "$out"; then - out="ca-bundle.crt" # use a sensible default -fi - -currentdate=`date` - -cat >$out <> $out - diff --git a/project/jni/curl/lib/formdata.c b/project/jni/curl/lib/formdata.c index 5ec3e384e..c241e6e9b 100644 --- a/project/jni/curl/lib/formdata.c +++ b/project/jni/curl/lib/formdata.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,127 +20,35 @@ * ***************************************************************************/ -/* - Debug the form generator stand-alone by compiling this source file with: +#include "curl_setup.h" - gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -DCURLDEBUG -o formdata \ - -I../include formdata.c strequal.c memdebug.c mprintf.c strerror.c - - (depending on circumstances you may need further externals added) - - run the 'formdata' executable the output should end with: - All Tests seem to have worked ... - and the following parts should be there: - -Content-Disposition: form-data; name="simple_COPYCONTENTS" -value for simple COPYCONTENTS - -Content-Disposition: form-data; name="COPYCONTENTS_+_CONTENTTYPE" -Content-Type: image/gif -value for COPYCONTENTS + CONTENTTYPE - -Content-Disposition: form-data; name="PRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH" -vlue for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH -(or you might see P^@RNAME and v^@lue at the start) - -Content-Disposition: form-data; name="simple_PTRCONTENTS" -value for simple PTRCONTENTS - -Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH" -vlue for PTRCONTENTS + CONTENTSLENGTH -(or you might see v^@lue at the start) - -Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE" -Content-Type: application/octet-stream -vlue for PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE -(or you might see v^@lue at the start) - -Content-Disposition: form-data; name="FILE1_+_CONTENTTYPE"; filename="formdata.h" -Content-Type: text/html -... - -Content-Disposition: form-data; name="FILE1_+_FILE2" -Content-Type: multipart/mixed, boundary=curlz1s0dkticx49MV1KGcYP5cvfSsz -... -Content-Disposition: attachment; filename="formdata.h" -Content-Type: application/octet-stream -... -Content-Disposition: attachment; filename="Makefile.b32" -Content-Type: application/octet-stream -... - -Content-Disposition: form-data; name="FILE1_+_FILE2_+_FILE3" -Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1 -... -Content-Disposition: attachment; filename="formdata.h" -Content-Type: application/octet-stream -... -Content-Disposition: attachment; filename="Makefile.b32" -Content-Type: application/octet-stream -... -Content-Disposition: attachment; filename="formdata.h" -Content-Type: application/octet-stream -... - - -Content-Disposition: form-data; name="ARRAY: FILE1_+_FILE2_+_FILE3" -Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1 -... -Content-Disposition: attachment; filename="formdata.h" -Content-Type: application/octet-stream -... -Content-Disposition: attachment; filename="Makefile.b32" -Content-Type: application/octet-stream -... -Content-Disposition: attachment; filename="formdata.h" -Content-Type: application/octet-stream -... - -Content-Disposition: form-data; name="FILECONTENT" -... - - */ - -#include "setup.h" #include -/* Length of the random boundary string. */ -#define BOUNDARY_LENGTH 40 +#ifndef CURL_DISABLE_HTTP -#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) - -#include -#include -#include -#include -#include #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) #include #endif + #include "urldata.h" /* for struct SessionHandle */ -#include "easyif.h" /* for Curl_convert_... prototypes */ #include "formdata.h" -#include "curl_rand.h" +#include "vtls/vtls.h" #include "strequal.h" -#include "curl_memory.h" #include "sendf.h" +#include "strdup.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" -#endif /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */ - -#ifndef CURL_DISABLE_HTTP - #ifndef HAVE_BASENAME static char *Curl_basename(char *path); #define basename(x) Curl_basename((x)) #endif static size_t readfromfile(struct Form *form, char *buffer, size_t size); +static char *formboundary(struct SessionHandle *data); /* What kind of Content-Type to use on un-specified files with unrecognized extensions. */ @@ -149,6 +57,14 @@ static size_t readfromfile(struct Form *form, char *buffer, size_t size); #define FORM_FILE_SEPARATOR ',' #define FORM_TYPE_SEPARATOR ';' +#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME +#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME +#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS +#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE +#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER +#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK +#define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER + /*************************************************************************** * * AddHttpPost() @@ -161,7 +77,7 @@ static size_t readfromfile(struct Form *form, char *buffer, size_t size); ***************************************************************************/ static struct curl_httppost * AddHttpPost(char *name, size_t namelength, - char *value, size_t contentslength, + char *value, curl_off_t contentslength, char *buffer, size_t bufferlength, char *contenttype, long flags, @@ -177,14 +93,14 @@ AddHttpPost(char *name, size_t namelength, post->name = name; post->namelength = (long)(name?(namelength?namelength:strlen(name)):0); post->contents = value; - post->contentslength = (long)contentslength; + post->contentlen = contentslength; post->buffer = buffer; post->bufferlength = (long)bufferlength; post->contenttype = contenttype; post->contentheader = contentHeader; post->showfilename = showfilename; post->userp = userp, - post->flags = flags; + post->flags = flags | CURL_HTTPPOST_LARGE; } else return NULL; @@ -241,8 +157,6 @@ static FormInfo * AddFormInfo(char *value, /* then move the original 'more' to point to ourselves */ parent_form_info->more = form_info; } - else - return NULL; return form_info; } @@ -257,8 +171,8 @@ static FormInfo * AddFormInfo(char *value, * Returns some valid contenttype for filename. * ***************************************************************************/ -static const char * ContentTypeForFilename (const char *filename, - const char *prevtype) +static const char *ContentTypeForFilename(const char *filename, + const char *prevtype) { const char *contenttype = NULL; unsigned int i; @@ -267,7 +181,7 @@ static const char * ContentTypeForFilename (const char *filename, * extensions and pick the first we match! */ struct ContentType { - char extension[6]; + const char *extension; const char *type; }; static const struct ContentType ctts[]={ @@ -301,46 +215,6 @@ static const char * ContentTypeForFilename (const char *filename, return contenttype; } -/*************************************************************************** - * - * memdup() - * - * Copies the 'source' data to a newly allocated buffer buffer (that is - * returned). Uses buffer_length if not null, else uses strlen to determine - * the length of the buffer to be copied - * - * Returns the new pointer or NULL on failure. - * - ***************************************************************************/ -static char *memdup(const char *src, size_t buffer_length) -{ - size_t length; - bool add = FALSE; - char *buffer; - - if(buffer_length) - length = buffer_length; - else if(src) { - length = strlen(src); - add = TRUE; - } - else - /* no length and a NULL src pointer! */ - return strdup(""); - - buffer = malloc(length+add); - if(!buffer) - return NULL; /* fail */ - - memcpy(buffer, src, length); - - /* if length unknown do null termination */ - if(add) - buffer[length] = '\0'; - - return buffer; -} - /*************************************************************************** * * FormAdd() @@ -383,7 +257,7 @@ static char *memdup(const char *src, size_t buffer_length) * CURL_FORMADD_NULL if a null pointer was given for a char * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used - * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or an error) + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated * CURL_FORMADD_MEMORY if some allocation for string copying failed. * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array @@ -423,7 +297,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, while(return_value == CURL_FORMADD_OK) { /* first see if we have more parts of the array param */ - if( array_state && forms ) { + if(array_state && forms) { /* get the upcoming option from the given array */ option = forms->option; array_value = (char *)forms->value; @@ -461,8 +335,10 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, */ case CURLFORM_PTRNAME: #ifdef CURL_DOES_CONVERSIONS - /* treat CURLFORM_PTR like CURLFORM_COPYNAME so we'll - have safe memory for the eventual conversion */ + /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy + * the data in all cases so that we'll have safe memory for the eventual + * conversion. + */ #else current_form->flags |= HTTPPOST_PTRNAME; /* fall through */ #endif @@ -504,16 +380,19 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, } break; case CURLFORM_CONTENTSLENGTH: - if(current_form->contentslength) - return_value = CURL_FORMADD_OPTION_TWICE; - else - current_form->contentslength = - array_state?(size_t)array_value:(size_t)va_arg(params, long); + current_form->contentslength = + array_state?(size_t)array_value:(size_t)va_arg(params, long); + break; + + case CURLFORM_CONTENTLEN: + current_form->flags |= CURL_HTTPPOST_LARGE; + current_form->contentslength = + array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t); break; /* Get contents from a given file name */ case CURLFORM_FILECONTENT: - if(current_form->flags != 0) + if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE)) return_value = CURL_FORMADD_OPTION_TWICE; else { const char *filename = array_state? @@ -541,9 +420,21 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, if(current_form->value) { if(current_form->flags & HTTPPOST_FILENAME) { if(filename) { - if((current_form = AddFormInfo(strdup(filename), - NULL, current_form)) == NULL) + char *fname = strdup(filename); + if(!fname) return_value = CURL_FORMADD_MEMORY; + else { + form = AddFormInfo(fname, NULL, current_form); + if(!form) { + free(fname); + return_value = CURL_FORMADD_MEMORY; + } + else { + form->value_alloc = TRUE; + current_form = form; + form = NULL; + } + } } else return_value = CURL_FORMADD_NULL; @@ -567,46 +458,18 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, break; } - case CURLFORM_BUFFER: - { - const char *filename = array_state?array_value: - va_arg(params, char *); - - if(current_form->value) { - if(current_form->flags & HTTPPOST_BUFFER) { - if(filename) { - if((current_form = AddFormInfo(strdup(filename), - NULL, current_form)) == NULL) - return_value = CURL_FORMADD_MEMORY; - } - else - return_value = CURL_FORMADD_NULL; - } - else - return_value = CURL_FORMADD_OPTION_TWICE; - } - else { - if(filename) { - current_form->value = strdup(filename); - if(!current_form->value) - return_value = CURL_FORMADD_MEMORY; - } - else - return_value = CURL_FORMADD_NULL; - current_form->flags |= HTTPPOST_BUFFER; - } - break; - } - case CURLFORM_BUFFERPTR: - current_form->flags |= HTTPPOST_PTRBUFFER; + current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER; if(current_form->buffer) return_value = CURL_FORMADD_OPTION_TWICE; else { char *buffer = array_state?array_value:va_arg(params, char *); - if(buffer) + if(buffer) { current_form->buffer = buffer; /* store for the moment */ + current_form->value = buffer; /* make it non-NULL to be accepted + as fine */ + } else return_value = CURL_FORMADD_NULL; } @@ -646,10 +509,21 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, if(current_form->contenttype) { if(current_form->flags & HTTPPOST_FILENAME) { if(contenttype) { - if((current_form = AddFormInfo(NULL, - strdup(contenttype), - current_form)) == NULL) + char *type = strdup(contenttype); + if(!type) return_value = CURL_FORMADD_MEMORY; + else { + form = AddFormInfo(NULL, type, current_form); + if(!form) { + free(type); + return_value = CURL_FORMADD_MEMORY; + } + else { + form->contenttype_alloc = TRUE; + current_form = form; + form = NULL; + } + } } else return_value = CURL_FORMADD_NULL; @@ -675,10 +549,10 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, /* this "cast increases required alignment of target type" but we consider it OK anyway */ struct curl_slist* list = array_state? - (struct curl_slist*)array_value: + (struct curl_slist*)(void*)array_value: va_arg(params, struct curl_slist*); - if( current_form->contentheader ) + if(current_form->contentheader) return_value = CURL_FORMADD_OPTION_TWICE; else current_form->contentheader = list; @@ -686,10 +560,11 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, break; } case CURLFORM_FILENAME: + case CURLFORM_BUFFER: { const char *filename = array_state?array_value: va_arg(params, char *); - if( current_form->showfilename ) + if(current_form->showfilename) return_value = CURL_FORMADD_OPTION_TWICE; else { current_form->showfilename = strdup(filename); @@ -702,6 +577,31 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, } default: return_value = CURL_FORMADD_UNKNOWN_OPTION; + break; + } + } + + if(CURL_FORMADD_OK != return_value) { + /* On error, free allocated fields for all nodes of the FormInfo linked + list without deallocating nodes. List nodes are deallocated later on */ + FormInfo *ptr; + for(ptr = first_form; ptr != NULL; ptr = ptr->more) { + if(ptr->name_alloc) { + Curl_safefree(ptr->name); + ptr->name_alloc = FALSE; + } + if(ptr->value_alloc) { + Curl_safefree(ptr->value); + ptr->value_alloc = FALSE; + } + if(ptr->contenttype_alloc) { + Curl_safefree(ptr->contenttype); + ptr->contenttype_alloc = FALSE; + } + if(ptr->showfilename_alloc) { + Curl_safefree(ptr->showfilename); + ptr->showfilename_alloc = FALSE; + } } } @@ -713,53 +613,63 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, for(form = first_form; form != NULL; form = form->more) { - if( ((!form->name || !form->value) && !post) || - ( (form->contentslength) && - (form->flags & HTTPPOST_FILENAME) ) || - ( (form->flags & HTTPPOST_FILENAME) && - (form->flags & HTTPPOST_PTRCONTENTS) ) || + if(((!form->name || !form->value) && !post) || + ( (form->contentslength) && + (form->flags & HTTPPOST_FILENAME) ) || + ( (form->flags & HTTPPOST_FILENAME) && + (form->flags & HTTPPOST_PTRCONTENTS) ) || - ( (!form->buffer) && - (form->flags & HTTPPOST_BUFFER) && - (form->flags & HTTPPOST_PTRBUFFER) ) || + ( (!form->buffer) && + (form->flags & HTTPPOST_BUFFER) && + (form->flags & HTTPPOST_PTRBUFFER) ) || - ( (form->flags & HTTPPOST_READFILE) && - (form->flags & HTTPPOST_PTRCONTENTS) ) + ( (form->flags & HTTPPOST_READFILE) && + (form->flags & HTTPPOST_PTRCONTENTS) ) ) { return_value = CURL_FORMADD_INCOMPLETE; break; } else { - if( ((form->flags & HTTPPOST_FILENAME) || - (form->flags & HTTPPOST_BUFFER)) && - !form->contenttype ) { + if(((form->flags & HTTPPOST_FILENAME) || + (form->flags & HTTPPOST_BUFFER)) && + !form->contenttype ) { + char *f = form->flags & HTTPPOST_BUFFER? + form->showfilename : form->value; + /* our contenttype is missing */ - form->contenttype - = strdup(ContentTypeForFilename(form->value, prevtype)); + form->contenttype = strdup(ContentTypeForFilename(f, prevtype)); if(!form->contenttype) { return_value = CURL_FORMADD_MEMORY; break; } form->contenttype_alloc = TRUE; } - if( !(form->flags & HTTPPOST_PTRNAME) && - (form == first_form) ) { + if(!(form->flags & HTTPPOST_PTRNAME) && + (form == first_form) ) { /* Note that there's small risk that form->name is NULL here if the app passed in a bad combo, so we better check for that first. */ - if(form->name) + if(form->name) { /* copy name (without strdup; possibly contains null characters) */ - form->name = memdup(form->name, form->namelength); + form->name = Curl_memdup(form->name, form->namelength? + form->namelength: + strlen(form->name)+1); + } if(!form->name) { return_value = CURL_FORMADD_MEMORY; break; } form->name_alloc = TRUE; } - if( !(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE | - HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER | - HTTPPOST_CALLBACK)) ) { + if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE | + HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER | + HTTPPOST_CALLBACK)) && form->value) { /* copy value (without strdup; possibly contains null characters) */ - form->value = memdup(form->value, form->contentslength); + size_t clen = (size_t) form->contentslength; + if(!clen) + clen = strlen(form->value)+1; + + form->value = Curl_memdup(form->value, clen); + if(!form->value) { return_value = CURL_FORMADD_MEMORY; break; @@ -784,32 +694,39 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, prevtype = form->contenttype; } } - } - - if(return_value) { - /* we return on error, free possibly allocated fields */ - if(!form) - form = current_form; - if(form) { - if(form->name_alloc) - free(form->name); - if(form->value_alloc) - free(form->value); - if(form->contenttype_alloc) - free(form->contenttype); - if(form->showfilename_alloc) - free(form->showfilename); + if(CURL_FORMADD_OK != return_value) { + /* On error, free allocated fields for nodes of the FormInfo linked + list which are not already owned by the httppost linked list + without deallocating nodes. List nodes are deallocated later on */ + FormInfo *ptr; + for(ptr = form; ptr != NULL; ptr = ptr->more) { + if(ptr->name_alloc) { + Curl_safefree(ptr->name); + ptr->name_alloc = FALSE; + } + if(ptr->value_alloc) { + Curl_safefree(ptr->value); + ptr->value_alloc = FALSE; + } + if(ptr->contenttype_alloc) { + Curl_safefree(ptr->contenttype); + ptr->contenttype_alloc = FALSE; + } + if(ptr->showfilename_alloc) { + Curl_safefree(ptr->showfilename); + ptr->showfilename_alloc = FALSE; + } + } } } - /* always delete the allocated memory before returning */ - form = first_form; - while(form != NULL) { - FormInfo *delete_form; - - delete_form = form; - form = form->more; - free (delete_form); + /* Always deallocate FormInfo linked list nodes without touching node + fields given that these have either been deallocated or are owned + now by the httppost linked list */ + while(first_form) { + FormInfo *ptr = first_form->more; + free(first_form); + first_form = ptr; } return return_value; @@ -817,6 +734,8 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, /* * curl_formadd() is a public API to add a section to the multipart formpost. + * + * @unittest: 1308 */ CURLFORMcode curl_formadd(struct curl_httppost **httppost, @@ -831,6 +750,70 @@ CURLFORMcode curl_formadd(struct curl_httppost **httppost, return result; } +#ifdef __VMS +#include +/* + * get_vms_file_size does what it takes to get the real size of the file + * + * For fixed files, find out the size of the EOF block and adjust. + * + * For all others, have to read the entire file in, discarding the contents. + * Most posted text files will be small, and binary files like zlib archives + * and CD/DVD images should be either a STREAM_LF format or a fixed format. + * + */ +curl_off_t VmsRealFileSize(const char * name, + const struct_stat * stat_buf) +{ + char buffer[8192]; + curl_off_t count; + int ret_stat; + FILE * file; + + file = fopen(name, "r"); /* VMS */ + if(file == NULL) + return 0; + + count = 0; + ret_stat = 1; + while(ret_stat > 0) { + ret_stat = fread(buffer, 1, sizeof(buffer), file); + if(ret_stat != 0) + count += ret_stat; + } + fclose(file); + + return count; +} + +/* + * + * VmsSpecialSize checks to see if the stat st_size can be trusted and + * if not to call a routine to get the correct size. + * + */ +static curl_off_t VmsSpecialSize(const char * name, + const struct_stat * stat_buf) +{ + switch(stat_buf->st_fab_rfm) { + case FAB$C_VAR: + case FAB$C_VFC: + return VmsRealFileSize(name, stat_buf); + break; + default: + return stat_buf->st_size; + } +} + +#endif + +#ifndef __VMS +#define filesize(name, stat_data) (stat_data.st_size) +#else + /* Getting the expected file size needs help on VMS */ +#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data) +#endif + /* * AddFormData() adds a chunk of data to the FormData linked list. * @@ -839,10 +822,16 @@ CURLFORMcode curl_formadd(struct curl_httppost **httppost, static CURLcode AddFormData(struct FormData **formp, enum formtype type, const void *line, - size_t length, + curl_off_t length, curl_off_t *size) { - struct FormData *newform = malloc(sizeof(struct FormData)); + struct FormData *newform; + char *alloc2 = NULL; + CURLcode result = CURLE_OK; + if(length < 0 || (size && *size < 0)) + return CURLE_BAD_FUNCTION_ARGUMENT; + + newform = malloc(sizeof(struct FormData)); if(!newform) return CURLE_OUT_OF_MEMORY; newform->next = NULL; @@ -851,15 +840,22 @@ static CURLcode AddFormData(struct FormData **formp, /* we make it easier for plain strings: */ if(!length) length = strlen((char *)line); - - newform->line = malloc(length+1); - if(!newform->line) { - free(newform); - return CURLE_OUT_OF_MEMORY; +#if (SIZEOF_SIZE_T < CURL_SIZEOF_CURL_OFF_T) + else if(length >= (curl_off_t)(size_t)-1) { + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto error; } - memcpy(newform->line, line, length); - newform->length = length; - newform->line[length]=0; /* zero terminate for easier debugging */ +#endif + + newform->line = malloc((size_t)length+1); + if(!newform->line) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + alloc2 = newform->line; + memcpy(newform->line, line, (size_t)length); + newform->length = (size_t)length; + newform->line[(size_t)length]=0; /* zero terminate for easier debugging */ } else /* For callbacks and files we don't have any actual data so we just keep a @@ -885,13 +881,22 @@ static CURLcode AddFormData(struct FormData **formp, file */ if(!strequal("-", newform->line)) { struct_stat file; - if(!stat(newform->line, &file)) { - *size += file.st_size; + if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode)) + *size += filesize(newform->line, file); + else { + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto error; } } } } return CURLE_OK; + error: + if(newform) + free(newform); + if(alloc2) + free(alloc2); + return result; } /* @@ -934,54 +939,26 @@ void Curl_formclean(struct FormData **form_ptr) *form_ptr = NULL; } -#ifdef CURL_DOES_CONVERSIONS -/* - * Curl_formcovert() is used from http.c, this converts any - form items that need to be sent in the network encoding. - Returns CURLE_OK on success. - */ -CURLcode Curl_formconvert(struct SessionHandle *data, struct FormData *form) -{ - struct FormData *next; - CURLcode rc; - - if(!form) - return CURLE_OK; - - if(!data) - return CURLE_BAD_FUNCTION_ARGUMENT; - - do { - next=form->next; /* the following form line */ - if(form->type == FORM_DATA) { - rc = Curl_convert_to_network(data, form->line, form->length); - /* Curl_convert_to_network calls failf if unsuccessful */ - if(rc != CURLE_OK) - return rc; - } - } while((form = next) != NULL); /* continue */ - return CURLE_OK; -} -#endif /* CURL_DOES_CONVERSIONS */ - /* * curl_formget() * Serialize a curl_httppost struct. * Returns 0 on success. + * + * @unittest: 1308 */ int curl_formget(struct curl_httppost *form, void *arg, curl_formget_callback append) { - CURLcode rc; + CURLcode result; curl_off_t size; struct FormData *data, *ptr; - rc = Curl_getformdata(NULL, &data, form, NULL, &size); - if(rc != CURLE_OK) - return (int)rc; + result = Curl_getformdata(NULL, &data, form, NULL, &size); + if(result) + return (int)result; - for (ptr = data; ptr; ptr = ptr->next) { - if(ptr->type == FORM_FILE) { + for(ptr = data; ptr; ptr = ptr->next) { + if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) { char buffer[8192]; size_t nread; struct Form temp; @@ -990,14 +967,15 @@ int curl_formget(struct curl_httppost *form, void *arg, do { nread = readfromfile(&temp, buffer, sizeof(buffer)); - if((nread == (size_t) -1) || (nread != append(arg, buffer, nread))) { - if(temp.fp) { + if((nread == (size_t) -1) || + (nread > sizeof(buffer)) || + (nread != append(arg, buffer, nread))) { + if(temp.fp) fclose(temp.fp); - } Curl_formclean(&data); return -1; } - } while(nread == sizeof(buffer)); + } while(nread); } else { if(ptr->length != append(arg, ptr->line, ptr->length)) { @@ -1026,18 +1004,16 @@ void curl_formfree(struct curl_httppost *form) next=form->next; /* the following form line */ /* recurse to sub-contents */ - if(form->more) - curl_formfree(form->more); + curl_formfree(form->more); - if( !(form->flags & HTTPPOST_PTRNAME) && form->name) + if(!(form->flags & HTTPPOST_PTRNAME)) free(form->name); /* free the name */ - if( !(form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_CALLBACK)) && - form->contents) + if(!(form->flags & + (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK)) + ) free(form->contents); /* free the contents */ - if(form->contenttype) - free(form->contenttype); /* free the content type */ - if(form->showfilename) - free(form->showfilename); /* free the faked file name */ + free(form->contenttype); /* free the content type */ + free(form->showfilename); /* free the faked file name */ free(form); /* free the struct */ } while((form = next) != NULL); /* continue */ @@ -1105,6 +1081,49 @@ static char *strippath(const char *fullfile) return base; /* returns an allocated string or NULL ! */ } +static CURLcode formdata_add_filename(const struct curl_httppost *file, + struct FormData **form, + curl_off_t *size) +{ + CURLcode result = CURLE_OK; + char *filename = file->showfilename; + char *filebasename = NULL; + char *filename_escaped = NULL; + + if(!filename) { + filebasename = strippath(file->contents); + if(!filebasename) + return CURLE_OUT_OF_MEMORY; + filename = filebasename; + } + + if(strchr(filename, '\\') || strchr(filename, '"')) { + char *p0, *p1; + + /* filename need be escaped */ + filename_escaped = malloc(strlen(filename)*2+1); + if(!filename_escaped) { + free(filebasename); + return CURLE_OUT_OF_MEMORY; + } + p0 = filename_escaped; + p1 = filename; + while(*p1) { + if(*p1 == '\\' || *p1 == '"') + *p0++ = '\\'; + *p0++ = *p1++; + } + *p0 = '\0'; + filename = filename_escaped; + } + result = AddFormDataf(form, size, + "; filename=\"%s\"", + filename); + free(filename_escaped); + free(filebasename); + return result; +} + /* * Curl_getformdata() converts a linked list of "meta data" into a complete * (possibly huge) multipart formdata. The input list is in 'post', while the @@ -1129,17 +1148,17 @@ CURLcode Curl_getformdata(struct SessionHandle *data, struct curl_httppost *file; CURLcode result = CURLE_OK; - curl_off_t size=0; /* support potentially ENORMOUS formposts */ + curl_off_t size = 0; /* support potentially ENORMOUS formposts */ char *boundary; - char *fileboundary=NULL; + char *fileboundary = NULL; struct curl_slist* curList; - *finalform=NULL; /* default form is empty */ + *finalform = NULL; /* default form is empty */ if(!post) return result; /* no input => no output! */ - boundary = Curl_FormBoundary(); + boundary = formboundary(data); if(!boundary) return CURLE_OUT_OF_MEMORY; @@ -1194,10 +1213,15 @@ CURLcode Curl_getformdata(struct SessionHandle *data, /* If used, this is a link to more file names, we must then do the magic to include several files with the same field name */ - fileboundary = Curl_FormBoundary(); + free(fileboundary); + fileboundary = formboundary(data); + if(!fileboundary) { + result = CURLE_OUT_OF_MEMORY; + break; + } result = AddFormDataf(&form, &size, - "\r\nContent-Type: multipart/mixed," + "\r\nContent-Type: multipart/mixed;" " boundary=%s\r\n", fileboundary); if(result) @@ -1214,24 +1238,13 @@ CURLcode Curl_getformdata(struct SessionHandle *data, if(post->more) { /* if multiple-file */ - char *filebasename= NULL; - if(!file->showfilename) { - filebasename = strippath(file->contents); - if(!filebasename) { - Curl_formclean(&firstform); - free(boundary); - return CURLE_OUT_OF_MEMORY; - } - } - result = AddFormDataf(&form, &size, "\r\n--%s\r\nContent-Disposition: " - "attachment; filename=\"%s\"", - fileboundary, - (file->showfilename?file->showfilename: - filebasename)); - if(filebasename) - free(filebasename); + "attachment", + fileboundary); + if(result) + break; + result = formdata_add_filename(file, &form, &size); if(result) break; } @@ -1240,15 +1253,9 @@ CURLcode Curl_getformdata(struct SessionHandle *data, /* it should be noted that for the HTTPPOST_FILENAME and HTTPPOST_CALLBACK cases the ->showfilename struct member is always assigned at this point */ - char *filebasename= - (!post->showfilename)?strippath(post->contents):NULL; - - result = AddFormDataf(&form, &size, - "; filename=\"%s\"", - (post->showfilename?post->showfilename: - filebasename)); - if(filebasename) - free(filebasename); + if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) { + result = formdata_add_filename(post, &form, &size); + } if(result) break; @@ -1264,18 +1271,15 @@ CURLcode Curl_getformdata(struct SessionHandle *data, } curList = file->contentheader; - while( curList ) { + while(curList) { /* Process the additional headers specified for this form */ result = AddFormDataf( &form, &size, "\r\n%s", curList->data ); if(result) break; curList = curList->next; } - if(result) { - Curl_formclean(&firstform); - free(boundary); - return result; - } + if(result) + break; result = AddFormDataf(&form, &size, "\r\n\r\n"); if(result) @@ -1297,7 +1301,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data, if(fileread) { if(fileread != stdin) { - /* close the file again */ + /* close the file */ fclose(fileread); /* add the file name only - for later reading from this */ result = AddFormData(&form, FORM_FILE, file->contents, 0, &size); @@ -1319,7 +1323,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data, } else { if(data) - failf(data, "couldn't open file \"%s\"\n", file->contents); + failf(data, "couldn't open file \"%s\"", file->contents); *finalform = NULL; result = CURLE_READ_ERROR; } @@ -1329,23 +1333,21 @@ CURLcode Curl_getformdata(struct SessionHandle *data, result = AddFormData(&form, FORM_CONTENT, post->buffer, post->bufferlength, &size); else if(post->flags & HTTPPOST_CALLBACK) - /* the contents should be read with the callback and the size - is set with the contentslength */ + /* the contents should be read with the callback and the size is set + with the contentslength */ result = AddFormData(&form, FORM_CALLBACK, post->userp, - post->contentslength, &size); + post->flags&CURL_HTTPPOST_LARGE? + post->contentlen:post->contentslength, &size); else /* include the contents we got */ result = AddFormData(&form, FORM_CONTENT, post->contents, - post->contentslength, &size); - + post->flags&CURL_HTTPPOST_LARGE? + post->contentlen:post->contentslength, &size); file = file->more; } while(file && !result); /* for each specified file for this field */ - if(result) { - Curl_formclean(&firstform); - free(boundary); - return result; - } + if(result) + break; if(post->more) { /* this was a multiple-file inclusion, make a termination file @@ -1353,33 +1355,29 @@ CURLcode Curl_getformdata(struct SessionHandle *data, result = AddFormDataf(&form, &size, "\r\n--%s--", fileboundary); - free(fileboundary); if(result) break; } } while((post = post->next) != NULL); /* for each field */ - if(result) { - Curl_formclean(&firstform); - free(boundary); - return result; - } /* end-boundary for everything */ - result = AddFormDataf(&form, &size, - "\r\n--%s--\r\n", - boundary); + if(!result) + result = AddFormDataf(&form, &size, "\r\n--%s--\r\n", boundary); + if(result) { Curl_formclean(&firstform); + free(fileboundary); free(boundary); return result; } *sizep = size; + free(fileboundary); free(boundary); - *finalform=firstform; + *finalform = firstform; return result; } @@ -1401,26 +1399,67 @@ int Curl_FormInit(struct Form *form, struct FormData *formdata ) return 0; } +#ifndef __VMS +# define fopen_read fopen +#else + /* + * vmsfopenread + * + * For upload to work as expected on VMS, different optional + * parameters must be added to the fopen command based on + * record format of the file. + * + */ +# define fopen_read vmsfopenread +static FILE * vmsfopenread(const char *file, const char *mode) { + struct_stat statbuf; + int result; + + result = stat(file, &statbuf); + + switch (statbuf.st_fab_rfm) { + case FAB$C_VAR: + case FAB$C_VFC: + case FAB$C_STMCR: + return fopen(file, "r"); /* VMS */ + break; + default: + return fopen(file, "r", "rfm=stmlf", "ctx=stm"); + } +} +#endif + +/* + * readfromfile() + * + * The read callback that this function may use can return a value larger than + * 'size' (which then this function returns) that indicates a problem and it + * must be properly dealt with + */ static size_t readfromfile(struct Form *form, char *buffer, size_t size) { size_t nread; - bool callback = (bool)(form->data->type == FORM_CALLBACK); + bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE; - if(callback) - nread = form->fread_func(buffer, 1, size, form->data->line); + if(callback) { + if(form->fread_func == ZERO_NULL) + return 0; + else + nread = form->fread_func(buffer, 1, size, form->data->line); + } else { if(!form->fp) { /* this file hasn't yet been opened */ - form->fp = fopen(form->data->line, "rb"); /* b is for binary */ + form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */ if(!form->fp) return (size_t)-1; /* failure */ } nread = fread(buffer, 1, size, form->fp); } - if(!nread || nread > size) { + if(!nread) { /* this is the last chunk from the file, move on */ - if(!callback) { + if(form->fp) { fclose(form->fp); form->fp = NULL; } @@ -1460,7 +1499,7 @@ size_t Curl_FormReader(char *buffer, } do { - if( (form->data->length - form->sent ) > wantedsize - gotsize) { + if((form->data->length - form->sent ) > wantedsize - gotsize) { memcpy(buffer + gotsize , form->data->line + form->sent, wantedsize - gotsize); @@ -1507,168 +1546,18 @@ char *Curl_formpostheader(void *formp, size_t *len) return header; } - -#ifdef _FORM_DEBUG -int FormAddTest(const char * errormsg, - struct curl_httppost **httppost, - struct curl_httppost **last_post, - ...) +/* + * formboundary() creates a suitable boundary string and returns an allocated + * one. + */ +static char *formboundary(struct SessionHandle *data) { - int result; - va_list arg; - va_start(arg, last_post); - if((result = FormAdd(httppost, last_post, arg))) - fprintf (stderr, "ERROR doing FormAdd ret: %d action: %s\n", result, - errormsg); - va_end(arg); - return result; + /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615) + combinations */ + return aprintf("------------------------%08x%08x", + Curl_rand(data), Curl_rand(data)); } - -int main(int argc, argv_item_t argv[]) -{ - char name1[] = "simple_COPYCONTENTS"; - char name2[] = "COPYCONTENTS_+_CONTENTTYPE"; - char name3[] = "PTRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH"; - char name4[] = "simple_PTRCONTENTS"; - char name5[] = "PTRCONTENTS_+_CONTENTSLENGTH"; - char name6[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE"; - char name7[] = "FILE1_+_CONTENTTYPE"; - char name8[] = "FILE1_+_FILE2"; - char name9[] = "FILE1_+_FILE2_+_FILE3"; - char name10[] = "ARRAY: FILE1_+_FILE2_+_FILE3"; - char name11[] = "FILECONTENT"; - char value1[] = "value for simple COPYCONTENTS"; - char value2[] = "value for COPYCONTENTS + CONTENTTYPE"; - char value3[] = "value for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH"; - char value4[] = "value for simple PTRCONTENTS"; - char value5[] = "value for PTRCONTENTS + CONTENTSLENGTH"; - char value6[] = "value for PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE"; - char value7[] = "formdata.h"; - char value8[] = "Makefile.b32"; - char type2[] = "image/gif"; - char type6[] = "text/plain"; - char type7[] = "text/html"; - int name3length = strlen(name3); - int value3length = strlen(value3); - int value5length = strlen(value5); - int value6length = strlen(value6); - int errors = 0; - CURLcode rc; - curl_off_t size; - size_t nread; - char buffer[4096]; - struct curl_httppost *httppost=NULL; - struct curl_httppost *last_post=NULL; - struct curl_forms forms[4]; - - struct FormData *form; - struct Form formread; - - (void) argc; - (void) argv; - - Curl_srand(); /* Because we do not call curl_global_init() here. */ - - if(FormAddTest("simple COPYCONTENTS test", &httppost, &last_post, - CURLFORM_COPYNAME, name1, CURLFORM_COPYCONTENTS, value1, - CURLFORM_END)) - ++errors; - if(FormAddTest("COPYCONTENTS + CONTENTTYPE test", &httppost, &last_post, - CURLFORM_COPYNAME, name2, CURLFORM_COPYCONTENTS, value2, - CURLFORM_CONTENTTYPE, type2, CURLFORM_END)) - ++errors; - /* make null character at start to check that contentslength works - correctly */ - name3[1] = '\0'; - value3[1] = '\0'; - if(FormAddTest("PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH test", - &httppost, &last_post, - CURLFORM_PTRNAME, name3, CURLFORM_COPYCONTENTS, value3, - CURLFORM_CONTENTSLENGTH, value3length, - CURLFORM_NAMELENGTH, name3length, CURLFORM_END)) - ++errors; - if(FormAddTest("simple PTRCONTENTS test", &httppost, &last_post, - CURLFORM_COPYNAME, name4, CURLFORM_PTRCONTENTS, value4, - CURLFORM_END)) - ++errors; - /* make null character at start to check that contentslength works - correctly */ - value5[1] = '\0'; - if(FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost, &last_post, - CURLFORM_COPYNAME, name5, CURLFORM_PTRCONTENTS, value5, - CURLFORM_CONTENTSLENGTH, value5length, CURLFORM_END)) - ++errors; - /* make null character at start to check that contentslength works - correctly */ - value6[1] = '\0'; - if(FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test", - &httppost, &last_post, - CURLFORM_COPYNAME, name6, CURLFORM_PTRCONTENTS, value6, - CURLFORM_CONTENTSLENGTH, value6length, - CURLFORM_CONTENTTYPE, type6, CURLFORM_END)) - ++errors; - if(FormAddTest("FILE + CONTENTTYPE test", &httppost, &last_post, - CURLFORM_COPYNAME, name7, CURLFORM_FILE, value7, - CURLFORM_CONTENTTYPE, type7, CURLFORM_END)) - ++errors; - if(FormAddTest("FILE1 + FILE2 test", &httppost, &last_post, - CURLFORM_COPYNAME, name8, CURLFORM_FILE, value7, - CURLFORM_FILE, value8, CURLFORM_END)) - ++errors; - if(FormAddTest("FILE1 + FILE2 + FILE3 test", &httppost, &last_post, - CURLFORM_COPYNAME, name9, CURLFORM_FILE, value7, - CURLFORM_FILE, value8, CURLFORM_FILE, value7, CURLFORM_END)) - ++errors; - forms[0].option = CURLFORM_FILE; - forms[0].value = value7; - forms[1].option = CURLFORM_FILE; - forms[1].value = value8; - forms[2].option = CURLFORM_FILE; - forms[2].value = value7; - forms[3].option = CURLFORM_END; - if(FormAddTest("FILE1 + FILE2 + FILE3 ARRAY test", &httppost, &last_post, - CURLFORM_COPYNAME, name10, CURLFORM_ARRAY, forms, - CURLFORM_END)) - ++errors; - if(FormAddTest("FILECONTENT test", &httppost, &last_post, - CURLFORM_COPYNAME, name11, CURLFORM_FILECONTENT, value7, - CURLFORM_END)) - ++errors; - - rc = Curl_getformdata(NULL, &form, httppost, NULL, &size); - if(rc != CURLE_OK) { - if(rc != CURLE_READ_ERROR) { - const char *errortext = curl_easy_strerror(rc); - fprintf(stdout, "\n==> Curl_getformdata error: %s\n", errortext); - } - return 0; - } - - Curl_FormInit(&formread, form); - - for(;;) { - nread = Curl_FormReader(buffer, 1, sizeof(buffer), - (FILE *)&formread); - - if(nread < 1) - break; - fwrite(buffer, nread, 1, stdout); - } - - fprintf(stdout, "size: "); - fprintf(stdout, "%" FORMAT_OFF_T, size); - fprintf(stdout, "\n"); - if(errors) - fprintf(stdout, "\n==> %d Test(s) failed!\n", errors); - else - fprintf(stdout, "\nAll Tests seem to have worked (please check output)\n"); - - return 0; -} - -#endif /* _FORM_DEBUG */ - #else /* CURL_DISABLE_HTTP */ CURLFORMcode curl_formadd(struct curl_httppost **httppost, struct curl_httppost **last_post, @@ -1694,37 +1583,5 @@ void curl_formfree(struct curl_httppost *form) /* does nothing HTTP is disabled */ } -#endif /* CURL_DISABLE_HTTP */ -#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) - -/* - * Curl_FormBoundary() creates a suitable boundary string and returns an - * allocated one. This is also used by SSL-code so it must be present even - * if HTTP is disabled! - */ -char *Curl_FormBoundary(void) -{ - char *retstring; - size_t i; - - static const char table16[]="0123456789abcdef"; - - retstring = malloc(BOUNDARY_LENGTH+1); - - if(!retstring) - return NULL; /* failed */ - - strcpy(retstring, "----------------------------"); - - for(i=strlen(retstring); i, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -54,7 +54,7 @@ typedef struct FormInfo { size_t namelength; char *value; bool value_alloc; - size_t contentslength; + curl_off_t contentslength; char *contenttype; bool contenttype_alloc; long flags; diff --git a/project/jni/curl/lib/ftp.c b/project/jni/curl/lib/ftp.c index 8e370c5d2..9b728cc98 100644 --- a/project/jni/curl/lib/ftp.c +++ b/project/jni/curl/lib/ftp.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,22 +20,10 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_FTP -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif @@ -61,8 +49,6 @@ #include #include "urldata.h" #include "sendf.h" -#include "easyif.h" /* for Curl_convert_... prototypes */ - #include "if2ip.h" #include "hostip.h" #include "progress.h" @@ -73,14 +59,10 @@ #include "ftp.h" #include "fileinfo.h" #include "ftplistparser.h" - -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) -#include "krb4.h" -#endif - +#include "curl_sec.h" #include "strtoofft.h" #include "strequal.h" -#include "sslgen.h" +#include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "inet_ntop.h" @@ -93,9 +75,9 @@ #include "rawstr.h" #include "speedcheck.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include +#include "http_proxy.h" +#include "non-ascii.h" +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -109,10 +91,21 @@ #endif #ifdef CURL_DISABLE_VERBOSE_STRINGS -#define ftp_pasv_verbose(a,b,c,d) do { } while(0) +#define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt #endif /* Local API functions */ +#ifndef DEBUGBUILD +static void _state(struct connectdata *conn, + ftpstate newstate); +#define state(x,y) _state(x,y) +#else +static void _state(struct connectdata *conn, + ftpstate newstate, + int lineno); +#define state(x,y) _state(x,y,__LINE__) +#endif + static CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote); static CURLcode ftp_quit(struct connectdata *conn); @@ -124,8 +117,8 @@ static void ftp_pasv_verbose(struct connectdata *conn, char *newhost, /* ascii version */ int port); #endif -static CURLcode ftp_state_post_rest(struct connectdata *conn); -static CURLcode ftp_state_post_cwd(struct connectdata *conn); +static CURLcode ftp_state_prepare_transfer(struct connectdata *conn); +static CURLcode ftp_state_mdtm(struct connectdata *conn); static CURLcode ftp_state_quote(struct connectdata *conn, bool init, ftpstate instate); static CURLcode ftp_nb_type(struct connectdata *conn, @@ -137,11 +130,12 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode ftp_connect(struct connectdata *conn, bool *done); static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection); -static CURLcode ftp_nextconnect(struct connectdata *conn); +static CURLcode ftp_do_more(struct connectdata *conn, int *completed); static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done); -static int ftp_getsock(struct connectdata *conn, - curl_socket_t *socks, +static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks); +static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks); static CURLcode ftp_doing(struct connectdata *conn, bool *dophase_done); static CURLcode ftp_setup_connection(struct connectdata * conn); @@ -151,14 +145,19 @@ static CURLcode wc_statemach(struct connectdata *conn); static void wc_data_dtor(void *ptr); -static CURLcode ftp_state_post_retr_size(struct connectdata *conn, - curl_off_t filesize); +static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize); + +static CURLcode ftp_readresp(curl_socket_t sockfd, + struct pingpong *pp, + int *ftpcode, + size_t *size); +static CURLcode ftp_dophase_done(struct connectdata *conn, + bool connected); /* easy-to-use macro: */ -#define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \ - return result -#define PPSENDF(x,y,z) if((result = Curl_pp_sendf(x,y,z)) != CURLE_OK) \ - return result +#define PPSENDF(x,y,z) result = Curl_pp_sendf(x,y,z); \ + if(result) \ + return result /* @@ -170,16 +169,20 @@ const struct Curl_handler Curl_handler_ftp = { ftp_setup_connection, /* setup_connection */ ftp_do, /* do_it */ ftp_done, /* done */ - ftp_nextconnect, /* do_more */ + ftp_do_more, /* do_more */ ftp_connect, /* connect_it */ ftp_multi_statemach, /* connecting */ ftp_doing, /* doing */ ftp_getsock, /* proto_getsock */ ftp_getsock, /* doing_getsock */ + ftp_domore_getsock, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ftp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_FTP, /* defport */ - PROT_FTP /* protocol */ + CURLPROTO_FTP, /* protocol */ + PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD + | PROTOPT_NOURLQUERY /* flags */ }; @@ -193,16 +196,20 @@ const struct Curl_handler Curl_handler_ftps = { ftp_setup_connection, /* setup_connection */ ftp_do, /* do_it */ ftp_done, /* done */ - ftp_nextconnect, /* do_more */ + ftp_do_more, /* do_more */ ftp_connect, /* connect_it */ ftp_multi_statemach, /* connecting */ ftp_doing, /* doing */ ftp_getsock, /* proto_getsock */ ftp_getsock, /* doing_getsock */ + ftp_domore_getsock, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ftp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_FTPS, /* defport */ - PROT_FTP | PROT_FTPS | PROT_SSL /* protocol */ + CURLPROTO_FTPS, /* protocol */ + PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION | + PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */ }; #endif @@ -213,7 +220,7 @@ const struct Curl_handler Curl_handler_ftps = { static const struct Curl_handler Curl_handler_ftp_proxy = { "FTP", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -222,10 +229,13 @@ static const struct Curl_handler Curl_handler_ftp_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_FTP, /* defport */ - PROT_HTTP /* protocol */ + CURLPROTO_HTTP, /* protocol */ + PROTOPT_NONE /* flags */ }; @@ -236,7 +246,7 @@ static const struct Curl_handler Curl_handler_ftp_proxy = { static const struct Curl_handler Curl_handler_ftps_proxy = { "FTPS", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -245,14 +255,26 @@ static const struct Curl_handler Curl_handler_ftps_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_FTPS, /* defport */ - PROT_HTTP /* protocol */ + CURLPROTO_HTTP, /* protocol */ + PROTOPT_NONE /* flags */ }; #endif #endif +static void close_secondarysocket(struct connectdata *conn) +{ + if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) { + Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); + conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; + } + conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; + conn->tunnel_state[SECONDARYSOCKET] = TUNNEL_INIT; +} /* * NOTE: back in the old days, we added code in the FTP code that made NOBODY @@ -270,20 +292,18 @@ static void freedirs(struct ftp_conn *ftpc) { int i; if(ftpc->dirs) { - for (i=0; i < ftpc->dirdepth; i++){ - if(ftpc->dirs[i]) { - free(ftpc->dirs[i]); - ftpc->dirs[i]=NULL; - } + for(i=0; i < ftpc->dirdepth; i++) { + free(ftpc->dirs[i]); + ftpc->dirs[i]=NULL; } free(ftpc->dirs); ftpc->dirs = NULL; ftpc->dirdepth = 0; } - if(ftpc->file) { - free(ftpc->file); - ftpc->file = NULL; - } + Curl_safefree(ftpc->file); + + /* no longer of any use */ + Curl_safefree(ftpc->newhost); } /* Returns non-zero if the given string contains CR (\r) or LF (\n), @@ -294,25 +314,22 @@ static void freedirs(struct ftp_conn *ftpc) */ static bool isBadFtpString(const char *string) { - return (bool)((NULL != strchr(string, '\r')) || - (NULL != strchr(string, '\n'))); + return ((NULL != strchr(string, '\r')) || + (NULL != strchr(string, '\n'))) ? TRUE : FALSE; } /*********************************************************************** * - * AllowServerConnect() + * AcceptServerConnect() * - * When we've issue the PORT command, we have told the server to connect - * to us. This function will sit and wait here until the server has - * connected. + * After connection request is received from the server this function is + * called to accept the connection and close the listening socket * */ -static CURLcode AllowServerConnect(struct connectdata *conn) +static CURLcode AcceptServerConnect(struct connectdata *conn) { struct SessionHandle *data = conn->data; curl_socket_t sock = conn->sock[SECONDARYSOCKET]; - long timeout_ms; - long interval_ms; curl_socket_t s = CURL_SOCKET_BAD; #ifdef ENABLE_IPV6 struct Curl_sockaddr_storage add; @@ -321,47 +338,257 @@ static CURLcode AllowServerConnect(struct connectdata *conn) #endif curl_socklen_t size = (curl_socklen_t) sizeof(add); - for(;;) { - timeout_ms = Curl_timeleft(conn, NULL, TRUE); + if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) { + size = sizeof(add); - if(timeout_ms < 0) { - /* if a timeout was already reached, bail out */ - failf(data, "Timeout while waiting for server connect"); - return CURLE_OPERATION_TIMEDOUT; + s=accept(sock, (struct sockaddr *) &add, &size); + } + Curl_closesocket(conn, sock); /* close the first socket */ + + if(CURL_SOCKET_BAD == s) { + failf(data, "Error accept()ing server connect"); + return CURLE_FTP_PORT_FAILED; + } + infof(data, "Connection accepted from server\n"); + /* when this happens within the DO state it is important that we mark us as + not needing DO_MORE anymore */ + conn->bits.do_more = FALSE; + + conn->sock[SECONDARYSOCKET] = s; + (void)curlx_nonblock(s, TRUE); /* enable non-blocking */ + conn->sock_accepted[SECONDARYSOCKET] = TRUE; + + if(data->set.fsockopt) { + int error = 0; + + /* activate callback for setting socket options */ + error = data->set.fsockopt(data->set.sockopt_client, + s, + CURLSOCKTYPE_ACCEPT); + + if(error) { + close_secondarysocket(conn); + return CURLE_ABORTED_BY_CALLBACK; + } + } + + return CURLE_OK; + +} + +/* + * ftp_timeleft_accept() returns the amount of milliseconds left allowed for + * waiting server to connect. If the value is negative, the timeout time has + * already elapsed. + * + * The start time is stored in progress.t_acceptdata - as set with + * Curl_pgrsTime(..., TIMER_STARTACCEPT); + * + */ +static long ftp_timeleft_accept(struct SessionHandle *data) +{ + long timeout_ms = DEFAULT_ACCEPT_TIMEOUT; + long other; + struct timeval now; + + if(data->set.accepttimeout > 0) + timeout_ms = data->set.accepttimeout; + + now = Curl_tvnow(); + + /* check if the generic timeout possibly is set shorter */ + other = Curl_timeleft(data, &now, FALSE); + if(other && (other < timeout_ms)) + /* note that this also works fine for when other happens to be negative + due to it already having elapsed */ + timeout_ms = other; + else { + /* subtract elapsed time */ + timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata); + if(!timeout_ms) + /* avoid returning 0 as that means no timeout! */ + return -1; + } + + return timeout_ms; +} + + +/*********************************************************************** + * + * ReceivedServerConnect() + * + * After allowing server to connect to us from data port, this function + * checks both data connection for connection establishment and ctrl + * connection for a negative response regarding a failure in connecting + * + */ +static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received) +{ + struct SessionHandle *data = conn->data; + curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET]; + curl_socket_t data_sock = conn->sock[SECONDARYSOCKET]; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + int result; + long timeout_ms; + ssize_t nread; + int ftpcode; + + *received = FALSE; + + timeout_ms = ftp_timeleft_accept(data); + infof(data, "Checking for server connect\n"); + if(timeout_ms < 0) { + /* if a timeout was already reached, bail out */ + failf(data, "Accept timeout occurred while waiting server connect"); + return CURLE_FTP_ACCEPT_TIMEOUT; + } + + /* First check whether there is a cached response from server */ + if(pp->cache_size && pp->cache && pp->cache[0] > '3') { + /* Data connection could not be established, let's return */ + infof(data, "There is negative response in cache while serv connect\n"); + Curl_GetFTPResponse(&nread, conn, &ftpcode); + return CURLE_FTP_ACCEPT_FAILED; + } + + result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0); + + /* see if the connection request is already here */ + switch (result) { + case -1: /* error */ + /* let's die here */ + failf(data, "Error while waiting for server connect"); + return CURLE_FTP_ACCEPT_FAILED; + case 0: /* Server connect is not received yet */ + break; /* loop */ + default: + + if(result & CURL_CSELECT_IN2) { + infof(data, "Ready to accept data connection from server\n"); + *received = TRUE; + } + else if(result & CURL_CSELECT_IN) { + infof(data, "Ctrl conn has data while waiting for data conn\n"); + Curl_GetFTPResponse(&nread, conn, &ftpcode); + + if(ftpcode/100 > 3) + return CURLE_FTP_ACCEPT_FAILED; + + return CURLE_FTP_WEIRD_SERVER_REPLY; } - interval_ms = 1000; /* use 1 second timeout intervals */ - if(timeout_ms < interval_ms) - interval_ms = timeout_ms; + break; + } /* switch() */ - switch (Curl_socket_ready(sock, CURL_SOCKET_BAD, (int)interval_ms)) { - case -1: /* error */ - /* let's die here */ - failf(data, "Error while waiting for server connect"); - return CURLE_FTP_PORT_FAILED; - case 0: /* timeout */ - break; /* loop */ - default: - /* we have received data here */ - if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) { - size = sizeof(add); + return CURLE_OK; +} - s=accept(sock, (struct sockaddr *) &add, &size); - } - sclose(sock); /* close the first socket */ - if(CURL_SOCKET_BAD == s) { - failf(data, "Error accept()ing server connect"); - return CURLE_FTP_PORT_FAILED; - } - infof(data, "Connection accepted from server\n"); +/*********************************************************************** + * + * InitiateTransfer() + * + * After connection from server is accepted this function is called to + * setup transfer parameters and initiate the data transfer. + * + */ +static CURLcode InitiateTransfer(struct connectdata *conn) +{ + struct SessionHandle *data = conn->data; + struct FTP *ftp = data->req.protop; + CURLcode result = CURLE_OK; - conn->sock[SECONDARYSOCKET] = s; - curlx_nonblock(s, TRUE); /* enable non-blocking */ - return CURLE_OK; - } /* switch() */ + if(conn->ssl[SECONDARYSOCKET].use) { + /* since we only have a plaintext TCP connection here, we must now + * do the TLS stuff */ + infof(data, "Doing the SSL/TLS handshake on the data stream\n"); + result = Curl_ssl_connect(conn, SECONDARYSOCKET); + if(result) + return result; } - /* never reaches this point */ + + if(conn->proto.ftpc.state_saved == FTP_STOR) { + *(ftp->bytecountp)=0; + + /* When we know we're uploading a specified file, we can get the file + size prior to the actual upload. */ + + Curl_pgrsSetUploadSize(data, data->state.infilesize); + + /* set the SO_SNDBUF for the secondary socket for those who need it */ + Curl_sndbufset(conn->sock[SECONDARYSOCKET]); + + Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */ + SECONDARYSOCKET, ftp->bytecountp); + } + else { + /* FTP download: */ + Curl_setup_transfer(conn, SECONDARYSOCKET, + conn->proto.ftpc.retr_size_saved, FALSE, + ftp->bytecountp, -1, NULL); /* no upload here */ + } + + conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */ + state(conn, FTP_STOP); + + return CURLE_OK; +} + +/*********************************************************************** + * + * AllowServerConnect() + * + * When we've issue the PORT command, we have told the server to connect to + * us. This function checks whether data connection is established if so it is + * accepted. + * + */ +static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected) +{ + struct SessionHandle *data = conn->data; + long timeout_ms; + CURLcode result = CURLE_OK; + + *connected = FALSE; + infof(data, "Preparing for accepting server on data port\n"); + + /* Save the time we start accepting server connect */ + Curl_pgrsTime(data, TIMER_STARTACCEPT); + + timeout_ms = ftp_timeleft_accept(data); + if(timeout_ms < 0) { + /* if a timeout was already reached, bail out */ + failf(data, "Accept timeout occurred while waiting server connect"); + return CURLE_FTP_ACCEPT_TIMEOUT; + } + + /* see if the connection request is already here */ + result = ReceivedServerConnect(conn, connected); + if(result) + return result; + + if(*connected) { + result = AcceptServerConnect(conn); + if(result) + return result; + + result = InitiateTransfer(conn); + if(result) + return result; + } + else { + /* Add timeout to multi handle and break out of the loop */ + if(!result && *connected == FALSE) { + if(data->set.accepttimeout > 0) + Curl_expire(data, data->set.accepttimeout); + else + Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT); + } + } + + return result; } /* macro to check for a three-digit ftp status code at the start of the @@ -372,17 +599,17 @@ static CURLcode AllowServerConnect(struct connectdata *conn) /* macro to check for the last line in an FTP server response */ #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3])) -static int ftp_endofresp(struct pingpong *pp, - int *code) +static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len, + int *code) { - char *line = pp->linestart_resp; - size_t len = pp->nread_resp; + (void)conn; if((len > 3) && LASTLINE(line)) { *code = curlx_sltosi(strtol(line, NULL, 10)); - return 1; + return TRUE; } - return 0; + + return FALSE; } static CURLcode ftp_readresp(curl_socket_t sockfd, @@ -391,8 +618,8 @@ static CURLcode ftp_readresp(curl_socket_t sockfd, size_t *size) /* size of the response */ { struct connectdata *conn = pp->conn; -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) struct SessionHandle *data = conn->data; +#ifdef HAVE_GSSAPI char * const buf = data->state.buffer; #endif CURLcode result = CURLE_OK; @@ -400,7 +627,7 @@ static CURLcode ftp_readresp(curl_socket_t sockfd, result = Curl_pp_readresp(sockfd, pp, &code, size); -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) +#if defined(HAVE_GSSAPI) /* handle the security-oriented responses 6xx ***/ /* FIXME: some errorchecking perhaps... ***/ switch(code) { @@ -420,16 +647,23 @@ static CURLcode ftp_readresp(curl_socket_t sockfd, #endif /* store the latest code for later retrieval */ - conn->data->info.httpcode=code; + data->info.httpcode=code; if(ftpcode) *ftpcode = code; - if(421 == code) + if(421 == code) { /* 421 means "Service not available, closing control connection." and FTP * servers use it to signal that idle session timeout has been exceeded. - * If we ignored the response, it could end up hanging in some cases. */ + * If we ignored the response, it could end up hanging in some cases. + * + * This response code can come at any point so having it treated + * generically is a good idea. + */ + infof(data, "We got a 421 - timeout!\n"); + state(conn, FTP_STOP); return CURLE_OPERATION_TIMEDOUT; + } return result; } @@ -508,7 +742,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ */ } else { - switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, (int)interval_ms)) { + switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, interval_ms)) { case -1: /* select() error, stop reading */ failf(data, "FTP response aborted due to select/poll error: %d", SOCKERRNO); @@ -545,63 +779,76 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ return result; } -/* This is the ONLY way to change FTP state! */ -static void state(struct connectdata *conn, - ftpstate newstate) -{ #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ - static const char * const names[]={ - "STOP", - "WAIT220", - "AUTH", - "USER", - "PASS", - "ACCT", - "PBSZ", - "PROT", - "CCC", - "PWD", - "SYST", - "NAMEFMT", - "QUOTE", - "RETR_PREQUOTE", - "STOR_PREQUOTE", - "POSTQUOTE", - "CWD", - "MKD", - "MDTM", - "TYPE", - "LIST_TYPE", - "RETR_TYPE", - "STOR_TYPE", - "SIZE", - "RETR_SIZE", - "STOR_SIZE", - "REST", - "RETR_REST", - "PORT", - "PRET", - "PASV", - "LIST", - "RETR", - "STOR", - "QUIT" - }; +static const char * const ftp_state_names[]={ + "STOP", + "WAIT220", + "AUTH", + "USER", + "PASS", + "ACCT", + "PBSZ", + "PROT", + "CCC", + "PWD", + "SYST", + "NAMEFMT", + "QUOTE", + "RETR_PREQUOTE", + "STOR_PREQUOTE", + "POSTQUOTE", + "CWD", + "MKD", + "MDTM", + "TYPE", + "LIST_TYPE", + "RETR_TYPE", + "STOR_TYPE", + "SIZE", + "RETR_SIZE", + "STOR_SIZE", + "REST", + "RETR_REST", + "PORT", + "PRET", + "PASV", + "LIST", + "RETR", + "STOR", + "QUIT" +}; #endif + +/* This is the ONLY way to change FTP state! */ +static void _state(struct connectdata *conn, + ftpstate newstate +#ifdef DEBUGBUILD + , int lineno +#endif + ) +{ struct ftp_conn *ftpc = &conn->proto.ftpc; -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + +#if defined(DEBUGBUILD) + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) lineno; +#else if(ftpc->state != newstate) - infof(conn->data, "FTP %p state change from %s to %s\n", - ftpc, names[ftpc->state], names[newstate]); + infof(conn->data, "FTP %p (line %d) state change from %s to %s\n", + (void *)ftpc, lineno, ftp_state_names[ftpc->state], + ftp_state_names[newstate]); #endif +#endif + ftpc->state = newstate; } static CURLcode ftp_state_user(struct connectdata *conn) { CURLcode result; - struct FTP *ftp = conn->data->state.proto.ftp; + struct FTP *ftp = conn->data->req.protop; /* send USER */ PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:""); @@ -616,7 +863,7 @@ static CURLcode ftp_state_pwd(struct connectdata *conn) CURLcode result; /* send PWD to discover our entry point */ - PPSENDF(&conn->proto.ftpc.pp, "PWD", NULL); + PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD"); state(conn, FTP_PWD); return CURLE_OK; @@ -630,6 +877,50 @@ static int ftp_getsock(struct connectdata *conn, return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks); } +/* For the FTP "DO_MORE" phase only */ +static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(!numsocks) + return GETSOCK_BLANK; + + /* When in DO_MORE state, we could be either waiting for us to connect to a + * remote site, or we could wait for that site to connect to us. Or just + * handle ordinary commands. + */ + + if(FTP_STOP == ftpc->state) { + int bits = GETSOCK_READSOCK(0); + + /* if stopped and still in this state, then we're also waiting for a + connect on the secondary connection */ + socks[0] = conn->sock[FIRSTSOCKET]; + + if(!conn->data->set.ftp_use_port) { + int s; + int i; + /* PORT is used to tell the server to connect to us, and during that we + don't do happy eyeballs, but we do if we connect to the server */ + for(s=1, i=0; i<2; i++) { + if(conn->tempsock[i] != CURL_SOCKET_BAD) { + socks[s] = conn->tempsock[i]; + bits |= GETSOCK_WRITESOCK(s++); + } + } + } + else { + socks[1] = conn->sock[SECONDARYSOCKET]; + bits |= GETSOCK_WRITESOCK(1); + } + + return bits; + } + else + return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks); +} + /* This is called after the FTP_QUOTE state is passed. ftp_state_cwd() sends the range of CWD commands to the server to change to @@ -643,7 +934,7 @@ static CURLcode ftp_state_cwd(struct connectdata *conn) if(ftpc->cwddone) /* already done and fine */ - result = ftp_state_post_cwd(conn); + result = ftp_state_mdtm(conn); else { ftpc->count2 = 0; /* count2 counts failed CWDs */ @@ -671,7 +962,7 @@ static CURLcode ftp_state_cwd(struct connectdata *conn) } else { /* No CWD necessary */ - result = ftp_state_post_cwd(conn); + result = ftp_state_mdtm(conn); } } } @@ -707,12 +998,13 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, static const char mode[][5] = { "EPRT", "PORT" }; int rc; int error; - char *host=NULL; + char *host = NULL; char *string_ftpport = data->set.str[STRING_FTPPORT]; struct Curl_dns_entry *h=NULL; unsigned short port_min = 0; unsigned short port_max = 0; unsigned short port; + bool possibly_non_local = TRUE; char *addr = NULL; @@ -737,7 +1029,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, char *port_sep = NULL; addr = calloc(addrlen+1, 1); - if (!addr) + if(!addr) return CURLE_OUT_OF_MEMORY; #ifdef ENABLE_IPV6 @@ -749,11 +1041,11 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, } else #endif - if( *string_ftpport == ':') { + if(*string_ftpport == ':') { /* :port */ ip_end = string_ftpport; } - else if( (ip_end = strchr(string_ftpport, ':')) != NULL) { + else if((ip_end = strchr(string_ftpport, ':')) != NULL) { /* either ipv6 or (ipv4|domain|interface):port(-range) */ #ifdef ENABLE_IPV6 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) { @@ -761,19 +1053,18 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, port_min = port_max = 0; strcpy(addr, string_ftpport); ip_end = NULL; /* this got no port ! */ - } else + } + else #endif - { /* (ipv4|domain|interface):port(-range) */ strncpy(addr, string_ftpport, ip_end - ip_start ); - } } else /* ipv4|interface */ strcpy(addr, string_ftpport); /* parse the port */ - if( ip_end != NULL ) { + if(ip_end != NULL) { if((port_start = strchr(ip_end, ':')) != NULL) { port_min = curlx_ultous(strtoul(port_start+1, NULL, 10)); if((port_sep = strchr(port_start, '-')) != NULL) { @@ -796,13 +1087,20 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(*addr != '\0') { /* attempt to get the address of the given interface name */ - if(!Curl_if2ip(conn->ip_addr->ai_family, addr, - hbuf, sizeof(hbuf))) - /* not an interface, use the given string as host name instead */ - host = addr; - else - host = hbuf; /* use the hbuf for host name */ - }else + switch(Curl_if2ip(conn->ip_addr->ai_family, + Curl_ipv6_scope(conn->ip_addr->ai_addr), + conn->scope_id, addr, hbuf, sizeof(hbuf))) { + case IF2IP_NOT_FOUND: + /* not an interface, use the given string as host name instead */ + host = addr; + break; + case IF2IP_AF_NOT_SUPPORTED: + return CURLE_FTP_PORT_FAILED; + case IF2IP_FOUND: + host = hbuf; /* use the hbuf for host name */ + } + } + else /* there was only a port(-range) given, default the host */ host = NULL; } /* data->set.ftpport */ @@ -815,28 +1113,27 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { failf(data, "getsockname() failed: %s", Curl_strerror(conn, SOCKERRNO) ); - if (addr) - free(addr); + free(addr); return CURLE_FTP_PORT_FAILED; } - switch(sa->sa_family) - { + switch(sa->sa_family) { #ifdef ENABLE_IPV6 - case AF_INET6: - Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf)); - break; + case AF_INET6: + Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf)); + break; #endif - default: - Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf)); - break; + default: + Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf)); + break; } host = hbuf; /* use this host name */ + possibly_non_local = FALSE; /* we know it is local now */ } /* resolv ip/host to ip */ rc = Curl_resolv(conn, host, 0, &h); if(rc == CURLRESOLV_PENDING) - (void)Curl_wait_for_resolv(conn, &h); + (void)Curl_resolver_wait_resolv(conn, &h); if(h) { res = h->addr; /* when we return from this function, we can forget about this entry @@ -846,27 +1143,22 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, else res = NULL; /* failure! */ - if (addr) + if(res == NULL) { + failf(data, "failed to resolve the address provided to PORT: %s", host); free(addr); - - if (res == NULL) { - failf(data, "Curl_resolv failed, we can not recover!"); return CURLE_FTP_PORT_FAILED; } + free(addr); + host = NULL; + /* step 2, create a socket for the requested address */ portsock = CURL_SOCKET_BAD; error = 0; - for (ai = res; ai; ai = ai->ai_next) { - /* - * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype): - */ - if(ai->ai_socktype == 0) - ai->ai_socktype = conn->socktype; - - portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if(portsock == CURL_SOCKET_BAD) { + for(ai = res; ai; ai = ai->ai_next) { + result = Curl_socket(conn, ai, NULL, &portsock); + if(result) { error = SOCKERRNO; continue; } @@ -882,8 +1174,8 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, memcpy(sa, ai->ai_addr, ai->ai_addrlen); sslen = ai->ai_addrlen; - for( port = port_min; port <= port_max; ) { - if( sa->sa_family == AF_INET ) + for(port = port_min; port <= port_max;) { + if(sa->sa_family == AF_INET) sa4->sin_port = htons(port); #ifdef ENABLE_IPV6 else @@ -893,28 +1185,29 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(bind(portsock, sa, sslen) ) { /* It failed. */ error = SOCKERRNO; - if(error == EADDRNOTAVAIL) { - + if(possibly_non_local && (error == EADDRNOTAVAIL)) { /* The requested bind address is not local. Use the address used for * the control connection instead and restart the port loop */ - failf(data, "bind(port=%hu) failed: %s", port, + + infof(data, "bind(port=%hu) on non-local address failed: %s\n", port, Curl_strerror(conn, error) ); sslen = sizeof(ss); if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { failf(data, "getsockname() failed: %s", Curl_strerror(conn, SOCKERRNO) ); - sclose(portsock); + Curl_closesocket(conn, portsock); return CURLE_FTP_PORT_FAILED; } port = port_min; + possibly_non_local = FALSE; /* don't try this again */ continue; } else if(error != EADDRINUSE && error != EACCES) { failf(data, "bind(port=%hu) failed: %s", port, Curl_strerror(conn, error) ); - sclose(portsock); + Curl_closesocket(conn, portsock); return CURLE_FTP_PORT_FAILED; } } @@ -925,9 +1218,9 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, } /* maybe all ports were in use already*/ - if (port > port_max) { + if(port > port_max) { failf(data, "bind() failed, we ran out of ports!"); - sclose(portsock); + Curl_closesocket(conn, portsock); return CURLE_FTP_PORT_FAILED; } @@ -937,7 +1230,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) { failf(data, "getsockname() failed: %s", Curl_strerror(conn, SOCKERRNO) ); - sclose(portsock); + Curl_closesocket(conn, portsock); return CURLE_FTP_PORT_FAILED; } @@ -945,7 +1238,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(listen(portsock, 1)) { failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO)); - sclose(portsock); + Curl_closesocket(conn, portsock); return CURLE_FTP_PORT_FAILED; } @@ -962,17 +1255,17 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, conn->bits.ftp_use_eprt = TRUE; #endif - for (; fcmd != DONE; fcmd++) { + for(; fcmd != DONE; fcmd++) { if(!conn->bits.ftp_use_eprt && (EPRT == fcmd)) /* if disabled, goto next */ continue; if((PORT == fcmd) && sa->sa_family != AF_INET) - /* PORT is ipv4 only */ + /* PORT is IPv4 only */ continue; - switch (sa->sa_family) { + switch(sa->sa_family) { case AF_INET: port = ntohs(sa4->sin_port); break; @@ -997,8 +1290,16 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd], sa->sa_family == AF_INET?1:2, myhost, port); - if(result) + if(result) { + failf(data, "Failure sending EPRT command: %s", + curl_easy_strerror(result)); + Curl_closesocket(conn, portsock); + /* don't retry using PORT */ + ftpc->count1 = PORT; + /* bail out */ + state(conn, FTP_STOP); return result; + } break; } else if(PORT == fcmd) { @@ -1018,8 +1319,14 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff)); result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp); - if(result) + if(result) { + failf(data, "Failure sending PORT command: %s", + curl_easy_strerror(result)); + Curl_closesocket(conn, portsock); + /* bail out */ + state(conn, FTP_STOP); return result; + } break; } } @@ -1027,11 +1334,11 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, /* store which command was sent */ ftpc->count1 = fcmd; + close_secondarysocket(conn); + /* we set the secondary socket variable to this for now, it is only so that the cleanup function will close it in case we fail before the true secondary stuff is made */ - if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) - sclose(conn->sock[SECONDARYSOCKET]); conn->sock[SECONDARYSOCKET] = portsock; /* this tcpconnect assignment below is a hackish work-around to make the @@ -1041,7 +1348,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, The *proper* fix is to make sure that the active connection from the server is done in a non-blocking way. Currently, it is still BLOCKING. */ - conn->bits.tcpconnect = TRUE; + conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE; state(conn, FTP_PORT); return result; @@ -1086,13 +1393,17 @@ static CURLcode ftp_state_use_pasv(struct connectdata *conn) return result; } -/* REST is the last command in the chain of commands when a "head"-like - request is made. Thus, if an actual transfer is to be made this is where - we take off for real. */ -static CURLcode ftp_state_post_rest(struct connectdata *conn) +/* + * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc. + * + * REST is the last command in the chain of commands when a "head"-like + * request is made. Thus, if an actual transfer is to be made this is where we + * take off for real. + */ +static CURLcode ftp_state_prepare_transfer(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->state.proto.ftp; + struct FTP *ftp = conn->data->req.protop; struct SessionHandle *data = conn->data; if(ftp->transfer != FTPTRANSFER_BODY) { @@ -1132,10 +1443,10 @@ static CURLcode ftp_state_post_rest(struct connectdata *conn) return result; } -static CURLcode ftp_state_post_size(struct connectdata *conn) +static CURLcode ftp_state_rest(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->state.proto.ftp; + struct FTP *ftp = conn->data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) { @@ -1148,15 +1459,15 @@ static CURLcode ftp_state_post_size(struct connectdata *conn) state(conn, FTP_REST); } else - result = ftp_state_post_rest(conn); + result = ftp_state_prepare_transfer(conn); return result; } -static CURLcode ftp_state_post_type(struct connectdata *conn) +static CURLcode ftp_state_size(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->state.proto.ftp; + struct FTP *ftp = conn->data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) { @@ -1168,12 +1479,12 @@ static CURLcode ftp_state_post_type(struct connectdata *conn) state(conn, FTP_SIZE); } else - result = ftp_state_post_size(conn); + result = ftp_state_rest(conn); return result; } -static CURLcode ftp_state_post_listtype(struct connectdata *conn) +static CURLcode ftp_state_list(struct connectdata *conn) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; @@ -1192,13 +1503,13 @@ static CURLcode ftp_state_post_listtype(struct connectdata *conn) The other ftp_filemethods will CWD into dir/dir/ first and then just do LIST (in that case: nothing to do here) */ - char *cmd,*lstArg,*slashPos; + char *cmd, *lstArg, *slashPos; lstArg = NULL; if((data->set.ftp_filemethod == FTPFILE_NOCWD) && data->state.path && data->state.path[0] && - strchr(data->state.path,'/')) { + strchr(data->state.path, '/')) { lstArg = strdup(data->state.path); if(!lstArg) @@ -1208,7 +1519,7 @@ static CURLcode ftp_state_post_listtype(struct connectdata *conn) if(lstArg[strlen(lstArg) - 1] != '/') { /* chop off the file part if format is dir/dir/file */ - slashPos = strrchr(lstArg,'/'); + slashPos = strrchr(lstArg, '/'); if(slashPos) *(slashPos+1) = '\0'; } @@ -1222,24 +1533,24 @@ static CURLcode ftp_state_post_listtype(struct connectdata *conn) lstArg? lstArg: "" ); if(!cmd) { - if(lstArg) - free(lstArg); + free(lstArg); return CURLE_OUT_OF_MEMORY; } - PPSENDF(&conn->proto.ftpc.pp, "%s",cmd); - - if(lstArg) - free(lstArg); + result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd); + free(lstArg); free(cmd); + if(result) + return result; + state(conn, FTP_LIST); return result; } -static CURLcode ftp_state_post_retrtype(struct connectdata *conn) +static CURLcode ftp_state_retr_prequote(struct connectdata *conn) { CURLcode result = CURLE_OK; @@ -1250,7 +1561,7 @@ static CURLcode ftp_state_post_retrtype(struct connectdata *conn) return result; } -static CURLcode ftp_state_post_stortype(struct connectdata *conn) +static CURLcode ftp_state_stor_prequote(struct connectdata *conn) { CURLcode result = CURLE_OK; @@ -1261,10 +1572,10 @@ static CURLcode ftp_state_post_stortype(struct connectdata *conn) return result; } -static CURLcode ftp_state_post_mdtm(struct connectdata *conn) +static CURLcode ftp_state_type(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->state.proto.ftp; + struct FTP *ftp = conn->data->req.protop; struct SessionHandle *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; @@ -1287,14 +1598,14 @@ static CURLcode ftp_state_post_mdtm(struct connectdata *conn) return result; } else - result = ftp_state_post_type(conn); + result = ftp_state_size(conn); return result; } /* This is called after the CWD commands have been done in the beginning of the DO phase */ -static CURLcode ftp_state_post_cwd(struct connectdata *conn) +static CURLcode ftp_state_mdtm(struct connectdata *conn) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; @@ -1310,7 +1621,7 @@ static CURLcode ftp_state_post_cwd(struct connectdata *conn) state(conn, FTP_MDTM); } else - result = ftp_state_post_mdtm(conn); + result = ftp_state_type(conn); return result; } @@ -1321,7 +1632,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn, bool sizechecked) { CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->state.proto.ftp; + struct FTP *ftp = conn->data->req.protop; struct SessionHandle *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; int seekerr = CURL_SEEKFUNC_OK; @@ -1371,8 +1682,8 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn, BUFSIZE : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread = - conn->fread_func(data->state.buffer, 1, readthisamountnow, - conn->fread_in); + data->state.fread_func(data->state.buffer, 1, readthisamountnow, + data->state.in); passed += actuallyread; if((actuallyread == 0) || (actuallyread > readthisamountnow)) { @@ -1385,10 +1696,10 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn, } } /* now, decrease the size of the read */ - if(data->set.infilesize>0) { - data->set.infilesize -= data->state.resume_from; + if(data->state.infilesize>0) { + data->state.infilesize -= data->state.resume_from; - if(data->set.infilesize <= 0) { + if(data->state.infilesize <= 0) { infof(data, "File already completely uploaded\n"); /* no data to transfer */ @@ -1419,7 +1730,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn, { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct FTP *ftp = data->state.proto.ftp; + struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; bool quote=FALSE; struct curl_slist *item; @@ -1485,11 +1796,23 @@ static CURLcode ftp_state_quote(struct connectdata *conn, else { if(ftpc->known_filesize != -1) { Curl_pgrsSetDownloadSize(data, ftpc->known_filesize); - result = ftp_state_post_retr_size(conn, ftpc->known_filesize); + result = ftp_state_retr(conn, ftpc->known_filesize); } else { - PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); - state(conn, FTP_RETR_SIZE); + if(data->set.ignorecl) { + /* This code is to support download of growing files. It prevents + the state machine from requesting the file size from the + server. With an unknown file size the download continues until + the server terminates it, otherwise the client stops if the + received byte count exceeds the reported file size. Set option + CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/ + PPSENDF(&ftpc->pp, "RETR %s", ftpc->file); + state(conn, FTP_RETR); + } + else { + PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); + state(conn, FTP_RETR_SIZE); + } } } break; @@ -1504,25 +1827,139 @@ static CURLcode ftp_state_quote(struct connectdata *conn, return result; } +/* called from ftp_state_pasv_resp to switch to PASV in case of EPSV + problems */ +static CURLcode ftp_epsv_disable(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + if(conn->bits.ipv6) { + /* We can't disable EPSV when doing IPv6, so this is instead a fail */ + failf(conn->data, "Failed EPSV attempt, exiting\n"); + return CURLE_FTP_WEIRD_SERVER_REPLY; + } + + infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n"); + /* disable it for next transfer */ + conn->bits.ftp_use_epsv = FALSE; + conn->data->state.errorbuf = FALSE; /* allow error message to get + rewritten */ + PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV"); + conn->proto.ftpc.count1++; + /* remain in/go to the FTP_PASV state */ + state(conn, FTP_PASV); + return result; +} + +/* + * Perform the necessary magic that needs to be done once the TCP connection + * to the proxy has completed. + */ +static CURLcode proxy_magic(struct connectdata *conn, + char *newhost, unsigned short newport, + bool *magicdone) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + +#if defined(CURL_DISABLE_PROXY) + (void) newhost; + (void) newport; +#endif + + *magicdone = FALSE; + + switch(conn->proxytype) { + case CURLPROXY_SOCKS5: + case CURLPROXY_SOCKS5_HOSTNAME: + result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, + newport, SECONDARYSOCKET, conn); + *magicdone = TRUE; + break; + case CURLPROXY_SOCKS4: + result = Curl_SOCKS4(conn->proxyuser, newhost, newport, + SECONDARYSOCKET, conn, FALSE); + *magicdone = TRUE; + break; + case CURLPROXY_SOCKS4A: + result = Curl_SOCKS4(conn->proxyuser, newhost, newport, + SECONDARYSOCKET, conn, TRUE); + *magicdone = TRUE; + break; + case CURLPROXY_HTTP: + case CURLPROXY_HTTP_1_0: + /* do nothing here. handled later. */ + break; + default: + failf(data, "unknown proxytype option given"); + result = CURLE_COULDNT_CONNECT; + break; + } + + if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { + /* BLOCKING */ + /* We want "seamless" FTP operations through HTTP proxy tunnel */ + + /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the + * member conn->proto.http; we want FTP through HTTP and we have to + * change the member temporarily for connecting to the HTTP proxy. After + * Curl_proxyCONNECT we have to set back the member to the original + * struct FTP pointer + */ + struct HTTP http_proxy; + struct FTP *ftp_save = data->req.protop; + memset(&http_proxy, 0, sizeof(http_proxy)); + data->req.protop = &http_proxy; + + result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport, TRUE); + + data->req.protop = ftp_save; + + if(result) + return result; + + if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) { + /* the CONNECT procedure is not complete, the tunnel is not yet up */ + state(conn, FTP_STOP); /* this phase is completed */ + return result; + } + else + *magicdone = TRUE; + } + + return result; +} + +static char *control_address(struct connectdata *conn) +{ + /* Returns the control connection IP address. + If a proxy tunnel is used, returns the original host name instead, because + the effective control connection address is the proxy address, + not the ftp host. */ + if(conn->bits.tunnel_proxy || + conn->proxytype == CURLPROXY_SOCKS5 || + conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME || + conn->proxytype == CURLPROXY_SOCKS4 || + conn->proxytype == CURLPROXY_SOCKS4A) + return conn->host.name; + + return conn->ip_addr_str; +} + static CURLcode ftp_state_pasv_resp(struct connectdata *conn, int ftpcode) { struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result; struct SessionHandle *data=conn->data; - Curl_addrinfo *conninfo; struct Curl_dns_entry *addr=NULL; int rc; unsigned short connectport; /* the local port connect() should use! */ - unsigned short newport=0; /* remote port */ - bool connected; - - /* newhost must be able to hold a full IP-style address in ASCII, which - in the IPv6 case means 5*8-1 = 39 letters */ -#define NEWHOST_BUFSIZE 48 - char newhost[NEWHOST_BUFSIZE]; char *str=&data->state.buffer[4]; /* start on the first letter */ + /* if we come here again, make sure the former name is cleared */ + Curl_safefree(ftpc->newhost); + if((ftpc->count1 == 0) && (ftpcode == 229)) { /* positive EPSV response */ @@ -1531,12 +1968,12 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, unsigned int num; char separator[4]; ptr++; - if(5 == sscanf(ptr, "%c%c%c%u%c", - &separator[0], - &separator[1], - &separator[2], - &num, - &separator[3])) { + if(5 == sscanf(ptr, "%c%c%c%u%c", + &separator[0], + &separator[1], + &separator[2], + &num, + &separator[3])) { const char sep1 = separator[0]; int i; @@ -1548,20 +1985,15 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, break; } } + if(num > 0xffff) { + failf(data, "Illegal port number in EPSV reply"); + return CURLE_FTP_WEIRD_PASV_REPLY; + } if(ptr) { - newport = (unsigned short)(num & 0xffff); - - if(conn->bits.tunnel_proxy || - data->set.proxytype == CURLPROXY_SOCKS5 || - data->set.proxytype == CURLPROXY_SOCKS5_HOSTNAME || - data->set.proxytype == CURLPROXY_SOCKS4 || - data->set.proxytype == CURLPROXY_SOCKS4A) - /* proxy tunnel -> use other host info because ip_addr_str is the - proxy address not the ftp host */ - snprintf(newhost, sizeof(newhost), "%s", conn->host.name); - else - /* use the same IP we are already connected to */ - snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str); + ftpc->newport = (unsigned short)(num & 0xffff); + ftpc->newhost = strdup(control_address(conn)); + if(!ftpc->newhost) + return CURLE_OUT_OF_MEMORY; } } else @@ -1589,8 +2021,8 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, */ while(*str) { if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d", - &ip[0], &ip[1], &ip[2], &ip[3], - &port[0], &port[1])) + &ip[0], &ip[1], &ip[2], &ip[3], + &port[0], &port[1])) break; str++; } @@ -1602,57 +2034,41 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, /* we got OK from server */ if(data->set.ftp_skip_ip) { - /* told to ignore the remotely given IP but instead use the one we used + /* told to ignore the remotely given IP but instead use the host we used for the control connection */ - infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n", + infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n", ip[0], ip[1], ip[2], ip[3], - conn->ip_addr_str); - if(conn->bits.tunnel_proxy || - data->set.proxytype == CURLPROXY_SOCKS5 || - data->set.proxytype == CURLPROXY_SOCKS5_HOSTNAME || - data->set.proxytype == CURLPROXY_SOCKS4 || - data->set.proxytype == CURLPROXY_SOCKS4A) - /* proxy tunnel -> use other host info because ip_addr_str is the - proxy address not the ftp host */ - snprintf(newhost, sizeof(newhost), "%s", conn->host.name); - else - snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str); + conn->host.name); + ftpc->newhost = strdup(control_address(conn)); } else - snprintf(newhost, sizeof(newhost), - "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); - newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff); + ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + + if(!ftpc->newhost) + return CURLE_OUT_OF_MEMORY; + + ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff); } else if(ftpc->count1 == 0) { /* EPSV failed, move on to PASV */ - - /* disable it for next transfer */ - conn->bits.ftp_use_epsv = FALSE; - infof(data, "disabling EPSV usage\n"); - - PPSENDF(&ftpc->pp, "PASV", NULL); - ftpc->count1++; - /* remain in the FTP_PASV state */ - return result; + return ftp_epsv_disable(conn); } else { failf(data, "Bad PASV/EPSV response: %03d", ftpcode); return CURLE_FTP_WEIRD_PASV_REPLY; } - if(data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) { + if(conn->bits.proxy) { /* - * This is a tunnel through a http proxy and we need to connect to the - * proxy again here. - * - * We don't want to rely on a former host lookup that might've expired - * now, instead we remake the lookup here and now! + * This connection uses a proxy and we need to connect to the proxy again + * here. We don't want to rely on a former host lookup that might've + * expired now, instead we remake the lookup here and now! */ rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr); if(rc == CURLRESOLV_PENDING) /* BLOCKING, ignores the return code but 'addr' will be NULL in case of failure */ - (void)Curl_wait_for_resolv(conn, &addr); + (void)Curl_resolver_wait_resolv(conn, &addr); connectport = (unsigned short)conn->port; /* we connect to the proxy's port */ @@ -1665,109 +2081,43 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, } else { /* normal, direct, ftp connection */ - rc = Curl_resolv(conn, newhost, newport, &addr); + rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr); if(rc == CURLRESOLV_PENDING) /* BLOCKING */ - (void)Curl_wait_for_resolv(conn, &addr); + (void)Curl_resolver_wait_resolv(conn, &addr); - connectport = newport; /* we connect to the remote port */ + connectport = ftpc->newport; /* we connect to the remote port */ if(!addr) { - failf(data, "Can't resolve new host %s:%hu", newhost, connectport); + failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport); return CURLE_FTP_CANT_GET_HOST; } } - result = Curl_connecthost(conn, - addr, - &conn->sock[SECONDARYSOCKET], - &conninfo, - &connected); + conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; + result = Curl_connecthost(conn, addr); - Curl_resolv_unlock(data, addr); /* we're done using this address */ + if(result) { + Curl_resolv_unlock(data, addr); /* we're done using this address */ + if(ftpc->count1 == 0 && ftpcode == 229) + return ftp_epsv_disable(conn); - if(result && ftpc->count1 == 0 && ftpcode == 229) { - infof(data, "got positive EPSV response, but can't connect. " - "Disabling EPSV\n"); - /* disable it for next transfer */ - conn->bits.ftp_use_epsv = FALSE; - data->state.errorbuf = FALSE; /* allow error message to get rewritten */ - PPSENDF(&ftpc->pp, "PASV", NULL); - ftpc->count1++; - /* remain in the FTP_PASV state */ return result; - } + } - if(result) - return result; - - conn->bits.tcpconnect = connected; /* simply TRUE or FALSE */ /* * When this is used from the multi interface, this might've returned with * the 'connected' set to FALSE and thus we are now awaiting a non-blocking - * connect to connect and we should not be "hanging" here waiting. + * connect to connect. */ if(data->set.verbose) /* this just dumps information about this second connection */ - ftp_pasv_verbose(conn, conninfo, newhost, connectport); - - switch(data->set.proxytype) { -#ifndef CURL_DISABLE_PROXY - /* FIX: this MUST wait for a proper connect first if 'connected' is - * FALSE */ - case CURLPROXY_SOCKS5: - case CURLPROXY_SOCKS5_HOSTNAME: - result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, newport, - SECONDARYSOCKET, conn); - break; - case CURLPROXY_SOCKS4: - result = Curl_SOCKS4(conn->proxyuser, newhost, newport, - SECONDARYSOCKET, conn, FALSE); - break; - case CURLPROXY_SOCKS4A: - result = Curl_SOCKS4(conn->proxyuser, newhost, newport, - SECONDARYSOCKET, conn, TRUE); - break; -#endif /* CURL_DISABLE_PROXY */ - case CURLPROXY_HTTP: - case CURLPROXY_HTTP_1_0: - /* do nothing here. handled later. */ - break; - default: - failf(data, "unknown proxytype option given"); - result = CURLE_COULDNT_CONNECT; - break; - } -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY) - if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { - /* FIX: this MUST wait for a proper connect first if 'connected' is - * FALSE */ - - /* BLOCKING */ - /* We want "seamless" FTP operations through HTTP proxy tunnel */ - - /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member - * conn->proto.http; we want FTP through HTTP and we have to change the - * member temporarily for connecting to the HTTP proxy. After - * Curl_proxyCONNECT we have to set back the member to the original struct - * FTP pointer - */ - struct HTTP http_proxy; - struct FTP *ftp_save = data->state.proto.ftp; - memset(&http_proxy, 0, sizeof(http_proxy)); - data->state.proto.http = &http_proxy; - - result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport); - - data->state.proto.ftp = ftp_save; - - if(CURLE_OK != result) - return result; - } -#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */ + ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport); + Curl_resolv_unlock(data, addr); /* we're done using this address */ + conn->bits.do_more = TRUE; state(conn, FTP_STOP); /* this phase is completed */ return result; @@ -1781,7 +2131,9 @@ static CURLcode ftp_state_port_resp(struct connectdata *conn, ftpport fcmd = (ftpport)ftpc->count1; CURLcode result = CURLE_OK; - if(ftpcode != 200) { + /* The FTP spec tells a positive response should have code 200. + Be more permissive here to tolerate deviant servers. */ + if(ftpcode / 100 != 2) { /* the command failed */ if(EPRT == fcmd) { @@ -1801,6 +2153,7 @@ static CURLcode ftp_state_port_resp(struct connectdata *conn, else { infof(data, "Connect data stream actively\n"); state(conn, FTP_STOP); /* end of DO phase */ + result = ftp_dophase_done(conn, FALSE); } return result; @@ -1811,7 +2164,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, { CURLcode result = CURLE_OK; struct SessionHandle *data=conn->data; - struct FTP *ftp = data->state.proto.ftp; + struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; switch(ftpcode) { @@ -1841,14 +2194,14 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, ftpc->file && data->set.get_filetime && (data->info.filetime>=0) ) { - struct tm *tm; time_t filetime = (time_t)data->info.filetime; -#ifdef HAVE_GMTIME_R struct tm buffer; - tm = (struct tm *)gmtime_r(&filetime, &buffer); -#else - tm = gmtime(&filetime); -#endif + const struct tm *tm = &buffer; + + result = Curl_gmtime(filetime, &buffer); + if(result) + return result; + /* format: "Tue, 15 Nov 1994 12:45:26" */ snprintf(buf, BUFSIZE-1, "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", @@ -1905,7 +2258,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, } if(!result) - result = ftp_state_post_mdtm(conn); + result = ftp_state_type(conn); return result; } @@ -1929,23 +2282,23 @@ static CURLcode ftp_state_type_resp(struct connectdata *conn, ftpcode); if(instate == FTP_TYPE) - result = ftp_state_post_type(conn); + result = ftp_state_size(conn); else if(instate == FTP_LIST_TYPE) - result = ftp_state_post_listtype(conn); + result = ftp_state_list(conn); else if(instate == FTP_RETR_TYPE) - result = ftp_state_post_retrtype(conn); + result = ftp_state_retr_prequote(conn); else if(instate == FTP_STOR_TYPE) - result = ftp_state_post_stortype(conn); + result = ftp_state_stor_prequote(conn); return result; } -static CURLcode ftp_state_post_retr_size(struct connectdata *conn, +static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize) { CURLcode result = CURLE_OK; struct SessionHandle *data=conn->data; - struct FTP *ftp = data->state.proto.ftp; + struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; if(data->set.max_filesize && (filesize > data->set.max_filesize)) { @@ -1970,8 +2323,8 @@ static CURLcode ftp_state_post_retr_size(struct connectdata *conn, if(data->state.resume_from< 0) { /* We're supposed to download the last abs(from) bytes */ if(filesize < -data->state.resume_from) { - failf(data, "Offset (%" FORMAT_OFF_T - ") was beyond file size (%" FORMAT_OFF_T ")", + failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T + ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", data->state.resume_from, filesize); return CURLE_BAD_DOWNLOAD_RESUME; } @@ -1982,8 +2335,8 @@ static CURLcode ftp_state_post_retr_size(struct connectdata *conn, } else { if(filesize < data->state.resume_from) { - failf(data, "Offset (%" FORMAT_OFF_T - ") was beyond file size (%" FORMAT_OFF_T ")", + failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T + ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", data->state.resume_from, filesize); return CURLE_BAD_DOWNLOAD_RESUME; } @@ -2005,13 +2358,13 @@ static CURLcode ftp_state_post_retr_size(struct connectdata *conn, } /* Set resume file transfer offset */ - infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T - "\n", data->state.resume_from); + infof(data, "Instructs server to resume from offset %" + CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from); - PPSENDF(&ftpc->pp, "REST %" FORMAT_OFF_T, data->state.resume_from); + PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T, + data->state.resume_from); state(conn, FTP_RETR_REST); - } else { /* no resume */ @@ -2038,18 +2391,18 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn, #ifdef CURL_FTP_HTTPSTYLE_HEAD if(-1 != filesize) { snprintf(buf, sizeof(data->state.buffer), - "Content-Length: %" FORMAT_OFF_T "\r\n", filesize); + "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize); result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); if(result) return result; } #endif Curl_pgrsSetDownloadSize(data, filesize); - result = ftp_state_post_size(conn); + result = ftp_state_rest(conn); } else if(instate == FTP_RETR_SIZE) { Curl_pgrsSetDownloadSize(data, filesize); - result = ftp_state_post_retr_size(conn, filesize); + result = ftp_state_retr(conn, filesize); } else if(instate == FTP_STOR_SIZE) { data->state.resume_from = filesize; @@ -2077,7 +2430,7 @@ static CURLcode ftp_state_rest_resp(struct connectdata *conn, return result; } #endif - result = ftp_state_post_rest(conn); + result = ftp_state_prepare_transfer(conn); break; case FTP_RETR_REST: @@ -2096,53 +2449,40 @@ static CURLcode ftp_state_rest_resp(struct connectdata *conn, } static CURLcode ftp_state_stor_resp(struct connectdata *conn, - int ftpcode) + int ftpcode, ftpstate instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct FTP *ftp = data->state.proto.ftp; if(ftpcode>=400) { failf(data, "Failed FTP upload: %0d", ftpcode); + state(conn, FTP_STOP); /* oops, we never close the sockets! */ return CURLE_UPLOAD_FAILED; } - if(data->set.ftp_use_port) { - /* BLOCKING */ - /* PORT means we are now awaiting the server to connect to us. */ - result = AllowServerConnect(conn); - if( result ) - return result; - } + conn->proto.ftpc.state_saved = instate; - if(conn->ssl[SECONDARYSOCKET].use) { - /* since we only have a plaintext TCP connection here, we must now - do the TLS stuff */ - infof(data, "Doing the SSL/TLS handshake on the data stream\n"); - /* BLOCKING */ - result = Curl_ssl_connect(conn, SECONDARYSOCKET); + /* PORT means we are now awaiting the server to connect to us. */ + if(data->set.ftp_use_port) { + bool connected; + + state(conn, FTP_STOP); /* no longer in STOR state */ + + result = AllowServerConnect(conn, &connected); if(result) return result; + + if(!connected) { + struct ftp_conn *ftpc = &conn->proto.ftpc; + infof(data, "Data conn was not available immediately\n"); + ftpc->wait_data_conn = TRUE; + } + + return CURLE_OK; } - - *(ftp->bytecountp)=0; - - /* When we know we're uploading a specified file, we can get the file - size prior to the actual upload. */ - - Curl_pgrsSetUploadSize(data, data->set.infilesize); - - /* set the SO_SNDBUF for the secondary socket for those who need it */ - Curl_sndbufset(conn->sock[SECONDARYSOCKET]); - - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */ - SECONDARYSOCKET, ftp->bytecountp); - state(conn, FTP_STOP); - - conn->proto.ftpc.pp.pending_resp = TRUE; /* expect a server response */ - - return result; + else + return InitiateTransfer(conn); } /* for LIST and RETR responses */ @@ -2152,7 +2492,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn, { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct FTP *ftp = data->state.proto.ftp; + struct FTP *ftp = data->req.protop; char *buf = data->state.buffer; if((ftpcode == 150) || (ftpcode == 125)) { @@ -2160,7 +2500,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn, /* A; 150 Opening BINARY mode data connection for /etc/passwd (2241 - bytes). (ok, the file is being transfered) + bytes). (ok, the file is being transferred) B: 150 Opening ASCII mode data connection for /bin/ls @@ -2169,7 +2509,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn, 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes). D: - 150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes). + 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes) E: 125 Data connection already open; Transfer starting. */ @@ -2192,7 +2532,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn, /* * It seems directory listings either don't show the size or very * often uses size 0 anyway. ASCII transfers may very well turn out - * that the transfered amount of data is not the same as this line + * that the transferred amount of data is not the same as this line * tells, why using this number in those cases only confuses us. * * Example D above makes this parsing a little tricky */ @@ -2223,38 +2563,38 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn, else if(ftp->downloadsize > -1) size = ftp->downloadsize; - if(data->set.ftp_use_port) { - /* BLOCKING */ - result = AllowServerConnect(conn); - if( result ) - return result; - } - - if(conn->ssl[SECONDARYSOCKET].use) { - /* since we only have a plaintext TCP connection here, we must now - do the TLS stuff */ - infof(data, "Doing the SSL/TLS handshake on the data stream\n"); - result = Curl_ssl_connect(conn, SECONDARYSOCKET); - if(result) - return result; - } - if(size > data->req.maxdownload && data->req.maxdownload > 0) size = data->req.size = data->req.maxdownload; else if((instate != FTP_LIST) && (data->set.prefer_ascii)) size = -1; /* kludge for servers that understate ASCII mode file size */ - infof(data, "Maxdownload = %" FORMAT_OFF_T "\n", data->req.maxdownload); + infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n", + data->req.maxdownload); if(instate != FTP_LIST) - infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size); + infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n", + size); /* FTP download: */ - Curl_setup_transfer(conn, SECONDARYSOCKET, size, FALSE, - ftp->bytecountp, -1, NULL); /* no upload here */ + conn->proto.ftpc.state_saved = instate; + conn->proto.ftpc.retr_size_saved = size; - conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */ - state(conn, FTP_STOP); + if(data->set.ftp_use_port) { + bool connected; + + result = AllowServerConnect(conn, &connected); + if(result) + return result; + + if(!connected) { + struct ftp_conn *ftpc = &conn->proto.ftpc; + infof(data, "Data conn was not available immediately\n"); + state(conn, FTP_STOP); + ftpc->wait_data_conn = TRUE; + } + } + else + return InitiateTransfer(conn); } else { if((instate == FTP_LIST) && (ftpcode == 450)) { @@ -2278,19 +2618,6 @@ static CURLcode ftp_state_loggedin(struct connectdata *conn) { CURLcode result = CURLE_OK; -#ifdef HAVE_KRB4 - if(conn->data->set.krb) { - /* We may need to issue a KAUTH here to have access to the files - * do it if user supplied a password - */ - if(conn->passwd && *conn->passwd) { - /* BLOCKING */ - result = Curl_krb_kauth(conn); - if(result) - return result; - } - } -#endif if(conn->ssl[FIRSTSOCKET].use) { /* PBSZ = PROTECTION BUFFER SIZE. @@ -2322,7 +2649,7 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn, { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct FTP *ftp = data->state.proto.ftp; + struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; (void)instate; /* no use for this yet */ @@ -2402,7 +2729,6 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) if(pp->sendleft) return Curl_pp_flushsend(pp); - /* we read a piece of response */ result = ftp_readresp(sock, pp, &ftpcode, &nread); if(result) return result; @@ -2411,14 +2737,17 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) /* we have now received a full FTP server response */ switch(ftpc->state) { case FTP_WAIT220: - if(ftpcode != 220) { + if(ftpcode == 230) + /* 230 User logged in - already! */ + return ftp_state_user_resp(conn, ftpcode, ftpc->state); + else if(ftpcode != 220) { failf(data, "Got a %03d ftp-server response when 220 was expected", ftpcode); return CURLE_FTP_WEIRD_SERVER_REPLY; } /* We have received a 220 response fine, now we proceed. */ -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) +#ifdef HAVE_GSSAPI if(data->set.krb) { /* If not anonymous login, try a secure login. Note that this procedure is still BLOCKING. */ @@ -2428,14 +2757,14 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) set a valid level */ Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); - if(Curl_sec_login(conn) != CURLE_OK) + if(Curl_sec_login(conn)) infof(data, "Logging in with password in cleartext!\n"); else infof(data, "Authentication successful\n"); } #endif - if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) { + if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { /* We don't have a SSL/TLS connection yet, but FTPS is requested. Try a FTPS connection now */ @@ -2453,7 +2782,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) default: failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d", (int)data->set.ftpsslauth); - return CURLE_FAILED_INIT; /* we don't know what to do */ + return CURLE_UNKNOWN_OPTION; /* we don't know what to do */ } PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]); state(conn, FTP_AUTH); @@ -2479,8 +2808,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) if((ftpcode == 234) || (ftpcode == 334)) { /* Curl_ssl_connect is BLOCKING */ result = Curl_ssl_connect(conn, FIRSTSOCKET); - if(CURLE_OK == result) { - conn->protocol |= PROT_FTPS; + if(!result) { conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */ result = ftp_state_user(conn); } @@ -2492,7 +2820,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) /* remain in this same state */ } else { - if(data->set.ftp_ssl > CURLUSESSL_TRY) + if(data->set.use_ssl > CURLUSESSL_TRY) /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */ result = CURLE_USE_SSL_FAILED; else @@ -2515,7 +2843,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) case FTP_PBSZ: PPSENDF(&ftpc->pp, "PROT %c", - data->set.ftp_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); + data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); state(conn, FTP_PROT); break; @@ -2524,17 +2852,17 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) if(ftpcode/100 == 2) /* We have enabled SSL for the data connection! */ conn->ssl[SECONDARYSOCKET].use = - (bool)(data->set.ftp_ssl != CURLUSESSL_CONTROL); + (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE; /* FTP servers typically responds with 500 if they decide to reject our 'P' request */ - else if(data->set.ftp_ssl > CURLUSESSL_CONTROL) + else if(data->set.use_ssl > CURLUSESSL_CONTROL) /* we failed and bails out */ return CURLE_USE_SSL_FAILED; if(data->set.ftp_ccc) { /* CCC - Clear Command Channel */ - PPSENDF(&ftpc->pp, "CCC", NULL); + PPSENDF(&ftpc->pp, "%s", "CCC"); state(conn, FTP_CCC); } else { @@ -2572,17 +2900,23 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) return CURLE_OUT_OF_MEMORY; /* Reply format is like - 257"" and the RFC959 - says + 257[rubbish]"" and the + RFC959 says The directory name can contain any character; embedded double-quotes should be escaped by double-quotes (the "quote-doubling" convention). */ + + /* scan for the first double-quote for non-standard responses */ + while(ptr < &data->state.buffer[sizeof(data->state.buffer)] + && *ptr != '\n' && *ptr != '\0' && *ptr != '"') + ptr++; + if('\"' == *ptr) { /* it started good */ ptr++; - for (store = dir; *ptr;) { + for(store = dir; *ptr;) { if('\"' == *ptr) { if('\"' == ptr[1]) { /* "quote-doubling" */ @@ -2600,12 +2934,6 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) store++; ptr++; } - if(ftpc->entrypath) - free(ftpc->entrypath); - ftpc->entrypath =dir; /* remember this */ - infof(data, "Entry path is '%s'\n", ftpc->entrypath); - /* also save it where getinfo can access it: */ - data->state.most_recent_ftp_entrypath = ftpc->entrypath; /* If the path name does not look like an absolute path (i.e.: it does not start with a '/'), we probably need some server-dependent @@ -2619,11 +2947,27 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) if the path name looks strange to minimize overhead on other systems. */ - if(!ftpc->server_os && ftpc->entrypath[0] != '/') { - PPSENDF(&ftpc->pp, "SYST", NULL); + if(!ftpc->server_os && dir[0] != '/') { + + result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST"); + if(result) { + free(dir); + return result; + } + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'\n", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; state(conn, FTP_SYST); break; } + + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'\n", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; } else { /* couldn't get the path */ @@ -2648,24 +2992,33 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) /* Reply format is like 215 */ - while (*ptr == ' ') + while(*ptr == ' ') ptr++; - for (store = os; *ptr && *ptr != ' ';) + for(store = os; *ptr && *ptr != ' ';) *store++ = *ptr++; *store = '\0'; /* zero terminate */ - ftpc->server_os = os; /* Check for special servers here. */ - if(strequal(ftpc->server_os, "OS/400")) { + if(strequal(os, "OS/400")) { /* Force OS400 name format 1. */ - PPSENDF(&ftpc->pp, "SITE NAMEFMT 1", NULL); + result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1"); + if(result) { + free(os); + return result; + } + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; state(conn, FTP_NAMEFMT); break; } - else { - /* Nothing special for the target server. */ - } + else { + /* Nothing special for the target server. */ + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; + } } else { /* Cannot identify server OS. Continue anyway and cross fingers. */ @@ -2691,7 +3044,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) case FTP_RETR_PREQUOTE: case FTP_STOR_PREQUOTE: if((ftpcode >= 400) && !ftpc->count2) { - /* failure reponse code, and not allowed to fail */ + /* failure response code, and not allowed to fail */ failf(conn->data, "QUOT command failed with %03d", ftpcode); return CURLE_QUOTE_ERROR; } @@ -2727,7 +3080,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]); } else { - result = ftp_state_post_cwd(conn); + result = ftp_state_mdtm(conn); if(result) return result; } @@ -2769,7 +3122,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) case FTP_PRET: if(ftpcode != 200) { - /* there only is this one standard OK return code. */ + /* there only is this one standard OK return code. */ failf(data, "PRET command not accepted: %03d", ftpcode); return CURLE_FTP_PRET_FAILED; } @@ -2790,7 +3143,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) break; case FTP_STOR: - result = ftp_state_stor_resp(conn, ftpcode); + result = ftp_state_stor_resp(conn, ftpcode, ftpc->state); break; case FTP_QUIT: @@ -2811,24 +3164,24 @@ static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done) { struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result = Curl_pp_multi_statemach(&ftpc->pp); + CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE); /* Check for the state outside of the Curl_socket_ready() return code checks since at times we are in fact already in this state when this function gets called. */ - *done = (bool)(ftpc->state == FTP_STOP); + *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE; return result; } -static CURLcode ftp_easy_statemach(struct connectdata *conn) +static CURLcode ftp_block_statemach(struct connectdata *conn) { struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; CURLcode result = CURLE_OK; while(ftpc->state != FTP_STOP) { - result = Curl_pp_easy_statemach(pp); + result = Curl_pp_statemach(pp, TRUE); if(result) break; } @@ -2836,123 +3189,33 @@ static CURLcode ftp_easy_statemach(struct connectdata *conn) return result; } -/* - * Allocate and initialize the struct FTP for the current SessionHandle. If - * need be. - */ - -#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \ - defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__) - /* workaround icc 9.1 optimizer issue */ -#pragma optimize("", off) -#endif - -static CURLcode ftp_init(struct connectdata *conn) -{ - struct FTP *ftp; - - if(NULL == conn->data->state.proto.ftp) { - conn->data->state.proto.ftp = malloc(sizeof(struct FTP)); - if(NULL == conn->data->state.proto.ftp) - return CURLE_OUT_OF_MEMORY; - } - - ftp = conn->data->state.proto.ftp; - - /* get some initial data into the ftp struct */ - ftp->bytecountp = &conn->data->req.bytecount; - ftp->transfer = FTPTRANSFER_BODY; - ftp->downloadsize = 0; - - /* No need to duplicate user+password, the connectdata struct won't change - during a session, but we re-init them here since on subsequent inits - since the conn struct may have changed or been replaced. - */ - ftp->user = conn->user; - ftp->passwd = conn->passwd; - if(TRUE == isBadFtpString(ftp->user)) - return CURLE_URL_MALFORMAT; - if(TRUE == isBadFtpString(ftp->passwd)) - return CURLE_URL_MALFORMAT; - - conn->proto.ftpc.known_filesize = -1; /* unknown size for now */ - - return CURLE_OK; -} - -#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \ - defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__) - /* workaround icc 9.1 optimizer issue */ -#pragma optimize("", on) -#endif - /* * ftp_connect() should do everything that is to be considered a part of * the connection phase. * * The variable 'done' points to will be TRUE if the protocol-layer connect - * phase is done when this function returns, or FALSE is not. When called as - * a part of the easy interface, it will always be TRUE. + * phase is done when this function returns, or FALSE if not. + * */ static CURLcode ftp_connect(struct connectdata *conn, bool *done) /* see description above */ { CURLcode result; struct ftp_conn *ftpc = &conn->proto.ftpc; - struct SessionHandle *data=conn->data; struct pingpong *pp = &ftpc->pp; *done = FALSE; /* default to not done yet */ - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); - - result = ftp_init(conn); - if(CURLE_OK != result) - return result; - - /* We always support persistant connections on ftp */ - conn->bits.close = FALSE; + /* We always support persistent connections on ftp */ + connkeep(conn, "FTP default"); pp->response_time = RESP_TIMEOUT; /* set default response time-out */ pp->statemach_act = ftp_statemach_act; pp->endofresp = ftp_endofresp; pp->conn = conn; -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY) - if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { - /* for FTP over HTTP proxy */ - struct HTTP http_proxy; - struct FTP *ftp_save; - + if(conn->handler->flags & PROTOPT_SSL) { /* BLOCKING */ - /* We want "seamless" FTP operations through HTTP proxy tunnel */ - - /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member - * conn->proto.http; we want FTP through HTTP and we have to change the - * member temporarily for connecting to the HTTP proxy. After - * Curl_proxyCONNECT we have to set back the member to the original struct - * FTP pointer - */ - ftp_save = data->state.proto.ftp; - memset(&http_proxy, 0, sizeof(http_proxy)); - data->state.proto.http = &http_proxy; - - result = Curl_proxyCONNECT(conn, FIRSTSOCKET, - conn->host.name, conn->remote_port); - - data->state.proto.ftp = ftp_save; - - if(CURLE_OK != result) - return result; - } -#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */ - - if(conn->protocol & PROT_FTPS) { - /* BLOCKING */ - /* FTPS is simply ftp with SSL for the control channel */ - /* now, perform the SSL initialization for this socket */ result = Curl_ssl_connect(conn, FIRSTSOCKET); if(result) return result; @@ -2964,13 +3227,7 @@ static CURLcode ftp_connect(struct connectdata *conn, response */ state(conn, FTP_WAIT220); - if(data->state.used_interface == Curl_if_multi) - result = ftp_multi_statemach(conn, done); - else { - result = ftp_easy_statemach(conn); - if(!result) - *done = TRUE; - } + result = ftp_multi_statemach(conn, done); return result; } @@ -2988,12 +3245,12 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, bool premature) { struct SessionHandle *data = conn->data; - struct FTP *ftp = data->state.proto.ftp; + struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; ssize_t nread; int ftpcode; - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; bool was_ctl_valid = ftpc->ctl_valid; char *path; const char *path_to_use = data->state.path; @@ -3010,8 +3267,11 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, case CURLE_BAD_DOWNLOAD_RESUME: case CURLE_FTP_WEIRD_PASV_REPLY: case CURLE_FTP_PORT_FAILED: + case CURLE_FTP_ACCEPT_FAILED: + case CURLE_FTP_ACCEPT_TIMEOUT: case CURLE_FTP_COULDNT_SET_TYPE: case CURLE_FTP_COULDNT_RETR_FILE: + case CURLE_PARTIAL_FILE: case CURLE_UPLOAD_FAILED: case CURLE_REMOTE_ACCESS_DENIED: case CURLE_FILESIZE_EXCEEDED: @@ -3031,14 +3291,13 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, ftpc->ctl_valid = FALSE; ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the current path, as this connection is going */ - conn->bits.close = TRUE; /* marked for closure */ + connclose(conn, "FTP ended with bad error code"); result = status; /* use the already set error code */ break; } /* now store a copy of the directory we are in */ - if(ftpc->prevpath) - free(ftpc->prevpath); + free(ftpc->prevpath); if(data->set.wildcardmatch) { if(data->set.chunk_end && ftpc->file) { @@ -3051,8 +3310,12 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, path = curl_easy_unescape(data, path_to_use, 0, NULL); if(!path) { /* out of memory, but we can limp along anyway (and should try to - * since we're in the out of memory cleanup path) */ - ftpc->prevpath = NULL; /* no path */ + * since we may already be in the out of memory cleanup path) */ + if(!result) + result = CURLE_OUT_OF_MEMORY; + ftpc->ctl_valid = FALSE; /* mark control connection as bad */ + connclose(conn, "FTP: out of memory!"); /* mark for connection closure */ + ftpc->prevpath = NULL; /* no path remembering */ } else { size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */ @@ -3083,13 +3346,20 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, /* shut down the socket to inform the server we're done */ #ifdef _WIN32_WCE - shutdown(conn->sock[SECONDARYSOCKET],2); /* SD_BOTH */ + shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */ #endif if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) { - if(!result && ftpc->dont_check && data->req.maxdownload > 0) + if(!result && ftpc->dont_check && data->req.maxdownload > 0) { /* partial download completed */ - result = Curl_pp_sendf(pp, "ABOR"); + result = Curl_pp_sendf(pp, "%s", "ABOR"); + if(result) { + failf(data, "Failure sending ABOR command: %s", + curl_easy_strerror(result)); + ftpc->ctl_valid = FALSE; /* mark control connection as bad */ + connclose(conn, "ABOR command failed"); /* connection closure */ + } + } if(conn->ssl[SECONDARYSOCKET].use) { /* The secondary socket is using SSL so we must close down that part @@ -3099,10 +3369,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, /* Note that we keep "use" set to TRUE since that (next) connection is still requested to use SSL */ } - if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) { - sclose(conn->sock[SECONDARYSOCKET]); - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; - } + close_secondarysocket(conn); } if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid && @@ -3110,7 +3377,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, /* * Let's see what the server says about the transfer we just performed, * but lower the timeout as sometimes this connection has died while the - * data has been transfered. This happens when doing through NATs etc that + * data has been transferred. This happens when doing through NATs etc that * abandon old silent connections. */ long old_time = pp->response_time; @@ -3125,7 +3392,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) { failf(data, "control connection looks dead"); ftpc->ctl_valid = FALSE; /* mark control connection as bad */ - conn->bits.close = TRUE; /* mark for closure */ + connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */ } if(result) @@ -3135,7 +3402,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, /* we have just sent ABOR and there is no reliable way to check if it was * successful or not; we have to close the connection now */ infof(data, "partial download completed, closing connection\n"); - conn->bits.close = TRUE; /* mark for closure */ + connclose(conn, "Partial download with no ability to check"); return result; } @@ -3153,13 +3420,13 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, use checking further */ ; else if(data->set.upload) { - if((-1 != data->set.infilesize) && - (data->set.infilesize != *ftp->bytecountp) && + if((-1 != data->state.infilesize) && + (data->state.infilesize != *ftp->bytecountp) && !data->set.crlf && (ftp->transfer == FTPTRANSFER_BODY)) { - failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T - " out of %" FORMAT_OFF_T " bytes)", - *ftp->bytecountp, data->set.infilesize); + failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T + " out of %" CURL_FORMAT_CURL_OFF_T " bytes)", + *ftp->bytecountp, data->state.infilesize); result = CURLE_PARTIAL_FILE; } } @@ -3175,8 +3442,8 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, *ftp->bytecountp) && #endif /* CURL_DO_LINEEND_CONV */ (data->req.maxdownload != *ftp->bytecountp)) { - failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes", - *ftp->bytecountp); + failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T + " bytes", *ftp->bytecountp); result = CURLE_PARTIAL_FILE; } else if(!ftpc->dont_check && @@ -3234,7 +3501,7 @@ CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote) acceptfail = TRUE; } - FTPSENDF(conn, "%s", cmd); + PPSENDF(&conn->proto.ftpc.pp, "%s", cmd); pp->response = Curl_tvnow(); /* timeout relative now */ @@ -3341,26 +3608,27 @@ static CURLcode ftp_range(struct connectdata *conn) if((-1 == to) && (from>=0)) { /* X - */ data->state.resume_from = from; - DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n", - from)); + DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T + " to end of file\n", from)); } else if(from < 0) { /* -Y */ data->req.maxdownload = -from; data->state.resume_from = from; - DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n", - -from)); + DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T + " bytes\n", -from)); } else { /* X-Y */ data->req.maxdownload = (to-from)+1; /* include last byte */ data->state.resume_from = from; - DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T - " getting %" FORMAT_OFF_T " bytes\n", + DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T + " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n", from, data->req.maxdownload)); } - DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T - " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n", + DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T + " to %" CURL_FORMAT_CURL_OFF_T ", totally %" + CURL_FORMAT_CURL_OFF_T " bytes\n", from, to, data->req.maxdownload)); ftpc->dont_check = TRUE; /* dont check for successful transfer */ } @@ -3371,31 +3639,114 @@ static CURLcode ftp_range(struct connectdata *conn) /* - * ftp_nextconnect() + * ftp_do_more() * * This function shall be called when the second FTP (data) connection is * connected. + * + * 'complete' can return 0 for incomplete, 1 for done and -1 for go back + * (which basically is only for when PASV is being sent to retry a failed + * EPSV). */ -static CURLcode ftp_nextconnect(struct connectdata *conn) +static CURLcode ftp_do_more(struct connectdata *conn, int *completep) { struct SessionHandle *data=conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result = CURLE_OK; + bool connected = FALSE; + bool complete = FALSE; /* the ftp struct is inited in ftp_connect() */ - struct FTP *ftp = data->state.proto.ftp; + struct FTP *ftp = data->req.protop; - DEBUGF(infof(data, "DO-MORE phase starts\n")); + /* if the second connection isn't done yet, wait for it */ + if(!conn->bits.tcpconnect[SECONDARYSOCKET]) { + if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) { + /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port + aren't used so we blank their arguments. TODO: make this nicer */ + result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0, FALSE); + + return result; + } + + result = Curl_is_connected(conn, SECONDARYSOCKET, &connected); + + /* Ready to do more? */ + if(connected) { + DEBUGF(infof(data, "DO-MORE connected phase starts\n")); + if(conn->bits.proxy) { + infof(data, "Connection to proxy confirmed\n"); + result = proxy_magic(conn, ftpc->newhost, ftpc->newport, &connected); + } + } + else { + if(result && (ftpc->count1 == 0)) { + *completep = -1; /* go back to DOING please */ + /* this is a EPSV connect failing, try PASV instead */ + return ftp_epsv_disable(conn); + } + return result; + } + } + + if(ftpc->state) { + /* already in a state so skip the intial commands. + They are only done to kickstart the do_more state */ + result = ftp_multi_statemach(conn, &complete); + + *completep = (int)complete; + + /* if we got an error or if we don't wait for a data connection return + immediately */ + if(result || (ftpc->wait_data_conn != TRUE)) + return result; + + if(ftpc->wait_data_conn) + /* if we reach the end of the FTP state machine here, *complete will be + TRUE but so is ftpc->wait_data_conn, which says we need to wait for + the data connection and therefore we're not actually complete */ + *completep = 0; + } if(ftp->transfer <= FTPTRANSFER_INFO) { /* a transfer is about to take place, or if not a file name was given so we'll do a SIZE on it later and then we need the right TYPE first */ - if(data->set.upload) { + if(ftpc->wait_data_conn == TRUE) { + bool serv_conned; + + result = ReceivedServerConnect(conn, &serv_conned); + if(result) + return result; /* Failed to accept data connection */ + + if(serv_conned) { + /* It looks data connection is established */ + result = AcceptServerConnect(conn); + ftpc->wait_data_conn = FALSE; + if(!result) + result = InitiateTransfer(conn); + + if(result) + return result; + + *completep = 1; /* this state is now complete when the server has + connected back to us */ + } + } + else if(data->set.upload) { result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE); if(result) return result; + + result = ftp_multi_statemach(conn, &complete); + if(ftpc->wait_data_conn) + /* if we reach the end of the FTP state machine here, *complete will be + TRUE but so is ftpc->wait_data_conn, which says we need to wait for + the data connection and therefore we're not actually complete */ + *completep = 0; + else + *completep = (int)complete; } else { /* download */ @@ -3422,17 +3773,23 @@ static CURLcode ftp_nextconnect(struct connectdata *conn) if(result) return result; } + + result = ftp_multi_statemach(conn, &complete); + *completep = (int)complete; } - result = ftp_easy_statemach(conn); + return result; } - if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY)) + if(!result && (ftp->transfer != FTPTRANSFER_BODY)) /* no data to transfer. FIX: it feels like a kludge to have this here too! */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - /* end of transfer */ - DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result)); + if(!ftpc->wait_data_conn) { + /* no waiting for the data connection so this is now complete */ + *completep = 1; + DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result)); + } return result; } @@ -3459,11 +3816,10 @@ CURLcode ftp_perform(struct connectdata *conn, if(conn->data->set.opt_no_body) { /* requested no body means no transfer... */ - struct FTP *ftp = conn->data->state.proto.ftp; + struct FTP *ftp = conn->data->req.protop; ftp->transfer = FTPTRANSFER_INFO; } - *dophase_done = FALSE; /* not done yet */ /* start the first command in the DO phase */ @@ -3472,16 +3828,14 @@ CURLcode ftp_perform(struct connectdata *conn, return result; /* run the state-machine */ - if(conn->data->state.used_interface == Curl_if_multi) - result = ftp_multi_statemach(conn, dophase_done); - else { - result = ftp_easy_statemach(conn); - *dophase_done = TRUE; /* with the easy interface we are done here */ - } - *connected = conn->bits.tcpconnect; + result = ftp_multi_statemach(conn, dophase_done); + + *connected = conn->bits.tcpconnect[SECONDARYSOCKET]; + + infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected); if(*dophase_done) - DEBUGF(infof(conn->data, "DO phase is complete\n")); + DEBUGF(infof(conn->data, "DO phase is complete1\n")); return result; } @@ -3491,7 +3845,7 @@ static void wc_data_dtor(void *ptr) struct ftp_wc_tmpdata *tmp = ptr; if(tmp) Curl_ftp_parselist_data_free(&tmp->parser); - Curl_safefree(tmp); + free(tmp); } static CURLcode init_wc_data(struct connectdata *conn) @@ -3499,7 +3853,7 @@ static CURLcode init_wc_data(struct connectdata *conn) char *last_slash; char *path = conn->data->state.path; struct WildcardData *wildcard = &(conn->data->wildcard); - CURLcode ret = CURLE_OK; + CURLcode result = CURLE_OK; struct ftp_wc_tmpdata *ftp_tmp; last_slash = strrchr(conn->data->state.path, '/'); @@ -3507,12 +3861,12 @@ static CURLcode init_wc_data(struct connectdata *conn) last_slash++; if(last_slash[0] == '\0') { wildcard->state = CURLWC_CLEAN; - ret = ftp_parse_url_path(conn); - return ret; + result = ftp_parse_url_path(conn); + return result; } else { wildcard->pattern = strdup(last_slash); - if (!wildcard->pattern) + if(!wildcard->pattern) return CURLE_OUT_OF_MEMORY; last_slash[0] = '\0'; /* cut file from path */ } @@ -3520,14 +3874,14 @@ static CURLcode init_wc_data(struct connectdata *conn) else { /* there is only 'wildcard pattern' or nothing */ if(path[0]) { wildcard->pattern = strdup(path); - if (!wildcard->pattern) + if(!wildcard->pattern) return CURLE_OUT_OF_MEMORY; path[0] = '\0'; } else { /* only list */ wildcard->state = CURLWC_CLEAN; - ret = ftp_parse_url_path(conn); - return ret; + result = ftp_parse_url_path(conn); + return result; } } @@ -3535,14 +3889,16 @@ static CURLcode init_wc_data(struct connectdata *conn) resources for wildcard transfer */ /* allocate ftp protocol specific temporary wildcard data */ - ftp_tmp = malloc(sizeof(struct ftp_wc_tmpdata)); + ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata)); if(!ftp_tmp) { + Curl_safefree(wildcard->pattern); return CURLE_OUT_OF_MEMORY; } /* INITIALIZE parselist structure */ ftp_tmp->parser = Curl_ftp_parselist_data_alloc(); if(!ftp_tmp->parser) { + Curl_safefree(wildcard->pattern); free(ftp_tmp); return CURLE_OUT_OF_MEMORY; } @@ -3555,25 +3911,33 @@ static CURLcode init_wc_data(struct connectdata *conn) conn->data->set.ftp_filemethod = FTPFILE_MULTICWD; /* try to parse ftp url */ - ret = ftp_parse_url_path(conn); - if(ret) { - return ret; + result = ftp_parse_url_path(conn); + if(result) { + Curl_safefree(wildcard->pattern); + wildcard->tmp_dtor(wildcard->tmp); + wildcard->tmp_dtor = ZERO_NULL; + wildcard->tmp = NULL; + return result; + } + + wildcard->path = strdup(conn->data->state.path); + if(!wildcard->path) { + Curl_safefree(wildcard->pattern); + wildcard->tmp_dtor(wildcard->tmp); + wildcard->tmp_dtor = ZERO_NULL; + wildcard->tmp = NULL; + return CURLE_OUT_OF_MEMORY; } /* backup old write_function */ ftp_tmp->backup.write_function = conn->data->set.fwrite_func; - /* parsing write function (callback included directly from ftplistparser.c) */ + /* parsing write function */ conn->data->set.fwrite_func = Curl_ftp_parselist; /* backup old file descriptor */ ftp_tmp->backup.file_descriptor = conn->data->set.out; /* let the writefunc callback know what curl pointer is working with */ conn->data->set.out = conn; - wildcard->path = strdup(conn->data->state.path); - if(!wildcard->path) { - return CURLE_OUT_OF_MEMORY; - } - infof(conn->data, "Wildcard - Parsing started\n"); return CURLE_OK; } @@ -3582,16 +3946,16 @@ static CURLcode init_wc_data(struct connectdata *conn) static CURLcode wc_statemach(struct connectdata *conn) { struct WildcardData * const wildcard = &(conn->data->wildcard); - CURLcode ret = CURLE_OK; + CURLcode result = CURLE_OK; switch (wildcard->state) { case CURLWC_INIT: - ret = init_wc_data(conn); + result = init_wc_data(conn); if(wildcard->state == CURLWC_CLEAN) /* only listing! */ break; else - wildcard->state = ret ? CURLWC_ERROR : CURLWC_MATCHING; + wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING; break; case CURLWC_MATCHING: { @@ -3600,6 +3964,8 @@ static CURLcode wc_statemach(struct connectdata *conn) struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp; conn->data->set.fwrite_func = ftp_tmp->backup.write_function; conn->data->set.out = ftp_tmp->backup.file_descriptor; + ftp_tmp->backup.write_function = ZERO_NULL; + ftp_tmp->backup.file_descriptor = NULL; wildcard->state = CURLWC_DOWNLOADING; if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) { @@ -3619,20 +3985,14 @@ static CURLcode wc_statemach(struct connectdata *conn) /* filelist has at least one file, lets get first one */ struct ftp_conn *ftpc = &conn->proto.ftpc; struct curl_fileinfo *finfo = wildcard->filelist->head->ptr; - char *tmp_path = malloc(strlen(conn->data->state.path) + - strlen(finfo->filename) + 1); - if(!tmp_path) { - return CURLE_OUT_OF_MEMORY; - } - tmp_path[0] = 0; - /* make full path to matched file */ - strcat(tmp_path, wildcard->path); - strcat(tmp_path, finfo->filename); + char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); + if(!tmp_path) + return CURLE_OUT_OF_MEMORY; + /* switch default "state.pathbuffer" and tmp_path, good to see ftp_parse_url_path function to understand this trick */ - if(conn->data->state.pathbuffer) - free(conn->data->state.pathbuffer); + Curl_safefree(conn->data->state.pathbuffer); conn->data->state.pathbuffer = tmp_path; conn->data->state.path = tmp_path; @@ -3659,10 +4019,9 @@ static CURLcode wc_statemach(struct connectdata *conn) if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE) ftpc->known_filesize = finfo->size; - ret = ftp_parse_url_path(conn); - if(ret) { - return ret; - } + result = ftp_parse_url_path(conn); + if(result) + return result; /* we don't need the Curl_fileinfo of first file anymore */ Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL); @@ -3686,11 +4045,11 @@ static CURLcode wc_statemach(struct connectdata *conn) case CURLWC_CLEAN: { struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp; - ret = CURLE_OK; - if(ftp_tmp) { - ret = Curl_ftp_parselist_geterror(ftp_tmp->parser); - } - wildcard->state = ret ? CURLWC_ERROR : CURLWC_DONE; + result = CURLE_OK; + if(ftp_tmp) + result = Curl_ftp_parselist_geterror(ftp_tmp->parser); + + wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE; } break; case CURLWC_DONE: @@ -3698,7 +4057,7 @@ static CURLcode wc_statemach(struct connectdata *conn) break; } - return ret; + return result; } /*********************************************************************** @@ -3712,40 +4071,31 @@ static CURLcode wc_statemach(struct connectdata *conn) */ static CURLcode ftp_do(struct connectdata *conn, bool *done) { - CURLcode retcode = CURLE_OK; + CURLcode result = CURLE_OK; + struct ftp_conn *ftpc = &conn->proto.ftpc; *done = FALSE; /* default to false */ - - /* - Since connections can be re-used between SessionHandles, this might be a - connection already existing but on a fresh SessionHandle struct so we must - make sure we have a good 'struct FTP' to play with. For new connections, - the struct FTP is allocated and setup in the ftp_connect() function. - */ - Curl_reset_reqproto(conn); - retcode = ftp_init(conn); - if(retcode) - return retcode; + ftpc->wait_data_conn = FALSE; /* default to no such wait */ if(conn->data->set.wildcardmatch) { - retcode = wc_statemach(conn); + result = wc_statemach(conn); if(conn->data->wildcard.state == CURLWC_SKIP || conn->data->wildcard.state == CURLWC_DONE) { /* do not call ftp_regular_transfer */ return CURLE_OK; } - if(retcode) /* error, loop or skipping the file */ - return retcode; + if(result) /* error, loop or skipping the file */ + return result; } else { /* no wildcard FSM needed */ - retcode = ftp_parse_url_path(conn); - if(retcode) - return retcode; + result = ftp_parse_url_path(conn); + if(result) + return result; } - retcode = ftp_regular_transfer(conn, done); + result = ftp_regular_transfer(conn, done); - return retcode; + return result; } @@ -3757,41 +4107,38 @@ CURLcode Curl_ftpsendf(struct connectdata *conn, char s[SBUF_SIZE]; size_t write_len; char *sptr=s; - CURLcode res = CURLE_OK; -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) + CURLcode result = CURLE_OK; +#ifdef HAVE_GSSAPI enum protection_level data_sec = conn->data_prot; #endif va_list ap; va_start(ap, fmt); - vsnprintf(s, SBUF_SIZE-3, fmt, ap); + write_len = vsnprintf(s, SBUF_SIZE-3, fmt, ap); va_end(ap); - strcat(s, "\r\n"); /* append a trailing CRLF */ + strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */ + write_len +=2; bytes_written=0; - write_len = strlen(s); -#ifdef CURL_DOES_CONVERSIONS - res = Curl_convert_to_network(conn->data, s, write_len); + result = Curl_convert_to_network(conn->data, s, write_len); /* Curl_convert_to_network calls failf if unsuccessful */ - if(res != CURLE_OK) { - return(res); - } -#endif /* CURL_DOES_CONVERSIONS */ + if(result) + return result; for(;;) { -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) +#ifdef HAVE_GSSAPI conn->data_prot = PROT_CMD; #endif - res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, - &bytes_written); -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) + result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, + &bytes_written); +#ifdef HAVE_GSSAPI DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); conn->data_prot = data_sec; #endif - if(CURLE_OK != res) + if(result) break; if(conn->data->set.verbose) @@ -3806,7 +4153,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn, break; } - return res; + return result; } /*********************************************************************** @@ -3824,10 +4171,19 @@ static CURLcode ftp_quit(struct connectdata *conn) CURLcode result = CURLE_OK; if(conn->proto.ftpc.ctl_valid) { - PPSENDF(&conn->proto.ftpc.pp, "QUIT", NULL); + result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT"); + if(result) { + failf(conn->data, "Failure sending QUIT command: %s", + curl_easy_strerror(result)); + conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */ + connclose(conn, "QUIT command failed"); /* mark for connection closure */ + state(conn, FTP_STOP); + return result; + } + state(conn, FTP_QUIT); - result = ftp_easy_statemach(conn); + result = ftp_block_statemach(conn); } return result; @@ -3868,18 +4224,14 @@ static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection) } freedirs(ftpc); - if(ftpc->prevpath) { - free(ftpc->prevpath); - ftpc->prevpath = NULL; - } - if(ftpc->server_os) { - free(ftpc->server_os); - ftpc->server_os = NULL; - } + free(ftpc->prevpath); + ftpc->prevpath = NULL; + free(ftpc->server_os); + ftpc->server_os = NULL; Curl_pp_disconnect(pp); -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) +#ifdef HAVE_GSSAPI Curl_sec_end(conn); #endif @@ -3898,7 +4250,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) { struct SessionHandle *data = conn->data; /* the ftp struct is already inited in ftp_connect() */ - struct FTP *ftp = data->state.proto.ftp; + struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; const char *slash_pos; /* position of the first '/' char in curpos */ const char *path_to_use = data->state.path; @@ -3922,16 +4274,17 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) the first condition in the if() right here, is there just in case someone decides to set path to NULL one day */ - if(data->state.path && - data->state.path[0] && - (data->state.path[strlen(data->state.path) - 1] != '/') ) - filename = data->state.path; /* this is a full file path */ - /* + if(path_to_use[0] && + (path_to_use[strlen(path_to_use) - 1] != '/') ) + filename = path_to_use; /* this is a full file path */ + /* + else { ftpc->file is not used anywhere other than for operations on a file. In other words, never for directory operations. So we can safely leave filename as NULL here and use it as a argument in dir/file decisions. - */ + } + */ break; case FTPFILE_SINGLECWD: @@ -3943,12 +4296,17 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) } slash_pos=strrchr(cur_pos, '/'); if(slash_pos || !*cur_pos) { + size_t dirlen = slash_pos-cur_pos; + ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0])); if(!ftpc->dirs) return CURLE_OUT_OF_MEMORY; + if(!dirlen) + dirlen++; + ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/", - slash_pos?(int)(slash_pos-cur_pos):1, + slash_pos ? curlx_uztosi(dirlen) : 1, NULL); if(!ftpc->dirs[0]) { freedirs(ftpc); @@ -3985,9 +4343,9 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) /* seek out the next path component */ if(slash_pos-cur_pos) { /* we skip empty path components, like "x//y" since the FTP command - CWD requires a parameter and a non-existant parameter a) doesn't + CWD requires a parameter and a non-existent parameter a) doesn't work on many servers and b) has no effect on the others. */ - int len = (int)(slash_pos - cur_pos + absolute_dir); + int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir); ftpc->dirs[ftpc->dirdepth] = curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL); if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */ @@ -4003,20 +4361,29 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) } else { cur_pos = slash_pos + 1; /* jump to the rest of the string */ + if(!ftpc->dirdepth) { + /* path starts with a slash, add that as a directory */ + ftpc->dirs[ftpc->dirdepth] = strdup("/"); + if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */ + failf(data, "no memory"); + freedirs(ftpc); + return CURLE_OUT_OF_MEMORY; + } + } continue; } cur_pos = slash_pos + 1; /* jump to the rest of the string */ if(++ftpc->dirdepth >= ftpc->diralloc) { /* enlarge array */ - char *bigger; + char **bigger; ftpc->diralloc *= 2; /* double the size each time */ bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0])); if(!bigger) { freedirs(ftpc); return CURLE_OUT_OF_MEMORY; } - ftpc->dirs = (char **)bigger; + ftpc->dirs = bigger; } } } @@ -4058,8 +4425,8 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) return CURLE_OUT_OF_MEMORY; } - dlen -= ftpc->file?(int)strlen(ftpc->file):0; - if((dlen == (int)strlen(ftpc->prevpath)) && + dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0; + if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) && strnequal(path, ftpc->prevpath, dlen)) { infof(data, "Request has same path as previous transfer\n"); ftpc->cwddone = TRUE; @@ -4074,18 +4441,17 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) static CURLcode ftp_dophase_done(struct connectdata *conn, bool connected) { - CURLcode result = CURLE_OK; - struct FTP *ftp = conn->data->state.proto.ftp; + struct FTP *ftp = conn->data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; - if(connected) - result = ftp_nextconnect(conn); + if(connected) { + int completed; + CURLcode result = ftp_do_more(conn, &completed); - if(result && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) { - /* Failure detected, close the second socket if it was created already */ - sclose(conn->sock[SECONDARYSOCKET]); - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; - return result; + if(result) { + close_secondarysocket(conn); + return result; + } } if(ftp->transfer != FTPTRANSFER_BODY) @@ -4097,20 +4463,21 @@ static CURLcode ftp_dophase_done(struct connectdata *conn, ftpc->ctl_valid = TRUE; /* seems good */ - return result; + return CURLE_OK; } /* called from multi.c while DOing */ static CURLcode ftp_doing(struct connectdata *conn, - bool *dophase_done) + bool *dophase_done) { - CURLcode result; - result = ftp_multi_statemach(conn, dophase_done); + CURLcode result = ftp_multi_statemach(conn, dophase_done); - if(*dophase_done) { + if(result) + DEBUGF(infof(conn->data, "DO phase failed\n")); + else if(*dophase_done) { result = ftp_dophase_done(conn, FALSE /* not connected */); - DEBUGF(infof(conn->data, "DO phase is complete\n")); + DEBUGF(infof(conn->data, "DO phase is complete2\n")); } return result; } @@ -4139,8 +4506,8 @@ CURLcode ftp_regular_transfer(struct connectdata *conn, Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); - Curl_pgrsSetUploadSize(data, 0); - Curl_pgrsSetDownloadSize(data, 0); + Curl_pgrsSetUploadSize(data, -1); + Curl_pgrsSetDownloadSize(data, -1); ftpc->ctl_valid = TRUE; /* starts good */ @@ -4148,13 +4515,14 @@ CURLcode ftp_regular_transfer(struct connectdata *conn, &connected, /* have we connected after PASV/PORT */ dophase_done); /* all commands in the DO-phase done? */ - if(CURLE_OK == result) { + if(!result) { if(!*dophase_done) /* the DO phase has not completed yet */ return CURLE_OK; result = ftp_dophase_done(conn, connected); + if(result) return result; } @@ -4164,11 +4532,12 @@ CURLcode ftp_regular_transfer(struct connectdata *conn, return result; } -static CURLcode ftp_setup_connection(struct connectdata * conn) +static CURLcode ftp_setup_connection(struct connectdata *conn) { struct SessionHandle *data = conn->data; - char * type; + char *type; char command; + struct FTP *ftp; if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { /* Unless we have asked to tunnel ftp operations through the proxy, we @@ -4184,18 +4553,18 @@ static CURLcode ftp_setup_connection(struct connectdata * conn) return CURLE_UNSUPPORTED_PROTOCOL; #endif } - /* - * We explicitly mark this connection as persistent here as we're doing - * FTP over HTTP and thus we accidentally avoid setting this value - * otherwise. - */ - conn->bits.close = FALSE; + /* set it up as a HTTP connection instead */ + return conn->handler->setup_connection(conn); #else failf(data, "FTP over http proxy requires HTTP support built-in!"); return CURLE_UNSUPPORTED_PROTOCOL; #endif } + conn->data->req.protop = ftp = malloc(sizeof(struct FTP)); + if(NULL == ftp) + return CURLE_OUT_OF_MEMORY; + data->state.path++; /* don't include the initial slash */ data->state.slash_removed = TRUE; /* we've skipped the slash */ @@ -4228,6 +4597,24 @@ static CURLcode ftp_setup_connection(struct connectdata * conn) } } + /* get some initial data into the ftp struct */ + ftp->bytecountp = &conn->data->req.bytecount; + ftp->transfer = FTPTRANSFER_BODY; + ftp->downloadsize = 0; + + /* No need to duplicate user+password, the connectdata struct won't change + during a session, but we re-init them here since on subsequent inits + since the conn struct may have changed or been replaced. + */ + ftp->user = conn->user; + ftp->passwd = conn->passwd; + if(isBadFtpString(ftp->user)) + return CURLE_URL_MALFORMAT; + if(isBadFtpString(ftp->passwd)) + return CURLE_URL_MALFORMAT; + + conn->proto.ftpc.known_filesize = -1; /* unknown size for now */ + return CURLE_OK; } diff --git a/project/jni/curl/lib/ftp.h b/project/jni/curl/lib/ftp.h index d8ef34823..7495e3e07 100644 --- a/project/jni/curl/lib/ftp.h +++ b/project/jni/curl/lib/ftp.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -66,7 +66,7 @@ typedef enum { FTP_STOR_TYPE, /* set type when about to STOR a file */ FTP_SIZE, /* get the remote file's size for head-like request */ FTP_RETR_SIZE, /* get the remote file's size for RETR */ - FTP_STOR_SIZE, /* get the size for (resumed) STOR */ + FTP_STOR_SIZE, /* get the size for STOR */ FTP_REST, /* when used to check if the server supports it in head-like */ FTP_RETR_REST, /* when asking for "resume" in for RETR */ FTP_PORT, /* generic state for PORT, LPRT and EPRT, check count1 */ @@ -93,16 +93,10 @@ struct ftp_wc_tmpdata { typedef enum { FTPFILE_MULTICWD = 1, /* as defined by RFC1738 */ FTPFILE_NOCWD = 2, /* use SIZE / RETR / STOR on the full path */ - FTPFILE_SINGLECWD = 3 /* make one CWD, then SIZE / RETR / STOR on the file */ + FTPFILE_SINGLECWD = 3 /* make one CWD, then SIZE / RETR / STOR on the + file */ } curl_ftpfile; -typedef enum { - FTPTRANSFER_BODY, /* yes do transfer a body */ - FTPTRANSFER_INFO, /* do still go through to get info/headers */ - FTPTRANSFER_NONE, /* don't get anything and don't get info */ - FTPTRANSFER_LAST /* end of list marker, never used */ -} curl_ftptransfer; - /* This FTP struct is used in the SessionHandle. All FTP data that is connection-oriented must be in FTP_conn to properly deal with the fact that perhaps the SessionHandle is changed between the times the connection is @@ -114,7 +108,7 @@ struct FTP { /* transfer a file/body or not, done as a typedefed enum just to make debuggers display the full symbol and not just the numerical value */ - curl_ftptransfer transfer; + curl_pp_transfer transfer; curl_off_t downloadsize; }; @@ -138,6 +132,7 @@ struct ftp_conn { already has been done */ bool cwdfail; /* set TRUE if a CWD command fails, as then we must prevent caching the current directory */ + bool wait_data_conn; /* this is set TRUE if data connection is waited */ char *prevpath; /* conn->path from the previous transfer */ char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a and others (A/I or zero) */ @@ -145,9 +140,20 @@ struct ftp_conn { int count2; /* general purpose counter for the state machine */ int count3; /* general purpose counter for the state machine */ ftpstate state; /* always use ftp.c:state() to change state! */ + ftpstate state_saved; /* transfer type saved to be reloaded after + data connection is established */ + curl_off_t retr_size_saved; /* Size of retrieved file saved */ char * server_os; /* The target server operating system. */ curl_off_t known_filesize; /* file size is different from -1, if wildcard - LIST parsing was done and wc_statemach set it */ + LIST parsing was done and wc_statemach set + it */ + /* newhost is the (allocated) IP addr or host name to connect the data + connection to */ + char *newhost; /* this is the pair to connect the DATA... */ + unsigned short newport; /* connection to */ + }; +#define DEFAULT_ACCEPT_TIMEOUT 60000 /* milliseconds == one minute */ + #endif /* HEADER_CURL_FTP_H */ diff --git a/project/jni/curl/lib/ftplistparser.c b/project/jni/curl/lib/ftplistparser.c index c59ea7e16..abbf76e27 100644 --- a/project/jni/curl/lib/ftplistparser.c +++ b/project/jni/curl/lib/ftplistparser.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -23,36 +23,32 @@ /** * Now implemented: * - * 1) UNIX version 1 + * 1) Unix version 1 * drwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog - * 2) UNIX version 2 + * 2) Unix version 2 * drwxr-xr-x 1 user01 ftp 512 Jan 29 1997 prog - * 3) UNIX version 3 + * 3) Unix version 3 * drwxr-xr-x 1 1 1 512 Jan 29 23:32 prog - * 4) UNIX symlink + * 4) Unix symlink * lrwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog -> prog2000 * 5) DOS style * 01-29-97 11:32PM prog */ -#include "setup.h" +#include "curl_setup.h" -#include +#ifndef CURL_DISABLE_FTP -#include "ftplistparser.h" -#include "curl_fnmatch.h" +#include #include "urldata.h" -#include "ftp.h" #include "fileinfo.h" #include "llist.h" #include "strtoofft.h" #include "rawstr.h" #include "ftp.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "ftplistparser.h" +#include "curl_fnmatch.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -191,8 +187,7 @@ struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void) void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data) { - if(*pl_data) - free(*pl_data); + free(*pl_data); *pl_data = NULL; } @@ -280,26 +275,6 @@ static void PL_ERROR(struct connectdata *conn, CURLcode err) parser->error = err; } -static bool ftp_pl_gettime(struct ftp_parselist_data *parser, char *string) -{ - (void)parser; - (void)string; - /* TODO - * There could be possible parse timestamp from server. Leaving unimplemented - * for now. - * If you want implement this, please add CURLFINFOFLAG_KNOWN_TIME flag to - * parser->file_data->flags - * - * Ftp servers are giving usually these formats: - * Apr 11 1998 (unknown time.. set it to 00:00:00?) - * Apr 11 12:21 (unknown year -> set it to NOW() time?) - * 08-05-09 02:49PM (ms-dos format) - * 20100421092538 -> for MLST/MLSD response - */ - - return FALSE; -} - static CURLcode ftp_pl_insert_finfo(struct connectdata *conn, struct curl_fileinfo *finfo) { @@ -329,7 +304,8 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn, compare = Curl_fnmatch; /* filter pattern-corresponding filenames */ - if(compare(conn->data->set.fnmatch_data, wc->pattern, finfo->filename) == 0) { + if(compare(conn->data->set.fnmatch_data, wc->pattern, + finfo->filename) == 0) { /* discard symlink which is containing multiple " -> " */ if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target && (strstr(finfo->strings.target, " -> "))) { @@ -364,7 +340,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, struct ftp_parselist_data *parser = tmpdata->parser; struct curl_fileinfo *finfo; unsigned long i = 0; - CURLcode rc; + CURLcode result; if(parser->error) { /* error in previous call */ /* scenario: @@ -447,9 +423,13 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, else if(c == '\n') { finfo->b_data[parser->item_length - 1] = 0; if(strncmp("total ", finfo->b_data, 6) == 0) { - char *endptr = NULL; - /* here we can deal with directory size */ - curlx_strtoofft(finfo->b_data+6, &endptr, 10); + char *endptr = finfo->b_data+6; + /* here we can deal with directory size, pass the leading white + spaces and then the digits */ + while(ISSPACE(*endptr)) + endptr++; + while(ISDIGIT(*endptr)) + endptr++; if(*endptr != 0) { PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); return bufflen; @@ -644,7 +624,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, parser->state.UNIX.main = PL_UNIX_TIME; parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1; } - else if (!ISDIGIT(c)) { + else if(!ISDIGIT(c)) { PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); return bufflen; } @@ -715,9 +695,11 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, if(c == ' ') { finfo->b_data[parser->item_offset + parser->item_length -1] = 0; parser->offsets.time = parser->item_offset; - if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) { - parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME; - } + /* + if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) { + parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME; + } + */ if(finfo->filetype == CURLFILETYPE_SYMLINK) { parser->state.UNIX.main = PL_UNIX_SYMLINK; parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE; @@ -746,28 +728,27 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, case PL_UNIX_FILENAME_NAME: parser->item_length++; if(c == '\r') { - parser->item_length--; parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL; } else if(c == '\n') { finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; parser->offsets.filename = parser->item_offset; parser->state.UNIX.main = PL_UNIX_FILETYPE; - rc = ftp_pl_insert_finfo(conn, finfo); - if(rc) { - PL_ERROR(conn, rc); + result = ftp_pl_insert_finfo(conn, finfo); + if(result) { + PL_ERROR(conn, result); return bufflen; } } break; case PL_UNIX_FILENAME_WINDOWSEOL: if(c == '\n') { - finfo->b_data[parser->item_offset + parser->item_length] = 0; + finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; parser->offsets.filename = parser->item_offset; parser->state.UNIX.main = PL_UNIX_FILETYPE; - rc = ftp_pl_insert_finfo(conn, finfo); - if(rc) { - PL_ERROR(conn, rc); + result = ftp_pl_insert_finfo(conn, finfo); + if(result) { + PL_ERROR(conn, result); return bufflen; } } @@ -853,17 +834,16 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, } break; case PL_UNIX_SYMLINK_TARGET: - parser->item_length ++; + parser->item_length++; if(c == '\r') { - parser->item_length --; parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL; } else if(c == '\n') { finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; parser->offsets.symlink_target = parser->item_offset; - rc = ftp_pl_insert_finfo(conn, finfo); - if(rc) { - PL_ERROR(conn, rc); + result = ftp_pl_insert_finfo(conn, finfo); + if(result) { + PL_ERROR(conn, result); return bufflen; } parser->state.UNIX.main = PL_UNIX_FILETYPE; @@ -873,9 +853,9 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, if(c == '\n') { finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; parser->offsets.symlink_target = parser->item_offset; - rc = ftp_pl_insert_finfo(conn, finfo); - if(rc) { - PL_ERROR(conn, rc); + result = ftp_pl_insert_finfo(conn, finfo); + if(result) { + PL_ERROR(conn, result); return bufflen; } parser->state.UNIX.main = PL_UNIX_FILETYPE; @@ -959,7 +939,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, } else { char *endptr; - finfo->size = curlx_strtoofft(finfo->b_data + parser->item_offset, + finfo->size = curlx_strtoofft(finfo->b_data + + parser->item_offset, &endptr, 10); if(!*endptr) { if(finfo->size == CURL_OFF_T_MAX || @@ -1005,9 +986,9 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, parser->offsets.filename = parser->item_offset; finfo->b_data[finfo->b_used - 1] = 0; parser->offsets.filename = parser->item_offset; - rc = ftp_pl_insert_finfo(conn, finfo); - if(rc) { - PL_ERROR(conn, rc); + result = ftp_pl_insert_finfo(conn, finfo); + if(result) { + PL_ERROR(conn, result); return bufflen; } parser->state.NT.main = PL_WINNT_DATE; @@ -1017,9 +998,9 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, case PL_WINNT_FILENAME_WINEOL: if(c == '\n') { parser->offsets.filename = parser->item_offset; - rc = ftp_pl_insert_finfo(conn, finfo); - if(rc) { - PL_ERROR(conn, rc); + result = ftp_pl_insert_finfo(conn, finfo); + if(result) { + PL_ERROR(conn, result); return bufflen; } parser->state.NT.main = PL_WINNT_DATE; @@ -1035,7 +1016,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, } break; default: - return bufflen+1; + return bufflen + 1; } i++; @@ -1043,3 +1024,5 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, return bufflen; } + +#endif /* CURL_DISABLE_FTP */ diff --git a/project/jni/curl/lib/ftplistparser.h b/project/jni/curl/lib/ftplistparser.h index 67a06c296..8128887c0 100644 --- a/project/jni/curl/lib/ftplistparser.h +++ b/project/jni/curl/lib/ftplistparser.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,8 +21,9 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "curl_setup.h" -#include +#ifndef CURL_DISABLE_FTP /* WRITEFUNCTION callback for parsing LIST responses */ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, @@ -36,4 +37,5 @@ struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void); void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data); +#endif /* CURL_DISABLE_FTP */ #endif /* HEADER_CURL_FTPLISTPARSER_H */ diff --git a/project/jni/curl/lib/getenv.c b/project/jni/curl/lib/getenv.c index 36fbb7583..50bb79f53 100644 --- a/project/jni/curl/lib/getenv.c +++ b/project/jni/curl/lib/getenv.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,15 +20,7 @@ * ***************************************************************************/ -#include "setup.h" - -#include -#include -#include - -#ifdef __VMS -#include -#endif +#include "curl_setup.h" #include #include "curl_memory.h" @@ -46,14 +38,10 @@ char *GetEnv(const char *variable) char *temp = getenv(variable); env[0] = '\0'; if(temp != NULL) - ExpandEnvironmentStrings(temp, env, sizeof(env)); + ExpandEnvironmentStringsA(temp, env, sizeof(env)); return (env[0] != '\0')?strdup(env):NULL; #else char *env = getenv(variable); -#ifdef __VMS - if(env && strcmp("HOME",variable) == 0) - env = decc_translate_vms(env); -#endif return (env && env[0])?strdup(env):NULL; #endif #endif diff --git a/project/jni/curl/lib/getinfo.c b/project/jni/curl/lib/getinfo.c index 946686281..39189cb60 100644 --- a/project/jni/curl/lib/getinfo.c +++ b/project/jni/curl/lib/getinfo.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,23 +20,19 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #include #include "urldata.h" #include "getinfo.h" -#include -#include -#include -#include -#include "curl_memory.h" -#include "sslgen.h" +#include "vtls/vtls.h" #include "connect.h" /* Curl_getconnectinfo() */ #include "progress.h" -/* Make this the last #include */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* @@ -46,21 +42,23 @@ CURLcode Curl_initinfo(struct SessionHandle *data) { struct Progress *pro = &data->progress; - struct PureInfo *info =&data->info; + struct PureInfo *info = &data->info; pro->t_nslookup = 0; pro->t_connect = 0; + pro->t_appconnect = 0; pro->t_pretransfer = 0; pro->t_starttransfer = 0; pro->timespent = 0; pro->t_redirect = 0; info->httpcode = 0; - info->httpversion=0; - info->filetime=-1; /* -1 is an illegal time and thus means unknown */ + info->httpproxycode = 0; + info->httpversion = 0; + info->filetime = -1; /* -1 is an illegal time and thus means unknown */ + info->timecond = FALSE; - if(info->contenttype) - free(info->contenttype); + free(info->contenttype); info->contenttype = NULL; info->header_size = 0; @@ -75,56 +73,63 @@ CURLcode Curl_initinfo(struct SessionHandle *data) return CURLE_OK; } -CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) +static CURLcode getinfo_char(struct SessionHandle *data, CURLINFO info, + char **param_charp) { - va_list arg; - long *param_longp=NULL; - double *param_doublep=NULL; - char **param_charp=NULL; - struct curl_slist **param_slistp=NULL; - int type; - curl_socket_t sockfd; - - union { - struct curl_certinfo * to_certinfo; - struct curl_slist * to_slist; - } ptr; - - if(!data) - return CURLE_BAD_FUNCTION_ARGUMENT; - - va_start(arg, info); - - type = CURLINFO_TYPEMASK & (int)info; - switch(type) { - case CURLINFO_STRING: - param_charp = va_arg(arg, char **); - if(NULL == param_charp) - return CURLE_BAD_FUNCTION_ARGUMENT; - break; - case CURLINFO_LONG: - param_longp = va_arg(arg, long *); - if(NULL == param_longp) - return CURLE_BAD_FUNCTION_ARGUMENT; - break; - case CURLINFO_DOUBLE: - param_doublep = va_arg(arg, double *); - if(NULL == param_doublep) - return CURLE_BAD_FUNCTION_ARGUMENT; - break; - case CURLINFO_SLIST: - param_slistp = va_arg(arg, struct curl_slist **); - if(NULL == param_slistp) - return CURLE_BAD_FUNCTION_ARGUMENT; - break; - default: - return CURLE_BAD_FUNCTION_ARGUMENT; - } - switch(info) { case CURLINFO_EFFECTIVE_URL: *param_charp = data->change.url?data->change.url:(char *)""; break; + case CURLINFO_CONTENT_TYPE: + *param_charp = data->info.contenttype; + break; + case CURLINFO_PRIVATE: + *param_charp = (char *) data->set.private_data; + break; + case CURLINFO_FTP_ENTRY_PATH: + /* Return the entrypath string from the most recent connection. + This pointer was copied from the connectdata structure by FTP. + The actual string may be free()ed by subsequent libcurl calls so + it must be copied to a safer area before the next libcurl call. + Callers must never free it themselves. */ + *param_charp = data->state.most_recent_ftp_entrypath; + break; + case CURLINFO_REDIRECT_URL: + /* Return the URL this request would have been redirected to if that + option had been enabled! */ + *param_charp = data->info.wouldredirect; + break; + case CURLINFO_PRIMARY_IP: + /* Return the ip address of the most recent (primary) connection */ + *param_charp = data->info.conn_primary_ip; + break; + case CURLINFO_LOCAL_IP: + /* Return the source/local ip address of the most recent (primary) + connection */ + *param_charp = data->info.conn_local_ip; + break; + case CURLINFO_RTSP_SESSION_ID: + *param_charp = data->set.str[STRING_RTSP_SESSION_ID]; + break; + + default: + return CURLE_UNKNOWN_OPTION; + } + + return CURLE_OK; +} + +static CURLcode getinfo_long(struct SessionHandle *data, CURLINFO info, + long *param_longp) +{ + curl_socket_t sockfd; + + union { + unsigned long *to_ulong; + long *to_long; + } lptr; + + switch(info) { case CURLINFO_RESPONSE_CODE: *param_longp = data->info.httpcode; break; @@ -140,6 +145,71 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) case CURLINFO_REQUEST_SIZE: *param_longp = data->info.request_size; break; + case CURLINFO_SSL_VERIFYRESULT: + *param_longp = data->set.ssl.certverifyresult; + break; + case CURLINFO_REDIRECT_COUNT: + *param_longp = data->set.followlocation; + break; + case CURLINFO_HTTPAUTH_AVAIL: + lptr.to_long = param_longp; + *lptr.to_ulong = data->info.httpauthavail; + break; + case CURLINFO_PROXYAUTH_AVAIL: + lptr.to_long = param_longp; + *lptr.to_ulong = data->info.proxyauthavail; + break; + case CURLINFO_OS_ERRNO: + *param_longp = data->state.os_errno; + break; + case CURLINFO_NUM_CONNECTS: + *param_longp = data->info.numconnects; + break; + case CURLINFO_LASTSOCKET: + sockfd = Curl_getconnectinfo(data, NULL); + + /* note: this is not a good conversion for systems with 64 bit sockets and + 32 bit longs */ + if(sockfd != CURL_SOCKET_BAD) + *param_longp = (long)sockfd; + else + /* this interface is documented to return -1 in case of badness, which + may not be the same as the CURL_SOCKET_BAD value */ + *param_longp = -1; + break; + case CURLINFO_PRIMARY_PORT: + /* Return the (remote) port of the most recent (primary) connection */ + *param_longp = data->info.conn_primary_port; + break; + case CURLINFO_LOCAL_PORT: + /* Return the local port of the most recent (primary) connection */ + *param_longp = data->info.conn_local_port; + break; + case CURLINFO_CONDITION_UNMET: + /* return if the condition prevented the document to get transferred */ + *param_longp = data->info.timecond ? 1L : 0L; + break; + case CURLINFO_RTSP_CLIENT_CSEQ: + *param_longp = data->state.rtsp_next_client_CSeq; + break; + case CURLINFO_RTSP_SERVER_CSEQ: + *param_longp = data->state.rtsp_next_server_CSeq; + break; + case CURLINFO_RTSP_CSEQ_RECV: + *param_longp = data->state.rtsp_CSeq_recv; + break; + + default: + return CURLE_UNKNOWN_OPTION; + } + + return CURLE_OK; +} + +static CURLcode getinfo_double(struct SessionHandle *data, CURLINFO info, + double *param_doublep) +{ + switch(info) { case CURLINFO_TOTAL_TIME: *param_doublep = data->progress.timespent; break; @@ -170,9 +240,6 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) case CURLINFO_SPEED_UPLOAD: *param_doublep = (double)data->progress.ulspeed; break; - case CURLINFO_SSL_VERIFYRESULT: - *param_longp = data->set.ssl.certverifyresult; - break; case CURLINFO_CONTENT_LENGTH_DOWNLOAD: *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)? (double)data->progress.size_dl:-1; @@ -184,100 +251,152 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) case CURLINFO_REDIRECT_TIME: *param_doublep = data->progress.t_redirect; break; - case CURLINFO_REDIRECT_COUNT: - *param_longp = data->set.followlocation; - break; - case CURLINFO_CONTENT_TYPE: - *param_charp = data->info.contenttype; - break; - case CURLINFO_PRIVATE: - *param_charp = (char *) data->set.private_data; - break; - case CURLINFO_HTTPAUTH_AVAIL: - *param_longp = data->info.httpauthavail; - break; - case CURLINFO_PROXYAUTH_AVAIL: - *param_longp = data->info.proxyauthavail; - break; - case CURLINFO_OS_ERRNO: - *param_longp = data->state.os_errno; - break; - case CURLINFO_NUM_CONNECTS: - *param_longp = data->info.numconnects; - break; + + default: + return CURLE_UNKNOWN_OPTION; + } + + return CURLE_OK; +} + +static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info, + struct curl_slist **param_slistp) +{ + union { + struct curl_certinfo *to_certinfo; + struct curl_slist *to_slist; + } ptr; + + switch(info) { case CURLINFO_SSL_ENGINES: *param_slistp = Curl_ssl_engines_list(data); break; case CURLINFO_COOKIELIST: *param_slistp = Curl_cookie_list(data); break; - case CURLINFO_FTP_ENTRY_PATH: - /* Return the entrypath string from the most recent connection. - This pointer was copied from the connectdata structure by FTP. - The actual string may be free()ed by subsequent libcurl calls so - it must be copied to a safer area before the next libcurl call. - Callers must never free it themselves. */ - *param_charp = data->state.most_recent_ftp_entrypath; - break; - case CURLINFO_LASTSOCKET: - sockfd = Curl_getconnectinfo(data, NULL); - - /* note: this is not a good conversion for systems with 64 bit sockets and - 32 bit longs */ - if(sockfd != CURL_SOCKET_BAD) - *param_longp = (long)sockfd; - else - /* this interface is documented to return -1 in case of badness, which - may not be the same as the CURL_SOCKET_BAD value */ - *param_longp = -1; - break; - case CURLINFO_REDIRECT_URL: - /* Return the URL this request would have been redirected to if that - option had been enabled! */ - *param_charp = data->info.wouldredirect; - break; - case CURLINFO_PRIMARY_IP: - /* Return the ip address of the most recent (primary) connection */ - *param_charp = data->info.conn_primary_ip; - break; - case CURLINFO_PRIMARY_PORT: - /* Return the (remote) port of the most recent (primary) connection */ - *param_longp = data->info.conn_primary_port; - break; - case CURLINFO_LOCAL_IP: - /* Return the source/local ip address of the most recent (primary) - connection */ - *param_charp = data->info.conn_local_ip; - break; - case CURLINFO_LOCAL_PORT: - /* Return the local port of the most recent (primary) connection */ - *param_longp = data->info.conn_local_port; - break; case CURLINFO_CERTINFO: /* Return the a pointer to the certinfo struct. Not really an slist pointer but we can pretend it is here */ ptr.to_certinfo = &data->info.certs; *param_slistp = ptr.to_slist; break; - case CURLINFO_CONDITION_UNMET: - /* return if the condition prevented the document to get transfered */ - *param_longp = data->info.timecond; - break; - case CURLINFO_RTSP_SESSION_ID: - *param_charp = data->set.str[STRING_RTSP_SESSION_ID]; - break; - case CURLINFO_RTSP_CLIENT_CSEQ: - *param_longp = data->state.rtsp_next_client_CSeq; - break; - case CURLINFO_RTSP_SERVER_CSEQ: - *param_longp = data->state.rtsp_next_server_CSeq; - break; - case CURLINFO_RTSP_CSEQ_RECV: - *param_longp = data->state.rtsp_CSeq_recv; - break; + case CURLINFO_TLS_SESSION: + case CURLINFO_TLS_SSL_PTR: + { + struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **) + param_slistp; + struct curl_tlssessioninfo *tsi = &data->tsi; + struct connectdata *conn = data->easy_conn; + *tsip = tsi; + tsi->backend = Curl_ssl_backend(); + tsi->internals = NULL; + + if(conn && tsi->backend != CURLSSLBACKEND_NONE) { + unsigned int i; + for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) { + if(conn->ssl[i].use) { +#if defined(USE_AXTLS) + tsi->internals = (void *)conn->ssl[i].ssl; +#elif defined(USE_CYASSL) + tsi->internals = (void *)conn->ssl[i].handle; +#elif defined(USE_DARWINSSL) + tsi->internals = (void *)conn->ssl[i].ssl_ctx; +#elif defined(USE_GNUTLS) + tsi->internals = (void *)conn->ssl[i].session; +#elif defined(USE_GSKIT) + tsi->internals = (void *)conn->ssl[i].handle; +#elif defined(USE_MBEDTLS) + tsi->internals = (void *)&conn->ssl[i].ssn; +#elif defined(USE_NSS) + tsi->internals = (void *)conn->ssl[i].handle; +#elif defined(USE_OPENSSL) + /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */ + tsi->internals = ((info == CURLINFO_TLS_SESSION) ? + (void *)conn->ssl[i].ctx : + (void *)conn->ssl[i].handle); +#elif defined(USE_POLARSSL) + tsi->internals = (void *)&conn->ssl[i].ssn; +#elif defined(USE_SCHANNEL) + tsi->internals = (void *)&conn->ssl[i].ctxt->ctxt_handle; +#elif defined(USE_SSL) +#error "SSL backend specific information missing for CURLINFO_TLS_SSL_PTR" +#endif + break; + } + } + } + } + break; default: - return CURLE_BAD_FUNCTION_ARGUMENT; + return CURLE_UNKNOWN_OPTION; } + return CURLE_OK; } + +static CURLcode getinfo_socket(struct SessionHandle *data, CURLINFO info, + curl_socket_t *param_socketp) +{ + switch(info) { + case CURLINFO_ACTIVESOCKET: + *param_socketp = Curl_getconnectinfo(data, NULL); + break; + default: + return CURLE_UNKNOWN_OPTION; + } + + return CURLE_OK; +} + +CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) +{ + va_list arg; + long *param_longp = NULL; + double *param_doublep = NULL; + char **param_charp = NULL; + struct curl_slist **param_slistp = NULL; + curl_socket_t *param_socketp = NULL; + int type; + CURLcode result = CURLE_UNKNOWN_OPTION; + + if(!data) + return result; + + va_start(arg, info); + + type = CURLINFO_TYPEMASK & (int)info; + switch(type) { + case CURLINFO_STRING: + param_charp = va_arg(arg, char **); + if(param_charp) + result = getinfo_char(data, info, param_charp); + break; + case CURLINFO_LONG: + param_longp = va_arg(arg, long *); + if(param_longp) + result = getinfo_long(data, info, param_longp); + break; + case CURLINFO_DOUBLE: + param_doublep = va_arg(arg, double *); + if(param_doublep) + result = getinfo_double(data, info, param_doublep); + break; + case CURLINFO_SLIST: + param_slistp = va_arg(arg, struct curl_slist **); + if(param_slistp) + result = getinfo_slist(data, info, param_slistp); + break; + case CURLINFO_SOCKET: + param_socketp = va_arg(arg, curl_socket_t *); + if(param_socketp) + result = getinfo_socket(data, info, param_socketp); + break; + default: + break; + } + + va_end(arg); + + return result; +} diff --git a/project/jni/curl/lib/getinfo.h b/project/jni/curl/lib/getinfo.h index 3879ff73a..4c2c16848 100644 --- a/project/jni/curl/lib/getinfo.h +++ b/project/jni/curl/lib/getinfo.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/project/jni/curl/lib/gopher.c b/project/jni/curl/lib/gopher.c index 3d8fcffda..19f2f5a89 100644 --- a/project/jni/curl/lib/gopher.c +++ b/project/jni/curl/lib/gopher.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,53 +20,10 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_GOPHER -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include - -#ifdef WIN32 -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#include -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#ifdef HAVE_SYS_SELECT_H -#include -#endif - - -#endif - #include "urldata.h" #include #include "transfer.h" @@ -79,14 +36,10 @@ #include "select.h" #include "url.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" - /* * Forward declarations. */ @@ -110,10 +63,13 @@ const struct Curl_handler Curl_handler_gopher = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_GOPHER, /* defport */ - PROT_GOPHER /* protocol */ + CURLPROTO_GOPHER, /* protocol */ + PROTOPT_NONE /* flags */ }; static CURLcode gopher_do(struct connectdata *conn, bool *done) @@ -127,16 +83,18 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) char *sel; char *sel_org = NULL; ssize_t amount, k; + int len; *done = TRUE; /* unconditionally */ /* Create selector. Degenerate cases: / and /1 => convert to "" */ - if (strlen(path) <= 2) + if(strlen(path) <= 2) { sel = (char *)""; + len = (int)strlen(sel); + } else { char *newp; size_t j, i; - int len; /* Otherwise, drop / and the first character (i.e., item type) ... */ newp = path; @@ -150,31 +108,31 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) /* ... and finally unescape */ sel = curl_easy_unescape(data, newp, 0, &len); - if (!sel) + if(!sel) return CURLE_OUT_OF_MEMORY; sel_org = sel; } /* We use Curl_write instead of Curl_sendf to make sure the entire buffer is sent, which could be sizeable with long selectors. */ - k = curlx_uztosz(strlen(sel)); + k = curlx_uztosz(len); for(;;) { result = Curl_write(conn, sockfd, sel, k, &amount); - if (CURLE_OK == result) { /* Which may not have written it all! */ + if(!result) { /* Which may not have written it all! */ result = Curl_client_write(conn, CLIENTWRITE_HEADER, sel, amount); if(result) { - Curl_safefree(sel_org); + free(sel_org); return result; } k -= amount; sel += amount; - if (k < 1) + if(k < 1) break; /* but it did write it all */ } else { failf(data, "Failed sending Gopher request"); - Curl_safefree(sel_org); + free(sel_org); return result; } /* Don't busyloop. The entire loop thing is a work-around as it causes a @@ -189,12 +147,12 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) Curl_socket_ready(CURL_SOCKET_BAD, sockfd, 100); } - Curl_safefree(sel_org); + free(sel_org); /* We can use Curl_sendf to send the terminal \r\n relatively safely and save allocing another string/doing another _write loop. */ result = Curl_sendf(sockfd, conn, "\r\n"); - if (result != CURLE_OK) { + if(result) { failf(data, "Failed sending Gopher request"); return result; } diff --git a/project/jni/curl/lib/gopher.h b/project/jni/curl/lib/gopher.h index 38bbc4b73..501c990a8 100644 --- a/project/jni/curl/lib/gopher.h +++ b/project/jni/curl/lib/gopher.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/project/jni/curl/lib/gtls.c b/project/jni/curl/lib/gtls.c deleted file mode 100644 index 845dbbb12..000000000 --- a/project/jni/curl/lib/gtls.c +++ /dev/null @@ -1,959 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code - * but sslgen.c should ever call or use these functions. - * - * Note: don't use the GnuTLS' *_t variable type names in this source code, - * since they were not present in 1.0.X. - */ - -#include "setup.h" -#ifdef USE_GNUTLS -#include -#include -#include - -#include -#include -#include -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "inet_pton.h" -#include "gtls.h" -#include "sslgen.h" -#include "parsedate.h" -#include "connect.h" /* for the connect timeout */ -#include "select.h" -#include "rawstr.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/* - Some hackish cast macros based on: - http://library.gnome.org/devel/glib/unstable/glib-Type-Conversion-Macros.html -*/ -#ifndef GNUTLS_POINTER_TO_INT_CAST -#define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p)) -#endif -#ifndef GNUTLS_INT_TO_POINTER_CAST -#define GNUTLS_INT_TO_POINTER_CAST(i) ((void*) (long) (i)) -#endif - -/* Enable GnuTLS debugging by defining GTLSDEBUG */ -/*#define GTLSDEBUG */ - -#ifdef GTLSDEBUG -static void tls_log_func(int level, const char *str) -{ - fprintf(stderr, "|<%d>| %s", level, str); -} -#endif -static bool gtls_inited = FALSE; - -/* - * Custom push and pull callback functions used by GNU TLS to read and write - * to the socket. These functions are simple wrappers to send() and recv() - * (although here using the sread/swrite macros as defined by setup_once.h). - * We use custom functions rather than the GNU TLS defaults because it allows - * us to get specific about the fourth "flags" argument, and to use arbitrary - * private data with gnutls_transport_set_ptr if we wish. - * - * When these custom push and pull callbacks fail, GNU TLS checks its own - * session-specific error variable, and when not set also its own global - * errno variable, in order to take appropriate action. GNU TLS does not - * require that the transport is actually a socket. This implies that for - * Windows builds these callbacks should ideally set the session-specific - * error variable using function gnutls_transport_set_errno or as a last - * resort global errno variable using gnutls_transport_set_global_errno, - * with a transport agnostic error value. This implies that some winsock - * error translation must take place in these callbacks. - */ - -#ifdef USE_WINSOCK -# define gtls_EINTR 4 -# define gtls_EIO 5 -# define gtls_EAGAIN 11 -static int gtls_mapped_sockerrno(void) -{ - switch(SOCKERRNO) { - case WSAEWOULDBLOCK: - return gtls_EAGAIN; - case WSAEINTR: - return gtls_EINTR; - default: - break; - } - return gtls_EIO; -} -#endif - -static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) -{ - ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); -#ifdef USE_WINSOCK - if(ret < 0) - gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); -#endif - return ret; -} - -static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) -{ - ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); -#ifdef USE_WINSOCK - if(ret < 0) - gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); -#endif - return ret; -} - -/* Curl_gtls_init() - * - * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that - * are not thread-safe and thus this function itself is not thread-safe and - * must only be called from within curl_global_init() to keep the thread - * situation under control! - */ -int Curl_gtls_init(void) -{ - int ret = 1; - if(!gtls_inited) { - ret = gnutls_global_init()?0:1; -#ifdef GTLSDEBUG - gnutls_global_set_log_function(tls_log_func); - gnutls_global_set_log_level(2); -#endif - gtls_inited = TRUE; - } - return ret; -} - -int Curl_gtls_cleanup(void) -{ - if(gtls_inited) { - gnutls_global_deinit(); - gtls_inited = FALSE; - } - return 1; -} - -static void showtime(struct SessionHandle *data, - const char *text, - time_t stamp) -{ - struct tm *tm; -#ifdef HAVE_GMTIME_R - struct tm buffer; - tm = (struct tm *)gmtime_r(&stamp, &buffer); -#else - tm = gmtime(&stamp); -#endif - snprintf(data->state.buffer, - BUFSIZE, - "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT\n", - text, - Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); - infof(data, "%s", data->state.buffer); -} - -static gnutls_datum load_file (const char *file) -{ - FILE *f; - gnutls_datum loaded_file = { NULL, 0 }; - long filelen; - void *ptr; - - if (!(f = fopen(file, "r"))) - return loaded_file; - if (fseek(f, 0, SEEK_END) != 0 - || (filelen = ftell(f)) < 0 - || fseek(f, 0, SEEK_SET) != 0 - || !(ptr = malloc((size_t)filelen))) - goto out; - if (fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) { - free(ptr); - goto out; - } - - loaded_file.data = ptr; - loaded_file.size = (unsigned int)filelen; -out: - fclose(f); - return loaded_file; -} - -static void unload_file(gnutls_datum data) { - free(data.data); -} - - -/* this function does a SSL/TLS (re-)handshake */ -static CURLcode handshake(struct connectdata *conn, - int sockindex, - bool duringconnect, - bool nonblocking) -{ - struct SessionHandle *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - gnutls_session session = conn->ssl[sockindex].session; - curl_socket_t sockfd = conn->sock[sockindex]; - long timeout_ms; - int rc; - int what; - - for(;;) { - /* check allowed time left */ - timeout_ms = Curl_timeleft(conn, NULL, duringconnect); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it's available. */ - if(connssl->connecting_state == ssl_connect_2_reading - || connssl->connecting_state == ssl_connect_2_writing) { - - curl_socket_t writefd = ssl_connect_2_writing== - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading== - connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - - what = Curl_socket_ready(readfd, writefd, - nonblocking?0:(int)timeout_ms?1000:timeout_ms); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - else if(0 == what) { - if(nonblocking) - return CURLE_OK; - else if(timeout_ms) { - /* timeout */ - failf(data, "SSL connection timeout at %ld", timeout_ms); - return CURLE_OPERATION_TIMEDOUT; - } - } - /* socket is readable or writable */ - } - - rc = gnutls_handshake(session); - - if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { - connssl->connecting_state = - gnutls_record_get_direction(session)? - ssl_connect_2_writing:ssl_connect_2_reading; - if(nonblocking) - return CURLE_OK; - } - else if (rc < 0) { - failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc)); - return CURLE_SSL_CONNECT_ERROR; - } - else { - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - return CURLE_OK; - } - } -} - -static gnutls_x509_crt_fmt do_file_type(const char *type) -{ - if(!type || !type[0]) - return GNUTLS_X509_FMT_PEM; - if(Curl_raw_equal(type, "PEM")) - return GNUTLS_X509_FMT_PEM; - if(Curl_raw_equal(type, "DER")) - return GNUTLS_X509_FMT_DER; - return -1; -} - -static CURLcode -gtls_connect_step1(struct connectdata *conn, - int sockindex) -{ - static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; - struct SessionHandle *data = conn->data; - gnutls_session session; - int rc; - void *ssl_sessionid; - size_t ssl_idsize; - bool sni = TRUE; /* default is SNI enabled */ -#ifdef ENABLE_IPV6 - struct in6_addr addr; -#else - struct in_addr addr; -#endif - - if(conn->ssl[sockindex].state == ssl_connection_complete) - /* to make us tolerant against being called more than once for the - same connection */ - return CURLE_OK; - - if(!gtls_inited) - Curl_gtls_init(); - - /* GnuTLS only supports SSLv3 and TLSv1 */ - if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { - failf(data, "GnuTLS does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - } - else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) - sni = FALSE; /* SSLv3 has no SNI */ - - /* allocate a cred struct */ - rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred); - if(rc != GNUTLS_E_SUCCESS) { - failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc)); - return CURLE_SSL_CONNECT_ERROR; - } - - if(data->set.ssl.CAfile) { - /* set the trusted CA cert bundle file */ - gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred, - GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); - - rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, - data->set.ssl.CAfile, - GNUTLS_X509_FMT_PEM); - if(rc < 0) { - infof(data, "error reading ca cert file %s (%s)\n", - data->set.ssl.CAfile, gnutls_strerror(rc)); - if(data->set.ssl.verifypeer) - return CURLE_SSL_CACERT_BADFILE; - } - else - infof(data, "found %d certificates in %s\n", - rc, data->set.ssl.CAfile); - } - - if(data->set.ssl.CRLfile) { - /* set the CRL list file */ - rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred, - data->set.ssl.CRLfile, - GNUTLS_X509_FMT_PEM); - if(rc < 0) { - failf(data, "error reading crl file %s (%s)\n", - data->set.ssl.CRLfile, gnutls_strerror(rc)); - return CURLE_SSL_CRL_BADFILE; - } - else - infof(data, "found %d CRL in %s\n", - rc, data->set.ssl.CRLfile); - } - - /* Initialize TLS session as a client */ - rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT); - if(rc != GNUTLS_E_SUCCESS) { - failf(data, "gnutls_init() failed: %d", rc); - return CURLE_SSL_CONNECT_ERROR; - } - - /* convenient assign */ - session = conn->ssl[sockindex].session; - - if ((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && -#ifdef ENABLE_IPV6 - (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && -#endif - sni && - (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name, - strlen(conn->host.name)) < 0)) - infof(data, "WARNING: failed to configure server name indication (SNI) " - "TLS extension\n"); - - /* Use default priorities */ - rc = gnutls_set_default_priority(session); - if(rc != GNUTLS_E_SUCCESS) - return CURLE_SSL_CONNECT_ERROR; - - if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) { - static const int protocol_priority[] = { GNUTLS_SSL3, 0 }; - gnutls_protocol_set_priority(session, protocol_priority); - if(rc != GNUTLS_E_SUCCESS) - return CURLE_SSL_CONNECT_ERROR; - } - - /* Sets the priority on the certificate types supported by gnutls. Priority - is higher for types specified before others. After specifying the types - you want, you must append a 0. */ - rc = gnutls_certificate_type_set_priority(session, cert_type_priority); - if(rc != GNUTLS_E_SUCCESS) - return CURLE_SSL_CONNECT_ERROR; - - if(data->set.str[STRING_CERT]) { - if( gnutls_certificate_set_x509_key_file( - conn->ssl[sockindex].cred, - data->set.str[STRING_CERT], - data->set.str[STRING_KEY] ? - data->set.str[STRING_KEY] : data->set.str[STRING_CERT], - do_file_type(data->set.str[STRING_CERT_TYPE]) ) != GNUTLS_E_SUCCESS) { - failf(data, "error reading X.509 key or certificate file"); - return CURLE_SSL_CONNECT_ERROR; - } - } - - /* put the credentials to the current session */ - rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, - conn->ssl[sockindex].cred); - - /* set the connection handle (file descriptor for the socket) */ - gnutls_transport_set_ptr(session, - GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex])); - - /* register callback functions to send and receive data. */ - gnutls_transport_set_push_function(session, Curl_gtls_push); - gnutls_transport_set_pull_function(session, Curl_gtls_pull); - - /* lowat must be set to zero when using custom push and pull functions. */ - gnutls_transport_set_lowat(session, 0); - - /* This might be a reconnect, so we check for a session ID in the cache - to speed up things */ - - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) { - /* we got a session id, use it! */ - gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); - - /* Informational message */ - infof (data, "SSL re-using session ID\n"); - } - - return CURLE_OK; -} - -static Curl_recv gtls_recv; -static Curl_send gtls_send; - -static CURLcode -gtls_connect_step3(struct connectdata *conn, - int sockindex) -{ - unsigned int cert_list_size; - const gnutls_datum *chainp; - unsigned int verify_status; - gnutls_x509_crt x509_cert,x509_issuer; - gnutls_datum issuerp; - char certbuf[256]; /* big enough? */ - size_t size; - unsigned int algo; - unsigned int bits; - time_t certclock; - const char *ptr; - struct SessionHandle *data = conn->data; - gnutls_session session = conn->ssl[sockindex].session; - int rc; - int incache; - void *ssl_sessionid; - - /* This function will return the peer's raw certificate (chain) as sent by - the peer. These certificates are in raw format (DER encoded for - X.509). In case of a X.509 then a certificate list may be present. The - first certificate in the list is the peer's certificate, following the - issuer's certificate, then the issuer's issuer etc. */ - - chainp = gnutls_certificate_get_peers(session, &cert_list_size); - if(!chainp) { - if(data->set.ssl.verifypeer || - data->set.ssl.verifyhost || - data->set.ssl.issuercert) { - failf(data, "failed to get server cert"); - return CURLE_PEER_FAILED_VERIFICATION; - } - infof(data, "\t common name: WARNING couldn't obtain\n"); - } - - if(data->set.ssl.verifypeer) { - /* This function will try to verify the peer's certificate and return its - status (trusted, invalid etc.). The value of status should be one or - more of the gnutls_certificate_status_t enumerated elements bitwise - or'd. To avoid denial of service attacks some default upper limits - regarding the certificate key size and chain size are set. To override - them use gnutls_certificate_set_verify_limits(). */ - - rc = gnutls_certificate_verify_peers2(session, &verify_status); - if(rc < 0) { - failf(data, "server cert verify failed: %d", rc); - return CURLE_SSL_CONNECT_ERROR; - } - - /* verify_status is a bitmask of gnutls_certificate_status bits */ - if(verify_status & GNUTLS_CERT_INVALID) { - if(data->set.ssl.verifypeer) { - failf(data, "server certificate verification failed. CAfile: %s " - "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none", - data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none"); - return CURLE_SSL_CACERT; - } - else - infof(data, "\t server certificate verification FAILED\n"); - } - else - infof(data, "\t server certificate verification OK\n"); - } - else - infof(data, "\t server certificate verification SKIPPED\n"); - - /* initialize an X.509 certificate structure. */ - gnutls_x509_crt_init(&x509_cert); - - /* convert the given DER or PEM encoded Certificate to the native - gnutls_x509_crt_t format */ - gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); - - if (data->set.ssl.issuercert) { - gnutls_x509_crt_init(&x509_issuer); - issuerp = load_file(data->set.ssl.issuercert); - gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); - rc = gnutls_x509_crt_check_issuer(x509_cert,x509_issuer); - unload_file(issuerp); - if (rc <= 0) { - failf(data, "server certificate issuer check failed (IssuerCert: %s)", - data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); - return CURLE_SSL_ISSUER_ERROR; - } - infof(data,"\t server certificate issuer check OK (Issuer Cert: %s)\n", - data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); - } - - size=sizeof(certbuf); - rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, - 0, /* the first and only one */ - FALSE, - certbuf, - &size); - if(rc) { - infof(data, "error fetching CN from cert:%s\n", - gnutls_strerror(rc)); - } - - /* This function will check if the given certificate's subject matches the - given hostname. This is a basic implementation of the matching described - in RFC2818 (HTTPS), which takes into account wildcards, and the subject - alternative name PKIX extension. Returns non zero on success, and zero on - failure. */ - rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name); - - if(!rc) { - if(data->set.ssl.verifyhost > 1) { - failf(data, "SSL: certificate subject name (%s) does not match " - "target host name '%s'", certbuf, conn->host.dispname); - gnutls_x509_crt_deinit(x509_cert); - return CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, "\t common name: %s (does not match '%s')\n", - certbuf, conn->host.dispname); - } - else - infof(data, "\t common name: %s (matched)\n", certbuf); - - /* Check for time-based validity */ - certclock = gnutls_x509_crt_get_expiration_time(x509_cert); - - if(certclock == (time_t)-1) { - failf(data, "server cert expiration date verify failed"); - return CURLE_SSL_CONNECT_ERROR; - } - - if(certclock < time(NULL)) { - if(data->set.ssl.verifypeer) { - failf(data, "server certificate expiration date has passed."); - return CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, "\t server certificate expiration date FAILED\n"); - } - else - infof(data, "\t server certificate expiration date OK\n"); - - certclock = gnutls_x509_crt_get_activation_time(x509_cert); - - if(certclock == (time_t)-1) { - failf(data, "server cert activation date verify failed"); - return CURLE_SSL_CONNECT_ERROR; - } - - if(certclock > time(NULL)) { - if(data->set.ssl.verifypeer) { - failf(data, "server certificate not activated yet."); - return CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, "\t server certificate activation date FAILED\n"); - } - else - infof(data, "\t server certificate activation date OK\n"); - - /* Show: - - - ciphers used - - subject - - start date - - expire date - - common name - - issuer - - */ - - /* public key algorithm's parameters */ - algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits); - infof(data, "\t certificate public key: %s\n", - gnutls_pk_algorithm_get_name(algo)); - - /* version of the X.509 certificate. */ - infof(data, "\t certificate version: #%d\n", - gnutls_x509_crt_get_version(x509_cert)); - - - size = sizeof(certbuf); - gnutls_x509_crt_get_dn(x509_cert, certbuf, &size); - infof(data, "\t subject: %s\n", certbuf); - - certclock = gnutls_x509_crt_get_activation_time(x509_cert); - showtime(data, "start date", certclock); - - certclock = gnutls_x509_crt_get_expiration_time(x509_cert); - showtime(data, "expire date", certclock); - - size = sizeof(certbuf); - gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size); - infof(data, "\t issuer: %s\n", certbuf); - - gnutls_x509_crt_deinit(x509_cert); - - /* compression algorithm (if any) */ - ptr = gnutls_compression_get_name(gnutls_compression_get(session)); - /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */ - infof(data, "\t compression: %s\n", ptr); - - /* the name of the cipher used. ie 3DES. */ - ptr = gnutls_cipher_get_name(gnutls_cipher_get(session)); - infof(data, "\t cipher: %s\n", ptr); - - /* the MAC algorithms name. ie SHA1 */ - ptr = gnutls_mac_get_name(gnutls_mac_get(session)); - infof(data, "\t MAC: %s\n", ptr); - - conn->ssl[sockindex].state = ssl_connection_complete; - conn->recv[sockindex] = gtls_recv; - conn->send[sockindex] = gtls_send; - - { - /* we always unconditionally get the session id here, as even if we - already got it from the cache and asked to use it in the connection, it - might've been rejected and then a new one is in use now and we need to - detect that. */ - void *connect_sessionid; - size_t connect_idsize; - - /* get the session ID data size */ - gnutls_session_get_data(session, NULL, &connect_idsize); - connect_sessionid = malloc(connect_idsize); /* get a buffer for it */ - - if(connect_sessionid) { - /* extract session ID to the allocated buffer */ - gnutls_session_get_data(session, connect_sessionid, &connect_idsize); - - incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)); - if (incache) { - /* there was one before in the cache, so instead of risking that the - previous one was rejected, we just kill that and store the new */ - Curl_ssl_delsessionid(conn, ssl_sessionid); - } - - /* store this session id */ - return Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize); - } - } - - return CURLE_OK; -} - - -/* - * This function is called after the TCP connect has completed. Setup the TLS - * layer and do all necessary magic. - */ -/* We use connssl->connecting_state to keep track of the connection status; - there are three states: 'ssl_connect_1' (not started yet or complete), - 'ssl_connect_2_reading' (waiting for data from server), and - 'ssl_connect_2_writing' (waiting to be able to write). - */ -static CURLcode -gtls_connect_common(struct connectdata *conn, - int sockindex, - bool nonblocking, - bool *done) -{ - int rc; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - /* Initiate the connection, if not already done */ - if(ssl_connect_1==connssl->connecting_state) { - rc = gtls_connect_step1 (conn, sockindex); - if(rc) - return rc; - } - - rc = handshake(conn, sockindex, TRUE, nonblocking); - if(rc) - /* handshake() sets its own error message with failf() */ - return rc; - - /* Finish connecting once the handshake is done */ - if(ssl_connect_1==connssl->connecting_state) { - rc = gtls_connect_step3(conn, sockindex); - if(rc) - return rc; - } - - *done = ssl_connect_1==connssl->connecting_state; - - return CURLE_OK; -} - -CURLcode -Curl_gtls_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) -{ - return gtls_connect_common(conn, sockindex, TRUE, done); -} - -CURLcode -Curl_gtls_connect(struct connectdata *conn, - int sockindex) - -{ - CURLcode retcode; - bool done = FALSE; - - retcode = gtls_connect_common(conn, sockindex, FALSE, &done); - if(retcode) - return retcode; - - DEBUGASSERT(done); - - return CURLE_OK; -} - -static ssize_t gtls_send(struct connectdata *conn, - int sockindex, - const void *mem, - size_t len, - CURLcode *curlcode) -{ - ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len); - - if(rc < 0 ) { - *curlcode = (rc == GNUTLS_E_AGAIN) - ? CURLE_AGAIN - : CURLE_SEND_ERROR; - - rc = -1; - } - - return rc; -} - -void Curl_gtls_close_all(struct SessionHandle *data) -{ - /* FIX: make the OpenSSL code more generic and use parts of it here */ - (void)data; -} - -static void close_one(struct connectdata *conn, - int idx) -{ - if(conn->ssl[idx].session) { - gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR); - gnutls_deinit(conn->ssl[idx].session); - conn->ssl[idx].session = NULL; - } - if(conn->ssl[idx].cred) { - gnutls_certificate_free_credentials(conn->ssl[idx].cred); - conn->ssl[idx].cred = NULL; - } -} - -void Curl_gtls_close(struct connectdata *conn, int sockindex) -{ - close_one(conn, sockindex); -} - -/* - * This function is called to shut down the SSL layer but keep the - * socket open (CCC - Clear Command Channel) - */ -int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) -{ - ssize_t result; - int retval = 0; - struct SessionHandle *data = conn->data; - int done = 0; - char buf[120]; - - /* This has only been tested on the proftpd server, and the mod_tls code - sends a close notify alert without waiting for a close notify alert in - response. Thus we wait for a close notify alert from the server, but - we do not send one. Let's hope other servers do the same... */ - - if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) - gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR); - - if(conn->ssl[sockindex].session) { - while(!done) { - int what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); - if(what > 0) { - /* Something to read, let's do it and hope that it is the close - notify alert from the server */ - result = gnutls_record_recv(conn->ssl[sockindex].session, - buf, sizeof(buf)); - switch(result) { - case 0: - /* This is the expected response. There was no data but only - the close notify alert */ - done = 1; - break; - case GNUTLS_E_AGAIN: - case GNUTLS_E_INTERRUPTED: - infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n"); - break; - default: - retval = -1; - done = 1; - break; - } - } - else if(0 == what) { - /* timeout */ - failf(data, "SSL shutdown timeout"); - done = 1; - break; - } - else { - /* anything that gets here is fatally bad */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - retval = -1; - done = 1; - } - } - gnutls_deinit(conn->ssl[sockindex].session); - } - gnutls_certificate_free_credentials(conn->ssl[sockindex].cred); - - conn->ssl[sockindex].cred = NULL; - conn->ssl[sockindex].session = NULL; - - return retval; -} - -static ssize_t gtls_recv(struct connectdata *conn, /* connection data */ - int num, /* socketindex */ - char *buf, /* store read data here */ - size_t buffersize, /* max amount to read */ - CURLcode *curlcode) -{ - ssize_t ret; - - ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize); - if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) { - *curlcode = CURLE_AGAIN; - return -1; - } - - if(ret == GNUTLS_E_REHANDSHAKE) { - /* BLOCKING call, this is bad but a work-around for now. Fixing this "the - proper way" takes a whole lot of work. */ - CURLcode rc = handshake(conn, num, FALSE, FALSE); - if(rc) - /* handshake() writes error message on its own */ - *curlcode = rc; - else - *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */ - return -1; - } - - if(ret < 0) { - failf(conn->data, "GnuTLS recv error (%d): %s", - (int)ret, gnutls_strerror((int)ret)); - *curlcode = CURLE_RECV_ERROR; - return -1; - } - - return ret; -} - -void Curl_gtls_session_free(void *ptr) -{ - free(ptr); -} - -size_t Curl_gtls_version(char *buffer, size_t size) -{ - return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL)); -} - -int Curl_gtls_seed(struct SessionHandle *data) -{ - /* we have the "SSL is seeded" boolean static to prevent multiple - time-consuming seedings in vain */ - static bool ssl_seeded = FALSE; - - /* Quickly add a bit of entropy */ - gcry_fast_random_poll(); - - if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] || - data->set.str[STRING_SSL_EGDSOCKET]) { - - /* TODO: to a good job seeding the RNG - This may involve the gcry_control function and these options: - GCRYCTL_SET_RANDOM_SEED_FILE - GCRYCTL_SET_RNDEGD_SOCKET - */ - ssl_seeded = TRUE; - } - return 0; -} - -#endif /* USE_GNUTLS */ diff --git a/project/jni/curl/lib/hash.c b/project/jni/curl/lib/hash.c index cdcd26017..a0889783d 100644 --- a/project/jni/curl/lib/hash.c +++ b/project/jni/curl/lib/hash.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,17 +20,10 @@ * ***************************************************************************/ -#include "setup.h" - -#include -#include +#include "curl_setup.h" #include "hash.h" #include "llist.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -41,16 +34,24 @@ hash_element_dtor(void *user, void *element) struct curl_hash *h = (struct curl_hash *) user; struct curl_hash_element *e = (struct curl_hash_element *) element; - if(e->key) - free(e->key); + Curl_safefree(e->key); - if(e->ptr) + if(e->ptr) { h->dtor(e->ptr); + e->ptr = NULL; + } + + e->key_len = 0; free(e); } -/* return 1 on error, 0 is fine */ +/* Initializes a hash structure. + * Return 1 on error, 0 is fine. + * + * @unittest: 1602 + * @unittest: 1603 + */ int Curl_hash_init(struct curl_hash *h, int slots, @@ -72,47 +73,27 @@ Curl_hash_init(struct curl_hash *h, h->table = malloc(slots * sizeof(struct curl_llist *)); if(h->table) { - for (i = 0; i < slots; ++i) { + for(i = 0; i < slots; ++i) { h->table[i] = Curl_llist_alloc((curl_llist_dtor) hash_element_dtor); if(!h->table[i]) { - while(i--) + while(i--) { Curl_llist_destroy(h->table[i], NULL); + h->table[i] = NULL; + } free(h->table); + h->table = NULL; + h->slots = 0; return 1; /* failure */ } } return 0; /* fine */ } - else + else { + h->slots = 0; return 1; /* failure */ -} - -struct curl_hash * -Curl_hash_alloc(int slots, - hash_function hfunc, - comp_function comparator, - curl_hash_dtor dtor) -{ - struct curl_hash *h; - - if(!slots || !hfunc || !comparator ||!dtor) { - return NULL; /* failure */ } - - h = malloc(sizeof(struct curl_hash)); - if(h) { - if(Curl_hash_init(h, slots, hfunc, comparator, dtor)) { - /* failure */ - free(h); - h = NULL; - } - } - - return h; } - - static struct curl_hash_element * mk_hash_element(const void *key, size_t key_len, const void *p) { @@ -140,7 +121,12 @@ mk_hash_element(const void *key, size_t key_len, const void *p) #define FETCH_LIST(x,y,z) x->table[x->hash_func(y, z, x->slots)] /* Insert the data in the hash. If there already was a match in the hash, - that data is replaced. */ + * that data is replaced. + * + * @unittest: 1305 + * @unittest: 1602 + * @unittest: 1603 + */ void * Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p) { @@ -148,7 +134,7 @@ Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p) struct curl_llist_element *le; struct curl_llist *l = FETCH_LIST (h, key, key_len); - for (le = l->head; le; le = le->next) { + for(le = l->head; le; le = le->next) { he = (struct curl_hash_element *) le->ptr; if(h->comp_func(he->key, he->key_len, key, key_len)) { Curl_llist_remove(l, le, (void *)h); @@ -176,34 +162,46 @@ Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p) return NULL; /* failure */ } -/* remove the identified hash entry, returns non-zero on failure */ +/* Remove the identified hash entry. + * Returns non-zero on failure. + * + * @unittest: 1603 + */ int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len) { struct curl_llist_element *le; struct curl_hash_element *he; struct curl_llist *l = FETCH_LIST(h, key, key_len); - for (le = l->head; le; le = le->next) { + for(le = l->head; le; le = le->next) { he = le->ptr; if(h->comp_func(he->key, he->key_len, key, key_len)) { Curl_llist_remove(l, le, (void *) h); + --h->size; return 0; } } return 1; } +/* Retrieves a hash element. + * + * @unittest: 1603 + */ void * Curl_hash_pick(struct curl_hash *h, void *key, size_t key_len) { struct curl_llist_element *le; struct curl_hash_element *he; - struct curl_llist *l = FETCH_LIST(h, key, key_len); + struct curl_llist *l; - for (le = l->head; le; le = le->next) { - he = le->ptr; - if(h->comp_func(he->key, he->key_len, key, key_len)) { - return he->ptr; + if(h) { + l = FETCH_LIST(h, key, key_len); + for(le = l->head; le; le = le->next) { + he = le->ptr; + if(h->comp_func(he->key, he->key_len, key, key_len)) { + return he->ptr; + } } } @@ -218,10 +216,10 @@ Curl_hash_apply(curl_hash *h, void *user, struct curl_llist_element *le; int i; - for (i = 0; i < h->slots; ++i) { - for (le = (h->table[i])->head; - le; - le = le->next) { + for(i = 0; i < h->slots; ++i) { + for(le = (h->table[i])->head; + le; + le = le->next) { curl_hash_element *el = le->ptr; cb(user, el->ptr); } @@ -229,19 +227,39 @@ Curl_hash_apply(curl_hash *h, void *user, } #endif +/* Destroys all the entries in the given hash and resets its attributes, + * prepping the given hash for [static|dynamic] deallocation. + * + * @unittest: 1305 + * @unittest: 1602 + * @unittest: 1603 + */ void -Curl_hash_clean(struct curl_hash *h) +Curl_hash_destroy(struct curl_hash *h) { int i; - for (i = 0; i < h->slots; ++i) { + for(i = 0; i < h->slots; ++i) { Curl_llist_destroy(h->table[i], (void *) h); h->table[i] = NULL; } - free(h->table); + Curl_safefree(h->table); + h->size = 0; + h->slots = 0; } +/* Removes all the entries in the given hash. + * + * @unittest: 1602 + */ +void +Curl_hash_clean(struct curl_hash *h) +{ + Curl_hash_clean_with_criterium(h, NULL, NULL); +} + +/* Cleans all entries that pass the comp function criteria. */ void Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, int (*comp)(void *, void *)) @@ -251,14 +269,17 @@ Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, struct curl_llist *list; int i; - for (i = 0; i < h->slots; ++i) { + if(!h) + return; + + for(i = 0; i < h->slots; ++i) { list = h->table[i]; le = list->head; /* get first list entry */ while(le) { struct curl_hash_element *he = le->ptr; lnext = le->next; /* ask the callback function if we shall remove this entry or not */ - if(comp(user, he->ptr)) { + if(comp == NULL || comp(user, he->ptr)) { Curl_llist_remove(list, le, (void *) h); --h->size; /* one less entry in the hash now */ } @@ -267,17 +288,6 @@ Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, } } -void -Curl_hash_destroy(struct curl_hash *h) -{ - if(!h) - return; - - Curl_hash_clean(h); - - free(h); -} - size_t Curl_hash_str(void* key, size_t key_length, size_t slots_num) { const char* key_str = (const char *) key; @@ -292,48 +302,86 @@ size_t Curl_hash_str(void* key, size_t key_length, size_t slots_num) return (h % slots_num); } -size_t Curl_str_key_compare(void*k1, size_t key1_len, void*k2, size_t key2_len) +size_t Curl_str_key_compare(void *k1, size_t key1_len, + void *k2, size_t key2_len) { - char *key1 = (char *)k1; - char *key2 = (char *)k2; - - if(key1_len == key2_len && - *key1 == *key2 && - memcmp(key1, key2, key1_len) == 0) { + if((key1_len == key2_len) && !memcmp(k1, k2, key1_len)) return 1; - } return 0; } +void Curl_hash_start_iterate(struct curl_hash *hash, + struct curl_hash_iterator *iter) +{ + iter->hash = hash; + iter->slot_index = 0; + iter->current_element = NULL; +} + +struct curl_hash_element * +Curl_hash_next_element(struct curl_hash_iterator *iter) +{ + int i; + struct curl_hash *h = iter->hash; + + /* Get the next element in the current list, if any */ + if(iter->current_element) + iter->current_element = iter->current_element->next; + + /* If we have reached the end of the list, find the next one */ + if(!iter->current_element) { + for(i = iter->slot_index;i < h->slots;i++) { + if(h->table[i]->head) { + iter->current_element = h->table[i]->head; + iter->slot_index = i+1; + break; + } + } + } + + if(iter->current_element) { + struct curl_hash_element *he = iter->current_element->ptr; + return he; + } + else { + iter->current_element = NULL; + return NULL; + } +} + #if 0 /* useful function for debugging hashes and their contents */ void Curl_hash_print(struct curl_hash *h, void (*func)(void *)) { - int i; - struct curl_llist_element *le; - struct curl_llist *list; - struct curl_hash_element *he; + struct curl_hash_iterator iter; + struct curl_hash_element *he; + int last_index = -1; + if(!h) return; fprintf(stderr, "=Hash dump=\n"); - for (i = 0; i < h->slots; i++) { - list = h->table[i]; - le = list->head; /* get first list entry */ - if(le) { - fprintf(stderr, "index %d:", i); - while(le) { - he = le->ptr; - if(func) - func(he->ptr); - else - fprintf(stderr, " [%p]", he->ptr); - le = le->next; + Curl_hash_start_iterate(h, &iter); + + he = Curl_hash_next_element(&iter); + while(he) { + if(iter.slot_index != last_index) { + fprintf(stderr, "index %d:", iter.slot_index); + if(last_index >= 0) { + fprintf(stderr, "\n"); } - fprintf(stderr, "\n"); + last_index = iter.slot_index; } + + if(func) + func(he->ptr); + else + fprintf(stderr, " [%p]", (void *)he->ptr); + + he = Curl_hash_next_element(&iter); } + fprintf(stderr, "\n"); } #endif diff --git a/project/jni/curl/lib/hash.h b/project/jni/curl/lib/hash.h index 993aaedd2..57a17f02a 100644 --- a/project/jni/curl/lib/hash.h +++ b/project/jni/curl/lib/hash.h @@ -1,5 +1,5 @@ -#ifndef __HASH_H -#define __HASH_H +#ifndef HEADER_CURL_HASH_H +#define HEADER_CURL_HASH_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,7 +22,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #include @@ -62,6 +62,11 @@ struct curl_hash_element { size_t key_len; }; +struct curl_hash_iterator { + struct curl_hash *hash; + int slot_index; + struct curl_llist_element *current_element; +}; int Curl_hash_init(struct curl_hash *h, int slots, @@ -69,24 +74,27 @@ int Curl_hash_init(struct curl_hash *h, comp_function comparator, curl_hash_dtor dtor); -struct curl_hash *Curl_hash_alloc(int slots, - hash_function hfunc, - comp_function comparator, - curl_hash_dtor dtor); - void *Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p); int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len); void *Curl_hash_pick(struct curl_hash *, void * key, size_t key_len); void Curl_hash_apply(struct curl_hash *h, void *user, void (*cb)(void *user, void *ptr)); int Curl_hash_count(struct curl_hash *h); +void Curl_hash_destroy(struct curl_hash *h); void Curl_hash_clean(struct curl_hash *h); void Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, int (*comp)(void *, void *)); -void Curl_hash_destroy(struct curl_hash *h); - size_t Curl_hash_str(void* key, size_t key_length, size_t slots_num); size_t Curl_str_key_compare(void*k1, size_t key1_len, void*k2, size_t key2_len); -#endif +void Curl_hash_start_iterate(struct curl_hash *hash, + struct curl_hash_iterator *iter); +struct curl_hash_element * +Curl_hash_next_element(struct curl_hash_iterator *iter); + +void Curl_hash_print(struct curl_hash *h, + void (*func)(void *)); + + +#endif /* HEADER_CURL_HASH_H */ diff --git a/project/jni/curl/lib/hmac.c b/project/jni/curl/lib/hmac.c index 8cb5f2eaa..664c77418 100644 --- a/project/jni/curl/lib/hmac.c +++ b/project/jni/curl/lib/hmac.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,15 +22,11 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_CRYPTO_AUTH #include "curl_hmac.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -59,7 +55,8 @@ Curl_HMAC_init(const HMAC_params * hashparams, unsigned char b; /* Create HMAC context. */ - i = sizeof *ctxt + 2 * hashparams->hmac_ctxtsize + hashparams->hmac_resultlen; + i = sizeof *ctxt + 2 * hashparams->hmac_ctxtsize + + hashparams->hmac_resultlen; ctxt = malloc(i); if(!ctxt) @@ -84,14 +81,14 @@ Curl_HMAC_init(const HMAC_params * hashparams, (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1); (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt2); - for (i = 0; i < keylen; i++) { + for(i = 0; i < keylen; i++) { b = (unsigned char)(*key ^ hmac_ipad); (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &b, 1); b = (unsigned char)(*key++ ^ hmac_opad); (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &b, 1); } - for (; i < hashparams->hmac_maxkeylen; i++) { + for(; i < hashparams->hmac_maxkeylen; i++) { (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &hmac_ipad, 1); (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &hmac_opad, 1); } @@ -114,7 +111,8 @@ int Curl_HMAC_final(HMAC_context * ctxt, unsigned char * result) { const HMAC_params * hashparams = ctxt->hmac_hash; - /* Do not get result if called with a null parameter: only release storage. */ + /* Do not get result if called with a null parameter: only release + storage. */ if(!result) result = (unsigned char *) ctxt->hmac_hashctxt2 + diff --git a/project/jni/curl/lib/hostares.c b/project/jni/curl/lib/hostares.c deleted file mode 100644 index 97cb27ab9..000000000 --- a/project/jni/curl/lib/hostares.c +++ /dev/null @@ -1,413 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "setup.h" - -#include - -#ifdef HAVE_LIMITS_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototypes */ -#endif -#ifdef HAVE_UNISTD_H -#include /* for the close() proto */ -#endif -#ifdef __VMS -#include -#include -#include -#endif - -#ifdef HAVE_PROCESS_H -#include -#endif - -#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) -#undef in_addr_t -#define in_addr_t unsigned long -#endif - -#include "urldata.h" -#include "sendf.h" -#include "hostip.h" -#include "hash.h" -#include "share.h" -#include "strerror.h" -#include "url.h" -#include "multiif.h" -#include "inet_pton.h" -#include "connect.h" -#include "select.h" -#include "progress.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/*********************************************************************** - * Only for ares-enabled builds - **********************************************************************/ - -#ifdef CURLRES_ARES - -/* - * Curl_resolv_fdset() is called when someone from the outside world (using - * curl_multi_fdset()) wants to get our fd_set setup and we're talking with - * ares. The caller must make sure that this function is only called when we - * have a working ares channel. - * - * Returns: CURLE_OK always! - */ - -int Curl_resolv_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) - -{ - struct timeval maxtime; - struct timeval timebuf; - struct timeval *timeout; - int max = ares_getsock(conn->data->state.areschannel, - (ares_socket_t *)socks, numsocks); - - - maxtime.tv_sec = CURL_TIMEOUT_RESOLVE; - maxtime.tv_usec = 0; - - timeout = ares_timeout(conn->data->state.areschannel, &maxtime, &timebuf); - - Curl_expire(conn->data, - (timeout->tv_sec * 1000) + (timeout->tv_usec/1000)); - - return max; -} - -/* - * waitperform() - * - * 1) Ask ares what sockets it currently plays with, then - * 2) wait for the timeout period to check for action on ares' sockets. - * 3) tell ares to act on all the sockets marked as "with action" - * - * return number of sockets it worked on - */ - -static int waitperform(struct connectdata *conn, int timeout_ms) -{ - struct SessionHandle *data = conn->data; - int nfds; - int bitmask; - ares_socket_t socks[ARES_GETSOCK_MAXNUM]; - struct pollfd pfd[ARES_GETSOCK_MAXNUM]; - int i; - int num = 0; - - bitmask = ares_getsock(data->state.areschannel, socks, ARES_GETSOCK_MAXNUM); - - for(i=0; i < ARES_GETSOCK_MAXNUM; i++) { - pfd[i].events = 0; - pfd[i].revents = 0; - if(ARES_GETSOCK_READABLE(bitmask, i)) { - pfd[i].fd = socks[i]; - pfd[i].events |= POLLRDNORM|POLLIN; - } - if(ARES_GETSOCK_WRITABLE(bitmask, i)) { - pfd[i].fd = socks[i]; - pfd[i].events |= POLLWRNORM|POLLOUT; - } - if(pfd[i].events != 0) - num++; - else - break; - } - - if(num) - nfds = Curl_poll(pfd, num, timeout_ms); - else - nfds = 0; - - if(!nfds) - /* Call ares_process() unconditonally here, even if we simply timed out - above, as otherwise the ares name resolve won't timeout! */ - ares_process_fd(data->state.areschannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); - else { - /* move through the descriptors and ask for processing on them */ - for(i=0; i < num; i++) - ares_process_fd(data->state.areschannel, - pfd[i].revents & (POLLRDNORM|POLLIN)? - pfd[i].fd:ARES_SOCKET_BAD, - pfd[i].revents & (POLLWRNORM|POLLOUT)? - pfd[i].fd:ARES_SOCKET_BAD); - } - return nfds; -} - -/* - * Curl_is_resolved() is called repeatedly to check if a previous name resolve - * request has completed. It should also make sure to time-out if the - * operation seems to take too long. - * - * Returns normal CURLcode errors. - */ -CURLcode Curl_is_resolved(struct connectdata *conn, - struct Curl_dns_entry **dns) -{ - struct SessionHandle *data = conn->data; - - *dns = NULL; - - waitperform(conn, 0); - - if(conn->async.done) { - /* we're done, kill the ares handle */ - if(!conn->async.dns) { - failf(data, "Could not resolve host: %s (%s)", conn->host.dispname, - ares_strerror(conn->async.status)); - return CURLE_COULDNT_RESOLVE_HOST; - } - *dns = conn->async.dns; - } - - return CURLE_OK; -} - -/* - * Curl_wait_for_resolv() waits for a resolve to finish. This function should - * be avoided since using this risk getting the multi interface to "hang". - * - * If 'entry' is non-NULL, make it point to the resolved dns entry - * - * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and - * CURLE_OPERATION_TIMEDOUT if a time-out occurred. - */ -CURLcode Curl_wait_for_resolv(struct connectdata *conn, - struct Curl_dns_entry **entry) -{ - CURLcode rc=CURLE_OK; - struct SessionHandle *data = conn->data; - long timeout; - struct timeval now = Curl_tvnow(); - - timeout = Curl_timeleft(conn, &now, TRUE); - if(!timeout) - timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */ - - /* Wait for the name resolve query to complete. */ - for(;;) { - struct timeval *tvp, tv, store; - long timediff; - int itimeout; - int timeout_ms; - - itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout; - - store.tv_sec = itimeout/1000; - store.tv_usec = (itimeout%1000)*1000; - - tvp = ares_timeout(data->state.areschannel, &store, &tv); - - /* use the timeout period ares returned to us above if less than one - second is left, otherwise just use 1000ms to make sure the progress - callback gets called frequent enough */ - if(!tvp->tv_sec) - timeout_ms = (int)(tvp->tv_usec/1000); - else - timeout_ms = 1000; - - waitperform(conn, timeout_ms); - - if(conn->async.done) - break; - - if(Curl_pgrsUpdate(conn)) { - rc = CURLE_ABORTED_BY_CALLBACK; - timeout = -1; /* trigger the cancel below */ - } - else { - struct timeval now2 = Curl_tvnow(); - timediff = Curl_tvdiff(now2, now); /* spent time */ - timeout -= timediff?timediff:1; /* always deduct at least 1 */ - now = now2; /* for next loop */ - } - if(timeout < 0) { - /* our timeout, so we cancel the ares operation */ - ares_cancel(data->state.areschannel); - break; - } - } - - /* Operation complete, if the lookup was successful we now have the entry - in the cache. */ - - if(entry) - *entry = conn->async.dns; - - if(!conn->async.dns) { - /* a name was not resolved */ - if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) { - if (conn->bits.httpproxy) { - failf(data, "Resolving proxy timed out: %s", conn->proxy.dispname); - rc = CURLE_COULDNT_RESOLVE_PROXY; - } - else { - failf(data, "Resolving host timed out: %s", conn->host.dispname); - rc = CURLE_COULDNT_RESOLVE_HOST; - } - } - else if(conn->async.done) { - if (conn->bits.httpproxy) { - failf(data, "Could not resolve proxy: %s (%s)", conn->proxy.dispname, - ares_strerror(conn->async.status)); - rc = CURLE_COULDNT_RESOLVE_PROXY; - } - else { - failf(data, "Could not resolve host: %s (%s)", conn->host.dispname, - ares_strerror(conn->async.status)); - rc = CURLE_COULDNT_RESOLVE_HOST; - } - } - else - rc = CURLE_OPERATION_TIMEDOUT; - - /* close the connection, since we can't return failure here without - cleaning up this connection properly */ - conn->bits.close = TRUE; - } - - return rc; -} - -/* - * ares_query_completed_cb() is the callback that ares will call when - * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(), - * when using ares, is completed either successfully or with failure. - */ -static void ares_query_completed_cb(void *arg, /* (struct connectdata *) */ - int status, -#ifdef HAVE_CARES_CALLBACK_TIMEOUTS - int timeouts, -#endif - struct hostent *hostent) -{ - struct connectdata *conn = (struct connectdata *)arg; - struct Curl_addrinfo * ai = NULL; - -#ifdef HAVE_CARES_CALLBACK_TIMEOUTS - (void)timeouts; /* ignored */ -#endif - - if (status == CURL_ASYNC_SUCCESS) { - ai = Curl_he2ai(hostent, conn->async.port); - } - - (void)Curl_addrinfo_callback(arg, status, ai); -} - -/* - * Curl_getaddrinfo() - when using ares - * - * Returns name information about the given hostname and port number. If - * successful, the 'hostent' is returned and the forth argument will point to - * memory we need to free after use. That memory *MUST* be freed with - * Curl_freeaddrinfo(), nothing else. - */ -Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, - const char *hostname, - int port, - int *waitp) -{ - char *bufp; - struct SessionHandle *data = conn->data; - struct in_addr in; - int family = PF_INET; -#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ - struct in6_addr in6; -#endif /* CURLRES_IPV6 */ - - *waitp = 0; /* default to synchronous response */ - - /* First check if this is an IPv4 address string */ - if(Curl_inet_pton(AF_INET, hostname, &in) > 0) { - /* This is a dotted IP address 123.123.123.123-style */ - return Curl_ip2addr(AF_INET, &in, hostname, port); - } - -#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ - /* Otherwise, check if this is an IPv6 address string */ - if (Curl_inet_pton (AF_INET6, hostname, &in6) > 0) { - /* This must be an IPv6 address literal. */ - return Curl_ip2addr(AF_INET6, &in6, hostname, port); - } - - switch(conn->ip_version) { - default: -#if ARES_VERSION >= 0x010601 - family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older - c-ares versions this just falls through and defaults - to PF_INET */ - break; -#endif - case CURL_IPRESOLVE_V4: - family = PF_INET; - break; - case CURL_IPRESOLVE_V6: - family = PF_INET6; - break; - } -#endif /* CURLRES_IPV6 */ - - bufp = strdup(hostname); - - if(bufp) { - Curl_safefree(conn->async.hostname); - conn->async.hostname = bufp; - conn->async.port = port; - conn->async.done = FALSE; /* not done */ - conn->async.status = 0; /* clear */ - conn->async.dns = NULL; /* clear */ - - /* areschannel is already setup in the Curl_open() function */ - ares_gethostbyname(data->state.areschannel, hostname, family, - (ares_host_callback)ares_query_completed_cb, conn); - - *waitp = 1; /* expect asynchronous response */ - } - return NULL; /* no struct yet */ -} -#endif /* CURLRES_ARES */ diff --git a/project/jni/curl/lib/hostasyn.c b/project/jni/curl/lib/hostasyn.c index 127b8d332..c96734a5a 100644 --- a/project/jni/curl/lib/hostasyn.c +++ b/project/jni/curl/lib/hostasyn.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,13 +20,8 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif @@ -36,16 +31,9 @@ #ifdef HAVE_ARPA_INET_H #include #endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototypes */ -#endif -#ifdef HAVE_UNISTD_H -#include /* for the close() proto */ -#endif #ifdef __VMS #include #include -#include #endif #ifdef HAVE_PROCESS_H @@ -59,10 +47,6 @@ #include "share.h" #include "strerror.h" #include "url.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -82,12 +66,12 @@ * * The storage operation locks and unlocks the DNS cache. */ -CURLcode Curl_addrinfo_callback(struct connectdata * conn, +CURLcode Curl_addrinfo_callback(struct connectdata *conn, int status, struct Curl_addrinfo *ai) { struct Curl_dns_entry *dns = NULL; - CURLcode rc = CURLE_OK; + CURLcode result = CURLE_OK; conn->async.status = status; @@ -104,14 +88,15 @@ CURLcode Curl_addrinfo_callback(struct connectdata * conn, if(!dns) { /* failed to store, cleanup and return error */ Curl_freeaddrinfo(ai); - rc = CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; } if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); } - else - rc = CURLE_OUT_OF_MEMORY; + else { + result = CURLE_OUT_OF_MEMORY; + } } conn->async.dns = dns; @@ -121,9 +106,48 @@ CURLcode Curl_addrinfo_callback(struct connectdata * conn, async struct */ conn->async.done = TRUE; - /* ipv4: The input hostent struct will be freed by ares when we return from + /* IPv4: The input hostent struct will be freed by ares when we return from this function */ - return rc; + return result; +} + +/* Call this function after Curl_connect() has returned async=TRUE and + then a successful name resolve has been received. + + Note: this function disconnects and frees the conn data in case of + resolve failure */ +CURLcode Curl_async_resolved(struct connectdata *conn, + bool *protocol_done) +{ + CURLcode result; + + if(conn->async.dns) { + conn->dns_entry = conn->async.dns; + conn->async.dns = NULL; + } + + result = Curl_setup_conn(conn, protocol_done); + + if(result) + /* We're not allowed to return failure with memory left allocated + in the connectdata struct, free those here */ + Curl_disconnect(conn, FALSE); /* close the connection */ + + return result; +} + +/* + * Curl_getaddrinfo() is the generic low-level name resolve API within this + * source file. There are several versions of this function - for different + * name resolve layers (selected at build-time). They all take this same set + * of arguments + */ +Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) +{ + return Curl_resolver_getaddrinfo(conn, hostname, port, waitp); } #endif /* CURLRES_ASYNCH */ diff --git a/project/jni/curl/lib/hostcheck.c b/project/jni/curl/lib/hostcheck.c new file mode 100644 index 000000000..4db9e6ba8 --- /dev/null +++ b/project/jni/curl/lib/hostcheck.c @@ -0,0 +1,147 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_OPENSSL) || defined(USE_AXTLS) || defined(USE_GSKIT) +/* these backends use functions from this file */ + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#include "hostcheck.h" +#include "rawstr.h" +#include "inet_pton.h" + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* + * Match a hostname against a wildcard pattern. + * E.g. + * "foo.host.com" matches "*.host.com". + * + * We use the matching rule described in RFC6125, section 6.4.3. + * https://tools.ietf.org/html/rfc6125#section-6.4.3 + * + * In addition: ignore trailing dots in the host names and wildcards, so that + * the names are used normalized. This is what the browsers do. + * + * Do not allow wildcard matching on IP numbers. There are apparently + * certificates being used with an IP address in the CN field, thus making no + * apparent distinction between a name and an IP. We need to detect the use of + * an IP address and not wildcard match on such names. + * + * NOTE: hostmatch() gets called with copied buffers so that it can modify the + * contents at will. + */ + +static int hostmatch(char *hostname, char *pattern) +{ + const char *pattern_label_end, *pattern_wildcard, *hostname_label_end; + int wildcard_enabled; + size_t prefixlen, suffixlen; + struct in_addr ignored; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 si6; +#endif + + /* normalize pattern and hostname by stripping off trailing dots */ + size_t len = strlen(hostname); + if(hostname[len-1]=='.') + hostname[len-1]=0; + len = strlen(pattern); + if(pattern[len-1]=='.') + pattern[len-1]=0; + + pattern_wildcard = strchr(pattern, '*'); + if(pattern_wildcard == NULL) + return Curl_raw_equal(pattern, hostname) ? + CURL_HOST_MATCH : CURL_HOST_NOMATCH; + + /* detect IP address as hostname and fail the match if so */ + if(Curl_inet_pton(AF_INET, hostname, &ignored) > 0) + return CURL_HOST_NOMATCH; +#ifdef ENABLE_IPV6 + else if(Curl_inet_pton(AF_INET6, hostname, &si6.sin6_addr) > 0) + return CURL_HOST_NOMATCH; +#endif + + /* We require at least 2 dots in pattern to avoid too wide wildcard + match. */ + wildcard_enabled = 1; + pattern_label_end = strchr(pattern, '.'); + if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL || + pattern_wildcard > pattern_label_end || + Curl_raw_nequal(pattern, "xn--", 4)) { + wildcard_enabled = 0; + } + if(!wildcard_enabled) + return Curl_raw_equal(pattern, hostname) ? + CURL_HOST_MATCH : CURL_HOST_NOMATCH; + + hostname_label_end = strchr(hostname, '.'); + if(hostname_label_end == NULL || + !Curl_raw_equal(pattern_label_end, hostname_label_end)) + return CURL_HOST_NOMATCH; + + /* The wildcard must match at least one character, so the left-most + label of the hostname is at least as large as the left-most label + of the pattern. */ + if(hostname_label_end - hostname < pattern_label_end - pattern) + return CURL_HOST_NOMATCH; + + prefixlen = pattern_wildcard - pattern; + suffixlen = pattern_label_end - (pattern_wildcard+1); + return Curl_raw_nequal(pattern, hostname, prefixlen) && + Curl_raw_nequal(pattern_wildcard+1, hostname_label_end - suffixlen, + suffixlen) ? + CURL_HOST_MATCH : CURL_HOST_NOMATCH; +} + +int Curl_cert_hostcheck(const char *match_pattern, const char *hostname) +{ + char *matchp; + char *hostp; + int res = 0; + if(!match_pattern || !*match_pattern || + !hostname || !*hostname) /* sanity check */ + ; + else { + matchp = strdup(match_pattern); + if(matchp) { + hostp = strdup(hostname); + if(hostp) { + if(hostmatch(hostp, matchp) == CURL_HOST_MATCH) + res= 1; + free(hostp); + } + free(matchp); + } + } + + return res; +} + +#endif /* OPENSSL or AXTLS or GSKIT */ diff --git a/project/jni/curl/lib/hostcheck.h b/project/jni/curl/lib/hostcheck.h new file mode 100644 index 000000000..86e3b96a9 --- /dev/null +++ b/project/jni/curl/lib/hostcheck.h @@ -0,0 +1,32 @@ +#ifndef HEADER_CURL_HOSTCHECK_H +#define HEADER_CURL_HOSTCHECK_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include + +#define CURL_HOST_NOMATCH 0 +#define CURL_HOST_MATCH 1 +int Curl_cert_hostcheck(const char *match_pattern, const char *hostname); + +#endif /* HEADER_CURL_HOSTCHECK_H */ + diff --git a/project/jni/curl/lib/hostip.c b/project/jni/curl/lib/hostip.c index 3db5b4967..a4bde568f 100644 --- a/project/jni/curl/lib/hostip.c +++ b/project/jni/curl/lib/hostip.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,13 +20,8 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif @@ -36,16 +31,9 @@ #ifdef HAVE_ARPA_INET_H #include #endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototypes */ -#endif -#ifdef HAVE_UNISTD_H -#include /* for the close() proto */ -#endif #ifdef __VMS #include #include -#include #endif #ifdef HAVE_SETJMP_H @@ -68,10 +56,7 @@ #include "url.h" #include "inet_ntop.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -110,13 +95,15 @@ * hostip.c - method-independent resolver functions and utility functions * hostasyn.c - functions for asynchronous name resolves * hostsyn.c - functions for synchronous name resolves - * hostares.c - functions for ares-using name resolves - * hostthre.c - functions for threaded name resolves - * hostip4.c - ipv4-specific functions - * hostip6.c - ipv6-specific functions + * hostip4.c - IPv4 specific functions + * hostip6.c - IPv6 specific functions * + * The two asynchronous name resolver backends are implemented in: + * asyn-ares.c - functions for ares-using name resolves + * asyn-thread.c - functions for threaded name resolves + * The hostip.h is the united header file for all this. It defines the - * CURLRES_* defines based on the config*.h and setup.h defines. + * CURLRES_* defines based on the config*.h and curl_setup.h defines. */ /* These two symbols are for the global DNS cache */ @@ -150,7 +137,7 @@ struct curl_hash *Curl_global_host_cache_init(void) void Curl_global_host_cache_dtor(void) { if(host_cache_initialized) { - Curl_hash_clean(&hostname_cache); + Curl_hash_destroy(&hostname_cache); host_cache_initialized = 0; } } @@ -205,14 +192,23 @@ Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize) } /* - * Return a hostcache id string for the providing host + port, to be used by + * Return a hostcache id string for the provided host + port, to be used by * the DNS caching. */ static char * -create_hostcache_id(const char *server, int port) +create_hostcache_id(const char *name, int port) { /* create and return the new allocated entry */ - return aprintf("%s:%d", server, port); + char *id = aprintf("%s:%d", name, port); + char *ptr = id; + if(ptr) { + /* lower case the name part */ + while(*ptr && (*ptr != ':')) { + *ptr = (char)TOLOWER(*ptr); + ptr++; + } + } + return id; } struct hostcache_prune_data { @@ -234,7 +230,8 @@ hostcache_timestamp_remove(void *datap, void *hc) (struct hostcache_prune_data *) datap; struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc; - return (data->now - c->timestamp >= data->cache_timeout); + return (0 != c->timestamp) + && (data->now - c->timestamp >= data->cache_timeout); } /* @@ -280,33 +277,6 @@ void Curl_hostcache_prune(struct SessionHandle *data) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); } -/* - * Check if the entry should be pruned. Assumes a locked cache. - */ -static int -remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns) -{ - struct hostcache_prune_data user; - - if( !dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache) - /* cache forever means never prune, and NULL hostcache means - we can't do it */ - return 0; - - time(&user.now); - user.cache_timeout = data->set.dns_cache_timeout; - - if( !hostcache_timestamp_remove(&user,dns) ) - return 0; - - Curl_hash_clean_with_criterium(data->dns.hostcache, - (void *) &user, - hostcache_timestamp_remove); - - return 1; -} - - #ifdef HAVE_SIGSETJMP /* Beware this is a global and unique instance. This is used to store the return address that we can jump back to from inside a signal handler. This @@ -314,6 +284,82 @@ remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns) sigjmp_buf curl_jmpenv; #endif +/* lookup address, returns entry if found and not stale */ +static struct Curl_dns_entry * +fetch_addr(struct connectdata *conn, + const char *hostname, + int port) +{ + char *entry_id = NULL; + struct Curl_dns_entry *dns = NULL; + size_t entry_len; + struct SessionHandle *data = conn->data; + + /* Create an entry id, based upon the hostname and port */ + entry_id = create_hostcache_id(hostname, port); + /* If we can't create the entry id, fail */ + if(!entry_id) + return dns; + + entry_len = strlen(entry_id); + + /* See if its already in our dns cache */ + dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1); + + if(dns && (data->set.dns_cache_timeout != -1)) { + /* See whether the returned entry is stale. Done before we release lock */ + struct hostcache_prune_data user; + + time(&user.now); + user.cache_timeout = data->set.dns_cache_timeout; + + if(hostcache_timestamp_remove(&user, dns)) { + infof(data, "Hostname in DNS cache was stale, zapped\n"); + dns = NULL; /* the memory deallocation is being handled by the hash */ + Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1); + } + } + + /* free the allocated entry_id again */ + free(entry_id); + + return dns; +} + +/* + * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache. + * + * Curl_resolv() checks initially and multi_runsingle() checks each time + * it discovers the handle in the state WAITRESOLVE whether the hostname + * has already been resolved and the address has already been stored in + * the DNS cache. This short circuits waiting for a lot of pending + * lookups for the same hostname requested by different handles. + * + * Returns the Curl_dns_entry entry pointer or NULL if not in the cache. + * + * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after + * use, or we'll leak memory! + */ +struct Curl_dns_entry * +Curl_fetch_addr(struct connectdata *conn, + const char *hostname, + int port) +{ + struct SessionHandle *data = conn->data; + struct Curl_dns_entry *dns = NULL; + + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + dns = fetch_addr(conn, hostname, port); + + if(dns) dns->inuse++; /* we use it! */ + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + + return dns; +} /* * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache. @@ -349,11 +395,11 @@ Curl_cache_addr(struct SessionHandle *data, return NULL; } - dns->inuse = 0; /* init to not used */ + dns->inuse = 1; /* the cache has the first reference */ dns->addr = addr; /* this is the address(es) */ time(&dns->timestamp); if(dns->timestamp == 0) - dns->timestamp = 1; /* zero indicates that entry isn't in hash table */ + dns->timestamp = 1; /* zero indicates CURLOPT_RESOLVE entry */ /* Store the resolved data in our DNS cache. */ dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1, @@ -399,37 +445,20 @@ int Curl_resolv(struct connectdata *conn, int port, struct Curl_dns_entry **entry) { - char *entry_id = NULL; struct Curl_dns_entry *dns = NULL; - size_t entry_len; struct SessionHandle *data = conn->data; CURLcode result; int rc = CURLRESOLV_ERROR; /* default to failure */ *entry = NULL; - /* Create an entry id, based upon the hostname and port */ - entry_id = create_hostcache_id(hostname, port); - /* If we can't create the entry id, fail */ - if(!entry_id) - return rc; - - entry_len = strlen(entry_id); - if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - /* See if its already in our dns cache */ - dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1); - - /* free the allocated entry_id again */ - free(entry_id); - - /* See whether the returned entry is stale. Done before we release lock */ - if( remove_entry_if_stale(data, dns) ) - dns = NULL; /* the memory deallocation is being handled by the hash */ + dns = fetch_addr(conn, hostname, port); if(dns) { + infof(data, "Hostname %s was found in DNS cache\n", hostname); dns->inuse++; /* we use it! */ rc = CURLRESOLV_RESOLVED; } @@ -464,7 +493,7 @@ int Curl_resolv(struct connectdata *conn, /* the response to our resolve call will come asynchronously at a later time, good or bad */ /* First, check that we haven't received the info by now */ - result = Curl_is_resolved(conn, &dns); + result = Curl_resolver_is_resolved(conn, &dns); if(result) /* error detected */ return CURLRESOLV_ERROR; if(dns) @@ -558,8 +587,12 @@ int Curl_resolv_timeout(struct connectdata *conn, *entry = NULL; + if(timeoutms < 0) + /* got an already expired timeout */ + return CURLRESOLV_TIMEDOUT; + #ifdef USE_ALARM_TIMEOUT - if (data->set.no_signal) + if(data->set.no_signal) /* Ignore the timeout when signals are disabled */ timeout = 0; else @@ -574,32 +607,6 @@ int Curl_resolv_timeout(struct connectdata *conn, we want to wait less than one second we must bail out already now. */ return CURLRESOLV_TIMEDOUT; - /************************************************************* - * Set signal handler to catch SIGALRM - * Store the old value to be able to set it back later! - *************************************************************/ -#ifdef HAVE_SIGACTION - sigaction(SIGALRM, NULL, &sigact); - keep_sigact = sigact; - keep_copysig = TRUE; /* yes, we have a copy */ - sigact.sa_handler = alarmfunc; -#ifdef SA_RESTART - /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */ - sigact.sa_flags &= ~SA_RESTART; -#endif - /* now set the new struct */ - sigaction(SIGALRM, &sigact, NULL); -#else /* HAVE_SIGACTION */ - /* no sigaction(), revert to the much lamer signal() */ -#ifdef HAVE_SIGNAL - keep_sigact = signal(SIGALRM, alarmfunc); -#endif -#endif /* HAVE_SIGACTION */ - - /* alarm() makes a signal get sent when the timeout fires off, and that - will abort system calls */ - prev_alarm = alarm(curlx_sltoui(timeout/1000L)); - /* This allows us to time-out from the name resolver, as the timeout will generate a signal and we will siglongjmp() from that here. This technique has problems (see alarmfunc). @@ -612,6 +619,33 @@ int Curl_resolv_timeout(struct connectdata *conn, rc = CURLRESOLV_ERROR; goto clean_up; } + else { + /************************************************************* + * Set signal handler to catch SIGALRM + * Store the old value to be able to set it back later! + *************************************************************/ +#ifdef HAVE_SIGACTION + sigaction(SIGALRM, NULL, &sigact); + keep_sigact = sigact; + keep_copysig = TRUE; /* yes, we have a copy */ + sigact.sa_handler = alarmfunc; +#ifdef SA_RESTART + /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */ + sigact.sa_flags &= ~SA_RESTART; +#endif + /* now set the new struct */ + sigaction(SIGALRM, &sigact, NULL); +#else /* HAVE_SIGACTION */ + /* no sigaction(), revert to the much lamer signal() */ +#ifdef HAVE_SIGNAL + keep_sigact = signal(SIGALRM, alarmfunc); +#endif +#endif /* HAVE_SIGACTION */ + + /* alarm() makes a signal get sent when the timeout fires off, and that + will abort system calls */ + prev_alarm = alarm(curlx_sltoui(timeout/1000L)); + } #else #ifndef CURLRES_ASYNCH @@ -678,47 +712,169 @@ clean_up: * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been * made, the struct may be destroyed due to pruning. It is important that only * one unlock is made for each Curl_resolv() call. + * + * May be called with 'data' == NULL for global cache. */ void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns) { - DEBUGASSERT(dns && (dns->inuse>0)); - - if(data->share) + if(data && data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - dns->inuse--; - /* only free if nobody is using AND it is not in hostcache (timestamp == - 0) */ - if (dns->inuse == 0 && dns->timestamp == 0) { - Curl_freeaddrinfo(dns->addr); - free(dns); - } + freednsentry(dns); - if(data->share) + if(data && data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); } /* - * File-internal: free a cache dns entry. + * File-internal: release cache dns entry reference, free if inuse drops to 0 */ static void freednsentry(void *freethis) { - struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis; + struct Curl_dns_entry *dns = (struct Curl_dns_entry *) freethis; + DEBUGASSERT(dns && (dns->inuse>0)); - /* mark the entry as not in hostcache */ - p->timestamp = 0; - if (p->inuse == 0) { - Curl_freeaddrinfo(p->addr); - free(p); + dns->inuse--; + if(dns->inuse == 0) { + Curl_freeaddrinfo(dns->addr); + free(dns); } } /* - * Curl_mk_dnscache() creates a new DNS cache and returns the handle for it. + * Curl_mk_dnscache() inits a new DNS cache and returns success/failure. */ -struct curl_hash *Curl_mk_dnscache(void) +int Curl_mk_dnscache(struct curl_hash *hash) { - return Curl_hash_alloc(7, Curl_hash_str, Curl_str_key_compare, freednsentry); + return Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare, + freednsentry); +} + +/* + * Curl_hostcache_clean() + * + * This _can_ be called with 'data' == NULL but then of course no locking + * can be done! + */ + +void Curl_hostcache_clean(struct SessionHandle *data, + struct curl_hash *hash) +{ + if(data && data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + Curl_hash_clean(hash); + + if(data && data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); } +CURLcode Curl_loadhostpairs(struct SessionHandle *data) +{ + struct curl_slist *hostp; + char hostname[256]; + char address[256]; + int port; + + for(hostp = data->change.resolve; hostp; hostp = hostp->next ) { + if(!hostp->data) + continue; + if(hostp->data[0] == '-') { + char *entry_id; + size_t entry_len; + + if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) { + infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'!\n", + hostp->data); + continue; + } + + /* Create an entry id, based upon the hostname and port */ + entry_id = create_hostcache_id(hostname, port); + /* If we can't create the entry id, fail */ + if(!entry_id) { + return CURLE_OUT_OF_MEMORY; + } + + entry_len = strlen(entry_id); + + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + /* delete entry, ignore if it didn't exist */ + Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1); + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + + /* free the allocated entry_id again */ + free(entry_id); + } + else { + struct Curl_dns_entry *dns; + Curl_addrinfo *addr; + char *entry_id; + size_t entry_len; + + if(3 != sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port, + address)) { + infof(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!\n", + hostp->data); + continue; + } + + addr = Curl_str2addr(address, port); + if(!addr) { + infof(data, "Address in '%s' found illegal!\n", hostp->data); + continue; + } + + /* Create an entry id, based upon the hostname and port */ + entry_id = create_hostcache_id(hostname, port); + /* If we can't create the entry id, fail */ + if(!entry_id) { + Curl_freeaddrinfo(addr); + return CURLE_OUT_OF_MEMORY; + } + + entry_len = strlen(entry_id); + + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + /* See if its already in our dns cache */ + dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1); + + /* free the allocated entry_id again */ + free(entry_id); + + if(!dns) { + /* if not in the cache already, put this host in the cache */ + dns = Curl_cache_addr(data, addr, hostname, port); + if(dns) { + dns->timestamp = 0; /* mark as added by CURLOPT_RESOLVE */ + /* release the returned reference; the cache itself will keep the + * entry alive: */ + dns->inuse--; + } + } + else + /* this is a duplicate, free it again */ + Curl_freeaddrinfo(addr); + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + + if(!dns) { + Curl_freeaddrinfo(addr); + return CURLE_OUT_OF_MEMORY; + } + infof(data, "Added %s:%d:%s to DNS cache\n", + hostname, port, address); + } + } + data->change.resolve = NULL; /* dealt with now */ + + return CURLE_OK; +} diff --git a/project/jni/curl/lib/hostip.h b/project/jni/curl/lib/hostip.h index 2f8d4b56c..37ccd96e1 100644 --- a/project/jni/curl/lib/hostip.h +++ b/project/jni/curl/lib/hostip.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,9 +22,10 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #include "hash.h" #include "curl_addrinfo.h" +#include "asyn.h" #ifdef HAVE_SETJMP_H #include @@ -35,14 +36,6 @@ #define in_addr_t unsigned long #endif -/* - * Comfortable CURLRES_* definitions are included from setup.h - */ - -#ifdef USE_ARES -#include -#endif - /* Allocate enough memory to hold the full name information structs and * everything. OSF1 is known to require at least 8872 bytes. The buffer * required for storing all possible aliases and IP numbers is according to @@ -53,17 +46,7 @@ #define CURL_TIMEOUT_RESOLVE 300 /* when using asynch methods, we allow this many seconds for a name resolve */ -#ifdef CURLRES_ARES -#define CURL_ASYNC_SUCCESS ARES_SUCCESS -#if ARES_VERSION >= 0x010500 -/* c-ares 1.5.0 or later, the callback proto is modified */ -#define HAVE_CARES_CALLBACK_TIMEOUTS 1 -#endif -#else #define CURL_ASYNC_SUCCESS CURLE_OK -#define ares_cancel(x) do {} while(0) -#define ares_destroy(x) do {} while(0) -#endif struct addrinfo; struct hostent; @@ -82,11 +65,10 @@ void Curl_global_host_cache_dtor(void); struct Curl_dns_entry { Curl_addrinfo *addr; - /* timestamp == 0 -- entry not in hostcache - timestamp != 0 -- entry is in hostcache */ + /* timestamp == 0 -- CURLOPT_RESOLVE entry, doesn't timeout */ time_t timestamp; - long inuse; /* use-counter, make very sure you decrease this - when you're done using the address you received */ + /* use-counter, use Curl_resolv_unlock to release reference */ + long inuse; }; /* @@ -107,12 +89,22 @@ int Curl_resolv_timeout(struct connectdata *conn, const char *hostname, int port, struct Curl_dns_entry **dnsentry, long timeoutms); +#ifdef CURLRES_IPV6 +/* + * Curl_ipv6works() returns TRUE if IPv6 seems to work. + */ +bool Curl_ipv6works(void); +#else +#define Curl_ipv6works() FALSE +#endif + /* * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've * been set and returns TRUE if they are OK. */ bool Curl_ipvalid(struct connectdata *conn); + /* * Curl_getaddrinfo() is the generic low-level name resolve API within this * source file. There are several versions of this function - for different @@ -124,20 +116,6 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, int port, int *waitp); -CURLcode Curl_is_resolved(struct connectdata *conn, - struct Curl_dns_entry **dns); -CURLcode Curl_wait_for_resolv(struct connectdata *conn, - struct Curl_dns_entry **dnsentry); - -/* Curl_resolv_getsock() is a generic function that exists in multiple - versions depending on what name resolve technology we've built to use. The - function is called from the multi_getsock() function. 'sock' is a pointer - to an array to hold the file descriptors, with 'numsock' being the size of - that array (in number of entries). This function is supposed to return - bitmask indicating what file descriptors (referring to array indexes in the - 'sock' array) to wait for, read/write. */ -int Curl_resolv_getsock(struct connectdata *conn, curl_socket_t *sock, - int numsocks); /* unlock a previously resolved dns entry */ void Curl_resolv_unlock(struct SessionHandle *data, @@ -146,8 +124,8 @@ void Curl_resolv_unlock(struct SessionHandle *data, /* for debugging purposes only: */ void Curl_scan_cache_used(void *user, void *ptr); -/* make a new dns cache and return the handle */ -struct curl_hash *Curl_mk_dnscache(void); +/* init a new dns cache and return success */ +int Curl_mk_dnscache(struct curl_hash *hash); /* prune old entries from the DNS cache */ void Curl_hostcache_prune(struct SessionHandle *data); @@ -167,11 +145,18 @@ int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa, /* IPv4 threadsafe resolve function used for synch and asynch builds */ Curl_addrinfo *Curl_ipv4_resolve_r(const char * hostname, int port); +CURLcode Curl_async_resolved(struct connectdata *conn, + bool *protocol_connect); + +#ifndef CURLRES_ASYNCH +#define Curl_async_resolved(x,y) CURLE_OK +#endif + /* * Curl_addrinfo_callback() is used when we build with any asynch specialty. * Handles end of async request processing. Inserts ai into hostcache when * status is CURL_ASYNC_SUCCESS. Twiddles fields in conn to indicate async - * request completed wether successfull or failed. + * request completed whether successful or failed. */ CURLcode Curl_addrinfo_callback(struct connectdata *conn, int status, @@ -185,6 +170,18 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn, const char *Curl_printable_address(const Curl_addrinfo *ip, char *buf, size_t bufsize); +/* + * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache. + * + * Returns the Curl_dns_entry entry pointer or NULL if not in the cache. + * + * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after + * use, or we'll leak memory! + */ +struct Curl_dns_entry * +Curl_fetch_addr(struct connectdata *conn, + const char *hostname, + int port); /* * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache. * @@ -194,13 +191,6 @@ struct Curl_dns_entry * Curl_cache_addr(struct SessionHandle *data, Curl_addrinfo *addr, const char *hostname, int port); -/* - * Curl_destroy_thread_data() cleans up async resolver data. - * Complementary of ares_destroy. - */ -struct Curl_async; /* forward-declaration */ -void Curl_destroy_thread_data(struct Curl_async *async); - #ifndef INADDR_NONE #define CURL_INADDR_NONE (in_addr_t) ~0 #else @@ -216,4 +206,45 @@ void Curl_destroy_thread_data(struct Curl_async *async); extern sigjmp_buf curl_jmpenv; #endif +/* + * Function provided by the resolver backend to set DNS servers to use. + */ +CURLcode Curl_set_dns_servers(struct SessionHandle *data, char *servers); + +/* + * Function provided by the resolver backend to set + * outgoing interface to use for DNS requests + */ +CURLcode Curl_set_dns_interface(struct SessionHandle *data, + const char *interf); + +/* + * Function provided by the resolver backend to set + * local IPv4 address to use as source address for DNS requests + */ +CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, + const char *local_ip4); + +/* + * Function provided by the resolver backend to set + * local IPv6 address to use as source address for DNS requests + */ +CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, + const char *local_ip6); + +/* + * Clean off entries from the cache + */ +void Curl_hostcache_clean(struct SessionHandle *data, struct curl_hash *hash); + +/* + * Destroy the hostcache of this handle. + */ +void Curl_hostcache_destroy(struct SessionHandle *data); + +/* + * Populate the cache with specified entries from CURLOPT_RESOLVE. + */ +CURLcode Curl_loadhostpairs(struct SessionHandle *data); + #endif /* HEADER_CURL_HOSTIP_H */ diff --git a/project/jni/curl/lib/hostip4.c b/project/jni/curl/lib/hostip4.c index 6dc525765..25c452965 100644 --- a/project/jni/curl/lib/hostip4.c +++ b/project/jni/curl/lib/hostip4.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,14 +20,8 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#include -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif @@ -37,16 +31,9 @@ #ifdef HAVE_ARPA_INET_H #include #endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototypes */ -#endif -#ifdef HAVE_UNISTD_H -#include /* for the close() proto */ -#endif #ifdef __VMS #include #include -#include #endif #ifdef HAVE_PROCESS_H @@ -61,18 +48,15 @@ #include "strerror.h" #include "url.h" #include "inet_pton.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /*********************************************************************** - * Only for plain-ipv4 builds + * Only for plain IPv4 builds **********************************************************************/ -#ifdef CURLRES_IPV4 /* plain ipv4 code coming up */ +#ifdef CURLRES_IPV4 /* plain IPv4 code coming up */ /* * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've * been set and returns TRUE if they are OK. @@ -80,15 +64,16 @@ bool Curl_ipvalid(struct connectdata *conn) { if(conn->ip_version == CURL_IPRESOLVE_V6) - /* an ipv6 address was requested and we can't get/use one */ + /* An IPv6 address was requested and we can't get/use one */ return FALSE; return TRUE; /* OK, proceed */ } #ifdef CURLRES_SYNCH + /* - * Curl_getaddrinfo() - the ipv4 synchronous version. + * Curl_getaddrinfo() - the IPv4 synchronous version. * * The original code to this function was from the Dancer source code, written * by Bjorn Reese, it has since been patched and modified considerably. @@ -125,6 +110,8 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, #endif /* CURLRES_SYNCH */ #endif /* CURLRES_IPV4 */ +#if defined(CURLRES_IPV4) && !defined(CURLRES_ARES) + /* * Curl_ipv4_resolve_r() - ipv4 threadsafe resolver function. * @@ -150,7 +137,7 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, #if defined(HAVE_GETADDRINFO_THREADSAFE) else { struct addrinfo hints; - char sbuf[NI_MAXSERV]; + char sbuf[12]; char *sbufptr = NULL; memset(&hints, 0, sizeof(hints)); @@ -317,3 +304,4 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, return ai; } +#endif /* defined(CURLRES_IPV4) && !defined(CURLRES_ARES) */ diff --git a/project/jni/curl/lib/hostip6.c b/project/jni/curl/lib/hostip6.c index ca0280790..2f58376d2 100644 --- a/project/jni/curl/lib/hostip6.c +++ b/project/jni/curl/lib/hostip6.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,13 +20,8 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif @@ -36,16 +31,9 @@ #ifdef HAVE_ARPA_INET_H #include #endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototypes */ -#endif -#ifdef HAVE_UNISTD_H -#include /* for the close() proto */ -#endif #ifdef __VMS #include #include -#include #endif #ifdef HAVE_PROCESS_H @@ -61,24 +49,21 @@ #include "url.h" #include "inet_pton.h" #include "connect.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "curl_printf.h" #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" /*********************************************************************** - * Only for ipv6-enabled builds + * Only for IPv6-enabled builds **********************************************************************/ #ifdef CURLRES_IPV6 - #if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) /* These are strictly for memory tracing and are using the same style as the * family otherwise present in memdebug.c. I put these ones here since they - * require a bunch of structs I didn't wanna include in memdebug.c + * require a bunch of structs I didn't want to include in memdebug.c */ /* @@ -108,20 +93,38 @@ int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa, } #endif /* defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) */ +/* + * Curl_ipv6works() returns TRUE if IPv6 seems to work. + */ +bool Curl_ipv6works(void) +{ + /* the nature of most system is that IPv6 status doesn't come and go + during a program's lifetime so we only probe the first time and then we + have the info kept for fast re-use */ + static int ipv6_works = -1; + if(-1 == ipv6_works) { + /* probe to see if we have a working IPv6 stack */ + curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); + if(s == CURL_SOCKET_BAD) + /* an IPv6 address was requested but we can't get/use one */ + ipv6_works = 0; + else { + ipv6_works = 1; + Curl_closesocket(NULL, s); + } + } + return (ipv6_works>0)?TRUE:FALSE; +} + /* * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've * been set and returns TRUE if they are OK. */ bool Curl_ipvalid(struct connectdata *conn) { - if(conn->ip_version == CURL_IPRESOLVE_V6) { - /* see if we have an IPv6 stack */ - curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); - if(s == CURL_SOCKET_BAD) - /* an ipv6 address was requested and we can't get/use one */ - return FALSE; - sclose(s); - } + if(conn->ip_version == CURL_IPRESOLVE_V6) + return Curl_ipv6works(); + return TRUE; } @@ -131,7 +134,7 @@ bool Curl_ipvalid(struct connectdata *conn) static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai) { printf("dump_addrinfo:\n"); - for ( ; ai; ai = ai->ai_next) { + for(; ai; ai = ai->ai_next) { char buf[INET6_ADDRSTRLEN]; printf(" fam %2d, CNAME %s, ", @@ -143,11 +146,11 @@ static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai) } } #else -#define dump_addrinfo(x,y) +#define dump_addrinfo(x,y) Curl_nop_stmt #endif /* - * Curl_getaddrinfo() when built ipv6-enabled (non-threading and + * Curl_getaddrinfo() when built IPv6-enabled (non-threading and * non-ares version). * * Returns name information about the given hostname and port number. If @@ -163,17 +166,17 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, struct addrinfo hints; Curl_addrinfo *res; int error; - char sbuf[NI_MAXSERV]; + char sbuf[12]; char *sbufptr = NULL; char addrbuf[128]; int pf; +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) struct SessionHandle *data = conn->data; +#endif *waitp = 0; /* synchronous response only */ - /* - * Check if a limited name resolve has been requested. - */ + /* Check if a limited name resolve has been requested */ switch(conn->ip_version) { case CURL_IPRESOLVE_V4: pf = PF_INET; @@ -186,23 +189,9 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, break; } - if (pf != PF_INET) { - /* see if we have an IPv6 stack */ - curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); - if(s == CURL_SOCKET_BAD) { - /* Some non-IPv6 stacks have been found to make very slow name resolves - * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if - * the stack seems to be a non-ipv6 one. */ - - pf = PF_INET; - } - else { - /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest - * possible checks. And close the socket again. - */ - sclose(s); - } - } + if((pf != PF_INET) && !Curl_ipv6works()) + /* The stack seems to be a non-IPv6 one */ + pf = PF_INET; memset(&hints, 0, sizeof(hints)); hints.ai_family = pf; @@ -218,6 +207,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, snprintf(sbuf, sizeof(sbuf), "%d", port); sbufptr=sbuf; } + error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res); if(error) { infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port); @@ -229,5 +219,5 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, return res; } #endif /* CURLRES_SYNCH */ -#endif /* CURLRES_IPV6 */ +#endif /* CURLRES_IPV6 */ diff --git a/project/jni/curl/lib/hostsyn.c b/project/jni/curl/lib/hostsyn.c index b68e4702e..db4c82fcc 100644 --- a/project/jni/curl/lib/hostsyn.c +++ b/project/jni/curl/lib/hostsyn.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,13 +20,8 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif @@ -36,16 +31,9 @@ #ifdef HAVE_ARPA_INET_H #include #endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototypes */ -#endif -#ifdef HAVE_UNISTD_H -#include /* for the close() proto */ -#endif #ifdef __VMS #include #include -#include #endif #ifdef HAVE_PROCESS_H @@ -59,10 +47,6 @@ #include "share.h" #include "strerror.h" #include "url.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -73,51 +57,51 @@ #ifdef CURLRES_SYNCH /* - * Curl_wait_for_resolv() for synch-builds. Curl_resolv() can never return - * wait==TRUE, so this function will never be called. If it still gets called, - * we return failure at once. - * - * We provide this function only to allow multi.c to remain unaware if we are - * doing asynch resolves or not. + * Function provided by the resolver backend to set DNS servers to use. */ -CURLcode Curl_wait_for_resolv(struct connectdata *conn, - struct Curl_dns_entry **entry) +CURLcode Curl_set_dns_servers(struct SessionHandle *data, + char *servers) { - (void)conn; - *entry=NULL; - return CURLE_COULDNT_RESOLVE_HOST; + (void)data; + (void)servers; + return CURLE_NOT_BUILT_IN; + } /* - * This function will never be called when synch-built. If it still gets - * called, we return failure at once. - * - * We provide this function only to allow multi.c to remain unaware if we are - * doing asynch resolves or not. + * Function provided by the resolver backend to set + * outgoing interface to use for DNS requests */ -CURLcode Curl_is_resolved(struct connectdata *conn, - struct Curl_dns_entry **dns) +CURLcode Curl_set_dns_interface(struct SessionHandle *data, + const char *interf) { - (void)conn; - *dns = NULL; - - return CURLE_COULDNT_RESOLVE_HOST; + (void)data; + (void)interf; + return CURLE_NOT_BUILT_IN; } /* - * We just return OK, this function is never actually used for synch builds. - * It is present here to keep #ifdefs out from multi.c + * Function provided by the resolver backend to set + * local IPv4 address to use as source address for DNS requests */ - -int Curl_resolv_getsock(struct connectdata *conn, - curl_socket_t *sock, - int numsocks) +CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, + const char *local_ip4) { - (void)conn; - (void)sock; - (void)numsocks; + (void)data; + (void)local_ip4; + return CURLE_NOT_BUILT_IN; +} - return 0; /* no bits since we don't use any socks */ +/* + * Function provided by the resolver backend to set + * local IPv6 address to use as source address for DNS requests + */ +CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, + const char *local_ip6) +{ + (void)data; + (void)local_ip6; + return CURLE_NOT_BUILT_IN; } #endif /* truly sync */ diff --git a/project/jni/curl/lib/http.c b/project/jni/curl/lib/http.c index e35437f1e..b85ff0d5a 100644 --- a/project/jni/curl/lib/http.c +++ b/project/jni/curl/lib/http.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,39 +20,14 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_HTTP -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include -#ifdef WIN32 -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_TIME_H -#ifdef TIME_WITH_SYS_TIME -#include -#endif -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif #ifdef HAVE_NETDB_H #include #endif @@ -70,45 +45,43 @@ #include #endif -#endif - #include "urldata.h" #include #include "transfer.h" #include "sendf.h" -#include "easyif.h" /* for Curl_convert_... prototypes */ #include "formdata.h" #include "progress.h" #include "curl_base64.h" #include "cookie.h" #include "strequal.h" -#include "sslgen.h" +#include "vtls/vtls.h" #include "http_digest.h" -#include "http_ntlm.h" +#include "curl_ntlm.h" +#include "curl_ntlm_wb.h" #include "http_negotiate.h" #include "url.h" #include "share.h" #include "hostip.h" #include "http.h" -#include "curl_memory.h" #include "select.h" #include "parsedate.h" /* for the week day and month names */ #include "strtoofft.h" #include "multiif.h" #include "rawstr.h" #include "content_encoding.h" -#include "rtsp.h" +#include "http_proxy.h" #include "warnless.h" +#include "non-ascii.h" +#include "conncache.h" +#include "pipeline.h" +#include "http2.h" +#include "connect.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" -/* Default proxy timeout in milliseconds */ -#define PROXY_TIMEOUT (3600*1000) - /* * Forward declarations. */ @@ -116,6 +89,8 @@ static int http_getsock_do(struct connectdata *conn, curl_socket_t *socks, int numsocks); +static int http_should_fail(struct connectdata *conn); + #ifdef USE_SSL static CURLcode https_connecting(struct connectdata *conn, bool *done); static int https_getsock(struct connectdata *conn, @@ -130,7 +105,7 @@ static int https_getsock(struct connectdata *conn, */ const struct Curl_handler Curl_handler_http = { "HTTP", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -139,10 +114,13 @@ const struct Curl_handler Curl_handler_http = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ http_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_HTTP, /* defport */ - PROT_HTTP, /* protocol */ + CURLPROTO_HTTP, /* protocol */ + PROTOPT_CREDSPERREQUEST /* flags */ }; #ifdef USE_SSL @@ -151,7 +129,7 @@ const struct Curl_handler Curl_handler_http = { */ const struct Curl_handler Curl_handler_https = { "HTTPS", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -160,26 +138,76 @@ const struct Curl_handler Curl_handler_https = { ZERO_NULL, /* doing */ https_getsock, /* proto_getsock */ http_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_HTTPS, /* defport */ - PROT_HTTP | PROT_HTTPS | PROT_SSL /* protocol */ + CURLPROTO_HTTPS, /* protocol */ + PROTOPT_SSL | PROTOPT_CREDSPERREQUEST /* flags */ }; #endif +CURLcode Curl_http_setup_conn(struct connectdata *conn) +{ + /* allocate the HTTP-specific struct for the SessionHandle, only to survive + during this request */ + struct HTTP *http; + DEBUGASSERT(conn->data->req.protop == NULL); + + http = calloc(1, sizeof(struct HTTP)); + if(!http) + return CURLE_OUT_OF_MEMORY; + + conn->data->req.protop = http; + + Curl_http2_setup_conn(conn); + Curl_http2_setup_req(conn->data); + + return CURLE_OK; +} + /* * checkheaders() checks the linked list of custom HTTP headers for a * particular header (prefix). * * Returns a pointer to the first matching header or NULL if none matched. */ -char *Curl_checkheaders(struct SessionHandle *data, const char *thisheader) +char *Curl_checkheaders(const struct connectdata *conn, + const char *thisheader) { struct curl_slist *head; size_t thislen = strlen(thisheader); + struct SessionHandle *data = conn->data; - for(head = data->set.headers; head; head=head->next) { + for(head = data->set.headers;head; head=head->next) { + if(Curl_raw_nequal(head->data, thisheader, thislen)) + return head->data; + } + return NULL; +} + +/* + * checkProxyHeaders() checks the linked list of custom proxy headers + * if proxy headers are not available, then it will lookup into http header + * link list + * + * It takes a connectdata struct as input instead of the SessionHandle simply + * to know if this is a proxy request or not, as it then might check a + * different header list. + * + */ +char *Curl_checkProxyheaders(const struct connectdata *conn, + const char *thisheader) +{ + struct curl_slist *head; + size_t thislen = strlen(thisheader); + struct SessionHandle *data = conn->data; + + for(head = (conn->bits.proxy && data->set.sep_headers)? + data->set.proxyheaders:data->set.headers; + head; head=head->next) { if(Curl_raw_nequal(head->data, thisheader, thislen)) return head->data; } @@ -192,25 +220,25 @@ char *Curl_checkheaders(struct SessionHandle *data, const char *thisheader) * case of allocation failure. Returns an empty string if the header value * consists entirely of whitespace. */ -char *Curl_copy_header_value(const char *h) +char *Curl_copy_header_value(const char *header) { const char *start; const char *end; char *value; size_t len; - DEBUGASSERT(h); + DEBUGASSERT(header); /* Find the end of the header name */ - while (*h && (*h != ':')) - ++h; + while(*header && (*header != ':')) + ++header; - if (*h) + if(*header) /* Skip over colon */ - ++h; + ++header; /* Find the first non-space letter */ - start = h; + start = header; while(*start && ISSPACE(*start)) start++; @@ -229,7 +257,7 @@ char *Curl_copy_header_value(const char *h) end--; /* get length of the type */ - len = end-start+1; + len = end - start + 1; value = malloc(len + 1); if(!value) @@ -249,11 +277,13 @@ char *Curl_copy_header_value(const char *h) */ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) { - char *authorization; - struct SessionHandle *data=conn->data; + size_t size = 0; + char *authorization = NULL; + struct SessionHandle *data = conn->data; char **userp; const char *user; const char *pwd; + CURLcode result; if(proxy) { userp = &conn->allocptr.proxyuserpwd; @@ -267,20 +297,24 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) } snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd); - if(Curl_base64_encode(data, data->state.buffer, - strlen(data->state.buffer), - &authorization) > 0) { - if(*userp) - free(*userp); - *userp = aprintf( "%sAuthorization: Basic %s\r\n", - proxy?"Proxy-":"", - authorization); - free(authorization); - if(!*userp) - return CURLE_OUT_OF_MEMORY; - } - else + + result = Curl_base64_encode(data, + data->state.buffer, strlen(data->state.buffer), + &authorization, &size); + if(result) + return result; + + if(!authorization) + return CURLE_REMOTE_ACCESS_DENIED; + + free(*userp); + *userp = aprintf("%sAuthorization: Basic %s\r\n", + proxy?"Proxy-":"", + authorization); + free(authorization); + if(!*userp) return CURLE_OUT_OF_MEMORY; + return CURLE_OK; } @@ -293,17 +327,19 @@ static bool pickoneauth(struct auth *pick) { bool picked; /* only deal with authentication we want */ - long avail = pick->avail & pick->want; + unsigned long avail = pick->avail & pick->want; picked = TRUE; /* The order of these checks is highly relevant, as this will be the order of preference in case of the existence of multiple accepted types. */ - if(avail & CURLAUTH_GSSNEGOTIATE) - pick->picked = CURLAUTH_GSSNEGOTIATE; + if(avail & CURLAUTH_NEGOTIATE) + pick->picked = CURLAUTH_NEGOTIATE; else if(avail & CURLAUTH_DIGEST) pick->picked = CURLAUTH_DIGEST; else if(avail & CURLAUTH_NTLM) pick->picked = CURLAUTH_NTLM; + else if(avail & CURLAUTH_NTLM_WB) + pick->picked = CURLAUTH_NTLM_WB; else if(avail & CURLAUTH_BASIC) pick->picked = CURLAUTH_BASIC; else { @@ -338,17 +374,16 @@ static bool pickoneauth(struct auth *pick) * } * } */ -CURLcode Curl_http_perhapsrewind(struct connectdata *conn) +static CURLcode http_perhapsrewind(struct connectdata *conn) { struct SessionHandle *data = conn->data; - struct HTTP *http = data->state.proto.http; + struct HTTP *http = data->req.protop; curl_off_t bytessent; curl_off_t expectsend = -1; /* default is unknown */ - if(!http || !(conn->protocol & PROT_HTTP)) - /* If this is still NULL, we have not reach very far and we can - safely skip this rewinding stuff, or this is attempted to get used - when HTTP isn't activated */ + if(!http) + /* If this is still NULL, we have not reach very far and we can safely + skip this rewinding stuff */ return CURLE_OK; switch(data->set.httpreq) { @@ -361,22 +396,27 @@ CURLcode Curl_http_perhapsrewind(struct connectdata *conn) bytessent = http->writebytecount; - if(conn->bits.authneg) + if(conn->bits.authneg) { /* This is a state where we are known to be negotiating and we don't send any data then. */ expectsend = 0; + } + else if(!conn->bits.protoconnstart) { + /* HTTP CONNECT in progress: there is no body */ + expectsend = 0; + } else { /* figure out how much data we are expected to send */ switch(data->set.httpreq) { case HTTPREQ_POST: - if(data->set.postfieldsize != -1) - expectsend = data->set.postfieldsize; + if(data->state.infilesize != -1) + expectsend = data->state.infilesize; else if(data->set.postfields) expectsend = (curl_off_t)strlen(data->set.postfields); break; case HTTPREQ_PUT: - if(data->set.infilesize != -1) - expectsend = data->set.infilesize; + if(data->state.infilesize != -1) + expectsend = data->state.infilesize; break; case HTTPREQ_POST_FORM: expectsend = http->postsize; @@ -389,31 +429,39 @@ CURLcode Curl_http_perhapsrewind(struct connectdata *conn) conn->bits.rewindaftersend = FALSE; /* default */ if((expectsend == -1) || (expectsend > bytessent)) { +#if defined(USE_NTLM) /* There is still data left to send */ if((data->state.authproxy.picked == CURLAUTH_NTLM) || - (data->state.authhost.picked == CURLAUTH_NTLM)) { + (data->state.authhost.picked == CURLAUTH_NTLM) || + (data->state.authproxy.picked == CURLAUTH_NTLM_WB) || + (data->state.authhost.picked == CURLAUTH_NTLM_WB)) { if(((expectsend - bytessent) < 2000) || - (conn->ntlm.state != NTLMSTATE_NONE)) { + (conn->ntlm.state != NTLMSTATE_NONE) || + (conn->proxyntlm.state != NTLMSTATE_NONE)) { /* The NTLM-negotiation has started *OR* there is just a little (<2K) data left to send, keep on sending. */ /* rewind data when completely done sending! */ - if(!conn->bits.authneg) + if(!conn->bits.authneg) { conn->bits.rewindaftersend = TRUE; + infof(data, "Rewind stream after send\n"); + } return CURLE_OK; } + if(conn->bits.close) /* this is already marked to get closed */ return CURLE_OK; - infof(data, "NTLM send, close instead of sending %" FORMAT_OFF_T - " bytes\n", (curl_off_t)(expectsend - bytessent)); + infof(data, "NTLM send, close instead of sending %" + CURL_FORMAT_CURL_OFF_T " bytes\n", + (curl_off_t)(expectsend - bytessent)); } +#endif - /* This is not NTLM or NTLM with many bytes left to send: close - */ - conn->bits.close = TRUE; + /* This is not NTLM or many bytes left to send: close */ + connclose(conn, "Mid-auth HTTP and much data left to send"); data->req.size = 0; /* don't download any more than 0 bytes */ /* There still is data left to send, but this connection is marked for @@ -439,7 +487,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) struct SessionHandle *data = conn->data; bool pickhost = FALSE; bool pickproxy = FALSE; - CURLcode code = CURLE_OK; + CURLcode result = CURLE_OK; if(100 <= data->req.httpcode && 199 >= data->req.httpcode) /* this is a transient response code, ignore */ @@ -475,9 +523,9 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) if((data->set.httpreq != HTTPREQ_GET) && (data->set.httpreq != HTTPREQ_HEAD) && !conn->bits.rewindaftersend) { - code = Curl_http_perhapsrewind(conn); - if(code) - return code; + result = http_perhapsrewind(conn); + if(result) + return result; } } @@ -496,13 +544,13 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) data->state.authhost.done = TRUE; } } - if(Curl_http_should_fail(conn)) { + if(http_should_fail(conn)) { failf (data, "The requested URL returned error: %d", data->req.httpcode); - code = CURLE_HTTP_RETURNED_ERROR; + result = CURLE_HTTP_RETURNED_ERROR; } - return code; + return result; } @@ -517,12 +565,14 @@ output_auth_headers(struct connectdata *conn, const char *path, bool proxy) { - struct SessionHandle *data = conn->data; - const char *auth=NULL; + const char *auth = NULL; CURLcode result = CURLE_OK; -#ifdef HAVE_GSSAPI - struct negotiatedata *negdata = proxy? - &data->state.proxyneg:&data->state.negotiate; +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_SPNEGO) + struct SessionHandle *data = conn->data; +#endif +#ifdef USE_SPNEGO + struct negotiatedata *negdata = proxy ? + &data->state.proxyneg : &data->state.negotiate; #endif #ifdef CURL_DISABLE_CRYPTO_AUTH @@ -530,10 +580,11 @@ output_auth_headers(struct connectdata *conn, (void)path; #endif -#ifdef HAVE_GSSAPI - if((authstatus->picked == CURLAUTH_GSSNEGOTIATE) && +#ifdef USE_SPNEGO + negdata->state = GSS_AUTHNONE; + if((authstatus->picked == CURLAUTH_NEGOTIATE) && negdata->context && !GSS_ERROR(negdata->status)) { - auth="GSS-Negotiate"; + auth="Negotiate"; result = Curl_output_negotiate(conn, proxy); if(result) return result; @@ -551,6 +602,15 @@ output_auth_headers(struct connectdata *conn, } else #endif +#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) + if(authstatus->picked == CURLAUTH_NTLM_WB) { + auth="NTLM_WB"; + result = Curl_output_ntlm_wb(conn, proxy); + if(result) + return result; + } + else +#endif #ifndef CURL_DISABLE_CRYPTO_AUTH if(authstatus->picked == CURLAUTH_DIGEST) { auth="Digest"; @@ -566,9 +626,9 @@ output_auth_headers(struct connectdata *conn, if(authstatus->picked == CURLAUTH_BASIC) { /* Basic */ if((proxy && conn->bits.proxy_user_passwd && - !Curl_checkheaders(data, "Proxy-authorization:")) || + !Curl_checkProxyheaders(conn, "Proxy-authorization:")) || (!proxy && conn->bits.user_passwd && - !Curl_checkheaders(data, "Authorization:"))) { + !Curl_checkheaders(conn, "Authorization:"))) { auth="Basic"; result = http_output_basic(conn, proxy); if(result) @@ -584,7 +644,7 @@ output_auth_headers(struct connectdata *conn, proxy?"Proxy":"Server", auth, proxy?(conn->proxyuser?conn->proxyuser:""): (conn->user?conn->user:"")); - authstatus->multi = (bool)(!authstatus->done); + authstatus->multi = (!authstatus->done) ? TRUE : FALSE; } else authstatus->multi = FALSE; @@ -606,12 +666,12 @@ output_auth_headers(struct connectdata *conn, * * @returns CURLcode */ -static CURLcode -http_output_auth(struct connectdata *conn, - const char *request, - const char *path, - bool proxytunnel) /* TRUE if this is the request setting - up the proxy tunnel */ +CURLcode +Curl_http_output_auth(struct connectdata *conn, + const char *request, + const char *path, + bool proxytunnel) /* TRUE if this is the request setting + up the proxy tunnel */ { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; @@ -625,7 +685,7 @@ http_output_auth(struct connectdata *conn, if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) || conn->bits.user_passwd) - /* continue please */ ; + /* continue please */; else { authhost->done = TRUE; authproxy->done = TRUE; @@ -682,34 +742,30 @@ http_output_auth(struct connectdata *conn, * proxy CONNECT loop. */ -CURLcode Curl_http_input_auth(struct connectdata *conn, - int httpcode, - const char *header) /* the first non-space */ +CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, + const char *auth) /* the first non-space */ { /* * This resource requires authentication */ struct SessionHandle *data = conn->data; - long *availp; - const char *start; +#ifdef USE_SPNEGO + struct negotiatedata *negdata = proxy? + &data->state.proxyneg:&data->state.negotiate; +#endif + unsigned long *availp; struct auth *authp; - if(httpcode == 407) { - start = header+strlen("Proxy-authenticate:"); + if(proxy) { availp = &data->info.proxyauthavail; authp = &data->state.authproxy; } else { - start = header+strlen("WWW-Authenticate:"); availp = &data->info.httpauthavail; authp = &data->state.authhost; } - /* pass all white spaces */ - while(*start && ISSPACE(*start)) - start++; - /* * Here we check if we want the specific single authentication (using ==) and * if we do, we initiate usage of it. @@ -727,73 +783,65 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, * */ -#ifdef HAVE_GSSAPI - if(checkprefix("GSS-Negotiate", start) || - checkprefix("Negotiate", start)) { - int neg; - *availp |= CURLAUTH_GSSNEGOTIATE; - authp->avail |= CURLAUTH_GSSNEGOTIATE; + while(*auth) { +#ifdef USE_SPNEGO + if(checkprefix("Negotiate", auth)) { + *availp |= CURLAUTH_NEGOTIATE; + authp->avail |= CURLAUTH_NEGOTIATE; - if(data->state.negotiate.state == GSS_AUTHSENT) { - /* if we sent GSS authentication in the outgoing request and we get this - back, we're in trouble */ - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; - } - else { - neg = Curl_input_negotiate(conn, (bool)(httpcode == 407), start); - if(neg == 0) { - DEBUGASSERT(!data->req.newurl); - data->req.newurl = strdup(data->change.url); - if(!data->req.newurl) - return CURLE_OUT_OF_MEMORY; - data->state.authproblem = FALSE; - /* we received GSS auth info and we dealt with it fine */ - data->state.negotiate.state = GSS_AUTHRECV; - } - else { - data->state.authproblem = TRUE; - } - } - } - else -#endif -#ifdef USE_NTLM - /* NTLM support requires the SSL crypto libs */ - if(checkprefix("NTLM", start)) { - *availp |= CURLAUTH_NTLM; - authp->avail |= CURLAUTH_NTLM; - if(authp->picked == CURLAUTH_NTLM) { - /* NTLM authentication is picked and activated */ - CURLntlm ntlm = - Curl_input_ntlm(conn, (bool)(httpcode == 407), start); - - if(CURLNTLM_BAD != ntlm) - data->state.authproblem = FALSE; - else { - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; + if(authp->picked == CURLAUTH_NEGOTIATE) { + if(negdata->state == GSS_AUTHSENT || negdata->state == GSS_AUTHNONE) { + CURLcode result = Curl_input_negotiate(conn, proxy, auth); + if(!result) { + DEBUGASSERT(!data->req.newurl); + data->req.newurl = strdup(data->change.url); + if(!data->req.newurl) + return CURLE_OUT_OF_MEMORY; + data->state.authproblem = FALSE; + /* we received a GSS auth token and we dealt with it fine */ + negdata->state = GSS_AUTHRECV; + } + else + data->state.authproblem = TRUE; } } } else #endif -#ifndef CURL_DISABLE_CRYPTO_AUTH - if(checkprefix("Digest", start)) { - if((authp->avail & CURLAUTH_DIGEST) != 0) { - infof(data, "Ignoring duplicate digest auth header.\n"); - } - else { - CURLdigest dig; - *availp |= CURLAUTH_DIGEST; - authp->avail |= CURLAUTH_DIGEST; +#ifdef USE_NTLM + /* NTLM support requires the SSL crypto libs */ + if(checkprefix("NTLM", auth)) { + *availp |= CURLAUTH_NTLM; + authp->avail |= CURLAUTH_NTLM; + if(authp->picked == CURLAUTH_NTLM || + authp->picked == CURLAUTH_NTLM_WB) { + /* NTLM authentication is picked and activated */ + CURLcode result = Curl_input_ntlm(conn, proxy, auth); + if(!result) { + data->state.authproblem = FALSE; +#ifdef NTLM_WB_ENABLED + if(authp->picked == CURLAUTH_NTLM_WB) { + *availp &= ~CURLAUTH_NTLM; + authp->avail &= ~CURLAUTH_NTLM; + *availp |= CURLAUTH_NTLM_WB; + authp->avail |= CURLAUTH_NTLM_WB; - /* We call this function on input Digest headers even if Digest - * authentication isn't activated yet, as we need to store the - * incoming data from this header in case we are gonna use Digest. */ - dig = Curl_input_digest(conn, (bool)(httpcode == 407), start); - - if(CURLDIGEST_FINE != dig) { + /* Get the challenge-message which will be passed to + * ntlm_auth for generating the type 3 message later */ + while(*auth && ISSPACE(*auth)) + auth++; + if(checkprefix("NTLM", auth)) { + auth += strlen("NTLM"); + while(*auth && ISSPACE(*auth)) + auth++; + if(*auth) + if((conn->challenge_header = strdup(auth)) == NULL) + return CURLE_OUT_OF_MEMORY; + } + } +#endif + } + else { infof(data, "Authentication problem. Ignoring this.\n"); data->state.authproblem = TRUE; } @@ -801,24 +849,55 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, } else #endif - if(checkprefix("Basic", start)) { - *availp |= CURLAUTH_BASIC; - authp->avail |= CURLAUTH_BASIC; - if(authp->picked == CURLAUTH_BASIC) { - /* We asked for Basic authentication but got a 40X back - anyway, which basically means our name+password isn't - valid. */ - authp->avail = CURLAUTH_NONE; - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; - } - } +#ifndef CURL_DISABLE_CRYPTO_AUTH + if(checkprefix("Digest", auth)) { + if((authp->avail & CURLAUTH_DIGEST) != 0) { + infof(data, "Ignoring duplicate digest auth header.\n"); + } + else { + CURLcode result; + *availp |= CURLAUTH_DIGEST; + authp->avail |= CURLAUTH_DIGEST; + /* We call this function on input Digest headers even if Digest + * authentication isn't activated yet, as we need to store the + * incoming data from this header in case we are gonna use + * Digest. */ + result = Curl_input_digest(conn, proxy, auth); + if(result) { + infof(data, "Authentication problem. Ignoring this.\n"); + data->state.authproblem = TRUE; + } + } + } + else +#endif + if(checkprefix("Basic", auth)) { + *availp |= CURLAUTH_BASIC; + authp->avail |= CURLAUTH_BASIC; + if(authp->picked == CURLAUTH_BASIC) { + /* We asked for Basic authentication but got a 40X back + anyway, which basically means our name+password isn't + valid. */ + authp->avail = CURLAUTH_NONE; + infof(data, "Authentication problem. Ignoring this.\n"); + data->state.authproblem = TRUE; + } + } + + /* there may be multiple methods on one line, so keep reading */ + while(*auth && *auth != ',') /* read up to the next comma */ + auth++; + if(*auth == ',') /* if we're on a comma, skip it */ + auth++; + while(*auth && ISSPACE(*auth)) + auth++; + } return CURLE_OK; } /** - * Curl_http_should_fail() determines whether an HTTP response has gotten us + * http_should_fail() determines whether an HTTP response has gotten us * into an error state or not. * * @param conn all information about the current connection @@ -827,7 +906,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, * * @retval 1 communications should not continue */ -int Curl_http_should_fail(struct connectdata *conn) +static int http_should_fail(struct connectdata *conn) { struct SessionHandle *data; int httpcode; @@ -851,14 +930,6 @@ int Curl_http_should_fail(struct connectdata *conn) if(httpcode < 400) return 0; - if(data->state.resume_from && - (data->set.httpreq==HTTPREQ_GET) && - (httpcode == 416)) { - /* "Requested Range Not Satisfiable", just proceed and - pretend this is no error */ - return 0; - } - /* ** Any code >= 400 that's not 401 or 407 is always ** a terminal error @@ -885,16 +956,6 @@ int Curl_http_should_fail(struct connectdata *conn) ** the client needs to reauthenticate. Once that info is ** available, use it here. */ -#if 0 /* set to 1 when debugging this functionality */ - infof(data,"%s: authstage = %d\n",__FUNCTION__,data->state.authstage); - infof(data,"%s: authwant = 0x%08x\n",__FUNCTION__,data->state.authwant); - infof(data,"%s: authavail = 0x%08x\n",__FUNCTION__,data->state.authavail); - infof(data,"%s: httpcode = %d\n",__FUNCTION__,k->httpcode); - infof(data,"%s: authdone = %d\n",__FUNCTION__,data->state.authdone); - infof(data,"%s: newurl = %s\n",__FUNCTION__,data->req.newurl ? - data->req.newurl : "(null)"); - infof(data,"%s: authproblem = %d\n",__FUNCTION__,data->state.authproblem); -#endif /* ** Either we're not authenticating, or we're supposed to @@ -922,7 +983,7 @@ static size_t readmoredata(char *buffer, void *userp) { struct connectdata *conn = (struct connectdata *)userp; - struct HTTP *http = conn->data->state.proto.http; + struct HTTP *http = conn->data->req.protop; size_t fullsize = size * nitems; if(0 == http->postsize) @@ -930,7 +991,7 @@ static size_t readmoredata(char *buffer, return 0; /* make sure that a HTTP request is never sent away chunked! */ - conn->data->req.forbidchunk = (bool)(http->sending == HTTPSEND_REQUEST); + conn->data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE; if(http->postsize <= (curl_off_t)fullsize) { memcpy(buffer, http->postdata, (size_t)http->postsize); @@ -940,8 +1001,8 @@ static size_t readmoredata(char *buffer, /* move backup data into focus and continue on that */ http->postdata = http->backup.postdata; http->postsize = http->backup.postsize; - conn->fread_func = http->backup.fread_func; - conn->fread_in = http->backup.fread_in; + conn->data->state.fread_func = http->backup.fread_func; + conn->data->state.in = http->backup.fread_in; http->sending++; /* move one step up */ @@ -971,6 +1032,16 @@ Curl_send_buffer *Curl_add_buffer_init(void) return calloc(1, sizeof(Curl_send_buffer)); } +/* + * Curl_add_buffer_free() frees all associated resources. + */ +void Curl_add_buffer_free(Curl_send_buffer *buff) +{ + if(buff) /* deal with NULL input */ + free(buff->buffer); + free(buff); +} + /* * Curl_add_buffer_send() sends a header buffer and frees all associated * memory. Body data may be appended to the header data if desired. @@ -990,10 +1061,10 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, { ssize_t amount; - CURLcode res; + CURLcode result; char *ptr; size_t size; - struct HTTP *http = conn->data->state.proto.http; + struct HTTP *http = conn->data->req.protop; size_t sendsize; curl_socket_t sockfd; size_t headersize; @@ -1013,19 +1084,16 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, DEBUGASSERT(size > included_body_bytes); -#ifdef CURL_DOES_CONVERSIONS - res = Curl_convert_to_network(conn->data, ptr, headersize); + result = Curl_convert_to_network(conn->data, ptr, headersize); /* Curl_convert_to_network calls failf if unsuccessful */ - if(res != CURLE_OK) { + if(result) { /* conversion failed, free memory and return to the caller */ - if(in->buffer) - free(in->buffer); - free(in); - return res; + Curl_add_buffer_free(in); + return result; } -#endif /* CURL_DOES_CONVERSIONS */ - if(conn->protocol & PROT_HTTPS) { + + if((conn->handler->flags & PROTOPT_SSL) && conn->httpversion != 20) { /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk when we speak HTTPS, as if only a fraction of it is sent now, this data needs to fit into the normal read-callback buffer later on and that @@ -1046,9 +1114,9 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, else sendsize = size; - res = Curl_write(conn, sockfd, ptr, sendsize, &amount); + result = Curl_write(conn, sockfd, ptr, sendsize, &amount); - if(CURLE_OK == res) { + if(!result) { /* * Note that we may not send the entire chunk at once, and we have a set * number of data bytes at the end of the big buffer (out of which we may @@ -1061,7 +1129,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, if(conn->data->set.verbose) { /* this data _may_ contain binary stuff */ Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, headlen, conn); - if((size_t)amount > headlen) { + if(bodylen) { /* there was body data sent beyond the initial header part, pass that on to the debug callback too */ Curl_debug(conn->data, CURLINFO_DATA_OUT, @@ -1089,14 +1157,14 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, ptr = in->buffer + amount; /* backup the currently set pointers */ - http->backup.fread_func = conn->fread_func; - http->backup.fread_in = conn->fread_in; + http->backup.fread_func = conn->data->state.fread_func; + http->backup.fread_in = conn->data->state.in; http->backup.postdata = http->postdata; http->backup.postsize = http->postsize; /* set the new pointers for the request-sending */ - conn->fread_func = (curl_read_callback)readmoredata; - conn->fread_in = (void *)conn; + conn->data->state.fread_func = (curl_read_callback)readmoredata; + conn->data->state.in = (void *)conn; http->postdata = ptr; http->postsize = (curl_off_t)size; @@ -1119,14 +1187,12 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, */ return CURLE_SEND_ERROR; else - conn->writechannel_inuse = FALSE; + Curl_pipeline_leave_write(conn); } } - if(in->buffer) - free(in->buffer); - free(in); + Curl_add_buffer_free(in); - return res; + return result; } @@ -1147,8 +1213,7 @@ CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...) return result; } /* If we failed, we cleanup the whole buffer and return error */ - if(in->buffer) - free(in->buffer); + free(in->buffer); free(in); return CURLE_OUT_OF_MEMORY; } @@ -1267,529 +1332,35 @@ Curl_compareheader(const char *headerline, /* line to check */ return FALSE; /* no match */ } -#ifndef CURL_DISABLE_PROXY -/* - * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This - * function will issue the necessary commands to get a seamless tunnel through - * this proxy. After that, the socket can be used just as a normal socket. - * - * This badly needs to be rewritten. CONNECT should be sent and dealt with - * like any ordinary HTTP request, and not specially crafted like this. This - * function only remains here like this for now since the rewrite is a bit too - * much work to do at the moment. - * - * This function is BLOCKING which is nasty for all multi interface using apps. - */ - -CURLcode Curl_proxyCONNECT(struct connectdata *conn, - int sockindex, - const char *hostname, - unsigned short remote_port) -{ - int subversion=0; - struct SessionHandle *data=conn->data; - struct SingleRequest *k = &data->req; - CURLcode result; - long timeout = - data->set.timeout?data->set.timeout:PROXY_TIMEOUT; /* in milliseconds */ - curl_socket_t tunnelsocket = conn->sock[sockindex]; - curl_off_t cl=0; - bool closeConnection = FALSE; - bool chunked_encoding = FALSE; - long check; - -#define SELECT_OK 0 -#define SELECT_ERROR 1 -#define SELECT_TIMEOUT 2 - int error = SELECT_OK; - - conn->bits.proxy_connect_closed = FALSE; - - do { - if(!conn->bits.tunnel_connecting) { /* BEGIN CONNECT PHASE */ - char *host_port; - Curl_send_buffer *req_buffer; - - infof(data, "Establish HTTP proxy tunnel to %s:%hu\n", - hostname, remote_port); - - if(data->req.newurl) { - /* This only happens if we've looped here due to authentication - reasons, and we don't really use the newly cloned URL here - then. Just free() it. */ - free(data->req.newurl); - data->req.newurl = NULL; - } - - /* initialize a dynamic send-buffer */ - req_buffer = Curl_add_buffer_init(); - - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; - - host_port = aprintf("%s:%hu", hostname, remote_port); - if(!host_port) { - free(req_buffer); - return CURLE_OUT_OF_MEMORY; - } - - /* Setup the proxy-authorization header, if any */ - result = http_output_auth(conn, "CONNECT", host_port, TRUE); - - if(CURLE_OK == result) { - char *host=(char *)""; - const char *proxyconn=""; - const char *useragent=""; - const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ? - "1.0" : "1.1"; - - if(!Curl_checkheaders(data, "Host:")) { - host = aprintf("Host: %s\r\n", host_port); - if(!host) { - free(req_buffer); - free(host_port); - return CURLE_OUT_OF_MEMORY; - } - } - if(!Curl_checkheaders(data, "Proxy-Connection:")) - proxyconn = "Proxy-Connection: Keep-Alive\r\n"; - - if(!Curl_checkheaders(data, "User-Agent:") && - data->set.str[STRING_USERAGENT]) - useragent = conn->allocptr.uagent; - - /* Send the connect request to the proxy */ - /* BLOCKING */ - result = - Curl_add_bufferf(req_buffer, - "CONNECT %s:%hu HTTP/%s\r\n" - "%s" /* Host: */ - "%s" /* Proxy-Authorization */ - "%s" /* User-Agent */ - "%s", /* Proxy-Connection */ - hostname, remote_port, http, - host, - conn->allocptr.proxyuserpwd? - conn->allocptr.proxyuserpwd:"", - useragent, - proxyconn); - - if(host && *host) - free(host); - - if(CURLE_OK == result) - result = Curl_add_custom_headers(conn, req_buffer); - - if(CURLE_OK == result) - /* CRLF terminate the request */ - result = Curl_add_bufferf(req_buffer, "\r\n"); - - if(CURLE_OK == result) { - /* Now send off the request */ - result = Curl_add_buffer_send(req_buffer, conn, - &data->info.request_size, 0, sockindex); - } - req_buffer = NULL; - if(result) - failf(data, "Failed sending CONNECT to proxy"); - } - free(host_port); - Curl_safefree(req_buffer); - if(result) - return result; - - conn->bits.tunnel_connecting = TRUE; - } /* END CONNECT PHASE */ - - /* now we've issued the CONNECT and we're waiting to hear back - - we try not to block here in multi-mode because that might be a LONG - wait if the proxy cannot connect-through to the remote host. */ - - /* if timeout is requested, find out how much remaining time we have */ - check = timeout - /* timeout time */ - Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */ - if(check <= 0) { - failf(data, "Proxy CONNECT aborted due to timeout"); - return CURLE_RECV_ERROR; - } - - /* if we're in multi-mode and we would block, return instead for a retry */ - if(Curl_if_multi == data->state.used_interface) { - if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0)) - /* return so we'll be called again polling-style */ - return CURLE_OK; - else { - DEBUGF(infof(data, - "Multi mode finished polling for response from " - "proxy CONNECT.")); - } - } - else { - DEBUGF(infof(data, "Easy mode waiting response from proxy CONNECT.")); - } - - /* at this point, either: - 1) we're in easy-mode and so it's okay to block waiting for a CONNECT - response - 2) we're in multi-mode and we didn't block - it's either an error or we - now have some data waiting. - In any case, the tunnel_connecting phase is over. */ - conn->bits.tunnel_connecting = FALSE; - - { /* BEGIN NEGOTIATION PHASE */ - size_t nread; /* total size read */ - int perline; /* count bytes per line */ - int keepon=TRUE; - ssize_t gotbytes; - char *ptr; - char *line_start; - - ptr=data->state.buffer; - line_start = ptr; - - nread=0; - perline=0; - keepon=TRUE; - - while((nreadnow); /* spent time */ - if(check <= 0) { - failf(data, "Proxy CONNECT aborted due to timeout"); - error = SELECT_TIMEOUT; /* already too little time */ - break; - } - - /* loop every second at least, less if the timeout is near */ - switch (Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, - check<1000L?(int)check:1000)) { - case -1: /* select() error, stop reading */ - error = SELECT_ERROR; - failf(data, "Proxy CONNECT aborted due to select/poll error"); - break; - case 0: /* timeout */ - break; - default: - DEBUGASSERT(ptr+BUFSIZE-nread <= data->state.buffer+BUFSIZE+1); - result = Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes); - if(result==CURLE_AGAIN) - continue; /* go loop yourself */ - else if(result) - keepon = FALSE; - else if(gotbytes <= 0) { - keepon = FALSE; - if(data->set.proxyauth && data->state.authproxy.avail) { - /* proxy auth was requested and there was proxy auth available, - then deem this as "mere" proxy disconnect */ - conn->bits.proxy_connect_closed = TRUE; - } - else { - error = SELECT_ERROR; - failf(data, "Proxy CONNECT aborted"); - } - } - else { - /* - * We got a whole chunk of data, which can be anything from one - * byte to a set of lines and possibly just a piece of the last - * line. - */ - int i; - - nread += gotbytes; - - if(keepon > TRUE) { - /* This means we are currently ignoring a response-body */ - - nread = 0; /* make next read start over in the read buffer */ - ptr=data->state.buffer; - if(cl) { - /* A Content-Length based body: simply count down the counter - and make sure to break out of the loop when we're done! */ - cl -= gotbytes; - if(cl<=0) { - keepon = FALSE; - break; - } - } - else { - /* chunked-encoded body, so we need to do the chunked dance - properly to know when the end of the body is reached */ - CHUNKcode r; - ssize_t tookcareof=0; - - /* now parse the chunked piece of data so that we can - properly tell when the stream ends */ - r = Curl_httpchunk_read(conn, ptr, gotbytes, &tookcareof); - if(r == CHUNKE_STOP) { - /* we're done reading chunks! */ - infof(data, "chunk reading DONE\n"); - keepon = FALSE; - } - else - infof(data, "Read %zd bytes of chunk, continue\n", - tookcareof); - } - } - else - for(i = 0; i < gotbytes; ptr++, i++) { - perline++; /* amount of bytes in this line so far */ - if(*ptr == 0x0a) { - char letter; - int writetype; - -#ifdef CURL_DOES_CONVERSIONS - /* convert from the network encoding */ - result = Curl_convert_from_network(data, line_start, - perline); - /* Curl_convert_from_network calls failf if unsuccessful */ - if(result) - return result; -#endif /* CURL_DOES_CONVERSIONS */ - - /* output debug if that is requested */ - if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, - line_start, (size_t)perline, conn); - - /* send the header to the callback */ - writetype = CLIENTWRITE_HEADER; - if(data->set.include_header) - writetype |= CLIENTWRITE_BODY; - - result = Curl_client_write(conn, writetype, line_start, - perline); - if(result) - return result; - - /* Newlines are CRLF, so the CR is ignored as the line isn't - really terminated until the LF comes. Treat a following CR - as end-of-headers as well.*/ - - if(('\r' == line_start[0]) || - ('\n' == line_start[0])) { - /* end of response-headers from the proxy */ - nread = 0; /* make next read start over in the read - buffer */ - ptr=data->state.buffer; - if((407 == k->httpcode) && !data->state.authproblem) { - /* If we get a 407 response code with content length - when we have no auth problem, we must ignore the - whole response-body */ - keepon = 2; - - if(cl) { - - infof(data, "Ignore %" FORMAT_OFF_T - " bytes of response-body\n", cl); - /* remove the remaining chunk of what we already - read */ - cl -= (gotbytes - i); - - if(cl<=0) - /* if the whole thing was already read, we are done! - */ - keepon=FALSE; - } - else if(chunked_encoding) { - CHUNKcode r; - /* We set ignorebody true here since the chunked - decoder function will acknowledge that. Pay - attention so that this is cleared again when this - function returns! */ - k->ignorebody = TRUE; - infof(data, "%zd bytes of chunk left\n", gotbytes-i); - - if(line_start[1] == '\n') { - /* this can only be a LF if the letter at index 0 - was a CR */ - line_start++; - i++; - } - - /* now parse the chunked piece of data so that we can - properly tell when the stream ends */ - r = Curl_httpchunk_read(conn, line_start+1, - gotbytes -i, &gotbytes); - if(r == CHUNKE_STOP) { - /* we're done reading chunks! */ - infof(data, "chunk reading DONE\n"); - keepon = FALSE; - } - else - infof(data, "Read %zd bytes of chunk, continue\n", - gotbytes); - } - else { - /* without content-length or chunked encoding, we - can't keep the connection alive since the close is - the end signal so we bail out at once instead */ - keepon=FALSE; - } - } - else - keepon = FALSE; - break; /* breaks out of for-loop, not switch() */ - } - - /* keep a backup of the position we are about to blank */ - letter = line_start[perline]; - line_start[perline]=0; /* zero terminate the buffer */ - if((checkprefix("WWW-Authenticate:", line_start) && - (401 == k->httpcode)) || - (checkprefix("Proxy-authenticate:", line_start) && - (407 == k->httpcode))) { - result = Curl_http_input_auth(conn, k->httpcode, - line_start); - if(result) - return result; - } - else if(checkprefix("Content-Length:", line_start)) { - cl = curlx_strtoofft(line_start + - strlen("Content-Length:"), NULL, 10); - } - else if(Curl_compareheader(line_start, - "Connection:", "close")) - closeConnection = TRUE; - else if(Curl_compareheader(line_start, - "Transfer-Encoding:", - "chunked")) { - infof(data, "CONNECT responded chunked\n"); - chunked_encoding = TRUE; - /* init our chunky engine */ - Curl_httpchunk_init(conn); - } - else if(Curl_compareheader(line_start, - "Proxy-Connection:", "close")) - closeConnection = TRUE; - else if(2 == sscanf(line_start, "HTTP/1.%d %d", - &subversion, - &k->httpcode)) { - /* store the HTTP code from the proxy */ - data->info.httpproxycode = k->httpcode; - } - /* put back the letter we blanked out before */ - line_start[perline]= letter; - - perline=0; /* line starts over here */ - line_start = ptr+1; /* this skips the zero byte we wrote */ - } - } - } - break; - } /* switch */ - if(Curl_pgrsUpdate(conn)) - return CURLE_ABORTED_BY_CALLBACK; - } /* while there's buffer left and loop is requested */ - - if(error) - return CURLE_RECV_ERROR; - - if(data->info.httpproxycode != 200) { - /* Deal with the possibly already received authenticate - headers. 'newurl' is set to a new URL if we must loop. */ - result = Curl_http_auth_act(conn); - if(result) - return result; - - if(conn->bits.close) - /* the connection has been marked for closure, most likely in the - Curl_http_auth_act() function and thus we can kill it at once - below - */ - closeConnection = TRUE; - } - - if(closeConnection && data->req.newurl) { - /* Connection closed by server. Don't use it anymore */ - sclose(conn->sock[sockindex]); - conn->sock[sockindex] = CURL_SOCKET_BAD; - break; - } - } /* END NEGOTIATION PHASE */ - } while(data->req.newurl); - - if(200 != data->req.httpcode) { - failf(data, "Received HTTP code %d from proxy after CONNECT", - data->req.httpcode); - - if(closeConnection && data->req.newurl) - conn->bits.proxy_connect_closed = TRUE; - - return CURLE_RECV_ERROR; - } - - /* If a proxy-authorization header was used for the proxy, then we should - make sure that it isn't accidentally used for the document request - after we've connected. So let's free and clear it here. */ - Curl_safefree(conn->allocptr.proxyuserpwd); - conn->allocptr.proxyuserpwd = NULL; - - data->state.authproxy.done = TRUE; - - infof (data, "Proxy replied OK to CONNECT request\n"); - data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */ - return CURLE_OK; -} -#endif /* CURL_DISABLE_PROXY */ - /* * Curl_http_connect() performs HTTP stuff to do at connect-time, called from * the generic Curl_connect(). */ CURLcode Curl_http_connect(struct connectdata *conn, bool *done) { - struct SessionHandle *data; CURLcode result; - data=conn->data; - /* We default to persistent connections. We set this already in this connect function to make the re-use checks properly be able to check this bit. */ - conn->bits.close = FALSE; + connkeep(conn, "HTTP default"); -#ifndef CURL_DISABLE_PROXY - /* If we are not using a proxy and we want a secure connection, perform SSL - * initialization & connection now. If using a proxy with https, then we - * must tell the proxy to CONNECT to the host we want to talk to. Only - * after the connect has occurred, can we start talking SSL - */ - if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { + /* the CONNECT procedure might not have been completed */ + result = Curl_proxy_connect(conn); + if(result) + return result; - /* either SSL over proxy, or explicitly asked for */ - result = Curl_proxyCONNECT(conn, FIRSTSOCKET, - conn->host.name, - conn->remote_port); - if(CURLE_OK != result) - return result; - } - - if(conn->bits.tunnel_connecting) { + if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) /* nothing else to do except wait right now - we're not done here. */ return CURLE_OK; - } -#endif /* CURL_DISABLE_PROXY */ - if(conn->protocol & PROT_HTTPS) { + if(conn->given->flags & PROTOPT_SSL) { /* perform SSL initialization */ - if(data->state.used_interface == Curl_if_multi) { - result = https_connecting(conn, done); - if(result) - return result; - } - else { - /* BLOCKING */ - result = Curl_ssl_connect(conn, FIRSTSOCKET); - if(result) - return result; - *done = TRUE; - } + result = https_connecting(conn, done); + if(result) + return result; } - else { + else *done = TRUE; - } return CURLE_OK; } @@ -1811,25 +1382,27 @@ static int http_getsock_do(struct connectdata *conn, static CURLcode https_connecting(struct connectdata *conn, bool *done) { CURLcode result; - DEBUGASSERT((conn) && (conn->protocol & PROT_HTTPS)); + DEBUGASSERT((conn) && (conn->handler->flags & PROTOPT_SSL)); /* perform SSL initialization for this socket */ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done); if(result) - conn->bits.close = TRUE; /* a failed connection is marked for closure - to prevent (bad) re-use or similar */ + connclose(conn, "Failed HTTPS connection"); + return result; } #endif -#if defined(USE_SSLEAY) || defined(USE_GNUTLS) -/* This function is for OpenSSL and GnuTLS only. It should be made to query - the generic SSL layer instead. */ +#if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ + defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS) || \ + defined(USE_MBEDTLS) +/* This function is for OpenSSL, GnuTLS, darwinssl, schannel and polarssl only. + It should be made to query the generic SSL layer instead. */ static int https_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks) { - if(conn->protocol & PROT_HTTPS) { + if(conn->handler->flags & PROTOPT_SSL) { struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; if(!numsocks) @@ -1849,7 +1422,7 @@ static int https_getsock(struct connectdata *conn, return CURLE_OK; } #else -#ifdef USE_NSS +#ifdef USE_SSL static int https_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks) @@ -1859,32 +1432,8 @@ static int https_getsock(struct connectdata *conn, (void)numsocks; return GETSOCK_BLANK; } -#else -#ifdef USE_QSOSSL -static int https_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - (void)conn; - (void)socks; - (void)numsocks; - return GETSOCK_BLANK; -} -#else -#ifdef USE_POLARSSL -static int https_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - (void)conn; - (void)socks; - (void)numsocks; - return GETSOCK_BLANK; -} -#endif -#endif -#endif -#endif +#endif /* USE_SSL */ +#endif /* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL */ /* * Curl_http_done() gets called from Curl_done() after a single HTTP request @@ -1895,14 +1444,26 @@ CURLcode Curl_http_done(struct connectdata *conn, CURLcode status, bool premature) { struct SessionHandle *data = conn->data; - struct HTTP *http =data->state.proto.http; - (void)premature; /* not used */ + struct HTTP *http = data->req.protop; +#ifdef USE_NGHTTP2 + struct http_conn *httpc = &conn->proto.httpc; +#endif Curl_unencode_cleanup(conn); +#ifdef USE_SPNEGO + if(data->state.proxyneg.state == GSS_AUTHSENT || + data->state.negotiate.state == GSS_AUTHSENT) { + /* add forbid re-use if http-code != 401/407 as a WA only needed for + * 401/407 that signal auth failure (empty) otherwise state will be RECV + * with current code */ + if((data->req.httpcode != 401) && (data->req.httpcode != 407)) + connclose(conn, "Negotiate transfer completed"); + Curl_cleanup_negotiate(data); + } +#endif + /* set the proper values (possibly modified on POST) */ - conn->fread_func = data->set.fread_func; /* restore */ - conn->fread_in = data->set.in; /* restore */ conn->seek_func = data->set.seek_func; /* restore */ conn->seek_client = data->set.seek_client; /* restore */ @@ -1910,13 +1471,32 @@ CURLcode Curl_http_done(struct connectdata *conn, return CURLE_OK; if(http->send_buffer) { - Curl_send_buffer *buff = http->send_buffer; - - free(buff->buffer); - free(buff); + Curl_add_buffer_free(http->send_buffer); http->send_buffer = NULL; /* clear the pointer */ } +#ifdef USE_NGHTTP2 + if(http->header_recvbuf) { + DEBUGF(infof(data, "free header_recvbuf!!\n")); + Curl_add_buffer_free(http->header_recvbuf); + http->header_recvbuf = NULL; /* clear the pointer */ + Curl_add_buffer_free(http->trailer_recvbuf); + http->trailer_recvbuf = NULL; /* clear the pointer */ + if(http->push_headers) { + /* if they weren't used and then freed before */ + for(; http->push_headers_used > 0; --http->push_headers_used) { + free(http->push_headers[http->push_headers_used - 1]); + } + free(http->push_headers); + http->push_headers = NULL; + } + } + if(http->stream_id) { + nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0); + http->stream_id = 0; + } +#endif + if(HTTPREQ_POST_FORM == data->set.httpreq) { data->req.bytecount = http->readbytecount + http->writebytecount; @@ -1930,12 +1510,13 @@ CURLcode Curl_http_done(struct connectdata *conn, else if(HTTPREQ_PUT == data->set.httpreq) data->req.bytecount = http->readbytecount + http->writebytecount; - if(status != CURLE_OK) - return (status); + if(status) + return status; if(!premature && /* this check is pointless when DONE is called before the entire operation is complete */ !conn->bits.retry && + !data->set.connect_only && ((http->readbytecount + data->req.headerbytecount - data->req.deductheadercount)) <= 0) { @@ -1950,18 +1531,25 @@ CURLcode Curl_http_done(struct connectdata *conn, } -/* Determine if we should use HTTP 1.1 for this request. Reasons to avoid it - are if the user specifically requested HTTP 1.0, if the server we are - connected to only supports 1.0, or if any server previously contacted to - handle this request only supports 1.0. */ -static bool use_http_1_1(const struct SessionHandle *data, - const struct connectdata *conn) +/* + * Determine if we should use HTTP 1.1 (OR BETTER) for this request. Reasons + * to avoid it include: + * + * - if the user specifically requested HTTP 1.0 + * - if the server we are connected to only supports 1.0 + * - if any server previously contacted to handle this request only supports + * 1.0. + */ +static bool use_http_1_1plus(const struct SessionHandle *data, + const struct connectdata *conn) { - return (bool)((data->set.httpversion == CURL_HTTP_VERSION_1_1) || - ((data->set.httpversion != CURL_HTTP_VERSION_1_0) && - ((conn->httpversion == 11) || - ((conn->httpversion != 10) && - (data->state.httpversion != 10))))); + if((data->state.httpversion == 10) || (conn->httpversion == 10)) + return FALSE; + if((data->set.httpversion == CURL_HTTP_VERSION_1_0) && + (conn->httpversion <= 10)) + return FALSE; + return ((data->set.httpversion == CURL_HTTP_VERSION_NONE) || + (data->set.httpversion >= CURL_HTTP_VERSION_1_1)); } /* check and possibly add an Expect: header */ @@ -1973,66 +1561,140 @@ static CURLcode expect100(struct SessionHandle *data, const char *ptr; data->state.expect100header = FALSE; /* default to false unless it is set to TRUE below */ - if(use_http_1_1(data, conn)) { - /* if not doing HTTP 1.0 or disabled explicitly, we add a Expect: - 100-continue to the headers which actually speeds up post operations - (as there is one packet coming back from the web server) */ - ptr = Curl_checkheaders(data, "Expect:"); - if (ptr) { + if(use_http_1_1plus(data, conn) && + (conn->httpversion != 20)) { + /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an + Expect: 100-continue to the headers which actually speeds up post + operations (as there is one packet coming back from the web server) */ + ptr = Curl_checkheaders(conn, "Expect:"); + if(ptr) { data->state.expect100header = Curl_compareheader(ptr, "Expect:", "100-continue"); } else { result = Curl_add_bufferf(req_buffer, "Expect: 100-continue\r\n"); - if(result == CURLE_OK) + if(!result) data->state.expect100header = TRUE; } } return result; } +enum proxy_use { + HEADER_SERVER, /* direct to server */ + HEADER_PROXY, /* regular request to proxy */ + HEADER_CONNECT /* sending CONNECT to a proxy */ +}; + CURLcode Curl_add_custom_headers(struct connectdata *conn, - Curl_send_buffer *req_buffer) + bool is_connect, + Curl_send_buffer *req_buffer) { char *ptr; - struct curl_slist *headers=conn->data->set.headers; + struct curl_slist *h[2]; + struct curl_slist *headers; + int numlists=1; /* by default */ + struct SessionHandle *data = conn->data; + int i; - while(headers) { - ptr = strchr(headers->data, ':'); - if(ptr) { - /* we require a colon for this to be a true header */ + enum proxy_use proxy; - ptr++; /* pass the colon */ - while(*ptr && ISSPACE(*ptr)) - ptr++; + if(is_connect) + proxy = HEADER_CONNECT; + else + proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy? + HEADER_PROXY:HEADER_SERVER; - if(*ptr) { - /* only send this if the contents was non-blank */ + switch(proxy) { + case HEADER_SERVER: + h[0] = data->set.headers; + break; + case HEADER_PROXY: + h[0] = data->set.headers; + if(data->set.sep_headers) { + h[1] = data->set.proxyheaders; + numlists++; + } + break; + case HEADER_CONNECT: + if(data->set.sep_headers) + h[0] = data->set.proxyheaders; + else + h[0] = data->set.headers; + break; + } - if(conn->allocptr.host && - /* a Host: header was sent already, don't pass on any custom Host: - header as that will produce *two* in the same request! */ - checkprefix("Host:", headers->data)) - ; - else if(conn->data->set.httpreq == HTTPREQ_POST_FORM && - /* this header (extended by formdata.c) is sent later */ - checkprefix("Content-Type:", headers->data)) - ; - else if(conn->bits.authneg && - /* while doing auth neg, don't allow the custom length since - we will force length zero then */ - checkprefix("Content-Length", headers->data)) - ; - else { - CURLcode result = Curl_add_bufferf(req_buffer, "%s\r\n", - headers->data); - if(result) - return result; + /* loop through one or two lists */ + for(i=0; i < numlists; i++) { + headers = h[i]; + + while(headers) { + ptr = strchr(headers->data, ':'); + if(ptr) { + /* we require a colon for this to be a true header */ + + ptr++; /* pass the colon */ + while(*ptr && ISSPACE(*ptr)) + ptr++; + + if(*ptr) { + /* only send this if the contents was non-blank */ + + if(conn->allocptr.host && + /* a Host: header was sent already, don't pass on any custom Host: + header as that will produce *two* in the same request! */ + checkprefix("Host:", headers->data)) + ; + else if(data->set.httpreq == HTTPREQ_POST_FORM && + /* this header (extended by formdata.c) is sent later */ + checkprefix("Content-Type:", headers->data)) + ; + else if(conn->bits.authneg && + /* while doing auth neg, don't allow the custom length since + we will force length zero then */ + checkprefix("Content-Length", headers->data)) + ; + else if(conn->allocptr.te && + /* when asking for Transfer-Encoding, don't pass on a custom + Connection: */ + checkprefix("Connection", headers->data)) + ; + else { + CURLcode result = Curl_add_bufferf(req_buffer, "%s\r\n", + headers->data); + if(result) + return result; + } } } + else { + ptr = strchr(headers->data, ';'); + if(ptr) { + + ptr++; /* pass the semicolon */ + while(*ptr && ISSPACE(*ptr)) + ptr++; + + if(*ptr) { + /* this may be used for something else in the future */ + } + else { + if(*(--ptr) == ';') { + CURLcode result; + + /* send no-value custom header if terminated by semicolon */ + *ptr = ':'; + result = Curl_add_bufferf(req_buffer, "%s\r\n", + headers->data); + if(result) + return result; + } + } + } + } + headers = headers->next; } - headers = headers->next; } return CURLE_OK; } @@ -2040,9 +1702,21 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, CURLcode Curl_add_timecondition(struct SessionHandle *data, Curl_send_buffer *req_buffer) { - struct tm *tm; + const struct tm *tm; char *buf = data->state.buffer; - CURLcode result = CURLE_OK; + struct tm keeptime; + CURLcode result; + + if(data->set.timecondition == CURL_TIMECOND_NONE) + /* no condition was asked for */ + return CURLE_OK; + + result = Curl_gmtime(data->set.timevalue, &keeptime); + if(result) { + failf(data, "Invalid TIMEVALUE"); + return result; + } + tm = &keeptime; /* The If-Modified-Since header family should have their times set in * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be @@ -2051,14 +1725,6 @@ CURLcode Curl_add_timecondition(struct SessionHandle *data, * Time)." (see page 20 of RFC2616). */ -#ifdef HAVE_GMTIME_R - /* thread-safe version */ - struct tm keeptime; - tm = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime); -#else - tm = gmtime(&data->set.timevalue); -#endif - /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ snprintf(buf, BUFSIZE-1, "%s, %02d %s %4d %02d:%02d:%02d GMT", @@ -2071,8 +1737,9 @@ CURLcode Curl_add_timecondition(struct SessionHandle *data, tm->tm_sec); switch(data->set.timecondition) { - case CURL_TIMECOND_IFMODSINCE: default: + break; + case CURL_TIMECOND_IFMODSINCE: result = Curl_add_bufferf(req_buffer, "If-Modified-Since: %s\r\n", buf); break; @@ -2096,8 +1763,8 @@ CURLcode Curl_add_timecondition(struct SessionHandle *data, */ CURLcode Curl_http(struct connectdata *conn, bool *done) { - struct SessionHandle *data=conn->data; - CURLcode result=CURLE_OK; + struct SessionHandle *data = conn->data; + CURLcode result = CURLE_OK; struct HTTP *http; const char *ppath = data->state.path; bool paste_ftp_userpwd = FALSE; @@ -2107,11 +1774,13 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) const char *ptr; const char *request; Curl_HttpReq httpreq = data->set.httpreq; +#if !defined(CURL_DISABLE_COOKIES) char *addcookies = NULL; +#endif curl_off_t included_body = 0; const char *httpstring; Curl_send_buffer *req_buffer; - curl_off_t postsize; /* off_t type to be able to hold a large file size */ + curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */ int seekerr = CURL_SEEKFUNC_OK; /* Always consider the DO phase done after this function call, even if there @@ -2119,34 +1788,52 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) the rest of the request in the PERFORM phase. */ *done = TRUE; - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); + if(conn->httpversion < 20) { /* unless the connection is re-used and already + http2 */ + switch(conn->negnpn) { + case CURL_HTTP_VERSION_2: + conn->httpversion = 20; /* we know we're on HTTP/2 now */ + result = Curl_http2_init(conn); + if(result) + return result; - if(!data->state.proto.http) { - /* Only allocate this struct if we don't already have it! */ + result = Curl_http2_setup(conn); + if(result) + return result; - http = calloc(1, sizeof(struct HTTP)); - if(!http) - return CURLE_OUT_OF_MEMORY; - data->state.proto.http = http; + result = Curl_http2_switched(conn, NULL, 0); + if(result) + return result; + break; + case CURL_HTTP_VERSION_1_1: + /* continue with HTTP/1.1 when explicitly requested */ + break; + default: + /* and as fallback */ + break; + } } - else - http = data->state.proto.http; + else { + /* prepare for a http2 request */ + result = Curl_http2_setup(conn); + if(result) + return result; + } + + http = data->req.protop; if(!data->state.this_is_a_follow) { - /* this is not a followed location, get the original host name */ - if(data->state.first_host) - /* Free to avoid leaking memory on multiple requests*/ - free(data->state.first_host); + /* Free to avoid leaking memory on multiple requests*/ + free(data->state.first_host); data->state.first_host = strdup(conn->host.name); if(!data->state.first_host) return CURLE_OUT_OF_MEMORY; } + http->writebytecount = http->readbytecount = 0; - if( (conn->protocol&(PROT_HTTP|PROT_FTP)) && - data->set.upload) { + if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) && + data->set.upload) { httpreq = HTTPREQ_PUT; } @@ -2181,13 +1868,13 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) it might have been used in the proxy connect, but if we have got a header with the user-agent string specified, we erase the previously made string here. */ - if(Curl_checkheaders(data, "User-Agent:") && conn->allocptr.uagent) { + if(Curl_checkheaders(conn, "User-Agent:")) { free(conn->allocptr.uagent); conn->allocptr.uagent=NULL; } /* setup the authentication headers */ - result = http_output_auth(conn, request, ppath, FALSE); + result = Curl_http_output_auth(conn, request, ppath, FALSE); if(result) return result; @@ -2202,15 +1889,20 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->bits.authneg = FALSE; Curl_safefree(conn->allocptr.ref); - if(data->change.referer && !Curl_checkheaders(data, "Referer:")) + if(data->change.referer && !Curl_checkheaders(conn, "Referer:")) { conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer); + if(!conn->allocptr.ref) + return CURLE_OUT_OF_MEMORY; + } else conn->allocptr.ref = NULL; - if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(data, "Cookie:")) +#if !defined(CURL_DISABLE_COOKIES) + if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie:")) addcookies = data->set.str[STRING_COOKIE]; +#endif - if(!Curl_checkheaders(data, "Accept-Encoding:") && + if(!Curl_checkheaders(conn, "Accept-Encoding:") && data->set.str[STRING_ENCODING]) { Curl_safefree(conn->allocptr.accept_encoding); conn->allocptr.accept_encoding = @@ -2219,40 +1911,69 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return CURLE_OUT_OF_MEMORY; } - ptr = Curl_checkheaders(data, "Transfer-Encoding:"); - if(ptr) { - /* Some kind of TE is requested, check if 'chunked' is chosen */ - data->req.upload_chunky = - Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"); +#ifdef HAVE_LIBZ + /* we only consider transfer-encoding magic if libz support is built-in */ + + if(!Curl_checkheaders(conn, "TE:") && + data->set.http_transfer_encoding) { + /* When we are to insert a TE: header in the request, we must also insert + TE in a Connection: header, so we need to merge the custom provided + Connection: header and prevent the original to get sent. Note that if + the user has inserted his/hers own TE: header we don't do this magic + but then assume that the user will handle it all! */ + char *cptr = Curl_checkheaders(conn, "Connection:"); +#define TE_HEADER "TE: gzip\r\n" + + Curl_safefree(conn->allocptr.te); + + /* Create the (updated) Connection: header */ + conn->allocptr.te = cptr? aprintf("%s, TE\r\n" TE_HEADER, cptr): + strdup("Connection: TE\r\n" TE_HEADER); + + if(!conn->allocptr.te) + return CURLE_OUT_OF_MEMORY; } +#endif + + if(conn->httpversion == 20) + /* In HTTP2 forbids Transfer-Encoding: chunked */ + ptr = NULL; else { - if((conn->protocol&PROT_HTTP) && - data->set.upload && - (data->set.infilesize == -1)) { - if(conn->bits.authneg) - /* don't enable chunked during auth neg */ - ; - else if(use_http_1_1(data, conn)) { - /* HTTP, upload, unknown file size and not HTTP 1.0 */ - data->req.upload_chunky = TRUE; - } - else { - failf(data, "Chunky upload is not supported by HTTP 1.0"); - return CURLE_UPLOAD_FAILED; - } + ptr = Curl_checkheaders(conn, "Transfer-Encoding:"); + if(ptr) { + /* Some kind of TE is requested, check if 'chunked' is chosen */ + data->req.upload_chunky = + Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"); } else { - /* else, no chunky upload */ - data->req.upload_chunky = FALSE; - } + if((conn->handler->protocol&PROTO_FAMILY_HTTP) && + data->set.upload && + (data->state.infilesize == -1)) { + if(conn->bits.authneg) + /* don't enable chunked during auth neg */ + ; + else if(use_http_1_1plus(data, conn)) { + /* HTTP, upload, unknown file size and not HTTP 1.0 */ + data->req.upload_chunky = TRUE; + } + else { + failf(data, "Chunky upload is not supported by HTTP 1.0"); + return CURLE_UPLOAD_FAILED; + } + } + else { + /* else, no chunky upload */ + data->req.upload_chunky = FALSE; + } - if(data->req.upload_chunky) - te = "Transfer-Encoding: chunked\r\n"; + if(data->req.upload_chunky) + te = "Transfer-Encoding: chunked\r\n"; + } } Curl_safefree(conn->allocptr.host); - ptr = Curl_checkheaders(data, "Host:"); + ptr = Curl_checkheaders(conn, "Host:"); if(ptr && (!data->state.this_is_a_follow || Curl_raw_equal(data->state.first_host, conn->host.name))) { #if !defined(CURL_DISABLE_COOKIES) @@ -2262,29 +1983,52 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) redirected request is being out on thin ice. Except if the host name is the same as the first one! */ char *cookiehost = Curl_copy_header_value(ptr); - if (!cookiehost) + if(!cookiehost) return CURLE_OUT_OF_MEMORY; - if (!*cookiehost) + if(!*cookiehost) /* ignore empty data */ free(cookiehost); else { - char *colon = strchr(cookiehost, ':'); - if (colon) - *colon = 0; /* The host must not include an embedded port number */ + /* If the host begins with '[', we start searching for the port after + the bracket has been closed */ + int startsearch = 0; + if(*cookiehost == '[') { + char *closingbracket; + /* since the 'cookiehost' is an allocated memory area that will be + freed later we cannot simply increment the pointer */ + memmove(cookiehost, cookiehost + 1, strlen(cookiehost) - 1); + closingbracket = strchr(cookiehost, ']'); + if(closingbracket) + *closingbracket = 0; + } + else { + char *colon = strchr(cookiehost + startsearch, ':'); + if(colon) + *colon = 0; /* The host must not include an embedded port number */ + } Curl_safefree(conn->allocptr.cookiehost); conn->allocptr.cookiehost = cookiehost; } #endif - conn->allocptr.host = NULL; + if(strcmp("Host:", ptr)) { + conn->allocptr.host = aprintf("%s\r\n", ptr); + if(!conn->allocptr.host) + return CURLE_OUT_OF_MEMORY; + } + else + /* when clearing the header */ + conn->allocptr.host = NULL; } else { /* When building Host: headers, we must put the host name within [brackets] if the host name is a plain IPv6-address. RFC2732-style. */ - if(((conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTPS)) || - (!(conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTP)) ) - /* if(HTTPS on port 443) OR (non-HTTPS on port 80) then don't include + if(((conn->given->protocol&CURLPROTO_HTTPS) && + (conn->remote_port == PORT_HTTPS)) || + ((conn->given->protocol&CURLPROTO_HTTP) && + (conn->remote_port == PORT_HTTP)) ) + /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include the port number in the host string */ conn->allocptr.host = aprintf("Host: %s%s%s\r\n", conn->bits.ipv6_ip?"[":"", @@ -2334,8 +2078,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) memcpy(newurl + newlen + (ptr - url), ptr + currlen, /* copy the trailing zero byte too */ urllen - (ptr-url) - currlen + 1); - if(data->change.url_alloc) - free(data->change.url); + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } data->change.url = newurl; data->change.url_alloc = TRUE; } @@ -2345,7 +2091,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } ppath = data->change.url; if(checkprefix("ftp://", ppath)) { - if (data->set.proxy_transfer_mode) { + if(data->set.proxy_transfer_mode) { /* when doing ftp, append ;type= if not present */ char *type = strstr(ppath, ";type="); if(type && type[6] && type[7] == 0) { @@ -2362,14 +2108,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) char *p = ftp_typecode; /* avoid sending invalid URLs like ftp://example.com;type=i if the * user specified ftp://example.com without the slash */ - if (!*data->state.path && ppath[strlen(ppath) - 1] != '/') { + if(!*data->state.path && ppath[strlen(ppath) - 1] != '/') { *p++ = '/'; } snprintf(p, sizeof(ftp_typecode) - 1, ";type=%c", data->set.prefer_ascii ? 'a' : 'i'); } } - if (conn->bits.user_passwd && !conn->bits.userpwd_in_url) + if(conn->bits.user_passwd && !conn->bits.userpwd_in_url) paste_ftp_userpwd = TRUE; } } @@ -2379,13 +2125,13 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* we must build the whole post sequence first, so that we have a size of the whole transfer before we start to send it */ result = Curl_getformdata(data, &http->sendit, data->set.httppost, - Curl_checkheaders(data, "Content-Type:"), + Curl_checkheaders(conn, "Content-Type:"), &http->postsize); if(result) return result; } - http->p_accept = Curl_checkheaders(data, "Accept:")?NULL:"Accept: */*\r\n"; + http->p_accept = Curl_checkheaders(conn, "Accept:")?NULL:"Accept: */*\r\n"; if(( (HTTPREQ_POST == httpreq) || (HTTPREQ_POST_FORM == httpreq) || @@ -2404,7 +2150,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) * This is meant to get the size of the present remote-file by itself. * We don't support this now. Bail out! */ - data->state.resume_from = 0; + data->state.resume_from = 0; } if(data->state.resume_from && !data->state.this_is_a_follow) { @@ -2431,16 +2177,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) BUFSIZE : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread = - data->set.fread_func(data->state.buffer, 1, readthisamountnow, - data->set.in); + data->state.fread_func(data->state.buffer, 1, readthisamountnow, + data->state.in); passed += actuallyread; if((actuallyread == 0) || (actuallyread > readthisamountnow)) { /* this checks for greater-than only to make sure that the CURL_READFUNC_ABORT return code still aborts */ - failf(data, "Could only read %" FORMAT_OFF_T - " bytes from the input", - passed); + failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T + " bytes from the input", passed); return CURLE_READ_ERROR; } } while(passed < data->state.resume_from); @@ -2448,10 +2193,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } /* now, decrease the size of the read */ - if(data->set.infilesize>0) { - data->set.infilesize -= data->state.resume_from; + if(data->state.infilesize>0) { + data->state.infilesize -= data->state.resume_from; - if(data->set.infilesize <= 0) { + if(data->state.infilesize <= 0) { failf(data, "File already completely uploaded"); return CURLE_PARTIAL_FILE; } @@ -2466,46 +2211,44 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) * ones if any such are specified. */ if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) && - !Curl_checkheaders(data, "Range:")) { + !Curl_checkheaders(conn, "Range:")) { /* if a line like this was already allocated, free the previous one */ - if(conn->allocptr.rangeline) - free(conn->allocptr.rangeline); + free(conn->allocptr.rangeline); conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", data->state.range); } else if((httpreq != HTTPREQ_GET) && - !Curl_checkheaders(data, "Content-Range:")) { + !Curl_checkheaders(conn, "Content-Range:")) { /* if a line like this was already allocated, free the previous one */ - if(conn->allocptr.rangeline) - free(conn->allocptr.rangeline); + free(conn->allocptr.rangeline); if(data->set.set_resume_from < 0) { /* Upload resume was asked for, but we don't know the size of the remote part so we tell the server (and act accordingly) that we upload the whole file (again) */ conn->allocptr.rangeline = - aprintf("Content-Range: bytes 0-%" FORMAT_OFF_T - "/%" FORMAT_OFF_T "\r\n", - data->set.infilesize - 1, data->set.infilesize); + aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T + "/%" CURL_FORMAT_CURL_OFF_T "\r\n", + data->state.infilesize - 1, data->state.infilesize); } else if(data->state.resume_from) { /* This is because "resume" was selected */ curl_off_t total_expected_size= - data->state.resume_from + data->set.infilesize; + data->state.resume_from + data->state.infilesize; conn->allocptr.rangeline = - aprintf("Content-Range: bytes %s%" FORMAT_OFF_T - "/%" FORMAT_OFF_T "\r\n", - data->state.range, total_expected_size-1, - total_expected_size); + aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T + "/%" CURL_FORMAT_CURL_OFF_T "\r\n", + data->state.range, total_expected_size-1, + total_expected_size); } else { /* Range was selected and then we just pass the incoming range and append total size */ conn->allocptr.rangeline = - aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n", - data->state.range, data->set.infilesize); + aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n", + data->state.range, data->state.infilesize); } if(!conn->allocptr.rangeline) return CURLE_OUT_OF_MEMORY; @@ -2514,7 +2257,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* Use 1.1 unless the user specifically asked for 1.0 or the server only supports 1.0 */ - httpstring= use_http_1_1(data, conn)?"1.1":"1.0"; + httpstring= use_http_1_1plus(data, conn)?"1.1":"1.0"; /* initialize a dynamic send-buffer */ req_buffer = Curl_add_buffer_init(); @@ -2525,69 +2268,85 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* add the main request stuff */ /* GET/HEAD/POST/PUT */ result = Curl_add_bufferf(req_buffer, "%s ", request); - if (result) + if(result) return result; /* url */ - if (paste_ftp_userpwd) + if(paste_ftp_userpwd) result = Curl_add_bufferf(req_buffer, "ftp://%s:%s@%s", conn->user, conn->passwd, ppath + sizeof("ftp://") - 1); else result = Curl_add_buffer(req_buffer, ppath, strlen(ppath)); - if (result) + if(result) return result; - result = Curl_add_bufferf(req_buffer, - "%s" /* ftp typecode (;type=x) */ - " HTTP/%s\r\n" /* HTTP version */ - "%s" /* proxyuserpwd */ - "%s" /* userpwd */ - "%s" /* range */ - "%s" /* user agent */ - "%s" /* host */ - "%s" /* accept */ - "%s" /* accept-encoding */ - "%s" /* referer */ - "%s" /* Proxy-Connection */ - "%s",/* transfer-encoding */ + result = + Curl_add_bufferf(req_buffer, + "%s" /* ftp typecode (;type=x) */ + " HTTP/%s\r\n" /* HTTP version */ + "%s" /* host */ + "%s" /* proxyuserpwd */ + "%s" /* userpwd */ + "%s" /* range */ + "%s" /* user agent */ + "%s" /* accept */ + "%s" /* TE: */ + "%s" /* accept-encoding */ + "%s" /* referer */ + "%s",/* transfer-encoding */ - ftp_typecode, - httpstring, - conn->allocptr.proxyuserpwd? - conn->allocptr.proxyuserpwd:"", - conn->allocptr.userpwd?conn->allocptr.userpwd:"", - (data->state.use_range && conn->allocptr.rangeline)? - conn->allocptr.rangeline:"", - (data->set.str[STRING_USERAGENT] && - *data->set.str[STRING_USERAGENT] && conn->allocptr.uagent)? - conn->allocptr.uagent:"", - (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */ - http->p_accept?http->p_accept:"", - (data->set.str[STRING_ENCODING] && - *data->set.str[STRING_ENCODING] && - conn->allocptr.accept_encoding)? - conn->allocptr.accept_encoding:"", - (data->change.referer && conn->allocptr.ref)? - conn->allocptr.ref:"" /* Referer: */, - (conn->bits.httpproxy && - !conn->bits.tunnel_proxy && - !Curl_checkheaders(data, "Proxy-Connection:"))? - "Proxy-Connection: Keep-Alive\r\n":"", - te + ftp_typecode, + httpstring, + (conn->allocptr.host?conn->allocptr.host:""), + conn->allocptr.proxyuserpwd? + conn->allocptr.proxyuserpwd:"", + conn->allocptr.userpwd?conn->allocptr.userpwd:"", + (data->state.use_range && conn->allocptr.rangeline)? + conn->allocptr.rangeline:"", + (data->set.str[STRING_USERAGENT] && + *data->set.str[STRING_USERAGENT] && + conn->allocptr.uagent)? + conn->allocptr.uagent:"", + http->p_accept?http->p_accept:"", + conn->allocptr.te?conn->allocptr.te:"", + (data->set.str[STRING_ENCODING] && + *data->set.str[STRING_ENCODING] && + conn->allocptr.accept_encoding)? + conn->allocptr.accept_encoding:"", + (data->change.referer && conn->allocptr.ref)? + conn->allocptr.ref:"" /* Referer: */, + te ); - /* - * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM - * with basic and digest, it will be freed anyway by the next request - */ + /* clear userpwd to avoid re-using credentials from re-used connections */ + Curl_safefree(conn->allocptr.userpwd); - Curl_safefree (conn->allocptr.userpwd); - conn->allocptr.userpwd = NULL; + /* + * Free proxyuserpwd for Negotiate/NTLM. Cannot reuse as it is associated + * with the connection and shouldn't be repeated over it either. + */ + switch (data->state.authproxy.picked) { + case CURLAUTH_NEGOTIATE: + case CURLAUTH_NTLM: + case CURLAUTH_NTLM_WB: + Curl_safefree(conn->allocptr.proxyuserpwd); + break; + } if(result) return result; + if(!(conn->handler->flags&PROTOPT_SSL) && + conn->httpversion != 20 && + (data->set.httpversion == CURL_HTTP_VERSION_2)) { + /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done + over SSL */ + result = Curl_http2_request_upgrade(req_buffer, conn); + if(result) + return result; + } + #if !defined(CURL_DISABLE_COOKIES) if(data->cookies || addcookies) { struct Cookie *co=NULL; /* no cookies from start */ @@ -2599,7 +2358,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->allocptr.cookiehost? conn->allocptr.cookiehost:host, data->state.path, - (bool)(conn->protocol&PROT_HTTPS?TRUE:FALSE)); + (conn->handler->protocol&CURLPROTO_HTTPS)? + TRUE:FALSE); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } if(co) { @@ -2613,8 +2373,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) break; } result = Curl_add_bufferf(req_buffer, - "%s%s=%s", count?"; ":"", - co->name, co->value); + "%s%s=%s", count?"; ":"", + co->name, co->value); if(result) break; count++; @@ -2623,17 +2383,16 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } Curl_cookie_freelist(store, FALSE); /* free the cookie list */ } - if(addcookies && (CURLE_OK == result)) { + if(addcookies && !result) { if(!count) result = Curl_add_bufferf(req_buffer, "Cookie: "); - if(CURLE_OK == result) { - result = Curl_add_bufferf(req_buffer, "%s%s", - count?"; ":"", - addcookies); + if(!result) { + result = Curl_add_bufferf(req_buffer, "%s%s", count?"; ":"", + addcookies); count++; } } - if(count && (CURLE_OK == result)) + if(count && !result) result = Curl_add_buffer(req_buffer, "\r\n", 2); if(result) @@ -2641,18 +2400,16 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } #endif - if(data->set.timecondition) { - result = Curl_add_timecondition(data, req_buffer); - if(result) - return result; - } + result = Curl_add_timecondition(data, req_buffer); + if(result) + return result; - result = Curl_add_custom_headers(conn, req_buffer); + result = Curl_add_custom_headers(conn, FALSE, req_buffer); if(result) return result; http->postdata = NULL; /* nothing to post at this point */ - Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */ + Curl_pgrsSetUploadSize(data, -1); /* upload size is unknown atm */ /* If 'authdone' is FALSE, we must not set the write socket index to the Curl_transfer() call below, as we're not ready to actually upload any @@ -2685,22 +2442,23 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* Get the currently set callback function pointer and store that in the form struct since we might want the actual user-provided callback later - on. The conn->fread_func pointer itself will be changed for the + on. The data->set.fread_func pointer itself will be changed for the multipart case to the function that returns a multipart formatted stream. */ - http->form.fread_func = conn->fread_func; + http->form.fread_func = data->state.fread_func; /* Set the read function to read from the generated form data */ - conn->fread_func = (curl_read_callback)Curl_FormReader; - conn->fread_in = &http->form; + data->state.fread_func = (curl_read_callback)Curl_FormReader; + data->state.in = &http->form; http->sending = HTTPSEND_BODY; - if(!data->req.upload_chunky) { + if(!data->req.upload_chunky && + !Curl_checkheaders(conn, "Content-Length:")) { /* only add Content-Length if not uploading chunked */ result = Curl_add_bufferf(req_buffer, - "Content-Length: %" FORMAT_OFF_T "\r\n", - http->postsize); + "Content-Length: %" CURL_FORMAT_CURL_OFF_T + "\r\n", http->postsize); if(result) return result; } @@ -2750,14 +2508,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_formclean(&http->sendit); /* free that whole lot */ return result; } -#ifdef CURL_DOES_CONVERSIONS -/* time to convert the form data... */ - result = Curl_formconvert(data, http->sendit); + + /* convert the form data */ + result = Curl_convert_form(data, http->sendit); if(result) { Curl_formclean(&http->sendit); /* free that whole lot */ return result; } -#endif /* CURL_DOES_CONVERSIONS */ + break; case HTTPREQ_PUT: /* Let's PUT the data to the server! */ @@ -2765,20 +2523,23 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(conn->bits.authneg) postsize = 0; else - postsize = data->set.infilesize; + postsize = data->state.infilesize; - if((postsize != -1) && !data->req.upload_chunky) { + if((postsize != -1) && !data->req.upload_chunky && + !Curl_checkheaders(conn, "Content-Length:")) { /* only add Content-Length if not uploading chunked */ result = Curl_add_bufferf(req_buffer, - "Content-Length: %" FORMAT_OFF_T "\r\n", - postsize ); + "Content-Length: %" CURL_FORMAT_CURL_OFF_T + "\r\n", postsize); if(result) return result; } - result = expect100(data, conn, req_buffer); - if(result) - return result; + if(postsize != 0) { + result = expect100(data, conn, req_buffer); + if(result) + return result; + } result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */ if(result) @@ -2808,27 +2569,26 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) postsize = 0; else { /* figure out the size of the postfields */ - postsize = (data->set.postfieldsize != -1)? - data->set.postfieldsize: + postsize = (data->state.infilesize != -1)? + data->state.infilesize: (data->set.postfields? (curl_off_t)strlen(data->set.postfields):-1); } - if(!data->req.upload_chunky) { - /* We only set Content-Length and allow a custom Content-Length if - we don't upload data chunked, as RFC2616 forbids us to set both - kinds of headers (Transfer-Encoding: chunked and Content-Length) */ - if(conn->bits.authneg || !Curl_checkheaders(data, "Content-Length:")) { - /* we allow replacing this header if not during auth negotiation, - although it isn't very wise to actually set your own */ - result = Curl_add_bufferf(req_buffer, - "Content-Length: %" FORMAT_OFF_T"\r\n", - postsize); - if(result) - return result; - } + /* We only set Content-Length and allow a custom Content-Length if + we don't upload data chunked, as RFC2616 forbids us to set both + kinds of headers (Transfer-Encoding: chunked and Content-Length) */ + if((postsize != -1) && !data->req.upload_chunky && + !Curl_checkheaders(conn, "Content-Length:")) { + /* we allow replacing this header if not during auth negotiation, + although it isn't very wise to actually set your own */ + result = Curl_add_bufferf(req_buffer, + "Content-Length: %" CURL_FORMAT_CURL_OFF_T + "\r\n", postsize); + if(result) + return result; } - if(!Curl_checkheaders(data, "Content-Type:")) { + if(!Curl_checkheaders(conn, "Content-Type:")) { result = Curl_add_bufferf(req_buffer, "Content-Type: application/" "x-www-form-urlencoded\r\n"); @@ -2840,7 +2600,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) the somewhat bigger ones we allow the app to disable it. Just make sure that the expect100header is always set to the preferred value here. */ - ptr = Curl_checkheaders(data, "Expect:"); + ptr = Curl_checkheaders(conn, "Expect:"); if(ptr) { data->state.expect100header = Curl_compareheader(ptr, "Expect:", "100-continue"); @@ -2855,7 +2615,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(data->set.postfields) { - if(!data->state.expect100header && + /* In HTTP2, we send request body in DATA frame regardless of + its size. */ + if(conn->httpversion != 20 && + !data->state.expect100header && (postsize < MAX_INITIAL_POST_SIZE)) { /* if we don't use expect: 100 AND postsize is less than MAX_INITIAL_POST_SIZE @@ -2872,20 +2635,25 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* We're not sending it 'chunked', append it to the request already now to reduce the number if send() calls */ result = Curl_add_buffer(req_buffer, data->set.postfields, - (size_t)postsize); + (size_t)postsize); included_body = postsize; } else { - /* Append the POST data chunky-style */ - result = Curl_add_bufferf(req_buffer, "%x\r\n", (int)postsize); - if(CURLE_OK == result) - result = Curl_add_buffer(req_buffer, data->set.postfields, - (size_t)postsize); - if(CURLE_OK == result) - result = Curl_add_buffer(req_buffer, - "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7); - /* CR LF 0 CR LF CR LF */ - included_body = postsize + 7; + if(postsize) { + /* Append the POST data chunky-style */ + result = Curl_add_bufferf(req_buffer, "%x\r\n", (int)postsize); + if(!result) { + result = Curl_add_buffer(req_buffer, data->set.postfields, + (size_t)postsize); + if(!result) + result = Curl_add_buffer(req_buffer, "\r\n", 2); + included_body = postsize + 2; + } + } + if(!result) + result = Curl_add_buffer(req_buffer, "\x30\x0d\x0a\x0d\x0a", 5); + /* 0 CR LF CR LF */ + included_body += 5; } if(result) return result; @@ -2899,8 +2667,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) http->sending = HTTPSEND_BODY; - conn->fread_func = (curl_read_callback)readmoredata; - conn->fread_in = (void *)conn; + data->state.fread_func = (curl_read_callback)readmoredata; + data->state.in = (void *)conn; /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, http->postsize); @@ -2919,13 +2687,13 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* Chunky upload is selected and we're negotiating auth still, send end-of-data only */ result = Curl_add_buffer(req_buffer, - "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7); - /* CR LF 0 CR LF CR LF */ + "\x30\x0d\x0a\x0d\x0a", 5); + /* 0 CR LF CR LF */ if(result) return result; } - else if(data->set.postfieldsize) { + else if(data->state.infilesize) { /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, postsize?postsize:-1); @@ -2976,6 +2744,17 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_pgrsSetUploadCounter(data, http->writebytecount); if(Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; + + if(http->writebytecount >= postsize) { + /* already sent the entire request body, mark the "upload" as + complete */ + infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T + " out of %" CURL_FORMAT_CURL_OFF_T " bytes\n", + http->writebytecount, postsize); + data->req.upload_done = TRUE; + data->req.keepon &= ~KEEP_SEND; /* we're done writing */ + data->req.exp100 = EXP100_SEND_DATA; /* already sent */ + } } return result; @@ -2996,13 +2775,13 @@ checkhttpprefix(struct SessionHandle *data, /* convert from the network encoding using a scratch area */ char *scratch = strdup(s); if(NULL == scratch) { - failf (data, "Failed to allocate memory for conversion!"); - return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ + failf (data, "Failed to allocate memory for conversion!"); + return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ } if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) { /* Curl_convert_from_network calls failf if unsuccessful */ - free(scratch); - return FALSE; /* can't return CURLE_foobar so return FALSE */ + free(scratch); + return FALSE; /* can't return CURLE_foobar so return FALSE */ } s = scratch; #endif /* CURL_DOES_CONVERSIONS */ @@ -3015,9 +2794,8 @@ checkhttpprefix(struct SessionHandle *data, head = head->next; } - if((rc != TRUE) && (checkprefix("HTTP/", s))) { + if(!rc && (checkprefix("HTTP/", s))) rc = TRUE; - } #ifdef CURL_DOES_CONVERSIONS free(scratch); @@ -3059,7 +2837,7 @@ checkprotoprefix(struct SessionHandle *data, struct connectdata *conn, const char *s) { #ifndef CURL_DISABLE_RTSP - if(conn->protocol & PROT_RTSP) + if(conn->handler->protocol & CURLPROTO_RTSP) return checkrtspprefix(data, s); #else (void)conn; @@ -3111,6 +2889,42 @@ static CURLcode header_append(struct SessionHandle *data, return CURLE_OK; } +static void print_http_error(struct SessionHandle *data) +{ + struct SingleRequest *k = &data->req; + char *beg = k->p; + + /* make sure that data->req.p points to the HTTP status line */ + if(!strncmp(beg, "HTTP", 4)) { + + /* skip to HTTP status code */ + beg = strchr(beg, ' '); + if(beg && *++beg) { + + /* find trailing CR */ + char end_char = '\r'; + char *end = strchr(beg, end_char); + if(!end) { + /* try to find LF (workaround for non-compliant HTTP servers) */ + end_char = '\n'; + end = strchr(beg, end_char); + } + + if(end) { + /* temporarily replace CR or LF by NUL and print the error message */ + *end = '\0'; + failf(data, "The requested URL returned error: %s", beg); + + /* restore the previously replaced CR or LF */ + *end = end_char; + return; + } + } + } + + /* fall-back to printing the HTTP status code only */ + failf(data, "The requested URL returned error: %d", k->httpcode); +} /* * Read any HTTP header lines from the server and pass them to the client app. @@ -3225,17 +3039,40 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, k->header = TRUE; k->headerline = 0; /* restart the header line counter */ - /* if we did wait for this do enable write now! */ - if(k->exp100) { - k->exp100 = EXP100_SEND_DATA; - k->keepon |= KEEP_SEND; + /* "A user agent MAY ignore unexpected 1xx status responses." */ + switch(k->httpcode) { + case 100: + /* if we did wait for this do enable write now! */ + if(k->exp100) { + k->exp100 = EXP100_SEND_DATA; + k->keepon |= KEEP_SEND; + } + break; + case 101: + /* Switching Protocols */ + if(k->upgr101 == UPGR101_REQUESTED) { + infof(data, "Received 101\n"); + k->upgr101 = UPGR101_RECEIVED; + + /* switch to http2 now. The bytes after response headers + are also processed here, otherwise they are lost. */ + result = Curl_http2_switched(conn, k->str, *nread); + if(result) + return result; + *nread = 0; + } + break; + default: + break; } } else { k->header = FALSE; /* no more header to parse! */ if((k->size == -1) && !k->chunk && !conn->bits.close && - (conn->httpversion >= 11) && !(conn->protocol & PROT_RTSP)) { + (conn->httpversion == 11) && + !(conn->handler->protocol & CURLPROTO_RTSP) && + data->set.httpreq != HTTPREQ_HEAD) { /* On HTTP 1.1, when connection is not to get closed, but no Content-Length nor Content-Encoding chunked have been received, according to RFC2616 section 4.4 point 5, we @@ -3243,26 +3080,28 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, signal the end of the document. */ infof(data, "no chunk, no close, no size. Assume close to " "signal end\n"); - conn->bits.close = TRUE; + connclose(conn, "HTTP: No end-of-message indicator"); } } - if(417 == k->httpcode) { - /* - * we got: "417 Expectation Failed" this means: - * we have made a HTTP call and our Expect Header - * seems to cause a problem => abort the write operations - * (or prevent them from starting). - */ - k->exp100 = EXP100_FAILED; - k->keepon &= ~KEEP_SEND; + /* At this point we have some idea about the fate of the connection. + If we are closing the connection it may result auth failure. */ +#if defined(USE_NTLM) + if(conn->bits.close && + (((data->req.httpcode == 401) && + (conn->ntlm.state == NTLMSTATE_TYPE2)) || + ((data->req.httpcode == 407) && + (conn->proxyntlm.state == NTLMSTATE_TYPE2)))) { + infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n"); + data->state.authproblem = TRUE; } +#endif /* * When all the headers have been parsed, see if we should give * up and return an error. */ - if(Curl_http_should_fail(conn)) { + if(http_should_fail(conn)) { failf (data, "The requested URL returned error: %d", k->httpcode); return CURLE_HTTP_RETURNED_ERROR; @@ -3297,6 +3136,46 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, if(result) return result; + if(k->httpcode >= 300) { + if((!conn->bits.authneg) && !conn->bits.close && + !conn->bits.rewindaftersend) { + /* + * General treatment of errors when about to send data. Including : + * "417 Expectation Failed", while waiting for 100-continue. + * + * The check for close above is done simply because of something + * else has already deemed the connection to get closed then + * something else should've considered the big picture and we + * avoid this check. + * + * rewindaftersend indicates that something has told libcurl to + * continue sending even if it gets discarded + */ + + switch(data->set.httpreq) { + case HTTPREQ_PUT: + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + /* We got an error response. If this happened before the whole + * request body has been sent we stop sending and mark the + * connection for closure after we've read the entire response. + */ + if(!k->upload_done) { + infof(data, "HTTP error before end of send, stop sending\n"); + connclose(conn, "Stop sending data before everything sent"); + k->upload_done = TRUE; + k->keepon &= ~KEEP_SEND; /* don't send */ + if(data->state.expect100header) + k->exp100 = EXP100_FAILED; + } + break; + + default: /* default label present to avoid compiler warnings */ + break; + } + } + } + if(conn->bits.rewindaftersend) { /* We rewind after a complete send, so thus we continue sending now */ @@ -3314,6 +3193,16 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, */ if(data->set.opt_no_body) *stop_reading = TRUE; +#ifndef CURL_DISABLE_RTSP + else if((conn->handler->protocol & CURLPROTO_RTSP) && + (data->set.rtspreq == RTSPREQ_DESCRIBE) && + (k->size <= -1)) + /* Respect section 4.4 of rfc2326: If the Content-Length header is + absent, a length 0 must be assumed. It will prevent libcurl from + hanging on DECRIBE request that got refused for whatever + reason */ + *stop_reading = TRUE; +#endif else { /* If we know the expected size of this document, we set the maximum download size to the size of the expected @@ -3388,33 +3277,45 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, res = Curl_convert_from_network(data, &scratch[0], SCRATCHSIZE); - if(CURLE_OK != res) { + if(res) /* Curl_convert_from_network calls failf if unsuccessful */ return res; - } #else #define HEADER1 k->p /* no conversion needed, just use k->p */ #endif /* CURL_DOES_CONVERSIONS */ - if(conn->protocol & PROT_HTTP) { + if(conn->handler->protocol & PROTO_FAMILY_HTTP) { + /* + * https://tools.ietf.org/html/rfc7230#section-3.1.2 + * + * The reponse code is always a three-digit number in HTTP as the spec + * says. We try to allow any number here, but we cannot make + * guarantees on future behaviors since it isn't within the protocol. + */ nc = sscanf(HEADER1, - " HTTP/%d.%d %3d", - &httpversion_major, - &conn->httpversion, - &k->httpcode); + " HTTP/%d.%d %d", + &httpversion_major, + &conn->httpversion, + &k->httpcode); if(nc==3) { conn->httpversion += 10 * httpversion_major; + + if(k->upgr101 == UPGR101_RECEIVED) { + /* supposedly upgraded to http2 now */ + if(conn->httpversion != 20) + infof(data, "Lying server, not serving HTTP/2\n"); + } } else { /* this is the real world, not a Nirvana NCSA 1.5.x returns this crap when asked for HTTP/1.1 - */ + */ nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode); conn->httpversion = 10; /* If user has set option HTTP200ALIASES, compare header line against list of aliases - */ + */ if(!nc) { if(checkhttpprefix(data, k->p)) { nc = 1; @@ -3424,7 +3325,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, } } } - else if(conn->protocol & PROT_RTSP) { + else if(conn->handler->protocol & CURLPROTO_RTSP) { nc = sscanf(HEADER1, " RTSP/%d.%d %3d", &rtspversion_major, @@ -3444,8 +3345,8 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, data->info.httpcode = k->httpcode; data->info.httpversion = conn->httpversion; - if (!data->state.httpversion || - data->state.httpversion > conn->httpversion) + if(!data->state.httpversion || + data->state.httpversion > conn->httpversion) /* store the lowest server version we encounter */ data->state.httpversion = conn->httpversion; @@ -3469,8 +3370,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, } else { /* serious error, go home! */ - failf (data, "The requested URL returned error: %d", - k->httpcode); + print_http_error(data); return CURLE_HTTP_RETURNED_ERROR; } } @@ -3480,7 +3380,15 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, we get one of those fancy headers that tell us the server keeps it open for us! */ infof(data, "HTTP 1.0, assume close after body\n"); - conn->bits.close = TRUE; + connclose(conn, "HTTP/1.0 close after body"); + } + else if(conn->httpversion == 20 || + (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) { + DEBUGF(infof(data, "HTTP/2 found, allow multiplexing\n")); + + /* HTTP/2 cannot blacklist multiplexing since it is a core + functionality of the protocol */ + conn->bundle->multiuse = BUNDLE_MULTIPLEX; } else if(conn->httpversion >= 11 && !conn->bits.close) { @@ -3489,7 +3397,11 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, DEBUGF(infof(data, "HTTP 1.1 or later with persistent connection, " "pipelining supported\n")); - conn->server_supports_pipelining = TRUE; + /* Activate pipelining if needed */ + if(conn->bundle) { + if(!Curl_pipeline_site_blacklisted(data, conn)) + conn->bundle->multiuse = BUNDLE_PIPELINING; + } } switch(k->httpcode) { @@ -3522,14 +3434,10 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, } } -#ifdef CURL_DOES_CONVERSIONS - /* convert from the network encoding */ result = Curl_convert_from_network(data, k->p, strlen(k->p)); - if(CURLE_OK != result) { - return(result); - } /* Curl_convert_from_network calls failf if unsuccessful */ -#endif /* CURL_DOES_CONVERSIONS */ + if(result) + return result; /* Check for Content-Length: header lines to get size */ if(!k->ignorecl && !data->set.ignorecl && @@ -3552,17 +3460,17 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, /* Negative Content-Length is really odd, and we know it happens for example when older Apache servers send large files */ - conn->bits.close = TRUE; - infof(data, "Negative content-length: %" FORMAT_OFF_T + connclose(conn, "negative content-length"); + infof(data, "Negative content-length: %" CURL_FORMAT_CURL_OFF_T ", closing after transfer\n", contentlength); } } /* check for Content-Type: header lines to get the MIME-type */ else if(checkprefix("Content-Type:", k->p)) { char *contenttype = Curl_copy_header_value(k->p); - if (!contenttype) + if(!contenttype) return CURLE_OUT_OF_MEMORY; - if (!*contenttype) + if(!*contenttype) /* ignore empty data */ free(contenttype); else { @@ -3570,6 +3478,19 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, data->info.contenttype = contenttype; } } + else if(checkprefix("Server:", k->p)) { + if(conn->httpversion < 20) { + /* only do this for non-h2 servers */ + char *server_name = Curl_copy_header_value(k->p); + + /* Turn off pipelining if the server version is blacklisted */ + if(conn->bundle && (conn->bundle->multiuse == BUNDLE_PIPELINING)) { + if(Curl_pipeline_server_blacklisted(data, server_name)) + conn->bundle->multiuse = BUNDLE_NO_MULTIUSE; + } + free(server_name); + } + } else if((conn->httpversion == 10) && conn->bits.httpproxy && Curl_compareheader(k->p, @@ -3580,7 +3501,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, * connection will be kept alive for our pleasure. * Default action for 1.0 is to close. */ - conn->bits.close = FALSE; /* don't close when done */ + connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */ infof(data, "HTTP/1.0 proxy connection set to keep alive!\n"); } else if((conn->httpversion == 11) && @@ -3591,7 +3512,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, * We get a HTTP/1.1 response from a proxy and it says it'll * close down after this transfer. */ - conn->bits.close = TRUE; /* close when done */ + connclose(conn, "Proxy-Connection: asked to close after done"); infof(data, "HTTP/1.1 proxy connection set close!\n"); } else if((conn->httpversion == 10) && @@ -3602,7 +3523,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, * pleasure. Default action for 1.0 is to close. * * [RFC2068, section 19.7.1] */ - conn->bits.close = FALSE; /* don't close when done */ + connkeep(conn, "Connection keep-alive"); infof(data, "HTTP/1.0 connection set to keep alive!\n"); } else if(Curl_compareheader(k->p, "Connection:", "close")) { @@ -3612,10 +3533,11 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, * the connection will close when this request has been * served. */ - conn->bits.close = TRUE; /* close when done */ + connclose(conn, "Connection: close used"); } - else if(Curl_compareheader(k->p, "Transfer-Encoding:", "chunked") && - !(conn->protocol & PROT_RTSP)) { + else if(checkprefix("Transfer-Encoding:", k->p)) { + /* One or more encodings. We check for chunked and/or a compression + algorithm. */ /* * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding * means that the server will send a series of "chunks". Each @@ -3624,10 +3546,52 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, * with the previously mentioned size. There can be any amount * of chunks, and a chunk-data set to zero signals the * end-of-chunks. */ - k->chunk = TRUE; /* chunks coming our way */ - /* init our chunky engine */ - Curl_httpchunk_init(conn); + char *start; + + /* Find the first non-space letter */ + start = k->p + 18; + + for(;;) { + /* skip whitespaces and commas */ + while(*start && (ISSPACE(*start) || (*start == ','))) + start++; + + if(checkprefix("chunked", start)) { + k->chunk = TRUE; /* chunks coming our way */ + + /* init our chunky engine */ + Curl_httpchunk_init(conn); + + start += 7; + } + + if(k->auto_decoding) + /* TODO: we only support the first mentioned compression for now */ + break; + + if(checkprefix("identity", start)) { + k->auto_decoding = IDENTITY; + start += 8; + } + else if(checkprefix("deflate", start)) { + k->auto_decoding = DEFLATE; + start += 7; + } + else if(checkprefix("gzip", start)) { + k->auto_decoding = GZIP; + start += 4; + } + else if(checkprefix("x-gzip", start)) { + k->auto_decoding = GZIP; + start += 6; + } + else + /* unknown! */ + break; + + } + } else if(checkprefix("Content-Encoding:", k->p) && data->set.str[STRING_ENCODING]) { @@ -3647,37 +3611,41 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, /* Record the content-encoding for later use */ if(checkprefix("identity", start)) - k->content_encoding = IDENTITY; + k->auto_decoding = IDENTITY; else if(checkprefix("deflate", start)) - k->content_encoding = DEFLATE; + k->auto_decoding = DEFLATE; else if(checkprefix("gzip", start) || checkprefix("x-gzip", start)) - k->content_encoding = GZIP; - else if(checkprefix("compress", start) - || checkprefix("x-compress", start)) - k->content_encoding = COMPRESS; + k->auto_decoding = GZIP; } else if(checkprefix("Content-Range:", k->p)) { /* Content-Range: bytes [num]- Content-Range: bytes: [num]- Content-Range: [num]- + Content-Range: [asterisk]/[total] The second format was added since Sun's webserver JavaWebServer/1.1.1 obviously sends the header this way! The third added since some servers use that! + The forth means the requested range was unsatisfied. */ char *ptr = k->p + 14; - /* Move forward until first digit */ - while(*ptr && !ISDIGIT(*ptr)) + /* Move forward until first digit or asterisk */ + while(*ptr && !ISDIGIT(*ptr) && *ptr != '*') ptr++; - k->offset = curlx_strtoofft(ptr, NULL, 10); + /* if it truly stopped on a digit */ + if(ISDIGIT(*ptr)) { + k->offset = curlx_strtoofft(ptr, NULL, 10); - if(data->state.resume_from == k->offset) - /* we asked for a resume and we got it */ - k->content_range = TRUE; + if(data->state.resume_from == k->offset) + /* we asked for a resume and we got it */ + k->content_range = TRUE; + } + else + data->state.resume_from = 0; /* get everything */ } #if !defined(CURL_DISABLE_COOKIES) else if(data->cookies && @@ -3706,21 +3674,30 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, (401 == k->httpcode)) || (checkprefix("Proxy-authenticate:", k->p) && (407 == k->httpcode))) { - result = Curl_http_input_auth(conn, k->httpcode, k->p); + + bool proxy = (k->httpcode == 407) ? TRUE : FALSE; + char *auth = Curl_copy_header_value(k->p); + if(!auth) + return CURLE_OUT_OF_MEMORY; + + result = Curl_http_input_auth(conn, proxy, auth); + + free(auth); + if(result) return result; } else if((k->httpcode >= 300 && k->httpcode < 400) && - checkprefix("Location:", k->p)) { + checkprefix("Location:", k->p) && + !data->req.location) { /* this is the URL that the server advises us to use instead */ char *location = Curl_copy_header_value(k->p); - if (!location) + if(!location) return CURLE_OUT_OF_MEMORY; - if (!*location) + if(!*location) /* ignore empty data */ free(location); else { - DEBUGASSERT(!data->req.location); data->req.location = location; if(data->set.http_follow_location) { @@ -3731,19 +3708,18 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, /* some cases of POST and PUT etc needs to rewind the data stream at this point */ - result = Curl_http_perhapsrewind(conn); + result = http_perhapsrewind(conn); if(result) return result; } } } -#ifndef CURL_DISABLE_RTSP - else if(conn->protocol & PROT_RTSP) { + else if(conn->handler->protocol & CURLPROTO_RTSP) { result = Curl_rtsp_parseheader(conn, k->p); if(result) return result; } -#endif + /* * End of header-checks. Write them to the client. */ diff --git a/project/jni/curl/lib/http.h b/project/jni/curl/lib/http.h index 3007c319f..5000df448 100644 --- a/project/jni/curl/lib/http.h +++ b/project/jni/curl/lib/http.h @@ -1,6 +1,5 @@ -#ifndef __HTTP_H -#define __HTTP_H - +#ifndef HEADER_CURL_HTTP_H +#define HEADER_CURL_HTTP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -8,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,23 +21,31 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "curl_setup.h" + #ifndef CURL_DISABLE_HTTP +#ifdef USE_NGHTTP2 +#include +#endif + extern const struct Curl_handler Curl_handler_http; #ifdef USE_SSL extern const struct Curl_handler Curl_handler_https; #endif +/* Header specific functions */ bool Curl_compareheader(const char *headerline, /* line to check */ const char *header, /* header keyword _with_ colon */ const char *content); /* content string to find */ -char *Curl_checkheaders(struct SessionHandle *data, const char *thisheader); - -char *Curl_copy_header_value(const char *h); - +char *Curl_checkheaders(const struct connectdata *conn, + const char *thisheader); +char *Curl_copy_header_value(const char *header); +char *Curl_checkProxyheaders(const struct connectdata *conn, + const char *thisheader); /* ------------------------------------------------------------------------- */ /* * The add_buffer series of functions are used to build one large memory chunk @@ -53,6 +60,7 @@ struct Curl_send_buffer { typedef struct Curl_send_buffer Curl_send_buffer; Curl_send_buffer *Curl_add_buffer_init(void); +void Curl_add_buffer_free(Curl_send_buffer *buff); CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...); CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size); CURLcode Curl_add_buffer_send(Curl_send_buffer *in, @@ -64,18 +72,14 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, CURLcode Curl_add_timecondition(struct SessionHandle *data, Curl_send_buffer *buf); CURLcode Curl_add_custom_headers(struct connectdata *conn, - Curl_send_buffer *req_buffer); - - -/* ftp can use this as well */ -CURLcode Curl_proxyCONNECT(struct connectdata *conn, - int tunnelsocket, - const char *hostname, unsigned short remote_port); + bool is_connect, + Curl_send_buffer *req_buffer); /* protocol-specific functions set up to be called by the main engine */ CURLcode Curl_http(struct connectdata *conn, bool *done); CURLcode Curl_http_done(struct connectdata *, CURLcode, bool premature); CURLcode Curl_http_connect(struct connectdata *conn, bool *done); +CURLcode Curl_http_setup_conn(struct connectdata *conn); /* The following functions are defined in http_chunks.c */ void Curl_httpchunk_init(struct connectdata *conn); @@ -84,13 +88,11 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap, /* These functions are in http.c */ void Curl_http_auth_stage(struct SessionHandle *data, int stage); -CURLcode Curl_http_input_auth(struct connectdata *conn, - int httpcode, const char *header); +CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, + const char *auth); CURLcode Curl_http_auth_act(struct connectdata *conn); CURLcode Curl_http_perhapsrewind(struct connectdata *conn); -int Curl_http_should_fail(struct connectdata *conn); - /* If only the PICKNONE bit is set, there has been a round-trip and we selected to use no auth at all. Ie, we actively select no auth, as opposed to not having one selected. The other CURLAUTH_* defines are present in the @@ -151,6 +153,73 @@ struct HTTP { void *send_buffer; /* used if the request couldn't be sent in one chunk, points to an allocated send_buffer struct */ + +#ifdef USE_NGHTTP2 + /*********** for HTTP/2 we store stream-local data here *************/ + int32_t stream_id; /* stream we are interested in */ + + bool bodystarted; + /* We store non-final and final response headers here, per-stream */ + Curl_send_buffer *header_recvbuf; + size_t nread_header_recvbuf; /* number of bytes in header_recvbuf fed into + upper layer */ + Curl_send_buffer *trailer_recvbuf; + int status_code; /* HTTP status code */ + const uint8_t *pausedata; /* pointer to data received in on_data_chunk */ + size_t pauselen; /* the number of bytes left in data */ + bool closed; /* TRUE on HTTP2 stream close */ + uint32_t error_code; /* HTTP/2 error code */ + + char *mem; /* points to a buffer in memory to store received data */ + size_t len; /* size of the buffer 'mem' points to */ + size_t memlen; /* size of data copied to mem */ + + const uint8_t *upload_mem; /* points to a buffer to read from */ + size_t upload_len; /* size of the buffer 'upload_mem' points to */ + curl_off_t upload_left; /* number of bytes left to upload */ + + char **push_headers; /* allocated array */ + size_t push_headers_used; /* number of entries filled in */ + size_t push_headers_alloc; /* number of entries allocated */ +#endif +}; + +typedef int (*sending)(void); /* Curl_send */ +typedef int (*recving)(void); /* Curl_recv */ + +#ifdef USE_NGHTTP2 +/* h2 settings for this connection */ +struct h2settings { + uint32_t max_concurrent_streams; + bool enable_push; +}; +#endif + + +struct http_conn { +#ifdef USE_NGHTTP2 +#define H2_BINSETTINGS_LEN 80 + nghttp2_session *h2; + uint8_t binsettings[H2_BINSETTINGS_LEN]; + size_t binlen; /* length of the binsettings data */ + sending send_underlying; /* underlying send Curl_send callback */ + recving recv_underlying; /* underlying recv Curl_recv callback */ + char *inbuf; /* buffer to receive data from underlying socket */ + size_t inbuflen; /* number of bytes filled in inbuf */ + size_t nread_inbuf; /* number of bytes read from in inbuf */ + /* We need separate buffer for transmission and reception because we + may call nghttp2_session_send() after the + nghttp2_session_mem_recv() but mem buffer is still not full. In + this case, we wrongly sends the content of mem buffer if we share + them for both cases. */ + int32_t pause_stream_id; /* stream ID which paused + nghttp2_session_mem_recv */ + + /* this is a hash of all individual streams (SessionHandle structs) */ + struct h2settings settings; +#else + int unused; /* prevent a compiler warning */ +#endif }; CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, @@ -158,4 +227,26 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, ssize_t *nread, bool *stop_reading); -#endif +/** + * Curl_http_output_auth() setups the authentication headers for the + * host/proxy and the correct authentication + * method. conn->data->state.authdone is set to TRUE when authentication is + * done. + * + * @param conn all information about the current connection + * @param request pointer to the request keyword + * @param path pointer to the requested path + * @param proxytunnel boolean if this is the request setting up a "proxy + * tunnel" + * + * @returns CURLcode + */ +CURLcode +Curl_http_output_auth(struct connectdata *conn, + const char *request, + const char *path, + bool proxytunnel); /* TRUE if this is the request setting + up the proxy tunnel */ + +#endif /* HEADER_CURL_HTTP_H */ + diff --git a/project/jni/curl/lib/http2.c b/project/jni/curl/lib/http2.c new file mode 100644 index 000000000..91abbf04e --- /dev/null +++ b/project/jni/curl/lib/http2.c @@ -0,0 +1,1709 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_NGHTTP2 +#include "curl_printf.h" +#include +#include "urldata.h" +#include "http2.h" +#include "http.h" +#include "sendf.h" +#include "curl_base64.h" +#include "rawstr.h" +#include "multiif.h" +#include "conncache.h" +#include "url.h" +#include "connect.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#define MIN(x,y) ((x)<(y)?(x):(y)) + +#if (NGHTTP2_VERSION_NUM < 0x010000) +#error too old nghttp2 version, upgrade! +#endif + +/* + * Curl_http2_init_state() is called when the easy handle is created and + * allows for HTTP/2 specific init of state. + */ +void Curl_http2_init_state(struct UrlState *state) +{ + state->stream_weight = NGHTTP2_DEFAULT_WEIGHT; +} + +/* + * Curl_http2_init_userset() is called when the easy handle is created and + * allows for HTTP/2 specific user-set fields. + */ +void Curl_http2_init_userset(struct UserDefined *set) +{ + set->stream_weight = NGHTTP2_DEFAULT_WEIGHT; +} + +static int http2_perform_getsock(const struct connectdata *conn, + curl_socket_t *sock, /* points to + numsocks + number of + sockets */ + int numsocks) +{ + const struct http_conn *c = &conn->proto.httpc; + int bitmap = GETSOCK_BLANK; + (void)numsocks; + + /* TODO We should check underlying socket state if it is SSL socket + because of renegotiation. */ + sock[0] = conn->sock[FIRSTSOCKET]; + + if(nghttp2_session_want_read(c->h2)) + bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); + + if(nghttp2_session_want_write(c->h2)) + bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); + + return bitmap; +} + +static int http2_getsock(struct connectdata *conn, + curl_socket_t *sock, /* points to numsocks + number of sockets */ + int numsocks) +{ + return http2_perform_getsock(conn, sock, numsocks); +} + +static CURLcode http2_disconnect(struct connectdata *conn, + bool dead_connection) +{ + struct HTTP *http = conn->data->req.protop; + struct http_conn *c = &conn->proto.httpc; + (void)dead_connection; + + DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n")); + + nghttp2_session_del(c->h2); + Curl_safefree(c->inbuf); + + if(http) { + Curl_add_buffer_free(http->header_recvbuf); + http->header_recvbuf = NULL; /* clear the pointer */ + Curl_add_buffer_free(http->trailer_recvbuf); + http->trailer_recvbuf = NULL; /* clear the pointer */ + for(; http->push_headers_used > 0; --http->push_headers_used) { + free(http->push_headers[http->push_headers_used - 1]); + } + free(http->push_headers); + http->push_headers = NULL; + } + + DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n")); + + return CURLE_OK; +} + +/* called from Curl_http_setup_conn */ +void Curl_http2_setup_req(struct SessionHandle *data) +{ + struct HTTP *http = data->req.protop; + + http->nread_header_recvbuf = 0; + http->bodystarted = FALSE; + http->status_code = -1; + http->pausedata = NULL; + http->pauselen = 0; + http->error_code = NGHTTP2_NO_ERROR; + http->closed = FALSE; + http->mem = data->state.buffer; + http->len = BUFSIZE; + http->memlen = 0; +} + +/* called from Curl_http_setup_conn */ +void Curl_http2_setup_conn(struct connectdata *conn) +{ + conn->proto.httpc.settings.max_concurrent_streams = + DEFAULT_MAX_CONCURRENT_STREAMS; +} + +/* + * HTTP2 handler interface. This isn't added to the general list of protocols + * but will be used at run-time when the protocol is dynamically switched from + * HTTP to HTTP2. + */ +const struct Curl_handler Curl_handler_http2 = { + "HTTP2", /* scheme */ + ZERO_NULL, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + ZERO_NULL, /* do_more */ + ZERO_NULL, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + http2_getsock, /* proto_getsock */ + http2_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + http2_perform_getsock, /* perform_getsock */ + http2_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ + PORT_HTTP, /* defport */ + CURLPROTO_HTTP, /* protocol */ + PROTOPT_NONE /* flags */ +}; + +const struct Curl_handler Curl_handler_http2_ssl = { + "HTTP2", /* scheme */ + ZERO_NULL, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + ZERO_NULL, /* do_more */ + ZERO_NULL, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + http2_getsock, /* proto_getsock */ + http2_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + http2_perform_getsock, /* perform_getsock */ + http2_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ + PORT_HTTP, /* defport */ + CURLPROTO_HTTPS, /* protocol */ + PROTOPT_SSL /* flags */ +}; + +/* + * Store nghttp2 version info in this buffer, Prefix with a space. Return + * total length written. + */ +int Curl_http2_ver(char *p, size_t len) +{ + nghttp2_info *h2 = nghttp2_version(0); + return snprintf(p, len, " nghttp2/%s", h2->version_str); +} + +/* + * The implementation of nghttp2_send_callback type. Here we write |data| with + * size |length| to the network and return the number of bytes actually + * written. See the documentation of nghttp2_send_callback for the details. + */ +static ssize_t send_callback(nghttp2_session *h2, + const uint8_t *data, size_t length, int flags, + void *userp) +{ + struct connectdata *conn = (struct connectdata *)userp; + struct http_conn *c = &conn->proto.httpc; + ssize_t written; + CURLcode result = CURLE_OK; + + (void)h2; + (void)flags; + + written = ((Curl_send*)c->send_underlying)(conn, FIRSTSOCKET, + data, length, &result); + + if(result == CURLE_AGAIN) { + return NGHTTP2_ERR_WOULDBLOCK; + } + + if(written == -1) { + failf(conn->data, "Failed sending HTTP2 data"); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + + if(!written) + return NGHTTP2_ERR_WOULDBLOCK; + + return written; +} + + +/* We pass a pointer to this struct in the push callback, but the contents of + the struct are hidden from the user. */ +struct curl_pushheaders { + struct SessionHandle *data; + const nghttp2_push_promise *frame; +}; + +/* + * push header access function. Only to be used from within the push callback + */ +char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) +{ + /* Verify that we got a good easy handle in the push header struct, mostly to + detect rubbish input fast(er). */ + if(!h || !GOOD_EASY_HANDLE(h->data)) + return NULL; + else { + struct HTTP *stream = h->data->req.protop; + if(num < stream->push_headers_used) + return stream->push_headers[num]; + } + return NULL; +} + +/* + * push header access function. Only to be used from within the push callback + */ +char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) +{ + /* Verify that we got a good easy handle in the push header struct, + mostly to detect rubbish input fast(er). Also empty header name + is just a rubbish too. We have to allow ":" at the beginning of + the header, but header == ":" must be rejected. If we have ':' in + the middle of header, it could be matched in middle of the value, + this is because we do prefix match.*/ + if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] || + Curl_raw_equal(header, ":") || strchr(header + 1, ':')) + return NULL; + else { + struct HTTP *stream = h->data->req.protop; + size_t len = strlen(header); + size_t i; + for(i=0; ipush_headers_used; i++) { + if(!strncmp(header, stream->push_headers[i], len)) { + /* sub-match, make sure that it is followed by a colon */ + if(stream->push_headers[i][len] != ':') + continue; + return &stream->push_headers[i][len+1]; + } + } + } + return NULL; +} + +static CURL *duphandle(struct SessionHandle *data) +{ + struct SessionHandle *second = curl_easy_duphandle(data); + if(second) { + /* setup the request struct */ + struct HTTP *http = calloc(1, sizeof(struct HTTP)); + if(!http) { + (void)Curl_close(second); + second = NULL; + } + else { + second->req.protop = http; + http->header_recvbuf = Curl_add_buffer_init(); + if(!http->header_recvbuf) { + free(http); + (void)Curl_close(second); + second = NULL; + } + else { + Curl_http2_setup_req(second); + second->state.stream_weight = data->state.stream_weight; + } + } + } + return second; +} + + +static int push_promise(struct SessionHandle *data, + struct connectdata *conn, + const nghttp2_push_promise *frame) +{ + int rv; + DEBUGF(infof(data, "PUSH_PROMISE received, stream %u!\n", + frame->promised_stream_id)); + if(data->multi->push_cb) { + struct HTTP *stream; + struct HTTP *newstream; + struct curl_pushheaders heads; + CURLMcode rc; + struct http_conn *httpc; + size_t i; + /* clone the parent */ + struct SessionHandle *newhandle = duphandle(data); + if(!newhandle) { + infof(data, "failed to duplicate handle\n"); + rv = 1; /* FAIL HARD */ + goto fail; + } + + heads.data = data; + heads.frame = frame; + /* ask the application */ + DEBUGF(infof(data, "Got PUSH_PROMISE, ask application!\n")); + + stream = data->req.protop; + if(!stream) { + failf(data, "Internal NULL stream!\n"); + rv = 1; + goto fail; + } + + rv = data->multi->push_cb(data, newhandle, + stream->push_headers_used, &heads, + data->multi->push_userp); + + /* free the headers again */ + for(i=0; ipush_headers_used; i++) + free(stream->push_headers[i]); + free(stream->push_headers); + stream->push_headers = NULL; + + if(rv) { + /* denied, kill off the new handle again */ + (void)Curl_close(newhandle); + goto fail; + } + + newstream = newhandle->req.protop; + newstream->stream_id = frame->promised_stream_id; + newhandle->req.maxdownload = -1; + newhandle->req.size = -1; + + /* approved, add to the multi handle and immediately switch to PERFORM + state with the given connection !*/ + rc = Curl_multi_add_perform(data->multi, newhandle, conn); + if(rc) { + infof(data, "failed to add handle to multi\n"); + Curl_close(newhandle); + rv = 1; + goto fail; + } + + httpc = &conn->proto.httpc; + nghttp2_session_set_stream_user_data(httpc->h2, + frame->promised_stream_id, newhandle); + } + else { + DEBUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n")); + rv = 1; + } + fail: + return rv; +} + +static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, + void *userp) +{ + struct connectdata *conn = (struct connectdata *)userp; + struct http_conn *httpc = &conn->proto.httpc; + struct SessionHandle *data_s = NULL; + struct HTTP *stream = NULL; + static int lastStream = -1; + int rv; + size_t left, ncopy; + int32_t stream_id = frame->hd.stream_id; + + if(!stream_id) { + /* stream ID zero is for connection-oriented stuff */ + if(frame->hd.type == NGHTTP2_SETTINGS) { + uint32_t max_conn = httpc->settings.max_concurrent_streams; + DEBUGF(infof(conn->data, "Got SETTINGS\n")); + httpc->settings.max_concurrent_streams = + nghttp2_session_get_remote_settings( + session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS); + httpc->settings.enable_push = + nghttp2_session_get_remote_settings( + session, NGHTTP2_SETTINGS_ENABLE_PUSH); + DEBUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n", + httpc->settings.max_concurrent_streams)); + DEBUGF(infof(conn->data, "ENABLE_PUSH == %s\n", + httpc->settings.enable_push?"TRUE":"false")); + if(max_conn != httpc->settings.max_concurrent_streams) { + /* only signal change if the value actually changed */ + infof(conn->data, + "Connection state changed (MAX_CONCURRENT_STREAMS updated)!\n"); + Curl_multi_connchanged(conn->data->multi); + } + } + return 0; + } + data_s = nghttp2_session_get_stream_user_data(session, stream_id); + if(lastStream != stream_id) { + lastStream = stream_id; + } + if(!data_s) { + DEBUGF(infof(conn->data, + "No SessionHandle associated with stream: %x\n", + stream_id)); + return 0; + } + + stream = data_s->req.protop; + if(!stream) + return NGHTTP2_ERR_CALLBACK_FAILURE; + + DEBUGF(infof(data_s, "on_frame_recv() header %x stream %x\n", + frame->hd.type, stream_id)); + + switch(frame->hd.type) { + case NGHTTP2_DATA: + /* If body started on this stream, then receiving DATA is illegal. */ + if(!stream->bodystarted) { + rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, + stream_id, NGHTTP2_PROTOCOL_ERROR); + + if(nghttp2_is_fatal(rv)) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + break; + case NGHTTP2_HEADERS: + if(stream->bodystarted) { + /* Only valid HEADERS after body started is trailer HEADERS. We + buffer them in on_header callback. */ + break; + } + + /* nghttp2 guarantees that :status is received, and we store it to + stream->status_code */ + DEBUGASSERT(stream->status_code != -1); + + /* Only final status code signals the end of header */ + if(stream->status_code / 100 != 1) { + stream->bodystarted = TRUE; + stream->status_code = -1; + } + + Curl_add_buffer(stream->header_recvbuf, "\r\n", 2); + + left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf; + ncopy = MIN(stream->len, left); + + memcpy(&stream->mem[stream->memlen], + stream->header_recvbuf->buffer + stream->nread_header_recvbuf, + ncopy); + stream->nread_header_recvbuf += ncopy; + + DEBUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n", + ncopy, stream_id, stream->mem)); + + stream->len -= ncopy; + stream->memlen += ncopy; + + data_s->state.drain++; + { + /* get the pointer from userp again since it was re-assigned above */ + struct connectdata *conn_s = (struct connectdata *)userp; + + /* if we receive data for another handle, wake that up */ + if(conn_s->data != data_s) + Curl_expire(data_s, 1); + } + break; + case NGHTTP2_PUSH_PROMISE: + rv = push_promise(data_s, conn, &frame->push_promise); + if(rv) { /* deny! */ + rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, + frame->push_promise.promised_stream_id, + NGHTTP2_CANCEL); + if(nghttp2_is_fatal(rv)) { + return rv; + } + } + break; + default: + DEBUGF(infof(conn->data, "Got frame type %x for stream %u!\n", + frame->hd.type, stream_id)); + break; + } + return 0; +} + +static int on_invalid_frame_recv(nghttp2_session *session, + const nghttp2_frame *frame, + int lib_error_code, void *userp) +{ + struct SessionHandle *data_s = NULL; + (void)userp; + + data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); + if(data_s) { + DEBUGF(infof(data_s, + "on_invalid_frame_recv() was called, error=%d:%s\n", + lib_error_code, nghttp2_strerror(lib_error_code))); + } + return 0; +} + +static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, + int32_t stream_id, + const uint8_t *data, size_t len, void *userp) +{ + struct HTTP *stream; + struct SessionHandle *data_s; + size_t nread; + struct connectdata *conn = (struct connectdata *)userp; + (void)session; + (void)flags; + (void)data; + + DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ + + /* get the stream from the hash based on Stream ID */ + data_s = nghttp2_session_get_stream_user_data(session, stream_id); + if(!data_s) + /* Receiving a Stream ID not in the hash should not happen, this is an + internal error more than anything else! */ + return NGHTTP2_ERR_CALLBACK_FAILURE; + + stream = data_s->req.protop; + if(!stream) + return NGHTTP2_ERR_CALLBACK_FAILURE; + + nread = MIN(stream->len, len); + memcpy(&stream->mem[stream->memlen], data, nread); + + stream->len -= nread; + stream->memlen += nread; + + data_s->state.drain++; + + /* if we receive data for another handle, wake that up */ + if(conn->data != data_s) + Curl_expire(data_s, 1); /* TODO: fix so that this can be set to 0 for + immediately? */ + + DEBUGF(infof(data_s, "%zu data received for stream %u " + "(%zu left in buffer %p, total %zu)\n", + nread, stream_id, + stream->len, stream->mem, + stream->memlen)); + + if(nread < len) { + stream->pausedata = data + nread; + stream->pauselen = len - nread; + DEBUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer" + ", stream %u\n", + len - nread, stream_id)); + data_s->easy_conn->proto.httpc.pause_stream_id = stream_id; + return NGHTTP2_ERR_PAUSE; + } + return 0; +} + +static int before_frame_send(nghttp2_session *session, + const nghttp2_frame *frame, + void *userp) +{ + struct SessionHandle *data_s; + (void)userp; + + data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); + if(data_s) { + DEBUGF(infof(data_s, "before_frame_send() was called\n")); + } + + return 0; +} +static int on_frame_send(nghttp2_session *session, + const nghttp2_frame *frame, + void *userp) +{ + struct SessionHandle *data_s; + (void)userp; + + data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); + if(data_s) { + DEBUGF(infof(data_s, "on_frame_send() was called, length = %zd\n", + frame->hd.length)); + } + return 0; +} +static int on_frame_not_send(nghttp2_session *session, + const nghttp2_frame *frame, + int lib_error_code, void *userp) +{ + struct SessionHandle *data_s; + (void)userp; + + data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); + if(data_s) { + DEBUGF(infof(data_s, + "on_frame_not_send() was called, lib_error_code = %d\n", + lib_error_code)); + } + return 0; +} +static int on_stream_close(nghttp2_session *session, int32_t stream_id, + uint32_t error_code, void *userp) +{ + struct SessionHandle *data_s; + struct HTTP *stream; + (void)session; + (void)stream_id; + (void)userp; + + if(stream_id) { + /* get the stream from the hash based on Stream ID, stream ID zero is for + connection-oriented stuff */ + data_s = nghttp2_session_get_stream_user_data(session, stream_id); + if(!data_s) { + /* We could get stream ID not in the hash. For example, if we + decided to reject stream (e.g., PUSH_PROMISE). */ + return 0; + } + DEBUGF(infof(data_s, "on_stream_close(), error_code = %d, stream %u\n", + error_code, stream_id)); + stream = data_s->req.protop; + if(!stream) + return NGHTTP2_ERR_CALLBACK_FAILURE; + + stream->error_code = error_code; + stream->closed = TRUE; + + /* remove the entry from the hash as the stream is now gone */ + nghttp2_session_set_stream_user_data(session, stream_id, 0); + DEBUGF(infof(data_s, "Removed stream %u hash!\n", stream_id)); + } + return 0; +} + +static int on_begin_headers(nghttp2_session *session, + const nghttp2_frame *frame, void *userp) +{ + struct HTTP *stream; + struct SessionHandle *data_s = NULL; + (void)userp; + + data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); + if(!data_s) { + return 0; + } + + DEBUGF(infof(data_s, "on_begin_headers() was called\n")); + + if(frame->hd.type != NGHTTP2_HEADERS) { + return 0; + } + + stream = data_s->req.protop; + if(!stream || !stream->bodystarted) { + return 0; + } + + /* This is trailer HEADERS started. Allocate buffer for them. */ + DEBUGF(infof(data_s, "trailer field started\n")); + + assert(stream->trailer_recvbuf == NULL); + + stream->trailer_recvbuf = Curl_add_buffer_init(); + if(!stream->trailer_recvbuf) { + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; + } + + return 0; +} + +/* Decode HTTP status code. Returns -1 if no valid status code was + decoded. */ +static int decode_status_code(const uint8_t *value, size_t len) +{ + int i; + int res; + + if(len != 3) { + return -1; + } + + res = 0; + + for(i = 0; i < 3; ++i) { + char c = value[i]; + + if(c < '0' || c > '9') { + return -1; + } + + res *= 10; + res += c - '0'; + } + + return res; +} + +/* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */ +static int on_header(nghttp2_session *session, const nghttp2_frame *frame, + const uint8_t *name, size_t namelen, + const uint8_t *value, size_t valuelen, + uint8_t flags, + void *userp) +{ + struct HTTP *stream; + struct SessionHandle *data_s; + int32_t stream_id = frame->hd.stream_id; + struct connectdata *conn = (struct connectdata *)userp; + (void)flags; + + DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ + + /* get the stream from the hash based on Stream ID */ + data_s = nghttp2_session_get_stream_user_data(session, stream_id); + if(!data_s) + /* Receiving a Stream ID not in the hash should not happen, this is an + internal error more than anything else! */ + return NGHTTP2_ERR_CALLBACK_FAILURE; + + stream = data_s->req.protop; + if(!stream) { + failf(data_s, "Internal NULL stream! 5\n"); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + + /* Store received PUSH_PROMISE headers to be used when the subsequent + PUSH_PROMISE callback comes */ + if(frame->hd.type == NGHTTP2_PUSH_PROMISE) { + char *h; + + if(!stream->push_headers) { + stream->push_headers_alloc = 10; + stream->push_headers = malloc(stream->push_headers_alloc * + sizeof(char *)); + stream->push_headers_used = 0; + } + else if(stream->push_headers_used == + stream->push_headers_alloc) { + char **headp; + stream->push_headers_alloc *= 2; + headp = realloc(stream->push_headers, + stream->push_headers_alloc * sizeof(char *)); + if(!headp) { + free(stream->push_headers); + stream->push_headers = NULL; + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; + } + stream->push_headers = headp; + } + h = aprintf("%s:%s", name, value); + if(h) + stream->push_headers[stream->push_headers_used++] = h; + return 0; + } + + if(stream->bodystarted) { + /* This is trailer fields. */ + /* 3 is for ":" and "\r\n". */ + uint32_t n = (uint32_t)(namelen + valuelen + 3); + + DEBUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen, + value)); + + Curl_add_buffer(stream->trailer_recvbuf, &n, sizeof(n)); + Curl_add_buffer(stream->trailer_recvbuf, name, namelen); + Curl_add_buffer(stream->trailer_recvbuf, ":", 1); + Curl_add_buffer(stream->trailer_recvbuf, value, valuelen); + Curl_add_buffer(stream->trailer_recvbuf, "\r\n\0", 3); + + return 0; + } + + if(namelen == sizeof(":status") - 1 && + memcmp(":status", name, namelen) == 0) { + /* nghttp2 guarantees :status is received first and only once, and + value is 3 digits status code, and decode_status_code always + succeeds. */ + stream->status_code = decode_status_code(value, valuelen); + DEBUGASSERT(stream->status_code != -1); + + Curl_add_buffer(stream->header_recvbuf, "HTTP/2.0 ", 9); + Curl_add_buffer(stream->header_recvbuf, value, valuelen); + Curl_add_buffer(stream->header_recvbuf, "\r\n", 2); + data_s->state.drain++; + /* if we receive data for another handle, wake that up */ + if(conn->data != data_s) + Curl_expire(data_s, 1); + + DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n", + stream->status_code, data_s)); + return 0; + } + + /* nghttp2 guarantees that namelen > 0, and :status was already + received, and this is not pseudo-header field . */ + /* convert to a HTTP1-style header */ + Curl_add_buffer(stream->header_recvbuf, name, namelen); + Curl_add_buffer(stream->header_recvbuf, ":", 1); + Curl_add_buffer(stream->header_recvbuf, value, valuelen); + Curl_add_buffer(stream->header_recvbuf, "\r\n", 2); + data_s->state.drain++; + /* if we receive data for another handle, wake that up */ + if(conn->data != data_s) + Curl_expire(data_s, 1); + + DEBUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen, + value)); + + return 0; /* 0 is successful */ +} + +static ssize_t data_source_read_callback(nghttp2_session *session, + int32_t stream_id, + uint8_t *buf, size_t length, + uint32_t *data_flags, + nghttp2_data_source *source, + void *userp) +{ + struct SessionHandle *data_s; + struct HTTP *stream = NULL; + size_t nread; + (void)source; + (void)userp; + + if(stream_id) { + /* get the stream from the hash based on Stream ID, stream ID zero is for + connection-oriented stuff */ + data_s = nghttp2_session_get_stream_user_data(session, stream_id); + if(!data_s) + /* Receiving a Stream ID not in the hash should not happen, this is an + internal error more than anything else! */ + return NGHTTP2_ERR_CALLBACK_FAILURE; + + stream = data_s->req.protop; + if(!stream) + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + else + return NGHTTP2_ERR_INVALID_ARGUMENT; + + nread = MIN(stream->upload_len, length); + if(nread > 0) { + memcpy(buf, stream->upload_mem, nread); + stream->upload_mem += nread; + stream->upload_len -= nread; + stream->upload_left -= nread; + } + + if(stream->upload_left == 0) + *data_flags = 1; + else if(nread == 0) + return NGHTTP2_ERR_DEFERRED; + + DEBUGF(infof(data_s, "data_source_read_callback: " + "returns %zu bytes stream %u\n", + nread, stream_id)); + + return nread; +} + +/* + * The HTTP2 settings we send in the Upgrade request + */ +static nghttp2_settings_entry settings[] = { + { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 }, + { NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, NGHTTP2_INITIAL_WINDOW_SIZE }, +}; + +#define H2_BUFSIZE 32768 + +/* + * Initialize nghttp2 for a Curl connection + */ +CURLcode Curl_http2_init(struct connectdata *conn) +{ + if(!conn->proto.httpc.h2) { + int rc; + nghttp2_session_callbacks *callbacks; + + conn->proto.httpc.inbuf = malloc(H2_BUFSIZE); + if(conn->proto.httpc.inbuf == NULL) + return CURLE_OUT_OF_MEMORY; + + rc = nghttp2_session_callbacks_new(&callbacks); + + if(rc) { + failf(conn->data, "Couldn't initialize nghttp2 callbacks!"); + return CURLE_OUT_OF_MEMORY; /* most likely at least */ + } + + /* nghttp2_send_callback */ + nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); + /* nghttp2_on_frame_recv_callback */ + nghttp2_session_callbacks_set_on_frame_recv_callback + (callbacks, on_frame_recv); + /* nghttp2_on_invalid_frame_recv_callback */ + nghttp2_session_callbacks_set_on_invalid_frame_recv_callback + (callbacks, on_invalid_frame_recv); + /* nghttp2_on_data_chunk_recv_callback */ + nghttp2_session_callbacks_set_on_data_chunk_recv_callback + (callbacks, on_data_chunk_recv); + /* nghttp2_before_frame_send_callback */ + nghttp2_session_callbacks_set_before_frame_send_callback + (callbacks, before_frame_send); + /* nghttp2_on_frame_send_callback */ + nghttp2_session_callbacks_set_on_frame_send_callback + (callbacks, on_frame_send); + /* nghttp2_on_frame_not_send_callback */ + nghttp2_session_callbacks_set_on_frame_not_send_callback + (callbacks, on_frame_not_send); + /* nghttp2_on_stream_close_callback */ + nghttp2_session_callbacks_set_on_stream_close_callback + (callbacks, on_stream_close); + /* nghttp2_on_begin_headers_callback */ + nghttp2_session_callbacks_set_on_begin_headers_callback + (callbacks, on_begin_headers); + /* nghttp2_on_header_callback */ + nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header); + + /* The nghttp2 session is not yet setup, do it */ + rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn); + + nghttp2_session_callbacks_del(callbacks); + + if(rc) { + failf(conn->data, "Couldn't initialize nghttp2!"); + return CURLE_OUT_OF_MEMORY; /* most likely at least */ + } + } + return CURLE_OK; +} + +/* + * Append headers to ask for a HTTP1.1 to HTTP2 upgrade. + */ +CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, + struct connectdata *conn) +{ + CURLcode result; + ssize_t binlen; + char *base64; + size_t blen; + struct SingleRequest *k = &conn->data->req; + uint8_t *binsettings = conn->proto.httpc.binsettings; + + /* As long as we have a fixed set of settings, we don't have to dynamically + * figure out the base64 strings since it'll always be the same. However, + * the settings will likely not be fixed every time in the future. + */ + + /* this returns number of bytes it wrote */ + binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN, + settings, + sizeof(settings)/sizeof(settings[0])); + if(!binlen) { + failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload"); + return CURLE_FAILED_INIT; + } + conn->proto.httpc.binlen = binlen; + + result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen, + &base64, &blen); + if(result) + return result; + + result = Curl_add_bufferf(req, + "Connection: Upgrade, HTTP2-Settings\r\n" + "Upgrade: %s\r\n" + "HTTP2-Settings: %s\r\n", + NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64); + free(base64); + + k->upgr101 = UPGR101_REQUESTED; + + return result; +} + +static ssize_t http2_handle_stream_close(struct connectdata *conn, + struct SessionHandle *data, + struct HTTP *stream, CURLcode *err) { + char *trailer_pos, *trailer_end; + CURLcode result; + struct http_conn *httpc = &conn->proto.httpc; + + if(httpc->pause_stream_id == stream->stream_id) { + httpc->pause_stream_id = 0; + } + /* Reset to FALSE to prevent infinite loop in readwrite_data + function. */ + stream->closed = FALSE; + if(stream->error_code != NGHTTP2_NO_ERROR) { + failf(data, "HTTP/2 stream %u was not closed cleanly: error_code = %d", + stream->stream_id, stream->error_code); + *err = CURLE_HTTP2; + return -1; + } + + if(stream->trailer_recvbuf && stream->trailer_recvbuf->buffer) { + trailer_pos = stream->trailer_recvbuf->buffer; + trailer_end = trailer_pos + stream->trailer_recvbuf->size_used; + + for(; trailer_pos < trailer_end;) { + uint32_t n; + memcpy(&n, trailer_pos, sizeof(n)); + trailer_pos += sizeof(n); + + result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailer_pos, n); + if(result) { + *err = result; + return -1; + } + + trailer_pos += n + 1; + } + } + + DEBUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n")); + return 0; +} + +/* + * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight + * and dependency to the peer. It also stores the updated values in the state + * struct. + */ + +static void h2_pri_spec(struct SessionHandle *data, + nghttp2_priority_spec *pri_spec) +{ + struct HTTP *depstream = (data->set.stream_depends_on? + data->set.stream_depends_on->req.protop:NULL); + int32_t depstream_id = depstream? depstream->stream_id:0; + nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight, + data->set.stream_depends_e); + data->state.stream_weight = data->set.stream_weight; + data->state.stream_depends_e = data->set.stream_depends_e; + data->state.stream_depends_on = data->set.stream_depends_on; +} + +/* + * h2_session_send() checks if there's been an update in the priority / + * dependency settings and if so it submits a PRIORITY frame with the updated + * info. + */ +static int h2_session_send(struct SessionHandle *data, + nghttp2_session *h2) +{ + struct HTTP *stream = data->req.protop; + if((data->set.stream_weight != data->state.stream_weight) || + (data->set.stream_depends_e != data->state.stream_depends_e) || + (data->set.stream_depends_on != data->state.stream_depends_on) ) { + /* send new weight and/or dependency */ + nghttp2_priority_spec pri_spec; + int rv; + + h2_pri_spec(data, &pri_spec); + + DEBUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)\n", + stream->stream_id, data)); + rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id, + &pri_spec); + if(rv) + return rv; + } + + return nghttp2_session_send(h2); +} + +/* + * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return + * a regular CURLcode value. + */ +static ssize_t http2_recv(struct connectdata *conn, int sockindex, + char *mem, size_t len, CURLcode *err) +{ + CURLcode result = CURLE_OK; + ssize_t rv; + ssize_t nread; + struct http_conn *httpc = &conn->proto.httpc; + struct SessionHandle *data = conn->data; + struct HTTP *stream = data->req.protop; + + (void)sockindex; /* we always do HTTP2 on sockindex 0 */ + + /* If stream is closed, return 0 to signal the http routine to close + the connection. We need to handle stream closure here, + otherwise, we may be going to read from underlying connection, + and gets EAGAIN, and we will get stuck there. */ + if(stream->memlen == 0 && stream->closed) { + return http2_handle_stream_close(conn, data, stream, err); + } + + /* Nullify here because we call nghttp2_session_send() and they + might refer to the old buffer. */ + stream->upload_mem = NULL; + stream->upload_len = 0; + + /* + * At this point 'stream' is just in the SessionHandle the connection + * identifies as its owner at this time. + */ + + if(stream->bodystarted && + stream->nread_header_recvbuf < stream->header_recvbuf->size_used) { + /* If there is body data pending for this stream to return, do that */ + size_t left = + stream->header_recvbuf->size_used - stream->nread_header_recvbuf; + size_t ncopy = MIN(len, left); + memcpy(mem, stream->header_recvbuf->buffer + stream->nread_header_recvbuf, + ncopy); + stream->nread_header_recvbuf += ncopy; + + DEBUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n", + (int)ncopy)); + return ncopy; + } + + DEBUGF(infof(data, "http2_recv: easy %p (stream %u)\n", + data, stream->stream_id)); + + if((data->state.drain) && stream->memlen) { + DEBUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n", + stream->memlen, stream->stream_id, + stream->mem, mem)); + if(mem != stream->mem) { + /* if we didn't get the same buffer this time, we must move the data to + the beginning */ + memmove(mem, stream->mem, stream->memlen); + stream->len = len - stream->memlen; + stream->mem = mem; + } + } + else if(stream->pausedata) { + nread = MIN(len, stream->pauselen); + memcpy(mem, stream->pausedata, nread); + + stream->pausedata += nread; + stream->pauselen -= nread; + + infof(data, "%zu data bytes written\n", nread); + if(stream->pauselen == 0) { + DEBUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id)); + assert(httpc->pause_stream_id == stream->stream_id); + httpc->pause_stream_id = 0; + + stream->pausedata = NULL; + stream->pauselen = 0; + + /* When NGHTTP2_ERR_PAUSE is returned from + data_source_read_callback, we might not process DATA frame + fully. Calling nghttp2_session_mem_recv() again will + continue to process DATA frame, but if there is no incoming + frames, then we have to call it again with 0-length data. + Without this, on_stream_close callback will not be called, + and stream could be hanged. */ + nghttp2_session_mem_recv(httpc->h2, NULL, 0); + } + DEBUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n", + nread, stream->stream_id)); + return nread; + } + else if(httpc->pause_stream_id) { + /* If a stream paused nghttp2_session_mem_recv previously, and has + not processed all data, it still refers to the buffer in + nghttp2_session. If we call nghttp2_session_mem_recv(), we may + overwrite that buffer. To avoid that situation, just return + here with CURLE_AGAIN. This could be busy loop since data in + socket is not read. But it seems that usually streams are + notified with its drain property, and socket is read again + quickly. */ + *err = CURLE_AGAIN; + return -1; + } + else { + char *inbuf; + /* remember where to store incoming data for this stream and how big the + buffer is */ + stream->mem = mem; + stream->len = len; + stream->memlen = 0; + + if(httpc->inbuflen == 0) { + nread = ((Curl_recv *)httpc->recv_underlying)( + conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result); + + if(nread == -1) { + if(result != CURLE_AGAIN) + failf(data, "Failed receiving HTTP2 data"); + *err = result; + return -1; + } + + if(nread == 0) { + failf(data, "Unexpected EOF"); + *err = CURLE_RECV_ERROR; + return -1; + } + + DEBUGF(infof(data, "nread=%zd\n", nread)); + + httpc->inbuflen = nread; + inbuf = httpc->inbuf; + } + else { + nread = httpc->inbuflen - httpc->nread_inbuf; + inbuf = httpc->inbuf + httpc->nread_inbuf; + + DEBUGF(infof(data, "Use data left in connection buffer, nread=%zd\n", + nread)); + } + rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread); + + if(nghttp2_is_fatal((int)rv)) { + failf(data, "nghttp2_session_mem_recv() returned %d:%s\n", + rv, nghttp2_strerror((int)rv)); + *err = CURLE_RECV_ERROR; + return 0; + } + DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv)); + if(nread == rv) { + DEBUGF(infof(data, "All data in connection buffer processed\n")); + httpc->inbuflen = 0; + httpc->nread_inbuf = 0; + } + else { + httpc->nread_inbuf += rv; + DEBUGF(infof(data, "%zu bytes left in connection buffer\n", + httpc->inbuflen - httpc->nread_inbuf)); + } + /* Always send pending frames in nghttp2 session, because + nghttp2_session_mem_recv() may queue new frame */ + rv = h2_session_send(data, httpc->h2); + if(rv != 0) { + *err = CURLE_SEND_ERROR; + return 0; + } + } + if(stream->memlen) { + ssize_t retlen = stream->memlen; + DEBUGF(infof(data, "http2_recv: returns %zd for stream %u\n", + retlen, stream->stream_id)); + stream->memlen = 0; + + if(httpc->pause_stream_id == stream->stream_id) { + /* data for this stream is returned now, but this stream caused a pause + already so we need it called again asap */ + DEBUGF(infof(data, "Data returned for PAUSED stream %u\n", + stream->stream_id)); + } + else + data->state.drain = 0; /* this stream is hereby drained */ + + return retlen; + } + /* If stream is closed, return 0 to signal the http routine to close + the connection */ + if(stream->closed) { + return http2_handle_stream_close(conn, data, stream, err); + } + *err = CURLE_AGAIN; + DEBUGF(infof(data, "http2_recv returns AGAIN for stream %u\n", + stream->stream_id)); + return -1; +} + +/* Index where :authority header field will appear in request header + field list. */ +#define AUTHORITY_DST_IDX 3 + +/* return number of received (decrypted) bytes */ +static ssize_t http2_send(struct connectdata *conn, int sockindex, + const void *mem, size_t len, CURLcode *err) +{ + /* + * BIG TODO: Currently, we send request in this function, but this + * function is also used to send request body. It would be nice to + * add dedicated function for request. + */ + int rv; + struct http_conn *httpc = &conn->proto.httpc; + struct HTTP *stream = conn->data->req.protop; + nghttp2_nv *nva; + size_t nheader; + size_t i; + size_t authority_idx; + char *hdbuf = (char*)mem; + char *end; + nghttp2_data_provider data_prd; + int32_t stream_id; + nghttp2_session *h2 = httpc->h2; + nghttp2_priority_spec pri_spec; + + (void)sockindex; + + DEBUGF(infof(conn->data, "http2_send len=%zu\n", len)); + + if(stream->stream_id != -1) { + /* If stream_id != -1, we have dispatched request HEADERS, and now + are going to send or sending request body in DATA frame */ + stream->upload_mem = mem; + stream->upload_len = len; + nghttp2_session_resume_data(h2, stream->stream_id); + rv = h2_session_send(conn->data, h2); + if(nghttp2_is_fatal(rv)) { + *err = CURLE_SEND_ERROR; + return -1; + } + len -= stream->upload_len; + + /* Nullify here because we call nghttp2_session_send() and they + might refer to the old buffer. */ + stream->upload_mem = NULL; + stream->upload_len = 0; + + if(stream->upload_left) { + /* we are sure that we have more data to send here. Calling the + following API will make nghttp2_session_want_write() return + nonzero if remote window allows it, which then libcurl checks + socket is writable or not. See http2_perform_getsock(). */ + nghttp2_session_resume_data(h2, stream->stream_id); + } + + DEBUGF(infof(conn->data, "http2_send returns %zu for stream %u\n", len, + stream->stream_id)); + return len; + } + + /* Calculate number of headers contained in [mem, mem + len) */ + /* Here, we assume the curl http code generate *correct* HTTP header + field block */ + nheader = 0; + for(i = 0; i < len; ++i) { + if(hdbuf[i] == 0x0a) { + ++nheader; + } + } + /* We counted additional 2 \n in the first and last line. We need 3 + new headers: :method, :path and :scheme. Therefore we need one + more space. */ + nheader += 1; + nva = malloc(sizeof(nghttp2_nv) * nheader); + if(nva == NULL) { + *err = CURLE_OUT_OF_MEMORY; + return -1; + } + /* Extract :method, :path from request line */ + end = strchr(hdbuf, ' '); + if(!end) + goto fail; + nva[0].name = (unsigned char *)":method"; + nva[0].namelen = (uint16_t)strlen((char *)nva[0].name); + nva[0].value = (unsigned char *)hdbuf; + nva[0].valuelen = (uint16_t)(end - hdbuf); + nva[0].flags = NGHTTP2_NV_FLAG_NONE; + + hdbuf = end + 1; + + end = strchr(hdbuf, ' '); + if(!end) + goto fail; + nva[1].name = (unsigned char *)":path"; + nva[1].namelen = (uint16_t)strlen((char *)nva[1].name); + nva[1].value = (unsigned char *)hdbuf; + nva[1].valuelen = (uint16_t)(end - hdbuf); + nva[1].flags = NGHTTP2_NV_FLAG_NONE; + + nva[2].name = (unsigned char *)":scheme"; + nva[2].namelen = (uint16_t)strlen((char *)nva[2].name); + if(conn->handler->flags & PROTOPT_SSL) + nva[2].value = (unsigned char *)"https"; + else + nva[2].value = (unsigned char *)"http"; + nva[2].valuelen = (uint16_t)strlen((char *)nva[2].value); + nva[2].flags = NGHTTP2_NV_FLAG_NONE; + + hdbuf = strchr(hdbuf, 0x0a); + if(!hdbuf) + goto fail; + ++hdbuf; + + authority_idx = 0; + + i = 3; + while(i < nheader) { + size_t hlen; + int skip = 0; + end = strchr(hdbuf, ':'); + if(!end) + goto fail; + hlen = end - hdbuf; + if(hlen == 10 && Curl_raw_nequal("connection", hdbuf, 10)) { + /* skip Connection: headers! */ + skip = 1; + --nheader; + } + else if(hlen == 4 && Curl_raw_nequal("host", hdbuf, 4)) { + authority_idx = i; + nva[i].name = (unsigned char *)":authority"; + nva[i].namelen = (uint16_t)strlen((char *)nva[i].name); + } + else { + nva[i].name = (unsigned char *)hdbuf; + nva[i].namelen = (uint16_t)(end - hdbuf); + } + hdbuf = end + 1; + for(; *hdbuf == ' '; ++hdbuf); + end = strchr(hdbuf, 0x0d); + if(!end) + goto fail; + if(!skip) { + nva[i].value = (unsigned char *)hdbuf; + nva[i].valuelen = (uint16_t)(end - hdbuf); + nva[i].flags = NGHTTP2_NV_FLAG_NONE; + /* Inspect Content-Length header field and retrieve the request + entity length so that we can set END_STREAM to the last DATA + frame. */ + if(nva[i].namelen == 14 && + Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) { + size_t j; + stream->upload_left = 0; + for(j = 0; j < nva[i].valuelen; ++j) { + stream->upload_left *= 10; + stream->upload_left += nva[i].value[j] - '0'; + } + DEBUGF(infof(conn->data, + "request content-length=%" + CURL_FORMAT_CURL_OFF_T + "\n", stream->upload_left)); + } + ++i; + } + hdbuf = end + 2; + } + + /* :authority must come before non-pseudo header fields */ + if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) { + nghttp2_nv authority = nva[authority_idx]; + for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) { + nva[i] = nva[i - 1]; + } + nva[i] = authority; + } + + h2_pri_spec(conn->data, &pri_spec); + + switch(conn->data->set.httpreq) { + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + case HTTPREQ_PUT: + data_prd.read_callback = data_source_read_callback; + data_prd.source.ptr = NULL; + stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader, + &data_prd, conn->data); + break; + default: + stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader, + NULL, conn->data); + } + + Curl_safefree(nva); + + if(stream_id < 0) { + DEBUGF(infof(conn->data, "http2_send() send error\n")); + *err = CURLE_SEND_ERROR; + return -1; + } + + infof(conn->data, "Using Stream ID: %x (easy handle %p)\n", + stream_id, conn->data); + stream->stream_id = stream_id; + + /* this does not call h2_session_send() since there can not have been any + * priority upodate since the nghttp2_submit_request() call above */ + rv = nghttp2_session_send(h2); + + if(rv != 0) { + *err = CURLE_SEND_ERROR; + return -1; + } + + if(stream->stream_id != -1) { + /* If whole HEADERS frame was sent off to the underlying socket, + the nghttp2 library calls data_source_read_callback. But only + it found that no data available, so it deferred the DATA + transmission. Which means that nghttp2_session_want_write() + returns 0 on http2_perform_getsock(), which results that no + writable socket check is performed. To workaround this, we + issue nghttp2_session_resume_data() here to bring back DATA + transmission from deferred state. */ + nghttp2_session_resume_data(h2, stream->stream_id); + } + + return len; + +fail: + free(nva); + *err = CURLE_SEND_ERROR; + return -1; +} + +CURLcode Curl_http2_setup(struct connectdata *conn) +{ + CURLcode result; + struct http_conn *httpc = &conn->proto.httpc; + struct HTTP *stream = conn->data->req.protop; + + stream->stream_id = -1; + + if(!stream->header_recvbuf) + stream->header_recvbuf = Curl_add_buffer_init(); + + if((conn->handler == &Curl_handler_http2_ssl) || + (conn->handler == &Curl_handler_http2)) + return CURLE_OK; /* already done */ + + if(conn->handler->flags & PROTOPT_SSL) + conn->handler = &Curl_handler_http2_ssl; + else + conn->handler = &Curl_handler_http2; + + result = Curl_http2_init(conn); + if(result) + return result; + + infof(conn->data, "Using HTTP2, server supports multi-use\n"); + stream->upload_left = 0; + stream->upload_mem = NULL; + stream->upload_len = 0; + + httpc->inbuflen = 0; + httpc->nread_inbuf = 0; + + httpc->pause_stream_id = 0; + + conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ + conn->httpversion = 20; + conn->bundle->multiuse = BUNDLE_MULTIPLEX; + + infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n"); + Curl_multi_connchanged(conn->data->multi); + + /* switch on TCP_NODELAY as we need to send off packets without delay for + maximum throughput */ + Curl_tcpnodelay(conn, conn->sock[FIRSTSOCKET]); + + return CURLE_OK; +} + +CURLcode Curl_http2_switched(struct connectdata *conn, + const char *mem, size_t nread) +{ + CURLcode result; + struct http_conn *httpc = &conn->proto.httpc; + int rv; + ssize_t nproc; + struct SessionHandle *data = conn->data; + struct HTTP *stream = conn->data->req.protop; + + result = Curl_http2_setup(conn); + if(result) + return result; + + httpc->recv_underlying = (recving)conn->recv[FIRSTSOCKET]; + httpc->send_underlying = (sending)conn->send[FIRSTSOCKET]; + conn->recv[FIRSTSOCKET] = http2_recv; + conn->send[FIRSTSOCKET] = http2_send; + + if(conn->data->req.upgr101 == UPGR101_RECEIVED) { + /* stream 1 is opened implicitly on upgrade */ + stream->stream_id = 1; + /* queue SETTINGS frame (again) */ + rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings, + httpc->binlen, NULL); + if(rv != 0) { + failf(data, "nghttp2_session_upgrade() failed: %s(%d)", + nghttp2_strerror(rv), rv); + return CURLE_HTTP2; + } + + nghttp2_session_set_stream_user_data(httpc->h2, + stream->stream_id, + conn->data); + } + else { + /* stream ID is unknown at this point */ + stream->stream_id = -1; + rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, NULL, 0); + if(rv != 0) { + failf(data, "nghttp2_submit_settings() failed: %s(%d)", + nghttp2_strerror(rv), rv); + return CURLE_HTTP2; + } + } + + /* we are going to copy mem to httpc->inbuf. This is required since + mem is part of buffer pointed by stream->mem, and callbacks + called by nghttp2_session_mem_recv() will write stream specific + data into stream->mem, overwriting data already there. */ + if(H2_BUFSIZE < nread) { + failf(data, "connection buffer size is too small to store data following " + "HTTP Upgrade response header: buflen=%zu, datalen=%zu", + H2_BUFSIZE, nread); + return CURLE_HTTP2; + } + + infof(conn->data, "Copying HTTP/2 data in stream buffer to connection buffer" + " after upgrade: len=%zu\n", + nread); + + memcpy(httpc->inbuf, mem, nread); + httpc->inbuflen = nread; + + nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf, + httpc->inbuflen); + + if(nghttp2_is_fatal((int)nproc)) { + failf(data, "nghttp2_session_mem_recv() failed: %s(%d)", + nghttp2_strerror((int)nproc), (int)nproc); + return CURLE_HTTP2; + } + + DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc)); + + if((ssize_t)nread == nproc) { + httpc->inbuflen = 0; + httpc->nread_inbuf = 0; + } + else { + httpc->nread_inbuf += nproc; + } + + /* Try to send some frames since we may read SETTINGS already. */ + rv = h2_session_send(data, httpc->h2); + + if(rv != 0) { + failf(data, "nghttp2_session_send() failed: %s(%d)", + nghttp2_strerror(rv), rv); + return CURLE_HTTP2; + } + + return CURLE_OK; +} + +#else /* !USE_NGHTTP2 */ + +/* Satisfy external references even if http2 is not compiled in. */ + +#define CURL_DISABLE_TYPECHECK +#include + +char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) +{ + (void) h; + (void) num; + return NULL; +} + +char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) +{ + (void) h; + (void) header; + return NULL; +} + +#endif /* USE_NGHTTP2 */ diff --git a/project/jni/curl/lib/http2.h b/project/jni/curl/lib/http2.h new file mode 100644 index 000000000..2d073347e --- /dev/null +++ b/project/jni/curl/lib/http2.h @@ -0,0 +1,65 @@ +#ifndef HEADER_CURL_HTTP2_H +#define HEADER_CURL_HTTP2_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_NGHTTP2 +#include "http.h" + +/* value for MAX_CONCURRENT_STREAMS we use until we get an updated setting + from the peer */ +#define DEFAULT_MAX_CONCURRENT_STREAMS 13 + +/* + * Store nghttp2 version info in this buffer, Prefix with a space. Return + * total length written. + */ +int Curl_http2_ver(char *p, size_t len); + +CURLcode Curl_http2_init(struct connectdata *conn); +void Curl_http2_init_state(struct UrlState *state); +void Curl_http2_init_userset(struct UserDefined *set); +CURLcode Curl_http2_send_request(struct connectdata *conn); +CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, + struct connectdata *conn); +CURLcode Curl_http2_setup(struct connectdata *conn); +CURLcode Curl_http2_switched(struct connectdata *conn, + const char *data, size_t nread); +/* called from Curl_http_setup_conn */ +void Curl_http2_setup_conn(struct connectdata *conn); +void Curl_http2_setup_req(struct SessionHandle *data); +#else /* USE_NGHTTP2 */ +#define Curl_http2_init(x) CURLE_UNSUPPORTED_PROTOCOL +#define Curl_http2_send_request(x) CURLE_UNSUPPORTED_PROTOCOL +#define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL +#define Curl_http2_setup(x) CURLE_UNSUPPORTED_PROTOCOL +#define Curl_http2_switched(x,y,z) CURLE_UNSUPPORTED_PROTOCOL +#define Curl_http2_setup_conn(x) +#define Curl_http2_setup_req(x) +#define Curl_http2_init_state(x) +#define Curl_http2_init_userset(x) +#endif + +#endif /* HEADER_CURL_HTTP2_H */ + diff --git a/project/jni/curl/lib/http_chunks.c b/project/jni/curl/lib/http_chunks.c index 56d8248ff..53091738a 100644 --- a/project/jni/curl/lib/http_chunks.c +++ b/project/jni/curl/lib/http_chunks.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -19,28 +19,22 @@ * KIND, either express or implied. * ***************************************************************************/ -#include "setup.h" + +#include "curl_setup.h" #ifndef CURL_DISABLE_HTTP -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include #include "urldata.h" /* it includes http_chunks.h */ #include "sendf.h" /* for the client write stuff */ #include "content_encoding.h" #include "http.h" +#include "non-ascii.h" /* for Curl_convert_to_network prototype */ +#include "strtoofft.h" +#include "warnless.h" + +/* The last #include files should be: */ #include "curl_memory.h" -#include "easyif.h" /* for Curl_convert_to_network prototype */ - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ #include "memdebug.h" /* @@ -84,16 +78,16 @@ We avoid the use of isxdigit to accommodate non-ASCII hosts. */ static bool Curl_isxdigit(char digit) { - return (bool)( (digit >= 0x30 && digit <= 0x39) /* 0-9 */ - || (digit >= 0x41 && digit <= 0x46) /* A-F */ - || (digit >= 0x61 && digit <= 0x66) ); /* a-f */ + return ( (digit >= 0x30 && digit <= 0x39) /* 0-9 */ + || (digit >= 0x41 && digit <= 0x46) /* A-F */ + || (digit >= 0x61 && digit <= 0x66) /* a-f */ ) ? TRUE : FALSE; } void Curl_httpchunk_init(struct connectdata *conn) { struct Curl_chunker *chunk = &conn->chunk; - chunk->hexindex=0; /* start at 0 */ - chunk->dataleft=0; /* no data left yet! */ + chunk->hexindex=0; /* start at 0 */ + chunk->dataleft=0; /* no data left yet! */ chunk->state = CHUNK_HEX; /* we get hex first! */ } @@ -118,7 +112,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, struct Curl_chunker *ch = &conn->chunk; struct SingleRequest *k = &data->req; size_t piece; - size_t length = (size_t)datalen; + curl_off_t length = (curl_off_t)datalen; size_t *wrote = (size_t *)wrotep; *wrote = 0; /* nothing's written yet */ @@ -146,74 +140,62 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, } } else { - if(0 == ch->hexindex) { + char *endptr; + if(0 == ch->hexindex) /* This is illegal data, we received junk where we expected a hexadecimal digit. */ return CHUNKE_ILLEGAL_HEX; - } + /* length and datap are unmodified */ ch->hexbuffer[ch->hexindex]=0; -#ifdef CURL_DOES_CONVERSIONS + /* convert to host encoding before calling strtoul */ - result = Curl_convert_from_network(conn->data, - ch->hexbuffer, + result = Curl_convert_from_network(conn->data, ch->hexbuffer, ch->hexindex); - if(result != CURLE_OK) { + if(result) { /* Curl_convert_from_network calls failf if unsuccessful */ /* Treat it as a bad hex character */ - return(CHUNKE_ILLEGAL_HEX); + return CHUNKE_ILLEGAL_HEX; } -#endif /* CURL_DOES_CONVERSIONS */ - ch->datasize=strtoul(ch->hexbuffer, NULL, 16); - ch->state = CHUNK_POSTHEX; + + ch->datasize=curlx_strtoofft(ch->hexbuffer, &endptr, 16); + if((ch->datasize == CURL_OFF_T_MAX) && (errno == ERANGE)) + /* overflow is an error */ + return CHUNKE_ILLEGAL_HEX; + ch->state = CHUNK_LF; /* now wait for the CRLF */ } break; - case CHUNK_POSTHEX: - /* In this state, we're waiting for CRLF to arrive. We support - this to allow so called chunk-extensions to show up here - before the CRLF comes. */ - if(*datap == 0x0d) - ch->state = CHUNK_CR; - length--; - datap++; - break; - - case CHUNK_CR: - /* waiting for the LF */ + case CHUNK_LF: + /* waiting for the LF after a chunk size */ if(*datap == 0x0a) { /* we're now expecting data to come, unless size was zero! */ if(0 == ch->datasize) { ch->state = CHUNK_TRAILER; /* now check for trailers */ conn->trlPos=0; } - else { + else ch->state = CHUNK_DATA; - } } - else - /* previously we got a fake CR, go back to CR waiting! */ - ch->state = CHUNK_CR; + datap++; length--; break; case CHUNK_DATA: - /* we get pure and fine data - - We expect another 'datasize' of data. We have 'length' right now, - it can be more or less than 'datasize'. Get the smallest piece. + /* We expect 'datasize' of data. We have 'length' right now, it can be + more or less than 'datasize'. Get the smallest piece. */ - piece = (ch->datasize >= length)?length:ch->datasize; + piece = curlx_sotouz((ch->datasize >= length)?length:ch->datasize); /* Write the data portion available */ #ifdef HAVE_LIBZ switch (conn->data->set.http_ce_skip? - IDENTITY : data->req.content_encoding) { + IDENTITY : data->req.auto_decoding) { case IDENTITY: #endif if(!k->ignorebody) { - if( !data->set.http_te_skip ) + if(!data->set.http_te_skip) result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, piece); else @@ -236,7 +218,6 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, (ssize_t)piece); break; - case COMPRESS: default: failf (conn->data, "Unrecognized content encoding type. " @@ -257,37 +238,22 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, if(0 == ch->datasize) /* end of data this round, we now expect a trailing CRLF */ - ch->state = CHUNK_POSTCR; - break; - - case CHUNK_POSTCR: - if(*datap == 0x0d) { ch->state = CHUNK_POSTLF; - datap++; - length--; - } - else - return CHUNKE_BAD_CHUNK; - break; case CHUNK_POSTLF: if(*datap == 0x0a) { - /* - * The last one before we go back to hex state and start all - * over. - */ - Curl_httpchunk_init(conn); - datap++; - length--; + /* The last one before we go back to hex state and start all over. */ + Curl_httpchunk_init(conn); /* sets state back to CHUNK_HEX */ } - else + else if(*datap != 0x0d) return CHUNKE_BAD_CHUNK; - + datap++; + length--; break; case CHUNK_TRAILER: - if(*datap == 0x0d) { + if((*datap == 0x0d) || (*datap == 0x0a)) { /* this is the end of a trailer, but if the trailer was zero bytes there was no trailer and we move on */ @@ -297,17 +263,14 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, conn->trailer[conn->trlPos++]=0x0a; conn->trailer[conn->trlPos]=0; -#ifdef CURL_DOES_CONVERSIONS /* Convert to host encoding before calling Curl_client_write */ - result = Curl_convert_from_network(conn->data, - conn->trailer, + result = Curl_convert_from_network(conn->data, conn->trailer, conn->trlPos); - if(result != CURLE_OK) + if(result) /* Curl_convert_from_network calls failf if unsuccessful */ /* Treat it as a bad chunk */ return CHUNKE_BAD_CHUNK; -#endif /* CURL_DOES_CONVERSIONS */ if(!data->set.http_te_skip) { result = Curl_client_write(conn, CLIENTWRITE_HEADER, conn->trailer, conn->trlPos); @@ -316,6 +279,9 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, } conn->trlPos=0; ch->state = CHUNK_TRAILER_CR; + if(*datap == 0x0a) + /* already on the LF */ + break; } else { /* no trailer, we're on the final CRLF pair */ @@ -361,27 +327,18 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, case CHUNK_TRAILER_POSTCR: /* We enter this state when a CR should arrive so we expect to have to first pass a CR before we wait for LF */ - if(*datap != 0x0d) { + if((*datap != 0x0d) && (*datap != 0x0a)) { /* not a CR then it must be another header in the trailer */ ch->state = CHUNK_TRAILER; break; } - datap++; - length--; - /* now wait for the final LF */ - ch->state = CHUNK_STOP; - break; - - case CHUNK_STOPCR: - /* Read the final CRLF that ends all chunk bodies */ - if(*datap == 0x0d) { - ch->state = CHUNK_STOP; + /* skip if CR */ datap++; length--; } - else - return CHUNKE_BAD_CHUNK; + /* now wait for the final LF */ + ch->state = CHUNK_STOP; break; case CHUNK_STOP: @@ -390,17 +347,35 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, /* Record the length of any data left in the end of the buffer even if there's no more chunks to read */ + ch->dataleft = curlx_sotouz(length); - ch->dataleft = length; return CHUNKE_STOP; /* return stop */ } else return CHUNKE_BAD_CHUNK; - - default: - return CHUNKE_STATE_ERROR; } } return CHUNKE_OK; } + +const char *Curl_chunked_strerror(CHUNKcode code) +{ + switch (code) { + default: + return "OK"; + case CHUNKE_TOO_LONG_HEX: + return "Too long hexadecimal number"; + case CHUNKE_ILLEGAL_HEX: + return "Illegal or missing hexadecimal sequence"; + case CHUNKE_BAD_CHUNK: + return "Malformed encoding found"; + case CHUNKE_WRITE_ERROR: + return "Write error"; + case CHUNKE_BAD_ENCODING: + return "Bad content-encoding found"; + case CHUNKE_OUT_OF_MEMORY: + return "Out of memory"; + } +} + #endif /* CURL_DISABLE_HTTP */ diff --git a/project/jni/curl/lib/http_chunks.h b/project/jni/curl/lib/http_chunks.h index 6056e188c..3a8b4ddf3 100644 --- a/project/jni/curl/lib/http_chunks.h +++ b/project/jni/curl/lib/http_chunks.h @@ -1,5 +1,5 @@ -#ifndef __HTTP_CHUNKS_H -#define __HTTP_CHUNKS_H +#ifndef HEADER_CURL_HTTP_CHUNKS_H +#define HEADER_CURL_HTTP_CHUNKS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -29,40 +29,25 @@ #define MAXNUM_SIZE 16 typedef enum { - CHUNK_FIRST, /* never use */ - - /* In this we await and buffer all hexadecimal digits until we get one - that isn't a hexadecimal digit. When done, we go POSTHEX */ + /* await and buffer all hexadecimal digits until we get one that isn't a + hexadecimal digit. When done, we go CHUNK_LF */ CHUNK_HEX, - /* We have received the hexadecimal digit and we eat all characters until - we get a CRLF pair. When we see a CR we go to the CR state. */ - CHUNK_POSTHEX, - - /* A single CR has been found and we should get a LF right away in this - state or we go back to POSTHEX. When LF is received, we go to DATA. - If the size given was zero, we set state to STOP and return. */ - CHUNK_CR, + /* wait for LF, ignore all else */ + CHUNK_LF, /* We eat the amount of data specified. When done, we move on to the POST_CR state. */ CHUNK_DATA, - /* POSTCR should get a CR and nothing else, then move to POSTLF */ - CHUNK_POSTCR, - - /* POSTLF should get a LF and nothing else, then move back to HEX as the - CRLF combination marks the end of a chunk */ + /* POSTLF should get a CR and then a LF and nothing else, then move back to + HEX as the CRLF combination marks the end of a chunk. A missing CR is no + big deal. */ CHUNK_POSTLF, - /* Each Chunk body should end with a CRLF. Read a CR and nothing else, - then move to CHUNK_STOP */ - CHUNK_STOPCR, - - /* This is mainly used to really mark that we're out of the game. - NOTE: that there's a 'dataleft' field in the struct that will tell how - many bytes that were not passed to the client in the end of the last - buffer! */ + /* Used to mark that we're out of the game. NOTE: that there's a 'dataleft' + field in the struct that will tell how many bytes that were not passed to + the client in the end of the last buffer! */ CHUNK_STOP, /* At this point optional trailer headers can be found, unless the next line @@ -77,10 +62,7 @@ typedef enum { signalled If this is an empty trailer CHUNKE_STOP will be signalled. Otherwise the trailer will be broadcasted via Curl_client_write() and the next state will be CHUNK_TRAILER */ - CHUNK_TRAILER_POSTCR, - - CHUNK_LAST /* never use */ - + CHUNK_TRAILER_POSTCR } ChunkyState; typedef enum { @@ -90,18 +72,20 @@ typedef enum { CHUNKE_ILLEGAL_HEX, CHUNKE_BAD_CHUNK, CHUNKE_WRITE_ERROR, - CHUNKE_STATE_ERROR, CHUNKE_BAD_ENCODING, CHUNKE_OUT_OF_MEMORY, CHUNKE_LAST } CHUNKcode; +const char *Curl_chunked_strerror(CHUNKcode code); + struct Curl_chunker { char hexbuffer[ MAXNUM_SIZE + 1]; int hexindex; ChunkyState state; - size_t datasize; + curl_off_t datasize; size_t dataleft; /* untouched data amount at the end of the last buffer */ }; -#endif +#endif /* HEADER_CURL_HTTP_CHUNKS_H */ + diff --git a/project/jni/curl/lib/http_digest.c b/project/jni/curl/lib/http_digest.c index 45d8aeba8..dc867d52e 100644 --- a/project/jni/curl/lib/http_digest.c +++ b/project/jni/curl/lib/http_digest.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -19,104 +19,21 @@ * KIND, either express or implied. * ***************************************************************************/ -#include "setup.h" + +#include "curl_setup.h" #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include #include "urldata.h" -#include "sendf.h" #include "rawstr.h" -#include "curl_base64.h" -#include "curl_md5.h" +#include "curl_sasl.h" #include "http_digest.h" -#include "strtok.h" -#include "url.h" /* for Curl_safefree() */ +#include "curl_printf.h" + +/* The last #include files should be: */ #include "curl_memory.h" -#include "easyif.h" /* included for Curl_convert_... prototypes */ - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ #include "memdebug.h" -#define MAX_VALUE_LENGTH 256 -#define MAX_CONTENT_LENGTH 1024 - -/* - * Return 0 on success and then the buffers are filled in fine. - * - * Non-zero means failure to parse. - */ -static int get_pair(const char *str, char *value, char *content, - const char **endptr) -{ - int c; - bool starts_with_quote = FALSE; - bool escape = FALSE; - - for(c=MAX_VALUE_LENGTH-1; (*str && (*str != '=') && c--); ) - *value++ = *str++; - *value=0; - - if('=' != *str++) - /* eek, no match */ - return 1; - - if('\"' == *str) { - /* this starts with a quote so it must end with one as well! */ - str++; - starts_with_quote = TRUE; - } - - for(c=MAX_CONTENT_LENGTH-1; *str && c--; str++) { - switch(*str) { - case '\\': - if(!escape) { - /* possibly the start of an escaped quote */ - escape = TRUE; - *content++ = '\\'; /* even though this is an escape character, we still - store it as-is in the target buffer */ - continue; - } - break; - case ',': - if(!starts_with_quote) { - /* this signals the end of the content if we didn't get a starting quote - and then we do "sloppy" parsing */ - c=0; /* the end */ - continue; - } - break; - case '\r': - case '\n': - /* end of string */ - c=0; - continue; - case '\"': - if(!escape && starts_with_quote) { - /* end of string */ - c=0; - continue; - } - break; - } - escape = FALSE; - *content++ = *str; - } - *content=0; - - *endptr = str; - - return 0; /* all is fine! */ -} - /* Test example headers: WWW-Authenticate: Digest realm="testrealm", nonce="1053604598" @@ -124,149 +41,31 @@ Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598" */ -CURLdigest Curl_input_digest(struct connectdata *conn, - bool proxy, - const char *header) /* rest of the *-authenticate: - header */ +CURLcode Curl_input_digest(struct connectdata *conn, + bool proxy, + const char *header) /* rest of the *-authenticate: + header */ { - char *token = NULL; - char *tmp = NULL; - bool foundAuth = FALSE; - bool foundAuthInt = FALSE; - struct SessionHandle *data=conn->data; - bool before = FALSE; /* got a nonce before */ - struct digestdata *d; + struct SessionHandle *data = conn->data; + + /* Point to the correct struct with this */ + struct digestdata *digest; if(proxy) { - d = &data->state.proxydigest; + digest = &data->state.proxydigest; } else { - d = &data->state.digest; + digest = &data->state.digest; } - /* skip initial whitespaces */ + if(!checkprefix("Digest", header)) + return CURLE_BAD_CONTENT_ENCODING; + + header += strlen("Digest"); while(*header && ISSPACE(*header)) header++; - if(checkprefix("Digest", header)) { - header += strlen("Digest"); - - /* If we already have received a nonce, keep that in mind */ - if(d->nonce) - before = TRUE; - - /* clear off any former leftovers and init to defaults */ - Curl_digest_cleanup_one(d); - - for(;;) { - char value[MAX_VALUE_LENGTH]; - char content[MAX_CONTENT_LENGTH]; - - while(*header && ISSPACE(*header)) - header++; - - /* extract a value=content pair */ - if(!get_pair(header, value, content, &header)) { - if(Curl_raw_equal(value, "nonce")) { - d->nonce = strdup(content); - if(!d->nonce) - return CURLDIGEST_NOMEM; - } - else if(Curl_raw_equal(value, "stale")) { - if(Curl_raw_equal(content, "true")) { - d->stale = TRUE; - d->nc = 1; /* we make a new nonce now */ - } - } - else if(Curl_raw_equal(value, "realm")) { - d->realm = strdup(content); - if(!d->realm) - return CURLDIGEST_NOMEM; - } - else if(Curl_raw_equal(value, "opaque")) { - d->opaque = strdup(content); - if(!d->opaque) - return CURLDIGEST_NOMEM; - } - else if(Curl_raw_equal(value, "qop")) { - char *tok_buf; - /* tokenize the list and choose auth if possible, use a temporary - clone of the buffer since strtok_r() ruins it */ - tmp = strdup(content); - if(!tmp) - return CURLDIGEST_NOMEM; - token = strtok_r(tmp, ",", &tok_buf); - while(token != NULL) { - if(Curl_raw_equal(token, "auth")) { - foundAuth = TRUE; - } - else if(Curl_raw_equal(token, "auth-int")) { - foundAuthInt = TRUE; - } - token = strtok_r(NULL, ",", &tok_buf); - } - free(tmp); - /*select only auth o auth-int. Otherwise, ignore*/ - if(foundAuth) { - d->qop = strdup("auth"); - if(!d->qop) - return CURLDIGEST_NOMEM; - } - else if(foundAuthInt) { - d->qop = strdup("auth-int"); - if(!d->qop) - return CURLDIGEST_NOMEM; - } - } - else if(Curl_raw_equal(value, "algorithm")) { - d->algorithm = strdup(content); - if(!d->algorithm) - return CURLDIGEST_NOMEM; - if(Curl_raw_equal(content, "MD5-sess")) - d->algo = CURLDIGESTALGO_MD5SESS; - else if(Curl_raw_equal(content, "MD5")) - d->algo = CURLDIGESTALGO_MD5; - else - return CURLDIGEST_BADALGO; - } - else { - /* unknown specifier, ignore it! */ - } - } - else - break; /* we're done here */ - - /* pass all additional spaces here */ - while(*header && ISSPACE(*header)) - header++; - if(',' == *header) - /* allow the list to be comma-separated */ - header++; - } - /* We had a nonce since before, and we got another one now without - 'stale=true'. This means we provided bad credentials in the previous - request */ - if(before && !d->stale) - return CURLDIGEST_BAD; - - /* We got this header without a nonce, that's a bad Digest line! */ - if(!d->nonce) - return CURLDIGEST_BAD; - } - else - /* else not a digest, get out */ - return CURLDIGEST_NONE; - - return CURLDIGEST_FINE; -} - -/* convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/ -static void md5_to_ascii(unsigned char *source, /* 16 bytes */ - unsigned char *dest) /* 33 bytes */ -{ - int i; - for(i=0; i<16; i++) - snprintf((char *)&dest[i*2], 3, "%02x", source[i]); + return Curl_sasl_decode_digest_http_message(header, digest); } CURLcode Curl_output_digest(struct connectdata *conn, @@ -274,137 +73,60 @@ CURLcode Curl_output_digest(struct connectdata *conn, const unsigned char *request, const unsigned char *uripath) { - /* We have a Digest setup for this, use it! Now, to get all the details for - this sorted out, I must urge you dear friend to read up on the RFC2617 - section 3.2.2, */ - unsigned char md5buf[16]; /* 16 bytes/128 bits */ - unsigned char request_digest[33]; - unsigned char *md5this; - unsigned char *ha1; - unsigned char ha2[33];/* 32 digits and 1 zero byte */ - char cnoncebuf[7]; - char *cnonce; - char *tmp = NULL; - struct timeval now; + CURLcode result; + struct SessionHandle *data = conn->data; + unsigned char *path; + char *tmp; + char *response; + size_t len; + bool have_chlg; + /* Point to the address of the pointer that holds the string to send to the + server, which is for a plain host or for a HTTP proxy */ char **allocuserpwd; + + /* Point to the name and password for this */ const char *userp; const char *passwdp; + + /* Point to the correct struct with this */ + struct digestdata *digest; struct auth *authp; - struct SessionHandle *data = conn->data; - struct digestdata *d; -#ifdef CURL_DOES_CONVERSIONS - CURLcode rc; -/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines. - It converts digest text to ASCII so the MD5 will be correct for - what ultimately goes over the network. -*/ -#define CURL_OUTPUT_DIGEST_CONV(a, b) \ - rc = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \ - if(rc != CURLE_OK) { \ - free(b); \ - return rc; \ - } -#else -#define CURL_OUTPUT_DIGEST_CONV(a, b) -#endif /* CURL_DOES_CONVERSIONS */ - if(proxy) { - d = &data->state.proxydigest; + digest = &data->state.proxydigest; allocuserpwd = &conn->allocptr.proxyuserpwd; userp = conn->proxyuser; passwdp = conn->proxypasswd; authp = &data->state.authproxy; } else { - d = &data->state.digest; + digest = &data->state.digest; allocuserpwd = &conn->allocptr.userpwd; userp = conn->user; passwdp = conn->passwd; authp = &data->state.authhost; } - if(*allocuserpwd) { - Curl_safefree(*allocuserpwd); - *allocuserpwd = NULL; - } + Curl_safefree(*allocuserpwd); /* not set means empty */ if(!userp) - userp=""; + userp = ""; if(!passwdp) - passwdp=""; + passwdp = ""; - if(!d->nonce) { +#if defined(USE_WINDOWS_SSPI) + have_chlg = digest->input_token ? TRUE : FALSE; +#else + have_chlg = digest->nonce ? TRUE : FALSE; +#endif + + if(!have_chlg) { authp->done = FALSE; return CURLE_OK; } - authp->done = TRUE; - - if(!d->nc) - d->nc = 1; - - if(!d->cnonce) { - /* Generate a cnonce */ - now = Curl_tvnow(); - snprintf(cnoncebuf, sizeof(cnoncebuf), "%06ld", (long)now.tv_sec); - if(Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), &cnonce)) - d->cnonce = cnonce; - else - return CURLE_OUT_OF_MEMORY; - } - - /* - if the algorithm is "MD5" or unspecified (which then defaults to MD5): - - A1 = unq(username-value) ":" unq(realm-value) ":" passwd - - if the algorithm is "MD5-sess" then: - - A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd ) - ":" unq(nonce-value) ":" unq(cnonce-value) - */ - - md5this = (unsigned char *) - aprintf("%s:%s:%s", userp, d->realm, passwdp); - if(!md5this) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - free(md5this); /* free this again */ - - ha1 = malloc(33); /* 32 digits and 1 zero byte */ - if(!ha1) - return CURLE_OUT_OF_MEMORY; - - md5_to_ascii(md5buf, ha1); - - if(d->algo == CURLDIGESTALGO_MD5SESS) { - /* nonce and cnonce are OUTSIDE the hash */ - tmp = aprintf("%s:%s:%s", ha1, d->nonce, d->cnonce); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - CURL_OUTPUT_DIGEST_CONV(data, tmp); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, (unsigned char *)tmp); - free(tmp); /* free this again */ - md5_to_ascii(md5buf, ha1); - } - - /* - If the "qop" directive's value is "auth" or is unspecified, then A2 is: - - A2 = Method ":" digest-uri-value - - If the "qop" value is "auth-int", then A2 is: - - A2 = Method ":" digest-uri-value ":" H(entity-body) - - (The "Method" value is the HTTP request method as specified in section - 5.1.1 of RFC 2616) - */ /* So IE browsers < v7 cut off the URI part at the query part when they evaluate the MD5 and some (IIS?) servers work with them so we may need to @@ -413,172 +135,45 @@ CURLcode Curl_output_digest(struct connectdata *conn, Apache servers can be set to do the Digest IE-style automatically using the BrowserMatch feature: - http://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie + https://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie Further details on Digest implementation differences: http://www.fngtps.com/2006/09/http-authentication */ + if(authp->iestyle && ((tmp = strchr((char *)uripath, '?')) != NULL)) { - md5this = (unsigned char *)aprintf("%s:%.*s", request, - (int)(tmp - (char *)uripath), uripath); + size_t urilen = tmp - (char *)uripath; + + path = (unsigned char *) aprintf("%.*s", urilen, uripath); } else - md5this = (unsigned char *)aprintf("%s:%s", request, uripath); + path = (unsigned char *) strdup((char *) uripath); - if(!md5this) { - free(ha1); - return CURLE_OUT_OF_MEMORY; - } - - if(d->qop && Curl_raw_equal(d->qop, "auth-int")) { - /* We don't support auth-int at the moment. I can't see a easy way to get - entity-body here */ - /* TODO: Append H(entity-body)*/ - } - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - free(md5this); /* free this again */ - md5_to_ascii(md5buf, ha2); - - if(d->qop) { - md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s", - ha1, - d->nonce, - d->nc, - d->cnonce, - d->qop, - ha2); - } - else { - md5this = (unsigned char *)aprintf("%s:%s:%s", - ha1, - d->nonce, - ha2); - } - free(ha1); - if(!md5this) + if(!path) return CURLE_OUT_OF_MEMORY; - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - free(md5this); /* free this again */ - md5_to_ascii(md5buf, request_digest); + result = Curl_sasl_create_digest_http_message(data, userp, passwdp, request, + path, digest, &response, &len); + free(path); + if(result) + return result; - /* for test case 64 (snooped from a Mozilla 1.3a request) - - Authorization: Digest username="testuser", realm="testrealm", \ - nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca" - */ - - if(d->qop) { - *allocuserpwd = - aprintf( "%sAuthorization: Digest " - "username=\"%s\", " - "realm=\"%s\", " - "nonce=\"%s\", " - "uri=\"%s\", " - "cnonce=\"%s\", " - "nc=%08x, " - "qop=\"%s\", " - "response=\"%s\"", - proxy?"Proxy-":"", - userp, - d->realm, - d->nonce, - uripath, /* this is the PATH part of the URL */ - d->cnonce, - d->nc, - d->qop, - request_digest); - - if(Curl_raw_equal(d->qop, "auth")) - d->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 padded - which tells to the server how many times you are using the - same nonce in the qop=auth mode. */ - } - else { - *allocuserpwd = - aprintf( "%sAuthorization: Digest " - "username=\"%s\", " - "realm=\"%s\", " - "nonce=\"%s\", " - "uri=\"%s\", " - "response=\"%s\"", - proxy?"Proxy-":"", - userp, - d->realm, - d->nonce, - uripath, /* this is the PATH part of the URL */ - request_digest); - } + *allocuserpwd = aprintf("%sAuthorization: Digest %s\r\n", + proxy ? "Proxy-" : "", + response); + free(response); if(!*allocuserpwd) return CURLE_OUT_OF_MEMORY; - /* Add optional fields */ - if(d->opaque) { - /* append opaque */ - tmp = aprintf("%s, opaque=\"%s\"", *allocuserpwd, d->opaque); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - free(*allocuserpwd); - *allocuserpwd = tmp; - } - - if(d->algorithm) { - /* append algorithm */ - tmp = aprintf("%s, algorithm=\"%s\"", *allocuserpwd, d->algorithm); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - free(*allocuserpwd); - *allocuserpwd = tmp; - } - - /* append CRLF + zero (3 bytes) to the userpwd header */ - tmp = realloc(*allocuserpwd, strlen(*allocuserpwd) + 3); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - strcat(tmp, "\r\n"); - *allocuserpwd = tmp; + authp->done = TRUE; return CURLE_OK; } -void Curl_digest_cleanup_one(struct digestdata *d) -{ - if(d->nonce) - free(d->nonce); - d->nonce = NULL; - - if(d->cnonce) - free(d->cnonce); - d->cnonce = NULL; - - if(d->realm) - free(d->realm); - d->realm = NULL; - - if(d->opaque) - free(d->opaque); - d->opaque = NULL; - - if(d->qop) - free(d->qop); - d->qop = NULL; - - if(d->algorithm) - free(d->algorithm); - d->algorithm = NULL; - - d->nc = 0; - d->algo = CURLDIGESTALGO_MD5; /* default algorithm */ - d->stale = FALSE; /* default means normal, not stale */ -} - - void Curl_digest_cleanup(struct SessionHandle *data) { - Curl_digest_cleanup_one(&data->state.digest); - Curl_digest_cleanup_one(&data->state.proxydigest); + Curl_sasl_digest_cleanup(&data->state.digest); + Curl_sasl_digest_cleanup(&data->state.proxydigest); } #endif diff --git a/project/jni/curl/lib/http_digest.h b/project/jni/curl/lib/http_digest.h index 8c96378d6..49aad897c 100644 --- a/project/jni/curl/lib/http_digest.h +++ b/project/jni/curl/lib/http_digest.h @@ -1,5 +1,5 @@ -#ifndef __HTTP_DIGEST_H -#define __HTTP_DIGEST_H +#ifndef HEADER_CURL_HTTP_DIGEST_H +#define HEADER_CURL_HTTP_DIGEST_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,37 +21,22 @@ * KIND, either express or implied. * ***************************************************************************/ - -typedef enum { - CURLDIGEST_NONE, /* not a digest */ - CURLDIGEST_BAD, /* a digest, but one we don't like */ - CURLDIGEST_BADALGO, /* unsupported algorithm requested */ - CURLDIGEST_NOMEM, - CURLDIGEST_FINE, /* a digest we act on */ - - CURLDIGEST_LAST /* last entry in this enum, don't use */ -} CURLdigest; - -enum { - CURLDIGESTALGO_MD5, - CURLDIGESTALGO_MD5SESS -}; +#include "curl_setup.h" /* this is for digest header input */ -CURLdigest Curl_input_digest(struct connectdata *conn, - bool proxy, const char *header); +CURLcode Curl_input_digest(struct connectdata *conn, + bool proxy, const char *header); /* this is for creating digest header output */ CURLcode Curl_output_digest(struct connectdata *conn, bool proxy, const unsigned char *request, const unsigned char *uripath); -void Curl_digest_cleanup_one(struct digestdata *dig); #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) void Curl_digest_cleanup(struct SessionHandle *data); #else -#define Curl_digest_cleanup(x) do {} while(0) +#define Curl_digest_cleanup(x) Curl_nop_stmt #endif -#endif +#endif /* HEADER_CURL_HTTP_DIGEST_H */ diff --git a/project/jni/curl/lib/http_negotiate.c b/project/jni/curl/lib/http_negotiate.c index 80b0b507d..4a808f8f3 100644 --- a/project/jni/curl/lib/http_negotiate.c +++ b/project/jni/curl/lib/http_negotiate.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -19,327 +19,170 @@ * KIND, either express or implied. * ***************************************************************************/ -#include "setup.h" -#ifdef HAVE_GSSAPI -#ifdef HAVE_OLD_GSSMIT -#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name -#endif +#include "curl_setup.h" -#ifndef CURL_DISABLE_HTTP - /* -- WIN32 approved -- */ -#include -#include -#include -#include -#include +#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) #include "urldata.h" #include "sendf.h" +#include "curl_gssapi.h" #include "rawstr.h" #include "curl_base64.h" #include "http_negotiate.h" +#include "curl_sasl.h" +#include "url.h" +#include "curl_printf.h" + +/* The last #include files should be: */ #include "curl_memory.h" - -#ifdef HAVE_SPNEGO -# include -# ifdef USE_SSLEAY -# ifdef USE_OPENSSL -# include -# else -# include -# endif -# else -# error "Can't compile SPNEGO support without OpenSSL." -# endif -#endif - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ #include "memdebug.h" -static int -get_gss_name(struct connectdata *conn, bool proxy, gss_name_t *server) +CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, + const char *header) { - struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: - &conn->data->state.negotiate; - OM_uint32 major_status, minor_status; - gss_buffer_desc token = GSS_C_EMPTY_BUFFER; - char name[2048]; - const char* service; - - /* GSSAPI implementation by Globus (known as GSI) requires the name to be - of form "/" instead of @ (ie. slash instead - of at-sign). Also GSI servers are often identified as 'host' not 'khttp'. - Change following lines if you want to use GSI */ - - /* IIS uses the @ form but uses 'http' as the service name */ - - if(neg_ctx->gss) - service = "KHTTP"; - else - service = "HTTP"; - - token.length = strlen(service) + 1 + strlen(proxy ? conn->proxy.name : - conn->host.name) + 1; - if(token.length + 1 > sizeof(name)) - return EMSGSIZE; - - snprintf(name, sizeof(name), "%s@%s", service, proxy ? conn->proxy.name : - conn->host.name); - - token.value = (void *) name; - major_status = gss_import_name(&minor_status, - &token, - GSS_C_NT_HOSTBASED_SERVICE, - server); - - return GSS_ERROR(major_status) ? -1 : 0; -} - -static void -log_gss_error(struct connectdata *conn, OM_uint32 error_status, const char *prefix) -{ - OM_uint32 maj_stat, min_stat; - OM_uint32 msg_ctx = 0; - gss_buffer_desc status_string; - char buf[1024]; - size_t len; - - snprintf(buf, sizeof(buf), "%s", prefix); - len = strlen(buf); - do { - maj_stat = gss_display_status(&min_stat, - error_status, - GSS_C_MECH_CODE, - GSS_C_NO_OID, - &msg_ctx, - &status_string); - if(sizeof(buf) > len + status_string.length + 1) { - snprintf(buf + len, sizeof(buf) - len, - ": %s", (char*) status_string.value); - len += status_string.length; - } - gss_release_buffer(&min_stat, &status_string); - } while(!GSS_ERROR(maj_stat) && msg_ctx != 0); - - infof(conn->data, "%s", buf); -} - -/* returning zero (0) means success, everything else is treated as "failure" - with no care exactly what the failure was */ -int Curl_input_negotiate(struct connectdata *conn, bool proxy, - const char *header) -{ - struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: - &conn->data->state.negotiate; - OM_uint32 major_status, minor_status, minor_status2; + struct SessionHandle *data = conn->data; + struct negotiatedata *neg_ctx = proxy?&data->state.proxyneg: + &data->state.negotiate; + OM_uint32 major_status, minor_status, discard_st; + gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; - int ret; - size_t len, rawlen; - bool gss; - const char* protocol; - - while(*header && ISSPACE(*header)) - header++; - if(checkprefix("GSS-Negotiate", header)) { - protocol = "GSS-Negotiate"; - gss = TRUE; - } - else if(checkprefix("Negotiate", header)) { - protocol = "Negotiate"; - gss = FALSE; - } - else - return -1; - - if(neg_ctx->context) { - if(neg_ctx->gss != gss) { - return -1; - } - } - else { - neg_ctx->protocol = protocol; - neg_ctx->gss = gss; - } + size_t len; + size_t rawlen = 0; + CURLcode result; if(neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) { - /* We finished succesfully our part of authentication, but server + /* We finished successfully our part of authentication, but server * rejected it (since we're again here). Exit with an error since we * can't invent anything better */ - Curl_cleanup_negotiate(conn->data); - return -1; + Curl_cleanup_negotiate(data); + return CURLE_LOGIN_DENIED; } - if(neg_ctx->server_name == NULL && - (ret = get_gss_name(conn, proxy, &neg_ctx->server_name))) - return ret; + if(!neg_ctx->server_name) { + /* Generate our SPN */ + char *spn = Curl_sasl_build_gssapi_spn( + proxy ? data->set.str[STRING_PROXY_SERVICE_NAME] : + data->set.str[STRING_SERVICE_NAME], + proxy ? conn->proxy.name : conn->host.name); + if(!spn) + return CURLE_OUT_OF_MEMORY; - header += strlen(neg_ctx->protocol); + /* Populate the SPN structure */ + spn_token.value = spn; + spn_token.length = strlen(spn); + + /* Import the SPN */ + major_status = gss_import_name(&minor_status, &spn_token, + GSS_C_NT_HOSTBASED_SERVICE, + &neg_ctx->server_name); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, minor_status, "gss_import_name() failed: "); + + free(spn); + + return CURLE_OUT_OF_MEMORY; + } + + free(spn); + } + + header += strlen("Negotiate"); while(*header && ISSPACE(*header)) header++; len = strlen(header); if(len > 0) { - rawlen = Curl_base64_decode(header, - (unsigned char **)&input_token.value); - if(rawlen == 0) - return -1; + result = Curl_base64_decode(header, (unsigned char **)&input_token.value, + &rawlen); + if(result) + return result; + + if(!rawlen) { + infof(data, "Negotiate handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + input_token.length = rawlen; -#ifdef HAVE_SPNEGO /* Handle SPNEGO */ - if(checkprefix("Negotiate", header)) { - ASN1_OBJECT * object = NULL; - int rc = 1; - unsigned char * spnegoToken = NULL; - size_t spnegoTokenLength = 0; - unsigned char * mechToken = NULL; - size_t mechTokenLength = 0; - - if(input_token.value == NULL) - return CURLE_OUT_OF_MEMORY; - - spnegoToken = malloc(input_token.length); - if(spnegoToken == NULL) - return CURLE_OUT_OF_MEMORY; - - spnegoTokenLength = input_token.length; - - object = OBJ_txt2obj ("1.2.840.113554.1.2.2", 1); - if(!parseSpnegoTargetToken(spnegoToken, - spnegoTokenLength, - NULL, - NULL, - &mechToken, - &mechTokenLength, - NULL, - NULL)) { - free(spnegoToken); - spnegoToken = NULL; - infof(conn->data, "Parse SPNEGO Target Token failed\n"); - } - else { - free(input_token.value); - input_token.value = malloc(mechTokenLength); - if (input_token.value == NULL) - return CURLE_OUT_OF_MEMORY; - - memcpy(input_token.value, mechToken,mechTokenLength); - input_token.length = mechTokenLength; - free(mechToken); - mechToken = NULL; - infof(conn->data, "Parse SPNEGO Target Token succeeded\n"); - } - } -#endif + DEBUGASSERT(input_token.value != NULL); } - major_status = gss_init_sec_context(&minor_status, - GSS_C_NO_CREDENTIAL, - &neg_ctx->context, - neg_ctx->server_name, - GSS_C_NO_OID, - GSS_C_DELEG_FLAG, - 0, - GSS_C_NO_CHANNEL_BINDINGS, - &input_token, - NULL, - &output_token, - NULL, - NULL); - if(input_token.length > 0) - gss_release_buffer(&minor_status2, &input_token); + major_status = Curl_gss_init_sec_context(data, + &minor_status, + &neg_ctx->context, + neg_ctx->server_name, + &Curl_spnego_mech_oid, + GSS_C_NO_CHANNEL_BINDINGS, + &input_token, + &output_token, + TRUE, + NULL); + Curl_safefree(input_token.value); + neg_ctx->status = major_status; if(GSS_ERROR(major_status)) { - /* Curl_cleanup_negotiate(conn->data) ??? */ - log_gss_error(conn, minor_status, - "gss_init_sec_context() failed: "); - return -1; + if(output_token.value) + gss_release_buffer(&discard_st, &output_token); + Curl_gss_log_error(conn->data, minor_status, + "gss_init_sec_context() failed: "); + return CURLE_OUT_OF_MEMORY; } - if(output_token.length == 0) { - return -1; + if(!output_token.value || !output_token.length) { + if(output_token.value) + gss_release_buffer(&discard_st, &output_token); + return CURLE_OUT_OF_MEMORY; } neg_ctx->output_token = output_token; - /* conn->bits.close = FALSE; */ - return 0; + return CURLE_OK; } - CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) { struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: &conn->data->state.negotiate; char *encoded = NULL; - size_t len; + size_t len = 0; char *userp; + CURLcode result; + OM_uint32 discard_st; -#ifdef HAVE_SPNEGO /* Handle SPNEGO */ - if(checkprefix("Negotiate", neg_ctx->protocol)) { - ASN1_OBJECT * object = NULL; - int rc = 1; - unsigned char * spnegoToken = NULL; - size_t spnegoTokenLength = 0; - unsigned char * responseToken = NULL; - size_t responseTokenLength = 0; - - responseToken = malloc(neg_ctx->output_token.length); - if( responseToken == NULL) - return CURLE_OUT_OF_MEMORY; - memcpy(responseToken, neg_ctx->output_token.value, - neg_ctx->output_token.length); - responseTokenLength = neg_ctx->output_token.length; - - object=OBJ_txt2obj ("1.2.840.113554.1.2.2", 1); - if(!makeSpnegoInitialToken (object, - responseToken, - responseTokenLength, - &spnegoToken, - &spnegoTokenLength)) { - free(responseToken); - responseToken = NULL; - infof(conn->data, "Make SPNEGO Initial Token failed\n"); - } - else { - free(responseToken); - responseToken = NULL; - free(neg_ctx->output_token.value); - neg_ctx->output_token.value = malloc(spnegoTokenLength); - if(neg_ctx->output_token.value == NULL) { - free(spnegoToken); - spnegoToken = NULL; - return CURLE_OUT_OF_MEMORY; - } - memcpy(neg_ctx->output_token.value, spnegoToken,spnegoTokenLength); - neg_ctx->output_token.length = spnegoTokenLength; - free(spnegoToken); - spnegoToken = NULL; - infof(conn->data, "Make SPNEGO Initial Token succeeded\n"); - } + result = Curl_base64_encode(conn->data, + neg_ctx->output_token.value, + neg_ctx->output_token.length, + &encoded, &len); + if(result) { + gss_release_buffer(&discard_st, &neg_ctx->output_token); + neg_ctx->output_token.value = NULL; + neg_ctx->output_token.length = 0; + return result; } -#endif - len = Curl_base64_encode(conn->data, - neg_ctx->output_token.value, - neg_ctx->output_token.length, - &encoded); - if(len == 0) - return CURLE_OUT_OF_MEMORY; + if(!encoded || !len) { + gss_release_buffer(&discard_st, &neg_ctx->output_token); + neg_ctx->output_token.value = NULL; + neg_ctx->output_token.length = 0; + return CURLE_REMOTE_ACCESS_DENIED; + } - userp = aprintf("%sAuthorization: %s %s\r\n", proxy ? "Proxy-" : "", - neg_ctx->protocol, encoded); - - if(proxy) + userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "", + encoded); + if(proxy) { + Curl_safefree(conn->allocptr.proxyuserpwd); conn->allocptr.proxyuserpwd = userp; - else + } + else { + Curl_safefree(conn->allocptr.userpwd); conn->allocptr.userpwd = userp; + } + free(encoded); - Curl_cleanup_negotiate (conn->data); + return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK; } @@ -349,7 +192,7 @@ static void cleanup(struct negotiatedata *neg_ctx) if(neg_ctx->context != GSS_C_NO_CONTEXT) gss_delete_sec_context(&minor_status, &neg_ctx->context, GSS_C_NO_BUFFER); - if(neg_ctx->output_token.length != 0) + if(neg_ctx->output_token.value) gss_release_buffer(&minor_status, &neg_ctx->output_token); if(neg_ctx->server_name != GSS_C_NO_NAME) @@ -364,6 +207,4 @@ void Curl_cleanup_negotiate(struct SessionHandle *data) cleanup(&data->state.proxyneg); } - -#endif -#endif +#endif /* HAVE_GSSAPI && !CURL_DISABLE_HTTP && USE_SPNEGO */ diff --git a/project/jni/curl/lib/http_negotiate.h b/project/jni/curl/lib/http_negotiate.h index 35501f044..acbbf6ae5 100644 --- a/project/jni/curl/lib/http_negotiate.h +++ b/project/jni/curl/lib/http_negotiate.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,17 +22,21 @@ * ***************************************************************************/ -#ifdef HAVE_GSSAPI +#ifdef USE_SPNEGO /* this is for Negotiate header input */ -int Curl_input_negotiate(struct connectdata *conn, bool proxy, - const char *header); +CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, + const char *header); /* this is for creating Negotiate header output */ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy); void Curl_cleanup_negotiate(struct SessionHandle *data); -#endif /* HAVE_GSSAPI */ +#ifdef USE_WINDOWS_SSPI +#define GSS_ERROR(status) (status & 0x80000000) +#endif + +#endif /* USE_SPNEGO */ #endif /* HEADER_CURL_HTTP_NEGOTIATE_H */ diff --git a/project/jni/curl/lib/http_negotiate_sspi.c b/project/jni/curl/lib/http_negotiate_sspi.c new file mode 100644 index 000000000..d2643bb41 --- /dev/null +++ b/project/jni/curl/lib/http_negotiate_sspi.c @@ -0,0 +1,302 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_WINDOWS_SSPI + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) + +#include "urldata.h" +#include "sendf.h" +#include "rawstr.h" +#include "warnless.h" +#include "curl_base64.h" +#include "curl_sasl.h" +#include "http_negotiate.h" +#include "curl_multibyte.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, + const char *header) +{ + struct SessionHandle *data = conn->data; + BYTE *input_token = NULL; + SecBufferDesc out_buff_desc; + SecBuffer out_sec_buff; + SecBufferDesc in_buff_desc; + SecBuffer in_sec_buff; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + size_t len = 0, input_token_len = 0; + CURLcode result; + + /* Point to the username and password */ + const char *userp; + const char *passwdp; + + /* Point to the correct struct with this */ + struct negotiatedata *neg_ctx; + + if(proxy) { + userp = conn->proxyuser; + passwdp = conn->proxypasswd; + neg_ctx = &data->state.proxyneg; + } + else { + userp = conn->user; + passwdp = conn->passwd; + neg_ctx = &data->state.negotiate; + } + + /* Not set means empty */ + if(!userp) + userp = ""; + + if(!passwdp) + passwdp = ""; + + if(neg_ctx->context && neg_ctx->status == SEC_E_OK) { + /* We finished successfully our part of authentication, but server + * rejected it (since we're again here). Exit with an error since we + * can't invent anything better */ + Curl_cleanup_negotiate(data); + return CURLE_LOGIN_DENIED; + } + + if(!neg_ctx->server_name) { + /* Check proxy auth requested but no given proxy name */ + if(proxy && !conn->proxy.name) + return CURLE_BAD_FUNCTION_ARGUMENT; + + /* Generate our SPN */ + neg_ctx->server_name = Curl_sasl_build_spn( + proxy ? data->set.str[STRING_PROXY_SERVICE_NAME] : + data->set.str[STRING_SERVICE_NAME], + proxy ? conn->proxy.name : conn->host.name); + if(!neg_ctx->server_name) + return CURLE_OUT_OF_MEMORY; + } + + if(!neg_ctx->output_token) { + PSecPkgInfo SecurityPackage; + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_NEGOTIATE), + &SecurityPackage); + if(status != SEC_E_OK) + return CURLE_NOT_BUILT_IN; + + /* Allocate input and output buffers according to the max token size + as indicated by the security package */ + neg_ctx->token_max = SecurityPackage->cbMaxToken; + neg_ctx->output_token = malloc(neg_ctx->token_max); + s_pSecFn->FreeContextBuffer(SecurityPackage); + } + + /* Obtain the input token, if any */ + header += strlen("Negotiate"); + while(*header && ISSPACE(*header)) + header++; + + len = strlen(header); + if(!len) { + /* Is this the first call in a new negotiation? */ + if(neg_ctx->context) { + /* The server rejected our authentication and hasn't suppled any more + negotiation mechanisms */ + return CURLE_LOGIN_DENIED; + } + + /* We have to acquire credentials and allocate memory for the context */ + neg_ctx->credentials = malloc(sizeof(CredHandle)); + neg_ctx->context = malloc(sizeof(CtxtHandle)); + + if(!neg_ctx->credentials || !neg_ctx->context) + return CURLE_OUT_OF_MEMORY; + + if(userp && *userp) { + /* Populate our identity structure */ + result = Curl_create_sspi_identity(userp, passwdp, &neg_ctx->identity); + if(result) + return result; + + /* Allow proper cleanup of the identity structure */ + neg_ctx->p_identity = &neg_ctx->identity; + } + else + /* Use the current Windows user */ + neg_ctx->p_identity = NULL; + + /* Acquire our credientials handle */ + neg_ctx->status = + s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_NEGOTIATE), + SECPKG_CRED_OUTBOUND, NULL, + neg_ctx->p_identity, NULL, NULL, + neg_ctx->credentials, &expiry); + if(neg_ctx->status != SEC_E_OK) + return CURLE_LOGIN_DENIED; + } + else { + result = Curl_base64_decode(header, + (unsigned char **)&input_token, + &input_token_len); + if(result) + return result; + + if(!input_token_len) { + infof(data, + "Negotiate handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + } + + /* Setup the "output" security buffer */ + out_buff_desc.ulVersion = SECBUFFER_VERSION; + out_buff_desc.cBuffers = 1; + out_buff_desc.pBuffers = &out_sec_buff; + out_sec_buff.BufferType = SECBUFFER_TOKEN; + out_sec_buff.pvBuffer = neg_ctx->output_token; + out_sec_buff.cbBuffer = curlx_uztoul(neg_ctx->token_max); + + /* Setup the "input" security buffer if present */ + if(input_token) { + in_buff_desc.ulVersion = SECBUFFER_VERSION; + in_buff_desc.cBuffers = 1; + in_buff_desc.pBuffers = &in_sec_buff; + in_sec_buff.BufferType = SECBUFFER_TOKEN; + in_sec_buff.pvBuffer = input_token; + in_sec_buff.cbBuffer = curlx_uztoul(input_token_len); + } + + /* Generate our message */ + neg_ctx->status = s_pSecFn->InitializeSecurityContext( + neg_ctx->credentials, + input_token ? neg_ctx->context : NULL, + neg_ctx->server_name, + ISC_REQ_CONFIDENTIALITY, + 0, + SECURITY_NATIVE_DREP, + input_token ? &in_buff_desc : NULL, + 0, + neg_ctx->context, + &out_buff_desc, + &attrs, + &expiry); + + free(input_token); + + if(GSS_ERROR(neg_ctx->status)) + return CURLE_OUT_OF_MEMORY; + + if(neg_ctx->status == SEC_I_COMPLETE_NEEDED || + neg_ctx->status == SEC_I_COMPLETE_AND_CONTINUE) { + neg_ctx->status = s_pSecFn->CompleteAuthToken(neg_ctx->context, + &out_buff_desc); + if(GSS_ERROR(neg_ctx->status)) + return CURLE_RECV_ERROR; + } + + neg_ctx->output_token_length = out_sec_buff.cbBuffer; + + return CURLE_OK; +} + +CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) +{ + struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: + &conn->data->state.negotiate; + char *encoded = NULL; + size_t len = 0; + char *userp; + CURLcode result; + + result = Curl_base64_encode(conn->data, + (const char*)neg_ctx->output_token, + neg_ctx->output_token_length, + &encoded, &len); + if(result) + return result; + + if(!len) + return CURLE_REMOTE_ACCESS_DENIED; + + userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "", + encoded); + + if(proxy) { + Curl_safefree(conn->allocptr.proxyuserpwd); + conn->allocptr.proxyuserpwd = userp; + } + else { + Curl_safefree(conn->allocptr.userpwd); + conn->allocptr.userpwd = userp; + } + + free(encoded); + + return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK; +} + +static void cleanup(struct negotiatedata *neg_ctx) +{ + /* Free our security context */ + if(neg_ctx->context) { + s_pSecFn->DeleteSecurityContext(neg_ctx->context); + free(neg_ctx->context); + neg_ctx->context = NULL; + } + + /* Free our credentials handle */ + if(neg_ctx->credentials) { + s_pSecFn->FreeCredentialsHandle(neg_ctx->credentials); + free(neg_ctx->credentials); + neg_ctx->credentials = NULL; + } + + /* Free our identity */ + Curl_sspi_free_identity(neg_ctx->p_identity); + neg_ctx->p_identity = NULL; + + /* Free the SPN and output token */ + Curl_safefree(neg_ctx->server_name); + Curl_safefree(neg_ctx->output_token); + + /* Reset any variables */ + neg_ctx->token_max = 0; +} + +void Curl_cleanup_negotiate(struct SessionHandle *data) +{ + cleanup(&data->state.negotiate); + cleanup(&data->state.proxyneg); +} + +#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */ + +#endif /* USE_WINDOWS_SSPI */ diff --git a/project/jni/curl/lib/http_ntlm.c b/project/jni/curl/lib/http_ntlm.c deleted file mode 100644 index f5b696a69..000000000 --- a/project/jni/curl/lib/http_ntlm.c +++ /dev/null @@ -1,1305 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ -#include "setup.h" - -/* NTLM details: - - http://davenport.sourceforge.net/ntlm.html - http://www.innovation.ch/java/ntlm.html - - Another implementation: - http://lxr.mozilla.org/mozilla/source/security/manager/ssl/src/nsNTLMAuthModule.cpp - -*/ - -#ifndef CURL_DISABLE_HTTP -#ifdef USE_NTLM - -#define DEBUG_ME 0 - -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#if (defined(NETWARE) && !defined(__NOVELL_LIBC__)) -#include -#endif - -#include "urldata.h" -#include "easyif.h" /* for Curl_convert_... prototypes */ -#include "sendf.h" -#include "rawstr.h" -#include "curl_base64.h" -#include "http_ntlm.h" -#include "url.h" -#include "curl_gethostname.h" -#include "curl_memory.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* "NTLMSSP" signature is always in ASCII regardless of the platform */ -#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" - -#ifdef USE_SSLEAY -#include "ssluse.h" -# ifdef USE_OPENSSL -# include -# ifndef OPENSSL_NO_MD4 -# include -# endif -# include -# include -# include -# else -# include -# ifndef OPENSSL_NO_MD4 -# include -# endif -# include -# include -# include -# endif - -#if OPENSSL_VERSION_NUMBER < 0x00907001L -#define DES_key_schedule des_key_schedule -#define DES_cblock des_cblock -#define DES_set_odd_parity des_set_odd_parity -#define DES_set_key des_set_key -#define DES_ecb_encrypt des_ecb_encrypt - -/* This is how things were done in the old days */ -#define DESKEY(x) x -#define DESKEYARG(x) x -#else -/* Modern version */ -#define DESKEYARG(x) *x -#define DESKEY(x) &x -#endif - -#ifdef OPENSSL_NO_MD4 -/* This requires MD4, but OpenSSL was compiled without it */ -#define USE_NTRESPONSES 0 -#define USE_NTLM2SESSION 0 -#endif - -#elif defined(USE_GNUTLS) - -#include "gtls.h" -#include - -#define MD5_DIGEST_LENGTH 16 -#define MD4_DIGEST_LENGTH 16 - -#elif defined(USE_NSS) - -#include "curl_md4.h" -#include "nssg.h" -#include -#include -#include -#define MD5_DIGEST_LENGTH MD5_LENGTH - -#elif defined(USE_WINDOWS_SSPI) - -#include "curl_sspi.h" - -#else -# error "Can't compile NTLM support without a crypto library." -#endif - -/* The last #include file should be: */ -#include "memdebug.h" - -#ifndef USE_NTRESPONSES -/* Define this to make the type-3 message include the NT response message */ -#define USE_NTRESPONSES 1 - -/* Define this to make the type-3 message include the NTLM2Session response - message, requires USE_NTRESPONSES. */ -#define USE_NTLM2SESSION 1 -#endif - -#ifndef USE_WINDOWS_SSPI -/* this function converts from the little endian format used in the incoming - package to whatever endian format we're using natively */ -static unsigned int readint_le(unsigned char *buf) /* must point to a - 4 bytes buffer*/ -{ - return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | - ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); -} -#endif - -#if DEBUG_ME -# define DEBUG_OUT(x) x -static void print_flags(FILE *handle, unsigned long flags) -{ - if(flags & NTLMFLAG_NEGOTIATE_UNICODE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE "); - if(flags & NTLMFLAG_NEGOTIATE_OEM) - fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM "); - if(flags & NTLMFLAG_REQUEST_TARGET) - fprintf(handle, "NTLMFLAG_REQUEST_TARGET "); - if(flags & (1<<3)) - fprintf(handle, "NTLMFLAG_UNKNOWN_3 "); - if(flags & NTLMFLAG_NEGOTIATE_SIGN) - fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN "); - if(flags & NTLMFLAG_NEGOTIATE_SEAL) - fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL "); - if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE "); - if(flags & NTLMFLAG_NEGOTIATE_LM_KEY) - fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY "); - if(flags & NTLMFLAG_NEGOTIATE_NETWARE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE "); - if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) - fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY "); - if(flags & (1<<10)) - fprintf(handle, "NTLMFLAG_UNKNOWN_10 "); - if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS) - fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS "); - if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED) - fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED "); - if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED) - fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED "); - if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL) - fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL "); - if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN) - fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN "); - if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN) - fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN "); - if(flags & NTLMFLAG_TARGET_TYPE_SERVER) - fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER "); - if(flags & NTLMFLAG_TARGET_TYPE_SHARE) - fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE "); - if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) - fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY "); - if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE) - fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE "); - if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE) - fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE "); - if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY) - fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY "); - if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) - fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO "); - if(flags & (1<<24)) - fprintf(handle, "NTLMFLAG_UNKNOWN_24 "); - if(flags & (1<<25)) - fprintf(handle, "NTLMFLAG_UNKNOWN_25 "); - if(flags & (1<<26)) - fprintf(handle, "NTLMFLAG_UNKNOWN_26 "); - if(flags & (1<<27)) - fprintf(handle, "NTLMFLAG_UNKNOWN_27 "); - if(flags & (1<<28)) - fprintf(handle, "NTLMFLAG_UNKNOWN_28 "); - if(flags & NTLMFLAG_NEGOTIATE_128) - fprintf(handle, "NTLMFLAG_NEGOTIATE_128 "); - if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE "); - if(flags & NTLMFLAG_NEGOTIATE_56) - fprintf(handle, "NTLMFLAG_NEGOTIATE_56 "); -} - -static void print_hex(FILE *handle, const char *buf, size_t len) -{ - const char *p = buf; - fprintf(stderr, "0x"); - while(len-- > 0) - fprintf(stderr, "%02.2x", (unsigned int)*p++); -} -#else -# define DEBUG_OUT(x) -#endif - -/* - (*) = A "security buffer" is a triplet consisting of two shorts and one - long: - - 1. a 'short' containing the length of the buffer in bytes - 2. a 'short' containing the allocated space for the buffer in bytes - 3. a 'long' containing the offset to the start of the buffer from the - beginning of the NTLM message, in bytes. -*/ - - -CURLntlm Curl_input_ntlm(struct connectdata *conn, - bool proxy, /* if proxy or not */ - const char *header) /* rest of the www-authenticate: - header */ -{ - /* point to the correct struct with this */ - struct ntlmdata *ntlm; -#ifndef USE_WINDOWS_SSPI - static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; -#endif - -#ifdef USE_NSS - if(CURLE_OK != Curl_nss_force_init(conn->data)) - return CURLNTLM_BAD; -#endif - - ntlm = proxy?&conn->proxyntlm:&conn->ntlm; - - /* skip initial whitespaces */ - while(*header && ISSPACE(*header)) - header++; - - if(checkprefix("NTLM", header)) { - header += strlen("NTLM"); - - while(*header && ISSPACE(*header)) - header++; - - if(*header) { - /* We got a type-2 message here: - - Index Description Content - 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" - (0x4e544c4d53535000) - 8 NTLM Message Type long (0x02000000) - 12 Target Name security buffer(*) - 20 Flags long - 24 Challenge 8 bytes - (32) Context (optional) 8 bytes (two consecutive longs) - (40) Target Information (optional) security buffer(*) - 32 (48) start of data block - */ - size_t size; - unsigned char *buffer; - size = Curl_base64_decode(header, &buffer); - if(!buffer) - return CURLNTLM_BAD; - - ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */ - -#ifdef USE_WINDOWS_SSPI - ntlm->type_2 = malloc(size+1); - if(ntlm->type_2 == NULL) { - free(buffer); - return CURLE_OUT_OF_MEMORY; - } - ntlm->n_type_2 = size; - memcpy(ntlm->type_2, buffer, size); -#else - ntlm->flags = 0; - - if((size < 32) || - (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) || - (memcmp(buffer+8, type2_marker, sizeof(type2_marker)) != 0)) { - /* This was not a good enough type-2 message */ - free(buffer); - return CURLNTLM_BAD; - } - - ntlm->flags = readint_le(&buffer[20]); - memcpy(ntlm->nonce, &buffer[24], 8); - - DEBUG_OUT({ - fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); - print_flags(stderr, ntlm->flags); - fprintf(stderr, "\n nonce="); - print_hex(stderr, (char *)ntlm->nonce, 8); - fprintf(stderr, "\n****\n"); - fprintf(stderr, "**** Header %s\n ", header); - }); -#endif - free(buffer); - } - else { - if(ntlm->state >= NTLMSTATE_TYPE1) - return CURLNTLM_BAD; - - ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */ - } - } - return CURLNTLM_FINE; -} - -#ifndef USE_WINDOWS_SSPI - -#ifdef USE_SSLEAY -/* - * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The - * key schedule ks is also set. - */ -static void setup_des_key(const unsigned char *key_56, - DES_key_schedule DESKEYARG(ks)) -{ - DES_cblock key; - - key[0] = key_56[0]; - key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1)); - key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2)); - key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3)); - key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4)); - key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5)); - key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6)); - key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF); - - DES_set_odd_parity(&key); - DES_set_key(&key, ks); -} - -#else /* defined(USE_SSLEAY) */ - -/* - * Turns a 56 bit key into the 64 bit, odd parity key. Used by GnuTLS and NSS. - */ -static void extend_key_56_to_64(const unsigned char *key_56, char *key) -{ - key[0] = key_56[0]; - key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1)); - key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2)); - key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3)); - key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4)); - key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5)); - key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6)); - key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF); -} - -#if defined(USE_GNUTLS) - -/* - * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. - */ -static void setup_des_key(const unsigned char *key_56, - gcry_cipher_hd_t *des) -{ - char key[8]; - extend_key_56_to_64(key_56, key); - gcry_cipher_setkey(*des, key, 8); -} - -#elif defined(USE_NSS) - -/* - * Expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of data, using - * the expanded key. The caller is responsible for giving 64 bit of valid - * data is IN and (at least) 64 bit large buffer as OUT. - */ -static bool encrypt_des(const unsigned char *in, unsigned char *out, - const unsigned char *key_56) -{ - const CK_MECHANISM_TYPE mech = CKM_DES_ECB; /* DES cipher in ECB mode */ - PK11SlotInfo *slot = NULL; - char key[8]; /* expanded 64 bit key */ - SECItem key_item; - PK11SymKey *symkey = NULL; - SECItem *param = NULL; - PK11Context *ctx = NULL; - int out_len; /* not used, required by NSS */ - bool rv = FALSE; - - /* use internal slot for DES encryption (requires NSS to be initialized) */ - slot = PK11_GetInternalKeySlot(); - if(!slot) - return FALSE; - - /* expand the 56 bit key to 64 bit and wrap by NSS */ - extend_key_56_to_64(key_56, key); - key_item.data = (unsigned char *)key; - key_item.len = /* hard-wired */ 8; - symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_ENCRYPT, - &key_item, NULL); - if(!symkey) - goto fail; - - /* create DES encryption context */ - param = PK11_ParamFromIV(mech, /* no IV in ECB mode */ NULL); - if(!param) - goto fail; - ctx = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, symkey, param); - if(!ctx) - goto fail; - - /* perform the encryption */ - if(SECSuccess == PK11_CipherOp(ctx, out, &out_len, /* outbuflen */ 8, - (unsigned char *)in, /* inbuflen */ 8) - && SECSuccess == PK11_Finalize(ctx)) - rv = /* all OK */ TRUE; - -fail: - /* cleanup */ - if(ctx) - PK11_DestroyContext(ctx, PR_TRUE); - if(symkey) - PK11_FreeSymKey(symkey); - if(param) - SECITEM_FreeItem(param, PR_TRUE); - PK11_FreeSlot(slot); - return rv; -} - -#endif /* defined(USE_NSS) */ - -#endif /* defined(USE_SSLEAY) */ - - /* - * takes a 21 byte array and treats it as 3 56-bit DES keys. The - * 8 byte plaintext is encrypted with each key and the resulting 24 - * bytes are stored in the results array. - */ -static void lm_resp(const unsigned char *keys, - const unsigned char *plaintext, - unsigned char *results) -{ -#ifdef USE_SSLEAY - DES_key_schedule ks; - - setup_des_key(keys, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results, - DESKEY(ks), DES_ENCRYPT); - - setup_des_key(keys+7, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8), - DESKEY(ks), DES_ENCRYPT); - - setup_des_key(keys+14, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16), - DESKEY(ks), DES_ENCRYPT); -#elif defined(USE_GNUTLS) - gcry_cipher_hd_t des; - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(keys, &des); - gcry_cipher_encrypt(des, results, 8, plaintext, 8); - gcry_cipher_close(des); - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(keys+7, &des); - gcry_cipher_encrypt(des, results+8, 8, plaintext, 8); - gcry_cipher_close(des); - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(keys+14, &des); - gcry_cipher_encrypt(des, results+16, 8, plaintext, 8); - gcry_cipher_close(des); -#elif defined(USE_NSS) - encrypt_des(plaintext, results, keys); - encrypt_des(plaintext, results+8, keys+7); - encrypt_des(plaintext, results+16, keys+14); -#endif -} - - -/* - * Set up lanmanager hashed password - */ -static void mk_lm_hash(struct SessionHandle *data, - const char *password, - unsigned char *lmbuffer /* 21 bytes */) -{ - unsigned char pw[14]; - static const unsigned char magic[] = { - 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */ - }; - size_t len = CURLMIN(strlen(password), 14); - - Curl_strntoupper((char *)pw, password, len); - memset(&pw[len], 0, 14-len); - -#ifdef CURL_DOES_CONVERSIONS - /* - * The LanManager hashed password needs to be created using the - * password in the network encoding not the host encoding. - */ - if(data) - Curl_convert_to_network(data, (char *)pw, 14); -#else - (void)data; -#endif - - { - /* Create LanManager hashed password. */ - -#ifdef USE_SSLEAY - DES_key_schedule ks; - - setup_des_key(pw, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer, - DESKEY(ks), DES_ENCRYPT); - - setup_des_key(pw+7, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8), - DESKEY(ks), DES_ENCRYPT); -#elif defined(USE_GNUTLS) - gcry_cipher_hd_t des; - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(pw, &des); - gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8); - gcry_cipher_close(des); - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(pw+7, &des); - gcry_cipher_encrypt(des, lmbuffer+8, 8, magic, 8); - gcry_cipher_close(des); -#elif defined(USE_NSS) - encrypt_des(magic, lmbuffer, pw); - encrypt_des(magic, lmbuffer+8, pw+7); -#endif - - memset(lmbuffer + 16, 0, 21 - 16); - } -} - -#if USE_NTRESPONSES -static void ascii_to_unicode_le(unsigned char *dest, const char *src, - size_t srclen) -{ - size_t i; - for (i=0; itype_2) { - free(ntlm->type_2); - ntlm->type_2 = NULL; - } - if(ntlm->has_handles) { - s_pSecFn->DeleteSecurityContext(&ntlm->c_handle); - s_pSecFn->FreeCredentialsHandle(&ntlm->handle); - ntlm->has_handles = 0; - } - if(ntlm->p_identity) { - if(ntlm->identity.User) free(ntlm->identity.User); - if(ntlm->identity.Password) free(ntlm->identity.Password); - if(ntlm->identity.Domain) free(ntlm->identity.Domain); - ntlm->p_identity = NULL; - } -} - -#endif - -#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff) -#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \ - (((x) >>16)&0xff), (((x)>>24) & 0xff) - -#define HOSTNAME_MAX 1024 - -/* this is for creating ntlm header output */ -CURLcode Curl_output_ntlm(struct connectdata *conn, - bool proxy) -{ - const char *domain=""; /* empty */ - char host [HOSTNAME_MAX+ 1] = ""; /* empty */ -#ifndef USE_WINDOWS_SSPI - size_t domlen = strlen(domain); - size_t hostlen = strlen(host); - size_t hostoff; /* host name offset */ - size_t domoff; /* domain name offset */ -#endif - size_t size; - char *base64=NULL; - unsigned char ntlmbuf[1024]; /* enough, unless the user+host+domain is very - long */ - - /* point to the address of the pointer that holds the string to sent to the - server, which is for a plain host or for a HTTP proxy */ - char **allocuserpwd; - - /* point to the name and password for this */ - const char *userp; - const char *passwdp; - /* point to the correct struct with this */ - struct ntlmdata *ntlm; - struct auth *authp; - - DEBUGASSERT(conn); - DEBUGASSERT(conn->data); - -#ifdef USE_NSS - if(CURLE_OK != Curl_nss_force_init(conn->data)) - return CURLE_OUT_OF_MEMORY; -#endif - - if(proxy) { - allocuserpwd = &conn->allocptr.proxyuserpwd; - userp = conn->proxyuser; - passwdp = conn->proxypasswd; - ntlm = &conn->proxyntlm; - authp = &conn->data->state.authproxy; - } - else { - allocuserpwd = &conn->allocptr.userpwd; - userp = conn->user; - passwdp = conn->passwd; - ntlm = &conn->ntlm; - authp = &conn->data->state.authhost; - } - authp->done = FALSE; - - /* not set means empty */ - if(!userp) - userp=""; - - if(!passwdp) - passwdp=""; - -#ifdef USE_WINDOWS_SSPI - if (s_hSecDll == NULL) { - /* not thread safe and leaks - use curl_global_init() to avoid */ - CURLcode err = Curl_sspi_global_init(); - if (s_hSecDll == NULL) - return err; - } -#endif - - switch(ntlm->state) { - case NTLMSTATE_TYPE1: - default: /* for the weird cases we (re)start here */ -#ifdef USE_WINDOWS_SSPI - { - SecBuffer buf; - SecBufferDesc desc; - SECURITY_STATUS status; - ULONG attrs; - const char *user; - int domlen; - TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */ - - ntlm_sspi_cleanup(ntlm); - - user = strchr(userp, '\\'); - if(!user) - user = strchr(userp, '/'); - - if(user) { - domain = userp; - domlen = user - userp; - user++; - } - else { - user = userp; - domain = ""; - domlen = 0; - } - - if(user && *user) { - /* note: initialize all of this before doing the mallocs so that - * it can be cleaned up later without leaking memory. - */ - ntlm->p_identity = &ntlm->identity; - memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity)); - if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL) - return CURLE_OUT_OF_MEMORY; - ntlm->identity.UserLength = strlen(user); - if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL) - return CURLE_OUT_OF_MEMORY; - ntlm->identity.PasswordLength = strlen(passwdp); - if((ntlm->identity.Domain = malloc(domlen+1)) == NULL) - return CURLE_OUT_OF_MEMORY; - strncpy((char *)ntlm->identity.Domain, domain, domlen); - ntlm->identity.Domain[domlen] = '\0'; - ntlm->identity.DomainLength = domlen; - ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; - } - else { - ntlm->p_identity = NULL; - } - - if(s_pSecFn->AcquireCredentialsHandleA( - NULL, (char *)"NTLM", SECPKG_CRED_OUTBOUND, NULL, ntlm->p_identity, - NULL, NULL, &ntlm->handle, &tsDummy - ) != SEC_E_OK) { - return CURLE_OUT_OF_MEMORY; - } - - desc.ulVersion = SECBUFFER_VERSION; - desc.cBuffers = 1; - desc.pBuffers = &buf; - buf.cbBuffer = sizeof(ntlmbuf); - buf.BufferType = SECBUFFER_TOKEN; - buf.pvBuffer = ntlmbuf; - - status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, NULL, - (char *) host, - ISC_REQ_CONFIDENTIALITY | - ISC_REQ_REPLAY_DETECT | - ISC_REQ_CONNECTION, - 0, SECURITY_NETWORK_DREP, - NULL, 0, - &ntlm->c_handle, &desc, - &attrs, &tsDummy); - - if(status == SEC_I_COMPLETE_AND_CONTINUE || - status == SEC_I_CONTINUE_NEEDED) { - s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc); - } - else if(status != SEC_E_OK) { - s_pSecFn->FreeCredentialsHandle(&ntlm->handle); - return CURLE_RECV_ERROR; - } - - ntlm->has_handles = 1; - size = buf.cbBuffer; - } -#else - hostoff = 0; - domoff = hostoff + hostlen; /* This is 0: remember that host and domain - are empty */ - - /* Create and send a type-1 message: - - Index Description Content - 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" - (0x4e544c4d53535000) - 8 NTLM Message Type long (0x01000000) - 12 Flags long - 16 Supplied Domain security buffer(*) - 24 Supplied Workstation security buffer(*) - 32 start of data block - - */ -#if USE_NTLM2SESSION -#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY -#else -#define NTLM2FLAG 0 -#endif - snprintf((char *)ntlmbuf, sizeof(ntlmbuf), NTLMSSP_SIGNATURE "%c" - "\x01%c%c%c" /* 32-bit type = 1 */ - "%c%c%c%c" /* 32-bit NTLM flag field */ - "%c%c" /* domain length */ - "%c%c" /* domain allocated space */ - "%c%c" /* domain name offset */ - "%c%c" /* 2 zeroes */ - "%c%c" /* host length */ - "%c%c" /* host allocated space */ - "%c%c" /* host name offset */ - "%c%c" /* 2 zeroes */ - "%s" /* host name */ - "%s", /* domain string */ - 0, /* trailing zero */ - 0,0,0, /* part of type-1 long */ - - LONGQUARTET( - NTLMFLAG_NEGOTIATE_OEM| - NTLMFLAG_REQUEST_TARGET| - NTLMFLAG_NEGOTIATE_NTLM_KEY| - NTLM2FLAG| - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN - ), - SHORTPAIR(domlen), - SHORTPAIR(domlen), - SHORTPAIR(domoff), - 0,0, - SHORTPAIR(hostlen), - SHORTPAIR(hostlen), - SHORTPAIR(hostoff), - 0,0, - host /* this is empty */, domain /* this is empty */); - - /* initial packet length */ - size = 32 + hostlen + domlen; -#endif - - DEBUG_OUT({ - fprintf(stderr, "**** TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", - LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM| - NTLMFLAG_REQUEST_TARGET| - NTLMFLAG_NEGOTIATE_NTLM_KEY| - NTLM2FLAG| - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), - NTLMFLAG_NEGOTIATE_OEM| - NTLMFLAG_REQUEST_TARGET| - NTLMFLAG_NEGOTIATE_NTLM_KEY| - NTLM2FLAG| - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); - print_flags(stderr, - NTLMFLAG_NEGOTIATE_OEM| - NTLMFLAG_REQUEST_TARGET| - NTLMFLAG_NEGOTIATE_NTLM_KEY| - NTLM2FLAG| - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); - fprintf(stderr, "\n****\n"); - }); - - /* now size is the size of the base64 encoded package size */ - size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64); - - if(size >0 ) { - Curl_safefree(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", - proxy?"Proxy-":"", - base64); - DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); - free(base64); - } - else - return CURLE_OUT_OF_MEMORY; /* FIX TODO */ - - break; - - case NTLMSTATE_TYPE2: - /* We received the type-2 message already, create a type-3 message: - - Index Description Content - 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" - (0x4e544c4d53535000) - 8 NTLM Message Type long (0x03000000) - 12 LM/LMv2 Response security buffer(*) - 20 NTLM/NTLMv2 Response security buffer(*) - 28 Domain Name security buffer(*) - 36 User Name security buffer(*) - 44 Workstation Name security buffer(*) - (52) Session Key (optional) security buffer(*) - (60) Flags (optional) long - 52 (64) start of data block - - */ - - { -#ifdef USE_WINDOWS_SSPI - SecBuffer type_2, type_3; - SecBufferDesc type_2_desc, type_3_desc; - SECURITY_STATUS status; - ULONG attrs; - TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */ - - type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION; - type_2_desc.cBuffers = type_3_desc.cBuffers = 1; - type_2_desc.pBuffers = &type_2; - type_3_desc.pBuffers = &type_3; - - type_2.BufferType = SECBUFFER_TOKEN; - type_2.pvBuffer = ntlm->type_2; - type_2.cbBuffer = ntlm->n_type_2; - type_3.BufferType = SECBUFFER_TOKEN; - type_3.pvBuffer = ntlmbuf; - type_3.cbBuffer = sizeof(ntlmbuf); - - status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, &ntlm->c_handle, - (char *) host, - ISC_REQ_CONFIDENTIALITY | - ISC_REQ_REPLAY_DETECT | - ISC_REQ_CONNECTION, - 0, SECURITY_NETWORK_DREP, &type_2_desc, - 0, &ntlm->c_handle, &type_3_desc, - &attrs, &tsDummy); - - if(status != SEC_E_OK) - return CURLE_RECV_ERROR; - - size = type_3.cbBuffer; - - ntlm_sspi_cleanup(ntlm); - -#else - int lmrespoff; - unsigned char lmresp[24]; /* fixed-size */ -#if USE_NTRESPONSES - int ntrespoff; - unsigned char ntresp[24]; /* fixed-size */ -#endif - size_t useroff; - const char *user; - size_t userlen; - - user = strchr(userp, '\\'); - if(!user) - user = strchr(userp, '/'); - - if(user) { - domain = userp; - domlen = (user - domain); - user++; - } - else - user = userp; - userlen = strlen(user); - - if(Curl_gethostname(host, HOSTNAME_MAX)) { - infof(conn->data, "gethostname() failed, continuing without!"); - hostlen = 0; - } - else { - /* If the workstation if configured with a full DNS name (i.e. - * workstation.somewhere.net) gethostname() returns the fully qualified - * name, which NTLM doesn't like. - */ - char *dot = strchr(host, '.'); - if(dot) - *dot = '\0'; - hostlen = strlen(host); - } - -#if USE_NTLM2SESSION - /* We don't support NTLM2 if we don't have USE_NTRESPONSES */ - if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { - unsigned char ntbuffer[0x18]; - unsigned char tmp[0x18]; - unsigned char md5sum[MD5_DIGEST_LENGTH]; - unsigned char entropy[8]; - - /* Need to create 8 bytes random data */ -#ifdef USE_SSLEAY - MD5_CTX MD5pw; - Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */ - RAND_bytes(entropy,8); -#elif defined(USE_GNUTLS) - gcry_md_hd_t MD5pw; - Curl_gtls_seed(conn->data); /* Initiate the seed if not already done */ - gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM); -#elif defined(USE_NSS) - PK11Context *MD5pw; - unsigned int outlen; - Curl_nss_seed(conn->data); /* Initiate the seed if not already done */ - PK11_GenerateRandom(entropy, 8); -#endif - - /* 8 bytes random data as challenge in lmresp */ - memcpy(lmresp,entropy,8); - /* Pad with zeros */ - memset(lmresp+8,0,0x10); - - /* Fill tmp with challenge(nonce?) + entropy */ - memcpy(tmp,&ntlm->nonce[0],8); - memcpy(tmp+8,entropy,8); - -#ifdef USE_SSLEAY - MD5_Init(&MD5pw); - MD5_Update(&MD5pw, tmp, 16); - MD5_Final(md5sum, &MD5pw); -#elif defined(USE_GNUTLS) - gcry_md_open(&MD5pw, GCRY_MD_MD5, 0); - gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH); - memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH); - gcry_md_close(MD5pw); -#elif defined(USE_NSS) - MD5pw = PK11_CreateDigestContext(SEC_OID_MD5); - PK11_DigestOp(MD5pw, tmp, 16); - PK11_DigestFinal(MD5pw, md5sum, &outlen, MD5_DIGEST_LENGTH); - PK11_DestroyContext(MD5pw, PR_TRUE); -#endif - - /* We shall only use the first 8 bytes of md5sum, - but the des code in lm_resp only encrypt the first 8 bytes */ - if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY) - return CURLE_OUT_OF_MEMORY; - lm_resp(ntbuffer, md5sum, ntresp); - - /* End of NTLM2 Session code */ - } - else -#endif - { - -#if USE_NTRESPONSES - unsigned char ntbuffer[0x18]; -#endif - unsigned char lmbuffer[0x18]; - -#if USE_NTRESPONSES - if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY) - return CURLE_OUT_OF_MEMORY; - lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); -#endif - - mk_lm_hash(conn->data, passwdp, lmbuffer); - lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); - /* A safer but less compatible alternative is: - * lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); - * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ - } - - lmrespoff = 64; /* size of the message header */ -#if USE_NTRESPONSES - ntrespoff = lmrespoff + 0x18; - domoff = ntrespoff + 0x18; -#else - domoff = lmrespoff + 0x18; -#endif - useroff = domoff + domlen; - hostoff = useroff + userlen; - - /* - * In the case the server sets the flag NTLMFLAG_NEGOTIATE_UNICODE, we - * need to filter it off because libcurl doesn't UNICODE encode the - * strings it packs into the NTLM authenticate packet. - */ - ntlm->flags &= ~NTLMFLAG_NEGOTIATE_UNICODE; - - /* Create the big type-3 message binary blob */ - size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf), - NTLMSSP_SIGNATURE "%c" - "\x03%c%c%c" /* type-3, 32 bits */ - - "%c%c" /* LanManager length */ - "%c%c" /* LanManager allocated space */ - "%c%c" /* LanManager offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* NT-response length */ - "%c%c" /* NT-response allocated space */ - "%c%c" /* NT-response offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* domain length */ - "%c%c" /* domain allocated space */ - "%c%c" /* domain name offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* user length */ - "%c%c" /* user allocated space */ - "%c%c" /* user offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* host length */ - "%c%c" /* host allocated space */ - "%c%c" /* host offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* session key length (unknown purpose) */ - "%c%c" /* session key allocated space (unknown purpose) */ - "%c%c" /* session key offset (unknown purpose) */ - "%c%c" /* 2 zeroes */ - - "%c%c%c%c" /* flags */ - - /* domain string */ - /* user string */ - /* host string */ - /* LanManager response */ - /* NT response */ - , - 0, /* zero termination */ - 0,0,0, /* type-3 long, the 24 upper bits */ - - SHORTPAIR(0x18), /* LanManager response length, twice */ - SHORTPAIR(0x18), - SHORTPAIR(lmrespoff), - 0x0, 0x0, - -#if USE_NTRESPONSES - SHORTPAIR(0x18), /* NT-response length, twice */ - SHORTPAIR(0x18), - SHORTPAIR(ntrespoff), - 0x0, 0x0, -#else - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, -#endif - SHORTPAIR(domlen), - SHORTPAIR(domlen), - SHORTPAIR(domoff), - 0x0, 0x0, - - SHORTPAIR(userlen), - SHORTPAIR(userlen), - SHORTPAIR(useroff), - 0x0, 0x0, - - SHORTPAIR(hostlen), - SHORTPAIR(hostlen), - SHORTPAIR(hostoff), - 0x0, 0x0, - - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - - LONGQUARTET(ntlm->flags)); - DEBUGASSERT(size==64); - - DEBUGASSERT(size == (size_t)lmrespoff); - /* We append the binary hashes */ - if(size < (sizeof(ntlmbuf) - 0x18)) { - memcpy(&ntlmbuf[size], lmresp, 0x18); - size += 0x18; - } - - DEBUG_OUT({ - fprintf(stderr, "**** TYPE3 header lmresp="); - print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18); - }); - -#if USE_NTRESPONSES - if(size < (sizeof(ntlmbuf) - 0x18)) { - DEBUGASSERT(size == (size_t)ntrespoff); - memcpy(&ntlmbuf[size], ntresp, 0x18); - size += 0x18; - } - - DEBUG_OUT({ - fprintf(stderr, "\n ntresp="); - print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18); - }); - -#endif - - DEBUG_OUT({ - fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", - LONGQUARTET(ntlm->flags), ntlm->flags); - print_flags(stderr, ntlm->flags); - fprintf(stderr, "\n****\n"); - }); - - - /* Make sure that the domain, user and host strings fit in the target - buffer before we copy them there. */ - if(size + userlen + domlen + hostlen >= sizeof(ntlmbuf)) { - failf(conn->data, "user + domain + host name too big"); - return CURLE_OUT_OF_MEMORY; - } - - DEBUGASSERT(size == domoff); - memcpy(&ntlmbuf[size], domain, domlen); - size += domlen; - - DEBUGASSERT(size == useroff); - memcpy(&ntlmbuf[size], user, userlen); - size += userlen; - - DEBUGASSERT(size == hostoff); - memcpy(&ntlmbuf[size], host, hostlen); - size += hostlen; - -#ifdef CURL_DOES_CONVERSIONS - /* convert domain, user, and host to ASCII but leave the rest as-is */ - if(CURLE_OK != Curl_convert_to_network(conn->data, - (char *)&ntlmbuf[domoff], - size-domoff)) { - return CURLE_CONV_FAILED; - } -#endif /* CURL_DOES_CONVERSIONS */ - -#endif - - /* convert the binary blob into base64 */ - size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64); - - if(size >0 ) { - Curl_safefree(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", - proxy?"Proxy-":"", - base64); - DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); - free(base64); - } - else - return CURLE_OUT_OF_MEMORY; /* FIX TODO */ - - ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */ - authp->done = TRUE; - } - break; - - case NTLMSTATE_TYPE3: - /* connection is already authenticated, - * don't send a header in future requests */ - if(*allocuserpwd) { - free(*allocuserpwd); - *allocuserpwd=NULL; - } - authp->done = TRUE; - break; - } - - return CURLE_OK; -} - - -void -Curl_ntlm_cleanup(struct connectdata *conn) -{ -#ifdef USE_WINDOWS_SSPI - ntlm_sspi_cleanup(&conn->ntlm); - ntlm_sspi_cleanup(&conn->proxyntlm); -#else - (void)conn; -#endif -} - - -#endif /* USE_NTLM */ -#endif /* !CURL_DISABLE_HTTP */ diff --git a/project/jni/curl/lib/http_proxy.c b/project/jni/curl/lib/http_proxy.c new file mode 100644 index 000000000..e082ba291 --- /dev/null +++ b/project/jni/curl/lib/http_proxy.c @@ -0,0 +1,590 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP) + +#include "urldata.h" +#include +#include "http_proxy.h" +#include "sendf.h" +#include "http.h" +#include "url.h" +#include "select.h" +#include "rawstr.h" +#include "progress.h" +#include "non-ascii.h" +#include "connect.h" +#include "curl_printf.h" +#include "curlx.h" + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +CURLcode Curl_proxy_connect(struct connectdata *conn) +{ + if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { +#ifndef CURL_DISABLE_PROXY + /* for [protocol] tunneled through HTTP proxy */ + struct HTTP http_proxy; + void *prot_save; + CURLcode result; + + /* BLOCKING */ + /* We want "seamless" operations through HTTP proxy tunnel */ + + /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the + * member conn->proto.http; we want [protocol] through HTTP and we have + * to change the member temporarily for connecting to the HTTP + * proxy. After Curl_proxyCONNECT we have to set back the member to the + * original pointer + * + * This function might be called several times in the multi interface case + * if the proxy's CONNTECT response is not instant. + */ + prot_save = conn->data->req.protop; + memset(&http_proxy, 0, sizeof(http_proxy)); + conn->data->req.protop = &http_proxy; + connkeep(conn, "HTTP proxy CONNECT"); + result = Curl_proxyCONNECT(conn, FIRSTSOCKET, + conn->host.name, conn->remote_port, FALSE); + conn->data->req.protop = prot_save; + if(CURLE_OK != result) + return result; + Curl_safefree(conn->allocptr.proxyuserpwd); +#else + return CURLE_NOT_BUILT_IN; +#endif + } + /* no HTTP tunnel proxy, just return */ + return CURLE_OK; +} + +/* + * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This + * function will issue the necessary commands to get a seamless tunnel through + * this proxy. After that, the socket can be used just as a normal socket. + * + * 'blocking' set to TRUE means that this function will do the entire CONNECT + * + response in a blocking fashion. Should be avoided! + */ + +CURLcode Curl_proxyCONNECT(struct connectdata *conn, + int sockindex, + const char *hostname, + int remote_port, + bool blocking) +{ + int subversion=0; + struct SessionHandle *data=conn->data; + struct SingleRequest *k = &data->req; + CURLcode result; + curl_socket_t tunnelsocket = conn->sock[sockindex]; + curl_off_t cl=0; + bool closeConnection = FALSE; + bool chunked_encoding = FALSE; + long check; + +#define SELECT_OK 0 +#define SELECT_ERROR 1 +#define SELECT_TIMEOUT 2 + int error = SELECT_OK; + + if(conn->tunnel_state[sockindex] == TUNNEL_COMPLETE) + return CURLE_OK; /* CONNECT is already completed */ + + conn->bits.proxy_connect_closed = FALSE; + + do { + if(TUNNEL_INIT == conn->tunnel_state[sockindex]) { + /* BEGIN CONNECT PHASE */ + char *host_port; + Curl_send_buffer *req_buffer; + + infof(data, "Establish HTTP proxy tunnel to %s:%hu\n", + hostname, remote_port); + + /* This only happens if we've looped here due to authentication + reasons, and we don't really use the newly cloned URL here + then. Just free() it. */ + free(data->req.newurl); + data->req.newurl = NULL; + + /* initialize a dynamic send-buffer */ + req_buffer = Curl_add_buffer_init(); + + if(!req_buffer) + return CURLE_OUT_OF_MEMORY; + + host_port = aprintf("%s:%hu", hostname, remote_port); + if(!host_port) { + Curl_add_buffer_free(req_buffer); + return CURLE_OUT_OF_MEMORY; + } + + /* Setup the proxy-authorization header, if any */ + result = Curl_http_output_auth(conn, "CONNECT", host_port, TRUE); + + free(host_port); + + if(!result) { + char *host=(char *)""; + const char *useragent=""; + const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ? + "1.0" : "1.1"; + char *hostheader= /* host:port with IPv6 support */ + aprintf("%s%s%s:%hu", conn->bits.ipv6_ip?"[":"", + hostname, conn->bits.ipv6_ip?"]":"", + remote_port); + if(!hostheader) { + Curl_add_buffer_free(req_buffer); + return CURLE_OUT_OF_MEMORY; + } + + if(!Curl_checkProxyheaders(conn, "Host:")) { + host = aprintf("Host: %s\r\n", hostheader); + if(!host) { + free(hostheader); + Curl_add_buffer_free(req_buffer); + return CURLE_OUT_OF_MEMORY; + } + } + if(!Curl_checkProxyheaders(conn, "User-Agent:") && + data->set.str[STRING_USERAGENT]) + useragent = conn->allocptr.uagent; + + result = + Curl_add_bufferf(req_buffer, + "CONNECT %s HTTP/%s\r\n" + "%s" /* Host: */ + "%s" /* Proxy-Authorization */ + "%s", /* User-Agent */ + hostheader, + http, + host, + conn->allocptr.proxyuserpwd? + conn->allocptr.proxyuserpwd:"", + useragent); + + if(host && *host) + free(host); + free(hostheader); + + if(!result) + result = Curl_add_custom_headers(conn, TRUE, req_buffer); + + if(!result) + /* CRLF terminate the request */ + result = Curl_add_bufferf(req_buffer, "\r\n"); + + if(!result) { + /* Send the connect request to the proxy */ + /* BLOCKING */ + result = + Curl_add_buffer_send(req_buffer, conn, + &data->info.request_size, 0, sockindex); + } + req_buffer = NULL; + if(result) + failf(data, "Failed sending CONNECT to proxy"); + } + + Curl_add_buffer_free(req_buffer); + if(result) + return result; + + conn->tunnel_state[sockindex] = TUNNEL_CONNECT; + } /* END CONNECT PHASE */ + + check = Curl_timeleft(data, NULL, TRUE); + if(check <= 0) { + failf(data, "Proxy CONNECT aborted due to timeout"); + return CURLE_RECV_ERROR; + } + + if(!blocking) { + if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0)) + /* return so we'll be called again polling-style */ + return CURLE_OK; + else { + DEBUGF(infof(data, + "Read response immediately from proxy CONNECT\n")); + } + } + + /* at this point, the tunnel_connecting phase is over. */ + + { /* READING RESPONSE PHASE */ + size_t nread; /* total size read */ + int perline; /* count bytes per line */ + int keepon=TRUE; + ssize_t gotbytes; + char *ptr; + char *line_start; + + ptr=data->state.buffer; + line_start = ptr; + + nread=0; + perline=0; + + while((nreadstate.buffer+BUFSIZE+1); + result = Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, + &gotbytes); + if(result==CURLE_AGAIN) + continue; /* go loop yourself */ + else if(result) + keepon = FALSE; + else if(gotbytes <= 0) { + keepon = FALSE; + if(data->set.proxyauth && data->state.authproxy.avail) { + /* proxy auth was requested and there was proxy auth available, + then deem this as "mere" proxy disconnect */ + conn->bits.proxy_connect_closed = TRUE; + infof(data, "Proxy CONNECT connection closed\n"); + } + else { + error = SELECT_ERROR; + failf(data, "Proxy CONNECT aborted"); + } + } + else { + /* + * We got a whole chunk of data, which can be anything from one + * byte to a set of lines and possibly just a piece of the last + * line. + */ + int i; + + nread += gotbytes; + + if(keepon > TRUE) { + /* This means we are currently ignoring a response-body */ + + nread = 0; /* make next read start over in the read buffer */ + ptr=data->state.buffer; + if(cl) { + /* A Content-Length based body: simply count down the counter + and make sure to break out of the loop when we're done! */ + cl -= gotbytes; + if(cl<=0) { + keepon = FALSE; + break; + } + } + else { + /* chunked-encoded body, so we need to do the chunked dance + properly to know when the end of the body is reached */ + CHUNKcode r; + ssize_t tookcareof=0; + + /* now parse the chunked piece of data so that we can + properly tell when the stream ends */ + r = Curl_httpchunk_read(conn, ptr, gotbytes, &tookcareof); + if(r == CHUNKE_STOP) { + /* we're done reading chunks! */ + infof(data, "chunk reading DONE\n"); + keepon = FALSE; + /* we did the full CONNECT treatment, go COMPLETE */ + conn->tunnel_state[sockindex] = TUNNEL_COMPLETE; + } + else + infof(data, "Read %zd bytes of chunk, continue\n", + tookcareof); + } + } + else + for(i = 0; i < gotbytes; ptr++, i++) { + perline++; /* amount of bytes in this line so far */ + if(*ptr == 0x0a) { + char letter; + int writetype; + + /* convert from the network encoding */ + result = Curl_convert_from_network(data, line_start, + perline); + /* Curl_convert_from_network calls failf if unsuccessful */ + if(result) + return result; + + /* output debug if that is requested */ + if(data->set.verbose) + Curl_debug(data, CURLINFO_HEADER_IN, + line_start, (size_t)perline, conn); + + /* send the header to the callback */ + writetype = CLIENTWRITE_HEADER; + if(data->set.include_header) + writetype |= CLIENTWRITE_BODY; + + result = Curl_client_write(conn, writetype, line_start, + perline); + + data->info.header_size += (long)perline; + data->req.headerbytecount += (long)perline; + + if(result) + return result; + + /* Newlines are CRLF, so the CR is ignored as the line isn't + really terminated until the LF comes. Treat a following CR + as end-of-headers as well.*/ + + if(('\r' == line_start[0]) || + ('\n' == line_start[0])) { + /* end of response-headers from the proxy */ + nread = 0; /* make next read start over in the read + buffer */ + ptr=data->state.buffer; + if((407 == k->httpcode) && !data->state.authproblem) { + /* If we get a 407 response code with content length + when we have no auth problem, we must ignore the + whole response-body */ + keepon = 2; + + if(cl) { + infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T + " bytes of response-body\n", cl); + + /* remove the remaining chunk of what we already + read */ + cl -= (gotbytes - i); + + if(cl<=0) + /* if the whole thing was already read, we are done! + */ + keepon=FALSE; + } + else if(chunked_encoding) { + CHUNKcode r; + /* We set ignorebody true here since the chunked + decoder function will acknowledge that. Pay + attention so that this is cleared again when this + function returns! */ + k->ignorebody = TRUE; + infof(data, "%zd bytes of chunk left\n", gotbytes-i); + + if(line_start[1] == '\n') { + /* this can only be a LF if the letter at index 0 + was a CR */ + line_start++; + i++; + } + + /* now parse the chunked piece of data so that we can + properly tell when the stream ends */ + r = Curl_httpchunk_read(conn, line_start+1, + gotbytes -i, &gotbytes); + if(r == CHUNKE_STOP) { + /* we're done reading chunks! */ + infof(data, "chunk reading DONE\n"); + keepon = FALSE; + /* we did the full CONNECT treatment, go to + COMPLETE */ + conn->tunnel_state[sockindex] = TUNNEL_COMPLETE; + } + else + infof(data, "Read %zd bytes of chunk, continue\n", + gotbytes); + } + else { + /* without content-length or chunked encoding, we + can't keep the connection alive since the close is + the end signal so we bail out at once instead */ + keepon=FALSE; + } + } + else { + keepon = FALSE; + if(200 == data->info.httpproxycode) { + if(gotbytes - (i+1)) + failf(data, "Proxy CONNECT followed by %zd bytes " + "of opaque data. Data ignored (known bug #39)", + gotbytes - (i+1)); + } + } + /* we did the full CONNECT treatment, go to COMPLETE */ + conn->tunnel_state[sockindex] = TUNNEL_COMPLETE; + break; /* breaks out of for-loop, not switch() */ + } + + /* keep a backup of the position we are about to blank */ + letter = line_start[perline]; + line_start[perline]=0; /* zero terminate the buffer */ + if((checkprefix("WWW-Authenticate:", line_start) && + (401 == k->httpcode)) || + (checkprefix("Proxy-authenticate:", line_start) && + (407 == k->httpcode))) { + + bool proxy = (k->httpcode == 407) ? TRUE : FALSE; + char *auth = Curl_copy_header_value(line_start); + if(!auth) + return CURLE_OUT_OF_MEMORY; + + result = Curl_http_input_auth(conn, proxy, auth); + + free(auth); + + if(result) + return result; + } + else if(checkprefix("Content-Length:", line_start)) { + cl = curlx_strtoofft(line_start + + strlen("Content-Length:"), NULL, 10); + } + else if(Curl_compareheader(line_start, + "Connection:", "close")) + closeConnection = TRUE; + else if(Curl_compareheader(line_start, + "Transfer-Encoding:", + "chunked")) { + infof(data, "CONNECT responded chunked\n"); + chunked_encoding = TRUE; + /* init our chunky engine */ + Curl_httpchunk_init(conn); + } + else if(Curl_compareheader(line_start, + "Proxy-Connection:", "close")) + closeConnection = TRUE; + else if(2 == sscanf(line_start, "HTTP/1.%d %d", + &subversion, + &k->httpcode)) { + /* store the HTTP code from the proxy */ + data->info.httpproxycode = k->httpcode; + } + /* put back the letter we blanked out before */ + line_start[perline]= letter; + + perline=0; /* line starts over here */ + line_start = ptr+1; /* this skips the zero byte we wrote */ + } + } + } + break; + } /* switch */ + if(Curl_pgrsUpdate(conn)) + return CURLE_ABORTED_BY_CALLBACK; + } /* while there's buffer left and loop is requested */ + + if(error) + return CURLE_RECV_ERROR; + + if(data->info.httpproxycode != 200) { + /* Deal with the possibly already received authenticate + headers. 'newurl' is set to a new URL if we must loop. */ + result = Curl_http_auth_act(conn); + if(result) + return result; + + if(conn->bits.close) + /* the connection has been marked for closure, most likely in the + Curl_http_auth_act() function and thus we can kill it at once + below + */ + closeConnection = TRUE; + } + + if(closeConnection && data->req.newurl) { + /* Connection closed by server. Don't use it anymore */ + Curl_closesocket(conn, conn->sock[sockindex]); + conn->sock[sockindex] = CURL_SOCKET_BAD; + break; + } + } /* END READING RESPONSE PHASE */ + + /* If we are supposed to continue and request a new URL, which basically + * means the HTTP authentication is still going on so if the tunnel + * is complete we start over in INIT state */ + if(data->req.newurl && + (TUNNEL_COMPLETE == conn->tunnel_state[sockindex])) { + conn->tunnel_state[sockindex] = TUNNEL_INIT; + infof(data, "TUNNEL_STATE switched to: %d\n", + conn->tunnel_state[sockindex]); + } + + } while(data->req.newurl); + + if(200 != data->req.httpcode) { + if(closeConnection && data->req.newurl) { + conn->bits.proxy_connect_closed = TRUE; + infof(data, "Connect me again please\n"); + } + else { + free(data->req.newurl); + data->req.newurl = NULL; + /* failure, close this connection to avoid re-use */ + connclose(conn, "proxy CONNECT failure"); + Curl_closesocket(conn, conn->sock[sockindex]); + conn->sock[sockindex] = CURL_SOCKET_BAD; + } + + /* to back to init state */ + conn->tunnel_state[sockindex] = TUNNEL_INIT; + + if(conn->bits.proxy_connect_closed) + /* this is not an error, just part of the connection negotiation */ + return CURLE_OK; + else { + failf(data, "Received HTTP code %d from proxy after CONNECT", + data->req.httpcode); + return CURLE_RECV_ERROR; + } + } + + conn->tunnel_state[sockindex] = TUNNEL_COMPLETE; + + /* If a proxy-authorization header was used for the proxy, then we should + make sure that it isn't accidentally used for the document request + after we've connected. So let's free and clear it here. */ + Curl_safefree(conn->allocptr.proxyuserpwd); + conn->allocptr.proxyuserpwd = NULL; + + data->state.authproxy.done = TRUE; + + infof (data, "Proxy replied OK to CONNECT request\n"); + data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */ + conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the + document request */ + return CURLE_OK; +} +#endif /* CURL_DISABLE_PROXY */ diff --git a/project/jni/curl/lib/http_proxy.h b/project/jni/curl/lib/http_proxy.h new file mode 100644 index 000000000..fd0433033 --- /dev/null +++ b/project/jni/curl/lib/http_proxy.h @@ -0,0 +1,42 @@ +#ifndef HEADER_CURL_HTTP_PROXY_H +#define HEADER_CURL_HTTP_PROXY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP) +/* ftp can use this as well */ +CURLcode Curl_proxyCONNECT(struct connectdata *conn, + int tunnelsocket, + const char *hostname, int remote_port, + bool blocking); + +/* Default proxy timeout in milliseconds */ +#define PROXY_TIMEOUT (3600*1000) + +CURLcode Curl_proxy_connect(struct connectdata *conn); + +#else +#define Curl_proxyCONNECT(x,y,z,w,v) CURLE_NOT_BUILT_IN +#define Curl_proxy_connect(x) CURLE_OK +#endif + +#endif /* HEADER_CURL_HTTP_PROXY_H */ diff --git a/project/jni/curl/lib/idn_win32.c b/project/jni/curl/lib/idn_win32.c new file mode 100644 index 000000000..8dc300b36 --- /dev/null +++ b/project/jni/curl/lib/idn_win32.c @@ -0,0 +1,111 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + + /* + * IDN conversions using Windows kernel32 and normaliz libraries. + */ + +#include "curl_setup.h" + +#ifdef USE_WIN32_IDN + +#include "curl_multibyte.h" +#include "curl_memory.h" +#include "warnless.h" + + /* The last #include file should be: */ +#include "memdebug.h" + +#ifdef WANT_IDN_PROTOTYPES +# if defined(_SAL_VERSION) +WINNORMALIZEAPI int WINAPI +IdnToAscii(_In_ DWORD dwFlags, + _In_reads_(cchUnicodeChar) LPCWSTR lpUnicodeCharStr, + _In_ int cchUnicodeChar, + _Out_writes_opt_(cchASCIIChar) LPWSTR lpASCIICharStr, + _In_ int cchASCIIChar); +WINNORMALIZEAPI int WINAPI +IdnToUnicode(_In_ DWORD dwFlags, + _In_reads_(cchASCIIChar) LPCWSTR lpASCIICharStr, + _In_ int cchASCIIChar, + _Out_writes_opt_(cchUnicodeChar) LPWSTR lpUnicodeCharStr, + _In_ int cchUnicodeChar); +# else +WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags, + const WCHAR *lpUnicodeCharStr, + int cchUnicodeChar, + WCHAR *lpASCIICharStr, + int cchASCIIChar); +WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags, + const WCHAR *lpASCIICharStr, + int cchASCIIChar, + WCHAR *lpUnicodeCharStr, + int cchUnicodeChar); +# endif +#endif + +#define IDN_MAX_LENGTH 255 + +bool curl_win32_idn_to_ascii(const char *in, char **out); +bool curl_win32_ascii_to_idn(const char *in, char **out); + +bool curl_win32_idn_to_ascii(const char *in, char **out) +{ + bool success = FALSE; + + wchar_t *in_w = Curl_convert_UTF8_to_wchar(in); + if(in_w) { + wchar_t punycode[IDN_MAX_LENGTH]; + int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH); + free(in_w); + if(chars) { + *out = Curl_convert_wchar_to_UTF8(punycode); + if(*out) + success = TRUE; + } + } + + return success; +} + +bool curl_win32_ascii_to_idn(const char *in, char **out) +{ + bool success = FALSE; + + wchar_t *in_w = Curl_convert_UTF8_to_wchar(in); + if(in_w) { + size_t in_len = wcslen(in_w) + 1; + wchar_t unicode[IDN_MAX_LENGTH]; + int chars = IdnToUnicode(0, in_w, curlx_uztosi(in_len), + unicode, IDN_MAX_LENGTH); + free(in_w); + if(chars) { + *out = Curl_convert_wchar_to_UTF8(unicode); + if(*out) + success = TRUE; + } + } + + return success; +} + +#endif /* USE_WIN32_IDN */ diff --git a/project/jni/curl/lib/if2ip.c b/project/jni/curl/lib/if2ip.c index 19504d1fd..63bea541d 100644 --- a/project/jni/curl/lib/if2ip.c +++ b/project/jni/curl/lib/if2ip.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,14 +20,8 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef HAVE_SYS_SOCKET_H -# include -#endif #ifdef HAVE_NETINET_IN_H # include #endif @@ -59,9 +53,7 @@ #include "inet_ntop.h" #include "strequal.h" #include "if2ip.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -69,92 +61,213 @@ /* ------------------------------------------------------------------ */ +/* Return the scope of the given address. */ +unsigned int Curl_ipv6_scope(const struct sockaddr *sa) +{ +#ifndef ENABLE_IPV6 + (void) sa; +#else + if(sa->sa_family == AF_INET6) { + const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *)(void *) sa; + const unsigned char * b = sa6->sin6_addr.s6_addr; + unsigned short w = (unsigned short) ((b[0] << 8) | b[1]); + + switch(w & 0xFFC0) { + case 0xFE80: + return IPV6_SCOPE_LINKLOCAL; + case 0xFEC0: + return IPV6_SCOPE_SITELOCAL; + case 0x0000: + w = b[1] | b[2] | b[3] | b[4] | b[5] | b[6] | b[7] | b[8] | b[9] | + b[10] | b[11] | b[12] | b[13] | b[14]; + if(w || b[15] != 0x01) + break; + return IPV6_SCOPE_NODELOCAL; + default: + break; + } + } +#endif + + return IPV6_SCOPE_GLOBAL; +} + + #if defined(HAVE_GETIFADDRS) -char *Curl_if2ip(int af, const char *interface, char *buf, int buf_size) +bool Curl_if_is_interface_name(const char *interf) { - struct ifaddrs *iface, *head; - char *ip=NULL; + bool result = FALSE; - if (getifaddrs(&head) >= 0) { - for (iface=head; iface != NULL; iface=iface->ifa_next) { - if ((iface->ifa_addr != NULL) && - (iface->ifa_addr->sa_family == af) && - curl_strequal(iface->ifa_name, interface)) { - void *addr; - char scope[12]=""; -#ifdef ENABLE_IPV6 - if (af == AF_INET6) { - unsigned int scopeid = 0; - addr = &((struct sockaddr_in6 *)iface->ifa_addr)->sin6_addr; -#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID - /* Include the scope of this interface as part of the address */ - scopeid = ((struct sockaddr_in6 *)iface->ifa_addr)->sin6_scope_id; -#endif - if (scopeid) - snprintf(scope, sizeof(scope), "%%%u", scopeid); - } - else -#endif - addr = &((struct sockaddr_in *)iface->ifa_addr)->sin_addr; - ip = (char *) Curl_inet_ntop(af, addr, buf, buf_size); - strlcat(buf, scope, buf_size); + struct ifaddrs *iface, *head; + + if(getifaddrs(&head) >= 0) { + for(iface=head; iface != NULL; iface=iface->ifa_next) { + if(curl_strequal(iface->ifa_name, interf)) { + result = TRUE; break; } } freeifaddrs(head); } - return ip; + return result; +} + +if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, + unsigned int remote_scope_id, const char *interf, + char *buf, int buf_size) +{ + struct ifaddrs *iface, *head; + if2ip_result_t res = IF2IP_NOT_FOUND; + +#ifndef ENABLE_IPV6 + (void) remote_scope; + +#ifndef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID + (void) remote_scope_id; +#endif + +#endif + + if(getifaddrs(&head) >= 0) { + for(iface = head; iface != NULL; iface=iface->ifa_next) { + if(iface->ifa_addr != NULL) { + if(iface->ifa_addr->sa_family == af) { + if(curl_strequal(iface->ifa_name, interf)) { + void *addr; + char *ip; + char scope[12] = ""; + char ipstr[64]; +#ifdef ENABLE_IPV6 + if(af == AF_INET6) { + unsigned int scopeid = 0; + unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr); + + if(ifscope != remote_scope) { + /* We are interested only in interface addresses whose + scope matches the remote address we want to + connect to: global for global, link-local for + link-local, etc... */ + if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED; + continue; + } + + addr = + &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr; +#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID + /* Include the scope of this interface as part of the address */ + scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr) + ->sin6_scope_id; + + /* If given, scope id should match. */ + if(remote_scope_id && scopeid != remote_scope_id) { + if(res == IF2IP_NOT_FOUND) + res = IF2IP_AF_NOT_SUPPORTED; + + continue; + } +#endif + if(scopeid) + snprintf(scope, sizeof(scope), "%%%u", scopeid); + } + else +#endif + addr = + &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr; + res = IF2IP_FOUND; + ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr)); + snprintf(buf, buf_size, "%s%s", ip, scope); + break; + } + } + else if((res == IF2IP_NOT_FOUND) && + curl_strequal(iface->ifa_name, interf)) { + res = IF2IP_AF_NOT_SUPPORTED; + } + } + } + + freeifaddrs(head); + } + + return res; } #elif defined(HAVE_IOCTL_SIOCGIFADDR) -char *Curl_if2ip(int af, const char *interface, char *buf, int buf_size) +bool Curl_if_is_interface_name(const char *interf) +{ + /* This is here just to support the old interfaces */ + char buf[256]; + + return (Curl_if2ip(AF_INET, 0 /* unused */, 0, interf, buf, sizeof(buf)) == + IF2IP_NOT_FOUND) ? FALSE : TRUE; +} + +if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, + unsigned int remote_scope_id, const char *interf, + char *buf, int buf_size) { struct ifreq req; struct in_addr in; struct sockaddr_in *s; curl_socket_t dummy; size_t len; - char *ip; - if(!interface || (af != AF_INET)) - return NULL; + (void)remote_scope; + (void)remote_scope_id; - len = strlen(interface); + if(!interf || (af != AF_INET)) + return IF2IP_NOT_FOUND; + + len = strlen(interf); if(len >= sizeof(req.ifr_name)) - return NULL; + return IF2IP_NOT_FOUND; dummy = socket(AF_INET, SOCK_STREAM, 0); if(CURL_SOCKET_BAD == dummy) - return NULL; + return IF2IP_NOT_FOUND; memset(&req, 0, sizeof(req)); - memcpy(req.ifr_name, interface, len+1); + memcpy(req.ifr_name, interf, len+1); req.ifr_addr.sa_family = AF_INET; if(ioctl(dummy, SIOCGIFADDR, &req) < 0) { sclose(dummy); - return NULL; + /* With SIOCGIFADDR, we cannot tell the difference between an interface + that does not exist and an interface that has no address of the + correct family. Assume the interface does not exist */ + return IF2IP_NOT_FOUND; } s = (struct sockaddr_in *)&req.ifr_addr; memcpy(&in, &s->sin_addr, sizeof(in)); - ip = (char *) Curl_inet_ntop(s->sin_family, &in, buf, buf_size); + Curl_inet_ntop(s->sin_family, &in, buf, buf_size); sclose(dummy); - return ip; + return IF2IP_FOUND; } #else -char *Curl_if2ip(int af, const char *interf, char *buf, int buf_size) +bool Curl_if_is_interface_name(const char *interf) +{ + (void) interf; + + return FALSE; +} + +if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, + unsigned int remote_scope_id, const char *interf, + char *buf, int buf_size) { (void) af; + (void) remote_scope; + (void) remote_scope_id; (void) interf; (void) buf; (void) buf_size; - return NULL; + return IF2IP_NOT_FOUND; } #endif diff --git a/project/jni/curl/lib/if2ip.h b/project/jni/curl/lib/if2ip.h index cdf2638ae..f3a7ff0b2 100644 --- a/project/jni/curl/lib/if2ip.h +++ b/project/jni/curl/lib/if2ip.h @@ -1,5 +1,5 @@ -#ifndef __IF2IP_H -#define __IF2IP_H +#ifndef HEADER_CURL_IF2IP_H +#define HEADER_CURL_IF2IP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,12 +21,29 @@ * KIND, either express or implied. * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -extern char *Curl_if2ip(int af, const char *interf, char *buf, int buf_size); +/* IPv6 address scopes. */ +#define IPV6_SCOPE_GLOBAL 0 /* Global scope. */ +#define IPV6_SCOPE_LINKLOCAL 1 /* Link-local scope. */ +#define IPV6_SCOPE_SITELOCAL 2 /* Site-local scope (deprecated). */ +#define IPV6_SCOPE_NODELOCAL 3 /* Loopback. */ + +unsigned int Curl_ipv6_scope(const struct sockaddr *sa); + +bool Curl_if_is_interface_name(const char *interf); + +typedef enum { + IF2IP_NOT_FOUND = 0, /* Interface not found */ + IF2IP_AF_NOT_SUPPORTED = 1, /* Int. exists but has no address for this af */ + IF2IP_FOUND = 2 /* The address has been stored in "buf" */ +} if2ip_result_t; + +if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, + unsigned int remote_scope_id, const char *interf, + char *buf, int buf_size); #ifdef __INTERIX -#include /* Nedelcho Stanev's work-around for SFU 3.0 */ struct ifreq { @@ -60,6 +77,7 @@ struct ifreq { #define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ #define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */ -#endif /* interix */ -#endif +#endif /* __INTERIX */ + +#endif /* HEADER_CURL_IF2IP_H */ diff --git a/project/jni/curl/lib/imap.c b/project/jni/curl/lib/imap.c index 9c39625b3..ff25e54e0 100644 --- a/project/jni/curl/lib/imap.c +++ b/project/jni/curl/lib/imap.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -18,27 +18,24 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * RFC2195 CRAM-MD5 authentication + * RFC2595 Using TLS with IMAP, POP3 and ACAP + * RFC2831 DIGEST-MD5 authentication * RFC3501 IMAPv4 protocol + * RFC4422 Simple Authentication and Security Layer (SASL) + * RFC4616 PLAIN authentication + * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism + * RFC4959 IMAP Extension for SASL Initial Client Response * RFC5092 IMAP URL Scheme + * RFC6749 OAuth 2.0 Authorization Framework + * Draft LOGIN SASL Mechanism * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_IMAP -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif @@ -64,9 +61,6 @@ #include #include "urldata.h" #include "sendf.h" -#include "easyif.h" /* for Curl_convert_... prototypes */ - -#include "if2ip.h" #include "hostip.h" #include "progress.h" #include "transfer.h" @@ -77,37 +71,44 @@ #include "strtoofft.h" #include "strequal.h" -#include "sslgen.h" +#include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" #include "rawstr.h" -#include "strtoofft.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include +#include "curl_sasl.h" +#include "warnless.h" +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /* Local API functions */ -static CURLcode imap_parse_url_path(struct connectdata *conn); static CURLcode imap_regular_transfer(struct connectdata *conn, bool *done); static CURLcode imap_do(struct connectdata *conn, bool *done); -static CURLcode imap_done(struct connectdata *conn, - CURLcode, bool premature); +static CURLcode imap_done(struct connectdata *conn, CURLcode status, + bool premature); static CURLcode imap_connect(struct connectdata *conn, bool *done); -static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection); +static CURLcode imap_disconnect(struct connectdata *conn, bool dead); static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done); -static int imap_getsock(struct connectdata *conn, - curl_socket_t *socks, +static int imap_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks); -static CURLcode imap_doing(struct connectdata *conn, - bool *dophase_done); -static CURLcode imap_setup_connection(struct connectdata * conn); +static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done); +static CURLcode imap_setup_connection(struct connectdata *conn); +static char *imap_atom(const char *str, bool escape_only); +static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...); +static CURLcode imap_parse_url_options(struct connectdata *conn); +static CURLcode imap_parse_url_path(struct connectdata *conn); +static CURLcode imap_parse_custom_request(struct connectdata *conn); +static CURLcode imap_perform_authenticate(struct connectdata *conn, + const char *mech, + const char *initresp); +static CURLcode imap_continue_authenticate(struct connectdata *conn, + const char *resp); +static void imap_get_message(char *buffer, char** outptr); /* * IMAP protocol handler. @@ -124,13 +125,15 @@ const struct Curl_handler Curl_handler_imap = { imap_doing, /* doing */ imap_getsock, /* proto_getsock */ imap_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ imap_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_IMAP, /* defport */ - PROT_IMAP /* protocol */ + CURLPROTO_IMAP, /* protocol */ + PROTOPT_CLOSEACTION /* flags */ }; - #ifdef USE_SSL /* * IMAPS protocol handler. @@ -147,10 +150,13 @@ const struct Curl_handler Curl_handler_imaps = { imap_doing, /* doing */ imap_getsock, /* proto_getsock */ imap_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ imap_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_IMAPS, /* defport */ - PROT_IMAP | PROT_IMAPS | PROT_SSL /* protocol */ + CURLPROTO_IMAPS, /* protocol */ + PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */ }; #endif @@ -161,7 +167,7 @@ const struct Curl_handler Curl_handler_imaps = { static const struct Curl_handler Curl_handler_imap_proxy = { "IMAP", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -170,13 +176,15 @@ static const struct Curl_handler Curl_handler_imap_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_IMAP, /* defport */ - PROT_HTTP /* protocol */ + CURLPROTO_HTTP, /* protocol */ + PROTOPT_NONE /* flags */ }; - #ifdef USE_SSL /* * HTTP-proxyed IMAPS protocol handler. @@ -184,7 +192,7 @@ static const struct Curl_handler Curl_handler_imap_proxy = { static const struct Curl_handler Curl_handler_imaps_proxy = { "IMAPS", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -193,213 +201,934 @@ static const struct Curl_handler Curl_handler_imaps_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_IMAPS, /* defport */ - PROT_HTTP /* protocol */ + CURLPROTO_HTTP, /* protocol */ + PROTOPT_NONE /* flags */ }; #endif #endif +/* SASL parameters for the imap protocol */ +static const struct SASLproto saslimap = { + "imap", /* The service name */ + '+', /* Code received when continuation is expected */ + 'O', /* Code to receive upon authentication success */ + 0, /* Maximum initial response length (no max) */ + imap_perform_authenticate, /* Send authentication command */ + imap_continue_authenticate, /* Send authentication continuation */ + imap_get_message /* Get SASL response message */ +}; + + +#ifdef USE_SSL +static void imap_to_imaps(struct connectdata *conn) +{ + /* Change the connection handler */ + conn->handler = &Curl_handler_imaps; + + /* Set the connection's upgraded to TLS flag */ + conn->tls_upgraded = TRUE; +} +#else +#define imap_to_imaps(x) Curl_nop_stmt +#endif + /*********************************************************************** * - * imapsendf() + * imap_matchresp() * - * Sends the formated string as an IMAP command to a server + * Determines whether the untagged response is related to the specified + * command by checking if it is in format "* ..." or + * "* ...". * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * - * Designed to never block. + * The "* " marker is assumed to have already been checked by the caller. */ -static CURLcode imapsendf(struct connectdata *conn, - const char *idstr, /* id to wait for at the - completion of this command */ - const char *fmt, ...) +static bool imap_matchresp(const char *line, size_t len, const char *cmd) { - CURLcode res; + const char *end = line + len; + size_t cmd_len = strlen(cmd); + + /* Skip the untagged response marker */ + line += 2; + + /* Do we have a number after the marker? */ + if(line < end && ISDIGIT(*line)) { + /* Skip the number */ + do + line++; + while(line < end && ISDIGIT(*line)); + + /* Do we have the space character? */ + if(line == end || *line != ' ') + return FALSE; + + line++; + } + + /* Does the command name match and is it followed by a space character or at + the end of line? */ + if(line + cmd_len <= end && Curl_raw_nequal(line, cmd, cmd_len) && + (line[cmd_len] == ' ' || line + cmd_len + 2 == end)) + return TRUE; + + return FALSE; +} + +/*********************************************************************** + * + * imap_endofresp() + * + * Checks whether the given string is a valid tagged, untagged or continuation + * response which can be processed by the response handler. + */ +static bool imap_endofresp(struct connectdata *conn, char *line, size_t len, + int *resp) +{ + struct IMAP *imap = conn->data->req.protop; struct imap_conn *imapc = &conn->proto.imapc; - va_list ap; - va_start(ap, fmt); - - imapc->idstr = idstr; /* this is the thing */ - - res = Curl_pp_vsendf(&imapc->pp, fmt, ap); - - va_end(ap); - - return res; -} - -static const char *getcmdid(struct connectdata *conn) -{ - static const char * const ids[]= { - "A", - "B", - "C", - "D" - }; - - struct imap_conn *imapc = &conn->proto.imapc; - - /* get the next id, but wrap at end of table */ - imapc->cmdid = (int)((imapc->cmdid+1) % (sizeof(ids)/sizeof(ids[0]))); - - return ids[imapc->cmdid]; -} - -/* For the IMAP "protocol connect" and "doing" phases only */ -static int imap_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - return Curl_pp_getsock(&conn->proto.imapc.pp, socks, numsocks); -} - -/* fucntion that checks for an imap status code at the start of the - given string */ -static int imap_endofresp(struct pingpong *pp, int *resp) -{ - char *line = pp->linestart_resp; - size_t len = pp->nread_resp; - struct imap_conn *imapc = &pp->conn->proto.imapc; - const char *id = imapc->idstr; + const char *id = imapc->resptag; size_t id_len = strlen(id); - if(len >= id_len + 3) { - if(!memcmp(id, line, id_len) && (line[id_len] == ' ') ) { - /* end of response */ - *resp = line[id_len+1]; /* O, N or B */ - return TRUE; - } - else if((imapc->state == IMAP_FETCH) && - !memcmp("* ", line, 2) ) { - /* FETCH response we're interested in */ - *resp = '*'; - return TRUE; + /* Do we have a tagged command response? */ + if(len >= id_len + 1 && !memcmp(id, line, id_len) && line[id_len] == ' ') { + line += id_len + 1; + len -= id_len + 1; + + if(len >= 2 && !memcmp(line, "OK", 2)) + *resp = 'O'; + else if(len >= 2 && !memcmp(line, "NO", 2)) + *resp = 'N'; + else if(len >= 3 && !memcmp(line, "BAD", 3)) + *resp = 'B'; + else { + failf(conn->data, "Bad tagged response"); + *resp = -1; } + + return TRUE; } - return FALSE; /* nothing for us */ + + /* Do we have an untagged command response? */ + if(len >= 2 && !memcmp("* ", line, 2)) { + switch(imapc->state) { + /* States which are interested in untagged responses */ + case IMAP_CAPABILITY: + if(!imap_matchresp(line, len, "CAPABILITY")) + return FALSE; + break; + + case IMAP_LIST: + if((!imap->custom && !imap_matchresp(line, len, "LIST")) || + (imap->custom && !imap_matchresp(line, len, imap->custom) && + (strcmp(imap->custom, "STORE") || + !imap_matchresp(line, len, "FETCH")) && + strcmp(imap->custom, "SELECT") && + strcmp(imap->custom, "EXAMINE") && + strcmp(imap->custom, "SEARCH") && + strcmp(imap->custom, "EXPUNGE") && + strcmp(imap->custom, "LSUB") && + strcmp(imap->custom, "UID") && + strcmp(imap->custom, "NOOP"))) + return FALSE; + break; + + case IMAP_SELECT: + /* SELECT is special in that its untagged responses do not have a + common prefix so accept anything! */ + break; + + case IMAP_FETCH: + if(!imap_matchresp(line, len, "FETCH")) + return FALSE; + break; + + case IMAP_SEARCH: + if(!imap_matchresp(line, len, "SEARCH")) + return FALSE; + break; + + /* Ignore other untagged responses */ + default: + return FALSE; + } + + *resp = '*'; + return TRUE; + } + + /* Do we have a continuation response? This should be a + symbol followed by + a space and optionally some text as per RFC-3501 for the AUTHENTICATE and + APPEND commands and as outlined in Section 4. Examples of RFC-4959 but + some e-mail servers ignore this and only send a single + instead. */ + if(!imap->custom && ((len == 3 && !memcmp("+", line, 1)) || + (len >= 2 && !memcmp("+ ", line, 2)))) { + switch(imapc->state) { + /* States which are interested in continuation responses */ + case IMAP_AUTHENTICATE: + case IMAP_APPEND: + *resp = '+'; + break; + + default: + failf(conn->data, "Unexpected continuation response"); + *resp = -1; + break; + } + + return TRUE; + } + + return FALSE; /* Nothing for us */ } -/* This is the ONLY way to change IMAP state! */ -static void state(struct connectdata *conn, - imapstate newstate) +/*********************************************************************** + * + * imap_get_message() + * + * Gets the authentication message from the response buffer. + */ +static void imap_get_message(char *buffer, char** outptr) { + size_t len = 0; + char* message = NULL; + + /* Find the start of the message */ + for(message = buffer + 2; *message == ' ' || *message == '\t'; message++) + ; + + /* Find the end of the message */ + for(len = strlen(message); len--;) + if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && + message[len] != '\t') + break; + + /* Terminate the message */ + if(++len) { + message[len] = '\0'; + } + + *outptr = message; +} + +/*********************************************************************** + * + * state() + * + * This is the ONLY way to change IMAP state! + */ +static void state(struct connectdata *conn, imapstate newstate) +{ + struct imap_conn *imapc = &conn->proto.imapc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ static const char * const names[]={ "STOP", "SERVERGREET", - "LOGIN", + "CAPABILITY", "STARTTLS", + "UPGRADETLS", + "AUTHENTICATE", + "LOGIN", + "LIST", "SELECT", "FETCH", + "FETCH_FINAL", + "APPEND", + "APPEND_FINAL", + "SEARCH", "LOGOUT", /* LAST */ }; -#endif - struct imap_conn *imapc = &conn->proto.imapc; -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + if(imapc->state != newstate) infof(conn->data, "IMAP %p state change from %s to %s\n", - imapc, names[imapc->state], names[newstate]); + (void *)imapc, names[imapc->state], names[newstate]); #endif + imapc->state = newstate; } -static CURLcode imap_state_login(struct connectdata *conn) +/*********************************************************************** + * + * imap_perform_capability() + * + * Sends the CAPABILITY command in order to obtain a list of server side + * supported capabilities. + */ +static CURLcode imap_perform_capability(struct connectdata *conn) { - CURLcode result; - struct FTP *imap = conn->data->state.proto.imap; - const char *str; + CURLcode result = CURLE_OK; + struct imap_conn *imapc = &conn->proto.imapc; - str = getcmdid(conn); + imapc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */ + imapc->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */ + imapc->tls_supported = FALSE; /* Clear the TLS capability */ - /* send USER and password */ - result = imapsendf(conn, str, "%s LOGIN %s %s", str, - imap->user?imap->user:"", - imap->passwd?imap->passwd:""); - if(result) - return result; + /* Send the CAPABILITY command */ + result = imap_sendf(conn, "CAPABILITY"); - state(conn, IMAP_LOGIN); + if(!result) + state(conn, IMAP_CAPABILITY); - return CURLE_OK; + return result; } -/* for STARTTLS responses */ +/*********************************************************************** + * + * imap_perform_starttls() + * + * Sends the STARTTLS command to start the upgrade to TLS. + */ +static CURLcode imap_perform_starttls(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + /* Send the STARTTLS command */ + result = imap_sendf(conn, "STARTTLS"); + + if(!result) + state(conn, IMAP_STARTTLS); + + return result; +} + +/*********************************************************************** + * + * imap_perform_upgrade_tls() + * + * Performs the upgrade to TLS. + */ +static CURLcode imap_perform_upgrade_tls(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct imap_conn *imapc = &conn->proto.imapc; + + /* Start the SSL connection */ + result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone); + + if(!result) { + if(imapc->state != IMAP_UPGRADETLS) + state(conn, IMAP_UPGRADETLS); + + if(imapc->ssldone) { + imap_to_imaps(conn); + result = imap_perform_capability(conn); + } + } + + return result; +} + +/*********************************************************************** + * + * imap_perform_login() + * + * Sends a clear text LOGIN command to authenticate with. + */ +static CURLcode imap_perform_login(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + char *user; + char *passwd; + + /* Check we have a username and password to authenticate with and end the + connect phase if we don't */ + if(!conn->bits.user_passwd) { + state(conn, IMAP_STOP); + + return result; + } + + /* Make sure the username and password are in the correct atom format */ + user = imap_atom(conn->user, false); + passwd = imap_atom(conn->passwd, false); + + /* Send the LOGIN command */ + result = imap_sendf(conn, "LOGIN %s %s", user ? user : "", + passwd ? passwd : ""); + + free(user); + free(passwd); + + if(!result) + state(conn, IMAP_LOGIN); + + return result; +} + +/*********************************************************************** + * + * imap_perform_authenticate() + * + * Sends an AUTHENTICATE command allowing the client to login with the given + * SASL authentication mechanism. + */ +static CURLcode imap_perform_authenticate(struct connectdata *conn, + const char *mech, + const char *initresp) +{ + CURLcode result = CURLE_OK; + + if(initresp) { + /* Send the AUTHENTICATE command with the initial response */ + result = imap_sendf(conn, "AUTHENTICATE %s %s", mech, initresp); + } + else { + /* Send the AUTHENTICATE command */ + result = imap_sendf(conn, "AUTHENTICATE %s", mech); + } + + return result; +} + +/*********************************************************************** + * + * imap_continue_authenticate() + * + * Sends SASL continuation data or cancellation. + */ +static CURLcode imap_continue_authenticate(struct connectdata *conn, + const char *resp) +{ + struct imap_conn *imapc = &conn->proto.imapc; + + return Curl_pp_sendf(&imapc->pp, "%s", resp); +} + +/*********************************************************************** + * + * imap_perform_authentication() + * + * Initiates the authentication sequence, with the appropriate SASL + * authentication mechanism, falling back to clear text should a common + * mechanism not be available between the client and server. + */ +static CURLcode imap_perform_authentication(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct imap_conn *imapc = &conn->proto.imapc; + saslprogress progress; + + /* Check we have enough data to authenticate with and end the + connect phase if we don't */ + if(!Curl_sasl_can_authenticate(&imapc->sasl, conn)) { + state(conn, IMAP_STOP); + return result; + } + + /* Calculate the SASL login details */ + result = Curl_sasl_start(&imapc->sasl, conn, imapc->ir_supported, &progress); + + if(!result) { + if(progress == SASL_INPROGRESS) + state(conn, IMAP_AUTHENTICATE); + else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT)) + /* Perform clear text authentication */ + result = imap_perform_login(conn); + else { + /* Other mechanisms not supported */ + infof(conn->data, "No known authentication mechanisms supported!\n"); + result = CURLE_LOGIN_DENIED; + } + } + + return result; +} + +/*********************************************************************** + * + * imap_perform_list() + * + * Sends a LIST command or an alternative custom request. + */ +static CURLcode imap_perform_list(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct IMAP *imap = data->req.protop; + char *mailbox; + + if(imap->custom) + /* Send the custom request */ + result = imap_sendf(conn, "%s%s", imap->custom, + imap->custom_params ? imap->custom_params : ""); + else { + /* Make sure the mailbox is in the correct atom format if necessary */ + mailbox = imap->mailbox ? imap_atom(imap->mailbox, true) : strdup(""); + if(!mailbox) + return CURLE_OUT_OF_MEMORY; + + /* Send the LIST command */ + result = imap_sendf(conn, "LIST \"%s\" *", mailbox); + + free(mailbox); + } + + if(!result) + state(conn, IMAP_LIST); + + return result; +} + +/*********************************************************************** + * + * imap_perform_select() + * + * Sends a SELECT command to ask the server to change the selected mailbox. + */ +static CURLcode imap_perform_select(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct IMAP *imap = data->req.protop; + struct imap_conn *imapc = &conn->proto.imapc; + char *mailbox; + + /* Invalidate old information as we are switching mailboxes */ + Curl_safefree(imapc->mailbox); + Curl_safefree(imapc->mailbox_uidvalidity); + + /* Check we have a mailbox */ + if(!imap->mailbox) { + failf(conn->data, "Cannot SELECT without a mailbox."); + return CURLE_URL_MALFORMAT; + } + + /* Make sure the mailbox is in the correct atom format */ + mailbox = imap_atom(imap->mailbox, false); + if(!mailbox) + return CURLE_OUT_OF_MEMORY; + + /* Send the SELECT command */ + result = imap_sendf(conn, "SELECT %s", mailbox); + + free(mailbox); + + if(!result) + state(conn, IMAP_SELECT); + + return result; +} + +/*********************************************************************** + * + * imap_perform_fetch() + * + * Sends a FETCH command to initiate the download of a message. + */ +static CURLcode imap_perform_fetch(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct IMAP *imap = conn->data->req.protop; + + /* Check we have a UID */ + if(!imap->uid) { + failf(conn->data, "Cannot FETCH without a UID."); + return CURLE_URL_MALFORMAT; + } + + /* Send the FETCH command */ + if(imap->partial) + result = imap_sendf(conn, "FETCH %s BODY[%s]<%s>", + imap->uid, + imap->section ? imap->section : "", + imap->partial); + else + result = imap_sendf(conn, "FETCH %s BODY[%s]", + imap->uid, + imap->section ? imap->section : ""); + + if(!result) + state(conn, IMAP_FETCH); + + return result; +} + +/*********************************************************************** + * + * imap_perform_append() + * + * Sends an APPEND command to initiate the upload of a message. + */ +static CURLcode imap_perform_append(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct IMAP *imap = conn->data->req.protop; + char *mailbox; + + /* Check we have a mailbox */ + if(!imap->mailbox) { + failf(conn->data, "Cannot APPEND without a mailbox."); + return CURLE_URL_MALFORMAT; + } + + /* Check we know the size of the upload */ + if(conn->data->state.infilesize < 0) { + failf(conn->data, "Cannot APPEND with unknown input file size\n"); + return CURLE_UPLOAD_FAILED; + } + + /* Make sure the mailbox is in the correct atom format */ + mailbox = imap_atom(imap->mailbox, false); + if(!mailbox) + return CURLE_OUT_OF_MEMORY; + + /* Send the APPEND command */ + result = imap_sendf(conn, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}", + mailbox, conn->data->state.infilesize); + + free(mailbox); + + if(!result) + state(conn, IMAP_APPEND); + + return result; +} + +/*********************************************************************** + * + * imap_perform_search() + * + * Sends a SEARCH command. + */ +static CURLcode imap_perform_search(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct IMAP *imap = conn->data->req.protop; + + /* Check we have a query string */ + if(!imap->query) { + failf(conn->data, "Cannot SEARCH without a query string."); + return CURLE_URL_MALFORMAT; + } + + /* Send the SEARCH command */ + result = imap_sendf(conn, "SEARCH %s", imap->query); + + if(!result) + state(conn, IMAP_SEARCH); + + return result; +} + +/*********************************************************************** + * + * imap_perform_logout() + * + * Performs the logout action prior to sclose() being called. + */ +static CURLcode imap_perform_logout(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + /* Send the LOGOUT command */ + result = imap_sendf(conn, "LOGOUT"); + + if(!result) + state(conn, IMAP_LOGOUT); + + return result; +} + +/* For the initial server greeting */ +static CURLcode imap_state_servergreet_resp(struct connectdata *conn, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + + (void)instate; /* no use for this yet */ + + if(imapcode != 'O') { + failf(data, "Got unexpected imap-server response"); + result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */ + } + else + result = imap_perform_capability(conn); + + return result; +} + +/* For CAPABILITY responses */ +static CURLcode imap_state_capability_resp(struct connectdata *conn, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct imap_conn *imapc = &conn->proto.imapc; + const char *line = data->state.buffer; + size_t wordlen; + + (void)instate; /* no use for this yet */ + + /* Do we have a untagged response? */ + if(imapcode == '*') { + line += 2; + + /* Loop through the data line */ + for(;;) { + while(*line && + (*line == ' ' || *line == '\t' || + *line == '\r' || *line == '\n')) { + + line++; + } + + if(!*line) + break; + + /* Extract the word */ + for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' && + line[wordlen] != '\t' && line[wordlen] != '\r' && + line[wordlen] != '\n';) + wordlen++; + + /* Does the server support the STARTTLS capability? */ + if(wordlen == 8 && !memcmp(line, "STARTTLS", 8)) + imapc->tls_supported = TRUE; + + /* Has the server explicitly disabled clear text authentication? */ + else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13)) + imapc->login_disabled = TRUE; + + /* Does the server support the SASL-IR capability? */ + else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7)) + imapc->ir_supported = TRUE; + + /* Do we have a SASL based authentication mechanism? */ + else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) { + size_t llen; + unsigned int mechbit; + + line += 5; + wordlen -= 5; + + /* Test the word for a matching authentication mechanism */ + mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); + if(mechbit && llen == wordlen) + imapc->sasl.authmechs |= mechbit; + } + + line += wordlen; + } + } + else if(imapcode == 'O') { + if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { + /* We don't have a SSL/TLS connection yet, but SSL is requested */ + if(imapc->tls_supported) + /* Switch to TLS connection now */ + result = imap_perform_starttls(conn); + else if(data->set.use_ssl == CURLUSESSL_TRY) + /* Fallback and carry on with authentication */ + result = imap_perform_authentication(conn); + else { + failf(data, "STARTTLS not supported."); + result = CURLE_USE_SSL_FAILED; + } + } + else + result = imap_perform_authentication(conn); + } + else + result = imap_perform_authentication(conn); + + return result; +} + +/* For STARTTLS responses */ static CURLcode imap_state_starttls_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; + (void)instate; /* no use for this yet */ if(imapcode != 'O') { - failf(data, "STARTTLS denied. %c", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Curl_ssl_connect is BLOCKING */ - result = Curl_ssl_connect(conn, FIRSTSOCKET); - if(CURLE_OK == result) { - conn->protocol |= PROT_IMAPS; - result = imap_state_login(conn); + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied. %c", imapcode); + result = CURLE_USE_SSL_FAILED; } + else + result = imap_perform_authentication(conn); } - state(conn, IMAP_STOP); + else + result = imap_perform_upgrade_tls(conn); + return result; } -/* for LOGIN responses */ +/* For SASL authentication responses */ +static CURLcode imap_state_auth_resp(struct connectdata *conn, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct imap_conn *imapc = &conn->proto.imapc; + saslprogress progress; + + (void)instate; /* no use for this yet */ + + result = Curl_sasl_continue(&imapc->sasl, conn, imapcode, &progress); + if(!result) + switch(progress) { + case SASL_DONE: + state(conn, IMAP_STOP); /* Authenticated */ + break; + case SASL_IDLE: /* No mechanism left after cancellation */ + if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT)) + /* Perform clear text authentication */ + result = imap_perform_login(conn); + else { + failf(data, "Authentication cancelled"); + result = CURLE_LOGIN_DENIED; + } + break; + default: + break; + } + + return result; +} + +/* For LOGIN responses */ static CURLcode imap_state_login_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; + (void)instate; /* no use for this yet */ if(imapcode != 'O') { failf(data, "Access denied. %c", imapcode); result = CURLE_LOGIN_DENIED; } + else + /* End of connect phase */ + state(conn, IMAP_STOP); - state(conn, IMAP_STOP); return result; } -/* for the (first line of) FETCH BODY[TEXT] response */ -static CURLcode imap_state_fetch_resp(struct connectdata *conn, - int imapcode, +/* For LIST responses */ +static CURLcode imap_state_list_resp(struct connectdata *conn, int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + char *line = conn->data->state.buffer; + size_t len = strlen(line); + + (void)instate; /* No use for this yet */ + + if(imapcode == '*') { + /* Temporarily add the LF character back and send as body to the client */ + line[len] = '\n'; + result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1); + line[len] = '\0'; + } + else if(imapcode != 'O') + result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */ + else + /* End of DO phase */ + state(conn, IMAP_STOP); + + return result; +} + +/* For SELECT responses */ +static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct IMAP *imap = conn->data->req.protop; + struct imap_conn *imapc = &conn->proto.imapc; + const char *line = data->state.buffer; + char tmp[20]; + + (void)instate; /* no use for this yet */ + + if(imapcode == '*') { + /* See if this is an UIDVALIDITY response */ + if(sscanf(line + 2, "OK [UIDVALIDITY %19[0123456789]]", tmp) == 1) { + Curl_safefree(imapc->mailbox_uidvalidity); + imapc->mailbox_uidvalidity = strdup(tmp); + } + } + else if(imapcode == 'O') { + /* Check if the UIDVALIDITY has been specified and matches */ + if(imap->uidvalidity && imapc->mailbox_uidvalidity && + strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)) { + failf(conn->data, "Mailbox UIDVALIDITY has changed"); + result = CURLE_REMOTE_FILE_NOT_FOUND; + } + else { + /* Note the currently opened mailbox on this connection */ + imapc->mailbox = strdup(imap->mailbox); + + if(imap->custom) + result = imap_perform_list(conn); + else if(imap->query) + result = imap_perform_search(conn); + else + result = imap_perform_fetch(conn); + } + } + else { + failf(data, "Select failed"); + result = CURLE_LOGIN_DENIED; + } + + return result; +} + +/* For the (first line of the) FETCH responses */ +static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; struct imap_conn *imapc = &conn->proto.imapc; - struct FTP *imap = data->state.proto.imap; struct pingpong *pp = &imapc->pp; const char *ptr = data->state.buffer; + bool parsed = FALSE; + curl_off_t size = 0; + (void)instate; /* no use for this yet */ - if('*' != imapcode) { - Curl_pgrsSetDownloadSize(data, 0); + if(imapcode != '*') { + Curl_pgrsSetDownloadSize(data, -1); state(conn, IMAP_STOP); - return CURLE_OK; + return CURLE_REMOTE_FILE_NOT_FOUND; /* TODO: Fix error code */ } - /* Something like this comes "* 1 FETCH (BODY[TEXT] {2021}\r" */ + /* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse + the continuation data contained within the curly brackets */ while(*ptr && (*ptr != '{')) ptr++; if(*ptr == '{') { - curl_off_t filesize = curlx_strtoofft(ptr+1, NULL, 10); - if(filesize) - Curl_pgrsSetDownloadSize(data, filesize); + char *endptr; + size = curlx_strtoofft(ptr + 1, &endptr, 10); + if(endptr - ptr > 1 && endptr[0] == '}' && + endptr[1] == '\r' && endptr[2] == '\0') + parsed = TRUE; + } - infof(data, "Found %" FORMAT_OFF_TU " bytes to download\n", filesize); + if(parsed) { + infof(data, "Found %" CURL_FORMAT_CURL_OFF_TU " bytes to download\n", + size); + Curl_pgrsSetDownloadSize(data, size); if(pp->cache) { /* At this point there is a bunch of data in the header "cache" that is @@ -407,322 +1136,333 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, that there may even be additional "headers" after the body. */ size_t chunk = pp->cache_size; - if(chunk > (size_t)filesize) - /* the conversion from curl_off_t to size_t is always fine here */ - chunk = (size_t)filesize; + if(chunk > (size_t)size) + /* The conversion from curl_off_t to size_t is always fine here */ + chunk = (size_t)size; result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk); if(result) return result; - filesize -= chunk; + data->req.bytecount += chunk; - /* we've now used parts of or the entire cache */ + infof(data, "Written %" CURL_FORMAT_CURL_OFF_TU + " bytes, %" CURL_FORMAT_CURL_OFF_TU + " bytes are left for transfer\n", (curl_off_t)chunk, + size - chunk); + + /* Have we used the entire cache or just part of it?*/ if(pp->cache_size > chunk) { - /* part of, move the trailing data to the start and reduce the size */ - memmove(pp->cache, pp->cache+chunk, - pp->cache_size - chunk); + /* Only part of it so shrink the cache to fit the trailing data */ + memmove(pp->cache, pp->cache + chunk, pp->cache_size - chunk); pp->cache_size -= chunk; } else { - /* cache is drained */ - free(pp->cache); - pp->cache = NULL; + /* Free the cache */ + Curl_safefree(pp->cache); + + /* Reset the cache size */ pp->cache_size = 0; } } - infof(data, "Filesize left: %" FORMAT_OFF_T "\n", filesize); - - if(!filesize) - /* the entire data is already transfered! */ + if(data->req.bytecount == size) + /* The entire data is already transferred! */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - else + else { /* IMAP download */ - Curl_setup_transfer(conn, FIRSTSOCKET, filesize, FALSE, - imap->bytecountp, -1, NULL); /* no upload here */ - - data->req.maxdownload = filesize; + data->req.maxdownload = size; + Curl_setup_transfer(conn, FIRSTSOCKET, size, FALSE, NULL, -1, NULL); + } } - else + else { /* We don't know how to parse this line */ + failf(pp->conn->data, "Failed to parse FETCH response."); result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */ + } + /* End of DO phase */ state(conn, IMAP_STOP); + return result; } -/* start the DO phase */ -static CURLcode imap_select(struct connectdata *conn) +/* For final FETCH responses performed after the download */ +static CURLcode imap_state_fetch_final_resp(struct connectdata *conn, + int imapcode, + imapstate instate) { CURLcode result = CURLE_OK; - struct imap_conn *imapc = &conn->proto.imapc; - const char *str; - str = getcmdid(conn); + (void)instate; /* No use for this yet */ - result = imapsendf(conn, str, "%s SELECT %s", str, - imapc->mailbox?imapc->mailbox:""); - if(result) - return result; + if(imapcode != 'O') + result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: Fix error code */ + else + /* End of DONE phase */ + state(conn, IMAP_STOP); - state(conn, IMAP_SELECT); return result; } -static CURLcode imap_fetch(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - const char *str; - - str = getcmdid(conn); - - /* TODO: make this select the correct mail - * Use "1 body[text]" to get the full mail body of mail 1 - */ - result = imapsendf(conn, str, "%s FETCH 1 BODY[TEXT]", str); - if(result) - return result; - - /* - * When issued, the server will respond with a single line similar to - * '* 1 FETCH (BODY[TEXT] {2021}' - * - * Identifying the fetch and how many bytes of contents we can expect. We - * must extract that number before continuing to "download as usual". - */ - - state(conn, IMAP_FETCH); - return result; -} - -/* for SELECT responses */ -static CURLcode imap_state_select_resp(struct connectdata *conn, - int imapcode, +/* For APPEND responses */ +static CURLcode imap_state_append_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - (void)instate; /* no use for this yet */ - if(imapcode != 'O') { - failf(data, "Select failed"); - result = CURLE_LOGIN_DENIED; + (void)instate; /* No use for this yet */ + + if(imapcode != '+') { + result = CURLE_UPLOAD_FAILED; } + else { + /* Set the progress upload size */ + Curl_pgrsSetUploadSize(data, data->state.infilesize); + + /* IMAP upload */ + Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL); + + /* End of DO phase */ + state(conn, IMAP_STOP); + } + + return result; +} + +/* For final APPEND responses performed after the upload */ +static CURLcode imap_state_append_final_resp(struct connectdata *conn, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + + (void)instate; /* No use for this yet */ + + if(imapcode != 'O') + result = CURLE_UPLOAD_FAILED; else - result = imap_fetch(conn); + /* End of DONE phase */ + state(conn, IMAP_STOP); + + return result; +} + +/* For SEARCH responses */ +static CURLcode imap_state_search_resp(struct connectdata *conn, int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + char *line = conn->data->state.buffer; + size_t len = strlen(line); + + (void)instate; /* No use for this yet */ + + if(imapcode == '*') { + /* Temporarily add the LF character back and send as body to the client */ + line[len] = '\n'; + result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1); + line[len] = '\0'; + } + else if(imapcode != 'O') + result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */ + else + /* End of DO phase */ + state(conn, IMAP_STOP); + return result; } static CURLcode imap_statemach_act(struct connectdata *conn) { - CURLcode result; + CURLcode result = CURLE_OK; curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct SessionHandle *data=conn->data; int imapcode; struct imap_conn *imapc = &conn->proto.imapc; struct pingpong *pp = &imapc->pp; size_t nread = 0; + /* Busy upgrading the connection; right now all I/O is SSL/TLS, not IMAP */ + if(imapc->state == IMAP_UPGRADETLS) + return imap_perform_upgrade_tls(conn); + + /* Flush any data that needs to be sent */ if(pp->sendleft) return Curl_pp_flushsend(pp); - /* we read a piece of response */ - result = Curl_pp_readresp(sock, pp, &imapcode, &nread); - if(result) - return result; - - if(imapcode) - /* we have now received a full IMAP server response */ - switch(imapc->state) { - case IMAP_SERVERGREET: - if(imapcode != 'O') { - failf(data, "Got unexpected imap-server response"); - return CURLE_FTP_WEIRD_SERVER_REPLY; - } - - if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) { - /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch - to TLS connection now */ - const char *str; - - str = getcmdid(conn); - result = imapsendf(conn, str, "%s STARTTLS", str); - state(conn, IMAP_STARTTLS); - } - else - result = imap_state_login(conn); + do { + /* Read the response from the server */ + result = Curl_pp_readresp(sock, pp, &imapcode, &nread); if(result) return result; - break; - case IMAP_LOGIN: - result = imap_state_login_resp(conn, imapcode, imapc->state); - break; + /* Was there an error parsing the response line? */ + if(imapcode == -1) + return CURLE_FTP_WEIRD_SERVER_REPLY; - case IMAP_STARTTLS: - result = imap_state_starttls_resp(conn, imapcode, imapc->state); - break; - - case IMAP_FETCH: - result = imap_state_fetch_resp(conn, imapcode, imapc->state); - break; - - case IMAP_SELECT: - result = imap_state_select_resp(conn, imapcode, imapc->state); - break; - - case IMAP_LOGOUT: - /* fallthrough, just stop! */ - default: - /* internal error */ - state(conn, IMAP_STOP); - break; - } - - return result; -} - -/* called repeatedly until done from multi.c */ -static CURLcode imap_multi_statemach(struct connectdata *conn, - bool *done) -{ - struct imap_conn *imapc = &conn->proto.imapc; - CURLcode result = Curl_pp_multi_statemach(&imapc->pp); - - *done = (bool)(imapc->state == IMAP_STOP); - - return result; -} - -static CURLcode imap_easy_statemach(struct connectdata *conn) -{ - struct imap_conn *imapc = &conn->proto.imapc; - struct pingpong *pp = &imapc->pp; - CURLcode result = CURLE_OK; - - while(imapc->state != IMAP_STOP) { - result = Curl_pp_easy_statemach(pp); - if(result) + if(!imapcode) break; - } + + /* We have now received a full IMAP server response */ + switch(imapc->state) { + case IMAP_SERVERGREET: + result = imap_state_servergreet_resp(conn, imapcode, imapc->state); + break; + + case IMAP_CAPABILITY: + result = imap_state_capability_resp(conn, imapcode, imapc->state); + break; + + case IMAP_STARTTLS: + result = imap_state_starttls_resp(conn, imapcode, imapc->state); + break; + + case IMAP_AUTHENTICATE: + result = imap_state_auth_resp(conn, imapcode, imapc->state); + break; + + case IMAP_LOGIN: + result = imap_state_login_resp(conn, imapcode, imapc->state); + break; + + case IMAP_LIST: + result = imap_state_list_resp(conn, imapcode, imapc->state); + break; + + case IMAP_SELECT: + result = imap_state_select_resp(conn, imapcode, imapc->state); + break; + + case IMAP_FETCH: + result = imap_state_fetch_resp(conn, imapcode, imapc->state); + break; + + case IMAP_FETCH_FINAL: + result = imap_state_fetch_final_resp(conn, imapcode, imapc->state); + break; + + case IMAP_APPEND: + result = imap_state_append_resp(conn, imapcode, imapc->state); + break; + + case IMAP_APPEND_FINAL: + result = imap_state_append_final_resp(conn, imapcode, imapc->state); + break; + + case IMAP_SEARCH: + result = imap_state_search_resp(conn, imapcode, imapc->state); + break; + + case IMAP_LOGOUT: + /* fallthrough, just stop! */ + default: + /* internal error */ + state(conn, IMAP_STOP); + break; + } + } while(!result && imapc->state != IMAP_STOP && Curl_pp_moredata(pp)); return result; } -/* - * Allocate and initialize the struct IMAP for the current SessionHandle. If - * need be. - */ +/* Called repeatedly until done from multi.c */ +static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done) +{ + CURLcode result = CURLE_OK; + struct imap_conn *imapc = &conn->proto.imapc; + + if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) { + result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone); + if(result || !imapc->ssldone) + return result; + } + + result = Curl_pp_statemach(&imapc->pp, FALSE); + *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE; + + return result; +} + +static CURLcode imap_block_statemach(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct imap_conn *imapc = &conn->proto.imapc; + + while(imapc->state != IMAP_STOP && !result) + result = Curl_pp_statemach(&imapc->pp, TRUE); + + return result; +} + +/* Allocate and initialize the struct IMAP for the current SessionHandle if + required */ static CURLcode imap_init(struct connectdata *conn) { + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct FTP *imap = data->state.proto.imap; - if(!imap) { - imap = data->state.proto.imap = calloc(sizeof(struct FTP), 1); - if(!imap) - return CURLE_OUT_OF_MEMORY; - } + struct IMAP *imap; - /* get some initial data into the imap struct */ - imap->bytecountp = &data->req.bytecount; + imap = data->req.protop = calloc(sizeof(struct IMAP), 1); + if(!imap) + result = CURLE_OUT_OF_MEMORY; - /* No need to duplicate user+password, the connectdata struct won't change - during a session, but we re-init them here since on subsequent inits - since the conn struct may have changed or been replaced. - */ - imap->user = conn->user; - imap->passwd = conn->passwd; - - return CURLE_OK; + return result; } -/* - * imap_connect() should do everything that is to be considered a part of - * the connection phase. +/* For the IMAP "protocol connect" and "doing" phases only */ +static int imap_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks) +{ + return Curl_pp_getsock(&conn->proto.imapc.pp, socks, numsocks); +} + +/*********************************************************************** + * + * imap_connect() + * + * This function should do everything that is to be considered a part of the + * connection phase. * * The variable 'done' points to will be TRUE if the protocol-layer connect - * phase is done when this function returns, or FALSE is not. When called as - * a part of the easy interface, it will always be TRUE. + * phase is done when this function returns, or FALSE if not. */ -static CURLcode imap_connect(struct connectdata *conn, - bool *done) /* see description above */ +static CURLcode imap_connect(struct connectdata *conn, bool *done) { - CURLcode result; + CURLcode result = CURLE_OK; struct imap_conn *imapc = &conn->proto.imapc; - struct SessionHandle *data=conn->data; struct pingpong *pp = &imapc->pp; *done = FALSE; /* default to not done yet */ - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); + /* We always support persistent connections in IMAP */ + connkeep(conn, "IMAP default"); - result = imap_init(conn); - if(CURLE_OK != result) - return result; - - /* We always support persistant connections on imap */ - conn->bits.close = FALSE; - - pp->response_time = RESP_TIMEOUT; /* set default response time-out */ + /* Set the default response time-out */ + pp->response_time = RESP_TIMEOUT; pp->statemach_act = imap_statemach_act; pp->endofresp = imap_endofresp; pp->conn = conn; -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY) - if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { - /* for IMAP over HTTP proxy */ - struct HTTP http_proxy; - struct FTP *imap_save; + /* Set the default preferred authentication type and mechanism */ + imapc->preftype = IMAP_TYPE_ANY; + Curl_sasl_init(&imapc->sasl, &saslimap); - /* BLOCKING */ - /* We want "seamless" IMAP operations through HTTP proxy tunnel */ + /* Initialise the pingpong layer */ + Curl_pp_init(pp); - /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member - * conn->proto.http; we want IMAP through HTTP and we have to change the - * member temporarily for connecting to the HTTP proxy. After - * Curl_proxyCONNECT we have to set back the member to the original struct - * IMAP pointer - */ - imap_save = data->state.proto.imap; - memset(&http_proxy, 0, sizeof(http_proxy)); - data->state.proto.http = &http_proxy; + /* Parse the URL options */ + result = imap_parse_url_options(conn); + if(result) + return result; - result = Curl_proxyCONNECT(conn, FIRSTSOCKET, - conn->host.name, conn->remote_port); - - data->state.proto.imap = imap_save; - - if(CURLE_OK != result) - return result; - } -#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */ - - if(conn->protocol & PROT_IMAPS) { - /* BLOCKING */ - /* IMAPS is simply imap with SSL for the control channel */ - /* now, perform the SSL initialization for this socket */ - result = Curl_ssl_connect(conn, FIRSTSOCKET); - if(result) - return result; - } - - Curl_pp_init(pp); /* init generic pingpong data */ - - /* When we connect, we start in the state where we await the server greeting - response */ + /* Start off waiting for the server greeting response */ state(conn, IMAP_SERVERGREET); - imapc->idstr = "*"; /* we start off waiting for a '*' response */ - if(data->state.used_interface == Curl_if_multi) - result = imap_multi_statemach(conn, done); - else { - result = imap_easy_statemach(conn); - if(!result) - *done = TRUE; - } + /* Start off with an response id of '*' */ + strcpy(imapc->resptag, "*"); + + result = imap_multi_statemach(conn, done); return result; } @@ -739,25 +1479,57 @@ static CURLcode imap_connect(struct connectdata *conn, static CURLcode imap_done(struct connectdata *conn, CURLcode status, bool premature) { + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct FTP *imap = data->state.proto.imap; - CURLcode result=CURLE_OK; + struct IMAP *imap = data->req.protop; + (void)premature; if(!imap) - /* When the easy handle is removed from the multi while libcurl is still - * trying to resolve the host name, it seems that the imap struct is not - * yet initialized, but the removal action calls Curl_done() which calls - * this function. So we simply return success if no imap pointer is set. - */ + /* When the easy handle is removed from the multi interface while libcurl + is still trying to resolve the host name, the IMAP struct is not yet + initialized. However, the removal action calls Curl_done() which in + turn calls this function, so we simply return success. */ return CURLE_OK; if(status) { - conn->bits.close = TRUE; /* marked for closure */ - result = status; /* use the already set error code */ + connclose(conn, "IMAP done with bad status"); /* marked for closure */ + result = status; /* use the already set error code */ + } + else if(!data->set.connect_only && !imap->custom && + (imap->uid || data->set.upload)) { + /* Handle responses after FETCH or APPEND transfer has finished */ + if(!data->set.upload) + state(conn, IMAP_FETCH_FINAL); + else { + /* End the APPEND command first by sending an empty line */ + result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", ""); + if(!result) + state(conn, IMAP_APPEND_FINAL); + } + + /* Run the state-machine + + TODO: when the multi interface is used, this _really_ should be using + the imap_multi_statemach function but we have no general support for + non-blocking DONE operations, not in the multi state machine and with + Curl_done() invokes on several places in the code! + */ + if(!result) + result = imap_block_statemach(conn); } - /* clear these for next connection */ + /* Cleanup our per-request based variables */ + Curl_safefree(imap->mailbox); + Curl_safefree(imap->uidvalidity); + Curl_safefree(imap->uid); + Curl_safefree(imap->section); + Curl_safefree(imap->partial); + Curl_safefree(imap->query); + Curl_safefree(imap->custom); + Curl_safefree(imap->custom_params); + + /* Clear the transfer mode for the next request */ imap->transfer = FTPTRANSFER_BODY; return result; @@ -767,41 +1539,64 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status, * * imap_perform() * - * This is the actual DO function for IMAP. Get a file/directory according to - * the options previously setup. + * This is the actual DO function for IMAP. Fetch or append a message, or do + * other things according to the options previously setup. */ - -static -CURLcode imap_perform(struct connectdata *conn, - bool *connected, /* connect status after PASV / PORT */ - bool *dophase_done) +static CURLcode imap_perform(struct connectdata *conn, bool *connected, + bool *dophase_done) { - /* this is IMAP and no proxy */ - CURLcode result=CURLE_OK; + /* This is IMAP and no proxy */ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct IMAP *imap = data->req.protop; + struct imap_conn *imapc = &conn->proto.imapc; + bool selected = FALSE; DEBUGF(infof(conn->data, "DO phase starts\n")); if(conn->data->set.opt_no_body) { - /* requested no body means no transfer... */ - struct FTP *imap = conn->data->state.proto.imap; + /* Requested no body means no transfer */ imap->transfer = FTPTRANSFER_INFO; } *dophase_done = FALSE; /* not done yet */ - /* start the first command in the DO phase */ - result = imap_select(conn); + /* Determine if the requested mailbox (with the same UIDVALIDITY if set) + has already been selected on this connection */ + if(imap->mailbox && imapc->mailbox && + !strcmp(imap->mailbox, imapc->mailbox) && + (!imap->uidvalidity || !imapc->mailbox_uidvalidity || + !strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity))) + selected = TRUE; + + /* Start the first command in the DO phase */ + if(conn->data->set.upload) + /* APPEND can be executed directly */ + result = imap_perform_append(conn); + else if(imap->custom && (selected || !imap->mailbox)) + /* Custom command using the same mailbox or no mailbox */ + result = imap_perform_list(conn); + else if(!imap->custom && selected && imap->uid) + /* FETCH from the same mailbox */ + result = imap_perform_fetch(conn); + else if(!imap->custom && selected && imap->query) + /* SEARCH the current mailbox */ + result = imap_perform_search(conn); + else if(imap->mailbox && !selected && + (imap->custom || imap->uid || imap->query)) + /* SELECT the mailbox */ + result = imap_perform_select(conn); + else + /* LIST */ + result = imap_perform_list(conn); + if(result) return result; - /* run the state-machine */ - if(conn->data->state.used_interface == Curl_if_multi) - result = imap_multi_statemach(conn, dophase_done); - else { - result = imap_easy_statemach(conn); - *dophase_done = TRUE; /* with the easy interface we are done here */ - } - *connected = conn->bits.tcpconnect; + /* Run the state-machine */ + result = imap_multi_statemach(conn, dophase_done); + + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); @@ -820,52 +1615,21 @@ CURLcode imap_perform(struct connectdata *conn, */ static CURLcode imap_do(struct connectdata *conn, bool *done) { - CURLcode retcode = CURLE_OK; + CURLcode result = CURLE_OK; *done = FALSE; /* default to false */ - /* - Since connections can be re-used between SessionHandles, this might be a - connection already existing but on a fresh SessionHandle struct so we must - make sure we have a good 'struct IMAP' to play with. For new connections, - the struct IMAP is allocated and setup in the imap_connect() function. - */ - Curl_reset_reqproto(conn); - retcode = imap_init(conn); - if(retcode) - return retcode; - - retcode = imap_parse_url_path(conn); - if(retcode) - return retcode; - - retcode = imap_regular_transfer(conn, done); - - return retcode; -} - -/*********************************************************************** - * - * imap_logout() - * - * This should be called before calling sclose(). We should then wait for the - * response from the server before returning. The calling code should then try - * to close the connection. - * - */ -static CURLcode imap_logout(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - const char *str; - - str = getcmdid(conn); - - result = imapsendf(conn, str, "%s LOGOUT", str, NULL); + /* Parse the URL path */ + result = imap_parse_url_path(conn); if(result) return result; - state(conn, IMAP_LOGOUT); - result = imap_easy_statemach(conn); + /* Parse the custom request */ + result = imap_parse_custom_request(conn); + if(result) + return result; + + result = imap_regular_transfer(conn, done); return result; } @@ -879,51 +1643,36 @@ static CURLcode imap_logout(struct connectdata *conn) */ static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection) { - struct imap_conn *imapc= &conn->proto.imapc; + struct imap_conn *imapc = &conn->proto.imapc; + + /* We cannot send quit unconditionally. If this connection is stale or + bad in any way, sending quit and waiting around here will make the + disconnect wait in vain and cause more problems than we need to. */ /* The IMAP session may or may not have been allocated/setup at this point! */ - if(!dead_connection && imapc->pp.conn) - (void)imap_logout(conn); /* ignore errors on the LOGOUT */ + if(!dead_connection && imapc->pp.conn && imapc->pp.conn->bits.protoconnstart) + if(!imap_perform_logout(conn)) + (void)imap_block_statemach(conn); /* ignore errors on LOGOUT */ + /* Disconnect from the server */ Curl_pp_disconnect(&imapc->pp); + /* Cleanup the SASL module */ + Curl_sasl_cleanup(conn, imapc->sasl.authused); + + /* Cleanup our connection based variables */ Curl_safefree(imapc->mailbox); + Curl_safefree(imapc->mailbox_uidvalidity); return CURLE_OK; } -/*********************************************************************** - * - * imap_parse_url_path() - * - * Parse the URL path into separate path components. - * - */ -static CURLcode imap_parse_url_path(struct connectdata *conn) +/* Call this when the DO phase has completed */ +static CURLcode imap_dophase_done(struct connectdata *conn, bool connected) { - /* the imap struct is already inited in imap_connect() */ - struct imap_conn *imapc = &conn->proto.imapc; - struct SessionHandle *data = conn->data; - const char *path = data->state.path; - int len; + struct IMAP *imap = conn->data->req.protop; - if(!*path) - path = "INBOX"; - - /* url decode the path and use this mailbox */ - imapc->mailbox = curl_easy_unescape(data, path, 0, &len); - if(!imapc->mailbox) - return CURLE_OUT_OF_MEMORY; - - return CURLE_OK; -} - -/* call this when the DO phase has completed */ -static CURLcode imap_dophase_done(struct connectdata *conn, - bool connected) -{ - struct FTP *imap = conn->data->state.proto.imap; (void)connected; if(imap->transfer != FTPTRANSFER_BODY) @@ -933,18 +1682,19 @@ static CURLcode imap_dophase_done(struct connectdata *conn, return CURLE_OK; } -/* called from multi.c while DOing */ -static CURLcode imap_doing(struct connectdata *conn, - bool *dophase_done) +/* Called from multi.c while DOing */ +static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done) { - CURLcode result; - result = imap_multi_statemach(conn, dophase_done); + CURLcode result = imap_multi_statemach(conn, dophase_done); - if(*dophase_done) { + if(result) + DEBUGF(infof(conn->data, "DO phase failed\n")); + else if(*dophase_done) { result = imap_dophase_done(conn, FALSE /* not connected */); DEBUGF(infof(conn->data, "DO phase is complete\n")); } + return result; } @@ -956,46 +1706,48 @@ static CURLcode imap_doing(struct connectdata *conn, * * Performs all commands done before a regular transfer between a local and a * remote host. - * */ -static -CURLcode imap_regular_transfer(struct connectdata *conn, - bool *dophase_done) +static CURLcode imap_regular_transfer(struct connectdata *conn, + bool *dophase_done) { - CURLcode result=CURLE_OK; - bool connected=FALSE; + CURLcode result = CURLE_OK; + bool connected = FALSE; struct SessionHandle *data = conn->data; - data->req.size = -1; /* make sure this is unknown at this point */ + /* Make sure size is unknown at this point */ + data->req.size = -1; + + /* Set the progress data */ Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); - Curl_pgrsSetUploadSize(data, 0); - Curl_pgrsSetDownloadSize(data, 0); + Curl_pgrsSetUploadSize(data, -1); + Curl_pgrsSetDownloadSize(data, -1); - result = imap_perform(conn, - &connected, /* have we connected after PASV/PORT */ - dophase_done); /* all commands in the DO-phase done? */ - - if(CURLE_OK == result) { - - if(!*dophase_done) - /* the DO phase has not completed yet */ - return CURLE_OK; + /* Carry out the perform */ + result = imap_perform(conn, &connected, dophase_done); + /* Perform post DO phase operations if necessary */ + if(!result && *dophase_done) result = imap_dophase_done(conn, connected); - if(result) - return result; - } return result; } -static CURLcode imap_setup_connection(struct connectdata * conn) +static CURLcode imap_setup_connection(struct connectdata *conn) { struct SessionHandle *data = conn->data; + /* Initialise the IMAP layer */ + CURLcode result = imap_init(conn); + if(result) + return result; + + /* Clear the TLS upgraded flag */ + conn->tls_upgraded = FALSE; + + /* Set up the proxy if necessary */ if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { - /* Unless we have asked to tunnel imap operations through the proxy, we + /* Unless we have asked to tunnel IMAP operations through the proxy, we switch and use HTTP operations only */ #ifndef CURL_DISABLE_HTTP if(conn->handler == &Curl_handler_imap) @@ -1008,12 +1760,9 @@ static CURLcode imap_setup_connection(struct connectdata * conn) return CURLE_UNSUPPORTED_PROTOCOL; #endif } - /* - * We explicitly mark this connection as persistent here as we're doing - * IMAP over HTTP and thus we accidentally avoid setting this value - * otherwise. - */ - conn->bits.close = FALSE; + + /* set it up as an HTTP connection instead */ + return conn->handler->setup_connection(conn); #else failf(data, "IMAP over http proxy requires HTTP support built-in!"); return CURLE_UNSUPPORTED_PROTOCOL; @@ -1025,4 +1774,387 @@ static CURLcode imap_setup_connection(struct connectdata * conn) return CURLE_OK; } +/*********************************************************************** + * + * imap_sendf() + * + * Sends the formated string as an IMAP command to the server. + * + * Designed to never block. + */ +static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...) +{ + CURLcode result = CURLE_OK; + struct imap_conn *imapc = &conn->proto.imapc; + char *taggedfmt; + va_list ap; + + DEBUGASSERT(fmt); + + /* Calculate the next command ID wrapping at 3 digits */ + imapc->cmdid = (imapc->cmdid + 1) % 1000; + + /* Calculate the tag based on the connection ID and command ID */ + snprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d", + 'A' + curlx_sltosi(conn->connection_id % 26), imapc->cmdid); + + /* Prefix the format with the tag */ + taggedfmt = aprintf("%s %s", imapc->resptag, fmt); + if(!taggedfmt) + return CURLE_OUT_OF_MEMORY; + + /* Send the data with the tag */ + va_start(ap, fmt); + result = Curl_pp_vsendf(&imapc->pp, taggedfmt, ap); + va_end(ap); + + free(taggedfmt); + + return result; +} + +/*********************************************************************** + * + * imap_atom() + * + * Checks the input string for characters that need escaping and returns an + * atom ready for sending to the server. + * + * The returned string needs to be freed. + * + */ +static char *imap_atom(const char *str, bool escape_only) +{ + const char atom_specials[] = "(){ %*]"; + const char *p1; + char *p2; + size_t backsp_count = 0; + size_t quote_count = 0; + bool others_exists = FALSE; + size_t newlen = 0; + char *newstr = NULL; + + if(!str) + return NULL; + + /* Look for "atom-specials", counting the backslash and quote characters as + these will need escapping */ + p1 = str; + while(*p1) { + if(*p1 == '\\') + backsp_count++; + else if(*p1 == '"') + quote_count++; + else if(!escape_only) { + const char *p3 = atom_specials; + + while(*p3 && !others_exists) { + if(*p1 == *p3) + others_exists = TRUE; + + p3++; + } + } + + p1++; + } + + /* Does the input contain any "atom-special" characters? */ + if(!backsp_count && !quote_count && !others_exists) + return strdup(str); + + /* Calculate the new string length */ + newlen = strlen(str) + backsp_count + quote_count + (others_exists ? 2 : 0); + + /* Allocate the new string */ + newstr = (char *) malloc((newlen + 1) * sizeof(char)); + if(!newstr) + return NULL; + + /* Surround the string in quotes if necessary */ + p2 = newstr; + if(others_exists) { + newstr[0] = '"'; + newstr[newlen - 1] = '"'; + p2++; + } + + /* Copy the string, escaping backslash and quote characters along the way */ + p1 = str; + while(*p1) { + if(*p1 == '\\' || *p1 == '"') { + *p2 = '\\'; + p2++; + } + + *p2 = *p1; + + p1++; + p2++; + } + + /* Terminate the string */ + newstr[newlen] = '\0'; + + return newstr; +} + +/*********************************************************************** + * + * imap_is_bchar() + * + * Portable test of whether the specified char is a "bchar" as defined in the + * grammar of RFC-5092. + */ +static bool imap_is_bchar(char ch) +{ + switch(ch) { + /* bchar */ + case ':': case '@': case '/': + /* bchar -> achar */ + case '&': case '=': + /* bchar -> achar -> uchar -> unreserved */ + case '0': case '1': case '2': case '3': case '4': case '5': case '6': + case '7': case '8': case '9': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': + case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': + case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': + case 'V': case 'W': case 'X': case 'Y': case 'Z': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': + case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': + case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': + case 'v': case 'w': case 'x': case 'y': case 'z': + case '-': case '.': case '_': case '~': + /* bchar -> achar -> uchar -> sub-delims-sh */ + case '!': case '$': case '\'': case '(': case ')': case '*': + case '+': case ',': + /* bchar -> achar -> uchar -> pct-encoded */ + case '%': /* HEXDIG chars are already included above */ + return true; + + default: + return false; + } +} + +/*********************************************************************** + * + * imap_parse_url_options() + * + * Parse the URL login options. + */ +static CURLcode imap_parse_url_options(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct imap_conn *imapc = &conn->proto.imapc; + const char *ptr = conn->options; + + imapc->sasl.resetprefs = TRUE; + + while(!result && ptr && *ptr) { + const char *key = ptr; + const char *value; + + while(*ptr && *ptr != '=') + ptr++; + + value = ptr + 1; + + while(*ptr && *ptr != ';') + ptr++; + + if(strnequal(key, "AUTH=", 5)) + result = Curl_sasl_parse_url_auth_option(&imapc->sasl, + value, ptr - value); + else + result = CURLE_URL_MALFORMAT; + + if(*ptr == ';') + ptr++; + } + + switch(imapc->sasl.prefmech) { + case SASL_AUTH_NONE: + imapc->preftype = IMAP_TYPE_NONE; + break; + case SASL_AUTH_DEFAULT: + imapc->preftype = IMAP_TYPE_ANY; + break; + default: + imapc->preftype = IMAP_TYPE_SASL; + break; + } + + return result; +} + +/*********************************************************************** + * + * imap_parse_url_path() + * + * Parse the URL path into separate path components. + * + */ +static CURLcode imap_parse_url_path(struct connectdata *conn) +{ + /* The imap struct is already initialised in imap_connect() */ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct IMAP *imap = data->req.protop; + const char *begin = data->state.path; + const char *ptr = begin; + + /* See how much of the URL is a valid path and decode it */ + while(imap_is_bchar(*ptr)) + ptr++; + + if(ptr != begin) { + /* Remove the trailing slash if present */ + const char *end = ptr; + if(end > begin && end[-1] == '/') + end--; + + result = Curl_urldecode(data, begin, end - begin, &imap->mailbox, NULL, + TRUE); + if(result) + return result; + } + else + imap->mailbox = NULL; + + /* There can be any number of parameters in the form ";NAME=VALUE" */ + while(*ptr == ';') { + char *name; + char *value; + size_t valuelen; + + /* Find the length of the name parameter */ + begin = ++ptr; + while(*ptr && *ptr != '=') + ptr++; + + if(!*ptr) + return CURLE_URL_MALFORMAT; + + /* Decode the name parameter */ + result = Curl_urldecode(data, begin, ptr - begin, &name, NULL, TRUE); + if(result) + return result; + + /* Find the length of the value parameter */ + begin = ++ptr; + while(imap_is_bchar(*ptr)) + ptr++; + + /* Decode the value parameter */ + result = Curl_urldecode(data, begin, ptr - begin, &value, &valuelen, TRUE); + if(result) { + free(name); + return result; + } + + DEBUGF(infof(conn->data, "IMAP URL parameter '%s' = '%s'\n", name, value)); + + /* Process the known hierarchical parameters (UIDVALIDITY, UID, SECTION and + PARTIAL) stripping of the trailing slash character if it is present. + + Note: Unknown parameters trigger a URL_MALFORMAT error. */ + if(Curl_raw_equal(name, "UIDVALIDITY") && !imap->uidvalidity) { + if(valuelen > 0 && value[valuelen - 1] == '/') + value[valuelen - 1] = '\0'; + + imap->uidvalidity = value; + value = NULL; + } + else if(Curl_raw_equal(name, "UID") && !imap->uid) { + if(valuelen > 0 && value[valuelen - 1] == '/') + value[valuelen - 1] = '\0'; + + imap->uid = value; + value = NULL; + } + else if(Curl_raw_equal(name, "SECTION") && !imap->section) { + if(valuelen > 0 && value[valuelen - 1] == '/') + value[valuelen - 1] = '\0'; + + imap->section = value; + value = NULL; + } + else if(Curl_raw_equal(name, "PARTIAL") && !imap->partial) { + if(valuelen > 0 && value[valuelen - 1] == '/') + value[valuelen - 1] = '\0'; + + imap->partial = value; + value = NULL; + } + else { + free(name); + free(value); + + return CURLE_URL_MALFORMAT; + } + + free(name); + free(value); + } + + /* Does the URL contain a query parameter? Only valid when we have a mailbox + and no UID as per RFC-5092 */ + if(imap->mailbox && !imap->uid && *ptr == '?') { + /* Find the length of the query parameter */ + begin = ++ptr; + while(imap_is_bchar(*ptr)) + ptr++; + + /* Decode the query parameter */ + result = Curl_urldecode(data, begin, ptr - begin, &imap->query, NULL, + TRUE); + if(result) + return result; + } + + /* Any extra stuff at the end of the URL is an error */ + if(*ptr) + return CURLE_URL_MALFORMAT; + + return CURLE_OK; +} + +/*********************************************************************** + * + * imap_parse_custom_request() + * + * Parse the custom request. + */ +static CURLcode imap_parse_custom_request(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct IMAP *imap = data->req.protop; + const char *custom = data->set.str[STRING_CUSTOMREQUEST]; + + if(custom) { + /* URL decode the custom request */ + result = Curl_urldecode(data, custom, 0, &imap->custom, NULL, TRUE); + + /* Extract the parameters if specified */ + if(!result) { + const char *params = imap->custom; + + while(*params && *params != ' ') + params++; + + if(*params) { + imap->custom_params = strdup(params); + imap->custom[params - imap->custom] = '\0'; + + if(!imap->custom_params) + result = CURLE_OUT_OF_MEMORY; + } + } + } + + return result; +} + #endif /* CURL_DISABLE_IMAP */ diff --git a/project/jni/curl/lib/imap.h b/project/jni/curl/lib/imap.h index 2f0b62a61..e6b9b8944 100644 --- a/project/jni/curl/lib/imap.h +++ b/project/jni/curl/lib/imap.h @@ -1,5 +1,5 @@ -#ifndef __IMAP_H -#define __IMAP_H +#ifndef HEADER_CURL_IMAP_H +#define HEADER_CURL_IMAP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2009, Daniel Stenberg, , et al. + * Copyright (C) 2009 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -23,33 +23,74 @@ ***************************************************************************/ #include "pingpong.h" +#include "curl_sasl.h" /**************************************************************************** * IMAP unique setup ***************************************************************************/ typedef enum { - IMAP_STOP, /* do nothing state, stops the state machine */ - IMAP_SERVERGREET, /* waiting for the initial greeting immediately after - a connect */ - IMAP_LOGIN, + IMAP_STOP, /* do nothing state, stops the state machine */ + IMAP_SERVERGREET, /* waiting for the initial greeting immediately after + a connect */ + IMAP_CAPABILITY, IMAP_STARTTLS, + IMAP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS + (multi mode only) */ + IMAP_AUTHENTICATE, + IMAP_LOGIN, + IMAP_LIST, IMAP_SELECT, IMAP_FETCH, + IMAP_FETCH_FINAL, + IMAP_APPEND, + IMAP_APPEND_FINAL, + IMAP_SEARCH, IMAP_LOGOUT, - IMAP_LAST /* never used */ + IMAP_LAST /* never used */ } imapstate; +/* This IMAP struct is used in the SessionHandle. All IMAP data that is + connection-oriented must be in imap_conn to properly deal with the fact that + perhaps the SessionHandle is changed between the times the connection is + used. */ +struct IMAP { + curl_pp_transfer transfer; + char *mailbox; /* Mailbox to select */ + char *uidvalidity; /* UIDVALIDITY to check in select */ + char *uid; /* Message UID to fetch */ + char *section; /* Message SECTION to fetch */ + char *partial; /* Message PARTIAL to fetch */ + char *query; /* Query to search for */ + char *custom; /* Custom request */ + char *custom_params; /* Parameters for the custom request */ +}; + /* imap_conn is used for struct connection-oriented data in the connectdata struct */ struct imap_conn { struct pingpong pp; - char *mailbox; /* what to FETCH */ - imapstate state; /* always use imap.c:state() to change state! */ - int cmdid; /* id number/index */ - const char *idstr; /* pointer to a string for which to wait for as id */ + imapstate state; /* Always use imap.c:state() to change state! */ + bool ssldone; /* Is connect() over SSL done? */ + struct SASL sasl; /* SASL-related parameters */ + unsigned int preftype; /* Preferred authentication type */ + int cmdid; /* Last used command ID */ + char resptag[5]; /* Response tag to wait for */ + bool tls_supported; /* StartTLS capability supported by server */ + bool login_disabled; /* LOGIN command disabled by server */ + bool ir_supported; /* Initial response supported by server */ + char *mailbox; /* The last selected mailbox */ + char *mailbox_uidvalidity; /* UIDVALIDITY parsed from select response */ }; extern const struct Curl_handler Curl_handler_imap; extern const struct Curl_handler Curl_handler_imaps; -#endif /* __IMAP_H */ +/* Authentication type flags */ +#define IMAP_TYPE_CLEARTEXT (1 << 0) +#define IMAP_TYPE_SASL (1 << 1) + +/* Authentication type values */ +#define IMAP_TYPE_NONE 0 +#define IMAP_TYPE_ANY ~0U + +#endif /* HEADER_CURL_IMAP_H */ diff --git a/project/jni/curl/lib/inet_ntop.c b/project/jni/curl/lib/inet_ntop.c index 26867f4d2..da9a3ab43 100644 --- a/project/jni/curl/lib/inet_ntop.c +++ b/project/jni/curl/lib/inet_ntop.c @@ -18,27 +18,21 @@ * Original code by Paul Vixie. "curlified" by Gisle Vanem. */ -#include "setup.h" +#include "curl_setup.h" #ifndef HAVE_INET_NTOP #ifdef HAVE_SYS_PARAM_H #include #endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif -#include -#include -#define _MPRINTF_REPLACE /* use our functions only */ -#include +#include "curl_printf.h" #include "inet_ntop.h" @@ -69,8 +63,7 @@ static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size) ((int)((unsigned char)src[3])) & 0xff); len = strlen(tmp); - if(len == 0 || len >= size) - { + if(len == 0 || len >= size) { SET_ERRNO(ENOSPC); return (NULL); } @@ -105,61 +98,51 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) * Find the longest run of 0x00's in src[] for :: shorthanding. */ memset(words, '\0', sizeof(words)); - for (i = 0; i < IN6ADDRSZ; i++) - words[i/2] |= (src[i] << ((1 - (i % 2)) << 3)); + for(i = 0; i < IN6ADDRSZ; i++) + words[i/2] |= (src[i] << ((1 - (i % 2)) << 3)); best.base = -1; cur.base = -1; best.len = 0; cur.len = 0; - for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) - { - if(words[i] == 0) - { + for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { + if(words[i] == 0) { if(cur.base == -1) cur.base = i, cur.len = 1; else cur.len++; } - else if(cur.base != -1) - { + else if(cur.base != -1) { if(best.base == -1 || cur.len > best.len) - best = cur; + best = cur; cur.base = -1; } } if((cur.base != -1) && (best.base == -1 || cur.len > best.len)) - best = cur; + best = cur; if(best.base != -1 && best.len < 2) - best.base = -1; - - /* Format the result. - */ + best.base = -1; + /* Format the result. */ tp = tmp; - for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) - { - /* Are we inside the best run of 0x00's? - */ - if(best.base != -1 && i >= best.base && i < (best.base + best.len)) - { + for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { + /* Are we inside the best run of 0x00's? */ + if(best.base != -1 && i >= best.base && i < (best.base + best.len)) { if(i == best.base) - *tp++ = ':'; + *tp++ = ':'; continue; } /* Are we following an initial run of 0x00s or any real hex? */ if(i != 0) - *tp++ = ':'; + *tp++ = ':'; /* Is this address an encapsulated IPv4? */ if(i == 6 && best.base == 0 && - (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) - { - if(!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp))) - { + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { + if(!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp))) { SET_ERRNO(ENOSPC); return (NULL); } @@ -177,8 +160,7 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) /* Check for overflow, copy, and we're done. */ - if((size_t)(tp - tmp) > size) - { + if((size_t)(tp - tmp) > size) { SET_ERRNO(ENOSPC); return (NULL); } @@ -195,9 +177,9 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) * error, EAFNOSUPPORT or ENOSPC. * * On Windows we store the error in the thread errno, not - * in the winsock error code. This is to avoid loosing the + * in the winsock error code. This is to avoid losing the * actual last winsock error. So use macro ERRNO to fetch the - * errno this funtion sets when returning NULL, not SOCKERRNO. + * errno this function sets when returning NULL, not SOCKERRNO. */ char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size) { diff --git a/project/jni/curl/lib/inet_ntop.h b/project/jni/curl/lib/inet_ntop.h index 8db9775c8..9f4461271 100644 --- a/project/jni/curl/lib/inet_ntop.h +++ b/project/jni/curl/lib/inet_ntop.h @@ -1,5 +1,5 @@ -#ifndef __INET_NTOP_H -#define __INET_NTOP_H +#ifndef HEADER_CURL_INET_NTOP_H +#define HEADER_CURL_INET_NTOP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,7 +22,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size); @@ -31,7 +31,8 @@ char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size); #include #endif #define Curl_inet_ntop(af,addr,buf,size) \ - inet_ntop(af,addr,buf,(curl_socklen_t)size) + inet_ntop(af, addr, buf, (curl_socklen_t)size) #endif -#endif /* __INET_NTOP_H */ +#endif /* HEADER_CURL_INET_NTOP_H */ + diff --git a/project/jni/curl/lib/inet_pton.c b/project/jni/curl/lib/inet_pton.c index 967e30fb1..cf8b88a1d 100644 --- a/project/jni/curl/lib/inet_pton.c +++ b/project/jni/curl/lib/inet_pton.c @@ -16,24 +16,19 @@ * SOFTWARE. */ -#include "setup.h" +#include "curl_setup.h" #ifndef HAVE_INET_PTON #ifdef HAVE_SYS_PARAM_H #include #endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif -#include -#include #include "inet_pton.h" @@ -61,9 +56,9 @@ static int inet_pton6(const char *src, unsigned char *dst); * -1 if some other error occurred (`dst' is untouched in this case, too) * notice: * On Windows we store the error in the thread errno, not - * in the winsock error code. This is to avoid loosing the + * in the winsock error code. This is to avoid losing the * actual last winsock error. So use macro ERRNO to fetch the - * errno this funtion sets when returning (-1), not SOCKERRNO. + * errno this function sets when returning (-1), not SOCKERRNO. * author: * Paul Vixie, 1996. */ @@ -193,8 +188,8 @@ inet_pton6(const char *src, unsigned char *dst) } if(tp + INT16SZ > endp) return (0); - *tp++ = (unsigned char) (val >> 8) & 0xff; - *tp++ = (unsigned char) val & 0xff; + *tp++ = (unsigned char) ((val >> 8) & 0xff); + *tp++ = (unsigned char) (val & 0xff); saw_xdigit = 0; val = 0; continue; @@ -210,8 +205,8 @@ inet_pton6(const char *src, unsigned char *dst) if(saw_xdigit) { if(tp + INT16SZ > endp) return (0); - *tp++ = (unsigned char) (val >> 8) & 0xff; - *tp++ = (unsigned char) val & 0xff; + *tp++ = (unsigned char) ((val >> 8) & 0xff); + *tp++ = (unsigned char) (val & 0xff); } if(colonp != NULL) { /* @@ -223,7 +218,7 @@ inet_pton6(const char *src, unsigned char *dst) if(tp == endp) return (0); - for (i = 1; i <= n; i++) { + for(i = 1; i <= n; i++) { *(endp - i) = *(colonp + n - i); *(colonp + n - i) = 0; } diff --git a/project/jni/curl/lib/inet_pton.h b/project/jni/curl/lib/inet_pton.h index d53fddff8..9188d9598 100644 --- a/project/jni/curl/lib/inet_pton.h +++ b/project/jni/curl/lib/inet_pton.h @@ -1,5 +1,5 @@ -#ifndef __INET_PTON_H -#define __INET_PTON_H +#ifndef HEADER_CURL_INET_PTON_H +#define HEADER_CURL_INET_PTON_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,7 +22,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" int Curl_inet_pton(int, const char *, void *); @@ -33,4 +33,5 @@ int Curl_inet_pton(int, const char *, void *); #define Curl_inet_pton(x,y,z) inet_pton(x,y,z) #endif -#endif /* __INET_PTON_H */ +#endif /* HEADER_CURL_INET_PTON_H */ + diff --git a/project/jni/curl/lib/krb4.c b/project/jni/curl/lib/krb4.c deleted file mode 100644 index 2895cedaa..000000000 --- a/project/jni/curl/lib/krb4.c +++ /dev/null @@ -1,431 +0,0 @@ -/* This source code was modified by Martin Hedenfalk for - * use in Curl. Martin's latest changes were done 2000-09-18. - * - * It has since been patched away like a madman by Daniel Stenberg to make it - * better applied to curl conditions, and to make it not use globals, pollute - * name space and more. - * - * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Hgskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * Copyright (c) 2004 - 2010 Daniel Stenberg - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#include "setup.h" - -#ifndef CURL_DISABLE_FTP -#ifdef HAVE_KRB4 - -#include -#ifdef HAVE_NETDB_H -#include -#endif -#include -#include -#include - -#ifdef HAVE_UNISTD_H -#include /* for getpid() */ -#endif - -#include "urldata.h" -#include "curl_base64.h" -#include "ftp.h" -#include "sendf.h" -#include "krb4.h" -#include "inet_ntop.h" -#include "curl_memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -#define LOCAL_ADDR (&conn->local_addr) -#define REMOTE_ADDR conn->ip_addr->ai_addr -#define myctladdr LOCAL_ADDR -#define hisctladdr REMOTE_ADDR - -struct krb4_data { - des_cblock key; - des_key_schedule schedule; - char name[ANAME_SZ]; - char instance[INST_SZ]; - char realm[REALM_SZ]; -}; - -#ifndef HAVE_STRLCPY -/* if it ever goes non-static, make it Curl_ prefixed! */ -static size_t -strlcpy (char *dst, const char *src, size_t dst_sz) -{ - size_t n; - char *p; - - for (p = dst, n = 0; - n + 1 < dst_sz && *src != '\0'; - ++p, ++src, ++n) - *p = *src; - *p = '\0'; - if(*src == '\0') - return n; - else - return n + strlen (src); -} -#else -size_t strlcpy (char *dst, const char *src, size_t dst_sz); -#endif - -static int -krb4_check_prot(void *app_data, int level) -{ - app_data = NULL; /* prevent compiler warning */ - if(level == PROT_CONFIDENTIAL) - return -1; - return 0; -} - -static int -krb4_decode(void *app_data, void *buf, int len, int level, - struct connectdata *conn) -{ - MSG_DAT m; - int e; - struct krb4_data *d = app_data; - - if(level == PROT_SAFE) - e = krb_rd_safe(buf, len, &d->key, - (struct sockaddr_in *)REMOTE_ADDR, - (struct sockaddr_in *)LOCAL_ADDR, &m); - else - e = krb_rd_priv(buf, len, d->schedule, &d->key, - (struct sockaddr_in *)REMOTE_ADDR, - (struct sockaddr_in *)LOCAL_ADDR, &m); - if(e) { - struct SessionHandle *data = conn->data; - infof(data, "krb4_decode: %s\n", krb_get_err_text(e)); - return -1; - } - memmove(buf, m.app_data, m.app_length); - return m.app_length; -} - -static int -krb4_overhead(void *app_data, int level, int len) -{ - /* no arguments are used, just init them to prevent compiler warnings */ - app_data = NULL; - level = 0; - len = 0; - return 31; -} - -static int -krb4_encode(void *app_data, const void *from, int length, int level, void **to, - struct connectdata *conn) -{ - struct krb4_data *d = app_data; - *to = malloc(length + 31); - if(!*to) - return -1; - if(level == PROT_SAFE) - /* NOTE that the void* cast is safe, krb_mk_safe/priv don't modify the - * input buffer - */ - return krb_mk_safe((void*)from, *to, length, &d->key, - (struct sockaddr_in *)LOCAL_ADDR, - (struct sockaddr_in *)REMOTE_ADDR); - else if(level == PROT_PRIVATE) - return krb_mk_priv((void*)from, *to, length, d->schedule, &d->key, - (struct sockaddr_in *)LOCAL_ADDR, - (struct sockaddr_in *)REMOTE_ADDR); - else - return -1; -} - -static int -mk_auth(struct krb4_data *d, KTEXT adat, - const char *service, char *host, int checksum) -{ - int ret; - CREDENTIALS cred; - char sname[SNAME_SZ], inst[INST_SZ], realm[REALM_SZ]; - - strlcpy(sname, service, sizeof(sname)); - strlcpy(inst, krb_get_phost(host), sizeof(inst)); - strlcpy(realm, krb_realmofhost(host), sizeof(realm)); - ret = krb_mk_req(adat, sname, inst, realm, checksum); - if(ret) - return ret; - strlcpy(sname, service, sizeof(sname)); - strlcpy(inst, krb_get_phost(host), sizeof(inst)); - strlcpy(realm, krb_realmofhost(host), sizeof(realm)); - ret = krb_get_cred(sname, inst, realm, &cred); - memmove(&d->key, &cred.session, sizeof(des_cblock)); - des_key_sched(&d->key, d->schedule); - memset(&cred, 0, sizeof(cred)); - return ret; -} - -#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM -int krb_get_our_ip_for_realm(char *, struct in_addr *); -#endif - -static int -krb4_auth(void *app_data, struct connectdata *conn) -{ - int ret; - char *p; - unsigned char *ptr; - size_t len; - KTEXT_ST adat; - MSG_DAT msg_data; - int checksum; - u_int32_t cs; - struct krb4_data *d = app_data; - char *host = conn->host.name; - ssize_t nread; - int l = sizeof(conn->local_addr); - struct SessionHandle *data = conn->data; - CURLcode result; - - if(getsockname(conn->sock[FIRSTSOCKET], - (struct sockaddr *)LOCAL_ADDR, &l) < 0) - perror("getsockname()"); - - checksum = getpid(); - ret = mk_auth(d, &adat, "ftp", host, checksum); - if(ret == KDC_PR_UNKNOWN) - ret = mk_auth(d, &adat, "rcmd", host, checksum); - if(ret) { - infof(data, "%s\n", krb_get_err_text(ret)); - return AUTH_CONTINUE; - } - -#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM - if(krb_get_config_bool("nat_in_use")) { - struct sockaddr_in *localaddr = (struct sockaddr_in *)LOCAL_ADDR; - struct in_addr natAddr; - - if(krb_get_our_ip_for_realm(krb_realmofhost(host), - &natAddr) != KSUCCESS - && krb_get_our_ip_for_realm(NULL, &natAddr) != KSUCCESS) - infof(data, "Can't get address for realm %s\n", - krb_realmofhost(host)); - else { - if(natAddr.s_addr != localaddr->sin_addr.s_addr) { - char addr_buf[128]; - if(Curl_inet_ntop(AF_INET, natAddr, addr_buf, sizeof(addr_buf))) - infof(data, "Using NAT IP address (%s) for kerberos 4\n", addr_buf); - localaddr->sin_addr = natAddr; - } - } - } -#endif - - if(Curl_base64_encode(conn->data, (char *)adat.dat, adat.length, &p) < 1) { - Curl_failf(data, "Out of memory base64-encoding"); - return AUTH_CONTINUE; - } - - result = Curl_ftpsendf(conn, "ADAT %s", p); - - free(p); - - if(result) - return -2; - - if(Curl_GetFTPResponse(&nread, conn, NULL)) - return -1; - - if(data->state.buffer[0] != '2'){ - Curl_failf(data, "Server didn't accept auth data"); - return AUTH_ERROR; - } - - p = strstr(data->state.buffer, "ADAT="); - if(!p) { - Curl_failf(data, "Remote host didn't send adat reply"); - return AUTH_ERROR; - } - p += 5; - len = Curl_base64_decode(p, &ptr); - if(len > sizeof(adat.dat)-1) { - free(ptr); - len=0; - } - if(!len || !ptr) { - Curl_failf(data, "Failed to decode base64 from server"); - return AUTH_ERROR; - } - memcpy((char *)adat.dat, ptr, len); - free(ptr); - adat.length = len; - ret = krb_rd_safe(adat.dat, adat.length, &d->key, - (struct sockaddr_in *)hisctladdr, - (struct sockaddr_in *)myctladdr, &msg_data); - if(ret) { - Curl_failf(data, "Error reading reply from server: %s", - krb_get_err_text(ret)); - return AUTH_ERROR; - } - krb_get_int(msg_data.app_data, &cs, 4, 0); - if(cs - checksum != 1) { - Curl_failf(data, "Bad checksum returned from server"); - return AUTH_ERROR; - } - return AUTH_OK; -} - -struct Curl_sec_client_mech Curl_krb4_client_mech = { - "KERBEROS_V4", - sizeof(struct krb4_data), - NULL, /* init */ - krb4_auth, - NULL, /* end */ - krb4_check_prot, - krb4_overhead, - krb4_encode, - krb4_decode -}; - -static enum protection_level -krb4_set_command_prot(struct connectdata *conn, enum protection_level level) -{ - enum protection_level old = conn->command_prot; - DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); - conn->command_prot = level; - return old; -} - -CURLcode Curl_krb_kauth(struct connectdata *conn) -{ - des_cblock key; - des_key_schedule schedule; - KTEXT_ST tkt, tktcopy; - char *name; - char *p; - char passwd[100]; - size_t tmp; - ssize_t nread; - enum protection_level save; - CURLcode result; - unsigned char *ptr; - - save = krb4_set_command_prot(conn, PROT_PRIVATE); - - result = Curl_ftpsendf(conn, "SITE KAUTH %s", conn->user); - - if(result) - return result; - - result = Curl_GetFTPResponse(&nread, conn, NULL); - if(result) - return result; - - if(conn->data->state.buffer[0] != '3'){ - krb4_set_command_prot(conn, save); - return CURLE_FTP_WEIRD_SERVER_REPLY; - } - - p = strstr(conn->data->state.buffer, "T="); - if(!p) { - Curl_failf(conn->data, "Bad reply from server"); - krb4_set_command_prot(conn, save); - return CURLE_FTP_WEIRD_SERVER_REPLY; - } - - p += 2; - tmp = Curl_base64_decode(p, &ptr); - if(tmp >= sizeof(tkt.dat)) { - free(ptr); - tmp=0; - } - if(!tmp || !ptr) { - Curl_failf(conn->data, "Failed to decode base64 in reply"); - krb4_set_command_prot(conn, save); - return CURLE_FTP_WEIRD_SERVER_REPLY; - } - memcpy((char *)tkt.dat, ptr, tmp); - free(ptr); - tkt.length = tmp; - tktcopy.length = tkt.length; - - p = strstr(conn->data->state.buffer, "P="); - if(!p) { - Curl_failf(conn->data, "Bad reply from server"); - krb4_set_command_prot(conn, save); - return CURLE_FTP_WEIRD_SERVER_REPLY; - } - name = p + 2; - for(; *p && *p != ' ' && *p != '\r' && *p != '\n'; p++); - *p = 0; - - des_string_to_key (conn->passwd, &key); - des_key_sched(&key, schedule); - - des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat, - tkt.length, - schedule, &key, DES_DECRYPT); - if(strcmp ((char*)tktcopy.dat + 8, - KRB_TICKET_GRANTING_TICKET) != 0) { - afs_string_to_key(passwd, - krb_realmofhost(conn->host.name), - &key); - des_key_sched(&key, schedule); - des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat, - tkt.length, - schedule, &key, DES_DECRYPT); - } - memset(key, 0, sizeof(key)); - memset(schedule, 0, sizeof(schedule)); - memset(passwd, 0, sizeof(passwd)); - if(Curl_base64_encode(conn->data, (char *)tktcopy.dat, tktcopy.length, &p) - < 1) { - failf(conn->data, "Out of memory base64-encoding."); - krb4_set_command_prot(conn, save); - return CURLE_OUT_OF_MEMORY; - } - memset (tktcopy.dat, 0, tktcopy.length); - - result = Curl_ftpsendf(conn, "SITE KAUTH %s %s", name, p); - free(p); - if(result) - return result; - - result = Curl_GetFTPResponse(&nread, conn, NULL); - if(result) - return result; - krb4_set_command_prot(conn, save); - - return CURLE_OK; -} - -#endif /* HAVE_KRB4 */ -#endif /* CURL_DISABLE_FTP */ diff --git a/project/jni/curl/lib/krb5.c b/project/jni/curl/lib/krb5.c index cedab1657..65869c99d 100644 --- a/project/jni/curl/lib/krb5.c +++ b/project/jni/curl/lib/krb5.c @@ -1,8 +1,8 @@ /* GSSAPI/krb5 support for FTP - loosely based on old krb4.c * - * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2010 Kungliga Tekniska Hgskolan + * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Hgskolan * (Royal Institute of Technology, Stockholm, Sweden). - * Copyright (c) 2004 - 2009 Daniel Stenberg + * Copyright (c) 2004 - 2016 Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,49 +32,27 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -#include "setup.h" +#include "curl_setup.h" -#ifndef CURL_DISABLE_FTP -#ifdef HAVE_GSSAPI +#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP) -#ifdef HAVE_OLD_GSSMIT -#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name -#endif - -#include #ifdef HAVE_NETDB_H #include #endif -#include - -#ifdef HAVE_GSSGNU -# include -#elif defined HAVE_GSSMIT - /* MIT style */ -# include -# include -# include -#else - /* Heimdal-style */ -# include -#endif #include "urldata.h" #include "curl_base64.h" #include "ftp.h" +#include "curl_gssapi.h" #include "sendf.h" -#include "krb4.h" +#include "curl_sec.h" +#include "warnless.h" +#include "curl_printf.h" + +/* The last #include files should be: */ #include "curl_memory.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ #include "memdebug.h" -#define LOCAL_ADDR (&conn->local_addr) -#define REMOTE_ADDR conn->ip_addr->ai_addr - static int krb5_init(void *app_data) { @@ -94,16 +72,16 @@ krb5_check_prot(void *app_data, int level) } static int -krb5_decode(void *app_data, void *buf, int len, int level, - struct connectdata *conn) +krb5_decode(void *app_data, void *buf, int len, + int level UNUSED_PARAM, + struct connectdata *conn UNUSED_PARAM) { gss_ctx_id_t *context = app_data; OM_uint32 maj, min; gss_buffer_desc enc, dec; - /* shut gcc up */ - level = 0; - conn = NULL; + (void)level; + (void)conn; enc.value = buf; enc.length = len; @@ -115,7 +93,7 @@ krb5_decode(void *app_data, void *buf, int len, int level, } memcpy(buf, dec.value, dec.length); - len = dec.length; + len = curlx_uztosi(dec.length); gss_release_buffer(&min, &dec); return len; @@ -124,16 +102,15 @@ krb5_decode(void *app_data, void *buf, int len, int level, static int krb5_overhead(void *app_data, int level, int len) { - /* no arguments are used, just init them to prevent compiler warnings */ - app_data = NULL; - level = 0; - len = 0; + /* no arguments are used */ + (void)app_data; + (void)level; + (void)len; return 0; } static int -krb5_encode(void *app_data, const void *from, int length, int level, void **to, - struct connectdata *conn) +krb5_encode(void *app_data, const void *from, int length, int level, void **to) { gss_ctx_id_t *context = app_data; gss_buffer_desc dec, enc; @@ -141,9 +118,6 @@ krb5_encode(void *app_data, const void *from, int length, int level, void **to, int state; int len; - /* shut gcc up */ - conn = NULL; - /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal * libraries modify the input buffer in gss_seal() */ @@ -157,12 +131,13 @@ krb5_encode(void *app_data, const void *from, int length, int level, void **to, if(maj != GSS_S_COMPLETE) return -1; - /* malloc a new buffer, in case gss_release_buffer doesn't work as expected */ + /* malloc a new buffer, in case gss_release_buffer doesn't work as + expected */ *to = malloc(enc.length); if(!*to) return -1; memcpy(*to, enc.value, enc.length); - len = enc.length; + len = curlx_uztosi(enc.length); gss_release_buffer(&min, &enc); return len; } @@ -183,24 +158,25 @@ krb5_auth(void *app_data, struct connectdata *conn) gss_name_t gssname; gss_ctx_id_t *context = app_data; struct gss_channel_bindings_struct chan; + size_t base64_sz = 0; + struct sockaddr_in **remote_addr = + (struct sockaddr_in **)&conn->ip_addr->ai_addr; if(getsockname(conn->sock[FIRSTSOCKET], - (struct sockaddr *)LOCAL_ADDR, &l) < 0) + (struct sockaddr *)&conn->local_addr, &l) < 0) perror("getsockname()"); chan.initiator_addrtype = GSS_C_AF_INET; chan.initiator_address.length = l - 4; - chan.initiator_address.value = - &((struct sockaddr_in *)LOCAL_ADDR)->sin_addr.s_addr; + chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr; chan.acceptor_addrtype = GSS_C_AF_INET; chan.acceptor_address.length = l - 4; - chan.acceptor_address.value = - &((struct sockaddr_in *)REMOTE_ADDR)->sin_addr.s_addr; + chan.acceptor_address.value = &(*remote_addr)->sin_addr.s_addr; chan.application_data.length = 0; chan.application_data.value = NULL; /* this loop will execute twice (once for service, once for host) */ - while(1) { + for(;;) { /* this really shouldn't be repeated here, but can't help it */ if(service == srv_host) { result = Curl_ftpsendf(conn, "AUTH GSSAPI"); @@ -222,7 +198,8 @@ krb5_auth(void *app_data, struct connectdata *conn) if(maj != GSS_S_COMPLETE) { gss_release_name(&min, &gssname); if(service == srv_host) { - Curl_failf(data, "Error importing service name %s", input_buffer.value); + Curl_failf(data, "Error importing service name %s", + input_buffer.value); return AUTH_ERROR; } service = srv_host; @@ -240,19 +217,16 @@ krb5_auth(void *app_data, struct connectdata *conn) taken care by a final gss_release_buffer. */ gss_release_buffer(&min, &output_buffer); ret = AUTH_OK; - maj = gss_init_sec_context(&min, - GSS_C_NO_CREDENTIAL, - context, - gssname, - GSS_C_NO_OID, - GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, - 0, - &chan, - gssresp, - NULL, - &output_buffer, - NULL, - NULL); + maj = Curl_gss_init_sec_context(data, + &min, + context, + gssname, + &Curl_krb5_mech_oid, + &chan, + gssresp, + &output_buffer, + TRUE, + NULL); if(gssresp) { free(_gssresp.value); @@ -266,9 +240,11 @@ krb5_auth(void *app_data, struct connectdata *conn) } if(output_buffer.length != 0) { - if(Curl_base64_encode(data, (char *)output_buffer.value, - output_buffer.length, &p) < 1) { - Curl_infof(data, "Out of memory base64-encoding\n"); + result = Curl_base64_encode(data, (char *)output_buffer.value, + output_buffer.length, &p, &base64_sz); + if(result) { + Curl_infof(data, "base64-encoding: %s\n", + curl_easy_strerror(result)); ret = AUTH_CONTINUE; break; } @@ -287,7 +263,7 @@ krb5_auth(void *app_data, struct connectdata *conn) break; } - if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3'){ + if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3') { Curl_infof(data, "Server didn't accept auth data\n"); ret = AUTH_ERROR; break; @@ -296,10 +272,12 @@ krb5_auth(void *app_data, struct connectdata *conn) p = data->state.buffer + 4; p = strstr(p, "ADAT="); if(p) { - _gssresp.length = Curl_base64_decode(p + 5, (unsigned char **) - &_gssresp.value); - if(_gssresp.length < 1) { - Curl_failf(data, "Out of memory base64-encoding\n"); + result = Curl_base64_decode(p + 5, + (unsigned char **)&_gssresp.value, + &_gssresp.length); + if(result) { + Curl_failf(data, "base64-decoding: %s", + curl_easy_strerror(result)); ret = AUTH_CONTINUE; break; } @@ -325,10 +303,13 @@ krb5_auth(void *app_data, struct connectdata *conn) static void krb5_end(void *app_data) { - OM_uint32 maj, min; + OM_uint32 min; gss_ctx_id_t *context = app_data; - if (*context != GSS_C_NO_CONTEXT) { - maj = gss_delete_sec_context(&min, context, GSS_C_NO_BUFFER); + if(*context != GSS_C_NO_CONTEXT) { +#ifdef DEBUGBUILD + OM_uint32 maj = +#endif + gss_delete_sec_context(&min, context, GSS_C_NO_BUFFER); DEBUGASSERT(maj == GSS_S_COMPLETE); } } @@ -345,5 +326,4 @@ struct Curl_sec_client_mech Curl_krb5_client_mech = { krb5_decode }; -#endif /* HAVE_GSSAPI */ -#endif /* CURL_DISABLE_FTP */ +#endif /* HAVE_GSSAPI && !CURL_DISABLE_FTP */ diff --git a/project/jni/curl/lib/ldap.c b/project/jni/curl/lib/ldap.c index 529e45212..4f4c7072a 100644 --- a/project/jni/curl/lib/ldap.c +++ b/project/jni/curl/lib/ldap.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,7 +20,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #if !defined(CURL_DISABLE_LDAP) && !defined(USE_OPENLDAP) @@ -35,18 +35,11 @@ * OpenLDAP library versions, USE_OPENLDAP shall not be defined. */ -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include -#include - -#ifdef CURL_LDAP_WIN /* Use Windows LDAP implementation. */ +#ifdef USE_WIN32_LDAP /* Use Windows LDAP implementation. */ # include # ifndef LDAP_VENDOR_NAME -# error Your Platform SDK is NOT sufficient for LDAP support! Update your Platform SDK, or disable LDAP support! +# error Your Platform SDK is NOT sufficient for LDAP support! \ + Update your Platform SDK, or disable LDAP support! # else # include # endif @@ -61,8 +54,13 @@ # endif /* HAVE_LDAP_SSL && HAVE_LDAP_SSL_H */ #endif -#ifdef HAVE_UNISTD_H -# include +/* These are macros in both (in above ) and typedefs + * in BoringSSL's + */ +#ifdef HAVE_BORINGSSL +# undef X509_NAME +# undef X509_CERT_PAIR +# undef X509_EXTENSIONS #endif #include "urldata.h" @@ -74,13 +72,14 @@ #include "strequal.h" #include "strtok.h" #include "curl_ldap.h" -#include "curl_memory.h" +#include "curl_multibyte.h" #include "curl_base64.h" #include "rawstr.h" +#include "connect.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #ifndef HAVE_LDAP_URL_PARSE @@ -88,13 +87,25 @@ /* Use our own implementation. */ typedef struct { - char *lud_host; - int lud_port; - char *lud_dn; - char **lud_attrs; - int lud_scope; - char *lud_filter; - char **lud_exts; + char *lud_host; + int lud_port; +#if defined(USE_WIN32_LDAP) + TCHAR *lud_dn; + TCHAR **lud_attrs; +#else + char *lud_dn; + char **lud_attrs; +#endif + int lud_scope; +#if defined(USE_WIN32_LDAP) + TCHAR *lud_filter; +#else + char *lud_filter; +#endif + char **lud_exts; + size_t lud_attrs_dups; /* how many were dup'ed, this field is not in the + "real" struct so can only be used in code + without HAVE_LDAP_URL_PARSE defined */ } CURL_LDAPURLDesc; #undef LDAPURLDesc @@ -112,11 +123,11 @@ static void _ldap_free_urldesc (LDAPURLDesc *ludp); #define LDAP_TRACE(x) do { \ _ldap_trace ("%u: ", __LINE__); \ _ldap_trace x; \ - } while(0) + } WHILE_FALSE static void _ldap_trace (const char *fmt, ...); #else - #define LDAP_TRACE(x) ((void)0) + #define LDAP_TRACE(x) Curl_nop_stmt #endif @@ -137,10 +148,13 @@ const struct Curl_handler Curl_handler_ldap = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_LDAP, /* defport */ - PROT_LDAP /* protocol */ + CURLPROTO_LDAP, /* protocol */ + PROTOPT_NONE /* flags */ }; #ifdef HAVE_LDAP_SSL @@ -159,31 +173,43 @@ const struct Curl_handler Curl_handler_ldaps = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_LDAPS, /* defport */ - PROT_LDAP | PROT_SSL /* protocol */ + CURLPROTO_LDAPS, /* protocol */ + PROTOPT_SSL /* flags */ }; #endif static CURLcode Curl_ldap(struct connectdata *conn, bool *done) { - CURLcode status = CURLE_OK; + CURLcode result = CURLE_OK; int rc = 0; LDAP *server = NULL; LDAPURLDesc *ludp = NULL; - LDAPMessage *result = NULL; + LDAPMessage *ldapmsg = NULL; LDAPMessage *entryIterator; int num = 0; struct SessionHandle *data=conn->data; int ldap_proto = LDAP_VERSION3; int ldap_ssl = 0; - char *val_b64; - size_t val_b64_sz; - curl_off_t dlsize=0; + char *val_b64 = NULL; + size_t val_b64_sz = 0; + curl_off_t dlsize = 0; #ifdef LDAP_OPT_NETWORK_TIMEOUT - struct timeval ldap_timeout = {10,0}; /* 10 sec connection/search timeout */ + struct timeval ldap_timeout = {10, 0}; /* 10 sec connection/search timeout */ +#endif +#if defined(USE_WIN32_LDAP) + TCHAR *host = NULL; + TCHAR *user = NULL; + TCHAR *passwd = NULL; +#else + char *host = NULL; + char *user = NULL; + char *passwd = NULL; #endif *done = TRUE; /* unconditionally */ @@ -198,16 +224,42 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) #endif if(rc != 0) { failf(data, "LDAP local: %s", ldap_err2string(rc)); - status = CURLE_LDAP_INVALID_URL; + result = CURLE_LDAP_INVALID_URL; goto quit; } /* Get the URL scheme ( either ldap or ldaps ) */ - if(conn->protocol & PROT_SSL) + if(conn->given->flags & PROTOPT_SSL) ldap_ssl = 1; infof(data, "LDAP local: trying to establish %s connection\n", ldap_ssl ? "encrypted" : "cleartext"); +#if defined(USE_WIN32_LDAP) + host = Curl_convert_UTF8_to_tchar(conn->host.name); + if(!host) { + result = CURLE_OUT_OF_MEMORY; + + goto quit; + } + + if(conn->bits.user_passwd) { + user = Curl_convert_UTF8_to_tchar(conn->user); + passwd = Curl_convert_UTF8_to_tchar(conn->passwd); + if(!user || !passwd) { + result = CURLE_OUT_OF_MEMORY; + + goto quit; + } + } +#else + host = conn->host.name; + + if(conn->bits.user_passwd) { + user = conn->user; + passwd = conn->passwd; + } +#endif + #ifdef LDAP_OPT_NETWORK_TIMEOUT ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout); #endif @@ -215,9 +267,9 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(ldap_ssl) { #ifdef HAVE_LDAP_SSL -#ifdef CURL_LDAP_WIN - /* Win32 LDAP SDK doesnt support insecure mode without CA! */ - server = ldap_sslinit(conn->host.name, (int)conn->port, 1); +#ifdef USE_WIN32_LDAP + /* Win32 LDAP SDK doesn't support insecure mode without CA! */ + server = ldap_sslinit(host, (int)conn->port, 1); ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON); #else int ldap_option; @@ -226,7 +278,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) rc = ldapssl_client_init(NULL, NULL); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } if(data->set.ssl.verifypeer) { @@ -238,7 +290,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(!ldap_ca) { failf(data, "LDAP local: ERROR %s CA cert not set!", (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM")); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } infof(data, "LDAP local: using %s CA cert '%s'\n", @@ -249,25 +301,25 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) failf(data, "LDAP local: ERROR setting %s CA cert: %s", (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"), ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } ldap_option = LDAPSSL_VERIFY_SERVER; - } else { - ldap_option = LDAPSSL_VERIFY_NONE; } + else + ldap_option = LDAPSSL_VERIFY_NONE; rc = ldapssl_set_verify_mode(ldap_option); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting cert verify mode: %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } - server = ldapssl_init(conn->host.name, (int)conn->port, 1); + server = ldapssl_init(host, (int)conn->port, 1); if(server == NULL) { - failf(data, "LDAP local: Cannot connect to %s:%hu", - conn->host.name, conn->port); - status = CURLE_COULDNT_CONNECT; + failf(data, "LDAP local: Cannot connect to %s:%ld", + conn->host.dispname, conn->port); + result = CURLE_COULDNT_CONNECT; goto quit; } #elif defined(LDAP_OPT_X_TLS) @@ -275,13 +327,13 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) /* OpenLDAP SDK supports BASE64 files. */ if((data->set.str[STRING_CERT_TYPE]) && (!Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "PEM"))) { - failf(data, "LDAP local: ERROR OpenLDAP does only support PEM cert-type!"); - status = CURLE_SSL_CERTPROBLEM; + failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!"); + result = CURLE_SSL_CERTPROBLEM; goto quit; } if(!ldap_ca) { failf(data, "LDAP local: ERROR PEM CA cert not set!"); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca); @@ -289,25 +341,26 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting PEM CA cert: %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } ldap_option = LDAP_OPT_X_TLS_DEMAND; - } else { - ldap_option = LDAP_OPT_X_TLS_NEVER; } + else + ldap_option = LDAP_OPT_X_TLS_NEVER; + rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting cert verify mode: %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } - server = ldap_init(conn->host.name, (int)conn->port); + server = ldap_init(host, (int)conn->port); if(server == NULL) { - failf(data, "LDAP local: Cannot connect to %s:%hu", - conn->host.name, conn->port); - status = CURLE_COULDNT_CONNECT; + failf(data, "LDAP local: Cannot connect to %s:%ld", + conn->host.dispname, conn->port); + result = CURLE_COULDNT_CONNECT; goto quit; } ldap_option = LDAP_OPT_X_TLS_HARD; @@ -315,7 +368,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } /* @@ -323,7 +376,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } */ @@ -332,119 +385,278 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) should check in first place if we can support LDAP SSL/TLS */ failf(data, "LDAP local: SSL/TLS not supported with this version " "of the OpenLDAP toolkit\n"); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; #endif #endif #endif /* CURL_LDAP_USE_SSL */ - } else { - server = ldap_init(conn->host.name, (int)conn->port); + } + else { + server = ldap_init(host, (int)conn->port); if(server == NULL) { - failf(data, "LDAP local: Cannot connect to %s:%hu", - conn->host.name, conn->port); - status = CURLE_COULDNT_CONNECT; + failf(data, "LDAP local: Cannot connect to %s:%ld", + conn->host.dispname, conn->port); + result = CURLE_COULDNT_CONNECT; goto quit; } } -#ifdef CURL_LDAP_WIN +#ifdef USE_WIN32_LDAP ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); #endif - rc = ldap_simple_bind_s(server, - conn->bits.user_passwd ? conn->user : NULL, - conn->bits.user_passwd ? conn->passwd : NULL); + rc = ldap_simple_bind_s(server, user, passwd); if(!ldap_ssl && rc != 0) { ldap_proto = LDAP_VERSION2; ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); - rc = ldap_simple_bind_s(server, - conn->bits.user_passwd ? conn->user : NULL, - conn->bits.user_passwd ? conn->passwd : NULL); + rc = ldap_simple_bind_s(server, user, passwd); } if(rc != 0) { - failf(data, "LDAP local: ldap_simple_bind_s %s", ldap_err2string(rc)); - status = CURLE_LDAP_CANNOT_BIND; - goto quit; - } - - rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope, - ludp->lud_filter, ludp->lud_attrs, 0, &result); - - if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) { - failf(data, "LDAP remote: %s", ldap_err2string(rc)); - status = CURLE_LDAP_SEARCH_FAILED; + failf(data, "LDAP local: ldap_simple_bind_s %s", ldap_err2string(rc)); + result = CURLE_LDAP_CANNOT_BIND; goto quit; } - for(num = 0, entryIterator = ldap_first_entry(server, result); + rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope, + ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg); + + if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) { + failf(data, "LDAP remote: %s", ldap_err2string(rc)); + result = CURLE_LDAP_SEARCH_FAILED; + goto quit; + } + + for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg); entryIterator; - entryIterator = ldap_next_entry(server, entryIterator), num++) - { + entryIterator = ldap_next_entry(server, entryIterator), num++) { BerElement *ber = NULL; +#if defined(USE_WIN32_LDAP) + TCHAR *attribute; +#else char *attribute; /*! suspicious that this isn't 'const' */ - char *dn = ldap_get_dn(server, entryIterator); +#endif int i; - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)dn, 0); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); - - dlsize += strlen(dn)+5; - - for (attribute = ldap_first_attribute(server, entryIterator, &ber); - attribute; - attribute = ldap_next_attribute(server, entryIterator, ber)) + /* Get the DN and write it to the client */ { - BerValue **vals = ldap_get_values_len(server, entryIterator, attribute); + char *name; + size_t name_len; +#if defined(USE_WIN32_LDAP) + TCHAR *dn = ldap_get_dn(server, entryIterator); + name = Curl_convert_tchar_to_UTF8(dn); + if(!name) { + ldap_memfree(dn); - if(vals != NULL) - { - for (i = 0; (vals[i] != NULL); i++) - { - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *) attribute, 0); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); - dlsize += strlen(attribute)+3; + result = CURLE_OUT_OF_MEMORY; - if((strlen(attribute) > 7) && - (strcmp(";binary", - (char *)attribute + - (strlen((char *)attribute) - 7)) == 0)) { + goto quit; + } +#else + char *dn = name = ldap_get_dn(server, entryIterator); +#endif + name_len = strlen(name); + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); + if(result) { +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(name); +#endif + ldap_memfree(dn); + + goto quit; + } + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *) name, + name_len); + if(result) { +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(name); +#endif + ldap_memfree(dn); + + goto quit; + } + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + if(result) { +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(name); +#endif + ldap_memfree(dn); + + goto quit; + } + + dlsize += name_len + 5; + +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(name); +#endif + ldap_memfree(dn); + } + + /* Get the attributes and write them to the client */ + for(attribute = ldap_first_attribute(server, entryIterator, &ber); + attribute; + attribute = ldap_next_attribute(server, entryIterator, ber)) { + BerValue **vals; + size_t attr_len; +#if defined(USE_WIN32_LDAP) + char *attr = Curl_convert_tchar_to_UTF8(attribute); + if(!attr) { + if(ber) + ber_free(ber, 0); + + result = CURLE_OUT_OF_MEMORY; + + goto quit; + } +#else + char *attr = attribute; +#endif + attr_len = strlen(attr); + + vals = ldap_get_values_len(server, entryIterator, attribute); + if(vals != NULL) { + for(i = 0; (vals[i] != NULL); i++) { + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + + result = Curl_client_write(conn, CLIENTWRITE_BODY, + (char *) attr, attr_len); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + + dlsize += attr_len + 3; + + if((attr_len > 7) && + (strcmp(";binary", (char *) attr + (attr_len - 7)) == 0)) { /* Binary attribute, encode to base64. */ - val_b64_sz = Curl_base64_encode(data, - vals[i]->bv_val, - vals[i]->bv_len, - &val_b64); + result = Curl_base64_encode(data, + vals[i]->bv_val, + vals[i]->bv_len, + &val_b64, + &val_b64_sz); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + if(val_b64_sz > 0) { - Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz); + result = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, + val_b64_sz); free(val_b64); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + dlsize += val_b64_sz; } } else { - Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val, - vals[i]->bv_len); + result = Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val, + vals[i]->bv_len); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + dlsize += vals[i]->bv_len; } - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + dlsize++; } /* Free memory used to store values */ ldap_value_free_len(vals); } - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + + /* Free the attribute as we are done with it */ +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + if(result) + goto quit; dlsize++; Curl_pgrsSetDownloadCounter(data, dlsize); - ldap_memfree(attribute); } - ldap_memfree(dn); + if(ber) ber_free(ber, 0); } quit: - if(result) { - ldap_msgfree(result); + if(ldapmsg) { + ldap_msgfree(ldapmsg); LDAP_TRACE (("Received %d entries\n", num)); } if(rc == LDAP_SIZELIMIT_EXCEEDED) @@ -458,11 +670,17 @@ quit: ldapssl_client_deinit(); #endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */ +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(passwd); + Curl_unicodefree(user); + Curl_unicodefree(host); +#endif + /* no data to transfer */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - conn->bits.close = TRUE; + connclose(conn, "LDAP connection always disable re-use"); - return status; + return result; } #ifdef DEBUG_LDAP @@ -506,61 +724,34 @@ static int str2scope (const char *p) /* * Split 'str' into strings separated by commas. - * Note: res[] points into 'str'. + * Note: out[] points into 'str'. */ -static char **split_str (char *str) +static bool split_str(char *str, char ***out, size_t *count) { - char **res, *lasts, *s; - int i; + char **res; + char *lasts; + char *s; + size_t i; + size_t items = 1; - for (i = 2, s = strchr(str,','); s; i++) - s = strchr(++s,','); + s = strchr(str, ','); + while(s) { + items++; + s = strchr(++s, ','); + } - res = calloc(i, sizeof(char*)); + res = calloc(items, sizeof(char *)); if(!res) - return NULL; + return FALSE; - for (i = 0, s = strtok_r(str, ",", &lasts); s; - s = strtok_r(NULL, ",", &lasts), i++) + for(i = 0, s = strtok_r(str, ",", &lasts); s && i < items; + s = strtok_r(NULL, ",", &lasts), i++) res[i] = s; - return res; -} -/* - * Unescape the LDAP-URL components - */ -static bool unescape_elements (void *data, LDAPURLDesc *ludp) -{ - int i; + *out = res; + *count = items; - if(ludp->lud_filter) { - ludp->lud_filter = curl_easy_unescape(data, ludp->lud_filter, 0, NULL); - if(!ludp->lud_filter) - return (FALSE); - } - - for (i = 0; ludp->lud_attrs && ludp->lud_attrs[i]; i++) { - ludp->lud_attrs[i] = curl_easy_unescape(data, ludp->lud_attrs[i], 0, NULL); - if(!ludp->lud_attrs[i]) - return (FALSE); - } - - for (i = 0; ludp->lud_exts && ludp->lud_exts[i]; i++) { - ludp->lud_exts[i] = curl_easy_unescape(data, ludp->lud_exts[i], 0, NULL); - if(!ludp->lud_exts[i]) - return (FALSE); - } - - if(ludp->lud_dn) { - char *dn = ludp->lud_dn; - char *new_dn = curl_easy_unescape(data, dn, 0, NULL); - - free(dn); - ludp->lud_dn = new_dn; - if(!new_dn) - return (FALSE); - } - return (TRUE); + return TRUE; } /* @@ -579,8 +770,11 @@ static bool unescape_elements (void *data, LDAPURLDesc *ludp) */ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) { - char *p, *q; - int i; + int rc = LDAP_SUCCESS; + char *path; + char *p; + char *q; + size_t i; if(!conn->data || !conn->data->state.path || @@ -592,85 +786,190 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) ludp->lud_port = conn->remote_port; ludp->lud_host = conn->host.name; - /* parse DN (Distinguished Name). - */ - ludp->lud_dn = strdup(conn->data->state.path+1); - if(!ludp->lud_dn) + /* Duplicate the path */ + p = path = strdup(conn->data->state.path + 1); + if(!path) return LDAP_NO_MEMORY; - p = strchr(ludp->lud_dn, '?'); - LDAP_TRACE (("DN '%.*s'\n", p ? (size_t)(p-ludp->lud_dn) : - strlen(ludp->lud_dn), ludp->lud_dn)); - - if(!p) - goto success; - - *p++ = '\0'; - - /* parse attributes. skip "??". - */ + /* Parse the DN (Distinguished Name) */ q = strchr(p, '?'); if(q) *q++ = '\0'; - if(*p && *p != '?') { - ludp->lud_attrs = split_str(p); - if(!ludp->lud_attrs) - return LDAP_NO_MEMORY; + if(*p) { + char *dn = p; + char *unescaped; - for (i = 0; ludp->lud_attrs[i]; i++) - LDAP_TRACE (("attr[%d] '%s'\n", i, ludp->lud_attrs[i])); + LDAP_TRACE (("DN '%s'\n", dn)); + + /* Unescape the DN */ + unescaped = curl_easy_unescape(conn->data, dn, 0, NULL); + if(!unescaped) { + rc = LDAP_NO_MEMORY; + + goto quit; + } + +#if defined(USE_WIN32_LDAP) + /* Convert the unescaped string to a tchar */ + ludp->lud_dn = Curl_convert_UTF8_to_tchar(unescaped); + + /* Free the unescaped string as we are done with it */ + Curl_unicodefree(unescaped); + + if(!ludp->lud_dn) { + rc = LDAP_NO_MEMORY; + + goto quit; + } +#else + ludp->lud_dn = unescaped; +#endif } p = q; if(!p) - goto success; + goto quit; - /* parse scope. skip "??" - */ + /* Parse the attributes. skip "??" */ q = strchr(p, '?'); if(q) *q++ = '\0'; - if(*p && *p != '?') { + if(*p) { + char **attributes; + size_t count = 0; + + /* Split the string into an array of attributes */ + if(!split_str(p, &attributes, &count)) { + rc = LDAP_NO_MEMORY; + + goto quit; + } + + /* Allocate our array (+1 for the NULL entry) */ +#if defined(USE_WIN32_LDAP) + ludp->lud_attrs = calloc(count + 1, sizeof(TCHAR *)); +#else + ludp->lud_attrs = calloc(count + 1, sizeof(char *)); +#endif + if(!ludp->lud_attrs) { + free(attributes); + + rc = LDAP_NO_MEMORY; + + goto quit; + } + + for(i = 0; i < count; i++) { + char *unescaped; + + LDAP_TRACE (("attr[%d] '%s'\n", i, attributes[i])); + + /* Unescape the attribute */ + unescaped = curl_easy_unescape(conn->data, attributes[i], 0, NULL); + if(!unescaped) { + free(attributes); + + rc = LDAP_NO_MEMORY; + + goto quit; + } + +#if defined(USE_WIN32_LDAP) + /* Convert the unescaped string to a tchar */ + ludp->lud_attrs[i] = Curl_convert_UTF8_to_tchar(unescaped); + + /* Free the unescaped string as we are done with it */ + Curl_unicodefree(unescaped); + + if(!ludp->lud_attrs[i]) { + free(attributes); + + rc = LDAP_NO_MEMORY; + + goto quit; + } +#else + ludp->lud_attrs[i] = unescaped; +#endif + + ludp->lud_attrs_dups++; + } + + free(attributes); + } + + p = q; + if(!p) + goto quit; + + /* Parse the scope. skip "??" */ + q = strchr(p, '?'); + if(q) + *q++ = '\0'; + + if(*p) { ludp->lud_scope = str2scope(p); - if(ludp->lud_scope == -1) - return LDAP_INVALID_SYNTAX; + if(ludp->lud_scope == -1) { + rc = LDAP_INVALID_SYNTAX; + + goto quit; + } LDAP_TRACE (("scope %d\n", ludp->lud_scope)); } p = q; if(!p) - goto success; + goto quit; - /* parse filter - */ + /* Parse the filter */ q = strchr(p, '?'); if(q) *q++ = '\0'; - if(!*p) - return LDAP_INVALID_SYNTAX; - ludp->lud_filter = p; - LDAP_TRACE (("filter '%s'\n", ludp->lud_filter)); + if(*p) { + char *filter = p; + char *unescaped; + + LDAP_TRACE (("filter '%s'\n", filter)); + + /* Unescape the filter */ + unescaped = curl_easy_unescape(conn->data, filter, 0, NULL); + if(!unescaped) { + rc = LDAP_NO_MEMORY; + + goto quit; + } + +#if defined(USE_WIN32_LDAP) + /* Convert the unescaped string to a tchar */ + ludp->lud_filter = Curl_convert_UTF8_to_tchar(unescaped); + + /* Free the unescaped string as we are done with it */ + Curl_unicodefree(unescaped); + + if(!ludp->lud_filter) { + rc = LDAP_NO_MEMORY; + + goto quit; + } +#else + ludp->lud_filter = unescaped; +#endif + } p = q; - if(!p) - goto success; + if(p && !*p) { + rc = LDAP_INVALID_SYNTAX; - /* parse extensions - */ - ludp->lud_exts = split_str(p); - if(!ludp->lud_exts) - return LDAP_NO_MEMORY; + goto quit; + } - for (i = 0; ludp->lud_exts[i]; i++) - LDAP_TRACE (("exts[%d] '%s'\n", i, ludp->lud_exts[i])); +quit: + free(path); - success: - if(!unescape_elements(conn->data, ludp)) - return LDAP_NO_MEMORY; - return LDAP_SUCCESS; + return rc; } static int _ldap_url_parse (const struct connectdata *conn, @@ -694,28 +993,20 @@ static int _ldap_url_parse (const struct connectdata *conn, static void _ldap_free_urldesc (LDAPURLDesc *ludp) { - int i; + size_t i; if(!ludp) - return; + return; - if(ludp->lud_dn) - free(ludp->lud_dn); - - if(ludp->lud_filter) - free(ludp->lud_filter); + free(ludp->lud_dn); + free(ludp->lud_filter); if(ludp->lud_attrs) { - for (i = 0; ludp->lud_attrs[i]; i++) - free(ludp->lud_attrs[i]); + for(i = 0; i < ludp->lud_attrs_dups; i++) + free(ludp->lud_attrs[i]); free(ludp->lud_attrs); } - if(ludp->lud_exts) { - for (i = 0; ludp->lud_exts[i]; i++) - free(ludp->lud_exts[i]); - free(ludp->lud_exts); - } free (ludp); } #endif /* !HAVE_LDAP_URL_PARSE */ diff --git a/project/jni/curl/lib/llist.c b/project/jni/curl/lib/llist.c index 71238fa73..04b23e77c 100644 --- a/project/jni/curl/lib/llist.c +++ b/project/jni/curl/lib/llist.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,10 +20,7 @@ * ***************************************************************************/ -#include "setup.h" - -#include -#include +#include "curl_setup.h" #include "llist.h" #include "curl_memory.h" @@ -31,6 +28,9 @@ /* this must be the last include file */ #include "memdebug.h" +/* + * @unittest: 1300 + */ static void llist_init(struct curl_llist *l, curl_llist_dtor dtor) { @@ -46,7 +46,7 @@ Curl_llist_alloc(curl_llist_dtor dtor) struct curl_llist *list; list = malloc(sizeof(struct curl_llist)); - if(NULL == list) + if(!list) return NULL; llist_init(list, dtor); @@ -62,6 +62,8 @@ Curl_llist_alloc(curl_llist_dtor dtor) * inserted first in the list. * * Returns: 1 on success and 0 on failure. + * + * @unittest: 1300 */ int Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e, @@ -101,6 +103,9 @@ Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e, return 1; } +/* + * @unittest: 1300 + */ int Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e, void *user) @@ -115,7 +120,8 @@ Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e, list->tail = NULL; else e->next->prev = NULL; - } else { + } + else { e->prev->next = e->next; if(!e->next) list->tail = e->prev; @@ -125,6 +131,10 @@ Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e, list->dtor(user, e->ptr); + e->ptr = NULL; + e->prev = NULL; + e->next = NULL; + free(e); --list->size; @@ -148,8 +158,12 @@ Curl_llist_count(struct curl_llist *list) return list->size; } +/* + * @unittest: 1300 + */ int Curl_llist_move(struct curl_llist *list, struct curl_llist_element *e, - struct curl_llist *to_list, struct curl_llist_element *to_e) + struct curl_llist *to_list, + struct curl_llist_element *to_e) { /* Remove element from list */ if(e == NULL || list->size == 0) diff --git a/project/jni/curl/lib/llist.h b/project/jni/curl/lib/llist.h index c33912a4b..39ff408ee 100644 --- a/project/jni/curl/lib/llist.h +++ b/project/jni/curl/lib/llist.h @@ -1,5 +1,5 @@ -#ifndef __LLIST_H -#define __LLIST_H +#ifndef HEADER_CURL_LLIST_H +#define HEADER_CURL_LLIST_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,7 +22,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #include typedef void (*curl_llist_dtor)(void *, void *); @@ -53,4 +53,5 @@ void Curl_llist_destroy(struct curl_llist *, void *); int Curl_llist_move(struct curl_llist *, struct curl_llist_element *, struct curl_llist *, struct curl_llist_element *); -#endif +#endif /* HEADER_CURL_LLIST_H */ + diff --git a/project/jni/curl/lib/md4.c b/project/jni/curl/lib/md4.c index ecf3bfcd8..60f73a28b 100644 --- a/project/jni/curl/lib/md4.c +++ b/project/jni/curl/lib/md4.c @@ -1,281 +1,304 @@ -/*- - Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved. - - License to copy and use this software is granted provided that it - is identified as the "RSA Data Security, Inc. MD4 Message-Digest - Algorithm" in all material mentioning or referencing this software - or this function. - - License is also granted to make and use derivative works provided - that such works are identified as "derived from the RSA Data - Security, Inc. MD4 Message-Digest Algorithm" in all material - mentioning or referencing the derived work. - - RSA Data Security, Inc. makes no representations concerning either - the merchantability of this software or the suitability of this - software for any particular purpose. It is provided "as is" - without express or implied warranty of any kind. - - These notices must be retained in any copies of any part of this - documentation and/or software. +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD4 Message-Digest Algorithm (RFC 1320). + * + * Homepage: + http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. In case + * this attempt to disclaim copyright and place the software in the public + * domain is deemed null and void, then the software is Copyright (c) 2001 + * Alexander Peslyak and it is hereby released to the general public under the + * following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. */ -#include "setup.h" +#include "curl_setup.h" -/* NSS crypto library does not provide the MD4 hash algorithm, so that we have - * a local implementation of it */ -#ifdef USE_NSS +/* NSS and OS/400 crypto library do not provide the MD4 hash algorithm, so + * that we have a local implementation of it */ +#if defined(USE_NSS) || defined(USE_OS400CRYPTO) #include "curl_md4.h" +#include "warnless.h" + +#ifndef HAVE_OPENSSL + #include -typedef unsigned int UINT4; +/* Any 32-bit or wider unsigned integer data type will do */ +typedef unsigned int MD4_u32plus; -typedef struct MD4Context { - UINT4 state[4]; /* state (ABCD) */ - UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ - unsigned char buffer[64]; /* input buffer */ +typedef struct { + MD4_u32plus lo, hi; + MD4_u32plus a, b, c, d; + unsigned char buffer[64]; + MD4_u32plus block[16]; } MD4_CTX; -/* Constants for MD4Transform routine. +static void MD4_Init(MD4_CTX *ctx); +static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size); +static void MD4_Final(unsigned char *result, MD4_CTX *ctx); + +/* + * The basic MD4 functions. + * + * F and G are optimized compared to their RFC 1320 definitions, with the + * optimization for F borrowed from Colin Plumb's MD5 implementation. */ -#define S11 3 -#define S12 7 -#define S13 11 -#define S14 19 -#define S21 3 -#define S22 5 -#define S23 9 -#define S24 13 -#define S31 3 -#define S32 9 -#define S33 11 -#define S34 15 +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) -static void MD4Transform(UINT4 [4], const unsigned char [64]); -static void Encode(unsigned char *, UINT4 *, unsigned int); -static void Decode(UINT4 *, const unsigned char *, unsigned int); - -static unsigned char PADDING[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* F, G and H are basic MD4 functions. +/* + * The MD4 transformation for all three rounds. */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define STEP(f, a, b, c, d, x, s) \ + (a) += f((b), (c), (d)) + (x); \ + (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); -/* ROTATE_LEFT rotates x left n bits. +/* + * SET reads 4 input bytes in little-endian byte order and stores them + * in a properly aligned word in host byte order. + * + * The check for little-endian architectures that tolerate unaligned + * memory accesses is just an optimization. Nothing will break if it + * doesn't work. */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define SET(n) \ + (*(MD4_u32plus *)&ptr[(n) * 4]) +#define GET(n) \ + SET(n) +#else +#define SET(n) \ + (ctx->block[(n)] = \ + (MD4_u32plus)ptr[(n) * 4] | \ + ((MD4_u32plus)ptr[(n) * 4 + 1] << 8) | \ + ((MD4_u32plus)ptr[(n) * 4 + 2] << 16) | \ + ((MD4_u32plus)ptr[(n) * 4 + 3] << 24)) +#define GET(n) \ + (ctx->block[(n)]) +#endif -/* FF, GG and HH are transformations for rounds 1, 2 and 3 */ -/* Rotation is separate from addition to prevent recomputation */ -#define FF(a, b, c, d, x, s) { \ - (a) += F ((b), (c), (d)) + (x); \ - (a) = ROTATE_LEFT ((a), (s)); \ - } -#define GG(a, b, c, d, x, s) { \ - (a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; \ - (a) = ROTATE_LEFT ((a), (s)); \ - } -#define HH(a, b, c, d, x, s) { \ - (a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; \ - (a) = ROTATE_LEFT ((a), (s)); \ +/* + * This processes one or more 64-byte data blocks, but does NOT update + * the bit counters. There are no alignment requirements. + */ +static const void *body(MD4_CTX *ctx, const void *data, unsigned long size) +{ + const unsigned char *ptr; + MD4_u32plus a, b, c, d; + MD4_u32plus saved_a, saved_b, saved_c, saved_d; + + ptr = (const unsigned char *)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + +/* Round 1 */ + STEP(F, a, b, c, d, SET(0), 3) + STEP(F, d, a, b, c, SET(1), 7) + STEP(F, c, d, a, b, SET(2), 11) + STEP(F, b, c, d, a, SET(3), 19) + STEP(F, a, b, c, d, SET(4), 3) + STEP(F, d, a, b, c, SET(5), 7) + STEP(F, c, d, a, b, SET(6), 11) + STEP(F, b, c, d, a, SET(7), 19) + STEP(F, a, b, c, d, SET(8), 3) + STEP(F, d, a, b, c, SET(9), 7) + STEP(F, c, d, a, b, SET(10), 11) + STEP(F, b, c, d, a, SET(11), 19) + STEP(F, a, b, c, d, SET(12), 3) + STEP(F, d, a, b, c, SET(13), 7) + STEP(F, c, d, a, b, SET(14), 11) + STEP(F, b, c, d, a, SET(15), 19) + +/* Round 2 */ + STEP(G, a, b, c, d, GET(0) + 0x5a827999, 3) + STEP(G, d, a, b, c, GET(4) + 0x5a827999, 5) + STEP(G, c, d, a, b, GET(8) + 0x5a827999, 9) + STEP(G, b, c, d, a, GET(12) + 0x5a827999, 13) + STEP(G, a, b, c, d, GET(1) + 0x5a827999, 3) + STEP(G, d, a, b, c, GET(5) + 0x5a827999, 5) + STEP(G, c, d, a, b, GET(9) + 0x5a827999, 9) + STEP(G, b, c, d, a, GET(13) + 0x5a827999, 13) + STEP(G, a, b, c, d, GET(2) + 0x5a827999, 3) + STEP(G, d, a, b, c, GET(6) + 0x5a827999, 5) + STEP(G, c, d, a, b, GET(10) + 0x5a827999, 9) + STEP(G, b, c, d, a, GET(14) + 0x5a827999, 13) + STEP(G, a, b, c, d, GET(3) + 0x5a827999, 3) + STEP(G, d, a, b, c, GET(7) + 0x5a827999, 5) + STEP(G, c, d, a, b, GET(11) + 0x5a827999, 9) + STEP(G, b, c, d, a, GET(15) + 0x5a827999, 13) + +/* Round 3 */ + STEP(H, a, b, c, d, GET(0) + 0x6ed9eba1, 3) + STEP(H, d, a, b, c, GET(8) + 0x6ed9eba1, 9) + STEP(H, c, d, a, b, GET(4) + 0x6ed9eba1, 11) + STEP(H, b, c, d, a, GET(12) + 0x6ed9eba1, 15) + STEP(H, a, b, c, d, GET(2) + 0x6ed9eba1, 3) + STEP(H, d, a, b, c, GET(10) + 0x6ed9eba1, 9) + STEP(H, c, d, a, b, GET(6) + 0x6ed9eba1, 11) + STEP(H, b, c, d, a, GET(14) + 0x6ed9eba1, 15) + STEP(H, a, b, c, d, GET(1) + 0x6ed9eba1, 3) + STEP(H, d, a, b, c, GET(9) + 0x6ed9eba1, 9) + STEP(H, c, d, a, b, GET(5) + 0x6ed9eba1, 11) + STEP(H, b, c, d, a, GET(13) + 0x6ed9eba1, 15) + STEP(H, a, b, c, d, GET(3) + 0x6ed9eba1, 3) + STEP(H, d, a, b, c, GET(11) + 0x6ed9eba1, 9) + STEP(H, c, d, a, b, GET(7) + 0x6ed9eba1, 11) + STEP(H, b, c, d, a, GET(15) + 0x6ed9eba1, 15) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while(size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; +} + +static void MD4_Init(MD4_CTX *ctx) +{ + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; + + ctx->lo = 0; + ctx->hi = 0; +} + +static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) +{ + MD4_u32plus saved_lo; + unsigned long used, available; + + saved_lo = ctx->lo; + if((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->hi++; + ctx->hi += (MD4_u32plus)size >> 29; + + used = saved_lo & 0x3f; + + if(used) { + available = 64 - used; + + if(size < available) { + memcpy(&ctx->buffer[used], data, size); + return; + } + + memcpy(&ctx->buffer[used], data, available); + data = (const unsigned char *)data + available; + size -= available; + body(ctx, ctx->buffer, 64); } -/* MD4 initialization. Begins an MD4 operation, writing a new context. - */ -static void MD4Init(MD4_CTX *context) -{ - context->count[0] = context->count[1] = 0; - - /* Load magic initialization constants. - */ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; -} - -/* MD4 block update operation. Continues an MD4 message-digest - operation, processing another message block, and updating the - context. - */ -static void MD4Update(MD4_CTX *context, const unsigned char *input, - unsigned int inputLen) -{ - unsigned int i, bufindex, partLen; - - /* Compute number of bytes mod 64 */ - bufindex = (unsigned int)((context->count[0] >> 3) & 0x3F); - /* Update number of bits */ - if ((context->count[0] += ((UINT4)inputLen << 3)) - < ((UINT4)inputLen << 3)) - context->count[1]++; - context->count[1] += ((UINT4)inputLen >> 29); - - partLen = 64 - bufindex; - /* Transform as many times as possible. - */ - if (inputLen >= partLen) { - memcpy(&context->buffer[bufindex], input, partLen); - MD4Transform (context->state, context->buffer); - - for (i = partLen; i + 63 < inputLen; i += 64) - MD4Transform (context->state, &input[i]); - - bufindex = 0; + if(size >= 64) { + data = body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; } - else - i = 0; - /* Buffer remaining input */ - memcpy(&context->buffer[bufindex], &input[i], inputLen-i); + memcpy(ctx->buffer, data, size); } -/* MD4 padding. */ -static void MD4Pad(MD4_CTX *context) +static void MD4_Final(unsigned char *result, MD4_CTX *ctx) { - unsigned char bits[8]; - unsigned int bufindex, padLen; + unsigned long used, available; - /* Save number of bits */ - Encode (bits, context->count, 8); + used = ctx->lo & 0x3f; - /* Pad out to 56 mod 64. - */ - bufindex = (unsigned int)((context->count[0] >> 3) & 0x3f); - padLen = (bufindex < 56) ? (56 - bufindex) : (120 - bufindex); - MD4Update (context, PADDING, padLen); + ctx->buffer[used++] = 0x80; - /* Append length (before padding) */ - MD4Update (context, bits, 8); -} + available = 64 - used; -/* MD4 finalization. Ends an MD4 message-digest operation, writing the - the message digest and zeroizing the context. - */ -static void MD4Final (unsigned char digest[16], MD4_CTX *context) -{ - /* Do padding */ - MD4Pad (context); - - /* Store state in digest */ - Encode (digest, context->state, 16); - - /* Zeroize sensitive information. - */ - memset(context, 0, sizeof(*context)); -} - -/* MD4 basic transformation. Transforms state based on block. - */ -static void MD4Transform (UINT4 state[4], const unsigned char block[64]) -{ - UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - - Decode (x, block, 64); - - /* Round 1 */ - FF (a, b, c, d, x[ 0], S11); /* 1 */ - FF (d, a, b, c, x[ 1], S12); /* 2 */ - FF (c, d, a, b, x[ 2], S13); /* 3 */ - FF (b, c, d, a, x[ 3], S14); /* 4 */ - FF (a, b, c, d, x[ 4], S11); /* 5 */ - FF (d, a, b, c, x[ 5], S12); /* 6 */ - FF (c, d, a, b, x[ 6], S13); /* 7 */ - FF (b, c, d, a, x[ 7], S14); /* 8 */ - FF (a, b, c, d, x[ 8], S11); /* 9 */ - FF (d, a, b, c, x[ 9], S12); /* 10 */ - FF (c, d, a, b, x[10], S13); /* 11 */ - FF (b, c, d, a, x[11], S14); /* 12 */ - FF (a, b, c, d, x[12], S11); /* 13 */ - FF (d, a, b, c, x[13], S12); /* 14 */ - FF (c, d, a, b, x[14], S13); /* 15 */ - FF (b, c, d, a, x[15], S14); /* 16 */ - - /* Round 2 */ - GG (a, b, c, d, x[ 0], S21); /* 17 */ - GG (d, a, b, c, x[ 4], S22); /* 18 */ - GG (c, d, a, b, x[ 8], S23); /* 19 */ - GG (b, c, d, a, x[12], S24); /* 20 */ - GG (a, b, c, d, x[ 1], S21); /* 21 */ - GG (d, a, b, c, x[ 5], S22); /* 22 */ - GG (c, d, a, b, x[ 9], S23); /* 23 */ - GG (b, c, d, a, x[13], S24); /* 24 */ - GG (a, b, c, d, x[ 2], S21); /* 25 */ - GG (d, a, b, c, x[ 6], S22); /* 26 */ - GG (c, d, a, b, x[10], S23); /* 27 */ - GG (b, c, d, a, x[14], S24); /* 28 */ - GG (a, b, c, d, x[ 3], S21); /* 29 */ - GG (d, a, b, c, x[ 7], S22); /* 30 */ - GG (c, d, a, b, x[11], S23); /* 31 */ - GG (b, c, d, a, x[15], S24); /* 32 */ - - /* Round 3 */ - HH (a, b, c, d, x[ 0], S31); /* 33 */ - HH (d, a, b, c, x[ 8], S32); /* 34 */ - HH (c, d, a, b, x[ 4], S33); /* 35 */ - HH (b, c, d, a, x[12], S34); /* 36 */ - HH (a, b, c, d, x[ 2], S31); /* 37 */ - HH (d, a, b, c, x[10], S32); /* 38 */ - HH (c, d, a, b, x[ 6], S33); /* 39 */ - HH (b, c, d, a, x[14], S34); /* 40 */ - HH (a, b, c, d, x[ 1], S31); /* 41 */ - HH (d, a, b, c, x[ 9], S32); /* 42 */ - HH (c, d, a, b, x[ 5], S33); /* 43 */ - HH (b, c, d, a, x[13], S34); /* 44 */ - HH (a, b, c, d, x[ 3], S31); /* 45 */ - HH (d, a, b, c, x[11], S32); /* 46 */ - HH (c, d, a, b, x[ 7], S33); /* 47 */ - HH (b, c, d, a, x[15], S34); /* 48 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* Zeroize sensitive information. - */ - memset(x, 0, sizeof(x)); -} - -/* Encodes input (UINT4) into output (unsigned char). Assumes len is - a multiple of 4. - */ -static void Encode(unsigned char *output, UINT4 *input, unsigned int len) -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) { - output[j] = (unsigned char)(input[i] & 0xff); - output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); - output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); - output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + if(available < 8) { + memset(&ctx->buffer[used], 0, available); + body(ctx, ctx->buffer, 64); + used = 0; + available = 64; } + + memset(&ctx->buffer[used], 0, available - 8); + + ctx->lo <<= 3; + ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff); + ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff); + ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff); + ctx->buffer[59] = curlx_ultouc((ctx->lo >> 24)&0xff); + ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff); + ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff); + ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff); + ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24); + + body(ctx, ctx->buffer, 64); + + result[0] = curlx_ultouc((ctx->a)&0xff); + result[1] = curlx_ultouc((ctx->a >> 8)&0xff); + result[2] = curlx_ultouc((ctx->a >> 16)&0xff); + result[3] = curlx_ultouc(ctx->a >> 24); + result[4] = curlx_ultouc((ctx->b)&0xff); + result[5] = curlx_ultouc((ctx->b >> 8)&0xff); + result[6] = curlx_ultouc((ctx->b >> 16)&0xff); + result[7] = curlx_ultouc(ctx->b >> 24); + result[8] = curlx_ultouc((ctx->c)&0xff); + result[9] = curlx_ultouc((ctx->c >> 8)&0xff); + result[10] = curlx_ultouc((ctx->c >> 16)&0xff); + result[11] = curlx_ultouc(ctx->c >> 24); + result[12] = curlx_ultouc((ctx->d)&0xff); + result[13] = curlx_ultouc((ctx->d >> 8)&0xff); + result[14] = curlx_ultouc((ctx->d >> 16)&0xff); + result[15] = curlx_ultouc(ctx->d >> 24); + + memset(ctx, 0, sizeof(*ctx)); } -/* Decodes input (unsigned char) into output (UINT4). Assumes len is - a multiple of 4. - */ -static void Decode (UINT4 *output, const unsigned char *input, unsigned int len) -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | - (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); -} +#endif void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len) { MD4_CTX ctx; - MD4Init(&ctx); - MD4Update(&ctx, input, (unsigned int)len); - MD4Final(output, &ctx); + MD4_Init(&ctx); + MD4_Update(&ctx, input, curlx_uztoui(len)); + MD4_Final(output, &ctx); } -#endif /* USE_NSS */ +#endif /* defined(USE_NSS) || defined(USE_OS400CRYPTO) */ diff --git a/project/jni/curl/lib/md5.c b/project/jni/curl/lib/md5.c index b3912c583..6df07dc06 100644 --- a/project/jni/curl/lib/md5.c +++ b/project/jni/curl/lib/md5.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,18 +20,46 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_CRYPTO_AUTH -#include - #include "curl_md5.h" #include "curl_hmac.h" +#include "warnless.h" -#ifdef USE_GNUTLS +#if defined(USE_GNUTLS_NETTLE) + +#include +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +typedef struct md5_ctx MD5_CTX; + +static void MD5_Init(MD5_CTX * ctx) +{ + md5_init(ctx); +} + +static void MD5_Update(MD5_CTX * ctx, + const unsigned char * input, + unsigned int inputLen) +{ + md5_update(ctx, inputLen, input); +} + +static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx) +{ + md5_digest(ctx, 16, digest); +} + +#elif defined(USE_GNUTLS) #include +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" typedef gcry_md_hd_t MD5_CTX; @@ -53,323 +81,405 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx) gcry_md_close(*ctx); } -#else - -#ifdef USE_SSLEAY +#elif defined(USE_OPENSSL) /* When OpenSSL is available we use the MD5-function from OpenSSL */ +#include +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" -# ifdef USE_OPENSSL -# include -# else -# include -# endif +#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ + (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ + (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ + (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000)) -#else /* USE_SSLEAY */ -/* When OpenSSL is not available we use this code segment */ +/* For Apple operating systems: CommonCrypto has the functions we need. + These functions are available on Tiger and later, as well as iOS 2.0 + and later. If you're building for an older cat, well, sorry. -/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All -rights reserved. + Declaring the functions as static like this seems to be a bit more + reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */ +# include +# define MD5_CTX CC_MD5_CTX +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" -License to copy and use this software is granted provided that it -is identified as the "RSA Data Security, Inc. MD5 Message-Digest -Algorithm" in all material mentioning or referencing this software -or this function. - -License is also granted to make and use derivative works provided -that such works are identified as "derived from the RSA Data -Security, Inc. MD5 Message-Digest Algorithm" in all material -mentioning or referencing the derived work. - -RSA Data Security, Inc. makes no representations concerning either -the merchantability of this software or the suitability of this -software for any particular purpose. It is provided "as is" -without express or implied warranty of any kind. - -These notices must be retained in any copies of any part of this -documentation and/or software. - */ - -/* UINT4 defines a four byte word */ -typedef unsigned int UINT4; - -/* MD5 context. */ -struct md5_ctx { - UINT4 state[4]; /* state (ABCD) */ - UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ - unsigned char buffer[64]; /* input buffer */ -}; - -typedef struct md5_ctx MD5_CTX; - -static void MD5_Init(struct md5_ctx *); -static void MD5_Update(struct md5_ctx *, const unsigned char *, unsigned int); -static void MD5_Final(unsigned char [16], struct md5_ctx *); - -/* Constants for MD5Transform routine. - */ - -#define S11 7 -#define S12 12 -#define S13 17 -#define S14 22 -#define S21 5 -#define S22 9 -#define S23 14 -#define S24 20 -#define S31 4 -#define S32 11 -#define S33 16 -#define S34 23 -#define S41 6 -#define S42 10 -#define S43 15 -#define S44 21 - -static void MD5Transform(UINT4 [4], const unsigned char [64]); -static void Encode(unsigned char *, UINT4 *, unsigned int); -static void Decode(UINT4 *, const unsigned char *, unsigned int); - -static const unsigned char PADDING[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* F, G, H and I are basic MD5 functions. - */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | (~z))) - -/* ROTATE_LEFT rotates x left n bits. - */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. -Rotation is separate from addition to prevent recomputation. - */ -#define FF(a, b, c, d, x, s, ac) { \ - (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) { \ - (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) { \ - (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) { \ - (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } - -/* MD5 initialization. Begins an MD5 operation, writing a new context. - */ -static void MD5_Init(struct md5_ctx *context) +static void MD5_Init(MD5_CTX *ctx) { - context->count[0] = context->count[1] = 0; - /* Load magic initialization constants. */ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; + CC_MD5_Init(ctx); } -/* MD5 block update operation. Continues an MD5 message-digest - operation, processing another message block, and updating the - context. - */ -static void MD5_Update (struct md5_ctx *context, /* context */ - const unsigned char *input, /* input block */ - unsigned int inputLen) /* length of input block */ +static void MD5_Update(MD5_CTX *ctx, + const unsigned char *input, + unsigned int inputLen) { - unsigned int i, bufindex, partLen; - - /* Compute number of bytes mod 64 */ - bufindex = (unsigned int)((context->count[0] >> 3) & 0x3F); - - /* Update number of bits */ - if((context->count[0] += ((UINT4)inputLen << 3)) - < ((UINT4)inputLen << 3)) - context->count[1]++; - context->count[1] += ((UINT4)inputLen >> 29); - - partLen = 64 - bufindex; - - /* Transform as many times as possible. */ - if(inputLen >= partLen) { - memcpy(&context->buffer[bufindex], input, partLen); - MD5Transform(context->state, context->buffer); - - for (i = partLen; i + 63 < inputLen; i += 64) - MD5Transform(context->state, &input[i]); - - bufindex = 0; - } - else - i = 0; - - /* Buffer remaining input */ - memcpy(&context->buffer[bufindex], &input[i], inputLen-i); + CC_MD5_Update(ctx, input, inputLen); } -/* MD5 finalization. Ends an MD5 message-digest operation, writing the - the message digest and zeroizing the context. -*/ -static void MD5_Final(unsigned char digest[16], /* message digest */ - struct md5_ctx *context) /* context */ +static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) { - unsigned char bits[8]; - unsigned int count, padLen; - - /* Save number of bits */ - Encode (bits, context->count, 8); - - /* Pad out to 56 mod 64. */ - count = (unsigned int)((context->count[0] >> 3) & 0x3f); - padLen = (count < 56) ? (56 - count) : (120 - count); - MD5_Update (context, PADDING, padLen); - - /* Append length (before padding) */ - MD5_Update (context, bits, 8); - - /* Store state in digest */ - Encode (digest, context->state, 16); - - /* Zeroize sensitive information. */ - memset ((void *)context, 0, sizeof (*context)); + CC_MD5_Final(digest, ctx); } -/* MD5 basic transformation. Transforms state based on block. */ -static void MD5Transform(UINT4 state[4], - const unsigned char block[64]) +#elif defined(_WIN32) + +#include +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +typedef struct { + HCRYPTPROV hCryptProv; + HCRYPTHASH hHash; +} MD5_CTX; + +static void MD5_Init(MD5_CTX *ctx) { - UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - - Decode (x, block, 64); - - /* Round 1 */ - FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ - FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ - FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ - FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ - FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ - FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ - FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ - FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ - FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ - FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ - FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ - GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ - GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ - GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ - GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ - GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ - GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ - GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ - GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ - GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ - GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ - HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ - HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ - HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ - HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ - HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ - HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ - HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ - HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ - HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ - II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ - II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ - II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ - II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ - II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ - II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ - II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ - II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ - II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* Zeroize sensitive information. */ - memset((void *)x, 0, sizeof (x)); -} - -/* Encodes input (UINT4) into output (unsigned char). Assumes len is - a multiple of 4. - */ -static void Encode (unsigned char *output, - UINT4 *input, - unsigned int len) -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) { - output[j] = (unsigned char)(input[i] & 0xff); - output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); - output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); - output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash); } } -/* Decodes input (unsigned char) into output (UINT4). Assumes len is - a multiple of 4. -*/ -static void Decode (UINT4 *output, - const unsigned char *input, - unsigned int len) +static void MD5_Update(MD5_CTX *ctx, + const unsigned char *input, + unsigned int inputLen) { - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | - (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); + CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); } -#endif /* USE_SSLEAY */ +static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) +{ + unsigned long length = 0; + CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0); + if(length == 16) + CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0); + if(ctx->hHash) + CryptDestroyHash(ctx->hHash); + if(ctx->hCryptProv) + CryptReleaseContext(ctx->hCryptProv, 0); +} -#endif /* USE_GNUTLS */ +#elif defined(USE_AXTLS) +#include +#include +#include +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" +#else +/* When no other crypto library is available we use this code segment */ +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. + */ + +#include + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* Any 32-bit or wider unsigned integer data type will do */ +typedef unsigned int MD5_u32plus; + +typedef struct { + MD5_u32plus lo, hi; + MD5_u32plus a, b, c, d; + unsigned char buffer[64]; + MD5_u32plus block[16]; +} MD5_CTX; + +static void MD5_Init(MD5_CTX *ctx); +static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size); +static void MD5_Final(unsigned char *result, MD5_CTX *ctx); + +/* + * The basic MD5 functions. + * + * F and G are optimized compared to their RFC 1321 definitions for + * architectures that lack an AND-NOT instruction, just like in Colin Plumb's + * implementation. + */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define H(x, y, z) (((x) ^ (y)) ^ (z)) +#define H2(x, y, z) ((x) ^ ((y) ^ (z))) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) + +/* + * The MD5 transformation for all four rounds. + */ +#define STEP(f, a, b, c, d, x, t, s) \ + (a) += f((b), (c), (d)) + (x) + (t); \ + (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ + (a) += (b); + +/* + * SET reads 4 input bytes in little-endian byte order and stores them + * in a properly aligned word in host byte order. + * + * The check for little-endian architectures that tolerate unaligned + * memory accesses is just an optimization. Nothing will break if it + * doesn't work. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define SET(n) \ + (*(MD5_u32plus *)&ptr[(n) * 4]) +#define GET(n) \ + SET(n) +#else +#define SET(n) \ + (ctx->block[(n)] = \ + (MD5_u32plus)ptr[(n) * 4] | \ + ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ + ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ + ((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) +#define GET(n) \ + (ctx->block[(n)]) +#endif + +/* + * This processes one or more 64-byte data blocks, but does NOT update + * the bit counters. There are no alignment requirements. + */ +static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) +{ + const unsigned char *ptr; + MD5_u32plus a, b, c, d; + MD5_u32plus saved_a, saved_b, saved_c, saved_d; + + ptr = (const unsigned char *)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + +/* Round 1 */ + STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) + STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) + STEP(F, c, d, a, b, SET(2), 0x242070db, 17) + STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) + STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) + STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) + STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) + STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) + STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) + STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) + STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) + STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) + STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) + STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) + STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) + STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) + +/* Round 2 */ + STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) + STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) + STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) + STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) + STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) + STEP(G, d, a, b, c, GET(10), 0x02441453, 9) + STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) + STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) + STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) + STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) + STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) + STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) + STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) + STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) + STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) + STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) + +/* Round 3 */ + STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) + STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11) + STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) + STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23) + STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) + STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11) + STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) + STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23) + STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) + STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11) + STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) + STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23) + STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) + STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11) + STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) + STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23) + +/* Round 4 */ + STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) + STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) + STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) + STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) + STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) + STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) + STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) + STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) + STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) + STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) + STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) + STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) + STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) + STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) + STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) + STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while(size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; +} + +static void MD5_Init(MD5_CTX *ctx) +{ + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; + + ctx->lo = 0; + ctx->hi = 0; +} + +static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) +{ + MD5_u32plus saved_lo; + unsigned long used, available; + + saved_lo = ctx->lo; + if((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->hi++; + ctx->hi += (MD5_u32plus)size >> 29; + + used = saved_lo & 0x3f; + + if(used) { + available = 64 - used; + + if(size < available) { + memcpy(&ctx->buffer[used], data, size); + return; + } + + memcpy(&ctx->buffer[used], data, available); + data = (const unsigned char *)data + available; + size -= available; + body(ctx, ctx->buffer, 64); + } + + if(size >= 64) { + data = body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; + } + + memcpy(ctx->buffer, data, size); +} + +static void MD5_Final(unsigned char *result, MD5_CTX *ctx) +{ + unsigned long used, available; + + used = ctx->lo & 0x3f; + + ctx->buffer[used++] = 0x80; + + available = 64 - used; + + if(available < 8) { + memset(&ctx->buffer[used], 0, available); + body(ctx, ctx->buffer, 64); + used = 0; + available = 64; + } + + memset(&ctx->buffer[used], 0, available - 8); + + ctx->lo <<= 3; + ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff); + ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff); + ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff); + ctx->buffer[59] = curlx_ultouc(ctx->lo >> 24); + ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff); + ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff); + ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff); + ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24); + + body(ctx, ctx->buffer, 64); + + result[0] = curlx_ultouc((ctx->a)&0xff); + result[1] = curlx_ultouc((ctx->a >> 8)&0xff); + result[2] = curlx_ultouc((ctx->a >> 16)&0xff); + result[3] = curlx_ultouc(ctx->a >> 24); + result[4] = curlx_ultouc((ctx->b)&0xff); + result[5] = curlx_ultouc((ctx->b >> 8)&0xff); + result[6] = curlx_ultouc((ctx->b >> 16)&0xff); + result[7] = curlx_ultouc(ctx->b >> 24); + result[8] = curlx_ultouc((ctx->c)&0xff); + result[9] = curlx_ultouc((ctx->c >> 8)&0xff); + result[10] = curlx_ultouc((ctx->c >> 16)&0xff); + result[11] = curlx_ultouc(ctx->c >> 24); + result[12] = curlx_ultouc((ctx->d)&0xff); + result[13] = curlx_ultouc((ctx->d >> 8)&0xff); + result[14] = curlx_ultouc((ctx->d >> 16)&0xff); + result[15] = curlx_ultouc(ctx->d >> 24); + + memset(ctx, 0, sizeof(*ctx)); +} + +#endif /* CRYPTO LIBS */ const HMAC_params Curl_HMAC_MD5[] = { { @@ -382,14 +492,69 @@ const HMAC_params Curl_HMAC_MD5[] = { } }; +const MD5_params Curl_DIGEST_MD5[] = { + { + (Curl_MD5_init_func) MD5_Init, /* Digest initialization function */ + (Curl_MD5_update_func) MD5_Update, /* Digest update function */ + (Curl_MD5_final_func) MD5_Final, /* Digest computation end function */ + sizeof(MD5_CTX), /* Size of digest context struct */ + 16 /* Result size */ + } +}; +/* + * @unittest: 1601 + */ void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */ const unsigned char *input) { MD5_CTX ctx; MD5_Init(&ctx); - MD5_Update(&ctx, input, (unsigned int)strlen((char *)input)); + MD5_Update(&ctx, input, curlx_uztoui(strlen((char *)input))); MD5_Final(outbuffer, &ctx); } +MD5_context *Curl_MD5_init(const MD5_params *md5params) +{ + MD5_context *ctxt; + + /* Create MD5 context */ + ctxt = malloc(sizeof *ctxt); + + if(!ctxt) + return ctxt; + + ctxt->md5_hashctx = malloc(md5params->md5_ctxtsize); + + if(!ctxt->md5_hashctx) { + free(ctxt); + return NULL; + } + + ctxt->md5_hash = md5params; + + (*md5params->md5_init_func)(ctxt->md5_hashctx); + + return ctxt; +} + +int Curl_MD5_update(MD5_context *context, + const unsigned char *data, + unsigned int len) +{ + (*context->md5_hash->md5_update_func)(context->md5_hashctx, data, len); + + return 0; +} + +int Curl_MD5_final(MD5_context *context, unsigned char *result) +{ + (*context->md5_hash->md5_final_func)(result, context->md5_hashctx); + + free(context->md5_hashctx); + free(context); + + return 0; +} + #endif /* CURL_DISABLE_CRYPTO_AUTH */ diff --git a/project/jni/curl/lib/memdebug.c b/project/jni/curl/lib/memdebug.c index 69e204b6a..804b5fa34 100644 --- a/project/jni/curl/lib/memdebug.c +++ b/project/jni/curl/lib/memdebug.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,38 +20,73 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifdef CURLDEBUG + #include -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#define _MPRINTF_REPLACE -#include +#include "curl_printf.h" #include "urldata.h" -#include -#include -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif #define MEMDEBUG_NODEFINES /* don't redefine the standard functions */ #include "curl_memory.h" #include "memdebug.h" #ifndef HAVE_ASSERT_H -# define assert(x) do { } while (0) +# define assert(x) Curl_nop_stmt +#endif + +/* + * Until 2011-08-17 libcurl's Memory Tracking feature also performed + * automatic malloc and free filling operations using 0xA5 and 0x13 + * values. Our own preinitialization of dynamically allocated memory + * might be useful when not using third party memory debuggers, but + * on the other hand this would fool memory debuggers into thinking + * that all dynamically allocated memory is properly initialized. + * + * As a default setting, libcurl's Memory Tracking feature no longer + * performs preinitialization of dynamically allocated memory on its + * own. If you know what you are doing, and really want to retain old + * behavior, you can achieve this compiling with preprocessor symbols + * CURL_MT_MALLOC_FILL and CURL_MT_FREE_FILL defined with appropriate + * values. + */ + +#ifdef CURL_MT_MALLOC_FILL +# if (CURL_MT_MALLOC_FILL < 0) || (CURL_MT_MALLOC_FILL > 0xff) +# error "invalid CURL_MT_MALLOC_FILL or out of range" +# endif +#endif + +#ifdef CURL_MT_FREE_FILL +# if (CURL_MT_FREE_FILL < 0) || (CURL_MT_FREE_FILL > 0xff) +# error "invalid CURL_MT_FREE_FILL or out of range" +# endif +#endif + +#if defined(CURL_MT_MALLOC_FILL) && defined(CURL_MT_FREE_FILL) +# if (CURL_MT_MALLOC_FILL == CURL_MT_FREE_FILL) +# error "CURL_MT_MALLOC_FILL same as CURL_MT_FREE_FILL" +# endif +#endif + +#ifdef CURL_MT_MALLOC_FILL +# define mt_malloc_fill(buf,len) memset((buf), CURL_MT_MALLOC_FILL, (len)) +#else +# define mt_malloc_fill(buf,len) Curl_nop_stmt +#endif + +#ifdef CURL_MT_FREE_FILL +# define mt_free_fill(buf,len) memset((buf), CURL_MT_FREE_FILL, (len)) +#else +# define mt_free_fill(buf,len) Curl_nop_stmt #endif struct memdebug { size_t size; union { + curl_off_t o; double d; void * p; } mem[1]; @@ -76,8 +111,8 @@ static long memsize = 0; /* set number of mallocs allowed */ void curl_memdebug(const char *logname) { if(!logfile) { - if(logname) - logfile = fopen(logname, "w"); + if(logname && *logname) + logfile = fopen(logname, FOPEN_WRITETEXT); else logfile = stderr; #ifdef MEMDEBUG_LOG_SYNC @@ -111,6 +146,7 @@ static bool countcheck(const char *func, int line, const char *source) /* log to stderr also */ fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n", source, line, func); + fflush(logfile); /* because it might crash now */ } SET_ERRNO(ENOMEM); return TRUE; /* RETURN ERROR! */ @@ -118,10 +154,6 @@ static bool countcheck(const char *func, int line, const char *source) else memsize--; /* countdown */ - /* log the countdown */ - if(source) - curl_memlog("LIMIT %s:%d %ld ALLOCS left\n", - source, line, memsize); } @@ -144,13 +176,15 @@ void *curl_domalloc(size_t wantedsize, int line, const char *source) mem = (Curl_cmalloc)(size); if(mem) { /* fill memory with junk */ - memset(mem->mem, 0xA5, wantedsize); + mt_malloc_fill(mem->mem, wantedsize); mem->size = wantedsize; } if(source) - curl_memlog("MEM %s:%d malloc(%zd) = %p\n", - source, line, wantedsize, mem ? mem->mem : 0); + curl_memlog("MEM %s:%d malloc(%zu) = %p\n", + source, line, wantedsize, + mem ? (void *)mem->mem : (void *)0); + return (mem ? mem->mem : NULL); } @@ -170,16 +204,15 @@ void *curl_docalloc(size_t wanted_elements, size_t wanted_size, user_size = wanted_size * wanted_elements; size = sizeof(struct memdebug) + user_size; - mem = (Curl_cmalloc)(size); - if(mem) { - /* fill memory with zeroes */ - memset(mem->mem, 0, user_size); + mem = (Curl_ccalloc)(1, size); + if(mem) mem->size = user_size; - } if(source) curl_memlog("MEM %s:%d calloc(%zu,%zu) = %p\n", - source, line, wanted_elements, wanted_size, mem?mem->mem:0); + source, line, wanted_elements, wanted_size, + mem ? (void *)mem->mem : (void *)0); + return (mem ? mem->mem : NULL); } @@ -201,11 +234,37 @@ char *curl_dostrdup(const char *str, int line, const char *source) if(source) curl_memlog("MEM %s:%d strdup(%p) (%zu) = %p\n", - source, line, str, len, mem); + source, line, (void *)str, len, (void *)mem); return mem; } +#if defined(WIN32) && defined(UNICODE) +wchar_t *curl_dowcsdup(const wchar_t *str, int line, const char *source) +{ + wchar_t *mem; + size_t wsiz, bsiz; + + assert(str != NULL); + + if(countcheck("wcsdup", line, source)) + return NULL; + + wsiz = wcslen(str) + 1; + bsiz = wsiz * sizeof(wchar_t); + + mem = curl_domalloc(bsiz, 0, NULL); /* NULL prevents logging */ + if(mem) + memcpy(mem, str, bsiz); + + if(source) + curl_memlog("MEM %s:%d wcsdup(%p) (%zu) = %p\n", + source, line, (void *)str, bsiz, (void *)mem); + + return mem; +} +#endif + /* We provide a realloc() that accepts a NULL as pointer, which then performs a malloc(). In order to work with ares. */ void *curl_dorealloc(void *ptr, size_t wantedsize, @@ -236,7 +295,8 @@ void *curl_dorealloc(void *ptr, size_t wantedsize, mem = (Curl_crealloc)(mem, size); if(source) curl_memlog("MEM %s:%d realloc(%p, %zu) = %p\n", - source, line, ptr, wantedsize, mem?mem->mem:NULL); + source, line, (void *)ptr, wantedsize, + mem ? (void *)mem->mem : (void *)0); if(mem) { mem->size = wantedsize; @@ -250,7 +310,7 @@ void curl_dofree(void *ptr, int line, const char *source) { struct memdebug *mem; - assert(ptr != NULL); + if(ptr) { #ifdef __INTEL_COMPILER # pragma warning(push) @@ -258,51 +318,77 @@ void curl_dofree(void *ptr, int line, const char *source) /* 1684: conversion from pointer to same-sized integral type */ #endif - mem = (void *)((char *)ptr - offsetof(struct memdebug, mem)); + mem = (void *)((char *)ptr - offsetof(struct memdebug, mem)); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif - /* destroy */ - memset(mem->mem, 0x13, mem->size); + /* destroy */ + mt_free_fill(mem->mem, mem->size); - /* free for real */ - (Curl_cfree)(mem); + /* free for real */ + (Curl_cfree)(mem); + } if(source) - curl_memlog("MEM %s:%d free(%p)\n", source, line, ptr); + curl_memlog("MEM %s:%d free(%p)\n", source, line, (void *)ptr); } curl_socket_t curl_socket(int domain, int type, int protocol, int line, const char *source) { const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? - "FD %s:%d socket() = %d\n" : - (sizeof(curl_socket_t) == sizeof(long)) ? - "FD %s:%d socket() = %ld\n" : - "FD %s:%d socket() = %zd\n" ; + "FD %s:%d socket() = %d\n" : + (sizeof(curl_socket_t) == sizeof(long)) ? + "FD %s:%d socket() = %ld\n" : + "FD %s:%d socket() = %zd\n"; curl_socket_t sockfd = socket(domain, type, protocol); + if(source && (sockfd != CURL_SOCKET_BAD)) curl_memlog(fmt, source, line, sockfd); + return sockfd; } +#ifdef HAVE_SOCKETPAIR +int curl_socketpair(int domain, int type, int protocol, + curl_socket_t socket_vector[2], + int line, const char *source) +{ + const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? + "FD %s:%d socketpair() = %d %d\n" : + (sizeof(curl_socket_t) == sizeof(long)) ? + "FD %s:%d socketpair() = %ld %ld\n" : + "FD %s:%d socketpair() = %zd %zd\n"; + + int res = socketpair(domain, type, protocol, socket_vector); + + if(source && (0 == res)) + curl_memlog(fmt, source, line, socket_vector[0], socket_vector[1]); + + return res; +} +#endif + curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen, int line, const char *source) { const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? - "FD %s:%d accept() = %d\n" : - (sizeof(curl_socket_t) == sizeof(long)) ? - "FD %s:%d accept() = %ld\n" : - "FD %s:%d accept() = %zd\n" ; + "FD %s:%d accept() = %d\n" : + (sizeof(curl_socket_t) == sizeof(long)) ? + "FD %s:%d accept() = %ld\n" : + "FD %s:%d accept() = %zd\n"; struct sockaddr *addr = (struct sockaddr *)saddr; curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen; + curl_socket_t sockfd = accept(s, addr, addrlen); + if(source && (sockfd != CURL_SOCKET_BAD)) curl_memlog(fmt, source, line, sockfd); + return sockfd; } @@ -310,10 +396,10 @@ curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen, void curl_mark_sclose(curl_socket_t sockfd, int line, const char *source) { const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? - "FD %s:%d sclose(%d)\n" : - (sizeof(curl_socket_t) == sizeof(long)) ? - "FD %s:%d sclose(%ld)\n" : - "FD %s:%d sclose(%zd)\n" ; + "FD %s:%d sclose(%d)\n": + (sizeof(curl_socket_t) == sizeof(long)) ? + "FD %s:%d sclose(%ld)\n": + "FD %s:%d sclose(%zd)\n"; if(source) curl_memlog(fmt, source, line, sockfd); @@ -331,9 +417,11 @@ FILE *curl_fopen(const char *file, const char *mode, int line, const char *source) { FILE *res=fopen(file, mode); + if(source) curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n", - source, line, file, mode, res); + source, line, file, mode, (void *)res); + return res; } @@ -342,9 +430,11 @@ FILE *curl_fdopen(int filedes, const char *mode, int line, const char *source) { FILE *res=fdopen(filedes, mode); + if(source) curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n", - source, line, filedes, mode, res); + source, line, filedes, mode, (void *)res); + return res; } #endif @@ -356,9 +446,11 @@ int curl_fclose(FILE *file, int line, const char *source) assert(file != NULL); res=fclose(file); + if(source) curl_memlog("FILE %s:%d fclose(%p)\n", - source, line, file); + source, line, (void *)file); + return res; } diff --git a/project/jni/curl/lib/memdebug.h b/project/jni/curl/lib/memdebug.h index 56b9f12b2..ce1a842af 100644 --- a/project/jni/curl/lib/memdebug.h +++ b/project/jni/curl/lib/memdebug.h @@ -1,6 +1,6 @@ +#ifndef HEADER_CURL_MEMDEBUG_H +#define HEADER_CURL_MEMDEBUG_H #ifdef CURLDEBUG -#ifndef _CURL_MEMDEBUG_H -#define _CURL_MEMDEBUG_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -8,11 +8,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -28,18 +28,11 @@ * as well as the library. Do not mix with library internals! */ -#include "setup.h" +#include "curl_setup.h" #include -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#include +#define CURL_MT_LOGFNAME_BUFSIZE 512 #define logfile curl_debuglogfile @@ -47,10 +40,17 @@ extern FILE *logfile; /* memory functions */ CURL_EXTERN void *curl_domalloc(size_t size, int line, const char *source); -CURL_EXTERN void *curl_docalloc(size_t elements, size_t size, int line, const char *source); -CURL_EXTERN void *curl_dorealloc(void *ptr, size_t size, int line, const char *source); +CURL_EXTERN void *curl_docalloc(size_t elements, size_t size, int line, + const char *source); +CURL_EXTERN void *curl_dorealloc(void *ptr, size_t size, int line, + const char *source); CURL_EXTERN void curl_dofree(void *ptr, int line, const char *source); CURL_EXTERN char *curl_dostrdup(const char *str, int line, const char *source); +#if defined(WIN32) && defined(UNICODE) +CURL_EXTERN wchar_t *curl_dowcsdup(const wchar_t *str, int line, + const char *source); +#endif + CURL_EXTERN void curl_memdebug(const char *logname); CURL_EXTERN void curl_memlimit(long limit); CURL_EXTERN void curl_memlog(const char *format, ...); @@ -64,6 +64,11 @@ CURL_EXTERN int curl_sclose(curl_socket_t sockfd, int line , const char *source); CURL_EXTERN curl_socket_t curl_accept(curl_socket_t s, void *a, void *alen, int line, const char *source); +#ifdef HAVE_SOCKETPAIR +CURL_EXTERN int curl_socketpair(int domain, int type, int protocol, + curl_socket_t socket_vector[2], + int line , const char *source); +#endif /* FILE functions */ CURL_EXTERN FILE *curl_fopen(const char *file, const char *mode, int line, @@ -84,11 +89,30 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source); #define realloc(ptr,size) curl_dorealloc(ptr, size, __LINE__, __FILE__) #define free(ptr) curl_dofree(ptr, __LINE__, __FILE__) +#ifdef WIN32 +# ifdef UNICODE +# undef wcsdup +# define wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__) +# undef _wcsdup +# define _wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__) +# undef _tcsdup +# define _tcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__) +# else +# undef _tcsdup +# define _tcsdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__) +# endif +#endif + +#undef socket #define socket(domain,type,protocol)\ - curl_socket(domain,type,protocol,__LINE__,__FILE__) + curl_socket(domain, type, protocol, __LINE__, __FILE__) #undef accept /* for those with accept as a macro */ #define accept(sock,addr,len)\ - curl_accept(sock,addr,len,__LINE__,__FILE__) + curl_accept(sock, addr, len, __LINE__, __FILE__) +#ifdef HAVE_SOCKETPAIR +#define socketpair(domain,type,protocol,socket_vector)\ + curl_socketpair(domain, type, protocol, socket_vector, __LINE__, __FILE__) +#endif #ifdef HAVE_GETADDRINFO #if defined(getaddrinfo) && defined(__osf__) @@ -96,25 +120,25 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source); our macro as for other platforms. Instead, we redefine the new name they define getaddrinfo to become! */ #define ogetaddrinfo(host,serv,hint,res) \ - curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__) + curl_dogetaddrinfo(host, serv, hint, res, __LINE__, __FILE__) #else #undef getaddrinfo #define getaddrinfo(host,serv,hint,res) \ - curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__) + curl_dogetaddrinfo(host, serv, hint, res, __LINE__, __FILE__) #endif #endif /* HAVE_GETADDRINFO */ #ifdef HAVE_GETNAMEINFO #undef getnameinfo #define getnameinfo(sa,salen,host,hostlen,serv,servlen,flags) \ - curl_dogetnameinfo(sa,salen,host,hostlen,serv,servlen,flags, __LINE__, \ - __FILE__) + curl_dogetnameinfo(sa, salen, host, hostlen, serv, servlen, flags, \ + __LINE__, __FILE__) #endif /* HAVE_GETNAMEINFO */ #ifdef HAVE_FREEADDRINFO #undef freeaddrinfo #define freeaddrinfo(data) \ - curl_dofreeaddrinfo(data,__LINE__,__FILE__) + curl_dofreeaddrinfo(data, __LINE__, __FILE__) #endif /* HAVE_FREEADDRINFO */ /* sclose is probably already defined, redefine it! */ @@ -131,9 +155,23 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source); #endif /* MEMDEBUG_NODEFINES */ -#endif /* _CURL_MEMDEBUG_H */ #endif /* CURLDEBUG */ +/* +** Following section applies even when CURLDEBUG is not defined. +*/ + #ifndef fake_sclose -#define fake_sclose(x) +#define fake_sclose(x) Curl_nop_stmt #endif + +/* + * Curl_safefree defined as a macro to allow MemoryTracking feature + * to log free() calls at same location where Curl_safefree is used. + * This macro also assigns NULL to given pointer when free'd. + */ + +#define Curl_safefree(ptr) \ + do { free((ptr)); (ptr) = NULL;} WHILE_FALSE + +#endif /* HEADER_CURL_MEMDEBUG_H */ diff --git a/project/jni/curl/lib/mprintf.c b/project/jni/curl/lib/mprintf.c index 536c0c247..f5fc9962f 100644 --- a/project/jni/curl/lib/mprintf.c +++ b/project/jni/curl/lib/mprintf.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1999 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1999 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -32,15 +32,10 @@ * * If you ever want truly portable and good *printf() clones, the project that * took on from here is named 'Trio' and you find more details on the trio web - * page at http://daniel.haxx.se/trio/ + * page at https://daniel.haxx.se/projects/trio/ */ -#include "setup.h" -#include -#include -#include -#include -#include +#include "curl_setup.h" #if defined(DJGPP) && (DJGPP_MINOR < 4) #undef _MPRINTF_REPLACE /* don't use x_was_used() here */ @@ -77,6 +72,19 @@ # endif #endif +/* + * Non-ANSI integer extensions + */ + +#if (defined(__BORLANDC__) && (__BORLANDC__ >= 0x520)) || \ + (defined(__WATCOMC__) && defined(__386__)) || \ + (defined(__POCC__) && defined(_MSC_VER)) || \ + (defined(_WIN32_WCE)) || \ + (defined(__MINGW32__)) || \ + (defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)) +# define MP_HAVE_INT_EXTENSIONS +#endif + /* * Max integer data types that mprintf.c is capable */ @@ -108,7 +116,7 @@ static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; done++; \ else \ return done; /* return immediately on failure */ \ - } while(0) + } WHILE_FALSE /* Data type to read from the arglist */ typedef enum { @@ -124,7 +132,7 @@ typedef enum { FORMAT_WIDTH /* For internal use */ } FormatType; -/* convertion and display flags */ +/* conversion and display flags */ enum { FLAGS_NEW = 0, FLAGS_SPACE = 1<<0, @@ -194,114 +202,29 @@ static long dprintf_DollarString(char *input, char **end) return 0; } -static int dprintf_IsQualifierNoDollar(char c) +static bool dprintf_IsQualifierNoDollar(const char *fmt) { - switch (c) { +#if defined(MP_HAVE_INT_EXTENSIONS) + if(!strncmp(fmt, "I32", 3) || !strncmp(fmt, "I64", 3)) { + return TRUE; + } +#endif + + switch(*fmt) { case '-': case '+': case ' ': case '#': case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'h': case 'l': case 'L': case 'z': case 'q': case '*': case 'O': - return 1; /* true */ - default: - return 0; /* false */ - } -} - -#ifdef DPRINTF_DEBUG2 -static void dprintf_Pass1Report(va_stack_t *vto, int max) -{ - int i; - char buffer[256]; - int bit; - int flags; - - for(i=0; i CURL_SIZEOF_LONG) + flags |= FLAGS_LONGLONG; +#else + flags |= FLAGS_LONG; +#endif + break; +#endif case 'l': if(flags & FLAGS_LONG) flags |= FLAGS_LONGLONG; @@ -480,11 +424,11 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, break; case 'x': vto[i].type = FORMAT_INT; - flags |= FLAGS_HEX; + flags |= FLAGS_HEX|FLAGS_UNSIGNED; break; case 'X': vto[i].type = FORMAT_INT; - flags |= FLAGS_HEX|FLAGS_UPPER; + flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED; break; case 'c': vto[i].type = FORMAT_INT; @@ -542,72 +486,66 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, } } -#ifdef DPRINTF_DEBUG2 - dprintf_Pass1Report(vto, max_param); -#endif - /* Read the arg list parameters into our data list */ - for (i=0; i$ sequence */ param=dprintf_DollarString(f, &f); @@ -739,23 +677,23 @@ static int dprintf_formatf( OUTCHAR(' '); break; } - if(p->flags & FLAGS_UNSIGNED) { - /* Decimal unsigned integer. */ - base = 10; - goto unsigned_number; - } if(p->flags & FLAGS_OCTAL) { /* Octal unsigned integer. */ base = 8; goto unsigned_number; } - if(p->flags & FLAGS_HEX) { + else if(p->flags & FLAGS_HEX) { /* Hexadecimal unsigned integer. */ digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; base = 16; goto unsigned_number; } + else if(p->flags & FLAGS_UNSIGNED) { + /* Decimal unsigned integer. */ + base = 10; + goto unsigned_number; + } /* Decimal integer. */ base = 10; @@ -853,7 +791,7 @@ static int dprintf_formatf( size_t len; str = (char *) p->data.str; - if( str == NULL) { + if(str == NULL) { /* Write null[] if there's space. */ if(prec == -1 || prec >= (long) sizeof(null) - 1) { str = null; @@ -866,11 +804,11 @@ static int dprintf_formatf( len = 0; } } + else if(prec != -1) + len = (size_t)prec; else len = strlen(str); - if(prec != -1 && (size_t) prec < len) - len = (size_t)prec; width -= (long)len; if(p->flags & FLAGS_ALT) @@ -880,7 +818,7 @@ static int dprintf_formatf( while(width-- > 0) OUTCHAR(' '); - while(len-- > 0) + while((len-- > 0) && *str) OUTCHAR(*str++); if(p->flags&FLAGS_LEFT) while(width-- > 0) @@ -914,7 +852,7 @@ static int dprintf_formatf( if(p->flags & FLAGS_LEFT) while(width-- > 0) OUTCHAR(' '); - for (point = strnil; *point != '\0'; ++point) + for(point = strnil; *point != '\0'; ++point) OUTCHAR(*point); if(! (p->flags & FLAGS_LEFT)) while(width-- > 0) @@ -926,7 +864,7 @@ static int dprintf_formatf( case FORMAT_DOUBLE: { char formatbuf[32]="%"; - char *fptr; + char *fptr = &formatbuf[1]; size_t left = sizeof(formatbuf)-strlen(formatbuf); int len; @@ -943,15 +881,15 @@ static int dprintf_formatf( prec = (long)vto[p->precision].data.num.as_signed; if(p->flags & FLAGS_LEFT) - strcat(formatbuf, "-"); + *fptr++ = '-'; if(p->flags & FLAGS_SHOWSIGN) - strcat(formatbuf, "+"); + *fptr++ = '+'; if(p->flags & FLAGS_SPACE) - strcat(formatbuf, " "); + *fptr++ = ' '; if(p->flags & FLAGS_ALT) - strcat(formatbuf, "#"); + *fptr++ = '#'; - fptr=&formatbuf[strlen(formatbuf)]; + *fptr = 0; if(width >= 0) { /* RECURSIVE USAGE */ @@ -976,8 +914,8 @@ static int dprintf_formatf( *fptr = 0; /* and a final zero termination */ - /* NOTE NOTE NOTE!! Not all sprintf() implementations returns number - of output characters */ + /* NOTE NOTE NOTE!! Not all sprintf implementations return number of + output characters */ (sprintf)(work, formatbuf, p->data.dnum); for(fptr=work; *fptr; fptr++) @@ -1202,45 +1140,3 @@ int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save) { return dprintf_formatf(whereto, fputc, format, ap_save); } - -#ifdef DPRINTF_DEBUG -int main() -{ - char buffer[129]; - char *ptr; -#ifdef HAVE_LONG_LONG_TYPE - LONG_LONG_TYPE one=99; - LONG_LONG_TYPE two=100; - LONG_LONG_TYPE test = 0x1000000000LL; - curl_mprintf("%lld %lld %lld\n", one, two, test); -#endif - - curl_mprintf("%3d %5d\n", 10, 1998); - - ptr=curl_maprintf("test this then baby %s%s%s%s%s%s %d %d %d loser baby get a kiss in yer face now!", "", "pretty long string pretty long string pretty long string pretty long string pretty long string", "/", "/", "/", "pretty long string", 1998, 1999, 2001); - - puts(ptr); - - memset(ptr, 55, strlen(ptr)+1); - - free(ptr); - -#if 1 - curl_mprintf(buffer, "%s %s %d", "daniel", "stenberg", 19988); - puts(buffer); - - curl_mfprintf(stderr, "%s %#08x\n", "dummy", 65); - - printf("%s %#08x\n", "dummy", 65); - { - double tryout = 3.14156592; - curl_mprintf(buffer, "%.2g %G %f %e %E", tryout, tryout, tryout, tryout, tryout); - puts(buffer); - printf("%.2g %G %f %e %E\n", tryout, tryout, tryout, tryout, tryout); - } -#endif - - return 0; -} - -#endif diff --git a/project/jni/curl/lib/multi.c b/project/jni/curl/lib/multi.c index ff4bf861b..a147963f8 100644 --- a/project/jni/curl/lib/multi.c +++ b/project/jni/curl/lib/multi.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,14 +20,7 @@ * ***************************************************************************/ -#include "setup.h" - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif +#include "curl_setup.h" #include @@ -37,15 +30,19 @@ #include "connect.h" #include "progress.h" #include "easyif.h" +#include "share.h" #include "multiif.h" #include "sendf.h" #include "timeval.h" #include "http.h" +#include "select.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "speedcheck.h" +#include "conncache.h" +#include "multihandle.h" +#include "pipeline.h" +#include "sigpipe.h" +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -59,152 +56,32 @@ #define CURL_SOCKET_HASH_TABLE_SIZE 911 #endif -struct Curl_message { - /* the 'CURLMsg' is the part that is visible to the external user */ - struct CURLMsg extmsg; -}; - -/* NOTE: if you add a state here, add the name to the statename[] array as - well! -*/ -typedef enum { - CURLM_STATE_INIT, /* 0 - start in this state */ - CURLM_STATE_CONNECT, /* 1 - resolve/connect has been sent off */ - CURLM_STATE_WAITRESOLVE, /* 2 - awaiting the resolve to finalize */ - CURLM_STATE_WAITCONNECT, /* 3 - awaiting the connect to finalize */ - CURLM_STATE_WAITPROXYCONNECT, /* 4 - awaiting proxy CONNECT to finalize */ - CURLM_STATE_PROTOCONNECT, /* 5 - completing the protocol-specific connect - phase */ - CURLM_STATE_WAITDO, /* 6 - wait for our turn to send the request */ - CURLM_STATE_DO, /* 7 - start send off the request (part 1) */ - CURLM_STATE_DOING, /* 8 - sending off the request (part 1) */ - CURLM_STATE_DO_MORE, /* 9 - send off the request (part 2) */ - CURLM_STATE_DO_DONE, /* 10 - done sending off request */ - CURLM_STATE_WAITPERFORM, /* 11 - wait for our turn to read the response */ - CURLM_STATE_PERFORM, /* 12 - transfer data */ - CURLM_STATE_TOOFAST, /* 13 - wait because limit-rate exceeded */ - CURLM_STATE_DONE, /* 14 - post data transfer operation */ - CURLM_STATE_COMPLETED, /* 15 - operation complete */ - CURLM_STATE_MSGSENT, /* 16 - the operation complete message is sent */ - CURLM_STATE_LAST /* 17 - not a true state, never use this */ -} CURLMstate; - -/* we support N sockets per easy handle. Set the corresponding bit to what - action we should wait for */ -#define MAX_SOCKSPEREASYHANDLE 5 -#define GETSOCK_READABLE (0x00ff) -#define GETSOCK_WRITABLE (0xff00) - -struct closure { - struct closure *next; /* a simple one-way list of structs */ - struct SessionHandle *easy_handle; -}; - -struct Curl_one_easy { - /* first, two fields for the linked list of these */ - struct Curl_one_easy *next; - struct Curl_one_easy *prev; - - struct SessionHandle *easy_handle; /* the easy handle for this unit */ - struct connectdata *easy_conn; /* the "unit's" connection */ - - CURLMstate state; /* the handle's state */ - CURLcode result; /* previous result */ - - struct Curl_message msg; /* A single posted message. */ - - /* Array with the plain socket numbers this handle takes care of, in no - particular order. Note that all sockets are added to the sockhash, where - the state etc are also kept. This array is mostly used to detect when a - socket is to be removed from the hash. See singlesocket(). */ - curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE]; - int numsocks; -}; +#define CURL_CONNECTION_HASH_SIZE 97 #define CURL_MULTI_HANDLE 0x000bab1e #define GOOD_MULTI_HANDLE(x) \ - ((x)&&(((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE)) -#define GOOD_EASY_HANDLE(x) \ - (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER) + ((x) && (((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE)) -/* This is the struct known as CURLM on the outside */ -struct Curl_multi { - /* First a simple identifier to easier detect if a user mix up - this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */ - long type; - - /* We have a linked list with easy handles */ - struct Curl_one_easy easy; - - int num_easy; /* amount of entries in the linked list above. */ - int num_alive; /* amount of easy handles that are added but have not yet - reached COMPLETE state */ - - struct curl_llist *msglist; /* a list of messages from completed transfers */ - - /* callback function and user data pointer for the *socket() API */ - curl_socket_callback socket_cb; - void *socket_userp; - - /* Hostname cache */ - struct curl_hash *hostcache; - - /* timetree points to the splay-tree of time nodes to figure out expire - times of all currently set timers */ - struct Curl_tree *timetree; - - /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note - the pluralis form, there can be more than one easy handle waiting on the - same actual socket) */ - struct curl_hash *sockhash; - - /* Whether pipelining is enabled for this multi handle */ - bool pipelining_enabled; - - /* shared connection cache */ - struct conncache *connc; - long maxconnects; /* if >0, a fixed limit of the maximum number of entries - we're allowed to grow the connection cache to */ - - /* list of easy handles kept around for doing nice connection closures */ - struct closure *closure; - - /* timer callback and user data pointer for the *socket() API */ - curl_multi_timer_callback timer_cb; - void *timer_userp; - struct timeval timer_lastcall; /* the fixed time for the timeout for the - previous callback */ -}; - -static void multi_connc_remove_handle(struct Curl_multi *multi, - struct SessionHandle *data); static void singlesocket(struct Curl_multi *multi, - struct Curl_one_easy *easy); -static CURLMcode add_closure(struct Curl_multi *multi, - struct SessionHandle *data); + struct SessionHandle *data); static int update_timer(struct Curl_multi *multi); -static CURLcode addHandleToSendOrPendPipeline(struct SessionHandle *handle, - struct connectdata *conn); -static int checkPendPipeline(struct connectdata *conn); -static void moveHandleFromSendToRecvPipeline(struct SessionHandle *handle, - struct connectdata *conn); -static void moveHandleFromRecvToDonePipeline(struct SessionHandle *handle, - struct connectdata *conn); -static bool isHandleAtHead(struct SessionHandle *handle, - struct curl_llist *pipeline); static CURLMcode add_next_timeout(struct timeval now, struct Curl_multi *multi, struct SessionHandle *d); +static CURLMcode multi_timeout(struct Curl_multi *multi, + long *timeout_ms); #ifdef DEBUGBUILD static const char * const statename[]={ "INIT", + "CONNECT_PEND", "CONNECT", "WAITRESOLVE", "WAITCONNECT", "WAITPROXYCONNECT", + "SENDPROTOCONNECT", "PROTOCONNECT", "WAITDO", "DO", @@ -222,44 +99,70 @@ static const char * const statename[]={ static void multi_freetimeout(void *a, void *b); +/* function pointer called once when switching TO a state */ +typedef void (*init_multistate_func)(struct SessionHandle *data); + /* always use this function to change state, to make debugging easier */ -static void multistate(struct Curl_one_easy *easy, CURLMstate state) -{ +static void mstate(struct SessionHandle *data, CURLMstate state #ifdef DEBUGBUILD - long connectindex = -5000; + , int lineno +#endif +) +{ + CURLMstate oldstate = data->mstate; + static const init_multistate_func finit[CURLM_STATE_LAST] = { + NULL, + NULL, + Curl_init_CONNECT, /* CONNECT */ + /* the rest is NULL too */ + }; + +#if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) lineno; #endif - CURLMstate oldstate = easy->state; if(oldstate == state) /* don't bother when the new state is the same as the old state */ return; - easy->state = state; + data->mstate = state; -#ifdef DEBUGBUILD - if(easy->easy_conn) { - if(easy->state > CURLM_STATE_CONNECT && - easy->state < CURLM_STATE_COMPLETED) - connectindex = easy->easy_conn->connectindex; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + if(data->mstate >= CURLM_STATE_CONNECT_PEND && + data->mstate < CURLM_STATE_COMPLETED) { + long connection_id = -5000; - infof(easy->easy_handle, - "STATE: %s => %s handle %p; (connection #%ld) \n", - statename[oldstate], statename[easy->state], - (char *)easy, connectindex); + if(data->easy_conn) + connection_id = data->easy_conn->connection_id; + + infof(data, + "STATE: %s => %s handle %p; line %d (connection #%ld) \n", + statename[oldstate], statename[data->mstate], + (void *)data, lineno, connection_id); } #endif + if(state == CURLM_STATE_COMPLETED) /* changing to COMPLETED means there's one less easy handle 'alive' */ - easy->easy_handle->multi->num_alive--; + data->multi->num_alive--; + + /* if this state has an init-function, run it */ + if(finit[state]) + finit[state](data); } +#ifndef DEBUGBUILD +#define multistate(x,y) mstate(x,y) +#else +#define multistate(x,y) mstate(x,y, __LINE__) +#endif + /* * We add one of these structs to the sockhash for a particular socket */ struct Curl_sh_entry { struct SessionHandle *easy; - time_t timestamp; int action; /* what action READ/WRITE this socket waits for */ curl_socket_t socket; /* mainly to ease debugging */ void *socketp; /* settable by users with curl_multi_assign() */ @@ -269,13 +172,22 @@ struct Curl_sh_entry { #define SH_READ 1 #define SH_WRITE 2 +/* look up a given socket in the socket hash, skip invalid sockets */ +static struct Curl_sh_entry *sh_getentry(struct curl_hash *sh, + curl_socket_t s) +{ + if(s != CURL_SOCKET_BAD) + /* only look for proper sockets */ + return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t)); + return NULL; +} + /* make sure this socket is present in the hash for this handle */ static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh, curl_socket_t s, struct SessionHandle *data) { - struct Curl_sh_entry *there = - Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t)); + struct Curl_sh_entry *there = sh_getentry(sh, s); struct Curl_sh_entry *check; if(there) @@ -286,11 +198,12 @@ static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh, check = calloc(1, sizeof(struct Curl_sh_entry)); if(!check) return NULL; /* major failure */ + check->easy = data; check->socket = s; /* make/add new hash entry */ - if(NULL == Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) { + if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) { free(check); return NULL; /* major failure */ } @@ -302,15 +215,9 @@ static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh, /* delete the given socket + handle from the hash */ static void sh_delentry(struct curl_hash *sh, curl_socket_t s) { - struct Curl_sh_entry *there = - Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t)); - - if(there) { - /* this socket is in the hash */ - /* We remove the hash entry. (This'll end up in a call to - sh_freeentry().) */ - Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t)); - } + /* We remove the hash entry. This will end up in a call to + sh_freeentry(). */ + Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t)); } /* @@ -320,23 +227,22 @@ static void sh_freeentry(void *freethis) { struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis; - if(p) - free(p); + free(p); } -static size_t fd_key_compare(void*k1, size_t k1_len, void*k2, size_t k2_len) +static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len) { (void) k1_len; (void) k2_len; - return (*((int* ) k1)) == (*((int* ) k2)); + return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2)); } -static size_t hash_fd(void* key, size_t key_length, size_t slots_num) +static size_t hash_fd(void *key, size_t key_length, size_t slots_num) { - int fd = * ((int* ) key); + curl_socket_t fd = *((curl_socket_t *) key); (void) key_length; - return (fd % (int)slots_num); + return (fd % slots_num); } /* @@ -357,10 +263,10 @@ static size_t hash_fd(void* key, size_t key_length, size_t slots_num) * per call." * */ -static struct curl_hash *sh_init(void) +static int sh_init(struct curl_hash *hash, int hashsize) { - return Curl_hash_alloc(CURL_SOCKET_HASH_TABLE_SIZE, hash_fd, fd_key_compare, - sh_freeentry); + return Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare, + sh_freeentry); } /* @@ -389,8 +295,8 @@ static void multi_freeamsg(void *a, void *b) (void)b; } - -CURLM *curl_multi_init(void) +struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ + int chashsize) /* connection hash */ { struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi)); @@ -399,50 +305,63 @@ CURLM *curl_multi_init(void) multi->type = CURL_MULTI_HANDLE; - multi->hostcache = Curl_mk_dnscache(); - if(!multi->hostcache) + if(Curl_mk_dnscache(&multi->hostcache)) goto error; - multi->sockhash = sh_init(); - if(!multi->sockhash) + if(sh_init(&multi->sockhash, hashsize)) goto error; - multi->connc = Curl_mk_connc(CONNCACHE_MULTI, -1L); - if(!multi->connc) + if(Curl_conncache_init(&multi->conn_cache, chashsize)) goto error; multi->msglist = Curl_llist_alloc(multi_freeamsg); if(!multi->msglist) goto error; - /* Let's make the doubly-linked list a circular list. This makes - the linked list code simpler and allows inserting at the end - with less work (we didn't keep a tail pointer before). */ - multi->easy.next = &multi->easy; - multi->easy.prev = &multi->easy; + multi->pending = Curl_llist_alloc(multi_freeamsg); + if(!multi->pending) + goto error; + /* allocate a new easy handle to use when closing cached connections */ + multi->closure_handle = curl_easy_init(); + if(!multi->closure_handle) + goto error; + + multi->closure_handle->multi = multi; + multi->closure_handle->state.conn_cache = &multi->conn_cache; + + multi->max_pipeline_length = 5; + + /* -1 means it not set by user, use the default value */ + multi->maxconnects = -1; return (CURLM *) multi; error: - if(multi->sockhash) - Curl_hash_destroy(multi->sockhash); - if(multi->hostcache) - Curl_hash_destroy(multi->hostcache); - if(multi->connc) - Curl_rm_connc(multi->connc); + + Curl_hash_destroy(&multi->sockhash); + Curl_hash_destroy(&multi->hostcache); + Curl_conncache_destroy(&multi->conn_cache); + Curl_close(multi->closure_handle); + multi->closure_handle = NULL; + Curl_llist_destroy(multi->msglist, NULL); + Curl_llist_destroy(multi->pending, NULL); free(multi); return NULL; } +CURLM *curl_multi_init(void) +{ + return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE, + CURL_CONNECTION_HASH_SIZE); +} + CURLMcode curl_multi_add_handle(CURLM *multi_handle, CURL *easy_handle) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct Curl_one_easy *easy; - struct closure *cl; - struct closure *prev=NULL; - struct SessionHandle *data = easy_handle; + struct curl_llist *timeoutlist; + struct Curl_multi *multi = (struct Curl_multi *)multi_handle; + struct SessionHandle *data = (struct SessionHandle *)easy_handle; /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) @@ -452,95 +371,72 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, if(!GOOD_EASY_HANDLE(easy_handle)) return CURLM_BAD_EASY_HANDLE; - /* Prevent users to add the same handle more than once! */ - if(((struct SessionHandle *)easy_handle)->multi) - /* possibly we should create a new unique error code for this condition */ - return CURLM_BAD_EASY_HANDLE; + /* Prevent users from adding same easy handle more than once and prevent + adding to more than one multi stack */ + if(data->multi) + return CURLM_ADDED_ALREADY; - data->state.timeoutlist = Curl_llist_alloc(multi_freetimeout); - if(!data->state.timeoutlist) + /* Allocate and initialize timeout list for easy handle */ + timeoutlist = Curl_llist_alloc(multi_freetimeout); + if(!timeoutlist) return CURLM_OUT_OF_MEMORY; - /* Now, time to add an easy handle to the multi stack */ - easy = calloc(1, sizeof(struct Curl_one_easy)); - if(!easy) - return CURLM_OUT_OF_MEMORY; + /* + * No failure allowed in this function beyond this point. And no + * modification of easy nor multi handle allowed before this except for + * potential multi's connection cache growing which won't be undone in this + * function no matter what. + */ - cl = multi->closure; - while(cl) { - struct closure *next = cl->next; - if(cl->easy_handle == (struct SessionHandle *)easy_handle) { - /* remove this handle from the closure list */ - free(cl); - if(prev) - prev->next = next; - else - multi->closure = next; - break; /* no need to continue since this handle can only be present once - in the list */ - } - prev = cl; - cl = next; - } + /* Make easy handle use timeout list initialized above */ + data->state.timeoutlist = timeoutlist; + timeoutlist = NULL; /* set the easy handle */ - easy->easy_handle = easy_handle; - multistate(easy, CURLM_STATE_INIT); + multistate(data, CURLM_STATE_INIT); - /* set the back pointer to one_easy to assist in removal */ - easy->easy_handle->multi_pos = easy; - - /* for multi interface connections, we share DNS cache automatically if the - easy handle's one is currently private. */ - if(easy->easy_handle->dns.hostcache && - (easy->easy_handle->dns.hostcachetype == HCACHE_PRIVATE)) { - Curl_hash_destroy(easy->easy_handle->dns.hostcache); - easy->easy_handle->dns.hostcache = NULL; - easy->easy_handle->dns.hostcachetype = HCACHE_NONE; - } - - if(!easy->easy_handle->dns.hostcache || - (easy->easy_handle->dns.hostcachetype == HCACHE_NONE)) { - easy->easy_handle->dns.hostcache = multi->hostcache; - easy->easy_handle->dns.hostcachetype = HCACHE_MULTI; - } - - if(easy->easy_handle->state.connc) { - if(easy->easy_handle->state.connc->type == CONNCACHE_PRIVATE) { - /* kill old private version */ - Curl_rm_connc(easy->easy_handle->state.connc); - /* point out our shared one instead */ - easy->easy_handle->state.connc = multi->connc; + if((data->set.global_dns_cache) && + (data->dns.hostcachetype != HCACHE_GLOBAL)) { + /* global dns cache was requested but still isn't */ + struct curl_hash *global = Curl_global_host_cache_init(); + if(global) { + /* only do this if the global cache init works */ + data->dns.hostcache = global; + data->dns.hostcachetype = HCACHE_GLOBAL; } - /* else it is already using multi? */ } - else - /* point out our shared one */ - easy->easy_handle->state.connc = multi->connc; + /* for multi interface connections, we share DNS cache automatically if the + easy handle's one is currently not set. */ + else if(!data->dns.hostcache || + (data->dns.hostcachetype == HCACHE_NONE)) { + data->dns.hostcache = &multi->hostcache; + data->dns.hostcachetype = HCACHE_MULTI; + } - /* Make sure the type is setup correctly */ - easy->easy_handle->state.connc->type = CONNCACHE_MULTI; + /* Point to the multi's connection cache */ + data->state.conn_cache = &multi->conn_cache; - /* This adds the new entry at the back of the list - to try and maintain a FIFO queue so the pipelined - requests are in order. */ + /* This adds the new entry at the 'end' of the doubly-linked circular + list of SessionHandle structs to try and maintain a FIFO queue so + the pipelined requests are in order. */ - /* We add this new entry last in the list. We make our 'next' point to the - 'first' struct and our 'prev' point to the previous 'prev' */ - easy->next = &multi->easy; - easy->prev = multi->easy.prev; + /* We add this new entry last in the list. */ - /* make 'easy' the last node in the chain */ - multi->easy.prev = easy; + data->next = NULL; /* end of the line */ + if(multi->easyp) { + struct SessionHandle *last = multi->easylp; + last->next = data; + data->prev = last; + multi->easylp = data; /* the new last node */ + } + else { + /* first node, make prev NULL! */ + data->prev = NULL; + multi->easylp = multi->easyp = data; /* both first and last */ + } - /* if there was a prev node, make sure its 'next' pointer links to - the new node */ - easy->prev->next = easy; - - Curl_easy_addmulti(easy_handle, multi_handle); - - /* make the SessionHandle struct refer back to this struct */ - easy->easy_handle->set.one_easy = easy; + /* make the SessionHandle refer back to this multi handle */ + data->multi = multi_handle; /* Set the timeout for this handle to expire really soon so that it will be taken care of even when this handle is added in the midst of operation @@ -548,32 +444,11 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, sockets that time-out or have actions will be dealt with. Since this handle has no action yet, we make sure it times out to get things to happen. */ - Curl_expire(easy->easy_handle, 1); + Curl_expire(data, 1); /* increase the node-counter */ multi->num_easy++; - if((multi->num_easy * 4) > multi->connc->num) { - /* We want the connection cache to have plenty room. Before we supported - the shared cache every single easy handle had 5 entries in their cache - by default. */ - long newmax = multi->num_easy * 4; - - if(multi->maxconnects && (multi->maxconnects < newmax)) - /* don't grow beyond the allowed size */ - newmax = multi->maxconnects; - - if(newmax > multi->connc->num) { - /* we only do this is we can in fact grow the cache */ - CURLcode res = Curl_ch_connc(easy_handle, multi->connc, newmax); - if(res != CURLE_OK) { - /* FIXME: may need to do more cleanup here */ - curl_multi_remove_handle(multi_handle, easy_handle); - return CURLM_OUT_OF_MEMORY; - } - } - } - /* increase the alive-counter */ multi->num_alive++; @@ -605,7 +480,7 @@ static void debug_print_sock_hash(void *p) struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p; fprintf(stderr, " [easy %p/magic %x/socket %d]", - (void *)sh->easy, sh->easy->magic, (int)sh->socket); + (void *)sh->data, sh->data->magic, (int)sh->socket); } #endif @@ -613,8 +488,11 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, CURL *curl_handle) { struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct Curl_one_easy *easy; - struct SessionHandle *data = curl_handle; + struct SessionHandle *easy = curl_handle; + struct SessionHandle *data = easy; + bool premature; + bool easy_owns_conn; + struct curl_llist_element *e; /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) @@ -624,168 +502,163 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, if(!GOOD_EASY_HANDLE(curl_handle)) return CURLM_BAD_EASY_HANDLE; - /* pick-up from the 'curl_handle' the kept position in the list */ - easy = data->multi_pos; + /* Prevent users from trying to remove same easy handle more than once */ + if(!data->multi) + return CURLM_OK; /* it is already removed so let's say it is fine! */ - if(easy) { - bool premature = (bool)(easy->state < CURLM_STATE_COMPLETED); - bool easy_owns_conn = (bool)(easy->easy_conn && - (easy->easy_conn->data == easy->easy_handle)); + premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE; + easy_owns_conn = (data->easy_conn && (data->easy_conn->data == easy)) ? + TRUE : FALSE; - /* If the 'state' is not INIT or COMPLETED, we might need to do something - nice to put the easy_handle in a good known state when this returns. */ - if(premature) - /* this handle is "alive" so we need to count down the total number of - alive connections when this is removed */ - multi->num_alive--; + /* If the 'state' is not INIT or COMPLETED, we might need to do something + nice to put the easy_handle in a good known state when this returns. */ + if(premature) { + /* this handle is "alive" so we need to count down the total number of + alive connections when this is removed */ + multi->num_alive--; - if(easy->easy_conn && - (easy->easy_conn->send_pipe->size + - easy->easy_conn->recv_pipe->size > 1) && - easy->state > CURLM_STATE_WAITDO && - easy->state < CURLM_STATE_COMPLETED) { - /* If the handle is in a pipeline and has started sending off its - request but not received its reponse yet, we need to close - connection. */ - easy->easy_conn->bits.close = TRUE; - /* Set connection owner so that Curl_done() closes it. - We can sefely do this here since connection is killed. */ - easy->easy_conn->data = easy->easy_handle; - } - - /* The timer must be shut down before easy->multi is set to NULL, - else the timenode will remain in the splay tree after - curl_easy_cleanup is called. */ - Curl_expire(easy->easy_handle, 0); - - /* destroy the timeout list that is held in the easy handle */ - if(data->state.timeoutlist) { - Curl_llist_destroy(data->state.timeoutlist, NULL); - data->state.timeoutlist = NULL; - } - - if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) { - /* clear out the usage of the shared DNS cache */ - easy->easy_handle->dns.hostcache = NULL; - easy->easy_handle->dns.hostcachetype = HCACHE_NONE; - } - - if(easy->easy_conn) { - - /* we must call Curl_done() here (if we still "own it") so that we don't - leave a half-baked one around */ - if (easy_owns_conn) { - - /* Curl_done() clears the conn->data field to lose the association - between the easy handle and the connection - - Note that this ignores the return code simply because there's - nothing really useful to do with it anyway! */ - (void)Curl_done(&easy->easy_conn, easy->result, premature); - - if(easy->easy_conn) - /* the connection is still alive, set back the association to enable - the check below to trigger TRUE */ - easy->easy_conn->data = easy->easy_handle; - } - else - /* Clear connection pipelines, if Curl_done above was not called */ - Curl_getoff_all_pipelines(easy->easy_handle, easy->easy_conn); - } - - /* figure out if the easy handle is used by one or more connections in the - cache */ - multi_connc_remove_handle(multi, easy->easy_handle); - - if(easy->easy_handle->state.connc->type == CONNCACHE_MULTI) { - /* if this was using the shared connection cache we clear the pointer - to that since we're not part of that handle anymore */ - easy->easy_handle->state.connc = NULL; - - /* Since we return the connection back to the communal connection pool - we mark the last connection as inaccessible */ - easy->easy_handle->state.lastconnect = -1; - - /* Modify the connectindex since this handle can't point to the - connection cache anymore. - - TODO: consider if this is really what we want. The connection cache - is within the multi handle and that owns the connections so we should - not need to touch connections like this when we just remove an easy - handle... - */ - if(easy->easy_conn && easy_owns_conn && - (easy->easy_conn->send_pipe->size + - easy->easy_conn->recv_pipe->size == 0)) - easy->easy_conn->connectindex = -1; - } - - /* change state without using multistate(), only to make singlesocket() do - what we want */ - easy->state = CURLM_STATE_COMPLETED; - singlesocket(multi, easy); /* to let the application know what sockets - that vanish with this handle */ - - Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association - to this multi handle */ - - { - /* make sure there's no pending message in the queue sent from this easy - handle */ - struct curl_llist_element *e; - - for(e = multi->msglist->head; e; e = e->next) { - struct Curl_message *msg = e->ptr; - - if(msg->extmsg.easy_handle == easy->easy_handle) { - Curl_llist_remove(multi->msglist, e, NULL); - /* there can only be one from this specific handle */ - break; - } - } - } - - /* make the previous node point to our next */ - if(easy->prev) - easy->prev->next = easy->next; - /* make our next point to our previous node */ - if(easy->next) - easy->next->prev = easy->prev; - - easy->easy_handle->set.one_easy = NULL; /* detached */ - - /* Null the position in the controlling structure */ - easy->easy_handle->multi_pos = NULL; - - /* NOTE NOTE NOTE - We do not touch the easy handle here! */ - free(easy); - - multi->num_easy--; /* one less to care about now */ - - update_timer(multi); - return CURLM_OK; + /* When this handle gets removed, other handles may be able to get the + connection */ + Curl_multi_process_pending_handles(multi); } + + if(data->easy_conn && + data->mstate > CURLM_STATE_DO && + data->mstate < CURLM_STATE_COMPLETED) { + /* If the handle is in a pipeline and has started sending off its + request but not received its response yet, we need to close + connection. */ + connclose(data->easy_conn, "Removed with partial response"); + /* Set connection owner so that Curl_done() closes it. + We can safely do this here since connection is killed. */ + data->easy_conn->data = easy; + easy_owns_conn = TRUE; + } + + /* The timer must be shut down before data->multi is set to NULL, + else the timenode will remain in the splay tree after + curl_easy_cleanup is called. */ + Curl_expire(data, 0); + + if(data->dns.hostcachetype == HCACHE_MULTI) { + /* stop using the multi handle's DNS cache */ + data->dns.hostcache = NULL; + data->dns.hostcachetype = HCACHE_NONE; + } + + if(data->easy_conn) { + + /* we must call Curl_done() here (if we still "own it") so that we don't + leave a half-baked one around */ + if(easy_owns_conn) { + + /* Curl_done() clears the conn->data field to lose the association + between the easy handle and the connection + + Note that this ignores the return code simply because there's + nothing really useful to do with it anyway! */ + (void)Curl_done(&data->easy_conn, data->result, premature); + } + else + /* Clear connection pipelines, if Curl_done above was not called */ + Curl_getoff_all_pipelines(data, data->easy_conn); + } + + Curl_wildcard_dtor(&data->wildcard); + + /* destroy the timeout list that is held in the easy handle, do this *after* + Curl_done() as that may actuall call Curl_expire that uses this */ + if(data->state.timeoutlist) { + Curl_llist_destroy(data->state.timeoutlist, NULL); + data->state.timeoutlist = NULL; + } + + /* as this was using a shared connection cache we clear the pointer to that + since we're not part of that multi handle anymore */ + data->state.conn_cache = NULL; + + /* change state without using multistate(), only to make singlesocket() do + what we want */ + data->mstate = CURLM_STATE_COMPLETED; + singlesocket(multi, easy); /* to let the application know what sockets that + vanish with this handle */ + + /* Remove the association between the connection and the handle */ + if(data->easy_conn) { + data->easy_conn->data = NULL; + data->easy_conn = NULL; + } + + data->multi = NULL; /* clear the association to this multi handle */ + + /* make sure there's no pending message in the queue sent from this easy + handle */ + + for(e = multi->msglist->head; e; e = e->next) { + struct Curl_message *msg = e->ptr; + + if(msg->extmsg.easy_handle == easy) { + Curl_llist_remove(multi->msglist, e, NULL); + /* there can only be one from this specific handle */ + break; + } + } + + /* make the previous node point to our next */ + if(data->prev) + data->prev->next = data->next; else - return CURLM_BAD_EASY_HANDLE; /* twasn't found */ + multi->easyp = data->next; /* point to first node */ + + /* make our next point to our previous node */ + if(data->next) + data->next->prev = data->prev; + else + multi->easylp = data->prev; /* point to last node */ + + /* NOTE NOTE NOTE + We do not touch the easy handle here! */ + multi->num_easy--; /* one less to care about now */ + + update_timer(multi); + return CURLM_OK; } -bool Curl_multi_canPipeline(const struct Curl_multi* multi) +/* Return TRUE if the application asked for a certain set of pipelining */ +bool Curl_pipeline_wanted(const struct Curl_multi *multi, int bits) { - return multi->pipelining_enabled; + return (multi && (multi->pipelining & bits)) ? TRUE : FALSE; } void Curl_multi_handlePipeBreak(struct SessionHandle *data) { - struct Curl_one_easy *one_easy = data->set.one_easy; - - if(one_easy) - one_easy->easy_conn = NULL; + data->easy_conn = NULL; } static int waitconnect_getsock(struct connectdata *conn, curl_socket_t *sock, int numsocks) +{ + int i; + int s=0; + int rc=0; + + if(!numsocks) + return GETSOCK_BLANK; + + for(i=0; i<2; i++) { + if(conn->tempsock[i] != CURL_SOCKET_BAD) { + sock[s] = conn->tempsock[i]; + rc |= GETSOCK_WRITESOCK(s++); + } + } + + return rc; +} + +static int waitproxyconnect_getsock(struct connectdata *conn, + curl_socket_t *sock, + int numsocks) { if(!numsocks) return GETSOCK_BLANK; @@ -794,31 +667,23 @@ static int waitconnect_getsock(struct connectdata *conn, /* when we've sent a CONNECT to a proxy, we should rather wait for the socket to become readable to be able to get the response headers */ - if(conn->bits.tunnel_connecting) + if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) return GETSOCK_READSOCK(0); return GETSOCK_WRITESOCK(0); } static int domore_getsock(struct connectdata *conn, - curl_socket_t *sock, + curl_socket_t *socks, int numsocks) { - if(!numsocks) - return GETSOCK_BLANK; - - /* When in DO_MORE state, we could be either waiting for us - to connect to a remote site, or we could wait for that site - to connect to us. It makes a difference in the way: if we - connect to the site we wait for the socket to become writable, if - the site connects to us we wait for it to become readable */ - sock[0] = conn->sock[SECONDARYSOCKET]; - - return GETSOCK_WRITESOCK(0); + if(conn && conn->handler->domore_getsock) + return conn->handler->domore_getsock(conn, socks, numsocks); + return GETSOCK_BLANK; } /* returns bitmapped flags for this handle and its sockets */ -static int multi_getsock(struct Curl_one_easy *easy, +static int multi_getsock(struct SessionHandle *data, curl_socket_t *socks, /* points to numsocks number of sockets */ int numsocks) @@ -828,16 +693,16 @@ static int multi_getsock(struct Curl_one_easy *easy, happen when this is called from curl_multi_remove_handle() => singlesocket() => multi_getsock(). */ - if(easy->easy_handle->state.pipe_broke || !easy->easy_conn) + if(data->state.pipe_broke || !data->easy_conn) return 0; - if(easy->state > CURLM_STATE_CONNECT && - easy->state < CURLM_STATE_COMPLETED) { + if(data->mstate > CURLM_STATE_CONNECT && + data->mstate < CURLM_STATE_COMPLETED) { /* Set up ownership correctly */ - easy->easy_conn->data = easy->easy_handle; + data->easy_conn->data = data; } - switch(easy->state) { + switch(data->mstate) { default: #if 0 /* switch back on these cases to get the compiler to check for all enums to be present */ @@ -855,27 +720,31 @@ static int multi_getsock(struct Curl_one_easy *easy, return 0; case CURLM_STATE_WAITRESOLVE: - return Curl_resolv_getsock(easy->easy_conn, socks, numsocks); + return Curl_resolver_getsock(data->easy_conn, socks, numsocks); case CURLM_STATE_PROTOCONNECT: - return Curl_protocol_getsock(easy->easy_conn, socks, numsocks); + case CURLM_STATE_SENDPROTOCONNECT: + return Curl_protocol_getsock(data->easy_conn, socks, numsocks); case CURLM_STATE_DO: case CURLM_STATE_DOING: - return Curl_doing_getsock(easy->easy_conn, socks, numsocks); + return Curl_doing_getsock(data->easy_conn, socks, numsocks); case CURLM_STATE_WAITPROXYCONNECT: + return waitproxyconnect_getsock(data->easy_conn, socks, numsocks); + case CURLM_STATE_WAITCONNECT: - return waitconnect_getsock(easy->easy_conn, socks, numsocks); + return waitconnect_getsock(data->easy_conn, socks, numsocks); case CURLM_STATE_DO_MORE: - return domore_getsock(easy->easy_conn, socks, numsocks); + return domore_getsock(data->easy_conn, socks, numsocks); case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch - to waiting for the same as the *PERFORM states */ + to waiting for the same as the *PERFORM + states */ case CURLM_STATE_PERFORM: case CURLM_STATE_WAITPERFORM: - return Curl_single_getsock(easy->easy_conn, socks, numsocks); + return Curl_single_getsock(data->easy_conn, socks, numsocks); } } @@ -888,7 +757,7 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle, Some easy handles may not have connected to the remote host yet, and then we must make sure that is done. */ struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct Curl_one_easy *easy; + struct SessionHandle *data; int this_max_fd=-1; curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; int bitmap; @@ -898,18 +767,18 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle, if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; - easy=multi->easy.next; - while(easy != &multi->easy) { - bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE); + data=multi->easyp; + while(data) { + bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE); for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { curl_socket_t s = CURL_SOCKET_BAD; - if(bitmap & GETSOCK_READSOCK(i)) { + if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) { FD_SET(sockbunch[i], read_fd_set); s = sockbunch[i]; } - if(bitmap & GETSOCK_WRITESOCK(i)) { + if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) { FD_SET(sockbunch[i], write_fd_set); s = sockbunch[i]; } @@ -922,7 +791,7 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle, } } - easy = easy->next; /* check next handle */ + data = data->next; /* check next handle */ } *max_fd = this_max_fd; @@ -930,129 +799,366 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle, return CURLM_OK; } +CURLMcode curl_multi_wait(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret) +{ + struct Curl_multi *multi=(struct Curl_multi *)multi_handle; + struct SessionHandle *data; + curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; + int bitmap; + unsigned int i; + unsigned int nfds = 0; + unsigned int curlfds; + struct pollfd *ufds = NULL; + long timeout_internal; + int retcode = 0; + + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + + /* If the internally desired timeout is actually shorter than requested from + the outside, then use the shorter time! But only if the internal timer + is actually larger than -1! */ + (void)multi_timeout(multi, &timeout_internal); + if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms)) + timeout_ms = (int)timeout_internal; + + /* Count up how many fds we have from the multi handle */ + data=multi->easyp; + while(data) { + bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE); + + for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { + curl_socket_t s = CURL_SOCKET_BAD; + + if(bitmap & GETSOCK_READSOCK(i)) { + ++nfds; + s = sockbunch[i]; + } + if(bitmap & GETSOCK_WRITESOCK(i)) { + ++nfds; + s = sockbunch[i]; + } + if(s == CURL_SOCKET_BAD) { + break; + } + } + + data = data->next; /* check next handle */ + } + + curlfds = nfds; /* number of internal file descriptors */ + nfds += extra_nfds; /* add the externally provided ones */ + + if(nfds || extra_nfds) { + ufds = malloc(nfds * sizeof(struct pollfd)); + if(!ufds) + return CURLM_OUT_OF_MEMORY; + } + nfds = 0; + + /* only do the second loop if we found descriptors in the first stage run + above */ + + if(curlfds) { + /* Add the curl handles to our pollfds first */ + data=multi->easyp; + while(data) { + bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE); + + for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { + curl_socket_t s = CURL_SOCKET_BAD; + + if(bitmap & GETSOCK_READSOCK(i)) { + ufds[nfds].fd = sockbunch[i]; + ufds[nfds].events = POLLIN; + ++nfds; + s = sockbunch[i]; + } + if(bitmap & GETSOCK_WRITESOCK(i)) { + ufds[nfds].fd = sockbunch[i]; + ufds[nfds].events = POLLOUT; + ++nfds; + s = sockbunch[i]; + } + if(s == CURL_SOCKET_BAD) { + break; + } + } + + data = data->next; /* check next handle */ + } + } + + /* Add external file descriptions from poll-like struct curl_waitfd */ + for(i = 0; i < extra_nfds; i++) { + ufds[nfds].fd = extra_fds[i].fd; + ufds[nfds].events = 0; + if(extra_fds[i].events & CURL_WAIT_POLLIN) + ufds[nfds].events |= POLLIN; + if(extra_fds[i].events & CURL_WAIT_POLLPRI) + ufds[nfds].events |= POLLPRI; + if(extra_fds[i].events & CURL_WAIT_POLLOUT) + ufds[nfds].events |= POLLOUT; + ++nfds; + } + + if(nfds) { + int pollrc; + /* wait... */ + pollrc = Curl_poll(ufds, nfds, timeout_ms); + DEBUGF(infof(data, "Curl_poll(%d ds, %d ms) == %d\n", + nfds, timeout_ms, pollrc)); + + if(pollrc > 0) { + retcode = pollrc; + /* copy revents results from the poll to the curl_multi_wait poll + struct, the bit values of the actual underlying poll() implementation + may not be the same as the ones in the public libcurl API! */ + for(i = 0; i < extra_nfds; i++) { + unsigned short mask = 0; + unsigned r = ufds[curlfds + i].revents; + + if(r & POLLIN) + mask |= CURL_WAIT_POLLIN; + if(r & POLLOUT) + mask |= CURL_WAIT_POLLOUT; + if(r & POLLPRI) + mask |= CURL_WAIT_POLLPRI; + + extra_fds[i].revents = mask; + } + } + } + + free(ufds); + if(ret) + *ret = retcode; + return CURLM_OK; +} + +/* + * Curl_multi_connchanged() is called to tell that there is a connection in + * this multi handle that has changed state (pipelining become possible, the + * number of allowed streams changed or similar), and a subsequent use of this + * multi handle should move CONNECT_PEND handles back to CONNECT to have them + * retry. + */ +void Curl_multi_connchanged(struct Curl_multi *multi) +{ + multi->recheckstate = TRUE; +} + +/* + * multi_ischanged() is called + * + * Returns TRUE/FALSE whether the state is changed to trigger a CONNECT_PEND + * => CONNECT action. + * + * Set 'clear' to TRUE to have it also clear the state variable. + */ +static bool multi_ischanged(struct Curl_multi *multi, bool clear) +{ + bool retval = multi->recheckstate; + if(clear) + multi->recheckstate = FALSE; + return retval; +} + +CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, + struct SessionHandle *data, + struct connectdata *conn) +{ + CURLMcode rc; + + rc = curl_multi_add_handle(multi, data); + if(!rc) { + struct SingleRequest *k = &data->req; + + /* pass in NULL for 'conn' here since we don't want to init the + connection, only this transfer */ + Curl_init_do(data, NULL); + + /* take this handle to the perform state right away */ + multistate(data, CURLM_STATE_PERFORM); + data->easy_conn = conn; + k->keepon |= KEEP_RECV; /* setup to receive! */ + } + return rc; +} + static CURLMcode multi_runsingle(struct Curl_multi *multi, struct timeval now, - struct Curl_one_easy *easy) + struct SessionHandle *data) { struct Curl_message *msg = NULL; bool connected; bool async; bool protocol_connect = FALSE; - bool dophase_done; + bool dophase_done = FALSE; bool done = FALSE; - CURLMcode result = CURLM_OK; + CURLMcode rc; + CURLcode result = CURLE_OK; struct SingleRequest *k; - struct SessionHandle *data; long timeout_ms; + int control; - if(!GOOD_EASY_HANDLE(easy->easy_handle)) + if(!GOOD_EASY_HANDLE(data)) return CURLM_BAD_EASY_HANDLE; - data = easy->easy_handle; - do { - /* this is a do-while loop just to allow a break to skip to the end - of it */ bool disconnect_conn = FALSE; + rc = CURLM_OK; /* Handle the case when the pipe breaks, i.e., the connection we're using gets cleaned up and we're left with nothing. */ if(data->state.pipe_broke) { - infof(data, "Pipe broke: handle 0x%p, url = %s\n", - easy, data->state.path); + infof(data, "Pipe broke: handle %p, url = %s\n", + (void *)data, data->state.path); - if(easy->state < CURLM_STATE_COMPLETED) { + if(data->mstate < CURLM_STATE_COMPLETED) { /* Head back to the CONNECT state */ - multistate(easy, CURLM_STATE_CONNECT); - result = CURLM_CALL_MULTI_PERFORM; - easy->result = CURLE_OK; + multistate(data, CURLM_STATE_CONNECT); + rc = CURLM_CALL_MULTI_PERFORM; + result = CURLE_OK; } data->state.pipe_broke = FALSE; - easy->easy_conn = NULL; - break; + data->easy_conn = NULL; + continue; } - if(easy->easy_conn && easy->state > CURLM_STATE_CONNECT && - easy->state < CURLM_STATE_COMPLETED) - /* Make sure we set the connection's current owner */ - easy->easy_conn->data = data; + if(!data->easy_conn && + data->mstate > CURLM_STATE_CONNECT && + data->mstate < CURLM_STATE_DONE) { + /* In all these states, the code will blindly access 'data->easy_conn' + so this is precaution that it isn't NULL. And it silences static + analyzers. */ + failf(data, "In state %d with no easy_conn, bail out!\n", data->mstate); + return CURLM_INTERNAL_ERROR; + } - if(easy->easy_conn && - (easy->state >= CURLM_STATE_CONNECT) && - (easy->state < CURLM_STATE_COMPLETED)) { + if(multi_ischanged(multi, TRUE)) { + DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n")); + Curl_multi_process_pending_handles(multi); + } + + if(data->easy_conn && data->mstate > CURLM_STATE_CONNECT && + data->mstate < CURLM_STATE_COMPLETED) + /* Make sure we set the connection's current owner */ + data->easy_conn->data = data; + + if(data->easy_conn && + (data->mstate >= CURLM_STATE_CONNECT) && + (data->mstate < CURLM_STATE_COMPLETED)) { /* we need to wait for the connect state as only then is the start time stored, but we must not check already completed handles */ - timeout_ms = Curl_timeleft(easy->easy_conn, &now, - (easy->state <= CURLM_STATE_WAITDO)? + timeout_ms = Curl_timeleft(data, &now, + (data->mstate <= CURLM_STATE_WAITDO)? TRUE:FALSE); if(timeout_ms < 0) { /* Handle timed out */ - if(easy->state == CURLM_STATE_WAITRESOLVE) + if(data->mstate == CURLM_STATE_WAITRESOLVE) failf(data, "Resolving timed out after %ld milliseconds", Curl_tvdiff(now, data->progress.t_startsingle)); - else if(easy->state == CURLM_STATE_WAITCONNECT) + else if(data->mstate == CURLM_STATE_WAITCONNECT) failf(data, "Connection timed out after %ld milliseconds", Curl_tvdiff(now, data->progress.t_startsingle)); else { k = &data->req; - failf(data, "Operation timed out after %ld milliseconds with %" - FORMAT_OFF_T " out of %" FORMAT_OFF_T " bytes received", - Curl_tvdiff(now, data->progress.t_startsingle), k->bytecount, - k->size); + if(k->size != -1) { + failf(data, "Operation timed out after %ld milliseconds with %" + CURL_FORMAT_CURL_OFF_T " out of %" + CURL_FORMAT_CURL_OFF_T " bytes received", + Curl_tvdiff(k->now, data->progress.t_startsingle), + k->bytecount, k->size); + } + else { + failf(data, "Operation timed out after %ld milliseconds with %" + CURL_FORMAT_CURL_OFF_T " bytes received", + Curl_tvdiff(now, data->progress.t_startsingle), + k->bytecount); + } } - easy->result = CURLE_OPERATION_TIMEDOUT; - multistate(easy, CURLM_STATE_COMPLETED); - break; + + /* Force connection closed if the connection has indeed been used */ + if(data->mstate > CURLM_STATE_DO) { + connclose(data->easy_conn, "Disconnected with pending data"); + disconnect_conn = TRUE; + } + result = CURLE_OPERATION_TIMEDOUT; + (void)Curl_done(&data->easy_conn, result, TRUE); + /* Skip the statemachine and go directly to error handling section. */ + goto statemachine_end; } } - switch(easy->state) { + switch(data->mstate) { case CURLM_STATE_INIT: /* init this transfer. */ - easy->result=Curl_pretransfer(data); + result=Curl_pretransfer(data); - if(CURLE_OK == easy->result) { + if(!result) { /* after init, go CONNECT */ - multistate(easy, CURLM_STATE_CONNECT); - result = CURLM_CALL_MULTI_PERFORM; - - data->state.used_interface = Curl_if_multi; + multistate(data, CURLM_STATE_CONNECT); + Curl_pgrsTime(data, TIMER_STARTOP); + rc = CURLM_CALL_MULTI_PERFORM; } break; - case CURLM_STATE_CONNECT: - /* Connect. We get a connection identifier filled in. */ - Curl_pgrsTime(data, TIMER_STARTSINGLE); - easy->result = Curl_connect(data, &easy->easy_conn, - &async, &protocol_connect); + case CURLM_STATE_CONNECT_PEND: + /* We will stay here until there is a connection available. Then + we try again in the CURLM_STATE_CONNECT state. */ + break; - if(CURLE_OK == easy->result) { + case CURLM_STATE_CONNECT: + /* Connect. We want to get a connection identifier filled in. */ + Curl_pgrsTime(data, TIMER_STARTSINGLE); + result = Curl_connect(data, &data->easy_conn, + &async, &protocol_connect); + if(CURLE_NO_CONNECTION_AVAILABLE == result) { + /* There was no connection available. We will go to the pending + state and wait for an available connection. */ + multistate(data, CURLM_STATE_CONNECT_PEND); + + /* add this handle to the list of connect-pending handles */ + if(!Curl_llist_insert_next(multi->pending, multi->pending->tail, data)) + result = CURLE_OUT_OF_MEMORY; + else + result = CURLE_OK; + break; + } + + if(!result) { /* Add this handle to the send or pend pipeline */ - easy->result = addHandleToSendOrPendPipeline(data, - easy->easy_conn); - if(CURLE_OK == easy->result) { + result = Curl_add_handle_to_pipeline(data, data->easy_conn); + if(result) + disconnect_conn = TRUE; + else { if(async) /* We're now waiting for an asynchronous name lookup */ - multistate(easy, CURLM_STATE_WAITRESOLVE); + multistate(data, CURLM_STATE_WAITRESOLVE); else { /* after the connect has been sent off, go WAITCONNECT unless the protocol connect is already done and we can go directly to WAITDO or DO! */ - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; if(protocol_connect) - multistate(easy, multi->pipelining_enabled? + multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? CURLM_STATE_WAITDO:CURLM_STATE_DO); else { #ifndef CURL_DISABLE_HTTP - if(easy->easy_conn->bits.tunnel_connecting) - multistate(easy, CURLM_STATE_WAITPROXYCONNECT); + if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) + multistate(data, CURLM_STATE_WAITPROXYCONNECT); else #endif - multistate(easy, CURLM_STATE_WAITCONNECT); + multistate(data, CURLM_STATE_WAITCONNECT); } } } @@ -1063,43 +1169,58 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* awaiting an asynch name resolve to complete */ { struct Curl_dns_entry *dns = NULL; + struct connectdata *conn = data->easy_conn; /* check if we have the name resolved by now */ - easy->result = Curl_is_resolved(easy->easy_conn, &dns); + dns = Curl_fetch_addr(conn, conn->host.name, (int)conn->port); if(dns) { - /* Update sockets here. Mainly because the socket(s) may have been - closed and the application thus needs to be told, even if it is - likely that the same socket(s) will again be used further down. */ - singlesocket(multi, easy); +#ifdef CURLRES_ASYNCH + conn->async.dns = dns; + conn->async.done = TRUE; +#endif + result = CURLE_OK; + infof(data, "Hostname was found in DNS cache\n"); + } + if(!dns) + result = Curl_resolver_is_resolved(data->easy_conn, &dns); + + /* Update sockets here, because the socket(s) may have been + closed and the application thus needs to be told, even if it + is likely that the same socket(s) will again be used further + down. If the name has not yet been resolved, it is likely + that new sockets have been opened in an attempt to contact + another resolver. */ + singlesocket(multi, data); + + if(dns) { /* Perform the next step in the connection phase, and then move on to the WAITCONNECT state */ - easy->result = Curl_async_resolved(easy->easy_conn, - &protocol_connect); + result = Curl_async_resolved(data->easy_conn, &protocol_connect); - if(CURLE_OK != easy->result) + if(result) /* if Curl_async_resolved() returns failure, the connection struct is already freed and gone */ - easy->easy_conn = NULL; /* no more connection */ + data->easy_conn = NULL; /* no more connection */ else { /* call again please so that we get the next socket setup */ - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; if(protocol_connect) - multistate(easy, multi->pipelining_enabled? + multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? CURLM_STATE_WAITDO:CURLM_STATE_DO); else { #ifndef CURL_DISABLE_HTTP - if(easy->easy_conn->bits.tunnel_connecting) - multistate(easy, CURLM_STATE_WAITPROXYCONNECT); + if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) + multistate(data, CURLM_STATE_WAITPROXYCONNECT); else #endif - multistate(easy, CURLM_STATE_WAITCONNECT); + multistate(data, CURLM_STATE_WAITCONNECT); } } } - if(CURLE_OK != easy->result) { + if(result) { /* failure detected */ disconnect_conn = TRUE; break; @@ -1110,157 +1231,135 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, #ifndef CURL_DISABLE_HTTP case CURLM_STATE_WAITPROXYCONNECT: /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */ - easy->result = Curl_http_connect(easy->easy_conn, &protocol_connect); + result = Curl_http_connect(data->easy_conn, &protocol_connect); - if(easy->easy_conn->bits.proxy_connect_closed) { - /* reset the error buffer */ - if(data->set.errorbuffer) - data->set.errorbuffer[0] = '\0'; - data->state.errorbuf = FALSE; - - easy->result = CURLE_OK; - result = CURLM_CALL_MULTI_PERFORM; - multistate(easy, CURLM_STATE_CONNECT); + if(data->easy_conn->bits.proxy_connect_closed) { + rc = CURLM_CALL_MULTI_PERFORM; + /* connect back to proxy again */ + result = CURLE_OK; + Curl_done(&data->easy_conn, CURLE_OK, FALSE); + multistate(data, CURLM_STATE_CONNECT); } - else if (CURLE_OK == easy->result) { - if(!easy->easy_conn->bits.tunnel_connecting) - multistate(easy, CURLM_STATE_WAITCONNECT); + else if(!result) { + if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_COMPLETE) { + rc = CURLM_CALL_MULTI_PERFORM; + /* initiate protocol connect phase */ + multistate(data, CURLM_STATE_SENDPROTOCONNECT); + } } break; #endif case CURLM_STATE_WAITCONNECT: - /* awaiting a completion of an asynch connect */ - easy->result = Curl_is_connected(easy->easy_conn, - FIRSTSOCKET, - &connected); - if(connected) { - /* see if we need to do any proxy magic first once we connected */ - easy->result = Curl_connected_proxy(easy->easy_conn); - - if(!easy->result) - /* if everything is still fine we do the protocol-specific connect - setup */ - easy->result = Curl_protocol_connect(easy->easy_conn, - &protocol_connect); + /* awaiting a completion of an asynch TCP connect */ + result = Curl_is_connected(data->easy_conn, FIRSTSOCKET, &connected); + if(connected && !result) { + rc = CURLM_CALL_MULTI_PERFORM; + multistate(data, data->easy_conn->bits.tunnel_proxy? + CURLM_STATE_WAITPROXYCONNECT: + CURLM_STATE_SENDPROTOCONNECT); } - - if(CURLE_OK != easy->result) { + else if(result) { /* failure detected */ /* Just break, the cleaning up is handled all in one place */ disconnect_conn = TRUE; break; } + break; - if(connected) { - if(!protocol_connect) { - /* We have a TCP connection, but 'protocol_connect' may be false - and then we continue to 'STATE_PROTOCONNECT'. If protocol - connect is TRUE, we move on to STATE_DO. - BUT if we are using a proxy we must change to WAITPROXYCONNECT - */ -#ifndef CURL_DISABLE_HTTP - if(easy->easy_conn->bits.tunnel_connecting) - multistate(easy, CURLM_STATE_WAITPROXYCONNECT); - else -#endif - multistate(easy, CURLM_STATE_PROTOCONNECT); - - } - else - /* after the connect has completed, go WAITDO or DO */ - multistate(easy, multi->pipelining_enabled? - CURLM_STATE_WAITDO:CURLM_STATE_DO); - - result = CURLM_CALL_MULTI_PERFORM; + case CURLM_STATE_SENDPROTOCONNECT: + result = Curl_protocol_connect(data->easy_conn, &protocol_connect); + if(!protocol_connect) + /* switch to waiting state */ + multistate(data, CURLM_STATE_PROTOCONNECT); + else if(!result) { + /* protocol connect has completed, go WAITDO or DO */ + multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? + CURLM_STATE_WAITDO:CURLM_STATE_DO); + rc = CURLM_CALL_MULTI_PERFORM; + } + else if(result) { + /* failure detected */ + Curl_posttransfer(data); + Curl_done(&data->easy_conn, result, TRUE); + disconnect_conn = TRUE; } break; case CURLM_STATE_PROTOCONNECT: /* protocol-specific connect phase */ - easy->result = Curl_protocol_connecting(easy->easy_conn, - &protocol_connect); - if((easy->result == CURLE_OK) && protocol_connect) { + result = Curl_protocol_connecting(data->easy_conn, &protocol_connect); + if(!result && protocol_connect) { /* after the connect has completed, go WAITDO or DO */ - multistate(easy, multi->pipelining_enabled? + multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? CURLM_STATE_WAITDO:CURLM_STATE_DO); - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; } - else if(easy->result) { + else if(result) { /* failure detected */ Curl_posttransfer(data); - Curl_done(&easy->easy_conn, easy->result, FALSE); + Curl_done(&data->easy_conn, result, TRUE); disconnect_conn = TRUE; } break; case CURLM_STATE_WAITDO: /* Wait for our turn to DO when we're pipelining requests */ -#ifdef DEBUGBUILD - infof(data, "Conn %ld send pipe %zu inuse %d athead %d\n", - easy->easy_conn->connectindex, - easy->easy_conn->send_pipe->size, - easy->easy_conn->writechannel_inuse?1:0, - isHandleAtHead(data, - easy->easy_conn->send_pipe)?1:0); -#endif - if(!easy->easy_conn->writechannel_inuse && - isHandleAtHead(data, - easy->easy_conn->send_pipe)) { - /* Grab the channel */ - easy->easy_conn->writechannel_inuse = TRUE; - multistate(easy, CURLM_STATE_DO); - result = CURLM_CALL_MULTI_PERFORM; + if(Curl_pipeline_checkget_write(data, data->easy_conn)) { + /* Grabbed the channel */ + multistate(data, CURLM_STATE_DO); + rc = CURLM_CALL_MULTI_PERFORM; } break; case CURLM_STATE_DO: if(data->set.connect_only) { /* keep connection open for application to use the socket */ - easy->easy_conn->bits.close = FALSE; - multistate(easy, CURLM_STATE_DONE); - easy->result = CURLE_OK; - result = CURLM_OK; + connkeep(data->easy_conn, "CONNECT_ONLY"); + multistate(data, CURLM_STATE_DONE); + result = CURLE_OK; + rc = CURLM_CALL_MULTI_PERFORM; } else { /* Perform the protocol's DO action */ - easy->result = Curl_do(&easy->easy_conn, - &dophase_done); + result = Curl_do(&data->easy_conn, &dophase_done); - if(CURLE_OK == easy->result) { + /* When Curl_do() returns failure, data->easy_conn might be NULL! */ + + if(!result) { if(!dophase_done) { /* some steps needed for wildcard matching */ if(data->set.wildcardmatch) { struct WildcardData *wc = &data->wildcard; if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) { /* skip some states if it is important */ - Curl_done(&easy->easy_conn, CURLE_OK, FALSE); - multistate(easy, CURLM_STATE_DONE); - result = CURLM_CALL_MULTI_PERFORM; + Curl_done(&data->easy_conn, CURLE_OK, FALSE); + multistate(data, CURLM_STATE_DONE); + rc = CURLM_CALL_MULTI_PERFORM; break; } } /* DO was not completed in one function call, we must continue DOING... */ - multistate(easy, CURLM_STATE_DOING); - result = CURLM_OK; + multistate(data, CURLM_STATE_DOING); + rc = CURLM_OK; } /* after DO, go DO_DONE... or DO_MORE */ - else if(easy->easy_conn->bits.do_more) { + else if(data->easy_conn->bits.do_more) { /* we're supposed to do more, but we need to sit down, relax and wait a little while first */ - multistate(easy, CURLM_STATE_DO_MORE); - result = CURLM_OK; + multistate(data, CURLM_STATE_DO_MORE); + rc = CURLM_OK; } else { /* we're done with the DO, now DO_DONE */ - multistate(easy, CURLM_STATE_DO_DONE); - result = CURLM_CALL_MULTI_PERFORM; + multistate(data, CURLM_STATE_DO_DONE); + rc = CURLM_CALL_MULTI_PERFORM; } } - else if ((CURLE_SEND_ERROR == easy->result) && - easy->easy_conn->bits.reuse) { + else if((CURLE_SEND_ERROR == result) && + data->easy_conn->bits.reuse) { /* * In this situation, a connection that we were trying to use * may have unexpectedly died. If possible, send the connection @@ -1271,50 +1370,52 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, CURLcode drc; bool retry = FALSE; - drc = Curl_retry_request(easy->easy_conn, &newurl); + drc = Curl_retry_request(data->easy_conn, &newurl); if(drc) { /* a failure here pretty much implies an out of memory */ - easy->result = drc; + result = drc; disconnect_conn = TRUE; } else - retry = (bool)(newurl?TRUE:FALSE); + retry = (newurl)?TRUE:FALSE; Curl_posttransfer(data); - drc = Curl_done(&easy->easy_conn, easy->result, FALSE); + drc = Curl_done(&data->easy_conn, result, FALSE); /* When set to retry the connection, we must to go back to * the CONNECT state */ if(retry) { - if ((drc == CURLE_OK) || (drc == CURLE_SEND_ERROR)) { + if(!drc || (drc == CURLE_SEND_ERROR)) { follow = FOLLOW_RETRY; drc = Curl_follow(data, newurl, follow); - if(drc == CURLE_OK) { - multistate(easy, CURLM_STATE_CONNECT); - result = CURLM_CALL_MULTI_PERFORM; - easy->result = CURLE_OK; + if(!drc) { + multistate(data, CURLM_STATE_CONNECT); + rc = CURLM_CALL_MULTI_PERFORM; + result = CURLE_OK; } else { /* Follow failed */ - easy->result = drc; + result = drc; free(newurl); } } else { /* done didn't return OK or SEND_ERROR */ - easy->result = drc; + result = drc; free(newurl); } } else { /* Have error handler disconnect conn if we can't retry */ disconnect_conn = TRUE; + free(newurl); } } else { /* failure detected */ Curl_posttransfer(data); - Curl_done(&easy->easy_conn, easy->result, FALSE); + if(data->easy_conn) + Curl_done(&data->easy_conn, result, FALSE); disconnect_conn = TRUE; } } @@ -1322,182 +1423,190 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, case CURLM_STATE_DOING: /* we continue DOING until the DO phase is complete */ - easy->result = Curl_protocol_doing(easy->easy_conn, - &dophase_done); - if(CURLE_OK == easy->result) { + result = Curl_protocol_doing(data->easy_conn, + &dophase_done); + if(!result) { if(dophase_done) { - /* after DO, go PERFORM... or DO_MORE */ - if(easy->easy_conn->bits.do_more) { - /* we're supposed to do more, but we need to sit down, relax - and wait a little while first */ - multistate(easy, CURLM_STATE_DO_MORE); - result = CURLM_OK; - } - else { - /* we're done with the DO, now DO_DONE */ - multistate(easy, CURLM_STATE_DO_DONE); - result = CURLM_CALL_MULTI_PERFORM; - } + /* after DO, go DO_DONE or DO_MORE */ + multistate(data, data->easy_conn->bits.do_more? + CURLM_STATE_DO_MORE: + CURLM_STATE_DO_DONE); + rc = CURLM_CALL_MULTI_PERFORM; } /* dophase_done */ } else { /* failure detected */ Curl_posttransfer(data); - Curl_done(&easy->easy_conn, easy->result, FALSE); + Curl_done(&data->easy_conn, result, FALSE); disconnect_conn = TRUE; } break; case CURLM_STATE_DO_MORE: - /* Ready to do more? */ - easy->result = Curl_is_connected(easy->easy_conn, - SECONDARYSOCKET, - &connected); - if(connected) { - /* - * When we are connected, DO MORE and then go DO_DONE - */ - easy->result = Curl_do_more(easy->easy_conn); + /* + * When we are connected, DO MORE and then go DO_DONE + */ + result = Curl_do_more(data->easy_conn, &control); - /* No need to remove ourselves from the send pipeline here since that - is done for us in Curl_done() */ - - if(CURLE_OK == easy->result) { - multistate(easy, CURLM_STATE_DO_DONE); - result = CURLM_CALL_MULTI_PERFORM; - } - else { - /* failure detected */ - Curl_posttransfer(data); - Curl_done(&easy->easy_conn, easy->result, FALSE); - disconnect_conn = TRUE; + /* No need to remove this handle from the send pipeline here since that + is done in Curl_done() */ + if(!result) { + if(control) { + /* if positive, advance to DO_DONE + if negative, go back to DOING */ + multistate(data, control==1? + CURLM_STATE_DO_DONE: + CURLM_STATE_DOING); + rc = CURLM_CALL_MULTI_PERFORM; } + else + /* stay in DO_MORE */ + rc = CURLM_OK; + } + else { + /* failure detected */ + Curl_posttransfer(data); + Curl_done(&data->easy_conn, result, FALSE); + disconnect_conn = TRUE; } break; case CURLM_STATE_DO_DONE: /* Move ourselves from the send to recv pipeline */ - moveHandleFromSendToRecvPipeline(data, easy->easy_conn); + Curl_move_handle_from_send_to_recv_pipe(data, data->easy_conn); /* Check if we can move pending requests to send pipe */ - checkPendPipeline(easy->easy_conn); - multistate(easy, CURLM_STATE_WAITPERFORM); - result = CURLM_CALL_MULTI_PERFORM; + Curl_multi_process_pending_handles(multi); + + /* Only perform the transfer if there's a good socket to work with. + Having both BAD is a signal to skip immediately to DONE */ + if((data->easy_conn->sockfd != CURL_SOCKET_BAD) || + (data->easy_conn->writesockfd != CURL_SOCKET_BAD)) + multistate(data, CURLM_STATE_WAITPERFORM); + else + multistate(data, CURLM_STATE_DONE); + rc = CURLM_CALL_MULTI_PERFORM; break; case CURLM_STATE_WAITPERFORM: /* Wait for our turn to PERFORM */ - if(!easy->easy_conn->readchannel_inuse && - isHandleAtHead(data, - easy->easy_conn->recv_pipe)) { - /* Grab the channel */ - easy->easy_conn->readchannel_inuse = TRUE; - multistate(easy, CURLM_STATE_PERFORM); - result = CURLM_CALL_MULTI_PERFORM; + if(Curl_pipeline_checkget_read(data, data->easy_conn)) { + /* Grabbed the channel */ + multistate(data, CURLM_STATE_PERFORM); + rc = CURLM_CALL_MULTI_PERFORM; } -#ifdef DEBUGBUILD - else { - infof(data, "Conn %ld recv pipe %zu inuse %d athead %d\n", - easy->easy_conn->connectindex, - easy->easy_conn->recv_pipe->size, - easy->easy_conn->readchannel_inuse?1:0, - isHandleAtHead(data, - easy->easy_conn->recv_pipe)?1:0); - } -#endif break; case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */ /* if both rates are within spec, resume transfer */ - if( ( (data->set.max_send_speed == 0) || - (data->progress.ulspeed < data->set.max_send_speed )) && - ( (data->set.max_recv_speed == 0) || - (data->progress.dlspeed < data->set.max_recv_speed) ) ) - multistate(easy, CURLM_STATE_PERFORM); + if(Curl_pgrsUpdate(data->easy_conn)) + result = CURLE_ABORTED_BY_CALLBACK; + else + result = Curl_speedcheck(data, now); + + if(( (data->set.max_send_speed == 0) || + (data->progress.ulspeed < data->set.max_send_speed )) && + ( (data->set.max_recv_speed == 0) || + (data->progress.dlspeed < data->set.max_recv_speed))) + multistate(data, CURLM_STATE_PERFORM); break; case CURLM_STATE_PERFORM: + { + char *newurl = NULL; + bool retry = FALSE; + /* check if over send speed */ - if( (data->set.max_send_speed > 0) && - (data->progress.ulspeed > data->set.max_send_speed) ) { + if((data->set.max_send_speed > 0) && + (data->progress.ulspeed > data->set.max_send_speed)) { int buffersize; - multistate(easy, CURLM_STATE_TOOFAST); + multistate(data, CURLM_STATE_TOOFAST); /* calculate upload rate-limitation timeout. */ buffersize = (int)(data->set.buffer_size ? data->set.buffer_size : BUFSIZE); timeout_ms = Curl_sleep_time(data->set.max_send_speed, data->progress.ulspeed, buffersize); - Curl_expire(data, timeout_ms); + Curl_expire_latest(data, timeout_ms); break; } /* check if over recv speed */ - if( (data->set.max_recv_speed > 0) && - (data->progress.dlspeed > data->set.max_recv_speed) ) { + if((data->set.max_recv_speed > 0) && + (data->progress.dlspeed > data->set.max_recv_speed)) { int buffersize; - multistate(easy, CURLM_STATE_TOOFAST); + multistate(data, CURLM_STATE_TOOFAST); - /* Calculate download rate-limitation timeout. */ + /* Calculate download rate-limitation timeout. */ buffersize = (int)(data->set.buffer_size ? data->set.buffer_size : BUFSIZE); timeout_ms = Curl_sleep_time(data->set.max_recv_speed, data->progress.dlspeed, buffersize); - Curl_expire(data, timeout_ms); + Curl_expire_latest(data, timeout_ms); break; } /* read/write data if it is ready to do so */ - easy->result = Curl_readwrite(easy->easy_conn, &done); + result = Curl_readwrite(data->easy_conn, data, &done); k = &data->req; - if(!(k->keepon & KEEP_RECV)) { + if(!(k->keepon & KEEP_RECV)) /* We're done receiving */ - easy->easy_conn->readchannel_inuse = FALSE; - } + Curl_pipeline_leave_read(data->easy_conn); - if(!(k->keepon & KEEP_SEND)) { + if(!(k->keepon & KEEP_SEND)) /* We're done sending */ - easy->easy_conn->writechannel_inuse = FALSE; + Curl_pipeline_leave_write(data->easy_conn); + + if(done || (result == CURLE_RECV_ERROR)) { + /* If CURLE_RECV_ERROR happens early enough, we assume it was a race + * condition and the server closed the re-used connection exactly when + * we wanted to use it, so figure out if that is indeed the case. + */ + CURLcode ret = Curl_retry_request(data->easy_conn, &newurl); + if(!ret) + retry = (newurl)?TRUE:FALSE; + + if(retry) { + /* if we are to retry, set the result to OK and consider the + request as done */ + result = CURLE_OK; + done = TRUE; + } } - if(easy->result) { - /* The transfer phase returned error, we mark the connection to get + if(result) { + /* + * The transfer phase returned error, we mark the connection to get * closed to prevent being re-used. This is because we can't possibly * know if the connection is in a good shape or not now. Unless it is * a protocol which uses two "channels" like FTP, as then the error * happened in the data connection. */ - if(!(easy->easy_conn->protocol & PROT_DUALCHANNEL)) - easy->easy_conn->bits.close = TRUE; + + if(!(data->easy_conn->handler->flags & PROTOPT_DUAL)) + connclose(data->easy_conn, "Transfer returned error"); Curl_posttransfer(data); - Curl_done(&easy->easy_conn, easy->result, FALSE); + Curl_done(&data->easy_conn, result, FALSE); } - else if(TRUE == done) { - char *newurl = NULL; - bool retry = FALSE; + else if(done) { followtype follow=FOLLOW_NONE; - easy->result = Curl_retry_request(easy->easy_conn, &newurl); - if(!easy->result) - retry = (bool)(newurl?TRUE:FALSE); - /* call this even if the readwrite function returned error */ Curl_posttransfer(data); - /* we're no longer receving */ - moveHandleFromRecvToDonePipeline(data, - easy->easy_conn); + /* we're no longer receiving */ + Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe); /* expire the new receiving pipeline head */ - if(easy->easy_conn->recv_pipe->head) - Curl_expire(easy->easy_conn->recv_pipe->head->ptr, 1); + if(data->easy_conn->recv_pipe->head) + Curl_expire_latest(data->easy_conn->recv_pipe->head->ptr, 1); /* Check if we can move pending requests to send pipe */ - checkPendPipeline(easy->easy_conn); + Curl_multi_process_pending_handles(multi); /* When we follow redirects or is set to retry the connection, we must to go back to the CONNECT state */ @@ -1505,89 +1614,91 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(!retry) { /* if the URL is a follow-location and not just a retried request then figure out the URL here */ + free(newurl); newurl = data->req.newurl; data->req.newurl = NULL; follow = FOLLOW_REDIR; } else follow = FOLLOW_RETRY; - easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE); - if(easy->result == CURLE_OK) - easy->result = Curl_follow(data, newurl, follow); - if(CURLE_OK == easy->result) { - multistate(easy, CURLM_STATE_CONNECT); - result = CURLM_CALL_MULTI_PERFORM; + result = Curl_done(&data->easy_conn, CURLE_OK, FALSE); + if(!result) { + result = Curl_follow(data, newurl, follow); + if(!result) { + multistate(data, CURLM_STATE_CONNECT); + rc = CURLM_CALL_MULTI_PERFORM; + newurl = NULL; /* handed over the memory ownership to + Curl_follow(), make sure we don't free() it + here */ + } } - else if(newurl) - /* Since we "took it", we are in charge of freeing this on - failure */ - free(newurl); } else { /* after the transfer is done, go DONE */ /* but first check to see if we got a location info even though we're not following redirects */ - if (data->req.location) { + if(data->req.location) { + free(newurl); newurl = data->req.location; data->req.location = NULL; - easy->result = Curl_follow(data, newurl, FOLLOW_FAKE); - if (easy->result) - free(newurl); + result = Curl_follow(data, newurl, FOLLOW_FAKE); + if(!result) + newurl = NULL; /* allocation was handed over Curl_follow() */ + else + disconnect_conn = TRUE; } - multistate(easy, CURLM_STATE_DONE); - result = CURLM_CALL_MULTI_PERFORM; + multistate(data, CURLM_STATE_DONE); + rc = CURLM_CALL_MULTI_PERFORM; } } + free(newurl); break; + } case CURLM_STATE_DONE: + /* this state is highly transient, so run another loop after this */ + rc = CURLM_CALL_MULTI_PERFORM; - if(easy->easy_conn) { - /* Remove ourselves from the receive and done pipelines. Handle - should be on one of these lists, depending upon how we got here. */ - Curl_removeHandleFromPipeline(data, - easy->easy_conn->recv_pipe); - Curl_removeHandleFromPipeline(data, - easy->easy_conn->done_pipe); + if(data->easy_conn) { + CURLcode res; + + /* Remove ourselves from the receive pipeline, if we are there. */ + Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe); /* Check if we can move pending requests to send pipe */ - checkPendPipeline(easy->easy_conn); - - if(easy->easy_conn->bits.stream_was_rewound) { - /* This request read past its response boundary so we quickly let - the other requests consume those bytes since there is no - guarantee that the socket will become active again */ - result = CURLM_CALL_MULTI_PERFORM; - } + Curl_multi_process_pending_handles(multi); /* post-transfer command */ - easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE); + res = Curl_done(&data->easy_conn, result, FALSE); + + /* allow a previously set error code take precedence */ + if(!result) + result = res; + /* * If there are other handles on the pipeline, Curl_done won't set * easy_conn to NULL. In such a case, curl_multi_remove_handle() can * access free'd data, if the connection is free'd and the handle * removed before we perform the processing in CURLM_STATE_COMPLETED */ - if (easy->easy_conn) - easy->easy_conn = NULL; + if(data->easy_conn) + data->easy_conn = NULL; } if(data->set.wildcardmatch) { if(data->wildcard.state != CURLWC_DONE) { /* if a wildcard is set and we are not ending -> lets start again with CURLM_STATE_INIT */ - result = CURLM_CALL_MULTI_PERFORM; - multistate(easy, CURLM_STATE_INIT); + multistate(data, CURLM_STATE_INIT); break; } } /* after we have DONE what we're supposed to do, go COMPLETED, and it doesn't matter what the Curl_done() returned! */ - multistate(easy, CURLM_STATE_COMPLETED); - + multistate(data, CURLM_STATE_COMPLETED); break; case CURLM_STATE_COMPLETED: @@ -1598,20 +1709,22 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* Important: reset the conn pointer so that we don't point to memory that could be freed anytime */ - easy->easy_conn = NULL; + data->easy_conn = NULL; Curl_expire(data, 0); /* stop all timers */ break; case CURLM_STATE_MSGSENT: + data->result = result; return CURLM_OK; /* do nothing */ default: return CURLM_INTERNAL_ERROR; } + statemachine_end: - if(CURLM_STATE_COMPLETED > easy->state) { - if(CURLE_OK != easy->result) { + if(data->mstate < CURLM_STATE_COMPLETED) { + if(result) { /* * If an error was returned, and we aren't in completed state now, * then we go to completed and consider this transfer aborted. @@ -1622,65 +1735,74 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, data->state.pipe_broke = FALSE; - if(easy->easy_conn) { + /* Check if we can move pending requests to send pipe */ + Curl_multi_process_pending_handles(multi); + + if(data->easy_conn) { /* if this has a connection, unsubscribe from the pipelines */ - easy->easy_conn->writechannel_inuse = FALSE; - easy->easy_conn->readchannel_inuse = FALSE; - Curl_removeHandleFromPipeline(data, - easy->easy_conn->send_pipe); - Curl_removeHandleFromPipeline(data, - easy->easy_conn->recv_pipe); - Curl_removeHandleFromPipeline(data, - easy->easy_conn->done_pipe); - /* Check if we can move pending requests to send pipe */ - checkPendPipeline(easy->easy_conn); + Curl_pipeline_leave_write(data->easy_conn); + Curl_pipeline_leave_read(data->easy_conn); + Curl_removeHandleFromPipeline(data, data->easy_conn->send_pipe); + Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe); + + if(disconnect_conn) { + /* Don't attempt to send data over a connection that timed out */ + bool dead_connection = result == CURLE_OPERATION_TIMEDOUT; + /* disconnect properly */ + Curl_disconnect(data->easy_conn, dead_connection); + + /* This is where we make sure that the easy_conn pointer is reset. + We don't have to do this in every case block above where a + failure is detected */ + data->easy_conn = NULL; + } + } + else if(data->mstate == CURLM_STATE_CONNECT) { + /* Curl_connect() failed */ + (void)Curl_posttransfer(data); } - if(disconnect_conn) { - /* disconnect properly */ - Curl_disconnect(easy->easy_conn, /* dead_connection */ FALSE); - - /* This is where we make sure that the easy_conn pointer is reset. - We don't have to do this in every case block above where a - failure is detected */ - easy->easy_conn = NULL; - } - - multistate(easy, CURLM_STATE_COMPLETED); + multistate(data, CURLM_STATE_COMPLETED); } /* if there's still a connection to use, call the progress function */ - else if(easy->easy_conn && Curl_pgrsUpdate(easy->easy_conn)) - easy->result = CURLE_ABORTED_BY_CALLBACK; - } - } while(0); + else if(data->easy_conn && Curl_pgrsUpdate(data->easy_conn)) { + /* aborted due to progress callback return code must close the + connection */ + result = CURLE_ABORTED_BY_CALLBACK; + connclose(data->easy_conn, "Aborted by callback"); - if(CURLM_STATE_COMPLETED == easy->state) { - if(data->dns.hostcachetype == HCACHE_MULTI) { - /* clear out the usage of the shared DNS cache */ - data->dns.hostcache = NULL; - data->dns.hostcachetype = HCACHE_NONE; + /* if not yet in DONE state, go there, otherwise COMPLETED */ + multistate(data, (data->mstate < CURLM_STATE_DONE)? + CURLM_STATE_DONE: CURLM_STATE_COMPLETED); + rc = CURLM_CALL_MULTI_PERFORM; + } } - /* now fill in the Curl_message with this info */ - msg = &easy->msg; + if(CURLM_STATE_COMPLETED == data->mstate) { + /* now fill in the Curl_message with this info */ + msg = &data->msg; - msg->extmsg.msg = CURLMSG_DONE; - msg->extmsg.easy_handle = data; - msg->extmsg.data.result = easy->result; + msg->extmsg.msg = CURLMSG_DONE; + msg->extmsg.easy_handle = data; + msg->extmsg.data.result = result; - result = multi_addmsg(multi, msg); + rc = multi_addmsg(multi, msg); - multistate(easy, CURLM_STATE_MSGSENT); - } + multistate(data, CURLM_STATE_MSGSENT); + } + } while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE)); - return result; + data->result = result; + + + return rc; } CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) { struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct Curl_one_easy *easy; + struct SessionHandle *data; CURLMcode returncode=CURLM_OK; struct Curl_tree *t; struct timeval now = Curl_tvnow(); @@ -1688,12 +1810,13 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; - easy=multi->easy.next; - while(easy != &multi->easy) { + data=multi->easyp; + while(data) { CURLMcode result; - struct WildcardData *wc = &easy->easy_handle->wildcard; + struct WildcardData *wc = &data->wildcard; + SIGPIPE_VARIABLE(pipe_st); - if(easy->easy_handle->set.wildcardmatch) { + if(data->set.wildcardmatch) { if(!wc->filelist) { CURLcode ret = Curl_wildcard_init(wc); /* init wildcard structures */ if(ret) @@ -1701,11 +1824,11 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) } } - do - result = multi_runsingle(multi, now, easy); - while (CURLM_CALL_MULTI_PERFORM == result); + sigpipe_ignore(data, &pipe_st); + result = multi_runsingle(multi, now, data); + sigpipe_restore(&pipe_st); - if(easy->easy_handle->set.wildcardmatch) { + if(data->set.wildcardmatch) { /* destruct wildcard structures if it is needed */ if(wc->state == CURLWC_DONE || result) Curl_wildcard_dtor(wc); @@ -1714,7 +1837,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) if(result) returncode = result; - easy = easy->next; /* operate on next handle */ + data = data->next; /* operate on next handle */ } /* @@ -1737,75 +1860,88 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) *running_handles = multi->num_alive; - if( CURLM_OK >= returncode ) + if(CURLM_OK >= returncode) update_timer(multi); return returncode; } +static void close_all_connections(struct Curl_multi *multi) +{ + struct connectdata *conn; + + conn = Curl_conncache_find_first_connection(&multi->conn_cache); + while(conn) { + SIGPIPE_VARIABLE(pipe_st); + conn->data = multi->closure_handle; + + sigpipe_ignore(conn->data, &pipe_st); + /* This will remove the connection from the cache */ + (void)Curl_disconnect(conn, FALSE); + sigpipe_restore(&pipe_st); + + conn = Curl_conncache_find_first_connection(&multi->conn_cache); + } +} + CURLMcode curl_multi_cleanup(CURLM *multi_handle) { struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct Curl_one_easy *easy; - struct Curl_one_easy *nexteasy; - int i; - struct closure *cl; - struct closure *n; + struct SessionHandle *data; + struct SessionHandle *nextdata; if(GOOD_MULTI_HANDLE(multi)) { + bool restore_pipe = FALSE; + SIGPIPE_VARIABLE(pipe_st); + multi->type = 0; /* not good anymore */ - Curl_hash_destroy(multi->hostcache); - Curl_hash_destroy(multi->sockhash); - multi->hostcache = NULL; - multi->sockhash = NULL; - /* go over all connections that have close actions */ - for(i=0; i< multi->connc->num; i++) { - if(multi->connc->connects[i] && - multi->connc->connects[i]->protocol & PROT_CLOSEACTION) { - Curl_disconnect(multi->connc->connects[i], /* dead_connection */ FALSE); - multi->connc->connects[i] = NULL; - } - } - /* now walk through the list of handles we kept around only to be - able to close connections "properly" */ - cl = multi->closure; - while(cl) { - cl->easy_handle->state.shared_conn = NULL; /* no more shared */ - if(cl->easy_handle->state.closed) - /* close handle only if curl_easy_cleanup() already has been called - for this easy handle */ - Curl_close(cl->easy_handle); - n = cl->next; - free(cl); - cl= n; + /* Close all the connections in the connection cache */ + close_all_connections(multi); + + if(multi->closure_handle) { + sigpipe_ignore(multi->closure_handle, &pipe_st); + restore_pipe = TRUE; + + multi->closure_handle->dns.hostcache = &multi->hostcache; + Curl_hostcache_clean(multi->closure_handle, + multi->closure_handle->dns.hostcache); + + Curl_close(multi->closure_handle); } - Curl_rm_connc(multi->connc); - - /* remove the pending list of messages */ + Curl_hash_destroy(&multi->sockhash); + Curl_conncache_destroy(&multi->conn_cache); Curl_llist_destroy(multi->msglist, NULL); + Curl_llist_destroy(multi->pending, NULL); /* remove all easy handles */ - easy = multi->easy.next; - while(easy != &multi->easy) { - nexteasy=easy->next; - if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) { + data = multi->easyp; + while(data) { + nextdata=data->next; + if(data->dns.hostcachetype == HCACHE_MULTI) { /* clear out the usage of the shared DNS cache */ - easy->easy_handle->dns.hostcache = NULL; - easy->easy_handle->dns.hostcachetype = HCACHE_NONE; + Curl_hostcache_clean(data, data->dns.hostcache); + data->dns.hostcache = NULL; + data->dns.hostcachetype = HCACHE_NONE; } /* Clear the pointer to the connection cache */ - easy->easy_handle->state.connc = NULL; + data->state.conn_cache = NULL; + data->multi = NULL; /* clear the association */ - Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association */ - - free(easy); - easy = nexteasy; + data = nextdata; } + Curl_hash_destroy(&multi->hostcache); + + /* Free the blacklists by setting them to NULL */ + Curl_pipeline_set_site_blacklist(NULL, &multi->pipelining_site_bl); + Curl_pipeline_set_server_blacklist(NULL, &multi->pipelining_server_bl); + free(multi); + if(restore_pipe) + sigpipe_restore(&pipe_st); return CURLM_OK; } @@ -1856,7 +1992,7 @@ CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue) * call the callback accordingly. */ static void singlesocket(struct Curl_multi *multi, - struct Curl_one_easy *easy) + struct SessionHandle *data) { curl_socket_t socks[MAX_SOCKSPEREASYHANDLE]; int i; @@ -1864,15 +2000,13 @@ static void singlesocket(struct Curl_multi *multi, curl_socket_t s; int num; unsigned int curraction; - struct Curl_one_easy *easy_by_hash; - bool remove_sock_from_hash; for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) socks[i] = CURL_SOCKET_BAD; /* Fill in the 'current' struct with the state as it is now: what sockets to supervise and for what actions */ - curraction = multi_getsock(easy, socks, MAX_SOCKSPEREASYHANDLE); + curraction = multi_getsock(data, socks, MAX_SOCKSPEREASYHANDLE); /* We have 0 .. N sockets already and we get to know about the 0 .. M sockets we should have from now on. Detect the differences, remove no @@ -1887,7 +2021,7 @@ static void singlesocket(struct Curl_multi *multi, s = socks[i]; /* get it from the hash */ - entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); + entry = sh_getentry(&multi->sockhash, s); if(curraction & GETSOCK_READSOCK(i)) action |= CURL_POLL_IN; @@ -1902,18 +2036,19 @@ static void singlesocket(struct Curl_multi *multi, } else { /* this is a socket we didn't have before, add it! */ - entry = sh_addentry(multi->sockhash, s, easy->easy_handle); + entry = sh_addentry(&multi->sockhash, s, data); if(!entry) /* fatal */ return; } /* we know (entry != NULL) at this point, see the logic above */ - multi->socket_cb(easy->easy_handle, - s, - action, - multi->socket_userp, - entry->socketp); + if(multi->socket_cb) + multi->socket_cb(data, + s, + action, + multi->socket_userp, + entry->socketp); entry->action = action; /* store the current action state */ } @@ -1922,9 +2057,9 @@ static void singlesocket(struct Curl_multi *multi, /* when we've walked over all the sockets we should have right now, we must make sure to detect sockets that are removed */ - for(i=0; i< easy->numsocks; i++) { + for(i=0; i< data->numsocks; i++) { int j; - s = easy->sockets[i]; + s = data->sockets[i]; for(j=0; jsockhash, s); + if(entry) { /* this socket has been removed. Tell the app to remove it */ - remove_sock_from_hash = TRUE; + bool remove_sock_from_hash = TRUE; - entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); - if(entry) { - /* check if the socket to be removed serves a connection which has - other easy-s in a pipeline. In this case the socket should not be - removed. */ - struct connectdata *easy_conn; + /* check if the socket to be removed serves a connection which has + other easy-s in a pipeline. In this case the socket should not be + removed. */ + struct connectdata *easy_conn = data->easy_conn; + if(easy_conn) { + if(easy_conn->recv_pipe && easy_conn->recv_pipe->size > 1) { + /* the handle should not be removed from the pipe yet */ + remove_sock_from_hash = FALSE; - easy_by_hash = entry->easy->multi_pos; - easy_conn = easy_by_hash->easy_conn; - if(easy_conn) { - if (easy_conn->recv_pipe && easy_conn->recv_pipe->size > 1) { - /* the handle should not be removed from the pipe yet */ - remove_sock_from_hash = FALSE; - - /* Update the sockhash entry to instead point to the next in line - for the recv_pipe, or the first (in case this particular easy - isn't already) */ - if (entry->easy == easy->easy_handle) { - if (isHandleAtHead(easy->easy_handle, easy_conn->recv_pipe)) - entry->easy = easy_conn->recv_pipe->head->next->ptr; - else - entry->easy = easy_conn->recv_pipe->head->ptr; - } + /* Update the sockhash entry to instead point to the next in line + for the recv_pipe, or the first (in case this particular easy + isn't already) */ + if(entry->easy == data) { + if(Curl_recvpipe_head(data, easy_conn)) + entry->easy = easy_conn->recv_pipe->head->next->ptr; + else + entry->easy = easy_conn->recv_pipe->head->ptr; } - if (easy_conn->send_pipe && easy_conn->send_pipe->size > 1) { - /* the handle should not be removed from the pipe yet */ - remove_sock_from_hash = FALSE; - - /* Update the sockhash entry to instead point to the next in line - for the send_pipe, or the first (in case this particular easy - isn't already) */ - if (entry->easy == easy->easy_handle) { - if (isHandleAtHead(easy->easy_handle, easy_conn->send_pipe)) - entry->easy = easy_conn->send_pipe->head->next->ptr; - else - entry->easy = easy_conn->send_pipe->head->ptr; - } - } - /* Don't worry about overwriting recv_pipe head with send_pipe_head, - when action will be asked on the socket (see multi_socket()), the - head of the correct pipe will be taken according to the - action. */ } - } - else - /* just a precaution, this socket really SHOULD be in the hash already - but in case it isn't, we don't have to tell the app to remove it - either since it never got to know about it */ - remove_sock_from_hash = FALSE; + if(easy_conn->send_pipe && easy_conn->send_pipe->size > 1) { + /* the handle should not be removed from the pipe yet */ + remove_sock_from_hash = FALSE; - if (remove_sock_from_hash) { - multi->socket_cb(easy->easy_handle, - s, - CURL_POLL_REMOVE, + /* Update the sockhash entry to instead point to the next in line + for the send_pipe, or the first (in case this particular easy + isn't already) */ + if(entry->easy == data) { + if(Curl_sendpipe_head(data, easy_conn)) + entry->easy = easy_conn->send_pipe->head->next->ptr; + else + entry->easy = easy_conn->send_pipe->head->ptr; + } + } + /* Don't worry about overwriting recv_pipe head with send_pipe_head, + when action will be asked on the socket (see multi_socket()), the + head of the correct pipe will be taken according to the + action. */ + } + + if(remove_sock_from_hash) { + /* in this case 'entry' is always non-NULL */ + if(multi->socket_cb) + multi->socket_cb(data, + s, + CURL_POLL_REMOVE, + multi->socket_userp, + entry->socketp); + sh_delentry(&multi->sockhash, s); + } + } /* if sockhash entry existed */ + } /* for loop over numsocks */ + + memcpy(data->sockets, socks, num*sizeof(curl_socket_t)); + data->numsocks = num; +} + +/* + * Curl_multi_closed() + * + * Used by the connect code to tell the multi_socket code that one of the + * sockets we were using is about to be closed. This function will then + * remove it from the sockethash for this handle to make the multi_socket API + * behave properly, especially for the case when libcurl will create another + * socket again and it gets the same file descriptor number. + */ + +void Curl_multi_closed(struct connectdata *conn, curl_socket_t s) +{ + struct Curl_multi *multi = conn->data->multi; + if(multi) { + /* this is set if this connection is part of a handle that is added to + a multi handle, and only then this is necessary */ + struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); + + if(entry) { + if(multi->socket_cb) + multi->socket_cb(conn->data, s, CURL_POLL_REMOVE, multi->socket_userp, - entry ? entry->socketp : NULL); - sh_delentry(multi->sockhash, s); - } + entry->socketp); + /* now remove it from the socket hash */ + sh_delentry(&multi->sockhash, s); } } - - memcpy(easy->sockets, socks, num*sizeof(curl_socket_t)); - easy->numsocks = num; } + + /* * add_next_timeout() * @@ -2037,14 +2195,14 @@ static CURLMcode add_next_timeout(struct timeval now, break; e = n; } - if(!list->size) { + e = list->head; + if(!e) { /* clear the expire times within the handles that we remove from the splay tree */ tv->tv_sec = 0; tv->tv_usec = 0; } else { - e = list->head; /* copy the first entry to 'tv' */ memcpy(tv, e->ptr, sizeof(*tv)); @@ -2058,7 +2216,6 @@ static CURLMcode add_next_timeout(struct timeval now, return CURLM_OK; } - static CURLMcode multi_socket(struct Curl_multi *multi, bool checkall, curl_socket_t s, @@ -2071,16 +2228,17 @@ static CURLMcode multi_socket(struct Curl_multi *multi, struct timeval now = Curl_tvnow(); if(checkall) { - struct Curl_one_easy *easyp; /* *perform() deals with running_handles on its own */ result = curl_multi_perform(multi, running_handles); /* walk through each easy handle and do the socket state change magic and callbacks */ - easyp=multi->easy.next; - while(easyp != &multi->easy) { - singlesocket(multi, easyp); - easyp = easyp->next; + if(result != CURLM_BAD_HANDLE) { + data=multi->easyp; + while(data) { + singlesocket(multi, data); + data = data->next; + } } /* or should we fall-through and do the timer-based stuff? */ @@ -2088,8 +2246,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, } else if(s != CURL_SOCKET_TIMEOUT) { - struct Curl_sh_entry *entry = - Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); + struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); if(!entry) /* Unmatched socket, we can't act on it but we ignore this fact. In @@ -2099,6 +2256,8 @@ static CURLMcode multi_socket(struct Curl_multi *multi, and just move on. */ ; else { + SIGPIPE_VARIABLE(pipe_st); + data = entry->easy; if(data->magic != CURLEASY_MAGIC_NUMBER) @@ -2108,31 +2267,35 @@ static CURLMcode multi_socket(struct Curl_multi *multi, /* If the pipeline is enabled, take the handle which is in the head of the pipeline. If we should write into the socket, take the send_pipe head. If we should read from the socket, take the recv_pipe head. */ - if(data->set.one_easy->easy_conn) { - if ((ev_bitmask & CURL_POLL_OUT) && - data->set.one_easy->easy_conn->send_pipe && - data->set.one_easy->easy_conn->send_pipe->head) - data = data->set.one_easy->easy_conn->send_pipe->head->ptr; - else if ((ev_bitmask & CURL_POLL_IN) && - data->set.one_easy->easy_conn->recv_pipe && - data->set.one_easy->easy_conn->recv_pipe->head) - data = data->set.one_easy->easy_conn->recv_pipe->head->ptr; + if(data->easy_conn) { + if((ev_bitmask & CURL_POLL_OUT) && + data->easy_conn->send_pipe && + data->easy_conn->send_pipe->head) + data = data->easy_conn->send_pipe->head->ptr; + else if((ev_bitmask & CURL_POLL_IN) && + data->easy_conn->recv_pipe && + data->easy_conn->recv_pipe->head) + data = data->easy_conn->recv_pipe->head->ptr; } - if(data->set.one_easy->easy_conn) /* set socket event bitmask */ - data->set.one_easy->easy_conn->cselect_bits = ev_bitmask; + if(data->easy_conn && + !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK)) + /* set socket event bitmask if they're not locked */ + data->easy_conn->cselect_bits = ev_bitmask; - do - result = multi_runsingle(multi, now, data->set.one_easy); - while (CURLM_CALL_MULTI_PERFORM == result); + sigpipe_ignore(data, &pipe_st); + result = multi_runsingle(multi, now, data); + sigpipe_restore(&pipe_st); - if(data->set.one_easy->easy_conn) - data->set.one_easy->easy_conn->cselect_bits = 0; + if(data->easy_conn && + !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK)) + /* clear the bitmask only if not locked */ + data->easy_conn->cselect_bits = 0; if(CURLM_OK >= result) /* get the socket(s) and check if the state has been changed since last */ - singlesocket(multi, data->set.one_easy); + singlesocket(multi, data); /* Now we fall-through and do the timer-based stuff, since we don't want to force the user to have to deal with timeouts as long as at least @@ -2140,14 +2303,16 @@ static CURLMcode multi_socket(struct Curl_multi *multi, data = NULL; /* set data to NULL again to avoid calling multi_runsingle() in case there's no need to */ + now = Curl_tvnow(); /* get a newer time since the multi_runsingle() loop + may have taken some time */ } } - - now.tv_usec += 40000; /* compensate for bad precision timers that might've - triggered too early */ - if(now.tv_usec >= 1000000) { - now.tv_sec++; - now.tv_usec -= 1000000; + else { + /* Asked to run due to time-out. Clear the 'lastcall' variable to force + update_timer() to trigger a callback to the app again even if the same + timeout is still the one to run after this call. That handles the case + when the application asks libcurl to run the timeout prematurely. */ + memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); } /* @@ -2158,14 +2323,16 @@ static CURLMcode multi_socket(struct Curl_multi *multi, do { /* the first loop lap 'data' can be NULL */ if(data) { - do - result = multi_runsingle(multi, now, data->set.one_easy); - while (CURLM_CALL_MULTI_PERFORM == result); + SIGPIPE_VARIABLE(pipe_st); + + sigpipe_ignore(data, &pipe_st); + result = multi_runsingle(multi, now, data); + sigpipe_restore(&pipe_st); if(CURLM_OK >= result) /* get the socket(s) and check if the state has been changed since last */ - singlesocket(multi, data->set.one_easy); + singlesocket(multi, data); } /* Check if there's one (more) expired timer to deal with! This function @@ -2203,8 +2370,14 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle, case CURLMOPT_SOCKETDATA: multi->socket_userp = va_arg(param, void *); break; + case CURLMOPT_PUSHFUNCTION: + multi->push_cb = va_arg(param, curl_push_callback); + break; + case CURLMOPT_PUSHDATA: + multi->push_userp = va_arg(param, void *); + break; case CURLMOPT_PIPELINING: - multi->pipelining_enabled = (bool)(0 != va_arg(param, long)); + multi->pipelining = va_arg(param, long); break; case CURLMOPT_TIMERFUNCTION: multi->timer_cb = va_arg(param, curl_multi_timer_callback); @@ -2215,6 +2388,29 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle, case CURLMOPT_MAXCONNECTS: multi->maxconnects = va_arg(param, long); break; + case CURLMOPT_MAX_HOST_CONNECTIONS: + multi->max_host_connections = va_arg(param, long); + break; + case CURLMOPT_MAX_PIPELINE_LENGTH: + multi->max_pipeline_length = va_arg(param, long); + break; + case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE: + multi->content_length_penalty_size = va_arg(param, long); + break; + case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE: + multi->chunk_length_penalty_size = va_arg(param, long); + break; + case CURLMOPT_PIPELINING_SITE_BL: + res = Curl_pipeline_set_site_blacklist(va_arg(param, char **), + &multi->pipelining_site_bl); + break; + case CURLMOPT_PIPELINING_SERVER_BL: + res = Curl_pipeline_set_server_blacklist(va_arg(param, char **), + &multi->pipelining_server_bl); + break; + case CURLMOPT_MAX_TOTAL_CONNECTIONS: + multi->max_total_connections = va_arg(param, long); + break; default: res = CURLM_UNKNOWN_OPTION; break; @@ -2259,7 +2455,7 @@ CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles) static CURLMcode multi_timeout(struct Curl_multi *multi, long *timeout_ms) { - static struct timeval tv_zero = {0,0}; + static struct timeval tv_zero = {0, 0}; if(multi->timetree) { /* we have a tree of expire times */ @@ -2316,8 +2512,8 @@ static int update_timer(struct Curl_multi *multi) if(multi_timeout(multi, &timeout_ms)) { return -1; } - if( timeout_ms < 0 ) { - static const struct timeval none={0,0}; + if(timeout_ms < 0) { + static const struct timeval none={0, 0}; if(Curl_splaycomparekeys(none, multi->timer_lastcall)) { multi->timer_lastcall = none; /* there's no timeout now but there was one previously, tell the app to @@ -2339,135 +2535,6 @@ static int update_timer(struct Curl_multi *multi) return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp); } -static CURLcode addHandleToSendOrPendPipeline(struct SessionHandle *handle, - struct connectdata *conn) -{ - size_t pipeLen = conn->send_pipe->size + conn->recv_pipe->size; - struct curl_llist_element *sendhead = conn->send_pipe->head; - struct curl_llist *pipeline; - CURLcode rc; - - if(!Curl_isPipeliningEnabled(handle) || - pipeLen == 0) - pipeline = conn->send_pipe; - else { - if(conn->server_supports_pipelining && - pipeLen < MAX_PIPELINE_LENGTH) - pipeline = conn->send_pipe; - else - pipeline = conn->pend_pipe; - } - - rc = Curl_addHandleToPipeline(handle, pipeline); - - if (pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) { - /* this is a new one as head, expire it */ - conn->writechannel_inuse = FALSE; /* not in use yet */ - infof(conn->data, "%p is at send pipe head!\n", - conn->send_pipe->head->ptr); - Curl_expire(conn->send_pipe->head->ptr, 1); - } - - return rc; -} - -static int checkPendPipeline(struct connectdata *conn) -{ - int result = 0; - struct curl_llist_element *sendhead = conn->send_pipe->head; - - size_t pipeLen = conn->send_pipe->size + conn->recv_pipe->size; - if (conn->server_supports_pipelining || pipeLen == 0) { - struct curl_llist_element *curr = conn->pend_pipe->head; - const size_t maxPipeLen = - conn->server_supports_pipelining ? MAX_PIPELINE_LENGTH : 1; - - while(pipeLen < maxPipeLen && curr) { - Curl_llist_move(conn->pend_pipe, curr, - conn->send_pipe, conn->send_pipe->tail); - Curl_pgrsTime(curr->ptr, TIMER_PRETRANSFER); - ++result; /* count how many handles we moved */ - curr = conn->pend_pipe->head; - ++pipeLen; - } - } - - if (result) { - conn->now = Curl_tvnow(); - /* something moved, check for a new send pipeline leader */ - if(sendhead != conn->send_pipe->head) { - /* this is a new one as head, expire it */ - conn->writechannel_inuse = FALSE; /* not in use yet */ - infof(conn->data, "%p is at send pipe head!\n", - conn->send_pipe->head->ptr); - Curl_expire(conn->send_pipe->head->ptr, 1); - } - } - - return result; -} - -/* Move this transfer from the sending list to the receiving list. - - Pay special attention to the new sending list "leader" as it needs to get - checked to update what sockets it acts on. - -*/ -static void moveHandleFromSendToRecvPipeline(struct SessionHandle *handle, - struct connectdata *conn) -{ - struct curl_llist_element *curr; - - curr = conn->send_pipe->head; - while(curr) { - if(curr->ptr == handle) { - Curl_llist_move(conn->send_pipe, curr, - conn->recv_pipe, conn->recv_pipe->tail); - - if(conn->send_pipe->head) { - /* Since there's a new easy handle at the start of the send pipeline, - set its timeout value to 1ms to make it trigger instantly */ - conn->writechannel_inuse = FALSE; /* not used now */ - infof(conn->data, "%p is at send pipe head B!\n", - conn->send_pipe->head->ptr); - Curl_expire(conn->send_pipe->head->ptr, 1); - } - - /* The receiver's list is not really interesting here since either this - handle is now first in the list and we'll deal with it soon, or - another handle is already first and thus is already taken care of */ - - break; /* we're done! */ - } - curr = curr->next; - } -} - -static void moveHandleFromRecvToDonePipeline(struct SessionHandle *handle, - struct connectdata *conn) -{ - struct curl_llist_element *curr; - - curr = conn->recv_pipe->head; - while(curr) { - if(curr->ptr == handle) { - Curl_llist_move(conn->recv_pipe, curr, - conn->done_pipe, conn->done_pipe->tail); - break; - } - curr = curr->next; - } -} -static bool isHandleAtHead(struct SessionHandle *handle, - struct curl_llist *pipeline) -{ - struct curl_llist_element *curr = pipeline->head; - if(curr) - return (bool)(curr->ptr == handle); - - return FALSE; -} - /* * multi_freetimeout() * @@ -2543,8 +2610,8 @@ void Curl_expire(struct SessionHandle *data, long milli) struct timeval *nowp = &data->state.expiretime; int rc; - /* this is only interesting for multi-interface using libcurl, and only - while there is still a multi interface struct remaining! */ + /* this is only interesting while there is still an associated multi struct + remaining! */ if(!multi) return; @@ -2565,7 +2632,9 @@ void Curl_expire(struct SessionHandle *data, long milli) while(list->size > 0) Curl_llist_remove(list, list->tail, NULL); +#ifdef DEBUGBUILD infof(data, "Expire cleared\n"); +#endif nowp->tv_sec = 0; nowp->tv_usec = 0; } @@ -2618,14 +2687,53 @@ void Curl_expire(struct SessionHandle *data, long milli) #endif } +/* + * Curl_expire_latest() + * + * This is like Curl_expire() but will only add a timeout node to the list of + * timers if there is no timeout that will expire before the given time. + * + * Use this function if the code logic risks calling this function many times + * or if there's no particular conditional wait in the code for this specific + * time-out period to expire. + * + */ +void Curl_expire_latest(struct SessionHandle *data, long milli) +{ + struct timeval *expire = &data->state.expiretime; + + struct timeval set; + + set = Curl_tvnow(); + set.tv_sec += milli / 1000; + set.tv_usec += (milli % 1000) * 1000; + + if(set.tv_usec >= 1000000) { + set.tv_sec++; + set.tv_usec -= 1000000; + } + + if(expire->tv_sec || expire->tv_usec) { + /* This means that the struct is added as a node in the splay tree. + Compare if the new time is earlier, and only remove-old/add-new if it + is. */ + long diff = curlx_tvdiff(set, *expire); + if(diff > 0) + /* the new expire time was later than the top time, so just skip this */ + return; + } + + /* Just add the timeout like normal */ + Curl_expire(data, milli); +} + CURLMcode curl_multi_assign(CURLM *multi_handle, curl_socket_t s, void *hashp) { struct Curl_sh_entry *there = NULL; struct Curl_multi *multi = (struct Curl_multi *)multi_handle; - if(s != CURL_SOCKET_BAD) - there = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(curl_socket_t)); + there = sh_getentry(&multi->sockhash, s); if(!there) return CURLM_BAD_SOCKET; @@ -2635,139 +2743,75 @@ CURLMcode curl_multi_assign(CURLM *multi_handle, return CURLM_OK; } -static void multi_connc_remove_handle(struct Curl_multi *multi, - struct SessionHandle *data) +size_t Curl_multi_max_host_connections(struct Curl_multi *multi) { - /* a connection in the connection cache pointing to the given 'data' ? */ - int i; - - for(i=0; i< multi->connc->num; i++) { - struct connectdata * conn = multi->connc->connects[i]; - - if(conn && conn->data == data) { - /* If this easy_handle was the last one in charge for one or more - connections in the shared connection cache, we might need to keep - this handle around until either A) the connection is closed and - killed properly, or B) another easy_handle uses the connection. - - The reason why we need to have a easy_handle associated with a live - connection is simply that some connections will need a handle to get - closed down properly. Currently, the only connections that need to - keep a easy_handle handle around are using FTP(S). Such connections - have the PROT_CLOSEACTION bit set. - - Thus, we need to check for all connections in the shared cache that - points to this handle and are using PROT_CLOSEACTION. If there's any, - we need to add this handle to the list of "easy handles kept around - for nice connection closures". - */ - - if(conn->protocol & PROT_CLOSEACTION) { - /* this handle is still being used by a shared connection and - thus we leave it around for now */ - if(add_closure(multi, data) == CURLM_OK) - data->state.shared_conn = multi; - else { - /* out of memory - so much for graceful shutdown */ - Curl_disconnect(conn, /* dead_connection */ FALSE); - multi->connc->connects[i] = NULL; - } - } - else - /* disconect the easy handle from the connection since the connection - will now remain but this easy handle is going */ - conn->data = NULL; - } - } + return multi ? multi->max_host_connections : 0; } -/* Add the given data pointer to the list of 'closure handles' that are kept - around only to be able to close some connections nicely - just make sure - that this handle isn't already added, like for the cases when an easy - handle is removed, added and removed again... */ -static CURLMcode add_closure(struct Curl_multi *multi, - struct SessionHandle *data) +size_t Curl_multi_max_total_connections(struct Curl_multi *multi) { - struct closure *cl = multi->closure; - struct closure *p = NULL; - bool add = TRUE; + return multi ? multi->max_total_connections : 0; +} - /* Before adding, scan through all the other currently kept handles and see - if there are any connections still referring to them and kill them if - not. */ - while(cl) { - struct closure *n; - bool inuse = FALSE; - int i; +curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi) +{ + return multi ? multi->content_length_penalty_size : 0; +} - for(i=0; i< multi->connc->num; i++) { - if(multi->connc->connects[i] && - (multi->connc->connects[i]->data == cl->easy_handle)) { - inuse = TRUE; - break; - } +curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi) +{ + return multi ? multi->chunk_length_penalty_size : 0; +} + +struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi) +{ + return multi->pipelining_site_bl; +} + +struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi) +{ + return multi->pipelining_server_bl; +} + +void Curl_multi_process_pending_handles(struct Curl_multi *multi) +{ + struct curl_llist_element *e = multi->pending->head; + + while(e) { + struct SessionHandle *data = e->ptr; + struct curl_llist_element *next = e->next; + + if(data->mstate == CURLM_STATE_CONNECT_PEND) { + multistate(data, CURLM_STATE_CONNECT); + + /* Remove this node from the list */ + Curl_llist_remove(multi->pending, e, NULL); + + /* Make sure that the handle will be processed soonish. */ + Curl_expire_latest(data, 1); } - n = cl->next; - - if(!inuse) { - /* cl->easy_handle is now killable */ - - /* unmark it as not having a connection around that uses it anymore */ - cl->easy_handle->state.shared_conn= NULL; - - if(cl->easy_handle->state.closed) { - infof(data, "Delayed kill of easy handle %p\n", cl->easy_handle); - /* close handle only if curl_easy_cleanup() already has been called - for this easy handle */ - Curl_close(cl->easy_handle); - } - if(p) - p->next = n; - else - multi->closure = n; - free(cl); - } else { - if(cl->easy_handle == data) - add = FALSE; - - p = cl; - } - - cl = n; + e = next; /* operate on next handle */ } - - if (add) { - cl = calloc(1, sizeof(struct closure)); - if(!cl) - return CURLM_OUT_OF_MEMORY; - - cl->easy_handle = data; - cl->next = multi->closure; - multi->closure = cl; - } - - return CURLM_OK; } #ifdef DEBUGBUILD void Curl_multi_dump(const struct Curl_multi *multi_handle) { struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct Curl_one_easy *easy; + struct SessionHandle *data; int i; fprintf(stderr, "* Multi status: %d handles, %d alive\n", multi->num_easy, multi->num_alive); - for(easy=multi->easy.next; easy != &multi->easy; easy = easy->next) { - if(easy->state < CURLM_STATE_COMPLETED) { + for(data=multi->easyp; data; data = data->next) { + if(data->mstate < CURLM_STATE_COMPLETED) { /* only display handles that are not completed */ fprintf(stderr, "handle %p, state %s, %d sockets\n", - (void *)easy->easy_handle, - statename[easy->state], easy->numsocks); - for(i=0; i < easy->numsocks; i++) { - curl_socket_t s = easy->sockets[i]; - struct Curl_sh_entry *entry = - Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); + (void *)data, + statename[data->mstate], data->numsocks); + for(i=0; i < data->numsocks; i++) { + curl_socket_t s = data->sockets[i]; + struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); fprintf(stderr, "%d ", (int)s); if(!entry) { @@ -2778,7 +2822,7 @@ void Curl_multi_dump(const struct Curl_multi *multi_handle) entry->action&CURL_POLL_IN?"RECVING":"", entry->action&CURL_POLL_OUT?"SENDING":""); } - if(easy->numsocks) + if(data->numsocks) fprintf(stderr, "\n"); } } diff --git a/project/jni/curl/lib/multihandle.h b/project/jni/curl/lib/multihandle.h new file mode 100644 index 000000000..fc81a5540 --- /dev/null +++ b/project/jni/curl/lib/multihandle.h @@ -0,0 +1,152 @@ +#ifndef HEADER_CURL_MULTIHANDLE_H +#define HEADER_CURL_MULTIHANDLE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "conncache.h" + +struct Curl_message { + /* the 'CURLMsg' is the part that is visible to the external user */ + struct CURLMsg extmsg; +}; + +/* NOTE: if you add a state here, add the name to the statename[] array as + well! +*/ +typedef enum { + CURLM_STATE_INIT, /* 0 - start in this state */ + CURLM_STATE_CONNECT_PEND, /* 1 - no connections, waiting for one */ + CURLM_STATE_CONNECT, /* 2 - resolve/connect has been sent off */ + CURLM_STATE_WAITRESOLVE, /* 3 - awaiting the resolve to finalize */ + CURLM_STATE_WAITCONNECT, /* 4 - awaiting the TCP connect to finalize */ + CURLM_STATE_WAITPROXYCONNECT, /* 5 - awaiting proxy CONNECT to finalize */ + CURLM_STATE_SENDPROTOCONNECT, /* 6 - initiate protocol connect procedure */ + CURLM_STATE_PROTOCONNECT, /* 7 - completing the protocol-specific connect + phase */ + CURLM_STATE_WAITDO, /* 8 - wait for our turn to send the request */ + CURLM_STATE_DO, /* 9 - start send off the request (part 1) */ + CURLM_STATE_DOING, /* 10 - sending off the request (part 1) */ + CURLM_STATE_DO_MORE, /* 11 - send off the request (part 2) */ + CURLM_STATE_DO_DONE, /* 12 - done sending off request */ + CURLM_STATE_WAITPERFORM, /* 13 - wait for our turn to read the response */ + CURLM_STATE_PERFORM, /* 14 - transfer data */ + CURLM_STATE_TOOFAST, /* 15 - wait because limit-rate exceeded */ + CURLM_STATE_DONE, /* 16 - post data transfer operation */ + CURLM_STATE_COMPLETED, /* 17 - operation complete */ + CURLM_STATE_MSGSENT, /* 18 - the operation complete message is sent */ + CURLM_STATE_LAST /* 19 - not a true state, never use this */ +} CURLMstate; + +/* we support N sockets per easy handle. Set the corresponding bit to what + action we should wait for */ +#define MAX_SOCKSPEREASYHANDLE 5 +#define GETSOCK_READABLE (0x00ff) +#define GETSOCK_WRITABLE (0xff00) + +#define CURLPIPE_ANY (CURLPIPE_HTTP1 | CURLPIPE_MULTIPLEX) + +/* This is the struct known as CURLM on the outside */ +struct Curl_multi { + /* First a simple identifier to easier detect if a user mix up + this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */ + long type; + + /* We have a doubly-linked circular list with easy handles */ + struct SessionHandle *easyp; + struct SessionHandle *easylp; /* last node */ + + int num_easy; /* amount of entries in the linked list above. */ + int num_alive; /* amount of easy handles that are added but have not yet + reached COMPLETE state */ + + struct curl_llist *msglist; /* a list of messages from completed transfers */ + + struct curl_llist *pending; /* SessionHandles that are in the + CURLM_STATE_CONNECT_PEND state */ + + /* callback function and user data pointer for the *socket() API */ + curl_socket_callback socket_cb; + void *socket_userp; + + /* callback function and user data pointer for server push */ + curl_push_callback push_cb; + void *push_userp; + + /* Hostname cache */ + struct curl_hash hostcache; + + /* timetree points to the splay-tree of time nodes to figure out expire + times of all currently set timers */ + struct Curl_tree *timetree; + + /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note + the pluralis form, there can be more than one easy handle waiting on the + same actual socket) */ + struct curl_hash sockhash; + + /* pipelining wanted bits (CURLPIPE*) */ + long pipelining; + + bool recheckstate; /* see Curl_multi_connchanged */ + + /* Shared connection cache (bundles)*/ + struct conncache conn_cache; + + /* This handle will be used for closing the cached connections in + curl_multi_cleanup() */ + struct SessionHandle *closure_handle; + + long maxconnects; /* if >0, a fixed limit of the maximum number of entries + we're allowed to grow the connection cache to */ + + long max_host_connections; /* if >0, a fixed limit of the maximum number + of connections per host */ + + long max_total_connections; /* if >0, a fixed limit of the maximum number + of connections in total */ + + long max_pipeline_length; /* if >0, maximum number of requests in a + pipeline */ + + long content_length_penalty_size; /* a connection with a + content-length bigger than + this is not considered + for pipelining */ + + long chunk_length_penalty_size; /* a connection with a chunk length + bigger than this is not + considered for pipelining */ + + struct curl_llist *pipelining_site_bl; /* List of sites that are blacklisted + from pipelining */ + + struct curl_llist *pipelining_server_bl; /* List of server types that are + blacklisted from pipelining */ + + /* timer callback and user data pointer for the *socket() API */ + curl_multi_timer_callback timer_cb; + void *timer_userp; + struct timeval timer_lastcall; /* the fixed time for the timeout for the + previous callback */ +}; + +#endif /* HEADER_CURL_MULTIHANDLE_H */ diff --git a/project/jni/curl/lib/multiif.h b/project/jni/curl/lib/multiif.h index 76918181e..b229f53ee 100644 --- a/project/jni/curl/lib/multiif.h +++ b/project/jni/curl/lib/multiif.h @@ -1,5 +1,5 @@ -#ifndef __MULTIIF_H -#define __MULTIIF_H +#ifndef HEADER_CURL_MULTIIF_H +#define HEADER_CURL_MULTIIF_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,10 +26,14 @@ * Prototypes for library-wide functions provided by multi.c */ void Curl_expire(struct SessionHandle *data, long milli); - -bool Curl_multi_canPipeline(const struct Curl_multi* multi); +void Curl_expire_latest(struct SessionHandle *data, long milli); +bool Curl_pipeline_wanted(const struct Curl_multi* multi, int bits); void Curl_multi_handlePipeBreak(struct SessionHandle *data); +/* Internal version of curl_multi_init() accepts size parameters for the + socket and connection hashes */ +struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize); + /* the write bits start at bit 16 for the *getsock() bitmap */ #define GETSOCK_WRITEBITSTART 16 @@ -50,4 +54,44 @@ void Curl_multi_handlePipeBreak(struct SessionHandle *data); void Curl_multi_dump(const struct Curl_multi *multi_handle); #endif -#endif /* __MULTIIF_H */ +void Curl_multi_process_pending_handles(struct Curl_multi *multi); + +/* Return the value of the CURLMOPT_MAX_HOST_CONNECTIONS option */ +size_t Curl_multi_max_host_connections(struct Curl_multi *multi); + +/* Return the value of the CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE option */ +curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi); + +/* Return the value of the CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE option */ +curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi); + +/* Return the value of the CURLMOPT_PIPELINING_SITE_BL option */ +struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi); + +/* Return the value of the CURLMOPT_PIPELINING_SERVER_BL option */ +struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi); + +/* Return the value of the CURLMOPT_MAX_TOTAL_CONNECTIONS option */ +size_t Curl_multi_max_total_connections(struct Curl_multi *multi); + +void Curl_multi_connchanged(struct Curl_multi *multi); + +/* + * Curl_multi_closed() + * + * Used by the connect code to tell the multi_socket code that one of the + * sockets we were using is about to be closed. This function will then + * remove it from the sockethash for this handle to make the multi_socket API + * behave properly, especially for the case when libcurl will create another + * socket again and it gets the same file descriptor number. + */ + +void Curl_multi_closed(struct connectdata *conn, curl_socket_t s); + +/* + * Add a handle and move it into PERFORM state at once. For pushed streams. + */ +CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, + struct SessionHandle *data, + struct connectdata *conn); +#endif /* HEADER_CURL_MULTIIF_H */ diff --git a/project/jni/curl/lib/netrc.c b/project/jni/curl/lib/netrc.c index e9443253e..541310e2b 100644 --- a/project/jni/curl/lib/netrc.c +++ b/project/jni/curl/lib/netrc.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,70 +20,48 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#include -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif #ifdef HAVE_PWD_H #include #endif -#ifdef __VMS -#include -#endif #include #include "netrc.h" #include "strequal.h" #include "strtok.h" -#include "curl_memory.h" #include "rawstr.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" -/* Debug this single source file with: - 'make netrc' then run './netrc'! - - Oh, make sure you have a .netrc file too ;-) - */ - /* Get user and password from .netrc when given a machine name */ -enum { +enum host_lookup_state { NOTHING, HOSTFOUND, /* the 'machine' keyword was found */ - HOSTCOMPLETE, /* the machine name following the keyword was found too */ - HOSTVALID, /* this is "our" machine! */ - - HOSTEND /* LAST enum */ + HOSTVALID /* this is "our" machine! */ }; -/* make sure we have room for at least this size: */ -#define LOGINSIZE 64 -#define PASSWORDSIZE 64 - -/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */ +/* + * @unittest: 1304 + * + * *loginp and *passwordp MUST be allocated if they aren't NULL when passed + * in. + */ int Curl_parsenetrc(const char *host, - char *login, - char *password, + char **loginp, + char **passwordp, char *netrcfile) { FILE *file; int retcode=1; - int specific_login = (login[0] != 0); - char *home = NULL; - bool home_alloc = FALSE; + int specific_login = (*loginp && **loginp != 0); bool netrc_alloc = FALSE; - int state=NOTHING; + enum host_lookup_state state=NOTHING; char state_login=0; /* Found a login keyword */ char state_password=0; /* Found a password keyword */ @@ -91,53 +69,49 @@ int Curl_parsenetrc(const char *host, #define NETRC DOT_CHAR "netrc" -#ifdef DEBUGBUILD - { - /* This is a hack to allow testing. - * If compiled with --enable-debug and CURL_DEBUG_NETRC is defined, - * then it's the path to a substitute .netrc for testing purposes *only* */ - - char *override = curl_getenv("CURL_DEBUG_NETRC"); - - if(override) { - fprintf(stderr, "NETRC: overridden " NETRC " file: %s\n", override); - netrcfile = override; - netrc_alloc = TRUE; - } - } -#endif /* DEBUGBUILD */ if(!netrcfile) { - home = curl_getenv("HOME"); /* portable environment reader */ + bool home_alloc = FALSE; + char *home = curl_getenv("HOME"); /* portable environment reader */ if(home) { home_alloc = TRUE; -#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) +#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) + } + else { + struct passwd pw, *pw_res; + char pwbuf[1024]; + if(!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) + && pw_res) { + home = strdup(pw.pw_dir); + if(!home) + return CURLE_OUT_OF_MEMORY; + home_alloc = TRUE; + } +#elif defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) } else { struct passwd *pw; pw= getpwuid(geteuid()); if(pw) { -#ifdef __VMS - home = decc_translate_vms(pw->pw_dir); -#else home = pw->pw_dir; -#endif } #endif } if(!home) - return -1; + return retcode; /* no home directory found (or possibly out of memory) */ netrcfile = curl_maprintf("%s%s%s", home, DIR_CHAR, NETRC); + if(home_alloc) + free(home); if(!netrcfile) { - if(home_alloc) - free(home); return -1; } netrc_alloc = TRUE; } - file = fopen(netrcfile, "r"); + file = fopen(netrcfile, FOPEN_READTEXT); + if(netrc_alloc) + free(netrcfile); if(file) { char *tok; char *tok_buf; @@ -149,7 +123,7 @@ int Curl_parsenetrc(const char *host, tok=strtok_r(netrcbuffer, " \t\n", &tok_buf); while(!done && tok) { - if(login[0] && password[0]) { + if((*loginp && **loginp) && (*passwordp && **passwordp)) { done=TRUE; break; } @@ -163,14 +137,15 @@ int Curl_parsenetrc(const char *host, 'password'. */ state=HOSTFOUND; } + else if(Curl_raw_equal("default", tok)) { + state=HOSTVALID; + retcode=0; /* we did find our host */ + } break; case HOSTFOUND: if(Curl_raw_equal(host, tok)) { /* and yes, this is our host! */ state=HOSTVALID; -#ifdef _NETRC_DEBUG - fprintf(stderr, "HOST: %s\n", tok); -#endif retcode=0; /* we did find our host */ } else @@ -181,22 +156,26 @@ int Curl_parsenetrc(const char *host, /* we are now parsing sub-keywords concerning "our" host */ if(state_login) { if(specific_login) { - state_our_login = Curl_raw_equal(login, tok); + state_our_login = Curl_raw_equal(*loginp, tok); } else { - strncpy(login, tok, LOGINSIZE-1); -#ifdef _NETRC_DEBUG - fprintf(stderr, "LOGIN: %s\n", login); -#endif + free(*loginp); + *loginp = strdup(tok); + if(!*loginp) { + retcode = -1; /* allocation failed */ + goto out; + } } state_login=0; } else if(state_password) { if(state_our_login || !specific_login) { - strncpy(password, tok, PASSWORDSIZE-1); -#ifdef _NETRC_DEBUG - fprintf(stderr, "PASSWORD: %s\n", password); -#endif + free(*passwordp); + *passwordp = strdup(tok); + if(!*passwordp) { + retcode = -1; /* allocation failed */ + goto out; + } } state_password=0; } @@ -216,30 +195,9 @@ int Curl_parsenetrc(const char *host, } /* while(tok) */ } /* while fgets() */ + out: fclose(file); } - if(home_alloc) - free(home); - if(netrc_alloc) - free(netrcfile); - return retcode; } - -#ifdef _NETRC_DEBUG -int main(int argc, argv_item_t argv[]) -{ - char login[64]=""; - char password[64]=""; - - if(argc<2) - return -1; - - if(0 == ParseNetrc(argv[1], login, password)) { - printf("HOST: %s LOGIN: %s PASSWORD: %s\n", - argv[1], login, password); - } -} - -#endif diff --git a/project/jni/curl/lib/netrc.h b/project/jni/curl/lib/netrc.h index 5406d4c5d..d980166e6 100644 --- a/project/jni/curl/lib/netrc.h +++ b/project/jni/curl/lib/netrc.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,14 +21,16 @@ * KIND, either express or implied. * ***************************************************************************/ + +/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */ int Curl_parsenetrc(const char *host, - char *login, - char *password, + char **loginp, + char **passwordp, char *filename); - /* Assume: password[0]=0, host[0] != 0. - * If login[0] = 0, search for login and password within a machine section - * in the netrc. - * If login[0] != 0, search for password within machine and login. + /* Assume: (*passwordp)[0]=0, host[0] != 0. + * If (*loginp)[0] = 0, search for login and password within a machine + * section in the netrc. + * If (*loginp)[0] != 0, search for password within machine and login. */ #endif /* HEADER_CURL_NETRC_H */ diff --git a/project/jni/curl/lib/non-ascii.c b/project/jni/curl/lib/non-ascii.c new file mode 100644 index 000000000..205ff04ba --- /dev/null +++ b/project/jni/curl/lib/non-ascii.c @@ -0,0 +1,338 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef CURL_DOES_CONVERSIONS + +#include + +#include "non-ascii.h" +#include "formdata.h" +#include "sendf.h" +#include "urldata.h" + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +#ifdef HAVE_ICONV +#include +/* set default codesets for iconv */ +#ifndef CURL_ICONV_CODESET_OF_NETWORK +#define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1" +#endif +#ifndef CURL_ICONV_CODESET_FOR_UTF8 +#define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8" +#endif +#define ICONV_ERROR (size_t)-1 +#endif /* HAVE_ICONV */ + +/* + * Curl_convert_clone() returns a malloced copy of the source string (if + * returning CURLE_OK), with the data converted to network format. + */ +CURLcode Curl_convert_clone(struct SessionHandle *data, + const char *indata, + size_t insize, + char **outbuf) +{ + char *convbuf; + CURLcode result; + + convbuf = malloc(insize); + if(!convbuf) + return CURLE_OUT_OF_MEMORY; + + memcpy(convbuf, indata, insize); + result = Curl_convert_to_network(data, convbuf, insize); + if(result) { + free(convbuf); + return result; + } + + *outbuf = convbuf; /* return the converted buffer */ + + return CURLE_OK; +} + +/* + * Curl_convert_to_network() is an internal function for performing ASCII + * conversions on non-ASCII platforms. It convers the buffer _in place_. + */ +CURLcode Curl_convert_to_network(struct SessionHandle *data, + char *buffer, size_t length) +{ + if(data->set.convtonetwork) { + /* use translation callback */ + CURLcode result = data->set.convtonetwork(buffer, length); + if(result) { + failf(data, + "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s", + (int)result, curl_easy_strerror(result)); + } + + return result; + } + else { +#ifdef HAVE_ICONV + /* do the translation ourselves */ + char *input_ptr, *output_ptr; + size_t in_bytes, out_bytes, rc; + int error; + + /* open an iconv conversion descriptor if necessary */ + if(data->outbound_cd == (iconv_t)-1) { + data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, + CURL_ICONV_CODESET_OF_HOST); + if(data->outbound_cd == (iconv_t)-1) { + error = ERRNO; + failf(data, + "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", + CURL_ICONV_CODESET_OF_NETWORK, + CURL_ICONV_CODESET_OF_HOST, + error, strerror(error)); + return CURLE_CONV_FAILED; + } + } + /* call iconv */ + input_ptr = output_ptr = buffer; + in_bytes = out_bytes = length; + rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes, + &output_ptr, &out_bytes); + if((rc == ICONV_ERROR) || (in_bytes != 0)) { + error = ERRNO; + failf(data, + "The Curl_convert_to_network iconv call failed with errno %i: %s", + error, strerror(error)); + return CURLE_CONV_FAILED; + } +#else + failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required"); + return CURLE_CONV_REQD; +#endif /* HAVE_ICONV */ + } + + return CURLE_OK; +} + +/* + * Curl_convert_from_network() is an internal function for performing ASCII + * conversions on non-ASCII platforms. It convers the buffer _in place_. + */ +CURLcode Curl_convert_from_network(struct SessionHandle *data, + char *buffer, size_t length) +{ + if(data->set.convfromnetwork) { + /* use translation callback */ + CURLcode result = data->set.convfromnetwork(buffer, length); + if(result) { + failf(data, + "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s", + (int)result, curl_easy_strerror(result)); + } + + return result; + } + else { +#ifdef HAVE_ICONV + /* do the translation ourselves */ + char *input_ptr, *output_ptr; + size_t in_bytes, out_bytes, rc; + int error; + + /* open an iconv conversion descriptor if necessary */ + if(data->inbound_cd == (iconv_t)-1) { + data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, + CURL_ICONV_CODESET_OF_NETWORK); + if(data->inbound_cd == (iconv_t)-1) { + error = ERRNO; + failf(data, + "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", + CURL_ICONV_CODESET_OF_HOST, + CURL_ICONV_CODESET_OF_NETWORK, + error, strerror(error)); + return CURLE_CONV_FAILED; + } + } + /* call iconv */ + input_ptr = output_ptr = buffer; + in_bytes = out_bytes = length; + rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes, + &output_ptr, &out_bytes); + if((rc == ICONV_ERROR) || (in_bytes != 0)) { + error = ERRNO; + failf(data, + "Curl_convert_from_network iconv call failed with errno %i: %s", + error, strerror(error)); + return CURLE_CONV_FAILED; + } +#else + failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required"); + return CURLE_CONV_REQD; +#endif /* HAVE_ICONV */ + } + + return CURLE_OK; +} + +/* + * Curl_convert_from_utf8() is an internal function for performing UTF-8 + * conversions on non-ASCII platforms. + */ +CURLcode Curl_convert_from_utf8(struct SessionHandle *data, + char *buffer, size_t length) +{ + if(data->set.convfromutf8) { + /* use translation callback */ + CURLcode result = data->set.convfromutf8(buffer, length); + if(result) { + failf(data, + "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s", + (int)result, curl_easy_strerror(result)); + } + + return result; + } + else { +#ifdef HAVE_ICONV + /* do the translation ourselves */ + const char *input_ptr; + char *output_ptr; + size_t in_bytes, out_bytes, rc; + int error; + + /* open an iconv conversion descriptor if necessary */ + if(data->utf8_cd == (iconv_t)-1) { + data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, + CURL_ICONV_CODESET_FOR_UTF8); + if(data->utf8_cd == (iconv_t)-1) { + error = ERRNO; + failf(data, + "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", + CURL_ICONV_CODESET_OF_HOST, + CURL_ICONV_CODESET_FOR_UTF8, + error, strerror(error)); + return CURLE_CONV_FAILED; + } + } + /* call iconv */ + input_ptr = output_ptr = buffer; + in_bytes = out_bytes = length; + rc = iconv(data->utf8_cd, &input_ptr, &in_bytes, + &output_ptr, &out_bytes); + if((rc == ICONV_ERROR) || (in_bytes != 0)) { + error = ERRNO; + failf(data, + "The Curl_convert_from_utf8 iconv call failed with errno %i: %s", + error, strerror(error)); + return CURLE_CONV_FAILED; + } + if(output_ptr < input_ptr) { + /* null terminate the now shorter output string */ + *output_ptr = 0x00; + } +#else + failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required"); + return CURLE_CONV_REQD; +#endif /* HAVE_ICONV */ + } + + return CURLE_OK; +} + +/* + * Init conversion stuff for a SessionHandle + */ +void Curl_convert_init(struct SessionHandle *data) +{ +#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) + /* conversion descriptors for iconv calls */ + data->outbound_cd = (iconv_t)-1; + data->inbound_cd = (iconv_t)-1; + data->utf8_cd = (iconv_t)-1; +#else + (void)data; +#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ +} + +/* + * Setup conversion stuff for a SessionHandle + */ +void Curl_convert_setup(struct SessionHandle *data) +{ + data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, + CURL_ICONV_CODESET_OF_NETWORK); + data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, + CURL_ICONV_CODESET_OF_HOST); + data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, + CURL_ICONV_CODESET_FOR_UTF8); +} + +/* + * Close conversion stuff for a SessionHandle + */ + +void Curl_convert_close(struct SessionHandle *data) +{ +#ifdef HAVE_ICONV + /* close iconv conversion descriptors */ + if(data->inbound_cd != (iconv_t)-1) { + iconv_close(data->inbound_cd); + } + if(data->outbound_cd != (iconv_t)-1) { + iconv_close(data->outbound_cd); + } + if(data->utf8_cd != (iconv_t)-1) { + iconv_close(data->utf8_cd); + } +#else + (void)data; +#endif /* HAVE_ICONV */ +} + +/* + * Curl_convert_form() is used from http.c, this converts any form items that + need to be sent in the network encoding. Returns CURLE_OK on success. + */ +CURLcode Curl_convert_form(struct SessionHandle *data, struct FormData *form) +{ + CURLcode result; + + if(!data) + return CURLE_BAD_FUNCTION_ARGUMENT; + + while(form) { + if(form->type == FORM_DATA) { + result = Curl_convert_to_network(data, form->line, form->length); + /* Curl_convert_to_network calls failf if unsuccessful */ + if(result) + return result; + } + + form = form->next; + } + + return CURLE_OK; +} + +#endif /* CURL_DOES_CONVERSIONS */ diff --git a/project/jni/curl/lib/non-ascii.h b/project/jni/curl/lib/non-ascii.h new file mode 100644 index 000000000..f3e2049e4 --- /dev/null +++ b/project/jni/curl/lib/non-ascii.h @@ -0,0 +1,63 @@ +#ifndef HEADER_CURL_NON_ASCII_H +#define HEADER_CURL_NON_ASCII_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef CURL_DOES_CONVERSIONS + +#include "urldata.h" + +/* + * Curl_convert_clone() returns a malloced copy of the source string (if + * returning CURLE_OK), with the data converted to network format. + * + * If no conversion was needed *outbuf may be NULL. + */ +CURLcode Curl_convert_clone(struct SessionHandle *data, + const char *indata, + size_t insize, + char **outbuf); + +void Curl_convert_init(struct SessionHandle *data); +void Curl_convert_setup(struct SessionHandle *data); +void Curl_convert_close(struct SessionHandle *data); + +CURLcode Curl_convert_to_network(struct SessionHandle *data, + char *buffer, size_t length); +CURLcode Curl_convert_from_network(struct SessionHandle *data, + char *buffer, size_t length); +CURLcode Curl_convert_from_utf8(struct SessionHandle *data, + char *buffer, size_t length); +CURLcode Curl_convert_form(struct SessionHandle *data, struct FormData *form); +#else +#define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK) +#define Curl_convert_init(x) Curl_nop_stmt +#define Curl_convert_setup(x) Curl_nop_stmt +#define Curl_convert_close(x) Curl_nop_stmt +#define Curl_convert_to_network(a,b,c) ((void)a, CURLE_OK) +#define Curl_convert_from_network(a,b,c) ((void)a, CURLE_OK) +#define Curl_convert_from_utf8(a,b,c) ((void)a, CURLE_OK) +#define Curl_convert_form(a,b) CURLE_OK +#endif + +#endif /* HEADER_CURL_NON_ASCII_H */ diff --git a/project/jni/curl/lib/nonblock.c b/project/jni/curl/lib/nonblock.c index cd819506c..b764278a5 100644 --- a/project/jni/curl/lib/nonblock.c +++ b/project/jni/curl/lib/nonblock.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,23 +20,14 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_SYS_IOCTL_H #include #endif -#ifdef HAVE_UNISTD_H -#include -#endif #ifdef HAVE_FCNTL_H #include #endif -#ifdef HAVE_STDLIB_H -#include -#endif #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE)) #include @@ -64,35 +55,34 @@ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */ /* most recent unix versions */ int flags; - flags = fcntl(sockfd, F_GETFL, 0); - if(FALSE != nonblock) - return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + flags = sfcntl(sockfd, F_GETFL, 0); + if(nonblock) + return sfcntl(sockfd, F_SETFL, flags | O_NONBLOCK); else - return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); + return sfcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); #elif defined(HAVE_IOCTL_FIONBIO) /* older unix versions */ - int flags; - flags = nonblock; + int flags = nonblock ? 1 : 0; return ioctl(sockfd, FIONBIO, &flags); #elif defined(HAVE_IOCTLSOCKET_FIONBIO) /* Windows */ - unsigned long flags; - flags = nonblock; + unsigned long flags = nonblock ? 1UL : 0UL; return ioctlsocket(sockfd, FIONBIO, &flags); #elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO) /* Amiga */ - return IoctlSocket(sockfd, FIONBIO, (long)nonblock); + long flags = nonblock ? 1L : 0L; + return IoctlSocket(sockfd, FIONBIO, (char *)&flags); #elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK) /* BeOS */ - long b = nonblock ? 1 : 0; + long b = nonblock ? 1L : 0L; return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); #else diff --git a/project/jni/curl/lib/nonblock.h b/project/jni/curl/lib/nonblock.h index adcd2c15e..98cdc25ab 100644 --- a/project/jni/curl/lib/nonblock.h +++ b/project/jni/curl/lib/nonblock.h @@ -1,5 +1,5 @@ -#ifndef __NONBLOCK_H -#define __NONBLOCK_H +#ifndef HEADER_CURL_NONBLOCK_H +#define HEADER_CURL_NONBLOCK_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -27,4 +27,5 @@ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */ int nonblock /* TRUE or FALSE */); -#endif +#endif /* HEADER_CURL_NONBLOCK_H */ + diff --git a/project/jni/curl/lib/nss.c b/project/jni/curl/lib/nss.c deleted file mode 100644 index 6d3f12c03..000000000 --- a/project/jni/curl/lib/nss.c +++ /dev/null @@ -1,1481 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Source file for all NSS-specific code for the TLS/SSL layer. No code - * but sslgen.c should ever call or use these functions. - */ - -#include "setup.h" - -#include -#include -#include -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include "urldata.h" -#include "sendf.h" -#include "formdata.h" /* for the boundary function */ -#include "url.h" /* for the ssl config check function */ -#include "connect.h" -#include "strequal.h" -#include "select.h" -#include "sslgen.h" - -#define _MPRINTF_REPLACE /* use the internal *printf() functions */ -#include - -#ifdef USE_NSS - -#include "nssg.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "curl_memory.h" -#include "rawstr.h" -#include "easyif.h" /* for Curl_convert_from_utf8 prototype */ - -/* The last #include file should be: */ -#include "memdebug.h" - -#define SSL_DIR "/etc/pki/nssdb" - -/* enough to fit the string "PEM Token #[0|1]" */ -#define SLOTSIZE 13 - -PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd); - -PRLock * nss_initlock = NULL; -PRLock * nss_crllock = NULL; - -volatile int initialized = 0; - -typedef struct { - const char *name; - int num; - PRInt32 version; /* protocol version valid for this cipher */ -} cipher_s; - -#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \ - (x)->pValue=(v); (x)->ulValueLen = (l) - -#define CERT_NewTempCertificate __CERT_NewTempCertificate - -enum sslversion { SSL2 = 1, SSL3 = 2, TLS = 4 }; - -#define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0]) -static const cipher_s cipherlist[] = { - /* SSL2 cipher suites */ - {"rc4", SSL_EN_RC4_128_WITH_MD5, SSL2}, - {"rc4-md5", SSL_EN_RC4_128_WITH_MD5, SSL2}, - {"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5, SSL2}, - {"rc2", SSL_EN_RC2_128_CBC_WITH_MD5, SSL2}, - {"rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, SSL2}, - {"des", SSL_EN_DES_64_CBC_WITH_MD5, SSL2}, - {"desede3", SSL_EN_DES_192_EDE3_CBC_WITH_MD5, SSL2}, - /* SSL3/TLS cipher suites */ - {"rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5, SSL3 | TLS}, - {"rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA, SSL3 | TLS}, - {"rsa_3des_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL3 | TLS}, - {"rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA, SSL3 | TLS}, - {"rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL3 | TLS}, - {"rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL3 | TLS}, - {"rsa_null_md5", SSL_RSA_WITH_NULL_MD5, SSL3 | TLS}, - {"rsa_null_sha", SSL_RSA_WITH_NULL_SHA, SSL3 | TLS}, - {"fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, SSL3 | TLS}, - {"fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA, SSL3 | TLS}, - {"fortezza", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, SSL3 | TLS}, - {"fortezza_rc4_128_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, SSL3 | TLS}, - {"fortezza_null", SSL_FORTEZZA_DMS_WITH_NULL_SHA, SSL3 | TLS}, - /* TLS 1.0: Exportable 56-bit Cipher Suites. */ - {"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, SSL3 | TLS}, - {"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, SSL3 | TLS}, - /* AES ciphers. */ - {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA, SSL3 | TLS}, - {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA, SSL3 | TLS}, -#ifdef NSS_ENABLE_ECC - /* ECC ciphers. */ - {"ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA, TLS}, - {"ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS}, - {"ecdh_ecdsa_3des_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS}, - {"ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS}, - {"ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS}, - {"ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA, TLS}, - {"ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS}, - {"ecdhe_ecdsa_3des_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS}, - {"ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS}, - {"ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS}, - {"ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA, TLS}, - {"ecdh_rsa_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS}, - {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, TLS}, - {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS}, - {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS}, - {"echde_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA, TLS}, - {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS}, - {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS}, - {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS}, - {"ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS}, - {"ecdh_anon_null_sha", TLS_ECDH_anon_WITH_NULL_SHA, TLS}, - {"ecdh_anon_rc4_128sha", TLS_ECDH_anon_WITH_RC4_128_SHA, TLS}, - {"ecdh_anon_3des_sha", TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, TLS}, - {"ecdh_anon_aes_128_sha", TLS_ECDH_anon_WITH_AES_128_CBC_SHA, TLS}, - {"ecdh_anon_aes_256_sha", TLS_ECDH_anon_WITH_AES_256_CBC_SHA, TLS}, -#endif -}; - -/* following ciphers are new in NSS 3.4 and not enabled by default, therefore - they are enabled explicitly */ -static const int enable_ciphers_by_default[] = { - TLS_DHE_DSS_WITH_AES_128_CBC_SHA, - TLS_DHE_DSS_WITH_AES_256_CBC_SHA, - TLS_DHE_RSA_WITH_AES_128_CBC_SHA, - TLS_DHE_RSA_WITH_AES_256_CBC_SHA, - TLS_RSA_WITH_AES_128_CBC_SHA, - TLS_RSA_WITH_AES_256_CBC_SHA, - SSL_NULL_WITH_NULL_NULL -}; - -#ifdef HAVE_PK11_CREATEGENERICOBJECT -static const char* pem_library = "libnsspem.so"; -#endif -SECMODModule* mod = NULL; - -static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model, - char *cipher_list) -{ - unsigned int i; - PRBool cipher_state[NUM_OF_CIPHERS]; - PRBool found; - char *cipher; - SECStatus rv; - - /* First disable all ciphers. This uses a different max value in case - * NSS adds more ciphers later we don't want them available by - * accident - */ - for(i=0; icacert[slotID] = PK11_CreateGenericObject(slot, theTemplate, 4, - PR_FALSE /* isPerm */); - - PK11_FreeSlot(slot); - - if(ssl->cacert[slotID] == NULL) { - free(nickname); - return 0; - } -#else - /* We don't have PK11_CreateGenericObject but a file-based cert was passed - * in. We need to fail. - */ - return 0; -#endif - - done: - /* Double-check that the certificate or nickname requested exists in - * either the token or the NSS certificate database. - */ - if(!cacert) { - cert = PK11_FindCertFromNickname((char *)nickname, NULL); - - /* An invalid nickname was passed in */ - if(cert == NULL) { - free(nickname); - PR_SetError(SEC_ERROR_UNKNOWN_CERT, 0); - return 0; - } - - CERT_DestroyCertificate(cert); - } - - free(nickname); - - return 1; -} - -/* add given CRL to cache if it is not already there */ -static SECStatus nss_cache_crl(SECItem *crlDER) -{ - CERTCertDBHandle *db = CERT_GetDefaultCertDB(); - CERTSignedCrl *crl = SEC_FindCrlByDERCert(db, crlDER, 0); - if(crl) { - /* CRL already cached */ - SEC_DestroyCrl(crl); - SECITEM_FreeItem(crlDER, PR_FALSE); - return SECSuccess; - } - - /* acquire lock before call of CERT_CacheCRL() */ - PR_Lock(nss_crllock); - if(SECSuccess != CERT_CacheCRL(db, crlDER)) { - /* unable to cache CRL */ - PR_Unlock(nss_crllock); - SECITEM_FreeItem(crlDER, PR_FALSE); - return SECFailure; - } - - /* we need to clear session cache, so that the CRL could take effect */ - SSL_ClearSessionCache(); - PR_Unlock(nss_crllock); - return SECSuccess; -} - -static SECStatus nss_load_crl(const char* crlfilename) -{ - PRFileDesc *infile; - PRFileInfo info; - SECItem filedata = { 0, NULL, 0 }; - SECItem crlDER = { 0, NULL, 0 }; - char *body; - - infile = PR_Open(crlfilename, PR_RDONLY, 0); - if(!infile) - return SECFailure; - - if(PR_SUCCESS != PR_GetOpenFileInfo(infile, &info)) - goto fail; - - if(!SECITEM_AllocItem(NULL, &filedata, info.size + /* zero ended */ 1)) - goto fail; - - if(info.size != PR_Read(infile, filedata.data, info.size)) - goto fail; - - /* place a trailing zero right after the visible data */ - body = (char*)filedata.data; - body[--filedata.len] = '\0'; - - body = strstr(body, "-----BEGIN"); - if(body) { - /* assume ASCII */ - char *trailer; - char *begin = PORT_Strchr(body, '\n'); - if(!begin) - begin = PORT_Strchr(body, '\r'); - if(!begin) - goto fail; - - trailer = strstr(++begin, "-----END"); - if(!trailer) - goto fail; - - /* retrieve DER from ASCII */ - *trailer = '\0'; - if(ATOB_ConvertAsciiToItem(&crlDER, begin)) - goto fail; - - SECITEM_FreeItem(&filedata, PR_FALSE); - } - else - /* assume DER */ - crlDER = filedata; - - PR_Close(infile); - return nss_cache_crl(&crlDER); - -fail: - PR_Close(infile); - SECITEM_FreeItem(&filedata, PR_FALSE); - return SECFailure; -} - -static int nss_load_key(struct connectdata *conn, int sockindex, - char *key_file) -{ -#ifdef HAVE_PK11_CREATEGENERICOBJECT - PK11SlotInfo * slot = NULL; - CK_ATTRIBUTE *attrs; - CK_ATTRIBUTE theTemplate[20]; - CK_BBOOL cktrue = CK_TRUE; - CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY; - CK_SLOT_ID slotID; - char slotname[SLOTSIZE]; - struct ssl_connect_data *sslconn = &conn->ssl[sockindex]; - - attrs = theTemplate; - - /* FIXME: grok the various file types */ - - slotID = 1; /* hardcoded for now */ - - snprintf(slotname, sizeof(slotname), "PEM Token #%ld", slotID); - slot = PK11_FindSlotByName(slotname); - - if(!slot) - return 0; - - PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++; - PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++; - PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)key_file, - strlen(key_file)+1); attrs++; - - /* When adding an encrypted key the PKCS#11 will be set as removed */ - sslconn->key = PK11_CreateGenericObject(slot, theTemplate, 3, - PR_FALSE /* isPerm */); - if(sslconn->key == NULL) { - PR_SetError(SEC_ERROR_BAD_KEY, 0); - return 0; - } - - /* This will force the token to be seen as re-inserted */ - SECMOD_WaitForAnyTokenEvent(mod, 0, 0); - PK11_IsPresent(slot); - - /* parg is initialized in nss_Init_Tokens() */ - if(PK11_Authenticate(slot, PR_TRUE, - conn->data->set.str[STRING_KEY_PASSWD]) != SECSuccess) { - - PK11_FreeSlot(slot); - return 0; - } - PK11_FreeSlot(slot); - - return 1; -#else - /* If we don't have PK11_CreateGenericObject then we can't load a file-based - * key. - */ - (void)conn; /* unused */ - (void)key_file; /* unused */ - return 0; -#endif -} - -static int display_error(struct connectdata *conn, PRInt32 err, - const char *filename) -{ - switch(err) { - case SEC_ERROR_BAD_PASSWORD: - failf(conn->data, "Unable to load client key: Incorrect password"); - return 1; - case SEC_ERROR_UNKNOWN_CERT: - failf(conn->data, "Unable to load certificate %s", filename); - return 1; - default: - break; - } - return 0; /* The caller will print a generic error */ -} - -static int cert_stuff(struct connectdata *conn, - int sockindex, char *cert_file, char *key_file) -{ - struct SessionHandle *data = conn->data; - int rv = 0; - - if(cert_file) { - rv = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE); - if(!rv) { - if(!display_error(conn, PR_GetError(), cert_file)) - failf(data, "Unable to load client cert %d.", PR_GetError()); - return 0; - } - } - if(key_file || (is_file(cert_file))) { - if(key_file) - rv = nss_load_key(conn, sockindex, key_file); - else - /* In case the cert file also has the key */ - rv = nss_load_key(conn, sockindex, cert_file); - if(!rv) { - if(!display_error(conn, PR_GetError(), key_file)) - failf(data, "Unable to load client key %d.", PR_GetError()); - - return 0; - } - } - return 1; -} - -static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg) -{ - (void)slot; /* unused */ - if(retry || NULL == arg) - return NULL; - else - return (char *)PORT_Strdup((char *)arg); -} - -static SECStatus BadCertHandler(void *arg, PRFileDesc *sock) -{ - SECStatus success = SECSuccess; - struct connectdata *conn = (struct connectdata *)arg; - PRErrorCode err = PR_GetError(); - CERTCertificate *cert = NULL; - char *subject, *subject_cn, *issuer; - - if(conn->data->set.ssl.certverifyresult!=0) - return success; - - conn->data->set.ssl.certverifyresult=err; - cert = SSL_PeerCertificate(sock); - subject = CERT_NameToAscii(&cert->subject); - subject_cn = CERT_GetCommonName(&cert->subject); - issuer = CERT_NameToAscii(&cert->issuer); - CERT_DestroyCertificate(cert); - - switch(err) { - case SEC_ERROR_CA_CERT_INVALID: - infof(conn->data, "Issuer certificate is invalid: '%s'\n", issuer); - if(conn->data->set.ssl.verifypeer) - success = SECFailure; - break; - case SEC_ERROR_UNTRUSTED_ISSUER: - if(conn->data->set.ssl.verifypeer) - success = SECFailure; - infof(conn->data, "Certificate is signed by an untrusted issuer: '%s'\n", - issuer); - break; - case SSL_ERROR_BAD_CERT_DOMAIN: - if(conn->data->set.ssl.verifyhost) { - failf(conn->data, "SSL: certificate subject name '%s' does not match " - "target host name '%s'", subject_cn, conn->host.dispname); - success = SECFailure; - } else { - infof(conn->data, "warning: SSL: certificate subject name '%s' does not " - "match target host name '%s'\n", subject_cn, conn->host.dispname); - } - break; - case SEC_ERROR_EXPIRED_CERTIFICATE: - if(conn->data->set.ssl.verifypeer) - success = SECFailure; - infof(conn->data, "Remote Certificate has expired.\n"); - break; - case SEC_ERROR_UNKNOWN_ISSUER: - if(conn->data->set.ssl.verifypeer) - success = SECFailure; - infof(conn->data, "Peer's certificate issuer is not recognized: '%s'\n", - issuer); - break; - default: - if(conn->data->set.ssl.verifypeer) - success = SECFailure; - infof(conn->data, "Bad certificate received. Subject = '%s', " - "Issuer = '%s'\n", subject, issuer); - break; - } - if(success == SECSuccess) - infof(conn->data, "SSL certificate verify ok.\n"); - PR_Free(subject); - PR_Free(subject_cn); - PR_Free(issuer); - - return success; -} - -/** - * Inform the application that the handshake is complete. - */ -static SECStatus HandshakeCallback(PRFileDesc *sock, void *arg) -{ - (void)sock; - (void)arg; - return SECSuccess; -} - -static void display_cert_info(struct SessionHandle *data, - CERTCertificate *cert) -{ - char *subject, *issuer, *common_name; - PRExplodedTime printableTime; - char timeString[256]; - PRTime notBefore, notAfter; - - subject = CERT_NameToAscii(&cert->subject); - issuer = CERT_NameToAscii(&cert->issuer); - common_name = CERT_GetCommonName(&cert->subject); - infof(data, "\tsubject: %s\n", subject); - - CERT_GetCertTimes(cert, ¬Before, ¬After); - PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime); - PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime); - infof(data, "\tstart date: %s\n", timeString); - PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime); - PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime); - infof(data, "\texpire date: %s\n", timeString); - infof(data, "\tcommon name: %s\n", common_name); - infof(data, "\tissuer: %s\n", issuer); - - PR_Free(subject); - PR_Free(issuer); - PR_Free(common_name); -} - -static void display_conn_info(struct connectdata *conn, PRFileDesc *sock) -{ - SSLChannelInfo channel; - SSLCipherSuiteInfo suite; - CERTCertificate *cert; - - if(SSL_GetChannelInfo(sock, &channel, sizeof channel) == - SECSuccess && channel.length == sizeof channel && - channel.cipherSuite) { - if(SSL_GetCipherSuiteInfo(channel.cipherSuite, - &suite, sizeof suite) == SECSuccess) { - infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName); - } - } - - infof(conn->data, "Server certificate:\n"); - - cert = SSL_PeerCertificate(sock); - display_cert_info(conn->data, cert); - CERT_DestroyCertificate(cert); - - return; -} - -/** - * - * Check that the Peer certificate's issuer certificate matches the one found - * by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the - * issuer check, so we provide comments that mimic the OpenSSL - * X509_check_issued function (in x509v3/v3_purp.c) - */ -static SECStatus check_issuer_cert(PRFileDesc *sock, - char *issuer_nickname) -{ - CERTCertificate *cert,*cert_issuer,*issuer; - SECStatus res=SECSuccess; - void *proto_win = NULL; - - /* - PRArenaPool *tmpArena = NULL; - CERTAuthKeyID *authorityKeyID = NULL; - SECITEM *caname = NULL; - */ - - cert = SSL_PeerCertificate(sock); - cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner); - - proto_win = SSL_RevealPinArg(sock); - issuer = NULL; - issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win); - - if ((!cert_issuer) || (!issuer)) - res = SECFailure; - else if (SECITEM_CompareItem(&cert_issuer->derCert, - &issuer->derCert)!=SECEqual) - res = SECFailure; - - CERT_DestroyCertificate(cert); - CERT_DestroyCertificate(issuer); - CERT_DestroyCertificate(cert_issuer); - return res; -} - -/** - * - * Callback to pick the SSL client certificate. - */ -static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, - struct CERTDistNamesStr *caNames, - struct CERTCertificateStr **pRetCert, - struct SECKEYPrivateKeyStr **pRetKey) -{ - static const char pem_nickname[] = "PEM Token #1"; - const char *pem_slotname = pem_nickname; - - struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; - struct SessionHandle *data = connssl->data; - const char *nickname = connssl->client_nickname; - - if (mod && nickname && - 0 == strncmp(nickname, pem_nickname, /* length of "PEM Token" */ 9)) { - - /* use the cert/key provided by PEM reader */ - PK11SlotInfo *slot; - void *proto_win = SSL_RevealPinArg(sock); - *pRetKey = NULL; - - *pRetCert = PK11_FindCertFromNickname(nickname, proto_win); - if (NULL == *pRetCert) { - failf(data, "NSS: client certificate not found: %s", nickname); - return SECFailure; - } - - slot = PK11_FindSlotByName(pem_slotname); - if (NULL == slot) { - failf(data, "NSS: PK11 slot not found: %s", pem_slotname); - return SECFailure; - } - - *pRetKey = PK11_FindPrivateKeyFromCert(slot, *pRetCert, NULL); - PK11_FreeSlot(slot); - if (NULL == *pRetKey) { - failf(data, "NSS: private key not found for certificate: %s", nickname); - return SECFailure; - } - - infof(data, "NSS: client certificate: %s\n", nickname); - display_cert_info(data, *pRetCert); - return SECSuccess; - } - - /* use the default NSS hook */ - if (SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames, - pRetCert, pRetKey) - || NULL == *pRetCert) { - - if (NULL == nickname) - failf(data, "NSS: client certificate not found (nickname not " - "specified)"); - else - failf(data, "NSS: client certificate not found: %s", nickname); - - return SECFailure; - } - - /* get certificate nickname if any */ - nickname = (*pRetCert)->nickname; - if (NULL == nickname) - nickname = "[unknown]"; - - if (NULL == *pRetKey) { - failf(data, "NSS: private key not found for certificate: %s", nickname); - return SECFailure; - } - - infof(data, "NSS: using client certificate: %s\n", nickname); - display_cert_info(data, *pRetCert); - return SECSuccess; -} - -/* This function is supposed to decide, which error codes should be used - * to conclude server is TLS intolerant. - * - * taken from xulrunner - nsNSSIOLayer.cpp - */ -static PRBool -isTLSIntoleranceError(PRInt32 err) -{ - switch (err) { - case SSL_ERROR_BAD_MAC_ALERT: - case SSL_ERROR_BAD_MAC_READ: - case SSL_ERROR_HANDSHAKE_FAILURE_ALERT: - case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT: - case SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE: - case SSL_ERROR_ILLEGAL_PARAMETER_ALERT: - case SSL_ERROR_NO_CYPHER_OVERLAP: - case SSL_ERROR_BAD_SERVER: - case SSL_ERROR_BAD_BLOCK_PADDING: - case SSL_ERROR_UNSUPPORTED_VERSION: - case SSL_ERROR_PROTOCOL_VERSION_ALERT: - case SSL_ERROR_RX_MALFORMED_FINISHED: - case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE: - case SSL_ERROR_DECODE_ERROR_ALERT: - case SSL_ERROR_RX_UNKNOWN_ALERT: - return PR_TRUE; - default: - return PR_FALSE; - } -} - -static CURLcode init_nss(struct SessionHandle *data) -{ - char *cert_dir; - struct_stat st; - if(initialized) - return CURLE_OK; - - /* First we check if $SSL_DIR points to a valid dir */ - cert_dir = getenv("SSL_DIR"); - if(cert_dir) { - if((stat(cert_dir, &st) != 0) || - (!S_ISDIR(st.st_mode))) { - cert_dir = NULL; - } - } - - /* Now we check if the default location is a valid dir */ - if(!cert_dir) { - if((stat(SSL_DIR, &st) == 0) && - (S_ISDIR(st.st_mode))) { - cert_dir = (char *)SSL_DIR; - } - } - - if(!NSS_IsInitialized()) { - SECStatus rv; - initialized = 1; - infof(data, "Initializing NSS with certpath: %s\n", - cert_dir ? cert_dir : "none"); - if(!cert_dir) { - rv = NSS_NoDB_Init(NULL); - } - else { - char *certpath = - PR_smprintf("%s%s", NSS_VersionCheck("3.12.0") ? "sql:" : "", cert_dir); - rv = NSS_Initialize(certpath, "", "", "", NSS_INIT_READONLY); - PR_smprintf_free(certpath); - } - if(rv != SECSuccess) { - infof(data, "Unable to initialize NSS database\n"); - initialized = 0; - return CURLE_SSL_CACERT_BADFILE; - } - } - - if(num_enabled_ciphers() == 0) - NSS_SetDomesticPolicy(); - - return CURLE_OK; -} - -/** - * Global SSL init - * - * @retval 0 error initializing SSL - * @retval 1 SSL initialized successfully - */ -int Curl_nss_init(void) -{ - /* curl_global_init() is not thread-safe so this test is ok */ - if (nss_initlock == NULL) { - PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256); - nss_initlock = PR_NewLock(); - nss_crllock = PR_NewLock(); - } - - /* We will actually initialize NSS later */ - - return 1; -} - -CURLcode Curl_nss_force_init(struct SessionHandle *data) -{ - CURLcode rv; - if(!nss_initlock) { - failf(data, "unable to initialize NSS, curl_global_init() should have been " - "called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL"); - return CURLE_OUT_OF_MEMORY; - } - - PR_Lock(nss_initlock); - rv = init_nss(data); - PR_Unlock(nss_initlock); - return rv; -} - -/* Global cleanup */ -void Curl_nss_cleanup(void) -{ - /* This function isn't required to be threadsafe and this is only done - * as a safety feature. - */ - PR_Lock(nss_initlock); - if (initialized) { - /* Free references to client certificates held in the SSL session cache. - * Omitting this hampers destruction of the security module owning - * the certificates. */ - SSL_ClearSessionCache(); - - if(mod && SECSuccess == SECMOD_UnloadUserModule(mod)) { - SECMOD_DestroyModule(mod); - mod = NULL; - } - NSS_Shutdown(); - } - PR_Unlock(nss_initlock); - - PR_DestroyLock(nss_initlock); - PR_DestroyLock(nss_crllock); - nss_initlock = NULL; - - initialized = 0; -} - -/* - * This function uses SSL_peek to determine connection status. - * - * Return codes: - * 1 means the connection is still in place - * 0 means the connection has been closed - * -1 means the connection status is unknown - */ -int -Curl_nss_check_cxn(struct connectdata *conn) -{ - int rc; - char buf; - - rc = - PR_Recv(conn->ssl[FIRSTSOCKET].handle, (void *)&buf, 1, PR_MSG_PEEK, - PR_SecondsToInterval(1)); - if(rc > 0) - return 1; /* connection still in place */ - - if(rc == 0) - return 0; /* connection has been closed */ - - return -1; /* connection status unknown */ -} - -/* - * This function is called when an SSL connection is closed. - */ -void Curl_nss_close(struct connectdata *conn, int sockindex) -{ - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - if(connssl->handle) { - PR_Close(connssl->handle); - - /* NSS closes the socket we previously handed to it, so we must mark it - as closed to avoid double close */ - fake_sclose(conn->sock[sockindex]); - conn->sock[sockindex] = CURL_SOCKET_BAD; - if(connssl->client_nickname != NULL) { - free(connssl->client_nickname); - connssl->client_nickname = NULL; - } -#ifdef HAVE_PK11_CREATEGENERICOBJECT - if(connssl->key) - (void)PK11_DestroyGenericObject(connssl->key); - if(connssl->cacert[1]) - (void)PK11_DestroyGenericObject(connssl->cacert[1]); - if(connssl->cacert[0]) - (void)PK11_DestroyGenericObject(connssl->cacert[0]); -#endif - connssl->handle = NULL; - } -} - -/* - * This function is called when the 'data' struct is going away. Close - * down everything and free all resources! - */ -int Curl_nss_close_all(struct SessionHandle *data) -{ - (void)data; - return 0; -} - -/* handle client certificate related errors if any; return false otherwise */ -static bool handle_cc_error(PRInt32 err, struct SessionHandle *data) -{ - switch(err) { - case SSL_ERROR_BAD_CERT_ALERT: - failf(data, "SSL error: SSL_ERROR_BAD_CERT_ALERT"); - return true; - - case SSL_ERROR_REVOKED_CERT_ALERT: - failf(data, "SSL error: SSL_ERROR_REVOKED_CERT_ALERT"); - return true; - - case SSL_ERROR_EXPIRED_CERT_ALERT: - failf(data, "SSL error: SSL_ERROR_EXPIRED_CERT_ALERT"); - return true; - - default: - return false; - } -} - -static Curl_recv nss_recv; -static Curl_send nss_send; - -CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) -{ - PRInt32 err; - PRFileDesc *model = NULL; - PRBool ssl2 = PR_FALSE; - PRBool ssl3 = PR_FALSE; - PRBool tlsv1 = PR_FALSE; - struct SessionHandle *data = conn->data; - curl_socket_t sockfd = conn->sock[sockindex]; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - int curlerr; - const int *cipher_to_enable; - PRSocketOptionData sock_opt; - long time_left; - PRUint32 timeout; - - if (connssl->state == ssl_connection_complete) - return CURLE_OK; - - connssl->data = data; - -#ifdef HAVE_PK11_CREATEGENERICOBJECT - connssl->cacert[0] = NULL; - connssl->cacert[1] = NULL; - connssl->key = NULL; -#endif - - /* FIXME. NSS doesn't support multiple databases open at the same time. */ - PR_Lock(nss_initlock); - curlerr = init_nss(conn->data); - if(CURLE_OK != curlerr) { - PR_Unlock(nss_initlock); - goto error; - } - - curlerr = CURLE_SSL_CONNECT_ERROR; - -#ifdef HAVE_PK11_CREATEGENERICOBJECT - if(!mod) { - char *configstring = aprintf("library=%s name=PEM", pem_library); - if(!configstring) { - PR_Unlock(nss_initlock); - goto error; - } - mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE); - free(configstring); - - if(!mod || !mod->loaded) { - if(mod) { - SECMOD_DestroyModule(mod); - mod = NULL; - } - infof(data, "WARNING: failed to load NSS PEM library %s. Using " - "OpenSSL PEM certificates will not work.\n", pem_library); - } - } -#endif - - PK11_SetPasswordFunc(nss_get_password); - PR_Unlock(nss_initlock); - - model = PR_NewTCPSocket(); - if(!model) - goto error; - model = SSL_ImportFD(NULL, model); - - /* make the socket nonblocking */ - sock_opt.option = PR_SockOpt_Nonblocking; - sock_opt.value.non_blocking = PR_TRUE; - if(PR_SetSocketOption(model, &sock_opt) != SECSuccess) - goto error; - - if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess) - goto error; - if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess) - goto error; - if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess) - goto error; - - switch (data->set.ssl.version) { - default: - case CURL_SSLVERSION_DEFAULT: - ssl3 = PR_TRUE; - if (data->state.ssl_connect_retry) - infof(data, "TLS disabled due to previous handshake failure\n"); - else - tlsv1 = PR_TRUE; - break; - case CURL_SSLVERSION_TLSv1: - tlsv1 = PR_TRUE; - break; - case CURL_SSLVERSION_SSLv2: - ssl2 = PR_TRUE; - break; - case CURL_SSLVERSION_SSLv3: - ssl3 = PR_TRUE; - break; - } - - if(SSL_OptionSet(model, SSL_ENABLE_SSL2, ssl2) != SECSuccess) - goto error; - if(SSL_OptionSet(model, SSL_ENABLE_SSL3, ssl3) != SECSuccess) - goto error; - if(SSL_OptionSet(model, SSL_ENABLE_TLS, tlsv1) != SECSuccess) - goto error; - - if(SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, ssl2) != SECSuccess) - goto error; - - /* reset the flag to avoid an infinite loop */ - data->state.ssl_connect_retry = FALSE; - - /* enable all ciphers from enable_ciphers_by_default */ - cipher_to_enable = enable_ciphers_by_default; - while (SSL_NULL_WITH_NULL_NULL != *cipher_to_enable) { - if (SSL_CipherPrefSet(model, *cipher_to_enable, PR_TRUE) != SECSuccess) { - curlerr = CURLE_SSL_CIPHER; - goto error; - } - cipher_to_enable++; - } - - if(data->set.ssl.cipher_list) { - if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) { - curlerr = CURLE_SSL_CIPHER; - goto error; - } - } - - if(data->set.ssl.verifyhost == 1) - infof(data, "warning: ignoring unsupported value (1) of ssl.verifyhost\n"); - - data->set.ssl.certverifyresult=0; /* not checked yet */ - if(SSL_BadCertHook(model, (SSLBadCertHandler) BadCertHandler, conn) - != SECSuccess) { - goto error; - } - if(SSL_HandshakeCallback(model, (SSLHandshakeCallback) HandshakeCallback, - NULL) != SECSuccess) - goto error; - - if(!data->set.ssl.verifypeer) - /* skip the verifying of the peer */ - ; - else if(data->set.ssl.CAfile) { - int rc = nss_load_cert(&conn->ssl[sockindex], data->set.ssl.CAfile, - PR_TRUE); - if(!rc) { - curlerr = CURLE_SSL_CACERT_BADFILE; - goto error; - } - } - else if(data->set.ssl.CApath) { - struct_stat st; - PRDir *dir; - PRDirEntry *entry; - - if(stat(data->set.ssl.CApath, &st) == -1) { - curlerr = CURLE_SSL_CACERT_BADFILE; - goto error; - } - - if(S_ISDIR(st.st_mode)) { - int rc; - - dir = PR_OpenDir(data->set.ssl.CApath); - do { - entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN); - - if(entry) { - char fullpath[PATH_MAX]; - - snprintf(fullpath, sizeof(fullpath), "%s/%s", data->set.ssl.CApath, - entry->name); - rc = nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE); - /* FIXME: check this return value! */ - } - /* This is purposefully tolerant of errors so non-PEM files - * can be in the same directory */ - } while(entry != NULL); - PR_CloseDir(dir); - } - } - infof(data, - " CAfile: %s\n" - " CApath: %s\n", - data->set.ssl.CAfile ? data->set.ssl.CAfile : "none", - data->set.ssl.CApath ? data->set.ssl.CApath : "none"); - - if (data->set.ssl.CRLfile) { - if(SECSuccess != nss_load_crl(data->set.ssl.CRLfile)) { - curlerr = CURLE_SSL_CRL_BADFILE; - goto error; - } - infof(data, - " CRLfile: %s\n", - data->set.ssl.CRLfile ? data->set.ssl.CRLfile : "none"); - } - - if(data->set.str[STRING_CERT]) { - bool nickname_alloc = FALSE; - char *nickname = fmt_nickname(data->set.str[STRING_CERT], &nickname_alloc); - if(!nickname) - return CURLE_OUT_OF_MEMORY; - - if(!cert_stuff(conn, sockindex, data->set.str[STRING_CERT], - data->set.str[STRING_KEY])) { - /* failf() is already done in cert_stuff() */ - if(nickname_alloc) - free(nickname); - return CURLE_SSL_CERTPROBLEM; - } - - /* this "takes over" the pointer to the allocated name or makes a - dup of it */ - connssl->client_nickname = nickname_alloc?nickname:strdup(nickname); - if(!connssl->client_nickname) - return CURLE_OUT_OF_MEMORY; - - } - else - connssl->client_nickname = NULL; - - if(SSL_GetClientAuthDataHook(model, SelectClientCert, - (void *)connssl) != SECSuccess) { - curlerr = CURLE_SSL_CERTPROBLEM; - goto error; - } - - /* Import our model socket onto the existing file descriptor */ - connssl->handle = PR_ImportTCPSocket(sockfd); - connssl->handle = SSL_ImportFD(model, connssl->handle); - if(!connssl->handle) - goto error; - - PR_Close(model); /* We don't need this any more */ - model = NULL; - - /* This is the password associated with the cert that we're using */ - if (data->set.str[STRING_KEY_PASSWD]) { - SSL_SetPKCS11PinArg(connssl->handle, data->set.str[STRING_KEY_PASSWD]); - } - - /* Force handshake on next I/O */ - SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE); - - SSL_SetURL(connssl->handle, conn->host.name); - - /* check timeout situation */ - time_left = Curl_timeleft(conn, NULL, TRUE); - if(time_left < 0L) { - failf(data, "timed out before SSL handshake"); - goto error; - } - timeout = PR_MillisecondsToInterval((PRUint32) time_left); - - /* Force the handshake now */ - if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) { - if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) - curlerr = CURLE_PEER_FAILED_VERIFICATION; - else if(conn->data->set.ssl.certverifyresult!=0) - curlerr = CURLE_SSL_CACERT; - goto error; - } - - connssl->state = ssl_connection_complete; - conn->recv[sockindex] = nss_recv; - conn->send[sockindex] = nss_send; - - display_conn_info(conn, connssl->handle); - - if (data->set.str[STRING_SSL_ISSUERCERT]) { - SECStatus ret; - bool nickname_alloc = FALSE; - char *nickname = fmt_nickname(data->set.str[STRING_SSL_ISSUERCERT], - &nickname_alloc); - - if(!nickname) - return CURLE_OUT_OF_MEMORY; - - ret = check_issuer_cert(connssl->handle, nickname); - - if(nickname_alloc) - free(nickname); - - if(SECFailure == ret) { - infof(data,"SSL certificate issuer check failed\n"); - curlerr = CURLE_SSL_ISSUER_ERROR; - goto error; - } - else { - infof(data, "SSL certificate issuer check ok\n"); - } - } - - return CURLE_OK; - - error: - /* reset the flag to avoid an infinite loop */ - data->state.ssl_connect_retry = FALSE; - - err = PR_GetError(); - if(handle_cc_error(err, data)) - curlerr = CURLE_SSL_CERTPROBLEM; - else - infof(data, "NSS error %d\n", err); - - if(model) - PR_Close(model); - - if (ssl3 && tlsv1 && isTLSIntoleranceError(err)) { - /* schedule reconnect through Curl_retry_request() */ - data->state.ssl_connect_retry = TRUE; - infof(data, "Error in TLS handshake, trying SSLv3...\n"); - return CURLE_OK; - } - - return curlerr; -} - -static ssize_t nss_send(struct connectdata *conn, /* connection data */ - int sockindex, /* socketindex */ - const void *mem, /* send this data */ - size_t len, /* amount to write */ - CURLcode *curlcode) -{ - int rc; - - rc = PR_Send(conn->ssl[sockindex].handle, mem, (int)len, 0, -1); - - if(rc < 0) { - PRInt32 err = PR_GetError(); - if(err == PR_WOULD_BLOCK_ERROR) - *curlcode = CURLE_AGAIN; - else if(handle_cc_error(err, conn->data)) - *curlcode = CURLE_SSL_CERTPROBLEM; - else { - failf(conn->data, "SSL write: error %d", err); - *curlcode = CURLE_SEND_ERROR; - } - return -1; - } - return rc; /* number of bytes */ -} - -static ssize_t nss_recv(struct connectdata * conn, /* connection data */ - int num, /* socketindex */ - char *buf, /* store read data here */ - size_t buffersize, /* max amount to read */ - CURLcode *curlcode) -{ - ssize_t nread; - - nread = PR_Recv(conn->ssl[num].handle, buf, (int)buffersize, 0, -1); - if(nread < 0) { - /* failed SSL read */ - PRInt32 err = PR_GetError(); - - if(err == PR_WOULD_BLOCK_ERROR) - *curlcode = CURLE_AGAIN; - else if(handle_cc_error(err, conn->data)) - *curlcode = CURLE_SSL_CERTPROBLEM; - else { - failf(conn->data, "SSL read: errno %d", err); - *curlcode = CURLE_RECV_ERROR; - } - return -1; - } - return nread; -} - -size_t Curl_nss_version(char *buffer, size_t size) -{ - return snprintf(buffer, size, "NSS/%s", NSS_VERSION); -} - -int Curl_nss_seed(struct SessionHandle *data) -{ - /* TODO: implement? */ - (void) data; - return 0; -} - -#endif /* USE_NSS */ diff --git a/project/jni/curl/lib/nwlib.c b/project/jni/curl/lib/nwlib.c index f9c8a4298..7feb8fc3b 100644 --- a/project/jni/curl/lib/nwlib.c +++ b/project/jni/curl/lib/nwlib.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,20 +20,21 @@ * ***************************************************************************/ -#ifdef NETWARE /* Novell NetWare */ +#include "curl_setup.h" -#include +#ifdef NETWARE /* Novell NetWare */ #ifdef __NOVELL_LIBC__ /* For native LibC-based NLM we need to register as a real lib. */ -#include -#include #include #include #include #include #include +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" typedef struct { @@ -57,9 +58,9 @@ rtag_t gAllocTag = (rtag_t) NULL; NXMutex_t *gLibLock = (NXMutex_t *) NULL; /* internal library function prototypes... */ -int DisposeLibraryData ( void * ); -void DisposeThreadData ( void * ); -int GetOrSetUpData ( int id, libdata_t **data, libthreaddata_t **threaddata ); +int DisposeLibraryData( void * ); +void DisposeThreadData( void * ); +int GetOrSetUpData( int id, libdata_t **data, libthreaddata_t **threaddata ); int _NonAppStart( void *NLMHandle, @@ -92,12 +93,12 @@ int _NonAppStart( void *NLMHandle, #pragma unused(messages) #endif -/* -** Here we process our command line, post errors (to the error screen), -** perform initializations and anything else we need to do before being able -** to accept calls into us. If we succeed, we return non-zero and the NetWare -** Loader will leave us up, otherwise we fail to load and get dumped. -*/ + /* + * Here we process our command line, post errors (to the error screen), + * perform initializations and anything else we need to do before being able + * to accept calls into us. If we succeed, we return non-zero and the NetWare + * Loader will leave us up, otherwise we fail to load and get dumped. + */ gAllocTag = AllocateResourceTag(NLMHandle, " memory allocations", AllocSignature); @@ -128,9 +129,9 @@ int _NonAppStart( void *NLMHandle, } /* -** Here we clean up any resources we allocated. Resource tags is a big part -** of what we created, but NetWare doesn't ask us to free those. -*/ + * Here we clean up any resources we allocated. Resource tags is a big part + * of what we created, but NetWare doesn't ask us to free those. + */ void _NonAppStop( void ) { (void) unregister_library(gLibId); @@ -138,16 +139,16 @@ void _NonAppStop( void ) } /* -** This function cannot be the first in the file for if the file is linked -** first, then the check-unload function's offset will be nlmname.nlm+0 -** which is how to tell that there isn't one. When the check function is -** first in the linked objects, it is ambiguous. For this reason, we will -** put it inside this file after the stop function. -** -** Here we check to see if it's alright to ourselves to be unloaded. If not, -** we return a non-zero value. Right now, there isn't any reason not to allow -** it. -*/ + * This function cannot be the first in the file for if the file is linked + * first, then the check-unload function's offset will be nlmname.nlm+0 + * which is how to tell that there isn't one. When the check function is + * first in the linked objects, it is ambiguous. For this reason, we will + * put it inside this file after the stop function. + * + * Here we check to see if it's alright to ourselves to be unloaded. If not, + * we return a non-zero value. Right now, there isn't any reason not to allow + * it. + */ int _NonAppCheckUnload( void ) { return 0; @@ -165,22 +166,22 @@ int GetOrSetUpData(int id, libdata_t **appData, err = 0; thread_data = (libthreaddata_t *) NULL; -/* -** Attempt to get our data for the application calling us. This is where we -** store whatever application-specific information we need to carry in support -** of calling applications. -*/ + /* + * Attempt to get our data for the application calling us. This is where we + * store whatever application-specific information we need to carry in + * support of calling applications. + */ app_data = (libdata_t *) get_app_data(id); if(!app_data) { -/* -** This application hasn't called us before; set up application AND per-thread -** data. Of course, just in case a thread from this same application is calling -** us simultaneously, we better lock our application data-creation mutex. We -** also need to recheck for data after we acquire the lock because WE might be -** that other thread that was too late to create the data and the first thread -** in will have created it. -*/ + /* + * This application hasn't called us before; set up application AND + * per-thread data. Of course, just in case a thread from this same + * application is calling us simultaneously, we better lock our application + * data-creation mutex. We also need to recheck for data after we acquire + * the lock because WE might be that other thread that was too late to + * create the data and the first thread in will have created it. + */ NXLock(gLibLock); if(!(app_data = (libdata_t *) get_app_data(id))) { @@ -202,13 +203,14 @@ int GetOrSetUpData(int id, libdata_t **appData, } if(app_data) { -/* -** Here we burn in the application data that we were trying to get by calling -** get_app_data(). Next time we call the first function, we'll get this data -** we're just now setting. We also go on here to establish the per-thread data -** for the calling thread, something we'll have to do on each application -** thread the first time it calls us. -*/ + /* + * Here we burn in the application data that we were trying to get + * by calling get_app_data(). Next time we call the first function, + * we'll get this data we're just now setting. We also go on here to + * establish the per-thread data for the calling thread, something + * we'll have to do on each application thread the first time + * it calls us. + */ err = set_app_data(gLibId, app_data); if(err) { @@ -238,13 +240,13 @@ int GetOrSetUpData(int id, libdata_t **appData, if(key != -1 /* couldn't create a key? no thread data */ && !(err = NXKeyGetValue(key, (void **) &thread_data)) && !thread_data) { -/* -** Allocate the per-thread data for the calling thread. Regardless of whether -** there was already application data or not, this may be the first call by a -** a new thread. The fact that we allocation 20 bytes on a pointer is not very -** important, this just helps to demonstrate that we can have arbitrarily -** complex per-thread data. -*/ + /* + * Allocate the per-thread data for the calling thread. Regardless of + * whether there was already application data or not, this may be the + * first call by a new thread. The fact that we allocation 20 bytes on + * a pointer is not very important, this just helps to demonstrate that + * we can have arbitrarily complex per-thread data. + */ thread_data = malloc(sizeof(libthreaddata_t)); if(thread_data) { @@ -280,9 +282,7 @@ int DisposeLibraryData( void *data ) if(data) { void *tenbytes = ((libdata_t *) data)->tenbytes; - if(tenbytes) - free(tenbytes); - + free(tenbytes); free(data); } @@ -294,9 +294,7 @@ void DisposeThreadData( void *data ) if(data) { void *twentybytes = ((libthreaddata_t *) data)->twentybytes; - if(twentybytes) - free(twentybytes); - + free(twentybytes); free(data); } } @@ -307,13 +305,13 @@ void DisposeThreadData( void *data ) int main ( void ) { - /* initialize any globals here... */ + /* initialize any globals here... */ - /* do this if any global initializing was done - SynchronizeStart(); - */ - ExitThread (TSR_THREAD, 0); - return 0; + /* do this if any global initializing was done + SynchronizeStart(); + */ + ExitThread (TSR_THREAD, 0); + return 0; } #endif /* __NOVELL_LIBC__ */ diff --git a/project/jni/curl/lib/nwos.c b/project/jni/curl/lib/nwos.c index ac365124f..28137e919 100644 --- a/project/jni/curl/lib/nwos.c +++ b/project/jni/curl/lib/nwos.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,21 +20,20 @@ * ***************************************************************************/ -#ifdef NETWARE /* Novell NetWare */ +#include "curl_setup.h" -#include +#ifdef NETWARE /* Novell NetWare */ #ifdef __NOVELL_LIBC__ /* For native LibC-based NLM we need to do nothing. */ int netware_init ( void ) { - return 0; + return 0; } #else /* __NOVELL_LIBC__ */ /* For native CLib-based NLM we need to initialize the LONG namespace. */ -#include #include #include #include @@ -48,48 +47,42 @@ NETINET_DEFINE_CONTEXT int netware_init ( void ) { - int rc = 0; - unsigned int myHandle = GetNLMHandle(); - /* import UnAugmentAsterisk dynamically for NW4.x compatibility */ - void (*pUnAugmentAsterisk)(int) = (void(*)(int)) - ImportSymbol(myHandle, "UnAugmentAsterisk"); - /* import UseAccurateCaseForPaths dynamically for NW3.x compatibility */ - void (*pUseAccurateCaseForPaths)(int) = (void(*)(int)) - ImportSymbol(myHandle, "UseAccurateCaseForPaths"); - if(pUnAugmentAsterisk) - pUnAugmentAsterisk(1); - if(pUseAccurateCaseForPaths) - pUseAccurateCaseForPaths(1); - UnimportSymbol(myHandle, "UnAugmentAsterisk"); - UnimportSymbol(myHandle, "UseAccurateCaseForPaths"); - /* set long name space */ - if((SetCurrentNameSpace(4) == 255)) { - rc = 1; - } - if((SetTargetNameSpace(4) == 255)) { - rc = rc + 2; - } - return rc; + int rc = 0; + unsigned int myHandle = GetNLMHandle(); + /* import UnAugmentAsterisk dynamically for NW4.x compatibility */ + void (*pUnAugmentAsterisk)(int) = (void(*)(int)) + ImportSymbol(myHandle, "UnAugmentAsterisk"); + /* import UseAccurateCaseForPaths dynamically for NW3.x compatibility */ + void (*pUseAccurateCaseForPaths)(int) = (void(*)(int)) + ImportSymbol(myHandle, "UseAccurateCaseForPaths"); + if(pUnAugmentAsterisk) + pUnAugmentAsterisk(1); + if(pUseAccurateCaseForPaths) + pUseAccurateCaseForPaths(1); + UnimportSymbol(myHandle, "UnAugmentAsterisk"); + UnimportSymbol(myHandle, "UseAccurateCaseForPaths"); + /* set long name space */ + if((SetCurrentNameSpace(4) == 255)) { + rc = 1; + } + if((SetTargetNameSpace(4) == 255)) { + rc = rc + 2; + } + return rc; } /* dummy function to satisfy newer prelude */ int __init_environment ( void ) { - return 0; + return 0; } /* dummy function to satisfy newer prelude */ int __deinit_environment ( void ) { - return 0; + return 0; } #endif /* __NOVELL_LIBC__ */ -#else /* NETWARE */ - -#ifdef __POCC__ -# pragma warn(disable:2024) /* Disable warning #2024: Empty input file */ -#endif - #endif /* NETWARE */ diff --git a/project/jni/curl/lib/openldap.c b/project/jni/curl/lib/openldap.c index 7010da6c2..7241bb906 100644 --- a/project/jni/curl/lib/openldap.c +++ b/project/jni/curl/lib/openldap.c @@ -6,10 +6,11 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010, Howard Chu, + * Copyright (C) 2011 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,7 +21,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #if !defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP) @@ -40,28 +41,29 @@ #include "urldata.h" #include #include "sendf.h" -#include "sslgen.h" +#include "vtls/vtls.h" #include "transfer.h" #include "curl_ldap.h" -#include "curl_memory.h" #include "curl_base64.h" +#include "connect.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #ifndef _LDAP_PVT_H extern int ldap_pvt_url_scheme2proto(const char *); -extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url, LDAP **ld); +extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url, + LDAP **ld); #endif -static CURLcode ldap_setup(struct connectdata *conn); +static CURLcode ldap_setup_connection(struct connectdata *conn); static CURLcode ldap_do(struct connectdata *conn, bool *done); static CURLcode ldap_done(struct connectdata *conn, CURLcode, bool); static CURLcode ldap_connect(struct connectdata *conn, bool *done); static CURLcode ldap_connecting(struct connectdata *conn, bool *done); -static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection); +static CURLcode ldap_disconnect(struct connectdata *conn, bool dead); static Curl_recv ldap_recv; @@ -71,7 +73,7 @@ static Curl_recv ldap_recv; const struct Curl_handler Curl_handler_ldap = { "LDAP", /* scheme */ - ldap_setup, /* setup_connection */ + ldap_setup_connection, /* setup_connection */ ldap_do, /* do_it */ ldap_done, /* done */ ZERO_NULL, /* do_more */ @@ -80,10 +82,13 @@ const struct Curl_handler Curl_handler_ldap = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ldap_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_LDAP, /* defport */ - PROT_LDAP /* protocol */ + CURLPROTO_LDAP, /* protocol */ + PROTOPT_NONE /* flags */ }; #ifdef USE_SSL @@ -93,7 +98,7 @@ const struct Curl_handler Curl_handler_ldap = { const struct Curl_handler Curl_handler_ldaps = { "LDAPS", /* scheme */ - ldap_setup, /* setup_connection */ + ldap_setup_connection, /* setup_connection */ ldap_do, /* do_it */ ldap_done, /* done */ ZERO_NULL, /* do_more */ @@ -102,10 +107,13 @@ const struct Curl_handler Curl_handler_ldaps = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ldap_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_LDAPS, /* defport */ - PROT_LDAP | PROT_SSL /* protocol */ + CURLPROTO_LDAP, /* protocol */ + PROTOPT_SSL /* flags */ }; #endif @@ -139,7 +147,7 @@ typedef struct ldapreqinfo { int nument; } ldapreqinfo; -static CURLcode ldap_setup(struct connectdata *conn) +static CURLcode ldap_setup_connection(struct connectdata *conn) { ldapconninfo *li; LDAPURLDesc *lud; @@ -148,11 +156,11 @@ static CURLcode ldap_setup(struct connectdata *conn) CURLcode status; rc = ldap_url_parse(data->change.url, &lud); - if (rc != LDAP_URL_SUCCESS) { + if(rc != LDAP_URL_SUCCESS) { const char *msg = "url parsing problem"; status = CURLE_URL_MALFORMAT; - if (rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) { - if (rc == LDAP_URL_ERR_MEM) + if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) { + if(rc == LDAP_URL_ERR_MEM) status = CURLE_OUT_OF_MEMORY; msg = url_errs[rc]; } @@ -163,9 +171,11 @@ static CURLcode ldap_setup(struct connectdata *conn) ldap_free_urldesc(lud); li = calloc(1, sizeof(ldapconninfo)); + if(!li) + return CURLE_OUT_OF_MEMORY; li->proto = proto; conn->proto.generic = li; - conn->bits.close = FALSE; + connkeep(conn, "OpenLDAP default"); /* TODO: * - provide option to choose SASL Binds instead of Simple */ @@ -179,19 +189,22 @@ static Sockbuf_IO ldapsb_tls; static CURLcode ldap_connect(struct connectdata *conn, bool *done) { ldapconninfo *li = conn->proto.generic; - struct SessionHandle *data=conn->data; + struct SessionHandle *data = conn->data; int rc, proto = LDAP_VERSION3; - char hosturl[1024], *ptr; + char hosturl[1024]; + char *ptr; + + (void)done; strcpy(hosturl, "ldap"); ptr = hosturl+4; - if (conn->protocol & PROT_SSL) + if(conn->handler->flags & PROTOPT_SSL) *ptr++ = 's'; snprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d", conn->host.name, conn->remote_port); rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld); - if (rc) { + if(rc) { failf(data, "LDAP local: Cannot connect to %s, %s", hosturl, ldap_err2string(rc)); return CURLE_COULDNT_CONNECT; @@ -199,76 +212,39 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done) ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto); -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY) - if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { - /* for LDAP over HTTP proxy */ - struct HTTP http_proxy; - ldapconninfo *li_save; +#ifdef USE_SSL + if(conn->handler->flags & PROTOPT_SSL) { CURLcode result; - - /* BLOCKING */ - /* We want "seamless" LDAP operations through HTTP proxy tunnel */ - - /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member - * conn->proto.http; we want LDAP through HTTP and we have to change the - * member temporarily for connecting to the HTTP proxy. After - * Curl_proxyCONNECT we have to set back the member to the original struct - * LDAP pointer - */ - li_save = data->state.proto.generic; - memset(&http_proxy, 0, sizeof(http_proxy)); - data->state.proto.http = &http_proxy; - result = Curl_proxyCONNECT(conn, FIRSTSOCKET, - conn->host.name, conn->remote_port); - - data->state.proto.generic = li_save; - - if(CURLE_OK != result) + result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone); + if(result) return result; } -#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */ - -#ifdef USE_SSL - if (conn->protocol & PROT_SSL) { - CURLcode res; - if (data->state.used_interface == Curl_if_easy) { - res = Curl_ssl_connect(conn, FIRSTSOCKET); - if (res) - return res; - li->ssldone = TRUE; - } else { - res = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone); - if (res) - return res; - } - } #endif - if (data->state.used_interface == Curl_if_easy) - return ldap_connecting(conn, done); - return CURLE_OK; } static CURLcode ldap_connecting(struct connectdata *conn, bool *done) { ldapconninfo *li = conn->proto.generic; - struct SessionHandle *data=conn->data; - LDAPMessage *result = NULL; - struct timeval tv = {0,1}, *tvp; + struct SessionHandle *data = conn->data; + LDAPMessage *msg = NULL; + struct timeval tv = {0, 1}, *tvp; int rc, err; char *info = NULL; #ifdef USE_SSL - if (conn->protocol & PROT_SSL) { + if(conn->handler->flags & PROTOPT_SSL) { /* Is the SSL handshake complete yet? */ - if (!li->ssldone) { - CURLcode res = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone); - if (res || !li->ssldone) - return res; + if(!li->ssldone) { + CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, + &li->ssldone); + if(result || !li->ssldone) + return result; } + /* Have we installed the libcurl SSL handlers into the sockbuf yet? */ - if (!li->sslinst) { + if(!li->sslinst) { Sockbuf *sb; ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, conn); @@ -279,54 +255,57 @@ static CURLcode ldap_connecting(struct connectdata *conn, bool *done) } #endif - if (data->state.used_interface == Curl_if_easy) - tvp = NULL; /* let ldap_result block indefinitely */ - else - tvp = &tv; + tvp = &tv; retry: - if (!li->didbind) { + if(!li->didbind) { char *binddn; struct berval passwd; - if (conn->bits.user_passwd) { + if(conn->bits.user_passwd) { binddn = conn->user; passwd.bv_val = conn->passwd; passwd.bv_len = strlen(passwd.bv_val); - } else { + } + else { binddn = NULL; passwd.bv_val = NULL; passwd.bv_len = 0; } rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd, NULL, NULL, &li->msgid); - if (rc) + if(rc) return CURLE_LDAP_CANNOT_BIND; li->didbind = TRUE; - if (tvp) + if(tvp) return CURLE_OK; } - rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, tvp, &result); - if (rc < 0) { + rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, tvp, &msg); + if(rc < 0) { failf(data, "LDAP local: bind ldap_result %s", ldap_err2string(rc)); return CURLE_LDAP_CANNOT_BIND; } - if (rc == 0) { + if(rc == 0) { /* timed out */ return CURLE_OK; } - rc = ldap_parse_result(li->ld, result, &err, NULL, &info, NULL, NULL, 1); - if (rc) { + + rc = ldap_parse_result(li->ld, msg, &err, NULL, &info, NULL, NULL, 1); + if(rc) { failf(data, "LDAP local: bind ldap_parse_result %s", ldap_err2string(rc)); return CURLE_LDAP_CANNOT_BIND; } + /* Try to fallback to LDAPv2? */ - if (err == LDAP_PROTOCOL_ERROR) { + if(err == LDAP_PROTOCOL_ERROR) { int proto; ldap_get_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto); - if (proto == LDAP_VERSION3) { - ldap_memfree(info); + if(proto == LDAP_VERSION3) { + if(info) { + ldap_memfree(info); + info = NULL; + } proto = LDAP_VERSION2; ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto); li->didbind = FALSE; @@ -334,13 +313,19 @@ retry: } } - if (err) { + if(err) { failf(data, "LDAP remote: bind failed %s %s", ldap_err2string(rc), info ? info : ""); + if(info) + ldap_memfree(info); return CURLE_LOGIN_DENIED; } + + if(info) + ldap_memfree(info); conn->recv[FIRSTSOCKET] = ldap_recv; *done = TRUE; + return CURLE_OK; } @@ -349,8 +334,8 @@ static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection) ldapconninfo *li = conn->proto.generic; (void) dead_connection; - if (li) { - if (li->ld) { + if(li) { + if(li->ld) { ldap_unbind_ext(li->ld, NULL, NULL); li->ld = NULL; } @@ -370,16 +355,16 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done) int msgid; struct SessionHandle *data=conn->data; - conn->bits.close = FALSE; + connkeep(conn, "OpenLDAP do"); infof(data, "LDAP local: %s\n", data->change.url); rc = ldap_url_parse(data->change.url, &ludp); - if (rc != LDAP_URL_SUCCESS) { + if(rc != LDAP_URL_SUCCESS) { const char *msg = "url parsing problem"; status = CURLE_URL_MALFORMAT; - if (rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) { - if (rc == LDAP_URL_ERR_MEM) + if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) { + if(rc == LDAP_URL_ERR_MEM) status = CURLE_OUT_OF_MEMORY; msg = url_errs[rc]; } @@ -391,13 +376,15 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done) ludp->lud_filter, ludp->lud_attrs, 0, NULL, NULL, NULL, 0, &msgid); ldap_free_urldesc(ludp); - if (rc != LDAP_SUCCESS) { + if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc)); return CURLE_LDAP_SEARCH_FAILED; } - lr = calloc(1,sizeof(ldapreqinfo)); + lr = calloc(1, sizeof(ldapreqinfo)); + if(!lr) + return CURLE_OUT_OF_MEMORY; lr->msgid = msgid; - data->state.proto.generic = lr; + data->req.protop = lr; Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL); *done = TRUE; return CURLE_OK; @@ -406,20 +393,22 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done) static CURLcode ldap_done(struct connectdata *conn, CURLcode res, bool premature) { - ldapreqinfo *lr = conn->data->state.proto.generic; + ldapreqinfo *lr = conn->data->req.protop; + (void)res; (void)premature; - if (lr) { + if(lr) { /* if there was a search in progress, abandon it */ - if (lr->msgid) { + if(lr->msgid) { ldapconninfo *li = conn->proto.generic; ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL); lr->msgid = 0; } - conn->data->state.proto.generic = NULL; + conn->data->req.protop = NULL; free(lr); } + return CURLE_OK; } @@ -427,19 +416,20 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err) { ldapconninfo *li = conn->proto.generic; - struct SessionHandle *data=conn->data; - ldapreqinfo *lr = data->state.proto.generic; + struct SessionHandle *data = conn->data; + ldapreqinfo *lr = data->req.protop; int rc, ret; - LDAPMessage *result = NULL; + LDAPMessage *msg = NULL; LDAPMessage *ent; BerElement *ber = NULL; - struct timeval tv = {0,1}; + struct timeval tv = {0, 1}; + (void)len; (void)buf; (void)sockindex; - rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_RECEIVED, &tv, &result); - if (rc < 0) { + rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_RECEIVED, &tv, &msg); + if(rc < 0) { failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc)); *err = CURLE_RECV_ERROR; return -1; @@ -449,29 +439,33 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, ret = -1; /* timed out */ - if (result == NULL) + if(!msg) return ret; - for (ent = ldap_first_message(li->ld, result); ent; + for(ent = ldap_first_message(li->ld, msg); ent; ent = ldap_next_message(li->ld, ent)) { struct berval bv, *bvals, **bvp = &bvals; int binary = 0, msgtype; + CURLcode writeerr; msgtype = ldap_msgtype(ent); - if (msgtype == LDAP_RES_SEARCH_RESULT) { + if(msgtype == LDAP_RES_SEARCH_RESULT) { int code; char *info = NULL; rc = ldap_parse_result(li->ld, ent, &code, NULL, &info, NULL, NULL, 0); - if (rc) { - failf(data, "LDAP local: search ldap_parse_result %s", ldap_err2string(rc)); + if(rc) { + failf(data, "LDAP local: search ldap_parse_result %s", + ldap_err2string(rc)); *err = CURLE_LDAP_SEARCH_FAILED; - } else if (code && code != LDAP_SIZELIMIT_EXCEEDED) { + } + else if(code && code != LDAP_SIZELIMIT_EXCEEDED) { failf(data, "LDAP remote: search failed %s %s", ldap_err2string(rc), - info ? info : ""); + info ? info : ""); *err = CURLE_LDAP_SEARCH_FAILED; - } else { + } + else { /* successful */ - if (code == LDAP_SIZELIMIT_EXCEEDED) + if(code == LDAP_SIZELIMIT_EXCEEDED) infof(data, "There are more than %d entries\n", lr->nument); data->req.size = data->req.bytecount; *err = CURLE_OK; @@ -480,83 +474,163 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, lr->msgid = 0; ldap_memfree(info); break; - } else if (msgtype != LDAP_RES_SEARCH_ENTRY) { - continue; } + else if(msgtype != LDAP_RES_SEARCH_ENTRY) + continue; lr->nument++; rc = ldap_get_dn_ber(li->ld, ent, &ber, &bv); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, bv.bv_len); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + if(rc < 0) { + /* TODO: verify that this is really how this return code should be + handled */ + *err = CURLE_RECV_ERROR; + return -1; + } + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); + if(writeerr) { + *err = writeerr; + return -1; + } + + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, + bv.bv_len); + if(writeerr) { + *err = writeerr; + return -1; + } + + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + if(writeerr) { + *err = writeerr; + return -1; + } data->req.bytecount += bv.bv_len + 5; - for (rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp); + for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp); rc == LDAP_SUCCESS; rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp)) { int i; - if (bv.bv_val == NULL) break; + if(bv.bv_val == NULL) break; - if (bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7)) + if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7)) binary = 1; else binary = 0; - for (i=0; bvals[i].bv_val != NULL; i++) { + for(i=0; bvals[i].bv_val != NULL; i++) { int binval = 0; - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, bv.bv_len); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1); + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); + if(writeerr) { + *err = writeerr; + return -1; + } + + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, + bv.bv_len); + if(writeerr) { + *err = writeerr; + return -1; + } + + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1); + if(writeerr) { + *err = writeerr; + return -1; + } data->req.bytecount += bv.bv_len + 2; - if (!binary) { + if(!binary) { /* check for leading or trailing whitespace */ - if (ISSPACE(bvals[i].bv_val[0]) || - ISSPACE(bvals[i].bv_val[bvals[i].bv_len-1])) { + if(ISSPACE(bvals[i].bv_val[0]) || + ISSPACE(bvals[i].bv_val[bvals[i].bv_len-1])) binval = 1; - } else { + else { /* check for unprintable characters */ unsigned int j; - for (j=0; jreq.bytecount += 2; if(val_b64_sz > 0) { - Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz); + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, + val_b64_sz); + if(writeerr) { + *err = writeerr; + return -1; + } free(val_b64); data->req.bytecount += val_b64_sz; } - } else { - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1); - Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val, - bvals[i].bv_len); + } + else { + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1); + if(writeerr) { + *err = writeerr; + return -1; + } + + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val, + bvals[i].bv_len); + if(writeerr) { + *err = writeerr; + return -1; + } + data->req.bytecount += bvals[i].bv_len + 1; } - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + if(writeerr) { + *err = writeerr; + return -1; + } + data->req.bytecount++; } ber_memfree(bvals); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + if(writeerr) { + *err = writeerr; + return -1; + } data->req.bytecount++; } - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + if(writeerr) { + *err = writeerr; + return -1; + } data->req.bytecount++; ber_free(ber, 0); } - ldap_msgfree(result); + ldap_msgfree(msg); return ret; } @@ -587,7 +661,7 @@ static int ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg) { (void)arg; - if (opt == LBER_SB_OPT_DATA_READY) { + if(opt == LBER_SB_OPT_DATA_READY) { struct connectdata *conn = sbiod->sbiod_pvt; return Curl_ssl_data_pending(conn, FIRSTSOCKET); } @@ -603,7 +677,7 @@ ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) CURLcode err = CURLE_RECV_ERROR; ret = li->recv(conn, FIRSTSOCKET, buf, len, &err); - if (ret < 0 && err == CURLE_AGAIN) { + if(ret < 0 && err == CURLE_AGAIN) { SET_SOCKERRNO(EWOULDBLOCK); } return ret; @@ -618,7 +692,7 @@ ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) CURLcode err = CURLE_SEND_ERROR; ret = li->send(conn, FIRSTSOCKET, buf, len, &err); - if (ret < 0 && err == CURLE_AGAIN) { + if(ret < 0 && err == CURLE_AGAIN) { SET_SOCKERRNO(EWOULDBLOCK); } return ret; diff --git a/project/jni/curl/lib/parsedate.c b/project/jni/curl/lib/parsedate.c index 3e003db31..dfcf855c8 100644 --- a/project/jni/curl/lib/parsedate.c +++ b/project/jni/curl/lib/parsedate.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -72,13 +72,11 @@ 20040911 +0200 */ -#include "setup.h" -#include -#include -#include -#ifdef HAVE_STDLIB_H -#include /* for strtol() */ +#include "curl_setup.h" + +#ifdef HAVE_LIMITS_H +#include #endif #include @@ -100,6 +98,24 @@ struct tzinfo { int offset; /* +/- in minutes */ }; +/* + * parsedate() + * + * Returns: + * + * PARSEDATE_OK - a fine conversion + * PARSEDATE_FAIL - failed to convert + * PARSEDATE_LATER - time overflow at the far end of time_t + * PARSEDATE_SOONER - time underflow at the low end of time_t + */ + +static int parsedate(const char *date, time_t *output); + +#define PARSEDATE_OK 0 +#define PARSEDATE_FAIL -1 +#define PARSEDATE_LATER 1 +#define PARSEDATE_SOONER 2 + /* Here's a bunch of frequently used time zone names. These were supported by the old getdate parser. */ #define tDAYZONE -60 /* offset for daylight savings time */ @@ -160,7 +176,8 @@ static const struct tzinfo tz[]= { {"G", +7 * 60}, /* Golf */ {"H", +8 * 60}, /* Hotel */ {"I", +9 * 60}, /* India */ - /* "J", Juliet is not used as a timezone, to indicate the observer's local time */ + /* "J", Juliet is not used as a timezone, to indicate the observer's local + time */ {"K", +10 * 60}, /* Kilo */ {"L", +11 * 60}, /* Lima */ {"M", +12 * 60}, /* Mike */ @@ -282,11 +299,11 @@ static time_t my_timegm(struct my_tm *tm) year = tm->tm_year + 1900; month = tm->tm_mon; - if (month < 0) { + if(month < 0) { year += (11 - month) / 12; month = 11 - (11 - month) % 12; } - else if (month >= 12) { + else if(month >= 12) { year -= month / 12; month = month % 12; } @@ -301,7 +318,7 @@ static time_t my_timegm(struct my_tm *tm) } /* - * Curl_parsedate() + * parsedate() * * Returns: * @@ -311,7 +328,7 @@ static time_t my_timegm(struct my_tm *tm) * PARSEDATE_SOONER - time underflow at the low end of time_t */ -int Curl_parsedate(const char *date, time_t *output) +static int parsedate(const char *date, time_t *output) { time_t t = 0; int wdaynum=-1; /* day of the week number, 0-6 (mon-sun) */ @@ -336,9 +353,11 @@ int Curl_parsedate(const char *date, time_t *output) /* a name coming up */ char buf[32]=""; size_t len; - sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]", - buf); - len = strlen(buf); + if(sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz]", buf)) + len = strlen(buf); + else + len = 0; if(wdaynum == -1) { wdaynum = checkday(buf, len); @@ -379,7 +398,26 @@ int Curl_parsedate(const char *date, time_t *output) secnum = 0; } else { - val = curlx_sltosi(strtol(date, &end, 10)); + long lval; + int error; + int old_errno; + + old_errno = ERRNO; + SET_ERRNO(0); + lval = strtol(date, &end, 10); + error = ERRNO; + if(error != old_errno) + SET_ERRNO(old_errno); + + if(error) + return PARSEDATE_FAIL; + +#if LONG_MAX != INT_MAX + if((lval > (long)INT_MAX) || (lval < (long)INT_MIN)) + return PARSEDATE_FAIL; +#endif + + val = curlx_sltosi(lval); if((tzoff == -1) && ((end - date) == 4) && @@ -387,7 +425,7 @@ int Curl_parsedate(const char *date, time_t *output) (indate< date) && ((date[-1] == '+' || date[-1] == '-'))) { /* four digits and a value less than or equal to 1400 (to take into - account all sorts of funny time zone diffs) and it is preceeded + account all sorts of funny time zone diffs) and it is preceded with a plus or minus. This is a time zone indication. 1400 is picked since +1300 is frequently used and +1400 is mentioned as an edge number in the document "ISO C 200X Proposal: Timezone @@ -466,6 +504,10 @@ int Curl_parsedate(const char *date, time_t *output) return PARSEDATE_SOONER; } + if((mdaynum > 31) || (monnum > 11) || + (hournum > 23) || (minnum > 59) || (secnum > 60)) + return PARSEDATE_FAIL; /* clearly an illegal date */ + tm.tm_sec = secnum; tm.tm_min = minnum; tm.tm_hour = hournum; @@ -488,8 +530,10 @@ int Curl_parsedate(const char *date, time_t *output) /* Add the time zone diff between local time zone and GMT. */ long delta = (long)(tzoff!=-1?tzoff:0); - if((delta>0) && (t + delta < t)) - return -1; /* time_t overflow */ + if((delta>0) && (t > LONG_MAX - delta)) { + *output = 0x7fffffff; + return PARSEDATE_LATER; /* time_t overflow */ + } t += delta; } @@ -501,8 +545,8 @@ int Curl_parsedate(const char *date, time_t *output) time_t curl_getdate(const char *p, const time_t *now) { - time_t parsed; - int rc = Curl_parsedate(p, &parsed); + time_t parsed = -1; + int rc = parsedate(p, &parsed); (void)now; /* legacy argument from the past that we ignore */ switch(rc) { @@ -514,3 +558,26 @@ time_t curl_getdate(const char *p, const time_t *now) /* everything else is fail */ return -1; } + +/* + * Curl_gmtime() is a gmtime() replacement for portability. Do not use the + * gmtime_r() or gmtime() functions anywhere else but here. + * + */ + +CURLcode Curl_gmtime(time_t intime, struct tm *store) +{ + const struct tm *tm; +#ifdef HAVE_GMTIME_R + /* thread-safe version */ + tm = (struct tm *)gmtime_r(&intime, store); +#else + tm = gmtime(&intime); + if(tm) + *store = *tm; /* copy the pointed struct to the local copy */ +#endif + + if(!tm) + return CURLE_BAD_FUNCTION_ARGUMENT; + return CURLE_OK; +} diff --git a/project/jni/curl/lib/parsedate.h b/project/jni/curl/lib/parsedate.h index e1bf5441f..2e59eb17c 100644 --- a/project/jni/curl/lib/parsedate.h +++ b/project/jni/curl/lib/parsedate.h @@ -1,5 +1,5 @@ -#ifndef __CURL_PARSEDATE_H -#define __CURL_PARSEDATE_H +#ifndef HEADER_CURL_PARSEDATE_H +#define HEADER_CURL_PARSEDATE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -25,22 +25,7 @@ extern const char * const Curl_wkday[7]; extern const char * const Curl_month[12]; -/* - * Curl_parsedate() - * - * Returns: - * - * PARSEDATE_OK - a fine conversion - * PARSEDATE_FAIL - failed to convert - * PARSEDATE_LATER - time overflow at the far end of time_t - * PARSEDATE_SOONER - time underflow at the low end of time_t - */ +CURLcode Curl_gmtime(time_t intime, struct tm *store); -int Curl_parsedate(const char *date, time_t *output); +#endif /* HEADER_CURL_PARSEDATE_H */ -#define PARSEDATE_OK 0 -#define PARSEDATE_FAIL -1 -#define PARSEDATE_LATER 1 -#define PARSEDATE_SOONER 2 - -#endif diff --git a/project/jni/curl/lib/pingpong.c b/project/jni/curl/lib/pingpong.c index 81f804f8e..5fea5dee7 100644 --- a/project/jni/curl/lib/pingpong.c +++ b/project/jni/curl/lib/pingpong.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -23,7 +23,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #include "urldata.h" #include "sendf.h" @@ -32,9 +32,9 @@ #include "speedcheck.h" #include "pingpong.h" #include "multiif.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include +#include "non-ascii.h" +#include "vtls/vtls.h" +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -75,48 +75,10 @@ long Curl_pp_state_timeout(struct pingpong *pp) return timeout_ms; } - /* - * Curl_pp_multi_statemach() - * - * called repeatedly until done when the multi interface is used. + * Curl_pp_statemach() */ -CURLcode Curl_pp_multi_statemach(struct pingpong *pp) -{ - struct connectdata *conn = pp->conn; - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - int rc; - struct SessionHandle *data=conn->data; - CURLcode result = CURLE_OK; - long timeout_ms = Curl_pp_state_timeout(pp); - - if(timeout_ms <= 0) { - failf(data, "server response timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - rc = Curl_socket_ready(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */ - pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */ - 0); - - if(rc == -1) { - failf(data, "select/poll error"); - return CURLE_OUT_OF_MEMORY; - } - else if(rc != 0) - result = pp->statemach_act(conn); - - /* if rc == 0, then select() timed out */ - - return result; -} - -/* - * Curl_pp_easy_statemach() - * - * called repeatedly until done when the easy interface is used. - */ -CURLcode Curl_pp_easy_statemach(struct pingpong *pp) +CURLcode Curl_pp_statemach(struct pingpong *pp, bool block) { struct connectdata *conn = pp->conn; curl_socket_t sock = conn->sock[FIRSTSOCKET]; @@ -124,29 +86,44 @@ CURLcode Curl_pp_easy_statemach(struct pingpong *pp) long interval_ms; long timeout_ms = Curl_pp_state_timeout(pp); struct SessionHandle *data=conn->data; - CURLcode result; + CURLcode result = CURLE_OK; if(timeout_ms <=0 ) { failf(data, "server response timeout"); return CURLE_OPERATION_TIMEDOUT; /* already too little time */ } - interval_ms = 1000; /* use 1 second timeout intervals */ - if(timeout_ms < interval_ms) - interval_ms = timeout_ms; - - rc = Curl_socket_ready(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */ - pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */ - (int)interval_ms); - - if(Curl_pgrsUpdate(conn)) - result = CURLE_ABORTED_BY_CALLBACK; + if(block) { + interval_ms = 1000; /* use 1 second timeout intervals */ + if(timeout_ms < interval_ms) + interval_ms = timeout_ms; + } else - result = Curl_speedcheck(data, Curl_tvnow()); + interval_ms = 0; /* immediate */ - if(result) - ; - else if(rc == -1) { + if(Curl_pp_moredata(pp)) + /* We are receiving and there is data in the cache so just read it */ + rc = 1; + else if(!pp->sendleft && Curl_ssl_data_pending(conn, FIRSTSOCKET)) + /* We are receiving and there is data ready in the SSL library */ + rc = 1; + else + rc = Curl_socket_ready(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */ + pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */ + interval_ms); + + if(block) { + /* if we didn't wait, we don't have to spend time on this now */ + if(Curl_pgrsUpdate(conn)) + result = CURLE_ABORTED_BY_CALLBACK; + else + result = Curl_speedcheck(data, Curl_tvnow()); + + if(result) + return result; + } + + if(rc == -1) { failf(data, "select/poll error"); result = CURLE_OUT_OF_MEMORY; } @@ -170,15 +147,12 @@ void Curl_pp_init(struct pingpong *pp) /*********************************************************************** * - * Curl_pp_sendfv() + * Curl_pp_vsendf() * * Send the formated string as a command to a pingpong server. Note that * the string should not have any CRLF appended, as this function will * append the necessary things itself. * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * * made to never block */ CURLcode Curl_pp_vsendf(struct pingpong *pp, @@ -186,71 +160,75 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp, va_list args) { ssize_t bytes_written; -/* may still not be big enough for some krb5 tokens */ -#define SBUF_SIZE 1024 - char s[SBUF_SIZE]; size_t write_len; - char *sptr=s; - CURLcode res = CURLE_OK; + char *fmt_crlf; + char *s; + CURLcode result; struct connectdata *conn = pp->conn; struct SessionHandle *data = conn->data; -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) +#ifdef HAVE_GSSAPI enum protection_level data_sec = conn->data_prot; #endif - vsnprintf(s, SBUF_SIZE-3, fmt, args); + DEBUGASSERT(pp->sendleft == 0); + DEBUGASSERT(pp->sendsize == 0); + DEBUGASSERT(pp->sendthis == NULL); - strcat(s, "\r\n"); /* append a trailing CRLF */ + fmt_crlf = aprintf("%s\r\n", fmt); /* append a trailing CRLF */ + if(!fmt_crlf) + return CURLE_OUT_OF_MEMORY; - bytes_written=0; + s = vaprintf(fmt_crlf, args); /* trailing CRLF appended */ + free(fmt_crlf); + if(!s) + return CURLE_OUT_OF_MEMORY; + + bytes_written = 0; write_len = strlen(s); Curl_pp_init(pp); -#ifdef CURL_DOES_CONVERSIONS - res = Curl_convert_to_network(data, s, write_len); + result = Curl_convert_to_network(data, s, write_len); /* Curl_convert_to_network calls failf if unsuccessful */ - if(res != CURLE_OK) { - return res; + if(result) { + free(s); + return result; } -#endif /* CURL_DOES_CONVERSIONS */ -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) +#ifdef HAVE_GSSAPI conn->data_prot = PROT_CMD; #endif - res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, - &bytes_written); -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) + result = Curl_write(conn, conn->sock[FIRSTSOCKET], s, write_len, + &bytes_written); +#ifdef HAVE_GSSAPI DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); conn->data_prot = data_sec; #endif - if(CURLE_OK != res) - return res; + if(result) { + free(s); + return result; + } if(conn->data->set.verbose) Curl_debug(conn->data, CURLINFO_HEADER_OUT, - sptr, (size_t)bytes_written, conn); + s, (size_t)bytes_written, conn); if(bytes_written != (ssize_t)write_len) { - /* the whole chunk was not sent, store the rest of the data */ - write_len -= bytes_written; - sptr += bytes_written; - pp->sendthis = malloc(write_len); - if(pp->sendthis) { - memcpy(pp->sendthis, sptr, write_len); - pp->sendsize = pp->sendleft = write_len; - } - else { - failf(data, "out of memory"); - res = CURLE_OUT_OF_MEMORY; - } + /* the whole chunk was not sent, keep it around and adjust sizes */ + pp->sendthis = s; + pp->sendsize = write_len; + pp->sendleft = write_len - bytes_written; } - else + else { + free(s); + pp->sendthis = NULL; + pp->sendleft = pp->sendsize = 0; pp->response = Curl_tvnow(); + } - return res; + return CURLE_OK; } @@ -262,23 +240,20 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp, * the string should not have any CRLF appended, as this function will * append the necessary things itself. * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * * made to never block */ CURLcode Curl_pp_sendf(struct pingpong *pp, const char *fmt, ...) { - CURLcode res; + CURLcode result; va_list ap; va_start(ap, fmt); - res = Curl_pp_vsendf(pp, fmt, ap); + result = Curl_pp_vsendf(pp, fmt, ap); va_end(ap); - return res; + return result; } /* @@ -308,18 +283,15 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, /* number of bytes in the current line, so far */ perline = (ssize_t)(ptr-pp->linestart_resp); - keepon=TRUE; - while((pp->nread_respcache) { /* we had data in the "cache", copy that instead of doing an actual * read * - * ftp->cache_size is cast to int here. This should be safe, - * because it would have been populated with something of size - * int to begin with, even though its datatype may be larger - * than an int. + * pp->cache_size is cast to ssize_t here. This should be safe, because + * it would have been populated with something of size int to begin + * with, even though its datatype may be larger than an int. */ DEBUGASSERT((ptr+pp->cache_size) <= (buf+BUFSIZE+1)); memcpy(ptr, pp->cache, pp->cache_size); @@ -329,33 +301,28 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, pp->cache_size = 0; /* zero the size just in case */ } else { - int res; -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) +#ifdef HAVE_GSSAPI enum protection_level prot = conn->data_prot; conn->data_prot = PROT_CLEAR; #endif DEBUGASSERT((ptr+BUFSIZE-pp->nread_resp) <= (buf+BUFSIZE+1)); - res = Curl_read(conn, sockfd, ptr, BUFSIZE-pp->nread_resp, - &gotbytes); -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) + result = Curl_read(conn, sockfd, ptr, BUFSIZE-pp->nread_resp, + &gotbytes); +#ifdef HAVE_GSSAPI DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST); conn->data_prot = prot; #endif - if(res == CURLE_AGAIN) + if(result == CURLE_AGAIN) return CURLE_OK; /* return */ -#ifdef CURL_DOES_CONVERSIONS - if((res == CURLE_OK) && (gotbytes > 0)) { + if(!result && (gotbytes > 0)) /* convert from the network encoding */ - res = Curl_convert_from_network(data, ptr, gotbytes); - /* Curl_convert_from_network calls failf if unsuccessful */ - } -#endif /* CURL_DOES_CONVERSIONS */ + result = Curl_convert_from_network(data, ptr, gotbytes); + /* Curl_convert_from_network calls failf if unsuccessful */ - if(CURLE_OK != res) { - result = (CURLcode)res; /* Set outer result variable to this error. */ + if(result) + /* Set outer result variable to this error. */ keepon = FALSE; - } } if(!keepon) @@ -379,11 +346,11 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, for(i = 0; i < gotbytes; ptr++, i++) { perline++; if(*ptr=='\n') { - /* a newline is CRLF in ftp-talk, so the CR is ignored as + /* a newline is CRLF in pp-talk, so the CR is ignored as the line isn't really terminated until the LF comes */ /* output debug output if that is requested */ -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) +#ifdef HAVE_GSSAPI if(!conn->sec_complete) #endif if(data->set.verbose) @@ -400,15 +367,12 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, if(result) return result; - if(pp->endofresp(pp, code)) { + if(pp->endofresp(conn, pp->linestart_resp, perline, code)) { /* This is the end of the last line, copy the last line to the - start of the buffer and zero terminate, for old times sake (and - krb4)! */ - char *meow; - int n; - for(meow=pp->linestart_resp, n=0; meowlinestart_resp; + memmove(buf, pp->linestart_resp, n); + buf[n]=0; /* zero terminate */ keepon=FALSE; pp->linestart_resp = ptr+1; /* advance pointer */ i++; /* skip this before getting out */ @@ -429,6 +393,9 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, it may actually contain another end of response already! */ clipamount = gotbytes - i; restart = TRUE; + DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing " + "server response left\n", + (int)clipamount)); } else if(keepon) { @@ -436,8 +403,8 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, /* We got an excessive line without newlines and we need to deal with it. We keep the first bytes of the line then we throw away the rest. */ - infof(data, "Excessive server response line length received, %zd bytes." - " Stripping\n", gotbytes); + infof(data, "Excessive server response line length received, " + "%zd bytes. Stripping\n", gotbytes); restart = TRUE; /* we keep 40 bytes since all our pingpong protocols are only @@ -445,9 +412,9 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, clipamount = 40; } else if(pp->nread_resp > BUFSIZE/2) { - /* We got a large chunk of data and there's potentially still trailing - data to take care of, so we put any such part in the "cache", clear - the buffer to make space and restart. */ + /* We got a large chunk of data and there's potentially still + trailing data to take care of, so we put any such part in the + "cache", clear the buffer to make space and restart. */ clipamount = perline; restart = TRUE; } @@ -505,11 +472,9 @@ CURLcode Curl_pp_flushsend(struct pingpong *pp) /* we have a piece of a command still left to send */ struct connectdata *conn = pp->conn; ssize_t written; - CURLcode result = CURLE_OK; curl_socket_t sock = conn->sock[FIRSTSOCKET]; - - result = Curl_write(conn, sock, pp->sendthis + pp->sendsize - - pp->sendleft, pp->sendleft, &written); + CURLcode result = Curl_write(conn, sock, pp->sendthis + pp->sendsize - + pp->sendleft, pp->sendleft, &written); if(result) return result; @@ -528,13 +493,15 @@ CURLcode Curl_pp_flushsend(struct pingpong *pp) CURLcode Curl_pp_disconnect(struct pingpong *pp) { - if(pp->cache) { - free(pp->cache); - pp->cache = NULL; - } + free(pp->cache); + pp->cache = NULL; return CURLE_OK; } - +bool Curl_pp_moredata(struct pingpong *pp) +{ + return (!pp->sendleft && pp->cache && pp->nread_resp < pp->cache_size) ? + TRUE : FALSE; +} #endif diff --git a/project/jni/curl/lib/pingpong.h b/project/jni/curl/lib/pingpong.h index cbbff8f3e..2f649d5bf 100644 --- a/project/jni/curl/lib/pingpong.h +++ b/project/jni/curl/lib/pingpong.h @@ -1,5 +1,5 @@ -#ifndef __PINGPONG_H -#define __PINGPONG_H +#ifndef HEADER_CURL_PINGPONG_H +#define HEADER_CURL_PINGPONG_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,9 +22,7 @@ * ***************************************************************************/ -#include - -#include "setup.h" +#include "curl_setup.h" #if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_FTP) || \ !defined(CURL_DISABLE_POP3) || !defined(CURL_DISABLE_SMTP) @@ -34,6 +32,13 @@ /* forward-declaration, this is defined in urldata.h */ struct connectdata; +typedef enum { + FTPTRANSFER_BODY, /* yes do transfer a body */ + FTPTRANSFER_INFO, /* do still go through to get info/headers */ + FTPTRANSFER_NONE, /* don't get anything and don't get info */ + FTPTRANSFER_LAST /* end of list marker, never used */ +} curl_pp_transfer; + /* * 'pingpong' is the generic struct used for protocols doing server<->client * conversations in a back-and-forth style such as FTP, IMAP, POP3, SMTP etc. @@ -66,23 +71,17 @@ struct pingpong { CURLcode (*statemach_act)(struct connectdata *conn); - int (*endofresp)(struct pingpong *pp, int *code); + bool (*endofresp)(struct connectdata *conn, char *ptr, size_t len, + int *code); }; /* - * Curl_pp_multi_statemach() + * Curl_pp_statemach() * - * called repeatedly until done when the multi interface is used. + * called repeatedly until done. Set 'wait' to make it wait a while on the + * socket if there's no traffic. */ -CURLcode Curl_pp_multi_statemach(struct pingpong *pp); - -/* - * Curl_pp_easy_statemach() - * - * called repeatedly until done when the easy interface is used. - */ -CURLcode Curl_pp_easy_statemach(struct pingpong *pp); - +CURLcode Curl_pp_statemach(struct pingpong *pp, bool block); /* initialize stuff to prepare for reading a fresh new response */ void Curl_pp_init(struct pingpong *pp); @@ -100,9 +99,6 @@ long Curl_pp_state_timeout(struct pingpong *pp); * the string should not have any CRLF appended, as this function will * append the necessary things itself. * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * * made to never block */ CURLcode Curl_pp_sendf(struct pingpong *pp, @@ -116,9 +112,6 @@ CURLcode Curl_pp_sendf(struct pingpong *pp, * the string should not have any CRLF appended, as this function will * append the necessary things itself. * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * * made to never block */ CURLcode Curl_pp_vsendf(struct pingpong *pp, @@ -144,4 +137,14 @@ CURLcode Curl_pp_disconnect(struct pingpong *pp); int Curl_pp_getsock(struct pingpong *pp, curl_socket_t *socks, int numsocks); -#endif /* __PINGPONG_H */ + +/*********************************************************************** + * + * Curl_pp_moredata() + * + * Returns whether there are still more data in the cache and so a call + * to Curl_pp_readresp() will not block. + */ +bool Curl_pp_moredata(struct pingpong *pp); + +#endif /* HEADER_CURL_PINGPONG_H */ diff --git a/project/jni/curl/lib/pipeline.c b/project/jni/curl/lib/pipeline.c new file mode 100644 index 000000000..95b89b54b --- /dev/null +++ b/project/jni/curl/lib/pipeline.c @@ -0,0 +1,434 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2013, Linus Nielsen Feltzing, + * Copyright (C) 2013-2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "urldata.h" +#include "url.h" +#include "progress.h" +#include "multiif.h" +#include "pipeline.h" +#include "sendf.h" +#include "rawstr.h" + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +struct site_blacklist_entry { + char *hostname; + unsigned short port; +}; + +static void site_blacklist_llist_dtor(void *user, void *element) +{ + struct site_blacklist_entry *entry = element; + (void)user; + + Curl_safefree(entry->hostname); + free(entry); +} + +static void server_blacklist_llist_dtor(void *user, void *element) +{ + (void)user; + free(element); +} + +bool Curl_pipeline_penalized(struct SessionHandle *data, + struct connectdata *conn) +{ + if(data) { + bool penalized = FALSE; + curl_off_t penalty_size = + Curl_multi_content_length_penalty_size(data->multi); + curl_off_t chunk_penalty_size = + Curl_multi_chunk_length_penalty_size(data->multi); + curl_off_t recv_size = -2; /* Make it easy to spot in the log */ + + /* Find the head of the recv pipe, if any */ + if(conn->recv_pipe && conn->recv_pipe->head) { + struct SessionHandle *recv_handle = conn->recv_pipe->head->ptr; + + recv_size = recv_handle->req.size; + + if(penalty_size > 0 && recv_size > penalty_size) + penalized = TRUE; + } + + if(chunk_penalty_size > 0 && + (curl_off_t)conn->chunk.datasize > chunk_penalty_size) + penalized = TRUE; + + infof(data, "Conn: %ld (%p) Receive pipe weight: (%" + CURL_FORMAT_CURL_OFF_T "/%zu), penalized: %s\n", + conn->connection_id, (void *)conn, recv_size, + conn->chunk.datasize, penalized?"TRUE":"FALSE"); + return penalized; + } + return FALSE; +} + +static CURLcode addHandleToPipeline(struct SessionHandle *data, + struct curl_llist *pipeline) +{ + if(!Curl_llist_insert_next(pipeline, pipeline->tail, data)) + return CURLE_OUT_OF_MEMORY; + return CURLE_OK; +} + + +CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle, + struct connectdata *conn) +{ + struct curl_llist_element *sendhead = conn->send_pipe->head; + struct curl_llist *pipeline; + CURLcode result; + + pipeline = conn->send_pipe; + + result = addHandleToPipeline(handle, pipeline); + + if(pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) { + /* this is a new one as head, expire it */ + Curl_pipeline_leave_write(conn); /* not in use yet */ + Curl_expire(conn->send_pipe->head->ptr, 1); + } + +#if 0 /* enable for pipeline debugging */ + print_pipeline(conn); +#endif + + return result; +} + +/* Move this transfer from the sending list to the receiving list. + + Pay special attention to the new sending list "leader" as it needs to get + checked to update what sockets it acts on. + +*/ +void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle, + struct connectdata *conn) +{ + struct curl_llist_element *curr; + + curr = conn->send_pipe->head; + while(curr) { + if(curr->ptr == handle) { + Curl_llist_move(conn->send_pipe, curr, + conn->recv_pipe, conn->recv_pipe->tail); + + if(conn->send_pipe->head) { + /* Since there's a new easy handle at the start of the send pipeline, + set its timeout value to 1ms to make it trigger instantly */ + Curl_pipeline_leave_write(conn); /* not used now */ +#ifdef DEBUGBUILD + infof(conn->data, "%p is at send pipe head B!\n", + (void *)conn->send_pipe->head->ptr); +#endif + Curl_expire(conn->send_pipe->head->ptr, 1); + } + + /* The receiver's list is not really interesting here since either this + handle is now first in the list and we'll deal with it soon, or + another handle is already first and thus is already taken care of */ + + break; /* we're done! */ + } + curr = curr->next; + } +} + +bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle, + struct connectdata *conn) +{ + if(handle->multi) { + struct curl_llist *blacklist = + Curl_multi_pipelining_site_bl(handle->multi); + + if(blacklist) { + struct curl_llist_element *curr; + + curr = blacklist->head; + while(curr) { + struct site_blacklist_entry *site; + + site = curr->ptr; + if(Curl_raw_equal(site->hostname, conn->host.name) && + site->port == conn->remote_port) { + infof(handle, "Site %s:%d is pipeline blacklisted\n", + conn->host.name, conn->remote_port); + return TRUE; + } + curr = curr->next; + } + } + } + return FALSE; +} + +CURLMcode Curl_pipeline_set_site_blacklist(char **sites, + struct curl_llist **list_ptr) +{ + struct curl_llist *old_list = *list_ptr; + struct curl_llist *new_list = NULL; + + if(sites) { + new_list = Curl_llist_alloc((curl_llist_dtor) site_blacklist_llist_dtor); + if(!new_list) + return CURLM_OUT_OF_MEMORY; + + /* Parse the URLs and populate the list */ + while(*sites) { + char *hostname; + char *port; + struct site_blacklist_entry *entry; + + hostname = strdup(*sites); + if(!hostname) { + Curl_llist_destroy(new_list, NULL); + return CURLM_OUT_OF_MEMORY; + } + + entry = malloc(sizeof(struct site_blacklist_entry)); + if(!entry) { + free(hostname); + Curl_llist_destroy(new_list, NULL); + return CURLM_OUT_OF_MEMORY; + } + + port = strchr(hostname, ':'); + if(port) { + *port = '\0'; + port++; + entry->port = (unsigned short)strtol(port, NULL, 10); + } + else { + /* Default port number for HTTP */ + entry->port = 80; + } + + entry->hostname = hostname; + + if(!Curl_llist_insert_next(new_list, new_list->tail, entry)) { + site_blacklist_llist_dtor(NULL, entry); + Curl_llist_destroy(new_list, NULL); + return CURLM_OUT_OF_MEMORY; + } + + sites++; + } + } + + /* Free the old list */ + if(old_list) { + Curl_llist_destroy(old_list, NULL); + } + + /* This might be NULL if sites == NULL, i.e the blacklist is cleared */ + *list_ptr = new_list; + + return CURLM_OK; +} + +bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle, + char *server_name) +{ + if(handle->multi && server_name) { + struct curl_llist *blacklist = + Curl_multi_pipelining_server_bl(handle->multi); + + if(blacklist) { + struct curl_llist_element *curr; + + curr = blacklist->head; + while(curr) { + char *bl_server_name; + + bl_server_name = curr->ptr; + if(Curl_raw_nequal(bl_server_name, server_name, + strlen(bl_server_name))) { + infof(handle, "Server %s is blacklisted\n", server_name); + return TRUE; + } + curr = curr->next; + } + } + + DEBUGF(infof(handle, "Server %s is not blacklisted\n", server_name)); + } + return FALSE; +} + +CURLMcode Curl_pipeline_set_server_blacklist(char **servers, + struct curl_llist **list_ptr) +{ + struct curl_llist *old_list = *list_ptr; + struct curl_llist *new_list = NULL; + + if(servers) { + new_list = Curl_llist_alloc((curl_llist_dtor) server_blacklist_llist_dtor); + if(!new_list) + return CURLM_OUT_OF_MEMORY; + + /* Parse the URLs and populate the list */ + while(*servers) { + char *server_name; + + server_name = strdup(*servers); + if(!server_name) + return CURLM_OUT_OF_MEMORY; + + if(!Curl_llist_insert_next(new_list, new_list->tail, server_name)) + return CURLM_OUT_OF_MEMORY; + + servers++; + } + } + + /* Free the old list */ + if(old_list) { + Curl_llist_destroy(old_list, NULL); + } + + /* This might be NULL if sites == NULL, i.e the blacklist is cleared */ + *list_ptr = new_list; + + return CURLM_OK; +} + +static bool pipe_head(struct SessionHandle *data, + struct curl_llist *pipeline) +{ + if(pipeline) { + struct curl_llist_element *curr = pipeline->head; + if(curr) + return (curr->ptr == data) ? TRUE : FALSE; + } + return FALSE; +} + +/* returns TRUE if the given handle is head of the recv pipe */ +bool Curl_recvpipe_head(struct SessionHandle *data, + struct connectdata *conn) +{ + return pipe_head(data, conn->recv_pipe); +} + +/* returns TRUE if the given handle is head of the send pipe */ +bool Curl_sendpipe_head(struct SessionHandle *data, + struct connectdata *conn) +{ + return pipe_head(data, conn->send_pipe); +} + + +/* + * Check if the write channel is available and this handle as at the head, + * then grab the channel and return TRUE. + * + * If not available, return FALSE. + */ + +bool Curl_pipeline_checkget_write(struct SessionHandle *data, + struct connectdata *conn) +{ + if(conn->bits.multiplex) + /* when multiplexing, we can use it at once */ + return TRUE; + + if(!conn->writechannel_inuse && Curl_sendpipe_head(data, conn)) { + /* Grab the channel */ + conn->writechannel_inuse = TRUE; + return TRUE; + } + return FALSE; +} + + +/* + * Check if the read channel is available and this handle as at the head, then + * grab the channel and return TRUE. + * + * If not available, return FALSE. + */ + +bool Curl_pipeline_checkget_read(struct SessionHandle *data, + struct connectdata *conn) +{ + if(conn->bits.multiplex) + /* when multiplexing, we can use it at once */ + return TRUE; + + if(!conn->readchannel_inuse && Curl_recvpipe_head(data, conn)) { + /* Grab the channel */ + conn->readchannel_inuse = TRUE; + return TRUE; + } + return FALSE; +} + +/* + * The current user of the pipeline write channel gives it up. + */ +void Curl_pipeline_leave_write(struct connectdata *conn) +{ + conn->writechannel_inuse = FALSE; +} + +/* + * The current user of the pipeline read channel gives it up. + */ +void Curl_pipeline_leave_read(struct connectdata *conn) +{ + conn->readchannel_inuse = FALSE; +} + + +#if 0 +void print_pipeline(struct connectdata *conn) +{ + struct curl_llist_element *curr; + struct connectbundle *cb_ptr; + struct SessionHandle *data = conn->data; + + cb_ptr = conn->bundle; + + if(cb_ptr) { + curr = cb_ptr->conn_list->head; + while(curr) { + conn = curr->ptr; + infof(data, "- Conn %ld (%p) send_pipe: %zu, recv_pipe: %zu\n", + conn->connection_id, + (void *)conn, + conn->send_pipe->size, + conn->recv_pipe->size); + curr = curr->next; + } + } +} + +#endif diff --git a/project/jni/curl/lib/pipeline.h b/project/jni/curl/lib/pipeline.h new file mode 100644 index 000000000..a39dfa8de --- /dev/null +++ b/project/jni/curl/lib/pipeline.h @@ -0,0 +1,56 @@ +#ifndef HEADER_CURL_PIPELINE_H +#define HEADER_CURL_PIPELINE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2015, Daniel Stenberg, , et al. + * Copyright (C) 2013 - 2014, Linus Nielsen Feltzing, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle, + struct connectdata *conn); +void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle, + struct connectdata *conn); +bool Curl_pipeline_penalized(struct SessionHandle *data, + struct connectdata *conn); + +bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle, + struct connectdata *conn); + +CURLMcode Curl_pipeline_set_site_blacklist(char **sites, + struct curl_llist **list_ptr); + +bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle, + char *server_name); + +CURLMcode Curl_pipeline_set_server_blacklist(char **servers, + struct curl_llist **list_ptr); + +bool Curl_pipeline_checkget_write(struct SessionHandle *data, + struct connectdata *conn); +bool Curl_pipeline_checkget_read(struct SessionHandle *data, + struct connectdata *conn); +void Curl_pipeline_leave_write(struct connectdata *conn); +void Curl_pipeline_leave_read(struct connectdata *conn); +bool Curl_recvpipe_head(struct SessionHandle *data, + struct connectdata *conn); +bool Curl_sendpipe_head(struct SessionHandle *data, + struct connectdata *conn); + +#endif /* HEADER_CURL_PIPELINE_H */ diff --git a/project/jni/curl/lib/polarssl.c b/project/jni/curl/lib/polarssl.c deleted file mode 100644 index bed76354a..000000000 --- a/project/jni/curl/lib/polarssl.c +++ /dev/null @@ -1,375 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2010, Hoi-Ho Chan, - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * Source file for all PolarSSL-specific code for the TLS/SSL layer. No code - * but sslgen.c should ever call or use these functions. - * - */ - -#include "setup.h" -#ifdef USE_POLARSSL - -#include -#include -#include -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "urldata.h" -#include "sendf.h" -#include "inet_pton.h" -#include "polarssl.h" -#include "sslgen.h" -#include "parsedate.h" -#include "connect.h" /* for the connect timeout */ -#include "select.h" -#include "rawstr.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -/* Define this to enable lots of debugging for PolarSSL */ -#undef POLARSSL_DEBUG - -#ifdef POLARSSL_DEBUG -static void polarssl_debug(void *context, int level, char *line) -{ - struct SessionHandle *data = NULL; - - if(!context) - return; - - data = (struct SessionHandle *)context; - - infof(data, "%s", line); -} -#else -#endif - -static Curl_recv polarssl_recv; -static Curl_send polarssl_send; - -/* - * This function loads all the client/CA certificates and CRLs. Setup the TLS - * layer and do all necessary magic. - */ -CURLcode -Curl_polarssl_connect(struct connectdata *conn, - int sockindex) -{ - struct SessionHandle *data = conn->data; - bool sni = TRUE; /* default is SNI enabled */ - int ret = -1; -#ifdef ENABLE_IPV6 - struct in6_addr addr; -#else - struct in_addr addr; -#endif - void *old_session = NULL; - size_t old_session_size = 0; - char buffer[1024]; - - if(conn->ssl[sockindex].state == ssl_connection_complete) - return CURLE_OK; - - /* PolarSSL only supports SSLv3 and TLSv1 */ - if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { - failf(data, "PolarSSL does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - } else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) { - sni = FALSE; /* SSLv3 has no SNI */ - } - - havege_init(&conn->ssl[sockindex].hs); - - /* Load the trusted CA */ - memset(&conn->ssl[sockindex].cacert, 0, sizeof(x509_cert)); - - if(data->set.str[STRING_SSL_CAFILE]) { - ret = x509parse_crtfile(&conn->ssl[sockindex].cacert, - data->set.str[STRING_SSL_CAFILE]); - - if(ret) { - failf(data, "Error reading ca cert file %s: -0x%04X", - data->set.str[STRING_SSL_CAFILE], -ret); - - if(data->set.ssl.verifypeer) - return CURLE_SSL_CACERT_BADFILE; - } - } - - /* Load the client certificate */ - memset(&conn->ssl[sockindex].clicert, 0, sizeof(x509_cert)); - - if(data->set.str[STRING_CERT]) { - ret = x509parse_crtfile(&conn->ssl[sockindex].clicert, - data->set.str[STRING_CERT]); - - if(ret) { - failf(data, "Error reading client cert file %s: -0x%04X", - data->set.str[STRING_CERT], -ret); - return CURLE_SSL_CERTPROBLEM; - } - } - - /* Load the client private key */ - if(data->set.str[STRING_KEY]) { - ret = x509parse_keyfile(&conn->ssl[sockindex].rsa, - data->set.str[STRING_KEY], - data->set.str[STRING_KEY_PASSWD]); - - if(ret) { - failf(data, "Error reading private key %s: -0x%04X", - data->set.str[STRING_KEY], -ret); - return CURLE_SSL_CERTPROBLEM; - } - } - - /* Load the CRL */ - memset(&conn->ssl[sockindex].crl, 0, sizeof(x509_crl)); - - if(data->set.str[STRING_SSL_CRLFILE]) { - ret = x509parse_crlfile(&conn->ssl[sockindex].crl, - data->set.str[STRING_SSL_CRLFILE]); - - if(ret) { - failf(data, "Error reading CRL file %s: -0x%04X", - data->set.str[STRING_SSL_CRLFILE], -ret); - return CURLE_SSL_CRL_BADFILE; - } - } - - infof(data, "PolarSSL: Connected to %s:%d\n", - conn->host.name, conn->remote_port); - - havege_init(&conn->ssl[sockindex].hs); - - if(ssl_init(&conn->ssl[sockindex].ssl)) { - failf(data, "PolarSSL: ssl_init failed"); - return CURLE_SSL_CONNECT_ERROR; - } - - ssl_set_endpoint(&conn->ssl[sockindex].ssl, SSL_IS_CLIENT); - ssl_set_authmode(&conn->ssl[sockindex].ssl, SSL_VERIFY_OPTIONAL); - - ssl_set_rng(&conn->ssl[sockindex].ssl, havege_rand, - &conn->ssl[sockindex].hs); - ssl_set_bio(&conn->ssl[sockindex].ssl, - net_recv, &conn->sock[sockindex], - net_send, &conn->sock[sockindex]); - - ssl_set_ciphers(&conn->ssl[sockindex].ssl, ssl_default_ciphers); - - if(!Curl_ssl_getsessionid(conn, &old_session, &old_session_size)) { - memcpy(&conn->ssl[sockindex].ssn, old_session, old_session_size); - infof(data, "PolarSSL re-using session\n"); - } - - ssl_set_session(&conn->ssl[sockindex].ssl, 1, 600, - &conn->ssl[sockindex].ssn); - - ssl_set_ca_chain(&conn->ssl[sockindex].ssl, - &conn->ssl[sockindex].cacert, - &conn->ssl[sockindex].crl, - conn->host.name); - - ssl_set_own_cert(&conn->ssl[sockindex].ssl, - &conn->ssl[sockindex].clicert, &conn->ssl[sockindex].rsa); - - if(!Curl_inet_pton(AF_INET, conn->host.name, &addr) && -#ifdef ENABLE_IPV6 - !Curl_inet_pton(AF_INET6, conn->host.name, &addr) && -#endif - sni && ssl_set_hostname(&conn->ssl[sockindex].ssl, conn->host.name)) { - infof(data, "WARNING: failed to configure " - "server name indication (SNI) TLS extension\n"); - } - - infof(data, "PolarSSL: performing SSL/TLS handshake...\n"); - -#ifdef POLARSSL_DEBUG - ssl_set_dbg(&conn->ssl[sockindex].ssl, polarssl_debug, data); -#endif - - for(;;) { - if (!(ret = ssl_handshake(&conn->ssl[sockindex].ssl))) { - break; - } else if(ret != POLARSSL_ERR_NET_TRY_AGAIN) { - failf(data, "ssl_handshake returned -0x%04X", -ret); - return CURLE_SSL_CONNECT_ERROR; - } else { - /* wait for data from server... */ - long timeout_ms = Curl_timeleft(conn, NULL, TRUE); - - if(timeout_ms < 0) { - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - switch(Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, timeout_ms)) { - case 0: - failf(data, "SSL handshake timeout"); - return CURLE_OPERATION_TIMEDOUT; - break; - case CURL_CSELECT_IN: - continue; - break; - default: - return CURLE_SSL_CONNECT_ERROR; - break; - } - } - } - - infof(data, "PolarSSL: Handshake complete, cipher is %s\n", - ssl_get_cipher(&conn->ssl[sockindex].ssl)); - - ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl); - - if(ret && data->set.ssl.verifypeer) { - if(ret & BADCERT_EXPIRED) - failf(data, "Cert verify failed: BADCERT_EXPIRED\n"); - - if(ret & BADCERT_REVOKED) - failf(data, "Cert verify failed: BADCERT_REVOKED"); - - if(ret & BADCERT_CN_MISMATCH) - failf(data, "Cert verify failed: BADCERT_CN_MISMATCH"); - - if(ret & BADCERT_NOT_TRUSTED) - failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED"); - - return CURLE_SSL_CACERT; - } - - if(conn->ssl[sockindex].ssl.peer_cert) { - /* If the session was resumed, there will be no peer certs */ - memset(buffer, 0, sizeof(buffer)); - - if(x509parse_cert_info(buffer, sizeof(buffer), (char *)"* ", - conn->ssl[sockindex].ssl.peer_cert) != -1) - infof(data, "Dumping cert info:\n%s\n", buffer); - } - - conn->ssl[sockindex].state = ssl_connection_complete; - conn->recv[sockindex] = polarssl_recv; - conn->send[sockindex] = polarssl_send; - - /* Save the current session data for possible re-use */ - { - void *new_session = malloc(sizeof(conn->ssl[sockindex].ssn)); - - if(new_session) { - memcpy(new_session, &conn->ssl[sockindex].ssn, - sizeof(conn->ssl[sockindex].ssn)); - - if(old_session) - Curl_ssl_delsessionid(conn, old_session); - - return Curl_ssl_addsessionid(conn, new_session, - sizeof(conn->ssl[sockindex].ssn)); - } - } - - return CURLE_OK; -} - -static ssize_t polarssl_send(struct connectdata *conn, - int sockindex, - const void *mem, - size_t len, - CURLcode *curlcode) -{ - int ret = -1; - - ret = ssl_write(&conn->ssl[sockindex].ssl, - (unsigned char *)mem, len); - - if(ret < 0) { - *curlcode = (ret == POLARSSL_ERR_NET_TRY_AGAIN) ? - CURLE_AGAIN : CURLE_SEND_ERROR; - ret = -1; - } - - return ret; -} - -void Curl_polarssl_close_all(struct SessionHandle *data) -{ - (void)data; -} - -void Curl_polarssl_close(struct connectdata *conn, int sockindex) -{ - rsa_free(&conn->ssl[sockindex].rsa); - x509_free(&conn->ssl[sockindex].clicert); - x509_free(&conn->ssl[sockindex].cacert); - x509_crl_free(&conn->ssl[sockindex].crl); - ssl_free(&conn->ssl[sockindex].ssl); -} - -static ssize_t polarssl_recv(struct connectdata *conn, - int num, - char *buf, - size_t buffersize, - CURLcode *curlcode) -{ - int ret = -1; - ssize_t len = -1; - - memset(buf, 0, buffersize); - ret = ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf, buffersize); - - if(ret <= 0) { - *curlcode = (ret == POLARSSL_ERR_NET_TRY_AGAIN) ? - CURLE_AGAIN : CURLE_RECV_ERROR; - return -1; - } - - len = ret; - - return len; -} - -void Curl_polarssl_session_free(void *ptr) -{ - free(ptr); -} - -size_t Curl_polarssl_version(char *buffer, size_t size) -{ - return snprintf(buffer, size, "PolarSSL"); -} - -#endif diff --git a/project/jni/curl/lib/pop3.c b/project/jni/curl/lib/pop3.c index 9f6744363..823761d2e 100644 --- a/project/jni/curl/lib/pop3.c +++ b/project/jni/curl/lib/pop3.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -18,28 +18,26 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * RFC1734 POP3 Authentication * RFC1939 POP3 protocol + * RFC2195 CRAM-MD5 authentication * RFC2384 POP URL Scheme + * RFC2449 POP3 Extension Mechanism * RFC2595 Using TLS with IMAP, POP3 and ACAP + * RFC2831 DIGEST-MD5 authentication + * RFC4422 Simple Authentication and Security Layer (SASL) + * RFC4616 PLAIN authentication + * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism + * RFC5034 POP3 SASL Authentication Mechanism + * RFC6749 OAuth 2.0 Authorization Framework + * Draft LOGIN SASL Mechanism * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_POP3 -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif @@ -65,9 +63,6 @@ #include #include "urldata.h" #include "sendf.h" -#include "easyif.h" /* for Curl_convert_... prototypes */ - -#include "if2ip.h" #include "hostip.h" #include "progress.h" #include "transfer.h" @@ -78,37 +73,40 @@ #include "strtoofft.h" #include "strequal.h" -#include "sslgen.h" +#include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" #include "rawstr.h" -#include "strtoofft.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "curl_sasl.h" +#include "curl_md5.h" +#include "warnless.h" +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /* Local API functions */ -static CURLcode pop3_parse_url_path(struct connectdata *conn); static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done); static CURLcode pop3_do(struct connectdata *conn, bool *done); -static CURLcode pop3_done(struct connectdata *conn, - CURLcode, bool premature); +static CURLcode pop3_done(struct connectdata *conn, CURLcode status, + bool premature); static CURLcode pop3_connect(struct connectdata *conn, bool *done); -static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection); +static CURLcode pop3_disconnect(struct connectdata *conn, bool dead); static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done); -static int pop3_getsock(struct connectdata *conn, - curl_socket_t *socks, +static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks); -static CURLcode pop3_doing(struct connectdata *conn, - bool *dophase_done); -static CURLcode pop3_setup_connection(struct connectdata * conn); +static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done); +static CURLcode pop3_setup_connection(struct connectdata *conn); +static CURLcode pop3_parse_url_options(struct connectdata *conn); +static CURLcode pop3_parse_url_path(struct connectdata *conn); +static CURLcode pop3_parse_custom_request(struct connectdata *conn); +static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech, + const char *initresp); +static CURLcode pop3_continue_auth(struct connectdata *conn, const char *resp); +static void pop3_get_message(char *buffer, char** outptr); /* * POP3 protocol handler. @@ -125,13 +123,15 @@ const struct Curl_handler Curl_handler_pop3 = { pop3_doing, /* doing */ pop3_getsock, /* proto_getsock */ pop3_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_POP3, /* defport */ - PROT_POP3 /* protocol */ + CURLPROTO_POP3, /* protocol */ + PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ }; - #ifdef USE_SSL /* * POP3S protocol handler. @@ -148,10 +148,14 @@ const struct Curl_handler Curl_handler_pop3s = { pop3_doing, /* doing */ pop3_getsock, /* proto_getsock */ pop3_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_POP3S, /* defport */ - PROT_POP3 | PROT_POP3S | PROT_SSL /* protocol */ + CURLPROTO_POP3S, /* protocol */ + PROTOPT_CLOSEACTION | PROTOPT_SSL + | PROTOPT_NOURLQUERY /* flags */ }; #endif @@ -162,7 +166,7 @@ const struct Curl_handler Curl_handler_pop3s = { static const struct Curl_handler Curl_handler_pop3_proxy = { "POP3", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -171,13 +175,15 @@ static const struct Curl_handler Curl_handler_pop3_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_POP3, /* defport */ - PROT_HTTP /* protocol */ + CURLPROTO_HTTP, /* protocol */ + PROTOPT_NONE /* flags */ }; - #ifdef USE_SSL /* * HTTP-proxyed POP3S protocol handler. @@ -185,7 +191,7 @@ static const struct Curl_handler Curl_handler_pop3_proxy = { static const struct Curl_handler Curl_handler_pop3s_proxy = { "POP3S", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -194,302 +200,831 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_POP3S, /* defport */ - PROT_HTTP /* protocol */ + CURLPROTO_HTTP, /* protocol */ + PROTOPT_NONE /* flags */ }; #endif #endif +/* SASL parameters for the pop3 protocol */ +static const struct SASLproto saslpop3 = { + "pop", /* The service name */ + '*', /* Code received when continuation is expected */ + '+', /* Code to receive upon authentication success */ + 255 - 8, /* Maximum initial response length (no max) */ + pop3_perform_auth, /* Send authentication command */ + pop3_continue_auth, /* Send authentication continuation */ + pop3_get_message /* Get SASL response message */ +}; -/* function that checks for a pop3 status code at the start of the given - string */ -static int pop3_endofresp(struct pingpong *pp, - int *resp) +#ifdef USE_SSL +static void pop3_to_pop3s(struct connectdata *conn) { - char *line = pp->linestart_resp; - size_t len = pp->nread_resp; + /* Change the connection handler */ + conn->handler = &Curl_handler_pop3s; + + /* Set the connection's upgraded to TLS flag */ + conn->tls_upgraded = TRUE; +} +#else +#define pop3_to_pop3s(x) Curl_nop_stmt +#endif + +/*********************************************************************** + * + * pop3_endofresp() + * + * Checks for an ending POP3 status code at the start of the given string, but + * also detects the APOP timestamp from the server greeting and various + * capabilities from the CAPA response including the supported authentication + * types and allowed SASL mechanisms. + */ +static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len, + int *resp) +{ + struct pop3_conn *pop3c = &conn->proto.pop3c; + + /* Do we have an error response? */ + if(len >= 4 && !memcmp("-ERR", line, 4)) { + *resp = '-'; - if( ((len >= 3) && !memcmp("+OK", line, 3)) || - ((len >= 4) && !memcmp("-ERR", line, 4)) ) { - *resp=line[1]; /* O or E */ return TRUE; } - return FALSE; /* nothing for us */ + /* Are we processing CAPA command responses? */ + if(pop3c->state == POP3_CAPA) { + /* Do we have the terminating line? */ + if(len >= 1 && !memcmp(line, ".", 1)) + /* Treat the response as a success */ + *resp = '+'; + else + /* Treat the response as an untagged continuation */ + *resp = '*'; + + return TRUE; + } + + /* Do we have a success response? */ + if(len >= 3 && !memcmp("+OK", line, 3)) { + *resp = '+'; + + return TRUE; + } + + /* Do we have a continuation response? */ + if(len >= 1 && !memcmp("+", line, 1)) { + *resp = '*'; + + return TRUE; + } + + return FALSE; /* Nothing for us */ } -/* This is the ONLY way to change POP3 state! */ -static void state(struct connectdata *conn, - pop3state newstate) +/*********************************************************************** + * + * pop3_get_message() + * + * Gets the authentication message from the response buffer. + */ +static void pop3_get_message(char *buffer, char** outptr) { + size_t len = 0; + char* message = NULL; + + /* Find the start of the message */ + for(message = buffer + 2; *message == ' ' || *message == '\t'; message++) + ; + + /* Find the end of the message */ + for(len = strlen(message); len--;) + if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && + message[len] != '\t') + break; + + /* Terminate the message */ + if(++len) { + message[len] = '\0'; + } + + *outptr = message; +} + +/*********************************************************************** + * + * state() + * + * This is the ONLY way to change POP3 state! + */ +static void state(struct connectdata *conn, pop3state newstate) +{ + struct pop3_conn *pop3c = &conn->proto.pop3c; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ - static const char * const names[]={ + static const char * const names[] = { "STOP", "SERVERGREET", + "CAPA", + "STARTTLS", + "UPGRADETLS", + "AUTH", + "APOP", "USER", "PASS", - "STARTTLS", - "LIST", - "RETR", + "COMMAND", "QUIT", /* LAST */ }; -#endif - struct pop3_conn *pop3c = &conn->proto.pop3c; -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + if(pop3c->state != newstate) infof(conn->data, "POP3 %p state change from %s to %s\n", - pop3c, names[pop3c->state], names[newstate]); + (void *)pop3c, names[pop3c->state], names[newstate]); #endif + pop3c->state = newstate; } -static CURLcode pop3_state_user(struct connectdata *conn) +/*********************************************************************** + * + * pop3_perform_capa() + * + * Sends the CAPA command in order to obtain a list of server side supported + * capabilities. + */ +static CURLcode pop3_perform_capa(struct connectdata *conn) { - CURLcode result; - struct FTP *pop3 = conn->data->state.proto.pop3; + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + + pop3c->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */ + pop3c->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */ + pop3c->tls_supported = FALSE; /* Clear the TLS capability */ + + /* Send the CAPA command */ + result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA"); + + if(!result) + state(conn, POP3_CAPA); + + return result; +} + +/*********************************************************************** + * + * pop3_perform_starttls() + * + * Sends the STLS command to start the upgrade to TLS. + */ +static CURLcode pop3_perform_starttls(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + /* Send the STLS command */ + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "STLS"); + + if(!result) + state(conn, POP3_STARTTLS); + + return result; +} + +/*********************************************************************** + * + * pop3_perform_upgrade_tls() + * + * Performs the upgrade to TLS. + */ +static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + + /* Start the SSL connection */ + result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone); + + if(!result) { + if(pop3c->state != POP3_UPGRADETLS) + state(conn, POP3_UPGRADETLS); + + if(pop3c->ssldone) { + pop3_to_pop3s(conn); + result = pop3_perform_capa(conn); + } + } + + return result; +} + +/*********************************************************************** + * + * pop3_perform_user() + * + * Sends a clear text USER command to authenticate with. + */ +static CURLcode pop3_perform_user(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + /* Check we have a username and password to authenticate with and end the + connect phase if we don't */ + if(!conn->bits.user_passwd) { + state(conn, POP3_STOP); - /* send USER */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s", - pop3->user?pop3->user:""); - if(result) return result; + } - state(conn, POP3_USER); + /* Send the USER command */ + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s", + conn->user ? conn->user : ""); + if(!result) + state(conn, POP3_USER); - return CURLE_OK; + return result; } -/* For the POP3 "protocol connect" and "doing" phases only */ -static int pop3_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) +#ifndef CURL_DISABLE_CRYPTO_AUTH +/*********************************************************************** + * + * pop3_perform_apop() + * + * Sends an APOP command to authenticate with. + */ +static CURLcode pop3_perform_apop(struct connectdata *conn) { - return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks); + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + size_t i; + MD5_context *ctxt; + unsigned char digest[MD5_DIGEST_LEN]; + char secret[2 * MD5_DIGEST_LEN + 1]; + + /* Check we have a username and password to authenticate with and end the + connect phase if we don't */ + if(!conn->bits.user_passwd) { + state(conn, POP3_STOP); + + return result; + } + + /* Create the digest */ + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp, + curlx_uztoui(strlen(pop3c->apoptimestamp))); + + Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd, + curlx_uztoui(strlen(conn->passwd))); + + /* Finalise the digest */ + Curl_MD5_final(ctxt, digest); + + /* Convert the calculated 16 octet digest into a 32 byte hex string */ + for(i = 0; i < MD5_DIGEST_LEN; i++) + snprintf(&secret[2 * i], 3, "%02x", digest[i]); + + result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret); + + if(!result) + state(conn, POP3_APOP); + + return result; +} +#endif + +/*********************************************************************** + * + * pop3_perform_auth() + * + * Sends an AUTH command allowing the client to login with the given SASL + * authentication mechanism. + */ +static CURLcode pop3_perform_auth(struct connectdata *conn, + const char *mech, + const char *initresp) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + + if(initresp) { /* AUTH ... */ + /* Send the AUTH command with the initial response */ + result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp); + } + else { + /* Send the AUTH command */ + result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech); + } + + return result; } -/* for STARTTLS responses */ +/*********************************************************************** + * + * pop3_continue_auth() + * + * Sends SASL continuation data or cancellation. + */ +static CURLcode pop3_continue_auth(struct connectdata *conn, + const char *resp) +{ + struct pop3_conn *pop3c = &conn->proto.pop3c; + + return Curl_pp_sendf(&pop3c->pp, "%s", resp); +} + +/*********************************************************************** + * + * pop3_perform_authentication() + * + * Initiates the authentication sequence, with the appropriate SASL + * authentication mechanism, falling back to APOP and clear text should a + * common mechanism not be available between the client and server. + */ +static CURLcode pop3_perform_authentication(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + saslprogress progress = SASL_IDLE; + + /* Check we have enough data to authenticate with and end the + connect phase if we don't */ + if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) { + state(conn, POP3_STOP); + return result; + } + + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) { + /* Calculate the SASL login details */ + result = Curl_sasl_start(&pop3c->sasl, conn, FALSE, &progress); + + if(!result) + if(progress == SASL_INPROGRESS) + state(conn, POP3_AUTH); + } + + if(!result && progress == SASL_IDLE) { +#ifndef CURL_DISABLE_CRYPTO_AUTH + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) + /* Perform APOP authentication */ + result = pop3_perform_apop(conn); + else +#endif + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) + /* Perform clear text authentication */ + result = pop3_perform_user(conn); + else { + /* Other mechanisms not supported */ + infof(conn->data, "No known authentication mechanisms supported!\n"); + result = CURLE_LOGIN_DENIED; + } + } + + return result; +} + +/*********************************************************************** + * + * pop3_perform_command() + * + * Sends a POP3 based command. + */ +static CURLcode pop3_perform_command(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct POP3 *pop3 = data->req.protop; + const char *command = NULL; + + /* Calculate the default command */ + if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) { + command = "LIST"; + + if(pop3->id[0] != '\0') + /* Message specific LIST so skip the BODY transfer */ + pop3->transfer = FTPTRANSFER_INFO; + } + else + command = "RETR"; + + /* Send the command */ + if(pop3->id[0] != '\0') + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s", + (pop3->custom && pop3->custom[0] != '\0' ? + pop3->custom : command), pop3->id); + else + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", + (pop3->custom && pop3->custom[0] != '\0' ? + pop3->custom : command)); + + if(!result) + state(conn, POP3_COMMAND); + + return result; +} + +/*********************************************************************** + * + * pop3_perform_quit() + * + * Performs the quit action prior to sclose() be called. + */ +static CURLcode pop3_perform_quit(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + /* Send the QUIT command */ + result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "QUIT"); + + if(!result) + state(conn, POP3_QUIT); + + return result; +} + +/* For the initial server greeting */ +static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct pop3_conn *pop3c = &conn->proto.pop3c; + const char *line = data->state.buffer; + size_t len = strlen(line); + size_t i; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + failf(data, "Got unexpected pop3-server response"); + result = CURLE_FTP_WEIRD_SERVER_REPLY; + } + else { + /* Does the server support APOP authentication? */ + if(len >= 4 && line[len - 2] == '>') { + /* Look for the APOP timestamp */ + for(i = 3; i < len - 2; ++i) { + if(line[i] == '<') { + /* Calculate the length of the timestamp */ + size_t timestamplen = len - 1 - i; + if(!timestamplen) + break; + + /* Allocate some memory for the timestamp */ + pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1); + + if(!pop3c->apoptimestamp) + break; + + /* Copy the timestamp */ + memcpy(pop3c->apoptimestamp, line + i, timestamplen); + pop3c->apoptimestamp[timestamplen] = '\0'; + + /* Store the APOP capability */ + pop3c->authtypes |= POP3_TYPE_APOP; + break; + } + } + } + + result = pop3_perform_capa(conn); + } + + return result; +} + +/* For CAPA responses */ +static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct pop3_conn *pop3c = &conn->proto.pop3c; + const char *line = data->state.buffer; + size_t len = strlen(line); + size_t wordlen; + + (void)instate; /* no use for this yet */ + + /* Do we have a untagged continuation response? */ + if(pop3code == '*') { + /* Does the server support the STLS capability? */ + if(len >= 4 && !memcmp(line, "STLS", 4)) + pop3c->tls_supported = TRUE; + + /* Does the server support clear text authentication? */ + else if(len >= 4 && !memcmp(line, "USER", 4)) + pop3c->authtypes |= POP3_TYPE_CLEARTEXT; + + /* Does the server support SASL based authentication? */ + else if(len >= 5 && !memcmp(line, "SASL ", 5)) { + pop3c->authtypes |= POP3_TYPE_SASL; + + /* Advance past the SASL keyword */ + line += 5; + len -= 5; + + /* Loop through the data line */ + for(;;) { + size_t llen; + unsigned int mechbit; + + while(len && + (*line == ' ' || *line == '\t' || + *line == '\r' || *line == '\n')) { + + line++; + len--; + } + + if(!len) + break; + + /* Extract the word */ + for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && + line[wordlen] != '\t' && line[wordlen] != '\r' && + line[wordlen] != '\n';) + wordlen++; + + /* Test the word for a matching authentication mechanism */ + mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); + if(mechbit && llen == wordlen) + pop3c->sasl.authmechs |= mechbit; + + line += wordlen; + len -= wordlen; + } + } + } + else if(pop3code == '+') { + if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { + /* We don't have a SSL/TLS connection yet, but SSL is requested */ + if(pop3c->tls_supported) + /* Switch to TLS connection now */ + result = pop3_perform_starttls(conn); + else if(data->set.use_ssl == CURLUSESSL_TRY) + /* Fallback and carry on with authentication */ + result = pop3_perform_authentication(conn); + else { + failf(data, "STLS not supported."); + result = CURLE_USE_SSL_FAILED; + } + } + else + result = pop3_perform_authentication(conn); + } + else { + /* Clear text is supported when CAPA isn't recognised */ + pop3c->authtypes |= POP3_TYPE_CLEARTEXT; + + result = pop3_perform_authentication(conn); + } + + return result; +} + +/* For STARTTLS responses */ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; + (void)instate; /* no use for this yet */ - if(pop3code != 'O') { - failf(data, "STARTTLS denied. %c", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Curl_ssl_connect is BLOCKING */ - result = Curl_ssl_connect(conn, FIRSTSOCKET); - if(CURLE_OK == result) { - conn->protocol |= PROT_POP3S; - result = pop3_state_user(conn); + if(pop3code != '+') { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied. %c", pop3code); + result = CURLE_USE_SSL_FAILED; } + else + result = pop3_perform_authentication(conn); } - state(conn, POP3_STOP); + else + result = pop3_perform_upgrade_tls(conn); + return result; } -/* for USER responses */ -static CURLcode pop3_state_user_resp(struct connectdata *conn, +/* For SASL authentication responses */ +static CURLcode pop3_state_auth_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct FTP *pop3 = data->state.proto.pop3; + struct pop3_conn *pop3c = &conn->proto.pop3c; + saslprogress progress; (void)instate; /* no use for this yet */ - if(pop3code != 'O') { + result = Curl_sasl_continue(&pop3c->sasl, conn, pop3code, &progress); + if(!result) + switch(progress) { + case SASL_DONE: + state(conn, POP3_STOP); /* Authenticated */ + break; + case SASL_IDLE: /* No mechanism left after cancellation */ +#ifndef CURL_DISABLE_CRYPTO_AUTH + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) + /* Perform APOP authentication */ + result = pop3_perform_apop(conn); + else +#endif + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) + /* Perform clear text authentication */ + result = pop3_perform_user(conn); + else { + failf(data, "Authentication cancelled"); + result = CURLE_LOGIN_DENIED; + } + break; + default: + break; + } + + return result; +} + +#ifndef CURL_DISABLE_CRYPTO_AUTH +/* For APOP responses */ +static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + failf(data, "Authentication failed: %d", pop3code); + result = CURLE_LOGIN_DENIED; + } + else + /* End of connect phase */ + state(conn, POP3_STOP); + + return result; +} +#endif + +/* For USER responses */ +static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { failf(data, "Access denied. %c", pop3code); result = CURLE_LOGIN_DENIED; } else - /* send PASS */ + /* Send the PASS command */ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s", - pop3->passwd?pop3->passwd:""); - if(result) - return result; + conn->passwd ? conn->passwd : ""); + if(!result) + state(conn, POP3_PASS); - state(conn, POP3_PASS); return result; } -/* for PASS responses */ -static CURLcode pop3_state_pass_resp(struct connectdata *conn, - int pop3code, +/* For PASS responses */ +static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; + (void)instate; /* no use for this yet */ - if(pop3code != 'O') { + if(pop3code != '+') { failf(data, "Access denied. %c", pop3code); result = CURLE_LOGIN_DENIED; } + else + /* End of connect phase */ + state(conn, POP3_STOP); - state(conn, POP3_STOP); return result; } -/* for the retr response */ -static CURLcode pop3_state_retr_resp(struct connectdata *conn, - int pop3code, - pop3state instate) +/* For command responses */ +static CURLcode pop3_state_command_resp(struct connectdata *conn, + int pop3code, + pop3state instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct FTP *pop3 = data->state.proto.pop3; + struct POP3 *pop3 = data->req.protop; struct pop3_conn *pop3c = &conn->proto.pop3c; struct pingpong *pp = &pop3c->pp; (void)instate; /* no use for this yet */ - if('O' != pop3code) { + if(pop3code != '+') { state(conn, POP3_STOP); return CURLE_RECV_ERROR; } - /* POP3 download */ - Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, - pop3->bytecountp, -1, NULL); /* no upload here */ + /* This 'OK' line ends with a CR LF pair which is the two first bytes of the + EOB string so count this is two matching bytes. This is necessary to make + the code detect the EOB if the only data than comes now is %2e CR LF like + when there is no body to return. */ + pop3c->eob = 2; - if(pp->cache) { - /* At this point there is a bunch of data in the header "cache" that is - actually body content, send it as body and then skip it. Do note - that there may even be additional "headers" after the body. */ + /* But since this initial CR LF pair is not part of the actual body, we set + the strip counter here so that these bytes won't be delivered. */ + pop3c->strip = 2; - /* we may get the EOB already here! */ - result = Curl_pop3_write(conn, pp->cache, pp->cache_size); - if(result) - return result; + if(pop3->transfer == FTPTRANSFER_BODY) { + /* POP3 download */ + Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL); - /* cache is drained */ - free(pp->cache); - pp->cache = NULL; - pp->cache_size = 0; + if(pp->cache) { + /* The header "cache" contains a bunch of data that is actually body + content so send it as such. Note that there may even be additional + "headers" after the body */ + + if(!data->set.opt_no_body) { + result = Curl_pop3_write(conn, pp->cache, pp->cache_size); + if(result) + return result; + } + + /* Free the cache */ + Curl_safefree(pp->cache); + + /* Reset the cache size */ + pp->cache_size = 0; + } } + /* End of DO phase */ state(conn, POP3_STOP); - return result; -} - -/* for the list response */ -static CURLcode pop3_state_list_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct FTP *pop3 = data->state.proto.pop3; - struct pop3_conn *pop3c = &conn->proto.pop3c; - struct pingpong *pp = &pop3c->pp; - - (void)instate; /* no use for this yet */ - - if('O' != pop3code) { - state(conn, POP3_STOP); - return CURLE_RECV_ERROR; - } - - /* POP3 download */ - Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, pop3->bytecountp, - -1, NULL); /* no upload here */ - - if(pp->cache) { - /* cache holds the email ID listing */ - - /* we may get the EOB already here! */ - result = Curl_pop3_write(conn, pp->cache, pp->cache_size); - if(result) - return result; - - /* cache is drained */ - free(pp->cache); - pp->cache = NULL; - pp->cache_size = 0; - } - - state(conn, POP3_STOP); - return result; -} - -/* start the DO phase for RETR */ -static CURLcode pop3_retr(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; - - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "RETR %s", pop3c->mailbox); - if(result) - return result; - - state(conn, POP3_RETR); - return result; -} - -/* start the DO phase for LIST */ -static CURLcode pop3_list(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; - - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST %s", pop3c->mailbox); - if(result) - return result; - - state(conn, POP3_LIST); return result; } static CURLcode pop3_statemach_act(struct connectdata *conn) { - CURLcode result; + CURLcode result = CURLE_OK; curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct SessionHandle *data=conn->data; int pop3code; struct pop3_conn *pop3c = &conn->proto.pop3c; struct pingpong *pp = &pop3c->pp; size_t nread = 0; + /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */ + if(pop3c->state == POP3_UPGRADETLS) + return pop3_perform_upgrade_tls(conn); + + /* Flush any data that needs to be sent */ if(pp->sendleft) return Curl_pp_flushsend(pp); - /* we read a piece of response */ - result = Curl_pp_readresp(sock, pp, &pop3code, &nread); - if(result) - return result; + do { + /* Read the response from the server */ + result = Curl_pp_readresp(sock, pp, &pop3code, &nread); + if(result) + return result; - if(pop3code) { - /* we have now received a full POP3 server response */ + if(!pop3code) + break; + + /* We have now received a full POP3 server response */ switch(pop3c->state) { case POP3_SERVERGREET: - if(pop3code != 'O') { - failf(data, "Got unexpected pop3-server response"); - return CURLE_FTP_WEIRD_SERVER_REPLY; - } - - if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) { - /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch - to TLS connection now */ - result = Curl_pp_sendf(&pop3c->pp, "STARTTLS", NULL); - state(conn, POP3_STARTTLS); - } - else - result = pop3_state_user(conn); - if(result) - return result; + result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state); break; + case POP3_CAPA: + result = pop3_state_capa_resp(conn, pop3code, pop3c->state); + break; + + case POP3_STARTTLS: + result = pop3_state_starttls_resp(conn, pop3code, pop3c->state); + break; + + case POP3_AUTH: + result = pop3_state_auth_resp(conn, pop3code, pop3c->state); + break; + +#ifndef CURL_DISABLE_CRYPTO_AUTH + case POP3_APOP: + result = pop3_state_apop_resp(conn, pop3code, pop3c->state); + break; +#endif + case POP3_USER: result = pop3_state_user_resp(conn, pop3code, pop3c->state); break; @@ -498,16 +1033,8 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_pass_resp(conn, pop3code, pop3c->state); break; - case POP3_STARTTLS: - result = pop3_state_starttls_resp(conn, pop3code, pop3c->state); - break; - - case POP3_RETR: - result = pop3_state_retr_resp(conn, pop3code, pop3c->state); - break; - - case POP3_LIST: - result = pop3_state_list_resp(conn, pop3code, pop3c->state); + case POP3_COMMAND: + result = pop3_state_command_resp(conn, pop3code, pop3c->state); break; case POP3_QUIT: @@ -517,148 +1044,105 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) state(conn, POP3_STOP); break; } - } + } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp)); + return result; } -/* called repeatedly until done from multi.c */ +/* Called repeatedly until done from multi.c */ static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done) { - struct pop3_conn *pop3c = &conn->proto.pop3c; - CURLcode result = Curl_pp_multi_statemach(&pop3c->pp); - - *done = (bool)(pop3c->state == POP3_STOP); - - return result; -} - -static CURLcode pop3_easy_statemach(struct connectdata *conn) -{ - struct pop3_conn *pop3c = &conn->proto.pop3c; - struct pingpong *pp = &pop3c->pp; CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; - while(pop3c->state != POP3_STOP) { - result = Curl_pp_easy_statemach(pp); - if(result) - break; + if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) { + result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone); + if(result || !pop3c->ssldone) + return result; } + result = Curl_pp_statemach(&pop3c->pp, FALSE); + *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE; + return result; } -/* - * Allocate and initialize the struct POP3 for the current SessionHandle. If - * need be. - */ +static CURLcode pop3_block_statemach(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + + while(pop3c->state != POP3_STOP && !result) + result = Curl_pp_statemach(&pop3c->pp, TRUE); + + return result; +} + +/* Allocate and initialize the POP3 struct for the current SessionHandle if + required */ static CURLcode pop3_init(struct connectdata *conn) { + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct FTP *pop3 = data->state.proto.pop3; - if(!pop3) { - pop3 = data->state.proto.pop3 = calloc(sizeof(struct FTP), 1); - if(!pop3) - return CURLE_OUT_OF_MEMORY; - } + struct POP3 *pop3; - /* get some initial data into the pop3 struct */ - pop3->bytecountp = &data->req.bytecount; + pop3 = data->req.protop = calloc(sizeof(struct POP3), 1); + if(!pop3) + result = CURLE_OUT_OF_MEMORY; - /* No need to duplicate user+password, the connectdata struct won't change - during a session, but we re-init them here since on subsequent inits - since the conn struct may have changed or been replaced. - */ - pop3->user = conn->user; - pop3->passwd = conn->passwd; - - return CURLE_OK; + return result; } -/* - * pop3_connect() should do everything that is to be considered a part of - * the connection phase. +/* For the POP3 "protocol connect" and "doing" phases only */ +static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks) +{ + return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks); +} + +/*********************************************************************** + * + * pop3_connect() + * + * This function should do everything that is to be considered a part of the + * connection phase. * * The variable 'done' points to will be TRUE if the protocol-layer connect - * phase is done when this function returns, or FALSE is not. When called as - * a part of the easy interface, it will always be TRUE. + * phase is done when this function returns, or FALSE if not. */ -static CURLcode pop3_connect(struct connectdata *conn, - bool *done) /* see description above */ +static CURLcode pop3_connect(struct connectdata *conn, bool *done) { - CURLcode result; + CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; - struct SessionHandle *data=conn->data; struct pingpong *pp = &pop3c->pp; *done = FALSE; /* default to not done yet */ - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); + /* We always support persistent connections in POP3 */ + connkeep(conn, "POP3 default"); - result = pop3_init(conn); - if(CURLE_OK != result) - return result; - - /* We always support persistant connections on pop3 */ - conn->bits.close = FALSE; - - pp->response_time = RESP_TIMEOUT; /* set default response time-out */ + /* Set the default response time-out */ + pp->response_time = RESP_TIMEOUT; pp->statemach_act = pop3_statemach_act; pp->endofresp = pop3_endofresp; pp->conn = conn; -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY) - if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { - /* for POP3 over HTTP proxy */ - struct HTTP http_proxy; - struct FTP *pop3_save; + /* Set the default preferred authentication type and mechanism */ + pop3c->preftype = POP3_TYPE_ANY; + Curl_sasl_init(&pop3c->sasl, &saslpop3); - /* BLOCKING */ - /* We want "seamless" POP3 operations through HTTP proxy tunnel */ + /* Initialise the pingpong layer */ + Curl_pp_init(pp); - /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member - * conn->proto.http; we want POP3 through HTTP and we have to change the - * member temporarily for connecting to the HTTP proxy. After - * Curl_proxyCONNECT we have to set back the member to the original struct - * POP3 pointer - */ - pop3_save = data->state.proto.pop3; - memset(&http_proxy, 0, sizeof(http_proxy)); - data->state.proto.http = &http_proxy; + /* Parse the URL options */ + result = pop3_parse_url_options(conn); + if(result) + return result; - result = Curl_proxyCONNECT(conn, FIRSTSOCKET, - conn->host.name, conn->remote_port); - - data->state.proto.pop3 = pop3_save; - - if(CURLE_OK != result) - return result; - } -#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */ - - if(conn->protocol & PROT_POP3S) { - /* BLOCKING */ - /* POP3S is simply pop3 with SSL for the control channel */ - /* now, perform the SSL initialization for this socket */ - result = Curl_ssl_connect(conn, FIRSTSOCKET); - if(result) - return result; - } - - Curl_pp_init(pp); /* init the response reader stuff */ - - /* When we connect, we start in the state where we await the server greet - response */ + /* Start off waiting for the server greeting response */ state(conn, POP3_SERVERGREET); - if(data->state.used_interface == Curl_if_multi) - result = pop3_multi_statemach(conn, done); - else { - result = pop3_easy_statemach(conn); - if(!result) - *done = TRUE; - } + result = pop3_multi_statemach(conn, done); return result; } @@ -675,25 +1159,29 @@ static CURLcode pop3_connect(struct connectdata *conn, static CURLcode pop3_done(struct connectdata *conn, CURLcode status, bool premature) { + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct FTP *pop3 = data->state.proto.pop3; - CURLcode result=CURLE_OK; + struct POP3 *pop3 = data->req.protop; + (void)premature; if(!pop3) - /* When the easy handle is removed from the multi while libcurl is still - * trying to resolve the host name, it seems that the pop3 struct is not - * yet initialized, but the removal action calls Curl_done() which calls - * this function. So we simply return success if no pop3 pointer is set. - */ + /* When the easy handle is removed from the multi interface while libcurl + is still trying to resolve the host name, the POP3 struct is not yet + initialized. However, the removal action calls Curl_done() which in + turn calls this function, so we simply return success. */ return CURLE_OK; if(status) { - conn->bits.close = TRUE; /* marked for closure */ - result = status; /* use the already set error code */ + connclose(conn, "POP3 done with bad status"); + result = status; /* use the already set error code */ } - /* clear these for next connection */ + /* Cleanup our per-request based variables */ + Curl_safefree(pop3->id); + Curl_safefree(pop3->custom); + + /* Clear the transfer mode for the next request */ pop3->transfer = FTPTRANSFER_BODY; return result; @@ -703,48 +1191,34 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, * * pop3_perform() * - * This is the actual DO function for POP3. Get a file/directory according to + * This is the actual DO function for POP3. Get a message/listing according to * the options previously setup. */ - -static -CURLcode pop3_perform(struct connectdata *conn, - bool *connected, /* connect status after PASV / PORT */ - bool *dophase_done) +static CURLcode pop3_perform(struct connectdata *conn, bool *connected, + bool *dophase_done) { - /* this is POP3 and no proxy */ - CURLcode result=CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; + /* This is POP3 and no proxy */ + CURLcode result = CURLE_OK; + struct POP3 *pop3 = conn->data->req.protop; DEBUGF(infof(conn->data, "DO phase starts\n")); if(conn->data->set.opt_no_body) { - /* requested no body means no transfer... */ - struct FTP *pop3 = conn->data->state.proto.pop3; + /* Requested no body means no transfer */ pop3->transfer = FTPTRANSFER_INFO; } *dophase_done = FALSE; /* not done yet */ - /* start the first command in the DO phase */ - /* If mailbox is empty, then assume user wants listing for mail IDs, - * otherwise, attempt to retrieve the mail-id stored in mailbox - */ - if (strlen(pop3c->mailbox)) - result = pop3_retr(conn); - else - result = pop3_list(conn); + /* Start the first command in the DO phase */ + result = pop3_perform_command(conn); if(result) return result; - /* run the state-machine */ - if(conn->data->state.used_interface == Curl_if_multi) - result = pop3_multi_statemach(conn, dophase_done); - else { - result = pop3_easy_statemach(conn); - *dophase_done = TRUE; /* with the easy interface we are done here */ - } - *connected = conn->bits.tcpconnect; + /* Run the state-machine */ + result = pop3_multi_statemach(conn, dophase_done); + + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); @@ -763,49 +1237,21 @@ CURLcode pop3_perform(struct connectdata *conn, */ static CURLcode pop3_do(struct connectdata *conn, bool *done) { - CURLcode retcode = CURLE_OK; + CURLcode result = CURLE_OK; *done = FALSE; /* default to false */ - /* - Since connections can be re-used between SessionHandles, this might be a - connection already existing but on a fresh SessionHandle struct so we must - make sure we have a good 'struct POP3' to play with. For new connections, - the struct POP3 is allocated and setup in the pop3_connect() function. - */ - Curl_reset_reqproto(conn); - retcode = pop3_init(conn); - if(retcode) - return retcode; - - retcode = pop3_parse_url_path(conn); - if(retcode) - return retcode; - - retcode = pop3_regular_transfer(conn, done); - - return retcode; -} - -/*********************************************************************** - * - * pop3_quit() - * - * This should be called before calling sclose(). We should then wait for the - * response from the server before returning. The calling code should then try - * to close the connection. - * - */ -static CURLcode pop3_quit(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "QUIT", NULL); + /* Parse the URL path */ + result = pop3_parse_url_path(conn); if(result) return result; - state(conn, POP3_QUIT); - result = pop3_easy_statemach(conn); + /* Parse the custom request */ + result = pop3_parse_custom_request(conn); + if(result) + return result; + + result = pop3_regular_transfer(conn, done); return result; } @@ -819,75 +1265,52 @@ static CURLcode pop3_quit(struct connectdata *conn) */ static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection) { - struct pop3_conn *pop3c= &conn->proto.pop3c; + struct pop3_conn *pop3c = &conn->proto.pop3c; /* We cannot send quit unconditionally. If this connection is stale or bad in any way, sending quit and waiting around here will make the - disconnect wait in vain and cause more problems than we need to. - */ + disconnect wait in vain and cause more problems than we need to. */ /* The POP3 session may or may not have been allocated/setup at this point! */ - if(!dead_connection && pop3c->pp.conn) - (void)pop3_quit(conn); /* ignore errors on the LOGOUT */ - + if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart) + if(!pop3_perform_quit(conn)) + (void)pop3_block_statemach(conn); /* ignore errors on QUIT */ + /* Disconnect from the server */ Curl_pp_disconnect(&pop3c->pp); - return CURLE_OK; -} + /* Cleanup the SASL module */ + Curl_sasl_cleanup(conn, pop3c->sasl.authused); -/*********************************************************************** - * - * pop3_parse_url_path() - * - * Parse the URL path into separate path components. - * - */ -static CURLcode pop3_parse_url_path(struct connectdata *conn) -{ - /* the pop3 struct is already inited in pop3_connect() */ - struct pop3_conn *pop3c = &conn->proto.pop3c; - struct SessionHandle *data = conn->data; - const char *path = data->state.path; - - /* url decode the path and use this mailbox */ - pop3c->mailbox = curl_easy_unescape(data, path, 0, NULL); - if (!pop3c->mailbox) - return CURLE_OUT_OF_MEMORY; + /* Cleanup our connection based variables */ + Curl_safefree(pop3c->apoptimestamp); return CURLE_OK; } -/* call this when the DO phase has completed */ -static CURLcode pop3_dophase_done(struct connectdata *conn, - bool connected) +/* Call this when the DO phase has completed */ +static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected) { - struct FTP *pop3 = conn->data->state.proto.pop3; - struct pop3_conn *pop3c = &conn->proto.pop3c; + (void)conn; (void)connected; - if(pop3->transfer != FTPTRANSFER_BODY) - /* no data to transfer */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - - free(pop3c->mailbox); - return CURLE_OK; } -/* called from multi.c while DOing */ -static CURLcode pop3_doing(struct connectdata *conn, - bool *dophase_done) +/* Called from multi.c while DOing */ +static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done) { - CURLcode result; - result = pop3_multi_statemach(conn, dophase_done); + CURLcode result = pop3_multi_statemach(conn, dophase_done); - if(*dophase_done) { + if(result) + DEBUGF(infof(conn->data, "DO phase failed\n")); + else if(*dophase_done) { result = pop3_dophase_done(conn, FALSE /* not connected */); DEBUGF(infof(conn->data, "DO phase is complete\n")); } + return result; } @@ -899,46 +1322,48 @@ static CURLcode pop3_doing(struct connectdata *conn, * * Performs all commands done before a regular transfer between a local and a * remote host. - * */ -static -CURLcode pop3_regular_transfer(struct connectdata *conn, - bool *dophase_done) +static CURLcode pop3_regular_transfer(struct connectdata *conn, + bool *dophase_done) { - CURLcode result=CURLE_OK; - bool connected=FALSE; + CURLcode result = CURLE_OK; + bool connected = FALSE; struct SessionHandle *data = conn->data; - data->req.size = -1; /* make sure this is unknown at this point */ + /* Make sure size is unknown at this point */ + data->req.size = -1; + + /* Set the progress data */ Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); - Curl_pgrsSetUploadSize(data, 0); - Curl_pgrsSetDownloadSize(data, 0); + Curl_pgrsSetUploadSize(data, -1); + Curl_pgrsSetDownloadSize(data, -1); - result = pop3_perform(conn, - &connected, /* have we connected after PASV/PORT */ - dophase_done); /* all commands in the DO-phase done? */ - - if(CURLE_OK == result) { - - if(!*dophase_done) - /* the DO phase has not completed yet */ - return CURLE_OK; + /* Carry out the perform */ + result = pop3_perform(conn, &connected, dophase_done); + /* Perform post DO phase operations if necessary */ + if(!result && *dophase_done) result = pop3_dophase_done(conn, connected); - if(result) - return result; - } return result; } -static CURLcode pop3_setup_connection(struct connectdata * conn) +static CURLcode pop3_setup_connection(struct connectdata *conn) { struct SessionHandle *data = conn->data; + /* Initialise the POP3 layer */ + CURLcode result = pop3_init(conn); + if(result) + return result; + + /* Clear the TLS upgraded flag */ + conn->tls_upgraded = FALSE; + + /* Set up the proxy if necessary */ if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { - /* Unless we have asked to tunnel pop3 operations through the proxy, we + /* Unless we have asked to tunnel POP3 operations through the proxy, we switch and use HTTP operations only */ #ifndef CURL_DISABLE_HTTP if(conn->handler == &Curl_handler_pop3) @@ -951,12 +1376,9 @@ static CURLcode pop3_setup_connection(struct connectdata * conn) return CURLE_UNSUPPORTED_PROTOCOL; #endif } - /* - * We explicitly mark this connection as persistent here as we're doing - * POP3 over HTTP and thus we accidentally avoid setting this value - * otherwise. - */ - conn->bits.close = FALSE; + + /* set it up as an HTTP connection instead */ + return conn->handler->setup_connection(conn); #else failf(data, "POP3 over http proxy requires HTTP support built-in!"); return CURLE_UNSUPPORTED_PROTOCOL; @@ -968,54 +1390,226 @@ static CURLcode pop3_setup_connection(struct connectdata * conn) return CURLE_OK; } -/* this is the 5-bytes End-Of-Body marker for POP3 */ -#define POP3_EOB "\x0d\x0a\x2e\x0d\x0a" -#define POP3_EOB_LEN 5 +/*********************************************************************** + * + * pop3_parse_url_options() + * + * Parse the URL login options. + */ +static CURLcode pop3_parse_url_options(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct pop3_conn *pop3c = &conn->proto.pop3c; + const char *ptr = conn->options; -/* + pop3c->sasl.resetprefs = TRUE; + + while(!result && ptr && *ptr) { + const char *key = ptr; + const char *value; + + while(*ptr && *ptr != '=') + ptr++; + + value = ptr + 1; + + while(*ptr && *ptr != ';') + ptr++; + + if(strnequal(key, "AUTH=", 5)) { + result = Curl_sasl_parse_url_auth_option(&pop3c->sasl, + value, ptr - value); + + if(result && strnequal(value, "+APOP", ptr - value)) { + pop3c->preftype = POP3_TYPE_APOP; + pop3c->sasl.prefmech = SASL_AUTH_NONE; + result = CURLE_OK; + } + } + else + result = CURLE_URL_MALFORMAT; + + if(*ptr == ';') + ptr++; + } + + if(pop3c->preftype != POP3_TYPE_APOP) + switch(pop3c->sasl.prefmech) { + case SASL_AUTH_NONE: + pop3c->preftype = POP3_TYPE_NONE; + break; + case SASL_AUTH_DEFAULT: + pop3c->preftype = POP3_TYPE_ANY; + break; + default: + pop3c->preftype = POP3_TYPE_SASL; + break; + } + + return result; +} + +/*********************************************************************** + * + * pop3_parse_url_path() + * + * Parse the URL path into separate path components. + */ +static CURLcode pop3_parse_url_path(struct connectdata *conn) +{ + /* The POP3 struct is already initialised in pop3_connect() */ + struct SessionHandle *data = conn->data; + struct POP3 *pop3 = data->req.protop; + const char *path = data->state.path; + + /* URL decode the path for the message ID */ + return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE); +} + +/*********************************************************************** + * + * pop3_parse_custom_request() + * + * Parse the custom request. + */ +static CURLcode pop3_parse_custom_request(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct POP3 *pop3 = data->req.protop; + const char *custom = data->set.str[STRING_CUSTOMREQUEST]; + + /* URL decode the custom request */ + if(custom) + result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE); + + return result; +} + +/*********************************************************************** + * + * Curl_pop3_write() + * * This function scans the body after the end-of-body and writes everything * until the end is found. */ -CURLcode Curl_pop3_write(struct connectdata *conn, - char *str, - size_t nread) +CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread) { - /* This code could be made into a special function in the handler struct. */ - CURLcode result; + /* This code could be made into a special function in the handler struct */ + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; struct SingleRequest *k = &data->req; - /* Detect the end-of-body marker, which is 5 bytes: - 0d 0a 2e 0d 0a. This marker can of course be spread out - over up to 5 different data chunks. Deal with it! */ struct pop3_conn *pop3c = &conn->proto.pop3c; - size_t checkmax = (nread >= POP3_EOB_LEN?POP3_EOB_LEN:nread); - size_t checkleft = POP3_EOB_LEN-pop3c->eob; - size_t check = (checkmax >= checkleft?checkleft:checkmax); + bool strip_dot = FALSE; + size_t last = 0; + size_t i; - if(!memcmp(POP3_EOB, &str[nread - check], check)) { - /* substring match */ - pop3c->eob += check; - if(pop3c->eob == POP3_EOB_LEN) { - /* full match, the transfer is done! */ - str[nread - check] = '\0'; - nread -= check; - k->keepon &= ~KEEP_RECV; + /* Search through the buffer looking for the end-of-body marker which is + 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches + the eob so the server will have prefixed it with an extra dot which we + need to strip out. Additionally the marker could of course be spread out + over 5 different data chunks. */ + for(i = 0; i < nread; i++) { + size_t prev = pop3c->eob; + + switch(str[i]) { + case 0x0d: + if(pop3c->eob == 0) { + pop3c->eob++; + + if(i) { + /* Write out the body part that didn't match */ + result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last], + i - last); + + if(result) + return result; + + last = i; + } + } + else if(pop3c->eob == 3) + pop3c->eob++; + else + /* If the character match wasn't at position 0 or 3 then restart the + pattern matching */ + pop3c->eob = 1; + break; + + case 0x0a: + if(pop3c->eob == 1 || pop3c->eob == 4) + pop3c->eob++; + else + /* If the character match wasn't at position 1 or 4 then start the + search again */ + pop3c->eob = 0; + break; + + case 0x2e: + if(pop3c->eob == 2) + pop3c->eob++; + else if(pop3c->eob == 3) { + /* We have an extra dot after the CRLF which we need to strip off */ + strip_dot = TRUE; + pop3c->eob = 0; + } + else + /* If the character match wasn't at position 2 then start the search + again */ + pop3c->eob = 0; + break; + + default: pop3c->eob = 0; + break; + } + + /* Did we have a partial match which has subsequently failed? */ + if(prev && prev >= pop3c->eob) { + /* Strip can only be non-zero for the very first mismatch after CRLF + and then both prev and strip are equal and nothing will be output + below */ + while(prev && pop3c->strip) { + prev--; + pop3c->strip--; + } + + if(prev) { + /* If the partial match was the CRLF and dot then only write the CRLF + as the server would have inserted the dot */ + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB, + strip_dot ? prev - 1 : prev); + + if(result) + return result; + + last = i; + strip_dot = FALSE; + } } } - else if(pop3c->eob) { - /* not a match, but we matched a piece before so we must now - send that part as body first, before we move on and send - this buffer */ - result = Curl_client_write(conn, CLIENTWRITE_BODY, - (char *)POP3_EOB, pop3c->eob); - if(result) - return result; + + if(pop3c->eob == POP3_EOB_LEN) { + /* We have a full match so the transfer is done, however we must transfer + the CRLF at the start of the EOB as this is considered to be part of the + message as per RFC-1939, sect. 3 */ + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2); + + k->keepon &= ~KEEP_RECV; pop3c->eob = 0; + + return result; } - result = Curl_client_write(conn, CLIENTWRITE_BODY, str, nread); + if(pop3c->eob) + /* While EOB is matching nothing should be output */ + return CURLE_OK; + + if(nread - last) { + result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last], + nread - last); + } return result; } diff --git a/project/jni/curl/lib/pop3.h b/project/jni/curl/lib/pop3.h index 337421cac..2d9610168 100644 --- a/project/jni/curl/lib/pop3.h +++ b/project/jni/curl/lib/pop3.h @@ -1,5 +1,5 @@ -#ifndef __POP3_H -#define __POP3_H +#ifndef HEADER_CURL_POP3_H +#define HEADER_CURL_POP3_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2009, Daniel Stenberg, , et al. + * Copyright (C) 2009 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,41 +22,74 @@ * ***************************************************************************/ +#include "pingpong.h" +#include "curl_sasl.h" + /**************************************************************************** * POP3 unique setup ***************************************************************************/ typedef enum { - POP3_STOP, /* do nothing state, stops the state machine */ - POP3_SERVERGREET, /* waiting for the initial greeting immediately after - a connect */ + POP3_STOP, /* do nothing state, stops the state machine */ + POP3_SERVERGREET, /* waiting for the initial greeting immediately after + a connect */ + POP3_CAPA, + POP3_STARTTLS, + POP3_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS + (multi mode only) */ + POP3_AUTH, + POP3_APOP, POP3_USER, POP3_PASS, - POP3_STARTTLS, - POP3_LIST, - POP3_RETR, + POP3_COMMAND, POP3_QUIT, - POP3_LAST /* never used */ + POP3_LAST /* never used */ } pop3state; +/* This POP3 struct is used in the SessionHandle. All POP3 data that is + connection-oriented must be in pop3_conn to properly deal with the fact that + perhaps the SessionHandle is changed between the times the connection is + used. */ +struct POP3 { + curl_pp_transfer transfer; + char *id; /* Message ID */ + char *custom; /* Custom Request */ +}; + /* pop3_conn is used for struct connection-oriented data in the connectdata struct */ struct pop3_conn { struct pingpong pp; - char *mailbox; /* what to RETR */ - size_t eob; /* number of bytes of the EOB (End Of Body) that has been - received thus far */ - pop3state state; /* always use pop3.c:state() to change state! */ + pop3state state; /* Always use pop3.c:state() to change state! */ + bool ssldone; /* Is connect() over SSL done? */ + size_t eob; /* Number of bytes of the EOB (End Of Body) that + have been received so far */ + size_t strip; /* Number of bytes from the start to ignore as + non-body */ + struct SASL sasl; /* SASL-related storage */ + unsigned int authtypes; /* Accepted authentication types */ + unsigned int preftype; /* Preferred authentication type */ + char *apoptimestamp; /* APOP timestamp from the server greeting */ + bool tls_supported; /* StartTLS capability supported by server */ }; extern const struct Curl_handler Curl_handler_pop3; extern const struct Curl_handler Curl_handler_pop3s; -/* - * This function scans the body after the end-of-body and writes everything - * until the end is found. - */ -CURLcode Curl_pop3_write(struct connectdata *conn, - char *str, - size_t nread); +/* Authentication type flags */ +#define POP3_TYPE_CLEARTEXT (1 << 0) +#define POP3_TYPE_APOP (1 << 1) +#define POP3_TYPE_SASL (1 << 2) -#endif /* __POP3_H */ +/* Authentication type values */ +#define POP3_TYPE_NONE 0 +#define POP3_TYPE_ANY ~0U + +/* This is the 5-bytes End-Of-Body marker for POP3 */ +#define POP3_EOB "\x0d\x0a\x2e\x0d\x0a" +#define POP3_EOB_LEN 5 + +/* This function scans the body after the end-of-body and writes everything + * until the end is found */ +CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread); + +#endif /* HEADER_CURL_POP3_H */ diff --git a/project/jni/curl/lib/progress.c b/project/jni/curl/lib/progress.c index e0758f2a8..713ab0852 100644 --- a/project/jni/curl/lib/progress.c +++ b/project/jni/curl/lib/progress.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,14 +20,12 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #include "urldata.h" #include "sendf.h" #include "progress.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include +#include "curl_printf.h" /* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero byte) */ @@ -42,8 +40,8 @@ static void time2str(char *r, curl_off_t seconds) if(h <= CURL_OFF_T_C(99)) { m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60); s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60)); - snprintf(r, 9, "%2" FORMAT_OFF_T ":%02" FORMAT_OFF_T ":%02" FORMAT_OFF_T, - h, m, s); + snprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T + ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s); } else { /* this equals to more than 99 hours, switch to a more suitable output @@ -51,9 +49,10 @@ static void time2str(char *r, curl_off_t seconds) d = seconds / CURL_OFF_T_C(86400); h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600); if(d <= CURL_OFF_T_C(999)) - snprintf(r, 9, "%3" FORMAT_OFF_T "d %02" FORMAT_OFF_T "h", d, h); + snprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T + "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h); else - snprintf(r, 9, "%7" FORMAT_OFF_T "d", d); + snprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d); } } @@ -69,40 +68,40 @@ static char *max5data(curl_off_t bytes, char *max5) #define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE) if(bytes < CURL_OFF_T_C(100000)) - snprintf(max5, 6, "%5" FORMAT_OFF_T, bytes); + snprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes); else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE) - snprintf(max5, 6, "%4" FORMAT_OFF_T "k", bytes/ONE_KILOBYTE); + snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE); else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE) /* 'XX.XM' is good as long as we're less than 100 megs */ - snprintf(max5, 6, "%2" FORMAT_OFF_T ".%0" FORMAT_OFF_T "M", - bytes/ONE_MEGABYTE, + snprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" + CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE, (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) ); #if (CURL_SIZEOF_CURL_OFF_T > 4) else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE) /* 'XXXXM' is good until we're at 10000MB or above */ - snprintf(max5, 6, "%4" FORMAT_OFF_T "M", bytes/ONE_MEGABYTE); + snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE) /* 10000 MB - 100 GB, we show it as XX.XG */ - snprintf(max5, 6, "%2" FORMAT_OFF_T ".%0" FORMAT_OFF_T "G", - bytes/ONE_GIGABYTE, + snprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" + CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE, (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) ); else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE) /* up to 10000GB, display without decimal: XXXXG */ - snprintf(max5, 6, "%4" FORMAT_OFF_T "G", bytes/ONE_GIGABYTE); + snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE); else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE) /* up to 10000TB, display without decimal: XXXXT */ - snprintf(max5, 6, "%4" FORMAT_OFF_T "T", bytes/ONE_TERABYTE); + snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE); else /* up to 10000PB, display without decimal: XXXXP */ - snprintf(max5, 6, "%4" FORMAT_OFF_T "P", bytes/ONE_PETABYTE); + snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE); /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number can hold, but our data type is signed so 8192PB will be the maximum. */ @@ -110,7 +109,7 @@ static char *max5data(curl_off_t bytes, char *max5) #else else - snprintf(max5, 6, "%4" FORMAT_OFF_T "M", bytes/ONE_MEGABYTE); + snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); #endif @@ -131,62 +130,84 @@ static char *max5data(curl_off_t bytes, char *max5) */ -void Curl_pgrsDone(struct connectdata *conn) +int Curl_pgrsDone(struct connectdata *conn) { + int rc; struct SessionHandle *data = conn->data; data->progress.lastshow=0; - Curl_pgrsUpdate(conn); /* the final (forced) update */ + rc = Curl_pgrsUpdate(conn); /* the final (forced) update */ + if(rc) + return rc; + + if(!(data->progress.flags & PGRS_HIDE) && + !data->progress.callback) + /* only output if we don't use a progress callback and we're not + * hidden */ + fprintf(data->set.err, "\n"); data->progress.speeder_c = 0; /* reset the progress meter display */ + return 0; } -/* reset all times except redirect */ -void Curl_pgrsResetTimes(struct SessionHandle *data) +/* reset all times except redirect, and reset the known transfer sizes */ +void Curl_pgrsResetTimesSizes(struct SessionHandle *data) { data->progress.t_nslookup = 0.0; data->progress.t_connect = 0.0; data->progress.t_pretransfer = 0.0; data->progress.t_starttransfer = 0.0; + + Curl_pgrsSetDownloadSize(data, -1); + Curl_pgrsSetUploadSize(data, -1); } void Curl_pgrsTime(struct SessionHandle *data, timerid timer) { + struct timeval now = Curl_tvnow(); + switch(timer) { default: case TIMER_NONE: /* mistake filter */ break; + case TIMER_STARTOP: + /* This is set at the start of a transfer */ + data->progress.t_startop = now; + break; case TIMER_STARTSINGLE: - /* This is set at the start of a single fetch */ - data->progress.t_startsingle = Curl_tvnow(); + /* This is set at the start of each single fetch */ + data->progress.t_startsingle = now; + break; + + case TIMER_STARTACCEPT: + data->progress.t_acceptdata = Curl_tvnow(); break; case TIMER_NAMELOOKUP: data->progress.t_nslookup = - Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle); + Curl_tvdiff_secs(now, data->progress.t_startsingle); break; case TIMER_CONNECT: data->progress.t_connect = - Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle); + Curl_tvdiff_secs(now, data->progress.t_startsingle); break; case TIMER_APPCONNECT: data->progress.t_appconnect = - Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle); + Curl_tvdiff_secs(now, data->progress.t_startsingle); break; case TIMER_PRETRANSFER: data->progress.t_pretransfer = - Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle); + Curl_tvdiff_secs(now, data->progress.t_startsingle); break; case TIMER_STARTTRANSFER: data->progress.t_starttransfer = - Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle); + Curl_tvdiff_secs(now, data->progress.t_startsingle); break; case TIMER_POSTRANSFER: /* this is the normal end-of-transfer thing */ break; case TIMER_REDIRECT: - data->progress.t_redirect = - Curl_tvdiff_secs(Curl_tvnow(), data->progress.start); + data->progress.t_redirect = Curl_tvdiff_secs(now, data->progress.start); break; } } @@ -195,6 +216,8 @@ void Curl_pgrsStartNow(struct SessionHandle *data) { data->progress.speeder_c = 0; /* reset the progress meter display */ data->progress.start = Curl_tvnow(); + /* clear all bits except HIDE and HEADERS_OUT */ + data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT; } void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size) @@ -209,22 +232,32 @@ void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size) void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size) { - data->progress.size_dl = size; - if(size >= 0) + if(size >= 0) { + data->progress.size_dl = size; data->progress.flags |= PGRS_DL_SIZE_KNOWN; - else + } + else { + data->progress.size_dl = 0; data->progress.flags &= ~PGRS_DL_SIZE_KNOWN; + } } void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size) { - data->progress.size_ul = size; - if(size >= 0) + if(size >= 0) { + data->progress.size_ul = size; data->progress.flags |= PGRS_UL_SIZE_KNOWN; - else + } + else { + data->progress.size_ul = 0; data->progress.flags &= ~PGRS_UL_SIZE_KNOWN; + } } +/* + * Curl_pgrsUpdate() returns 0 for success or the value returned by the + * progress callback! + */ int Curl_pgrsUpdate(struct connectdata *conn) { struct timeval now; @@ -333,12 +366,21 @@ int Curl_pgrsUpdate(struct connectdata *conn) } /* Calculations end */ if(!(data->progress.flags & PGRS_HIDE)) { - /* progress meter has not been shut off */ - if(data->set.fprogress) { - /* There's a callback set, so we call that instead of writing - anything ourselves. This really is the way to go. */ + if(data->set.fxferinfo) { + /* There's a callback set, call that */ + result= data->set.fxferinfo(data->set.progress_client, + data->progress.size_dl, + data->progress.downloaded, + data->progress.size_ul, + data->progress.uploaded); + if(result) + failf(data, "Callback aborted"); + return result; + } + else if(data->set.fprogress) { + /* The older deprecated callback is set, call that */ result= data->set.fprogress(data->set.progress_client, (double)data->progress.size_dl, (double)data->progress.downloaded, @@ -359,12 +401,14 @@ int Curl_pgrsUpdate(struct connectdata *conn) if(!(data->progress.flags & PGRS_HEADERS_OUT)) { if(data->state.resume_from) { fprintf(data->set.err, - "** Resuming transfer from byte position %" FORMAT_OFF_T "\n", - data->state.resume_from); + "** Resuming transfer from byte position %" + CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from); } fprintf(data->set.err, - " %% Total %% Received %% Xferd Average Speed Time Time Time Current\n" - " Dload Upload Total Spent Left Speed\n"); + " %% Total %% Received %% Xferd Average Speed " + "Time Time Time Current\n" + " Dload Upload " + "Total Spent Left Speed\n"); data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */ } @@ -403,17 +447,17 @@ int Curl_pgrsUpdate(struct connectdata *conn) time2str(time_total, total_estimate); time2str(time_spent, timespent); - /* Get the total amount of data expected to get transfered */ + /* Get the total amount of data expected to get transferred */ total_expected_transfer = (data->progress.flags & PGRS_UL_SIZE_KNOWN? data->progress.size_ul:data->progress.uploaded)+ (data->progress.flags & PGRS_DL_SIZE_KNOWN? data->progress.size_dl:data->progress.downloaded); - /* We have transfered this much so far */ + /* We have transferred this much so far */ total_transfer = data->progress.downloaded + data->progress.uploaded; - /* Get the percentage of data transfered so far */ + /* Get the percentage of data transferred so far */ if(total_expected_transfer > CURL_OFF_T_C(10000)) total_percen = total_transfer / (total_expected_transfer/CURL_OFF_T_C(100)); @@ -422,9 +466,9 @@ int Curl_pgrsUpdate(struct connectdata *conn) fprintf(data->set.err, "\r" - "%3" FORMAT_OFF_T " %s " - "%3" FORMAT_OFF_T " %s " - "%3" FORMAT_OFF_T " %s %s %s %s %s %s %s", + "%3" CURL_FORMAT_CURL_OFF_T " %s " + "%3" CURL_FORMAT_CURL_OFF_T " %s " + "%3" CURL_FORMAT_CURL_OFF_T " %s %s %s %s %s %s %s", total_percen, /* 3 letters */ /* total % */ max5data(total_expected_transfer, max5[2]), /* total size */ dlpercen, /* 3 letters */ /* rcvd % */ diff --git a/project/jni/curl/lib/progress.h b/project/jni/curl/lib/progress.h index 95944f0ba..ea00afa91 100644 --- a/project/jni/curl/lib/progress.h +++ b/project/jni/curl/lib/progress.h @@ -1,5 +1,5 @@ -#ifndef __PROGRESS_H -#define __PROGRESS_H +#ifndef HEADER_CURL_PROGRESS_H +#define HEADER_CURL_PROGRESS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -27,25 +27,27 @@ typedef enum { TIMER_NONE, + TIMER_STARTOP, + TIMER_STARTSINGLE, TIMER_NAMELOOKUP, TIMER_CONNECT, TIMER_APPCONNECT, TIMER_PRETRANSFER, TIMER_STARTTRANSFER, TIMER_POSTRANSFER, - TIMER_STARTSINGLE, + TIMER_STARTACCEPT, TIMER_REDIRECT, TIMER_LAST /* must be last */ } timerid; -void Curl_pgrsDone(struct connectdata *); +int Curl_pgrsDone(struct connectdata *); void Curl_pgrsStartNow(struct SessionHandle *data); void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size); void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size); void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size); void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size); int Curl_pgrsUpdate(struct connectdata *); -void Curl_pgrsResetTimes(struct SessionHandle *data); +void Curl_pgrsResetTimesSizes(struct SessionHandle *data); void Curl_pgrsTime(struct SessionHandle *data, timerid timer); @@ -67,4 +69,5 @@ void Curl_pgrsTime(struct SessionHandle *data, timerid timer); #define PGRS_HEADERS_OUT (1<<7) /* set when the headers have been written */ -#endif /* __PROGRESS_H */ +#endif /* HEADER_CURL_PROGRESS_H */ + diff --git a/project/jni/curl/lib/qssl.c b/project/jni/curl/lib/qssl.c deleted file mode 100644 index dd4f911d1..000000000 --- a/project/jni/curl/lib/qssl.c +++ /dev/null @@ -1,501 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "setup.h" - -#ifdef USE_QSOSSL -#include -#include -#include -#ifdef HAVE_LIMITS_H -# include -#endif - -#include -#include "urldata.h" -#include "sendf.h" -#include "qssl.h" -#include "sslgen.h" -#include "connect.h" /* for the connect timeout */ -#include "select.h" -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - - -int Curl_qsossl_init(void) - -{ - /* Nothing to do here. We must have connection data to initialize ssl, so - * defer. - */ - - return 1; -} - - -void Curl_qsossl_cleanup(void) - -{ - /* Nothing to do. */ -} - - -static CURLcode Curl_qsossl_init_session(struct SessionHandle * data) - -{ - int rc; - char * certname; - SSLInit initstr; - SSLInitApp initappstr; - - /* Initialize the job for SSL according to the current parameters. - * QsoSSL offers two ways to do it: SSL_Init_Application() that uses an - * application identifier to select certificates in the main certificate - * store, and SSL_Init() that uses named keyring files and a password. - * It is not possible to have different keyrings for the CAs and the - * local certificate. We thus use the certificate name to identify the - * keyring if given, else the CA file name. - * If the key file name is given, it is taken as the password for the - * keyring in certificate file. - * We first try to SSL_Init_Application(), then SSL_Init() if it failed. - */ - - certname = data->set.str[STRING_CERT]; - - if(!certname) { - certname = data->set.str[STRING_SSL_CAFILE]; - - if(!certname) - return CURLE_OK; /* Use previous setup. */ - } - - memset((char *) &initappstr, 0, sizeof initappstr); - initappstr.applicationID = certname; - initappstr.applicationIDLen = strlen(certname); - initappstr.protocol = SSL_VERSION_CURRENT; /* TLSV1 compat. SSLV[23]. */ - initappstr.sessionType = SSL_REGISTERED_AS_CLIENT; - rc = SSL_Init_Application(&initappstr); - - if(rc == SSL_ERROR_NOT_REGISTERED) { - initstr.keyringFileName = certname; - initstr.keyringPassword = data->set.str[STRING_KEY]; - initstr.cipherSuiteList = NULL; /* Use default. */ - initstr.cipherSuiteListLen = 0; - rc = SSL_Init(&initstr); - } - - switch (rc) { - - case 0: /* No error. */ - break; - - case SSL_ERROR_IO: - failf(data, "SSL_Init() I/O error: %s", strerror(errno)); - return CURLE_SSL_CONNECT_ERROR; - - case SSL_ERROR_BAD_CIPHER_SUITE: - return CURLE_SSL_CIPHER; - - case SSL_ERROR_KEYPASSWORD_EXPIRED: - case SSL_ERROR_NOT_REGISTERED: - return CURLE_SSL_CONNECT_ERROR; - - case SSL_ERROR_NO_KEYRING: - return CURLE_SSL_CACERT; - - case SSL_ERROR_CERT_EXPIRED: - return CURLE_SSL_CERTPROBLEM; - - default: - failf(data, "SSL_Init(): %s", SSL_Strerror(rc, NULL)); - return CURLE_SSL_CONNECT_ERROR; - } - - return CURLE_OK; -} - - -static CURLcode Curl_qsossl_create(struct connectdata * conn, int sockindex) - -{ - SSLHandle * h; - struct ssl_connect_data * connssl = &conn->ssl[sockindex]; - - h = SSL_Create(conn->sock[sockindex], SSL_ENCRYPT); - - if(!h) { - failf(conn->data, "SSL_Create() I/O error: %s", strerror(errno)); - return CURLE_SSL_CONNECT_ERROR; - } - - connssl->handle = h; - return CURLE_OK; -} - - -static int Curl_qsossl_trap_cert(SSLHandle * h) - -{ - return 1; /* Accept certificate. */ -} - - -static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex) - -{ - int rc; - struct SessionHandle * data = conn->data; - struct ssl_connect_data * connssl = &conn->ssl[sockindex]; - SSLHandle * h = connssl->handle; - long timeout_ms; - - h->exitPgm = NULL; - - if(!data->set.ssl.verifyhost) - h->exitPgm = Curl_qsossl_trap_cert; - - /* figure out how long time we should wait at maximum */ - timeout_ms = Curl_timeleft(conn, NULL, TRUE); - - if(timeout_ms < 0) { - /* time-out, bail out, go home */ - failf(data, "Connection time-out"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* SSL_Handshake() timeout resolution is second, so round up. */ - h->timeout = (timeout_ms + 1000 - 1) / 1000; - - /* Set-up protocol. */ - - switch (data->set.ssl.version) { - - default: - case CURL_SSLVERSION_DEFAULT: - h->protocol = SSL_VERSION_CURRENT; /* TLSV1 compat. SSLV[23]. */ - break; - - case CURL_SSLVERSION_TLSv1: - h->protocol = TLS_VERSION_1; - break; - - case CURL_SSLVERSION_SSLv2: - h->protocol = SSL_VERSION_2; - break; - - case CURL_SSLVERSION_SSLv3: - h->protocol = SSL_VERSION_3; - break; - } - - rc = SSL_Handshake(h, SSL_HANDSHAKE_AS_CLIENT); - - switch (rc) { - - case 0: /* No error. */ - break; - - case SSL_ERROR_BAD_CERTIFICATE: - case SSL_ERROR_BAD_CERT_SIG: - case SSL_ERROR_NOT_TRUSTED_ROOT: - return CURLE_PEER_FAILED_VERIFICATION; - - case SSL_ERROR_BAD_CIPHER_SUITE: - case SSL_ERROR_NO_CIPHERS: - return CURLE_SSL_CIPHER; - - case SSL_ERROR_CERTIFICATE_REJECTED: - case SSL_ERROR_CERT_EXPIRED: - case SSL_ERROR_NO_CERTIFICATE: - return CURLE_SSL_CERTPROBLEM; - - case SSL_ERROR_IO: - failf(data, "SSL_Handshake() I/O error: %s", strerror(errno)); - return CURLE_SSL_CONNECT_ERROR; - - default: - failf(data, "SSL_Handshake(): %s", SSL_Strerror(rc, NULL)); - return CURLE_SSL_CONNECT_ERROR; - } - - return CURLE_OK; -} - - -static Curl_recv qsossl_recv; -static Curl_send qsossl_send; - -CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex) - -{ - struct SessionHandle * data = conn->data; - struct ssl_connect_data * connssl = &conn->ssl[sockindex]; - int rc; - - rc = Curl_qsossl_init_session(data); - - if(rc == CURLE_OK) { - rc = Curl_qsossl_create(conn, sockindex); - - if(rc == CURLE_OK) - rc = Curl_qsossl_handshake(conn, sockindex); - else { - SSL_Destroy(connssl->handle); - connssl->handle = NULL; - connssl->use = FALSE; - connssl->state = ssl_connection_none; - } - } - if (rc == CURLE_OK) { - connssl->state = ssl_connection_complete; - conn->recv[sockindex] = qsossl_recv; - conn->send[sockindex] = qsossl_send; - } - - return rc; -} - - -static int Curl_qsossl_close_one(struct ssl_connect_data * conn, - struct SessionHandle * data) - -{ - int rc; - - if(!conn->handle) - return 0; - - rc = SSL_Destroy(conn->handle); - - if(rc) { - if(rc == SSL_ERROR_IO) { - failf(data, "SSL_Destroy() I/O error: %s", strerror(errno)); - return -1; - } - - /* An SSL error. */ - failf(data, "SSL_Destroy() returned error %s", SSL_Strerror(rc, NULL)); - return -1; - } - - conn->handle = NULL; - return 0; -} - - -void Curl_qsossl_close(struct connectdata *conn, int sockindex) - -{ - struct SessionHandle *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - if(connssl->use) - (void) Curl_qsossl_close_one(connssl, data); -} - - -int Curl_qsossl_close_all(struct SessionHandle * data) - -{ - /* Unimplemented. */ - (void) data; - return 0; -} - - -int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex) - -{ - struct ssl_connect_data * connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; - ssize_t nread; - int what; - int rc; - char buf[120]; - - if(!connssl->handle) - return 0; - - if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) - return 0; - - if(Curl_qsossl_close_one(connssl, data)) - return -1; - - rc = 0; - - what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); - - for (;;) { - if(what < 0) { - /* anything that gets here is fatally bad */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - rc = -1; - break; - } - - if(!what) { /* timeout */ - failf(data, "SSL shutdown timeout"); - break; - } - - /* Something to read, let's do it and hope that it is the close - notify alert from the server. No way to SSL_Read now, so use read(). */ - - nread = read(conn->sock[sockindex], buf, sizeof(buf)); - - if(nread < 0) { - failf(data, "read: %s", strerror(errno)); - rc = -1; - } - - if(nread <= 0) - break; - - what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0); - } - - return rc; -} - - -static ssize_t qsossl_send(struct connectdata * conn, int sockindex, - const void * mem, size_t len, CURLcode * curlcode) - -{ - /* SSL_Write() is said to return 'int' while write() and send() returns - 'size_t' */ - int rc; - - rc = SSL_Write(conn->ssl[sockindex].handle, (void *) mem, (int) len); - - if(rc < 0) { - switch(rc) { - - case SSL_ERROR_BAD_STATE: - /* The operation did not complete; the same SSL I/O function - should be called again later. This is basicly an EWOULDBLOCK - equivalent. */ - *curlcode = CURLE_AGAIN; - return -1; - - case SSL_ERROR_IO: - switch (errno) { - case EWOULDBLOCK: - case EINTR: - *curlcode = CURLE_AGAIN; - return -1; - } - - failf(conn->data, "SSL_Write() I/O error: %s", strerror(errno)); - *curlcode = CURLE_SEND_ERROR; - return -1; - } - - /* An SSL error. */ - failf(conn->data, "SSL_Write() returned error %s", - SSL_Strerror(rc, NULL)); - *curlcode = CURLE_SEND_ERROR; - return -1; - } - - return (ssize_t) rc; /* number of bytes */ -} - - -static ssize_t qsossl_recv(struct connectdata * conn, int num, char * buf, - size_t buffersize, CURLcode * curlcode) - -{ - char error_buffer[120]; /* OpenSSL documents that this must be at - least 120 bytes long. */ - unsigned long sslerror; - int buffsize; - int nread; - - buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - nread = SSL_Read(conn->ssl[num].handle, buf, buffsize); - - if(nread < 0) { - /* failed SSL_read */ - - switch (nread) { - - case SSL_ERROR_BAD_STATE: - /* there's data pending, re-invoke SSL_Read(). */ - *curlcode = CURLE_AGAIN; - return -1; - - case SSL_ERROR_IO: - switch (errno) { - case EWOULDBLOCK: - *curlcode = CURLE_AGAIN; - return -1; - } - - failf(conn->data, "SSL_Read() I/O error: %s", strerror(errno)); - *curlcode = CURLE_RECV_ERROR; - return -1; - - default: - failf(conn->data, "SSL read error: %s", SSL_Strerror(nread, NULL)); - *curlcode = CURLE_RECV_ERROR; - return -1; - } - } - return (ssize_t) nread; -} - - -size_t Curl_qsossl_version(char * buffer, size_t size) - -{ - strncpy(buffer, "IBM OS/400 SSL", size); - return strlen(buffer); -} - - -int Curl_qsossl_check_cxn(struct connectdata * cxn) - -{ - int err; - int errlen; - - /* The only thing that can be tested here is at the socket level. */ - - if(!cxn->ssl[FIRSTSOCKET].handle) - return 0; /* connection has been closed */ - - err = 0; - errlen = sizeof err; - - if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR, - (unsigned char *) &err, &errlen) || - errlen != sizeof err || err) - return 0; /* connection has been closed */ - - return -1; /* connection status unknown */ -} - -#endif /* USE_QSOSSL */ diff --git a/project/jni/curl/lib/qssl.h b/project/jni/curl/lib/qssl.h deleted file mode 100644 index 45190e623..000000000 --- a/project/jni/curl/lib/qssl.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef __QSSL_H -#define __QSSL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* - * This header should only be needed to get included by sslgen.c and qssl.c - */ - -#include "urldata.h" - -#ifdef USE_QSOSSL -int Curl_qsossl_init(void); -void Curl_qsossl_cleanup(void); -CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex); -void Curl_qsossl_close(struct connectdata *conn, int sockindex); -int Curl_qsossl_close_all(struct SessionHandle * data); -int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex); - -size_t Curl_qsossl_version(char * buffer, size_t size); -int Curl_qsossl_check_cxn(struct connectdata * cxn); - -/* API setup for QsoSSL */ -#define curlssl_init Curl_qsossl_init -#define curlssl_cleanup Curl_qsossl_cleanup -#define curlssl_connect Curl_qsossl_connect - -/* No session handling for QsoSSL */ -#define curlssl_session_free(x) -#define curlssl_close_all Curl_qsossl_close_all -#define curlssl_close Curl_qsossl_close -#define curlssl_shutdown(x,y) Curl_qsossl_shutdown(x,y) -#define curlssl_set_engine(x,y) CURLE_FAILED_INIT -#define curlssl_set_engine_default(x) CURLE_FAILED_INIT -#define curlssl_engines_list(x) NULL -#define curlssl_version Curl_qsossl_version -#define curlssl_check_cxn(x) Curl_qsossl_check_cxn(x) -#define curlssl_data_pending(x,y) 0 -#endif /* USE_QSOSSL */ -#endif diff --git a/project/jni/curl/lib/rawstr.c b/project/jni/curl/lib/rawstr.c index f3b302dc1..5665ebd36 100644 --- a/project/jni/curl/lib/rawstr.c +++ b/project/jni/curl/lib/rawstr.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,7 +20,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #include "rawstr.h" @@ -28,6 +28,10 @@ its behavior is altered by the current locale. */ char Curl_raw_toupper(char in) { +#if !defined(CURL_DOES_CONVERSIONS) + if(in >= 'a' && in <= 'z') + return (char)('A' + in - 'a'); +#else switch (in) { case 'a': return 'A'; @@ -82,13 +86,15 @@ char Curl_raw_toupper(char in) case 'z': return 'Z'; } +#endif + return in; } /* * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant * to be locale independent and only compare strings we know are safe for - * this. See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for + * this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for * some further explanation to why this function is necessary. * * The function is capable of comparing a-z case insensitively even for @@ -133,10 +139,10 @@ int Curl_raw_nequal(const char *first, const char *second, size_t max) */ void Curl_strntoupper(char *dest, const char *src, size_t n) { - if (n < 1) + if(n < 1) return; do { *dest++ = Curl_raw_toupper(*src); - } while (*src++ && --n); + } while(*src++ && --n); } diff --git a/project/jni/curl/lib/rawstr.h b/project/jni/curl/lib/rawstr.h index 7e9747a79..4af00f14a 100644 --- a/project/jni/curl/lib/rawstr.h +++ b/project/jni/curl/lib/rawstr.h @@ -1,5 +1,5 @@ -#ifndef __RAWSTR_H -#define __RAWSTR_H +#ifndef HEADER_CURL_RAWSTR_H +#define HEADER_CURL_RAWSTR_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -29,7 +29,8 @@ * to be locale independent and only compare strings we know are safe for * this. * - * The function is capable of comparing a-z case insensitively even for non-ascii. + * The function is capable of comparing a-z case insensitively even for + * non-ascii. */ int Curl_raw_equal(const char *first, const char *second); int Curl_raw_nequal(const char *first, const char *second, size_t max); @@ -40,5 +41,7 @@ char Curl_raw_toupper(char in); argument is zero-byte terminated */ #define checkprefix(a,b) Curl_raw_nequal(a,b,strlen(a)) -#endif void Curl_strntoupper(char *dest, const char *src, size_t n); + +#endif /* HEADER_CURL_RAWSTR_H */ + diff --git a/project/jni/curl/lib/rtsp.c b/project/jni/curl/lib/rtsp.c index 066e10fe3..24bf801d9 100644 --- a/project/jni/curl/lib/rtsp.c +++ b/project/jni/curl/lib/rtsp.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,7 +20,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_RTSP @@ -28,19 +28,18 @@ #include #include "transfer.h" #include "sendf.h" -#include "easyif.h" /* for Curl_convert_... prototypes */ #include "multiif.h" #include "http.h" #include "url.h" #include "progress.h" #include "rtsp.h" #include "rawstr.h" +#include "select.h" +#include "connect.h" +#include "curl_printf.h" + +/* The last #include files should be: */ #include "curl_memory.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ #include "memdebug.h" /* @@ -58,10 +57,31 @@ #define RTP_PKT_LENGTH(p) ((((int)((unsigned char)((p)[2]))) << 8) | \ ((int)((unsigned char)((p)[3])))) +/* protocol-specific functions set up to be called by the main engine */ +static CURLcode rtsp_do(struct connectdata *conn, bool *done); +static CURLcode rtsp_done(struct connectdata *conn, CURLcode, bool premature); +static CURLcode rtsp_connect(struct connectdata *conn, bool *done); +static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead); + static int rtsp_getsock_do(struct connectdata *conn, curl_socket_t *socks, int numsocks); +/* + * Parse and write out any available RTP data. + * + * nread: amount of data left after k->str. will be modified if RTP + * data is parsed and k->str is moved up + * readmore: whether or not the RTP parser needs more data right away + */ +static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data, + struct connectdata *conn, + ssize_t *nread, + bool *readmore); + +static CURLcode rtsp_setup_connection(struct connectdata *conn); + + /* this returns the socket to wait for in the DO and DOING state for the multi interface and then we're always _sending_ a request and thus we wait for the single socket to become writable only */ @@ -84,22 +104,71 @@ CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len); */ const struct Curl_handler Curl_handler_rtsp = { "RTSP", /* scheme */ - ZERO_NULL, /* setup_connection */ - Curl_rtsp, /* do_it */ - Curl_rtsp_done, /* done */ + rtsp_setup_connection, /* setup_connection */ + rtsp_do, /* do_it */ + rtsp_done, /* done */ ZERO_NULL, /* do_more */ - Curl_rtsp_connect, /* connect_it */ + rtsp_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ rtsp_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ - Curl_rtsp_disconnect, /* disconnect */ + rtsp_disconnect, /* disconnect */ + rtsp_rtp_readwrite, /* readwrite */ PORT_RTSP, /* defport */ - PROT_RTSP, /* protocol */ + CURLPROTO_RTSP, /* protocol */ + PROTOPT_NONE /* flags */ }; -CURLcode Curl_rtsp_connect(struct connectdata *conn, bool *done) + +static CURLcode rtsp_setup_connection(struct connectdata *conn) +{ + struct RTSP *rtsp; + + conn->data->req.protop = rtsp = calloc(1, sizeof(struct RTSP)); + if(!rtsp) + return CURLE_OUT_OF_MEMORY; + + return CURLE_OK; +} + + +/* + * The server may send us RTP data at any point, and RTSPREQ_RECEIVE does not + * want to block the application forever while receiving a stream. Therefore, + * we cannot assume that an RTSP socket is dead just because it is readable. + * + * Instead, if it is readable, run Curl_getconnectinfo() to peek at the socket + * and distinguish between closed and data. + */ +bool Curl_rtsp_connisdead(struct connectdata *check) +{ + int sval; + bool ret_val = TRUE; + + sval = Curl_socket_ready(check->sock[FIRSTSOCKET], CURL_SOCKET_BAD, 0); + if(sval == 0) { + /* timeout */ + ret_val = FALSE; + } + else if(sval & CURL_CSELECT_ERR) { + /* socket is in an error state */ + ret_val = TRUE; + } + else if((sval & CURL_CSELECT_IN) && check->data) { + /* readable with no error. could be closed or could be alive but we can + only check if we have a proper SessionHandle for the connection */ + curl_socket_t connectinfo = Curl_getconnectinfo(check->data, &check); + if(connectinfo != CURL_SOCKET_BAD) + ret_val = FALSE; + } + + return ret_val; +} + +static CURLcode rtsp_connect(struct connectdata *conn, bool *done) { CURLcode httpStatus; struct SessionHandle *data = conn->data; @@ -117,19 +186,19 @@ CURLcode Curl_rtsp_connect(struct connectdata *conn, bool *done) return httpStatus; } -CURLcode Curl_rtsp_disconnect(struct connectdata *conn, bool dead_connection) +static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead) { - (void) dead_connection; + (void) dead; Curl_safefree(conn->proto.rtspc.rtp_buf); return CURLE_OK; } -CURLcode Curl_rtsp_done(struct connectdata *conn, - CURLcode status, bool premature) +static CURLcode rtsp_done(struct connectdata *conn, + CURLcode status, bool premature) { struct SessionHandle *data = conn->data; - struct RTSP *rtsp = data->state.proto.rtsp; + struct RTSP *rtsp = data->req.protop; CURLcode httpStatus; long CSeq_sent; long CSeq_recv; @@ -145,7 +214,8 @@ CURLcode Curl_rtsp_done(struct connectdata *conn, CSeq_sent = rtsp->CSeq_sent; CSeq_recv = rtsp->CSeq_recv; if((data->set.rtspreq != RTSPREQ_RECEIVE) && (CSeq_sent != CSeq_recv)) { - failf(data, "The CSeq of this request %ld did not match the response %ld", + failf(data, + "The CSeq of this request %ld did not match the response %ld", CSeq_sent, CSeq_recv); return CURLE_RTSP_CSEQ_ERROR; } @@ -159,12 +229,12 @@ CURLcode Curl_rtsp_done(struct connectdata *conn, return httpStatus; } -CURLcode Curl_rtsp(struct connectdata *conn, bool *done) +static CURLcode rtsp_do(struct connectdata *conn, bool *done) { struct SessionHandle *data = conn->data; CURLcode result=CURLE_OK; Curl_RtspReq rtspreq = data->set.rtspreq; - struct RTSP *rtsp; + struct RTSP *rtsp = data->req.protop; struct HTTP *http; Curl_send_buffer *req_buffer; curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */ @@ -179,23 +249,11 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) const char *p_stream_uri = NULL; const char *p_transport = NULL; const char *p_uagent = NULL; + const char *p_proxyuserpwd = NULL; + const char *p_userpwd = NULL; *done = TRUE; - Curl_reset_reqproto(conn); - - if(!data->state.proto.rtsp) { - /* Only allocate this struct if we don't already have it! */ - - rtsp = calloc(1, sizeof(struct RTSP)); - if(!rtsp) - return CURLE_OUT_OF_MEMORY; - data->state.proto.rtsp = rtsp; - } - else { - rtsp = data->state.proto.rtsp; - } - http = &(rtsp->http_wrapper); /* Assert that no one has changed the RTSP struct in an evil way */ DEBUGASSERT((void *)http == (void *)rtsp); @@ -207,11 +265,10 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) * Since all RTSP requests are included here, there is no need to * support custom requests like HTTP. **/ - DEBUGASSERT((rtspreq > RTSPREQ_NONE && rtspreq < RTSPREQ_LAST)); data->set.opt_no_body = TRUE; /* most requests don't contain a body */ switch(rtspreq) { - case RTSPREQ_NONE: - failf(data, "Got invalid RTSP request: RTSPREQ_NONE"); + default: + failf(data, "Got invalid RTSP request"); return CURLE_BAD_FUNCTION_ARGUMENT; case RTSPREQ_OPTIONS: p_request = "OPTIONS"; @@ -238,6 +295,7 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) case RTSPREQ_GET_PARAMETER: /* GET_PARAMETER's no_body status is determined later */ p_request = "GET_PARAMETER"; + data->set.opt_no_body = FALSE; break; case RTSPREQ_SET_PARAMETER: p_request = "SET_PARAMETER"; @@ -266,11 +324,10 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) if(!p_session_id && (rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) { failf(data, "Refusing to issue an RTSP request [%s] without a session ID.", - p_request ? p_request : ""); + p_request); return CURLE_BAD_FUNCTION_ARGUMENT; } - /* TODO: auth? */ /* TODO: proxy? */ /* Stream URI. Default to server '*' if not specified */ @@ -282,7 +339,7 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) } /* Transport Header for SETUP requests */ - p_transport = Curl_checkheaders(data, "Transport:"); + p_transport = Curl_checkheaders(conn, "Transport:"); if(rtspreq == RTSPREQ_SETUP && !p_transport) { /* New Transport: setting? */ if(data->set.str[STRING_RTSP_TRANSPORT]) { @@ -306,11 +363,11 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) /* Accept Headers for DESCRIBE requests */ if(rtspreq == RTSPREQ_DESCRIBE) { /* Accept Header */ - p_accept = Curl_checkheaders(data, "Accept:")? + p_accept = Curl_checkheaders(conn, "Accept:")? NULL:"Accept: application/sdp\r\n"; /* Accept-Encoding header */ - if(!Curl_checkheaders(data, "Accept-Encoding:") && + if(!Curl_checkheaders(conn, "Accept-Encoding:") && data->set.str[STRING_ENCODING]) { Curl_safefree(conn->allocptr.accept_encoding); conn->allocptr.accept_encoding = @@ -327,18 +384,26 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) it might have been used in the proxy connect, but if we have got a header with the user-agent string specified, we erase the previously made string here. */ - if(Curl_checkheaders(data, "User-Agent:") && conn->allocptr.uagent) { + if(Curl_checkheaders(conn, "User-Agent:") && conn->allocptr.uagent) { Curl_safefree(conn->allocptr.uagent); conn->allocptr.uagent = NULL; } - else if(!Curl_checkheaders(data, "User-Agent:") && + else if(!Curl_checkheaders(conn, "User-Agent:") && data->set.str[STRING_USERAGENT]) { p_uagent = conn->allocptr.uagent; } + /* setup the authentication headers */ + result = Curl_http_output_auth(conn, p_request, p_stream_uri, FALSE); + if(result) + return result; + + p_proxyuserpwd = conn->allocptr.proxyuserpwd; + p_userpwd = conn->allocptr.userpwd; + /* Referrer */ Curl_safefree(conn->allocptr.ref); - if(data->change.referer && !Curl_checkheaders(data, "Referer:")) + if(data->change.referer && !Curl_checkheaders(conn, "Referer:")) conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer); else conn->allocptr.ref = NULL; @@ -355,7 +420,7 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) (rtspreq & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) { /* Check to see if there is a range set in the custom headers */ - if(!Curl_checkheaders(data, "Range:") && data->state.range) { + if(!Curl_checkheaders(conn, "Range:") && data->state.range) { Curl_safefree(conn->allocptr.rangeline); conn->allocptr.rangeline = aprintf("Range: %s\r\n", data->state.range); p_range = conn->allocptr.rangeline; @@ -365,11 +430,11 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) /* * Sanity check the custom headers */ - if(Curl_checkheaders(data, "CSeq:")) { + if(Curl_checkheaders(conn, "CSeq:")) { failf(data, "CSeq cannot be set as a custom header."); return CURLE_RTSP_CSEQ_ERROR; } - if(Curl_checkheaders(data, "Session:")) { + if(Curl_checkheaders(conn, "Session:")) { failf(data, "Session ID cannot be set as a custom header."); return CURLE_BAD_FUNCTION_ARGUMENT; } @@ -384,8 +449,7 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) Curl_add_bufferf(req_buffer, "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */ "CSeq: %ld\r\n", /* CSeq */ - (p_request ? p_request : ""), p_stream_uri, - rtsp->CSeq_sent); + p_request, p_stream_uri, rtsp->CSeq_sent); if(result) return result; @@ -409,13 +473,25 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) "%s" /* range */ "%s" /* referrer */ "%s" /* user-agent */ + "%s" /* proxyuserpwd */ + "%s" /* userpwd */ , p_transport ? p_transport : "", p_accept ? p_accept : "", p_accept_encoding ? p_accept_encoding : "", p_range ? p_range : "", p_referrer ? p_referrer : "", - p_uagent ? p_uagent : ""); + p_uagent ? p_uagent : "", + p_proxyuserpwd ? p_proxyuserpwd : "", + p_userpwd ? p_userpwd : ""); + + /* + * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM + * with basic and digest, it will be freed anyway by the next request + */ + Curl_safefree (conn->allocptr.userpwd); + conn->allocptr.userpwd = NULL; + if(result) return result; @@ -425,7 +501,7 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) return result; } - result = Curl_add_custom_headers(conn, req_buffer); + result = Curl_add_custom_headers(conn, FALSE, req_buffer); if(result) return result; @@ -434,13 +510,13 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) rtspreq == RTSPREQ_GET_PARAMETER) { if(data->set.upload) { - putsize = data->set.infilesize; + putsize = data->state.infilesize; data->set.httpreq = HTTPREQ_PUT; } else { - postsize = (data->set.postfieldsize != -1)? - data->set.postfieldsize: + postsize = (data->state.infilesize != -1)? + data->state.infilesize: (data->set.postfields? (curl_off_t)strlen(data->set.postfields):0); data->set.httpreq = HTTPREQ_POST; } @@ -448,9 +524,9 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) if(putsize > 0 || postsize > 0) { /* As stated in the http comments, it is probably not wise to * actually set a custom Content-Length in the headers */ - if(!Curl_checkheaders(data, "Content-Length:")) { + if(!Curl_checkheaders(conn, "Content-Length:")) { result = Curl_add_bufferf(req_buffer, - "Content-Length: %" FORMAT_OFF_T"\r\n", + "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n", (data->set.upload ? putsize : postsize)); if(result) return result; @@ -458,7 +534,7 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) if(rtspreq == RTSPREQ_SET_PARAMETER || rtspreq == RTSPREQ_GET_PARAMETER) { - if(!Curl_checkheaders(data, "Content-Type:")) { + if(!Curl_checkheaders(conn, "Content-Type:")) { result = Curl_add_bufferf(req_buffer, "Content-Type: text/parameters\r\n"); if(result) @@ -467,7 +543,7 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) } if(rtspreq == RTSPREQ_ANNOUNCE) { - if(!Curl_checkheaders(data, "Content-Type:")) { + if(!Curl_checkheaders(conn, "Content-Type:")) { result = Curl_add_bufferf(req_buffer, "Content-Type: application/sdp\r\n"); if(result) @@ -475,8 +551,9 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) } } - data->state.expect100header = FALSE; /* RTSP posts are simple/small */ - } else if(rtspreq == RTSPREQ_GET_PARAMETER) { + data->state.expect100header = FALSE; /* RTSP posts are simple/small */ + } + else if(rtspreq == RTSPREQ_GET_PARAMETER) { /* Check for an empty GET_PARAMETER (heartbeat) request */ data->set.httpreq = HTTPREQ_HEAD; data->set.opt_no_body = TRUE; @@ -523,10 +600,11 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) return result; } -CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, - struct connectdata *conn, - ssize_t *nread, - bool *readmore) { + +static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data, + struct connectdata *conn, + ssize_t *nread, + bool *readmore) { struct SingleRequest *k = &data->req; struct rtsp_conn *rtspc = &(conn->proto.rtspc); @@ -608,7 +686,7 @@ CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, } if(rtp_dataleft != 0 && rtp[0] == '$') { - DEBUGF(infof(data, "RTP Rewinding %zu %s\n", rtp_dataleft, + DEBUGF(infof(data, "RTP Rewinding %zd %s\n", rtp_dataleft, *readmore ? "(READMORE)" : "")); /* Store the incomplete RTP packet for a "rewind" */ @@ -687,15 +765,10 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn, if(checkprefix("CSeq:", header)) { /* Store the received CSeq. Match is verified in rtsp_done */ - int nc; - char *temp = strdup(header); - if(!temp) - return CURLE_OUT_OF_MEMORY; - Curl_strntoupper(temp, temp, sizeof(temp)); - nc = sscanf(temp, "CSEQ: %ld", &CSeq); - free(temp); + int nc = sscanf(&header[4], ": %ld", &CSeq); if(nc == 1) { - data->state.proto.rtsp->CSeq_recv = CSeq; /* mark the request */ + struct RTSP *rtsp = data->req.protop; + rtsp->CSeq_recv = CSeq; /* mark the request */ data->state.rtsp_CSeq_recv = CSeq; /* update the handle */ } else { @@ -707,7 +780,7 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *start; /* Find the first non-space letter */ - start = header + 9; + start = header + 8; while(*start && ISSPACE(*start)) start++; diff --git a/project/jni/curl/lib/rtsp.h b/project/jni/curl/lib/rtsp.h index 82e07068d..5a8d5556f 100644 --- a/project/jni/curl/lib/rtsp.h +++ b/project/jni/curl/lib/rtsp.h @@ -1,6 +1,5 @@ -#ifndef __RTSP_H_ -#define __RTSP_H_ - +#ifndef HEADER_CURL_RTSP_H +#define HEADER_CURL_RTSP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -8,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -26,27 +25,14 @@ extern const struct Curl_handler Curl_handler_rtsp; -/* - * Parse and write out any available RTP data. - * - * nread: amount of data left after k->str. will be modified if RTP - * data is parsed and k->str is moved up - * readmore: whether or not the RTP parser needs more data right away - */ -CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, - struct connectdata *conn, - ssize_t *nread, - bool *readmore); - - -/* protocol-specific functions set up to be called by the main engine */ -CURLcode Curl_rtsp(struct connectdata *conn, bool *done); -CURLcode Curl_rtsp_done(struct connectdata *conn, CURLcode, bool premature); -CURLcode Curl_rtsp_connect(struct connectdata *conn, bool *done); -CURLcode Curl_rtsp_disconnect(struct connectdata *conn, bool dead_connection); - +bool Curl_rtsp_connisdead(struct connectdata *check); CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header); +#else +/* disabled */ +#define Curl_rtsp_parseheader(x,y) CURLE_NOT_BUILT_IN +#define Curl_rtsp_connisdead(x) TRUE + #endif /* CURL_DISABLE_RTSP */ /* @@ -79,4 +65,5 @@ struct RTSP { }; -#endif /* __RTSP_H_ */ +#endif /* HEADER_CURL_RTSP_H */ + diff --git a/project/jni/curl/lib/security.c b/project/jni/curl/lib/security.c index 1aa280682..014bbf1b8 100644 --- a/project/jni/curl/lib/security.c +++ b/project/jni/curl/lib/security.c @@ -10,7 +10,7 @@ * Copyright (c) 1998, 1999 Kungliga Tekniska Hgskolan * (Royal Institute of Technology, Stockholm, Sweden). * - * Copyright (C) 2001 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 2001 - 2015, Daniel Stenberg, , et al. * * All rights reserved. * @@ -41,29 +41,27 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_FTP -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) - -#include -#include +#ifdef HAVE_GSSAPI #ifdef HAVE_NETDB_H #include #endif -#ifdef HAVE_UNISTD_H -#include +#ifdef HAVE_LIMITS_H +#include #endif #include "urldata.h" #include "curl_base64.h" #include "curl_memory.h" -#include "krb4.h" +#include "curl_sec.h" #include "ftp.h" #include "sendf.h" #include "rawstr.h" +#include "warnless.h" /* The last #include file should be: */ #include "memdebug.h" @@ -111,22 +109,12 @@ static char level_to_char(int level) { return 'P'; } -static const struct Curl_sec_client_mech * const mechs[] = { -#if defined(HAVE_GSSAPI) - &Curl_krb5_client_mech, -#endif -#if defined(HAVE_KRB4) - &Curl_krb4_client_mech, -#endif - NULL -}; - /* Send an FTP command defined by |message| and the optional arguments. The function returns the ftp_code. If an error occurs, -1 is returned. */ static int ftp_send_command(struct connectdata *conn, const char *message, ...) { int ftp_code; - ssize_t nread; + ssize_t nread=0; va_list args; char print_buffer[50]; @@ -134,11 +122,11 @@ static int ftp_send_command(struct connectdata *conn, const char *message, ...) vsnprintf(print_buffer, sizeof(print_buffer), message, args); va_end(args); - if(Curl_ftpsendf(conn, print_buffer) != CURLE_OK) { + if(Curl_ftpsendf(conn, print_buffer)) { ftp_code = -1; } else { - if(Curl_GetFTPResponse(&nread, conn, &ftp_code) != CURLE_OK) + if(Curl_GetFTPResponse(&nread, conn, &ftp_code)) ftp_code = -1; } @@ -147,25 +135,25 @@ static int ftp_send_command(struct connectdata *conn, const char *message, ...) } /* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode - saying whether an error occured or CURLE_OK if |len| was read. */ + saying whether an error occurred or CURLE_OK if |len| was read. */ static CURLcode socket_read(curl_socket_t fd, void *to, size_t len) { char *to_p = to; - CURLcode code; + CURLcode result; ssize_t nread; while(len > 0) { - code = Curl_read_plain(fd, to_p, len, &nread); - if(code == CURLE_OK) { + result = Curl_read_plain(fd, to_p, len, &nread); + if(!result) { len -= nread; to_p += nread; } else { /* FIXME: We are doing a busy wait */ - if(code == CURLE_AGAIN) + if(result == CURLE_AGAIN) continue; - return code; + return result; } } return CURLE_OK; @@ -173,27 +161,27 @@ socket_read(curl_socket_t fd, void *to, size_t len) /* Write |len| bytes from the buffer |to| to the socket |fd|. Return a - CURLcode saying whether an error occured or CURLE_OK if |len| was + CURLcode saying whether an error occurred or CURLE_OK if |len| was written. */ static CURLcode socket_write(struct connectdata *conn, curl_socket_t fd, const void *to, size_t len) { const char *to_p = to; - CURLcode code; + CURLcode result; ssize_t written; while(len > 0) { - code = Curl_write_plain(conn, fd, to_p, len, &written); - if(code == CURLE_OK) { + result = Curl_write_plain(conn, fd, to_p, len, &written); + if(!result) { len -= written; to_p += written; } else { /* FIXME: We are doing a busy wait */ - if(code == CURLE_AGAIN) + if(result == CURLE_AGAIN) continue; - return code; + return result; } } return CURLE_OK; @@ -201,25 +189,25 @@ socket_write(struct connectdata *conn, curl_socket_t fd, const void *to, static CURLcode read_data(struct connectdata *conn, curl_socket_t fd, - struct krb4buffer *buf) + struct krb5buffer *buf) { int len; void* tmp; - CURLcode ret; + CURLcode result; - ret = socket_read(fd, &len, sizeof(len)); - if (ret != CURLE_OK) - return ret; + result = socket_read(fd, &len, sizeof(len)); + if(result) + return result; len = ntohl(len); tmp = realloc(buf->data, len); - if (tmp == NULL) + if(tmp == NULL) return CURLE_OUT_OF_MEMORY; buf->data = tmp; - ret = socket_read(fd, buf->data, len); - if (ret != CURLE_OK) - return ret; + result = socket_read(fd, buf->data, len); + if(result) + return result; buf->size = conn->mech->decode(conn->app_data, buf->data, len, conn->data_prot, conn); buf->index = 0; @@ -227,7 +215,7 @@ static CURLcode read_data(struct connectdata *conn, } static size_t -buffer_read(struct krb4buffer *buf, void *data, size_t len) +buffer_read(struct krb5buffer *buf, void *data, size_t len) { if(buf->size - buf->index < len) len = buf->size - buf->index; @@ -261,7 +249,7 @@ static ssize_t sec_recv(struct connectdata *conn, int sockindex, buffer += bytes_read; while(len > 0) { - if(read_data(conn, fd, &conn->in_buffer) != CURLE_OK) + if(read_data(conn, fd, &conn->in_buffer)) return -1; if(conn->in_buffer.size == 0) { if(bytes_read > 0) @@ -283,12 +271,13 @@ static ssize_t sec_recv(struct connectdata *conn, int sockindex, static void do_sec_send(struct connectdata *conn, curl_socket_t fd, const char *from, int length) { - size_t bytes; - size_t htonl_bytes; - char *buffer; + int bytes, htonl_bytes; /* 32-bit integers for htonl */ + char *buffer = NULL; char *cmd_buffer; + size_t cmd_size = 0; + CURLcode error; enum protection_level prot_level = conn->data_prot; - bool iscmd = prot_level == PROT_CMD; + bool iscmd = (prot_level == PROT_CMD)?TRUE:FALSE; DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST); @@ -299,10 +288,18 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, prot_level = conn->command_prot; } bytes = conn->mech->encode(conn->app_data, from, length, prot_level, - (void**)&buffer, conn); + (void**)&buffer); + if(!buffer || bytes <= 0) + return; /* error */ + if(iscmd) { - bytes = Curl_base64_encode(conn->data, buffer, bytes, &cmd_buffer); - if(bytes > 0) { + error = Curl_base64_encode(conn->data, buffer, curlx_sitouz(bytes), + &cmd_buffer, &cmd_size); + if(error) { + free(buffer); + return; /* error */ + } + if(cmd_size > 0) { static const char *enc = "ENC "; static const char *mic = "MIC "; if(prot_level == PROT_PRIVATE) @@ -310,7 +307,7 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, else socket_write(conn, fd, mic, 4); - socket_write(conn, fd, cmd_buffer, bytes); + socket_write(conn, fd, cmd_buffer, cmd_size); socket_write(conn, fd, "\r\n", 2); infof(conn->data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic, cmd_buffer); @@ -320,7 +317,7 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, else { htonl_bytes = htonl(bytes); socket_write(conn, fd, &htonl_bytes, sizeof(htonl_bytes)); - socket_write(conn, fd, buffer, bytes); + socket_write(conn, fd, buffer, curlx_sitouz(bytes)); } free(buffer); } @@ -328,19 +325,17 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, static ssize_t sec_write(struct connectdata *conn, curl_socket_t fd, const char *buffer, size_t length) { - /* FIXME: Check for overflow */ - ssize_t len = conn->buffer_size; - int tx = 0; + ssize_t tx = 0, len = conn->buffer_size; - len -= conn->mech->overhead(conn->app_data, conn->data_prot, len); + len -= conn->mech->overhead(conn->app_data, conn->data_prot, + curlx_sztosi(len)); if(len <= 0) len = length; while(length) { - if(len >= 0 || length < (size_t)len) { - /* FIXME: Check for overflow. */ + if(length < (size_t)len) len = length; - } - do_sec_send(conn, fd, buffer, len); + + do_sec_send(conn, fd, buffer, curlx_sztosi(len)); length -= len; buffer += len; tx += len; @@ -364,15 +359,21 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer, int */ int decoded_len; char *buf; - int ret_code; + int ret_code = 0; + size_t decoded_sz = 0; + CURLcode error; DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); - decoded_len = Curl_base64_decode(buffer + 4, (unsigned char **)&buf); - if(decoded_len <= 0) { + error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz); + if(error || decoded_sz == 0) + return -1; + + if(decoded_sz > (size_t)INT_MAX) { free(buf); return -1; } + decoded_len = curlx_uztosi(decoded_sz); decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len, level, conn); @@ -387,13 +388,13 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer, } buf[decoded_len] = '\0'; - DEBUGASSERT(decoded_len > 3); - if(buf[3] == '-') - ret_code = 0; - else { - /* Check for error? */ - sscanf(buf, "%d", &ret_code); - } + if(decoded_len <= 3) + /* suspiciously short */ + return 0; + + if(buf[3] != '-') + /* safe to ignore return code */ + (void)sscanf(buf, "%d", &ret_code); if(buf[decoded_len - 1] == '\n') buf[decoded_len - 1] = '\0'; @@ -436,8 +437,8 @@ static int sec_set_protection_level(struct connectdata *conn) pbsz = strstr(conn->data->state.buffer, "PBSZ="); if(pbsz) { - /* FIXME: Checks for errors in sscanf? */ - sscanf(pbsz, "PBSZ=%u", &buffer_size); + /* ignore return code, use default value if it fails */ + (void)sscanf(pbsz, "PBSZ=%u", &buffer_size); if(buffer_size < conn->buffer_size) conn->buffer_size = buffer_size; } @@ -476,72 +477,63 @@ static CURLcode choose_mech(struct connectdata *conn) { int ret; struct SessionHandle *data = conn->data; - const struct Curl_sec_client_mech * const *mech; void *tmp_allocation; - const char *mech_name; + const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech; - for(mech = mechs; (*mech); ++mech) { - mech_name = (*mech)->name; - /* We have no mechanism with a NULL name but keep this check */ - DEBUGASSERT(mech_name != NULL); - if(mech_name == NULL) { - infof(data, "Skipping mechanism with empty name (%p)\n", mech); - continue; - } - tmp_allocation = realloc(conn->app_data, (*mech)->size); - if(tmp_allocation == NULL) { - failf(data, "Failed realloc of size %u", (*mech)->size); - mech = NULL; - return CURLE_OUT_OF_MEMORY; - } - conn->app_data = tmp_allocation; + tmp_allocation = realloc(conn->app_data, mech->size); + if(tmp_allocation == NULL) { + failf(data, "Failed realloc of size %u", mech->size); + mech = NULL; + return CURLE_OUT_OF_MEMORY; + } + conn->app_data = tmp_allocation; - if((*mech)->init) { - ret = (*mech)->init(conn->app_data); - if(ret != 0) { - infof(data, "Failed initialization for %s. Skipping it.\n", mech_name); - continue; + if(mech->init) { + ret = mech->init(conn->app_data); + if(ret) { + infof(data, "Failed initialization for %s. Skipping it.\n", + mech->name); + return CURLE_FAILED_INIT; + } + } + + infof(data, "Trying mechanism %s...\n", mech->name); + ret = ftp_send_command(conn, "AUTH %s", mech->name); + if(ret < 0) + /* FIXME: This error is too generic but it is OK for now. */ + return CURLE_COULDNT_CONNECT; + + if(ret/100 != 3) { + switch(ret) { + case 504: + infof(data, "Mechanism %s is not supported by the server (server " + "returned ftp code: 504).\n", mech->name); + break; + case 534: + infof(data, "Mechanism %s was rejected by the server (server returned " + "ftp code: 534).\n", mech->name); + break; + default: + if(ret/100 == 5) { + infof(data, "server does not support the security extensions\n"); + return CURLE_USE_SSL_FAILED; } + break; } + return CURLE_LOGIN_DENIED; + } - infof(data, "Trying mechanism %s...\n", mech_name); - ret = ftp_send_command(conn, "AUTH %s", mech_name); - if(ret < 0) - /* FIXME: This error is too generic but it is OK for now. */ - return CURLE_COULDNT_CONNECT; + /* Authenticate */ + ret = mech->auth(conn->app_data, conn); - if(ret/100 != 3) { - switch(ret) { - case 504: - infof(data, "Mechanism %s is not supported by the server (server " - "returned ftp code: 504).\n", mech_name); - break; - case 534: - infof(data, "Mechanism %s was rejected by the server (server returned " - "ftp code: 534).\n", mech_name); - break; - default: - if(ret/100 == 5) { - infof(data, "The server does not support the security extensions.\n"); - return CURLE_USE_SSL_FAILED; - } - break; - } - continue; - } - - /* Authenticate */ - ret = (*mech)->auth(conn->app_data, conn); - - if(ret == AUTH_CONTINUE) - continue; - else if(ret != AUTH_OK) { + if(ret != AUTH_CONTINUE) { + if(ret != AUTH_OK) { /* Mechanism has dumped the error to stderr, don't error here. */ return -1; } DEBUGASSERT(ret == AUTH_OK); - conn->mech = *mech; + conn->mech = mech; conn->sec_complete = 1; conn->recv[FIRSTSOCKET] = sec_recv; conn->send[FIRSTSOCKET] = sec_send; @@ -551,10 +543,9 @@ static CURLcode choose_mech(struct connectdata *conn) /* Set the requested protection level */ /* BLOCKING */ (void)sec_set_protection_level(conn); - break; } - return mech != NULL ? CURLE_OK : CURLE_FAILED_INIT; + return CURLE_OK; } CURLcode @@ -569,10 +560,8 @@ Curl_sec_end(struct connectdata *conn) { if(conn->mech != NULL && conn->mech->end) conn->mech->end(conn->app_data); - if(conn->app_data) { - free(conn->app_data); - conn->app_data = NULL; - } + free(conn->app_data); + conn->app_data = NULL; if(conn->in_buffer.data) { free(conn->in_buffer.data); conn->in_buffer.data = NULL; @@ -586,6 +575,6 @@ Curl_sec_end(struct connectdata *conn) conn->mech = NULL; } -#endif /* HAVE_KRB4 || HAVE_GSSAPI */ +#endif /* HAVE_GSSAPI */ #endif /* CURL_DISABLE_FTP */ diff --git a/project/jni/curl/lib/select.c b/project/jni/curl/lib/select.c index e6882da7a..abf55d878 100644 --- a/project/jni/curl/lib/select.c +++ b/project/jni/curl/lib/select.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,14 +20,11 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifdef HAVE_SYS_SELECT_H #include #endif -#ifdef HAVE_SYS_TIME_H -#include -#endif #if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE) #error "We can't compile without select() or poll() support." @@ -42,35 +39,23 @@ #include /* delay() */ #endif +#ifdef __VXWORKS__ +#include /* bzero() in FD_SET */ +#endif + #include #include "urldata.h" #include "connect.h" #include "select.h" - -/* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1] */ - -#if defined(USE_WINSOCK) || defined(TPF) -#define VERIFY_SOCK(x) do { } while(0) -#else -#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE)) -#define VERIFY_SOCK(x) do { \ - if(!VALID_SOCK(x)) { \ - SET_SOCKERRNO(EINVAL); \ - return -1; \ - } \ -} while(0) -#endif +#include "warnless.h" /* Convenience local macros */ #define elapsed_ms (int)curlx_tvdiff(curlx_tvnow(), initial_tv) -#ifdef CURL_ACKNOWLEDGE_EINTR -#define error_not_EINTR (1) -#else -#define error_not_EINTR (error != EINTR) -#endif +int Curl_ack_eintr = 0; +#define error_not_EINTR (Curl_ack_eintr || error != EINTR) /* * Internal function used for waiting a specific amount of ms @@ -83,16 +68,12 @@ * Timeout resolution, accuracy, as well as maximum supported * value is system dependent, neither factor is a citical issue * for the intended use of this function in the library. - * On non-DOS and non-Winsock platforms, when compiled with - * CURL_ACKNOWLEDGE_EINTR defined, EINTR condition is honored - * and function might exit early without awaiting full timeout, - * otherwise EINTR will be ignored and full timeout will elapse. * * Return values: * -1 = system call error, invalid timeout value, or interrupted * 0 = specified timeout has elapsed */ -static int wait_ms(int timeout_ms) +int Curl_wait_ms(int timeout_ms) { #if !defined(MSDOS) && !defined(USE_WINSOCK) #ifndef HAVE_POLL_FINE @@ -131,8 +112,10 @@ static int wait_ms(int timeout_ms) if(error && error_not_EINTR) break; pending_ms = timeout_ms - elapsed_ms; - if(pending_ms <= 0) + if(pending_ms <= 0) { + r = 0; /* Simulate a "call timed out" case */ break; + } } while(r == -1); #endif /* USE_WINSOCK */ if(r) @@ -141,28 +124,32 @@ static int wait_ms(int timeout_ms) } /* - * This is an internal function used for waiting for read or write - * events on a pair of file descriptors. It uses poll() when a fine - * poll() is available, in order to avoid limits with FD_SETSIZE, - * otherwise select() is used. An error is returned if select() is - * being used and a file descriptor is too large for FD_SETSIZE. + * Wait for read or write events on a set of file descriptors. It uses poll() + * when a fine poll() is available, in order to avoid limits with FD_SETSIZE, + * otherwise select() is used. An error is returned if select() is being used + * and a file descriptor is too large for FD_SETSIZE. + * * A negative timeout value makes this function wait indefinitely, * unles no valid file descriptor is given, when this happens the * negative timeout is ignored and the function times out immediately. - * When compiled with CURL_ACKNOWLEDGE_EINTR defined, EINTR condition - * is honored and function might exit early without awaiting timeout, - * otherwise EINTR will be ignored. * * Return values: * -1 = system call error or fd >= FD_SETSIZE * 0 = timeout - * CURL_CSELECT_IN | CURL_CSELECT_OUT | CURL_CSELECT_ERR + * [bitmask] = action as described below + * + * CURL_CSELECT_IN - first socket is readable + * CURL_CSELECT_IN2 - second socket is readable + * CURL_CSELECT_OUT - write socket is writable + * CURL_CSELECT_ERR - an error condition occurred */ -int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, - int timeout_ms) +int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ + curl_socket_t readfd1, + curl_socket_t writefd, /* socket to write to */ + long timeout_ms) /* milliseconds to wait */ { #ifdef HAVE_POLL_FINE - struct pollfd pfd[2]; + struct pollfd pfd[3]; int num; #else struct timeval pending_tv; @@ -172,14 +159,16 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, fd_set fds_err; curl_socket_t maxfd; #endif - struct timeval initial_tv = {0,0}; + struct timeval initial_tv = {0, 0}; int pending_ms = 0; int error; int r; int ret; - if((readfd == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) { - r = wait_ms(timeout_ms); + if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) && + (writefd == CURL_SOCKET_BAD)) { + /* no sockets, just wait */ + r = Curl_wait_ms((int)timeout_ms); return r; } @@ -189,15 +178,21 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, value indicating a blocking call should be performed. */ if(timeout_ms > 0) { - pending_ms = timeout_ms; + pending_ms = (int)timeout_ms; initial_tv = curlx_tvnow(); } #ifdef HAVE_POLL_FINE num = 0; - if(readfd != CURL_SOCKET_BAD) { - pfd[num].fd = readfd; + if(readfd0 != CURL_SOCKET_BAD) { + pfd[num].fd = readfd0; + pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI; + pfd[num].revents = 0; + num++; + } + if(readfd1 != CURL_SOCKET_BAD) { + pfd[num].fd = readfd1; pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI; pfd[num].revents = 0; num++; @@ -221,9 +216,11 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, if(error && error_not_EINTR) break; if(timeout_ms > 0) { - pending_ms = timeout_ms - elapsed_ms; - if(pending_ms <= 0) + pending_ms = (int)(timeout_ms - elapsed_ms); + if(pending_ms <= 0) { + r = 0; /* Simulate a "call timed out" case */ break; + } } } while(r == -1); @@ -234,13 +231,20 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, ret = 0; num = 0; - if(readfd != CURL_SOCKET_BAD) { + if(readfd0 != CURL_SOCKET_BAD) { if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP)) ret |= CURL_CSELECT_IN; if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL)) ret |= CURL_CSELECT_ERR; num++; } + if(readfd1 != CURL_SOCKET_BAD) { + if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP)) + ret |= CURL_CSELECT_IN2; + if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL)) + ret |= CURL_CSELECT_ERR; + num++; + } if(writefd != CURL_SOCKET_BAD) { if(pfd[num].revents & (POLLWRNORM|POLLOUT)) ret |= CURL_CSELECT_OUT; @@ -256,11 +260,18 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, maxfd = (curl_socket_t)-1; FD_ZERO(&fds_read); - if(readfd != CURL_SOCKET_BAD) { - VERIFY_SOCK(readfd); - FD_SET(readfd, &fds_read); - FD_SET(readfd, &fds_err); - maxfd = readfd; + if(readfd0 != CURL_SOCKET_BAD) { + VERIFY_SOCK(readfd0); + FD_SET(readfd0, &fds_read); + FD_SET(readfd0, &fds_err); + maxfd = readfd0; + } + if(readfd1 != CURL_SOCKET_BAD) { + VERIFY_SOCK(readfd1); + FD_SET(readfd1, &fds_read); + FD_SET(readfd1, &fds_err); + if(readfd1 > maxfd) + maxfd = readfd1; } FD_ZERO(&fds_write); @@ -283,7 +294,37 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, pending_tv.tv_sec = 0; pending_tv.tv_usec = 0; } + + /* WinSock select() must not be called with an fd_set that contains zero + fd flags, or it will return WSAEINVAL. But, it also can't be called + with no fd_sets at all! From the documentation: + + Any two of the parameters, readfds, writefds, or exceptfds, can be + given as null. At least one must be non-null, and any non-null + descriptor set must contain at least one handle to a socket. + + We know that we have at least one bit set in at least two fd_sets in + this case, but we may have no bits set in either fds_read or fd_write, + so check for that and handle it. Luckily, with WinSock, we can _also_ + ask how many bits are set on an fd_set. + + It is unclear why WinSock doesn't just handle this for us instead of + calling this an error. + + Note also that WinSock ignores the first argument, so we don't worry + about the fact that maxfd is computed incorrectly with WinSock (since + curl_socket_t is unsigned in such cases and thus -1 is the largest + value). + */ +#ifdef USE_WINSOCK + r = select((int)maxfd + 1, + fds_read.fd_count ? &fds_read : NULL, + fds_write.fd_count ? &fds_write : NULL, + &fds_err, ptimeout); +#else r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); +#endif + if(r != -1) break; error = SOCKERRNO; @@ -291,8 +332,10 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, break; if(timeout_ms > 0) { pending_ms = timeout_ms - elapsed_ms; - if(pending_ms <= 0) + if(pending_ms <= 0) { + r = 0; /* Simulate a "call timed out" case */ break; + } } } while(r == -1); @@ -302,10 +345,16 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, return 0; ret = 0; - if(readfd != CURL_SOCKET_BAD) { - if(FD_ISSET(readfd, &fds_read)) + if(readfd0 != CURL_SOCKET_BAD) { + if(FD_ISSET(readfd0, &fds_read)) ret |= CURL_CSELECT_IN; - if(FD_ISSET(readfd, &fds_err)) + if(FD_ISSET(readfd0, &fds_err)) + ret |= CURL_CSELECT_ERR; + } + if(readfd1 != CURL_SOCKET_BAD) { + if(FD_ISSET(readfd1, &fds_read)) + ret |= CURL_CSELECT_IN2; + if(FD_ISSET(readfd1, &fds_err)) ret |= CURL_CSELECT_ERR; } if(writefd != CURL_SOCKET_BAD) { @@ -328,9 +377,6 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, * A negative timeout value makes this function wait indefinitely, * unles no valid file descriptor is given, when this happens the * negative timeout is ignored and the function times out immediately. - * When compiled with CURL_ACKNOWLEDGE_EINTR defined, EINTR condition - * is honored and function might exit early without awaiting timeout, - * otherwise EINTR will be ignored. * * Return values: * -1 = system call error or fd >= FD_SETSIZE @@ -347,7 +393,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) fd_set fds_err; curl_socket_t maxfd; #endif - struct timeval initial_tv = {0,0}; + struct timeval initial_tv = {0, 0}; bool fds_none = TRUE; unsigned int i; int pending_ms = 0; @@ -355,7 +401,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) int r; if(ufds) { - for (i = 0; i < nfds; i++) { + for(i = 0; i < nfds; i++) { if(ufds[i].fd != CURL_SOCKET_BAD) { fds_none = FALSE; break; @@ -363,7 +409,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) } } if(fds_none) { - r = wait_ms(timeout_ms); + r = Curl_wait_ms(timeout_ms); return r; } @@ -392,8 +438,10 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) break; if(timeout_ms > 0) { pending_ms = timeout_ms - elapsed_ms; - if(pending_ms <= 0) + if(pending_ms <= 0) { + r = 0; /* Simulate a "call timed out" case */ break; + } } } while(r == -1); @@ -402,7 +450,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) if(r == 0) return 0; - for (i = 0; i < nfds; i++) { + for(i = 0; i < nfds; i++) { if(ufds[i].fd == CURL_SOCKET_BAD) continue; if(ufds[i].revents & POLLHUP) @@ -418,7 +466,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) FD_ZERO(&fds_err); maxfd = (curl_socket_t)-1; - for (i = 0; i < nfds; i++) { + for(i = 0; i < nfds; i++) { ufds[i].revents = 0; if(ufds[i].fd == CURL_SOCKET_BAD) continue; @@ -436,6 +484,16 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) } } +#ifdef USE_WINSOCK + /* WinSock select() can't handle zero events. See the comment about this in + Curl_check_socket(). */ + if(fds_read.fd_count == 0 && fds_write.fd_count == 0 + && fds_err.fd_count == 0) { + r = Curl_wait_ms(timeout_ms); + return r; + } +#endif + ptimeout = (timeout_ms < 0) ? NULL : &pending_tv; do { @@ -447,7 +505,19 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) pending_tv.tv_sec = 0; pending_tv.tv_usec = 0; } + +#ifdef USE_WINSOCK + r = select((int)maxfd + 1, + /* WinSock select() can't handle fd_sets with zero bits set, so + don't give it such arguments. See the comment about this in + Curl_check_socket(). + */ + fds_read.fd_count ? &fds_read : NULL, + fds_write.fd_count ? &fds_write : NULL, + fds_err.fd_count ? &fds_err : NULL, ptimeout); +#else r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); +#endif if(r != -1) break; error = SOCKERRNO; @@ -455,8 +525,10 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) break; if(timeout_ms > 0) { pending_ms = timeout_ms - elapsed_ms; - if(pending_ms <= 0) + if(pending_ms <= 0) { + r = 0; /* Simulate a "call timed out" case */ break; + } } } while(r == -1); @@ -466,7 +538,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) return 0; r = 0; - for (i = 0; i < nfds; i++) { + for(i = 0; i < nfds; i++) { ufds[i].revents = 0; if(ufds[i].fd == CURL_SOCKET_BAD) continue; @@ -501,6 +573,6 @@ int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv); tpf_process_signals(); - return(rc); + return rc; } #endif /* TPF */ diff --git a/project/jni/curl/lib/select.h b/project/jni/curl/lib/select.h index e431e5f07..695bb69cc 100644 --- a/project/jni/curl/lib/select.h +++ b/project/jni/curl/lib/select.h @@ -1,5 +1,5 @@ -#ifndef __SELECT_H -#define __SELECT_H +#ifndef HEADER_CURL_SELECT_H +#define HEADER_CURL_SELECT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,7 +22,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifdef HAVE_SYS_POLL_H #include @@ -30,24 +30,6 @@ #include #endif -/* - * poll() function on Windows Vista and later is called WSAPoll() - */ - -#if defined(USE_WINSOCK) && (USE_WINSOCK > 1) && \ - defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) -# undef HAVE_POLL -# define HAVE_POLL 1 -# undef HAVE_POLL_FINE -# define HAVE_POLL_FINE 1 -# define poll(x,y,z) WSAPoll((x),(y),(z)) -# if defined(_MSC_VER) && defined(POLLRDNORM) -# undef POLLPRI -# define POLLPRI POLLRDBAND -# define HAVE_STRUCT_POLLFD 1 -# endif -#endif - /* * Definition of pollfd struct and constants for platforms lacking them. */ @@ -84,14 +66,49 @@ struct pollfd #define POLLRDBAND POLLPRI #endif -int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, - int timeout_ms); +/* there are three CSELECT defines that are defined in the public header that + are exposed to users, but this *IN2 bit is only ever used internally and + therefore defined here */ +#define CURL_CSELECT_IN2 (CURL_CSELECT_ERR << 1) + +int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2, + curl_socket_t writefd, + long timeout_ms); + +/* provide the former API internally */ +#define Curl_socket_ready(x,y,z) \ + Curl_socket_check(x, CURL_SOCKET_BAD, y, z) int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms); +/* On non-DOS and non-Winsock platforms, when Curl_ack_eintr is set, + * EINTR condition is honored and function might exit early without + * awaiting full timeout. Otherwise EINTR will be ignored and full + * timeout will elapse. */ +extern int Curl_ack_eintr; + +int Curl_wait_ms(int timeout_ms); + #ifdef TPF int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, fd_set* excepts, struct timeval* tv); #endif -#endif /* __SELECT_H */ +/* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1], which + unfortunately makes it impossible for us to easily check if they're valid +*/ +#if defined(USE_WINSOCK) || defined(TPF) +#define VALID_SOCK(x) 1 +#define VERIFY_SOCK(x) Curl_nop_stmt +#else +#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE)) +#define VERIFY_SOCK(x) do { \ + if(!VALID_SOCK(x)) { \ + SET_SOCKERRNO(EINVAL); \ + return -1; \ + } \ +} WHILE_FALSE +#endif + +#endif /* HEADER_CURL_SELECT_H */ + diff --git a/project/jni/curl/lib/sendf.c b/project/jni/curl/lib/sendf.c index d04371f84..ea04ae83e 100644 --- a/project/jni/curl/lib/sendf.c +++ b/project/jni/curl/lib/sendf.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,46 +20,22 @@ * ***************************************************************************/ -#include "setup.h" - -#include -#include -#include -#include - -#ifdef HAVE_SYS_SOCKET_H -#include /* required for send() & recv() prototypes */ -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif +#include "curl_setup.h" #include + #include "urldata.h" #include "sendf.h" #include "connect.h" -#include "sslgen.h" +#include "vtls/vtls.h" #include "ssh.h" #include "multiif.h" -#include "rtsp.h" - -#define _MPRINTF_REPLACE /* use the internal *printf() functions */ -#include - -/* the krb4 functions only exists for FTP and if krb4 or gssapi is defined */ -#if !defined(CURL_DISABLE_FTP) && (defined(HAVE_KRB4) || defined(HAVE_GSSAPI)) -#include "krb4.h" -#else -#define Curl_sec_send(a,b,c,d) -1 -#define Curl_sec_read(a,b,c,d) -1 -#endif - -#include -#include "curl_memory.h" +#include "non-ascii.h" +#include "curl_printf.h" #include "strerror.h" -#include "easyif.h" /* for the Curl_convert_from_network prototype */ -/* The last #include file should be: */ + +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #ifdef CURL_DO_LINEEND_CONV @@ -76,10 +52,10 @@ static size_t convert_lineends(struct SessionHandle *data, /* sanity check */ if((startPtr == NULL) || (size < 1)) { - return(size); + return size; } - if(data->state.prev_block_had_trailing_cr == TRUE) { + if(data->state.prev_block_had_trailing_cr) { /* The previous block of incoming data had a trailing CR, which was turned into a LF. */ if(*startPtr == '\n') { @@ -138,9 +114,9 @@ static size_t convert_lineends(struct SessionHandle *data, /* tidy up by null terminating the now shorter data */ *outPtr = '\0'; - return(outPtr - startPtr); + return (outPtr - startPtr); } - return(size); + return size; } #endif /* CURL_DO_LINEEND_CONV */ @@ -195,7 +171,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, struct SessionHandle *data = conn->data; ssize_t bytes_written; size_t write_len; - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; char *s; char *sptr; va_list ap; @@ -211,9 +187,9 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, for(;;) { /* Write the buffer to the socket */ - res = Curl_write(conn, sockfd, sptr, write_len, &bytes_written); + result = Curl_write(conn, sockfd, sptr, write_len, &bytes_written); - if(CURLE_OK != res) + if(result) break; if(data->set.verbose) @@ -231,7 +207,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, free(s); /* free the output string */ - return res; + return result; } /* @@ -248,10 +224,10 @@ CURLcode Curl_write(struct connectdata *conn, ssize_t *written) { ssize_t bytes_written; - CURLcode curlcode = CURLE_OK; + CURLcode result = CURLE_OK; int num = (sockfd == conn->sock[SECONDARYSOCKET]); - bytes_written = conn->send[num](conn, num, mem, len, &curlcode); + bytes_written = conn->send[num](conn, num, mem, len, &result); *written = bytes_written; if(bytes_written >= 0) @@ -259,7 +235,7 @@ CURLcode Curl_write(struct connectdata *conn, return CURLE_OK; /* handle CURLE_AGAIN or a send failure */ - switch(curlcode) { + switch(result) { case CURLE_AGAIN: *written = 0; return CURLE_OK; @@ -270,7 +246,7 @@ CURLcode Curl_write(struct connectdata *conn, default: /* we got a specific curlcode, forward it */ - return (CURLcode)curlcode; + return result; } } @@ -298,7 +274,8 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num, /* this is just a case of EWOULDBLOCK */ bytes_written=0; *code = CURLE_AGAIN; - } else { + } + else { failf(conn->data, "Send failure: %s", Curl_strerror(conn, err)); conn->data->state.os_errno = err; @@ -320,14 +297,14 @@ CURLcode Curl_write_plain(struct connectdata *conn, ssize_t *written) { ssize_t bytes_written; - CURLcode retcode; + CURLcode result; int num = (sockfd == conn->sock[SECONDARYSOCKET]); - bytes_written = Curl_send_plain(conn, num, mem, len, &retcode); + bytes_written = Curl_send_plain(conn, num, mem, len, &result); *written = bytes_written; - return retcode; + return result; } ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf, @@ -353,7 +330,8 @@ ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf, ) { /* this is just a case of EWOULDBLOCK */ *code = CURLE_AGAIN; - } else { + } + else { failf(conn->data, "Recv failure: %s", Curl_strerror(conn, err)); conn->data->state.os_errno = err; @@ -393,25 +371,21 @@ static CURLcode pausewrite(struct SessionHandle *data, } -/* Curl_client_write() sends data to the write callback(s) - - The bit pattern defines to what "streams" to write to. Body and/or header. - The defines are in sendf.h of course. - - If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the - local character encoding. This is a problem and should be changed in - the future to leave the original data alone. +/* Curl_client_chop_write() writes chunks of data not larger than + * CURL_MAX_WRITE_SIZE via client write callback(s) and + * takes care of pause requests from the callbacks. */ -CURLcode Curl_client_write(struct connectdata *conn, - int type, - char *ptr, - size_t len) +CURLcode Curl_client_chop_write(struct connectdata *conn, + int type, + char * ptr, + size_t len) { struct SessionHandle *data = conn->data; - size_t wrote; + curl_write_callback writeheader = NULL; + curl_write_callback writebody = NULL; - if(0 == len) - len = strlen(ptr); + if(!len) + return CURLE_OK; /* If reading is actually paused, we're forced to append this chunk of data to the already held data, but only if it is the same type as otherwise it @@ -436,72 +410,107 @@ CURLcode Curl_client_write(struct connectdata *conn, /* update the pointer and the size */ data->state.tempwrite = newptr; data->state.tempwritesize = newlen; - return CURLE_OK; } - if(type & CLIENTWRITE_BODY) { - if((conn->protocol&PROT_FTP) && conn->proto.ftpc.transfertype == 'A') { -#ifdef CURL_DOES_CONVERSIONS - /* convert from the network encoding */ - size_t rc; - rc = Curl_convert_from_network(data, ptr, len); - /* Curl_convert_from_network calls failf if unsuccessful */ - if(rc != CURLE_OK) - return rc; -#endif /* CURL_DOES_CONVERSIONS */ - -#ifdef CURL_DO_LINEEND_CONV - /* convert end-of-line markers */ - len = convert_lineends(data, ptr, len); -#endif /* CURL_DO_LINEEND_CONV */ - } - /* If the previous block of data ended with CR and this block of data is - just a NL, then the length might be zero */ - if(len) { - wrote = data->set.fwrite_func(ptr, 1, len, data->set.out); - } - else { - wrote = len; - } - - if(CURL_WRITEFUNC_PAUSE == wrote) - return pausewrite(data, type, ptr, len); - - if(wrote != len) { - failf(data, "Failed writing body (%zu != %zu)", wrote, len); - return CURLE_WRITE_ERROR; - } - } - + /* Determine the callback(s) to use. */ + if(type & CLIENTWRITE_BODY) + writebody = data->set.fwrite_func; if((type & CLIENTWRITE_HEADER) && - (data->set.fwrite_header || data->set.writeheader) ) { + (data->set.fwrite_header || data->set.writeheader)) { /* * Write headers to the same callback or to the especially setup * header callback function (added after version 7.7.1). */ - curl_write_callback writeit= - data->set.fwrite_header?data->set.fwrite_header:data->set.fwrite_func; + writeheader = + data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func; + } - /* Note: The header is in the host encoding - regardless of the ftp transfer mode (ASCII/Image) */ + /* Chop data, write chunks. */ + while(len) { + size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE; - wrote = writeit(ptr, 1, len, data->set.writeheader); - if(CURL_WRITEFUNC_PAUSE == wrote) - /* here we pass in the HEADER bit only since if this was body as well - then it was passed already and clearly that didn't trigger the pause, - so this is saved for later with the HEADER bit only */ - return pausewrite(data, CLIENTWRITE_HEADER, ptr, len); + if(writebody) { + size_t wrote = writebody(ptr, 1, chunklen, data->set.out); - if(wrote != len) { - failf (data, "Failed writing header"); - return CURLE_WRITE_ERROR; + if(CURL_WRITEFUNC_PAUSE == wrote) { + if(conn->handler->flags & PROTOPT_NONETWORK) { + /* Protocols that work without network cannot be paused. This is + actually only FILE:// just now, and it can't pause since the + transfer isn't done using the "normal" procedure. */ + failf(data, "Write callback asked for PAUSE when not supported!"); + return CURLE_WRITE_ERROR; + } + else + return pausewrite(data, type, ptr, len); + } + else if(wrote != chunklen) { + failf(data, "Failed writing body (%zu != %zu)", wrote, chunklen); + return CURLE_WRITE_ERROR; + } } + + if(writeheader) { + size_t wrote = writeheader(ptr, 1, chunklen, data->set.writeheader); + + if(CURL_WRITEFUNC_PAUSE == wrote) + /* here we pass in the HEADER bit only since if this was body as well + then it was passed already and clearly that didn't trigger the + pause, so this is saved for later with the HEADER bit only */ + return pausewrite(data, CLIENTWRITE_HEADER, ptr, len); + + if(wrote != chunklen) { + failf (data, "Failed writing header"); + return CURLE_WRITE_ERROR; + } + } + + ptr += chunklen; + len -= chunklen; } return CURLE_OK; } + +/* Curl_client_write() sends data to the write callback(s) + + The bit pattern defines to what "streams" to write to. Body and/or header. + The defines are in sendf.h of course. + + If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the + local character encoding. This is a problem and should be changed in + the future to leave the original data alone. + */ +CURLcode Curl_client_write(struct connectdata *conn, + int type, + char *ptr, + size_t len) +{ + struct SessionHandle *data = conn->data; + + if(0 == len) + len = strlen(ptr); + + /* FTP data may need conversion. */ + if((type & CLIENTWRITE_BODY) && + (conn->handler->protocol & PROTO_FAMILY_FTP) && + conn->proto.ftpc.transfertype == 'A') { + /* convert from the network encoding */ + CURLcode result = Curl_convert_from_network(data, ptr, len); + /* Curl_convert_from_network calls failf if unsuccessful */ + if(result) + return result; + +#ifdef CURL_DO_LINEEND_CONV + /* convert end-of-line markers */ + len = convert_lineends(data, ptr, len); +#endif /* CURL_DO_LINEEND_CONV */ + } + + return Curl_client_chop_write(conn, type, ptr, len); +} + CURLcode Curl_read_plain(curl_socket_t sockfd, char *buf, size_t bytesfromsocket, @@ -511,11 +520,13 @@ CURLcode Curl_read_plain(curl_socket_t sockfd, if(-1 == nread) { int err = SOCKERRNO; + int return_error; #ifdef USE_WINSOCK - if(WSAEWOULDBLOCK == err) + return_error = WSAEWOULDBLOCK == err; #else - if((EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)) + return_error = EWOULDBLOCK == err || EAGAIN == err || EINTR == err; #endif + if(return_error) return CURLE_AGAIN; else return CURLE_RECV_ERROR; @@ -533,17 +544,19 @@ CURLcode Curl_read_plain(curl_socket_t sockfd, * Returns a regular CURLcode value. */ CURLcode Curl_read(struct connectdata *conn, /* connection data */ - curl_socket_t sockfd, /* read from this socket */ - char *buf, /* store read data here */ - size_t sizerequested, /* max amount to read */ - ssize_t *n) /* amount bytes read */ + curl_socket_t sockfd, /* read from this socket */ + char *buf, /* store read data here */ + size_t sizerequested, /* max amount to read */ + ssize_t *n) /* amount bytes read */ { - CURLcode curlcode = CURLE_RECV_ERROR; + CURLcode result = CURLE_RECV_ERROR; ssize_t nread = 0; size_t bytesfromsocket = 0; char *buffertofill = NULL; - bool pipelining = (bool)(conn->data->multi && - Curl_multi_canPipeline(conn->data->multi)); + + /* if HTTP/1 pipelining is both wanted and possible */ + bool pipelining = Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1) && + (conn->bundle->multiuse == BUNDLE_PIPELINING); /* Set 'num' to 0 or 1, depending on which socket that has been sent here. If it is the second socket, we set num to 1. Otherwise to 0. This lets @@ -578,9 +591,9 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */ buffertofill = buf; } - nread = conn->recv[num](conn, num, buffertofill, bytesfromsocket, &curlcode); + nread = conn->recv[num](conn, num, buffertofill, bytesfromsocket, &result); if(nread < 0) - return curlcode; + return result; if(pipelining) { memcpy(buf, conn->master_buffer, nread); @@ -622,7 +635,7 @@ static int showit(struct SessionHandle *data, curl_infotype type, size_t i; for(i = 0; i < size-4; i++) { if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) { - /* convert everthing through this CRLFCRLF but no further */ + /* convert everything through this CRLFCRLF but no further */ conv_size = i + 4; break; } @@ -675,11 +688,13 @@ int Curl_debug(struct SessionHandle *data, curl_infotype type, switch (type) { case CURLINFO_HEADER_IN: w = "Header"; + /* FALLTHROUGH */ case CURLINFO_DATA_IN: t = "from"; break; case CURLINFO_HEADER_OUT: w = "Header"; + /* FALLTHROUGH */ case CURLINFO_DATA_OUT: t = "to"; break; diff --git a/project/jni/curl/lib/sendf.h b/project/jni/curl/lib/sendf.h index 8f0ea24d7..48e9444c6 100644 --- a/project/jni/curl/lib/sendf.h +++ b/project/jni/curl/lib/sendf.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,7 +22,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *, const char *fmt, ...); @@ -32,9 +32,9 @@ void Curl_failf(struct SessionHandle *, const char *fmt, ...); #if defined(CURL_DISABLE_VERBOSE_STRINGS) #if defined(HAVE_VARIADIC_MACROS_C99) -#define infof(...) do { } while (0) +#define infof(...) Curl_nop_stmt #elif defined(HAVE_VARIADIC_MACROS_GCC) -#define infof(x...) do { } while (0) +#define infof(x...) Curl_nop_stmt #else #define infof (void) #endif @@ -51,8 +51,10 @@ void Curl_failf(struct SessionHandle *, const char *fmt, ...); #define CLIENTWRITE_HEADER (1<<1) #define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER) +CURLcode Curl_client_chop_write(struct connectdata *conn, int type, char *ptr, + size_t len) WARN_UNUSED_RESULT; CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr, - size_t len); + size_t len) WARN_UNUSED_RESULT; /* internal read-function, does plain socket only */ CURLcode Curl_read_plain(curl_socket_t sockfd, diff --git a/project/jni/curl/lib/setup-os400.h b/project/jni/curl/lib/setup-os400.h index cdeefe3dd..e32b72f21 100644 --- a/project/jni/curl/lib/setup-os400.h +++ b/project/jni/curl/lib/setup-os400.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -33,14 +33,16 @@ typedef unsigned long u_int32_t; -/* System API wrapper prototypes and definitions to support ASCII parameters. */ +/* System API wrapper prototypes & definitions to support ASCII parameters. */ #include #include -#include +#include +#include #include -extern int Curl_getaddrinfo_a(const char * nodename, const char * servname, +extern int Curl_getaddrinfo_a(const char * nodename, + const char * servname, const struct addrinfo * hints, struct addrinfo * * res); #define getaddrinfo Curl_getaddrinfo_a @@ -54,18 +56,91 @@ extern int Curl_getnameinfo_a(const struct sockaddr * sa, #define getnameinfo Curl_getnameinfo_a -/* SSL wrappers. */ +/* GSKit wrappers. */ -extern int Curl_SSL_Init_Application_a(SSLInitApp * init_app); -#define SSL_Init_Application Curl_SSL_Init_Application_a +extern int Curl_gsk_environment_open(gsk_handle * my_env_handle); +#define gsk_environment_open Curl_gsk_environment_open +extern int Curl_gsk_secure_soc_open(gsk_handle my_env_handle, + gsk_handle * my_session_handle); +#define gsk_secure_soc_open Curl_gsk_secure_soc_open -extern int Curl_SSL_Init_a(SSLInit * init); -#define SSL_Init Curl_SSL_Init_a +extern int Curl_gsk_environment_close(gsk_handle * my_env_handle); +#define gsk_environment_close Curl_gsk_environment_close +extern int Curl_gsk_secure_soc_close(gsk_handle * my_session_handle); +#define gsk_secure_soc_close Curl_gsk_secure_soc_close -extern char * Curl_SSL_Strerror_a(int sslreturnvalue, SSLErrorMsg * serrmsgp); -#define SSL_Strerror Curl_SSL_Strerror_a +extern int Curl_gsk_environment_init(gsk_handle my_env_handle); +#define gsk_environment_init Curl_gsk_environment_init + +extern int Curl_gsk_secure_soc_init(gsk_handle my_session_handle); +#define gsk_secure_soc_init Curl_gsk_secure_soc_init + +extern int Curl_gsk_attribute_set_buffer_a(gsk_handle my_gsk_handle, + GSK_BUF_ID bufID, + const char * buffer, + int bufSize); +#define gsk_attribute_set_buffer Curl_gsk_attribute_set_buffer_a + +extern int Curl_gsk_attribute_set_enum(gsk_handle my_gsk_handle, + GSK_ENUM_ID enumID, + GSK_ENUM_VALUE enumValue); +#define gsk_attribute_set_enum Curl_gsk_attribute_set_enum + +extern int Curl_gsk_attribute_set_numeric_value(gsk_handle my_gsk_handle, + GSK_NUM_ID numID, + int numValue); +#define gsk_attribute_set_numeric_value Curl_gsk_attribute_set_numeric_value + +extern int Curl_gsk_attribute_set_callback(gsk_handle my_gsk_handle, + GSK_CALLBACK_ID callBackID, + void * callBackAreaPtr); +#define gsk_attribute_set_callback Curl_gsk_attribute_set_callback + +extern int Curl_gsk_attribute_get_buffer_a(gsk_handle my_gsk_handle, + GSK_BUF_ID bufID, + const char * * buffer, + int * bufSize); +#define gsk_attribute_get_buffer Curl_gsk_attribute_get_buffer_a + +extern int Curl_gsk_attribute_get_enum(gsk_handle my_gsk_handle, + GSK_ENUM_ID enumID, + GSK_ENUM_VALUE * enumValue); +#define gsk_attribute_get_enum Curl_gsk_attribute_get_enum + +extern int Curl_gsk_attribute_get_numeric_value(gsk_handle my_gsk_handle, + GSK_NUM_ID numID, + int * numValue); +#define gsk_attribute_get_numeric_value Curl_gsk_attribute_get_numeric_value + +extern int Curl_gsk_attribute_get_cert_info(gsk_handle my_gsk_handle, + GSK_CERT_ID certID, + const gsk_cert_data_elem * * certDataElem, + int * certDataElementCount); +#define gsk_attribute_get_cert_info Curl_gsk_attribute_get_cert_info + +extern int Curl_gsk_secure_soc_misc(gsk_handle my_session_handle, + GSK_MISC_ID miscID); +#define gsk_secure_soc_misc Curl_gsk_secure_soc_misc + +extern int Curl_gsk_secure_soc_read(gsk_handle my_session_handle, + char * readBuffer, + int readBufSize, int * amtRead); +#define gsk_secure_soc_read Curl_gsk_secure_soc_read + +extern int Curl_gsk_secure_soc_write(gsk_handle my_session_handle, + char * writeBuffer, + int writeBufSize, int * amtWritten); +#define gsk_secure_soc_write Curl_gsk_secure_soc_write + +extern const char * Curl_gsk_strerror_a(int gsk_return_value); +#define gsk_strerror Curl_gsk_strerror_a + +extern int Curl_gsk_secure_soc_startInit(gsk_handle my_session_handle, + int IOCompletionPort, + Qso_OverlappedIO_t * communicationsArea); +#define gsk_secure_soc_startInit Curl_gsk_secure_soc_startInit /* GSSAPI wrappers. */ @@ -107,6 +182,7 @@ extern OM_uint32 Curl_gss_delete_sec_context_a(OM_uint32 * minor_status, gss_buffer_t output_token); #define gss_delete_sec_context Curl_gss_delete_sec_context_a + /* LDAP wrappers. */ #define BerValue struct berval @@ -136,5 +212,12 @@ extern int Curl_os400_recvfrom(int sd, char * buffer, int buflen, int flags, #define sendto Curl_os400_sendto #define recvfrom Curl_os400_recvfrom +#ifdef HAVE_LIBZ +#define zlibVersion Curl_os400_zlibVersion +#define inflateInit_ Curl_os400_inflateInit_ +#define inflateInit2_ Curl_os400_inflateInit2_ +#define inflate Curl_os400_inflate +#define inflateEnd Curl_os400_inflateEnd +#endif #endif /* HEADER_CURL_SETUP_OS400_H */ diff --git a/project/jni/curl/lib/setup-vms.h b/project/jni/curl/lib/setup-vms.h new file mode 100644 index 000000000..4b78e0bf0 --- /dev/null +++ b/project/jni/curl/lib/setup-vms.h @@ -0,0 +1,442 @@ +#ifndef HEADER_CURL_SETUP_VMS_H +#define HEADER_CURL_SETUP_VMS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* */ +/* JEM, 12/30/12, VMS now generates config.h, so only define wrappers for */ +/* getenv(), getpwuid() and provide is_vms_shell() */ +/* Also need upper case symbols for system services, and */ +/* OpenSSL, and some Kerberos image */ + +#ifdef __DECC +#pragma message save +#pragma message disable dollarid +#endif + +/* Hide the stuff we are overriding */ +#define getenv decc_getenv +#ifdef __DECC +# if __INITIAL_POINTER_SIZE != 64 +# define getpwuid decc_getpwuid +# endif +#endif +#include + char * decc$getenv(const char * __name); +#include + +#include +#include + +#undef getenv +#undef getpwuid +#define getenv vms_getenv +#define getpwuid vms_getpwuid + +/* VAX needs these in upper case when compiling exact case */ +#define sys$assign SYS$ASSIGN +#define sys$dassgn SYS$DASSGN +#define sys$qiow SYS$QIOW + +#ifdef __DECC +# if __INITIAL_POINTER_SIZE +# pragma __pointer_size __save +# endif +#endif + +#if __USE_LONG_GID_T +# define decc_getpwuid DECC$__LONG_GID_GETPWUID +#else +# if __INITIAL_POINTER_SIZE +# define decc_getpwuid decc$__32_getpwuid +# else +# define decc_getpwuid decc$getpwuid +# endif +#endif + + struct passwd * decc_getpwuid(uid_t uid); + +#ifdef __DECC +# if __INITIAL_POINTER_SIZE == 32 +/* Translate the path, but only if the path is a VMS file specification */ +/* The translation is usually only needed for older versions of VMS */ +static char * vms_translate_path(const char * path) { +char * unix_path; +char * test_str; + + /* See if the result is in VMS format, if not, we are done */ + /* Assume that this is a PATH, not just some data */ + test_str = strpbrk(path, ":[<^"); + if(test_str == NULL) { + return (char *)path; + } + + unix_path = decc$translate_vms(path); + + if((int)unix_path <= 0) { + /* We can not translate it, so return the original string */ + return (char *)path; + } +} +# else + /* VMS translate path is actually not needed on the current 64 bit */ + /* VMS platforms, so instead of figuring out the pointer settings */ + /* Change it to a noop */ +# define vms_translate_path(__path) __path +# endif +#endif + +#ifdef __DECC +# if __INITIAL_POINTER_SIZE +# pragma __pointer_size __restore +# endif +#endif + +static char * vms_getenv(const char * envvar) { + +char * result; +char * vms_path; + + /* first use the DECC getenv() function */ + result = decc$getenv(envvar); + if(result == NULL) { + return result; + } + + vms_path = result; + result = vms_translate_path(vms_path); + + /* note that if you backport this to use VAX C RTL, that the VAX C RTL */ + /* may do a malloc(2048) for each call to getenv(), so you will need */ + /* to add a free(vms_path) */ + /* Do not do a free() for DEC C RTL builds, which should be used for */ + /* VMS 5.5-2 and later, even if using GCC */ + + return result; +} + + +static struct passwd vms_passwd_cache; + +static struct passwd * vms_getpwuid(uid_t uid) { + +struct passwd * my_passwd; + +/* Hack needed to support 64 bit builds, decc_getpwnam is 32 bit only */ +#ifdef __DECC +# if __INITIAL_POINTER_SIZE +__char_ptr32 unix_path; +# else +char * unix_path; +# endif +#else +char * unix_path; +#endif + + my_passwd = decc_getpwuid(uid); + if(my_passwd == NULL) { + return my_passwd; + } + + unix_path = vms_translate_path(my_passwd->pw_dir); + + if((long)unix_path <= 0) { + /* We can not translate it, so return the original string */ + return my_passwd; + } + + /* If no changes needed just return it */ + if(unix_path == my_passwd->pw_dir) { + return my_passwd; + } + + /* Need to copy the structure returned */ + /* Since curl is only using pw_dir, no need to fix up * + /* the pw_shell when running under Bash */ + vms_passwd_cache.pw_name = my_passwd->pw_name; + vms_passwd_cache.pw_uid = my_passwd->pw_uid; + vms_passwd_cache.pw_gid = my_passwd->pw_uid; + vms_passwd_cache.pw_dir = unix_path; + vms_passwd_cache.pw_shell = my_passwd->pw_shell; + + return &vms_passwd_cache; +} + +#ifdef __DECC +#pragma message restore +#endif + +/* Bug - VMS OpenSSL and Kerberos universal symbols are in uppercase only */ +/* VMS libraries should have universal symbols in exact and uppercase */ + +#define ASN1_INTEGER_get ASN1_INTEGER_GET +#define ASN1_STRING_data ASN1_STRING_DATA +#define ASN1_STRING_length ASN1_STRING_LENGTH +#define ASN1_STRING_print ASN1_STRING_PRINT +#define ASN1_STRING_to_UTF8 ASN1_STRING_TO_UTF8 +#define ASN1_STRING_type ASN1_STRING_TYPE +#define BIO_ctrl BIO_CTRL +#define BIO_free BIO_FREE +#define BIO_new BIO_NEW +#define BIO_s_mem BIO_S_MEM +#define BN_bn2bin BN_BN2BIN +#define BN_num_bits BN_NUM_BITS +#define CRYPTO_cleanup_all_ex_data CRYPTO_CLEANUP_ALL_EX_DATA +#define CRYPTO_free CRYPTO_FREE +#define CRYPTO_malloc CRYPTO_MALLOC +#define CONF_modules_load_file CONF_MODULES_LOAD_FILE +#ifdef __VAX +# ifdef VMS_OLD_SSL + /* Ancient OpenSSL on VAX/VMS missing this constant */ +# define CONF_MFLAGS_IGNORE_MISSING_FILE 0x10 +# undef CONF_modules_load_file + static int CONF_modules_load_file(const char *filename, + const char *appname, + unsigned long flags) { + return 1; + } +# endif +#endif +#define DES_ecb_encrypt DES_ECB_ENCRYPT +#define DES_set_key DES_SET_KEY +#define DES_set_odd_parity DES_SET_ODD_PARITY +#define ENGINE_ctrl ENGINE_CTRL +#define ENGINE_ctrl_cmd ENGINE_CTRL_CMD +#define ENGINE_finish ENGINE_FINISH +#define ENGINE_free ENGINE_FREE +#define ENGINE_get_first ENGINE_GET_FIRST +#define ENGINE_get_id ENGINE_GET_ID +#define ENGINE_get_next ENGINE_GET_NEXT +#define ENGINE_init ENGINE_INIT +#define ENGINE_load_builtin_engines ENGINE_LOAD_BUILTIN_ENGINES +#define ENGINE_load_private_key ENGINE_LOAD_PRIVATE_KEY +#define ENGINE_set_default ENGINE_SET_DEFAULT +#define ERR_clear_error ERR_CLEAR_ERROR +#define ERR_error_string ERR_ERROR_STRING +#define ERR_error_string_n ERR_ERROR_STRING_N +#define ERR_free_strings ERR_FREE_STRINGS +#define ERR_get_error ERR_GET_ERROR +#define ERR_peek_error ERR_PEEK_ERROR +#define ERR_remove_state ERR_REMOVE_STATE +#define EVP_PKEY_copy_parameters EVP_PKEY_COPY_PARAMETERS +#define EVP_PKEY_free EVP_PKEY_FREE +#define EVP_cleanup EVP_CLEANUP +#define GENERAL_NAMES_free GENERAL_NAMES_FREE +#define i2d_X509_PUBKEY I2D_X509_PUBKEY +#define MD4_Final MD4_FINAL +#define MD4_Init MD4_INIT +#define MD4_Update MD4_UPDATE +#define MD5_Final MD5_FINAL +#define MD5_Init MD5_INIT +#define MD5_Update MD5_UPDATE +#define OPENSSL_add_all_algo_noconf OPENSSL_ADD_ALL_ALGO_NOCONF +#ifndef __VAX +#define OPENSSL_load_builtin_modules OPENSSL_LOAD_BUILTIN_MODULES +#endif +#define PEM_read_X509 PEM_READ_X509 +#define PEM_write_bio_X509 PEM_WRITE_BIO_X509 +#define PKCS12_PBE_add PKCS12_PBE_ADD +#define PKCS12_free PKCS12_FREE +#define PKCS12_parse PKCS12_PARSE +#define RAND_add RAND_ADD +#define RAND_bytes RAND_BYTES +#define RAND_egd RAND_EGD +#define RAND_file_name RAND_FILE_NAME +#define RAND_load_file RAND_LOAD_FILE +#define RAND_status RAND_STATUS +#define SSL_CIPHER_get_name SSL_CIPHER_GET_NAME +#define SSL_CTX_add_client_CA SSL_CTX_ADD_CLIENT_CA +#define SSL_CTX_callback_ctrl SSL_CTX_CALLBACK_CTRL +#define SSL_CTX_check_private_key SSL_CTX_CHECK_PRIVATE_KEY +#define SSL_CTX_ctrl SSL_CTX_CTRL +#define SSL_CTX_free SSL_CTX_FREE +#define SSL_CTX_get_cert_store SSL_CTX_GET_CERT_STORE +#define SSL_CTX_load_verify_locations SSL_CTX_LOAD_VERIFY_LOCATIONS +#define SSL_CTX_new SSL_CTX_NEW +#define SSL_CTX_set_cipher_list SSL_CTX_SET_CIPHER_LIST +#define SSL_CTX_set_def_passwd_cb_ud SSL_CTX_SET_DEF_PASSWD_CB_UD +#define SSL_CTX_set_default_passwd_cb SSL_CTX_SET_DEFAULT_PASSWD_CB +#define SSL_CTX_set_msg_callback SSL_CTX_SET_MSG_CALLBACK +#define SSL_CTX_set_verify SSL_CTX_SET_VERIFY +#define SSL_CTX_use_PrivateKey SSL_CTX_USE_PRIVATEKEY +#define SSL_CTX_use_PrivateKey_file SSL_CTX_USE_PRIVATEKEY_FILE +#define SSL_CTX_use_cert_chain_file SSL_CTX_USE_CERT_CHAIN_FILE +#define SSL_CTX_use_certificate SSL_CTX_USE_CERTIFICATE +#define SSL_CTX_use_certificate_file SSL_CTX_USE_CERTIFICATE_FILE +#define SSL_SESSION_free SSL_SESSION_FREE +#define SSL_connect SSL_CONNECT +#define SSL_free SSL_FREE +#define SSL_get1_session SSL_GET1_SESSION +#define SSL_get_certificate SSL_GET_CERTIFICATE +#define SSL_get_current_cipher SSL_GET_CURRENT_CIPHER +#define SSL_get_error SSL_GET_ERROR +#define SSL_get_peer_cert_chain SSL_GET_PEER_CERT_CHAIN +#define SSL_get_peer_certificate SSL_GET_PEER_CERTIFICATE +#define SSL_get_privatekey SSL_GET_PRIVATEKEY +#define SSL_get_session SSL_GET_SESSION +#define SSL_get_shutdown SSL_GET_SHUTDOWN +#define SSL_get_verify_result SSL_GET_VERIFY_RESULT +#define SSL_library_init SSL_LIBRARY_INIT +#define SSL_load_error_strings SSL_LOAD_ERROR_STRINGS +#define SSL_new SSL_NEW +#define SSL_peek SSL_PEEK +#define SSL_pending SSL_PENDING +#define SSL_read SSL_READ +#define SSL_set_connect_state SSL_SET_CONNECT_STATE +#define SSL_set_fd SSL_SET_FD +#define SSL_set_session SSL_SET_SESSION +#define SSL_shutdown SSL_SHUTDOWN +#define SSL_version SSL_VERSION +#define SSL_write SSL_WRITE +#define SSLeay SSLEAY +#define SSLv23_client_method SSLV23_CLIENT_METHOD +#define SSLv3_client_method SSLV3_CLIENT_METHOD +#define TLSv1_client_method TLSV1_CLIENT_METHOD +#define UI_create_method UI_CREATE_METHOD +#define UI_destroy_method UI_DESTROY_METHOD +#define UI_get0_user_data UI_GET0_USER_DATA +#define UI_get_input_flags UI_GET_INPUT_FLAGS +#define UI_get_string_type UI_GET_STRING_TYPE +#define UI_create_method UI_CREATE_METHOD +#define UI_destroy_method UI_DESTROY_METHOD +#define UI_method_get_closer UI_METHOD_GET_CLOSER +#define UI_method_get_opener UI_METHOD_GET_OPENER +#define UI_method_get_reader UI_METHOD_GET_READER +#define UI_method_get_writer UI_METHOD_GET_WRITER +#define UI_method_set_closer UI_METHOD_SET_CLOSER +#define UI_method_set_opener UI_METHOD_SET_OPENER +#define UI_method_set_reader UI_METHOD_SET_READER +#define UI_method_set_writer UI_METHOD_SET_WRITER +#define UI_OpenSSL UI_OPENSSL +#define UI_set_result UI_SET_RESULT +#define X509V3_EXT_print X509V3_EXT_PRINT +#define X509_EXTENSION_get_critical X509_EXTENSION_GET_CRITICAL +#define X509_EXTENSION_get_data X509_EXTENSION_GET_DATA +#define X509_EXTENSION_get_object X509_EXTENSION_GET_OBJECT +#define X509_LOOKUP_file X509_LOOKUP_FILE +#define X509_NAME_ENTRY_get_data X509_NAME_ENTRY_GET_DATA +#define X509_NAME_get_entry X509_NAME_GET_ENTRY +#define X509_NAME_get_index_by_NID X509_NAME_GET_INDEX_BY_NID +#define X509_NAME_print_ex X509_NAME_PRINT_EX +#define X509_STORE_CTX_get_current_cert X509_STORE_CTX_GET_CURRENT_CERT +#define X509_STORE_add_lookup X509_STORE_ADD_LOOKUP +#define X509_STORE_set_flags X509_STORE_SET_FLAGS +#define X509_check_issued X509_CHECK_ISSUED +#define X509_free X509_FREE +#define X509_get_ext_d2i X509_GET_EXT_D2I +#define X509_get_issuer_name X509_GET_ISSUER_NAME +#define X509_get_pubkey X509_GET_PUBKEY +#define X509_get_serialNumber X509_GET_SERIALNUMBER +#define X509_get_subject_name X509_GET_SUBJECT_NAME +#define X509_load_crl_file X509_LOAD_CRL_FILE +#define X509_verify_cert_error_string X509_VERIFY_CERT_ERROR_STRING +#define d2i_PKCS12_fp D2I_PKCS12_FP +#define i2t_ASN1_OBJECT I2T_ASN1_OBJECT +#define sk_num SK_NUM +#define sk_pop SK_POP +#define sk_pop_free SK_POP_FREE +#define sk_value SK_VALUE +#ifdef __VAX +#define OPENSSL_NO_SHA256 +#endif +#define SHA256_Final SHA256_FINAL +#define SHA256_Init SHA256_INIT +#define SHA256_Update SHA256_UPDATE + +#define USE_UPPERCASE_GSSAPI 1 +#define gss_seal GSS_SEAL +#define gss_unseal GSS_UNSEAL + +#define USE_UPPERCASE_KRBAPI 1 + +/* AI_NUMERICHOST needed for IP V6 support in Curl */ +#ifdef HAVE_NETDB_H +#include +#ifndef AI_NUMERICHOST +#ifdef ENABLE_IPV6 +#undef ENABLE_IPV6 +#endif +#endif +#endif + +/* VAX symbols are always in uppercase */ +#ifdef __VAX +#define inflate INFLATE +#define inflateEnd INFLATEEND +#define inflateInit2_ INFLATEINIT2_ +#define inflateInit_ INFLATEINIT_ +#define zlibVersion ZLIBVERSION +#endif + +/* Older VAX OpenSSL port defines these as Macros */ +/* Need to include the headers first and then redefine */ +/* that way a newer port will also work if some one has one */ +#ifdef __VAX + +# if (OPENSSL_VERSION_NUMBER < 0x00907001L) +# define des_set_odd_parity DES_SET_ODD_PARITY +# define des_set_key DES_SET_KEY +# define des_ecb_encrypt DES_ECB_ENCRYPT + +# endif +# include +# ifndef OpenSSL_add_all_algorithms +# define OpenSSL_add_all_algorithms OPENSSL_ADD_ALL_ALGORITHMS + void OPENSSL_ADD_ALL_ALGORITHMS(void); +# endif + + /* Curl defines these to lower case and VAX needs them in upper case */ + /* So we need static routines */ +# if (OPENSSL_VERSION_NUMBER < 0x00907001L) + +# undef des_set_odd_parity +# undef DES_set_odd_parity +# undef des_set_key +# undef DES_set_key +# undef des_ecb_encrypt +# undef DES_ecb_encrypt + + static void des_set_odd_parity(des_cblock *key) { + DES_SET_ODD_PARITY(key); + } + + static int des_set_key(const_des_cblock *key, + des_key_schedule schedule) { + return DES_SET_KEY(key, schedule); + } + + static void des_ecb_encrypt(const_des_cblock *input, + des_cblock *output, + des_key_schedule ks, int enc) { + DES_ECB_ENCRYPT(input, output, ks, enc); + } +#endif +/* Need this to stop a macro redefinition error */ +#if OPENSSL_VERSION_NUMBER < 0x00907000L +# ifdef X509_STORE_set_flags +# undef X509_STORE_set_flags +# define X509_STORE_set_flags(x,y) Curl_nop_stmt +# endif +#endif +#endif + +#endif /* HEADER_CURL_SETUP_VMS_H */ diff --git a/project/jni/curl/lib/share.c b/project/jni/curl/lib/share.c index e6b8e7a1f..01503e06e 100644 --- a/project/jni/curl/lib/share.c +++ b/project/jni/curl/lib/share.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,13 +20,12 @@ * ***************************************************************************/ -#include "setup.h" -#include -#include -#include +#include "curl_setup.h" + #include #include "urldata.h" #include "share.h" +#include "vtls/vtls.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -36,9 +35,15 @@ CURLSH * curl_share_init(void) { struct Curl_share *share = calloc(1, sizeof(struct Curl_share)); - if(share) + if(share) { share->specifier |= (1<hostcache)) { + free(share); + return NULL; + } + } + return share; } @@ -52,6 +57,7 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) curl_lock_function lockfunc; curl_unlock_function unlockfunc; void *ptr; + CURLSHcode res = CURLSHE_OK; if(share->dirty) /* don't allow setting options while one or more handles are already @@ -67,28 +73,40 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) share->specifier |= (1<hostcache) { - share->hostcache = Curl_mk_dnscache(); - if(!share->hostcache) - return CURLSHE_NOMEM; - } break; -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) case CURL_LOCK_DATA_COOKIE: +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) if(!share->cookies) { share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE ); if(!share->cookies) - return CURLSHE_NOMEM; + res = CURLSHE_NOMEM; } +#else /* CURL_DISABLE_HTTP */ + res = CURLSHE_NOT_BUILT_IN; +#endif + break; + + case CURL_LOCK_DATA_SSL_SESSION: +#ifdef USE_SSL + if(!share->sslsession) { + share->max_ssl_sessions = 8; + share->sslsession = calloc(share->max_ssl_sessions, + sizeof(struct curl_ssl_session)); + share->sessionage = 0; + if(!share->sslsession) + res = CURLSHE_NOMEM; + } +#else + res = CURLSHE_NOT_BUILT_IN; +#endif break; -#endif /* CURL_DISABLE_HTTP */ - case CURL_LOCK_DATA_SSL_SESSION: /* not supported (yet) */ case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */ + break; default: - return CURLSHE_BAD_OPTION; + res = CURLSHE_BAD_OPTION; } break; @@ -96,32 +114,35 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) /* this is a type this share will no longer share */ type = va_arg(param, int); share->specifier &= ~(1<hostcache) { - Curl_hash_destroy(share->hostcache); - share->hostcache = NULL; - } - break; + switch( type ) { + case CURL_LOCK_DATA_DNS: + break; + case CURL_LOCK_DATA_COOKIE: #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - case CURL_LOCK_DATA_COOKIE: - if(share->cookies) { - Curl_cookie_cleanup(share->cookies); - share->cookies = NULL; - } - break; -#endif /* CURL_DISABLE_HTTP */ + if(share->cookies) { + Curl_cookie_cleanup(share->cookies); + share->cookies = NULL; + } +#else /* CURL_DISABLE_HTTP */ + res = CURLSHE_NOT_BUILT_IN; +#endif + break; - case CURL_LOCK_DATA_SSL_SESSION: - break; + case CURL_LOCK_DATA_SSL_SESSION: +#ifdef USE_SSL + Curl_safefree(share->sslsession); +#else + res = CURLSHE_NOT_BUILT_IN; +#endif + break; - case CURL_LOCK_DATA_CONNECT: - break; + case CURL_LOCK_DATA_CONNECT: + break; - default: - return CURLSHE_BAD_OPTION; + default: + res = CURLSHE_BAD_OPTION; + break; } break; @@ -141,10 +162,13 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) break; default: - return CURLSHE_BAD_OPTION; + res = CURLSHE_BAD_OPTION; + break; } - return CURLSHE_OK; + va_end(param); + + return res; } CURLSHcode @@ -165,15 +189,20 @@ curl_share_cleanup(CURLSH *sh) return CURLSHE_IN_USE; } - if(share->hostcache) { - Curl_hash_destroy(share->hostcache); - share->hostcache = NULL; - } + Curl_hash_destroy(&share->hostcache); #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - if(share->cookies) - Curl_cookie_cleanup(share->cookies); -#endif /* CURL_DISABLE_HTTP */ + Curl_cookie_cleanup(share->cookies); +#endif + +#ifdef USE_SSL + if(share->sslsession) { + size_t i; + for(i = 0; i < share->max_ssl_sessions; i++) + Curl_ssl_kill_session(&(share->sslsession[i])); + free(share->sslsession); + } +#endif if(share->unlockfunc) share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata); diff --git a/project/jni/curl/lib/share.h b/project/jni/curl/lib/share.h index ea8e233d2..d23d3a040 100644 --- a/project/jni/curl/lib/share.h +++ b/project/jni/curl/lib/share.h @@ -1,6 +1,5 @@ -#ifndef __CURL_SHARE_H -#define __CURL_SHARE_H - +#ifndef HEADER_CURL_SHARE_H +#define HEADER_CURL_SHARE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -8,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -23,9 +22,10 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #include #include "cookie.h" +#include "urldata.h" /* SalfordC says "A structure member may not be volatile". Hence: */ @@ -44,12 +44,18 @@ struct Curl_share { curl_unlock_function unlockfunc; void *clientdata; - struct curl_hash *hostcache; + struct curl_hash hostcache; +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) struct CookieInfo *cookies; +#endif + + struct curl_ssl_session *sslsession; + size_t max_ssl_sessions; + long sessionage; }; CURLSHcode Curl_share_lock (struct SessionHandle *, curl_lock_data, curl_lock_access); CURLSHcode Curl_share_unlock (struct SessionHandle *, curl_lock_data); -#endif /* __CURL_SHARE_H */ +#endif /* HEADER_CURL_SHARE_H */ diff --git a/project/jni/curl/lib/sigpipe.h b/project/jni/curl/lib/sigpipe.h new file mode 100644 index 000000000..6559c7424 --- /dev/null +++ b/project/jni/curl/lib/sigpipe.h @@ -0,0 +1,78 @@ +#ifndef HEADER_CURL_SIGPIPE_H +#define HEADER_CURL_SIGPIPE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curl_setup.h" + +#if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGACTION) && defined(USE_OPENSSL) +#include + +struct sigpipe_ignore { + struct sigaction old_pipe_act; + bool no_signal; +}; + +#define SIGPIPE_VARIABLE(x) struct sigpipe_ignore x + +/* + * sigpipe_ignore() makes sure we ignore SIGPIPE while running libcurl + * internals, and then sigpipe_restore() will restore the situation when we + * return from libcurl again. + */ +static void sigpipe_ignore(struct SessionHandle *data, + struct sigpipe_ignore *ig) +{ + /* get a local copy of no_signal because the SessionHandle might not be + around when we restore */ + ig->no_signal = data->set.no_signal; + if(!data->set.no_signal) { + struct sigaction action; + /* first, extract the existing situation */ + memset(&ig->old_pipe_act, 0, sizeof(struct sigaction)); + sigaction(SIGPIPE, NULL, &ig->old_pipe_act); + action = ig->old_pipe_act; + /* ignore this signal */ + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); + } +} + +/* + * sigpipe_restore() puts back the outside world's opinion of signal handler + * and SIGPIPE handling. It MUST only be called after a corresponding + * sigpipe_ignore() was used. + */ +static void sigpipe_restore(struct sigpipe_ignore *ig) +{ + if(!ig->no_signal) + /* restore the outside state */ + sigaction(SIGPIPE, &ig->old_pipe_act, NULL); +} + +#else +/* for systems without sigaction */ +#define sigpipe_ignore(x,y) Curl_nop_stmt +#define sigpipe_restore(x) Curl_nop_stmt +#define SIGPIPE_VARIABLE(x) +#endif + +#endif /* HEADER_CURL_SIGPIPE_H */ diff --git a/project/jni/curl/lib/slist.c b/project/jni/curl/lib/slist.c index 7c0f67b1c..37ce97cbd 100644 --- a/project/jni/curl/lib/slist.c +++ b/project/jni/curl/lib/slist.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,17 +20,12 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#include -#include -#include - -#include -#include "curl_memory.h" #include "slist.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* returns last node in linked list */ @@ -50,6 +45,38 @@ static struct curl_slist *slist_get_last(struct curl_slist *list) return item; } +/* + * Curl_slist_append_nodup() appends a string to the linked list. Rather than + * copying the string in dynamic storage, it takes its ownership. The string + * should have been malloc()ated. Curl_slist_append_nodup always returns + * the address of the first record, so that you can use this function as an + * initialization function as well as an append function. + * If an error occurs, NULL is returned and the string argument is NOT + * released. + */ +struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list, char *data) +{ + struct curl_slist *last; + struct curl_slist *new_item; + + DEBUGASSERT(data); + + new_item = malloc(sizeof(struct curl_slist)); + if(!new_item) + return NULL; + + new_item->next = NULL; + new_item->data = data; + + /* if this is the first item, then new_item *is* the list */ + if(!list) + return new_item; + + last = slist_get_last(list); + last->next = new_item; + return list; +} + /* * curl_slist_append() appends a string to the linked list. It always returns * the address of the first record, so that you can use this function as an @@ -60,32 +87,16 @@ static struct curl_slist *slist_get_last(struct curl_slist *list) struct curl_slist *curl_slist_append(struct curl_slist *list, const char *data) { - struct curl_slist *last; - struct curl_slist *new_item; + char *dupdata = strdup(data); - new_item = malloc(sizeof(struct curl_slist)); - if(new_item) { - char *dupdata = strdup(data); - if(dupdata) { - new_item->next = NULL; - new_item->data = dupdata; - } - else { - free(new_item); - return NULL; - } - } - else + if(!dupdata) return NULL; - if(list) { - last = slist_get_last(list); - last->next = new_item; - return list; - } + list = Curl_slist_append_nodup(list, dupdata); + if(!list) + free(dupdata); - /* if this is the first item, then new_item *is* the list */ - return new_item; + return list; } /* @@ -101,7 +112,7 @@ struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist) while(inlist) { tmp = curl_slist_append(outlist, inlist->data); - if (!tmp) { + if(!tmp) { curl_slist_free_all(outlist); return NULL; } @@ -124,10 +135,7 @@ void curl_slist_free_all(struct curl_slist *list) item = list; do { next = item->next; - - if(item->data) { - free(item->data); - } + Curl_safefree(item->data); free(item); item = next; } while(next); diff --git a/project/jni/curl/lib/slist.h b/project/jni/curl/lib/slist.h index 161b1509e..b3f498c35 100644 --- a/project/jni/curl/lib/slist.h +++ b/project/jni/curl/lib/slist.h @@ -1,5 +1,5 @@ -#ifndef __SLIST_H -#define __SLIST_H +#ifndef HEADER_CURL_SLIST_H +#define HEADER_CURL_SLIST_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -29,4 +29,12 @@ */ struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist); -#endif /* __SLIST_H */ +/* + * Curl_slist_append_nodup() takes ownership of the given string and appends + * it to the list. + */ +struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list, + char *data); + +#endif /* HEADER_CURL_SLIST_H */ + diff --git a/project/jni/curl/lib/smb.c b/project/jni/curl/lib/smb.c new file mode 100644 index 000000000..2c33c1174 --- /dev/null +++ b/project/jni/curl/lib/smb.c @@ -0,0 +1,978 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2014, Bill Nagel , Exacq Technologies + * Copyright (C) 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ + (CURL_SIZEOF_CURL_OFF_T > 4) + +#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) + +#define BUILDING_CURL_SMB_C + +#ifdef HAVE_PROCESS_H +#include +#define getpid _getpid +#endif + +#include "smb.h" +#include "urldata.h" +#include "sendf.h" +#include "multiif.h" +#include "connect.h" +#include "progress.h" +#include "transfer.h" +#include "vtls/vtls.h" +#include "curl_ntlm_core.h" +#include "escape.h" +#include "curl_endian.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* Local API functions */ +static CURLcode smb_setup_connection(struct connectdata *conn); +static CURLcode smb_connect(struct connectdata *conn, bool *done); +static CURLcode smb_connection_state(struct connectdata *conn, bool *done); +static CURLcode smb_request_state(struct connectdata *conn, bool *done); +static CURLcode smb_done(struct connectdata *conn, CURLcode status, + bool premature); +static CURLcode smb_disconnect(struct connectdata *conn, bool dead); +static int smb_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks); +static CURLcode smb_parse_url_path(struct connectdata *conn); + +/* + * SMB handler interface + */ +const struct Curl_handler Curl_handler_smb = { + "SMB", /* scheme */ + smb_setup_connection, /* setup_connection */ + ZERO_NULL, /* do_it */ + smb_done, /* done */ + ZERO_NULL, /* do_more */ + smb_connect, /* connect_it */ + smb_connection_state, /* connecting */ + smb_request_state, /* doing */ + smb_getsock, /* proto_getsock */ + smb_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + smb_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ + PORT_SMB, /* defport */ + CURLPROTO_SMB, /* protocol */ + PROTOPT_NONE /* flags */ +}; + +#ifdef USE_SSL +/* + * SMBS handler interface + */ +const struct Curl_handler Curl_handler_smbs = { + "SMBS", /* scheme */ + smb_setup_connection, /* setup_connection */ + ZERO_NULL, /* do_it */ + smb_done, /* done */ + ZERO_NULL, /* do_more */ + smb_connect, /* connect_it */ + smb_connection_state, /* connecting */ + smb_request_state, /* doing */ + smb_getsock, /* proto_getsock */ + smb_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + smb_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ + PORT_SMBS, /* defport */ + CURLPROTO_SMBS, /* protocol */ + PROTOPT_SSL /* flags */ +}; +#endif + +#define MAX_PAYLOAD_SIZE 0x8000 +#define MAX_MESSAGE_SIZE (MAX_PAYLOAD_SIZE + 0x1000) +#define CLIENTNAME "curl" +#define SERVICENAME "?????" + +/* Append a string to an SMB message */ +#define MSGCAT(str) \ + strcpy(p, (str)); \ + p += strlen(str); + +/* Append a null-terminated string to an SMB message */ +#define MSGCATNULL(str) \ + strcpy(p, (str)); \ + p += strlen(str) + 1; + +/* SMB is mostly little endian */ +#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ + defined(__OS400__) +static unsigned short smb_swap16(unsigned short x) +{ + return (unsigned short) ((x << 8) | ((x >> 8) & 0xff)); +} + +static unsigned int smb_swap32(unsigned int x) +{ + return (x << 24) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | + ((x >> 24) & 0xff); +} + +#ifdef HAVE_LONGLONG +static unsigned long long smb_swap64(unsigned long long x) +{ + return ((unsigned long long) smb_swap32((unsigned int) x) << 32) | + smb_swap32((unsigned int) (x >> 32)); +} +#else +static unsigned __int64 smb_swap64(unsigned __int64 x) +{ + return ((unsigned __int64) smb_swap32((unsigned int) x) << 32) | + smb_swap32((unsigned int) (x >> 32)); +} +#endif +#else +# define smb_swap16(x) (x) +# define smb_swap32(x) (x) +# define smb_swap64(x) (x) +#endif + +/* SMB request state */ +enum smb_req_state { + SMB_REQUESTING, + SMB_TREE_CONNECT, + SMB_OPEN, + SMB_DOWNLOAD, + SMB_UPLOAD, + SMB_CLOSE, + SMB_TREE_DISCONNECT, + SMB_DONE +}; + +/* SMB request data */ +struct smb_request { + enum smb_req_state state; + char *share; + char *path; + unsigned short tid; /* Even if we connect to the same tree as another */ + unsigned short fid; /* request, the tid will be different */ + CURLcode result; +}; + +static void conn_state(struct connectdata *conn, enum smb_conn_state newstate) +{ + struct smb_conn *smb = &conn->proto.smbc; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* For debug purposes */ + static const char * const names[] = { + "SMB_NOT_CONNECTED", + "SMB_CONNECTING", + "SMB_NEGOTIATE", + "SMB_SETUP", + "SMB_CONNECTED", + /* LAST */ + }; + + if(smb->state != newstate) + infof(conn->data, "SMB conn %p state change from %s to %s\n", + (void *)smb, names[smb->state], names[newstate]); +#endif + + smb->state = newstate; +} + +static void request_state(struct connectdata *conn, + enum smb_req_state newstate) +{ + struct smb_request *req = conn->data->req.protop; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* For debug purposes */ + static const char * const names[] = { + "SMB_REQUESTING", + "SMB_TREE_CONNECT", + "SMB_OPEN", + "SMB_DOWNLOAD", + "SMB_UPLOAD", + "SMB_CLOSE", + "SMB_TREE_DISCONNECT", + "SMB_DONE", + /* LAST */ + }; + + if(req->state != newstate) + infof(conn->data, "SMB request %p state change from %s to %s\n", + (void *)req, names[req->state], names[newstate]); +#endif + + req->state = newstate; +} + +static CURLcode smb_setup_connection(struct connectdata *conn) +{ + struct smb_request *req; + + /* Initialize the request state */ + conn->data->req.protop = req = calloc(1, sizeof(struct smb_request)); + if(!req) + return CURLE_OUT_OF_MEMORY; + + /* Parse the URL path */ + return smb_parse_url_path(conn); +} + +static CURLcode smb_connect(struct connectdata *conn, bool *done) +{ + struct smb_conn *smbc = &conn->proto.smbc; + char *slash; + + (void) done; + + /* Check we have a username and password to authenticate with */ + if(!conn->bits.user_passwd) + return CURLE_LOGIN_DENIED; + + /* Initialize the connection state */ + memset(smbc, 0, sizeof(*smbc)); + smbc->state = SMB_CONNECTING; + smbc->recv_buf = malloc(MAX_MESSAGE_SIZE); + if(!smbc->recv_buf) + return CURLE_OUT_OF_MEMORY; + + /* Multiple requests are allowed with this connection */ + connkeep(conn, "SMB default"); + + /* Parse the username, domain, and password */ + slash = strchr(conn->user, '/'); + if(!slash) + slash = strchr(conn->user, '\\'); + + if(slash) { + smbc->user = slash + 1; + smbc->domain = strdup(conn->user); + if(!smbc->domain) + return CURLE_OUT_OF_MEMORY; + smbc->domain[slash - conn->user] = 0; + } + else { + smbc->user = conn->user; + smbc->domain = strdup(conn->host.name); + if(!smbc->domain) + return CURLE_OUT_OF_MEMORY; + } + + return CURLE_OK; +} + +static CURLcode smb_recv_message(struct connectdata *conn, void **msg) +{ + struct smb_conn *smbc = &conn->proto.smbc; + char *buf = smbc->recv_buf; + ssize_t bytes_read; + size_t nbt_size; + size_t msg_size; + size_t len = MAX_MESSAGE_SIZE - smbc->got; + CURLcode result; + + result = Curl_read(conn, FIRSTSOCKET, buf + smbc->got, len, &bytes_read); + if(result) + return result; + + if(!bytes_read) + return CURLE_OK; + + smbc->got += bytes_read; + + /* Check for a 32-bit nbt header */ + if(smbc->got < sizeof(unsigned int)) + return CURLE_OK; + + nbt_size = Curl_read16_be((unsigned char *)(buf + sizeof(unsigned short))) + + sizeof(unsigned int); + if(smbc->got < nbt_size) + return CURLE_OK; + + msg_size = sizeof(struct smb_header); + if(nbt_size >= msg_size + 1) { + /* Add the word count */ + msg_size += 1 + ((unsigned char) buf[msg_size]) * sizeof(unsigned short); + if(nbt_size >= msg_size + sizeof(unsigned short)) { + /* Add the byte count */ + msg_size += sizeof(unsigned short) + + Curl_read16_le((unsigned char *)&buf[msg_size]); + if(nbt_size < msg_size) + return CURLE_READ_ERROR; + } + } + + *msg = buf; + + return CURLE_OK; +} + +static void smb_pop_message(struct connectdata *conn) +{ + struct smb_conn *smbc = &conn->proto.smbc; + + smbc->got = 0; +} + +static void smb_format_message(struct connectdata *conn, struct smb_header *h, + unsigned char cmd, size_t len) +{ + struct smb_conn *smbc = &conn->proto.smbc; + struct smb_request *req = conn->data->req.protop; + unsigned int pid; + + memset(h, 0, sizeof(*h)); + h->nbt_length = htons((unsigned short) (sizeof(*h) - sizeof(unsigned int) + + len)); + memcpy((char *)h->magic, "\xffSMB", 4); + h->command = cmd; + h->flags = SMB_FLAGS_CANONICAL_PATHNAMES | SMB_FLAGS_CASELESS_PATHNAMES; + h->flags2 = smb_swap16(SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_KNOWS_LONG_NAME); + h->uid = smb_swap16(smbc->uid); + h->tid = smb_swap16(req->tid); + pid = getpid(); + h->pid_high = smb_swap16((unsigned short)(pid >> 16)); + h->pid = smb_swap16((unsigned short) pid); +} + +static CURLcode smb_send(struct connectdata *conn, ssize_t len, + size_t upload_size) +{ + struct smb_conn *smbc = &conn->proto.smbc; + ssize_t bytes_written; + CURLcode result; + + result = Curl_write(conn, FIRSTSOCKET, conn->data->state.uploadbuffer, + len, &bytes_written); + if(result) + return result; + + if(bytes_written != len) { + smbc->send_size = len; + smbc->sent = bytes_written; + } + + smbc->upload_size = upload_size; + + return CURLE_OK; +} + +static CURLcode smb_flush(struct connectdata *conn) +{ + struct smb_conn *smbc = &conn->proto.smbc; + ssize_t bytes_written; + ssize_t len = smbc->send_size - smbc->sent; + CURLcode result; + + if(!smbc->send_size) + return CURLE_OK; + + result = Curl_write(conn, FIRSTSOCKET, + conn->data->state.uploadbuffer + smbc->sent, + len, &bytes_written); + if(result) + return result; + + if(bytes_written != len) + smbc->sent += bytes_written; + else + smbc->send_size = 0; + + return CURLE_OK; +} + +static CURLcode smb_send_message(struct connectdata *conn, unsigned char cmd, + const void *msg, size_t msg_len) +{ + smb_format_message(conn, (struct smb_header *)conn->data->state.uploadbuffer, + cmd, msg_len); + memcpy(conn->data->state.uploadbuffer + sizeof(struct smb_header), + msg, msg_len); + + return smb_send(conn, sizeof(struct smb_header) + msg_len, 0); +} + +static CURLcode smb_send_negotiate(struct connectdata *conn) +{ + const char *msg = "\x00\x0c\x00\x02NT LM 0.12"; + + return smb_send_message(conn, SMB_COM_NEGOTIATE, msg, 15); +} + +static CURLcode smb_send_setup(struct connectdata *conn) +{ + struct smb_conn *smbc = &conn->proto.smbc; + struct smb_setup msg; + char *p = msg.bytes; + unsigned char lm_hash[21]; + unsigned char lm[24]; + unsigned char nt_hash[21]; + unsigned char nt[24]; + + size_t byte_count = sizeof(lm) + sizeof(nt); + byte_count += strlen(smbc->user) + strlen(smbc->domain); + byte_count += strlen(OS) + strlen(CLIENTNAME) + 4; /* 4 null chars */ + if(byte_count > sizeof(msg.bytes)) + return CURLE_FILESIZE_EXCEEDED; + + Curl_ntlm_core_mk_lm_hash(conn->data, conn->passwd, lm_hash); + Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm); +#if USE_NTRESPONSES + Curl_ntlm_core_mk_nt_hash(conn->data, conn->passwd, nt_hash); + Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt); +#else + memset(nt, 0, sizeof(nt)); +#endif + + memset(&msg, 0, sizeof(msg)); + msg.word_count = SMB_WC_SETUP_ANDX; + msg.andx.command = SMB_COM_NO_ANDX_COMMAND; + msg.max_buffer_size = smb_swap16(MAX_MESSAGE_SIZE); + msg.max_mpx_count = smb_swap16(1); + msg.vc_number = smb_swap16(1); + msg.session_key = smb_swap32(smbc->session_key); + msg.capabilities = smb_swap32(SMB_CAP_LARGE_FILES); + msg.lengths[0] = smb_swap16(sizeof(lm)); + msg.lengths[1] = smb_swap16(sizeof(nt)); + memcpy(p, lm, sizeof(lm)); + p += sizeof(lm); + memcpy(p, nt, sizeof(nt)); + p += sizeof(nt); + MSGCATNULL(smbc->user); + MSGCATNULL(smbc->domain); + MSGCATNULL(OS); + MSGCATNULL(CLIENTNAME); + byte_count = p - msg.bytes; + msg.byte_count = smb_swap16((unsigned short)byte_count); + + return smb_send_message(conn, SMB_COM_SETUP_ANDX, &msg, + sizeof(msg) - sizeof(msg.bytes) + byte_count); +} + +static CURLcode smb_send_tree_connect(struct connectdata *conn) +{ + struct smb_request *req = conn->data->req.protop; + struct smb_tree_connect msg; + char *p = msg.bytes; + + size_t byte_count = strlen(conn->host.name) + strlen(req->share); + byte_count += strlen(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */ + if(byte_count > sizeof(msg.bytes)) + return CURLE_FILESIZE_EXCEEDED; + + memset(&msg, 0, sizeof(msg)); + msg.word_count = SMB_WC_TREE_CONNECT_ANDX; + msg.andx.command = SMB_COM_NO_ANDX_COMMAND; + msg.pw_len = 0; + MSGCAT("\\\\"); + MSGCAT(conn->host.name); + MSGCAT("\\"); + MSGCATNULL(req->share); + MSGCATNULL(SERVICENAME); /* Match any type of service */ + byte_count = p - msg.bytes; + msg.byte_count = smb_swap16((unsigned short)byte_count); + + return smb_send_message(conn, SMB_COM_TREE_CONNECT_ANDX, &msg, + sizeof(msg) - sizeof(msg.bytes) + byte_count); +} + +static CURLcode smb_send_open(struct connectdata *conn) +{ + struct smb_request *req = conn->data->req.protop; + struct smb_nt_create msg; + size_t byte_count; + + if((strlen(req->path) + 1) > sizeof(msg.bytes)) + return CURLE_FILESIZE_EXCEEDED; + + memset(&msg, 0, sizeof(msg)); + msg.word_count = SMB_WC_NT_CREATE_ANDX; + msg.andx.command = SMB_COM_NO_ANDX_COMMAND; + byte_count = strlen(req->path); + msg.name_length = smb_swap16((unsigned short)byte_count); + msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL); + if(conn->data->set.upload) { + msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE); + msg.create_disposition = smb_swap32(SMB_FILE_OVERWRITE_IF); + } + else { + msg.access = smb_swap32(SMB_GENERIC_READ); + msg.create_disposition = smb_swap32(SMB_FILE_OPEN); + } + msg.byte_count = smb_swap16((unsigned short) ++byte_count); + strcpy(msg.bytes, req->path); + + return smb_send_message(conn, SMB_COM_NT_CREATE_ANDX, &msg, + sizeof(msg) - sizeof(msg.bytes) + byte_count); +} + +static CURLcode smb_send_close(struct connectdata *conn) +{ + struct smb_request *req = conn->data->req.protop; + struct smb_close msg; + + memset(&msg, 0, sizeof(msg)); + msg.word_count = SMB_WC_CLOSE; + msg.fid = smb_swap16(req->fid); + + return smb_send_message(conn, SMB_COM_CLOSE, &msg, sizeof(msg)); +} + +static CURLcode smb_send_tree_disconnect(struct connectdata *conn) +{ + struct smb_tree_disconnect msg; + + memset(&msg, 0, sizeof(msg)); + + return smb_send_message(conn, SMB_COM_TREE_DISCONNECT, &msg, sizeof(msg)); +} + +static CURLcode smb_send_read(struct connectdata *conn) +{ + struct smb_request *req = conn->data->req.protop; + curl_off_t offset = conn->data->req.offset; + struct smb_read msg; + + memset(&msg, 0, sizeof(msg)); + msg.word_count = SMB_WC_READ_ANDX; + msg.andx.command = SMB_COM_NO_ANDX_COMMAND; + msg.fid = smb_swap16(req->fid); + msg.offset = smb_swap32((unsigned int) offset); + msg.offset_high = smb_swap32((unsigned int) (offset >> 32)); + msg.min_bytes = smb_swap16(MAX_PAYLOAD_SIZE); + msg.max_bytes = smb_swap16(MAX_PAYLOAD_SIZE); + + return smb_send_message(conn, SMB_COM_READ_ANDX, &msg, sizeof(msg)); +} + +static CURLcode smb_send_write(struct connectdata *conn) +{ + struct smb_write *msg = (struct smb_write *)conn->data->state.uploadbuffer; + struct smb_request *req = conn->data->req.protop; + curl_off_t offset = conn->data->req.offset; + + curl_off_t upload_size = conn->data->req.size - conn->data->req.bytecount; + if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */ + upload_size = MAX_PAYLOAD_SIZE - 1; + + memset(msg, 0, sizeof(*msg)); + msg->word_count = SMB_WC_WRITE_ANDX; + msg->andx.command = SMB_COM_NO_ANDX_COMMAND; + msg->fid = smb_swap16(req->fid); + msg->offset = smb_swap32((unsigned int) offset); + msg->offset_high = smb_swap32((unsigned int) (offset >> 32)); + msg->data_length = smb_swap16((unsigned short) upload_size); + msg->data_offset = smb_swap16(sizeof(*msg) - sizeof(unsigned int)); + msg->byte_count = smb_swap16((unsigned short) (upload_size + 1)); + + smb_format_message(conn, &msg->h, SMB_COM_WRITE_ANDX, + sizeof(*msg) - sizeof(msg->h) + (size_t) upload_size); + + return smb_send(conn, sizeof(*msg), (size_t) upload_size); +} + +static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg) +{ + struct smb_conn *smbc = &conn->proto.smbc; + CURLcode result; + + /* Check if there is data in the transfer buffer */ + if(!smbc->send_size && smbc->upload_size) { + int nread = smbc->upload_size > BUFSIZE ? BUFSIZE : + (int) smbc->upload_size; + conn->data->req.upload_fromhere = conn->data->state.uploadbuffer; + result = Curl_fillreadbuffer(conn, nread, &nread); + if(result && result != CURLE_AGAIN) + return result; + if(!nread) + return CURLE_OK; + + smbc->upload_size -= nread; + smbc->send_size = nread; + smbc->sent = 0; + } + + /* Check if there is data to send */ + if(smbc->send_size) { + result = smb_flush(conn); + if(result) + return result; + } + + /* Check if there is still data to be sent */ + if(smbc->send_size || smbc->upload_size) + return CURLE_AGAIN; + + return smb_recv_message(conn, msg); +} + +static CURLcode smb_connection_state(struct connectdata *conn, bool *done) +{ + struct smb_conn *smbc = &conn->proto.smbc; + struct smb_negotiate_response *nrsp; + struct smb_header *h; + CURLcode result; + void *msg = NULL; + + if(smbc->state == SMB_CONNECTING) { +#ifdef USE_SSL + if((conn->handler->flags & PROTOPT_SSL)) { + bool ssl_done; + result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &ssl_done); + if(result && result != CURLE_AGAIN) + return result; + if(!ssl_done) + return CURLE_OK; + } +#endif + + result = smb_send_negotiate(conn); + if(result) { + connclose(conn, "SMB: failed to send negotiate message"); + return result; + } + + conn_state(conn, SMB_NEGOTIATE); + } + + /* Send the previous message and check for a response */ + result = smb_send_and_recv(conn, &msg); + if(result && result != CURLE_AGAIN) { + connclose(conn, "SMB: failed to communicate"); + return result; + } + + if(!msg) + return CURLE_OK; + + h = msg; + + switch(smbc->state) { + case SMB_NEGOTIATE: + if(h->status) { + connclose(conn, "SMB: negotiation failed"); + return CURLE_COULDNT_CONNECT; + } + nrsp = msg; + memcpy(smbc->challenge, nrsp->bytes, sizeof(smbc->challenge)); + smbc->session_key = smb_swap32(nrsp->session_key); + result = smb_send_setup(conn); + if(result) { + connclose(conn, "SMB: failed to send setup message"); + return result; + } + conn_state(conn, SMB_SETUP); + break; + + case SMB_SETUP: + if(h->status) { + connclose(conn, "SMB: authentication failed"); + return CURLE_LOGIN_DENIED; + } + smbc->uid = smb_swap16(h->uid); + conn_state(conn, SMB_CONNECTED); + *done = true; + break; + + default: + smb_pop_message(conn); + return CURLE_OK; /* ignore */ + } + + smb_pop_message(conn); + + return CURLE_OK; +} + +static CURLcode smb_request_state(struct connectdata *conn, bool *done) +{ + struct smb_request *req = conn->data->req.protop; + struct smb_header *h; + enum smb_req_state next_state = SMB_DONE; + unsigned short len; + unsigned short off; + CURLcode result; + void *msg = NULL; + + /* Start the request */ + if(req->state == SMB_REQUESTING) { + result = smb_send_tree_connect(conn); + if(result) { + connclose(conn, "SMB: failed to send tree connect message"); + return result; + } + + request_state(conn, SMB_TREE_CONNECT); + } + + /* Send the previous message and check for a response */ + result = smb_send_and_recv(conn, &msg); + if(result && result != CURLE_AGAIN) { + connclose(conn, "SMB: failed to communicate"); + return result; + } + + if(!msg) + return CURLE_OK; + + h = msg; + + switch(req->state) { + case SMB_TREE_CONNECT: + if(h->status) { + req->result = CURLE_REMOTE_FILE_NOT_FOUND; + if(h->status == smb_swap32(SMB_ERR_NOACCESS)) + req->result = CURLE_REMOTE_ACCESS_DENIED; + break; + } + req->tid = smb_swap16(h->tid); + next_state = SMB_OPEN; + break; + + case SMB_OPEN: + if(h->status) { + req->result = CURLE_REMOTE_FILE_NOT_FOUND; + next_state = SMB_TREE_DISCONNECT; + break; + } + req->fid = smb_swap16(((struct smb_nt_create_response *)msg)->fid); + conn->data->req.offset = 0; + if(conn->data->set.upload) { + conn->data->req.size = conn->data->state.infilesize; + Curl_pgrsSetUploadSize(conn->data, conn->data->req.size); + next_state = SMB_UPLOAD; + } + else { + conn->data->req.size = + smb_swap64(((struct smb_nt_create_response *)msg)->end_of_file); + Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size); + next_state = SMB_DOWNLOAD; + } + break; + + case SMB_DOWNLOAD: + if(h->status) { + req->result = CURLE_RECV_ERROR; + next_state = SMB_CLOSE; + break; + } + len = Curl_read16_le(((unsigned char *) msg) + + sizeof(struct smb_header) + 11); + off = Curl_read16_le(((unsigned char *) msg) + + sizeof(struct smb_header) + 13); + if(len > 0) { + struct smb_conn *smbc = &conn->proto.smbc; + if(off + sizeof(unsigned int) + len > smbc->got) { + failf(conn->data, "Invalid input packet"); + result = CURLE_RECV_ERROR; + } + else + result = Curl_client_write(conn, CLIENTWRITE_BODY, + (char *)msg + off + sizeof(unsigned int), + len); + if(result) { + req->result = result; + next_state = SMB_CLOSE; + break; + } + } + conn->data->req.bytecount += len; + conn->data->req.offset += len; + Curl_pgrsSetDownloadCounter(conn->data, conn->data->req.bytecount); + next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD; + break; + + case SMB_UPLOAD: + if(h->status) { + req->result = CURLE_UPLOAD_FAILED; + next_state = SMB_CLOSE; + break; + } + len = Curl_read16_le(((unsigned char *) msg) + + sizeof(struct smb_header) + 5); + conn->data->req.bytecount += len; + conn->data->req.offset += len; + Curl_pgrsSetUploadCounter(conn->data, conn->data->req.bytecount); + if(conn->data->req.bytecount >= conn->data->req.size) + next_state = SMB_CLOSE; + else + next_state = SMB_UPLOAD; + break; + + case SMB_CLOSE: + /* We don't care if the close failed, proceed to tree disconnect anyway */ + next_state = SMB_TREE_DISCONNECT; + break; + + case SMB_TREE_DISCONNECT: + next_state = SMB_DONE; + break; + + default: + smb_pop_message(conn); + return CURLE_OK; /* ignore */ + } + + smb_pop_message(conn); + + switch(next_state) { + case SMB_OPEN: + result = smb_send_open(conn); + break; + + case SMB_DOWNLOAD: + result = smb_send_read(conn); + break; + + case SMB_UPLOAD: + result = smb_send_write(conn); + break; + + case SMB_CLOSE: + result = smb_send_close(conn); + break; + + case SMB_TREE_DISCONNECT: + result = smb_send_tree_disconnect(conn); + break; + + case SMB_DONE: + result = req->result; + *done = true; + break; + + default: + break; + } + + if(result) { + connclose(conn, "SMB: failed to send message"); + return result; + } + + request_state(conn, next_state); + + return CURLE_OK; +} + +static CURLcode smb_done(struct connectdata *conn, CURLcode status, + bool premature) +{ + struct smb_request *req = conn->data->req.protop; + + (void) premature; + + Curl_safefree(req->share); + Curl_safefree(conn->data->req.protop); + + return status; +} + +static CURLcode smb_disconnect(struct connectdata *conn, bool dead) +{ + struct smb_conn *smbc = &conn->proto.smbc; + struct smb_request *req = conn->data->req.protop; + + (void) dead; + + Curl_safefree(smbc->domain); + Curl_safefree(smbc->recv_buf); + + /* smb_done is not always called, so cleanup the request */ + if(req) { + Curl_safefree(req->share); + Curl_safefree(conn->data->req.protop); + } + + return CURLE_OK; +} + +static int smb_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks) +{ + struct smb_conn *smbc = &conn->proto.smbc; + + if(!numsocks) + return GETSOCK_BLANK; + + socks[0] = conn->sock[FIRSTSOCKET]; + + if(smbc->send_size || smbc->upload_size) + return GETSOCK_WRITESOCK(0); + + return GETSOCK_READSOCK(0); +} + +static CURLcode smb_parse_url_path(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct smb_request *req = data->req.protop; + char *path; + char *slash; + + /* URL decode the path */ + result = Curl_urldecode(data, data->state.path, 0, &path, NULL, TRUE); + if(result) + return result; + + /* Parse the path for the share */ + req->share = strdup((*path == '/' || *path == '\\') ? path + 1 : path); + if(!req->share) { + free(path); + + return CURLE_OUT_OF_MEMORY; + } + + slash = strchr(req->share, '/'); + if(!slash) + slash = strchr(req->share, '\\'); + + /* The share must be present */ + if(!slash) { + free(path); + + return CURLE_URL_MALFORMAT; + } + + /* Parse the path for the file path converting any forward slashes into + backslashes */ + *slash++ = 0; + req->path = slash; + for(; *slash; slash++) { + if(*slash == '/') + *slash = '\\'; + } + + free(path); + + return CURLE_OK; +} + +#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ + +#endif /* CURL_DISABLE_SMB && USE_NTLM && CURL_SIZEOF_CURL_OFF_T > 4 */ diff --git a/project/jni/curl/lib/smb.h b/project/jni/curl/lib/smb.h new file mode 100644 index 000000000..1a4f66e5a --- /dev/null +++ b/project/jni/curl/lib/smb.h @@ -0,0 +1,271 @@ +#ifndef HEADER_CURL_SMB_H +#define HEADER_CURL_SMB_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2014, Bill Nagel , Exacq Technologies + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +enum smb_conn_state { + SMB_NOT_CONNECTED = 0, + SMB_CONNECTING, + SMB_NEGOTIATE, + SMB_SETUP, + SMB_CONNECTED +}; + +struct smb_conn { + enum smb_conn_state state; + char *user; + char *domain; + unsigned char challenge[8]; + unsigned int session_key; + unsigned short uid; + char *recv_buf; + size_t upload_size; + size_t send_size; + size_t sent; + size_t got; +}; + +/* + * Definitions for SMB protocol data structures + */ +#ifdef BUILDING_CURL_SMB_C + +#if defined(_MSC_VER) || defined(__ILEC400__) +# define PACK +# pragma pack(push) +# pragma pack(1) +#elif defined(__GNUC__) +# define PACK __attribute__((packed)) +#else +# define PACK +#endif + +#define SMB_COM_CLOSE 0x04 +#define SMB_COM_READ_ANDX 0x2e +#define SMB_COM_WRITE_ANDX 0x2f +#define SMB_COM_TREE_DISCONNECT 0x71 +#define SMB_COM_NEGOTIATE 0x72 +#define SMB_COM_SETUP_ANDX 0x73 +#define SMB_COM_TREE_CONNECT_ANDX 0x75 +#define SMB_COM_NT_CREATE_ANDX 0xa2 +#define SMB_COM_NO_ANDX_COMMAND 0xff + +#define SMB_WC_CLOSE 0x03 +#define SMB_WC_READ_ANDX 0x0c +#define SMB_WC_WRITE_ANDX 0x0e +#define SMB_WC_SETUP_ANDX 0x0d +#define SMB_WC_TREE_CONNECT_ANDX 0x04 +#define SMB_WC_NT_CREATE_ANDX 0x18 + +#define SMB_FLAGS_CANONICAL_PATHNAMES 0x10 +#define SMB_FLAGS_CASELESS_PATHNAMES 0x08 +#define SMB_FLAGS2_UNICODE_STRINGS 0x8000 +#define SMB_FLAGS2_IS_LONG_NAME 0x0040 +#define SMB_FLAGS2_KNOWS_LONG_NAME 0x0001 + +#define SMB_CAP_LARGE_FILES 0x08 +#define SMB_GENERIC_WRITE 0x40000000 +#define SMB_GENERIC_READ 0x80000000 +#define SMB_FILE_SHARE_ALL 0x07 +#define SMB_FILE_OPEN 0x01 +#define SMB_FILE_OVERWRITE_IF 0x05 + +#define SMB_ERR_NOACCESS 0x00050001 + +struct smb_header { + unsigned char nbt_type; + unsigned char nbt_flags; + unsigned short nbt_length; + unsigned char magic[4]; + unsigned char command; + unsigned int status; + unsigned char flags; + unsigned short flags2; + unsigned short pid_high; + unsigned char signature[8]; + unsigned short pad; + unsigned short tid; + unsigned short pid; + unsigned short uid; + unsigned short mid; +} PACK; + +struct smb_negotiate_response { + struct smb_header h; + unsigned char word_count; + unsigned short dialect_index; + unsigned char security_mode; + unsigned short max_mpx_count; + unsigned short max_number_vcs; + unsigned int max_buffer_size; + unsigned int max_raw_size; + unsigned int session_key; + unsigned int capabilities; + unsigned int system_time_low; + unsigned int system_time_high; + unsigned short server_time_zone; + unsigned char encryption_key_length; + unsigned short byte_count; + char bytes[1]; +} PACK; + +struct andx { + unsigned char command; + unsigned char pad; + unsigned short offset; +} PACK; + +struct smb_setup { + unsigned char word_count; + struct andx andx; + unsigned short max_buffer_size; + unsigned short max_mpx_count; + unsigned short vc_number; + unsigned int session_key; + unsigned short lengths[2]; + unsigned int pad; + unsigned int capabilities; + unsigned short byte_count; + char bytes[1024]; +} PACK; + +struct smb_tree_connect { + unsigned char word_count; + struct andx andx; + unsigned short flags; + unsigned short pw_len; + unsigned short byte_count; + char bytes[1024]; +} PACK; + +struct smb_nt_create { + unsigned char word_count; + struct andx andx; + unsigned char pad; + unsigned short name_length; + unsigned int flags; + unsigned int root_fid; + unsigned int access; +#ifdef HAVE_LONGLONG + unsigned long long allocation_size; +#else + unsigned __int64 allocation_size; +#endif + unsigned int ext_file_attributes; + unsigned int share_access; + unsigned int create_disposition; + unsigned int create_options; + unsigned int impersonation_level; + unsigned char security_flags; + unsigned short byte_count; + char bytes[1024]; +} PACK; + +struct smb_nt_create_response { + struct smb_header h; + unsigned char word_count; + struct andx andx; + unsigned char op_lock_level; + unsigned short fid; + unsigned int create_disposition; +#ifdef HAVE_LONGLONG + unsigned long long create_time; + unsigned long long last_access_time; + unsigned long long last_write_time; + unsigned long long last_change_time; +#else + unsigned __int64 create_time; + unsigned __int64 last_access_time; + unsigned __int64 last_write_time; + unsigned __int64 last_change_time; +#endif + unsigned int ext_file_attributes; +#ifdef HAVE_LONGLONG + unsigned long long allocation_size; + unsigned long long end_of_file; +#else + unsigned __int64 allocation_size; + unsigned __int64 end_of_file; +#endif +} PACK; + +struct smb_read { + unsigned char word_count; + struct andx andx; + unsigned short fid; + unsigned int offset; + unsigned short max_bytes; + unsigned short min_bytes; + unsigned int timeout; + unsigned short remaining; + unsigned int offset_high; + unsigned short byte_count; +} PACK; + +struct smb_write { + struct smb_header h; + unsigned char word_count; + struct andx andx; + unsigned short fid; + unsigned int offset; + unsigned int timeout; + unsigned short write_mode; + unsigned short remaining; + unsigned short pad; + unsigned short data_length; + unsigned short data_offset; + unsigned int offset_high; + unsigned short byte_count; + unsigned char pad2; +} PACK; + +struct smb_close { + unsigned char word_count; + unsigned short fid; + unsigned int last_mtime; + unsigned short byte_count; +} PACK; + +struct smb_tree_disconnect { + unsigned char word_count; + unsigned short byte_count; +} PACK; + +#if defined(_MSC_VER) || defined(__ILEC400__) +# pragma pack(pop) +#endif + +#endif /* BUILDING_CURL_SMB_C */ + +#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ + (CURL_SIZEOF_CURL_OFF_T > 4) + +#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) + +extern const struct Curl_handler Curl_handler_smb; +extern const struct Curl_handler Curl_handler_smbs; + +#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ + +#endif /* CURL_DISABLE_SMB && USE_NTLM && CURL_SIZEOF_CURL_OFF_T > 4 */ + +#endif /* HEADER_CURL_SMB_H */ diff --git a/project/jni/curl/lib/smtp.c b/project/jni/curl/lib/smtp.c index 82621a42b..83e51bf80 100644 --- a/project/jni/curl/lib/smtp.c +++ b/project/jni/curl/lib/smtp.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -18,30 +18,25 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * - * RFC2821 SMTP protocol - * RFC3207 SMTP over TLS - * RFC4954 SMTP Authentication + * RFC1870 SMTP Service Extension for Message Size * RFC2195 CRAM-MD5 authentication + * RFC2831 DIGEST-MD5 authentication + * RFC3207 SMTP over TLS + * RFC4422 Simple Authentication and Security Layer (SASL) * RFC4616 PLAIN authentication + * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism + * RFC4954 SMTP Authentication + * RFC5321 SMTP protocol + * RFC6749 OAuth 2.0 Authorization Framework + * Draft SMTP URL Interface + * Draft LOGIN SASL Mechanism * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_SMTP -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif @@ -67,9 +62,6 @@ #include #include "urldata.h" #include "sendf.h" -#include "easyif.h" /* for Curl_convert_... prototypes */ - -#include "if2ip.h" #include "hostip.h" #include "progress.h" #include "transfer.h" @@ -80,23 +72,17 @@ #include "strtoofft.h" #include "strequal.h" -#include "sslgen.h" +#include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" #include "rawstr.h" -#include "strtoofft.h" -#include "curl_base64.h" -#include "curl_md5.h" -#include "curl_hmac.h" #include "curl_gethostname.h" +#include "curl_sasl.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -104,18 +90,22 @@ /* Local API functions */ static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done); static CURLcode smtp_do(struct connectdata *conn, bool *done); -static CURLcode smtp_done(struct connectdata *conn, - CURLcode, bool premature); +static CURLcode smtp_done(struct connectdata *conn, CURLcode status, + bool premature); static CURLcode smtp_connect(struct connectdata *conn, bool *done); -static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection); +static CURLcode smtp_disconnect(struct connectdata *conn, bool dead); static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done); -static int smtp_getsock(struct connectdata *conn, - curl_socket_t *socks, +static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks); -static CURLcode smtp_doing(struct connectdata *conn, - bool *dophase_done); -static CURLcode smtp_setup_connection(struct connectdata * conn); - +static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done); +static CURLcode smtp_setup_connection(struct connectdata *conn); +static CURLcode smtp_parse_url_options(struct connectdata *conn); +static CURLcode smtp_parse_url_path(struct connectdata *conn); +static CURLcode smtp_parse_custom_request(struct connectdata *conn); +static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech, + const char *initresp); +static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp); +static void smtp_get_message(char *buffer, char** outptr); /* * SMTP protocol handler. @@ -132,13 +122,15 @@ const struct Curl_handler Curl_handler_smtp = { smtp_doing, /* doing */ smtp_getsock, /* proto_getsock */ smtp_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smtp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_SMTP, /* defport */ - PROT_SMTP /* protocol */ + CURLPROTO_SMTP, /* protocol */ + PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ }; - #ifdef USE_SSL /* * SMTPS protocol handler. @@ -155,10 +147,14 @@ const struct Curl_handler Curl_handler_smtps = { smtp_doing, /* doing */ smtp_getsock, /* proto_getsock */ smtp_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smtp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_SMTPS, /* defport */ - PROT_SMTP | PROT_SMTPS | PROT_SSL /* protocol */ + CURLPROTO_SMTPS, /* protocol */ + PROTOPT_CLOSEACTION | PROTOPT_SSL + | PROTOPT_NOURLQUERY /* flags */ }; #endif @@ -169,7 +165,7 @@ const struct Curl_handler Curl_handler_smtps = { static const struct Curl_handler Curl_handler_smtp_proxy = { "SMTP", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -178,13 +174,15 @@ static const struct Curl_handler Curl_handler_smtp_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_SMTP, /* defport */ - PROT_HTTP /* protocol */ + CURLPROTO_HTTP, /* protocol */ + PROTOPT_NONE /* flags */ }; - #ifdef USE_SSL /* * HTTP-proxyed SMTPS protocol handler. @@ -192,7 +190,7 @@ static const struct Curl_handler Curl_handler_smtp_proxy = { static const struct Curl_handler Curl_handler_smtps_proxy = { "SMTPS", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -201,96 +199,130 @@ static const struct Curl_handler Curl_handler_smtps_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_SMTPS, /* defport */ - PROT_HTTP /* protocol */ + CURLPROTO_HTTP, /* protocol */ + PROTOPT_NONE /* flags */ }; #endif #endif +/* SASL parameters for the smtp protocol */ +static const struct SASLproto saslsmtp = { + "smtp", /* The service name */ + 334, /* Code received when continuation is expected */ + 235, /* Code to receive upon authentication success */ + 512 - 8, /* Maximum initial response length (no max) */ + smtp_perform_auth, /* Send authentication command */ + smtp_continue_auth, /* Send authentication continuation */ + smtp_get_message /* Get SASL response message */ +}; -/* Function that checks for an ending smtp status code at the start of the - given string. - As a side effect, it also flags allowed authentication mechanisms according - to EHLO AUTH response. */ -static int smtp_endofresp(struct pingpong *pp, int *resp) +#ifdef USE_SSL +static void smtp_to_smtps(struct connectdata *conn) +{ + /* Change the connection handler */ + conn->handler = &Curl_handler_smtps; + + /* Set the connection's upgraded to TLS flag */ + conn->tls_upgraded = TRUE; +} +#else +#define smtp_to_smtps(x) Curl_nop_stmt +#endif + +/*********************************************************************** + * + * smtp_endofresp() + * + * Checks for an ending SMTP status code at the start of the given string, but + * also detects various capabilities from the EHLO response including the + * supported authentication mechanisms. + */ +static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len, + int *resp) { - char *line = pp->linestart_resp; - size_t len = pp->nread_resp; - struct connectdata *conn = pp->conn; struct smtp_conn *smtpc = &conn->proto.smtpc; - int result; - size_t wordlen; + bool result = FALSE; + /* Nothing for us */ if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2])) - return FALSE; /* Nothing for us. */ + return FALSE; - if((result = (line[3] == ' ')) != 0) + /* Do we have a command response? This should be the response code followed + by a space and optionally some text as per RFC-5321 and as outlined in + Section 4. Examples of RFC-4954 but some e-mail servers ignore this and + only send the response code instead as per Section 4.2. */ + if(line[3] == ' ' || len == 5) { + result = TRUE; *resp = curlx_sltosi(strtol(line, NULL, 10)); - line += 4; - len -= 4; - - if(smtpc->state == SMTP_EHLO && len >= 5 && !memcmp(line, "AUTH ", 5)) { - line += 5; - len -= 5; - - for (;;) { - while (len && - (*line == ' ' || *line == '\t' || - *line == '\r' || *line == '\n')) { - line++; - len--; - } - - if(!len) - break; - - for (wordlen = 0; wordlen < len && line[wordlen] != ' ' && - line[wordlen] != '\t' && line[wordlen] != '\r' && - line[wordlen] != '\n';) - wordlen++; - - if(wordlen == 5 && !memcmp(line, "LOGIN", 5)) - smtpc->authmechs |= SMTP_AUTH_LOGIN; - else if(wordlen == 5 && !memcmp(line, "PLAIN", 5)) - smtpc->authmechs |= SMTP_AUTH_PLAIN; - else if(wordlen == 8 && !memcmp(line, "CRAM-MD5", 8)) - smtpc->authmechs |= SMTP_AUTH_CRAM_MD5; - else if(wordlen == 10 && !memcmp(line, "DIGEST-MD5", 10)) - smtpc->authmechs |= SMTP_AUTH_DIGEST_MD5; - else if(wordlen == 6 && !memcmp(line, "GSSAPI", 6)) - smtpc->authmechs |= SMTP_AUTH_GSSAPI; - else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8)) - smtpc->authmechs |= SMTP_AUTH_EXTERNAL; - - line += wordlen; - len -= wordlen; - } + /* Make sure real server never sends internal value */ + if(*resp == 1) + *resp = 0; + } + /* Do we have a multiline (continuation) response? */ + else if(line[3] == '-' && + (smtpc->state == SMTP_EHLO || smtpc->state == SMTP_COMMAND)) { + result = TRUE; + *resp = 1; /* Internal response code */ } return result; } -/* This is the ONLY way to change SMTP state! */ -static void state(struct connectdata *conn, - smtpstate newstate) +/*********************************************************************** + * + * smtp_get_message() + * + * Gets the authentication message from the response buffer. + */ +static void smtp_get_message(char *buffer, char** outptr) +{ + size_t len = 0; + char* message = NULL; + + /* Find the start of the message */ + for(message = buffer + 4; *message == ' ' || *message == '\t'; message++) + ; + + /* Find the end of the message */ + for(len = strlen(message); len--;) + if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && + message[len] != '\t') + break; + + /* Terminate the message */ + if(++len) { + message[len] = '\0'; + } + + *outptr = message; +} + +/*********************************************************************** + * + * state() + * + * This is the ONLY way to change SMTP state! + */ +static void state(struct connectdata *conn, smtpstate newstate) { struct smtp_conn *smtpc = &conn->proto.smtpc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ - static const char * const names[]={ + static const char * const names[] = { "STOP", "SERVERGREET", "EHLO", "HELO", "STARTTLS", - "AUTHPLAIN", - "AUTHLOGIN", - "AUTHPASSWD", - "AUTHCRAM", + "UPGRADETLS", "AUTH", + "COMMAND", "MAIL", "RCPT", "DATA", @@ -298,220 +330,479 @@ static void state(struct connectdata *conn, "QUIT", /* LAST */ }; + if(smtpc->state != newstate) infof(conn->data, "SMTP %p state change from %s to %s\n", - smtpc, names[smtpc->state], names[newstate]); + (void *)smtpc, names[smtpc->state], names[newstate]); #endif + smtpc->state = newstate; } -static CURLcode smtp_state_ehlo(struct connectdata *conn) -{ - CURLcode result; - struct smtp_conn *smtpc = &conn->proto.smtpc; - - smtpc->authmechs = 0; /* No known authentication mechanisms yet. */ - - /* send EHLO */ - result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain); - - if(result) - return result; - - state(conn, SMTP_EHLO); - return CURLE_OK; -} - -static CURLcode smtp_state_helo(struct connectdata *conn) -{ - CURLcode result; - struct smtp_conn *smtpc = &conn->proto.smtpc; - - /* send HELO */ - result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain); - - if(result) - return result; - - state(conn, SMTP_HELO); - return CURLE_OK; -} - -static size_t smtp_auth_plain_data(struct connectdata * conn, char * * outptr) -{ - char plainauth[2 * MAX_CURL_USER_LENGTH + MAX_CURL_PASSWORD_LENGTH]; - size_t ulen; - size_t plen; - - ulen = strlen(conn->user); - plen = strlen(conn->passwd); - - if(2 * ulen + plen + 2 > sizeof plainauth) - return 0; - - memcpy(plainauth, conn->user, ulen); - plainauth[ulen] = '\0'; - memcpy(plainauth + ulen + 1, conn->user, ulen); - plainauth[2 * ulen + 1] = '\0'; - memcpy(plainauth + 2 * ulen + 2, conn->passwd, plen); - return Curl_base64_encode(conn->data, plainauth, 2 * ulen + plen + 2, outptr); -} - -static size_t smtp_auth_login_user(struct connectdata * conn, char * * outptr) -{ - size_t ulen; - - ulen = strlen(conn->user); - - if(!ulen) { - *outptr = strdup("="); - return *outptr? 1: 0; - } - - return Curl_base64_encode(conn->data, conn->user, ulen, outptr); -} - -static CURLcode smtp_authenticate(struct connectdata *conn) +/*********************************************************************** + * + * smtp_perform_ehlo() + * + * Sends the EHLO command to not only initialise communication with the ESMTP + * server but to also obtain a list of server side supported capabilities. + */ +static CURLcode smtp_perform_ehlo(struct connectdata *conn) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; - char * initresp; - const char * mech; - size_t l; - smtpstate state1; - smtpstate state2; - if(!conn->bits.user_passwd) - state(conn, SMTP_STOP); /* End of connect phase. */ - else { - initresp = (char *) NULL; - l = 1; + smtpc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanism yet */ + smtpc->sasl.authused = SASL_AUTH_NONE; /* Clear the authentication mechanism + used for esmtp connections */ + smtpc->tls_supported = FALSE; /* Clear the TLS capability */ + smtpc->auth_supported = FALSE; /* Clear the AUTH capability */ - /* Check supported authentication mechanisms by decreasing order of - preference. */ - mech = (const char *) NULL; /* Avoid compiler warnings. */ - state1 = SMTP_STOP; - state2 = SMTP_STOP; + /* Send the EHLO command */ + result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain); -#ifndef CURL_DISABLE_CRYPTO_AUTH - if(smtpc->authmechs & SMTP_AUTH_CRAM_MD5) { - mech = "CRAM-MD5"; - state1 = SMTP_AUTHCRAM; - } - else -#endif - if(smtpc->authmechs & SMTP_AUTH_PLAIN) { - mech = "PLAIN"; - state1 = SMTP_AUTHPLAIN; - state2 = SMTP_AUTH; - l = smtp_auth_plain_data(conn, &initresp); - } - else if(smtpc->authmechs & SMTP_AUTH_LOGIN) { - mech = "LOGIN"; - state1 = SMTP_AUTHLOGIN; - state2 = SMTP_AUTHPASSWD; - l = smtp_auth_login_user(conn, &initresp); - } - else { - infof(conn->data, "No known auth mechanisms supported!\n"); - result = CURLE_LOGIN_DENIED; /* Other mechanisms not supported. */ - } + if(!result) + state(conn, SMTP_EHLO); - if(!result) { - if(!l) - result = CURLE_OUT_OF_MEMORY; - else if(initresp && - l + strlen(mech) <= 512 - 8) { /* AUTH ... */ - result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp); - free(initresp); + return result; +} - if(!result) - state(conn, state2); - } - else { - Curl_safefree(initresp); +/*********************************************************************** + * + * smtp_perform_helo() + * + * Sends the HELO command to initialise communication with the SMTP server. + */ +static CURLcode smtp_perform_helo(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct smtp_conn *smtpc = &conn->proto.smtpc; - result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech); + smtpc->sasl.authused = SASL_AUTH_NONE; /* No authentication mechanism used + in smtp connections */ - if(!result) - state(conn, state1); - } + /* Send the HELO command */ + result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain); + + if(!result) + state(conn, SMTP_HELO); + + return result; +} + +/*********************************************************************** + * + * smtp_perform_starttls() + * + * Sends the STLS command to start the upgrade to TLS. + */ +static CURLcode smtp_perform_starttls(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + /* Send the STARTTLS command */ + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "STARTTLS"); + + if(!result) + state(conn, SMTP_STARTTLS); + + return result; +} + +/*********************************************************************** + * + * smtp_perform_upgrade_tls() + * + * Performs the upgrade to TLS. + */ +static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct smtp_conn *smtpc = &conn->proto.smtpc; + + /* Start the SSL connection */ + result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone); + + if(!result) { + if(smtpc->state != SMTP_UPGRADETLS) + state(conn, SMTP_UPGRADETLS); + + if(smtpc->ssldone) { + smtp_to_smtps(conn); + result = smtp_perform_ehlo(conn); } } return result; } -/* For the SMTP "protocol connect" and "doing" phases only */ -static int smtp_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) +/*********************************************************************** + * + * smtp_perform_auth() + * + * Sends an AUTH command allowing the client to login with the given SASL + * authentication mechanism. + */ +static CURLcode smtp_perform_auth(struct connectdata *conn, + const char *mech, + const char *initresp) { - return Curl_pp_getsock(&conn->proto.smtpc.pp, socks, numsocks); + CURLcode result = CURLE_OK; + struct smtp_conn *smtpc = &conn->proto.smtpc; + + if(initresp) { /* AUTH ... */ + /* Send the AUTH command with the initial response */ + result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp); + } + else { + /* Send the AUTH command */ + result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech); + } + + return result; } -/* for STARTTLS responses */ +/*********************************************************************** + * + * smtp_continue_auth() + * + * Sends SASL continuation data or cancellation. + */ +static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp) +{ + struct smtp_conn *smtpc = &conn->proto.smtpc; + + return Curl_pp_sendf(&smtpc->pp, "%s", resp); +} + +/*********************************************************************** + * + * smtp_perform_authentication() + * + * Initiates the authentication sequence, with the appropriate SASL + * authentication mechanism. + */ +static CURLcode smtp_perform_authentication(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct smtp_conn *smtpc = &conn->proto.smtpc; + saslprogress progress; + + /* Check we have enough data to authenticate with, and the + server supports authentiation, and end the connect phase if not */ + if(!smtpc->auth_supported || + !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) { + state(conn, SMTP_STOP); + return result; + } + + /* Calculate the SASL login details */ + result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress); + + if(!result) { + if(progress == SASL_INPROGRESS) + state(conn, SMTP_AUTH); + else { + /* Other mechanisms not supported */ + infof(conn->data, "No known authentication mechanisms supported!\n"); + result = CURLE_LOGIN_DENIED; + } + } + + return result; +} + +/*********************************************************************** + * + * smtp_perform_command() + * + * Sends a SMTP based command. + */ +static CURLcode smtp_perform_command(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct SMTP *smtp = data->req.protop; + + /* Send the command */ + if(smtp->rcpt) + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s %s", + smtp->custom && smtp->custom[0] != '\0' ? + smtp->custom : "VRFY", + smtp->rcpt->data); + else + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", + smtp->custom && smtp->custom[0] != '\0' ? + smtp->custom : "HELP"); + + if(!result) + state(conn, SMTP_COMMAND); + + return result; +} + +/*********************************************************************** + * + * smtp_perform_mail() + * + * Sends an MAIL command to initiate the upload of a message. + */ +static CURLcode smtp_perform_mail(struct connectdata *conn) +{ + char *from = NULL; + char *auth = NULL; + char *size = NULL; + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + + /* Calculate the FROM parameter */ + if(!data->set.str[STRING_MAIL_FROM]) + /* Null reverse-path, RFC-5321, sect. 3.6.3 */ + from = strdup("<>"); + else if(data->set.str[STRING_MAIL_FROM][0] == '<') + from = aprintf("%s", data->set.str[STRING_MAIL_FROM]); + else + from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]); + + if(!from) + return CURLE_OUT_OF_MEMORY; + + /* Calculate the optional AUTH parameter */ + if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) { + if(data->set.str[STRING_MAIL_AUTH][0] != '\0') + auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]); + else + /* Empty AUTH, RFC-2554, sect. 5 */ + auth = strdup("<>"); + + if(!auth) { + free(from); + + return CURLE_OUT_OF_MEMORY; + } + } + + /* Calculate the optional SIZE parameter */ + if(conn->proto.smtpc.size_supported && conn->data->state.infilesize > 0) { + size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize); + + if(!size) { + free(from); + free(auth); + + return CURLE_OUT_OF_MEMORY; + } + } + + /* Send the MAIL command */ + if(!auth && !size) + result = Curl_pp_sendf(&conn->proto.smtpc.pp, + "MAIL FROM:%s", from); + else if(auth && !size) + result = Curl_pp_sendf(&conn->proto.smtpc.pp, + "MAIL FROM:%s AUTH=%s", from, auth); + else if(auth && size) + result = Curl_pp_sendf(&conn->proto.smtpc.pp, + "MAIL FROM:%s AUTH=%s SIZE=%s", from, auth, size); + else + result = Curl_pp_sendf(&conn->proto.smtpc.pp, + "MAIL FROM:%s SIZE=%s", from, size); + + free(from); + free(auth); + free(size); + + if(!result) + state(conn, SMTP_MAIL); + + return result; +} + +/*********************************************************************** + * + * smtp_perform_rcpt_to() + * + * Sends a RCPT TO command for a given recipient as part of the message upload + * process. + */ +static CURLcode smtp_perform_rcpt_to(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct SMTP *smtp = data->req.protop; + + /* Send the RCPT TO command */ + if(smtp->rcpt->data[0] == '<') + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s", + smtp->rcpt->data); + else + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>", + smtp->rcpt->data); + if(!result) + state(conn, SMTP_RCPT); + + return result; +} + +/*********************************************************************** + * + * smtp_perform_quit() + * + * Performs the quit action prior to sclose() being called. + */ +static CURLcode smtp_perform_quit(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + /* Send the QUIT command */ + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "QUIT"); + + if(!result) + state(conn, SMTP_QUIT); + + return result; +} + +/* For the initial server greeting */ +static CURLcode smtp_state_servergreet_resp(struct connectdata *conn, + int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + + (void)instate; /* no use for this yet */ + + if(smtpcode/100 != 2) { + failf(data, "Got unexpected smtp-server response: %d", smtpcode); + result = CURLE_FTP_WEIRD_SERVER_REPLY; + } + else + result = smtp_perform_ehlo(conn); + + return result; +} + +/* For STARTTLS responses */ static CURLcode smtp_state_starttls_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; + (void)instate; /* no use for this yet */ if(smtpcode != 220) { - if(data->set.ftp_ssl != CURLUSESSL_TRY) { + if(data->set.use_ssl != CURLUSESSL_TRY) { failf(data, "STARTTLS denied. %c", smtpcode); - result = CURLE_LOGIN_DENIED; + result = CURLE_USE_SSL_FAILED; } else - result = smtp_authenticate(conn); - } - else { - /* Curl_ssl_connect is BLOCKING */ - result = Curl_ssl_connect(conn, FIRSTSOCKET); - if(CURLE_OK == result) { - conn->protocol |= PROT_SMTPS; - result = smtp_state_ehlo(conn); - } - } - return result; -} - -/* for EHLO responses */ -static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(smtpcode/100 != 2) { - if((data->set.ftp_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use) && - !conn->bits.user_passwd) - result = smtp_state_helo(conn); - else { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - } - else if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) { - /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch - to TLS connection now */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "STARTTLS"); - state(conn, SMTP_STARTTLS); + result = smtp_perform_authentication(conn); } else - result = smtp_authenticate(conn); + result = smtp_perform_upgrade_tls(conn); return result; } -/* for HELO responses */ -static CURLcode smtp_state_helo_resp(struct connectdata *conn, - int smtpcode, +/* For EHLO responses */ +static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct smtp_conn *smtpc = &conn->proto.smtpc; + const char *line = data->state.buffer; + size_t len = strlen(line); + size_t wordlen; + + (void)instate; /* no use for this yet */ + + if(smtpcode/100 != 2 && smtpcode != 1) { + if(data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use) + result = smtp_perform_helo(conn); + else { + failf(data, "Remote access denied: %d", smtpcode); + result = CURLE_REMOTE_ACCESS_DENIED; + } + } + else { + line += 4; + len -= 4; + + /* Does the server support the STARTTLS capability? */ + if(len >= 8 && !memcmp(line, "STARTTLS", 8)) + smtpc->tls_supported = TRUE; + + /* Does the server support the SIZE capability? */ + else if(len >= 4 && !memcmp(line, "SIZE", 4)) + smtpc->size_supported = TRUE; + + /* Does the server support authentication? */ + else if(len >= 5 && !memcmp(line, "AUTH ", 5)) { + smtpc->auth_supported = TRUE; + + /* Advance past the AUTH keyword */ + line += 5; + len -= 5; + + /* Loop through the data line */ + for(;;) { + size_t llen; + unsigned int mechbit; + + while(len && + (*line == ' ' || *line == '\t' || + *line == '\r' || *line == '\n')) { + + line++; + len--; + } + + if(!len) + break; + + /* Extract the word */ + for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && + line[wordlen] != '\t' && line[wordlen] != '\r' && + line[wordlen] != '\n';) + wordlen++; + + /* Test the word for a matching authentication mechanism */ + mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); + if(mechbit && llen == wordlen) + smtpc->sasl.authmechs |= mechbit; + + line += wordlen; + len -= wordlen; + } + } + + if(smtpcode != 1) { + if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { + /* We don't have a SSL/TLS connection yet, but SSL is requested */ + if(smtpc->tls_supported) + /* Switch to TLS connection now */ + result = smtp_perform_starttls(conn); + else if(data->set.use_ssl == CURLUSESSL_TRY) + /* Fallback and carry on with authentication */ + result = smtp_perform_authentication(conn); + else { + failf(data, "STARTTLS not supported."); + result = CURLE_USE_SSL_FAILED; + } + } + else + result = smtp_perform_authentication(conn); + } + } + + return result; +} + +/* For HELO responses */ +static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; @@ -520,357 +811,175 @@ static CURLcode smtp_state_helo_resp(struct connectdata *conn, (void)instate; /* no use for this yet */ if(smtpcode/100 != 2) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; + failf(data, "Remote access denied: %d", smtpcode); + result = CURLE_REMOTE_ACCESS_DENIED; } - else { - /* end the connect phase */ + else + /* End of connect phase */ state(conn, SMTP_STOP); - } - return result; -} - -/* for AUTH PLAIN (without initial response) responses */ -static CURLcode smtp_state_authplain_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t l; - char * plainauth; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - l = smtp_auth_plain_data(conn, &plainauth); - - if(!l) - result = CURLE_OUT_OF_MEMORY; - else { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth); - free(plainauth); - - if(!result) - state(conn, SMTP_AUTH); - } - } return result; } -/* for AUTH LOGIN (without initial response) responses */ -static CURLcode smtp_state_authlogin_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t l; - char * authuser; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - l = smtp_auth_login_user(conn, &authuser); - - if(!l) - result = CURLE_OUT_OF_MEMORY; - else { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser); - free(authuser); - - if(!result) - state(conn, SMTP_AUTHPASSWD); - } - } - - return result; -} - -/* for responses to user entry of AUTH LOGIN. */ -static CURLcode smtp_state_authpasswd_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t plen; - size_t l; - char *authpasswd; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - plen = strlen(conn->passwd); - - if(!plen) - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "="); - else { - l = Curl_base64_encode(data, conn->passwd, plen, &authpasswd); - - if(!l) - result = CURLE_OUT_OF_MEMORY; - else { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd); - free(authpasswd); - - if(!result) - state(conn, SMTP_AUTH); - } - } - } - - return result; -} - -#ifndef CURL_DISABLE_CRYPTO_AUTH - -/* for AUTH CRAM-MD5 responses. */ -static CURLcode smtp_state_authcram_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char * chlg64 = data->state.buffer; - unsigned char * chlg; - size_t chlglen; - size_t l; - char * rplyb64; - HMAC_context * ctxt; - unsigned char digest[16]; - char reply[MAX_CURL_USER_LENGTH + 32 /* 2 * size of MD5 digest */ + 1]; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - return CURLE_LOGIN_DENIED; - } - - /* Get the challenge. */ - for (chlg64 += 4; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++) - ; - - chlg = (unsigned char *) NULL; - chlglen = 0; - - if(*chlg64 != '=') { - for (l = strlen(chlg64); l--;) - if(chlg64[l] != '\r' && chlg64[l] != '\n' && chlg64[l] != ' ' && - chlg64[l] != '\t') - break; - - if(++l) { - chlg64[l] = '\0'; - - chlglen = Curl_base64_decode(chlg64, &chlg); - if(!chlglen) - return CURLE_OUT_OF_MEMORY; - } - } - - /* Compute digest. */ - ctxt = Curl_HMAC_init(Curl_HMAC_MD5, - (const unsigned char *) conn->passwd, - (unsigned int)(strlen(conn->passwd))); - - if(!ctxt) { - if(chlg) - free(chlg); - - return CURLE_OUT_OF_MEMORY; - } - - if(chlglen > 0) - Curl_HMAC_update(ctxt, chlg, (unsigned int)(chlglen)); - - if(chlg) - free(chlg); - - Curl_HMAC_final(ctxt, digest); - - /* Prepare the reply. */ - snprintf(reply, sizeof reply, - "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - conn->user, digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], - digest[6], digest[7], digest[8], digest[9], digest[10], digest[11], - digest[12], digest[13], digest[14], digest[15]); - - /* Encode it to base64 and send it. */ - l = Curl_base64_encode(data, reply, 0, &rplyb64); - - if(!l) - result = CURLE_OUT_OF_MEMORY; - else { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64); - free(rplyb64); - - if(!result) - state(conn, SMTP_AUTH); - } - - return result; -} - -#endif - -/* for final responses to AUTH sequences. */ +/* For SASL authentication responses */ static CURLcode smtp_state_auth_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 235) { - failf(data, "Authentication failed: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else - state(conn, SMTP_STOP); /* End of connect phase. */ - - return result; -} - -/* start the DO phase */ -static CURLcode smtp_mail(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - /* send MAIL */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:%s", - data->set.str[STRING_MAIL_FROM]); - if(result) - return result; - - state(conn, SMTP_MAIL); - return result; -} - -static CURLcode smtp_rcpt_to(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; + saslprogress progress; - /* send RCPT TO */ - if(smtpc->rcpt) { - if(smtpc->rcpt->data[0] == '<') - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s", - smtpc->rcpt->data); - else - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>", - smtpc->rcpt->data); - if(!result) - state(conn, SMTP_RCPT); - } - return result; -} - -/* for MAIL responses */ -static CURLcode smtp_state_mail_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; (void)instate; /* no use for this yet */ - if(smtpcode/100 != 2) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - state(conn, SMTP_STOP); - } - else { - struct smtp_conn *smtpc = &conn->proto.smtpc; - smtpc->rcpt = data->set.mail_rcpt; - - result = smtp_rcpt_to(conn); - } - - return result; -} - -/* for RCPT responses */ -static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - (void)instate; /* no use for this yet */ - - if(smtpcode/100 != 2) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - state(conn, SMTP_STOP); - } - else { - struct smtp_conn *smtpc = &conn->proto.smtpc; - - if(smtpc->rcpt) { - smtpc->rcpt = smtpc->rcpt->next; - result = smtp_rcpt_to(conn); - - /* if we failed or still is in RCPT sending, return */ - if(result || smtpc->rcpt) - return result; + result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress); + if(!result) + switch(progress) { + case SASL_DONE: + state(conn, SMTP_STOP); /* Authenticated */ + break; + case SASL_IDLE: /* No mechanism left after cancellation */ + failf(data, "Authentication cancelled"); + result = CURLE_LOGIN_DENIED; + break; + default: + break; } - /* send DATA */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "DATA"); - if(result) - return result; - - state(conn, SMTP_DATA); - } return result; } -/* for the DATA response */ -static CURLcode smtp_state_data_resp(struct connectdata *conn, - int smtpcode, +/* For command responses */ +static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct SMTP *smtp = data->req.protop; + char *line = data->state.buffer; + size_t len = strlen(line); + + (void)instate; /* no use for this yet */ + + if((smtp->rcpt && smtpcode/100 != 2 && smtpcode != 553 && smtpcode != 1) || + (!smtp->rcpt && smtpcode/100 != 2 && smtpcode != 1)) { + failf(data, "Command failed: %d", smtpcode); + result = CURLE_RECV_ERROR; + } + else { + /* Temporarily add the LF character back and send as body to the client */ + if(!data->set.opt_no_body) { + line[len] = '\n'; + result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1); + line[len] = '\0'; + } + + if(smtpcode != 1) { + if(smtp->rcpt) { + smtp->rcpt = smtp->rcpt->next; + + if(smtp->rcpt) { + /* Send the next command */ + result = smtp_perform_command(conn); + } + else + /* End of DO phase */ + state(conn, SMTP_STOP); + } + else + /* End of DO phase */ + state(conn, SMTP_STOP); + } + } + + return result; +} + +/* For MAIL responses */ +static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + + (void)instate; /* no use for this yet */ + + if(smtpcode/100 != 2) { + failf(data, "MAIL failed: %d", smtpcode); + result = CURLE_SEND_ERROR; + } + else + /* Start the RCPT TO command */ + result = smtp_perform_rcpt_to(conn); + + return result; +} + +/* For RCPT responses */ +static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct SMTP *smtp = data->req.protop; + + (void)instate; /* no use for this yet */ + + if(smtpcode/100 != 2) { + failf(data, "RCPT failed: %d", smtpcode); + result = CURLE_SEND_ERROR; + } + else { + smtp->rcpt = smtp->rcpt->next; + + if(smtp->rcpt) + /* Send the next RCPT TO command */ + result = smtp_perform_rcpt_to(conn); + else { + /* Send the DATA command */ + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA"); + + if(!result) + state(conn, SMTP_DATA); + } + } + + return result; +} + +/* For DATA response */ +static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct FTP *smtp = data->state.proto.smtp; (void)instate; /* no use for this yet */ if(smtpcode != 354) { + failf(data, "DATA failed: %d", smtpcode); + result = CURLE_SEND_ERROR; + } + else { + /* Set the progress upload size */ + Curl_pgrsSetUploadSize(data, data->state.infilesize); + + /* SMTP upload */ + Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL); + + /* End of DO phase */ state(conn, SMTP_STOP); - return CURLE_RECV_ERROR; } - /* SMTP upload */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */ - FIRSTSOCKET, smtp->bytecountp); - - state(conn, SMTP_STOP); - return CURLE_OK; + return result; } -/* for the POSTDATA response, which is received after the entire DATA - part has been sent off to the server */ +/* For POSTDATA responses, which are received after the entire DATA + part has been sent to the server */ static CURLcode smtp_state_postdata_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) + int smtpcode, + smtpstate instate) { CURLcode result = CURLE_OK; @@ -879,41 +988,47 @@ static CURLcode smtp_state_postdata_resp(struct connectdata *conn, if(smtpcode != 250) result = CURLE_RECV_ERROR; + /* End of DONE phase */ state(conn, SMTP_STOP); + return result; } static CURLcode smtp_statemach_act(struct connectdata *conn) { - CURLcode result; + CURLcode result = CURLE_OK; curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct SessionHandle *data=conn->data; + struct SessionHandle *data = conn->data; int smtpcode; struct smtp_conn *smtpc = &conn->proto.smtpc; struct pingpong *pp = &smtpc->pp; size_t nread = 0; + /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */ + if(smtpc->state == SMTP_UPGRADETLS) + return smtp_perform_upgrade_tls(conn); + + /* Flush any data that needs to be sent */ if(pp->sendleft) - /* we have a piece of a command still left to send */ return Curl_pp_flushsend(pp); - /* we read a piece of response */ - result = Curl_pp_readresp(sock, pp, &smtpcode, &nread); - if(result) - return result; + do { + /* Read the response from the server */ + result = Curl_pp_readresp(sock, pp, &smtpcode, &nread); + if(result) + return result; - if(smtpcode) { - /* we have now received a full SMTP server response */ + /* Store the latest response for later retrieval if necessary */ + if(smtpc->state != SMTP_QUIT && smtpcode != 1) + data->info.httpcode = smtpcode; + + if(!smtpcode) + break; + + /* We have now received a full SMTP server response */ switch(smtpc->state) { case SMTP_SERVERGREET: - if(smtpcode/100 != 2) { - failf(data, "Got unexpected smtp-server response: %d", smtpcode); - return CURLE_FTP_WEIRD_SERVER_REPLY; - } - - result = smtp_state_ehlo(conn); - if(result) - return result; + result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state); break; case SMTP_EHLO: @@ -928,28 +1043,14 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state); break; - case SMTP_AUTHPLAIN: - result = smtp_state_authplain_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTHLOGIN: - result = smtp_state_authlogin_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTHPASSWD: - result = smtp_state_authpasswd_resp(conn, smtpcode, smtpc->state); - break; - -#ifndef CURL_DISABLE_CRYPTO_AUTH - case SMTP_AUTHCRAM: - result = smtp_state_authcram_resp(conn, smtpcode, smtpc->state); - break; -#endif - case SMTP_AUTH: result = smtp_state_auth_resp(conn, smtpcode, smtpc->state); break; + case SMTP_COMMAND: + result = smtp_state_command_resp(conn, smtpcode, smtpc->state); + break; + case SMTP_MAIL: result = smtp_state_mail_resp(conn, smtpcode, smtpc->state); break; @@ -973,169 +1074,109 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) state(conn, SMTP_STOP); break; } - } - return result; -} - -/* called repeatedly until done from multi.c */ -static CURLcode smtp_multi_statemach(struct connectdata *conn, - bool *done) -{ - struct smtp_conn *smtpc = &conn->proto.smtpc; - CURLcode result = Curl_pp_multi_statemach(&smtpc->pp); - - *done = (bool)(smtpc->state == SMTP_STOP); + } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp)); return result; } -static CURLcode smtp_easy_statemach(struct connectdata *conn) +/* Called repeatedly until done from multi.c */ +static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done) { - struct smtp_conn *smtpc = &conn->proto.smtpc; - struct pingpong *pp = &smtpc->pp; CURLcode result = CURLE_OK; + struct smtp_conn *smtpc = &conn->proto.smtpc; - while(smtpc->state != SMTP_STOP) { - result = Curl_pp_easy_statemach(pp); - if(result) - break; + if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) { + result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone); + if(result || !smtpc->ssldone) + return result; } + result = Curl_pp_statemach(&smtpc->pp, FALSE); + *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE; + return result; } -/* - * Allocate and initialize the struct SMTP for the current SessionHandle. If - * need be. - */ +static CURLcode smtp_block_statemach(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct smtp_conn *smtpc = &conn->proto.smtpc; + + while(smtpc->state != SMTP_STOP && !result) + result = Curl_pp_statemach(&smtpc->pp, TRUE); + + return result; +} + +/* Allocate and initialize the SMTP struct for the current SessionHandle if + required */ static CURLcode smtp_init(struct connectdata *conn) { + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct FTP *smtp = data->state.proto.smtp; - if(!smtp) { - smtp = data->state.proto.smtp = calloc(sizeof(struct FTP), 1); - if(!smtp) - return CURLE_OUT_OF_MEMORY; - } + struct SMTP *smtp; - /* get some initial data into the smtp struct */ - smtp->bytecountp = &data->req.bytecount; + smtp = data->req.protop = calloc(sizeof(struct SMTP), 1); + if(!smtp) + result = CURLE_OUT_OF_MEMORY; - /* No need to duplicate user+password, the connectdata struct won't change - during a session, but we re-init them here since on subsequent inits - since the conn struct may have changed or been replaced. - */ - smtp->user = conn->user; - smtp->passwd = conn->passwd; - - return CURLE_OK; + return result; } -/* - * smtp_connect() should do everything that is to be considered a part of +/* For the SMTP "protocol connect" and "doing" phases only */ +static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks) +{ + return Curl_pp_getsock(&conn->proto.smtpc.pp, socks, numsocks); +} + +/*********************************************************************** + * + * smtp_connect() + * + * This function should do everything that is to be considered a part of * the connection phase. * - * The variable 'done' points to will be TRUE if the protocol-layer connect - * phase is done when this function returns, or FALSE is not. When called as - * a part of the easy interface, it will always be TRUE. + * The variable pointed to by 'done' will be TRUE if the protocol-layer + * connect phase is done when this function returns, or FALSE if not. */ -static CURLcode smtp_connect(struct connectdata *conn, - bool *done) /* see description above */ +static CURLcode smtp_connect(struct connectdata *conn, bool *done) { - CURLcode result; + CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; - struct SessionHandle *data=conn->data; - struct pingpong *pp=&smtpc->pp; - const char *path = conn->data->state.path; - int len; - char localhost[1024 + 1]; + struct pingpong *pp = &smtpc->pp; *done = FALSE; /* default to not done yet */ - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); + /* We always support persistent connections in SMTP */ + connkeep(conn, "SMTP default"); - result = smtp_init(conn); - if(CURLE_OK != result) + /* Set the default response time-out */ + pp->response_time = RESP_TIMEOUT; + pp->statemach_act = smtp_statemach_act; + pp->endofresp = smtp_endofresp; + pp->conn = conn; + + /* Initialize the SASL storage */ + Curl_sasl_init(&smtpc->sasl, &saslsmtp); + + /* Initialise the pingpong layer */ + Curl_pp_init(pp); + + /* Parse the URL options */ + result = smtp_parse_url_options(conn); + if(result) return result; - /* We always support persistant connections on smtp */ - conn->bits.close = FALSE; + /* Parse the URL path */ + result = smtp_parse_url_path(conn); + if(result) + return result; - pp->response_time = RESP_TIMEOUT; /* set default response time-out */ - pp->statemach_act = smtp_statemach_act; - pp->endofresp = smtp_endofresp; - pp->conn = conn; - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY) - if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { - /* for SMTP over HTTP proxy */ - struct HTTP http_proxy; - struct FTP *smtp_save; - - /* BLOCKING */ - /* We want "seamless" SMTP operations through HTTP proxy tunnel */ - - /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member - * conn->proto.http; we want SMTP through HTTP and we have to change the - * member temporarily for connecting to the HTTP proxy. After - * Curl_proxyCONNECT we have to set back the member to the original struct - * SMTP pointer - */ - smtp_save = data->state.proto.smtp; - memset(&http_proxy, 0, sizeof(http_proxy)); - data->state.proto.http = &http_proxy; - - result = Curl_proxyCONNECT(conn, FIRSTSOCKET, - conn->host.name, conn->remote_port); - - data->state.proto.smtp = smtp_save; - - if(CURLE_OK != result) - return result; - } -#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */ - - if(conn->protocol & PROT_SMTPS) { - /* BLOCKING */ - /* SMTPS is simply smtp with SSL for the control channel */ - /* now, perform the SSL initialization for this socket */ - result = Curl_ssl_connect(conn, FIRSTSOCKET); - if(result) - return result; - } - - Curl_pp_init(pp); /* init the response reader stuff */ - - pp->response_time = RESP_TIMEOUT; /* set default response time-out */ - pp->statemach_act = smtp_statemach_act; - pp->endofresp = smtp_endofresp; - pp->conn = conn; - - if(!*path) { - if(!Curl_gethostname(localhost, sizeof localhost)) - path = localhost; - else - path = "localhost"; - } - - /* url decode the path and use it as domain with EHLO */ - smtpc->domain = curl_easy_unescape(conn->data, path, 0, &len); - if(!smtpc->domain) - return CURLE_OUT_OF_MEMORY; - - /* When we connect, we start in the state where we await the server greeting - */ + /* Start off waiting for the server greeting response */ state(conn, SMTP_SERVERGREET); - if(data->state.used_interface == Curl_if_multi) - result = smtp_multi_statemach(conn, done); - else { - result = smtp_easy_statemach(conn); - if(!result) - *done = TRUE; - } + result = smtp_multi_statemach(conn, done); return result; } @@ -1152,52 +1193,85 @@ static CURLcode smtp_connect(struct connectdata *conn, static CURLcode smtp_done(struct connectdata *conn, CURLcode status, bool premature) { + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct FTP *smtp = data->state.proto.smtp; - CURLcode result=CURLE_OK; + struct SMTP *smtp = data->req.protop; + struct pingpong *pp = &conn->proto.smtpc.pp; + char *eob; + ssize_t len; ssize_t bytes_written; + (void)premature; - if(!smtp) - /* When the easy handle is removed from the multi while libcurl is still - * trying to resolve the host name, it seems that the smtp struct is not - * yet initialized, but the removal action calls Curl_done() which calls - * this function. So we simply return success if no smtp pointer is set. - */ + if(!smtp || !pp->conn) + /* When the easy handle is removed from the multi interface while libcurl + is still trying to resolve the host name, the SMTP struct is not yet + initialized. However, the removal action calls Curl_done() which in + turn calls this function, so we simply return success. */ return CURLE_OK; if(status) { - conn->bits.close = TRUE; /* marked for closure */ - result = status; /* use the already set error code */ + connclose(conn, "SMTP done with bad status"); /* marked for closure */ + result = status; /* use the already set error code */ } - else - /* TODO: make this work even when the socket is EWOULDBLOCK in this call! */ + else if(!data->set.connect_only && data->set.upload && data->set.mail_rcpt) { + /* Calculate the EOB taking into account any terminating CRLF from the + previous line of the email or the CRLF of the DATA command when there + is "no mail data". RFC-5321, sect. 4.1.1.4. - /* write to socket (send away data) */ - result = Curl_write(conn, - conn->writesockfd, /* socket to send to */ - SMTP_EOB, /* buffer pointer */ - SMTP_EOB_LEN, /* buffer size */ - &bytes_written); /* actually sent away */ + Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to + fail when using a different pointer following a previous write, that + returned CURLE_AGAIN, we duplicate the EOB now rather than when the + bytes written doesn't equal len. */ + if(smtp->trailing_crlf || !conn->data->state.infilesize) { + eob = strdup(SMTP_EOB + 2); + len = SMTP_EOB_LEN - 2; + } + else { + eob = strdup(SMTP_EOB); + len = SMTP_EOB_LEN; + } + if(!eob) + return CURLE_OUT_OF_MEMORY; - if(status == CURLE_OK) { - struct smtp_conn *smtpc = &conn->proto.smtpc; - struct pingpong *pp= &smtpc->pp; - pp->response = Curl_tvnow(); /* timeout relative now */ + /* Send the end of block data */ + result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written); + if(result) { + free(eob); + return result; + } + + if(bytes_written != len) { + /* The whole chunk was not sent so keep it around and adjust the + pingpong structure accordingly */ + pp->sendthis = eob; + pp->sendsize = len; + pp->sendleft = len - bytes_written; + } + else { + /* Successfully sent so adjust the response timeout relative to now */ + pp->response = Curl_tvnow(); + + free(eob); + } state(conn, SMTP_POSTDATA); - /* run the state-machine + + /* Run the state-machine TODO: when the multi interface is used, this _really_ should be using the smtp_multi_statemach function but we have no general support for non-blocking DONE operations, not in the multi state machine and with Curl_done() invokes on several places in the code! */ - result = smtp_easy_statemach(conn); + result = smtp_block_statemach(conn); } - /* clear these for next connection */ + /* Cleanup our per-request based variables */ + Curl_safefree(smtp->custom); + + /* Clear the transfer mode for the next request */ smtp->transfer = FTPTRANSFER_BODY; return result; @@ -1207,41 +1281,44 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, * * smtp_perform() * - * This is the actual DO function for SMTP. Get a file/directory according to - * the options previously setup. + * This is the actual DO function for SMTP. Transfer a mail, send a command + * or get some data according to the options previously setup. */ - -static -CURLcode smtp_perform(struct connectdata *conn, - bool *connected, /* connect status after PASV / PORT */ - bool *dophase_done) +static CURLcode smtp_perform(struct connectdata *conn, bool *connected, + bool *dophase_done) { - /* this is SMTP and no proxy */ - CURLcode result=CURLE_OK; + /* This is SMTP and no proxy */ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct SMTP *smtp = data->req.protop; DEBUGF(infof(conn->data, "DO phase starts\n")); - if(conn->data->set.opt_no_body) { - /* requested no body means no transfer... */ - struct FTP *smtp = conn->data->state.proto.smtp; + if(data->set.opt_no_body) { + /* Requested no body means no transfer */ smtp->transfer = FTPTRANSFER_INFO; } *dophase_done = FALSE; /* not done yet */ - /* start the first command in the DO phase */ - result = smtp_mail(conn); + /* Store the first recipient (or NULL if not specified) */ + smtp->rcpt = data->set.mail_rcpt; + + /* Start the first command in the DO phase */ + if(data->set.upload && data->set.mail_rcpt) + /* MAIL transfer */ + result = smtp_perform_mail(conn); + else + /* SMTP based command (VRFY, EXPN, NOOP, RSET or HELP) */ + result = smtp_perform_command(conn); + if(result) return result; - /* run the state-machine */ - if(conn->data->state.used_interface == Curl_if_multi) - result = smtp_multi_statemach(conn, dophase_done); - else { - result = smtp_easy_statemach(conn); - *dophase_done = TRUE; /* with the easy interface we are done here */ - } - *connected = conn->bits.tcpconnect; + /* Run the state-machine */ + result = smtp_multi_statemach(conn, dophase_done); + + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); @@ -1260,45 +1337,16 @@ CURLcode smtp_perform(struct connectdata *conn, */ static CURLcode smtp_do(struct connectdata *conn, bool *done) { - CURLcode retcode = CURLE_OK; + CURLcode result = CURLE_OK; *done = FALSE; /* default to false */ - /* - Since connections can be re-used between SessionHandles, this might be a - connection already existing but on a fresh SessionHandle struct so we must - make sure we have a good 'struct SMTP' to play with. For new connections, - the struct SMTP is allocated and setup in the smtp_connect() function. - */ - Curl_reset_reqproto(conn); - retcode = smtp_init(conn); - if(retcode) - return retcode; - - retcode = smtp_regular_transfer(conn, done); - - return retcode; -} - -/*********************************************************************** - * - * smtp_quit() - * - * This should be called before calling sclose(). We should then wait for the - * response from the server before returning. The calling code should then try - * to close the connection. - * - */ -static CURLcode smtp_quit(struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "QUIT"); + /* Parse the custom request */ + result = smtp_parse_custom_request(conn); if(result) return result; - state(conn, SMTP_QUIT); - result = smtp_easy_statemach(conn); + result = smtp_regular_transfer(conn, done); return result; } @@ -1312,57 +1360,57 @@ static CURLcode smtp_quit(struct connectdata *conn) */ static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection) { - struct smtp_conn *smtpc= &conn->proto.smtpc; + struct smtp_conn *smtpc = &conn->proto.smtpc; /* We cannot send quit unconditionally. If this connection is stale or bad in any way, sending quit and waiting around here will make the - disconnect wait in vain and cause more problems than we need to. - */ + disconnect wait in vain and cause more problems than we need to. */ /* The SMTP session may or may not have been allocated/setup at this point! */ - if(!dead_connection && smtpc->pp.conn) - (void)smtp_quit(conn); /* ignore errors on the LOGOUT */ + if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart) + if(!smtp_perform_quit(conn)) + (void)smtp_block_statemach(conn); /* ignore errors on QUIT */ + /* Disconnect from the server */ Curl_pp_disconnect(&smtpc->pp); - /* This won't already be freed in some error cases */ + /* Cleanup the SASL module */ + Curl_sasl_cleanup(conn, smtpc->sasl.authused); + + /* Cleanup our connection based variables */ Curl_safefree(smtpc->domain); - smtpc->domain = NULL; return CURLE_OK; } -/* call this when the DO phase has completed */ -static CURLcode smtp_dophase_done(struct connectdata *conn, - bool connected) +/* Call this when the DO phase has completed */ +static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected) { - struct FTP *smtp = conn->data->state.proto.smtp; - struct smtp_conn *smtpc= &conn->proto.smtpc; + struct SMTP *smtp = conn->data->req.protop; + (void)connected; if(smtp->transfer != FTPTRANSFER_BODY) /* no data to transfer */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - free(smtpc->domain); - smtpc->domain = NULL; - return CURLE_OK; } -/* called from multi.c while DOing */ -static CURLcode smtp_doing(struct connectdata *conn, - bool *dophase_done) +/* Called from multi.c while DOing */ +static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done) { - CURLcode result; - result = smtp_multi_statemach(conn, dophase_done); + CURLcode result = smtp_multi_statemach(conn, dophase_done); - if(*dophase_done) { + if(result) + DEBUGF(infof(conn->data, "DO phase failed\n")); + else if(*dophase_done) { result = smtp_dophase_done(conn, FALSE /* not connected */); DEBUGF(infof(conn->data, "DO phase is complete\n")); } + return result; } @@ -1375,44 +1423,43 @@ static CURLcode smtp_doing(struct connectdata *conn, * Performs all commands done before a regular transfer between a local and a * remote host. */ -static -CURLcode smtp_regular_transfer(struct connectdata *conn, - bool *dophase_done) +static CURLcode smtp_regular_transfer(struct connectdata *conn, + bool *dophase_done) { - CURLcode result=CURLE_OK; - bool connected=FALSE; + CURLcode result = CURLE_OK; + bool connected = FALSE; struct SessionHandle *data = conn->data; - data->req.size = -1; /* make sure this is unknown at this point */ + /* Make sure size is unknown at this point */ + data->req.size = -1; + + /* Set the progress data */ Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); - Curl_pgrsSetUploadSize(data, 0); - Curl_pgrsSetDownloadSize(data, 0); + Curl_pgrsSetUploadSize(data, -1); + Curl_pgrsSetDownloadSize(data, -1); - result = smtp_perform(conn, - &connected, /* have we connected after PASV/PORT */ - dophase_done); /* all commands in the DO-phase done? */ - - if(CURLE_OK == result) { - - if(!*dophase_done) - /* the DO phase has not completed yet */ - return CURLE_OK; + /* Carry out the perform */ + result = smtp_perform(conn, &connected, dophase_done); + /* Perform post DO phase operations if necessary */ + if(!result && *dophase_done) result = smtp_dophase_done(conn, connected); - if(result) - return result; - } return result; } -static CURLcode smtp_setup_connection(struct connectdata * conn) +static CURLcode smtp_setup_connection(struct connectdata *conn) { struct SessionHandle *data = conn->data; + CURLcode result; + /* Clear the TLS upgraded flag */ + conn->tls_upgraded = FALSE; + + /* Set up the proxy if necessary */ if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { - /* Unless we have asked to tunnel smtp operations through the proxy, we + /* Unless we have asked to tunnel SMTP operations through the proxy, we switch and use HTTP operations only */ #ifndef CURL_DISABLE_HTTP if(conn->handler == &Curl_handler_smtp) @@ -1425,83 +1472,207 @@ static CURLcode smtp_setup_connection(struct connectdata * conn) return CURLE_UNSUPPORTED_PROTOCOL; #endif } - /* - * We explicitly mark this connection as persistent here as we're doing - * SMTP over HTTP and thus we accidentally avoid setting this value - * otherwise. - */ - conn->bits.close = FALSE; + /* set it up as a HTTP connection instead */ + return conn->handler->setup_connection(conn); + #else failf(data, "SMTP over http proxy requires HTTP support built-in!"); return CURLE_UNSUPPORTED_PROTOCOL; #endif } + /* Initialise the SMTP layer */ + result = smtp_init(conn); + if(result) + return result; + data->state.path++; /* don't include the initial slash */ return CURLE_OK; } -CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread) +/*********************************************************************** + * + * smtp_parse_url_options() + * + * Parse the URL login options. + */ +static CURLcode smtp_parse_url_options(struct connectdata *conn) { - /* When sending SMTP payload, we must detect CRLF.CRLF sequences in - * the data and make sure it is sent as CRLF..CRLF instead, as - * otherwise it will wrongly be detected as end of data by the server. - */ + CURLcode result = CURLE_OK; + struct smtp_conn *smtpc = &conn->proto.smtpc; + const char *ptr = conn->options; + + smtpc->sasl.resetprefs = TRUE; + + while(!result && ptr && *ptr) { + const char *key = ptr; + const char *value; + + while(*ptr && *ptr != '=') + ptr++; + + value = ptr + 1; + + while(*ptr && *ptr != ';') + ptr++; + + if(strnequal(key, "AUTH=", 5)) + result = Curl_sasl_parse_url_auth_option(&smtpc->sasl, + value, ptr - value); + else + result = CURLE_URL_MALFORMAT; + + if(*ptr == ';') + ptr++; + } + + return result; +} + +/*********************************************************************** + * + * smtp_parse_url_path() + * + * Parse the URL path into separate path components. + */ +static CURLcode smtp_parse_url_path(struct connectdata *conn) +{ + /* The SMTP struct is already initialised in smtp_connect() */ + struct SessionHandle *data = conn->data; + struct smtp_conn *smtpc = &conn->proto.smtpc; + const char *path = data->state.path; + char localhost[HOSTNAME_MAX + 1]; + + /* Calculate the path if necessary */ + if(!*path) { + if(!Curl_gethostname(localhost, sizeof(localhost))) + path = localhost; + else + path = "localhost"; + } + + /* URL decode the path and use it as the domain in our EHLO */ + return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE); +} + +/*********************************************************************** + * + * smtp_parse_custom_request() + * + * Parse the custom request. + */ +static CURLcode smtp_parse_custom_request(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct SMTP *smtp = data->req.protop; + const char *custom = data->set.str[STRING_CUSTOMREQUEST]; + + /* URL decode the custom request */ + if(custom) + result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, TRUE); + + return result; +} + +CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread) +{ + /* When sending a SMTP payload we must detect CRLF. sequences making sure + they are sent as CRLF.. instead, as a . on the beginning of a line will + be deleted by the server when not part of an EOB terminator and a + genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of + data by the server + */ ssize_t i; ssize_t si; - struct smtp_conn *smtpc = &conn->proto.smtpc; struct SessionHandle *data = conn->data; + struct SMTP *smtp = data->req.protop; + char *scratch = data->state.scratch; + char *newscratch = NULL; + char *oldscratch = NULL; + size_t eob_sent; - if(data->state.scratch == NULL) - data->state.scratch = malloc(2*BUFSIZE); - if(data->state.scratch == NULL) { - failf (data, "Failed to alloc scratch buffer!"); - return CURLE_OUT_OF_MEMORY; + /* Do we need to allocate a scratch buffer? */ + if(!scratch || data->set.crlf) { + oldscratch = scratch; + + scratch = newscratch = malloc(2 * BUFSIZE); + if(!newscratch) { + failf(data, "Failed to alloc scratch buffer!"); + + return CURLE_OUT_OF_MEMORY; + } } + + /* Have we already sent part of the EOB? */ + eob_sent = smtp->eob; + /* This loop can be improved by some kind of Boyer-Moore style of approach but that is saved for later... */ - for(i = 0, si = 0; i < nread; i++, si++) { - ssize_t left = nread - i; + for(i = 0, si = 0; i < nread; i++) { + if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) { + smtp->eob++; - if(left>= (ssize_t)(SMTP_EOB_LEN-smtpc->eob)) { - if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i], - SMTP_EOB_LEN-smtpc->eob)) { - /* It matched, copy the replacement data to the target buffer - instead. Note that the replacement does not contain the - trailing CRLF but we instead continue to match on that one - to deal with repeated sequences. Like CRLF.CRLF.CRLF etc - */ - memcpy(&data->state.scratch[si], SMTP_EOB_REPL, - SMTP_EOB_REPL_LEN); - si+=SMTP_EOB_REPL_LEN-1; /* minus one since the for() increments - it */ - i+=SMTP_EOB_LEN-smtpc->eob-1-2; - smtpc->eob = 0; /* start over */ - continue; - } + /* Is the EOB potentially the terminating CRLF? */ + if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob) + smtp->trailing_crlf = TRUE; + else + smtp->trailing_crlf = FALSE; } - else if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i], - left)) { - /* the last piece of the data matches the EOB so we can't send that - until we know the rest of it */ - smtpc->eob += left; - break; + else if(smtp->eob) { + /* A previous substring matched so output that first */ + memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent); + si += smtp->eob - eob_sent; + + /* Then compare the first byte */ + if(SMTP_EOB[0] == data->req.upload_fromhere[i]) + smtp->eob = 1; + else + smtp->eob = 0; + + eob_sent = 0; + + /* Reset the trailing CRLF flag as there was more data */ + smtp->trailing_crlf = FALSE; } - data->state.scratch[si] = data->req.upload_fromhere[i]; - } /* for() */ - - if(si != nread) { - /* only use the new buffer if we replaced something */ - nread = si; - - /* upload from the new (replaced) buffer instead */ - data->req.upload_fromhere = data->state.scratch; - - /* set the new amount too */ - data->req.upload_present = nread; + /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */ + if(SMTP_EOB_FIND_LEN == smtp->eob) { + /* Copy the replacement data to the target buffer */ + memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent], + SMTP_EOB_REPL_LEN - eob_sent); + si += SMTP_EOB_REPL_LEN - eob_sent; + smtp->eob = 0; + eob_sent = 0; + } + else if(!smtp->eob) + scratch[si++] = data->req.upload_fromhere[i]; } + + if(smtp->eob - eob_sent) { + /* A substring matched before processing ended so output that now */ + memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent); + si += smtp->eob - eob_sent; + } + + /* Only use the new buffer if we replaced something */ + if(si != nread) { + /* Upload from the new (replaced) buffer instead */ + data->req.upload_fromhere = scratch; + + /* Save the buffer so it can be freed later */ + data->state.scratch = scratch; + + /* Free the old scratch buffer */ + free(oldscratch); + + /* Set the new amount too */ + data->req.upload_present = si; + } + else + free(newscratch); + return CURLE_OK; } diff --git a/project/jni/curl/lib/smtp.h b/project/jni/curl/lib/smtp.h index 417fd52e5..6ebec1839 100644 --- a/project/jni/curl/lib/smtp.h +++ b/project/jni/curl/lib/smtp.h @@ -1,5 +1,5 @@ -#ifndef __SMTP_H -#define __SMTP_H +#ifndef HEADER_CURL_SMTP_H +#define HEADER_CURL_SMTP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2009 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 2009 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -23,6 +23,7 @@ ***************************************************************************/ #include "pingpong.h" +#include "curl_sasl.h" /**************************************************************************** * SMTP unique setup @@ -34,50 +35,57 @@ typedef enum { SMTP_EHLO, SMTP_HELO, SMTP_STARTTLS, - SMTP_AUTHPLAIN, - SMTP_AUTHLOGIN, - SMTP_AUTHPASSWD, - SMTP_AUTHCRAM, + SMTP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS + (multi mode only) */ SMTP_AUTH, - SMTP_MAIL, /* MAIL FROM */ - SMTP_RCPT, /* RCPT TO */ + SMTP_COMMAND, /* VRFY, EXPN, NOOP, RSET and HELP */ + SMTP_MAIL, /* MAIL FROM */ + SMTP_RCPT, /* RCPT TO */ SMTP_DATA, SMTP_POSTDATA, SMTP_QUIT, - SMTP_LAST /* never used */ + SMTP_LAST /* never used */ } smtpstate; +/* This SMTP struct is used in the SessionHandle. All SMTP data that is + connection-oriented must be in smtp_conn to properly deal with the fact that + perhaps the SessionHandle is changed between the times the connection is + used. */ +struct SMTP { + curl_pp_transfer transfer; + char *custom; /* Custom Request */ + struct curl_slist *rcpt; /* Recipient list */ + size_t eob; /* Number of bytes of the EOB (End Of Body) that + have been received so far */ + bool trailing_crlf; /* Specifies if the tailing CRLF is present */ +}; + /* smtp_conn is used for struct connection-oriented data in the connectdata struct */ struct smtp_conn { struct pingpong pp; - char *domain; /* what to send in the EHLO */ - size_t eob; /* number of bytes of the EOB (End Of Body) that has been - received thus far */ - unsigned int authmechs; /* Accepted authentication methods. */ - smtpstate state; /* always use smtp.c:state() to change state! */ - struct curl_slist *rcpt; + smtpstate state; /* Always use smtp.c:state() to change state! */ + bool ssldone; /* Is connect() over SSL done? */ + char *domain; /* Client address/name to send in the EHLO */ + struct SASL sasl; /* SASL-related storage */ + bool tls_supported; /* StartTLS capability supported by server */ + bool size_supported; /* If server supports SIZE extension according to + RFC 1870 */ + bool auth_supported; /* AUTH capability supported by server */ }; -/* Authentication mechanism flags. */ -#define SMTP_AUTH_LOGIN 0x0001 -#define SMTP_AUTH_PLAIN 0x0002 -#define SMTP_AUTH_CRAM_MD5 0x0004 -#define SMTP_AUTH_DIGEST_MD5 0x0008 -#define SMTP_AUTH_GSSAPI 0x0010 -#define SMTP_AUTH_EXTERNAL 0x0020 - extern const struct Curl_handler Curl_handler_smtp; extern const struct Curl_handler Curl_handler_smtps; /* this is the 5-bytes End-Of-Body marker for SMTP */ #define SMTP_EOB "\x0d\x0a\x2e\x0d\x0a" #define SMTP_EOB_LEN 5 +#define SMTP_EOB_FIND_LEN 3 /* if found in data, replace it with this string instead */ #define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e" #define SMTP_EOB_REPL_LEN 4 -CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread); +CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread); -#endif /* __SMTP_H */ +#endif /* HEADER_CURL_SMTP_H */ diff --git a/project/jni/curl/lib/sockaddr.h b/project/jni/curl/lib/sockaddr.h index c69411b52..95ba4c3c9 100644 --- a/project/jni/curl/lib/sockaddr.h +++ b/project/jni/curl/lib/sockaddr.h @@ -1,5 +1,5 @@ -#ifndef __SOCKADDR_H -#define __SOCKADDR_H +#ifndef HEADER_CURL_SOCKADDR_H +#define HEADER_CURL_SOCKADDR_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,16 +22,22 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#ifdef HAVE_STRUCT_SOCKADDR_STORAGE struct Curl_sockaddr_storage { - struct sockaddr_storage buffer; -}; -#else -struct Curl_sockaddr_storage { - char buffer[256]; /* this should be big enough to fit a lot */ -}; + union { + struct sockaddr sa; + struct sockaddr_in sa_in; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 sa_in6; #endif +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE + struct sockaddr_storage sa_stor; +#else + char cbuf[256]; /* this should be big enough to fit a lot */ +#endif + } buffer; +}; + +#endif /* HEADER_CURL_SOCKADDR_H */ -#endif /* __SOCKADDR_H */ diff --git a/project/jni/curl/lib/socks.c b/project/jni/curl/lib/socks.c index 7b5740be4..e7d42e77b 100644 --- a/project/jni/curl/lib/socks.c +++ b/project/jni/curl/lib/socks.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,17 +20,10 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#if !defined(CURL_DISABLE_PROXY) || defined(USE_WINDOWS_SSPI) -#include +#if !defined(CURL_DISABLE_PROXY) -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif @@ -60,28 +53,21 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */ curl_socket_t sockfd, /* read from this socket */ char *buf, /* store read data here */ ssize_t buffersize, /* max amount to read */ - ssize_t *n, /* amount bytes read */ - long conn_timeout) /* timeout for data wait - relative to - conn->created */ + ssize_t *n) /* amount bytes read */ { ssize_t nread; ssize_t allread = 0; int result; - struct timeval tvnow; - long conntime; + long timeleft; *n = 0; for(;;) { - tvnow = Curl_tvnow(); - /* calculating how long connection is establishing */ - conntime = Curl_tvdiff(tvnow, conn->created); - if(conntime > conn_timeout) { + timeleft = Curl_timeleft(conn->data, NULL, TRUE); + if(timeleft < 0) { /* we already got the timeout */ result = CURLE_OPERATION_TIMEDOUT; break; } - if(Curl_socket_ready(sockfd, CURL_SOCKET_BAD, - (int)(conn_timeout - conntime)) <= 0) { + if(Curl_socket_ready(sockfd, CURL_SOCKET_BAD, timeleft) <= 0) { result = ~CURLE_OK; break; } @@ -133,19 +119,17 @@ CURLcode Curl_SOCKS4(const char *proxy_name, int result; CURLcode code; curl_socket_t sock = conn->sock[sockindex]; - long timeout; struct SessionHandle *data = conn->data; - /* get timeout */ - timeout = Curl_timeleft(conn, NULL, TRUE); - - if(timeout < 0) { + if(Curl_timeleft(data, NULL, TRUE) < 0) { /* time-out, bail out, go home */ failf(data, "Connection time-out"); return CURLE_OPERATION_TIMEDOUT; } - curlx_nonblock(sock, FALSE); + (void)curlx_nonblock(sock, FALSE); + + infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port); /* * Compose socks4 request @@ -160,10 +144,11 @@ CURLcode Curl_SOCKS4(const char *proxy_name, socksreq[0] = 4; /* version (SOCKS4) */ socksreq[1] = 1; /* connect */ - *((unsigned short*)&socksreq[2]) = htons((unsigned short)remote_port); + socksreq[2] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */ + socksreq[3] = (unsigned char)(remote_port & 0xff); /* PORT LSB */ /* DNS resolve only for SOCKS4, not SOCKS4a */ - if (!protocol4a) { + if(!protocol4a) { struct Curl_dns_entry *dns; Curl_addrinfo *hp=NULL; int rc; @@ -175,7 +160,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, if(rc == CURLRESOLV_PENDING) /* ignores the return code, but 'dns' remains NULL on failure */ - (void)Curl_wait_for_resolv(conn, &dns); + (void)Curl_resolver_wait_resolv(conn, &dns); /* * We cannot use 'hostent' as a struct that Curl_resolv() returns. It @@ -199,6 +184,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name, else hp = NULL; /* fail! */ + infof(data, "SOCKS4 connect to %s (locally resolved)\n", buf); + Curl_resolv_unlock(data, dns); /* not used anymore from now on */ } @@ -213,8 +200,15 @@ CURLcode Curl_SOCKS4(const char *proxy_name, * This is currently not supporting "Identification Protocol (RFC1413)". */ socksreq[8] = 0; /* ensure empty userid is NUL-terminated */ - if(proxy_name) - strlcat((char*)socksreq + 8, proxy_name, sizeof(socksreq) - 8); + if(proxy_name) { + size_t plen = strlen(proxy_name); + if(plen >= sizeof(socksreq) - 8) { + failf(data, "Too long SOCKS proxy name, can't use!\n"); + return CURLE_COULDNT_CONNECT; + } + /* copy the proxy name WITH trailing zero */ + memcpy(socksreq + 8, proxy_name, plen+1); + } /* * Make connection @@ -227,14 +221,14 @@ CURLcode Curl_SOCKS4(const char *proxy_name, (int)strlen((char*)socksreq + 8); /* size including NUL */ /* If SOCKS4a, set special invalid IP address 0.0.0.x */ - if (protocol4a) { + if(protocol4a) { socksreq[4] = 0; socksreq[5] = 0; socksreq[6] = 0; socksreq[7] = 1; /* If still enough room in buffer, also append hostname */ hostnamelen = (ssize_t)strlen(hostname) + 1; /* length including NUL */ - if (packetsize + hostnamelen <= SOCKS4REQLEN) + if(packetsize + hostnamelen <= SOCKS4REQLEN) strcpy((char*)socksreq + packetsize, hostname); else hostnamelen = 0; /* Flag: hostname did not fit in buffer */ @@ -244,16 +238,16 @@ CURLcode Curl_SOCKS4(const char *proxy_name, code = Curl_write_plain(conn, sock, (char *)socksreq, packetsize + hostnamelen, &written); - if((code != CURLE_OK) || (written != packetsize + hostnamelen)) { + if(code || (written != packetsize + hostnamelen)) { failf(data, "Failed to send SOCKS4 connect request."); return CURLE_COULDNT_CONNECT; } - if (protocol4a && hostnamelen == 0) { + if(protocol4a && hostnamelen == 0) { /* SOCKS4a with very long hostname - send that name separately */ hostnamelen = (ssize_t)strlen(hostname) + 1; code = Curl_write_plain(conn, sock, (char *)hostname, hostnamelen, &written); - if((code != CURLE_OK) || (written != hostnamelen)) { + if(code || (written != hostnamelen)) { failf(data, "Failed to send SOCKS4 connect request."); return CURLE_COULDNT_CONNECT; } @@ -263,8 +257,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name, /* Receive response */ result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize, - &actualread, timeout); - if((result != CURLE_OK) || (actualread != packetsize)) { + &actualread); + if(result || (actualread != packetsize)) { failf(data, "Failed to receive SOCKS4 connect request ack."); return CURLE_COULDNT_CONNECT; } @@ -296,13 +290,9 @@ CURLcode Curl_SOCKS4(const char *proxy_name, } /* Result */ - switch(socksreq[1]) - { + switch(socksreq[1]) { case 90: - if (protocol4a) - infof(data, "SOCKS4a request granted.\n"); - else - infof(data, "SOCKS4 request granted.\n"); + infof(data, "SOCKS4%s request granted.\n", protocol4a?"a":""); break; case 91: failf(data, @@ -310,8 +300,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name, ", request rejected or failed.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), - socksreq[1]); + (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; case 92: failf(data, @@ -320,8 +310,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name, "identd on the client.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), - socksreq[1]); + (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; case 93: failf(data, @@ -330,8 +320,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name, "report different user-ids.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), - socksreq[1]); + (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; default: failf(data, @@ -339,13 +329,13 @@ CURLcode Curl_SOCKS4(const char *proxy_name, ", Unknown.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), - socksreq[1]); + (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; } } - curlx_nonblock(sock, TRUE); + (void)curlx_nonblock(sock, TRUE); return CURLE_OK; /* Proxy was successful! */ } @@ -386,20 +376,19 @@ CURLcode Curl_SOCKS5(const char *proxy_name, curl_socket_t sock = conn->sock[sockindex]; struct SessionHandle *data = conn->data; long timeout; - bool socks5_resolve_local = (bool)(data->set.proxytype == CURLPROXY_SOCKS5); + bool socks5_resolve_local = (conn->proxytype == CURLPROXY_SOCKS5)?TRUE:FALSE; const size_t hostname_len = strlen(hostname); - ssize_t packetsize = 0; + ssize_t len = 0; /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ - if(!socks5_resolve_local && hostname_len > 255) - { - infof(conn->data,"SOCKS5: server resolving disabled for hostnames of " + if(!socks5_resolve_local && hostname_len > 255) { + infof(conn->data, "SOCKS5: server resolving disabled for hostnames of " "length > 255 [actual len=%zu]\n", hostname_len); socks5_resolve_local = TRUE; } /* get timeout */ - timeout = Curl_timeleft(conn, NULL, TRUE); + timeout = Curl_timeleft(data, NULL, TRUE); if(timeout < 0) { /* time-out, bail out, go home */ @@ -407,10 +396,10 @@ CURLcode Curl_SOCKS5(const char *proxy_name, return CURLE_OPERATION_TIMEDOUT; } - curlx_nonblock(sock, TRUE); + (void)curlx_nonblock(sock, TRUE); /* wait until socket gets connected */ - result = Curl_socket_ready(CURL_SOCKET_BAD, sock, (int)timeout); + result = Curl_socket_ready(CURL_SOCKET_BAD, sock, timeout); if(-1 == result) { failf(conn->data, "SOCKS5: no connection here"); @@ -422,7 +411,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, } if(result & CURL_CSELECT_ERR) { - failf(conn->data, "SOCKS5: error occured during connection"); + failf(conn->data, "SOCKS5: error occurred during connection"); return CURLE_COULDNT_CONNECT; } @@ -430,7 +419,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) socksreq[1] = (char)(proxy_name ? 3 : 2); /* number of methods (below) */ socksreq[2] = 0; /* no authentication */ - socksreq[3] = 1; /* gssapi */ + socksreq[3] = 1; /* GSS-API */ socksreq[4] = 2; /* username/password */ #else socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */ @@ -438,18 +427,18 @@ CURLcode Curl_SOCKS5(const char *proxy_name, socksreq[3] = 2; /* username/password */ #endif - curlx_nonblock(sock, FALSE); + (void)curlx_nonblock(sock, FALSE); code = Curl_write_plain(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]), &written); - if((code != CURLE_OK) || (written != (2 + (int)socksreq[1]))) { + if(code || (written != (2 + (int)socksreq[1]))) { failf(data, "Unable to send initial SOCKS5 request."); return CURLE_COULDNT_CONNECT; } - curlx_nonblock(sock, TRUE); + (void)curlx_nonblock(sock, TRUE); - result = Curl_socket_ready(sock, CURL_SOCKET_BAD, (int)timeout); + result = Curl_socket_ready(sock, CURL_SOCKET_BAD, timeout); if(-1 == result) { failf(conn->data, "SOCKS5 nothing to read"); @@ -461,15 +450,14 @@ CURLcode Curl_SOCKS5(const char *proxy_name, } if(result & CURL_CSELECT_ERR) { - failf(conn->data, "SOCKS5 read error occured"); + failf(conn->data, "SOCKS5 read error occurred"); return CURLE_RECV_ERROR; } - curlx_nonblock(sock, FALSE); + (void)curlx_nonblock(sock, FALSE); - result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread, - timeout); - if((result != CURLE_OK) || (actualread != 2)) { + result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); + if(result || (actualread != 2)) { failf(data, "Unable to receive initial SOCKS5 response."); return CURLE_COULDNT_CONNECT; } @@ -485,23 +473,22 @@ CURLcode Curl_SOCKS5(const char *proxy_name, #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) else if(socksreq[1] == 1) { code = Curl_SOCKS5_gssapi_negotiate(sockindex, conn); - if(code != CURLE_OK) { - failf(data, "Unable to negotiate SOCKS5 gssapi context."); + if(code) { + failf(data, "Unable to negotiate SOCKS5 GSS-API context."); return CURLE_COULDNT_CONNECT; } } #endif else if(socksreq[1] == 2) { /* Needs user name and password */ - size_t userlen, pwlen; - int len; + size_t proxy_name_len, proxy_password_len; if(proxy_name && proxy_password) { - userlen = strlen(proxy_name); - pwlen = strlen(proxy_password); + proxy_name_len = strlen(proxy_name); + proxy_password_len = strlen(proxy_password); } else { - userlen = 0; - pwlen = 0; + proxy_name_len = 0; + proxy_password_len = 0; } /* username/password request looks like @@ -513,24 +500,23 @@ CURLcode Curl_SOCKS5(const char *proxy_name, */ len = 0; socksreq[len++] = 1; /* username/pw subnegotiation version */ - socksreq[len++] = (unsigned char) userlen; - if(proxy_name && userlen) - memcpy(socksreq + len, proxy_name, userlen); - len += (int)userlen; - socksreq[len++] = (unsigned char) pwlen; - if(proxy_password && pwlen) - memcpy(socksreq + len, proxy_password, pwlen); - len += (int)pwlen; + socksreq[len++] = (unsigned char) proxy_name_len; + if(proxy_name && proxy_name_len) + memcpy(socksreq + len, proxy_name, proxy_name_len); + len += proxy_name_len; + socksreq[len++] = (unsigned char) proxy_password_len; + if(proxy_password && proxy_password_len) + memcpy(socksreq + len, proxy_password, proxy_password_len); + len += proxy_password_len; code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written); - if((code != CURLE_OK) || (len != written)) { + if(code || (len != written)) { failf(data, "Failed to send SOCKS5 sub-negotiation request."); return CURLE_COULDNT_CONNECT; } - result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread, - timeout); - if((result != CURLE_OK) || (actualread != 2)) { + result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); + if(result || (actualread != 2)) { failf(data, "Unable to receive SOCKS5 sub-negotiation response."); return CURLE_COULDNT_CONNECT; } @@ -575,36 +561,29 @@ CURLcode Curl_SOCKS5(const char *proxy_name, } /* Authentication is complete, now specify destination to the proxy */ - socksreq[0] = 5; /* version (SOCKS5) */ - socksreq[1] = 1; /* connect */ - socksreq[2] = 0; /* must be zero */ + len = 0; + socksreq[len++] = 5; /* version (SOCKS5) */ + socksreq[len++] = 1; /* connect */ + socksreq[len++] = 0; /* must be zero */ if(!socks5_resolve_local) { - packetsize = (ssize_t)(5 + hostname_len + 2); - - socksreq[3] = 3; /* ATYP: domain name = 3 */ - socksreq[4] = (char) hostname_len; /* address length */ - memcpy(&socksreq[5], hostname, hostname_len); /* address bytes w/o NULL */ - - *((unsigned short*)&socksreq[hostname_len+5]) = - htons((unsigned short)remote_port); + socksreq[len++] = 3; /* ATYP: domain name = 3 */ + socksreq[len++] = (char) hostname_len; /* address length */ + memcpy(&socksreq[len], hostname, hostname_len); /* address str w/o NULL */ + len += hostname_len; } else { struct Curl_dns_entry *dns; - Curl_addrinfo *hp=NULL; + Curl_addrinfo *hp = NULL; int rc = Curl_resolv(conn, hostname, remote_port, &dns); - packetsize = 10; - - socksreq[3] = 1; /* IPv4 = 1 */ - if(rc == CURLRESOLV_ERROR) return CURLE_COULDNT_RESOLVE_HOST; if(rc == CURLRESOLV_PENDING) { /* this requires that we're in "wait for resolve" state */ - code = Curl_wait_for_resolv(conn, &dns); - if(code != CURLE_OK) + code = Curl_resolver_wait_resolv(conn, &dns); + if(code) return code; } @@ -615,17 +594,31 @@ CURLcode Curl_SOCKS5(const char *proxy_name, if(dns) hp=dns->addr; if(hp) { - char buf[64]; - unsigned short ip[4]; - Curl_printable_address(hp, buf, sizeof(buf)); + struct sockaddr_in *saddr_in; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 *saddr_in6; +#endif + int i; - if(4 == sscanf( buf, "%hu.%hu.%hu.%hu", - &ip[0], &ip[1], &ip[2], &ip[3])) { - socksreq[4] = (unsigned char)ip[0]; - socksreq[5] = (unsigned char)ip[1]; - socksreq[6] = (unsigned char)ip[2]; - socksreq[7] = (unsigned char)ip[3]; + if(hp->ai_family == AF_INET) { + socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ + + saddr_in = (struct sockaddr_in*)(void*)hp->ai_addr; + for(i = 0; i < 4; i++) { + socksreq[len++] = ((unsigned char*)&saddr_in->sin_addr.s_addr)[i]; + infof(data, "%d\n", socksreq[len-1]); + } } +#ifdef ENABLE_IPV6 + else if(hp->ai_family == AF_INET6) { + socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ + + saddr_in6 = (struct sockaddr_in6*)(void*)hp->ai_addr; + for(i = 0; i < 16; i++) { + socksreq[len++] = ((unsigned char*)&saddr_in6->sin6_addr.s6_addr)[i]; + } + } +#endif else hp = NULL; /* fail! */ @@ -636,31 +629,36 @@ CURLcode Curl_SOCKS5(const char *proxy_name, hostname); return CURLE_COULDNT_RESOLVE_HOST; } - - *((unsigned short*)&socksreq[8]) = htons((unsigned short)remote_port); } + socksreq[len++] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */ + socksreq[len++] = (unsigned char)(remote_port & 0xff); /* PORT LSB */ + #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) if(conn->socks5_gssapi_enctype) { - failf(data, "SOCKS5 gssapi protection not yet implemented."); - } else + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + } + else #endif - code = Curl_write_plain(conn, sock, (char *)socksreq, packetsize, &written); - if((code != CURLE_OK) || (written != packetsize)) { + code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written); + + if(code || (len != written)) { failf(data, "Failed to send SOCKS5 connect request."); return CURLE_COULDNT_CONNECT; } - packetsize = 10; /* minimum packet size is 10 */ + len = 10; /* minimum packet size is 10 */ #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) if(conn->socks5_gssapi_enctype) { - failf(data, "SOCKS5 gssapi protection not yet implemented."); - } else + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + } + else #endif - result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize, - &actualread, timeout); - if((result != CURLE_OK) || (actualread != packetsize)) { + result = Curl_blockread_all(conn, sock, (char *)socksreq, + len, &actualread); + + if(result || (len != actualread)) { failf(data, "Failed to receive SOCKS5 connect request ack."); return CURLE_COULDNT_CONNECT; } @@ -671,13 +669,37 @@ CURLcode Curl_SOCKS5(const char *proxy_name, return CURLE_COULDNT_CONNECT; } if(socksreq[1] != 0) { /* Anything besides 0 is an error */ + if(socksreq[3] == 1) { failf(data, "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), - socksreq[1]); - return CURLE_COULDNT_CONNECT; + (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); + } + else if(socksreq[3] == 3) { + failf(data, + "Can't complete SOCKS5 connection to %s:%d. (%d)", + hostname, + (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); + } + else if(socksreq[3] == 4) { + failf(data, + "Can't complete SOCKS5 connection to %02x%02x:%02x%02x:" + "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%d. (%d)", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (unsigned char)socksreq[8], (unsigned char)socksreq[9], + (unsigned char)socksreq[10], (unsigned char)socksreq[11], + (unsigned char)socksreq[12], (unsigned char)socksreq[13], + (unsigned char)socksreq[14], (unsigned char)socksreq[15], + (unsigned char)socksreq[16], (unsigned char)socksreq[17], + (unsigned char)socksreq[18], (unsigned char)socksreq[19], + (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); + } + return CURLE_COULDNT_CONNECT; } /* Fix: in general, returned BND.ADDR is variable length parameter by RFC @@ -700,11 +722,11 @@ CURLcode Curl_SOCKS5(const char *proxy_name, if(socksreq[3] == 3) { /* domain name */ int addrlen = (int) socksreq[4]; - packetsize = 5 + addrlen + 2; + len = 5 + addrlen + 2; } else if(socksreq[3] == 4) { /* IPv6 */ - packetsize = 4 + 16 + 2; + len = 4 + 16 + 2; } /* At this point we already read first 10 bytes */ @@ -712,11 +734,11 @@ CURLcode Curl_SOCKS5(const char *proxy_name, if(!conn->socks5_gssapi_enctype) { /* decrypt_gssapi_blockread already read the whole packet */ #endif - if(packetsize > 10) { - packetsize -= 10; + if(len > 10) { + len -= 10; result = Curl_blockread_all(conn, sock, (char *)&socksreq[10], - packetsize, &actualread, timeout); - if((result != CURLE_OK) || (actualread != packetsize)) { + len, &actualread); + if(result || (len != actualread)) { failf(data, "Failed to receive SOCKS5 connect request ack."); return CURLE_COULDNT_CONNECT; } @@ -725,7 +747,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, } #endif - curlx_nonblock(sock, TRUE); + (void)curlx_nonblock(sock, TRUE); return CURLE_OK; /* Proxy was successful! */ } diff --git a/project/jni/curl/lib/socks.h b/project/jni/curl/lib/socks.h index 2bea66bf6..a44ada6be 100644 --- a/project/jni/curl/lib/socks.h +++ b/project/jni/curl/lib/socks.h @@ -1,5 +1,5 @@ -#ifndef __SOCKS_H -#define __SOCKS_H +#ifndef HEADER_CURL_SOCKS_H +#define HEADER_CURL_SOCKS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,6 +22,12 @@ * ***************************************************************************/ +#include "curl_setup.h" + +#ifdef CURL_DISABLE_PROXY +#define Curl_SOCKS4(a,b,c,d,e,f) CURLE_NOT_BUILT_IN +#define Curl_SOCKS5(a,b,c,d,e,f) CURLE_NOT_BUILT_IN +#else /* * Helper read-from-socket functions. Does the same as Curl_read() but it * blocks until all bytes amount of buffersize will be read. No more, no less. @@ -33,8 +39,7 @@ int Curl_blockread_all(struct connectdata *conn, curl_socket_t sockfd, char *buf, ssize_t buffersize, - ssize_t *n, - long conn_timeout); + ssize_t *n); /* * This function logs in to a SOCKS4(a) proxy and sends the specifics to the @@ -60,10 +65,13 @@ CURLcode Curl_SOCKS5(const char *proxy_name, #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) /* - * This function handles the sockss5 gssapie negotiation and initialisation + * This function handles the SOCKS5 GSS-API negotiation and initialisation */ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, struct connectdata *conn); #endif -#endif /* __SOCKS_H */ +#endif /* CURL_DISABLE_PROXY */ + +#endif /* HEADER_CURL_SOCKS_H */ + diff --git a/project/jni/curl/lib/socks_gssapi.c b/project/jni/curl/lib/socks_gssapi.c index 1ff6f6010..09457aecd 100644 --- a/project/jni/curl/lib/socks_gssapi.c +++ b/project/jni/curl/lib/socks_gssapi.c @@ -5,11 +5,12 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2009, Markus Moeller, + * Copyright (C) 2009, 2011, Markus Moeller, + * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,40 +21,26 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" -#ifndef CURL_DISABLE_PROXY - -#ifdef HAVE_GSSAPI -#ifdef HAVE_OLD_GSSMIT -#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name -#endif -#ifndef gss_nt_service_name -#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE -#endif -#include - -#ifdef HAVE_STDLIB_H -#include -#endif +#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_PROXY) +#include "curl_gssapi.h" #include "urldata.h" #include "sendf.h" #include "connect.h" #include "timeval.h" #include "socks.h" - -static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "warnless.h" +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" +static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; + /* - * Helper gssapi error functions. + * Helper GSS-API error functions. */ static int check_gss_err(struct SessionHandle *data, OM_uint32 major_status, @@ -61,7 +48,7 @@ static int check_gss_err(struct SessionHandle *data, const char* function) { if(GSS_ERROR(major_status)) { - OM_uint32 maj_stat,min_stat; + OM_uint32 maj_stat, min_stat; OM_uint32 msg_ctx = 0; gss_buffer_desc status_string; char buf[1024]; @@ -97,20 +84,18 @@ static int check_gss_err(struct SessionHandle *data, GSS_C_NULL_OID, &msg_ctx, &status_string); if(maj_stat == GSS_S_COMPLETE) { - if(sizeof(buf) > len + status_string.length) { + if(sizeof(buf) > len + status_string.length) strcpy(buf+len, (char*) status_string.value); - len += status_string.length; - } gss_release_buffer(&min_stat, &status_string); break; } gss_release_buffer(&min_stat, &status_string); } - failf(data, "GSSAPI error: %s failed:\n%s\n", function, buf); - return(1); + failf(data, "GSS-API error: %s failed:\n%s", function, buf); + return 1; } - return(0); + return 0; } CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, @@ -122,7 +107,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, ssize_t actualread; ssize_t written; int result; - long timeout; OM_uint32 gss_major_status, gss_minor_status, gss_status; OM_uint32 gss_ret_flags; int gss_conf_state, gss_enc; @@ -133,15 +117,12 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_buffer_desc* gss_token = GSS_C_NO_BUFFER; gss_name_t server = GSS_C_NO_NAME; gss_name_t gss_client_name = GSS_C_NO_NAME; - u_short us_length; + unsigned short us_length; char *user=NULL; - unsigned char socksreq[4]; /* room for gssapi exchange header only */ + unsigned char socksreq[4]; /* room for GSS-API exchange header only */ char *serviceptr = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE]; - /* get timeout */ - timeout = Curl_timeleft(conn, NULL, TRUE); - - /* GSSAPI request looks like + /* GSS-API request looks like * +----+------+-----+----------------+ * |VER | MTYP | LEN | TOKEN | * +----+------+----------------------+ @@ -150,7 +131,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, */ /* prepare service name */ - if (strchr(serviceptr,'/')) { + if(strchr(serviceptr, '/')) { service.value = malloc(strlen(serviceptr)); if(!service.value) return CURLE_OUT_OF_MEMORY; @@ -169,13 +150,13 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, serviceptr, conn->proxy.name); gss_major_status = gss_import_name(&gss_minor_status, &service, - gss_nt_service_name, &server); + GSS_C_NT_HOSTBASED_SERVICE, &server); } gss_release_buffer(&gss_status, &service); /* clear allocated memory */ - if(check_gss_err(data,gss_major_status, - gss_minor_status,"gss_import_name()")) { + if(check_gss_err(data, gss_major_status, + gss_minor_status, "gss_import_name()")) { failf(data, "Failed to create service name."); gss_release_name(&gss_status, &server); return CURLE_COULDNT_CONNECT; @@ -184,41 +165,38 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, /* As long as we need to keep sending some context info, and there's no */ /* errors, keep sending it... */ for(;;) { - gss_major_status = gss_init_sec_context(&gss_minor_status, - GSS_C_NO_CREDENTIAL, - &gss_context, server, - GSS_C_NULL_OID, - GSS_C_MUTUAL_FLAG | - GSS_C_REPLAY_FLAG, - 0, - NULL, - gss_token, - NULL, - &gss_send_token, - &gss_ret_flags, - NULL); + gss_major_status = Curl_gss_init_sec_context(data, + &gss_minor_status, + &gss_context, + server, + &Curl_krb5_mech_oid, + NULL, + gss_token, + &gss_send_token, + TRUE, + &gss_ret_flags); if(gss_token != GSS_C_NO_BUFFER) gss_release_buffer(&gss_status, &gss_recv_token); - if(check_gss_err(data,gss_major_status, - gss_minor_status,"gss_init_sec_context")) { + if(check_gss_err(data, gss_major_status, + gss_minor_status, "gss_init_sec_context")) { gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); - failf(data, "Failed to initial GSSAPI token."); + failf(data, "Failed to initial GSS-API token."); return CURLE_COULDNT_CONNECT; } if(gss_send_token.length != 0) { - socksreq[0] = 1; /* gssapi subnegotiation version */ + socksreq[0] = 1; /* GSS-API subnegotiation version */ socksreq[1] = 1; /* authentication message type */ us_length = htons((short)gss_send_token.length); - memcpy(socksreq+2,&us_length,sizeof(short)); + memcpy(socksreq+2, &us_length, sizeof(short)); code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); - if((code != CURLE_OK) || (4 != written)) { - failf(data, "Failed to send GSSAPI authentication request."); + if(code || (4 != written)) { + failf(data, "Failed to send GSS-API authentication request."); gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); @@ -229,8 +207,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, code = Curl_write_plain(conn, sock, (char *)gss_send_token.value, gss_send_token.length, &written); - if((code != CURLE_OK) || ((ssize_t)gss_send_token.length != written)) { - failf(data, "Failed to send GSSAPI authentication token."); + if(code || ((ssize_t)gss_send_token.length != written)) { + failf(data, "Failed to send GSS-API authentication token."); gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); @@ -246,7 +224,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, /* analyse response */ - /* GSSAPI response looks like + /* GSS-API response looks like * +----+------+-----+----------------+ * |VER | MTYP | LEN | TOKEN | * +----+------+----------------------+ @@ -254,10 +232,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, * +----+------+-----+----------------+ */ - result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, - &actualread, timeout); - if(result != CURLE_OK || actualread != 4) { - failf(data, "Failed to receive GSSAPI authentication response."); + result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); + if(result || (actualread != 4)) { + failf(data, "Failed to receive GSS-API authentication response."); gss_release_name(&gss_status, &server); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; @@ -273,7 +250,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } if(socksreq[1] != 1) { /* status / messgae type */ - failf(data, "Invalid GSSAPI authentication response type (%d %d).", + failf(data, "Invalid GSS-API authentication response type (%d %d).", socksreq[0], socksreq[1]); gss_release_name(&gss_status, &server); gss_delete_sec_context(&gss_status, &gss_context, NULL); @@ -287,7 +264,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_recv_token.value=malloc(us_length); if(!gss_recv_token.value) { failf(data, - "Could not allocate memory for GSSAPI authentication " + "Could not allocate memory for GSS-API authentication " "response token."); gss_release_name(&gss_status, &server); gss_delete_sec_context(&gss_status, &gss_context, NULL); @@ -295,11 +272,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, - gss_recv_token.length, - &actualread, timeout); + gss_recv_token.length, &actualread); - if(result != CURLE_OK || actualread != us_length) { - failf(data, "Failed to receive GSSAPI authentication token."); + if(result || (actualread != us_length)) { + failf(data, "Failed to receive GSS-API authentication token."); gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); @@ -315,8 +291,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_major_status = gss_inquire_context (&gss_minor_status, gss_context, &gss_client_name, NULL, NULL, NULL, NULL, NULL, NULL); - if(check_gss_err(data,gss_major_status, - gss_minor_status,"gss_inquire_context")) { + if(check_gss_err(data, gss_major_status, + gss_minor_status, "gss_inquire_context")) { gss_delete_sec_context(&gss_status, &gss_context, NULL); gss_release_name(&gss_status, &gss_client_name); failf(data, "Failed to determine user name."); @@ -324,8 +300,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } gss_major_status = gss_display_name(&gss_minor_status, gss_client_name, &gss_send_token, NULL); - if(check_gss_err(data,gss_major_status, - gss_minor_status,"gss_display_name")) { + if(check_gss_err(data, gss_major_status, + gss_minor_status, "gss_display_name")) { gss_delete_sec_context(&gss_status, &gss_context, NULL); gss_release_name(&gss_status, &gss_client_name); gss_release_buffer(&gss_status, &gss_send_token); @@ -344,12 +320,12 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, user[gss_send_token.length] = '\0'; gss_release_name(&gss_status, &gss_client_name); gss_release_buffer(&gss_status, &gss_send_token); - infof(data, "SOCKS5 server authencticated user %s with gssapi.\n",user); + infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n",user); free(user); user=NULL; /* Do encryption */ - socksreq[0] = 1; /* gssapi subnegotiation version */ + socksreq[0] = 1; /* GSS-API subnegotiation version */ socksreq[1] = 2; /* encryption message type */ gss_enc = 0; /* no data protection */ @@ -360,7 +336,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, else if(gss_ret_flags & GSS_C_INTEG_FLAG) gss_enc = 1; - infof(data, "SOCKS5 server supports gssapi %s data protection.\n", + infof(data, "SOCKS5 server supports GSS-API %s data protection.\n", (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality")); /* force for the moment to no data protection */ gss_enc = 0; @@ -396,7 +372,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, */ if(data->set.socks5_gssapi_nec) { us_length = htons((short)1); - memcpy(socksreq+2,&us_length,sizeof(short)); + memcpy(socksreq+2, &us_length, sizeof(short)); } else { gss_send_token.length = 1; @@ -411,22 +387,22 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, GSS_C_QOP_DEFAULT, &gss_send_token, &gss_conf_state, &gss_w_token); - if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_wrap")) { + if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_wrap")) { gss_release_buffer(&gss_status, &gss_send_token); gss_release_buffer(&gss_status, &gss_w_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); - failf(data, "Failed to wrap GSSAPI encryption value into token."); + failf(data, "Failed to wrap GSS-API encryption value into token."); return CURLE_COULDNT_CONNECT; } gss_release_buffer(&gss_status, &gss_send_token); us_length = htons((short)gss_w_token.length); - memcpy(socksreq+2,&us_length,sizeof(short)); + memcpy(socksreq+2, &us_length, sizeof(short)); } code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); - if((code != CURLE_OK) || (4 != written)) { - failf(data, "Failed to send GSSAPI encryption request."); + if(code || (4 != written)) { + failf(data, "Failed to send GSS-API encryption request."); gss_release_buffer(&gss_status, &gss_w_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; @@ -435,16 +411,17 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, if(data->set.socks5_gssapi_nec) { memcpy(socksreq, &gss_enc, 1); code = Curl_write_plain(conn, sock, socksreq, 1, &written); - if((code != CURLE_OK) || ( 1 != written)) { - failf(data, "Failed to send GSSAPI encryption type."); + if(code || ( 1 != written)) { + failf(data, "Failed to send GSS-API encryption type."); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } - } else { + } + else { code = Curl_write_plain(conn, sock, (char *)gss_w_token.value, gss_w_token.length, &written); - if((code != CURLE_OK) || ((ssize_t)gss_w_token.length != written)) { - failf(data, "Failed to send GSSAPI encryption type."); + if(code || ((ssize_t)gss_w_token.length != written)) { + failf(data, "Failed to send GSS-API encryption type."); gss_release_buffer(&gss_status, &gss_w_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; @@ -452,10 +429,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_release_buffer(&gss_status, &gss_w_token); } - result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, - &actualread, timeout); - if(result != CURLE_OK || actualread != 4) { - failf(data, "Failed to receive GSSAPI encryption response."); + result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); + if(result || (actualread != 4)) { + failf(data, "Failed to receive GSS-API encryption response."); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } @@ -469,7 +445,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } if(socksreq[1] != 2) { /* status / messgae type */ - failf(data, "Invalid GSSAPI encryption response type (%d %d).", + failf(data, "Invalid GSS-API encryption response type (%d %d).", socksreq[0], socksreq[1]); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; @@ -485,11 +461,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_OUT_OF_MEMORY; } result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, - gss_recv_token.length, - &actualread, timeout); + gss_recv_token.length, &actualread); - if(result != CURLE_OK || actualread != us_length) { - failf(data, "Failed to receive GSSAPI encryptrion type."); + if(result || (actualread != us_length)) { + failf(data, "Failed to receive GSS-API encryptrion type."); gss_release_buffer(&gss_status, &gss_recv_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; @@ -500,42 +475,42 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, &gss_recv_token, &gss_w_token, 0, GSS_C_QOP_DEFAULT); - if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_unwrap")) { + if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_unwrap")) { gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_w_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); - failf(data, "Failed to unwrap GSSAPI encryption value into token."); + failf(data, "Failed to unwrap GSS-API encryption value into token."); return CURLE_COULDNT_CONNECT; } gss_release_buffer(&gss_status, &gss_recv_token); if(gss_w_token.length != 1) { - failf(data, "Invalid GSSAPI encryption response length (%d).", + failf(data, "Invalid GSS-API encryption response length (%d).", gss_w_token.length); gss_release_buffer(&gss_status, &gss_w_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } - memcpy(socksreq,gss_w_token.value,gss_w_token.length); + memcpy(socksreq, gss_w_token.value, gss_w_token.length); gss_release_buffer(&gss_status, &gss_w_token); } else { if(gss_recv_token.length != 1) { - failf(data, "Invalid GSSAPI encryption response length (%d).", + failf(data, "Invalid GSS-API encryption response length (%d).", gss_recv_token.length); gss_release_buffer(&gss_status, &gss_recv_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } - memcpy(socksreq,gss_recv_token.value,gss_recv_token.length); + memcpy(socksreq, gss_recv_token.value, gss_recv_token.length); gss_release_buffer(&gss_status, &gss_recv_token); } infof(data, "SOCKS5 access with%s protection granted.\n", - (socksreq[0]==0)?"out gssapi data": - ((socksreq[0]==1)?" gssapi integrity":" gssapi confidentiality")); + (socksreq[0]==0)?"out GSS-API data": + ((socksreq[0]==1)?" GSS-API integrity":" GSS-API confidentiality")); conn->socks5_gssapi_enctype = socksreq[0]; if(socksreq[0] == 0) @@ -543,6 +518,5 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_OK; } -#endif -#endif /* CURL_DISABLE_PROXY */ +#endif /* HAVE_GSSAPI && !CURL_DISABLE_PROXY */ diff --git a/project/jni/curl/lib/socks_sspi.c b/project/jni/curl/lib/socks_sspi.c index e9fd551cc..356772e1f 100644 --- a/project/jni/curl/lib/socks_sspi.c +++ b/project/jni/curl/lib/socks_sspi.c @@ -5,11 +5,12 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2009, Markus Moeller, + * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2009, 2011, Markus Moeller, * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,137 +21,37 @@ * ***************************************************************************/ +#include "curl_setup.h" -#include "setup.h" - -#ifdef USE_WINDOWS_SSPI - -#include - -#ifdef HAVE_STDLIB_H -#include -#endif +#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_PROXY) #include "urldata.h" #include "sendf.h" #include "connect.h" +#include "strerror.h" #include "timeval.h" #include "socks.h" #include "curl_sspi.h" - -#define _MPRINTF_REPLACE /* use the internal *printf() functions */ -#include - +#include "curl_multibyte.h" +#include "warnless.h" +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" -/* - * Definitions required from ntsecapi.h are directly provided below this point - * to avoid including ntsecapi.h due to a conflict with OpenSSL's safestack.h - */ -#define KERB_WRAP_NO_ENCRYPT 0x80000001 - /* * Helper sspi error functions. */ -static int check_sspi_err(struct SessionHandle *data, - SECURITY_STATUS major_status, - SECURITY_STATUS minor_status, +static int check_sspi_err(struct connectdata *conn, + SECURITY_STATUS status, const char* function) { - const char *txt; - (void)minor_status; - - if(major_status != SEC_E_OK && - major_status != SEC_I_COMPLETE_AND_CONTINUE && - major_status != SEC_I_COMPLETE_NEEDED && - major_status != SEC_I_CONTINUE_NEEDED) { - failf(data, "SSPI error: %s failed: %d\n", function, major_status); - switch (major_status) { - case SEC_I_COMPLETE_AND_CONTINUE: - txt="SEC_I_COMPLETE_AND_CONTINUE"; - break; - case SEC_I_COMPLETE_NEEDED: - txt="SEC_I_COMPLETE_NEEDED"; - break; - case SEC_I_CONTINUE_NEEDED: - txt="SEC_I_CONTINUE_NEEDED"; - break; - case SEC_I_CONTEXT_EXPIRED: - txt="SEC_I_CONTEXT_EXPIRED"; - break; - case SEC_I_INCOMPLETE_CREDENTIALS: - txt="SEC_I_INCOMPLETE_CREDENTIALS"; - break; - case SEC_I_RENEGOTIATE: - txt="SEC_I_RENEGOTIATE"; - break; - case SEC_E_BUFFER_TOO_SMALL: - txt="SEC_E_BUFFER_TOO_SMALL"; - break; - case SEC_E_CONTEXT_EXPIRED: - txt="SEC_E_CONTEXT_EXPIRED"; - break; - case SEC_E_CRYPTO_SYSTEM_INVALID: - txt="SEC_E_CRYPTO_SYSTEM_INVALID"; - break; - case SEC_E_INCOMPLETE_MESSAGE: - txt="SEC_E_INCOMPLETE_MESSAGE"; - break; - case SEC_E_INSUFFICIENT_MEMORY: - txt="SEC_E_INSUFFICIENT_MEMORY"; - break; - case SEC_E_INTERNAL_ERROR: - txt="SEC_E_INTERNAL_ERROR"; - break; - case SEC_E_INVALID_HANDLE: - txt="SEC_E_INVALID_HANDLE"; - break; - case SEC_E_INVALID_TOKEN: - txt="SEC_E_INVALID_TOKEN"; - break; - case SEC_E_LOGON_DENIED: - txt="SEC_E_LOGON_DENIED"; - break; - case SEC_E_MESSAGE_ALTERED: - txt="SEC_E_MESSAGE_ALTERED"; - break; - case SEC_E_NO_AUTHENTICATING_AUTHORITY: - txt="SEC_E_NO_AUTHENTICATING_AUTHORITY"; - break; - case SEC_E_NO_CREDENTIALS: - txt="SEC_E_NO_CREDENTIALS"; - break; - case SEC_E_NOT_OWNER: - txt="SEC_E_NOT_OWNER"; - break; - case SEC_E_OUT_OF_SEQUENCE: - txt="SEC_E_OUT_OF_SEQUENCE"; - break; - case SEC_E_QOP_NOT_SUPPORTED: - txt="SEC_E_QOP_NOT_SUPPORTED"; - break; - case SEC_E_SECPKG_NOT_FOUND: - txt="SEC_E_SECPKG_NOT_FOUND"; - break; - case SEC_E_TARGET_UNKNOWN: - txt="SEC_E_TARGET_UNKNOWN"; - break; - case SEC_E_UNKNOWN_CREDENTIALS: - txt="SEC_E_UNKNOWN_CREDENTIALS"; - break; - case SEC_E_UNSUPPORTED_FUNCTION: - txt="SEC_E_UNSUPPORTED_FUNCTION"; - break; - case SEC_E_WRONG_PRINCIPAL: - txt="SEC_E_WRONG_PRINCIPAL"; - break; - default: - txt="Unknown error"; - - } - failf(data, "SSPI error: %s failed: %s\n", function, txt); + if(status != SEC_E_OK && + status != SEC_I_COMPLETE_AND_CONTINUE && + status != SEC_I_COMPLETE_NEEDED && + status != SEC_I_CONTINUE_NEEDED) { + failf(conn->data, "SSPI error: %s failed: %s", function, + Curl_sspi_strerror(conn, status)); return 1; } return 0; @@ -166,10 +67,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, ssize_t actualread; ssize_t written; int result; - long timeout; - /* Needs GSSAPI authentication */ - SECURITY_STATUS sspi_major_status, sspi_minor_status=0; - unsigned long sspi_ret_flags=0; + /* Needs GSS-API authentication */ + SECURITY_STATUS status; + unsigned long sspi_ret_flags = 0; int gss_enc; SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3]; SecBufferDesc input_desc, output_desc, wrap_desc; @@ -179,16 +79,13 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, PCtxtHandle context_handle = NULL; SecPkgCredentials_Names names; TimeStamp expiry; - char *service_name=NULL; - u_short us_length; - ULONG qop; - unsigned char socksreq[4]; /* room for gssapi exchange header only */ + char *service_name = NULL; + unsigned short us_length; + unsigned long qop; + unsigned char socksreq[4]; /* room for GSS-API exchange header only */ char *service = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE]; - /* get timeout */ - timeout = Curl_timeleft(conn, NULL, TRUE); - - /* GSSAPI request looks like + /* GSS-API request looks like * +----+------+-----+----------------+ * |VER | MTYP | LEN | TOKEN | * +----+------+----------------------+ @@ -197,7 +94,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, */ /* prepare service name */ - if (strchr(service, '/')) { + if(strchr(service, '/')) { service_name = malloc(strlen(service)); if(!service_name) return CURLE_OUT_OF_MEMORY; @@ -207,8 +104,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, service_name = malloc(strlen(service) + strlen(conn->proxy.name) + 2); if(!service_name) return CURLE_OUT_OF_MEMORY; - snprintf(service_name,strlen(service) +strlen(conn->proxy.name)+2,"%s/%s", - service,conn->proxy.name); + snprintf(service_name, strlen(service) +strlen(conn->proxy.name)+2, + "%s/%s", service, conn->proxy.name); } input_desc.cBuffers = 1; @@ -234,21 +131,19 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, cred_handle.dwLower = 0; cred_handle.dwUpper = 0; - sspi_major_status = s_pSecFn->AcquireCredentialsHandleA( NULL, - (char *)"Kerberos", - SECPKG_CRED_OUTBOUND, - NULL, - NULL, - NULL, - NULL, - &cred_handle, - &expiry); + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT("Kerberos"), + SECPKG_CRED_OUTBOUND, + NULL, + NULL, + NULL, + NULL, + &cred_handle, + &expiry); - if(check_sspi_err(data, sspi_major_status,sspi_minor_status, - "AcquireCredentialsHandleA") ) { + if(check_sspi_err(conn, status, "AcquireCredentialsHandle")) { failf(data, "Failed to acquire credentials."); free(service_name); - service_name=NULL; s_pSecFn->FreeCredentialsHandle(&cred_handle); return CURLE_COULDNT_CONNECT; } @@ -256,23 +151,29 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, /* As long as we need to keep sending some context info, and there's no */ /* errors, keep sending it... */ for(;;) { + TCHAR *sname; - sspi_major_status = s_pSecFn->InitializeSecurityContextA( - &cred_handle, - context_handle, - service_name, - ISC_REQ_MUTUAL_AUTH | - ISC_REQ_ALLOCATE_MEMORY | - ISC_REQ_CONFIDENTIALITY | - ISC_REQ_REPLAY_DETECT, - 0, - SECURITY_NATIVE_DREP, - &input_desc, - 0, - &sspi_context, - &output_desc, - &sspi_ret_flags, - &expiry); + sname = Curl_convert_UTF8_to_tchar(service_name); + if(!sname) + return CURLE_OUT_OF_MEMORY; + + status = s_pSecFn->InitializeSecurityContext(&cred_handle, + context_handle, + sname, + ISC_REQ_MUTUAL_AUTH | + ISC_REQ_ALLOCATE_MEMORY | + ISC_REQ_CONFIDENTIALITY | + ISC_REQ_REPLAY_DETECT, + 0, + SECURITY_NATIVE_DREP, + &input_desc, + 0, + &sspi_context, + &output_desc, + &sspi_ret_flags, + &expiry); + + Curl_unicodefree(sname); if(sspi_recv_token.pvBuffer) { s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); @@ -280,30 +181,30 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, sspi_recv_token.cbBuffer = 0; } - if(check_sspi_err(data,sspi_major_status,sspi_minor_status, - "InitializeSecurityContextA") ){ + if(check_sspi_err(conn, status, "InitializeSecurityContext")) { free(service_name); - service_name=NULL; s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); - s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); + if(sspi_recv_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); failf(data, "Failed to initialise security context."); return CURLE_COULDNT_CONNECT; } if(sspi_send_token.cbBuffer != 0) { - socksreq[0] = 1; /* gssapi subnegotiation version */ + socksreq[0] = 1; /* GSS-API subnegotiation version */ socksreq[1] = 1; /* authentication message type */ us_length = htons((short)sspi_send_token.cbBuffer); memcpy(socksreq+2, &us_length, sizeof(short)); code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); - if((code != CURLE_OK) || (4 != written)) { + if(code || (4 != written)) { failf(data, "Failed to send SSPI authentication request."); free(service_name); - service_name=NULL; - s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); - s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); + if(sspi_send_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); + if(sspi_recv_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; @@ -311,12 +212,13 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer, sspi_send_token.cbBuffer, &written); - if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) { + if(code || (sspi_send_token.cbBuffer != (size_t)written)) { failf(data, "Failed to send SSPI authentication token."); free(service_name); - service_name=NULL; - s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); - s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); + if(sspi_send_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); + if(sspi_recv_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; @@ -324,17 +226,24 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } - s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); - sspi_send_token.pvBuffer = NULL; + if(sspi_send_token.pvBuffer) { + s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); + sspi_send_token.pvBuffer = NULL; + } sspi_send_token.cbBuffer = 0; - s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); - sspi_recv_token.pvBuffer = NULL; + + if(sspi_recv_token.pvBuffer) { + s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); + sspi_recv_token.pvBuffer = NULL; + } sspi_recv_token.cbBuffer = 0; - if(sspi_major_status != SEC_I_CONTINUE_NEEDED) break; + + if(status != SEC_I_CONTINUE_NEEDED) + break; /* analyse response */ - /* GSSAPI response looks like + /* GSS-API response looks like * +----+------+-----+----------------+ * |VER | MTYP | LEN | TOKEN | * +----+------+----------------------+ @@ -342,12 +251,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, * +----+------+-----+----------------+ */ - result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, - &actualread, timeout); - if(result != CURLE_OK || actualread != 4) { + result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); + if(result || (actualread != 4)) { failf(data, "Failed to receive SSPI authentication response."); free(service_name); - service_name=NULL; s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; @@ -355,20 +262,18 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, /* ignore the first (VER) byte */ if(socksreq[1] == 255) { /* status / message type */ - failf(data, "User was rejected by the SOCKS5 server (%d %d).", - socksreq[0], socksreq[1]); + failf(data, "User was rejected by the SOCKS5 server (%u %u).", + (unsigned int)socksreq[0], (unsigned int)socksreq[1]); free(service_name); - service_name=NULL; s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } if(socksreq[1] != 1) { /* status / messgae type */ - failf(data, "Invalid SSPI authentication response type (%d %d).", - socksreq[0], socksreq[1]); + failf(data, "Invalid SSPI authentication response type (%u %u).", + (unsigned int)socksreq[0], (unsigned int)socksreq[1]); free(service_name); - service_name=NULL; s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; @@ -382,20 +287,18 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, if(!sspi_recv_token.pvBuffer) { free(service_name); - service_name=NULL; s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_OUT_OF_MEMORY; } result = Curl_blockread_all(conn, sock, (char *)sspi_recv_token.pvBuffer, - sspi_recv_token.cbBuffer, - &actualread, timeout); + sspi_recv_token.cbBuffer, &actualread); - if(result != CURLE_OK || actualread != us_length) { + if(result || (actualread != us_length)) { failf(data, "Failed to receive SSPI authentication token."); free(service_name); - service_name=NULL; - s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); + if(sspi_recv_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; @@ -405,26 +308,24 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } free(service_name); - service_name=NULL; /* Everything is good so far, user was authenticated! */ - sspi_major_status = s_pSecFn->QueryCredentialsAttributes( &cred_handle, - SECPKG_CRED_ATTR_NAMES, - &names); + status = s_pSecFn->QueryCredentialsAttributes(&cred_handle, + SECPKG_CRED_ATTR_NAMES, + &names); s_pSecFn->FreeCredentialsHandle(&cred_handle); - if(check_sspi_err(data,sspi_major_status,sspi_minor_status, - "QueryCredentialAttributes") ){ + if(check_sspi_err(conn, status, "QueryCredentialAttributes")) { s_pSecFn->DeleteSecurityContext(&sspi_context); s_pSecFn->FreeContextBuffer(names.sUserName); failf(data, "Failed to determine user name."); return CURLE_COULDNT_CONNECT; } - infof(data, "SOCKS5 server authencticated user %s with gssapi.\n", + infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n", names.sUserName); s_pSecFn->FreeContextBuffer(names.sUserName); /* Do encryption */ - socksreq[0] = 1; /* gssapi subnegotiation version */ + socksreq[0] = 1; /* GSS-API subnegotiation version */ socksreq[1] = 2; /* encryption message type */ gss_enc = 0; /* no data protection */ @@ -435,7 +336,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, else if(sspi_ret_flags & ISC_REQ_INTEGRITY) gss_enc = 1; - infof(data, "SOCKS5 server supports gssapi %s data protection.\n", + infof(data, "SOCKS5 server supports GSS-API %s data protection.\n", (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality") ); /* force to no data protection, avoid encryption/decryption for now */ gss_enc = 0; @@ -475,11 +376,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, memcpy(socksreq+2, &us_length, sizeof(short)); } else { - sspi_major_status = s_pSecFn->QueryContextAttributesA( &sspi_context, - SECPKG_ATTR_SIZES, - &sspi_sizes); - if(check_sspi_err(data,sspi_major_status,sspi_minor_status, - "QueryContextAttributesA")) { + status = s_pSecFn->QueryContextAttributes(&sspi_context, + SECPKG_ATTR_SIZES, + &sspi_sizes); + if(check_sspi_err(conn, status, "QueryContextAttributes")) { s_pSecFn->DeleteSecurityContext(&sspi_context); failf(data, "Failed to query security context attributes."); return CURLE_COULDNT_CONNECT; @@ -496,13 +396,13 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, sspi_w_token[1].cbBuffer = 1; sspi_w_token[1].pvBuffer = malloc(1); - if(!sspi_w_token[1].pvBuffer){ + if(!sspi_w_token[1].pvBuffer) { s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_OUT_OF_MEMORY; } - memcpy(sspi_w_token[1].pvBuffer,&gss_enc,1); + memcpy(sspi_w_token[1].pvBuffer, &gss_enc, 1); sspi_w_token[2].BufferType = SECBUFFER_PADDING; sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize; sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize); @@ -512,12 +412,11 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_OUT_OF_MEMORY; } - sspi_major_status = s_pSecFn->EncryptMessage( &sspi_context, - KERB_WRAP_NO_ENCRYPT, - &wrap_desc, - 0); - if(check_sspi_err(data,sspi_major_status,sspi_minor_status, - "EncryptMessage") ) { + status = s_pSecFn->EncryptMessage(&sspi_context, + KERB_WRAP_NO_ENCRYPT, + &wrap_desc, + 0); + if(check_sspi_err(conn, status, "EncryptMessage")) { s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); @@ -557,40 +456,43 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, sspi_w_token[2].cbBuffer = 0; us_length = htons((short)sspi_send_token.cbBuffer); - memcpy(socksreq+2,&us_length,sizeof(short)); + memcpy(socksreq+2, &us_length, sizeof(short)); } code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); - if((code != CURLE_OK) || (4 != written)) { + if(code || (4 != written)) { failf(data, "Failed to send SSPI encryption request."); - s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); + if(sspi_send_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } if(data->set.socks5_gssapi_nec) { - memcpy(socksreq,&gss_enc,1); + memcpy(socksreq, &gss_enc, 1); code = Curl_write_plain(conn, sock, (char *)socksreq, 1, &written); - if((code != CURLE_OK) || (1 != written)) { + if(code || (1 != written)) { failf(data, "Failed to send SSPI encryption type."); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } - } else { + } + else { code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer, sspi_send_token.cbBuffer, &written); - if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) { + if(code || (sspi_send_token.cbBuffer != (size_t)written)) { failf(data, "Failed to send SSPI encryption type."); - s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); + if(sspi_send_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } - s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); + if(sspi_send_token.pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); } - result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, - &actualread, timeout); - if(result != CURLE_OK || actualread != 4) { + result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); + if(result || (actualread != 4)) { failf(data, "Failed to receive SSPI encryption response."); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; @@ -598,15 +500,15 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, /* ignore the first (VER) byte */ if(socksreq[1] == 255) { /* status / message type */ - failf(data, "User was rejected by the SOCKS5 server (%d %d).", - socksreq[0], socksreq[1]); + failf(data, "User was rejected by the SOCKS5 server (%u %u).", + (unsigned int)socksreq[0], (unsigned int)socksreq[1]); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } if(socksreq[1] != 2) { /* status / message type */ - failf(data, "Invalid SSPI encryption response type (%d %d).", - socksreq[0], socksreq[1]); + failf(data, "Invalid SSPI encryption response type (%u %u).", + (unsigned int)socksreq[0], (unsigned int)socksreq[1]); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } @@ -621,11 +523,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_OUT_OF_MEMORY; } - result=Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer, - sspi_w_token[0].cbBuffer, - &actualread, timeout); + result = Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer, + sspi_w_token[0].cbBuffer, &actualread); - if(result != CURLE_OK || actualread != us_length) { + if(result || (actualread != us_length)) { failf(data, "Failed to receive SSPI encryption type."); s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); @@ -640,55 +541,59 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, sspi_w_token[1].cbBuffer = 0; sspi_w_token[1].pvBuffer = NULL; - sspi_major_status = s_pSecFn->DecryptMessage( &sspi_context, - &wrap_desc, - 0, - &qop); + status = s_pSecFn->DecryptMessage(&sspi_context, + &wrap_desc, + 0, + &qop); - if(check_sspi_err(data,sspi_major_status,sspi_minor_status, - "DecryptMessage")) { - s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + if(check_sspi_err(conn, status, "DecryptMessage")) { + if(sspi_w_token[0].pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + if(sspi_w_token[1].pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); failf(data, "Failed to query security context attributes."); return CURLE_COULDNT_CONNECT; } if(sspi_w_token[1].cbBuffer != 1) { - failf(data, "Invalid SSPI encryption response length (%d).", - sspi_w_token[1].cbBuffer); - s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + failf(data, "Invalid SSPI encryption response length (%lu).", + (unsigned long)sspi_w_token[1].cbBuffer); + if(sspi_w_token[0].pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + if(sspi_w_token[1].pvBuffer) + s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } - memcpy(socksreq,sspi_w_token[1].pvBuffer,sspi_w_token[1].cbBuffer); + memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - } else { + } + else { if(sspi_w_token[0].cbBuffer != 1) { - failf(data, "Invalid SSPI encryption response length (%d).", - sspi_w_token[0].cbBuffer); + failf(data, "Invalid SSPI encryption response length (%lu).", + (unsigned long)sspi_w_token[0].cbBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } - memcpy(socksreq,sspi_w_token[0].pvBuffer,sspi_w_token[0].cbBuffer); + memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); } infof(data, "SOCKS5 access with%s protection granted.\n", - (socksreq[0]==0)?"out gssapi data": - ((socksreq[0]==1)?" gssapi integrity":" gssapi confidentiality")); + (socksreq[0]==0)?"out GSS-API data": + ((socksreq[0]==1)?" GSS-API integrity":" GSS-API confidentiality")); /* For later use if encryption is required conn->socks5_gssapi_enctype = socksreq[0]; - if (socksreq[0] != 0) - conn->socks5_sspi_context = sspi_context; + if(socksreq[0] != 0) + conn->socks5_sspi_context = sspi_context; else { - s_pSecFn->DeleteSecurityContext(&sspi_context); - conn->socks5_sspi_context = sspi_context; + s_pSecFn->DeleteSecurityContext(&sspi_context); + conn->socks5_sspi_context = sspi_context; } */ return CURLE_OK; diff --git a/project/jni/curl/lib/speedcheck.c b/project/jni/curl/lib/speedcheck.c index 38bad5a57..4706d2dff 100644 --- a/project/jni/curl/lib/speedcheck.c +++ b/project/jni/curl/lib/speedcheck.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,10 +20,7 @@ * ***************************************************************************/ -#include "setup.h" - -#include -#include +#include "curl_setup.h" #include #include "urldata.h" @@ -44,21 +41,24 @@ CURLcode Curl_speedcheck(struct SessionHandle *data, (Curl_tvlong(data->state.keeps_speed) != 0) && (data->progress.current_speed < data->set.low_speed_limit)) { long howlong = Curl_tvdiff(now, data->state.keeps_speed); + long nextcheck = (data->set.low_speed_time * 1000) - howlong; /* We are now below the "low speed limit". If we are below it for "low speed time" seconds we consider that enough reason to abort the download. */ - - if( (howlong/1000) > data->set.low_speed_time) { + if(nextcheck <= 0) { /* we have been this slow for long enough, now die */ failf(data, "Operation too slow. " - "Less than %ld bytes/sec transfered the last %ld seconds", + "Less than %ld bytes/sec transferred the last %ld seconds", data->set.low_speed_limit, data->set.low_speed_time); return CURLE_OPERATION_TIMEDOUT; } - Curl_expire(data, howlong); + else { + /* wait complete low_speed_time */ + Curl_expire_latest(data, nextcheck); + } } else { /* we keep up the required speed all right */ @@ -68,7 +68,7 @@ CURLcode Curl_speedcheck(struct SessionHandle *data, /* if there is a low speed limit enabled, we set the expire timer to make this connection's speed get checked again no later than when this time is up */ - Curl_expire(data, data->set.low_speed_time*1000); + Curl_expire_latest(data, data->set.low_speed_time*1000); } return CURLE_OK; } diff --git a/project/jni/curl/lib/speedcheck.h b/project/jni/curl/lib/speedcheck.h index fc40e7d0c..e1921d66b 100644 --- a/project/jni/curl/lib/speedcheck.h +++ b/project/jni/curl/lib/speedcheck.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,7 +22,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #include "timeval.h" diff --git a/project/jni/curl/lib/splay.c b/project/jni/curl/lib/splay.c index dcc42cf26..7aa2e4bac 100644 --- a/project/jni/curl/lib/splay.c +++ b/project/jni/curl/lib/splay.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1997 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1997 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,7 +20,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #include "splay.h" @@ -48,7 +48,7 @@ struct Curl_tree *Curl_splay(struct timeval i, N.smaller = N.larger = NULL; l = r = &N; - for (;;) { + for(;;) { comp = compare(i, t->key); if(comp < 0) { if(t->smaller == NULL) @@ -93,18 +93,21 @@ struct Curl_tree *Curl_splay(struct timeval i, } /* Insert key i into the tree t. Return a pointer to the resulting tree or - NULL if something went wrong. */ + * NULL if something went wrong. + * + * @unittest: 1309 + */ struct Curl_tree *Curl_splayinsert(struct timeval i, struct Curl_tree *t, struct Curl_tree *node) { - static struct timeval KEY_NOTUSED = {-1,-1}; /* key that will *NEVER* appear */ + static const struct timeval KEY_NOTUSED = {-1, -1}; /* will *NEVER* appear */ if(node == NULL) return t; if(t != NULL) { - t = Curl_splay(i,t); + t = Curl_splay(i, t); if(compare(i, t->key)==0) { /* There already exists a node in the tree with the very same key. Build a linked list of nodes. We make the new 'node' struct the new master @@ -146,56 +149,6 @@ struct Curl_tree *Curl_splayinsert(struct timeval i, return node; } -#if 0 -/* Deletes 'i' from the tree if it's there (with an exact match). Returns a - pointer to the resulting tree. - - Function not used in libcurl. -*/ -struct Curl_tree *Curl_splayremove(struct timeval i, - struct Curl_tree *t, - struct Curl_tree **removed) -{ - struct Curl_tree *x; - - *removed = NULL; /* default to no removed */ - - if(t==NULL) - return NULL; - - t = Curl_splay(i,t); - if(compare(i, t->key) == 0) { /* found it */ - - /* FIRST! Check if there is a list with identical sizes */ - if((x = t->same) != NULL) { - /* there is, pick one from the list */ - - /* 'x' is the new root node */ - - x->key = t->key; - x->larger = t->larger; - x->smaller = t->smaller; - - *removed = t; - return x; /* new root */ - } - - if(t->smaller == NULL) { - x = t->larger; - } - else { - x = Curl_splay(i, t->smaller); - x->larger = t->larger; - } - *removed = t; - - return x; - } - else - return t; /* It wasn't there */ -} -#endif - /* Finds and deletes the best-fit node from the tree. Return a pointer to the resulting tree. best-fit means the node with the given or lower key */ struct Curl_tree *Curl_splaygetbest(struct timeval i, @@ -209,7 +162,7 @@ struct Curl_tree *Curl_splaygetbest(struct timeval i, return NULL; } - t = Curl_splay(i,t); + t = Curl_splay(i, t); if(compare(i, t->key) < 0) { /* too big node, try the smaller chain */ if(t->smaller) @@ -256,19 +209,21 @@ struct Curl_tree *Curl_splaygetbest(struct timeval i, /* Deletes the very node we point out from the tree if it's there. Stores a - pointer to the new resulting tree in 'newroot'. - - Returns zero on success and non-zero on errors! TODO: document error codes. - When returning error, it does not touch the 'newroot' pointer. - - NOTE: when the last node of the tree is removed, there's no tree left so - 'newroot' will be made to point to NULL. -*/ + * pointer to the new resulting tree in 'newroot'. + * + * Returns zero on success and non-zero on errors! TODO: document error codes. + * When returning error, it does not touch the 'newroot' pointer. + * + * NOTE: when the last node of the tree is removed, there's no tree left so + * 'newroot' will be made to point to NULL. + * + * @unittest: 1309 + */ int Curl_splayremovebyaddr(struct Curl_tree *t, struct Curl_tree *removenode, struct Curl_tree **newroot) { - static struct timeval KEY_NOTUSED = {-1,-1}; /* key that will *NEVER* appear */ + static const struct timeval KEY_NOTUSED = {-1, -1}; /* will *NEVER* appear */ struct Curl_tree *x; if(!t || !removenode) @@ -331,108 +286,3 @@ int Curl_splayremovebyaddr(struct Curl_tree *t, return 0; } -#ifdef DEBUGBUILD - -void Curl_splayprint(struct Curl_tree * t, int d, char output) -{ - struct Curl_tree *node; - int i; - int count; - if(t == NULL) - return; - - Curl_splayprint(t->larger, d+1, output); - for (i=0; ikey.tv_usec, i); -#else - fprintf(stderr, "%ld.%ld[%d]", (long)t->key.tv_sec, (long)t->key.tv_usec, i); -#endif - } - - for(count=0, node = t->same; node; node = node->same, count++) - ; - - if(output) { - if(count) - fprintf(stderr, " [%d more]\n", count); - else - fprintf(stderr, "\n"); - } - - Curl_splayprint(t->smaller, d+1, output); -} -#endif - -#ifdef TEST_SPLAY - -/*#define TEST2 */ -#define MAX 50 -#define TEST2 - -/* A sample use of these functions. Start with the empty tree, insert some - stuff into it, and then delete it */ -int main(int argc, argv_item_t argv[]) -{ - struct Curl_tree *root, *t; - void *ptrs[MAX]; - int adds=0; - int rc; - - static const long sizes[]={ - 50, 60, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200, 300, - 220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200, - 300, 220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, - 200, 300, 220, 80, 90}; - int i; - root = NULL; /* the empty tree */ - - for (i = 0; i < MAX; i++) { - struct timeval key; - ptrs[i] = t = malloc(sizeof(struct Curl_tree)); - if(!t) { - puts("out of memory!"); - return 0; - } - - key.tv_sec = 0; -#ifdef TEST2 - key.tv_usec = sizes[i]; -#elif defined(TEST1) - key.tv_usec = (541*i)%1023; -#elif defined(TEST3) - key.tv_usec = 100; -#endif - - t->payload = (void *)key.tv_usec; /* for simplicity */ - root = Curl_splayinsert(key, root, t); - } - -#if 0 - puts("Result:"); - Curl_splayprint(root, 0, 1); -#endif - -#if 1 - for (i = 0; i < MAX; i++) { - int rem = (i+7)%MAX; - struct Curl_tree *r; - printf("Tree look:\n"); - Curl_splayprint(root, 0, 1); - printf("remove pointer %d, payload %ld\n", rem, - (long)((struct Curl_tree *)ptrs[rem])->payload); - rc = Curl_splayremovebyaddr(root, (struct Curl_tree *)ptrs[rem], &root); - if(rc) - /* failed! */ - printf("remove %d failed!\n", rem); - } -#endif - - return 0; -} - -#endif /* TEST_SPLAY */ diff --git a/project/jni/curl/lib/splay.h b/project/jni/curl/lib/splay.h index 832e4e2bb..1af9414de 100644 --- a/project/jni/curl/lib/splay.h +++ b/project/jni/curl/lib/splay.h @@ -1,5 +1,5 @@ -#ifndef __SPLAY_H -#define __SPLAY_H +#ifndef HEADER_CURL_SPLAY_H +#define HEADER_CURL_SPLAY_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1997 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1997 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,6 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "curl_setup.h" struct Curl_tree { struct Curl_tree *smaller; /* smaller node */ @@ -59,7 +60,7 @@ int Curl_splayremovebyaddr(struct Curl_tree *t, #ifdef DEBUGBUILD void Curl_splayprint(struct Curl_tree * t, int d, char output); #else -#define Curl_splayprint(x,y,z) +#define Curl_splayprint(x,y,z) Curl_nop_stmt #endif -#endif +#endif /* HEADER_CURL_SPLAY_H */ diff --git a/project/jni/curl/lib/ssh.c b/project/jni/curl/lib/ssh.c index ffcb48b42..e63446bed 100644 --- a/project/jni/curl/lib/ssh.c +++ b/project/jni/curl/lib/ssh.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,14 +22,10 @@ /* #define CURL_LIBSSH2_DEBUG */ -#include "setup.h" +#include "curl_setup.h" #ifdef USE_LIBSSH2 -#include -#include -#include -#include -#include + #ifdef HAVE_LIMITS_H # include #endif @@ -37,22 +33,10 @@ #include #include -#ifdef HAVE_UNISTD_H -#include -#endif - #ifdef HAVE_FCNTL_H #include #endif -#ifdef HAVE_TIME_H -#include -#endif - -#ifndef WIN32 -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif @@ -69,7 +53,6 @@ #include #include #endif -#endif /* !WIN32 */ #if (defined(NETWARE) && defined(__NOVELL_LIBC__)) #undef in_addr_t @@ -79,8 +62,6 @@ #include #include "urldata.h" #include "sendf.h" -#include "easyif.h" /* for Curl_convert_... prototypes */ - #include "hostip.h" #include "progress.h" #include "transfer.h" @@ -92,7 +73,7 @@ #include "getinfo.h" #include "strequal.h" -#include "sslgen.h" +#include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "inet_ntop.h" @@ -102,21 +83,32 @@ #include "multiif.h" #include "select.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" +#ifdef WIN32 +# undef PATH_MAX +# define PATH_MAX MAX_PATH +# ifndef R_OK +# define R_OK 4 +# endif +#endif + #ifndef PATH_MAX #define PATH_MAX 1024 /* just an extra precaution since there are systems that have their definition hidden well */ #endif +#define sftp_libssh2_last_error(s) curlx_ultosi(libssh2_sftp_last_error(s)) + +#define sftp_libssh2_realpath(s,p,t,m) \ + libssh2_sftp_symlink_ex((s), (p), curlx_uztoui(strlen(p)), \ + (t), (m), LIBSSH2_SFTP_REALPATH) + /* Local functions: */ -static const char *sftp_libssh2_strerror(unsigned long err); +static const char *sftp_libssh2_strerror(int err); static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc); static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc); static LIBSSH2_FREE_FUNC(my_libssh2_free); @@ -141,7 +133,7 @@ static CURLcode sftp_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode sftp_doing(struct connectdata *conn, bool *dophase_done); -static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection); +static CURLcode sftp_disconnect(struct connectdata *conn, bool dead); static CURLcode sftp_perform(struct connectdata *conn, bool *connected, @@ -157,13 +149,15 @@ static int ssh_perform_getsock(const struct connectdata *conn, number of sockets */ int numsocks); +static CURLcode ssh_setup_connection(struct connectdata *conn); + /* * SCP protocol handler. */ const struct Curl_handler Curl_handler_scp = { "SCP", /* scheme */ - ZERO_NULL, /* setup_connection */ + ssh_setup_connection, /* setup_connection */ ssh_do, /* do_it */ scp_done, /* done */ ZERO_NULL, /* do_more */ @@ -172,10 +166,14 @@ const struct Curl_handler Curl_handler_scp = { scp_doing, /* doing */ ssh_getsock, /* proto_getsock */ ssh_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ssh_perform_getsock, /* perform_getsock */ scp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_SSH, /* defport */ - PROT_SCP /* protocol */ + CURLPROTO_SCP, /* protocol */ + PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION + | PROTOPT_NOURLQUERY /* flags */ }; @@ -185,7 +183,7 @@ const struct Curl_handler Curl_handler_scp = { const struct Curl_handler Curl_handler_sftp = { "SFTP", /* scheme */ - ZERO_NULL, /* setup_connection */ + ssh_setup_connection, /* setup_connection */ ssh_do, /* do_it */ sftp_done, /* done */ ZERO_NULL, /* do_more */ @@ -194,13 +192,16 @@ const struct Curl_handler Curl_handler_sftp = { sftp_doing, /* doing */ ssh_getsock, /* proto_getsock */ ssh_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ssh_perform_getsock, /* perform_getsock */ sftp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_SSH, /* defport */ - PROT_SFTP /* protocol */ + CURLPROTO_SFTP, /* protocol */ + PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION + | PROTOPT_NOURLQUERY /* flags */ }; - static void kbd_callback(const char *name, int name_len, const char *instruction, int instruction_len, int num_prompts, @@ -224,7 +225,7 @@ kbd_callback(const char *name, int name_len, const char *instruction, #endif /* CURL_LIBSSH2_DEBUG */ if(num_prompts == 1) { responses[0].text = strdup(conn->passwd); - responses[0].length = (unsigned int)strlen(conn->passwd); + responses[0].length = curlx_uztoui(strlen(conn->passwd)); } (void)prompts; (void)abstract; @@ -317,7 +318,8 @@ static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc) static LIBSSH2_FREE_FUNC(my_libssh2_free) { (void)abstract; /* arg not used */ - free(ptr); + if(ptr) /* ssh2 agent sometimes call free with null ptr */ + free(ptr); } /* @@ -326,10 +328,12 @@ static LIBSSH2_FREE_FUNC(my_libssh2_free) /* This is the ONLY way to change SSH state! */ static void state(struct connectdata *conn, sshstate nowstate) { + struct ssh_conn *sshc = &conn->proto.sshc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ static const char * const names[] = { "SSH_STOP", + "SSH_INIT", "SSH_S_STARTUP", "SSH_HOSTKEY", "SSH_AUTHLIST", @@ -337,6 +341,9 @@ static void state(struct connectdata *conn, sshstate nowstate) "SSH_AUTH_PKEY", "SSH_AUTH_PASS_INIT", "SSH_AUTH_PASS", + "SSH_AUTH_AGENT_INIT", + "SSH_AUTH_AGENT_LIST", + "SSH_AUTH_AGENT", "SSH_AUTH_HOST_INIT", "SSH_AUTH_HOST", "SSH_AUTH_KEY_INIT", @@ -381,13 +388,10 @@ static void state(struct connectdata *conn, sshstate nowstate) "SSH_SESSION_FREE", "QUIT" }; -#endif - struct ssh_conn *sshc = &conn->proto.sshc; -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) if(sshc->state != nowstate) { infof(conn->data, "SFTP %p state change from %s to %s\n", - sshc, names[sshc->state], names[nowstate]); + (void *)sshc, names[sshc->state], names[nowstate]); } #endif @@ -411,19 +415,19 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; /* Check for /~/ , indicating relative to the user's home directory */ - if(conn->protocol & PROT_SCP) { + if(conn->handler->protocol & CURLPROTO_SCP) { real_path = malloc(working_path_len+1); if(real_path == NULL) { free(working_path); return CURLE_OUT_OF_MEMORY; } - if((working_path_len > 1) && (working_path[1] == '~')) - /* It is referenced to the home directory, so strip the leading '/' */ - memcpy(real_path, working_path+1, 1 + working_path_len-1); + if((working_path_len > 3) && (!memcmp(working_path, "/~/", 3))) + /* It is referenced to the home directory, so strip the leading '/~/' */ + memcpy(real_path, working_path+3, 4 + working_path_len-3); else memcpy(real_path, working_path, 1 + working_path_len); } - else if(conn->protocol & PROT_SFTP) { + else if(conn->handler->protocol & CURLPROTO_SFTP) { if((working_path_len > 1) && (working_path[1] == '~')) { size_t homelen = strlen(homedir); real_path = malloc(homelen + working_path_len + 1); @@ -504,6 +508,187 @@ static int sshkeycallback(CURL *easy, #define libssh2_session_startup(x,y) libssh2_session_handshake(x,y) #endif +static CURLcode ssh_knownhost(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + +#ifdef HAVE_LIBSSH2_KNOWNHOST_API + struct SessionHandle *data = conn->data; + + if(data->set.str[STRING_SSH_KNOWNHOSTS]) { + /* we're asked to verify the host against a file */ + struct ssh_conn *sshc = &conn->proto.sshc; + int rc; + int keytype; + size_t keylen; + const char *remotekey = libssh2_session_hostkey(sshc->ssh_session, + &keylen, &keytype); + int keycheck = LIBSSH2_KNOWNHOST_CHECK_FAILURE; + int keybit = 0; + + if(remotekey) { + /* + * A subject to figure out is what host name we need to pass in here. + * What host name does OpenSSH store in its file if an IDN name is + * used? + */ + struct libssh2_knownhost *host; + enum curl_khmatch keymatch; + curl_sshkeycallback func = + data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback; + struct curl_khkey knownkey; + struct curl_khkey *knownkeyp = NULL; + struct curl_khkey foundkey; + + keybit = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)? + LIBSSH2_KNOWNHOST_KEY_SSHRSA:LIBSSH2_KNOWNHOST_KEY_SSHDSS; + +#ifdef HAVE_LIBSSH2_KNOWNHOST_CHECKP + keycheck = libssh2_knownhost_checkp(sshc->kh, + conn->host.name, + (conn->remote_port != PORT_SSH)? + conn->remote_port:-1, + remotekey, keylen, + LIBSSH2_KNOWNHOST_TYPE_PLAIN| + LIBSSH2_KNOWNHOST_KEYENC_RAW| + keybit, + &host); +#else + keycheck = libssh2_knownhost_check(sshc->kh, + conn->host.name, + remotekey, keylen, + LIBSSH2_KNOWNHOST_TYPE_PLAIN| + LIBSSH2_KNOWNHOST_KEYENC_RAW| + keybit, + &host); +#endif + + infof(data, "SSH host check: %d, key: %s\n", keycheck, + (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)? + host->key:""); + + /* setup 'knownkey' */ + if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) { + knownkey.key = host->key; + knownkey.len = 0; + knownkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)? + CURLKHTYPE_RSA : CURLKHTYPE_DSS; + knownkeyp = &knownkey; + } + + /* setup 'foundkey' */ + foundkey.key = remotekey; + foundkey.len = keylen; + foundkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)? + CURLKHTYPE_RSA : CURLKHTYPE_DSS; + + /* + * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the + * curl_khmatch enum are ever modified, we need to introduce a + * translation table here! + */ + keymatch = (enum curl_khmatch)keycheck; + + /* Ask the callback how to behave */ + rc = func(data, knownkeyp, /* from the knownhosts file */ + &foundkey, /* from the remote host */ + keymatch, data->set.ssh_keyfunc_userp); + } + else + /* no remotekey means failure! */ + rc = CURLKHSTAT_REJECT; + + switch(rc) { + default: /* unknown return codes will equal reject */ + /* FALLTHROUGH */ + case CURLKHSTAT_REJECT: + state(conn, SSH_SESSION_FREE); + /* FALLTHROUGH */ + case CURLKHSTAT_DEFER: + /* DEFER means bail out but keep the SSH_HOSTKEY state */ + result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; + break; + case CURLKHSTAT_FINE: + case CURLKHSTAT_FINE_ADD_TO_FILE: + /* proceed */ + if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) { + /* the found host+key didn't match but has been told to be fine + anyway so we add it in memory */ + int addrc = libssh2_knownhost_add(sshc->kh, + conn->host.name, NULL, + remotekey, keylen, + LIBSSH2_KNOWNHOST_TYPE_PLAIN| + LIBSSH2_KNOWNHOST_KEYENC_RAW| + keybit, NULL); + if(addrc) + infof(data, "Warning adding the known host %s failed!\n", + conn->host.name); + else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE) { + /* now we write the entire in-memory list of known hosts to the + known_hosts file */ + int wrc = + libssh2_knownhost_writefile(sshc->kh, + data->set.str[STRING_SSH_KNOWNHOSTS], + LIBSSH2_KNOWNHOST_FILE_OPENSSH); + if(wrc) { + infof(data, "Warning, writing %s failed!\n", + data->set.str[STRING_SSH_KNOWNHOSTS]); + } + } + } + break; + } + } +#else /* HAVE_LIBSSH2_KNOWNHOST_API */ + (void)conn; +#endif + return result; +} + +static CURLcode ssh_check_fingerprint(struct connectdata *conn) +{ + struct ssh_conn *sshc = &conn->proto.sshc; + struct SessionHandle *data = conn->data; + const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]; + char md5buffer[33]; + int i; + + const char *fingerprint = libssh2_hostkey_hash(sshc->ssh_session, + LIBSSH2_HOSTKEY_HASH_MD5); + + if(fingerprint) { + /* The fingerprint points to static storage (!), don't free() it. */ + for(i = 0; i < 16; i++) + snprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]); + infof(data, "SSH MD5 fingerprint: %s\n", md5buffer); + } + + /* Before we authenticate we check the hostkey's MD5 fingerprint + * against a known fingerprint, if available. + */ + if(pubkey_md5 && strlen(pubkey_md5) == 32) { + if(!fingerprint || !strequal(md5buffer, pubkey_md5)) { + if(fingerprint) + failf(data, + "Denied establishing ssh session: mismatch md5 fingerprint. " + "Remote %s is not equal to %s", md5buffer, pubkey_md5); + else + failf(data, + "Denied establishing ssh session: md5 fingerprint not available"); + state(conn, SSH_SESSION_FREE); + sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; + return sshc->actualcode; + } + else { + infof(data, "MD5 checksum match!\n"); + /* as we already matched, we skip the check for known hosts */ + return CURLE_OK; + } + } + else + return ssh_knownhost(conn); +} + /* * ssh_statemach_act() runs the SSH state machine as far as it can without * blocking and without reaching the end. The data the pointer 'block' points @@ -515,14 +700,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct SSHPROTO *sftp_scp = data->state.proto.ssh; + struct SSHPROTO *sftp_scp = data->req.protop; struct ssh_conn *sshc = &conn->proto.sshc; curl_socket_t sock = conn->sock[FIRSTSOCKET]; -#ifdef CURL_LIBSSH2_DEBUG - const char *fingerprint; -#endif /* CURL_LIBSSH2_DEBUG */ - const char *host_public_key_md5; - int rc = LIBSSH2_ERROR_NONE, i; + char *new_readdir_line; + int rc = LIBSSH2_ERROR_NONE; int err; int seekerr = CURL_SEEKFUNC_OK; *block = 0; /* we're not blocking by default */ @@ -530,12 +712,20 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) do { switch(sshc->state) { - case SSH_S_STARTUP: + case SSH_INIT: sshc->secondCreateDirs = 0; sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_OK; - rc = libssh2_session_startup(sshc->ssh_session, sock); + /* Set libssh2 to non-blocking, since everything internally is + non-blocking */ + libssh2_session_set_blocking(sshc->ssh_session, 0); + + state(conn, SSH_S_STARTUP); + /* fall-through */ + + case SSH_S_STARTUP: + rc = libssh2_session_startup(sshc->ssh_session, (int)sock); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } @@ -546,168 +736,19 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } - /* Set libssh2 to non-blocking, since everything internally is - non-blocking */ - libssh2_session_set_blocking(sshc->ssh_session, 0); - state(conn, SSH_HOSTKEY); /* fall-through */ case SSH_HOSTKEY: - -#ifdef CURL_LIBSSH2_DEBUG /* * Before we authenticate we should check the hostkey's fingerprint * against our known hosts. How that is handled (reading from file, - * whatever) is up to us. As for know not much is implemented, besides - * showing how to get the fingerprint. + * whatever) is up to us. */ - fingerprint = libssh2_hostkey_hash(sshc->ssh_session, - LIBSSH2_HOSTKEY_HASH_MD5); - - /* The fingerprint points to static storage (!), don't free() it. */ - infof(data, "Fingerprint: "); - for (rc = 0; rc < 16; rc++) { - infof(data, "%02X ", (unsigned char) fingerprint[rc]); - } - infof(data, "\n"); -#endif /* CURL_LIBSSH2_DEBUG */ - - /* Before we authenticate we check the hostkey's MD5 fingerprint - * against a known fingerprint, if available. This implementation pulls - * it from the curl option. - */ - if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] && - strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) == 32) { - char buf[33]; - host_public_key_md5 = libssh2_hostkey_hash(sshc->ssh_session, - LIBSSH2_HOSTKEY_HASH_MD5); - for (i = 0; i < 16; i++) - snprintf(&buf[i*2], 3, "%02x", - (unsigned char) host_public_key_md5[i]); - if(!strequal(buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5])) { - failf(data, - "Denied establishing ssh session: mismatch md5 fingerprint. " - "Remote %s is not equal to %s", - buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]); - state(conn, SSH_SESSION_FREE); - sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; - break; - } - } - -#ifdef HAVE_LIBSSH2_KNOWNHOST_API - if(data->set.str[STRING_SSH_KNOWNHOSTS]) { - /* we're asked to verify the host against a file */ - int keytype; - size_t keylen; - const char *remotekey = libssh2_session_hostkey(sshc->ssh_session, - &keylen, &keytype); - int keycheck; - int keybit; - - if(remotekey) { - /* - * A subject to figure out is what host name we need to pass in here. - * What host name does OpenSSH store in its file if an IDN name is - * used? - */ - struct libssh2_knownhost *host; - enum curl_khmatch keymatch; - curl_sshkeycallback func = - data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback; - struct curl_khkey knownkey; - struct curl_khkey *knownkeyp = NULL; - struct curl_khkey foundkey; - - keybit = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)? - LIBSSH2_KNOWNHOST_KEY_SSHRSA:LIBSSH2_KNOWNHOST_KEY_SSHDSS; - - keycheck = libssh2_knownhost_check(sshc->kh, - conn->host.name, - remotekey, keylen, - LIBSSH2_KNOWNHOST_TYPE_PLAIN| - LIBSSH2_KNOWNHOST_KEYENC_RAW| - keybit, - &host); - - infof(data, "SSH host check: %d, key: %s\n", keycheck, - (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)? - host->key:""); - - /* setup 'knownkey' */ - if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) { - knownkey.key = host->key; - knownkey.len = 0; - knownkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)? - CURLKHTYPE_RSA : CURLKHTYPE_DSS; - knownkeyp = &knownkey; - } - - /* setup 'foundkey' */ - foundkey.key = remotekey; - foundkey.len = keylen; - foundkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)? - CURLKHTYPE_RSA : CURLKHTYPE_DSS; - - /* - * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the - * curl_khmatch enum are ever modified, we need to introduce a - * translation table here! - */ - keymatch = (enum curl_khmatch)keycheck; - - /* Ask the callback how to behave */ - rc = func(data, knownkeyp, /* from the knownhosts file */ - &foundkey, /* from the remote host */ - keymatch, data->set.ssh_keyfunc_userp); - } - else - /* no remotekey means failure! */ - rc = CURLKHSTAT_REJECT; - - switch(rc) { - default: /* unknown return codes will equal reject */ - case CURLKHSTAT_REJECT: - state(conn, SSH_SESSION_FREE); - case CURLKHSTAT_DEFER: - /* DEFER means bail out but keep the SSH_HOSTKEY state */ - result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; - break; - case CURLKHSTAT_FINE: - case CURLKHSTAT_FINE_ADD_TO_FILE: - /* proceed */ - if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) { - /* the found host+key didn't match but has been told to be fine - anyway so we add it in memory */ - int addrc = libssh2_knownhost_add(sshc->kh, - conn->host.name, NULL, - remotekey, keylen, - LIBSSH2_KNOWNHOST_TYPE_PLAIN| - LIBSSH2_KNOWNHOST_KEYENC_RAW| - keybit, NULL); - if(addrc) - infof(data, "Warning adding the known host %s failed!\n", - conn->host.name); - else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE) { - /* now we write the entire in-memory list of known hosts to the - known_hosts file */ - int wrc = - libssh2_knownhost_writefile(sshc->kh, - data->set.str[STRING_SSH_KNOWNHOSTS], - LIBSSH2_KNOWNHOST_FILE_OPENSSH); - if(wrc) { - infof(data, "Warning, writing %s failed!\n", - data->set.str[STRING_SSH_KNOWNHOSTS]); - } - } - } - break; - } - } -#endif /* HAVE_LIBSSH2_KNOWNHOST_API */ - - state(conn, SSH_AUTHLIST); + result = ssh_check_fingerprint(conn); + if(!result) + state(conn, SSH_AUTHLIST); + /* ssh_check_fingerprint sets state appropriately on error */ break; case SSH_AUTHLIST: @@ -723,10 +764,16 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) */ sshc->authlist = libssh2_userauth_list(sshc->ssh_session, conn->user, - (unsigned int)strlen(conn->user)); + curlx_uztoui(strlen(conn->user))); if(!sshc->authlist) { - if((err = libssh2_session_last_errno(sshc->ssh_session)) == + if(libssh2_userauth_authenticated(sshc->ssh_session)) { + sshc->authed = TRUE; + infof(data, "SSH user accepted with no authentication\n"); + state(conn, SSH_AUTH_DONE); + break; + } + else if((err = libssh2_session_last_errno(sshc->ssh_session)) == LIBSSH2_ERROR_EAGAIN) { rc = LIBSSH2_ERROR_EAGAIN; break; @@ -752,7 +799,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) && (strstr(sshc->authlist, "publickey") != NULL)) { - char *home; + char *home = NULL; + bool out_of_memory = FALSE; sshc->rsa_pub = sshc->rsa = NULL; @@ -760,35 +808,58 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) HOME environment variable etc? */ home = curl_getenv("HOME"); - if(data->set.str[STRING_SSH_PUBLIC_KEY]) - sshc->rsa_pub = aprintf("%s", data->set.str[STRING_SSH_PUBLIC_KEY]); - else if(home) - sshc->rsa_pub = aprintf("%s/.ssh/id_dsa.pub", home); - else - /* as a final resort, try current dir! */ - sshc->rsa_pub = strdup("id_dsa.pub"); - - if(sshc->rsa_pub == NULL) { - Curl_safefree(home); - home = NULL; - state(conn, SSH_SESSION_FREE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; + if(data->set.str[STRING_SSH_PRIVATE_KEY]) + sshc->rsa = strdup(data->set.str[STRING_SSH_PRIVATE_KEY]); + else { + /* If no private key file is specified, try some common paths. */ + if(home) { + /* Try ~/.ssh first. */ + sshc->rsa = aprintf("%s/.ssh/id_rsa", home); + if(!sshc->rsa) + out_of_memory = TRUE; + else if(access(sshc->rsa, R_OK) != 0) { + Curl_safefree(sshc->rsa); + sshc->rsa = aprintf("%s/.ssh/id_dsa", home); + if(!sshc->rsa) + out_of_memory = TRUE; + else if(access(sshc->rsa, R_OK) != 0) { + Curl_safefree(sshc->rsa); + } + } + } + if(!out_of_memory && !sshc->rsa) { + /* Nothing found; try the current dir. */ + sshc->rsa = strdup("id_rsa"); + if(sshc->rsa && access(sshc->rsa, R_OK) != 0) { + Curl_safefree(sshc->rsa); + sshc->rsa = strdup("id_dsa"); + if(sshc->rsa && access(sshc->rsa, R_OK) != 0) { + Curl_safefree(sshc->rsa); + /* Out of guesses. Set to the empty string to avoid + * surprising info messages. */ + sshc->rsa = strdup(""); + } + } + } } - if(data->set.str[STRING_SSH_PRIVATE_KEY]) - sshc->rsa = aprintf("%s", data->set.str[STRING_SSH_PRIVATE_KEY]); - else if(home) - sshc->rsa = aprintf("%s/.ssh/id_dsa", home); - else - /* as a final resort, try current dir! */ - sshc->rsa = strdup("id_dsa"); + /* + * Unless the user explicitly specifies a public key file, let + * libssh2 extract the public key from the private key file. + * This is done by simply passing sshc->rsa_pub = NULL. + */ + if(data->set.str[STRING_SSH_PUBLIC_KEY] + /* treat empty string the same way as NULL */ + && data->set.str[STRING_SSH_PUBLIC_KEY][0]) { + sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]); + if(!sshc->rsa_pub) + out_of_memory = TRUE; + } - if(sshc->rsa == NULL) { - Curl_safefree(home); - home = NULL; + if(out_of_memory || sshc->rsa == NULL) { + free(home); + Curl_safefree(sshc->rsa); Curl_safefree(sshc->rsa_pub); - sshc->rsa_pub = NULL; state(conn, SSH_SESSION_FREE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; @@ -798,11 +869,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(!sshc->passphrase) sshc->passphrase = ""; - Curl_safefree(home); - home = NULL; + free(home); - infof(data, "Using ssh public key file %s\n", sshc->rsa_pub); - infof(data, "Using ssh private key file %s\n", sshc->rsa); + if(sshc->rsa_pub) + infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub); + infof(data, "Using SSH private key file '%s'\n", sshc->rsa); state(conn, SSH_AUTH_PKEY); } @@ -816,8 +887,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) */ rc = libssh2_userauth_publickey_fromfile_ex(sshc->ssh_session, conn->user, - (unsigned int) - strlen(conn->user), + curlx_uztoui( + strlen(conn->user)), sshc->rsa_pub, sshc->rsa, sshc->passphrase); if(rc == LIBSSH2_ERROR_EAGAIN) { @@ -825,9 +896,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } Curl_safefree(sshc->rsa_pub); - sshc->rsa_pub = NULL; Curl_safefree(sshc->rsa); - sshc->rsa = NULL; if(rc == 0) { sshc->authed = TRUE; @@ -855,9 +924,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) case SSH_AUTH_PASS: rc = libssh2_userauth_password_ex(sshc->ssh_session, conn->user, - (unsigned int)strlen(conn->user), + curlx_uztoui(strlen(conn->user)), conn->passwd, - (unsigned int)strlen(conn->passwd), + curlx_uztoui(strlen(conn->passwd)), NULL); if(rc == LIBSSH2_ERROR_EAGAIN) { break; @@ -869,6 +938,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } else { state(conn, SSH_AUTH_HOST_INIT); + rc = 0; /* clear rc and continue */ } break; @@ -878,12 +948,104 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_AUTH_HOST); } else { - state(conn, SSH_AUTH_KEY_INIT); + state(conn, SSH_AUTH_AGENT_INIT); } break; case SSH_AUTH_HOST: - state(conn, SSH_AUTH_KEY_INIT); + state(conn, SSH_AUTH_AGENT_INIT); + break; + + case SSH_AUTH_AGENT_INIT: +#ifdef HAVE_LIBSSH2_AGENT_API + if((data->set.ssh_auth_types & CURLSSH_AUTH_AGENT) + && (strstr(sshc->authlist, "publickey") != NULL)) { + + /* Connect to the ssh-agent */ + /* The agent could be shared by a curl thread i believe + but nothing obvious as keys can be added/removed at any time */ + if(!sshc->ssh_agent) { + sshc->ssh_agent = libssh2_agent_init(sshc->ssh_session); + if(!sshc->ssh_agent) { + infof(data, "Could not create agent object\n"); + + state(conn, SSH_AUTH_KEY_INIT); + break; + } + } + + rc = libssh2_agent_connect(sshc->ssh_agent); + if(rc == LIBSSH2_ERROR_EAGAIN) + break; + if(rc < 0) { + infof(data, "Failure connecting to agent\n"); + state(conn, SSH_AUTH_KEY_INIT); + } + else { + state(conn, SSH_AUTH_AGENT_LIST); + } + } + else +#endif /* HAVE_LIBSSH2_AGENT_API */ + state(conn, SSH_AUTH_KEY_INIT); + break; + + case SSH_AUTH_AGENT_LIST: +#ifdef HAVE_LIBSSH2_AGENT_API + rc = libssh2_agent_list_identities(sshc->ssh_agent); + + if(rc == LIBSSH2_ERROR_EAGAIN) + break; + if(rc < 0) { + infof(data, "Failure requesting identities to agent\n"); + state(conn, SSH_AUTH_KEY_INIT); + } + else { + state(conn, SSH_AUTH_AGENT); + sshc->sshagent_prev_identity = NULL; + } +#endif + break; + + case SSH_AUTH_AGENT: +#ifdef HAVE_LIBSSH2_AGENT_API + /* as prev_identity evolves only after an identity user auth finished we + can safely request it again as long as EAGAIN is returned here or by + libssh2_agent_userauth */ + rc = libssh2_agent_get_identity(sshc->ssh_agent, + &sshc->sshagent_identity, + sshc->sshagent_prev_identity); + if(rc == LIBSSH2_ERROR_EAGAIN) + break; + + if(rc == 0) { + rc = libssh2_agent_userauth(sshc->ssh_agent, conn->user, + sshc->sshagent_identity); + + if(rc < 0) { + if(rc != LIBSSH2_ERROR_EAGAIN) + /* tried and failed? go to next identity */ + sshc->sshagent_prev_identity = sshc->sshagent_identity; + else + break; + } + } + + if(rc < 0) + infof(data, "Failure requesting identities to agent\n"); + else if(rc == 1) + infof(data, "No identity would match\n"); + + if(rc == LIBSSH2_ERROR_NONE) { + sshc->authed = TRUE; + infof(data, "Agent based authentication successful\n"); + state(conn, SSH_AUTH_DONE); + } + else { + state(conn, SSH_AUTH_KEY_INIT); + rc = 0; /* clear rc and continue */ + } +#endif break; case SSH_AUTH_KEY_INIT: @@ -900,8 +1062,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* Authentication failed. Continue with keyboard-interactive now. */ rc = libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session, conn->user, - (unsigned int) - strlen(conn->user), + curlx_uztoui( + strlen(conn->user)), &kbd_callback); if(rc == LIBSSH2_ERROR_EAGAIN) { break; @@ -931,7 +1093,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) conn->sockfd = sock; conn->writesockfd = CURL_SOCKET_BAD; - if(conn->protocol == PROT_SFTP) { + if(conn->handler->protocol == CURLPROTO_SFTP) { state(conn, SSH_SFTP_INIT); break; } @@ -971,7 +1133,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* * Get the "home" directory */ - rc = libssh2_sftp_realpath(sshc->sftp_session, ".", + rc = sftp_libssh2_realpath(sshc->sftp_session, ".", tempHome, PATH_MAX-1); if(rc == LIBSSH2_ERROR_EAGAIN) { break; @@ -985,10 +1147,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } + conn->data->state.most_recent_ftp_entrypath = sshc->homedir; } else { /* Return the error type */ - err = (int)(libssh2_sftp_last_error(sshc->sftp_session)); + err = sftp_libssh2_last_error(sshc->sftp_session); result = sftp_libssh2_error_to_CURLE(err); sshc->actualcode = result?result:CURLE_SSH; DEBUGF(infof(data, "error = %d makes libcurl = %d\n", @@ -1043,28 +1206,57 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* * Support some of the "FTP" commands */ - if(curl_strequal("pwd", sshc->quote_item->data)) { - /* output debug output if that is requested */ - if(data->set.verbose) { - char tmp[PATH_MAX+1]; + char *cmd = sshc->quote_item->data; + sshc->acceptfail = FALSE; + /* if a command starts with an asterisk, which a legal SFTP command never + can, the command will be allowed to fail without it causing any + aborts or cancels etc. It will cause libcurl to act as if the command + is successful, whatever the server reponds. */ + + if(cmd[0] == '*') { + cmd++; + sshc->acceptfail = TRUE; + } + + if(curl_strequal("pwd", cmd)) { + /* output debug output if that is requested */ + char *tmp = aprintf("257 \"%s\" is current directory.\n", + sftp_scp->path); + if(!tmp) { + result = CURLE_OUT_OF_MEMORY; + state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + break; + } + if(data->set.verbose) { Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4, conn); - snprintf(tmp, PATH_MAX, "257 \"%s\" is current directory.\n", - sftp_scp->path); Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp), conn); } - state(conn, SSH_SFTP_NEXT_QUOTE); + /* this sends an FTP-like "header" to the header callback so that the + current directory can be read very similar to how it is read when + using ordinary FTP. */ + result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp)); + free(tmp); + if(result) { + state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + } + else + state(conn, SSH_SFTP_NEXT_QUOTE); break; } - else if(sshc->quote_item->data) { + else if(cmd) { /* * the arguments following the command must be separated from the * command with a space so we can check for it unconditionally */ - cp = strchr(sshc->quote_item->data, ' '); + cp = strchr(cmd, ' '); if(cp == NULL) { failf(data, "Syntax error in SFTP command. Supply parameter(s)!"); state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } @@ -1080,19 +1272,20 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) else failf(data, "Syntax error: Bad first parameter"); state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; break; } /* - * SFTP is a binary protocol, so we don't send text commands to - * the server. Instead, we scan for commands for commands used by + * SFTP is a binary protocol, so we don't send text commands + * to the server. Instead, we scan for commands used by * OpenSSH's sftp program and call the appropriate libssh2 * functions. */ - if(curl_strnequal(sshc->quote_item->data, "chgrp ", 6) || - curl_strnequal(sshc->quote_item->data, "chmod ", 6) || - curl_strnequal(sshc->quote_item->data, "chown ", 6) ) { + if(curl_strnequal(cmd, "chgrp ", 6) || + curl_strnequal(cmd, "chmod ", 6) || + curl_strnequal(cmd, "chown ", 6) ) { /* attribute change */ /* sshc->quote_path1 contains the mode to set */ @@ -1105,8 +1298,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) failf(data, "Syntax error in chgrp/chmod/chown: " "Bad second parameter"); Curl_safefree(sshc->quote_path1); - sshc->quote_path1 = NULL; state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; break; } @@ -1114,8 +1307,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_QUOTE_STAT); break; } - else if(curl_strnequal(sshc->quote_item->data, "ln ", 3) || - curl_strnequal(sshc->quote_item->data, "symlink ", 8)) { + else if(curl_strnequal(cmd, "ln ", 3) || + curl_strnequal(cmd, "symlink ", 8)) { /* symbolic linking */ /* sshc->quote_path1 is the source */ /* get the destination */ @@ -1127,20 +1320,20 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) failf(data, "Syntax error in ln/symlink: Bad second parameter"); Curl_safefree(sshc->quote_path1); - sshc->quote_path1 = NULL; state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; break; } state(conn, SSH_SFTP_QUOTE_SYMLINK); break; } - else if(curl_strnequal(sshc->quote_item->data, "mkdir ", 6)) { + else if(curl_strnequal(cmd, "mkdir ", 6)) { /* create dir */ state(conn, SSH_SFTP_QUOTE_MKDIR); break; } - else if(curl_strnequal(sshc->quote_item->data, "rename ", 7)) { + else if(curl_strnequal(cmd, "rename ", 7)) { /* rename file */ /* first param is the source path */ /* second param is the dest. path */ @@ -1151,30 +1344,29 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) else failf(data, "Syntax error in rename: Bad second parameter"); Curl_safefree(sshc->quote_path1); - sshc->quote_path1 = NULL; state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; break; } state(conn, SSH_SFTP_QUOTE_RENAME); break; } - else if(curl_strnequal(sshc->quote_item->data, "rmdir ", 6)) { + else if(curl_strnequal(cmd, "rmdir ", 6)) { /* delete dir */ state(conn, SSH_SFTP_QUOTE_RMDIR); break; } - else if(curl_strnequal(sshc->quote_item->data, "rm ", 3)) { + else if(curl_strnequal(cmd, "rm ", 3)) { state(conn, SSH_SFTP_QUOTE_UNLINK); break; } failf(data, "Unknown SFTP command"); Curl_safefree(sshc->quote_path1); - sshc->quote_path1 = NULL; Curl_safefree(sshc->quote_path2); - sshc->quote_path2 = NULL; state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } @@ -1185,14 +1377,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; case SSH_SFTP_NEXT_QUOTE: - if(sshc->quote_path1) { - Curl_safefree(sshc->quote_path1); - sshc->quote_path1 = NULL; - } - if(sshc->quote_path2) { - Curl_safefree(sshc->quote_path2); - sshc->quote_path2 = NULL; - } + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); sshc->quote_item = sshc->quote_item->next; @@ -1211,73 +1397,85 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; case SSH_SFTP_QUOTE_STAT: - if(!curl_strnequal(sshc->quote_item->data, "chmod", 5)) { + { + char *cmd = sshc->quote_item->data; + sshc->acceptfail = FALSE; + + /* if a command starts with an asterisk, which a legal SFTP command never + can, the command will be allowed to fail without it causing any + aborts or cancels etc. It will cause libcurl to act as if the command + is successful, whatever the server reponds. */ + + if(cmd[0] == '*') { + cmd++; + sshc->acceptfail = TRUE; + } + + if(!curl_strnequal(cmd, "chmod", 5)) { /* Since chown and chgrp only set owner OR group but libssh2 wants to * set them both at once, we need to obtain the current ownership * first. This takes an extra protocol round trip. */ rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2, - (unsigned int)strlen(sshc->quote_path2), + curlx_uztoui(strlen(sshc->quote_path2)), LIBSSH2_SFTP_STAT, &sshc->quote_attrs); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc != 0) { /* get those attributes */ - err = (int)(libssh2_sftp_last_error(sshc->sftp_session)); + else if(rc != 0 && !sshc->acceptfail) { /* get those attributes */ + err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); - sshc->quote_path1 = NULL; Curl_safefree(sshc->quote_path2); - sshc->quote_path2 = NULL; failf(data, "Attempt to get SFTP stats failed: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } } /* Now set the new attributes... */ - if(curl_strnequal(sshc->quote_item->data, "chgrp", 5)) { + if(curl_strnequal(cmd, "chgrp", 5)) { sshc->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10); sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; - if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0])) { + if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && + !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); - sshc->quote_path1 = NULL; Curl_safefree(sshc->quote_path2); - sshc->quote_path2 = NULL; failf(data, "Syntax error: chgrp gid not a number"); state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } } - else if(curl_strnequal(sshc->quote_item->data, "chmod", 5)) { + else if(curl_strnequal(cmd, "chmod", 5)) { sshc->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8); sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS; /* permissions are octal */ if(sshc->quote_attrs.permissions == 0 && !ISDIGIT(sshc->quote_path1[0])) { Curl_safefree(sshc->quote_path1); - sshc->quote_path1 = NULL; Curl_safefree(sshc->quote_path2); - sshc->quote_path2 = NULL; failf(data, "Syntax error: chmod permissions not a number"); state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } } - else if(curl_strnequal(sshc->quote_item->data, "chown", 5)) { + else if(curl_strnequal(cmd, "chown", 5)) { sshc->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10); sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; - if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0])) { + if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && + !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); - sshc->quote_path1 = NULL; Curl_safefree(sshc->quote_path2); - sshc->quote_path2 = NULL; failf(data, "Syntax error: chown uid not a number"); state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } @@ -1286,24 +1484,24 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* Now send the completed structure... */ state(conn, SSH_SFTP_QUOTE_SETSTAT); break; + } case SSH_SFTP_QUOTE_SETSTAT: rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2, - (unsigned int)strlen(sshc->quote_path2), + curlx_uztoui(strlen(sshc->quote_path2)), LIBSSH2_SFTP_SETSTAT, &sshc->quote_attrs); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc != 0) { - err = (int)(libssh2_sftp_last_error(sshc->sftp_session)); + else if(rc != 0 && !sshc->acceptfail) { + err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); - sshc->quote_path1 = NULL; Curl_safefree(sshc->quote_path2); - sshc->quote_path2 = NULL; failf(data, "Attempt to set SFTP stats failed: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } @@ -1312,22 +1510,21 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) case SSH_SFTP_QUOTE_SYMLINK: rc = libssh2_sftp_symlink_ex(sshc->sftp_session, sshc->quote_path1, - (unsigned int)strlen(sshc->quote_path1), + curlx_uztoui(strlen(sshc->quote_path1)), sshc->quote_path2, - (unsigned int)strlen(sshc->quote_path2), + curlx_uztoui(strlen(sshc->quote_path2)), LIBSSH2_SFTP_SYMLINK); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc != 0) { - err = (int)(libssh2_sftp_last_error(sshc->sftp_session)); + else if(rc != 0 && !sshc->acceptfail) { + err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); - sshc->quote_path1 = NULL; Curl_safefree(sshc->quote_path2); - sshc->quote_path2 = NULL; failf(data, "symlink command failed: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } @@ -1336,17 +1533,17 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) case SSH_SFTP_QUOTE_MKDIR: rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshc->quote_path1, - (unsigned int)strlen(sshc->quote_path1), - 0755); + curlx_uztoui(strlen(sshc->quote_path1)), + data->set.new_directory_perms); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc != 0) { - err = (int)(libssh2_sftp_last_error(sshc->sftp_session)); + else if(rc != 0 && !sshc->acceptfail) { + err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); - sshc->quote_path1 = NULL; failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } @@ -1355,23 +1552,23 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) case SSH_SFTP_QUOTE_RENAME: rc = libssh2_sftp_rename_ex(sshc->sftp_session, sshc->quote_path1, - (unsigned int)strlen(sshc->quote_path1), + curlx_uztoui(strlen(sshc->quote_path1)), sshc->quote_path2, - (unsigned int)strlen(sshc->quote_path2), + curlx_uztoui(strlen(sshc->quote_path2)), LIBSSH2_SFTP_RENAME_OVERWRITE | LIBSSH2_SFTP_RENAME_ATOMIC | LIBSSH2_SFTP_RENAME_NATIVE); + if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc != 0) { - err = (int)(libssh2_sftp_last_error(sshc->sftp_session)); + else if(rc != 0 && !sshc->acceptfail) { + err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); - sshc->quote_path1 = NULL; Curl_safefree(sshc->quote_path2); - sshc->quote_path2 = NULL; failf(data, "rename command failed: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } @@ -1380,16 +1577,16 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) case SSH_SFTP_QUOTE_RMDIR: rc = libssh2_sftp_rmdir_ex(sshc->sftp_session, sshc->quote_path1, - (unsigned int)strlen(sshc->quote_path1)); + curlx_uztoui(strlen(sshc->quote_path1))); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc != 0) { - err = (int)(libssh2_sftp_last_error(sshc->sftp_session)); + else if(rc != 0 && !sshc->acceptfail) { + err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); - sshc->quote_path1 = NULL; failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } @@ -1398,16 +1595,16 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) case SSH_SFTP_QUOTE_UNLINK: rc = libssh2_sftp_unlink_ex(sshc->sftp_session, sshc->quote_path1, - (unsigned int)strlen(sshc->quote_path1)); + curlx_uztoui(strlen(sshc->quote_path1))); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc != 0) { - err = (int)(libssh2_sftp_last_error(sshc->sftp_session)); + else if(rc != 0 && !sshc->acceptfail) { + err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); - sshc->quote_path1 = NULL; failf(data, "rm command failed: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } @@ -1418,9 +1615,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(data->set.upload) state(conn, SSH_SFTP_UPLOAD_INIT); else { - if(data->set.opt_no_body) - state(conn, SSH_STOP); - else if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') + if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') state(conn, SSH_SFTP_READDIR_INIT); else state(conn, SSH_SFTP_DOWNLOAD_INIT); @@ -1441,7 +1636,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) LIBSSH2_SFTP_ATTRIBUTES attrs; if(data->state.resume_from < 0) { rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path, - (unsigned int)strlen(sftp_scp->path), + curlx_uztoui(strlen(sftp_scp->path)), LIBSSH2_SFTP_STAT, &attrs); if(rc == LIBSSH2_ERROR_EAGAIN) { break; @@ -1452,7 +1647,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) else { curl_off_t size = attrs.filesize; if(size < 0) { - failf(data, "Bad file size (%" FORMAT_OFF_T ")", size); + failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); return CURLE_BAD_DOWNLOAD_RESUME; } data->state.resume_from = attrs.filesize; @@ -1463,7 +1658,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(data->set.ftp_append) /* Try to open for append, but create if nonexisting */ flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND; - else if (data->state.resume_from > 0) + else if(data->state.resume_from > 0) /* If we have restart position then open for append */ flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND; else @@ -1472,7 +1667,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path, - (unsigned int)strlen(sftp_scp->path), + curlx_uztoui(strlen(sftp_scp->path)), flags, data->set.new_file_perms, LIBSSH2_SFTP_OPENFILE); @@ -1485,7 +1680,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc) /* only when there was an SFTP protocol error can we extract the sftp error! */ - err = (int)(libssh2_sftp_last_error(sshc->sftp_session)); + err = sftp_libssh2_last_error(sshc->sftp_session); else err = -1; /* not an sftp error at all */ @@ -1524,7 +1719,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } } - /* If we have restart point then we need to seek to the correct + /* If we have a restart point then we need to seek to the correct position. */ if(data->state.resume_from > 0) { /* Let's read off the proper amount of bytes from the input. */ @@ -1533,7 +1728,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) SEEK_SET); } - if(seekerr != CURL_SEEKFUNC_OK){ + if(seekerr != CURL_SEEKFUNC_OK) { if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); @@ -1548,8 +1743,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) BUFSIZE : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread = - conn->fread_func(data->state.buffer, 1, readthisamountnow, - conn->fread_in); + data->state.fread_func(data->state.buffer, 1, + readthisamountnow, data->state.in); passed += actuallyread; if((actuallyread == 0) || (actuallyread > readthisamountnow)) { @@ -1563,17 +1758,17 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } /* now, decrease the size of the read */ - if(data->set.infilesize > 0) { - data->set.infilesize -= data->state.resume_from; - data->req.size = data->set.infilesize; - Curl_pgrsSetUploadSize(data, data->set.infilesize); + if(data->state.infilesize > 0) { + data->state.infilesize -= data->state.resume_from; + data->req.size = data->state.infilesize; + Curl_pgrsSetUploadSize(data, data->state.infilesize); } SFTP_SEEK(sshc->sftp_handle, data->state.resume_from); } - if(data->set.infilesize > 0) { - data->req.size = data->set.infilesize; - Curl_pgrsSetUploadSize(data, data->set.infilesize); + if(data->state.infilesize > 0) { + data->req.size = data->state.infilesize; + Curl_pgrsSetUploadSize(data, data->state.infilesize); } /* upload data */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL); @@ -1590,6 +1785,16 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) figure out a "real" bitmask */ sshc->orig_waitfor = data->req.keepon; + /* we want to use the _sending_ function even when the socket turns + out readable as the underlying libssh2 sftp send function will deal + with both accordingly */ + conn->cselect_bits = CURL_CSELECT_OUT; + + /* since we don't really wait for anything at this point, we want the + state machine to move on as soon as possible so we set a very short + timeout here */ + Curl_expire(data, 1); + state(conn, SSH_STOP); } break; @@ -1606,7 +1811,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; case SSH_SFTP_CREATE_DIRS: - if((sshc->slash_pos = strchr(sshc->slash_pos, '/')) != NULL) { + sshc->slash_pos = strchr(sshc->slash_pos, '/'); + if(sshc->slash_pos) { *sshc->slash_pos = 0; infof(data, "Creating directory '%s'\n", sftp_scp->path); @@ -1621,7 +1827,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) case SSH_SFTP_CREATE_DIRS_MKDIR: /* 'mode' - parameter is preliminary - default to 0644 */ rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sftp_scp->path, - (unsigned int)strlen(sftp_scp->path), + curlx_uztoui(strlen(sftp_scp->path)), data->set.new_directory_perms); if(rc == LIBSSH2_ERROR_EAGAIN) { break; @@ -1629,17 +1835,16 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) *sshc->slash_pos = '/'; ++sshc->slash_pos; if(rc == -1) { - unsigned int sftp_err = 0; /* * Abort if failure wasn't that the dir already exists or the * permission was denied (creation might succeed further down the * path) - retry on unspecific FAILURE also */ - sftp_err = (unsigned int)(libssh2_sftp_last_error(sshc->sftp_session)); - if((sftp_err != LIBSSH2_FX_FILE_ALREADY_EXISTS) && - (sftp_err != LIBSSH2_FX_FAILURE) && - (sftp_err != LIBSSH2_FX_PERMISSION_DENIED)) { - result = sftp_libssh2_error_to_CURLE(sftp_err); + err = sftp_libssh2_last_error(sshc->sftp_session); + if((err != LIBSSH2_FX_FILE_ALREADY_EXISTS) && + (err != LIBSSH2_FX_FAILURE) && + (err != LIBSSH2_FX_PERMISSION_DENIED)) { + result = sftp_libssh2_error_to_CURLE(err); state(conn, SSH_SFTP_CLOSE); sshc->actualcode = result?result:CURLE_SSH; break; @@ -1649,14 +1854,20 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; case SSH_SFTP_READDIR_INIT: + Curl_pgrsSetDownloadSize(data, -1); + if(data->set.opt_no_body) { + state(conn, SSH_STOP); + break; + } + /* * This is a directory that we are trying to get, so produce a directory * listing */ sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path, - (unsigned int) - strlen(sftp_scp->path), + curlx_uztoui( + strlen(sftp_scp->path)), 0, 0, LIBSSH2_SFTP_OPENDIR); if(!sshc->sftp_handle) { if(libssh2_session_last_errno(sshc->ssh_session) == @@ -1665,7 +1876,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } else { - err = (int)(libssh2_sftp_last_error(sshc->sftp_session)); + err = sftp_libssh2_last_error(sshc->sftp_session); failf(data, "Could not open directory for reading: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); @@ -1681,7 +1892,6 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } if((sshc->readdir_longentry = malloc(PATH_MAX+1)) == NULL) { Curl_safefree(sshc->readdir_filename); - sshc->readdir_filename = NULL; state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; @@ -1714,7 +1924,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } result = Curl_client_write(conn, CLIENTWRITE_BODY, tmpLine, sshc->readdir_len+1); - Curl_safefree(tmpLine); + free(tmpLine); if(result) { state(conn, SSH_STOP); @@ -1736,9 +1946,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->readdir_line = calloc(sshc->readdir_totalLen, 1); if(!sshc->readdir_line) { Curl_safefree(sshc->readdir_filename); - sshc->readdir_filename = NULL; Curl_safefree(sshc->readdir_longentry); - sshc->readdir_longentry = NULL; state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; @@ -1752,9 +1960,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->readdir_linkPath = malloc(PATH_MAX + 1); if(sshc->readdir_linkPath == NULL) { Curl_safefree(sshc->readdir_filename); - sshc->readdir_filename = NULL; Curl_safefree(sshc->readdir_longentry); - sshc->readdir_longentry = NULL; state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; @@ -1771,23 +1977,19 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } else if(sshc->readdir_len == 0) { Curl_safefree(sshc->readdir_filename); - sshc->readdir_filename = NULL; Curl_safefree(sshc->readdir_longentry); - sshc->readdir_longentry = NULL; state(conn, SSH_SFTP_READDIR_DONE); break; } else if(sshc->readdir_len <= 0) { - err = (int)(libssh2_sftp_last_error(sshc->sftp_session)); + err = sftp_libssh2_last_error(sshc->sftp_session); result = sftp_libssh2_error_to_CURLE(err); sshc->actualcode = result?result:CURLE_SSH; failf(data, "Could not open remote file for reading: %s :: %d", sftp_libssh2_strerror(err), libssh2_session_last_errno(sshc->ssh_session)); Curl_safefree(sshc->readdir_filename); - sshc->readdir_filename = NULL; Curl_safefree(sshc->readdir_longentry); - sshc->readdir_longentry = NULL; state(conn, SSH_SFTP_CLOSE); break; } @@ -1797,7 +1999,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->readdir_len = libssh2_sftp_symlink_ex(sshc->sftp_session, sshc->readdir_linkPath, - (unsigned int) strlen(sshc->readdir_linkPath), + curlx_uztoui(strlen(sshc->readdir_linkPath)), sshc->readdir_filename, PATH_MAX, LIBSSH2_SFTP_READLINK); if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) { @@ -1805,19 +2007,19 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } Curl_safefree(sshc->readdir_linkPath); - sshc->readdir_linkPath = NULL; - sshc->readdir_line = realloc(sshc->readdir_line, - sshc->readdir_totalLen + 4 + - sshc->readdir_len); - if(!sshc->readdir_line) { + + /* get room for the filename and extra output */ + sshc->readdir_totalLen += 4 + sshc->readdir_len; + new_readdir_line = realloc(sshc->readdir_line, sshc->readdir_totalLen); + if(!new_readdir_line) { + Curl_safefree(sshc->readdir_line); Curl_safefree(sshc->readdir_filename); - sshc->readdir_filename = NULL; Curl_safefree(sshc->readdir_longentry); - sshc->readdir_longentry = NULL; state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } + sshc->readdir_line = new_readdir_line; sshc->readdir_currLen += snprintf(sshc->readdir_line + sshc->readdir_currLen, @@ -1838,7 +2040,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->readdir_line, sshc->readdir_currLen); - if(result == CURLE_OK) { + if(!result) { /* output debug output if that is requested */ if(data->set.verbose) { @@ -1848,7 +2050,6 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) data->req.bytecount += sshc->readdir_currLen; } Curl_safefree(sshc->readdir_line); - sshc->readdir_line = NULL; if(result) { state(conn, SSH_STOP); } @@ -1864,9 +2065,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } sshc->sftp_handle = NULL; Curl_safefree(sshc->readdir_filename); - sshc->readdir_filename = NULL; Curl_safefree(sshc->readdir_longentry); - sshc->readdir_longentry = NULL; /* no data to transfer */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); @@ -1879,7 +2078,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) */ sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path, - (unsigned int)strlen(sftp_scp->path), + curlx_uztoui(strlen(sftp_scp->path)), LIBSSH2_FXF_READ, data->set.new_file_perms, LIBSSH2_SFTP_OPENFILE); if(!sshc->sftp_handle) { @@ -1889,7 +2088,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } else { - err = (int)(libssh2_sftp_last_error(sshc->sftp_session)); + err = sftp_libssh2_last_error(sshc->sftp_session); failf(data, "Could not open remote file for reading: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); @@ -1906,24 +2105,29 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) LIBSSH2_SFTP_ATTRIBUTES attrs; rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path, - (unsigned int)strlen(sftp_scp->path), + curlx_uztoui(strlen(sftp_scp->path)), LIBSSH2_SFTP_STAT, &attrs); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc) { + else if(rc || + !(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) || + (attrs.filesize == 0)) { /* * libssh2_sftp_open() didn't return an error, so maybe the server * just doesn't support stat() + * OR the server doesn't return a file size with a stat() + * OR file size is 0 */ data->req.size = -1; data->req.maxdownload = -1; + Curl_pgrsSetDownloadSize(data, -1); } else { curl_off_t size = attrs.filesize; if(size < 0) { - failf(data, "Bad file size (%" FORMAT_OFF_T ")", size); + failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); return CURLE_BAD_DOWNLOAD_RESUME; } if(conn->data->state.use_range) { @@ -1943,10 +2147,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* from is relative to end of file */ from += size; } - if(from >= size) { + if(from > size) { failf(data, "Offset (%" - FORMAT_OFF_T ") was beyond file size (%" FORMAT_OFF_T ")", - from, attrs.filesize); + CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" + CURL_FORMAT_CURL_OFF_T ")", from, attrs.filesize); return CURLE_BAD_DOWNLOAD_RESUME; } if(from > to) { @@ -1970,7 +2174,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* We're supposed to download the last abs(from) bytes */ if((curl_off_t)attrs.filesize < -data->state.resume_from) { failf(data, "Offset (%" - FORMAT_OFF_T ") was beyond file size (%" FORMAT_OFF_T ")", + CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" + CURL_FORMAT_CURL_OFF_T ")", data->state.resume_from, attrs.filesize); return CURLE_BAD_DOWNLOAD_RESUME; } @@ -1979,8 +2184,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } else { if((curl_off_t)attrs.filesize < data->state.resume_from) { - failf(data, "Offset (%" FORMAT_OFF_T - ") was beyond file size (%" FORMAT_OFF_T ")", + failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T + ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", data->state.resume_from, attrs.filesize); return CURLE_BAD_DOWNLOAD_RESUME; } @@ -1994,6 +2199,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) SFTP_SEEK(sshc->sftp_handle, data->state.resume_from); } } + /* Setup the actual download */ if(data->req.size == 0) { /* no data to transfer */ @@ -2009,11 +2215,14 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* not set by Curl_setup_transfer to preserve keepon bits */ conn->writesockfd = conn->sockfd; - /* FIXME: here should be explained why we need it to start the - * download */ + /* we want to use the _receiving_ function even when the socket turns + out writableable as the underlying libssh2 recv function will deal + with both accordingly */ conn->cselect_bits = CURL_CSELECT_IN; } if(result) { + /* this should never occur; the close state should be entered + at the time the error occurs */ state(conn, SSH_SFTP_CLOSE); sshc->actualcode = result; } @@ -2033,15 +2242,23 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } sshc->sftp_handle = NULL; } - Curl_safefree(sftp_scp->path); - sftp_scp->path = NULL; + if(sftp_scp) + Curl_safefree(sftp_scp->path); DEBUGF(infof(data, "SFTP DONE done\n")); -#if 0 /* PREV */ - state(conn, SSH_SFTP_SHUTDOWN); -#endif - state(conn, SSH_STOP); - result = sshc->actualcode; + + /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT + After nextstate is executed, the control should come back to + SSH_SFTP_CLOSE to pass the correct result back */ + if(sshc->nextstate != SSH_NO_STATE && + sshc->nextstate != SSH_SFTP_CLOSE) { + state(conn, sshc->nextstate); + sshc->nextstate = SSH_SFTP_CLOSE; + } + else { + state(conn, SSH_STOP); + result = sshc->actualcode; + } break; case SSH_SFTP_SHUTDOWN: @@ -2071,7 +2288,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } Curl_safefree(sshc->homedir); - sshc->homedir = NULL; + conn->data->state.most_recent_ftp_entrypath = NULL; state(conn, SSH_SESSION_DISCONNECT); break; @@ -2085,7 +2302,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } if(data->set.upload) { - if(data->set.infilesize < 0) { + if(data->state.infilesize < 0) { failf(data, "SCP requires a known file size for upload"); sshc->actualcode = CURLE_UPLOAD_FAILED; state(conn, SSH_SCP_CHANNEL_FREE); @@ -2107,7 +2324,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) */ sshc->ssh_channel = SCP_SEND(sshc->ssh_session, sftp_scp->path, data->set.new_file_perms, - data->set.infilesize); + data->state.infilesize); if(!sshc->ssh_channel) { if(libssh2_session_last_errno(sshc->ssh_session) == LIBSSH2_ERROR_EAGAIN) { @@ -2139,25 +2356,45 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->actualcode = result; } else { + /* store this original bitmask setup to use later on if we can't + figure out a "real" bitmask */ + sshc->orig_waitfor = data->req.keepon; + + /* we want to use the _sending_ function even when the socket turns + out readable as the underlying libssh2 scp send function will deal + with both accordingly */ + conn->cselect_bits = CURL_CSELECT_OUT; + state(conn, SSH_STOP); } break; case SSH_SCP_DOWNLOAD_INIT: { + curl_off_t bytecount; + /* * We must check the remote file; if it is a directory no values will * be set in sb */ - struct stat sb; - curl_off_t bytecount; - /* clear the struct scp recv will fill in */ - memset(&sb, 0, sizeof(struct stat)); + /* + * If support for >2GB files exists, use it. + */ /* get a fresh new channel from the ssh layer */ +#if LIBSSH2_VERSION_NUM < 0x010700 + struct stat sb; + memset(&sb, 0, sizeof(struct stat)); sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session, sftp_scp->path, &sb); +#else + libssh2_struct_stat sb; + memset(&sb, 0, sizeof(libssh2_struct_stat)); + sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session, + sftp_scp->path, &sb); +#endif + if(!sshc->ssh_channel) { if(libssh2_session_last_errno(sshc->ssh_session) == LIBSSH2_ERROR_EAGAIN) { @@ -2185,8 +2422,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* not set by Curl_setup_transfer to preserve keepon bits */ conn->writesockfd = conn->sockfd; - /* FIXME: here should be explained why we need it to start the - * download */ + /* we want to use the _receiving_ function even when the socket turns + out writableable as the underlying libssh2 recv function will deal + with both accordingly */ conn->cselect_bits = CURL_CSELECT_IN; if(result) { @@ -2289,7 +2527,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } Curl_safefree(sshc->homedir); - sshc->homedir = NULL; + conn->data->state.most_recent_ftp_entrypath = NULL; state(conn, SSH_SESSION_FREE); break; @@ -2302,6 +2540,25 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } #endif +#ifdef HAVE_LIBSSH2_AGENT_API + if(sshc->ssh_agent) { + rc = libssh2_agent_disconnect(sshc->ssh_agent); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + else if(rc < 0) { + infof(data, "Failed to disconnect from libssh2 agent\n"); + } + libssh2_agent_free (sshc->ssh_agent); + sshc->ssh_agent = NULL; + + /* NB: there is no need to free identities, they are part of internal + agent stuff */ + sshc->sshagent_identity = NULL; + sshc->sshagent_prev_identity = NULL; + } +#endif + if(sshc->ssh_session) { rc = libssh2_session_free(sshc->ssh_session); if(rc == LIBSSH2_ERROR_EAGAIN) { @@ -2312,10 +2569,42 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } sshc->ssh_session = NULL; } - conn->bits.close = TRUE; + + /* worst-case scenario cleanup */ + + DEBUGASSERT(sshc->ssh_session == NULL); + DEBUGASSERT(sshc->ssh_channel == NULL); + DEBUGASSERT(sshc->sftp_session == NULL); + DEBUGASSERT(sshc->sftp_handle == NULL); +#ifdef HAVE_LIBSSH2_KNOWNHOST_API + DEBUGASSERT(sshc->kh == NULL); +#endif +#ifdef HAVE_LIBSSH2_AGENT_API + DEBUGASSERT(sshc->ssh_agent == NULL); +#endif + + Curl_safefree(sshc->rsa_pub); + Curl_safefree(sshc->rsa); + + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + + Curl_safefree(sshc->homedir); + + Curl_safefree(sshc->readdir_filename); + Curl_safefree(sshc->readdir_longentry); + Curl_safefree(sshc->readdir_line); + Curl_safefree(sshc->readdir_linkPath); + + /* the code we are about to return */ + result = sshc->actualcode; + + memset(sshc, 0, sizeof(struct ssh_conn)); + + connclose(conn, "SSH session free"); + sshc->state = SSH_SESSION_FREE; /* current */ sshc->nextstate = SSH_NO_STATE; state(conn, SSH_STOP); - result = sshc->actualcode; break; case SSH_QUIT: @@ -2398,9 +2687,7 @@ static void ssh_block2waitfor(struct connectdata *conn, bool block) { struct ssh_conn *sshc = &conn->proto.sshc; int dir; - if(!block) - conn->waitfor = 0; - else if((dir = libssh2_session_block_directions(sshc->ssh_session))) { + if(block && (dir = libssh2_session_block_directions(sshc->ssh_session))) { /* translate the libssh2 define bits into our own bit defines */ conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) | ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0); @@ -2412,7 +2699,7 @@ static void ssh_block2waitfor(struct connectdata *conn, bool block) } #else /* no libssh2 directional support so we simply don't know */ -#define ssh_block2waitfor(x,y) +#define ssh_block2waitfor(x,y) Curl_nop_stmt #endif /* called repeatedly until done from multi.c */ @@ -2424,13 +2711,13 @@ static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done) implementation */ result = ssh_statemach_act(conn, &block); - *done = (bool)(sshc->state == SSH_STOP); + *done = (sshc->state == SSH_STOP) ? TRUE : FALSE; ssh_block2waitfor(conn, block); return result; } -static CURLcode ssh_easy_statemach(struct connectdata *conn, +static CURLcode ssh_block_statemach(struct connectdata *conn, bool duringconnect) { struct ssh_conn *sshc = &conn->proto.sshc; @@ -2442,31 +2729,37 @@ static CURLcode ssh_easy_statemach(struct connectdata *conn, long left; result = ssh_statemach_act(conn, &block); + if(result) + break; if(Curl_pgrsUpdate(conn)) return CURLE_ABORTED_BY_CALLBACK; + else { + struct timeval now = Curl_tvnow(); + result = Curl_speedcheck(data, now); + if(result) + break; + } - left = Curl_timeleft(conn, NULL, duringconnect); + left = Curl_timeleft(data, NULL, duringconnect); if(left < 0) { - failf(data, "Operation timed out\n"); + failf(data, "Operation timed out"); return CURLE_OPERATION_TIMEDOUT; } #ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION - if((CURLE_OK == result) && block) { + if(!result && block) { int dir = libssh2_session_block_directions(sshc->ssh_session); curl_socket_t sock = conn->sock[FIRSTSOCKET]; curl_socket_t fd_read = CURL_SOCKET_BAD; curl_socket_t fd_write = CURL_SOCKET_BAD; - if (LIBSSH2_SESSION_BLOCK_INBOUND & dir) { + if(LIBSSH2_SESSION_BLOCK_INBOUND & dir) fd_read = sock; - } - if (LIBSSH2_SESSION_BLOCK_OUTBOUND & dir) { + if(LIBSSH2_SESSION_BLOCK_OUTBOUND & dir) fd_write = sock; - } /* wait for the socket to become ready */ Curl_socket_ready(fd_read, fd_write, - (int)(left>1000?1000:left)); /* ignore result */ + left>1000?1000:left); /* ignore result */ } #endif @@ -2478,25 +2771,14 @@ static CURLcode ssh_easy_statemach(struct connectdata *conn, /* * SSH setup and connection */ -static CURLcode ssh_init(struct connectdata *conn) +static CURLcode ssh_setup_connection(struct connectdata *conn) { - struct SessionHandle *data = conn->data; struct SSHPROTO *ssh; - struct ssh_conn *sshc = &conn->proto.sshc; - sshc->actualcode = CURLE_OK; /* reset error code */ - sshc->secondCreateDirs =0; /* reset the create dir attempt state - variable */ - - if(data->state.proto.ssh) - return CURLE_OK; - - ssh = calloc(1, sizeof(struct SSHPROTO)); + conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO)); if(!ssh) return CURLE_OUT_OF_MEMORY; - data->state.proto.ssh = ssh; - return CURLE_OK; } @@ -2516,22 +2798,19 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done) CURLcode result; struct SessionHandle *data = conn->data; + /* initialize per-handle data if not already */ + if(!data->req.protop) + ssh_setup_connection(conn); + /* We default to persistent connections. We set this already in this connect function to make the re-use checks properly be able to check this bit. */ - conn->bits.close = FALSE; + connkeep(conn, "SSH default"); - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); - - result = ssh_init(conn); - if(result) - return result; - - if(conn->protocol & PROT_SCP) { + if(conn->handler->protocol & CURLPROTO_SCP) { conn->recv[FIRSTSOCKET] = scp_recv; conn->send[FIRSTSOCKET] = scp_send; - } else { + } + else { conn->recv[FIRSTSOCKET] = sftp_recv; conn->send[FIRSTSOCKET] = sftp_send; } @@ -2568,10 +2847,9 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done) rc = libssh2_knownhost_readfile(ssh->kh, data->set.str[STRING_SSH_KNOWNHOSTS], LIBSSH2_KNOWNHOST_FILE_OPENSSH); - if(rc) { + if(rc < 0) infof(data, "Failed to read known hosts from %s\n", data->set.str[STRING_SSH_KNOWNHOSTS]); - } } #endif /* HAVE_LIBSSH2_KNOWNHOST_API */ @@ -2580,15 +2858,9 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done) infof(data, "SSH socket: %d\n", (int)sock); #endif /* CURL_LIBSSH2_DEBUG */ - state(conn, SSH_S_STARTUP); + state(conn, SSH_INIT); - if(data->state.used_interface == Curl_if_multi) - result = ssh_multi_statemach(conn, done); - else { - result = ssh_easy_statemach(conn, TRUE); - if(!result) - *done = TRUE; - } + result = ssh_multi_statemach(conn, done); return result; } @@ -2617,14 +2889,9 @@ CURLcode scp_perform(struct connectdata *conn, state(conn, SSH_SCP_TRANS_INIT); /* run the state-machine */ - if(conn->data->state.used_interface == Curl_if_multi) { - result = ssh_multi_statemach(conn, dophase_done); - } - else { - result = ssh_easy_statemach(conn, FALSE); - *dophase_done = TRUE; /* with the easy interface we are done here */ - } - *connected = conn->bits.tcpconnect; + result = ssh_multi_statemach(conn, dophase_done); + + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); @@ -2653,37 +2920,30 @@ static CURLcode scp_doing(struct connectdata *conn, static CURLcode ssh_do(struct connectdata *conn, bool *done) { - CURLcode res; + CURLcode result; bool connected = 0; struct SessionHandle *data = conn->data; + struct ssh_conn *sshc = &conn->proto.sshc; *done = FALSE; /* default to false */ - /* - Since connections can be re-used between SessionHandles, this might be a - connection already existing but on a fresh SessionHandle struct so we must - make sure we have a good 'struct SSHPROTO' to play with. For new - connections, the struct SSHPROTO is allocated and setup in the - ssh_connect() function. - */ - Curl_reset_reqproto(conn); - res = ssh_init(conn); - if(res) - return res; - data->req.size = -1; /* make sure this is unknown at this point */ + sshc->actualcode = CURLE_OK; /* reset error code */ + sshc->secondCreateDirs =0; /* reset the create dir attempt state + variable */ + Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); - Curl_pgrsSetUploadSize(data, 0); - Curl_pgrsSetDownloadSize(data, 0); + Curl_pgrsSetUploadSize(data, -1); + Curl_pgrsSetDownloadSize(data, -1); - if(conn->protocol & PROT_SCP) - res = scp_perform(conn, &connected, done); + if(conn->handler->protocol & CURLPROTO_SCP) + result = scp_perform(conn, &connected, done); else - res = sftp_perform(conn, &connected, done); + result = sftp_perform(conn, &connected, done); - return res; + return result; } /* BLOCKING, but the function is using the state machine so the only reason @@ -2695,15 +2955,14 @@ static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection) struct ssh_conn *ssh = &conn->proto.sshc; (void) dead_connection; - Curl_safefree(conn->data->state.proto.ssh); - conn->data->state.proto.ssh = NULL; + Curl_safefree(conn->data->req.protop); if(ssh->ssh_session) { /* only if there's a session still around to use! */ state(conn, SSH_SESSION_DISCONNECT); - result = ssh_easy_statemach(conn, FALSE); + result = ssh_block_statemach(conn, FALSE); } return result; @@ -2714,9 +2973,9 @@ static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection) static CURLcode ssh_done(struct connectdata *conn, CURLcode status) { CURLcode result = CURLE_OK; - struct SSHPROTO *sftp_scp = conn->data->state.proto.ssh; + struct SSHPROTO *sftp_scp = conn->data->req.protop; - if(status == CURLE_OK) { + if(!status) { /* run the state-machine TODO: when the multi interface is used, this _really_ should be using @@ -2724,14 +2983,15 @@ static CURLcode ssh_done(struct connectdata *conn, CURLcode status) non-blocking DONE operations, not in the multi state machine and with Curl_done() invokes on several places in the code! */ - result = ssh_easy_statemach(conn, FALSE); + result = ssh_block_statemach(conn, FALSE); } else result = status; - Curl_safefree(sftp_scp->path); - sftp_scp->path = NULL; - Curl_pgrsDone(conn); + if(sftp_scp) + Curl_safefree(sftp_scp->path); + if(Curl_pgrsDone(conn)) + return CURLE_ABORTED_BY_CALLBACK; conn->data->req.keepon = 0; /* clear all bits */ return result; @@ -2743,7 +3003,7 @@ static CURLcode scp_done(struct connectdata *conn, CURLcode status, { (void)premature; /* not used */ - if(status == CURLE_OK) + if(!status) state(conn, SSH_SCP_DONE); return ssh_done(conn, status); @@ -2767,6 +3027,10 @@ static ssize_t scp_send(struct connectdata *conn, int sockindex, *err = CURLE_AGAIN; nwrite = 0; } + else if(nwrite < LIBSSH2_ERROR_NONE) { + *err = libssh2_session_error_to_CURLE((int)nwrite); + nwrite = -1; + } return nwrite; } @@ -2786,7 +3050,7 @@ static ssize_t scp_recv(struct connectdata *conn, int sockindex, libssh2_channel_read(conn->proto.sshc.ssh_channel, mem, len); ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); - if (nread == LIBSSH2_ERROR_EAGAIN) { + if(nread == LIBSSH2_ERROR_EAGAIN) { *err = CURLE_AGAIN; nread = -1; } @@ -2822,14 +3086,9 @@ CURLcode sftp_perform(struct connectdata *conn, state(conn, SSH_SFTP_QUOTE_INIT); /* run the state-machine */ - if(conn->data->state.used_interface == Curl_if_multi) { - result = ssh_multi_statemach(conn, dophase_done); - } - else { - result = ssh_easy_statemach(conn, FALSE); - *dophase_done = TRUE; /* with the easy interface we are done here */ - } - *connected = conn->bits.tcpconnect; + result = ssh_multi_statemach(conn, dophase_done); + + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); @@ -2842,8 +3101,7 @@ CURLcode sftp_perform(struct connectdata *conn, static CURLcode sftp_doing(struct connectdata *conn, bool *dophase_done) { - CURLcode result; - result = ssh_multi_statemach(conn, dophase_done); + CURLcode result = ssh_multi_statemach(conn, dophase_done); if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); @@ -2861,13 +3119,12 @@ static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection) DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n")); - Curl_safefree(conn->data->state.proto.ssh); - conn->data->state.proto.ssh = NULL; + Curl_safefree(conn->data->req.protop); if(conn->proto.sshc.ssh_session) { /* only if there's a session still around to use! */ state(conn, SSH_SFTP_SHUTDOWN); - result = ssh_easy_statemach(conn, FALSE); + result = ssh_block_statemach(conn, FALSE); } DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n")); @@ -2881,12 +3138,13 @@ static CURLcode sftp_done(struct connectdata *conn, CURLcode status, { struct ssh_conn *sshc = &conn->proto.sshc; - if(status == CURLE_OK) { - /* Before we shut down, see if there are any post-quote commands to - send: */ + if(!status) { + /* Post quote commands are executed after the SFTP_CLOSE state to avoid + errors that could happen due to open file handles during POSTQUOTE + operation */ if(!status && !premature && conn->data->set.postquote) { - sshc->nextstate = SSH_SFTP_CLOSE; - state(conn, SSH_SFTP_POSTQUOTE_INIT); + sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT; + state(conn, SSH_SFTP_CLOSE); } else state(conn, SSH_SFTP_CLOSE); @@ -2911,12 +3169,17 @@ static ssize_t sftp_send(struct connectdata *conn, int sockindex, *err = CURLE_AGAIN; nwrite = 0; } + else if(nwrite < LIBSSH2_ERROR_NONE) { + *err = libssh2_session_error_to_CURLE((int)nwrite); + nwrite = -1; + } return nwrite; } /* * Return number of received (decrypted) bytes + * or <0 on error */ static ssize_t sftp_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) @@ -2931,6 +3194,10 @@ static ssize_t sftp_recv(struct connectdata *conn, int sockindex, if(nread == LIBSSH2_ERROR_EAGAIN) { *err = CURLE_AGAIN; nread = -1; + + } + else if(nread < 0) { + *err = libssh2_session_error_to_CURLE((int)nread); } return nread; } @@ -2976,7 +3243,7 @@ get_pathname(const char **cpp, char **path) quot = *cp++; /* Search for terminating quote, unescape some chars */ - for (i = j = 0; i <= strlen(cp); i++) { + for(i = j = 0; i <= strlen(cp); i++) { if(cp[i] == quot) { /* Found quote */ i++; (*path)[j] = '\0'; @@ -3017,13 +3284,12 @@ get_pathname(const char **cpp, char **path) return CURLE_OK; fail: - Curl_safefree(*path); - *path = NULL; - return CURLE_QUOTE_ERROR; + Curl_safefree(*path); + return CURLE_QUOTE_ERROR; } -static const char *sftp_libssh2_strerror(unsigned long err) +static const char *sftp_libssh2_strerror(int err) { switch (err) { case LIBSSH2_FX_NO_SUCH_FILE: diff --git a/project/jni/curl/lib/ssh.h b/project/jni/curl/lib/ssh.h index 406220cc4..6a5e73139 100644 --- a/project/jni/curl/lib/ssh.h +++ b/project/jni/curl/lib/ssh.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,7 +22,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifdef HAVE_LIBSSH2_H #include @@ -36,13 +36,17 @@ typedef enum { SSH_NO_STATE = -1, /* Used for "nextState" so say there is none */ SSH_STOP = 0, /* do nothing state, stops the state machine */ - SSH_S_STARTUP, /* Session startup, First state in SSH-CONNECT */ + SSH_INIT, /* First state in SSH-CONNECT */ + SSH_S_STARTUP, /* Session startup */ SSH_HOSTKEY, /* verify hostkey */ SSH_AUTHLIST, SSH_AUTH_PKEY_INIT, SSH_AUTH_PKEY, SSH_AUTH_PASS_INIT, SSH_AUTH_PASS, + SSH_AUTH_AGENT_INIT, /* initialize then wait for connection to agent */ + SSH_AUTH_AGENT_LIST, /* ask for list then wait for entire list to come */ + SSH_AUTH_AGENT, /* attempt one key at a time */ SSH_AUTH_HOST_INIT, SSH_AUTH_HOST, SSH_AUTH_KEY_INIT, @@ -114,6 +118,8 @@ struct ssh_conn { char *quote_path1; /* two generic pointers for the QUOTE stuff */ char *quote_path2; LIBSSH2_SFTP_ATTRIBUTES quote_attrs; /* used by the SFTP_QUOTE state */ + bool acceptfail; /* used by the SFTP_QUOTE (continue if + quote command fails) */ char *homedir; /* when doing SFTP we figure out home dir in the connect phase */ @@ -136,6 +142,12 @@ struct ssh_conn { LIBSSH2_SFTP_HANDLE *sftp_handle; int orig_waitfor; /* default READ/WRITE bits wait for */ +#ifdef HAVE_LIBSSH2_AGENT_API + LIBSSH2_AGENT *ssh_agent; /* proxy to ssh-agent/pageant */ + struct libssh2_agent_publickey *sshagent_identity, + *sshagent_prev_identity; +#endif + /* note that HAVE_LIBSSH2_KNOWNHOST_API is a define set in the libssh2.h header */ #ifdef HAVE_LIBSSH2_KNOWNHOST_API @@ -146,22 +158,34 @@ struct ssh_conn { #ifdef USE_LIBSSH2 +/* Feature detection based on version numbers to better work with + non-configure platforms */ + #if !defined(LIBSSH2_VERSION_NUM) || (LIBSSH2_VERSION_NUM < 0x001000) # error "SCP/SFTP protocols require libssh2 0.16 or later" #endif -#if defined(LIBSSH2_VERSION_NUM) && (LIBSSH2_VERSION_NUM >= 0x010000) -# define HAVE_LIBSSH2_SFTP_SEEK64 1 -#else -# undef HAVE_LIBSSH2_SFTP_SEEK64 +#if LIBSSH2_VERSION_NUM >= 0x010000 +#define HAVE_LIBSSH2_SFTP_SEEK64 1 #endif -#if defined(LIBSSH2_VERSION_NUM) && (LIBSSH2_VERSION_NUM >= 0x010206) -# define HAVE_LIBSSH2_SCP_SEND64 1 -#else -# undef HAVE_LIBSSH2_SCP_SEND64 +#if LIBSSH2_VERSION_NUM >= 0x010100 +#define HAVE_LIBSSH2_VERSION 1 #endif +#if LIBSSH2_VERSION_NUM >= 0x010205 +#define HAVE_LIBSSH2_INIT 1 +#define HAVE_LIBSSH2_EXIT 1 +#endif + +#if LIBSSH2_VERSION_NUM >= 0x010206 +#define HAVE_LIBSSH2_KNOWNHOST_CHECKP 1 +#define HAVE_LIBSSH2_SCP_SEND64 1 +#endif + +#if LIBSSH2_VERSION_NUM >= 0x010208 +#define HAVE_LIBSSH2_SESSION_HANDSHAKE 1 +#endif extern const struct Curl_handler Curl_handler_scp; extern const struct Curl_handler Curl_handler_sftp; diff --git a/project/jni/curl/lib/sslgen.c b/project/jni/curl/lib/sslgen.c deleted file mode 100644 index bd8dc1722..000000000 --- a/project/jni/curl/lib/sslgen.c +++ /dev/null @@ -1,472 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* This file is for implementing all "generic" SSL functions that all libcurl - internals should use. It is then responsible for calling the proper - "backend" function. - - SSL-functions in libcurl should call functions in this source file, and not - to any specific SSL-layer. - - Curl_ssl_ - prefix for generic ones - Curl_ossl_ - prefix for OpenSSL ones - Curl_gtls_ - prefix for GnuTLS ones - Curl_nss_ - prefix for NSS ones - Curl_polarssl_ - prefix for PolarSSL ones - - Note that this source code uses curlssl_* functions, and they are all - defines/macros #defined by the lib-specific header files. - - "SSL/TLS Strong Encryption: An Introduction" - http://httpd.apache.org/docs-2.0/ssl/ssl_intro.html -*/ - -#include "setup.h" - -#include -#include -#include -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include "urldata.h" -#define SSLGEN_C -#include "sslgen.h" /* generic SSL protos etc */ -#include "ssluse.h" /* OpenSSL versions */ -#include "gtls.h" /* GnuTLS versions */ -#include "nssg.h" /* NSS versions */ -#include "qssl.h" /* QSOSSL versions */ -#include "polarssl.h" /* PolarSSL versions */ -#include "sendf.h" -#include "rawstr.h" -#include "url.h" -#include "curl_memory.h" -#include "progress.h" -/* The last #include file should be: */ -#include "memdebug.h" - -static bool safe_strequal(char* str1, char* str2) -{ - if(str1 && str2) - /* both pointers point to something then compare them */ - return (bool)(0 != Curl_raw_equal(str1, str2)); - else - /* if both pointers are NULL then treat them as equal */ - return (bool)(!str1 && !str2); -} - -bool -Curl_ssl_config_matches(struct ssl_config_data* data, - struct ssl_config_data* needle) -{ - if((data->version == needle->version) && - (data->verifypeer == needle->verifypeer) && - (data->verifyhost == needle->verifyhost) && - safe_strequal(data->CApath, needle->CApath) && - safe_strequal(data->CAfile, needle->CAfile) && - safe_strequal(data->random_file, needle->random_file) && - safe_strequal(data->egdsocket, needle->egdsocket) && - safe_strequal(data->cipher_list, needle->cipher_list)) - return TRUE; - - return FALSE; -} - -bool -Curl_clone_ssl_config(struct ssl_config_data *source, - struct ssl_config_data *dest) -{ - dest->sessionid = source->sessionid; - dest->verifyhost = source->verifyhost; - dest->verifypeer = source->verifypeer; - dest->version = source->version; - - if(source->CAfile) { - dest->CAfile = strdup(source->CAfile); - if(!dest->CAfile) - return FALSE; - } - else - dest->CAfile = NULL; - - if(source->CApath) { - dest->CApath = strdup(source->CApath); - if(!dest->CApath) - return FALSE; - } - else - dest->CApath = NULL; - - if(source->cipher_list) { - dest->cipher_list = strdup(source->cipher_list); - if(!dest->cipher_list) - return FALSE; - } - else - dest->cipher_list = NULL; - - if(source->egdsocket) { - dest->egdsocket = strdup(source->egdsocket); - if(!dest->egdsocket) - return FALSE; - } - else - dest->egdsocket = NULL; - - if(source->random_file) { - dest->random_file = strdup(source->random_file); - if(!dest->random_file) - return FALSE; - } - else - dest->random_file = NULL; - - return TRUE; -} - -void Curl_free_ssl_config(struct ssl_config_data* sslc) -{ - Curl_safefree(sslc->CAfile); - Curl_safefree(sslc->CApath); - Curl_safefree(sslc->cipher_list); - Curl_safefree(sslc->egdsocket); - Curl_safefree(sslc->random_file); -} - -#ifdef USE_SSL - -/* "global" init done? */ -static bool init_ssl=FALSE; - -/** - * Global SSL init - * - * @retval 0 error initializing SSL - * @retval 1 SSL initialized successfully - */ -int Curl_ssl_init(void) -{ - /* make sure this is only done once */ - if(init_ssl) - return 1; - init_ssl = TRUE; /* never again */ - - return curlssl_init(); -} - - -/* Global cleanup */ -void Curl_ssl_cleanup(void) -{ - if(init_ssl) { - /* only cleanup if we did a previous init */ - curlssl_cleanup(); - init_ssl = FALSE; - } -} - -CURLcode -Curl_ssl_connect(struct connectdata *conn, int sockindex) -{ - CURLcode res; - /* mark this is being ssl-enabled from here on. */ - conn->ssl[sockindex].use = TRUE; - conn->ssl[sockindex].state = ssl_connection_negotiating; - - res = curlssl_connect(conn, sockindex); - - if(!res) - Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ - - return res; -} - -CURLcode -Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, - bool *done) -{ -#ifdef curlssl_connect_nonblocking - CURLcode res; - /* mark this is being ssl requested from here on. */ - conn->ssl[sockindex].use = TRUE; - res = curlssl_connect_nonblocking(conn, sockindex, done); - if(!res && *done == TRUE) - Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ - return res; -#else - *done = TRUE; /* fallback to BLOCKING */ - conn->ssl[sockindex].use = TRUE; - return curlssl_connect(conn, sockindex); -#endif /* non-blocking connect support */ -} - -/* - * Check if there's a session ID for the given connection in the cache, and if - * there's one suitable, it is provided. Returns TRUE when no entry matched. - */ -int Curl_ssl_getsessionid(struct connectdata *conn, - void **ssl_sessionid, - size_t *idsize) /* set 0 if unknown */ -{ - struct curl_ssl_session *check; - struct SessionHandle *data = conn->data; - long i; - - if(!conn->ssl_config.sessionid) - /* session ID re-use is disabled */ - return TRUE; - - for(i=0; i< data->set.ssl.numsessions; i++) { - check = &data->state.session[i]; - if(!check->sessionid) - /* not session ID means blank entry */ - continue; - if(Curl_raw_equal(conn->host.name, check->name) && - (conn->remote_port == check->remote_port) && - Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) { - /* yes, we have a session ID! */ - data->state.sessionage++; /* increase general age */ - check->age = data->state.sessionage; /* set this as used in this age */ - *ssl_sessionid = check->sessionid; - if(idsize) - *idsize = check->idsize; - return FALSE; - } - } - *ssl_sessionid = NULL; - return TRUE; -} - -/* - * Kill a single session ID entry in the cache. - */ -static int kill_session(struct curl_ssl_session *session) -{ - if(session->sessionid) { - /* defensive check */ - - /* free the ID the SSL-layer specific way */ - curlssl_session_free(session->sessionid); - - session->sessionid=NULL; - session->age = 0; /* fresh */ - - Curl_free_ssl_config(&session->ssl_config); - - Curl_safefree(session->name); - session->name = NULL; /* no name */ - - return 0; /* ok */ - } - else - return 1; -} - -/* - * Delete the given session ID from the cache. - */ -void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) -{ - int i; - for(i=0; i< conn->data->set.ssl.numsessions; i++) { - struct curl_ssl_session *check = &conn->data->state.session[i]; - - if (check->sessionid == ssl_sessionid) { - kill_session(check); - break; - } - } -} - -/* - * Store session id in the session cache. The ID passed on to this function - * must already have been extracted and allocated the proper way for the SSL - * layer. Curl_XXXX_session_free() will be called to free/kill the session ID - * later on. - */ -CURLcode Curl_ssl_addsessionid(struct connectdata *conn, - void *ssl_sessionid, - size_t idsize) -{ - long i; - struct SessionHandle *data=conn->data; /* the mother of all structs */ - struct curl_ssl_session *store = &data->state.session[0]; - long oldest_age=data->state.session[0].age; /* zero if unused */ - char *clone_host; - - /* Even though session ID re-use might be disabled, that only disables USING - IT. We still store it here in case the re-using is again enabled for an - upcoming transfer */ - - clone_host = strdup(conn->host.name); - if(!clone_host) - return CURLE_OUT_OF_MEMORY; /* bail out */ - - /* Now we should add the session ID and the host name to the cache, (remove - the oldest if necessary) */ - - /* find an empty slot for us, or find the oldest */ - for(i=1; (iset.ssl.numsessions) && - data->state.session[i].sessionid; i++) { - if(data->state.session[i].age < oldest_age) { - oldest_age = data->state.session[i].age; - store = &data->state.session[i]; - } - } - if(i == data->set.ssl.numsessions) - /* cache is full, we must "kill" the oldest entry! */ - kill_session(store); - else - store = &data->state.session[i]; /* use this slot */ - - /* now init the session struct wisely */ - store->sessionid = ssl_sessionid; - store->idsize = idsize; - store->age = data->state.sessionage; /* set current age */ - if (store->name) - /* free it if there's one already present */ - free(store->name); - store->name = clone_host; /* clone host name */ - store->remote_port = conn->remote_port; /* port number */ - - if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) - return CURLE_OUT_OF_MEMORY; - - return CURLE_OK; -} - - -void Curl_ssl_close_all(struct SessionHandle *data) -{ - long i; - /* kill the session ID cache */ - if(data->state.session) { - for(i=0; i< data->set.ssl.numsessions; i++) - /* the single-killer function handles empty table slots */ - kill_session(&data->state.session[i]); - - /* free the cache data */ - free(data->state.session); - data->state.session = NULL; - } - - curlssl_close_all(data); -} - -void Curl_ssl_close(struct connectdata *conn, int sockindex) -{ - DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); - curlssl_close(conn, sockindex); -} - -CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex) -{ - if(curlssl_shutdown(conn, sockindex)) - return CURLE_SSL_SHUTDOWN_FAILED; - - conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */ - conn->ssl[sockindex].state = ssl_connection_none; - - return CURLE_OK; -} - -/* Selects an SSL crypto engine - */ -CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine) -{ - return curlssl_set_engine(data, engine); -} - -/* Selects the default SSL crypto engine - */ -CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data) -{ - return curlssl_set_engine_default(data); -} - -/* Return list of OpenSSL crypto engine names. */ -struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data) -{ - return curlssl_engines_list(data); -} - -/* - * This sets up a session ID cache to the specified size. Make sure this code - * is agnostic to what underlying SSL technology we use. - */ -CURLcode Curl_ssl_initsessions(struct SessionHandle *data, long amount) -{ - struct curl_ssl_session *session; - - if(data->state.session) - /* this is just a precaution to prevent multiple inits */ - return CURLE_OK; - - session = calloc(amount, sizeof(struct curl_ssl_session)); - if(!session) - return CURLE_OUT_OF_MEMORY; - - /* store the info in the SSL section */ - data->set.ssl.numsessions = amount; - data->state.session = session; - data->state.sessionage = 1; /* this is brand new */ - return CURLE_OK; -} - -size_t Curl_ssl_version(char *buffer, size_t size) -{ - return curlssl_version(buffer, size); -} - -/* - * This function tries to determine connection status. - * - * Return codes: - * 1 means the connection is still in place - * 0 means the connection has been closed - * -1 means the connection status is unknown - */ -int Curl_ssl_check_cxn(struct connectdata *conn) -{ - return curlssl_check_cxn(conn); -} - -bool Curl_ssl_data_pending(const struct connectdata *conn, - int connindex) -{ - return curlssl_data_pending(conn, connindex); -} - -void Curl_ssl_free_certinfo(struct SessionHandle *data) -{ - int i; - struct curl_certinfo *ci = &data->info.certs; - if(ci->num_of_certs) { - /* free all individual lists used */ - for(i=0; inum_of_certs; i++) - curl_slist_free_all(ci->certinfo[i]); - free(ci->certinfo); /* free the actual array too */ - ci->num_of_certs = 0; - } -} -#endif /* USE_SSL */ diff --git a/project/jni/curl/lib/sslgen.h b/project/jni/curl/lib/sslgen.h deleted file mode 100644 index 997e30d35..000000000 --- a/project/jni/curl/lib/sslgen.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef __SSLGEN_H -#define __SSLGEN_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2008, 2010, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -bool Curl_ssl_config_matches(struct ssl_config_data* data, - struct ssl_config_data* needle); -bool Curl_clone_ssl_config(struct ssl_config_data* source, - struct ssl_config_data* dest); -void Curl_free_ssl_config(struct ssl_config_data* sslc); - -#ifdef USE_SSL -int Curl_ssl_init(void); -void Curl_ssl_cleanup(void); -CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex); -CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done); -/* tell the SSL stuff to close down all open information regarding - connections (and thus session ID caching etc) */ -void Curl_ssl_close_all(struct SessionHandle *data); -void Curl_ssl_close(struct connectdata *conn, int sockindex); -CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex); -CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine); -/* Sets engine as default for all SSL operations */ -CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data); -struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data); - -/* init the SSL session ID cache */ -CURLcode Curl_ssl_initsessions(struct SessionHandle *, long); -size_t Curl_ssl_version(char *buffer, size_t size); -bool Curl_ssl_data_pending(const struct connectdata *conn, - int connindex); -int Curl_ssl_check_cxn(struct connectdata *conn); -void Curl_ssl_free_certinfo(struct SessionHandle *data); - -/* Functions to be used by SSL library adaptation functions */ - -/* extract a session ID */ -int Curl_ssl_getsessionid(struct connectdata *conn, - void **ssl_sessionid, - size_t *idsize) /* set 0 if unknown */; -/* add a new session ID */ -CURLcode Curl_ssl_addsessionid(struct connectdata *conn, - void *ssl_sessionid, - size_t idsize); -/* delete a session from the cache */ -void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid); - -#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */ - -#else -/* When SSL support is not present, just define away these function calls */ -#define Curl_ssl_init() 1 -#define Curl_ssl_cleanup() do { } while (0) -#define Curl_ssl_connect(x,y) CURLE_FAILED_INIT -#define Curl_ssl_close_all(x) -#define Curl_ssl_close(x,y) -#define Curl_ssl_shutdown(x,y) CURLE_FAILED_INIT -#define Curl_ssl_set_engine(x,y) CURLE_FAILED_INIT -#define Curl_ssl_set_engine_default(x) CURLE_FAILED_INIT -#define Curl_ssl_engines_list(x) NULL -#define Curl_ssl_send(a,b,c,d,e) -1 -#define Curl_ssl_recv(a,b,c,d,e) -1 -#define Curl_ssl_initsessions(x,y) CURLE_OK -#define Curl_ssl_version(x,y) 0 -#define Curl_ssl_data_pending(x,y) 0 -#define Curl_ssl_check_cxn(x) 0 -#define Curl_ssl_free_certinfo(x) - -#endif - -#endif /* USE_SSL */ diff --git a/project/jni/curl/lib/strdup.c b/project/jni/curl/lib/strdup.c index a3107cff7..30a42f3d9 100644 --- a/project/jni/curl/lib/strdup.c +++ b/project/jni/curl/lib/strdup.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -19,9 +19,12 @@ * KIND, either express or implied. * ***************************************************************************/ - -#include "setup.h" +#include "curl_setup.h" #include "strdup.h" +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" #ifndef HAVE_STRDUP char *curlx_strdup(const char *str) @@ -41,9 +44,30 @@ char *curlx_strdup(const char *str) if(!newstr) return (char *)NULL; - memcpy(newstr,str,(len+1)*sizeof(char)); + memcpy(newstr, str, (len+1)*sizeof(char)); return newstr; } #endif + +/*************************************************************************** + * + * Curl_memdup(source, length) + * + * Copies the 'source' data to a newly allocated buffer (that is + * returned). Copies 'length' bytes. + * + * Returns the new pointer or NULL on failure. + * + ***************************************************************************/ +char *Curl_memdup(const char *src, size_t length) +{ + char *buffer = malloc(length); + if(!buffer) + return NULL; /* fail */ + + memcpy(buffer, src, length); + + return buffer; +} diff --git a/project/jni/curl/lib/strdup.h b/project/jni/curl/lib/strdup.h index 4edbcd7d4..4c48ca412 100644 --- a/project/jni/curl/lib/strdup.h +++ b/project/jni/curl/lib/strdup.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,10 +21,11 @@ * KIND, either express or implied. * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef HAVE_STRDUP extern char *curlx_strdup(const char *str); #endif +char *Curl_memdup(const char *src, size_t buffer_length); #endif /* HEADER_CURL_STRDUP_H */ diff --git a/project/jni/curl/lib/strequal.c b/project/jni/curl/lib/strequal.c index f6bf5f3b9..01c378442 100644 --- a/project/jni/curl/lib/strequal.c +++ b/project/jni/curl/lib/strequal.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,10 +20,7 @@ * ***************************************************************************/ -#include "setup.h" - -#include -#include +#include "curl_setup.h" #ifdef HAVE_STRINGS_H #include @@ -31,6 +28,9 @@ #include "strequal.h" +/* + * @unittest: 1301 + */ int curl_strequal(const char *first, const char *second) { #if defined(HAVE_STRCASECMP) @@ -51,6 +51,9 @@ int curl_strequal(const char *first, const char *second) #endif } +/* + * @unittest: 1301 + */ int curl_strnequal(const char *first, const char *second, size_t max) { #if defined(HAVE_STRNCASECMP) @@ -74,48 +77,3 @@ int curl_strnequal(const char *first, const char *second, size_t max) return toupper(*first) == toupper(*second); #endif } - -#ifndef HAVE_STRLCAT -/* - * The strlcat() function appends the NUL-terminated string src to the end - * of dst. It will append at most size - strlen(dst) - 1 bytes, NUL-termi- - * nating the result. - * - * The strlcpy() and strlcat() functions return the total length of the - * string they tried to create. For strlcpy() that means the length of src. - * For strlcat() that means the initial length of dst plus the length of - * src. While this may seem somewhat confusing it was done to make trunca- - * tion detection simple. - * - * - */ -size_t Curl_strlcat(char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - union { - ssize_t sig; - size_t uns; - } dlen; - - /* Find the end of dst and adjust bytes left but don't go past end */ - while(n-- != 0 && *d != '\0') - d++; - dlen.sig = d - dst; - n = siz - dlen.uns; - - if(n == 0) - return(dlen.uns + strlen(s)); - while(*s != '\0') { - if(n != 1) { - *d++ = *s; - n--; - } - s++; - } - *d = '\0'; - - return(dlen.uns + (s - src)); /* count does not include NUL */ -} -#endif diff --git a/project/jni/curl/lib/strequal.h b/project/jni/curl/lib/strequal.h index 202c9197d..ff56df51f 100644 --- a/project/jni/curl/lib/strequal.h +++ b/project/jni/curl/lib/strequal.h @@ -1,5 +1,5 @@ -#ifndef __STREQUAL_H -#define __STREQUAL_H +#ifndef HEADER_CURL_STREQUAL_H +#define HEADER_CURL_STREQUAL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -27,9 +27,5 @@ #define strequal(a,b) curl_strequal(a,b) #define strnequal(a,b,c) curl_strnequal(a,b,c) -#ifndef HAVE_STRLCAT -#define strlcat(x,y,z) Curl_strlcat(x,y,z) -#endif -size_t strlcat(char *dst, const char *src, size_t siz); +#endif /* HEADER_CURL_STREQUAL_H */ -#endif diff --git a/project/jni/curl/lib/strerror.c b/project/jni/curl/lib/strerror.c index e8ecea59f..d222a1fc0 100644 --- a/project/jni/curl/lib/strerror.c +++ b/project/jni/curl/lib/strerror.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2004 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 2004 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,7 +20,7 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifdef HAVE_STRERROR_R # if (!defined(HAVE_POSIX_STRERROR_R) && \ @@ -29,24 +29,25 @@ (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)) || \ (defined(HAVE_GLIBC_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)) || \ (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)) -# error "strerror_r MUST be either POSIX-style, glibc-style or vxworks-style" +# error "strerror_r MUST be either POSIX, glibc or vxworks-style" # endif #endif #include -#include -#include -#include #ifdef USE_LIBIDN #include #endif +#ifdef USE_WINDOWS_SSPI +#include "curl_sspi.h" +#endif + #include "strerror.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "curl_printf.h" +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" const char * curl_easy_strerror(CURLcode error) @@ -65,6 +66,10 @@ curl_easy_strerror(CURLcode error) case CURLE_URL_MALFORMAT: return "URL using bad/illegal format or missing URL"; + case CURLE_NOT_BUILT_IN: + return "A requested feature, protocol or option was not found built-in in" + " this libcurl due to a build-time decision."; + case CURLE_COULDNT_RESOLVE_PROXY: return "Couldn't resolve proxy name"; @@ -80,6 +85,12 @@ curl_easy_strerror(CURLcode error) case CURLE_REMOTE_ACCESS_DENIED: return "Access denied to remote resource"; + case CURLE_FTP_ACCEPT_FAILED: + return "FTP: The server failed to connect to data port"; + + case CURLE_FTP_ACCEPT_TIMEOUT: + return "FTP: Accepting server connect has timed out"; + case CURLE_FTP_PRET_FAILED: return "FTP: The server did not accept the PRET command."; @@ -95,6 +106,9 @@ curl_easy_strerror(CURLcode error) case CURLE_FTP_CANT_GET_HOST: return "FTP: can't figure out the host in the PASV response"; + case CURLE_HTTP2: + return "Error in the HTTP2 framing layer"; + case CURLE_FTP_COULDNT_SET_TYPE: return "FTP: couldn't set file type"; @@ -167,8 +181,8 @@ curl_easy_strerror(CURLcode error) case CURLE_TOO_MANY_REDIRECTS : return "Number of redirects hit maximum amount"; - case CURLE_UNKNOWN_TELNET_OPTION: - return "User specified an unknown telnet option"; + case CURLE_UNKNOWN_OPTION: + return "An unknown option was passed in to libcurl"; case CURLE_TELNET_OPTION_SYNTAX : return "Malformed telnet option"; @@ -201,13 +215,14 @@ curl_easy_strerror(CURLcode error) return "Couldn't use specified SSL cipher"; case CURLE_SSL_CACERT: - return "Peer certificate cannot be authenticated with known CA certificates"; + return "Peer certificate cannot be authenticated with given CA " + "certificates"; case CURLE_SSL_CACERT_BADFILE: return "Problem with the SSL CA cert (path? access rights?)"; case CURLE_BAD_CONTENT_ENCODING: - return "Unrecognized HTTP Content-Encoding"; + return "Unrecognized or bad HTTP Content or Transfer-Encoding"; case CURLE_LDAP_INVALID_URL: return "Invalid LDAP URL"; @@ -281,11 +296,16 @@ curl_easy_strerror(CURLcode error) case CURLE_CHUNK_FAILED: return "Chunk callback failed"; + case CURLE_NO_CONNECTION_AVAILABLE: + return "The max connection limit is reached"; + + case CURLE_SSL_PINNEDPUBKEYNOTMATCH: + return "SSL public key does not match pinned public key"; + + case CURLE_SSL_INVALIDCERTSTATUS: + return "SSL server certificate status verification FAILED"; + /* error codes not used by current libcurl */ - case CURLE_OBSOLETE4: - case CURLE_OBSOLETE10: - case CURLE_OBSOLETE12: - case CURLE_OBSOLETE16: case CURLE_OBSOLETE20: case CURLE_OBSOLETE24: case CURLE_OBSOLETE29: @@ -314,7 +334,7 @@ curl_easy_strerror(CURLcode error) */ return "Unknown error"; #else - if(error == CURLE_OK) + if(!error) return "No error"; else return "Error"; @@ -350,6 +370,9 @@ curl_multi_strerror(CURLMcode error) case CURLM_UNKNOWN_OPTION: return "Unknown option"; + case CURLM_ADDED_ALREADY: + return "The easy handle is already added to a multi handle"; + case CURLM_LAST: break; } @@ -383,6 +406,9 @@ curl_share_strerror(CURLSHcode error) case CURLSHE_NOMEM: return "Out of memory"; + case CURLSHE_NOT_BUILT_IN: + return "Feature not enabled in this library"; + case CURLSHE_LAST: break; } @@ -575,7 +601,7 @@ get_winsock_error (int err, char *buf, size_t len) return NULL; } #else - if(err == CURLE_OK) + if(!err) return NULL; else p = "error"; @@ -619,7 +645,7 @@ const char *Curl_strerror(struct connectdata *conn, int err) FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL); - wcstombs(buf,wbuf,max); + wcstombs(buf, wbuf, max); } #else /* 'sys_nerr' is the maximum errno number, it is not widely portable */ @@ -627,7 +653,7 @@ const char *Curl_strerror(struct connectdata *conn, int err) strncpy(buf, strerror(err), max); else { if(!get_winsock_error(err, buf, max) && - !FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, + !FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, LANG_NEUTRAL, buf, (DWORD)max, NULL)) snprintf(buf, max, "Unknown error %d (%#x)", err, err); } @@ -662,7 +688,7 @@ const char *Curl_strerror(struct connectdata *conn, int err) #elif defined(HAVE_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R) /* * The vxworks-style strerror_r() does use the buffer we pass to the function. - * The buffer size should be at least MAXERRSTR_SIZE (150) defined in rtsold.h + * The buffer size should be at least NAME_MAX (256) */ { char buffer[256]; @@ -686,9 +712,9 @@ const char *Curl_strerror(struct connectdata *conn, int err) buf[max] = '\0'; /* make sure the string is zero terminated */ /* strip trailing '\r\n' or '\n'. */ - if((p = strrchr(buf,'\n')) != NULL && (p - buf) >= 2) + if((p = strrchr(buf, '\n')) != NULL && (p - buf) >= 2) *p = '\0'; - if((p = strrchr(buf,'\r')) != NULL && (p - buf) >= 1) + if((p = strrchr(buf, '\r')) != NULL && (p - buf) >= 1) *p = '\0'; if(old_errno != ERRNO) @@ -773,3 +799,345 @@ const char *Curl_idn_strerror (struct connectdata *conn, int err) #endif } #endif /* USE_LIBIDN */ + +#ifdef USE_WINDOWS_SSPI +const char *Curl_sspi_strerror (struct connectdata *conn, int err) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + char txtbuf[80]; + char msgbuf[sizeof(conn->syserr_buf)]; + char *p, *str, *msg = NULL; + bool msg_formatted = FALSE; + int old_errno; +#endif + const char *txt; + char *outbuf; + size_t outmax; + + DEBUGASSERT(conn); + + outbuf = conn->syserr_buf; + outmax = sizeof(conn->syserr_buf)-1; + *outbuf = '\0'; + +#ifndef CURL_DISABLE_VERBOSE_STRINGS + + old_errno = ERRNO; + + switch (err) { + case SEC_E_OK: + txt = "No error"; + break; + case CRYPT_E_REVOKED: + txt = "CRYPT_E_REVOKED"; + break; + case SEC_E_ALGORITHM_MISMATCH: + txt = "SEC_E_ALGORITHM_MISMATCH"; + break; + case SEC_E_BAD_BINDINGS: + txt = "SEC_E_BAD_BINDINGS"; + break; + case SEC_E_BAD_PKGID: + txt = "SEC_E_BAD_PKGID"; + break; + case SEC_E_BUFFER_TOO_SMALL: + txt = "SEC_E_BUFFER_TOO_SMALL"; + break; + case SEC_E_CANNOT_INSTALL: + txt = "SEC_E_CANNOT_INSTALL"; + break; + case SEC_E_CANNOT_PACK: + txt = "SEC_E_CANNOT_PACK"; + break; + case SEC_E_CERT_EXPIRED: + txt = "SEC_E_CERT_EXPIRED"; + break; + case SEC_E_CERT_UNKNOWN: + txt = "SEC_E_CERT_UNKNOWN"; + break; + case SEC_E_CERT_WRONG_USAGE: + txt = "SEC_E_CERT_WRONG_USAGE"; + break; + case SEC_E_CONTEXT_EXPIRED: + txt = "SEC_E_CONTEXT_EXPIRED"; + break; + case SEC_E_CROSSREALM_DELEGATION_FAILURE: + txt = "SEC_E_CROSSREALM_DELEGATION_FAILURE"; + break; + case SEC_E_CRYPTO_SYSTEM_INVALID: + txt = "SEC_E_CRYPTO_SYSTEM_INVALID"; + break; + case SEC_E_DECRYPT_FAILURE: + txt = "SEC_E_DECRYPT_FAILURE"; + break; + case SEC_E_DELEGATION_POLICY: + txt = "SEC_E_DELEGATION_POLICY"; + break; + case SEC_E_DELEGATION_REQUIRED: + txt = "SEC_E_DELEGATION_REQUIRED"; + break; + case SEC_E_DOWNGRADE_DETECTED: + txt = "SEC_E_DOWNGRADE_DETECTED"; + break; + case SEC_E_ENCRYPT_FAILURE: + txt = "SEC_E_ENCRYPT_FAILURE"; + break; + case SEC_E_ILLEGAL_MESSAGE: + txt = "SEC_E_ILLEGAL_MESSAGE"; + break; + case SEC_E_INCOMPLETE_CREDENTIALS: + txt = "SEC_E_INCOMPLETE_CREDENTIALS"; + break; + case SEC_E_INCOMPLETE_MESSAGE: + txt = "SEC_E_INCOMPLETE_MESSAGE"; + break; + case SEC_E_INSUFFICIENT_MEMORY: + txt = "SEC_E_INSUFFICIENT_MEMORY"; + break; + case SEC_E_INTERNAL_ERROR: + txt = "SEC_E_INTERNAL_ERROR"; + break; + case SEC_E_INVALID_HANDLE: + txt = "SEC_E_INVALID_HANDLE"; + break; + case SEC_E_INVALID_PARAMETER: + txt = "SEC_E_INVALID_PARAMETER"; + break; + case SEC_E_INVALID_TOKEN: + txt = "SEC_E_INVALID_TOKEN"; + break; + case SEC_E_ISSUING_CA_UNTRUSTED: + txt = "SEC_E_ISSUING_CA_UNTRUSTED"; + break; + case SEC_E_ISSUING_CA_UNTRUSTED_KDC: + txt = "SEC_E_ISSUING_CA_UNTRUSTED_KDC"; + break; + case SEC_E_KDC_CERT_EXPIRED: + txt = "SEC_E_KDC_CERT_EXPIRED"; + break; + case SEC_E_KDC_CERT_REVOKED: + txt = "SEC_E_KDC_CERT_REVOKED"; + break; + case SEC_E_KDC_INVALID_REQUEST: + txt = "SEC_E_KDC_INVALID_REQUEST"; + break; + case SEC_E_KDC_UNABLE_TO_REFER: + txt = "SEC_E_KDC_UNABLE_TO_REFER"; + break; + case SEC_E_KDC_UNKNOWN_ETYPE: + txt = "SEC_E_KDC_UNKNOWN_ETYPE"; + break; + case SEC_E_LOGON_DENIED: + txt = "SEC_E_LOGON_DENIED"; + break; + case SEC_E_MAX_REFERRALS_EXCEEDED: + txt = "SEC_E_MAX_REFERRALS_EXCEEDED"; + break; + case SEC_E_MESSAGE_ALTERED: + txt = "SEC_E_MESSAGE_ALTERED"; + break; + case SEC_E_MULTIPLE_ACCOUNTS: + txt = "SEC_E_MULTIPLE_ACCOUNTS"; + break; + case SEC_E_MUST_BE_KDC: + txt = "SEC_E_MUST_BE_KDC"; + break; + case SEC_E_NOT_OWNER: + txt = "SEC_E_NOT_OWNER"; + break; + case SEC_E_NO_AUTHENTICATING_AUTHORITY: + txt = "SEC_E_NO_AUTHENTICATING_AUTHORITY"; + break; + case SEC_E_NO_CREDENTIALS: + txt = "SEC_E_NO_CREDENTIALS"; + break; + case SEC_E_NO_IMPERSONATION: + txt = "SEC_E_NO_IMPERSONATION"; + break; + case SEC_E_NO_IP_ADDRESSES: + txt = "SEC_E_NO_IP_ADDRESSES"; + break; + case SEC_E_NO_KERB_KEY: + txt = "SEC_E_NO_KERB_KEY"; + break; + case SEC_E_NO_PA_DATA: + txt = "SEC_E_NO_PA_DATA"; + break; + case SEC_E_NO_S4U_PROT_SUPPORT: + txt = "SEC_E_NO_S4U_PROT_SUPPORT"; + break; + case SEC_E_NO_TGT_REPLY: + txt = "SEC_E_NO_TGT_REPLY"; + break; + case SEC_E_OUT_OF_SEQUENCE: + txt = "SEC_E_OUT_OF_SEQUENCE"; + break; + case SEC_E_PKINIT_CLIENT_FAILURE: + txt = "SEC_E_PKINIT_CLIENT_FAILURE"; + break; + case SEC_E_PKINIT_NAME_MISMATCH: + txt = "SEC_E_PKINIT_NAME_MISMATCH"; + break; + case SEC_E_POLICY_NLTM_ONLY: + txt = "SEC_E_POLICY_NLTM_ONLY"; + break; + case SEC_E_QOP_NOT_SUPPORTED: + txt = "SEC_E_QOP_NOT_SUPPORTED"; + break; + case SEC_E_REVOCATION_OFFLINE_C: + txt = "SEC_E_REVOCATION_OFFLINE_C"; + break; + case SEC_E_REVOCATION_OFFLINE_KDC: + txt = "SEC_E_REVOCATION_OFFLINE_KDC"; + break; + case SEC_E_SECPKG_NOT_FOUND: + txt = "SEC_E_SECPKG_NOT_FOUND"; + break; + case SEC_E_SECURITY_QOS_FAILED: + txt = "SEC_E_SECURITY_QOS_FAILED"; + break; + case SEC_E_SHUTDOWN_IN_PROGRESS: + txt = "SEC_E_SHUTDOWN_IN_PROGRESS"; + break; + case SEC_E_SMARTCARD_CERT_EXPIRED: + txt = "SEC_E_SMARTCARD_CERT_EXPIRED"; + break; + case SEC_E_SMARTCARD_CERT_REVOKED: + txt = "SEC_E_SMARTCARD_CERT_REVOKED"; + break; + case SEC_E_SMARTCARD_LOGON_REQUIRED: + txt = "SEC_E_SMARTCARD_LOGON_REQUIRED"; + break; + case SEC_E_STRONG_CRYPTO_NOT_SUPPORTED: + txt = "SEC_E_STRONG_CRYPTO_NOT_SUPPORTED"; + break; + case SEC_E_TARGET_UNKNOWN: + txt = "SEC_E_TARGET_UNKNOWN"; + break; + case SEC_E_TIME_SKEW: + txt = "SEC_E_TIME_SKEW"; + break; + case SEC_E_TOO_MANY_PRINCIPALS: + txt = "SEC_E_TOO_MANY_PRINCIPALS"; + break; + case SEC_E_UNFINISHED_CONTEXT_DELETED: + txt = "SEC_E_UNFINISHED_CONTEXT_DELETED"; + break; + case SEC_E_UNKNOWN_CREDENTIALS: + txt = "SEC_E_UNKNOWN_CREDENTIALS"; + break; + case SEC_E_UNSUPPORTED_FUNCTION: + txt = "SEC_E_UNSUPPORTED_FUNCTION"; + break; + case SEC_E_UNSUPPORTED_PREAUTH: + txt = "SEC_E_UNSUPPORTED_PREAUTH"; + break; + case SEC_E_UNTRUSTED_ROOT: + txt = "SEC_E_UNTRUSTED_ROOT"; + break; + case SEC_E_WRONG_CREDENTIAL_HANDLE: + txt = "SEC_E_WRONG_CREDENTIAL_HANDLE"; + break; + case SEC_E_WRONG_PRINCIPAL: + txt = "SEC_E_WRONG_PRINCIPAL"; + break; + case SEC_I_COMPLETE_AND_CONTINUE: + txt = "SEC_I_COMPLETE_AND_CONTINUE"; + break; + case SEC_I_COMPLETE_NEEDED: + txt = "SEC_I_COMPLETE_NEEDED"; + break; + case SEC_I_CONTEXT_EXPIRED: + txt = "SEC_I_CONTEXT_EXPIRED"; + break; + case SEC_I_CONTINUE_NEEDED: + txt = "SEC_I_CONTINUE_NEEDED"; + break; + case SEC_I_INCOMPLETE_CREDENTIALS: + txt = "SEC_I_INCOMPLETE_CREDENTIALS"; + break; + case SEC_I_LOCAL_LOGON: + txt = "SEC_I_LOCAL_LOGON"; + break; + case SEC_I_NO_LSA_CONTEXT: + txt = "SEC_I_NO_LSA_CONTEXT"; + break; + case SEC_I_RENEGOTIATE: + txt = "SEC_I_RENEGOTIATE"; + break; + case SEC_I_SIGNATURE_NEEDED: + txt = "SEC_I_SIGNATURE_NEEDED"; + break; + default: + txt = "Unknown error"; + } + + if(err == SEC_E_OK) + strncpy(outbuf, txt, outmax); + else if(err == SEC_E_ILLEGAL_MESSAGE) + snprintf(outbuf, outmax, + "SEC_E_ILLEGAL_MESSAGE (0x%04X%04X) - This error usually occurs " + "when a fatal SSL/TLS alert is received (e.g. handshake failed). " + "More detail may be available in the Windows System event log.", + (err >> 16) & 0xffff, err & 0xffff); + else { + str = txtbuf; + snprintf(txtbuf, sizeof(txtbuf), "%s (0x%04X%04X)", + txt, (err >> 16) & 0xffff, err & 0xffff); + txtbuf[sizeof(txtbuf)-1] = '\0'; + +#ifdef _WIN32_WCE + { + wchar_t wbuf[256]; + wbuf[0] = L'\0'; + + if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, LANG_NEUTRAL, + wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) { + wcstombs(msgbuf, wbuf, sizeof(msgbuf)-1); + msg_formatted = TRUE; + } + } +#else + if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, LANG_NEUTRAL, + msgbuf, sizeof(msgbuf)-1, NULL)) { + msg_formatted = TRUE; + } +#endif + if(msg_formatted) { + msgbuf[sizeof(msgbuf)-1] = '\0'; + /* strip trailing '\r\n' or '\n' */ + if((p = strrchr(msgbuf, '\n')) != NULL && (p - msgbuf) >= 2) + *p = '\0'; + if((p = strrchr(msgbuf, '\r')) != NULL && (p - msgbuf) >= 1) + *p = '\0'; + msg = msgbuf; + } + if(msg) + snprintf(outbuf, outmax, "%s - %s", str, msg); + else + strncpy(outbuf, str, outmax); + } + + if(old_errno != ERRNO) + SET_ERRNO(old_errno); + +#else + + if(err == SEC_E_OK) + txt = "No error"; + else + txt = "Error"; + + strncpy(outbuf, txt, outmax); + +#endif + + outbuf[outmax] = '\0'; + + return outbuf; +} +#endif /* USE_WINDOWS_SSPI */ diff --git a/project/jni/curl/lib/strerror.h b/project/jni/curl/lib/strerror.h index 7f2342aea..ae8c96bd4 100644 --- a/project/jni/curl/lib/strerror.h +++ b/project/jni/curl/lib/strerror.h @@ -1,5 +1,5 @@ -#ifndef __CURL_STRERROR_H -#define __CURL_STRERROR_H +#ifndef HEADER_CURL_STRERROR_H +#define HEADER_CURL_STRERROR_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -30,4 +30,8 @@ const char *Curl_strerror (struct connectdata *conn, int err); const char *Curl_idn_strerror (struct connectdata *conn, int err); #endif +#ifdef USE_WINDOWS_SSPI +const char *Curl_sspi_strerror (struct connectdata *conn, int err); #endif + +#endif /* HEADER_CURL_STRERROR_H */ diff --git a/project/jni/curl/lib/strtok.c b/project/jni/curl/lib/strtok.c index 91c254156..460eb87e5 100644 --- a/project/jni/curl/lib/strtok.c +++ b/project/jni/curl/lib/strtok.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,11 +20,10 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef HAVE_STRTOK_R #include -#include #include "strtok.h" diff --git a/project/jni/curl/lib/strtok.h b/project/jni/curl/lib/strtok.h index 8baf77948..90b831eb6 100644 --- a/project/jni/curl/lib/strtok.h +++ b/project/jni/curl/lib/strtok.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,7 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #include #ifndef HAVE_STRTOK_R diff --git a/project/jni/curl/lib/strtoofft.c b/project/jni/curl/lib/strtoofft.c index 61ff05bed..6d5d2d5c5 100644 --- a/project/jni/curl/lib/strtoofft.c +++ b/project/jni/curl/lib/strtoofft.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,7 +20,8 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" + #include "strtoofft.h" /* @@ -32,15 +33,11 @@ */ #ifdef NEED_CURL_STRTOLL -#include -#include -#include /* Range tests can be used for alphanum decoding if characters are consecutive, like in ASCII. Else an array is scanned. Determine this condition now. */ #if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25 -#include #define NO_RANGE_TEST @@ -110,9 +107,9 @@ curlx_strtoll(const char *nptr, char **endptr, int base) /* Loop handling digits. */ value = 0; overflow = 0; - for (i = get_char(end[0], base); - i != -1; - end++, i = get_char(end[0], base)) { + for(i = get_char(end[0], base); + i != -1; + end++, i = get_char(end[0], base)) { newval = base * value + i; if(newval < value) { /* We've overflowed. */ diff --git a/project/jni/curl/lib/strtoofft.h b/project/jni/curl/lib/strtoofft.h index 8208e87fa..f4039f3a3 100644 --- a/project/jni/curl/lib/strtoofft.h +++ b/project/jni/curl/lib/strtoofft.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,22 +22,22 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" /* * Determine which string to integral data type conversion function we use * to implement string conversion to our curl_off_t integral data type. * * Notice that curl_off_t might be 64 or 32 bit wide, and that it might use - * an undelying data type which might be 'long', 'int64_t', 'long long' or + * an underlying data type which might be 'long', 'int64_t', 'long long' or * '__int64' and more remotely other data types. * * On systems where the size of curl_off_t is greater than the size of 'long' - * the conversion funtion to use is strtoll() if it is available, otherwise, + * the conversion function to use is strtoll() if it is available, otherwise, * we emulate its functionality with our own clone. * * On systems where the size of curl_off_t is smaller or equal than the size - * of 'long' the conversion funtion to use is strtol(). + * of 'long' the conversion function to use is strtol(). */ #if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG) @@ -45,7 +45,14 @@ # define curlx_strtoofft strtoll # else # if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64) - _CRTIMP __int64 __cdecl _strtoi64(const char *, char **, int); +# if defined(_SAL_VERSION) + _Check_return_ _CRTIMP __int64 __cdecl _strtoi64( + _In_z_ const char *_String, + _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix); +# else + _CRTIMP __int64 __cdecl _strtoi64(const char *_String, + char **_EndPtr, int _Radix); +# endif # define curlx_strtoofft _strtoi64 # else curl_off_t curlx_strtoll(const char *nptr, char **endptr, int base); diff --git a/project/jni/curl/lib/telnet.c b/project/jni/curl/lib/telnet.c index 1a5683d40..4ebc49252 100644 --- a/project/jni/curl/lib/telnet.c +++ b/project/jni/curl/lib/telnet.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,31 +20,16 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_TELNET -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include -#if defined(WIN32) -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif +#ifdef HAVE_NETINET_IN_H #include -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include #endif +#ifdef HAVE_NETDB_H #include +#endif #ifdef HAVE_ARPA_INET_H #include #endif @@ -59,8 +44,6 @@ #include #endif -#endif /* WIN32 */ - #include "urldata.h" #include #include "transfer.h" @@ -68,30 +51,34 @@ #include "telnet.h" #include "connect.h" #include "progress.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include +#include "curl_printf.h" #define TELOPTS #define TELCMDS #include "arpa_telnet.h" -#include "curl_memory.h" #include "select.h" #include "strequal.h" #include "rawstr.h" +#include "warnless.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #define SUBBUFSIZE 512 -#define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer; -#define CURL_SB_TERM(x) { x->subend = x->subpointer; CURL_SB_CLEAR(x); } -#define CURL_SB_ACCUM(x,c) \ - if(x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \ - *x->subpointer++ = (c); \ - } +#define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer +#define CURL_SB_TERM(x) \ + do { \ + x->subend = x->subpointer; \ + CURL_SB_CLEAR(x); \ + } WHILE_FALSE +#define CURL_SB_ACCUM(x,c) \ + do { \ + if(x->subpointer < (x->subbuffer+sizeof x->subbuffer)) \ + *x->subpointer++ = (c); \ + } WHILE_FALSE #define CURL_SB_GET(x) ((*x->subpointer++)&0xff) #define CURL_SB_PEEK(x) ((*x->subpointer)&0xff) @@ -99,7 +86,7 @@ #define CURL_SB_LEN(x) (x->subend - x->subpointer) #ifdef CURL_DISABLE_VERBOSE_STRINGS -#define printoption(a,b,c,d) do { } while(0) +#define printoption(a,b,c,d) Curl_nop_stmt #endif #ifdef USE_WINSOCK @@ -127,10 +114,13 @@ static void printsub(struct SessionHandle *data, int direction, unsigned char *pointer, size_t length); static void suboption(struct connectdata *); +static void sendsuboption(struct connectdata *conn, int option); static CURLcode telnet_do(struct connectdata *conn, bool *done); static CURLcode telnet_done(struct connectdata *conn, CURLcode, bool premature); +static CURLcode send_telnet_data(struct connectdata *conn, + char *buffer, ssize_t nread); /* For negotiation compliant to RFC 1143 */ #define CURL_NO 0 @@ -166,9 +156,12 @@ struct TELNET { int him[256]; int himq[256]; int him_preferred[256]; + int subnegotiation[256]; char subopt_ttype[32]; /* Set with suboption TTYPE */ - char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */ - struct curl_slist *telnet_vars; /* Environment variables */ + char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */ + unsigned short subopt_wsx; /* Set with suboption NAWS */ + unsigned short subopt_wsy; /* Set with suboption NAWS */ + struct curl_slist *telnet_vars; /* Environment variables */ /* suboptions */ unsigned char subbuffer[SUBBUFSIZE]; @@ -193,10 +186,13 @@ const struct Curl_handler Curl_handler_telnet = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_TELNET, /* defport */ - PROT_TELNET /* protocol */ + CURLPROTO_TELNET, /* protocol */ + PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ }; @@ -230,9 +226,9 @@ check_wsock2 ( struct SessionHandle *data ) if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) || HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) { /* Our version isn't supported */ - failf(data,"insufficient winsock version to support " - "telnet"); - return CURLE_FAILED_INIT; + failf(data, "insufficient winsock version to support " + "telnet"); + return CURLE_FAILED_INIT; } /* Our version is supported */ @@ -249,7 +245,7 @@ CURLcode init_telnet(struct connectdata *conn) if(!tn) return CURLE_OUT_OF_MEMORY; - conn->data->state.proto.telnet = (void *)tn; /* make us known */ + conn->data->req.protop = tn; /* make us known */ tn->telrcv_state = CURL_TS_DATA; @@ -257,21 +253,49 @@ CURLcode init_telnet(struct connectdata *conn) CURL_SB_CLEAR(tn); /* Set the options we want by default */ - tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES; tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES; - tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES; tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES; + /* To be compliant with previous releases of libcurl + we enable this option by default. This behaviour + can be changed thanks to the "BINARY" option in + CURLOPT_TELNETOPTIONS + */ + tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES; + tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES; + + /* We must allow the server to echo what we sent + but it is not necessary to request the server + to do so (it might forces the server to close + the connection). Hence, we ignore ECHO in the + negotiate function + */ + tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES; + + /* Set the subnegotiation fields to send information + just after negotiation passed (do/will) + + Default values are (0,0) initialized by calloc. + According to the RFC1013 it is valid: + A value equal to zero is acceptable for the width (or height), + and means that no character width (or height) is being sent. + In this case, the width (or height) that will be assumed by the + Telnet server is operating system specific (it will probably be + based upon the terminal type information that may have been sent + using the TERMINAL TYPE Telnet option). */ + tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES; return CURLE_OK; } static void negotiate(struct connectdata *conn) { int i; - struct TELNET *tn = (struct TELNET *) conn->data->state.proto.telnet; + struct TELNET *tn = (struct TELNET *) conn->data->req.protop; + + for(i = 0;i < CURL_NTELOPTS;i++) { + if(i==CURL_TELOPT_ECHO) + continue; - for(i = 0;i < CURL_NTELOPTS;i++) - { if(tn->us_preferred[i] == CURL_YES) set_local_option(conn, i, CURL_YES); @@ -287,21 +311,17 @@ static void printoption(struct SessionHandle *data, const char *fmt; const char *opt; - if(data->set.verbose) - { - if(cmd == CURL_IAC) - { + if(data->set.verbose) { + if(cmd == CURL_IAC) { if(CURL_TELCMD_OK(option)) infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option)); else infof(data, "%s IAC %d\n", direction, option); } - else - { + else { fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" : (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0; - if(fmt) - { + if(fmt) { if(CURL_TELOPT_OK(option)) opt = CURL_TELOPT(option); else if(option == CURL_TELOPT_EXOPL) @@ -344,81 +364,73 @@ static void send_negotiation(struct connectdata *conn, int cmd, int option) static void set_remote_option(struct connectdata *conn, int option, int newstate) { - struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet; - if(newstate == CURL_YES) - { - switch(tn->him[option]) - { - case CURL_NO: - tn->him[option] = CURL_WANTYES; - send_negotiation(conn, CURL_DO, option); - break; + struct TELNET *tn = (struct TELNET *)conn->data->req.protop; + if(newstate == CURL_YES) { + switch(tn->him[option]) { + case CURL_NO: + tn->him[option] = CURL_WANTYES; + send_negotiation(conn, CURL_DO, option); + break; - case CURL_YES: - /* Already enabled */ - break; + case CURL_YES: + /* Already enabled */ + break; - case CURL_WANTNO: - switch(tn->himq[option]) - { - case CURL_EMPTY: - /* Already negotiating for CURL_YES, queue the request */ - tn->himq[option] = CURL_OPPOSITE; - break; - case CURL_OPPOSITE: - /* Error: already queued an enable request */ - break; - } + case CURL_WANTNO: + switch(tn->himq[option]) { + case CURL_EMPTY: + /* Already negotiating for CURL_YES, queue the request */ + tn->himq[option] = CURL_OPPOSITE; break; + case CURL_OPPOSITE: + /* Error: already queued an enable request */ + break; + } + break; - case CURL_WANTYES: - switch(tn->himq[option]) - { - case CURL_EMPTY: - /* Error: already negotiating for enable */ - break; - case CURL_OPPOSITE: - tn->himq[option] = CURL_EMPTY; - break; - } + case CURL_WANTYES: + switch(tn->himq[option]) { + case CURL_EMPTY: + /* Error: already negotiating for enable */ break; + case CURL_OPPOSITE: + tn->himq[option] = CURL_EMPTY; + break; + } + break; } } - else /* NO */ - { - switch(tn->him[option]) - { - case CURL_NO: - /* Already disabled */ - break; + else { /* NO */ + switch(tn->him[option]) { + case CURL_NO: + /* Already disabled */ + break; - case CURL_YES: - tn->him[option] = CURL_WANTNO; - send_negotiation(conn, CURL_DONT, option); - break; + case CURL_YES: + tn->him[option] = CURL_WANTNO; + send_negotiation(conn, CURL_DONT, option); + break; - case CURL_WANTNO: - switch(tn->himq[option]) - { - case CURL_EMPTY: - /* Already negotiating for NO */ - break; - case CURL_OPPOSITE: - tn->himq[option] = CURL_EMPTY; - break; - } + case CURL_WANTNO: + switch(tn->himq[option]) { + case CURL_EMPTY: + /* Already negotiating for NO */ break; + case CURL_OPPOSITE: + tn->himq[option] = CURL_EMPTY; + break; + } + break; - case CURL_WANTYES: - switch(tn->himq[option]) - { - case CURL_EMPTY: - tn->himq[option] = CURL_OPPOSITE; - break; - case CURL_OPPOSITE: - break; - } + case CURL_WANTYES: + switch(tn->himq[option]) { + case CURL_EMPTY: + tn->himq[option] = CURL_OPPOSITE; break; + case CURL_OPPOSITE: + break; + } + break; } } } @@ -426,19 +438,102 @@ void set_remote_option(struct connectdata *conn, int option, int newstate) static void rec_will(struct connectdata *conn, int option) { - struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet; - switch(tn->him[option]) - { + struct TELNET *tn = (struct TELNET *)conn->data->req.protop; + switch(tn->him[option]) { + case CURL_NO: + if(tn->him_preferred[option] == CURL_YES) { + tn->him[option] = CURL_YES; + send_negotiation(conn, CURL_DO, option); + } + else + send_negotiation(conn, CURL_DONT, option); + + break; + + case CURL_YES: + /* Already enabled */ + break; + + case CURL_WANTNO: + switch(tn->himq[option]) { + case CURL_EMPTY: + /* Error: DONT answered by WILL */ + tn->him[option] = CURL_NO; + break; + case CURL_OPPOSITE: + /* Error: DONT answered by WILL */ + tn->him[option] = CURL_YES; + tn->himq[option] = CURL_EMPTY; + break; + } + break; + + case CURL_WANTYES: + switch(tn->himq[option]) { + case CURL_EMPTY: + tn->him[option] = CURL_YES; + break; + case CURL_OPPOSITE: + tn->him[option] = CURL_WANTNO; + tn->himq[option] = CURL_EMPTY; + send_negotiation(conn, CURL_DONT, option); + break; + } + break; + } +} + +static +void rec_wont(struct connectdata *conn, int option) +{ + struct TELNET *tn = (struct TELNET *)conn->data->req.protop; + switch(tn->him[option]) { + case CURL_NO: + /* Already disabled */ + break; + + case CURL_YES: + tn->him[option] = CURL_NO; + send_negotiation(conn, CURL_DONT, option); + break; + + case CURL_WANTNO: + switch(tn->himq[option]) { + case CURL_EMPTY: + tn->him[option] = CURL_NO; + break; + + case CURL_OPPOSITE: + tn->him[option] = CURL_WANTYES; + tn->himq[option] = CURL_EMPTY; + send_negotiation(conn, CURL_DO, option); + break; + } + break; + + case CURL_WANTYES: + switch(tn->himq[option]) { + case CURL_EMPTY: + tn->him[option] = CURL_NO; + break; + case CURL_OPPOSITE: + tn->him[option] = CURL_NO; + tn->himq[option] = CURL_EMPTY; + break; + } + break; + } +} + +static void +set_local_option(struct connectdata *conn, int option, int newstate) +{ + struct TELNET *tn = (struct TELNET *)conn->data->req.protop; + if(newstate == CURL_YES) { + switch(tn->us[option]) { case CURL_NO: - if(tn->him_preferred[option] == CURL_YES) - { - tn->him[option] = CURL_YES; - send_negotiation(conn, CURL_DO, option); - } - else - { - send_negotiation(conn, CURL_DONT, option); - } + tn->us[option] = CURL_WANTYES; + send_negotiation(conn, CURL_WILL, option); break; case CURL_YES: @@ -446,159 +541,60 @@ void rec_will(struct connectdata *conn, int option) break; case CURL_WANTNO: - switch(tn->himq[option]) - { - case CURL_EMPTY: - /* Error: DONT answered by WILL */ - tn->him[option] = CURL_NO; - break; - case CURL_OPPOSITE: - /* Error: DONT answered by WILL */ - tn->him[option] = CURL_YES; - tn->himq[option] = CURL_EMPTY; - break; + switch(tn->usq[option]) { + case CURL_EMPTY: + /* Already negotiating for CURL_YES, queue the request */ + tn->usq[option] = CURL_OPPOSITE; + break; + case CURL_OPPOSITE: + /* Error: already queued an enable request */ + break; } break; case CURL_WANTYES: - switch(tn->himq[option]) - { - case CURL_EMPTY: - tn->him[option] = CURL_YES; - break; - case CURL_OPPOSITE: - tn->him[option] = CURL_WANTNO; - tn->himq[option] = CURL_EMPTY; - send_negotiation(conn, CURL_DONT, option); - break; + switch(tn->usq[option]) { + case CURL_EMPTY: + /* Error: already negotiating for enable */ + break; + case CURL_OPPOSITE: + tn->usq[option] = CURL_EMPTY; + break; } break; + } } -} - -static -void rec_wont(struct connectdata *conn, int option) -{ - struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet; - switch(tn->him[option]) - { + else { /* NO */ + switch(tn->us[option]) { case CURL_NO: /* Already disabled */ break; case CURL_YES: - tn->him[option] = CURL_NO; - send_negotiation(conn, CURL_DONT, option); + tn->us[option] = CURL_WANTNO; + send_negotiation(conn, CURL_WONT, option); break; case CURL_WANTNO: - switch(tn->himq[option]) - { - case CURL_EMPTY: - tn->him[option] = CURL_NO; - break; - - case CURL_OPPOSITE: - tn->him[option] = CURL_WANTYES; - tn->himq[option] = CURL_EMPTY; - send_negotiation(conn, CURL_DO, option); - break; + switch(tn->usq[option]) { + case CURL_EMPTY: + /* Already negotiating for NO */ + break; + case CURL_OPPOSITE: + tn->usq[option] = CURL_EMPTY; + break; } break; case CURL_WANTYES: - switch(tn->himq[option]) - { - case CURL_EMPTY: - tn->him[option] = CURL_NO; - break; - case CURL_OPPOSITE: - tn->him[option] = CURL_NO; - tn->himq[option] = CURL_EMPTY; - break; + switch(tn->usq[option]) { + case CURL_EMPTY: + tn->usq[option] = CURL_OPPOSITE; + break; + case CURL_OPPOSITE: + break; } break; - } -} - -static void -set_local_option(struct connectdata *conn, int option, int newstate) -{ - struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet; - if(newstate == CURL_YES) - { - switch(tn->us[option]) - { - case CURL_NO: - tn->us[option] = CURL_WANTYES; - send_negotiation(conn, CURL_WILL, option); - break; - - case CURL_YES: - /* Already enabled */ - break; - - case CURL_WANTNO: - switch(tn->usq[option]) - { - case CURL_EMPTY: - /* Already negotiating for CURL_YES, queue the request */ - tn->usq[option] = CURL_OPPOSITE; - break; - case CURL_OPPOSITE: - /* Error: already queued an enable request */ - break; - } - break; - - case CURL_WANTYES: - switch(tn->usq[option]) - { - case CURL_EMPTY: - /* Error: already negotiating for enable */ - break; - case CURL_OPPOSITE: - tn->usq[option] = CURL_EMPTY; - break; - } - break; - } - } - else /* NO */ - { - switch(tn->us[option]) - { - case CURL_NO: - /* Already disabled */ - break; - - case CURL_YES: - tn->us[option] = CURL_WANTNO; - send_negotiation(conn, CURL_WONT, option); - break; - - case CURL_WANTNO: - switch(tn->usq[option]) - { - case CURL_EMPTY: - /* Already negotiating for NO */ - break; - case CURL_OPPOSITE: - tn->usq[option] = CURL_EMPTY; - break; - } - break; - - case CURL_WANTYES: - switch(tn->usq[option]) - { - case CURL_EMPTY: - tn->usq[option] = CURL_OPPOSITE; - break; - case CURL_OPPOSITE: - break; - } - break; } } } @@ -606,98 +602,102 @@ set_local_option(struct connectdata *conn, int option, int newstate) static void rec_do(struct connectdata *conn, int option) { - struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet; - switch(tn->us[option]) - { - case CURL_NO: - if(tn->us_preferred[option] == CURL_YES) - { - tn->us[option] = CURL_YES; - send_negotiation(conn, CURL_WILL, option); - } - else - { - send_negotiation(conn, CURL_WONT, option); - } - break; + struct TELNET *tn = (struct TELNET *)conn->data->req.protop; + switch(tn->us[option]) { + case CURL_NO: + if(tn->us_preferred[option] == CURL_YES) { + tn->us[option] = CURL_YES; + send_negotiation(conn, CURL_WILL, option); + if(tn->subnegotiation[option] == CURL_YES) + /* transmission of data option */ + sendsuboption(conn, option); + } + else if(tn->subnegotiation[option] == CURL_YES) { + /* send information to achieve this option*/ + tn->us[option] = CURL_YES; + send_negotiation(conn, CURL_WILL, option); + sendsuboption(conn, option); + } + else + send_negotiation(conn, CURL_WONT, option); + break; - case CURL_YES: - /* Already enabled */ - break; + case CURL_YES: + /* Already enabled */ + break; - case CURL_WANTNO: - switch(tn->usq[option]) - { - case CURL_EMPTY: - /* Error: DONT answered by WILL */ - tn->us[option] = CURL_NO; - break; - case CURL_OPPOSITE: - /* Error: DONT answered by WILL */ - tn->us[option] = CURL_YES; - tn->usq[option] = CURL_EMPTY; - break; + case CURL_WANTNO: + switch(tn->usq[option]) { + case CURL_EMPTY: + /* Error: DONT answered by WILL */ + tn->us[option] = CURL_NO; + break; + case CURL_OPPOSITE: + /* Error: DONT answered by WILL */ + tn->us[option] = CURL_YES; + tn->usq[option] = CURL_EMPTY; + break; + } + break; + + case CURL_WANTYES: + switch(tn->usq[option]) { + case CURL_EMPTY: + tn->us[option] = CURL_YES; + if(tn->subnegotiation[option] == CURL_YES) { + /* transmission of data option */ + sendsuboption(conn, option); } break; - - case CURL_WANTYES: - switch(tn->usq[option]) - { - case CURL_EMPTY: - tn->us[option] = CURL_YES; - break; - case CURL_OPPOSITE: - tn->us[option] = CURL_WANTNO; - tn->himq[option] = CURL_EMPTY; - send_negotiation(conn, CURL_WONT, option); - break; - } + case CURL_OPPOSITE: + tn->us[option] = CURL_WANTNO; + tn->himq[option] = CURL_EMPTY; + send_negotiation(conn, CURL_WONT, option); break; + } + break; } } static void rec_dont(struct connectdata *conn, int option) { - struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet; - switch(tn->us[option]) - { - case CURL_NO: - /* Already disabled */ - break; + struct TELNET *tn = (struct TELNET *)conn->data->req.protop; + switch(tn->us[option]) { + case CURL_NO: + /* Already disabled */ + break; - case CURL_YES: + case CURL_YES: + tn->us[option] = CURL_NO; + send_negotiation(conn, CURL_WONT, option); + break; + + case CURL_WANTNO: + switch(tn->usq[option]) { + case CURL_EMPTY: tn->us[option] = CURL_NO; - send_negotiation(conn, CURL_WONT, option); break; - case CURL_WANTNO: - switch(tn->usq[option]) - { - case CURL_EMPTY: - tn->us[option] = CURL_NO; - break; - - case CURL_OPPOSITE: - tn->us[option] = CURL_WANTYES; - tn->usq[option] = CURL_EMPTY; - send_negotiation(conn, CURL_WILL, option); - break; - } + case CURL_OPPOSITE: + tn->us[option] = CURL_WANTYES; + tn->usq[option] = CURL_EMPTY; + send_negotiation(conn, CURL_WILL, option); break; + } + break; - case CURL_WANTYES: - switch(tn->usq[option]) - { - case CURL_EMPTY: - tn->us[option] = CURL_NO; - break; - case CURL_OPPOSITE: - tn->us[option] = CURL_NO; - tn->usq[option] = CURL_EMPTY; - break; - } + case CURL_WANTYES: + switch(tn->usq[option]) { + case CURL_EMPTY: + tn->us[option] = CURL_NO; break; + case CURL_OPPOSITE: + tn->us[option] = CURL_NO; + tn->usq[option] = CURL_EMPTY; + break; + } + break; } } @@ -709,20 +709,16 @@ static void printsub(struct SessionHandle *data, { unsigned int i = 0; - if(data->set.verbose) - { - if(direction) - { + if(data->set.verbose) { + if(direction) { infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT"); - if(length >= 3) - { + if(length >= 3) { int j; i = pointer[length-2]; j = pointer[length-1]; - if(i != CURL_IAC || j != CURL_SE) - { + if(i != CURL_IAC || j != CURL_SE) { infof(data, "(terminated by "); if(CURL_TELOPT_OK(i)) infof(data, "%s ", CURL_TELOPT(i)); @@ -741,28 +737,35 @@ static void printsub(struct SessionHandle *data, } length -= 2; } - if(length < 1) - { + if(length < 1) { infof(data, "(Empty suboption?)"); return; } if(CURL_TELOPT_OK(pointer[0])) { switch(pointer[0]) { - case CURL_TELOPT_TTYPE: - case CURL_TELOPT_XDISPLOC: - case CURL_TELOPT_NEW_ENVIRON: - infof(data, "%s", CURL_TELOPT(pointer[0])); - break; - default: - infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0])); - break; + case CURL_TELOPT_TTYPE: + case CURL_TELOPT_XDISPLOC: + case CURL_TELOPT_NEW_ENVIRON: + case CURL_TELOPT_NAWS: + infof(data, "%s", CURL_TELOPT(pointer[0])); + break; + default: + infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0])); + break; } } else infof(data, "%d (unknown)", pointer[i]); - switch(pointer[1]) { + switch(pointer[0]) { + case CURL_TELOPT_NAWS: + if(length > 4) + infof(data, "Width: %hu ; Height: %hu", (pointer[1]<<8) | pointer[2], + (pointer[3]<<8) | pointer[4]); + break; + default: + switch(pointer[1]) { case CURL_TELQUAL_IS: infof(data, " IS"); break; @@ -775,9 +778,9 @@ static void printsub(struct SessionHandle *data, case CURL_TELQUAL_NAME: infof(data, " NAME"); break; - } + } - switch(pointer[0]) { + switch(pointer[0]) { case CURL_TELOPT_TTYPE: case CURL_TELOPT_XDISPLOC: pointer[length] = 0; @@ -788,48 +791,52 @@ static void printsub(struct SessionHandle *data, infof(data, " "); for(i = 3;i < length;i++) { switch(pointer[i]) { - case CURL_NEW_ENV_VAR: - infof(data, ", "); - break; - case CURL_NEW_ENV_VALUE: - infof(data, " = "); - break; - default: - infof(data, "%c", pointer[i]); - break; + case CURL_NEW_ENV_VAR: + infof(data, ", "); + break; + case CURL_NEW_ENV_VALUE: + infof(data, " = "); + break; + default: + infof(data, "%c", pointer[i]); + break; } } } break; default: - for (i = 2; i < length; i++) + for(i = 2; i < length; i++) infof(data, " %.2x", pointer[i]); break; + } } - if(direction) - { infof(data, "\n"); - } } } static CURLcode check_telnet_options(struct connectdata *conn) { struct curl_slist *head; - char option_keyword[128]; - char option_arg[256]; - char *buf; + struct curl_slist *beg; + char option_keyword[128] = ""; + char option_arg[256] = ""; struct SessionHandle *data = conn->data; - struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet; + struct TELNET *tn = (struct TELNET *)conn->data->req.protop; + CURLcode result = CURLE_OK; + int binary_option; /* Add the user name as an environment variable if it was given on the command line */ - if(conn->bits.user_passwd) - { + if(conn->bits.user_passwd) { snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user); - tn->telnet_vars = curl_slist_append(tn->telnet_vars, option_arg); - + beg = curl_slist_append(tn->telnet_vars, option_arg); + if(!beg) { + curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; + return CURLE_OUT_OF_MEMORY; + } + tn->telnet_vars = beg; tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; } @@ -855,23 +862,56 @@ static CURLcode check_telnet_options(struct connectdata *conn) /* Environment variable */ if(Curl_raw_equal(option_keyword, "NEW_ENV")) { - buf = strdup(option_arg); - if(!buf) - return CURLE_OUT_OF_MEMORY; - tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf); + beg = curl_slist_append(tn->telnet_vars, option_arg); + if(!beg) { + result = CURLE_OUT_OF_MEMORY; + break; + } + tn->telnet_vars = beg; tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; continue; } + /* Window Size */ + if(Curl_raw_equal(option_keyword, "WS")) { + if(sscanf(option_arg, "%hu%*[xX]%hu", + &tn->subopt_wsx, &tn->subopt_wsy) == 2) + tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES; + else { + failf(data, "Syntax error in telnet option: %s", head->data); + result = CURLE_TELNET_OPTION_SYNTAX; + break; + } + continue; + } + + /* To take care or not of the 8th bit in data exchange */ + if(Curl_raw_equal(option_keyword, "BINARY")) { + binary_option=atoi(option_arg); + if(binary_option!=1) { + tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO; + tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO; + } + continue; + } + failf(data, "Unknown telnet option %s", head->data); - return CURLE_UNKNOWN_TELNET_OPTION; - } else { + result = CURLE_UNKNOWN_TELNET_OPTION; + break; + } + else { failf(data, "Syntax error in telnet option: %s", head->data); - return CURLE_TELNET_OPTION_SYNTAX; + result = CURLE_TELNET_OPTION_SYNTAX; + break; } } - return CURLE_OK; + if(result) { + curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; + } + + return result; } /* @@ -889,10 +929,10 @@ static void suboption(struct connectdata *conn) size_t len; size_t tmplen; int err; - char varname[128]; - char varval[128]; + char varname[128] = ""; + char varval[128] = ""; struct SessionHandle *data = conn->data; - struct TELNET *tn = (struct TELNET *)data->state.proto.telnet; + struct TELNET *tn = (struct TELNET *)data->req.protop; printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2); switch (CURL_SB_GET(tn)) { @@ -930,11 +970,12 @@ static void suboption(struct connectdata *conn) tmplen = (strlen(v->data) + 1); /* Add the variable only if it fits */ if(len + tmplen < (int)sizeof(temp)-6) { - sscanf(v->data, "%127[^,],%127s", varname, varval); - snprintf((char *)&temp[len], sizeof(temp) - len, - "%c%s%c%s", CURL_NEW_ENV_VAR, varname, - CURL_NEW_ENV_VALUE, varval); - len += tmplen; + if(sscanf(v->data, "%127[^,],%127s", varname, varval)) { + snprintf((char *)&temp[len], sizeof(temp) - len, + "%c%s%c%s", CURL_NEW_ENV_VAR, varname, + CURL_NEW_ENV_VALUE, varval); + len += tmplen; + } } } snprintf((char *)&temp[len], sizeof(temp) - len, @@ -951,6 +992,69 @@ static void suboption(struct connectdata *conn) return; } + +/* + * sendsuboption() + * + * Send suboption information to the server side. + */ + +static void sendsuboption(struct connectdata *conn, int option) +{ + ssize_t bytes_written; + int err; + unsigned short x, y; + unsigned char*uc1, *uc2; + + struct SessionHandle *data = conn->data; + struct TELNET *tn = (struct TELNET *)data->req.protop; + + switch (option) { + case CURL_TELOPT_NAWS: + /* We prepare data to be sent */ + CURL_SB_CLEAR(tn); + CURL_SB_ACCUM(tn, CURL_IAC); + CURL_SB_ACCUM(tn, CURL_SB); + CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS); + /* We must deal either with litte or big endien processors */ + /* Window size must be sent according to the 'network order' */ + x=htons(tn->subopt_wsx); + y=htons(tn->subopt_wsy); + uc1 = (unsigned char*)&x; + uc2 = (unsigned char*)&y; + CURL_SB_ACCUM(tn, uc1[0]); + CURL_SB_ACCUM(tn, uc1[1]); + CURL_SB_ACCUM(tn, uc2[0]); + CURL_SB_ACCUM(tn, uc2[1]); + + CURL_SB_ACCUM(tn, CURL_IAC); + CURL_SB_ACCUM(tn, CURL_SE); + CURL_SB_TERM(tn); + /* data suboption is now ready */ + + printsub(data, '>', (unsigned char *)tn->subbuffer+2, + CURL_SB_LEN(tn)-2); + + /* we send the header of the suboption... */ + bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data, "Sending data failed (%d)", err); + } + /* ... then the window size with the send_telnet_data() function + to deal with 0xFF cases ... */ + send_telnet_data(conn, (char *)tn->subbuffer+3, 4); + /* ... and the footer */ + bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer+7, 2); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data, "Sending data failed (%d)", err); + } + break; + } +} + + static CURLcode telrcv(struct connectdata *conn, const unsigned char *inbuf, /* Data received from socket */ @@ -961,7 +1065,7 @@ CURLcode telrcv(struct connectdata *conn, int in = 0; int startwrite=-1; struct SessionHandle *data = conn->data; - struct TELNET *tn = (struct TELNET *)data->state.proto.telnet; + struct TELNET *tn = (struct TELNET *)data->req.protop; #define startskipping() \ if(startwrite >= 0) { \ @@ -969,7 +1073,7 @@ CURLcode telrcv(struct connectdata *conn, CLIENTWRITE_BODY, \ (char *)&inbuf[startwrite], \ in-startwrite); \ - if(result != CURLE_OK) \ + if(result) \ return result; \ } \ startwrite = -1 @@ -980,69 +1084,61 @@ CURLcode telrcv(struct connectdata *conn, #define bufferflush() startskipping() - while(count--) - { + while(count--) { c = inbuf[in]; - /*infof(data,"In rcv state %d char %d\n", tn->telrcv_state, c);*/ - switch (tn->telrcv_state) - { - case CURL_TS_CR: - tn->telrcv_state = CURL_TS_DATA; - if(c == '\0') - { - startskipping(); - break; /* Ignore \0 after CR */ - } - writebyte(); - break; + switch (tn->telrcv_state) { + case CURL_TS_CR: + tn->telrcv_state = CURL_TS_DATA; + if(c == '\0') { + startskipping(); + break; /* Ignore \0 after CR */ + } + writebyte(); + break; - case CURL_TS_DATA: - if(c == CURL_IAC) - { - tn->telrcv_state = CURL_TS_IAC; - startskipping(); - break; - } - else if(c == '\r') - { - tn->telrcv_state = CURL_TS_CR; - } - writebyte(); + case CURL_TS_DATA: + if(c == CURL_IAC) { + tn->telrcv_state = CURL_TS_IAC; + startskipping(); break; + } + else if(c == '\r') + tn->telrcv_state = CURL_TS_CR; + writebyte(); + break; - case CURL_TS_IAC: - process_iac: + case CURL_TS_IAC: + process_iac: DEBUGASSERT(startwrite < 0); - switch (c) - { - case CURL_WILL: - tn->telrcv_state = CURL_TS_WILL; - break; - case CURL_WONT: - tn->telrcv_state = CURL_TS_WONT; - break; - case CURL_DO: - tn->telrcv_state = CURL_TS_DO; - break; - case CURL_DONT: - tn->telrcv_state = CURL_TS_DONT; - break; - case CURL_SB: - CURL_SB_CLEAR(tn); - tn->telrcv_state = CURL_TS_SB; - break; - case CURL_IAC: - tn->telrcv_state = CURL_TS_DATA; - writebyte(); - break; - case CURL_DM: - case CURL_NOP: - case CURL_GA: - default: - tn->telrcv_state = CURL_TS_DATA; - printoption(data, "RCVD", CURL_IAC, c); - break; + switch (c) { + case CURL_WILL: + tn->telrcv_state = CURL_TS_WILL; + break; + case CURL_WONT: + tn->telrcv_state = CURL_TS_WONT; + break; + case CURL_DO: + tn->telrcv_state = CURL_TS_DO; + break; + case CURL_DONT: + tn->telrcv_state = CURL_TS_DONT; + break; + case CURL_SB: + CURL_SB_CLEAR(tn); + tn->telrcv_state = CURL_TS_SB; + break; + case CURL_IAC: + tn->telrcv_state = CURL_TS_DATA; + writebyte(); + break; + case CURL_DM: + case CURL_NOP: + case CURL_GA: + default: + tn->telrcv_state = CURL_TS_DATA; + printoption(data, "RCVD", CURL_IAC, c); + break; } break; @@ -1076,23 +1172,17 @@ CURLcode telrcv(struct connectdata *conn, case CURL_TS_SB: if(c == CURL_IAC) - { tn->telrcv_state = CURL_TS_SE; - } else - { - CURL_SB_ACCUM(tn,c); - } + CURL_SB_ACCUM(tn, c); break; case CURL_TS_SE: - if(c != CURL_SE) - { - if(c != CURL_IAC) - { + if(c != CURL_SE) { + if(c != CURL_IAC) { /* * This is an error. We only expect to get "IAC IAC" or "IAC SE". - * Several things may have happend. An IAC was not doubled, the + * Several things may have happened. An IAC was not doubled, the * IAC SE was left off, or another option got inserted into the * suboption are all possibilities. If we assume that the IAC was * not doubled, and really the IAC SE was left off, we could get @@ -1109,7 +1199,7 @@ CURLcode telrcv(struct connectdata *conn, tn->telrcv_state = CURL_TS_IAC; goto process_iac; } - CURL_SB_ACCUM(tn,c); + CURL_SB_ACCUM(tn, c); tn->telrcv_state = CURL_TS_SB; } else @@ -1137,9 +1227,9 @@ static CURLcode send_telnet_data(struct connectdata *conn, unsigned char outbuf[2]; ssize_t bytes_written, total_written; int out_count; - CURLcode rc = CURLE_OK; + CURLcode result = CURLE_OK; - while(rc == CURLE_OK && nread--) { + while(!result && nread--) { outbuf[0] = *buffer++; out_count = 1; if(outbuf[0] == CURL_IAC) @@ -1154,39 +1244,43 @@ static CURLcode send_telnet_data(struct connectdata *conn, switch (Curl_poll(pfd, 1, -1)) { case -1: /* error, abort writing */ case 0: /* timeout (will never happen) */ - rc = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; break; default: /* write! */ bytes_written = 0; - rc = Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf+total_written, - out_count-total_written, &bytes_written); + result = Curl_write(conn, conn->sock[FIRSTSOCKET], + outbuf+total_written, out_count-total_written, + &bytes_written); total_written += bytes_written; break; } - /* handle partial write */ - } while (rc == CURLE_OK && total_written < out_count); + /* handle partial write */ + } while(!result && total_written < out_count); } - return rc; + return result; } static CURLcode telnet_done(struct connectdata *conn, CURLcode status, bool premature) { - struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet; + struct TELNET *tn = (struct TELNET *)conn->data->req.protop; (void)status; /* unused */ (void)premature; /* not used */ - curl_slist_free_all(tn->telnet_vars); + if(!tn) + return CURLE_OK; - free(conn->data->state.proto.telnet); - conn->data->state.proto.telnet = NULL; + curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; + + Curl_safefree(conn->data->req.protop); return CURLE_OK; } static CURLcode telnet_do(struct connectdata *conn, bool *done) { - CURLcode code; + CURLcode result; struct SessionHandle *data = conn->data; curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; #ifdef USE_WINSOCK @@ -1219,65 +1313,61 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) *done = TRUE; /* unconditionally */ - code = init_telnet(conn); - if(code) - return code; + result = init_telnet(conn); + if(result) + return result; - tn = (struct TELNET *)data->state.proto.telnet; + tn = (struct TELNET *)data->req.protop; - code = check_telnet_options(conn); - if(code) - return code; + result = check_telnet_options(conn); + if(result) + return result; #ifdef USE_WINSOCK /* ** This functionality only works with WinSock >= 2.0. So, ** make sure have it. */ - code = check_wsock2(data); - if(code) - return code; + result = check_wsock2(data); + if(result) + return result; /* OK, so we have WinSock 2.0. We need to dynamically */ /* load ws2_32.dll and get the function pointers we need. */ - wsock2 = LoadLibrary("WS2_32.DLL"); + wsock2 = LoadLibrary(TEXT("WS2_32.DLL")); if(wsock2 == NULL) { - failf(data,"failed to load WS2_32.DLL (%d)", ERRNO); + failf(data, "failed to load WS2_32.DLL (%d)", ERRNO); return CURLE_FAILED_INIT; } /* Grab a pointer to WSACreateEvent */ - create_event_func = GetProcAddress(wsock2,"WSACreateEvent"); + create_event_func = GetProcAddress(wsock2, "WSACreateEvent"); if(create_event_func == NULL) { - failf(data,"failed to find WSACreateEvent function (%d)", - ERRNO); + failf(data, "failed to find WSACreateEvent function (%d)", ERRNO); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } /* And WSACloseEvent */ - close_event_func = GetProcAddress(wsock2,"WSACloseEvent"); + close_event_func = GetProcAddress(wsock2, "WSACloseEvent"); if(close_event_func == NULL) { - failf(data,"failed to find WSACloseEvent function (%d)", - ERRNO); + failf(data, "failed to find WSACloseEvent function (%d)", ERRNO); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } /* And WSAEventSelect */ - event_select_func = GetProcAddress(wsock2,"WSAEventSelect"); + event_select_func = GetProcAddress(wsock2, "WSAEventSelect"); if(event_select_func == NULL) { - failf(data,"failed to find WSAEventSelect function (%d)", - ERRNO); + failf(data, "failed to find WSAEventSelect function (%d)", ERRNO); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } /* And WSAEnumNetworkEvents */ - enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents"); + enum_netevents_func = GetProcAddress(wsock2, "WSAEnumNetworkEvents"); if(enum_netevents_func == NULL) { - failf(data,"failed to find WSAEnumNetworkEvents function (%d)", - ERRNO); + failf(data, "failed to find WSAEnumNetworkEvents function (%d)", ERRNO); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } @@ -1290,11 +1380,19 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) /* First, create a sockets event object */ event_handle = (WSAEVENT)create_event_func(); if(event_handle == WSA_INVALID_EVENT) { - failf(data,"WSACreateEvent failed (%d)", SOCKERRNO); + failf(data, "WSACreateEvent failed (%d)", SOCKERRNO); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } + /* Tell winsock what events we want to listen to */ + if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == + SOCKET_ERROR) { + close_event_func(event_handle); + FreeLibrary(wsock2); + return CURLE_OK; + } + /* The get the Windows file handle for stdin */ stdin_handle = GetStdHandle(STD_INPUT_HANDLE); @@ -1302,21 +1400,16 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) objs[0] = event_handle; objs[1] = stdin_handle; - /* Tell winsock what events we want to listen to */ - if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) { - close_event_func(event_handle); - FreeLibrary(wsock2); - return CURLE_OK; - } - /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it, else use the old WaitForMultipleObjects() way */ - if(GetFileType(stdin_handle) == FILE_TYPE_PIPE) { + if(GetFileType(stdin_handle) == FILE_TYPE_PIPE || + data->set.is_fread_set) { /* Don't wait for stdin_handle, just wait for event_handle */ obj_count = 1; /* Check stdin_handle per 100 milliseconds */ wait_timeout = 100; - } else { + } + else { obj_count = 2; wait_timeout = 1000; } @@ -1328,24 +1421,46 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) case WAIT_TIMEOUT: { for(;;) { - if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) { - keepon = FALSE; - code = CURLE_READ_ERROR; - break; + if(data->set.is_fread_set) { + /* read from user-supplied method */ + result = (int)data->state.fread_func(buf, 1, BUFSIZE - 1, + data->state.in); + if(result == CURL_READFUNC_ABORT) { + keepon = FALSE; + result = CURLE_READ_ERROR; + break; + } + + if(result == CURL_READFUNC_PAUSE) + break; + + if(result == 0) /* no bytes */ + break; + + readfile_read = result; /* fall thru with number of bytes read */ + } + else { + /* read from stdin */ + if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, + &readfile_read, NULL)) { + keepon = FALSE; + result = CURLE_READ_ERROR; + break; + } + + if(!readfile_read) + break; + + if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), + &readfile_read, NULL)) { + keepon = FALSE; + result = CURLE_READ_ERROR; + break; + } } - if(!readfile_read) - break; - - if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), - &readfile_read, NULL)) { - keepon = FALSE; - code = CURLE_READ_ERROR; - break; - } - - code = send_telnet_data(conn, buf, readfile_read); - if(code) { + result = send_telnet_data(conn, buf, readfile_read); + if(result) { keepon = FALSE; break; } @@ -1358,12 +1473,12 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), &readfile_read, NULL)) { keepon = FALSE; - code = CURLE_READ_ERROR; + result = CURLE_READ_ERROR; break; } - code = send_telnet_data(conn, buf, readfile_read); - if(code) { + result = send_telnet_data(conn, buf, readfile_read); + if(result) { keepon = FALSE; break; } @@ -1372,22 +1487,23 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) case WAIT_OBJECT_0: + events.lNetworkEvents = 0; if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) { if((err = SOCKERRNO) != EINPROGRESS) { - infof(data,"WSAEnumNetworkEvents failed (%d)", err); + infof(data, "WSAEnumNetworkEvents failed (%d)", err); keepon = FALSE; - code = CURLE_READ_ERROR; + result = CURLE_READ_ERROR; } break; } if(events.lNetworkEvents & FD_READ) { /* read data from network */ - code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread); + result = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread); /* read would've blocked. Loop again */ - if(code == CURLE_AGAIN) + if(result == CURLE_AGAIN) break; /* returned not-zero, this an error */ - else if(code) { + else if(result) { keepon = FALSE; break; } @@ -1398,8 +1514,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) break; } - code = telrcv(conn, (unsigned char *)buf, nread); - if(code) { + result = telrcv(conn, (unsigned char *) buf, nread); + if(result) { keepon = FALSE; break; } @@ -1423,15 +1539,15 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) now = Curl_tvnow(); if(Curl_tvdiff(now, conn->created) >= data->set.timeout) { failf(data, "Time-out"); - code = CURLE_OPERATION_TIMEDOUT; + result = CURLE_OPERATION_TIMEDOUT; keepon = FALSE; } } } /* We called WSACreateEvent, so call WSACloseEvent */ - if(close_event_func(event_handle) == FALSE) { - infof(data,"WSACloseEvent failed (%d)", SOCKERRNO); + if(!close_event_func(event_handle)) { + infof(data, "WSACloseEvent failed (%d)", SOCKERRNO); } /* "Forget" pointers into the library we're about to free */ @@ -1442,17 +1558,18 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) /* We called LoadLibrary, so call FreeLibrary */ if(!FreeLibrary(wsock2)) - infof(data,"FreeLibrary(wsock2) failed (%d)", ERRNO); + infof(data, "FreeLibrary(wsock2) failed (%d)", ERRNO); #else pfd[0].fd = sockfd; pfd[0].events = POLLIN; - if (data->set.is_fread_set) { + if(data->set.is_fread_set) { poll_cnt = 1; interval_ms = 100; /* poll user-supplied read function */ } else { - pfd[1].fd = 0; + /* really using fread, so infile is a FILE* */ + pfd[1].fd = fileno((FILE *)data->state.in); pfd[1].events = POLLIN; poll_cnt = 2; interval_ms = 1 * 1000; @@ -1470,12 +1587,12 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) default: /* read! */ if(pfd[0].revents & POLLIN) { /* read data from network */ - code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread); + result = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread); /* read would've blocked. Loop again */ - if(code == CURLE_AGAIN) + if(result == CURLE_AGAIN) break; /* returned not-zero, this an error */ - else if(code) { + else if(result) { keepon = FALSE; break; } @@ -1488,8 +1605,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) total_dl += nread; Curl_pgrsSetDownloadCounter(data, total_dl); - code = telrcv(conn, (unsigned char *)buf, nread); - if(code) { + result = telrcv(conn, (unsigned char *)buf, nread); + if(result) { keepon = FALSE; break; } @@ -1504,32 +1621,33 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) } nread = 0; - if (poll_cnt == 2) { - if(pfd[1].revents & POLLIN) { /* read from stdin */ - nread = read(0, buf, BUFSIZE - 1); + if(poll_cnt == 2) { + if(pfd[1].revents & POLLIN) { /* read from in file */ + nread = read(pfd[1].fd, buf, BUFSIZE - 1); } } else { /* read from user-supplied method */ - nread = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in); - if (nread == CURL_READFUNC_ABORT) { + nread = (int)data->state.fread_func(buf, 1, BUFSIZE - 1, + data->state.in); + if(nread == CURL_READFUNC_ABORT) { keepon = FALSE; break; } - if (nread == CURL_READFUNC_PAUSE) + if(nread == CURL_READFUNC_PAUSE) break; } - if (nread > 0) { - code = send_telnet_data(conn, buf, nread); - if(code) { + if(nread > 0) { + result = send_telnet_data(conn, buf, nread); + if(result) { keepon = FALSE; break; } total_ul += nread; Curl_pgrsSetUploadCounter(data, total_ul); } - else if (nread < 0) + else if(nread < 0) keepon = FALSE; break; @@ -1539,20 +1657,20 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) now = Curl_tvnow(); if(Curl_tvdiff(now, conn->created) >= data->set.timeout) { failf(data, "Time-out"); - code = CURLE_OPERATION_TIMEDOUT; + result = CURLE_OPERATION_TIMEDOUT; keepon = FALSE; } } if(Curl_pgrsUpdate(conn)) { - code = CURLE_ABORTED_BY_CALLBACK; - break; + result = CURLE_ABORTED_BY_CALLBACK; + break; } } #endif /* mark this as "no further transfer wanted" */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - return code; + return result; } #endif diff --git a/project/jni/curl/lib/telnet.h b/project/jni/curl/lib/telnet.h index f00f7fd8f..419a399b7 100644 --- a/project/jni/curl/lib/telnet.h +++ b/project/jni/curl/lib/telnet.h @@ -1,6 +1,5 @@ -#ifndef __TELNET_H -#define __TELNET_H - +#ifndef HEADER_CURL_TELNET_H +#define HEADER_CURL_TELNET_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -12,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -25,4 +24,6 @@ #ifndef CURL_DISABLE_TELNET extern const struct Curl_handler Curl_handler_telnet; #endif -#endif + +#endif /* HEADER_CURL_TELNET_H */ + diff --git a/project/jni/curl/lib/tftp.c b/project/jni/curl/lib/tftp.c index fc741c941..f44733944 100644 --- a/project/jni/curl/lib/tftp.c +++ b/project/jni/curl/lib/tftp.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,30 +20,16 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_TFTP -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#if defined(WIN32) -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif +#ifdef HAVE_NETINET_IN_H #include -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include #endif +#ifdef HAVE_NETDB_H #include +#endif #ifdef HAVE_ARPA_INET_H #include #endif @@ -58,8 +44,6 @@ #include #endif -#endif /* WIN32 */ - #include "urldata.h" #include #include "transfer.h" @@ -72,14 +56,12 @@ #include "multiif.h" #include "url.h" #include "rawstr.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -#include "curl_memory.h" +#include "speedcheck.h" +#include "curl_printf.h" #include "select.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* RFC2348 allows the block size to be negotiated */ @@ -163,10 +145,11 @@ typedef struct tftp_state_data { /* Forward declarations */ -static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) ; -static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) ; +static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event); +static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event); static CURLcode tftp_connect(struct connectdata *conn, bool *done); -static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection); +static CURLcode tftp_disconnect(struct connectdata *conn, + bool dead_connection); static CURLcode tftp_do(struct connectdata *conn, bool *done); static CURLcode tftp_done(struct connectdata *conn, CURLcode, bool premature); @@ -193,10 +176,13 @@ const struct Curl_handler Curl_handler_tftp = { tftp_doing, /* doing */ tftp_getsock, /* proto_getsock */ tftp_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ tftp_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ PORT_TFTP, /* defport */ - PROT_TFTP /* protocol */ + CURLPROTO_TFTP, /* protocol */ + PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ }; /********************************************************** @@ -213,12 +199,12 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) { time_t maxtime, timeout; long timeout_ms; - bool start = (bool)(state->state == TFTP_STATE_START); + bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE; time(&state->start_time); /* Compute drop-dead time */ - timeout_ms = Curl_timeleft(state->conn, NULL, start); + timeout_ms = Curl_timeleft(state->conn->data, NULL, start); if(timeout_ms < 0) { /* time-out, bail out, go home */ @@ -232,7 +218,7 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) state->max_time = state->start_time+maxtime; /* Set per-block timeout to total */ - timeout = maxtime ; + timeout = maxtime; /* Average restart after 5 seconds */ state->retry_max = (int)timeout/5; @@ -255,11 +241,11 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) state->max_time = state->start_time+maxtime; - /* Set per-block timeout to 10% of total */ - timeout = maxtime/10 ; + /* Set per-block timeout to total */ + timeout = maxtime; - /* Average reposting an ACK after 15 seconds */ - state->retry_max = (int)timeout/15; + /* Average reposting an ACK after 5 seconds */ + state->retry_max = (int)timeout/5; } /* But bound the total number */ if(state->retry_max<3) @@ -329,14 +315,14 @@ static const char *tftp_option_get(const char *buf, size_t len, loc = Curl_strnlen( buf, len ); loc++; /* NULL term */ - if (loc >= len) + if(loc >= len) return NULL; *option = buf; loc += Curl_strnlen( buf+loc, len-loc ); loc++; /* NULL term */ - if (loc > len) + if(loc > len) return NULL; *value = &buf[strlen(*option) + 1]; @@ -352,7 +338,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, /* if OACK doesn't contain blksize option, the default (512) must be used */ state->blksize = TFTP_BLKSIZE_DEFAULT; - while (tmp < ptr + len) { + while(tmp < ptr + len) { const char *option, *value; tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value); @@ -382,7 +368,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, TFTP_BLKSIZE_MIN); return CURLE_TFTP_ILLEGAL; } - else if (blksize > state->requested_blksize) { + else if(blksize > state->requested_blksize) { /* could realloc pkt buffers here, but the spec doesn't call out * support for the server requesting a bigger blksize than the client * requests */ @@ -403,7 +389,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, /* tsize should be ignored on upload: Who cares about the size of the remote file? */ - if (!data->set.upload) { + if(!data->set.upload) { if(!tsize) { failf(data, "invalid tsize -:%s:- value in OACK packet", value); return CURLE_TFTP_ILLEGAL; @@ -419,41 +405,41 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, static size_t tftp_option_add(tftp_state_data_t *state, size_t csize, char *buf, const char *option) { - if( ( strlen(option) + csize + 1 ) > (size_t)state->blksize ) + if(( strlen(option) + csize + 1 ) > (size_t)state->blksize) return 0; strcpy(buf, option); - return( strlen(option) + 1 ); + return strlen(option) + 1; } static CURLcode tftp_connect_for_tx(tftp_state_data_t *state, tftp_event_t event) { - CURLcode res; + CURLcode result; #ifndef CURL_DISABLE_VERBOSE_STRINGS struct SessionHandle *data = state->conn->data; infof(data, "%s\n", "Connected for transmit"); #endif state->state = TFTP_STATE_TX; - res = tftp_set_timeouts(state); - if(res != CURLE_OK) - return(res); + result = tftp_set_timeouts(state); + if(result) + return result; return tftp_tx(state, event); } static CURLcode tftp_connect_for_rx(tftp_state_data_t *state, tftp_event_t event) { - CURLcode res; + CURLcode result; #ifndef CURL_DISABLE_VERBOSE_STRINGS struct SessionHandle *data = state->conn->data; infof(data, "%s\n", "Connected for receive"); #endif state->state = TFTP_STATE_RX; - res = tftp_set_timeouts(state); - if(res != CURLE_OK) - return(res); + result = tftp_set_timeouts(state); + if(result) + return result; return tftp_rx(state, event); } @@ -465,7 +451,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) char *filename; char buf[64]; struct SessionHandle *data = state->conn->data; - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; /* Set ascii mode if -B flag was used */ if(data->set.prefer_ascii) @@ -480,7 +466,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) if(state->retries>state->retry_max) { state->error = TFTP_ERR_NORESPONSE; state->state = TFTP_STATE_FIN; - return res; + return result; } if(data->set.upload) { @@ -488,8 +474,8 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) setpacketevent(&state->spacket, TFTP_EVENT_WRQ); state->conn->data->req.upload_fromhere = (char *)state->spacket.data+4; - if(data->set.infilesize != -1) - Curl_pgrsSetUploadSize(data, data->set.infilesize); + if(data->state.infilesize != -1) + Curl_pgrsSetUploadSize(data, data->state.infilesize); } else { /* If we are downloading, send an RRQ */ @@ -508,32 +494,36 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) "%s%c%s%c", filename, '\0', mode, '\0'); sbytes = 4 + strlen(filename) + strlen(mode); - /* add tsize option */ - if(data->set.upload && (data->set.infilesize != -1)) - snprintf( buf, sizeof(buf), "%" FORMAT_OFF_T, data->set.infilesize ); - else - strcpy(buf, "0"); /* the destination is large enough */ + /* optional addition of TFTP options */ + if(!data->set.tftp_no_options) { + /* add tsize option */ + if(data->set.upload && (data->state.infilesize != -1)) + snprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T, + data->state.infilesize); + else + strcpy(buf, "0"); /* the destination is large enough */ - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, - TFTP_OPTION_TSIZE); - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, buf); - /* add blksize option */ - snprintf( buf, sizeof(buf), "%d", state->requested_blksize ); - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, - TFTP_OPTION_BLKSIZE); - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, buf ); + sbytes += tftp_option_add(state, sbytes, + (char *)state->spacket.data+sbytes, + TFTP_OPTION_TSIZE); + sbytes += tftp_option_add(state, sbytes, + (char *)state->spacket.data+sbytes, buf); + /* add blksize option */ + snprintf(buf, sizeof(buf), "%d", state->requested_blksize); + sbytes += tftp_option_add(state, sbytes, + (char *)state->spacket.data+sbytes, + TFTP_OPTION_BLKSIZE); + sbytes += tftp_option_add(state, sbytes, + (char *)state->spacket.data+sbytes, buf ); - /* add timeout option */ - snprintf( buf, sizeof(buf), "%d", state->retry_time); - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, - TFTP_OPTION_INTERVAL); - sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, buf ); + /* add timeout option */ + snprintf(buf, sizeof(buf), "%d", state->retry_time); + sbytes += tftp_option_add(state, sbytes, + (char *)state->spacket.data+sbytes, + TFTP_OPTION_INTERVAL); + sbytes += tftp_option_add(state, sbytes, + (char *)state->spacket.data+sbytes, buf ); + } /* the typecase for the 3rd argument is mostly for systems that do not have a size_t argument, like older unixes that want an 'int' */ @@ -544,24 +534,24 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) if(senddata != (ssize_t)sbytes) { failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO)); } - Curl_safefree(filename); + free(filename); break; case TFTP_EVENT_OACK: if(data->set.upload) { - res = tftp_connect_for_tx(state, event); + result = tftp_connect_for_tx(state, event); } else { - res = tftp_connect_for_rx(state, event); + result = tftp_connect_for_rx(state, event); } break; case TFTP_EVENT_ACK: /* Connected for transmit */ - res = tftp_connect_for_tx(state, event); + result = tftp_connect_for_tx(state, event); break; case TFTP_EVENT_DATA: /* Connected for receive */ - res = tftp_connect_for_rx(state, event); + result = tftp_connect_for_rx(state, event); break; case TFTP_EVENT_ERROR: @@ -572,7 +562,8 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) failf(state->conn->data, "tftp_send_first: internal error"); break; } - return res; + + return result; } /* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit @@ -597,21 +588,25 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) case TFTP_EVENT_DATA: /* Is this the block we expect? */ rblock = getrpacketblock(&state->rpacket); - if(NEXT_BLOCKNUM(state->block) != rblock) { - /* No, log it, up the retry count and fail if over the limit */ + if(NEXT_BLOCKNUM(state->block) == rblock) { + /* This is the expected block. Reset counters and ACK it. */ + state->retries = 0; + } + else if(state->block == rblock) { + /* This is the last recently received block again. Log it and ACK it + again. */ + infof(data, "Received last DATA packet block %d again.\n", rblock); + } + else { + /* totally unexpected, just log it */ infof(data, - "Received unexpected DATA packet block %d\n", rblock); - state->retries++; - if(state->retries > state->retry_max) { - failf(data, "tftp_rx: giving up waiting for block %d", - NEXT_BLOCKNUM(state->block)); - return CURLE_TFTP_ILLEGAL; - } + "Received unexpected DATA packet block %d, expecting block %d\n", + rblock, NEXT_BLOCKNUM(state->block)); break; } - /* This is the expected block. Reset counters and ACK it. */ + + /* ACK this block. */ state->block = (unsigned short)rblock; - state->retries = 0; setpacketevent(&state->spacket, TFTP_EVENT_ACK); setpacketblock(&state->spacket, state->block); sbytes = sendto(state->sockfd, (void *)state->spacket.data, @@ -624,7 +619,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) } /* Check if completed (That is, a less than full packet is received) */ - if(state->rbytes < (ssize_t)state->blksize+4){ + if(state->rbytes < (ssize_t)state->blksize+4) { state->state = TFTP_STATE_FIN; } else { @@ -708,14 +703,14 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) struct SessionHandle *data = state->conn->data; ssize_t sbytes; int rblock; - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; struct SingleRequest *k = &data->req; switch(event) { case TFTP_EVENT_ACK: case TFTP_EVENT_OACK: - if (event == TFTP_EVENT_ACK) { + if(event == TFTP_EVENT_ACK) { /* Ack the packet */ rblock = getrpacketblock(&state->rpacket); @@ -734,21 +729,22 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) if(state->retries>state->retry_max) { failf(data, "tftp_tx: giving up waiting for block %d ack", state->block); - res = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; } else { /* Re-send the data packet */ - sbytes = sendto(state->sockfd, (void *)&state->spacket.data, + sbytes = sendto(state->sockfd, (void *)state->spacket.data, 4+state->sbytes, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); /* Check all sbytes were sent */ if(sbytes<0) { failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO)); - res = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; } } - return res; + + return result; } /* This is the expected packet. Reset the counters and send the next block */ @@ -765,11 +761,13 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) state->state = TFTP_STATE_FIN; return CURLE_OK; } - res = Curl_fillreadbuffer(state->conn, state->blksize, &state->sbytes); - if(res) - return res; - sbytes = sendto(state->sockfd, (void *)state->spacket.data, - 4+state->sbytes, SEND_4TH_ARG, + + result = Curl_fillreadbuffer(state->conn, state->blksize, &state->sbytes); + if(result) + return result; + + sbytes = sendto(state->sockfd, (void *) state->spacket.data, + 4 + state->sbytes, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); /* Check all sbytes were sent */ @@ -825,7 +823,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) break; } - return res; + return result; } /********************************************************** @@ -837,48 +835,47 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) **********************************************************/ static CURLcode tftp_translate_code(tftp_error_t error) { - CURLcode code = CURLE_OK; + CURLcode result = CURLE_OK; if(error != TFTP_ERR_NONE) { switch(error) { case TFTP_ERR_NOTFOUND: - code = CURLE_TFTP_NOTFOUND; + result = CURLE_TFTP_NOTFOUND; break; case TFTP_ERR_PERM: - code = CURLE_TFTP_PERM; + result = CURLE_TFTP_PERM; break; case TFTP_ERR_DISKFULL: - code = CURLE_REMOTE_DISK_FULL; + result = CURLE_REMOTE_DISK_FULL; break; case TFTP_ERR_UNDEF: case TFTP_ERR_ILLEGAL: - code = CURLE_TFTP_ILLEGAL; + result = CURLE_TFTP_ILLEGAL; break; case TFTP_ERR_UNKNOWNID: - code = CURLE_TFTP_UNKNOWNID; + result = CURLE_TFTP_UNKNOWNID; break; case TFTP_ERR_EXISTS: - code = CURLE_REMOTE_FILE_EXISTS; + result = CURLE_REMOTE_FILE_EXISTS; break; case TFTP_ERR_NOSUCHUSER: - code = CURLE_TFTP_NOSUCHUSER; + result = CURLE_TFTP_NOSUCHUSER; break; case TFTP_ERR_TIMEOUT: - code = CURLE_OPERATION_TIMEDOUT; + result = CURLE_OPERATION_TIMEDOUT; break; case TFTP_ERR_NORESPONSE: - code = CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; break; default: - code= CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; break; } } - else { - code = CURLE_OK; - } + else + result = CURLE_OK; - return(code); + return result; } /********************************************************** @@ -891,20 +888,21 @@ static CURLcode tftp_translate_code(tftp_error_t error) static CURLcode tftp_state_machine(tftp_state_data_t *state, tftp_event_t event) { - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; struct SessionHandle *data = state->conn->data; + switch(state->state) { case TFTP_STATE_START: DEBUGF(infof(data, "TFTP_STATE_START\n")); - res = tftp_send_first(state, event); + result = tftp_send_first(state, event); break; case TFTP_STATE_RX: DEBUGF(infof(data, "TFTP_STATE_RX\n")); - res = tftp_rx(state, event); + result = tftp_rx(state, event); break; case TFTP_STATE_TX: DEBUGF(infof(data, "TFTP_STATE_TX\n")); - res = tftp_tx(state, event); + result = tftp_tx(state, event); break; case TFTP_STATE_FIN: infof(data, "%s\n", "TFTP finished"); @@ -912,10 +910,11 @@ static CURLcode tftp_state_machine(tftp_state_data_t *state, default: DEBUGF(infof(data, "STATE: %d\n", state->state)); failf(data, "%s", "Internal state machine error"); - res = CURLE_TFTP_ILLEGAL; + result = CURLE_TFTP_ILLEGAL; break; } - return res; + + return result; } /********************************************************** @@ -949,16 +948,11 @@ static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection) **********************************************************/ static CURLcode tftp_connect(struct connectdata *conn, bool *done) { - CURLcode code; tftp_state_data_t *state; int blksize, rc; blksize = TFTP_BLKSIZE_DEFAULT; - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); - state = conn->proto.tftpc = calloc(1, sizeof(tftp_state_data_t)); if(!state) return CURLE_OUT_OF_MEMORY; @@ -984,9 +978,9 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done) return CURLE_OUT_OF_MEMORY; } - conn->bits.close = TRUE; /* we don't keep TFTP connections up bascially - because there's none or very little gain for UDP - */ + /* we don't keep TFTP connections up basically because there's none or very + * little gain for UDP */ + connclose(conn, "TFTP"); state->conn = conn; state->sockfd = state->conn->sock[FIRSTSOCKET]; @@ -1027,8 +1021,8 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done) Curl_pgrsStartNow(conn->data); *done = TRUE; - code = CURLE_OK; - return(code); + + return CURLE_OK; } /********************************************************** @@ -1041,18 +1035,20 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done) static CURLcode tftp_done(struct connectdata *conn, CURLcode status, bool premature) { - CURLcode code = CURLE_OK; + CURLcode result = CURLE_OK; tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; (void)status; /* unused */ (void)premature; /* not used */ - Curl_pgrsDone(conn); + if(Curl_pgrsDone(conn)) + return CURLE_ABORTED_BY_CALLBACK; /* If we have encountered an error */ - code = tftp_translate_code(state->error); + if(state) + result = tftp_translate_code(state->error); - return code; + return result; } /********************************************************** @@ -1169,7 +1165,7 @@ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event) time_t current; tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; - if (event) + if(event) *event = TFTP_EVENT_NONE; time(¤t); @@ -1180,8 +1176,8 @@ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event) state->state = TFTP_STATE_FIN; return 0; } - else if (current > state->rx_time+state->retry_time) { - if (event) + else if(current > state->rx_time+state->retry_time) { + if(event) *event = TFTP_EVENT_TIMEOUT; time(&state->rx_time); /* update even though we received nothing */ } @@ -1192,130 +1188,6 @@ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event) return (long)(state->max_time - current); } - -/********************************************************** - * - * tftp_easy_statemach - * - * Handle easy request until completion - * - **********************************************************/ -static CURLcode tftp_easy_statemach(struct connectdata *conn) -{ - int rc; - int check_time = 0; - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; - curl_socket_t fd_read; - long timeout_ms; - struct SingleRequest *k = &data->req; - struct timeval transaction_start = Curl_tvnow(); - - k->start = transaction_start; - k->now = transaction_start; - - /* Run the TFTP State Machine */ - for(; (state->state != TFTP_STATE_FIN) && (result == CURLE_OK); ) { - - timeout_ms = state->retry_time * 1000; - - if (data->set.upload) { - if (data->set.max_send_speed && - (data->progress.ulspeed > data->set.max_send_speed)) { - fd_read = CURL_SOCKET_BAD; - timeout_ms = Curl_sleep_time(data->set.max_send_speed, - data->progress.ulspeed, state->blksize); - } - else { - fd_read = state->sockfd; - } - } - else { - if (data->set.max_recv_speed && - (data->progress.dlspeed > data->set.max_recv_speed)) { - fd_read = CURL_SOCKET_BAD; - timeout_ms = Curl_sleep_time(data->set.max_recv_speed, - data->progress.dlspeed, state->blksize); - } - else { - fd_read = state->sockfd; - } - } - - if(data->set.timeout) { - timeout_ms = data->set.timeout - Curl_tvdiff(k->now, k->start); - if (timeout_ms > state->retry_time * 1000) - timeout_ms = state->retry_time * 1000; - else if(timeout_ms < 0) - timeout_ms = 0; - } - - - /* Wait until ready to read or timeout occurs */ - rc = Curl_socket_ready(fd_read, CURL_SOCKET_BAD, (int)(timeout_ms)); - - k->now = Curl_tvnow(); - - /* Force a progress callback if it's been too long */ - if (Curl_tvdiff(k->now, k->start) >= data->set.timeout) { - if(Curl_pgrsUpdate(conn)) { - tftp_state_machine(state, TFTP_EVENT_ERROR); - return CURLE_ABORTED_BY_CALLBACK; - } - k->start = k->now; - } - - if(rc == -1) { - /* bail out */ - int error = SOCKERRNO; - failf(data, "%s", Curl_strerror(conn, error)); - state->event = TFTP_EVENT_ERROR; - } - else { - - if(rc==0) { - /* A timeout occured, but our timeout is variable, so maybe - just continue? */ - long rtms = state->retry_time * 1000; - if (Curl_tvdiff(k->now, transaction_start) > rtms) { - state->event = TFTP_EVENT_TIMEOUT; - /* Force a look at transfer timeouts */ - check_time = 1; - } - else { - continue; /* skip state machine */ - } - } - else { - result = tftp_receive_packet(conn); - if (result == CURLE_OK) - transaction_start = Curl_tvnow(); - - if(k->bytecountp) - *k->bytecountp = k->bytecount; /* read count */ - if(k->writebytecountp) - *k->writebytecountp = k->writebytecount; /* write count */ - } - } - - if(check_time) { - tftp_state_timeout(conn, NULL); - check_time = 0; - } - - if(result) - return(result); - - result = tftp_state_machine(state, state->event); - } - - /* Tell curl we're done */ - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - - return(result); -} - /********************************************************** * * tftp_multi_statemach @@ -1338,11 +1210,11 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) failf(data, "TFTP response timeout"); return CURLE_OPERATION_TIMEDOUT; } - else if (event != TFTP_EVENT_NONE) { + else if(event != TFTP_EVENT_NONE) { result = tftp_state_machine(state, event); - if(result != CURLE_OK) - return(result); - *done = (bool)(state->state == TFTP_STATE_FIN); + if(result) + return result; + *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; if(*done) /* Tell curl we're done */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); @@ -1359,12 +1231,12 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) } else if(rc != 0) { result = tftp_receive_packet(conn); - if(result != CURLE_OK) - return(result); + if(result) + return result; result = tftp_state_machine(state, state->event); - if(result != CURLE_OK) - return(result); - *done = (bool)(state->state == TFTP_STATE_FIN); + if(result) + return result; + *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; if(*done) /* Tell curl we're done */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); @@ -1390,6 +1262,15 @@ static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done) if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); } + else if(!result) { + /* The multi code doesn't have this logic for the DOING state so we + provide it for TFTP since it may do the entire transfer in this + state. */ + if(Curl_pgrsUpdate(conn)) + result = CURLE_ABORTED_BY_CALLBACK; + else + result = Curl_speedcheck(conn->data, Curl_tvnow()); + } return result; } @@ -1409,15 +1290,10 @@ static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done) result = tftp_state_machine(state, TFTP_EVENT_INIT); - if(state->state == TFTP_STATE_FIN || result != CURLE_OK) - return(result); + if((state->state == TFTP_STATE_FIN) || result) + return result; - if(conn->data->state.used_interface == Curl_if_multi) - tftp_multi_statemach(conn, dophase_done); - else { - result = tftp_easy_statemach(conn); - *dophase_done = TRUE; /* with the easy interface we are done here */ - } + tftp_multi_statemach(conn, dophase_done); if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); @@ -1438,35 +1314,30 @@ static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done) static CURLcode tftp_do(struct connectdata *conn, bool *done) { - tftp_state_data_t *state; - CURLcode code; + tftp_state_data_t *state; + CURLcode result; *done = FALSE; - /* - Since connections can be re-used between SessionHandles, this might be a - connection already existing but on a fresh SessionHandle struct so we must - make sure we have a good 'struct TFTP' to play with. For new connections, - the struct TFTP is allocated and setup in the tftp_connect() function. - */ - Curl_reset_reqproto(conn); - if(!conn->proto.tftpc) { - code = tftp_connect(conn, done); - if(code) - return code; + result = tftp_connect(conn, done); + if(result) + return result; } - state = (tftp_state_data_t *)conn->proto.tftpc; - code = tftp_perform(conn, done); + state = (tftp_state_data_t *)conn->proto.tftpc; + if(!state) + return CURLE_BAD_CALLING_ORDER; + + result = tftp_perform(conn, done); /* If tftp_perform() returned an error, use that for return code. If it was OK, see if tftp_translate_code() has an error. */ - if (code == CURLE_OK) + if(!result) /* If we have encountered an internal tftp error, translate it. */ - code = tftp_translate_code(state->error); + result = tftp_translate_code(state->error); - return code; + return result; } static CURLcode tftp_setup_connection(struct connectdata * conn) diff --git a/project/jni/curl/lib/tftp.h b/project/jni/curl/lib/tftp.h index b2d67b26b..c2325b232 100644 --- a/project/jni/curl/lib/tftp.h +++ b/project/jni/curl/lib/tftp.h @@ -1,6 +1,5 @@ -#ifndef __TFTP_H -#define __TFTP_H - +#ifndef HEADER_CURL_TFTP_H +#define HEADER_CURL_TFTP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -12,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -25,4 +24,6 @@ #ifndef CURL_DISABLE_TFTP extern const struct Curl_handler Curl_handler_tftp; #endif -#endif + +#endif /* HEADER_CURL_TFTP_H */ + diff --git a/project/jni/curl/lib/timeval.c b/project/jni/curl/lib/timeval.c index cb39308e0..629f1c8f0 100644 --- a/project/jni/curl/lib/timeval.c +++ b/project/jni/curl/lib/timeval.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -32,9 +32,17 @@ struct timeval curlx_tvnow(void) ** increases monotonically and wraps once 49.7 days have elapsed. */ struct timeval now; +#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ + (_WIN32_WINNT < _WIN32_WINNT_VISTA) DWORD milliseconds = GetTickCount(); now.tv_sec = milliseconds / 1000; now.tv_usec = (milliseconds % 1000) * 1000; +#else + ULONGLONG milliseconds = GetTickCount64(); + now.tv_sec = (long) (milliseconds / 1000); + now.tv_usec = (long) (milliseconds % 1000) * 1000; +#endif + return now; } @@ -105,12 +113,20 @@ struct timeval curlx_tvnow(void) * Make sure that the first argument is the more recent time, as otherwise * we'll get a weird negative time-diff back... * - * Returns: the time difference in number of milliseconds. + * Returns: the time difference in number of milliseconds. For large diffs it + * returns 0x7fffffff on 32bit time_t systems. */ long curlx_tvdiff(struct timeval newer, struct timeval older) { +#if SIZEOF_TIME_T < 8 + /* for 32bit time_t systems, add a precaution to avoid overflow for really + big time differences */ + time_t diff = newer.tv_sec-older.tv_sec; + if(diff >= (0x7fffffff/1000)) + return 0x7fffffff; +#endif return (newer.tv_sec-older.tv_sec)*1000+ - (newer.tv_usec-older.tv_usec)/1000; + (long)(newer.tv_usec-older.tv_usec)/1000; } /* @@ -120,8 +136,11 @@ long curlx_tvdiff(struct timeval newer, struct timeval older) */ double curlx_tvdiff_secs(struct timeval newer, struct timeval older) { - return (double)(newer.tv_sec-older.tv_sec)+ - (double)(newer.tv_usec-older.tv_usec)/1000000.0; + if(newer.tv_sec != older.tv_sec) + return (double)(newer.tv_sec-older.tv_sec)+ + (double)(newer.tv_usec-older.tv_usec)/1000000.0; + else + return (double)(newer.tv_usec-older.tv_usec)/1000000.0; } /* return the number of seconds in the given input timeval struct */ diff --git a/project/jni/curl/lib/timeval.h b/project/jni/curl/lib/timeval.h index bc79a45ad..50c31a252 100644 --- a/project/jni/curl/lib/timeval.h +++ b/project/jni/curl/lib/timeval.h @@ -1,5 +1,5 @@ -#ifndef __TIMEVAL_H -#define __TIMEVAL_H +#ifndef HEADER_CURL_TIMEVAL_H +#define HEADER_CURL_TIMEVAL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -27,7 +27,7 @@ * as well as the library. Do not mix with library internals! */ -#include "setup.h" +#include "curl_setup.h" struct timeval curlx_tvnow(void); @@ -54,4 +54,5 @@ long Curl_tvlong(struct timeval t1); #define Curl_tvdiff(x,y) curlx_tvdiff(x,y) #define Curl_tvdiff_secs(x,y) curlx_tvdiff_secs(x,y) -#endif +#endif /* HEADER_CURL_TIMEVAL_H */ + diff --git a/project/jni/curl/lib/transfer.c b/project/jni/curl/lib/transfer.c index e4e3405d3..7481e0c8a 100644 --- a/project/jni/curl/lib/transfer.c +++ b/project/jni/curl/lib/transfer.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,36 +20,15 @@ * ***************************************************************************/ -#include "setup.h" - -/* -- WIN32 approved -- */ -#include -#include -#include -#include -#include -#include +#include "curl_setup.h" #include "strtoofft.h" #include "strequal.h" #include "rawstr.h" -#ifdef WIN32 -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif #ifdef HAVE_NETDB_H #include #endif @@ -78,8 +57,6 @@ #error "We can't compile without socket() support!" #endif -#endif /* WIN32 */ - #include "urldata.h" #include #include "netrc.h" @@ -93,26 +70,17 @@ #include "http.h" #include "url.h" #include "getinfo.h" -#include "sslgen.h" -#include "http_digest.h" -#include "http_ntlm.h" -#include "http_negotiate.h" -#include "share.h" -#include "curl_memory.h" +#include "vtls/vtls.h" #include "select.h" #include "multiif.h" -#include "easyif.h" /* for Curl_convert_to_network prototype */ -#include "rtsp.h" #include "connect.h" +#include "non-ascii.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" -#define CURL_TIMEOUT_EXPECT_100 1000 /* counting ms here */ - /* * This function will call the read callback to fill our buffer with data * to upload. @@ -125,11 +93,13 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) #ifdef CURL_DOES_CONVERSIONS bool sending_http_headers = FALSE; - if((conn->protocol&(PROT_HTTP|PROT_RTSP)) && - (data->state.proto.http->sending == HTTPSEND_REQUEST)) { - /* We're sending the HTTP request headers, not the data. - Remember that so we don't re-translate them into garbage. */ - sending_http_headers = TRUE; + if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) { + const struct HTTP *http = data->req.protop; + + if(http->sending == HTTPSEND_REQUEST) + /* We're sending the HTTP request headers, not the data. + Remember that so we don't re-translate them into garbage. */ + sending_http_headers = TRUE; } #endif @@ -141,8 +111,8 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) /* this function returns a size_t, so we typecast to int to prevent warnings with picky compilers */ - nread = (int)conn->fread_func(data->req.upload_fromhere, 1, - buffersize, conn->fread_in); + nread = (int)data->state.fread_func(data->req.upload_fromhere, 1, + buffersize, data->state.in); if(nread == CURL_READFUNC_ABORT) { failf(data, "operation aborted by callback"); @@ -150,14 +120,24 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) return CURLE_ABORTED_BY_CALLBACK; } else if(nread == CURL_READFUNC_PAUSE) { - struct SingleRequest *k = &data->req; - /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */ - k->keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */ - if(data->req.upload_chunky) { - /* Back out the preallocation done above */ - data->req.upload_fromhere -= (8 + 2); + + if(conn->handler->flags & PROTOPT_NONETWORK) { + /* protocols that work without network cannot be paused. This is + actually only FILE:// just now, and it can't pause since the transfer + isn't done using the "normal" procedure. */ + failf(data, "Read callback asked for PAUSE when not supported!"); + return CURLE_READ_ERROR; + } + else { + struct SingleRequest *k = &data->req; + /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */ + k->keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */ + if(data->req.upload_chunky) { + /* Back out the preallocation done above */ + data->req.upload_fromhere -= (8 + 2); + } + *nreadp = 0; } - *nreadp = 0; return CURLE_OK; /* nothing was read */ } else if((size_t)nread > buffersize) { @@ -187,11 +167,12 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) const char *endofline_native; const char *endofline_network; int hexlen; + + if( #ifdef CURL_DO_LINEEND_CONV - if((data->set.crlf) || (data->set.prefer_ascii)) { -#else - if(data->set.crlf) { -#endif /* CURL_DO_LINEEND_CONV */ + (data->set.prefer_ascii) || +#endif + (data->set.crlf)) { /* \n will become \r\n later on */ endofline_native = "\n"; endofline_network = "\x0a"; @@ -216,7 +197,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) strlen(endofline_network)); #ifdef CURL_DOES_CONVERSIONS - CURLcode res; + CURLcode result; int length; if(data->set.prefer_ascii) { /* translate the protocol and data */ @@ -226,25 +207,25 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) /* just translate the protocol portion */ length = strlen(hexbuffer); } - res = Curl_convert_to_network(data, data->req.upload_fromhere, length); + result = Curl_convert_to_network(data, data->req.upload_fromhere, length); /* Curl_convert_to_network calls failf if unsuccessful */ - if(res) - return(res); + if(result) + return result; #endif /* CURL_DOES_CONVERSIONS */ if((nread - hexlen) == 0) - /* mark this as done once this chunk is transfered */ + /* mark this as done once this chunk is transferred */ data->req.upload_done = TRUE; nread+=(int)strlen(endofline_native); /* for the added end of line */ } #ifdef CURL_DOES_CONVERSIONS else if((data->set.prefer_ascii) && (!sending_http_headers)) { - CURLcode res; - res = Curl_convert_to_network(data, data->req.upload_fromhere, nread); + CURLcode result; + result = Curl_convert_to_network(data, data->req.upload_fromhere, nread); /* Curl_convert_to_network calls failf if unsuccessful */ - if(res != CURLE_OK) - return(res); + if(result) + return result; } #endif /* CURL_DOES_CONVERSIONS */ @@ -303,9 +284,9 @@ CURLcode Curl_readrewind(struct connectdata *conn) else { /* If no CURLOPT_READFUNCTION is used, we know that we operate on a given FILE * stream and we can actually attempt to rewind that - ourself with fseek() */ - if(data->set.fread_func == (curl_read_callback)fread) { - if(-1 != fseek(data->set.in, 0, SEEK_SET)) + ourselves with fseek() */ + if(data->state.fread_func == (curl_read_callback)fread) { + if(-1 != fseek(data->state.in, 0, SEEK_SET)) /* successful rewind */ return CURLE_OK; } @@ -322,8 +303,20 @@ static int data_pending(const struct connectdata *conn) { /* in the case of libssh2, we can never be really sure that we have emptied its internal buffers so we MUST always try until we get EAGAIN back */ - return conn->protocol&(PROT_SCP|PROT_SFTP) || + return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) || +#if defined(USE_NGHTTP2) + Curl_ssl_data_pending(conn, FIRSTSOCKET) || + /* For HTTP/2, we may read up everything including responde body + with header fields in Curl_http_readwrite_headers. If no + content-length is provided, curl waits for the connection + close, which we emulate it using conn->proto.httpc.closed = + TRUE. The thing is if we read everything, then http2_recv won't + be called and we cannot signal the HTTP/2 stream has closed. As + a workaround, we return nonzero here to call http2_recv. */ + ((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion == 20); +#else Curl_ssl_data_pending(conn, FIRSTSOCKET); +#endif } static void read_rewind(struct connectdata *conn, @@ -349,12 +342,43 @@ static void read_rewind(struct connectdata *conn, } DEBUGF(infof(conn->data, - "Buffer after stream rewind (read_pos = %zu): [%s]", + "Buffer after stream rewind (read_pos = %zu): [%s]\n", conn->read_pos, buf)); } #endif } +/* + * Check to see if CURLOPT_TIMECONDITION was met by comparing the time of the + * remote document with the time provided by CURLOPT_TIMEVAL + */ +bool Curl_meets_timecondition(struct SessionHandle *data, time_t timeofdoc) +{ + if((timeofdoc == 0) || (data->set.timevalue == 0)) + return TRUE; + + switch(data->set.timecondition) { + case CURL_TIMECOND_IFMODSINCE: + default: + if(timeofdoc <= data->set.timevalue) { + infof(data, + "The requested document is not new enough\n"); + data->info.timecond = TRUE; + return FALSE; + } + break; + case CURL_TIMECOND_IFUNMODSINCE: + if(timeofdoc >= data->set.timevalue) { + infof(data, + "The requested document is not old enough\n"); + data->info.timecond = TRUE; + return FALSE; + } + break; + } + + return TRUE; +} /* * Go ahead and do a read if we have a readable socket or if @@ -370,9 +394,8 @@ static CURLcode readwrite_data(struct SessionHandle *data, ssize_t nread; /* number of bytes read */ size_t excess = 0; /* excess bytes read */ bool is_empty_data = FALSE; -#ifndef CURL_DISABLE_RTSP bool readmore = FALSE; /* used by RTP to signal for more data */ -#endif + int maxloops = 100; *done = FALSE; @@ -383,7 +406,18 @@ static CURLcode readwrite_data(struct SessionHandle *data, data->set.buffer_size : BUFSIZE; size_t bytestoread = buffersize; - if(k->size != -1 && !k->header) { + if( +#if defined(USE_NGHTTP2) + /* For HTTP/2, read data without caring about the content + length. This is safe because body in HTTP/2 is always + segmented thanks to its framing layer. Meanwhile, we have to + call Curl_read to ensure that http2_handle_stream_close is + called when we read all incoming bytes for a particular + stream. */ + !((conn->handler->protocol & PROTO_FAMILY_HTTP) && + conn->httpversion == 20) && +#endif + k->size != -1 && !k->header) { /* make sure we don't read "too much" if we can help it since we might be pipelining and then someone else might want to read what follows! */ @@ -406,6 +440,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, else { /* read nothing but since we wanted nothing we consider this an OK situation to proceed from */ + DEBUGF(infof(data, "readwrite_data: we're done!\n")); nread = 0; } @@ -418,7 +453,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, *didwhat |= KEEP_RECV; /* indicates data of zero size, i.e. empty file */ - is_empty_data = (bool)((nread == 0) && (k->bodywrites == 0)); + is_empty_data = ((nread == 0) && (k->bodywrites == 0)) ? TRUE : FALSE; /* NUL terminate, allowing string ops to be used */ if(0 < nread || is_empty_data) { @@ -436,16 +471,13 @@ static CURLcode readwrite_data(struct SessionHandle *data, in the flow below before the actual storing is done. */ k->str = k->buf; -#ifndef CURL_DISABLE_RTSP - /* Check for RTP at the beginning of the data */ - if(conn->protocol & PROT_RTSP) { - result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore); + if(conn->handler->readwrite) { + result = conn->handler->readwrite(data, conn, &nread, &readmore); if(result) return result; if(readmore) break; } -#endif #ifndef CURL_DISABLE_HTTP /* Since this is a two-state thing, we check if we are parsing @@ -457,20 +489,37 @@ static CURLcode readwrite_data(struct SessionHandle *data, if(result) return result; -#ifndef CURL_DISABLE_RTSP - /* Check for RTP after the headers if there is no Content */ - if(k->maxdownload <= 0 && nread > 0 && (conn->protocol & PROT_RTSP)) { - result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore); + if(conn->handler->readwrite && + (k->maxdownload <= 0 && nread > 0)) { + result = conn->handler->readwrite(data, conn, &nread, &readmore); if(result) return result; if(readmore) break; } -#endif - if(stop_reading) + if(stop_reading) { /* We've stopped dealing with input, get out of the do-while loop */ + + if(nread > 0) { + if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) { + infof(data, + "Rewinding stream by : %zd" + " bytes on url %s (zero-length body)\n", + nread, data->state.path); + read_rewind(conn, (size_t)nread); + } + else { + infof(data, + "Excess found in a non pipelined read:" + " excess = %zd" + " url = %s (zero-length body)\n", + nread, data->state.path); + } + } + break; + } } #endif /* CURL_DISABLE_HTTP */ @@ -480,12 +529,11 @@ static CURLcode readwrite_data(struct SessionHandle *data, is non-headers. */ if(k->str && !k->header && (nread > 0 || is_empty_data)) { - #ifndef CURL_DISABLE_HTTP if(0 == k->bodywrites && !is_empty_data) { /* These checks are only made the first time we are about to write a piece of the body */ - if(conn->protocol&(PROT_HTTP|PROT_RTSP)) { + if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) { /* HTTP-only checks */ if(data->req.newurl) { @@ -505,6 +553,18 @@ static CURLcode readwrite_data(struct SessionHandle *data, if(data->state.resume_from && !k->content_range && (data->set.httpreq==HTTPREQ_GET) && !k->ignorebody) { + + if(k->size == data->state.resume_from) { + /* The resume point is at the end of file, consider this fine + even if it doesn't allow resume from here. */ + infof(data, "The entire document is already downloaded"); + connclose(conn, "already downloaded"); + /* Abort download */ + k->keepon &= ~KEEP_RECV; + *done = TRUE; + return CURLE_OK; + } + /* we wanted to resume a download, although the server doesn't * seem to support this and we did this with a GET (if it * wasn't a GET we did a POST or PUT resume) */ @@ -518,34 +578,24 @@ static CURLcode readwrite_data(struct SessionHandle *data, requested. This seems to be what chapter 13.3.4 of RFC 2616 defines to be the correct action for a HTTP/1.1 client */ - if((k->timeofdoc > 0) && (data->set.timevalue > 0)) { - switch(data->set.timecondition) { - case CURL_TIMECOND_IFMODSINCE: - default: - if(k->timeofdoc < data->set.timevalue) { - infof(data, - "The requested document is not new enough\n"); - *done = TRUE; - data->info.timecond = TRUE; - return CURLE_OK; - } - break; - case CURL_TIMECOND_IFUNMODSINCE: - if(k->timeofdoc > data->set.timevalue) { - infof(data, - "The requested document is not old enough\n"); - *done = TRUE; - data->info.timecond = TRUE; - return CURLE_OK; - } - break; - } /* switch */ - } /* two valid time strings */ + + if(!Curl_meets_timecondition(data, k->timeofdoc)) { + *done = TRUE; + /* We're simulating a http 304 from server so we return + what should have been returned from the server */ + data->info.httpcode = 304; + infof(data, "Simulate a HTTP 304 response!\n"); + /* we abort the transfer before it is completed == we ruin the + re-use ability. Close the connection */ + connclose(conn, "Simulated 304 handling"); + return CURLE_OK; + } } /* we have a time condition */ - } /* this is HTTP */ + } /* this is HTTP or RTSP */ } /* this is the first time we write a body part */ #endif /* CURL_DISABLE_HTTP */ + k->bodywrites++; /* pass data to the debug function before it gets "dechunked" */ @@ -579,7 +629,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, failf(data, "Failed writing data"); return CURLE_WRITE_ERROR; } - failf(data, "Received problem %d in the chunky parser", (int)res); + failf(data, "%s in chunked-encoding", Curl_chunked_strerror(res)); return CURLE_RECV_ERROR; } else if(CHUNKE_STOP == res) { @@ -595,8 +645,9 @@ static CURLcode readwrite_data(struct SessionHandle *data, dataleft = conn->chunk.dataleft; if(dataleft != 0) { - infof(conn->data, "Leftovers after chunking: %zu bytes", dataleft); - if(conn->data->multi && Curl_multi_canPipeline(conn->data->multi)) { + infof(conn->data, "Leftovers after chunking: %zu bytes\n", + dataleft); + if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) { /* only attempt the rewind if we truly are pipelining */ infof(conn->data, "Rewinding %zu bytes\n",dataleft); read_rewind(conn, dataleft); @@ -619,14 +670,14 @@ static CURLcode readwrite_data(struct SessionHandle *data, excess = (size_t)(k->bytecount + nread - k->maxdownload); if(excess > 0 && !k->ignorebody) { - if(conn->data->multi && Curl_multi_canPipeline(conn->data->multi)) { + if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) { /* The 'excess' amount below can't be more than BUFSIZE which always will fit in a size_t */ infof(data, "Rewinding stream by : %zu" - " bytes on url %s (size = %" FORMAT_OFF_T - ", maxdownload = %" FORMAT_OFF_T - ", bytecount = %" FORMAT_OFF_T ", nread = %zd)\n", + " bytes on url %s (size = %" CURL_FORMAT_CURL_OFF_T + ", maxdownload = %" CURL_FORMAT_CURL_OFF_T + ", bytecount = %" CURL_FORMAT_CURL_OFF_T ", nread = %zd)\n", excess, data->state.path, k->size, k->maxdownload, k->bytecount, nread); read_rewind(conn, excess); @@ -635,9 +686,9 @@ static CURLcode readwrite_data(struct SessionHandle *data, infof(data, "Excess found in a non pipelined read:" " excess = %zu" - ", size = %" FORMAT_OFF_T - ", maxdownload = %" FORMAT_OFF_T - ", bytecount = %" FORMAT_OFF_T "\n", + ", size = %" CURL_FORMAT_CURL_OFF_T + ", maxdownload = %" CURL_FORMAT_CURL_OFF_T + ", bytecount = %" CURL_FORMAT_CURL_OFF_T "\n", excess, k->size, k->maxdownload, k->bytecount); } } @@ -663,12 +714,12 @@ static CURLcode readwrite_data(struct SessionHandle *data, /* Don't let excess data pollute body writes */ if(k->maxdownload == -1 || (curl_off_t)k->hbuflen <= k->maxdownload) result = Curl_client_write(conn, CLIENTWRITE_BODY, - data->state.headerbuff, - k->hbuflen); + data->state.headerbuff, + k->hbuflen); else result = Curl_client_write(conn, CLIENTWRITE_BODY, - data->state.headerbuff, - (size_t)k->maxdownload); + data->state.headerbuff, + (size_t)k->maxdownload); if(result) return result; @@ -681,22 +732,22 @@ static CURLcode readwrite_data(struct SessionHandle *data, encodings handled here. */ #ifdef HAVE_LIBZ switch (conn->data->set.http_ce_skip ? - IDENTITY : k->content_encoding) { + IDENTITY : k->auto_decoding) { case IDENTITY: #endif /* This is the default when the server sends no Content-Encoding header. See Curl_readwrite_init; the - memset() call initializes k->content_encoding to zero. */ + memset() call initializes k->auto_decoding to zero. */ if(!k->ignorebody) { #ifndef CURL_DISABLE_POP3 - if(conn->protocol&PROT_POP3) + if(conn->handler->protocol&PROTO_FAMILY_POP3) result = Curl_pop3_write(conn, k->str, nread); else #endif /* CURL_DISABLE_POP3 */ - result = Curl_client_write(conn, CLIENTWRITE_BODY, k->str, - nread); + result = Curl_client_write(conn, CLIENTWRITE_BODY, k->str, + nread); } #ifdef HAVE_LIBZ break; @@ -713,7 +764,6 @@ static CURLcode readwrite_data(struct SessionHandle *data, result = Curl_unencode_gzip_write(conn, k, nread); break; - case COMPRESS: default: failf (data, "Unrecognized content encoding type. " "libcurl understands `identity', `deflate' and `gzip' " @@ -731,24 +781,20 @@ static CURLcode readwrite_data(struct SessionHandle *data, } /* if(! header and data to read ) */ -#ifndef CURL_DISABLE_RTSP - if(excess > 0 && !conn->bits.stream_was_rewound && - (conn->protocol & PROT_RTSP)) { - /* Check for RTP after the content if there is unrewound excess */ - + if(conn->handler->readwrite && + (excess > 0 && !conn->bits.stream_was_rewound)) { /* Parse the excess data */ k->str += nread; nread = (ssize_t)excess; - result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore); + result = conn->handler->readwrite(data, conn, &nread, &readmore); if(result) return result; if(readmore) k->keepon |= KEEP_RECV; /* we're not done reading */ - break; + break; } -#endif if(is_empty_data) { /* if we received nothing, the server closed the connection and we @@ -756,7 +802,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, k->keepon &= ~KEEP_RECV; } - } while(data_pending(conn)); + } while(data_pending(conn) && maxloops--); if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) && conn->bits.close ) { @@ -789,10 +835,6 @@ static CURLcode readwrite_upload(struct SessionHandle *data, *didwhat |= KEEP_SEND; - /* - * We loop here to do the READ and SEND loop until we run out of - * data to send or until we get EWOULDBLOCK back - */ do { /* only read more data if there's no upload data already @@ -805,9 +847,10 @@ static CURLcode readwrite_upload(struct SessionHandle *data, /* HTTP pollution, this should be written nicer to become more protocol agnostic. */ int fillcount; + struct HTTP *http = data->req.protop; if((k->exp100 == EXP100_SENDING_REQUEST) && - (data->state.proto.http->sending == HTTPSEND_BODY)) { + (http->sending == HTTPSEND_BODY)) { /* If this call is to send body data, we must take some action: We have sent off the full HTTP 1.1 request, and we shall now go into the Expect: 100 state and await such a header */ @@ -817,12 +860,12 @@ static CURLcode readwrite_upload(struct SessionHandle *data, *didwhat &= ~KEEP_SEND; /* we didn't write anything actually */ /* set a timeout for the multi interface */ - Curl_expire(data, CURL_TIMEOUT_EXPECT_100); + Curl_expire(data, data->set.expect_100_timeout); break; } - if(conn->protocol&(PROT_HTTP|PROT_RTSP)) { - if(data->state.proto.http->sending == HTTPSEND_REQUEST) + if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) { + if(http->sending == HTTPSEND_REQUEST) /* We're sending the HTTP request headers, not the data. Remember that so we don't change the line endings. */ sending_http_headers = TRUE; @@ -858,29 +901,23 @@ static CURLcode readwrite_upload(struct SessionHandle *data, /* store number of bytes available for upload */ data->req.upload_present = nread; -#ifndef CURL_DISABLE_SMTP - if(conn->protocol & PROT_SMTP) { - result = Curl_smtp_escape_eob(conn, nread); - if(result) - return result; - } - else -#endif /* CURL_DISABLE_SMTP */ - /* convert LF to CRLF if so asked */ - if((!sending_http_headers) && + if((!sending_http_headers) && ( #ifdef CURL_DO_LINEEND_CONV - /* always convert if we're FTPing in ASCII mode */ - ((data->set.crlf) || (data->set.prefer_ascii))) { -#else - (data->set.crlf)) { + /* always convert if we're FTPing in ASCII mode */ + (data->set.prefer_ascii) || #endif - if(data->state.scratch == NULL) - data->state.scratch = malloc(2*BUFSIZE); - if(data->state.scratch == NULL) { - failf (data, "Failed to alloc scratch buffer!"); - return CURLE_OUT_OF_MEMORY; + (data->set.crlf))) { + /* Do we need to allocate a scratch buffer? */ + if(!data->state.scratch) { + data->state.scratch = malloc(2 * BUFSIZE); + if(!data->state.scratch) { + failf(data, "Failed to alloc scratch buffer!"); + + return CURLE_OUT_OF_MEMORY; + } } + /* * ASCII/EBCDIC Note: This is presumably a text (not binary) * transfer so the data should already be in ASCII. @@ -894,12 +931,14 @@ static CURLcode readwrite_upload(struct SessionHandle *data, if(!data->set.crlf) { /* we're here only because FTP is in ASCII mode... bump infilesize for the LF we just added */ - data->set.infilesize++; + if(data->state.infilesize != -1) + data->state.infilesize++; } } else data->state.scratch[si] = data->req.upload_fromhere[i]; } + if(si != nread) { /* only perform the special operation if we really did replace anything */ @@ -912,6 +951,14 @@ static CURLcode readwrite_upload(struct SessionHandle *data, data->req.upload_present = nread; } } + +#ifndef CURL_DISABLE_SMTP + if(conn->handler->protocol & PROTO_FAMILY_SMTP) { + result = Curl_smtp_escape_eob(conn, nread); + if(result) + return result; + } +#endif /* CURL_DISABLE_SMTP */ } /* if 0 == data->req.upload_present */ else { /* We have a partial buffer left from a previous "round". Use @@ -933,6 +980,14 @@ static CURLcode readwrite_upload(struct SessionHandle *data, Curl_debug(data, CURLINFO_DATA_OUT, data->req.upload_fromhere, (size_t)bytes_written, conn); + k->writebytecount += bytes_written; + + if(k->writebytecount == data->state.infilesize) { + /* we have sent all data we were supposed to */ + k->upload_done = TRUE; + infof(data, "We are completely uploaded and fine\n"); + } + if(data->req.upload_present != bytes_written) { /* we only wrote a part of the buffer (if anything), deal with it! */ @@ -954,10 +1009,9 @@ static CURLcode readwrite_upload(struct SessionHandle *data, } } - k->writebytecount += bytes_written; Curl_pgrsSetUploadCounter(data, k->writebytecount); - } while(0); /* just to break out from! */ + } WHILE_FALSE; /* just to break out from! */ return CURLE_OK; } @@ -967,9 +1021,9 @@ static CURLcode readwrite_upload(struct SessionHandle *data, * be read and written to/from the connection. */ CURLcode Curl_readwrite(struct connectdata *conn, + struct SessionHandle *data, bool *done) { - struct SessionHandle *data = conn->data; struct SingleRequest *k = &data->req; CURLcode result; int didwhat=0; @@ -993,6 +1047,11 @@ CURLcode Curl_readwrite(struct connectdata *conn, else fd_write = CURL_SOCKET_BAD; + if(conn->data->state.drain) { + select_res |= CURL_CSELECT_IN; + DEBUGF(infof(data, "Curl_readwrite: forcibly told to drain data\n")); + } + if(!select_res) /* Call for select()/poll() only, if read/write/error status is not known. */ select_res = Curl_socket_ready(fd_read, fd_write, 0); @@ -1047,7 +1106,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, */ long ms = Curl_tvdiff(k->now, k->start100); - if(ms > CURL_TIMEOUT_EXPECT_100) { + if(ms >= data->set.expect_100_timeout) { /* we've waited long enough, continue anyway */ k->exp100 = EXP100_SEND_DATA; k->keepon |= KEEP_SEND; @@ -1064,16 +1123,17 @@ CURLcode Curl_readwrite(struct connectdata *conn, return result; if(k->keepon) { - if(0 > Curl_timeleft(conn, &k->now, FALSE)) { + if(0 > Curl_timeleft(data, &k->now, FALSE)) { if(k->size != -1) { failf(data, "Operation timed out after %ld milliseconds with %" - FORMAT_OFF_T " out of %" FORMAT_OFF_T " bytes received", + CURL_FORMAT_CURL_OFF_T " out of %" + CURL_FORMAT_CURL_OFF_T " bytes received", Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount, k->size); } else { failf(data, "Operation timed out after %ld milliseconds with %" - FORMAT_OFF_T " bytes received", + CURL_FORMAT_CURL_OFF_T " bytes received", Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount); } return CURLE_OPERATION_TIMEDOUT; @@ -1095,7 +1155,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, (k->bytecount != (k->size + data->state.crlf_conversions)) && #endif /* CURL_DO_LINEEND_CONV */ !data->req.newurl) { - failf(data, "transfer closed with %" FORMAT_OFF_T + failf(data, "transfer closed with %" CURL_FORMAT_CURL_OFF_T " bytes remaining to read", k->size - k->bytecount); return CURLE_PARTIAL_FILE; @@ -1105,7 +1165,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, (conn->chunk.state != CHUNK_STOP)) { /* * In chunked mode, return an error if the connection is closed prior to - * the empty (terminiating) chunk is read. + * the empty (terminating) chunk is read. * * The condition above used to check for * conn->proto.http->chunk.datasize != 0 which is true after reading @@ -1120,8 +1180,8 @@ CURLcode Curl_readwrite(struct connectdata *conn, } /* Now update the "done" boolean we return */ - *done = (bool)(0 == (k->keepon&(KEEP_RECV|KEEP_SEND| - KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))); + *done = (0 == (k->keepon&(KEEP_RECV|KEEP_SEND| + KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))) ? TRUE : FALSE; return CURLE_OK; } @@ -1162,10 +1222,10 @@ int Curl_single_getsock(const struct connectdata *conn, if((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) { if((conn->sockfd != conn->writesockfd) || - !(data->req.keepon & KEEP_RECV)) { - /* only if they are not the same socket or we didn't have a readable + bitmap == GETSOCK_BLANK) { + /* only if they are not the same socket and we have a readable one, we increase index */ - if(data->req.keepon & KEEP_RECV) + if(bitmap != GETSOCK_BLANK) sockindex++; /* increase index if we need two entries */ DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD); @@ -1182,11 +1242,11 @@ int Curl_single_getsock(const struct connectdata *conn, /* * Determine optimum sleep time based on configured rate, current rate, * and packet size. - * Returns value in mili-seconds. + * Returns value in milliseconds. * * The basic idea is to adjust the desired rate up/down in this method * based on whether we are running too slow or too fast. Then, calculate - * how many miliseconds to wait for the next packet to achieve this new + * how many milliseconds to wait for the next packet to achieve this new * rate. */ long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, @@ -1195,33 +1255,33 @@ long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, curl_off_t min_sleep = 0; curl_off_t rv = 0; - if (rate_bps == 0) + if(rate_bps == 0) return 0; /* If running faster than about .1% of the desired speed, slow * us down a bit. Use shift instead of division as the 0.1% * cutoff is arbitrary anyway. */ - if (cur_rate_bps > (rate_bps + (rate_bps >> 10))) { + if(cur_rate_bps > (rate_bps + (rate_bps >> 10))) { /* running too fast, decrease target rate by 1/64th of rate */ rate_bps -= rate_bps >> 6; min_sleep = 1; } - else if (cur_rate_bps < (rate_bps - (rate_bps >> 10))) { + else if(cur_rate_bps < (rate_bps - (rate_bps >> 10))) { /* running too slow, increase target rate by 1/64th of rate */ rate_bps += rate_bps >> 6; } - /* Determine number of miliseconds to wait until we do + /* Determine number of milliseconds to wait until we do * the next packet at the adjusted rate. We should wait * longer when using larger packets, for instance. */ - rv = ((curl_off_t)((pkt_size * 8) * 1000) / rate_bps); + rv = ((curl_off_t)(pkt_size * 1000) / rate_bps); /* Catch rounding errors and always slow down at least 1ms if * we are running too fast. */ - if (rv < min_sleep) + if(rv < min_sleep) rv = min_sleep; /* Bound value to fit in 'long' on 32-bit platform. That's @@ -1233,201 +1293,22 @@ long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, return (long)rv; } - -/* - * Transfer() - * - * This function is what performs the actual transfer. It is capable of doing - * both ways simultaneously. The transfer must already have been setup by a - * call to Curl_setup_transfer(). - * - * Note that headers are created in a preallocated buffer of a default size. - * That buffer can be enlarged on demand, but it is never shrunken again. - * - */ - -static CURLcode -Transfer(struct connectdata *conn) +/* Curl_init_CONNECT() gets called each time the handle switches to CONNECT + which means this gets called once for each subsequent redirect etc */ +void Curl_init_CONNECT(struct SessionHandle *data) { - CURLcode result; - struct SessionHandle *data = conn->data; - struct SingleRequest *k = &data->req; - bool done=FALSE; - bool first=TRUE; - int timeout_ms; - int buffersize; - int totmp; - - if((conn->sockfd == CURL_SOCKET_BAD) && - (conn->writesockfd == CURL_SOCKET_BAD)) - /* nothing to read, nothing to write, we're already OK! */ - return CURLE_OK; - - /* we want header and/or body, if neither then don't do this! */ - if(!k->getheader && data->set.opt_no_body) - return CURLE_OK; - - while(!done) { - curl_socket_t fd_read = conn->sockfd; - curl_socket_t fd_write = conn->writesockfd; - int keepon = k->keepon; - timeout_ms = 1000; - - if(conn->waitfor) { - /* if waitfor is set, get the RECV and SEND bits from that but keep the - other bits */ - keepon &= ~ (KEEP_RECV|KEEP_SEND); - keepon |= conn->waitfor & (KEEP_RECV|KEEP_SEND); - } - - /* limit-rate logic: if speed exceeds threshold, then do not include fd in - select set. The current speed is recalculated in each Curl_readwrite() - call */ - if((keepon & KEEP_SEND) && - (!data->set.max_send_speed || - (data->progress.ulspeed < data->set.max_send_speed) )) { - k->keepon &= ~KEEP_SEND_HOLD; - } - else { - if (data->set.upload && data->set.max_send_speed && - (data->progress.ulspeed > data->set.max_send_speed) ) { - /* calculate upload rate-limitation timeout. */ - buffersize = (int)(data->set.buffer_size ? - data->set.buffer_size : BUFSIZE); - totmp = (int)Curl_sleep_time(data->set.max_send_speed, - data->progress.ulspeed, buffersize); - if (totmp < timeout_ms) - timeout_ms = totmp; - } - fd_write = CURL_SOCKET_BAD; - if(keepon & KEEP_SEND) - k->keepon |= KEEP_SEND_HOLD; /* hold it */ - } - - if((keepon & KEEP_RECV) && - (!data->set.max_recv_speed || - (data->progress.dlspeed < data->set.max_recv_speed)) ) { - k->keepon &= ~KEEP_RECV_HOLD; - } - else { - if ((!data->set.upload) && data->set.max_recv_speed && - (data->progress.dlspeed > data->set.max_recv_speed)) { - /* Calculate download rate-limitation timeout. */ - buffersize = (int)(data->set.buffer_size ? - data->set.buffer_size : BUFSIZE); - totmp = (int)Curl_sleep_time(data->set.max_recv_speed, - data->progress.dlspeed, buffersize); - if (totmp < timeout_ms) - timeout_ms = totmp; - } - fd_read = CURL_SOCKET_BAD; - if(keepon & KEEP_RECV) - k->keepon |= KEEP_RECV_HOLD; /* hold it */ - } - - /* pause logic. Don't check descriptors for paused connections */ - if(k->keepon & KEEP_RECV_PAUSE) - fd_read = CURL_SOCKET_BAD; - if(k->keepon & KEEP_SEND_PAUSE) - fd_write = CURL_SOCKET_BAD; - - /* The *_HOLD and *_PAUSE logic is necessary since even though there might - be no traffic during the select interval, we still call - Curl_readwrite() for the timeout case and if we limit transfer speed we - must make sure that this function doesn't transfer anything while in - HOLD status. - - The no timeout for the first round is for the protocols for which data - has already been slurped off the socket and thus waiting for action - won't work since it'll wait even though there is already data present - to work with. */ - if(first && - ((fd_read != CURL_SOCKET_BAD) || (fd_write != CURL_SOCKET_BAD))) - /* if this is the first lap and one of the file descriptors is fine - to work with, skip the timeout */ - timeout_ms = 0; - else { - totmp = Curl_timeleft(conn, &k->now, FALSE); - if(totmp < 0) - return CURLE_OPERATION_TIMEDOUT; - else if(!totmp) - totmp = 1000; - - if (totmp < timeout_ms) - timeout_ms = totmp; - } - - switch (Curl_socket_ready(fd_read, fd_write, timeout_ms)) { - case -1: /* select() error, stop reading */ -#ifdef EINTR - /* The EINTR is not serious, and it seems you might get this more - often when using the lib in a multi-threaded environment! */ - if(SOCKERRNO == EINTR) - continue; -#endif - return CURLE_RECV_ERROR; /* indicate a network problem */ - case 0: /* timeout */ - default: /* readable descriptors */ - - result = Curl_readwrite(conn, &done); - /* "done" signals to us if the transfer(s) are ready */ - break; - } - if(result) - return result; - - first = FALSE; /* not the first lap anymore */ - } - - return CURLE_OK; + data->state.fread_func = data->set.fread_func_set; + data->state.in = data->set.in_set; } -static void loadhostpairs(struct SessionHandle *data) -{ - struct curl_slist *hostp; - char hostname[256]; - char address[256]; - int port; - - for(hostp = data->change.resolve; hostp; hostp = hostp->next ) { - if(!hostp->data) - continue; - if(hostp->data[0] == '-') { - /* mark an entry for removal */ - } - else if(3 == sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port, - address)) { - struct Curl_dns_entry *dns; - Curl_addrinfo *addr; - - addr = Curl_str2addr(address, port); - if(!addr) { - infof(data, "Resolve %s found illegal!\n", hostp->data); - continue; - } - infof(data, "Added %s:%d:%s to DNS cache\n", - hostname, port, address); - - if(data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - /* put this host in the cache */ - dns = Curl_cache_addr(data, addr, hostname, port); - - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); - } - } - data->change.resolve = NULL; /* dealt with now */ -} - - /* - * Curl_pretransfer() is called immediately before a transfer starts. + * Curl_pretransfer() is called immediately before a transfer starts, and only + * once for one transfer no matter if it has redirects or do multi-pass + * authentication etc. */ CURLcode Curl_pretransfer(struct SessionHandle *data) { - CURLcode res; + CURLcode result; if(!data->change.url) { /* we can't do anything without URL */ failf(data, "No URL set!"); @@ -1435,56 +1316,68 @@ CURLcode Curl_pretransfer(struct SessionHandle *data) } /* Init the SSL session ID cache here. We do it here since we want to do it - after the *_setopt() calls (that could change the size of the cache) but + after the *_setopt() calls (that could specify the size of the cache) but before any transfer takes place. */ - res = Curl_ssl_initsessions(data, data->set.ssl.numsessions); - if(res) - return res; + result = Curl_ssl_initsessions(data, data->set.ssl.max_ssl_sessions); + if(result) + return result; data->set.followlocation=0; /* reset the location-follow counter */ data->state.this_is_a_follow = FALSE; /* reset this */ data->state.errorbuf = FALSE; /* no error has occurred */ data->state.httpversion = 0; /* don't assume any particular server version */ - data->state.ssl_connect_retry = FALSE; - data->state.authproblem = FALSE; data->state.authhost.want = data->set.httpauth; data->state.authproxy.want = data->set.proxyauth; Curl_safefree(data->info.wouldredirect); data->info.wouldredirect = NULL; + if(data->set.httpreq == HTTPREQ_PUT) + data->state.infilesize = data->set.filesize; + else + data->state.infilesize = data->set.postfieldsize; + /* If there is a list of cookie files to read, do it now! */ if(data->change.cookielist) Curl_cookie_loadfiles(data); /* If there is a list of host pairs to deal with */ if(data->change.resolve) - loadhostpairs(data); + result = Curl_loadhostpairs(data); - /* Allow data->set.use_port to set which port to use. This needs to be - * disabled for example when we follow Location: headers to URLs using - * different ports! */ - data->state.allow_port = TRUE; + if(!result) { + /* Allow data->set.use_port to set which port to use. This needs to be + * disabled for example when we follow Location: headers to URLs using + * different ports! */ + data->state.allow_port = TRUE; #if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL) - /************************************************************* - * Tell signal handler to ignore SIGPIPE - *************************************************************/ - if(!data->set.no_signal) - data->state.prev_signal = signal(SIGPIPE, SIG_IGN); + /************************************************************* + * Tell signal handler to ignore SIGPIPE + *************************************************************/ + if(!data->set.no_signal) + data->state.prev_signal = signal(SIGPIPE, SIG_IGN); #endif - Curl_initinfo(data); /* reset session-specific information "variables" */ - Curl_pgrsStartNow(data); + Curl_initinfo(data); /* reset session-specific information "variables" */ + Curl_pgrsResetTimesSizes(data); + Curl_pgrsStartNow(data); - if(data->set.timeout) - Curl_expire(data, data->set.timeout); + if(data->set.timeout) + Curl_expire(data, data->set.timeout); - if(data->set.connecttimeout) - Curl_expire(data, data->set.connecttimeout); + if(data->set.connecttimeout) + Curl_expire(data, data->set.connecttimeout); - return CURLE_OK; + /* In case the handle is re-used and an authentication method was picked + in the session we need to make sure we only use the one(s) we now + consider to be fine */ + data->state.authhost.picked &= data->state.authhost.want; + data->state.authproxy.picked &= data->state.authproxy.want; + } + + return result; } /* @@ -1500,11 +1393,6 @@ CURLcode Curl_posttransfer(struct SessionHandle *data) (void)data; /* unused parameter */ #endif - if(!(data->progress.flags & PGRS_HIDE) && - !data->progress.callback) - /* only output if we don't use a progress callback and we're not hidden */ - fprintf(data->set.err, "\n"); - return CURLE_OK; } @@ -1515,16 +1403,18 @@ CURLcode Curl_posttransfer(struct SessionHandle *data) */ static size_t strlen_url(const char *url) { - const char *ptr; + const unsigned char *ptr; size_t newlen=0; bool left=TRUE; /* left side of the ? */ - for(ptr=url; *ptr; ptr++) { + for(ptr=(unsigned char *)url; *ptr; ptr++) { switch(*ptr) { case '?': left=FALSE; /* fall through */ default: + if(*ptr >= 0x80) + newlen += 2; newlen++; break; case ' ': @@ -1545,9 +1435,9 @@ static void strcpy_url(char *output, const char *url) { /* we must add this with whitespace-replacing */ bool left=TRUE; - const char *iptr; + const unsigned char *iptr; char *optr = output; - for(iptr = url; /* read from here */ + for(iptr = (unsigned char *)url; /* read from here */ *iptr; /* until zero byte */ iptr++) { switch(*iptr) { @@ -1555,7 +1445,12 @@ static void strcpy_url(char *output, const char *url) left=FALSE; /* fall through */ default: - *optr++=*iptr; + if(*iptr >= 0x80) { + snprintf(optr, 4, "%%%02x", *iptr); + optr += 3; + } + else + *optr++=*iptr; break; case ' ': if(left) { @@ -1580,7 +1475,7 @@ static bool is_absolute_url(const char *url) char prot[16]; /* URL protocol string storage */ char letter; /* used for a silly sscanf */ - return (bool)(2 == sscanf(url, "%15[^?&/:]://%c", prot, &letter)); + return (2 == sscanf(url, "%15[^?&/:]://%c", prot, &letter)) ? TRUE : FALSE; } /* @@ -1672,26 +1567,37 @@ static char *concat_url(const char *base, const char *relurl) } } else { - /* We got a new absolute path for this server, cut off from the - first slash */ - pathsep = strchr(protsep, '/'); - if(pathsep) { - /* When people use badly formatted URLs, such as - "http://www.url.com?dir=/home/daniel" we must not use the first - slash, if there's a ?-letter before it! */ - char *sep = strchr(protsep, '?'); - if(sep && (sep < pathsep)) - pathsep = sep; - *pathsep=0; + /* We got a new absolute path for this server */ + + if((relurl[0] == '/') && (relurl[1] == '/')) { + /* the new URL starts with //, just keep the protocol part from the + original one */ + *protsep=0; + useurl = &relurl[2]; /* we keep the slashes from the original, so we + skip the new ones */ } else { - /* There was no slash. Now, since we might be operating on a badly - formatted URL, such as "http://www.url.com?id=2380" which doesn't - use a slash separator as it is supposed to, we need to check for a - ?-letter as well! */ - pathsep = strchr(protsep, '?'); - if(pathsep) + /* cut off the original URL from the first slash, or deal with URLs + without slash */ + pathsep = strchr(protsep, '/'); + if(pathsep) { + /* When people use badly formatted URLs, such as + "http://www.url.com?dir=/home/daniel" we must not use the first + slash, if there's a ?-letter before it! */ + char *sep = strchr(protsep, '?'); + if(sep && (sep < pathsep)) + pathsep = sep; *pathsep=0; + } + else { + /* There was no slash. Now, since we might be operating on a badly + formatted URL, such as "http://www.url.com?id=2380" which doesn't + use a slash separator as it is supposed to, we need to check for a + ?-letter as well! */ + pathsep = strchr(protsep, '?'); + if(pathsep) + *pathsep=0; + } } } @@ -1704,8 +1610,8 @@ static char *concat_url(const char *base, const char *relurl) urllen = strlen(url_clone); - newest = malloc( urllen + 1 + /* possible slash */ - newlen + 1 /* zero byte */); + newest = malloc(urllen + 1 + /* possible slash */ + newlen + 1 /* zero byte */); if(!newest) { free(url_clone); /* don't leak this */ @@ -1754,7 +1660,7 @@ CURLcode Curl_follow(struct SessionHandle *data, if(type == FOLLOW_REDIR) { if((data->set.maxredirs != -1) && (data->set.followlocation >= data->set.maxredirs)) { - failf(data,"Maximum (%ld) redirects followed", data->set.maxredirs); + failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs); return CURLE_TOO_MANY_REDIRECTS; } @@ -1768,15 +1674,14 @@ CURLcode Curl_follow(struct SessionHandle *data, when we get the next URL. We pick the ->url field, which may or may not be 100% correct */ - if(data->change.referer_alloc) - /* If we already have an allocated referer, free this first */ - free(data->change.referer); + if(data->change.referer_alloc) { + Curl_safefree(data->change.referer); + data->change.referer_alloc = FALSE; + } data->change.referer = strdup(data->change.url); - if (!data->change.referer) { - data->change.referer_alloc = FALSE; + if(!data->change.referer) return CURLE_OUT_OF_MEMORY; - } data->change.referer_alloc = TRUE; /* yes, free this later */ } } @@ -1787,29 +1692,27 @@ CURLcode Curl_follow(struct SessionHandle *data, to be absolute and this doesn't seem to be that! */ char *absolute = concat_url(data->change.url, newurl); - if (!absolute) + if(!absolute) return CURLE_OUT_OF_MEMORY; free(newurl); newurl = absolute; } else { + /* The new URL MAY contain space or high byte values, that means a mighty + stupid redirect URL but we still make an effort to do "right". */ + char *newest; + size_t newlen = strlen_url(newurl); + /* This is an absolute URL, don't allow the custom port number */ disallowport = TRUE; - if(strchr(newurl, ' ')) { - /* This new URL contains at least one space, this is a mighty stupid - redirect but we still make an effort to do "right". */ - char *newest; - size_t newlen = strlen_url(newurl); + newest = malloc(newlen+1); /* get memory for this */ + if(!newest) + return CURLE_OUT_OF_MEMORY; + strcpy_url(newest, newurl); /* create a space-free URL */ - newest = malloc(newlen+1); /* get memory for this */ - if (!newest) - return CURLE_OUT_OF_MEMORY; - strcpy_url(newest, newurl); /* create a space-free URL */ - - free(newurl); /* that was no good */ - newurl = newest; /* use this instead now */ - } + free(newurl); /* that was no good */ + newurl = newest; /* use this instead now */ } @@ -1823,12 +1726,13 @@ CURLcode Curl_follow(struct SessionHandle *data, if(disallowport) data->state.allow_port = FALSE; - if(data->change.url_alloc) - free(data->change.url); - else - data->change.url_alloc = TRUE; /* the URL is allocated */ + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } data->change.url = newurl; + data->change.url_alloc = TRUE; newurl = NULL; /* don't free! */ infof(data, "Issue another request to this URL: '%s'\n", data->change.url); @@ -1854,63 +1758,59 @@ CURLcode Curl_follow(struct SessionHandle *data, */ break; case 301: /* Moved Permanently */ - /* (quote from RFC2616, section 10.3.2): + /* (quote from RFC7231, section 6.4.2) * - * Note: When automatically redirecting a POST request after receiving a - * 301 status code, some existing HTTP/1.0 user agents will erroneously - * change it into a GET request. + * Note: For historical reasons, a user agent MAY change the request + * method from POST to GET for the subsequent request. If this + * behavior is undesired, the 307 (Temporary Redirect) status code + * can be used instead. * * ---- * - * Warning: Because most of importants user agents do this obvious RFC2616 - * violation, many webservers expect this misbehavior. So these servers - * often answers to a POST request with an error page. To be sure that - * libcurl gets the page that most user agents would get, libcurl has to - * force GET. + * Many webservers expect this, so these servers often answers to a POST + * request with an error page. To be sure that libcurl gets the page that + * most user agents would get, libcurl has to force GET. * - * This behaviour can be overridden with CURLOPT_POSTREDIR. + * This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and + * can be overridden with CURLOPT_POSTREDIR. */ - if( (data->set.httpreq == HTTPREQ_POST - || data->set.httpreq == HTTPREQ_POST_FORM) - && !data->set.post301) { - infof(data, - "Violate RFC 2616/10.3.2 and switch from POST to GET\n"); + if((data->set.httpreq == HTTPREQ_POST + || data->set.httpreq == HTTPREQ_POST_FORM) + && !(data->set.keep_post & CURL_REDIR_POST_301)) { + infof(data, "Switch from POST to GET\n"); data->set.httpreq = HTTPREQ_GET; } break; case 302: /* Found */ - /* (From 10.3.3) - - Note: RFC 1945 and RFC 2068 specify that the client is not allowed - to change the method on the redirected request. However, most - existing user agent implementations treat 302 as if it were a 303 - response, performing a GET on the Location field-value regardless - of the original request method. The status codes 303 and 307 have - been added for servers that wish to make unambiguously clear which - kind of reaction is expected of the client. - - (From 10.3.4) - - Note: Many pre-HTTP/1.1 user agents do not understand the 303 - status. When interoperability with such clients is a concern, the - 302 status code may be used instead, since most user agents react - to a 302 response as described here for 303. - - This behaviour can be overriden with CURLOPT_POSTREDIR - */ - if( (data->set.httpreq == HTTPREQ_POST - || data->set.httpreq == HTTPREQ_POST_FORM) - && !data->set.post302) { - infof(data, - "Violate RFC 2616/10.3.3 and switch from POST to GET\n"); + /* (quote from RFC7231, section 6.4.3) + * + * Note: For historical reasons, a user agent MAY change the request + * method from POST to GET for the subsequent request. If this + * behavior is undesired, the 307 (Temporary Redirect) status code + * can be used instead. + * + * ---- + * + * Many webservers expect this, so these servers often answers to a POST + * request with an error page. To be sure that libcurl gets the page that + * most user agents would get, libcurl has to force GET. + * + * This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and + * can be overridden with CURLOPT_POSTREDIR. + */ + if((data->set.httpreq == HTTPREQ_POST + || data->set.httpreq == HTTPREQ_POST_FORM) + && !(data->set.keep_post & CURL_REDIR_POST_302)) { + infof(data, "Switch from POST to GET\n"); data->set.httpreq = HTTPREQ_GET; } break; case 303: /* See Other */ - /* Disable both types of POSTs, since doing a second POST when - * following isn't what anyone would want! */ - if(data->set.httpreq != HTTPREQ_GET) { + /* Disable both types of POSTs, unless the user explicitely + asks for POST after POST */ + if(data->set.httpreq != HTTPREQ_GET + && !(data->set.keep_post & CURL_REDIR_POST_303)) { data->set.httpreq = HTTPREQ_GET; /* enforce GET request */ infof(data, "Disables POST, goes with %s\n", data->set.opt_no_body?"HEAD":"GET"); @@ -1932,39 +1832,12 @@ CURLcode Curl_follow(struct SessionHandle *data, break; } Curl_pgrsTime(data, TIMER_REDIRECT); - Curl_pgrsResetTimes(data); + Curl_pgrsResetTimesSizes(data); return CURLE_OK; #endif /* CURL_DISABLE_HTTP */ } -static CURLcode -connect_host(struct SessionHandle *data, - struct connectdata **conn) -{ - CURLcode res = CURLE_OK; - - bool async; - bool protocol_done=TRUE; /* will be TRUE always since this is only used - within the easy interface */ - Curl_pgrsTime(data, TIMER_STARTSINGLE); - res = Curl_connect(data, conn, &async, &protocol_done); - - if((CURLE_OK == res) && async) { - /* Now, if async is TRUE here, we need to wait for the name - to resolve */ - res = Curl_wait_for_resolv(*conn, NULL); - if(CURLE_OK == res) - /* Resolved, continue with the connection */ - res = Curl_async_resolved(*conn, &protocol_done); - else - /* if we can't resolve, we kill this "connection" now */ - (void)Curl_disconnect(*conn, /* dead_connection */ FALSE); - } - - return res; -} - CURLcode Curl_reconnect_request(struct connectdata **connp) { @@ -1980,10 +1853,12 @@ Curl_reconnect_request(struct connectdata **connp) infof(data, "Re-used connection seems dead, get a new one\n"); - conn->bits.close = TRUE; /* enforce close of this connection */ + connclose(conn, "Reconnect dead connection"); /* enforce close */ result = Curl_done(&conn, result, FALSE); /* we are so done with this */ - /* conn may no longer be a good pointer */ + /* conn may no longer be a good pointer, clear it to avoid mistakes by + parent functions */ + *connp = NULL; /* * According to bug report #1330310. We need to check for CURLE_SEND_ERROR @@ -1992,20 +1867,20 @@ Curl_reconnect_request(struct connectdata **connp) * (again). Slight Lack of feedback in the report, but I don't think this * extra check can do much harm. */ - if((CURLE_OK == result) || (CURLE_SEND_ERROR == result)) { + if(!result || (CURLE_SEND_ERROR == result)) { bool async; bool protocol_done = TRUE; /* Now, redo the connect and get a new connection */ result = Curl_connect(data, connp, &async, &protocol_done); - if(CURLE_OK == result) { + if(!result) { /* We have connected or sent away a name resolve query fine */ conn = *connp; /* setup conn to again point to something nice */ if(async) { /* Now, if async is TRUE here, we need to wait for the name to resolve */ - result = Curl_wait_for_resolv(conn, NULL); + result = Curl_resolver_wait_resolv(conn, NULL); if(result) return result; @@ -2032,15 +1907,14 @@ CURLcode Curl_retry_request(struct connectdata *conn, /* if we're talking upload, we can't do the checks below, unless the protocol is HTTP as when uploading over HTTP we will still get a response */ - if(data->set.upload && !(conn->protocol&(PROT_HTTP|PROT_RTSP))) + if(data->set.upload && + !(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP))) return CURLE_OK; - if(/* workaround for broken TLS servers */ data->state.ssl_connect_retry || - ((data->req.bytecount + - data->req.headerbytecount == 0) && - conn->bits.reuse && - !data->set.opt_no_body && - data->set.rtspreq != RTSPREQ_RECEIVE)) { + if((data->req.bytecount + data->req.headerbytecount == 0) && + conn->bits.reuse && + !data->set.opt_no_body && + (data->set.rtspreq != RTSPREQ_RECEIVE)) { /* We got no data, we attempted to re-use a connection and yet we want a "body". This might happen if the connection was left alive when we were done using it before, but that was closed when we wanted to read from @@ -2050,208 +1924,23 @@ CURLcode Curl_retry_request(struct connectdata *conn, if(!*url) return CURLE_OUT_OF_MEMORY; - conn->bits.close = TRUE; /* close this connection */ + connclose(conn, "retry"); /* close this connection */ conn->bits.retry = TRUE; /* mark this as a connection we're about to retry. Marking it this way should prevent i.e HTTP transfers to return error just because nothing has been - transfered! */ + transferred! */ + + + if(conn->handler->protocol&PROTO_FAMILY_HTTP) { + struct HTTP *http = data->req.protop; + if(http->writebytecount) + return Curl_readrewind(conn); + } } return CURLE_OK; } -static CURLcode Curl_do_perform(struct SessionHandle *data) -{ - CURLcode res; - CURLcode res2; - struct connectdata *conn=NULL; - char *newurl = NULL; /* possibly a new URL to follow to! */ - followtype follow = FOLLOW_NONE; - - data->state.used_interface = Curl_if_easy; - - res = Curl_pretransfer(data); - if(res) - return res; - - /* - * It is important that there is NO 'return' from this function at any other - * place than falling down to the end of the function! This is because we - * have cleanup stuff that must be done before we get back, and that is only - * performed after this do-while loop. - */ - - for(;;) { - res = connect_host(data, &conn); /* primary connection */ - - if(res == CURLE_OK) { - bool do_done; - if(data->set.connect_only) { - /* keep connection open for application to use the socket */ - conn->bits.close = FALSE; - res = Curl_done(&conn, CURLE_OK, FALSE); - break; - } - res = Curl_do(&conn, &do_done); - - if(res == CURLE_OK) { - if(conn->data->set.wildcardmatch) { - if(conn->data->wildcard.state == CURLWC_DONE || - conn->data->wildcard.state == CURLWC_SKIP) { - /* keep connection open for application to use the socket */ - conn->bits.close = FALSE; - res = Curl_done(&conn, CURLE_OK, FALSE); - break; - } - } - res = Transfer(conn); /* now fetch that URL please */ - if((res == CURLE_OK) || (res == CURLE_RECV_ERROR)) { - bool retry = FALSE; - CURLcode rc = Curl_retry_request(conn, &newurl); - if(rc) - res = rc; - else - retry = (newurl?TRUE:FALSE); - - if(retry) { - /* we know (newurl != NULL) at this point */ - res = CURLE_OK; - follow = FOLLOW_RETRY; - } - else if (res == CURLE_OK) { - /* - * We must duplicate the new URL here as the connection data may - * be free()ed in the Curl_done() function. We prefer the newurl - * one since that's used for redirects or just further requests - * for retries or multi-stage HTTP auth methods etc. - */ - if(data->req.newurl) { - follow = FOLLOW_REDIR; - newurl = strdup(data->req.newurl); - if (!newurl) - res = CURLE_OUT_OF_MEMORY; - } - else if(data->req.location) { - follow = FOLLOW_FAKE; - newurl = strdup(data->req.location); - if (!newurl) - res = CURLE_OUT_OF_MEMORY; - } - } - - /* in the above cases where 'newurl' gets assigned, we have a fresh - * allocated memory pointed to */ - } - if(res != CURLE_OK) { - /* The transfer phase returned error, we mark the connection to get - * closed to prevent being re-used. This is because we can't - * possibly know if the connection is in a good shape or not now. */ - conn->bits.close = TRUE; - - if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) { - /* if we failed anywhere, we must clean up the secondary socket if - it was used */ - sclose(conn->sock[SECONDARYSOCKET]); - conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; - } - } - - /* Always run Curl_done(), even if some of the previous calls - failed, but return the previous (original) error code */ - res2 = Curl_done(&conn, res, FALSE); - - if(CURLE_OK == res) - res = res2; - } - else if(conn) - /* Curl_do() failed, clean up left-overs in the done-call, but note - that at some cases the conn pointer is NULL when Curl_do() failed - and the connection cache is very small so only call Curl_done() if - conn is still "alive". */ - /* ignore return code since we already have an error to return */ - (void)Curl_done(&conn, res, FALSE); - - /* - * Important: 'conn' cannot be used here, since it may have been closed - * in 'Curl_done' or other functions. - */ - - if((res == CURLE_OK) && follow) { - res = Curl_follow(data, newurl, follow); - if(CURLE_OK == res) { - /* if things went fine, Curl_follow() freed or otherwise took - responsibility for the newurl pointer */ - newurl = NULL; - if(follow >= FOLLOW_RETRY) { - follow = FOLLOW_NONE; - continue; - } - /* else we break out of the loop below */ - } - } - } - break; /* it only reaches here when this shouldn't loop */ - - } /* loop if Location: */ - - if(newurl) - free(newurl); - - if(res && !data->state.errorbuf) { - /* - * As an extra precaution: if no error string has been set and there was - * an error, use the strerror() string or if things are so bad that not - * even that is good, set a bad string that mentions the error code. - */ - const char *str = curl_easy_strerror(res); - if(!str) - failf(data, "unspecified error %d", (int)res); - else - failf(data, "%s", str); - } - - /* run post-transfer unconditionally, but don't clobber the return code if - we already have an error code recorder */ - res2 = Curl_posttransfer(data); - if(!res && res2) - res = res2; - - return res; -} - -/* - * Curl_perform() is the internal high-level function that gets called by the - * external curl_easy_perform() function. It inits, performs and cleans up a - * single file transfer. - */ -CURLcode Curl_perform(struct SessionHandle *data) -{ - CURLcode res; - if(!data->set.wildcardmatch) - return Curl_do_perform(data); - - /* init main wildcard structures */ - res = Curl_wildcard_init(&data->wildcard); - if(res) - return res; - - res = Curl_do_perform(data); - if(res) { - Curl_wildcard_dtor(&data->wildcard); - return res; - } - - /* wildcard loop */ - while(!res && data->wildcard.state != CURLWC_DONE) - res = Curl_do_perform(data); - - Curl_wildcard_dtor(&data->wildcard); - - /* wildcard download finished or failed */ - data->wildcard.state = CURLWC_INIT; - return res; -} - /* * Curl_setup_transfer() is called to setup some basic properties for the * upcoming transfer. @@ -2305,6 +1994,7 @@ Curl_setup_transfer( k->keepon |= KEEP_RECV; if(conn->writesockfd != CURL_SOCKET_BAD) { + struct HTTP *http = data->req.protop; /* HTTP 1.1 magic: Even if we require a 100-return code before uploading data, we might @@ -2315,13 +2005,15 @@ Curl_setup_transfer( state info where we wait for the 100-return code */ if((data->state.expect100header) && - (data->state.proto.http->sending == HTTPSEND_BODY)) { + (conn->handler->protocol&PROTO_FAMILY_HTTP) && + (http->sending == HTTPSEND_BODY)) { /* wait with write until we either got 100-continue or a timeout */ k->exp100 = EXP100_AWAITING_CONTINUE; - k->start100 = k->start; + k->start100 = Curl_tvnow(); - /* set a timeout for the multi interface */ - Curl_expire(data, CURL_TIMEOUT_EXPECT_100); + /* Set a timeout for the multi interface. Add the inaccuracy margin so + that we don't fire slightly too early and get denied to run. */ + Curl_expire(data, data->set.expect_100_timeout); } else { if(data->state.expect100header) diff --git a/project/jni/curl/lib/transfer.h b/project/jni/curl/lib/transfer.h index 790e1e3ef..52b762abf 100644 --- a/project/jni/curl/lib/transfer.h +++ b/project/jni/curl/lib/transfer.h @@ -1,5 +1,5 @@ -#ifndef __TRANSFER_H -#define __TRANSFER_H +#ifndef HEADER_CURL_TRANSFER_H +#define HEADER_CURL_TRANSFER_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,7 +21,9 @@ * KIND, either express or implied. * ***************************************************************************/ -CURLcode Curl_perform(struct SessionHandle *data); + +void Curl_init_CONNECT(struct SessionHandle *data); + CURLcode Curl_pretransfer(struct SessionHandle *data); CURLcode Curl_second_connect(struct connectdata *conn); CURLcode Curl_posttransfer(struct SessionHandle *data); @@ -36,10 +38,12 @@ typedef enum { FOLLOW_LAST /* never used */ } followtype; -CURLcode Curl_follow(struct SessionHandle *data, char *newurl, followtype type); +CURLcode Curl_follow(struct SessionHandle *data, char *newurl, + followtype type); -CURLcode Curl_readwrite(struct connectdata *conn, bool *done); +CURLcode Curl_readwrite(struct connectdata *conn, + struct SessionHandle *data, bool *done); int Curl_single_getsock(const struct connectdata *conn, curl_socket_t *socks, int numsocks); @@ -47,6 +51,7 @@ CURLcode Curl_readrewind(struct connectdata *conn); CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp); CURLcode Curl_reconnect_request(struct connectdata **connp); CURLcode Curl_retry_request(struct connectdata *conn, char **url); +bool Curl_meets_timecondition(struct SessionHandle *data, time_t timeofdoc); /* This sets up a forthcoming transfer */ void @@ -64,4 +69,5 @@ Curl_setup_transfer (struct connectdata *data, long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, int pkt_size); -#endif +#endif /* HEADER_CURL_TRANSFER_H */ + diff --git a/project/jni/curl/lib/url.c b/project/jni/curl/lib/url.c index 8511ffe4c..d165d9c0a 100644 --- a/project/jni/curl/lib/url.c +++ b/project/jni/curl/lib/url.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,33 +20,11 @@ * ***************************************************************************/ -/* -- WIN32 approved -- */ +#include "curl_setup.h" -#include "setup.h" - -#include -#include -#include -#include -#include -#include - -#ifdef WIN32 -#include -#include -#else -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #ifdef HAVE_NETINET_IN_H #include #endif -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif #ifdef HAVE_NETDB_H #include #endif @@ -69,12 +47,14 @@ #include #endif +#ifdef HAVE_SYS_UN_H +#include +#endif + #ifndef HAVE_SOCKET #error "We can't compile without socket() support!" #endif -#endif /* WIN32 */ - #ifdef HAVE_LIMITS_H #include #endif @@ -86,21 +66,23 @@ #ifdef HAVE_IDN_FREE_H #include #else -void idn_free (void *ptr); /* prototype from idn-free.h, not provided by - libidn 0.4.5's make install! */ +/* prototype from idn-free.h, not provided by libidn 0.4.5's make install! */ +void idn_free (void *ptr); #endif #ifndef HAVE_IDN_FREE -/* if idn_free() was not found in this version of libidn, use plain free() - instead */ +/* if idn_free() was not found in this version of libidn use free() instead */ #define idn_free(x) (free)(x) #endif +#elif defined(USE_WIN32_IDN) +/* prototype for curl_win32_idn_to_ascii() */ +bool curl_win32_idn_to_ascii(const char *in, char **out); #endif /* USE_LIBIDN */ #include "urldata.h" #include "netrc.h" #include "formdata.h" -#include "sslgen.h" +#include "vtls/vtls.h" #include "hostip.h" #include "transfer.h" #include "sendf.h" @@ -120,6 +102,8 @@ void idn_free (void *ptr); /* prototype from idn-free.h, not provided by #include "speedcheck.h" #include "rawstr.h" #include "warnless.h" +#include "non-ascii.h" +#include "inet_pton.h" /* And now for the protocols */ #include "ftp.h" @@ -127,6 +111,7 @@ void idn_free (void *ptr); /* prototype from idn-free.h, not provided by #include "telnet.h" #include "tftp.h" #include "http.h" +#include "http2.h" #include "file.h" #include "curl_ldap.h" #include "ssh.h" @@ -134,23 +119,39 @@ void idn_free (void *ptr); /* prototype from idn-free.h, not provided by #include "url.h" #include "connect.h" #include "inet_ntop.h" -#include "http_ntlm.h" +#include "curl_ntlm.h" +#include "curl_ntlm_wb.h" #include "socks.h" -#include "rtsp.h" #include "curl_rtmp.h" #include "gopher.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "http_proxy.h" +#include "conncache.h" +#include "multihandle.h" +#include "pipeline.h" +#include "dotdot.h" +#include "strdup.h" +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /* Local static prototypes */ -static long ConnectionKillOne(struct SessionHandle *data); +static struct connectdata * +find_oldest_idle_connection(struct SessionHandle *data); +static struct connectdata * +find_oldest_idle_connection_in_bundle(struct SessionHandle *data, + struct connectbundle *bundle); static void conn_free(struct connectdata *conn); +static void free_fixed_hostname(struct hostname *host); static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke); +static CURLcode parse_url_login(struct SessionHandle *data, + struct connectdata *conn, + char **userptr, char **passwdptr, + char **optionsptr); +static CURLcode parse_login_details(const char *login, const size_t len, + char **userptr, char **passwdptr, + char **optionsptr); +static unsigned int get_protocol_family(unsigned int protocol); /* * Protocol table. @@ -184,8 +185,9 @@ static const struct Curl_handler * const protocols[] = { #ifndef CURL_DISABLE_LDAP &Curl_handler_ldap, -#if (defined(USE_OPENLDAP) && defined(USE_SSL)) || \ - (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)) +#if !defined(CURL_DISABLE_LDAPS) && \ + ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \ + (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL))) &Curl_handler_ldaps, #endif #endif @@ -217,6 +219,15 @@ static const struct Curl_handler * const protocols[] = { #endif #endif +#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ + (CURL_SIZEOF_CURL_OFF_T > 4) && \ + (!defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)) + &Curl_handler_smb, +#ifdef USE_SSL + &Curl_handler_smbs, +#endif +#endif + #ifndef CURL_DISABLE_SMTP &Curl_handler_smtp, #ifdef USE_SSL @@ -259,102 +270,96 @@ static const struct Curl_handler Curl_handler_dummy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ 0, /* defport */ - 0 /* protocol */ + 0, /* protocol */ + PROTOPT_NONE /* flags */ }; -void Curl_safefree(void *ptr) -{ - if(ptr) - free(ptr); -} - -static void close_connections(struct SessionHandle *data) -{ - /* Loop through all open connections and kill them one by one */ - long i; - do { - i = ConnectionKillOne(data); - } while(i != -1L); -} - -void Curl_freeset(struct SessionHandle * data) +void Curl_freeset(struct SessionHandle *data) { /* Free all dynamic strings stored in the data->set substructure. */ enum dupstring i; - for(i=(enum dupstring)0; i < STRING_LAST; i++) + for(i=(enum dupstring)0; i < STRING_LAST; i++) { Curl_safefree(data->set.str[i]); + } + + if(data->change.referer_alloc) { + Curl_safefree(data->change.referer); + data->change.referer_alloc = FALSE; + } + data->change.referer = NULL; + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } + data->change.url = NULL; } -static CURLcode setstropt(char **charp, char * s) +static CURLcode setstropt(char **charp, const char *s) { /* Release the previous storage at `charp' and replace by a dynamic storage copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */ - if(*charp) { - free(*charp); - *charp = (char *) NULL; - } + Curl_safefree(*charp); if(s) { - s = strdup(s); + char *str = strdup(s); - if(!s) + if(!str) return CURLE_OUT_OF_MEMORY; - *charp = s; + *charp = str; } return CURLE_OK; } -static CURLcode setstropt_userpwd(char *option, char **user_storage, - char **pwd_storage) +static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp) { - char* separator; CURLcode result = CURLE_OK; + char *user = NULL; + char *passwd = NULL; - if(!option) { - /* we treat a NULL passed in as a hint to clear existing info */ - Curl_safefree(*user_storage); - *user_storage = (char *) NULL; - Curl_safefree(*pwd_storage); - *pwd_storage = (char *) NULL; - return CURLE_OK; + /* Parse the login details if specified. It not then we treat NULL as a hint + to clear the existing data */ + if(option) { + result = parse_login_details(option, strlen(option), + (userp ? &user : NULL), + (passwdp ? &passwd : NULL), + NULL); } - separator = strchr(option, ':'); - if (separator != NULL) { + if(!result) { + /* Store the username part of option if required */ + if(userp) { + if(!user && option && option[0] == ':') { + /* Allocate an empty string instead of returning NULL as user name */ + user = strdup(""); + if(!user) + result = CURLE_OUT_OF_MEMORY; + } - /* store username part of option */ - char * p; - size_t username_len = (size_t)(separator-option); - p = malloc(username_len+1); - if(!p) - result = CURLE_OUT_OF_MEMORY; - else { - memcpy(p, option, username_len); - p[username_len] = '\0'; - Curl_safefree(*user_storage); - *user_storage = p; + Curl_safefree(*userp); + *userp = user; } - /* store password part of option */ - if (result == CURLE_OK) { - result = setstropt(pwd_storage, separator+1); + /* Store the password part of option if required */ + if(passwdp) { + Curl_safefree(*passwdp); + *passwdp = passwd; } } - else { - result = setstropt(user_storage, option); - } + return result; } -CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src) +CURLcode Curl_dupset(struct SessionHandle *dst, struct SessionHandle *src) { - CURLcode r = CURLE_OK; + CURLcode result = CURLE_OK; enum dupstring i; /* Copy src->set into dst->set first, then deal with the strings @@ -365,49 +370,27 @@ CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src) memset(dst->set.str, 0, STRING_LAST * sizeof(char *)); /* duplicate all strings */ - for(i=(enum dupstring)0; i< STRING_LAST; i++) { - r = setstropt(&dst->set.str[i], src->set.str[i]); - if(r != CURLE_OK) - break; + for(i=(enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) { + result = setstropt(&dst->set.str[i], src->set.str[i]); + if(result) + return result; } - /* If a failure occurred, freeing has to be performed externally. */ - return r; + /* duplicate memory areas pointed to */ + i = STRING_COPYPOSTFIELDS; + if(src->set.postfieldsize && src->set.str[i]) { + /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */ + dst->set.str[i] = Curl_memdup(src->set.str[i], + curlx_sotouz(src->set.postfieldsize)); + if(!dst->set.str[i]) + return CURLE_OUT_OF_MEMORY; + /* point to the new copy */ + dst->set.postfields = dst->set.str[i]; + } + + return CURLE_OK; } -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) -static void flush_cookies(struct SessionHandle *data, int cleanup) -{ - if(data->set.str[STRING_COOKIEJAR]) { - if(data->change.cookielist) { - /* If there is a list of cookie files to read, do it first so that - we have all the told files read before we write the new jar. - Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */ - Curl_cookie_loadfiles(data); - } - - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - - /* if we have a destination file for all the cookies to get dumped to */ - if(Curl_cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR])) - infof(data, "WARNING: failed to save cookies in %s\n", - data->set.str[STRING_COOKIEJAR]); - } - else { - if(cleanup && data->change.cookielist) - /* since nothing is written, we can just free the list of cookie file - names */ - curl_slist_free_all(data->change.cookielist); /* clean up list */ - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - } - - if(cleanup && (!data->share || (data->cookies != data->share->cookies))) { - Curl_cookie_cleanup(data->cookies); - } - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); -} -#endif - /* * This is the internal function curl_easy_cleanup() calls. This should * cleanup and free all resources associated with this sessionhandle. @@ -419,75 +402,25 @@ static void flush_cookies(struct SessionHandle *data, int cleanup) CURLcode Curl_close(struct SessionHandle *data) { - struct Curl_multi *m = data->multi; + struct Curl_multi *m; -#ifdef DEBUGBUILD - /* only for debugging, scan through all connections and see if there's a - pipe reference still identifying this handle */ - - if(data->state.connc && data->state.connc->type == CONNCACHE_MULTI) { - struct conncache *c = data->state.connc; - long i; - struct curl_llist *pipeline; - struct curl_llist_element *curr; - struct connectdata *connptr; - - for(i=0; i< c->num; i++) { - connptr = c->connects[i]; - if(!connptr) - continue; - - pipeline = connptr->send_pipe; - if(pipeline) { - for (curr = pipeline->head; curr; curr=curr->next) { - if(data == (struct SessionHandle *) curr->ptr) { - fprintf(stderr, - "problem we %p are still in send pipe for %p done %d\n", - data, connptr, (int)connptr->bits.done); - } - } - } - pipeline = connptr->recv_pipe; - if(pipeline) { - for (curr = pipeline->head; curr; curr=curr->next) { - if(data == (struct SessionHandle *) curr->ptr) { - fprintf(stderr, - "problem we %p are still in recv pipe for %p done %d\n", - data, connptr, (int)connptr->bits.done); - } - } - } - pipeline = connptr->done_pipe; - if(pipeline) { - for (curr = pipeline->head; curr; curr=curr->next) { - if(data == (struct SessionHandle *) curr->ptr) { - fprintf(stderr, - "problem we %p are still in done pipe for %p done %d\n", - data, connptr, (int)connptr->bits.done); - } - } - } - pipeline = connptr->pend_pipe; - if(pipeline) { - for (curr = pipeline->head; curr; curr=curr->next) { - if(data == (struct SessionHandle *) curr->ptr) { - fprintf(stderr, - "problem we %p are still in pend pipe for %p done %d\n", - data, connptr, (int)connptr->bits.done); - } - } - } - } - } -#endif + if(!data) + return CURLE_OK; Curl_expire(data, 0); /* shut off timers */ + m = data->multi; + if(m) /* This handle is still part of a multi handle, take care of this first and detach this handle from there. */ curl_multi_remove_handle(data->multi, data); + if(data->multi_easy) + /* when curl_easy_perform() is used, it creates its own multi handle to + use and this is the one */ + curl_multi_cleanup(data->multi_easy); + /* Destroy the timeout list that is held in the easy handle. It is /normally/ done by curl_multi_remove_handle() but this is "just in case" */ @@ -500,37 +433,15 @@ CURLcode Curl_close(struct SessionHandle *data) the multi handle, since that function uses the magic field! */ - if(data->state.connc) { - - if(data->state.connc->type == CONNCACHE_PRIVATE) { - /* close all connections still alive that are in the private connection - cache, as we no longer have the pointer left to the shared one. */ - close_connections(data); - - /* free the connection cache if allocated privately */ - Curl_rm_connc(data->state.connc); - } - } - - if(data->state.shared_conn) { - /* marked to be used by a pending connection so we can't kill this handle - just yet */ - data->state.closed = TRUE; - return CURLE_OK; - } - - if(data->dns.hostcachetype == HCACHE_PRIVATE) { - Curl_hash_destroy(data->dns.hostcache); - data->dns.hostcachetype = HCACHE_NONE; - data->dns.hostcache = NULL; - } - if(data->state.rangestringalloc) free(data->state.range); /* Free the pathbuffer */ Curl_safefree(data->state.pathbuffer); - Curl_safefree(data->state.proto.generic); + data->state.path = NULL; + + /* freed here just in case DONE wasn't called */ + Curl_free_request_state(data); /* Close down all open SSL info and sessions */ Curl_ssl_close_all(data); @@ -538,17 +449,25 @@ CURLcode Curl_close(struct SessionHandle *data) Curl_safefree(data->state.scratch); Curl_ssl_free_certinfo(data); - if(data->change.referer_alloc) - free(data->change.referer); + /* Cleanup possible redirect junk */ + free(data->req.newurl); + data->req.newurl = NULL; - if(data->change.url_alloc) - free(data->change.url); + if(data->change.referer_alloc) { + Curl_safefree(data->change.referer); + data->change.referer_alloc = FALSE; + } + data->change.referer = NULL; + + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } + data->change.url = NULL; Curl_safefree(data->state.headerbuff); -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - flush_cookies(data, 1); -#endif + Curl_flush_cookies(data, 1); Curl_digest_cleanup(data); @@ -556,20 +475,9 @@ CURLcode Curl_close(struct SessionHandle *data) Curl_safefree(data->info.wouldredirect); /* this destroys the channel and we cannot use it anymore after this */ - ares_destroy(data->state.areschannel); + Curl_resolver_cleanup(data->state.resolver); -#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) - /* close iconv conversion descriptors */ - if(data->inbound_cd != (iconv_t)-1) { - iconv_close(data->inbound_cd); - } - if(data->outbound_cd != (iconv_t)-1) { - iconv_close(data->outbound_cd); - } - if(data->utf8_cd != (iconv_t)-1) { - iconv_close(data->utf8_cd); - } -#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ + Curl_convert_close(data); /* No longer a dirty share, if it exists */ if(data->share) { @@ -583,133 +491,23 @@ CURLcode Curl_close(struct SessionHandle *data) return CURLE_OK; } -/* create a connection cache of a private or multi type */ -struct conncache *Curl_mk_connc(int type, - long amount) /* set -1 to use default */ -{ - /* It is subject for debate how many default connections to have for a multi - connection cache... */ - - struct conncache *c; - long default_amount; - long max_amount = (long)(((size_t)INT_MAX) / sizeof(struct connectdata *)); - - if(type == CONNCACHE_PRIVATE) { - default_amount = (amount < 1L) ? 5L : amount; - } - else { - default_amount = (amount < 1L) ? 10L : amount; - } - - if(default_amount > max_amount) - default_amount = max_amount; - - c = calloc(1, sizeof(struct conncache)); - if(!c) - return NULL; - - c->connects = calloc((size_t)default_amount, sizeof(struct connectdata *)); - if(!c->connects) { - free(c); - return NULL; - } - - c->num = default_amount; - - return c; -} - -/* Change number of entries of a connection cache */ -CURLcode Curl_ch_connc(struct SessionHandle *data, - struct conncache *c, - long newamount) -{ - long i; - struct connectdata **newptr; - long max_amount = (long)(((size_t)INT_MAX) / sizeof(struct connectdata *)); - - if(newamount < 1) - newamount = 1; /* we better have at least one entry */ - - if(!c) { - /* we get a NULL pointer passed in as connection cache, which means that - there is no cache created for this SessionHandle just yet, we create a - brand new with the requested size. - */ - data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, newamount); - if(!data->state.connc) - return CURLE_OUT_OF_MEMORY; - return CURLE_OK; - } - - if(newamount < c->num) { - /* Since this number is *decreased* from the existing number, we must - close the possibly open connections that live on the indexes that - are being removed! - - NOTE: for conncache_multi cases we must make sure that we only - close handles not in use. - */ - for(i=newamount; i< c->num; i++) - Curl_disconnect(c->connects[i], /* dead_connection */ FALSE); - - /* If the most recent connection is no longer valid, mark it - invalid. */ - if(data->state.lastconnect <= newamount) - data->state.lastconnect = -1; - } - if(newamount > 0) { - if(newamount > max_amount) - newamount = max_amount; - newptr = realloc(c->connects, sizeof(struct connectdata *) * newamount); - if(!newptr) - /* we closed a few connections in vain, but so what? */ - return CURLE_OUT_OF_MEMORY; - - /* nullify the newly added pointers */ - for(i=c->num; iconnects = newptr; - c->num = newamount; - } - /* we no longer support less than 1 as size for the connection cache, and - I'm not sure it ever worked to set it to zero */ - return CURLE_OK; -} - -/* Free a connection cache. This is called from Curl_close() and - curl_multi_cleanup(). */ -void Curl_rm_connc(struct conncache *c) -{ - if(c->connects) { - long i; - for(i = 0; i < c->num; ++i) - conn_free(c->connects[i]); - - free(c->connects); - } - - free(c); -} - /* * Initialize the UserDefined fields within a SessionHandle. * This may be safely called on a new or existing SessionHandle. */ CURLcode Curl_init_userdefined(struct UserDefined *set) { - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; set->out = stdout; /* default output to stdout */ - set->in = stdin; /* default input from stdin */ + set->in_set = stdin; /* default input from stdin */ set->err = stderr; /* default stderr to stderr */ /* use fwrite as default function to store output */ set->fwrite_func = (curl_write_callback)fwrite; /* use fread as default function to read input */ - set->fread_func = (curl_read_callback)fread; + set->fread_func_set = (curl_read_callback)fread; set->is_fread_set = 0; set->is_fwrite_set = 0; @@ -721,7 +519,7 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) set->convtonetwork = ZERO_NULL; set->convfromutf8 = ZERO_NULL; - set->infilesize = -1; /* we don't know any size */ + set->filesize = -1; /* we don't know the size */ set->postfieldsize = -1; /* unknown size */ set->maxredirs = -1; /* allow any amount by default */ @@ -735,7 +533,7 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ /* Set the default size of the SSL session ID cache */ - set->ssl.numsessions = 5; + set->ssl.max_ssl_sessions = 5; set->proxyport = CURL_DEFAULT_PROXY_PORT; /* from url.h */ set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ @@ -750,7 +548,10 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) * switched off unless wanted. */ set->ssl.verifypeer = TRUE; - set->ssl.verifyhost = 2; + set->ssl.verifyhost = TRUE; +#ifdef USE_TLS_SRP + set->ssl.authtype = CURL_TLSAUTH_NONE; +#endif set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth type */ set->ssl.sessionid = TRUE; /* session ID caching enabled by default */ @@ -761,9 +562,10 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) /* for the *protocols fields we don't use the CURLPROTO_ALL convenience define since we internally only use the lower 16 bits for the passed in bitmask to not conflict with the private bits */ - set->allowed_protocols = PROT_EXTMASK; - set->redir_protocols = - PROT_EXTMASK & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */ + set->allowed_protocols = CURLPROTO_ALL; + set->redir_protocols = CURLPROTO_ALL & /* All except FILE, SCP and SMB */ + ~(CURLPROTO_FILE | CURLPROTO_SCP | CURLPROTO_SMB | + CURLPROTO_SMBS); #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) /* @@ -771,25 +573,56 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) * seem not to follow rfc1961 section 4.3/4.4 */ set->socks5_gssapi_nec = FALSE; - /* set default gssapi service name */ - res = setstropt(&set->str[STRING_SOCKS5_GSSAPI_SERVICE], - (char *) CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE); - if (res != CURLE_OK) - return res; + /* set default GSS-API service name */ + result = setstropt(&set->str[STRING_SOCKS5_GSSAPI_SERVICE], + CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE); + if(result) + return result; + + /* set default negotiate proxy service name */ + result = setstropt(&set->str[STRING_PROXY_SERVICE_NAME], + CURL_DEFAULT_PROXY_SERVICE_NAME); + if(result) + return result; + + /* set default negotiate service name */ + result = setstropt(&set->str[STRING_SERVICE_NAME], + CURL_DEFAULT_SERVICE_NAME); + if(result) + return result; #endif /* This is our preferred CA cert bundle/path since install time */ #if defined(CURL_CA_BUNDLE) - res = setstropt(&set->str[STRING_SSL_CAFILE], (char *) CURL_CA_BUNDLE); -#elif defined(CURL_CA_PATH) - res = setstropt(&set->str[STRING_SSL_CAPATH], (char *) CURL_CA_PATH); + result = setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE); + if(result) + return result; +#endif +#if defined(CURL_CA_PATH) + result = setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH); + if(result) + return result; #endif set->wildcardmatch = FALSE; set->chunk_bgn = ZERO_NULL; set->chunk_end = ZERO_NULL; - return res; + /* tcp keepalives are disabled by default, but provide reasonable values for + * the interval and idle times. + */ + set->tcp_keepalive = FALSE; + set->tcp_keepintvl = 60; + set->tcp_keepidle = 60; + + set->ssl_enable_npn = TRUE; + set->ssl_enable_alpn = TRUE; + + set->expect_100_timeout = 1000L; /* Wait for a second by default. */ + set->sep_headers = TRUE; /* separated header lists by default */ + + Curl_http2_init_userset(set); + return result; } /** @@ -802,11 +635,8 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) CURLcode Curl_open(struct SessionHandle **curl) { - CURLcode res = CURLE_OK; + CURLcode result; struct SessionHandle *data; -#ifdef USE_ARES - int status; -#endif /* Very simple start-up: alloc the struct, init it with zeroes and return */ data = calloc(1, sizeof(struct SessionHandle)); @@ -818,41 +648,29 @@ CURLcode Curl_open(struct SessionHandle **curl) data->magic = CURLEASY_MAGIC_NUMBER; -#ifdef USE_ARES - if((status = ares_init(&data->state.areschannel)) != ARES_SUCCESS) { - DEBUGF(fprintf(stderr, "Error: ares_init failed\n")); + result = Curl_resolver_init(&data->state.resolver); + if(result) { + DEBUGF(fprintf(stderr, "Error: resolver_init failed\n")); free(data); - if(status == ARES_ENOMEM) - return CURLE_OUT_OF_MEMORY; - else - return CURLE_FAILED_INIT; + return result; } - /* make sure that all other returns from this function should destroy the - ares channel before returning error! */ -#endif /* We do some initial setup here, all those fields that can't be just 0 */ data->state.headerbuff = malloc(HEADERSIZE); if(!data->state.headerbuff) { DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n")); - res = CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; } else { - Curl_easy_initHandleData(data); - res = Curl_init_userdefined(&data->set); + result = Curl_init_userdefined(&data->set); data->state.headersize=HEADERSIZE; -#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) - /* conversion descriptors for iconv calls */ - data->outbound_cd = (iconv_t)-1; - data->inbound_cd = (iconv_t)-1; - data->utf8_cd = (iconv_t)-1; -#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ + Curl_convert_init(data); /* most recent connection is not yet defined */ - data->state.lastconnect = -1; + data->state.lastconnect = NULL; data->progress.flags |= PGRS_HIDE; data->state.current_speed = -1; /* init to negative == impossible */ @@ -860,15 +678,14 @@ CURLcode Curl_open(struct SessionHandle **curl) data->wildcard.state = CURLWC_INIT; data->wildcard.filelist = NULL; data->set.fnmatch = ZERO_NULL; - /* This no longer creates a connection cache here. It is instead made on - the first call to curl_easy_perform() or when the handle is added to a - multi stack. */ + data->set.maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ + + Curl_http2_init_state(&data->state); } - if(res) { - ares_destroy(data->state.areschannel); - if(data->state.headerbuff) - free(data->state.headerbuff); + if(result) { + Curl_resolver_cleanup(data->state.resolver); + free(data->state.headerbuff); Curl_freeset(data); free(data); data = NULL; @@ -876,7 +693,7 @@ CURLcode Curl_open(struct SessionHandle **curl) else *curl = data; - return res; + return result; } CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, @@ -884,6 +701,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, { char *argptr; CURLcode result = CURLE_OK; + long arg; #ifndef CURL_DISABLE_HTTP curl_off_t bigsize; #endif @@ -893,12 +711,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.dns_cache_timeout = va_arg(param, long); break; case CURLOPT_DNS_USE_GLOBAL_CACHE: - { /* remember we want this enabled */ - long use_cache = va_arg(param, long); - data->set.global_dns_cache = (bool)(0 != use_cache); - } - break; + arg = va_arg(param, long); + data->set.global_dns_cache = (0 != arg)?TRUE:FALSE; + break; case CURLOPT_SSL_CIPHER_LIST: /* set a list of cipher we want to use in the SSL connection */ result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST], @@ -925,40 +741,40 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Set the absolute number of maximum simultaneous alive connection that * libcurl is allowed to have. */ - result = Curl_ch_connc(data, data->state.connc, va_arg(param, long)); + data->set.maxconnects = va_arg(param, long); break; case CURLOPT_FORBID_REUSE: /* * When this transfer is done, it must not be left to be reused by a * subsequent transfer but shall be closed immediately. */ - data->set.reuse_forbid = (bool)(0 != va_arg(param, long)); + data->set.reuse_forbid = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FRESH_CONNECT: /* * This transfer shall not use a previously cached connection but * should be made with a fresh new connect! */ - data->set.reuse_fresh = (bool)(0 != va_arg(param, long)); + data->set.reuse_fresh = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_VERBOSE: /* * Verbose means infof() calls that give a lot of information about * the connection and transfer procedures as well as internal choices. */ - data->set.verbose = (bool)(0 != va_arg(param, long)); + data->set.verbose = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_HEADER: /* * Set to include the header in the general data output stream. */ - data->set.include_header = (bool)(0 != va_arg(param, long)); + data->set.include_header = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_NOPROGRESS: /* * Shut off the internal supported progress meter */ - data->set.hide_progress = (bool)(0 != va_arg(param, long)); + data->set.hide_progress = (0 != va_arg(param, long))?TRUE:FALSE; if(data->set.hide_progress) data->progress.flags |= PGRS_HIDE; else @@ -968,14 +784,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Do not include the body part in the output data stream. */ - data->set.opt_no_body = (bool)(0 != va_arg(param, long)); + data->set.opt_no_body = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FAILONERROR: /* - * Don't output the >=300 error code HTML-page, but instead only + * Don't output the >=400 error code HTML-page, but instead only * return error. */ - data->set.http_fail_on_error = (bool)(0 != va_arg(param, long)); + data->set.http_fail_on_error = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_UPLOAD: case CURLOPT_PUT: @@ -983,7 +799,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * We want to sent data to the remote host. If this is HTTP, that equals * using the PUT request. */ - data->set.upload = (bool)(0 != va_arg(param, long)); + data->set.upload = (0 != va_arg(param, long))?TRUE:FALSE; if(data->set.upload) { /* If this is HTTP, PUT is what's needed to "upload" */ data->set.httpreq = HTTPREQ_PUT; @@ -999,7 +815,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Try to get the file time of the remote document. The time will * later (possibly) become available using curl_easy_getinfo(). */ - data->set.get_filetime = (bool)(0 != va_arg(param, long)); + data->set.get_filetime = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_CREATE_MISSING_DIRS: /* @@ -1018,7 +834,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; default: /* reserve other values for future use */ - result = CURLE_FAILED_INIT; + result = CURLE_UNKNOWN_OPTION; break; } break; @@ -1029,9 +845,16 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ data->set.server_response_timeout = va_arg( param , long ) * 1000; break; + case CURLOPT_TFTP_NO_OPTIONS: + /* + * Option that prevents libcurl from sending TFTP option requests to the + * server. + */ + data->set.tftp_no_options = va_arg(param, long) != 0; + break; case CURLOPT_TFTP_BLKSIZE: /* - * TFTP option that specifies the block size to use for data transmission + * TFTP option that specifies the block size to use for data transmission. */ data->set.tftp_blksize = va_arg(param, long); break; @@ -1040,13 +863,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * An option that changes the command to one that asks for a list * only, no file info details. */ - data->set.ftp_list_only = (bool)(0 != va_arg(param, long)); + data->set.ftp_list_only = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_APPEND: /* * We want to upload and append to an existing file. */ - data->set.ftp_append = (bool)(0 != va_arg(param, long)); + data->set.ftp_append = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_FILEMETHOD: /* @@ -1074,7 +897,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * * Transfer using ASCII (instead of BINARY). */ - data->set.prefer_ascii = (bool)(0 != va_arg(param, long)); + data->set.prefer_ascii = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_TIMECONDITION: /* @@ -1095,7 +918,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Set explicit SSL version to try to connect with, as some SSL * implementations are lame. */ +#ifdef USE_SSL data->set.ssl.version = va_arg(param, long); +#else + result = CURLE_UNKNOWN_OPTION; +#endif break; #ifndef CURL_DISABLE_HTTP @@ -1103,10 +930,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Switch on automatic referer that gets set if curl follows locations. */ - data->set.http_auto_referer = (bool)(0 != va_arg(param, long)); + data->set.http_auto_referer = (0 != va_arg(param, long))?TRUE:FALSE; break; - case CURLOPT_ENCODING: + case CURLOPT_ACCEPT_ENCODING: /* * String to use at the value of Accept-Encoding header. * @@ -1119,14 +946,18 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, argptr = va_arg(param, char *); result = setstropt(&data->set.str[STRING_ENCODING], (argptr && !*argptr)? - (char *) ALL_CONTENT_ENCODINGS: argptr); + ALL_CONTENT_ENCODINGS: argptr); + break; + + case CURLOPT_TRANSFER_ENCODING: + data->set.http_transfer_encoding = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FOLLOWLOCATION: /* * Follow Location: header hints on a HTTP-server. */ - data->set.http_follow_location = (bool)(0 != va_arg(param, long)); + data->set.http_follow_location = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_UNRESTRICTED_AUTH: @@ -1135,7 +966,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * hostname changed. */ data->set.http_disable_hostname_check_before_authentication = - (bool)(0 != va_arg(param, long)); + (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_MAXREDIRS: @@ -1153,12 +984,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302 * CURL_REDIR_POST_301 - POST is kept as POST after 301 * CURL_REDIR_POST_302 - POST is kept as POST after 302 - * CURL_REDIR_POST_ALL - POST is kept as POST after 301 and 302 + * CURL_REDIR_POST_303 - POST is kept as POST after 303 + * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303 * other - POST is kept as POST after 301 and 302 */ - long postRedir = va_arg(param, long); - data->set.post301 = (bool)((postRedir & CURL_REDIR_POST_301)?TRUE:FALSE); - data->set.post302 = (bool)((postRedir & CURL_REDIR_POST_302)?TRUE:FALSE); + int postRedir = curlx_sltosi(va_arg(param, long)); + data->set.keep_post = postRedir & CURL_REDIR_POST_ALL; } break; @@ -1279,7 +1110,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * String to set in the HTTP Referer: field. */ if(data->change.referer_alloc) { - free(data->change.referer); + Curl_safefree(data->change.referer); data->change.referer_alloc = FALSE; } result = setstropt(&data->set.str[STRING_SET_REFERER], @@ -1302,6 +1133,28 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.headers = va_arg(param, struct curl_slist *); break; + case CURLOPT_PROXYHEADER: + /* + * Set a list with proxy headers to use (or replace internals with) + * + * Since CURLOPT_HTTPHEADER was the only way to set HTTP headers for a + * long time we remain doing it this way until CURLOPT_PROXYHEADER is + * used. As soon as this option has been used, if set to anything but + * NULL, custom headers for proxies are only picked from this list. + * + * Set this option to NULL to restore the previous behavior. + */ + data->set.proxyheaders = va_arg(param, struct curl_slist *); + break; + + case CURLOPT_HEADEROPT: + /* + * Set header option. + */ + arg = va_arg(param, long); + data->set.sep_headers = (arg & CURLHEADER_SEPARATE)? TRUE: FALSE; + break; + case CURLOPT_HTTP200ALIASES: /* * Set a list of aliases for HTTP 200 in response header @@ -1328,10 +1181,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* append the cookie file name to the list of file names, and deal with them later */ cl = curl_slist_append(data->change.cookielist, argptr); - - if(!cl) + if(!cl) { + curl_slist_free_all(data->change.cookielist); + data->change.cookielist = NULL; return CURLE_OUT_OF_MEMORY; - + } data->change.cookielist = cl; /* store the list for later use */ } break; @@ -1340,6 +1194,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Set cookie file name to dump all cookies to when we're done. */ + { + struct CookieInfo *newcookies; result = setstropt(&data->set.str[STRING_COOKIEJAR], va_arg(param, char *)); @@ -1347,8 +1203,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Activate the cookie parser. This may or may not already * have been made. */ - data->cookies = Curl_cookie_init(data, NULL, data->cookies, - data->set.cookiesession); + newcookies = Curl_cookie_init(data, NULL, data->cookies, + data->set.cookiesession); + if(!newcookies) + result = CURLE_OUT_OF_MEMORY; + data->cookies = newcookies; + } break; case CURLOPT_COOKIESESSION: @@ -1367,7 +1227,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * We run mostly with the original cookie spec, as hardly anyone implements * anything else. */ - data->set.cookiesession = (bool)(0 != va_arg(param, long)); + data->set.cookiesession = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_COOKIELIST: @@ -1378,39 +1238,51 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, if(Curl_raw_equal(argptr, "ALL")) { /* clear all cookies */ + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_clearall(data->cookies); - break; + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } else if(Curl_raw_equal(argptr, "SESS")) { /* clear session cookies */ + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_clearsess(data->cookies); - break; + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } else if(Curl_raw_equal(argptr, "FLUSH")) { - /* flush cookies to file */ - flush_cookies(data, 0); + /* flush cookies to file, takes care of the locking */ + Curl_flush_cookies(data, 0); + } + else if(Curl_raw_equal(argptr, "RELOAD")) { + /* reload cookies from file */ + Curl_cookie_loadfiles(data); break; } + else { + if(!data->cookies) + /* if cookie engine was not running, activate it */ + data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE); - if(!data->cookies) - /* if cookie engine was not running, activate it */ - data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE); + argptr = strdup(argptr); + if(!argptr || !data->cookies) { + result = CURLE_OUT_OF_MEMORY; + free(argptr); + } + else { + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - argptr = strdup(argptr); - if(!argptr) { - result = CURLE_OUT_OF_MEMORY; - break; + if(checkprefix("Set-Cookie:", argptr)) + /* HTTP Header format line */ + Curl_cookie_add(data, data->cookies, TRUE, argptr + 11, NULL, NULL); + + else + /* Netscape format line */ + Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL); + + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + free(argptr); + } } - if(checkprefix("Set-Cookie:", argptr)) - /* HTTP Header format line */ - Curl_cookie_add(data, data->cookies, TRUE, argptr + 11, NULL, NULL); - - else - /* Netscape format line */ - Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL); - - free(argptr); break; #endif /* CURL_DISABLE_COOKIES */ @@ -1430,7 +1302,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * This sets a requested HTTP version to be used. The value is one of * the listed enums in curl/curl.h. */ - data->set.httpversion = va_arg(param, long); + arg = va_arg(param, long); +#ifndef USE_NGHTTP2 + if(arg >= CURL_HTTP_VERSION_2) + return CURLE_UNSUPPORTED_PROTOCOL; +#endif + data->set.httpversion = arg; break; case CURLOPT_HTTPAUTH: @@ -1438,12 +1315,18 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Set HTTP Authentication type BITMASK. */ { - long auth = va_arg(param, long); + int bitcheck; + bool authbits; + unsigned long auth = va_arg(param, unsigned long); + + if(auth == CURLAUTH_NONE) { + data->set.httpauth = auth; + break; + } /* the DIGEST_IE bit is only used to set a special marker, for all the rest we need to handle it as normal DIGEST */ - data->state.authhost.iestyle = (bool)((auth & CURLAUTH_DIGEST_IE)? - TRUE:FALSE); + data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE)?TRUE:FALSE; if(auth & CURLAUTH_DIGEST_IE) { auth |= CURLAUTH_DIGEST; /* set standard digest bit */ @@ -1452,18 +1335,40 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* switch off bits we can't support */ #ifndef USE_NTLM - auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */ + auth &= ~CURLAUTH_NTLM; /* no NTLM support */ + auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ +#elif !defined(NTLM_WB_ENABLED) + auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ #endif -#ifndef HAVE_GSSAPI - auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI */ +#ifndef USE_SPNEGO + auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without + GSS-API or SSPI */ #endif - if(!auth) - return CURLE_FAILED_INIT; /* no supported types left! */ + + /* check if any auth bit lower than CURLAUTH_ONLY is still set */ + bitcheck = 0; + authbits = FALSE; + while(bitcheck < 31) { + if(auth & (1UL << bitcheck++)) { + authbits = TRUE; + break; + } + } + if(!authbits) + return CURLE_NOT_BUILT_IN; /* no supported types left! */ data->set.httpauth = auth; } break; + case CURLOPT_EXPECT_100_TIMEOUT_MS: + /* + * Time to wait for a response to a HTTP request containing an + * Expect: 100-continue header before sending the data anyway. + */ + data->set.expect_100_timeout = va_arg(param, long); + break; + #endif /* CURL_DISABLE_HTTP */ case CURLOPT_CUSTOMREQUEST: @@ -1484,7 +1389,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Tunnel operations through the proxy instead of normal proxy use */ - data->set.tunnel_thru_httpproxy = (bool)(0 != va_arg(param, long)); + data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_PROXYPORT: @@ -1499,12 +1404,18 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Set HTTP Authentication type BITMASK. */ { - long auth = va_arg(param, long); + int bitcheck; + bool authbits; + unsigned long auth = va_arg(param, unsigned long); + + if(auth == CURLAUTH_NONE) { + data->set.proxyauth = auth; + break; + } /* the DIGEST_IE bit is only used to set a special marker, for all the rest we need to handle it as normal DIGEST */ - data->state.authproxy.iestyle = (bool)((auth & CURLAUTH_DIGEST_IE)? - TRUE:FALSE); + data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE)?TRUE:FALSE; if(auth & CURLAUTH_DIGEST_IE) { auth |= CURLAUTH_DIGEST; /* set standard digest bit */ @@ -1512,13 +1423,27 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, } /* switch off bits we can't support */ #ifndef USE_NTLM - auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */ + auth &= ~CURLAUTH_NTLM; /* no NTLM support */ + auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ +#elif !defined(NTLM_WB_ENABLED) + auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ #endif -#ifndef HAVE_GSSAPI - auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI */ +#ifndef USE_SPNEGO + auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without + GSS-API or SSPI */ #endif - if(!auth) - return CURLE_FAILED_INIT; /* no supported types left! */ + + /* check if any auth bit lower than CURLAUTH_ONLY is still set */ + bitcheck = 0; + authbits = FALSE; + while(bitcheck < 31) { + if(auth & (1UL << bitcheck++)) { + authbits = TRUE; + break; + } + } + if(!authbits) + return CURLE_NOT_BUILT_IN; /* no supported types left! */ data->set.proxyauth = auth; } @@ -1558,7 +1483,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; default: /* reserve other values for future use */ - result = CURLE_FAILED_INIT; + result = CURLE_UNKNOWN_OPTION; break; } break; @@ -1567,21 +1492,38 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) case CURLOPT_SOCKS5_GSSAPI_SERVICE: /* - * Set gssapi service name + * Set GSS-API service name */ result = setstropt(&data->set.str[STRING_SOCKS5_GSSAPI_SERVICE], va_arg(param, char *)); break; + case CURLOPT_PROXY_SERVICE_NAME: + /* + * Set negotiate proxy service name + */ + result = setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME], + va_arg(param, char *)); + break; + case CURLOPT_SOCKS5_GSSAPI_NEC: /* * set flag for nec socks5 support */ - data->set.socks5_gssapi_nec = (bool)(0 != va_arg(param, long)); + data->set.socks5_gssapi_nec = (0 != va_arg(param, long))?TRUE:FALSE; break; + + case CURLOPT_SERVICE_NAME: + /* + * Set negotiate service identity + */ + result = setstropt(&data->set.str[STRING_SERVICE_NAME], + va_arg(param, char *)); + break; + #endif - case CURLOPT_WRITEHEADER: + case CURLOPT_HEADERDATA: /* * Custom pointer to pass the header write callback function */ @@ -1594,11 +1536,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ data->set.errorbuffer = va_arg(param, char *); break; - case CURLOPT_FILE: + case CURLOPT_WRITEDATA: /* - * FILE pointer to write to or include in the data write callback + * FILE pointer to write to. Or possibly + * used as argument to the write callback. */ - data->set.out = va_arg(param, FILE *); + data->set.out = va_arg(param, void *); break; case CURLOPT_FTPPORT: /* @@ -1606,19 +1549,20 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ result = setstropt(&data->set.str[STRING_FTPPORT], va_arg(param, char *)); - data->set.ftp_use_port = (bool)(NULL != data->set.str[STRING_FTPPORT]); + data->set.ftp_use_port = (NULL != data->set.str[STRING_FTPPORT]) ? + TRUE:FALSE; break; case CURLOPT_FTP_USE_EPRT: - data->set.ftp_use_eprt = (bool)(0 != va_arg(param, long)); + data->set.ftp_use_eprt = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_USE_EPSV: - data->set.ftp_use_epsv = (bool)(0 != va_arg(param, long)); + data->set.ftp_use_epsv = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_USE_PRET: - data->set.ftp_use_pret = (bool)(0 != va_arg(param, long)); + data->set.ftp_use_pret = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_SSL_CCC: @@ -1630,29 +1574,29 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the * bypass of the IP address in PASV responses. */ - data->set.ftp_skip_ip = (bool)(0 != va_arg(param, long)); + data->set.ftp_skip_ip = (0 != va_arg(param, long))?TRUE:FALSE; break; - case CURLOPT_INFILE: + case CURLOPT_READDATA: /* * FILE pointer to read the file to be uploaded from. Or possibly * used as argument to the read callback. */ - data->set.in = va_arg(param, FILE *); + data->set.in_set = va_arg(param, void *); break; case CURLOPT_INFILESIZE: /* * If known, this should inform curl about the file size of the * to-be-uploaded file. */ - data->set.infilesize = va_arg(param, long); + data->set.filesize = va_arg(param, long); break; case CURLOPT_INFILESIZE_LARGE: /* * If known, this should inform curl about the file size of the * to-be-uploaded file. */ - data->set.infilesize = va_arg(param, curl_off_t); + data->set.filesize = va_arg(param, curl_off_t); break; case CURLOPT_LOW_SPEED_LIMIT: /* @@ -1688,8 +1632,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ if(data->change.url_alloc) { /* the already set URL is allocated, free it first! */ - free(data->change.url); - data->change.url_alloc=FALSE; + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; } result = setstropt(&data->set.str[STRING_SET_URL], va_arg(param, char *)); @@ -1724,6 +1668,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.connecttimeout = va_arg(param, long); break; + case CURLOPT_ACCEPTTIMEOUT_MS: + /* + * The maximum time you allow curl to wait for server connect + */ + data->set.accepttimeout = va_arg(param, long); + break; + case CURLOPT_USERPWD: /* * user:password to use in the operation @@ -1732,6 +1683,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, &data->set.str[STRING_USERNAME], &data->set.str[STRING_PASSWORD]); break; + case CURLOPT_USERNAME: /* * authentication user name to use in the operation @@ -1739,6 +1691,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, result = setstropt(&data->set.str[STRING_USERNAME], va_arg(param, char *)); break; + case CURLOPT_PASSWORD: /* * authentication password to use in the operation @@ -1746,6 +1699,23 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, result = setstropt(&data->set.str[STRING_PASSWORD], va_arg(param, char *)); break; + + case CURLOPT_LOGIN_OPTIONS: + /* + * authentication options to use in the operation + */ + result = setstropt(&data->set.str[STRING_OPTIONS], + va_arg(param, char *)); + break; + + case CURLOPT_XOAUTH2_BEARER: + /* + * OAuth 2.0 bearer token to use in the operation + */ + result = setstropt(&data->set.str[STRING_BEARER], + va_arg(param, char *)); + break; + case CURLOPT_POSTQUOTE: /* * List of RAW FTP commands to use after a transfer @@ -1787,8 +1757,20 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->progress.callback = TRUE; /* no longer internal */ else data->progress.callback = FALSE; /* NULL enforces internal */ + break; + + case CURLOPT_XFERINFOFUNCTION: + /* + * Transfer info callback function + */ + data->set.fxferinfo = va_arg(param, curl_xferinfo_callback); + if(data->set.fxferinfo) + data->progress.callback = TRUE; /* no longer internal */ + else + data->progress.callback = FALSE; /* NULL enforces internal */ break; + case CURLOPT_PROGRESSDATA: /* * Custom client data to pass to the progress callback @@ -1895,11 +1877,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Read data callback */ - data->set.fread_func = va_arg(param, curl_read_callback); - if(!data->set.fread_func) { + data->set.fread_func_set = va_arg(param, curl_read_callback); + if(!data->set.fread_func_set) { data->set.is_fread_set = 0; /* When set to NULL, reset to our internal default function */ - data->set.fread_func = (curl_read_callback)fread; + data->set.fread_func_set = (curl_read_callback)fread; } else data->set.is_fread_set = 1; @@ -2000,7 +1982,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Kludgy option to enable CRLF conversions. Subject for removal. */ - data->set.crlf = (bool)(0 != va_arg(param, long)); + data->set.crlf = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_INTERFACE: @@ -2029,41 +2011,95 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ result = setstropt(&data->set.str[STRING_KRB_LEVEL], va_arg(param, char *)); - data->set.krb = (bool)(NULL != data->set.str[STRING_KRB_LEVEL]); + data->set.krb = (NULL != data->set.str[STRING_KRB_LEVEL])?TRUE:FALSE; + break; + case CURLOPT_GSSAPI_DELEGATION: + /* + * GSS-API credential delegation + */ + data->set.gssapi_delegation = va_arg(param, long); break; case CURLOPT_SSL_VERIFYPEER: /* * Enable peer SSL verifying. */ - data->set.ssl.verifypeer = va_arg(param, long); + data->set.ssl.verifypeer = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_SSL_VERIFYHOST: /* - * Enable verification of the CN contained in the peer certificate + * Enable verification of the host name in the peer certificate */ - data->set.ssl.verifyhost = va_arg(param, long); + arg = va_arg(param, long); + + /* Obviously people are not reading documentation and too many thought + this argument took a boolean when it wasn't and misused it. We thus ban + 1 as a sensible input and we warn about its use. Then we only have the + 2 action internally stored as TRUE. */ + + if(1 == arg) { + failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + + data->set.ssl.verifyhost = (0 != arg)?TRUE:FALSE; + break; + case CURLOPT_SSL_VERIFYSTATUS: + /* + * Enable certificate status verifying. + */ + if(!Curl_ssl_cert_status_request()) { + result = CURLE_NOT_BUILT_IN; + break; + } + + data->set.ssl.verifystatus = (0 != va_arg(param, long))?TRUE:FALSE; break; -#ifdef USE_SSLEAY - /* since these two options are only possible to use on an OpenSSL- - powered libcurl we #ifdef them on this condition so that libcurls - built against other SSL libs will return a proper error when trying - to set this option! */ case CURLOPT_SSL_CTX_FUNCTION: +#ifdef have_curlssl_ssl_ctx /* * Set a SSL_CTX callback */ data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback); +#else + result = CURLE_NOT_BUILT_IN; +#endif break; case CURLOPT_SSL_CTX_DATA: +#ifdef have_curlssl_ssl_ctx /* * Set a SSL_CTX callback parameter pointer */ data->set.ssl.fsslctxp = va_arg(param, void *); +#else + result = CURLE_NOT_BUILT_IN; +#endif + break; + case CURLOPT_SSL_FALSESTART: + /* + * Enable TLS false start. + */ + if(!Curl_ssl_false_start()) { + result = CURLE_NOT_BUILT_IN; + break; + } + + data->set.ssl.falsestart = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_CERTINFO: - data->set.ssl.certinfo = (bool)(0 != va_arg(param, long)); - break; +#ifdef have_curlssl_certinfo + data->set.ssl.certinfo = (0 != va_arg(param, long))?TRUE:FALSE; +#else + result = CURLE_NOT_BUILT_IN; #endif + break; + case CURLOPT_PINNEDPUBLICKEY: + /* + * Set pinned public key for SSL connection. + * Specify file name of the public key in DER format. + */ + result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY], + va_arg(param, char *)); + break; case CURLOPT_CAINFO: /* * Set CA info for SSL connection. Specify file name of the CA certificate @@ -2072,6 +2108,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, va_arg(param, char *)); break; case CURLOPT_CAPATH: +#ifdef have_curlssl_ca_path /* not supported by all backends */ /* * Set CA path info for SSL connection. Specify directory name of the CA * certificates which have been prepared using openssl c_rehash utility. @@ -2079,6 +2116,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* This does not work on windows. */ result = setstropt(&data->set.str[STRING_SSL_CAPATH], va_arg(param, char *)); +#else + result = CURLE_NOT_BUILT_IN; +#endif break; case CURLOPT_CRLFILE: /* @@ -2121,7 +2161,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * The application asks not to set any signal() or alarm() handlers, * even when using a timeout. */ - data->set.no_signal = (bool)(0 != va_arg(param, long)); + data->set.no_signal = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_SHARE: @@ -2138,8 +2178,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->dns.hostcachetype = HCACHE_NONE; } +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) if(data->share->cookies == data->cookies) data->cookies = NULL; +#endif + + if(data->share->sslsession == data->state.session) + data->state.session = NULL; data->share->dirty--; @@ -2155,23 +2200,23 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->share->dirty++; - if(data->share->hostcache) { - /* use shared host cache, first free the private one if any */ - if(data->dns.hostcachetype == HCACHE_PRIVATE) - Curl_hash_destroy(data->dns.hostcache); - - data->dns.hostcache = data->share->hostcache; + if(data->share->specifier & (1<< CURL_LOCK_DATA_DNS)) { + /* use shared host cache */ + data->dns.hostcache = &data->share->hostcache; data->dns.hostcachetype = HCACHE_SHARED; } #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) if(data->share->cookies) { /* use shared cookie list, first free own one if any */ - if(data->cookies) - Curl_cookie_cleanup(data->cookies); + Curl_cookie_cleanup(data->cookies); /* enable cookies since we now use a share that uses cookies! */ data->cookies = data->share->cookies; } #endif /* CURL_DISABLE_HTTP */ + if(data->share->sslsession) { + data->set.ssl.max_ssl_sessions = data->share->max_ssl_sessions; + data->state.session = data->share->sslsession; + } Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); } @@ -2199,8 +2244,15 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Make transfers attempt to use SSL/TLS. */ - data->set.ftp_ssl = (curl_usessl)va_arg(param, long); + data->set.use_ssl = (curl_usessl)va_arg(param, long); break; + + case CURLOPT_SSL_OPTIONS: + arg = va_arg(param, long); + data->set.ssl_enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST); + data->set.ssl_no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); + break; + #endif case CURLOPT_FTPSSLAUTH: /* @@ -2225,7 +2277,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Enable or disable TCP_NODELAY, which will disable/enable the Nagle * algorithm */ - data->set.tcp_nodelay = (bool)(0 != va_arg(param, long)); + data->set.tcp_nodelay = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_ACCOUNT: @@ -2234,14 +2286,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_IGNORE_CONTENT_LENGTH: - data->set.ignorecl = (bool)(0 != va_arg(param, long)); + data->set.ignorecl = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_CONNECT_ONLY: /* * No data transfer, set up connection and let application use the socket */ - data->set.connect_only = (bool)(0 != va_arg(param, long)); + data->set.connect_only = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_ALTERNATIVE_TO_USER: @@ -2278,8 +2330,23 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.opensocket_client = va_arg(param, void *); break; + case CURLOPT_CLOSESOCKETFUNCTION: + /* + * close socket callback function: called instead of close() + * when shutting down a connection + */ + data->set.fclosesocket = va_arg(param, curl_closesocket_callback); + break; + + case CURLOPT_CLOSESOCKETDATA: + /* + * socket callback data pointer. Might be NULL. + */ + data->set.closesocket_client = va_arg(param, void *); + break; + case CURLOPT_SSL_SESSIONID_CACHE: - data->set.ssl.sessionid = (bool)(0 != va_arg(param, long)); + data->set.ssl.sessionid = (0 != va_arg(param, long))?TRUE:FALSE; break; #ifdef USE_LIBSSH2 @@ -2340,14 +2407,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * disable libcurl transfer encoding is used */ - data->set.http_te_skip = (bool)(0 == va_arg(param, long)); + data->set.http_te_skip = (0 == va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_HTTP_CONTENT_DECODING: /* * raw data passed to the application when content encoding is used */ - data->set.http_ce_skip = (bool)(0 == va_arg(param, long)); + data->set.http_ce_skip = (0 == va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_NEW_FILE_PERMS: @@ -2370,7 +2437,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * know that an unsigned int will always hold the value so we blindly * typecast to this type */ - data->set.scope = curlx_sltoui(va_arg(param, long)); + data->set.scope_id = curlx_sltoui(va_arg(param, long)); break; case CURLOPT_PROTOCOLS: @@ -2378,7 +2445,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, transfer, which thus helps the app which takes URLs from users or other external inputs and want to restrict what protocol(s) to deal with. Defaults to CURLPROTO_ALL. */ - data->set.allowed_protocols = va_arg(param, long) & PROT_EXTMASK; + data->set.allowed_protocols = va_arg(param, long); break; case CURLOPT_REDIR_PROTOCOLS: @@ -2386,19 +2453,37 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs to be set in both bitmasks to be allowed to get redirected to. Defaults to all protocols except FILE and SCP. */ - data->set.redir_protocols = va_arg(param, long) & PROT_EXTMASK; + data->set.redir_protocols = va_arg(param, long); + break; + + case CURLOPT_DEFAULT_PROTOCOL: + /* Set the protocol to use when the URL doesn't include any protocol */ + result = setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL], + va_arg(param, char *)); break; case CURLOPT_MAIL_FROM: + /* Set the SMTP mail originator */ result = setstropt(&data->set.str[STRING_MAIL_FROM], va_arg(param, char *)); break; + case CURLOPT_MAIL_AUTH: + /* Set the SMTP auth originator */ + result = setstropt(&data->set.str[STRING_MAIL_AUTH], + va_arg(param, char *)); + break; + case CURLOPT_MAIL_RCPT: - /* get a list of mail recipients */ + /* Set the list of mail recipients */ data->set.mail_rcpt = va_arg(param, struct curl_slist *); break; + case CURLOPT_SASL_IR: + /* Enable/disable SASL initial response */ + data->set.sasl_ir = (0 != va_arg(param, long)) ? TRUE : FALSE; + break; + case CURLOPT_RTSP_REQUEST: { /* @@ -2509,7 +2594,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_WILDCARDMATCH: - data->set.wildcardmatch = (bool)(0 != va_arg(param, long)); + data->set.wildcardmatch = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_CHUNK_BGN_FUNCTION: data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback); @@ -2526,9 +2611,94 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, case CURLOPT_FNMATCH_DATA: data->set.fnmatch_data = va_arg(param, void *); break; +#ifdef USE_TLS_SRP + case CURLOPT_TLSAUTH_USERNAME: + result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME], + va_arg(param, char *)); + if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype) + data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ + break; + case CURLOPT_TLSAUTH_PASSWORD: + result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD], + va_arg(param, char *)); + if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype) + data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ + break; + case CURLOPT_TLSAUTH_TYPE: + if(strnequal((char *)va_arg(param, char *), "SRP", strlen("SRP"))) + data->set.ssl.authtype = CURL_TLSAUTH_SRP; + else + data->set.ssl.authtype = CURL_TLSAUTH_NONE; + break; +#endif + case CURLOPT_DNS_SERVERS: + result = Curl_set_dns_servers(data, va_arg(param, char *)); + break; + case CURLOPT_DNS_INTERFACE: + result = Curl_set_dns_interface(data, va_arg(param, char *)); + break; + case CURLOPT_DNS_LOCAL_IP4: + result = Curl_set_dns_local_ip4(data, va_arg(param, char *)); + break; + case CURLOPT_DNS_LOCAL_IP6: + result = Curl_set_dns_local_ip6(data, va_arg(param, char *)); + break; + + case CURLOPT_TCP_KEEPALIVE: + data->set.tcp_keepalive = (0 != va_arg(param, long))?TRUE:FALSE; + break; + case CURLOPT_TCP_KEEPIDLE: + data->set.tcp_keepidle = va_arg(param, long); + break; + case CURLOPT_TCP_KEEPINTVL: + data->set.tcp_keepintvl = va_arg(param, long); + break; + case CURLOPT_SSL_ENABLE_NPN: + data->set.ssl_enable_npn = (0 != va_arg(param, long))?TRUE:FALSE; + break; + case CURLOPT_SSL_ENABLE_ALPN: + data->set.ssl_enable_alpn = (0 != va_arg(param, long))?TRUE:FALSE; + break; + +#ifdef USE_UNIX_SOCKETS + case CURLOPT_UNIX_SOCKET_PATH: + result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], + va_arg(param, char *)); + break; +#endif + + case CURLOPT_PATH_AS_IS: + data->set.path_as_is = (0 != va_arg(param, long))?TRUE:FALSE; + break; + case CURLOPT_PIPEWAIT: + data->set.pipewait = (0 != va_arg(param, long))?TRUE:FALSE; + break; + case CURLOPT_STREAM_WEIGHT: +#ifndef USE_NGHTTP2 + return CURLE_NOT_BUILT_IN; +#else + arg = va_arg(param, long); + if((arg>=1) && (arg <= 256)) + data->set.stream_weight = (int)arg; + break; +#endif + case CURLOPT_STREAM_DEPENDS: + case CURLOPT_STREAM_DEPENDS_E: + { +#ifndef USE_NGHTTP2 + return CURLE_NOT_BUILT_IN; +#else + struct SessionHandle *dep = va_arg(param, struct SessionHandle *); + if(dep && GOOD_EASY_HANDLE(dep)) { + data->set.stream_depends_on = dep; + data->set.stream_depends_e = (option == CURLOPT_STREAM_DEPENDS_E); + } + break; +#endif + } default: /* unknown tag and its companion, just ignore: */ - result = CURLE_FAILED_INIT; /* correct this */ + result = CURLE_UNKNOWN_OPTION; break; } @@ -2540,6 +2710,9 @@ static void conn_free(struct connectdata *conn) if(!conn) return; + /* possible left-overs from the async name resolvers */ + Curl_resolver_cancel(conn); + /* close the SSL stuff before we close any sockets since they will/may write to the sockets */ Curl_ssl_close(conn, FIRSTSOCKET); @@ -2547,18 +2720,30 @@ static void conn_free(struct connectdata *conn) /* close possibly still open sockets */ if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) - sclose(conn->sock[SECONDARYSOCKET]); + Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET]) - sclose(conn->sock[FIRSTSOCKET]); + Curl_closesocket(conn, conn->sock[FIRSTSOCKET]); + if(CURL_SOCKET_BAD != conn->tempsock[0]) + Curl_closesocket(conn, conn->tempsock[0]); + if(CURL_SOCKET_BAD != conn->tempsock[1]) + Curl_closesocket(conn, conn->tempsock[1]); + +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ + defined(NTLM_WB_ENABLED) + Curl_ntlm_wb_cleanup(conn); +#endif Curl_safefree(conn->user); Curl_safefree(conn->passwd); + Curl_safefree(conn->oauth_bearer); + Curl_safefree(conn->options); Curl_safefree(conn->proxyuser); Curl_safefree(conn->proxypasswd); Curl_safefree(conn->allocptr.proxyuserpwd); Curl_safefree(conn->allocptr.uagent); Curl_safefree(conn->allocptr.userpwd); Curl_safefree(conn->allocptr.accept_encoding); + Curl_safefree(conn->allocptr.te); Curl_safefree(conn->allocptr.rangeline); Curl_safefree(conn->allocptr.ref); Curl_safefree(conn->allocptr.host); @@ -2571,22 +2756,26 @@ static void conn_free(struct connectdata *conn) Curl_llist_destroy(conn->send_pipe, NULL); Curl_llist_destroy(conn->recv_pipe, NULL); - Curl_llist_destroy(conn->pend_pipe, NULL); - Curl_llist_destroy(conn->done_pipe, NULL); - /* possible left-overs from the async name resolvers */ -#if defined(CURLRES_THREADED) - Curl_destroy_thread_data(&conn->async); -#elif defined(CURLRES_ASYNCH) - Curl_safefree(conn->async.hostname); - Curl_safefree(conn->async.os_specific); -#endif + conn->send_pipe = NULL; + conn->recv_pipe = NULL; + Curl_safefree(conn->localdev); Curl_free_ssl_config(&conn->ssl_config); free(conn); /* free all the connection oriented data */ } +/* + * Disconnects the given connection. Note the connection may not be the + * primary connection, like when freeing room in the connection cache or + * killing of a dead old connection. + * + * This function MUST NOT reset state in the SessionHandle struct if that + * isn't strictly bound to the life-time of *this* particular connection. + * + */ + CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) { struct SessionHandle *data; @@ -2595,7 +2784,7 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) data = conn->data; if(!data) { - DEBUGF(infof(data, "DISCONNECT without easy handle, ignoring\n")); + DEBUGF(fprintf(stderr, "DISCONNECT without easy handle, ignoring\n")); return CURLE_OK; } @@ -2604,83 +2793,33 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) conn->dns_entry = NULL; } -#if defined(DEBUGBUILD) && defined(AGGRESIVE_TEST) - /* scan for DNS cache entries still marked as in use */ - Curl_hash_apply(data->hostcache, - NULL, Curl_scan_cache_used); -#endif - Curl_hostcache_prune(data); /* kill old DNS cache entries */ - { - int has_host_ntlm = (conn->ntlm.state != NTLMSTATE_NONE); - int has_proxy_ntlm = (conn->proxyntlm.state != NTLMSTATE_NONE); - - /* Authentication data is a mix of connection-related and sessionhandle- - related stuff. NTLM is connection-related so when we close the shop - we shall forget. */ - - if (has_host_ntlm) { - data->state.authhost.done = FALSE; - data->state.authhost.picked = - data->state.authhost.want; - } - - if (has_proxy_ntlm) { - data->state.authproxy.done = FALSE; - data->state.authproxy.picked = - data->state.authproxy.want; - } - - if (has_host_ntlm || has_proxy_ntlm) { - data->state.authproblem = FALSE; - - Curl_ntlm_cleanup(conn); - } - } - - /* Cleanup possible redirect junk */ - if(data->req.newurl) { - free(data->req.newurl); - data->req.newurl = NULL; - } +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) + /* Cleanup NTLM connection-related data */ + Curl_http_ntlm_cleanup(conn); +#endif if(conn->handler->disconnect) /* This is set if protocol-specific cleanups should be made */ conn->handler->disconnect(conn, dead_connection); - if(-1 != conn->connectindex) { /* unlink ourselves! */ - infof(data, "Closing connection #%ld\n", conn->connectindex); - if(data->state.connc) - /* only clear the table entry if we still know in which cache we - used to be in */ - data->state.connc->connects[conn->connectindex] = NULL; - } + infof(data, "Closing connection %ld\n", conn->connection_id); + Curl_conncache_remove_conn(data->state.conn_cache, conn); -#ifdef USE_LIBIDN - if(conn->host.encalloc) - idn_free(conn->host.encalloc); /* encoded host name buffer, must be freed - with idn_free() since this was allocated - by libidn */ - if(conn->proxy.encalloc) - idn_free(conn->proxy.encalloc); /* encoded proxy name buffer, must be - freed with idn_free() since this was - allocated by libidn */ -#endif + free_fixed_hostname(&conn->host); + free_fixed_hostname(&conn->proxy); Curl_ssl_close(conn, FIRSTSOCKET); /* Indicate to all handles on the pipe that we're dead */ - if(Curl_isPipeliningEnabled(data)) { + if(Curl_pipeline_wanted(data->multi, CURLPIPE_ANY)) { signalPipeClose(conn->send_pipe, TRUE); signalPipeClose(conn->recv_pipe, TRUE); - signalPipeClose(conn->pend_pipe, TRUE); - signalPipeClose(conn->done_pipe, FALSE); } conn_free(conn); - data->state.current_conn = NULL; return CURLE_OK; } @@ -2703,82 +2842,45 @@ static bool SocketIsDead(curl_socket_t sock) return ret_val; } -#ifndef CURL_DISABLE_RTSP /* - * The server may send us RTP data at any point, and RTSPREQ_RECEIVE does not - * want to block the application forever while receiving a stream. Therefore, - * we cannot assume that an RTSP socket is dead just because it is readable. - * - * Instead, if it is readable, run Curl_getconnectinfo() to peek at the socket - * and distinguish between closed and data. + * IsPipeliningPossible() returns TRUE if the options set would allow + * pipelining/multiplexing and the connection is using a HTTP protocol. */ -static bool RTSPConnIsDead(struct connectdata *check) -{ - int sval; - bool ret_val = TRUE; - - sval = Curl_socket_ready(check->sock[FIRSTSOCKET], CURL_SOCKET_BAD, 0); - if(sval == 0) { - /* timeout */ - ret_val = FALSE; - } - else if (sval & CURL_CSELECT_ERR) { - /* socket is in an error state */ - ret_val = TRUE; - } - else if (sval & CURL_CSELECT_IN) { - /* readable with no error. could be closed or could be alive */ - curl_socket_t connectinfo = - Curl_getconnectinfo(check->data, &check); - if(connectinfo != CURL_SOCKET_BAD) - ret_val = FALSE; - } - - return ret_val; -} -#endif /* CURL_DISABLE_RTSP */ - static bool IsPipeliningPossible(const struct SessionHandle *handle, const struct connectdata *conn) { - if((conn->handler->protocol & PROT_HTTP) && - handle->multi && Curl_multi_canPipeline(handle->multi) && - (handle->set.httpreq == HTTPREQ_GET || - handle->set.httpreq == HTTPREQ_HEAD) && - handle->set.httpversion != CURL_HTTP_VERSION_1_0) - return TRUE; + /* If a HTTP protocol and pipelining is enabled */ + if(conn->handler->protocol & PROTO_FAMILY_HTTP) { + if(Curl_pipeline_wanted(handle->multi, CURLPIPE_HTTP1) && + (handle->set.httpversion != CURL_HTTP_VERSION_1_0) && + (handle->set.httpreq == HTTPREQ_GET || + handle->set.httpreq == HTTPREQ_HEAD)) + /* didn't ask for HTTP/1.0 and a GET or HEAD */ + return TRUE; + + if(Curl_pipeline_wanted(handle->multi, CURLPIPE_MULTIPLEX) && + (handle->set.httpversion >= CURL_HTTP_VERSION_2)) + /* allows HTTP/2 */ + return TRUE; + } return FALSE; } -bool Curl_isPipeliningEnabled(const struct SessionHandle *handle) -{ - if(handle->multi && Curl_multi_canPipeline(handle->multi)) - return TRUE; - - return FALSE; -} - -CURLcode Curl_addHandleToPipeline(struct SessionHandle *data, - struct curl_llist *pipeline) -{ - if(!Curl_llist_insert_next(pipeline, pipeline->tail, data)) - return CURLE_OUT_OF_MEMORY; - return CURLE_OK; -} - int Curl_removeHandleFromPipeline(struct SessionHandle *handle, struct curl_llist *pipeline) { - struct curl_llist_element *curr; + if(pipeline) { + struct curl_llist_element *curr; - curr = pipeline->head; - while(curr) { - if(curr->ptr == handle) { - Curl_llist_remove(pipeline, curr, NULL); - return 1; /* we removed a handle */ + curr = pipeline->head; + while(curr) { + if(curr->ptr == handle) { + Curl_llist_remove(pipeline, curr, NULL); + return 1; /* we removed a handle */ + } + curr = curr->next; } - curr = curr->next; } return 0; @@ -2813,18 +2915,15 @@ static struct SessionHandle* gethandleathead(struct curl_llist *pipeline) void Curl_getoff_all_pipelines(struct SessionHandle *data, struct connectdata *conn) { - bool recv_head = (bool)(conn->readchannel_inuse && - (gethandleathead(conn->recv_pipe) == data)); - - bool send_head = (bool)(conn->writechannel_inuse && - (gethandleathead(conn->send_pipe) == data)); + bool recv_head = (conn->readchannel_inuse && + Curl_recvpipe_head(data, conn)); + bool send_head = (conn->writechannel_inuse && + Curl_sendpipe_head(data, conn)); if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) && recv_head) - conn->readchannel_inuse = FALSE; + Curl_pipeline_leave_read(conn); if(Curl_removeHandleFromPipeline(data, conn->send_pipe) && send_head) - conn->writechannel_inuse = FALSE; - Curl_removeHandleFromPipeline(data, conn->pend_pipe); - Curl_removeHandleFromPipeline(data, conn->done_pipe); + Curl_pipeline_leave_write(conn); } static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke) @@ -2846,14 +2945,176 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke) } #endif - if (pipe_broke) - data->state.pipe_broke = TRUE; + if(pipe_broke) + data->state.pipe_broke = TRUE; Curl_multi_handlePipeBreak(data); Curl_llist_remove(pipeline, curr, NULL); curr = next; } } +/* + * This function finds the connection in the connection + * cache that has been unused for the longest time. + * + * Returns the pointer to the oldest idle connection, or NULL if none was + * found. + */ +static struct connectdata * +find_oldest_idle_connection(struct SessionHandle *data) +{ + struct conncache *bc = data->state.conn_cache; + struct curl_hash_iterator iter; + struct curl_llist_element *curr; + struct curl_hash_element *he; + long highscore=-1; + long score; + struct timeval now; + struct connectdata *conn_candidate = NULL; + struct connectbundle *bundle; + + now = Curl_tvnow(); + + Curl_hash_start_iterate(&bc->hash, &iter); + + he = Curl_hash_next_element(&iter); + while(he) { + struct connectdata *conn; + + bundle = he->ptr; + + curr = bundle->conn_list->head; + while(curr) { + conn = curr->ptr; + + if(!conn->inuse) { + /* Set higher score for the age passed since the connection was used */ + score = Curl_tvdiff(now, conn->now); + + if(score > highscore) { + highscore = score; + conn_candidate = conn; + } + } + curr = curr->next; + } + + he = Curl_hash_next_element(&iter); + } + + return conn_candidate; +} + +/* + * This function finds the connection in the connection + * bundle that has been unused for the longest time. + * + * Returns the pointer to the oldest idle connection, or NULL if none was + * found. + */ +static struct connectdata * +find_oldest_idle_connection_in_bundle(struct SessionHandle *data, + struct connectbundle *bundle) +{ + struct curl_llist_element *curr; + long highscore=-1; + long score; + struct timeval now; + struct connectdata *conn_candidate = NULL; + struct connectdata *conn; + + (void)data; + + now = Curl_tvnow(); + + curr = bundle->conn_list->head; + while(curr) { + conn = curr->ptr; + + if(!conn->inuse) { + /* Set higher score for the age passed since the connection was used */ + score = Curl_tvdiff(now, conn->now); + + if(score > highscore) { + highscore = score; + conn_candidate = conn; + } + } + curr = curr->next; + } + + return conn_candidate; +} + +/* + * This function checks if given connection is dead and disconnects if so. + * (That also removes it from the connection cache.) + * + * Returns TRUE if the connection actually was dead and disconnected. + */ +static bool disconnect_if_dead(struct connectdata *conn, + struct SessionHandle *data) +{ + size_t pipeLen = conn->send_pipe->size + conn->recv_pipe->size; + if(!pipeLen && !conn->inuse) { + /* The check for a dead socket makes sense only if there are no + handles in pipeline and the connection isn't already marked in + use */ + bool dead; + if(conn->handler->protocol & CURLPROTO_RTSP) + /* RTSP is a special case due to RTP interleaving */ + dead = Curl_rtsp_connisdead(conn); + else + dead = SocketIsDead(conn->sock[FIRSTSOCKET]); + + if(dead) { + conn->data = data; + infof(data, "Connection %ld seems to be dead!\n", conn->connection_id); + + /* disconnect resources */ + Curl_disconnect(conn, /* dead_connection */TRUE); + return TRUE; + } + } + return FALSE; +} + +/* + * Wrapper to use disconnect_if_dead() function in Curl_conncache_foreach() + * + * Returns always 0. + */ +static int call_disconnect_if_dead(struct connectdata *conn, + void *param) +{ + struct SessionHandle* data = (struct SessionHandle*)param; + disconnect_if_dead(conn, data); + return 0; /* continue iteration */ +} + +/* + * This function scans the connection cache for half-open/dead connections, + * closes and removes them. + * The cleanup is done at most once per second. + */ +static void prune_dead_connections(struct SessionHandle *data) +{ + struct timeval now = Curl_tvnow(); + long elapsed = Curl_tvdiff(now, data->state.conn_cache->last_cleanup); + + if(elapsed >= 1000L) { + Curl_conncache_foreach(data->state.conn_cache, data, + call_disconnect_if_dead); + data->state.conn_cache->last_cleanup = now; + } +} + + +static size_t max_pipeline_length(struct Curl_multi *multi) +{ + return multi ? multi->max_pipeline_length : 0; +} + /* * Given one filled in connection struct (named needle), this function should @@ -2863,303 +3124,405 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke) * If there is a match, this function returns TRUE - and has marked the * connection as 'in-use'. It must later be called with ConnectionDone() to * return back to 'idle' (unused) state. + * + * The force_reuse flag is set if the connection must be used, even if + * the pipelining strategy wants to open a new connection instead of reusing. */ static bool ConnectionExists(struct SessionHandle *data, struct connectdata *needle, - struct connectdata **usethis) + struct connectdata **usethis, + bool *force_reuse, + bool *waitpipe) { - long i; struct connectdata *check; + struct connectdata *chosen = 0; + bool foundPendingCandidate = FALSE; bool canPipeline = IsPipeliningPossible(data, needle); + struct connectbundle *bundle; - for(i=0; i< data->state.connc->num; i++) { - bool match = FALSE; - size_t pipeLen = 0; - /* - * Note that if we use a HTTP proxy, we check connections to that - * proxy and not to the actual remote server. - */ - check = data->state.connc->connects[i]; - if(!check) - /* NULL pointer means not filled-in entry */ - continue; +#ifdef USE_NTLM + bool wantNTLMhttp = ((data->state.authhost.want & + (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + (needle->handler->protocol & PROTO_FAMILY_HTTP)); + bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd && + ((data->state.authproxy.want & + (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + (needle->handler->protocol & PROTO_FAMILY_HTTP))); +#endif - pipeLen = check->send_pipe->size + check->recv_pipe->size; + *force_reuse = FALSE; + *waitpipe = FALSE; - if(check->connectindex == -1) { - check->connectindex = i; /* Set this appropriately since it might have - been set to -1 when the easy was removed - from the multi */ - } + /* We can't pipe if the site is blacklisted */ + if(canPipeline && Curl_pipeline_site_blacklisted(data, needle)) { + canPipeline = FALSE; + } - if(!pipeLen && !check->inuse) { - /* The check for a dead socket makes sense only if there are no - handles in pipeline and the connection isn't already marked in - use */ - bool dead; -#ifndef CURL_DISABLE_RTSP - if(check->protocol & PROT_RTSP) - /* RTSP is a special case due to RTP interleaving */ - dead = RTSPConnIsDead(check); - else -#endif /*CURL_DISABLE_RTSP*/ - dead = SocketIsDead(check->sock[FIRSTSOCKET]); + /* Look up the bundle with all the connections to this + particular host */ + bundle = Curl_conncache_find_bundle(needle, data->state.conn_cache); + if(bundle) { + /* Max pipe length is zero (unlimited) for multiplexed connections */ + size_t max_pipe_len = (bundle->multiuse != BUNDLE_MULTIPLEX)? + max_pipeline_length(data->multi):0; + size_t best_pipe_len = max_pipe_len; + struct curl_llist_element *curr; - if(dead) { - check->data = data; - infof(data, "Connection #%ld seems to be dead!\n", i); - - /* disconnect resources */ - Curl_disconnect(check, /* dead_connection */ TRUE); - data->state.connc->connects[i]=NULL; /* nothing here */ - - continue; - } - } + infof(data, "Found bundle for host %s: %p [%s]\n", + needle->host.name, (void *)bundle, + (bundle->multiuse== BUNDLE_PIPELINING? + "can pipeline": + (bundle->multiuse== BUNDLE_MULTIPLEX? + "can multiplex":"serially"))); + /* We can't pipe if we don't know anything about the server */ if(canPipeline) { - /* Make sure the pipe has only GET requests */ - struct SessionHandle* sh = gethandleathead(check->send_pipe); - struct SessionHandle* rh = gethandleathead(check->recv_pipe); - if(sh) { - if(!IsPipeliningPossible(sh, check)) - continue; - } - else if(rh) { - if(!IsPipeliningPossible(rh, check)) - continue; - } - -#ifdef DEBUGBUILD - if(pipeLen > MAX_PIPELINE_LENGTH) { - infof(data, "BAD! Connection #%ld has too big pipeline!\n", - check->connectindex); - } -#endif - } - else { - if(pipeLen > 0) { - /* can only happen within multi handles, and means that another easy - handle is using this connection */ - continue; - } - -#ifdef CURLRES_ASYNCH - /* ip_addr_str[0] is NUL only if the resolving of the name hasn't - completed yet and until then we don't re-use this connection */ - if(!check->ip_addr_str[0]) { - infof(data, - "Connection #%ld hasn't finished name resolve, can't reuse\n", - check->connectindex); - continue; - } -#endif - - if((check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) || check->bits.close) { - /* Don't pick a connection that hasn't connected yet or that is going - to get closed. */ - infof(data, "Connection #%ld isn't open enough, can't reuse\n", - check->connectindex); -#ifdef DEBUGBUILD - if(check->recv_pipe->size > 0) { - infof(data, "BAD! Unconnected #%ld has a non-empty recv pipeline!\n", - check->connectindex); + if(bundle->multiuse <= BUNDLE_UNKNOWN) { + if((bundle->multiuse == BUNDLE_UNKNOWN) && data->set.pipewait) { + infof(data, "Server doesn't support multi-use yet, wait\n"); + *waitpipe = TRUE; + return FALSE; /* no re-use */ } -#endif - continue; + + infof(data, "Server doesn't support multi-use (yet)\n"); + canPipeline = FALSE; + } + if((bundle->multiuse == BUNDLE_PIPELINING) && + !Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1)) { + /* not asked for, switch off */ + infof(data, "Could pipeline, but not asked to!\n"); + canPipeline = FALSE; + } + else if((bundle->multiuse == BUNDLE_MULTIPLEX) && + !Curl_pipeline_wanted(data->multi, CURLPIPE_MULTIPLEX)) { + infof(data, "Could multiplex, but not asked to!\n"); + canPipeline = FALSE; } } - if((needle->protocol&PROT_SSL) != (check->protocol&PROT_SSL)) - /* don't do mixed SSL and non-SSL connections */ - continue; + curr = bundle->conn_list->head; + while(curr) { + bool match = FALSE; + size_t pipeLen; - if(needle->protocol&PROT_SSL) { - if((data->set.ssl.verifypeer != check->verifypeer) || - (data->set.ssl.verifyhost != check->verifyhost)) + /* + * Note that if we use a HTTP proxy, we check connections to that + * proxy and not to the actual remote server. + */ + check = curr->ptr; + curr = curr->next; + + if(disconnect_if_dead(check, data)) continue; - } - if(needle->bits.proxy != check->bits.proxy) - /* don't do mixed proxy and non-proxy connections */ - continue; + pipeLen = check->send_pipe->size + check->recv_pipe->size; - if(!canPipeline && check->inuse) - /* this request can't be pipelined but the checked connection is already - in use so we skip it */ - continue; + if(canPipeline) { - if(!needle->bits.httpproxy || needle->protocol&PROT_SSL || - (needle->bits.httpproxy && check->bits.httpproxy && - needle->bits.tunnel_proxy && check->bits.tunnel_proxy && - Curl_raw_equal(needle->proxy.name, check->proxy.name) && - (needle->port == check->port))) { - /* The requested connection does not use a HTTP proxy or it uses SSL or - it is a non-SSL protocol tunneled over the same http proxy name and - port number */ - - if(Curl_raw_equal(needle->handler->scheme, check->handler->scheme) && - Curl_raw_equal(needle->host.name, check->host.name) && - (needle->remote_port == check->remote_port) ) { - if(needle->protocol & PROT_SSL) { - /* This is SSL, verify that we're using the same - ssl options as well */ - if(!Curl_ssl_config_matches(&needle->ssl_config, - &check->ssl_config)) { - DEBUGF(infof(data, - "Connection #%ld has different SSL parameters, " - "can't reuse\n", - check->connectindex)); - continue; + if(!check->bits.multiplex) { + /* If not multiplexing, make sure the pipe has only GET requests */ + struct SessionHandle* sh = gethandleathead(check->send_pipe); + struct SessionHandle* rh = gethandleathead(check->recv_pipe); + if(sh) { + if(!IsPipeliningPossible(sh, check)) + continue; } - else if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) { - DEBUGF(infof(data, - "Connection #%ld has not started ssl connect, " - "can't reuse\n", - check->connectindex)); + else if(rh) { + if(!IsPipeliningPossible(rh, check)) + continue; + } + } + } + else { + if(pipeLen > 0) { + /* can only happen within multi handles, and means that another easy + handle is using this connection */ + continue; + } + + if(Curl_resolver_asynch()) { + /* ip_addr_str[0] is NUL only if the resolving of the name hasn't + completed yet and until then we don't re-use this connection */ + if(!check->ip_addr_str[0]) { + infof(data, + "Connection #%ld is still name resolving, can't reuse\n", + check->connection_id); continue; } } - if((needle->protocol & PROT_FTP) || - ((needle->protocol & PROT_HTTP) && - (data->state.authhost.want==CURLAUTH_NTLM))) { - /* This is FTP or HTTP+NTLM, verify that we're using the same name - and password as well */ + + if((check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) || + check->bits.close) { + if(!check->bits.close) + foundPendingCandidate = TRUE; + /* Don't pick a connection that hasn't connected yet or that is going + to get closed. */ + infof(data, "Connection #%ld isn't open enough, can't reuse\n", + check->connection_id); +#ifdef DEBUGBUILD + if(check->recv_pipe->size > 0) { + infof(data, + "BAD! Unconnected #%ld has a non-empty recv pipeline!\n", + check->connection_id); + } +#endif + continue; + } + } + + if((needle->handler->flags&PROTOPT_SSL) != + (check->handler->flags&PROTOPT_SSL)) + /* don't do mixed SSL and non-SSL connections */ + if(get_protocol_family(check->handler->protocol) != + needle->handler->protocol || !check->tls_upgraded) + /* except protocols that have been upgraded via TLS */ + continue; + + if(needle->handler->flags&PROTOPT_SSL) { + if((data->set.ssl.verifypeer != check->verifypeer) || + (data->set.ssl.verifyhost != check->verifyhost)) + continue; + } + + if(needle->bits.proxy != check->bits.proxy) + /* don't do mixed proxy and non-proxy connections */ + continue; + + if(!canPipeline && check->inuse) + /* this request can't be pipelined but the checked connection is + already in use so we skip it */ + continue; + + if(needle->localdev || needle->localport) { + /* If we are bound to a specific local end (IP+port), we must not + re-use a random other one, although if we didn't ask for a + particular one we can reuse one that was bound. + + This comparison is a bit rough and too strict. Since the input + parameters can be specified in numerous ways and still end up the + same it would take a lot of processing to make it really accurate. + Instead, this matching will assume that re-uses of bound connections + will most likely also re-use the exact same binding parameters and + missing out a few edge cases shouldn't hurt anyone very much. + */ + if((check->localport != needle->localport) || + (check->localportrange != needle->localportrange) || + !check->localdev || + !needle->localdev || + strcmp(check->localdev, needle->localdev)) + continue; + } + + if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) { + /* This protocol requires credentials per connection, + so verify that we're using the same name and password as well */ + if(!strequal(needle->user, check->user) || + !strequal(needle->passwd, check->passwd)) { + /* one of them was different */ + continue; + } + } + + if(!needle->bits.httpproxy || needle->handler->flags&PROTOPT_SSL || + (needle->bits.httpproxy && check->bits.httpproxy && + needle->bits.tunnel_proxy && check->bits.tunnel_proxy && + Curl_raw_equal(needle->proxy.name, check->proxy.name) && + (needle->port == check->port))) { + /* The requested connection does not use a HTTP proxy or it uses SSL or + it is a non-SSL protocol tunneled over the same HTTP proxy name and + port number */ + if((Curl_raw_equal(needle->handler->scheme, check->handler->scheme) || + (get_protocol_family(check->handler->protocol) == + needle->handler->protocol && check->tls_upgraded)) && + Curl_raw_equal(needle->host.name, check->host.name) && + needle->remote_port == check->remote_port) { + /* The schemes match or the the protocol family is the same and the + previous connection was TLS upgraded, and the hostname and host + port match */ + if(needle->handler->flags & PROTOPT_SSL) { + /* This is a SSL connection so verify that we're using the same + SSL options as well */ + if(!Curl_ssl_config_matches(&needle->ssl_config, + &check->ssl_config)) { + DEBUGF(infof(data, + "Connection #%ld has different SSL parameters, " + "can't reuse\n", + check->connection_id)); + continue; + } + else if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) { + foundPendingCandidate = TRUE; + DEBUGF(infof(data, + "Connection #%ld has not started SSL connect, " + "can't reuse\n", + check->connection_id)); + continue; + } + } + match = TRUE; + } + } + else { /* The requested needle connection is using a proxy, + is the checked one using the same host, port and type? */ + if(check->bits.proxy && + (needle->proxytype == check->proxytype) && + (needle->bits.tunnel_proxy == check->bits.tunnel_proxy) && + Curl_raw_equal(needle->proxy.name, check->proxy.name) && + needle->port == check->port) { + /* This is the same proxy connection, use it! */ + match = TRUE; + } + } + + if(match) { +#if defined(USE_NTLM) + /* If we are looking for an HTTP+NTLM connection, check if this is + already authenticating with the right credentials. If not, keep + looking so that we can reuse NTLM connections if + possible. (Especially we must not reuse the same connection if + partway through a handshake!) */ + if(wantNTLMhttp) { if(!strequal(needle->user, check->user) || - !strequal(needle->passwd, check->passwd)) { - /* one of them was different */ + !strequal(needle->passwd, check->passwd)) + continue; + } + else if(check->ntlm.state != NTLMSTATE_NONE) { + /* Connection is using NTLM auth but we don't want NTLM */ + continue; + } + + /* Same for Proxy NTLM authentication */ + if(wantProxyNTLMhttp) { + if(!strequal(needle->proxyuser, check->proxyuser) || + !strequal(needle->proxypasswd, check->proxypasswd)) + continue; + } + else if(check->proxyntlm.state != NTLMSTATE_NONE) { + /* Proxy connection is using NTLM auth but we don't want NTLM */ + continue; + } + + if(wantNTLMhttp || wantProxyNTLMhttp) { + /* Credentials are already checked, we can use this connection */ + chosen = check; + + if((wantNTLMhttp && + (check->ntlm.state != NTLMSTATE_NONE)) || + (wantProxyNTLMhttp && + (check->proxyntlm.state != NTLMSTATE_NONE))) { + /* We must use this connection, no other */ + *force_reuse = TRUE; + break; + } + + /* Continue look up for a better connection */ + continue; + } +#endif + if(canPipeline) { + /* We can pipeline if we want to. Let's continue looking for + the optimal connection to use, i.e the shortest pipe that is not + blacklisted. */ + + if(pipeLen == 0) { + /* We have the optimal connection. Let's stop looking. */ + chosen = check; + break; + } + + /* We can't use the connection if the pipe is full */ + if(max_pipe_len && (pipeLen >= max_pipe_len)) { + infof(data, "Pipe is full, skip (%zu)\n", pipeLen); continue; } +#ifdef USE_NGHTTP2 + /* If multiplexed, make sure we don't go over concurrency limit */ + if(check->bits.multiplex) { + /* Multiplexed connections can only be HTTP/2 for now */ + struct http_conn *httpc = &check->proto.httpc; + if(pipeLen >= httpc->settings.max_concurrent_streams) { + infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)\n", + pipeLen); + continue; + } + } +#endif + /* We can't use the connection if the pipe is penalized */ + if(Curl_pipeline_penalized(data, check)) { + infof(data, "Penalized, skip\n"); + continue; + } + + if(max_pipe_len) { + if(pipeLen < best_pipe_len) { + /* This connection has a shorter pipe so far. We'll pick this + and continue searching */ + chosen = check; + best_pipe_len = pipeLen; + continue; + } + } + else { + /* When not pipelining (== multiplexed), we have a match here! */ + chosen = check; + infof(data, "Multiplexed connection found!\n"); + break; + } + } + else { + /* We have found a connection. Let's stop searching. */ + chosen = check; + break; } - match = TRUE; - } - } - else { /* The requested needle connection is using a proxy, - is the checked one using the same host, port and type? */ - if(check->bits.proxy && - (needle->proxytype == check->proxytype) && - (needle->bits.tunnel_proxy == check->bits.tunnel_proxy) && - Curl_raw_equal(needle->proxy.name, check->proxy.name) && - needle->port == check->port) { - /* This is the same proxy connection, use it! */ - match = TRUE; } } + } - if(match) { - check->inuse = TRUE; /* mark this as being in use so that no other - handle in a multi stack may nick it */ + if(chosen) { + *usethis = chosen; + return TRUE; /* yes, we found one to use! */ + } - *usethis = check; - return TRUE; /* yes, we found one to use! */ - } + if(foundPendingCandidate && data->set.pipewait) { + infof(data, + "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set\n"); + *waitpipe = TRUE; } return FALSE; /* no matching connecting exists */ } - - -/* - * This function frees/closes a connection in the connection cache. This - * should take the previously set policy into account when deciding which - * of the connections to kill. - */ -static long -ConnectionKillOne(struct SessionHandle *data) +/* Mark the connection as 'idle', or close it if the cache is full. + Returns TRUE if the connection is kept, or FALSE if it was closed. */ +static bool +ConnectionDone(struct SessionHandle *data, struct connectdata *conn) { - long i; - struct connectdata *conn; - long highscore=-1; - long connindex=-1; - long score; - struct timeval now; + /* data->multi->maxconnects can be negative, deal with it. */ + size_t maxconnects = + (data->multi->maxconnects < 0) ? data->multi->num_easy * 4: + data->multi->maxconnects; + struct connectdata *conn_candidate = NULL; - now = Curl_tvnow(); + /* Mark the current connection as 'unused' */ + conn->inuse = FALSE; - for(i=0; data->state.connc && (i< data->state.connc->num); i++) { - conn = data->state.connc->connects[i]; + if(maxconnects > 0 && + data->state.conn_cache->num_connections > maxconnects) { + infof(data, "Connection cache is full, closing the oldest one.\n"); - if(!conn || conn->inuse) - continue; + conn_candidate = find_oldest_idle_connection(data); - /* Set higher score for the age passed since the connection was used */ - score = Curl_tvdiff(now, conn->now); + if(conn_candidate) { + /* Set the connection's owner correctly */ + conn_candidate->data = data; - if(score > highscore) { - highscore = score; - connindex = i; + /* the winner gets the honour of being disconnected */ + (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE); } } - if(connindex >= 0) { - /* Set the connection's owner correctly */ - conn = data->state.connc->connects[connindex]; - conn->data = data; - /* the winner gets the honour of being disconnected */ - (void)Curl_disconnect(conn, /* dead_connection */ FALSE); - - /* clean the array entry */ - data->state.connc->connects[connindex] = NULL; - } - - return connindex; /* return the available index or -1 */ -} - -/* this connection can now be marked 'idle' */ -static void -ConnectionDone(struct connectdata *conn) -{ - conn->inuse = FALSE; -} - -/* - * The given input connection struct pointer is to be stored. If the "cache" - * is already full, we must clean out the most suitable using the previously - * set policy. - * - * The given connection should be unique. That must've been checked prior to - * this call. - */ -static long -ConnectionStore(struct SessionHandle *data, - struct connectdata *conn) -{ - long i; - for(i=0; i< data->state.connc->num; i++) { - if(!data->state.connc->connects[i]) - break; - } - if(i == data->state.connc->num) { - /* there was no room available, kill one */ - i = ConnectionKillOne(data); - if(-1 != i) - infof(data, "Connection (#%ld) was killed to make room (holds %ld)\n", - i, data->state.connc->num); - else - infof(data, "This connection did not fit in the connection cache\n"); - } - - conn->connectindex = i; /* Make the child know where the pointer to this - particular data is stored. But note that this -1 - if this is not within the cache and this is - probably not checked for everywhere (yet). */ - conn->inuse = TRUE; - if(-1 != i) { - /* Only do this if a true index was returned, if -1 was returned there - is no room in the cache for an unknown reason and we cannot store - this there. - - TODO: make sure we really can work with more handles than positions in - the cache, or possibly we should (allow to automatically) resize the - connection cache when we add more easy handles to a multi handle! - */ - data->state.connc->connects[i] = conn; /* fill in this */ - conn->data = data; - } - - return i; + return (conn_candidate == conn) ? FALSE : TRUE; } /* after a TCP connection to the proxy has been verified, this function does @@ -3168,27 +3531,30 @@ ConnectionStore(struct SessionHandle *data, Note: this function's sub-functions call failf() */ -CURLcode Curl_connected_proxy(struct connectdata *conn) +CURLcode Curl_connected_proxy(struct connectdata *conn, + int sockindex) { - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + if(!conn->bits.proxy || sockindex) + /* this magic only works for the primary socket as the secondary is used + for FTP only and it has FTP specific magic in ftp.c */ + return CURLE_OK; - switch(data->set.proxytype) { + switch(conn->proxytype) { #ifndef CURL_DISABLE_PROXY case CURLPROXY_SOCKS5: case CURLPROXY_SOCKS5_HOSTNAME: - result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, - conn->host.name, conn->remote_port, - FIRSTSOCKET, conn); - break; + return Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, + conn->host.name, conn->remote_port, + FIRSTSOCKET, conn); + case CURLPROXY_SOCKS4: - result = Curl_SOCKS4(conn->proxyuser, conn->host.name, - conn->remote_port, FIRSTSOCKET, conn, FALSE); - break; + return Curl_SOCKS4(conn->proxyuser, conn->host.name, + conn->remote_port, FIRSTSOCKET, conn, FALSE); + case CURLPROXY_SOCKS4A: - result = Curl_SOCKS4(conn->proxyuser, conn->host.name, - conn->remote_port, FIRSTSOCKET, conn, TRUE); - break; + return Curl_SOCKS4(conn->proxyuser, conn->host.name, + conn->remote_port, FIRSTSOCKET, conn, TRUE); + #endif /* CURL_DISABLE_PROXY */ case CURLPROXY_HTTP: case CURLPROXY_HTTP_1_0: @@ -3198,45 +3564,7 @@ CURLcode Curl_connected_proxy(struct connectdata *conn) break; } /* switch proxytype */ - return result; -} - -static CURLcode ConnectPlease(struct SessionHandle *data, - struct connectdata *conn, - bool *connected) -{ - CURLcode result; - Curl_addrinfo *addr; -#ifndef CURL_DISABLE_VERBOSE_STRINGS - char *hostname = conn->bits.proxy?conn->proxy.name:conn->host.name; - - infof(data, "About to connect() to %s%s port %ld (#%ld)\n", - conn->bits.proxy?"proxy ":"", - hostname, conn->port, conn->connectindex); -#else - (void)data; -#endif - - /************************************************************* - * Connect to server/proxy - *************************************************************/ - result= Curl_connecthost(conn, - conn->dns_entry, - &conn->sock[FIRSTSOCKET], - &addr, - connected); - if(CURLE_OK == result) { - /* All is cool, we store the current information */ - conn->ip_addr = addr; - - if(*connected) - result = Curl_connected_proxy(conn); - } - - if(result) - *connected = FALSE; /* mark it as not connected */ - - return result; + return CURLE_OK; } /* @@ -3248,7 +3576,7 @@ void Curl_verboseconnect(struct connectdata *conn) if(conn->data->set.verbose) infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n", conn->bits.proxy ? conn->proxy.dispname : conn->host.dispname, - conn->ip_addr_str, conn->port, conn->connectindex); + conn->ip_addr_str, conn->port, conn->connection_id); } #endif @@ -3319,11 +3647,10 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, bool *protocol_done) { CURLcode result=CURLE_OK; - struct SessionHandle *data = conn->data; *protocol_done = FALSE; - if(conn->bits.tcpconnect && conn->bits.protoconnstart) { + if(conn->bits.tcpconnect[FIRSTSOCKET] && conn->bits.protoconnstart) { /* We already are connected, get back. This may happen when the connect worked fine in the first call, like when we connect to a local server or proxy. Note that we don't know if the protocol is actually done. @@ -3336,20 +3663,21 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, return CURLE_OK; } - if(!conn->bits.tcpconnect) { - - Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ - Curl_verboseconnect(conn); - } - if(!conn->bits.protoconnstart) { + + result = Curl_proxy_connect(conn); + if(result) + return result; + + if(conn->bits.tunnel_proxy && conn->bits.httpproxy && + (conn->tunnel_state[FIRSTSOCKET] != TUNNEL_COMPLETE)) + /* when using an HTTP tunnel proxy, await complete tunnel establishment + before proceeding further. Return CURLE_OK so we'll be called again */ + return CURLE_OK; + if(conn->handler->connect_it) { /* is there a protocol-specific connect() procedure? */ - /* Set start time here for timeout purposes in the connect procedure, it - is later set again for the progress meter purpose */ - conn->now = Curl_tvnow(); - /* Call the protocol-specific connect function */ result = conn->handler->connect_it(conn, protocol_done); } @@ -3368,7 +3696,6 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, /* * Helpers for IDNA convertions. */ -#ifdef USE_LIBIDN static bool is_ASCII_name(const char *hostname) { const unsigned char *ch = (const unsigned char*)hostname; @@ -3380,6 +3707,7 @@ static bool is_ASCII_name(const char *hostname) return TRUE; } +#ifdef USE_LIBIDN /* * Check if characters in hostname is allowed in Top Level Domain. */ @@ -3429,6 +3757,8 @@ static bool tld_check_name(struct SessionHandle *data, static void fix_hostname(struct SessionHandle *data, struct connectdata *conn, struct hostname *host) { + size_t len; + #ifndef USE_LIBIDN (void)data; (void)conn; @@ -3439,29 +3769,67 @@ static void fix_hostname(struct SessionHandle *data, /* set the name we use to display the host name */ host->dispname = host->name; -#ifdef USE_LIBIDN - /************************************************************* - * Check name for non-ASCII and convert hostname to ACE form. - *************************************************************/ - if(!is_ASCII_name(host->name) && - stringprep_check_version(LIBIDN_REQUIRED_VERSION)) { - char *ace_hostname = NULL; - int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0); - infof (data, "Input domain encoded as `%s'\n", - stringprep_locale_charset ()); - if(rc != IDNA_SUCCESS) - infof(data, "Failed to convert %s to ACE; %s\n", - host->name, Curl_idn_strerror(conn,rc)); - else { - /* tld_check_name() displays a warning if the host name contains - "illegal" characters for this TLD */ - (void)tld_check_name(data, ace_hostname); + len = strlen(host->name); + if(len && (host->name[len-1] == '.')) + /* strip off a single trailing dot if present, primarily for SNI but + there's no use for it */ + host->name[len-1]=0; + /* Check name for non-ASCII and convert hostname to ACE form if we can */ + if(!is_ASCII_name(host->name)) { +#ifdef USE_LIBIDN + if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) { + char *ace_hostname = NULL; + + int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0); + infof(data, "Input domain encoded as `%s'\n", + stringprep_locale_charset()); + if(rc == IDNA_SUCCESS) { + /* tld_check_name() displays a warning if the host name contains + "illegal" characters for this TLD */ + (void)tld_check_name(data, ace_hostname); + + host->encalloc = ace_hostname; + /* change the name pointer to point to the encoded hostname */ + host->name = host->encalloc; + } + else + infof(data, "Failed to convert %s to ACE; %s\n", host->name, + Curl_idn_strerror(conn, rc)); + } +#elif defined(USE_WIN32_IDN) + char *ace_hostname = NULL; + + if(curl_win32_idn_to_ascii(host->name, &ace_hostname)) { host->encalloc = ace_hostname; /* change the name pointer to point to the encoded hostname */ host->name = host->encalloc; } + else + infof(data, "Failed to convert %s to ACE;\n", host->name); +#else + infof(data, "IDN support not present, can't parse Unicode domains\n"); +#endif } +} + +/* + * Frees data allocated by fix_hostname() + */ +static void free_fixed_hostname(struct hostname *host) +{ +#if defined(USE_LIBIDN) + if(host->encalloc) { + idn_free(host->encalloc); /* must be freed with idn_free() since this was + allocated by libidn */ + host->encalloc = NULL; + } +#elif defined(USE_WIN32_IDN) + free(host->encalloc); /* must be freed withidn_free() since this was + allocated by curl_win32_idn_to_ascii */ + host->encalloc = NULL; +#else + (void)host; #endif } @@ -3489,13 +3857,16 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ - conn->connectindex = -1; /* no index */ + conn->tempsock[0] = CURL_SOCKET_BAD; /* no file descriptor */ + conn->tempsock[1] = CURL_SOCKET_BAD; /* no file descriptor */ + conn->connection_id = -1; /* no ID */ conn->port = -1; /* unknown at this point */ + conn->remote_port = -1; /* unknown */ /* Default protocol-independent behavior doesn't support persistent connections, so we set this to force-close. Protocols that support this need to set this to FALSE in their "curl_do" functions. */ - conn->bits.close = TRUE; + connclose(conn, "Default to force-close"); /* Store creation time to help future close decision making */ conn->created = Curl_tvnow(); @@ -3514,18 +3885,20 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) #else /* CURL_DISABLE_PROXY */ - conn->bits.proxy = (bool)(data->set.str[STRING_PROXY] && - *data->set.str[STRING_PROXY]); - conn->bits.httpproxy = (bool)(conn->bits.proxy && - (conn->proxytype == CURLPROXY_HTTP || - conn->proxytype == CURLPROXY_HTTP_1_0)); + /* note that these two proxy bits are now just on what looks to be + requested, they may be altered down the road */ + conn->bits.proxy = (data->set.str[STRING_PROXY] && + *data->set.str[STRING_PROXY])?TRUE:FALSE; + conn->bits.httpproxy = (conn->bits.proxy && + (conn->proxytype == CURLPROXY_HTTP || + conn->proxytype == CURLPROXY_HTTP_1_0))?TRUE:FALSE; conn->bits.proxy_user_passwd = - (bool)(NULL != data->set.str[STRING_PROXYUSERNAME]); + (NULL != data->set.str[STRING_PROXYUSERNAME])?TRUE:FALSE; conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; #endif /* CURL_DISABLE_PROXY */ - conn->bits.user_passwd = (bool)(NULL != data->set.str[STRING_USERNAME]); + conn->bits.user_passwd = (NULL != data->set.str[STRING_USERNAME])?TRUE:FALSE; conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; @@ -3534,9 +3907,17 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->ip_version = data->set.ipver; - if(data->multi && Curl_multi_canPipeline(data->multi) && - !conn->master_buffer) { - /* Allocate master_buffer to be used for pipelining */ +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ + defined(NTLM_WB_ENABLED) + conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; + conn->ntlm_auth_hlpr_pid = 0; + conn->challenge_header = NULL; + conn->response_header = NULL; +#endif + + if(Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1) && + !conn->master_buffer) { + /* Allocate master_buffer to be used for HTTP/1 pipelining */ conn->master_buffer = calloc(BUFSIZE, sizeof (char)); if(!conn->master_buffer) goto error; @@ -3545,24 +3926,39 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) /* Initialize the pipeline lists */ conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor); conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor); - conn->pend_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor); - conn->done_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor); - if(!conn->send_pipe || !conn->recv_pipe || !conn->pend_pipe || - !conn->done_pipe) + if(!conn->send_pipe || !conn->recv_pipe) goto error; -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) +#ifdef HAVE_GSSAPI conn->data_prot = PROT_CLEAR; #endif + /* Store the local bind parameters that will be used for this connection */ + if(data->set.str[STRING_DEVICE]) { + conn->localdev = strdup(data->set.str[STRING_DEVICE]); + if(!conn->localdev) + goto error; + } + conn->localportrange = data->set.localportrange; + conn->localport = data->set.localport; + + /* the close socket stuff needs to be copied to the connection struct as + it may live on without (this specific) SessionHandle */ + conn->fclosesocket = data->set.fclosesocket; + conn->closesocket_client = data->set.closesocket_client; + return conn; error: + Curl_llist_destroy(conn->send_pipe, NULL); Curl_llist_destroy(conn->recv_pipe, NULL); - Curl_llist_destroy(conn->pend_pipe, NULL); - Curl_llist_destroy(conn->done_pipe, NULL); - Curl_safefree(conn->master_buffer); - Curl_safefree(conn); + + conn->send_pipe = NULL; + conn->recv_pipe = NULL; + + free(conn->master_buffer); + free(conn->localdev); + free(conn); return NULL; } @@ -3576,7 +3972,7 @@ static CURLcode findprotocol(struct SessionHandle *data, /* Scan protocol handler table and match against 'protostr' to set a few variables based on the URL. Now that the handler may be changed later when the protocol specific setup function is called. */ - for (pp = protocols; (p = *pp) != NULL; pp++) { + for(pp = protocols; (p = *pp) != NULL; pp++) { if(Curl_raw_equal(p->scheme, protostr)) { /* Protocol found in table. Check if allowed */ if(!(data->set.allowed_protocols & p->protocol)) @@ -3591,8 +3987,7 @@ static CURLcode findprotocol(struct SessionHandle *data, break; /* Perform setup complement if some. */ - conn->handler = p; - conn->protocol |= p->protocol; + conn->handler = conn->given = p; /* 'port' and 'remote_port' are set in setup_connection_internals() */ return CURLE_OK; @@ -3603,7 +3998,7 @@ static CURLcode findprotocol(struct SessionHandle *data, /* The protocol was not found in the table, but we don't have to assign it to anything since it is already assigned to a dummy-struct in the create_conn() function when the connectdata struct is allocated. */ - failf(data, "Protocol %s not supported or disabled in " LIBCURL_NAME, + failf(data, "Protocol \"%s\" not supported or disabled in " LIBCURL_NAME, protostr); return CURLE_UNSUPPORTED_PROTOCOL; @@ -3614,18 +4009,29 @@ static CURLcode findprotocol(struct SessionHandle *data, */ static CURLcode parseurlandfillconn(struct SessionHandle *data, struct connectdata *conn, - bool *prot_missing) + bool *prot_missing, + char **userp, char **passwdp, + char **optionsp) { char *at; char *fragment; char *path = data->state.path; char *query; int rc; - char protobuf[16]; - const char *protop; + char protobuf[16] = ""; + const char *protop = ""; + CURLcode result; + bool rebuild_url = FALSE; *prot_missing = FALSE; + /* We might pass the entire URL into the request so we need to make sure + * there are no bad characters in there.*/ + if(strpbrk(data->change.url, "\r\n")) { + failf(data, "Illegal characters found in URL"); + return CURLE_URL_MALFORMAT; + } + /************************************************************* * Parse the URL. * @@ -3705,7 +4111,7 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, * assigned, but the return value is EOF! */ #if defined(__DJGPP__) && (DJGPP_MINOR == 4) - if (!(rc == -1 && *conn->host.name)) + if(!(rc == -1 && *conn->host.name)) #endif { failf(data, " malformed"); @@ -3714,23 +4120,30 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, } /* - * Since there was no protocol part specified, we guess what protocol it - * is based on the first letters of the server name. + * Since there was no protocol part specified in the URL use the + * user-specified default protocol. If we weren't given a default make a + * guess by matching some protocols against the host's outermost + * sub-domain name. Finally if there was no match use HTTP. */ - /* Note: if you add a new protocol, please update the list in - * lib/version.c too! */ - - if(checkprefix("FTP.", conn->host.name)) - protop = "ftp"; - else if(checkprefix("DICT.", conn->host.name)) - protop = "DICT"; - else if(checkprefix("LDAP.", conn->host.name)) - protop = "LDAP"; - else if(checkprefix("IMAP.", conn->host.name)) - protop = "IMAP"; - else { - protop = "http"; + protop = data->set.str[STRING_DEFAULT_PROTOCOL]; + if(!protop) { + /* Note: if you add a new protocol, please update the list in + * lib/version.c too! */ + if(checkprefix("FTP.", conn->host.name)) + protop = "ftp"; + else if(checkprefix("DICT.", conn->host.name)) + protop = "DICT"; + else if(checkprefix("LDAP.", conn->host.name)) + protop = "LDAP"; + else if(checkprefix("IMAP.", conn->host.name)) + protop = "IMAP"; + else if(checkprefix("SMTP.", conn->host.name)) + protop = "smtp"; + else if(checkprefix("POP3.", conn->host.name)) + protop = "pop3"; + else + protop = "http"; } *prot_missing = TRUE; /* not given in URL */ @@ -3769,12 +4182,14 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, memcpy(path+1, query, hostlen); path[0]='/'; /* prepend the missing slash */ + rebuild_url = TRUE; *query=0; /* now cut off the hostname at the ? */ } else if(!path[0]) { /* if there's no path set, use a single slash */ strcpy(path, "/"); + rebuild_url = TRUE; } /* If the URL is malformatted (missing a '/' after hostname before path) we @@ -3787,38 +4202,145 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, is bigger than the path. Use +1 to move the zero byte too. */ memmove(&path[1], path, strlen(path)+1); path[0] = '/'; + rebuild_url = TRUE; + } + else if(!data->set.path_as_is) { + /* sanitise paths and remove ../ and ./ sequences according to RFC3986 */ + char *newp = Curl_dedotdotify(path); + if(!newp) + return CURLE_OUT_OF_MEMORY; + + if(strcmp(newp, path)) { + rebuild_url = TRUE; + free(data->state.pathbuffer); + data->state.pathbuffer = newp; + data->state.path = newp; + path = newp; + } + else + free(newp); } - if (conn->host.name[0] == '[') { + /* + * "rebuild_url" means that one or more URL components have been modified so + * we need to generate an updated full version. We need the corrected URL + * when communicating over HTTP proxy and we don't know at this point if + * we're using a proxy or not. + */ + if(rebuild_url) { + char *reurl; + + size_t plen = strlen(path); /* new path, should be 1 byte longer than + the original */ + size_t urllen = strlen(data->change.url); /* original URL length */ + + size_t prefixlen = strlen(conn->host.name); + + if(!*prot_missing) + prefixlen += strlen(protop) + strlen("://"); + + reurl = malloc(urllen + 2); /* 2 for zerobyte + slash */ + if(!reurl) + return CURLE_OUT_OF_MEMORY; + + /* copy the prefix */ + memcpy(reurl, data->change.url, prefixlen); + + /* append the trailing piece + zerobyte */ + memcpy(&reurl[prefixlen], path, plen + 1); + + /* possible free the old one */ + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } + + infof(data, "Rebuilt URL to: %s\n", reurl); + + data->change.url = reurl; + data->change.url_alloc = TRUE; /* free this later */ + } + + /* + * Parse the login details from the URL and strip them out of + * the host name + */ + result = parse_url_login(data, conn, userp, passwdp, optionsp); + if(result) + return result; + + if(conn->host.name[0] == '[') { /* This looks like an IPv6 address literal. See if there is an address - scope. */ - char *percent = strstr (conn->host.name, "%25"); - if (percent) { + scope if there is no location header */ + char *percent = strchr(conn->host.name, '%'); + if(percent) { + unsigned int identifier_offset = 3; char *endp; - unsigned long scope = strtoul (percent + 3, &endp, 10); - if (*endp == ']') { + unsigned long scope; + if(strncmp("%25", percent, 3) != 0) { + infof(data, + "Please URL encode %% as %%25, see RFC 6874.\n"); + identifier_offset = 1; + } + scope = strtoul(percent + identifier_offset, &endp, 10); + if(*endp == ']') { /* The address scope was well formed. Knock it out of the hostname. */ memmove(percent, endp, strlen(endp)+1); - if (!data->state.this_is_a_follow) - /* Don't honour a scope given in a Location: header */ - conn->scope = (unsigned int)scope; - } else - infof(data, "Invalid IPv6 address format\n"); + conn->scope_id = (unsigned int)scope; + } + else { + /* Zone identifier is not numeric */ +#if defined(HAVE_NET_IF_H) && defined(IFNAMSIZ) && defined(HAVE_IF_NAMETOINDEX) + char ifname[IFNAMSIZ + 2]; + char *square_bracket; + unsigned int scopeidx = 0; + strncpy(ifname, percent + identifier_offset, IFNAMSIZ + 2); + /* Ensure nullbyte termination */ + ifname[IFNAMSIZ + 1] = '\0'; + square_bracket = strchr(ifname, ']'); + if(square_bracket) { + /* Remove ']' */ + *square_bracket = '\0'; + scopeidx = if_nametoindex(ifname); + if(scopeidx == 0) { + infof(data, "Invalid network interface: %s; %s\n", ifname, + strerror(errno)); + } + } + if(scopeidx > 0) { + char *p = percent + identifier_offset + strlen(ifname); + + /* Remove zone identifier from hostname */ + memmove(percent, p, strlen(p) + 1); + conn->scope_id = scopeidx; + } + else +#endif /* HAVE_NET_IF_H && IFNAMSIZ */ + infof(data, "Invalid IPv6 address format\n"); + } } } - if(data->set.scope) + if(data->set.scope_id) /* Override any scope that was set above. */ - conn->scope = data->set.scope; + conn->scope_id = data->set.scope_id; /* Remove the fragment part of the path. Per RFC 2396, this is always the last part of the URI. We are looking for the first '#' so that we deal gracefully with non conformant URI such as http://example.com#foo#bar. */ fragment = strchr(path, '#'); - if(fragment) + if(fragment) { *fragment = 0; + /* we know the path part ended with a fragment, so we know the full URL + string does too and we need to cut it off from there so it isn't used + over proxy */ + fragment = strchr(data->change.url, '#'); + if(fragment) + *fragment = 0; + } + /* * So if the URL was A://B/C#D, * protop is A @@ -3842,11 +4364,11 @@ static CURLcode setup_range(struct SessionHandle *data) free(s->range); if(s->resume_from) - s->range = aprintf("%" FORMAT_OFF_TU "-", s->resume_from); + s->range = aprintf("%" CURL_FORMAT_CURL_OFF_TU "-", s->resume_from); else s->range = strdup(data->set.str[STRING_SET_RANGE]); - s->rangestringalloc = (bool)(s->range?TRUE:FALSE); + s->rangestringalloc = (s->range)?TRUE:FALSE; if(!s->range) return CURLE_OUT_OF_MEMORY; @@ -3861,26 +4383,40 @@ static CURLcode setup_range(struct SessionHandle *data) } -/*************************************************************** -* Setup connection internals specific to the requested protocol. -* This MUST get called after proxy magic has been figured out. -***************************************************************/ +/* + * setup_connection_internals() - + * + * Setup connection internals specific to the requested protocol in the + * SessionHandle. This is inited and setup before the connection is made but + * is about the particular protocol that is to be used. + * + * This MUST get called after proxy magic has been figured out. + */ static CURLcode setup_connection_internals(struct connectdata *conn) { const struct Curl_handler * p; CURLcode result; + struct SessionHandle *data = conn->data; + + /* in some case in the multi state-machine, we go back to the CONNECT state + and then a second (or third or...) call to this function will be made + without doing a DISCONNECT or DONE in between (since the connection is + yet in place) and therefore this function needs to first make sure + there's no lingering previous data allocated. */ + Curl_free_request_state(data); + + memset(&data->req, 0, sizeof(struct SingleRequest)); + data->req.maxdownload = -1; conn->socktype = SOCK_STREAM; /* most of them are TCP streams */ - /* Scan protocol handler table. */ - /* Perform setup complement if some. */ p = conn->handler; if(p->setup_connection) { result = (*p->setup_connection)(conn); - if(result != CURLE_OK) + if(result) return result; p = conn->handler; /* May have changed. */ @@ -3890,12 +4426,27 @@ static CURLcode setup_connection_internals(struct connectdata *conn) /* we check for -1 here since if proxy was detected already, this was very likely already set to the proxy port */ conn->port = p->defport; - conn->remote_port = (unsigned short)p->defport; - conn->protocol |= p->protocol; + + /* only if remote_port was not already parsed off the URL we use the + default port number */ + if(conn->remote_port < 0) + conn->remote_port = (unsigned short)conn->given->defport; return CURLE_OK; } +/* + * Curl_free_request_state() should free temp data that was allocated in the + * SessionHandle for this single request. + */ + +void Curl_free_request_state(struct SessionHandle *data) +{ + Curl_safefree(data->req.protop); + Curl_safefree(data->req.newurl); +} + + #ifndef CURL_DISABLE_PROXY /**************************************************************** * Checks if the host is in the noproxy list. returns true if it matches @@ -3929,9 +4480,9 @@ static bool check_noproxy(const char* name, const char* no_proxy) else namelen = strlen(name); - for (tok_start = 0; tok_start < no_proxy_len; tok_start = tok_end + 1) { - while (tok_start < no_proxy_len && - strchr(separator, no_proxy[tok_start]) != NULL) { + for(tok_start = 0; tok_start < no_proxy_len; tok_start = tok_end + 1) { + while(tok_start < no_proxy_len && + strchr(separator, no_proxy[tok_start]) != NULL) { /* Look for the beginning of the token. */ ++tok_start; } @@ -3939,10 +4490,10 @@ static bool check_noproxy(const char* name, const char* no_proxy) if(tok_start == no_proxy_len) break; /* It was all trailing separator chars, no more tokens. */ - for (tok_end = tok_start; tok_end < no_proxy_len && - strchr(separator, no_proxy[tok_end]) == NULL; ++tok_end) { + for(tok_end = tok_start; tok_end < no_proxy_len && + strchr(separator, no_proxy[tok_end]) == NULL; ++tok_end) /* Look for the end of the token. */ - } + ; /* To match previous behaviour, where it was necessary to specify * ".local.com" to prevent matching "notlocal.com", we will leave @@ -3964,7 +4515,7 @@ static bool check_noproxy(const char* name, const char* no_proxy) } } } /* if((tok_end - tok_start) <= namelen) */ - } /* for (tok_start = 0; tok_start < no_proxy_len; + } /* for(tok_start = 0; tok_start < no_proxy_len; tok_start = tok_end + 1) */ } /* NO_PROXY was specified and it wasn't just an asterisk */ @@ -4039,9 +4590,8 @@ static char *detect_proxy(struct connectdata *conn) prox=curl_getenv(proxy_env); } - if(prox && *prox) { /* don't count "" strings */ + if(prox) proxy = prox; /* use this */ - } else { proxy = curl_getenv("all_proxy"); /* default proxy to use */ if(!proxy) @@ -4049,8 +4599,7 @@ static char *detect_proxy(struct connectdata *conn) } } /* if(!check_noproxy(conn->host.name, no_proxy)) - it wasn't specified non-proxy */ - if(no_proxy) - free(no_proxy); + free(no_proxy); #else /* !CURL_DISABLE_HTTP */ @@ -4064,7 +4613,6 @@ static char *detect_proxy(struct connectdata *conn) * If this is supposed to use a proxy, we need to figure out the proxy * host name, so that we can re-use an existing connection * that may exist registered to the same proxy host. - * proxy will be freed before this function returns. */ static CURLcode parse_proxy(struct SessionHandle *data, struct connectdata *conn, char *proxy) @@ -4078,79 +4626,95 @@ static CURLcode parse_proxy(struct SessionHandle *data, char *atsign; /* We do the proxy host string parsing here. We want the host name and the - * port name. Accept a protocol:// prefix, even though it should just be - * ignored. + * port name. Accept a protocol:// prefix */ - /* Skip the protocol part if present */ + /* Parse the protocol part if present */ endofprot = strstr(proxy, "://"); - if(endofprot) + if(endofprot) { proxyptr = endofprot+3; + if(checkprefix("socks5h", proxy)) + conn->proxytype = CURLPROXY_SOCKS5_HOSTNAME; + else if(checkprefix("socks5", proxy)) + conn->proxytype = CURLPROXY_SOCKS5; + else if(checkprefix("socks4a", proxy)) + conn->proxytype = CURLPROXY_SOCKS4A; + else if(checkprefix("socks4", proxy) || checkprefix("socks", proxy)) + conn->proxytype = CURLPROXY_SOCKS4; + /* Any other xxx:// : change to http proxy */ + } else - proxyptr = proxy; + proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */ /* Is there a username and password given in this proxy url? */ atsign = strchr(proxyptr, '@'); if(atsign) { - char proxyuser[MAX_CURL_USER_LENGTH]; - char proxypasswd[MAX_CURL_PASSWORD_LENGTH]; - proxypasswd[0] = 0; - - if(1 <= sscanf(proxyptr, - "%" MAX_CURL_USER_LENGTH_TXT"[^:@]:" - "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", - proxyuser, proxypasswd)) { - CURLcode res = CURLE_OK; - + char *proxyuser = NULL; + char *proxypasswd = NULL; + CURLcode result = + parse_login_details(proxyptr, atsign - proxyptr, + &proxyuser, &proxypasswd, NULL); + if(!result) { /* found user and password, rip them out. note that we are unescaping them, as there is otherwise no way to have a username or password with reserved characters like ':' in them. */ Curl_safefree(conn->proxyuser); - conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); + if(proxyuser && strlen(proxyuser) < MAX_CURL_USER_LENGTH) + conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); + else + conn->proxyuser = strdup(""); if(!conn->proxyuser) - res = CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; else { Curl_safefree(conn->proxypasswd); - conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); + if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH) + conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); + else + conn->proxypasswd = strdup(""); if(!conn->proxypasswd) - res = CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; } - if(CURLE_OK == res) { + if(!result) { conn->bits.proxy_user_passwd = TRUE; /* enable it */ - atsign = strdup(atsign+1); /* the right side of the @-letter */ + atsign++; /* the right side of the @-letter */ - if(atsign) { - free(proxy); /* free the former proxy string */ - proxy = proxyptr = atsign; /* now use this instead */ - } - else - res = CURLE_OUT_OF_MEMORY; - } - - if(res) { - free(proxy); /* free the allocated proxy string */ - return res; + proxyptr = atsign; /* now use this instead */ } } + + free(proxyuser); + free(proxypasswd); + + if(result) + return result; } /* start scanning for port number at this point */ portptr = proxyptr; - /* detect and extract RFC2732-style IPv6-addresses */ + /* detect and extract RFC6874-style IPv6-addresses */ if(*proxyptr == '[') { char *ptr = ++proxyptr; /* advance beyond the initial bracket */ - while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '%') || - (*ptr == '.'))) + while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.'))) ptr++; - if(*ptr == ']') { + if(*ptr == '%') { + /* There might be a zone identifier */ + if(strncmp("%25", ptr, 3)) + infof(data, "Please URL encode %% as %%25, see RFC 6874.\n"); + ptr++; + /* Allow unresered characters as defined in RFC 3986 */ + while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') || + (*ptr == '.') || (*ptr == '_') || (*ptr == '~'))) + ptr++; + } + if(*ptr == ']') /* yeps, it ended nicely with a bracket as well */ *ptr++ = 0; - } else + else infof(data, "Invalid IPv6 address format\n"); portptr = ptr; /* Note that if this didn't end with a bracket, we still advanced the @@ -4162,12 +4726,32 @@ static CURLcode parse_proxy(struct SessionHandle *data, /* Get port number off proxy.server.com:1080 */ prox_portno = strchr(portptr, ':'); if(prox_portno) { + char *endp = NULL; + long port = 0; *prox_portno = 0x0; /* cut off number from host name */ prox_portno ++; /* now set the local port number */ - conn->port = strtol(prox_portno, NULL, 10); + port = strtol(prox_portno, &endp, 10); + if((endp && *endp && (*endp != '/') && (*endp != ' ')) || + (port >= 65536) ) { + /* meant to detect for example invalid IPv6 numerical addresses without + brackets: "2a00:fac0:a000::7:13". Accept a trailing slash only + because we then allow "URL style" with the number followed by a + slash, used in curl test cases already. Space is also an acceptable + terminating symbol. */ + infof(data, "No valid port number in proxy string (%s)\n", + prox_portno); + } + else + conn->port = port; } else { + if(proxyptr[0]=='/') + /* If the first character in the proxy string is a slash, fail + immediately. The following code will otherwise clear the string which + will lead to code running as if no proxy was set! */ + return CURLE_COULDNT_RESOLVE_PROXY; + /* without a port number after the host name, some people seem to use a slash so we strip everything from the first slash */ atsign = strchr(proxyptr, '/'); @@ -4184,7 +4768,6 @@ static CURLcode parse_proxy(struct SessionHandle *data, conn->proxy.rawalloc = strdup(proxyptr); conn->proxy.name = conn->proxy.rawalloc; - free(proxy); if(!conn->proxy.rawalloc) return CURLE_OUT_OF_MEMORY; @@ -4224,8 +4807,10 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data, #endif /* CURL_DISABLE_PROXY */ /* + * parse_url_login() * - * Parse a user name and password in the URL and strip it out of the host name + * Parse the login details (user name, password and options) from the URL and + * strip them out of the host name * * Inputs: data->set.use_netrc (CURLOPT_NETRC) * conn->host.name @@ -4233,80 +4818,233 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data, * Outputs: (almost :- all currently undefined) * conn->bits.user_passwd - non-zero if non-default passwords exist * user - non-zero length if defined - * passwd - ditto + * passwd - non-zero length if defined + * options - non-zero length if defined * conn->host.name - remove user name and password */ -static CURLcode parse_url_userpass(struct SessionHandle *data, - struct connectdata *conn, - char *user, char *passwd) +static CURLcode parse_url_login(struct SessionHandle *data, + struct connectdata *conn, + char **user, char **passwd, char **options) { + CURLcode result = CURLE_OK; + char *userp = NULL; + char *passwdp = NULL; + char *optionsp = NULL; + /* At this point, we're hoping all the other special cases have * been taken care of, so conn->host.name is at most - * [user[:password]]@]hostname + * [user[:password][;options]]@]hostname * * We need somewhere to put the embedded details, so do that first. */ - char *ptr=strchr(conn->host.name, '@'); - char *userpass = conn->host.name; + char *ptr = strchr(conn->host.name, '@'); + char *login = conn->host.name; - user[0] =0; /* to make everything well-defined */ - passwd[0]=0; + DEBUGASSERT(!**user); + DEBUGASSERT(!**passwd); + DEBUGASSERT(!**options); + + if(!ptr) + goto out; /* We will now try to extract the - * possible user+password pair in a string like: + * possible login information in a string like: * ftp://user:password@ftp.my.site:8021/README */ - if(ptr != NULL) { - /* there's a user+password given here, to the left of the @ */ + conn->host.name = ++ptr; - conn->host.name = ++ptr; + /* So the hostname is sane. Only bother interpreting the + * results if we could care. It could still be wasted + * work because it might be overtaken by the programmatically + * set user/passwd, but doing that first adds more cases here :-( + */ - /* So the hostname is sane. Only bother interpreting the - * results if we could care. It could still be wasted - * work because it might be overtaken by the programmatically - * set user/passwd, but doing that first adds more cases here :-( - */ + if(data->set.use_netrc == CURL_NETRC_REQUIRED) + goto out; + /* We could use the login information in the URL so extract it */ + result = parse_login_details(login, ptr - login - 1, + &userp, &passwdp, &optionsp); + if(result) + goto out; + + if(userp) { + char *newname; + + /* We have a user in the URL */ conn->bits.userpwd_in_url = TRUE; - if(data->set.use_netrc != CURL_NETRC_REQUIRED) { - /* We could use the one in the URL */ + conn->bits.user_passwd = TRUE; /* enable user+password */ - conn->bits.user_passwd = TRUE; /* enable user+password */ + /* Decode the user */ + newname = curl_easy_unescape(data, userp, 0, NULL); + if(!newname) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } - if(*userpass != ':') { - /* the name is given, get user+password */ - sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:@]:" - "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", - user, passwd); - } - else - /* no name given, get the password only */ - sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", passwd); + free(*user); + *user = newname; + } - if(user[0]) { - char *newname=curl_easy_unescape(data, user, 0, NULL); - if(!newname) - return CURLE_OUT_OF_MEMORY; - if(strlen(newname) < MAX_CURL_USER_LENGTH) - strcpy(user, newname); + if(passwdp) { + /* We have a password in the URL so decode it */ + char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL); + if(!newpasswd) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } - /* if the new name is longer than accepted, then just use - the unconverted name, it'll be wrong but what the heck */ - free(newname); - } - if(passwd[0]) { - /* we have a password found in the URL, decode it! */ - char *newpasswd=curl_easy_unescape(data, passwd, 0, NULL); - if(!newpasswd) - return CURLE_OUT_OF_MEMORY; - if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH) - strcpy(passwd, newpasswd); + free(*passwd); + *passwd = newpasswd; + } - free(newpasswd); - } + if(optionsp) { + /* We have an options list in the URL so decode it */ + char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL); + if(!newoptions) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + free(*options); + *options = newoptions; + } + + + out: + + free(userp); + free(passwdp); + free(optionsp); + + return result; +} + +/* + * parse_login_details() + * + * This is used to parse a login string for user name, password and options in + * the following formats: + * + * user + * user:password + * user:password;options + * user;options + * user;options:password + * :password + * :password;options + * ;options + * ;options:password + * + * Parameters: + * + * login [in] - The login string. + * len [in] - The length of the login string. + * userp [in/out] - The address where a pointer to newly allocated memory + * holding the user will be stored upon completion. + * passdwp [in/out] - The address where a pointer to newly allocated memory + * holding the password will be stored upon completion. + * optionsp [in/out] - The address where a pointer to newly allocated memory + * holding the options will be stored upon completion. + * + * Returns CURLE_OK on success. + */ +static CURLcode parse_login_details(const char *login, const size_t len, + char **userp, char **passwdp, + char **optionsp) +{ + CURLcode result = CURLE_OK; + char *ubuf = NULL; + char *pbuf = NULL; + char *obuf = NULL; + const char *psep = NULL; + const char *osep = NULL; + size_t ulen; + size_t plen; + size_t olen; + + /* Attempt to find the password separator */ + if(passwdp) { + psep = strchr(login, ':'); + + /* Within the constraint of the login string */ + if(psep >= login + len) + psep = NULL; + } + + /* Attempt to find the options separator */ + if(optionsp) { + osep = strchr(login, ';'); + + /* Within the constraint of the login string */ + if(osep >= login + len) + osep = NULL; + } + + /* Calculate the portion lengths */ + ulen = (psep ? + (size_t)(osep && psep > osep ? osep - login : psep - login) : + (osep ? (size_t)(osep - login) : len)); + plen = (psep ? + (osep && osep > psep ? (size_t)(osep - psep) : + (size_t)(login + len - psep)) - 1 : 0); + olen = (osep ? + (psep && psep > osep ? (size_t)(psep - osep) : + (size_t)(login + len - osep)) - 1 : 0); + + /* Allocate the user portion buffer */ + if(userp && ulen) { + ubuf = malloc(ulen + 1); + if(!ubuf) + result = CURLE_OUT_OF_MEMORY; + } + + /* Allocate the password portion buffer */ + if(!result && passwdp && plen) { + pbuf = malloc(plen + 1); + if(!pbuf) { + free(ubuf); + result = CURLE_OUT_OF_MEMORY; } } - return CURLE_OK; + + /* Allocate the options portion buffer */ + if(!result && optionsp && olen) { + obuf = malloc(olen + 1); + if(!obuf) { + free(pbuf); + free(ubuf); + result = CURLE_OUT_OF_MEMORY; + } + } + + if(!result) { + /* Store the user portion if necessary */ + if(ubuf) { + memcpy(ubuf, login, ulen); + ubuf[ulen] = '\0'; + Curl_safefree(*userp); + *userp = ubuf; + } + + /* Store the password portion if necessary */ + if(pbuf) { + memcpy(pbuf, psep + 1, plen); + pbuf[plen] = '\0'; + Curl_safefree(*passwdp); + *passwdp = pbuf; + } + + /* Store the options portion if necessary */ + if(obuf) { + memcpy(obuf, osep + 1, olen); + obuf[olen] = '\0'; + Curl_safefree(*optionsp); + *optionsp = obuf; + } + } + + return result; } /************************************************************* @@ -4346,8 +5084,19 @@ static CURLcode parse_remote_port(struct SessionHandle *data, portptr = NULL; /* no port number available */ } } - else + else { +#ifdef ENABLE_IPV6 + struct in6_addr in6; + if(Curl_inet_pton(AF_INET6, conn->host.name, &in6) > 0) { + /* This is a numerical IPv6 address, meaning this is a wrongly formatted + URL */ + failf(data, "IPv6 numerical address used in URL without brackets"); + return CURLE_URL_MALFORMAT; + } +#endif + portptr = strrchr(conn->host.name, ':'); + } if(data->set.use_port && data->state.allow_port) { /* if set, we use this and ignore the port possibly given in the URL */ @@ -4370,7 +5119,7 @@ static CURLcode parse_remote_port(struct SessionHandle *data, * stripped off. It would be better to work directly from the original * URL and simply replace the port part of it. */ - url = aprintf("%s://%s%s%s:%hu%s%s%s", conn->handler->scheme, + url = aprintf("%s://%s%s%s:%hu%s%s%s", conn->given->scheme, conn->bits.ipv6_ip?"[":"", conn->host.name, conn->bits.ipv6_ip?"]":"", conn->remote_port, data->state.slash_removed?"/":"", data->state.path, @@ -4378,8 +5127,10 @@ static CURLcode parse_remote_port(struct SessionHandle *data, if(!url) return CURLE_OUT_OF_MEMORY; - if(data->change.url_alloc) - free(data->change.url); + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } data->change.url = url; data->change.url_alloc = TRUE; @@ -4389,24 +5140,21 @@ static CURLcode parse_remote_port(struct SessionHandle *data, /* no CURLOPT_PORT given, extract the one from the URL */ char *rest; - unsigned long port; + long port; - port=strtoul(portptr+1, &rest, 10); /* Port number must be decimal */ + port=strtol(portptr+1, &rest, 10); /* Port number must be decimal */ - if(rest != (portptr+1) && *rest == '\0') { - /* The colon really did have only digits after it, - * so it is either a port number or a mistake */ - - if(port > 0xffff) { /* Single unix standard says port numbers are - * 16 bits long */ - failf(data, "Port number too large: %lu", port); - return CURLE_URL_MALFORMAT; - } + if((port < 0) || (port > 0xffff)) { + /* Single unix standard says port numbers are 16 bits long */ + failf(data, "Port number out of range"); + return CURLE_URL_MALFORMAT; + } + else if(rest != &portptr[1]) { *portptr = '\0'; /* cut off the name there */ conn->remote_port = curlx_ultous(port); } - else if(!port) + else /* Browser behavior adaptation. If there's a colon with no digits after, just cut off the name there which makes us ignore the colon and just use the default port. Firefox and Chrome both do that. */ @@ -4416,31 +5164,47 @@ static CURLcode parse_remote_port(struct SessionHandle *data, } /* - * Override a user name and password from the URL with that in the - * CURLOPT_USERPWD option or a .netrc file, if applicable. + * Override the login details from the URL with that in the CURLOPT_USERPWD + * option or a .netrc file, if applicable. */ -static void override_userpass(struct SessionHandle *data, - struct connectdata *conn, - char *user, char *passwd) +static CURLcode override_login(struct SessionHandle *data, + struct connectdata *conn, + char **userp, char **passwdp, char **optionsp) { - if(data->set.str[STRING_USERNAME] != NULL) { - strncpy(user, data->set.str[STRING_USERNAME], MAX_CURL_USER_LENGTH); - user[MAX_CURL_USER_LENGTH-1] = '\0'; /*To be on safe side*/ + if(data->set.str[STRING_USERNAME]) { + free(*userp); + *userp = strdup(data->set.str[STRING_USERNAME]); + if(!*userp) + return CURLE_OUT_OF_MEMORY; } - if(data->set.str[STRING_PASSWORD] != NULL) { - strncpy(passwd, data->set.str[STRING_PASSWORD], MAX_CURL_PASSWORD_LENGTH); - passwd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/ + + if(data->set.str[STRING_PASSWORD]) { + free(*passwdp); + *passwdp = strdup(data->set.str[STRING_PASSWORD]); + if(!*passwdp) + return CURLE_OUT_OF_MEMORY; + } + + if(data->set.str[STRING_OPTIONS]) { + free(*optionsp); + *optionsp = strdup(data->set.str[STRING_OPTIONS]); + if(!*optionsp) + return CURLE_OUT_OF_MEMORY; } conn->bits.netrc = FALSE; if(data->set.use_netrc != CURL_NETRC_IGNORED) { - if(Curl_parsenetrc(conn->host.name, - user, passwd, - data->set.str[STRING_NETRC_FILE])) { + int ret = Curl_parsenetrc(conn->host.name, + userp, passwdp, + data->set.str[STRING_NETRC_FILE]); + if(ret > 0) { infof(data, "Couldn't find host %s in the " DOT_CHAR "netrc file; using defaults\n", conn->host.name); } + else if(ret < 0 ) { + return CURLE_OUT_OF_MEMORY; + } else { /* set bits.netrc TRUE to remember that we got the name from a .netrc file, so that it is safe to use even if we followed a Location: to a @@ -4450,37 +5214,55 @@ static void override_userpass(struct SessionHandle *data, conn->bits.user_passwd = TRUE; /* enable user+password */ } } + + return CURLE_OK; } /* - * Set password so it's available in the connection. + * Set the login details so they're available in the connection */ -static CURLcode set_userpass(struct connectdata *conn, - const char *user, const char *passwd) +static CURLcode set_login(struct connectdata *conn, + const char *user, const char *passwd, + const char *options) { - /* If our protocol needs a password and we have none, use the defaults */ - if( (conn->protocol & (PROT_FTP|PROT_IMAP)) && - !conn->bits.user_passwd) { + CURLcode result = CURLE_OK; + /* If our protocol needs a password and we have none, use the defaults */ + if((conn->handler->flags & PROTOPT_NEEDSPWD) && !conn->bits.user_passwd) { + /* Store the default user */ conn->user = strdup(CURL_DEFAULT_USER); + + /* Store the default password */ if(conn->user) conn->passwd = strdup(CURL_DEFAULT_PASSWORD); else conn->passwd = NULL; + /* This is the default password, so DON'T set conn->bits.user_passwd */ } else { - /* store user + password, zero-length if not set */ + /* Store the user, zero-length if not set */ conn->user = strdup(user); + + /* Store the password (only if user is present), zero-length if not set */ if(conn->user) conn->passwd = strdup(passwd); else conn->passwd = NULL; } - if(!conn->user || !conn->passwd) - return CURLE_OUT_OF_MEMORY; - return CURLE_OK; + if(!conn->user || !conn->passwd) + result = CURLE_OUT_OF_MEMORY; + + /* Store the options, null if not set */ + if(!result && options[0]) { + conn->options = strdup(options); + + if(!conn->options) + result = CURLE_OUT_OF_MEMORY; + } + + return result; } /************************************************************* @@ -4491,26 +5273,48 @@ static CURLcode resolve_server(struct SessionHandle *data, bool *async) { CURLcode result=CURLE_OK; - long timeout_ms = Curl_timeleft(conn, NULL, TRUE); + long timeout_ms = Curl_timeleft(data, NULL, TRUE); /************************************************************* * Resolve the name of the server or proxy *************************************************************/ - if(conn->bits.reuse) { - /* We're reusing the connection - no need to resolve anything */ + if(conn->bits.reuse) + /* We're reusing the connection - no need to resolve anything, and + fix_hostname() was called already in create_conn() for the re-use + case. */ *async = FALSE; - if(conn->bits.proxy) - fix_hostname(data, conn, &conn->host); - } else { /* this is a fresh connect */ int rc; struct Curl_dns_entry *hostaddr; - /* set a pointer to the hostname we display */ - fix_hostname(data, conn, &conn->host); +#ifdef USE_UNIX_SOCKETS + if(data->set.str[STRING_UNIX_SOCKET_PATH]) { + /* Unix domain sockets are local. The host gets ignored, just use the + * specified domain socket address. Do not cache "DNS entries". There is + * no DNS involved and we already have the filesystem path available */ + const char *path = data->set.str[STRING_UNIX_SOCKET_PATH]; + hostaddr = calloc(1, sizeof(struct Curl_dns_entry)); + if(!hostaddr) + result = CURLE_OUT_OF_MEMORY; + else if((hostaddr->addr = Curl_unix2addr(path)) != NULL) + hostaddr->inuse++; + else { + /* Long paths are not supported for now */ + if(strlen(path) >= sizeof(((struct sockaddr_un *)0)->sun_path)) { + failf(data, "Unix socket path too long: '%s'", path); + result = CURLE_COULDNT_RESOLVE_HOST; + } + else + result = CURLE_OUT_OF_MEMORY; + free(hostaddr); + hostaddr = NULL; + } + } + else +#endif if(!conn->proxy.name || !*conn->proxy.name) { /* If not connecting via a proxy, extract the port from the URL, if it is * there, thus overriding any defaults that might have been set above. */ @@ -4522,7 +5326,7 @@ static CURLcode resolve_server(struct SessionHandle *data, if(rc == CURLRESOLV_PENDING) *async = TRUE; - else if (rc == CURLRESOLV_TIMEDOUT) + else if(rc == CURLRESOLV_TIMEDOUT) result = CURLE_OPERATION_TIMEDOUT; else if(!hostaddr) { @@ -4534,9 +5338,6 @@ static CURLcode resolve_server(struct SessionHandle *data, else { /* This is a proxy that hasn't been resolved yet. */ - /* IDN-fix the proxy name */ - fix_hostname(data, conn, &conn->proxy); - /* resolve proxy */ rc = Curl_resolv_timeout(conn, conn->proxy.name, (int)conn->port, &hostaddr, timeout_ms); @@ -4544,7 +5345,7 @@ static CURLcode resolve_server(struct SessionHandle *data, if(rc == CURLRESOLV_PENDING) *async = TRUE; - else if (rc == CURLRESOLV_TIMEDOUT) + else if(rc == CURLRESOLV_TIMEDOUT) result = CURLE_OPERATION_TIMEDOUT; else if(!hostaddr) { @@ -4568,8 +5369,8 @@ static CURLcode resolve_server(struct SessionHandle *data, static void reuse_conn(struct connectdata *old_conn, struct connectdata *conn) { - if(old_conn->proxy.rawalloc) - free(old_conn->proxy.rawalloc); + free_fixed_hostname(&old_conn->proxy); + free(old_conn->proxy.rawalloc); /* free the SSL config struct from this connection struct as this was allocated in vain and is targeted for destruction */ @@ -4601,13 +5402,11 @@ static void reuse_conn(struct connectdata *old_conn, old_conn->proxypasswd = NULL; } - /* host can change, when doing keepalive with a proxy ! */ - if(conn->bits.proxy) { - free(conn->host.rawalloc); - conn->host=old_conn->host; - } - else - free(old_conn->host.rawalloc); /* free the newly allocated name buffer */ + /* host can change, when doing keepalive with a proxy or if the case is + different this time etc */ + free_fixed_hostname(&conn->host); + Curl_safefree(conn->host.rawalloc); + conn->host=old_conn->host; /* persist connection info in session handle */ Curl_persistconninfo(conn); @@ -4619,10 +5418,14 @@ static void reuse_conn(struct connectdata *old_conn, Curl_safefree(old_conn->passwd); Curl_safefree(old_conn->proxyuser); Curl_safefree(old_conn->proxypasswd); + Curl_safefree(old_conn->localdev); + Curl_llist_destroy(old_conn->send_pipe, NULL); Curl_llist_destroy(old_conn->recv_pipe, NULL); - Curl_llist_destroy(old_conn->pend_pipe, NULL); - Curl_llist_destroy(old_conn->done_pipe, NULL); + + old_conn->send_pipe = NULL; + old_conn->recv_pipe = NULL; + Curl_safefree(old_conn->master_buffer); } @@ -4637,7 +5440,7 @@ static void reuse_conn(struct connectdata *old_conn, * @param data The sessionhandle pointer * @param in_connect is set to the next connection data pointer * @param async is set TRUE when an async DNS resolution is pending - * @see setup_conn() + * @see Curl_setup_conn() * * *NOTE* this function assigns the conn->data pointer! */ @@ -4646,15 +5449,21 @@ static CURLcode create_conn(struct SessionHandle *data, struct connectdata **in_connect, bool *async) { - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; struct connectdata *conn; struct connectdata *conn_temp = NULL; size_t urllen; - char user[MAX_CURL_USER_LENGTH]; - char passwd[MAX_CURL_PASSWORD_LENGTH]; + char *user = NULL; + char *passwd = NULL; + char *options = NULL; bool reuse; char *proxy = NULL; bool prot_missing = FALSE; + bool connections_available = TRUE; + bool force_reuse = FALSE; + bool waitpipe = FALSE; + size_t max_host_connections = Curl_multi_max_host_connections(data->multi); + size_t max_total_connections = Curl_multi_max_total_connections(data->multi); *async = FALSE; @@ -4662,8 +5471,10 @@ static CURLcode create_conn(struct SessionHandle *data, * Check input data *************************************************************/ - if(!data->change.url) - return CURLE_URL_MALFORMAT; + if(!data->change.url) { + result = CURLE_URL_MALFORMAT; + goto out; + } /* First, split up the current URL in parts so that we can use the parts for checking against the already present connections. In order @@ -4671,8 +5482,10 @@ static CURLcode create_conn(struct SessionHandle *data, connection data struct and fill in for comparison purposes. */ conn = allocate_conn(data); - if(!conn) - return CURLE_OUT_OF_MEMORY; + if(!conn) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } /* We must set the return variable as soon as possible, so that our parent can cleanup any possible allocs we may have done before @@ -4693,29 +5506,45 @@ static CURLcode create_conn(struct SessionHandle *data, urllen=LEAST_PATH_ALLOC; /* - * We malloc() the buffers below urllen+2 to make room for to possibilities: + * We malloc() the buffers below urllen+2 to make room for 2 possibilities: * 1 - an extra terminating zero * 2 - an extra slash (in case a syntax like "www.host.com?moo" is used) */ Curl_safefree(data->state.pathbuffer); + data->state.path = NULL; + data->state.pathbuffer = malloc(urllen+2); - if(NULL == data->state.pathbuffer) - return CURLE_OUT_OF_MEMORY; /* really bad error */ + if(NULL == data->state.pathbuffer) { + result = CURLE_OUT_OF_MEMORY; /* really bad error */ + goto out; + } data->state.path = data->state.pathbuffer; conn->host.rawalloc = malloc(urllen+2); - if(NULL == conn->host.rawalloc) - return CURLE_OUT_OF_MEMORY; + if(NULL == conn->host.rawalloc) { + Curl_safefree(data->state.pathbuffer); + data->state.path = NULL; + result = CURLE_OUT_OF_MEMORY; + goto out; + } conn->host.name = conn->host.rawalloc; conn->host.name[0] = 0; - result = parseurlandfillconn(data, conn, &prot_missing); - if(result != CURLE_OK) { - return result; + user = strdup(""); + passwd = strdup(""); + options = strdup(""); + if(!user || !passwd || !options) { + result = CURLE_OUT_OF_MEMORY; + goto out; } + result = parseurlandfillconn(data, conn, &prot_missing, &user, &passwd, + &options); + if(result) + goto out; + /************************************************************* * No protocol part in URL was used, add it! *************************************************************/ @@ -4724,12 +5553,22 @@ static CURLcode create_conn(struct SessionHandle *data, we're gonna follow a Location: later or... then we need the protocol part added so that we have a valid URL. */ char *reurl; + char *ch_lower; reurl = aprintf("%s://%s", conn->handler->scheme, data->change.url); if(!reurl) { - Curl_safefree(proxy); - return CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + /* Change protocol prefix to lower-case */ + for(ch_lower = reurl; *ch_lower != ':'; ch_lower++) + *ch_lower = (char)TOLOWER(*ch_lower); + + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; } data->change.url = reurl; @@ -4737,12 +5576,30 @@ static CURLcode create_conn(struct SessionHandle *data, } /************************************************************* - * Parse a user name and password in the URL and strip it out - * of the host name + * If the protocol can't handle url query strings, then cut + * off the unhandable part *************************************************************/ - result = parse_url_userpass(data, conn, user, passwd); - if(result != CURLE_OK) - return result; + if((conn->given->flags&PROTOPT_NOURLQUERY)) { + char *path_q_sep = strchr(conn->data->state.path, '?'); + if(path_q_sep) { + /* according to rfc3986, allow the query (?foo=bar) + also on protocols that can't handle it. + + cut the string-part after '?' + */ + + /* terminate the string */ + path_q_sep[0] = 0; + } + } + + if(data->set.str[STRING_BEARER]) { + conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]); + if(!conn->oauth_bearer) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + } #ifndef CURL_DISABLE_PROXY /************************************************************* @@ -4750,8 +5607,8 @@ static CURLcode create_conn(struct SessionHandle *data, *************************************************************/ if(conn->bits.proxy_user_passwd) { result = parse_proxy_auth(data, conn); - if(result != CURLE_OK) - return result; + if(result) + goto out; } /************************************************************* @@ -4762,33 +5619,65 @@ static CURLcode create_conn(struct SessionHandle *data, /* if global proxy is set, this is it */ if(NULL == proxy) { failf(data, "memory shortage"); - return CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; + goto out; } } if(data->set.str[STRING_NOPROXY] && check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY])) { - if(proxy) { - free(proxy); /* proxy is in exception list */ - proxy = NULL; - } + free(proxy); /* proxy is in exception list */ + proxy = NULL; } else if(!proxy) proxy = detect_proxy(conn); - if(proxy && !*proxy) { - free(proxy); /* Don't bother with an empty proxy string */ +#ifdef USE_UNIX_SOCKETS + if(proxy && data->set.str[STRING_UNIX_SOCKET_PATH]) { + free(proxy); /* Unix domain sockets cannot be proxied, so disable it */ proxy = NULL; } - /* proxy must be freed later unless NULL */ +#endif + + if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) { + free(proxy); /* Don't bother with an empty proxy string or if the + protocol doesn't work with network */ + proxy = NULL; + } + + /*********************************************************************** + * If this is supposed to use a proxy, we need to figure out the proxy host + * name, proxy type and port number, so that we can re-use an existing + * connection that may exist registered to the same proxy host. + ***********************************************************************/ if(proxy) { - long bits = conn->protocol & (PROT_HTTPS|PROT_SSL); + result = parse_proxy(data, conn, proxy); + + free(proxy); /* parse_proxy copies the proxy string */ + proxy = NULL; + + if(result) + goto out; if((conn->proxytype == CURLPROXY_HTTP) || (conn->proxytype == CURLPROXY_HTTP_1_0)) { - /* force this connection's protocol to become HTTP */ - conn->protocol = PROT_HTTP | bits; +#ifdef CURL_DISABLE_HTTP + /* asking for a HTTP proxy is a bit funny when HTTP is disabled... */ + result = CURLE_UNSUPPORTED_PROTOCOL; + goto out; +#else + /* force this connection's protocol to become HTTP if not already + compatible - if it isn't tunneling through */ + if(!(conn->handler->protocol & PROTO_FAMILY_HTTP) && + !conn->bits.tunnel_proxy) + conn->handler = &Curl_handler_http; + conn->bits.httpproxy = TRUE; +#endif + } + else { + conn->bits.httpproxy = FALSE; /* not a HTTP proxy */ + conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */ } conn->bits.proxy = TRUE; } @@ -4800,29 +5689,45 @@ static CURLcode create_conn(struct SessionHandle *data, conn->bits.tunnel_proxy = FALSE; } - /*********************************************************************** - * If this is supposed to use a proxy, we need to figure out the proxy - * host name, so that we can re-use an existing connection - * that may exist registered to the same proxy host. - ***********************************************************************/ - if(proxy) { - result = parse_proxy(data, conn, proxy); - /* parse_proxy has freed the proxy string, so don't try to use it again */ - proxy = NULL; - if(result != CURLE_OK) - return result; - } #endif /* CURL_DISABLE_PROXY */ + /************************************************************* + * If the protocol is using SSL and HTTP proxy is used, we set + * the tunnel_proxy bit. + *************************************************************/ + if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy) + conn->bits.tunnel_proxy = TRUE; + + /************************************************************* + * Figure out the remote port number and fix it in the URL + *************************************************************/ + result = parse_remote_port(data, conn); + if(result) + goto out; + + /* Check for overridden login details and set them accordingly so they + they are known when protocol->setup_connection is called! */ + result = override_login(data, conn, &user, &passwd, &options); + if(result) + goto out; + result = set_login(conn, user, passwd, options); + if(result) + goto out; + + /************************************************************* + * IDN-fix the hostnames + *************************************************************/ + fix_hostname(data, conn, &conn->host); + if(conn->proxy.name && *conn->proxy.name) + fix_hostname(data, conn, &conn->proxy); + /************************************************************* * Setup internals depending on protocol. Needs to be done after * we figured out what/if proxy to use. *************************************************************/ result = setup_connection_internals(conn); - if(result != CURLE_OK) { - Curl_safefree(proxy); - return result; - } + if(result) + goto out; conn->recv[FIRSTSOCKET] = Curl_recv_plain; conn->send[FIRSTSOCKET] = Curl_send_plain; @@ -4833,7 +5738,7 @@ static CURLcode create_conn(struct SessionHandle *data, * file: is a special case in that it doesn't need a network connection ***********************************************************************/ #ifndef CURL_DISABLE_FILE - if(conn->protocol & PROT_FILE) { + if(conn->handler->flags & PROTOPT_NONETWORK) { bool done; /* this is supposed to be the connect function so we better at least check that the file is present here! */ @@ -4841,11 +5746,11 @@ static CURLcode create_conn(struct SessionHandle *data, result = conn->handler->connect_it(conn, &done); /* Setup a "faked" transfer that'll do nothing */ - if(CURLE_OK == result) { + if(!result) { conn->data = data; - conn->bits.tcpconnect = TRUE; /* we are "connected */ + conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */ - ConnectionStore(data, conn); + Curl_conncache_add_conn(data->state.conn_cache, conn); /* * Setup whatever necessary for a resumed transfer @@ -4855,40 +5760,20 @@ static CURLcode create_conn(struct SessionHandle *data, DEBUGASSERT(conn->handler->done); /* we ignore the return code for the protocol-specific DONE */ (void)conn->handler->done(conn, result, FALSE); - return result; + goto out; } Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */ -1, NULL); /* no upload */ } - return result; + /* since we skip do_init() */ + Curl_init_do(data, conn); + + goto out; } #endif - /************************************************************* - * If the protocol is using SSL and HTTP proxy is used, we set - * the tunnel_proxy bit. - *************************************************************/ - if((conn->protocol&PROT_SSL) && conn->bits.httpproxy) - conn->bits.tunnel_proxy = TRUE; - - /************************************************************* - * Figure out the remote port number and fix it in the URL - *************************************************************/ - result = parse_remote_port(data, conn); - if(result != CURLE_OK) - return result; - - /************************************************************* - * Check for an overridden user name and password, then set it - * for use - *************************************************************/ - override_userpass(data, conn, user, passwd); - result = set_userpass(conn, user, passwd); - if(result != CURLE_OK) - return result; - /* Get a cloned copy of the SSL config situation stored in the connection struct. But to get this going nicely, we must first make sure that the strings in the master copy are pointing to the correct @@ -4905,9 +5790,17 @@ static CURLcode create_conn(struct SessionHandle *data, data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST]; +#ifdef USE_TLS_SRP + data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME]; + data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD]; +#endif - if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config)) - return CURLE_OUT_OF_MEMORY; + if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config)) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + prune_dead_connections(data); /************************************************************* * Check the current list of connections to see if we can @@ -4922,7 +5815,25 @@ static CURLcode create_conn(struct SessionHandle *data, if(data->set.reuse_fresh && !data->state.this_is_a_follow) reuse = FALSE; else - reuse = ConnectionExists(data, conn, &conn_temp); + reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe); + + /* If we found a reusable connection, we may still want to + open a new connection if we are pipelining. */ + if(reuse && !force_reuse && IsPipeliningPossible(data, conn_temp)) { + size_t pipelen = conn_temp->send_pipe->size + conn_temp->recv_pipe->size; + if(pipelen > 0) { + infof(data, "Found connection %ld, with requests in the pipe (%zu)\n", + conn_temp->connection_id, pipelen); + + if(conn_temp->bundle->num_connections < max_host_connections && + data->state.conn_cache->num_connections < max_total_connections) { + /* We want a new connection anyway */ + reuse = FALSE; + + infof(data, "We can reuse, but we want a new connection anyway\n"); + } + } + } if(reuse) { /* @@ -4931,28 +5842,118 @@ static CURLcode create_conn(struct SessionHandle *data, * just allocated before we can move along and use the previously * existing one. */ + conn_temp->inuse = TRUE; /* mark this as being in use so that no other + handle in a multi stack may nick it */ reuse_conn(conn, conn_temp); free(conn); /* we don't need this anymore */ conn = conn_temp; *in_connect = conn; - infof(data, "Re-using existing connection! (#%ld) with host %s\n", - conn->connectindex, + + infof(data, "Re-using existing connection! (#%ld) with %s %s\n", + conn->connection_id, + conn->bits.proxy?"proxy":"host", conn->proxy.name?conn->proxy.dispname:conn->host.dispname); } else { - /* - * This is a brand new connection, so let's store it in the connection - * cache of ours! - */ - ConnectionStore(data, conn); + /* We have decided that we want a new connection. However, we may not + be able to do that if we have reached the limit of how many + connections we are allowed to open. */ + struct connectbundle *bundle = NULL; + + if(waitpipe) + /* There is a connection that *might* become usable for pipelining + "soon", and we wait for that */ + connections_available = FALSE; + else + bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache); + + if(max_host_connections > 0 && bundle && + (bundle->num_connections >= max_host_connections)) { + struct connectdata *conn_candidate; + + /* The bundle is full. Let's see if we can kill a connection. */ + conn_candidate = find_oldest_idle_connection_in_bundle(data, bundle); + + if(conn_candidate) { + /* Set the connection's owner correctly, then kill it */ + conn_candidate->data = data; + (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE); + } + else { + infof(data, "No more connections allowed to host: %d\n", + max_host_connections); + connections_available = FALSE; + } + } + + if(connections_available && + (max_total_connections > 0) && + (data->state.conn_cache->num_connections >= max_total_connections)) { + struct connectdata *conn_candidate; + + /* The cache is full. Let's see if we can kill a connection. */ + conn_candidate = find_oldest_idle_connection(data); + + if(conn_candidate) { + /* Set the connection's owner correctly, then kill it */ + conn_candidate->data = data; + (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE); + } + else { + infof(data, "No connections available in cache\n"); + connections_available = FALSE; + } + } + + if(!connections_available) { + infof(data, "No connections available.\n"); + + conn_free(conn); + *in_connect = NULL; + + result = CURLE_NO_CONNECTION_AVAILABLE; + goto out; + } + else { + /* + * This is a brand new connection, so let's store it in the connection + * cache of ours! + */ + Curl_conncache_add_conn(data->state.conn_cache, conn); + } + +#if defined(USE_NTLM) + /* If NTLM is requested in a part of this connection, make sure we don't + assume the state is fine as this is a fresh connection and NTLM is + connection based. */ + if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + data->state.authhost.done) { + infof(data, "NTLM picked AND auth done set, clear picked!\n"); + data->state.authhost.picked = CURLAUTH_NONE; + data->state.authhost.done = FALSE; + } + + if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + data->state.authproxy.done) { + infof(data, "NTLM-proxy picked AND auth done set, clear picked!\n"); + data->state.authproxy.picked = CURLAUTH_NONE; + data->state.authproxy.done = FALSE; + } +#endif } + /* Mark the connection as used */ + conn->inuse = TRUE; + + /* Setup and init stuff before DO starts, in preparing for the transfer. */ + Curl_init_do(data, conn); + /* * Setup whatever necessary for a resumed transfer */ result = setup_range(data); if(result) - return result; + goto out; /* Continue connectdata initialization here. */ @@ -4960,8 +5961,6 @@ static CURLcode create_conn(struct SessionHandle *data, * Inherit the proper values from the urldata struct AFTER we have arranged * the persistent connection stuff */ - conn->fread_func = data->set.fread_func; - conn->fread_in = data->set.in; conn->seek_func = data->set.seek_func; conn->seek_client = data->set.seek_client; @@ -4970,28 +5969,33 @@ static CURLcode create_conn(struct SessionHandle *data, *************************************************************/ result = resolve_server(data, conn, async); + out: + + free(options); + free(passwd); + free(user); + free(proxy); return result; } -/* setup_conn() is called after the name resolve initiated in +/* Curl_setup_conn() is called after the name resolve initiated in * create_conn() is all done. * - * setup_conn() also handles reused connections + * Curl_setup_conn() also handles reused connections * * conn->data MUST already have been setup fine (in create_conn) */ -static CURLcode setup_conn(struct connectdata *conn, - bool *protocol_done) +CURLcode Curl_setup_conn(struct connectdata *conn, + bool *protocol_done) { - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; Curl_pgrsTime(data, TIMER_NAMELOOKUP); - if(conn->protocol & PROT_FILE) { - /* There's nothing in this function to setup if we're only doing - a file:// transfer */ + if(conn->handler->flags & PROTOPT_NONETWORK) { + /* nothing to setup when not using a network */ *protocol_done = TRUE; return result; } @@ -5022,47 +6026,23 @@ static CURLcode setup_conn(struct connectdata *conn, data->state.crlf_conversions = 0; /* reset CRLF conversion counter */ #endif /* CURL_DO_LINEEND_CONV */ - for(;;) { - /* loop for CURL_SERVER_CLOSED_CONNECTION */ + /* set start time here for timeout purposes in the connect procedure, it + is later set again for the progress meter purpose */ + conn->now = Curl_tvnow(); - if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) { - /* Try to connect only if not already connected */ - bool connected = FALSE; - - result = ConnectPlease(data, conn, &connected); - - if(connected) { - result = Curl_protocol_connect(conn, protocol_done); - if(CURLE_OK == result) - conn->bits.tcpconnect = TRUE; - } - else - conn->bits.tcpconnect = FALSE; - - /* if the connection was closed by the server while exchanging - authentication informations, retry with the new set - authentication information */ - if(conn->bits.proxy_connect_closed) { - /* reset the error buffer */ - if(data->set.errorbuffer) - data->set.errorbuffer[0] = '\0'; - data->state.errorbuf = FALSE; - continue; - } - - if(CURLE_OK != result) - return result; - } - else { - Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */ - Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */ - conn->bits.tcpconnect = TRUE; - *protocol_done = TRUE; - Curl_verboseconnect(conn); - Curl_updateconninfo(conn, conn->sock[FIRSTSOCKET]); - } - /* Stop the loop now */ - break; + if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) { + conn->bits.tcpconnect[FIRSTSOCKET] = FALSE; + result = Curl_connecthost(conn, conn->dns_entry); + if(result) + return result; + } + else { + Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */ + Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */ + conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; + *protocol_done = TRUE; + Curl_updateconninfo(conn, conn->sock[FIRSTSOCKET]); + Curl_verboseconnect(conn); } conn->now = Curl_tvnow(); /* time this *after* the connect is done, we @@ -5089,68 +6069,41 @@ CURLcode Curl_connect(struct SessionHandle *data, bool *asyncp, bool *protocol_done) { - CURLcode code; + CURLcode result; *asyncp = FALSE; /* assume synchronous resolves by default */ /* call the stuff that needs to be called */ - code = create_conn(data, in_connect, asyncp); + result = create_conn(data, in_connect, asyncp); - if(CURLE_OK == code) { + if(!result) { /* no error */ if((*in_connect)->send_pipe->size || (*in_connect)->recv_pipe->size) /* pipelining */ *protocol_done = TRUE; - else if (!*asyncp) { + else if(!*asyncp) { /* DNS resolution is done: that's either because this is a reused connection, in which case DNS was unnecessary, or because DNS really did finish already (synch resolver/fast async resolve) */ - code = setup_conn(*in_connect, protocol_done); + result = Curl_setup_conn(*in_connect, protocol_done); } } - if(code && *in_connect) { + if(result == CURLE_NO_CONNECTION_AVAILABLE) { + *in_connect = NULL; + return result; + } + + if(result && *in_connect) { /* We're not allowed to return failure with memory left allocated in the connectdata struct, free those here */ Curl_disconnect(*in_connect, FALSE); /* close the connection */ *in_connect = NULL; /* return a NULL */ } - return code; + return result; } -/* Call this function after Curl_connect() has returned async=TRUE and - then a successful name resolve has been received. - - Note: this function disconnects and frees the conn data in case of - resolve failure */ -CURLcode Curl_async_resolved(struct connectdata *conn, - bool *protocol_done) -{ -#ifdef CURLRES_ASYNCH - CURLcode code; - - if(conn->async.dns) { - conn->dns_entry = conn->async.dns; - conn->async.dns = NULL; - } - - code = setup_conn(conn, protocol_done); - - if(code) - /* We're not allowed to return failure with memory left allocated - in the connectdata struct, free those here */ - Curl_disconnect(conn, FALSE); /* close the connection */ - - return code; -#else - (void)conn; - (void)protocol_done; - return CURLE_OK; -#endif -} - - CURLcode Curl_done(struct connectdata **connp, CURLcode status, /* an error if this is called after an error was detected */ @@ -5165,57 +6118,73 @@ CURLcode Curl_done(struct connectdata **connp, conn = *connp; data = conn->data; - if(conn->bits.done) + DEBUGF(infof(data, "Curl_done\n")); + + if(data->state.done) /* Stop if Curl_done() has already been called */ return CURLE_OK; Curl_getoff_all_pipelines(data, conn); - if((conn->send_pipe->size + conn->recv_pipe->size != 0 && - !data->set.reuse_forbid && - !conn->bits.close)) - /* Stop if pipeline is not empty and we do not have to close - connection. */ - return CURLE_OK; - - conn->bits.done = TRUE; /* called just now! */ - /* Cleanup possible redirect junk */ - if(data->req.newurl) { - free(data->req.newurl); - data->req.newurl = NULL; - } - if(data->req.location) { - free(data->req.location); - data->req.location = NULL; - } + free(data->req.newurl); + data->req.newurl = NULL; + free(data->req.location); + data->req.location = NULL; - if(conn->dns_entry) { - Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ - conn->dns_entry = NULL; + switch(status) { + case CURLE_ABORTED_BY_CALLBACK: + case CURLE_READ_ERROR: + case CURLE_WRITE_ERROR: + /* When we're aborted due to a callback return code it basically have to + be counted as premature as there is trouble ahead if we don't. We have + many callbacks and protocols work differently, we could potentially do + this more fine-grained in the future. */ + premature = TRUE; + default: + break; } /* this calls the protocol-specific function pointer previously set */ if(conn->handler->done) result = conn->handler->done(conn, status, premature); else - result = CURLE_OK; + result = status; - Curl_pgrsDone(conn); /* done with the operation */ + if(CURLE_ABORTED_BY_CALLBACK != result) { + /* avoid this if we already aborted by callback to avoid this calling + another callback */ + CURLcode rc = Curl_pgrsDone(conn); + if(!result && rc) + result = CURLE_ABORTED_BY_CALLBACK; + } + + if((!premature && + conn->send_pipe->size + conn->recv_pipe->size != 0 && + !data->set.reuse_forbid && + !conn->bits.close)) { + /* Stop if pipeline is not empty and we do not have to close + connection. */ + DEBUGF(infof(data, "Connection still in use, no more Curl_done now!\n")); + return CURLE_OK; + } + + data->state.done = TRUE; /* called just now! */ + Curl_resolver_cancel(conn); + + if(conn->dns_entry) { + Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ + conn->dns_entry = NULL; + } /* if the transfer was completed in a paused state there can be buffered data left to write and then kill */ - if(data->state.tempwrite) { - free(data->state.tempwrite); - data->state.tempwrite = NULL; - } - - /* for ares-using, make sure all possible outstanding requests are properly - cancelled before we proceed */ - ares_cancel(data->state.areschannel); + free(data->state.tempwrite); + data->state.tempwrite = NULL; /* if data->set.reuse_forbid is TRUE, it means the libcurl client has - forced us to close this no matter what we think. + forced us to close this connection. This is ignored for requests taking + place in a NTLM authentication handshake if conn->bits.close is TRUE, it means that the connection should be closed in spite of all our efforts to be nice, due to protocol @@ -5226,13 +6195,15 @@ CURLcode Curl_done(struct connectdata **connp, state it is for re-using, so we're forced to close it. In a perfect world we can add code that keep track of if we really must close it here or not, but currently we have no such detail knowledge. - - connectindex == -1 here means that the connection has no spot in the - connection cache and thus we must disconnect it here. */ - if(data->set.reuse_forbid || conn->bits.close || premature || - (-1 == conn->connectindex)) { - CURLcode res2 = Curl_disconnect(conn, FALSE); /* close the connection */ + + if((data->set.reuse_forbid +#if defined(USE_NTLM) + && !(conn->ntlm.state == NTLMSTATE_TYPE2 || + conn->proxyntlm.state == NTLMSTATE_TYPE2) +#endif + ) || conn->bits.close || premature) { + CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */ /* If we had an error already, make sure we return that one. But if we got a new error, return that. */ @@ -5240,39 +6211,47 @@ CURLcode Curl_done(struct connectdata **connp, result = res2; } else { - ConnectionDone(conn); /* the connection is no longer in use */ + /* the connection is no longer in use */ + if(ConnectionDone(data, conn)) { + /* remember the most recently used connection */ + data->state.lastconnect = conn; - /* remember the most recently used connection */ - data->state.lastconnect = conn->connectindex; - - infof(data, "Connection #%ld to host %s left intact\n", - conn->connectindex, - conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname); + infof(data, "Connection #%ld to host %s left intact\n", + conn->connection_id, + conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname); + } + else + data->state.lastconnect = NULL; } *connp = NULL; /* to make the caller of this function better detect that this was either closed or handed over to the connection cache here, and therefore cannot be used from this point on */ + Curl_free_request_state(data); return result; } /* - * do_init() inits the readwrite session. This is inited each time (in the DO - * function before the protocol-specific DO functions are invoked) for a - * transfer, sometimes multiple times on the same SessionHandle. Make sure + * Curl_init_do() inits the readwrite session. This is inited each time (in + * the DO function before the protocol-specific DO functions are invoked) for + * a transfer, sometimes multiple times on the same SessionHandle. Make sure * nothing in here depends on stuff that are setup dynamically for the * transfer. + * + * Allow this function to get called with 'conn' set to NULL. */ -static CURLcode do_init(struct connectdata *conn) +CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn) { - struct SessionHandle *data = conn->data; struct SingleRequest *k = &data->req; - conn->bits.done = FALSE; /* Curl_done() is not called yet */ - conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */ + if(conn) + conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to + * use */ + + data->state.done = FALSE; /* Curl_done() is not called yet */ data->state.expect100header = FALSE; if(data->set.opt_no_body) @@ -5286,9 +6265,6 @@ static CURLcode do_init(struct connectdata *conn) HTTP. */ data->set.httpreq = HTTPREQ_GET; - /* NB: the content encoding software depends on this initialization */ - Curl_easy_initHandleData(data); - k->start = Curl_tvnow(); /* start time */ k->now = k->start; /* current time is now */ k->header = TRUE; /* assume header */ @@ -5300,7 +6276,6 @@ static CURLcode do_init(struct connectdata *conn) k->hbufp = data->state.headerbuff; k->ignorebody=FALSE; - Curl_pgrsTime(data, TIMER_PRETRANSFER); Curl_speedinit(data); Curl_pgrsSetUploadCounter(data, 0); @@ -5320,6 +6295,7 @@ static void do_complete(struct connectdata *conn) conn->data->req.chunk=FALSE; conn->data->req.maxfd = (conn->sockfd>conn->writesockfd? conn->sockfd:conn->writesockfd)+1; + Curl_pgrsTime(conn->data, TIMER_PRETRANSFER); } CURLcode Curl_do(struct connectdata **connp, bool *done) @@ -5328,63 +6304,171 @@ CURLcode Curl_do(struct connectdata **connp, bool *done) struct connectdata *conn = *connp; struct SessionHandle *data = conn->data; - /* setup and init stuff before DO starts, in preparing for the transfer */ - do_init(conn); - if(conn->handler->do_it) { /* generic protocol-specific function pointer set in curl_connect() */ result = conn->handler->do_it(conn, done); /* This was formerly done in transfer.c, but we better do it here */ if((CURLE_SEND_ERROR == result) && conn->bits.reuse) { - /* - * If the connection is using an easy handle, call reconnect - * to re-establish the connection. Otherwise, let the multi logic - * figure out how to re-establish the connection. - */ - if(!data->multi) { - result = Curl_reconnect_request(connp); + /* + * If the connection is using an easy handle, call reconnect + * to re-establish the connection. Otherwise, let the multi logic + * figure out how to re-establish the connection. + */ + if(!data->multi) { + result = Curl_reconnect_request(connp); - if(result == CURLE_OK) { - /* ... finally back to actually retry the DO phase */ - result = conn->handler->do_it(conn, done); - } - } - else { - return result; + if(!result) { + /* ... finally back to actually retry the DO phase */ + conn = *connp; /* re-assign conn since Curl_reconnect_request + creates a new connection */ + result = conn->handler->do_it(conn, done); } + } + else + return result; } - if((result == CURLE_OK) && *done) + if(!result && *done) /* do_complete must be called after the protocol-specific DO function */ do_complete(conn); } return result; } -CURLcode Curl_do_more(struct connectdata *conn) +/* + * Curl_do_more() is called during the DO_MORE multi state. It is basically a + * second stage DO state which (wrongly) was introduced to support FTP's + * second connection. + * + * TODO: A future libcurl should be able to work away this state. + * + * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to + * DOING state there's more work to do! + */ + +CURLcode Curl_do_more(struct connectdata *conn, int *complete) { CURLcode result=CURLE_OK; - if(conn->handler->do_more) - result = conn->handler->do_more(conn); + *complete = 0; - if(result == CURLE_OK) + if(conn->handler->do_more) + result = conn->handler->do_more(conn, complete); + + if(!result && (*complete == 1)) /* do_complete must be called after the protocol-specific DO function */ do_complete(conn); return result; } -/* Called on connect, and if there's already a protocol-specific struct - allocated for a different connection, this frees it that it can be setup - properly later on. */ -void Curl_reset_reqproto(struct connectdata *conn) +/* +* get_protocol_family() +* +* This is used to return the protocol family for a given protocol. +* +* Parameters: +* +* protocol [in] - A single bit protocol identifier such as HTTP or HTTPS. +* +* Returns the family as a single bit protocol identifier. +*/ + +unsigned int get_protocol_family(unsigned int protocol) { - struct SessionHandle *data = conn->data; - if(data->state.proto.generic && data->state.current_conn != conn) { - free(data->state.proto.generic); - data->state.proto.generic = NULL; + unsigned int family; + + switch(protocol) { + case CURLPROTO_HTTP: + case CURLPROTO_HTTPS: + family = CURLPROTO_HTTP; + break; + + case CURLPROTO_FTP: + case CURLPROTO_FTPS: + family = CURLPROTO_IMAP; + break; + + case CURLPROTO_SCP: + family = CURLPROTO_SCP; + break; + + case CURLPROTO_SFTP: + family = CURLPROTO_SFTP; + break; + + case CURLPROTO_TELNET: + family = CURLPROTO_TELNET; + break; + + case CURLPROTO_LDAP: + case CURLPROTO_LDAPS: + family = CURLPROTO_IMAP; + break; + + case CURLPROTO_DICT: + family = CURLPROTO_DICT; + break; + + case CURLPROTO_FILE: + family = CURLPROTO_FILE; + break; + + case CURLPROTO_TFTP: + family = CURLPROTO_TFTP; + break; + + case CURLPROTO_IMAP: + case CURLPROTO_IMAPS: + family = CURLPROTO_IMAP; + break; + + case CURLPROTO_POP3: + case CURLPROTO_POP3S: + family = CURLPROTO_POP3; + break; + + case CURLPROTO_SMTP: + case CURLPROTO_SMTPS: + family = CURLPROTO_SMTP; + break; + + case CURLPROTO_RTSP: + family = CURLPROTO_RTSP; + break; + + case CURLPROTO_RTMP: + case CURLPROTO_RTMPS: + family = CURLPROTO_RTMP; + break; + + case CURLPROTO_RTMPT: + case CURLPROTO_RTMPTS: + family = CURLPROTO_RTMPT; + break; + + case CURLPROTO_RTMPE: + family = CURLPROTO_RTMPE; + break; + + case CURLPROTO_RTMPTE: + family = CURLPROTO_RTMPTE; + break; + + case CURLPROTO_GOPHER: + family = CURLPROTO_GOPHER; + break; + + case CURLPROTO_SMB: + case CURLPROTO_SMBS: + family = CURLPROTO_SMB; + break; + + default: + family = 0; + break; } - data->state.current_conn = conn; + + return family; } diff --git a/project/jni/curl/lib/url.h b/project/jni/curl/lib/url.h index 241dc28c0..bb85e9bb3 100644 --- a/project/jni/curl/lib/url.h +++ b/project/jni/curl/lib/url.h @@ -1,5 +1,5 @@ -#ifndef __URL_H -#define __URL_H +#ifndef HEADER_CURL_URL_H +#define HEADER_CURL_URL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,13 +21,13 @@ * KIND, either express or implied. * ***************************************************************************/ - -#include /* to make sure we have ap_list */ +#include "curl_setup.h" /* * Prototypes for library-wide functions provided by url.c */ +CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn); CURLcode Curl_open(struct SessionHandle **curl); CURLcode Curl_init_userdefined(struct UserDefined *set); CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, @@ -37,25 +37,16 @@ void Curl_freeset(struct SessionHandle * data); CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */ CURLcode Curl_connect(struct SessionHandle *, struct connectdata **, bool *async, bool *protocol_connect); -CURLcode Curl_async_resolved(struct connectdata *conn, - bool *protocol_connect); CURLcode Curl_do(struct connectdata **, bool *done); -CURLcode Curl_do_more(struct connectdata *); +CURLcode Curl_do_more(struct connectdata *, int *completed); CURLcode Curl_done(struct connectdata **, CURLcode, bool premature); CURLcode Curl_disconnect(struct connectdata *, bool dead_connection); CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done); CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done); CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done); -void Curl_safefree(void *ptr); - -/* create a connection cache */ -struct conncache *Curl_mk_connc(int type, long amount); -/* free a connection cache */ -void Curl_rm_connc(struct conncache *c); -/* Change number of entries of a connection cache */ -CURLcode Curl_ch_connc(struct SessionHandle *data, - struct conncache *c, - long newamount); +CURLcode Curl_setup_conn(struct connectdata *conn, + bool *protocol_done); +void Curl_free_request_state(struct SessionHandle *data); int Curl_protocol_getsock(struct connectdata *conn, curl_socket_t *socks, @@ -76,21 +67,20 @@ void Curl_getoff_all_pipelines(struct SessionHandle *data, void Curl_close_connections(struct SessionHandle *data); -/* Called on connect, and if there's already a protocol-specific struct - allocated for a different connection, this frees it that it can be setup - properly later on. */ -void Curl_reset_reqproto(struct connectdata *conn); - #define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */ -#define CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE "rcmd" /* default socks5 gssapi service */ +#define CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE "rcmd" /* default socks5 gssapi + service */ +#define CURL_DEFAULT_PROXY_SERVICE_NAME "HTTP" /* default negotiate proxy + service */ +#define CURL_DEFAULT_SERVICE_NAME "HTTP" /* default negotiate service */ -CURLcode Curl_connected_proxy(struct connectdata *conn); +CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex); #ifdef CURL_DISABLE_VERBOSE_STRINGS -#define Curl_verboseconnect(x) do { } while (0) +#define Curl_verboseconnect(x) Curl_nop_stmt #else void Curl_verboseconnect(struct connectdata *conn); #endif -#endif +#endif /* HEADER_CURL_URL_H */ diff --git a/project/jni/curl/lib/urldata.h b/project/jni/curl/lib/urldata.h index f4f678620..f832ea886 100644 --- a/project/jni/curl/lib/urldata.h +++ b/project/jni/curl/lib/urldata.h @@ -1,5 +1,5 @@ -#ifndef __URLDATA_H -#define __URLDATA_H +#ifndef HEADER_CURL_URLDATA_H +#define HEADER_CURL_URLDATA_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -24,7 +24,7 @@ /* This file is for lib internal stuff */ -#include "setup.h" +#include "curl_setup.h" #define PORT_FTP 21 #define PORT_FTPS 990 @@ -40,6 +40,8 @@ #define PORT_IMAPS 993 #define PORT_POP3 110 #define PORT_POP3S 995 +#define PORT_SMB 445 +#define PORT_SMBS 445 #define PORT_SMTP 25 #define PORT_SMTPS 465 /* sometimes called SSMTP */ #define PORT_RTSP 554 @@ -58,6 +60,17 @@ #define CURL_DEFAULT_USER "anonymous" #define CURL_DEFAULT_PASSWORD "ftp@example.com" +/* Convenience defines for checking protocols or their SSL based version. Each + protocol handler should only ever have a single CURLPROTO_ in its protocol + field. */ +#define PROTO_FAMILY_HTTP (CURLPROTO_HTTP|CURLPROTO_HTTPS) +#define PROTO_FAMILY_FTP (CURLPROTO_FTP|CURLPROTO_FTPS) +#define PROTO_FAMILY_POP3 (CURLPROTO_POP3|CURLPROTO_POP3S) +#define PROTO_FAMILY_SMB (CURLPROTO_SMB|CURLPROTO_SMBS) +#define PROTO_FAMILY_SMTP (CURLPROTO_SMTP|CURLPROTO_SMTPS) + +#define DEFAULT_CONNCACHE_SIZE 5 + /* length of longest IPv6 address string including the trailing null */ #define MAX_IPADR_LEN sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") @@ -69,46 +82,41 @@ #include "cookie.h" #include "formdata.h" -#ifdef USE_SSLEAY #ifdef USE_OPENSSL -#include "openssl/rsa.h" -#include "openssl/crypto.h" -#include "openssl/x509.h" -#include "openssl/pem.h" -#include "openssl/ssl.h" -#include "openssl/err.h" +#include #ifdef HAVE_OPENSSL_ENGINE_H #include #endif -#ifdef HAVE_OPENSSL_PKCS12_H -#include -#endif -#else /* SSLeay-style includes */ -#include "rsa.h" -#include "crypto.h" -#include "x509.h" -#include "pem.h" -#include "ssl.h" -#include "err.h" -#ifdef HAVE_OPENSSL_ENGINE_H -#include -#endif -#ifdef HAVE_OPENSSL_PKCS12_H -#include -#endif #endif /* USE_OPENSSL */ -#ifdef USE_GNUTLS -#error Configuration error; cannot use GnuTLS *and* OpenSSL. -#endif -#endif /* USE_SSLEAY */ #ifdef USE_GNUTLS #include #endif -#ifdef USE_POLARSSL -#include +#ifdef USE_MBEDTLS + +#include +#include +#include +#include + +#elif defined USE_POLARSSL + #include +#include +#if POLARSSL_VERSION_NUMBER<0x01010000 +#include +#else +#include +#include +#endif /* POLARSSL_VERSION_NUMBER<0x01010000 */ + +#endif /* USE_POLARSSL */ + +#ifdef USE_CYASSL +#undef OCSP_REQUEST /* avoid cyassl/openssl/ssl.h clash with wincrypt.h */ +#undef OCSP_RESPONSE /* avoid cyassl/openssl/ssl.h clash with wincrypt.h */ +#include #endif #ifdef USE_NSS @@ -116,8 +124,29 @@ #include #endif -#ifdef USE_QSOSSL -#include +#ifdef USE_GSKIT +#include +#endif + +#ifdef USE_AXTLS +#include +#include +#undef malloc +#undef calloc +#undef realloc +#endif /* USE_AXTLS */ + +#ifdef USE_SCHANNEL +#include "curl_sspi.h" +#include +#include +#endif + +#ifdef USE_DARWINSSL +#include +/* For some reason, when building for iOS, the omnibus header above does + * not include SecureTransport.h as of iOS SDK 5.1. */ +#include #endif #ifdef HAVE_NETINET_IN_H @@ -134,14 +163,6 @@ #endif #endif -#ifdef USE_ARES -# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ - (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) -# define CARES_STATICLIB -# endif -# include -#endif - #include #include "http_chunks.h" /* for the structs and enum stuff */ @@ -157,7 +178,9 @@ #include "ssh.h" #include "http.h" #include "rtsp.h" +#include "smb.h" #include "wildcard.h" +#include "multihandle.h" #ifdef HAVE_GSSAPI # ifdef HAVE_GSSGNU @@ -184,6 +207,8 @@ #define HEADERSIZE 256 #define CURLEASY_MAGIC_NUMBER 0xc0dedbadU +#define GOOD_EASY_HANDLE(x) \ + ((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER)) /* Some convenience macros to get the larger/smaller value out of two given. We prefix with CURL to prevent name collisions. */ @@ -191,9 +216,9 @@ #define CURLMIN(x,y) ((x)<(y)?(x):(y)) -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) -/* Types needed for krb4/5-ftp connections */ -struct krb4buffer { +#ifdef HAVE_GSSAPI +/* Types needed for krb5-ftp connections */ +struct krb5buffer { void *data; size_t size; size_t index; @@ -211,6 +236,21 @@ enum protection_level { }; #endif +#ifdef USE_SCHANNEL +/* Structs to store Schannel handles */ +struct curl_schannel_cred { + CredHandle cred_handle; + TimeStamp time_stamp; + int refcount; + bool cached; +}; + +struct curl_schannel_ctxt { + CtxtHandle ctxt_handle; + TimeStamp time_stamp; +}; +#endif + /* enum for the nonblocking SSL connection state machine */ typedef enum { ssl_connect_1, @@ -234,49 +274,83 @@ struct ssl_connect_data { current state of the connection. */ bool use; ssl_connection_state state; -#ifdef USE_SSLEAY + ssl_connect_state connecting_state; +#if defined(USE_OPENSSL) /* these ones requires specific SSL-types */ SSL_CTX* ctx; SSL* handle; X509* server_cert; - ssl_connect_state connecting_state; -#endif /* USE_SSLEAY */ -#ifdef USE_GNUTLS - gnutls_session session; - gnutls_certificate_credentials cred; - ssl_connect_state connecting_state; -#endif /* USE_GNUTLS */ -#ifdef USE_POLARSSL - havege_state hs; +#elif defined(USE_GNUTLS) + gnutls_session_t session; + gnutls_certificate_credentials_t cred; +#ifdef USE_TLS_SRP + gnutls_srp_client_credentials_t srp_client_cred; +#endif +#elif defined(USE_MBEDTLS) + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_entropy_context entropy; + mbedtls_ssl_context ssl; + mbedtls_ssl_session ssn; + int server_fd; + mbedtls_x509_crt cacert; + mbedtls_x509_crt clicert; + mbedtls_x509_crl crl; + mbedtls_pk_context pk; + mbedtls_ssl_config config; + const char *protocols[3]; +#elif defined(USE_POLARSSL) + ctr_drbg_context ctr_drbg; + entropy_context entropy; ssl_context ssl; ssl_session ssn; int server_fd; - x509_cert cacert; - x509_cert clicert; + x509_crt cacert; + x509_crt clicert; x509_crl crl; rsa_context rsa; -#endif /* USE_POLARSSL */ -#ifdef USE_NSS +#elif defined(USE_CYASSL) + SSL_CTX* ctx; + SSL* handle; +#elif defined(USE_NSS) PRFileDesc *handle; char *client_nickname; struct SessionHandle *data; -#ifdef HAVE_PK11_CREATEGENERICOBJECT - PK11GenericObject *key; - PK11GenericObject *cacert[2]; + struct curl_llist *obj_list; + PK11GenericObject *obj_clicert; +#elif defined(USE_GSKIT) + gsk_handle handle; + int iocport; +#elif defined(USE_AXTLS) + SSL_CTX* ssl_ctx; + SSL* ssl; +#elif defined(USE_SCHANNEL) + struct curl_schannel_cred *cred; + struct curl_schannel_ctxt *ctxt; + SecPkgContext_StreamSizes stream_sizes; + size_t encdata_length, decdata_length; + size_t encdata_offset, decdata_offset; + unsigned char *encdata_buffer, *decdata_buffer; + unsigned long req_flags, ret_flags; + CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ + bool recv_sspi_close_notify; /* true if connection closed by close_notify */ + bool recv_connection_closed; /* true if connection closed, regardless how */ +#elif defined(USE_DARWINSSL) + SSLContextRef ssl_ctx; + curl_socket_t ssl_sockfd; + bool ssl_direction; /* true if writing, false if reading */ + size_t ssl_write_buffered_length; +#elif defined(USE_SSL) +#error "SSL backend specific information missing from ssl_connect_data" #endif -#endif /* USE_NSS */ -#ifdef USE_QSOSSL - SSLHandle *handle; -#endif /* USE_QSOSSL */ }; struct ssl_config_data { long version; /* what version the client wants to use */ long certverifyresult; /* result from the certificate verification */ - long verifypeer; /* set TRUE if this is desired */ - long verifyhost; /* 0: no verify - 1: check that CN exists - 2: CN must match hostname */ + + bool verifypeer; /* set TRUE if this is desired */ + bool verifyhost; /* set TRUE if CN/SAN must match hostname */ + bool verifystatus; /* set TRUE if certificate status must be checked */ char *CApath; /* certificate dir (doesn't work on windows) */ char *CAfile; /* certificate to verify peer against */ const char *CRLfile; /* CRL to check certificate revocation */ @@ -284,11 +358,18 @@ struct ssl_config_data { char *random_file; /* path to file containing "random" data */ char *egdsocket; /* path to file containing the EGD daemon socket */ char *cipher_list; /* list of ciphers to use */ - long numsessions; /* SSL session id cache size */ + size_t max_ssl_sessions; /* SSL session id cache size */ curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */ void *fsslctxp; /* parameter for call back */ bool sessionid; /* cache session IDs or not */ bool certinfo; /* gather lots of certificate info */ + bool falsestart; + +#ifdef USE_TLS_SRP + char *username; /* TLS username (for, e.g., SRP) */ + char *password; /* TLS password (for, e.g., SRP) */ + enum CURL_TLSAUTH authtype; /* TLS authentication type (default SRP) */ +#endif }; /* information stored about one single SSL session */ @@ -297,12 +378,16 @@ struct curl_ssl_session { void *sessionid; /* as returned from the SSL layer */ size_t idsize; /* if known, otherwise 0 */ long age; /* just a number, the higher the more recent */ - unsigned short remote_port; /* remote port to connect to */ + int remote_port; /* remote port to connect to */ struct ssl_config_data ssl_config; /* setup for this session */ }; /* Struct used for Digest challenge-response authentication */ struct digestdata { +#if defined(USE_WINDOWS_SSPI) + BYTE *input_token; + size_t input_token_len; +#else char *nonce; char *cnonce; char *realm; @@ -312,6 +397,7 @@ struct digestdata { char *qop; char *algorithm; int nc; /* nounce count */ +#endif }; typedef enum { @@ -330,34 +416,69 @@ typedef enum { #include #endif +/* Struct used for GSSAPI (Kerberos V5) authentication */ +#if defined(USE_KERBEROS5) +struct kerberos5data { +#if defined(USE_WINDOWS_SSPI) + CredHandle *credentials; + CtxtHandle *context; + TCHAR *spn; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + size_t token_max; + BYTE *output_token; +#else + gss_ctx_id_t context; + gss_name_t spn; +#endif +}; +#endif + /* Struct used for NTLM challenge-response authentication */ +#if defined(USE_NTLM) struct ntlmdata { curlntlm state; #ifdef USE_WINDOWS_SSPI - CredHandle handle; - CtxtHandle c_handle; + CredHandle *credentials; + CtxtHandle *context; SEC_WINNT_AUTH_IDENTITY identity; SEC_WINNT_AUTH_IDENTITY *p_identity; - int has_handles; - void *type_2; - int n_type_2; + size_t token_max; + BYTE *output_token; + BYTE *input_token; + size_t input_token_len; #else unsigned int flags; unsigned char nonce[8]; + void* target_info; /* TargetInfo received in the ntlm type-2 message */ + unsigned int target_info_len; #endif }; +#endif -#ifdef HAVE_GSSAPI +#ifdef USE_SPNEGO struct negotiatedata { - /* when doing Negotiate we first need to receive an auth token and then we - need to send our header */ + /* When doing Negotiate (SPNEGO) auth, we first need to send a token + and then validate the received one. */ enum { GSS_AUTHNONE, GSS_AUTHRECV, GSS_AUTHSENT } state; - bool gss; /* Whether we're processing GSS-Negotiate or Negotiate */ - const char* protocol; /* "GSS-Negotiate" or "Negotiate" */ +#ifdef HAVE_GSSAPI OM_uint32 status; gss_ctx_id_t context; gss_name_t server_name; gss_buffer_desc output_token; +#else +#ifdef USE_WINDOWS_SSPI + DWORD status; + CredHandle *credentials; + CtxtHandle *context; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + TCHAR *server_name; + size_t token_max; + BYTE *output_token; + size_t output_token_length; +#endif +#endif }; #endif @@ -366,6 +487,7 @@ struct negotiatedata { * Boolean values that concerns this connection. */ struct ConnectBits { + /* always modify bits.close with the connclose() and connkeep() macros! */ bool close; /* if set, we close the connection after this request */ bool reuse; /* if set, this is a re-used connection */ bool proxy; /* if set, this transfer is done through a proxy - any type */ @@ -378,8 +500,7 @@ struct ConnectBits { bool do_more; /* this is set TRUE if the ->curl_do_more() function is supposed to be called, after ->curl_do() */ - - bool tcpconnect; /* the TCP layer (or similar) is connected, this is set + bool tcpconnect[2]; /* the TCP layer (or similar) is connected, this is set the first time on the first connect function call */ bool protoconnstart;/* the protocol layer has STARTED its operation after the TCP layer connect */ @@ -390,8 +511,6 @@ struct ConnectBits { This is implicit when SSL-protocols are used through proxies, but can also be enabled explicitly by apps */ - bool tunnel_connecting; /* TRUE while we're still waiting for a proxy CONNECT - */ bool authneg; /* TRUE when the auth phase has started, which means that we are creating a request with an auth header, but it is not the final request in the auth @@ -409,11 +528,6 @@ struct ConnectBits { requests */ bool netrc; /* name+password provided by netrc */ bool userpwd_in_url; /* name+password found in url */ - - bool done; /* set to FALSE when Curl_do() is called and set to TRUE - when Curl_done() is called, to prevent Curl_done() to - get invoked twice when the multi interface is - used. */ bool stream_was_rewound; /* Indicates that the stream was rewound after a request read past the end of its response byte boundary */ @@ -423,6 +537,7 @@ struct ConnectBits { bool bound; /* set true if bind() has already been done on this socket/ connection */ bool type_set; /* type= was used in the URL */ + bool multiplex; /* connection is multiplexed */ }; struct hostname { @@ -477,10 +592,9 @@ struct Curl_async { /* These function pointer types are here only to allow easier typecasting within the source when we need to cast between data pointers (such as NULL) and function pointers. */ -typedef CURLcode (*Curl_do_more_func)(struct connectdata *); +typedef CURLcode (*Curl_do_more_func)(struct connectdata *, int *); typedef CURLcode (*Curl_done_func)(struct connectdata *, CURLcode, bool); - enum expect100 { EXP100_SEND_DATA, /* enough waiting, just send the body now */ EXP100_AWAITING_CONTINUE, /* waiting for the 100 Continue header */ @@ -489,6 +603,13 @@ enum expect100 { EXP100_FAILED /* used on 417 Expectation Failed */ }; +enum upgrade101 { + UPGR101_INIT, /* default state */ + UPGR101_REQUESTED, /* upgrade requested */ + UPGR101_RECEIVED, /* response received */ + UPGR101_WORKING /* talking upgraded protocol */ +}; + /* * Request specific data in the easy handle (SessionHandle). Previously, * these members were on the connectdata struct but since a conn struct may @@ -509,7 +630,7 @@ struct SingleRequest { long headerbytecount; /* only count received headers */ long deductheadercount; /* this amount of bytes doesn't count when we check - if anything has been transfered at the end of a + if anything has been transferred at the end of a connection. We use this counter to make only a 100 reply (without a following second response code) result in a CURLE_GOT_NOTHING error code */ @@ -539,13 +660,13 @@ struct SingleRequest { 'RTSP/1.? XXX' line */ struct timeval start100; /* time stamp to wait for the 100 code from */ enum expect100 exp100; /* expect 100 continue state */ + enum upgrade101 upgr101; /* 101 upgrade state */ - int content_encoding; /* What content encoding. sec 3.5, RFC2616. */ + int auto_decoding; /* What content encoding. sec 3.5, RFC2616. */ #define IDENTITY 0 /* No encoding */ #define DEFLATE 1 /* zlib deflate [RFC 1950 & 1951] */ #define GZIP 2 /* gzip algorithm [RFC 1952] */ -#define COMPRESS 3 /* Not handled, added for completeness */ #ifdef HAVE_LIBZ zlibInitState zlib_init; /* possible zlib init state; @@ -592,6 +713,9 @@ struct SingleRequest { bool forbidchunk; /* used only to explicitly forbid chunk-upload for specific upload buffers. See readmoredata() in http.c for details. */ + + void *protop; /* Allocated protocol-specific data. Each protocol + handler makes sure this points to data it needs. */ }; /* @@ -638,6 +762,12 @@ struct Curl_handler { curl_socket_t *socks, int numsocks); + /* Called from the multi interface during the DO_MORE phase, and it should + then return a proper fd set */ + int (*domore_getsock)(struct connectdata *conn, + curl_socket_t *socks, + int numsocks); + /* Called from the multi interface during the DO_DONE, PERFORM and WAITPERFORM phases, and it should then return a proper fd set. Not setting this will make libcurl use the generic default one. */ @@ -652,10 +782,35 @@ struct Curl_handler { */ CURLcode (*disconnect)(struct connectdata *, bool dead_connection); - long defport; /* Default port. */ - long protocol; /* PROT_* flags concerning the protocol set */ + /* If used, this function gets called from transfer.c:readwrite_data() to + allow the protocol to do extra reads/writes */ + CURLcode (*readwrite)(struct SessionHandle *data, struct connectdata *conn, + ssize_t *nread, bool *readmore); + + long defport; /* Default port. */ + unsigned int protocol; /* See CURLPROTO_* - this needs to be the single + specific protocol bit */ + unsigned int flags; /* Extra particular characteristics, see PROTOPT_* */ }; +#define PROTOPT_NONE 0 /* nothing extra */ +#define PROTOPT_SSL (1<<0) /* uses SSL */ +#define PROTOPT_DUAL (1<<1) /* this protocol uses two connections */ +#define PROTOPT_CLOSEACTION (1<<2) /* need action before socket close */ +/* some protocols will have to call the underlying functions without regard to + what exact state the socket signals. IE even if the socket says "readable", + the send function might need to be called while uploading, or vice versa. +*/ +#define PROTOPT_DIRLOCK (1<<3) +#define PROTOPT_NONETWORK (1<<4) /* protocol doesn't use the network! */ +#define PROTOPT_NEEDSPWD (1<<5) /* needs a password, and if none is set it + gets a default */ +#define PROTOPT_NOURLQUERY (1<<6) /* protocol can't handle + url query strings (?foo=bar) ! */ +#define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per + request instead of per connection */ + + /* return the count of bytes sent, or -1 on error */ typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */ int sockindex, /* socketindex */ @@ -685,52 +840,17 @@ struct connectdata { and a HTTP proxy may in fact respond using chunked encoding */ struct Curl_chunker chunk; + curl_closesocket_callback fclosesocket; /* function closing the socket(s) */ + void *closesocket_client; + bool inuse; /* This is a marker for the connection cache logic. If this is TRUE this handle is being used by an easy handle and cannot be used by any other easy handle without careful consideration (== only for pipelining). */ /**** Fields set when inited and not modified again */ - long connectindex; /* what index in the connection cache connects index this - particular struct has */ - long protocol; /* PROT_* flags concerning the protocol set */ -#define PROT_HTTP CURLPROTO_HTTP -#define PROT_HTTPS CURLPROTO_HTTPS -#define PROT_FTP CURLPROTO_FTP -#define PROT_TELNET CURLPROTO_TELNET -#define PROT_DICT CURLPROTO_DICT -#define PROT_LDAP CURLPROTO_LDAP -#define PROT_FILE CURLPROTO_FILE -#define PROT_FTPS CURLPROTO_FTPS -#define PROT_TFTP CURLPROTO_TFTP -#define PROT_SCP CURLPROTO_SCP -#define PROT_SFTP CURLPROTO_SFTP -#define PROT_IMAP CURLPROTO_IMAP -#define PROT_IMAPS CURLPROTO_IMAPS -#define PROT_POP3 CURLPROTO_POP3 -#define PROT_POP3S CURLPROTO_POP3S -#define PROT_SMTP CURLPROTO_SMTP -#define PROT_SMTPS CURLPROTO_SMTPS -#define PROT_RTSP CURLPROTO_RTSP -#define PROT_RTMP CURLPROTO_RTMP -#define PROT_RTMPT CURLPROTO_RTMPT -#define PROT_RTMPE CURLPROTO_RTMPE -#define PROT_RTMPTE CURLPROTO_RTMPTE -#define PROT_RTMPS CURLPROTO_RTMPS -#define PROT_RTMPTS CURLPROTO_RTMPTS -#define PROT_GOPHER CURLPROTO_GOPHER - -/* (1<<25) is currently the highest used bit in the public bitmask. We make - sure we use "private bits" above the public ones to make things easier; - Gopher will not conflict with the current bit 25. */ - -#define PROT_EXTMASK 0x03ffffff - -#define PROT_SSL (1<<29) /* protocol requires SSL */ - -/* these ones need action before socket close */ -#define PROT_CLOSEACTION (PROT_FTP | PROT_IMAP | PROT_POP3) -#define PROT_DUALCHANNEL PROT_FTP /* these protocols use two connections */ + long connection_id; /* Contains a unique number to make it easier to + track the connections in the log output */ /* 'dns_entry' is the particular host we use. This points to an entry in the DNS cache and it will not get pruned while locked. It gets unlocked in @@ -742,13 +862,14 @@ struct connectdata { within the DNS cache, so this pointer is only valid as long as the DNS cache entry remains locked. It gets unlocked in Curl_done() */ Curl_addrinfo *ip_addr; + Curl_addrinfo *tempaddr[2]; /* for happy eyeballs */ /* 'ip_addr_str' is the ip_addr data as a human readable string. It remains available as long as the connection does, which is longer than the ip_addr itself. */ char ip_addr_str[MAX_IPADR_LEN]; - unsigned int scope; /* address scope for IPv6 */ + unsigned int scope_id; /* Scope id for IPv6 */ int socktype; /* SOCK_STREAM or SOCK_DGRAM */ @@ -756,14 +877,13 @@ struct connectdata { struct hostname proxy; long port; /* which port to use locally */ - unsigned short remote_port; /* what remote port to connect to, - not the proxy port! */ + int remote_port; /* what remote port to connect to, not the proxy port! */ /* 'primary_ip' and 'primary_port' get filled with peer's numerical ip address and port number whenever an outgoing connection is - *attemted* from the primary socket to a remote address. When more + *attempted* from the primary socket to a remote address. When more than one address is tried for a connection these will hold data - for the last attempt. When the connection is actualy established + for the last attempt. When the connection is actually established these are updated with data which comes directly from the socket. */ char primary_ip[MAX_IPADR_LEN]; @@ -778,6 +898,9 @@ struct connectdata { char *user; /* user name string, allocated */ char *passwd; /* password string, allocated */ + char *options; /* options string, allocated */ + + char *oauth_bearer; /* bearer token for OAuth 2.0, allocated */ char *proxyuser; /* proxy user name string, allocated */ char *proxypasswd; /* proxy password string, allocated */ @@ -790,16 +913,29 @@ struct connectdata { struct timeval created; /* creation time */ curl_socket_t sock[2]; /* two sockets, the second is used for the data transfer when doing FTP */ - + curl_socket_t tempsock[2]; /* temporary sockets for happy eyeballs */ + bool sock_accepted[2]; /* TRUE if the socket on this index was created with + accept() */ Curl_recv *recv[2]; Curl_send *send[2]; struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */ struct ssl_config_data ssl_config; + bool tls_upgraded; struct ConnectBits bits; /* various state-flags for this connection */ - const struct Curl_handler * handler; /* Connection's protocol handler. */ + /* connecttime: when connect() is called on the current IP address. Used to + be able to track when to move on to try next IP - but only when the multi + interface is used. */ + struct timeval connecttime; + /* The two fields below get set in Curl_connecthost */ + int num_addr; /* number of addresses to try to connect to */ + long timeoutms_per_addr; /* how long time in milliseconds to spend on + trying to connect to each IP address */ + + const struct Curl_handler *handler; /* Connection's protocol handler */ + const struct Curl_handler *given; /* The protocol first given */ long ip_version; /* copied from the SessionHandle at creation time */ @@ -810,32 +946,37 @@ struct connectdata { well be the same we read from. CURL_SOCKET_BAD disables */ - /** Dynamicly allocated strings, may need to be freed before this **/ - /** struct is killed. **/ + /** Dynamicly allocated strings, MUST be freed before this **/ + /** struct is killed. **/ struct dynamically_allocated_data { - char *proxyuserpwd; /* free later if not NULL! */ - char *uagent; /* free later if not NULL! */ - char *accept_encoding; /* free later if not NULL! */ - char *userpwd; /* free later if not NULL! */ - char *rangeline; /* free later if not NULL! */ - char *ref; /* free later if not NULL! */ - char *host; /* free later if not NULL */ - char *cookiehost; /* free later if not NULL */ - char *rtsp_transport; /* free later if not NULL */ + char *proxyuserpwd; + char *uagent; + char *accept_encoding; + char *userpwd; + char *rangeline; + char *ref; + char *host; + char *cookiehost; + char *rtsp_transport; + char *te; /* TE: request header */ } allocptr; - int sec_complete; /* if kerberos is enabled for this connection */ -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) +#ifdef HAVE_GSSAPI + int sec_complete; /* if Kerberos is enabled for this connection */ enum protection_level command_prot; enum protection_level data_prot; enum protection_level request_data_prot; size_t buffer_size; - struct krb4buffer in_buffer; + struct krb5buffer in_buffer; void *app_data; const struct Curl_sec_client_mech *mech; struct sockaddr_in local_addr; #endif +#if defined(USE_KERBEROS5) /* Consider moving some of the above GSS-API */ + struct kerberos5data krb5; /* variables into the structure definition, */ +#endif /* however, some of them are ftp specific. */ + /* the two following *_inuse fields are only flags, not counters in any way. If TRUE it means the channel is in use, and if FALSE it means the channel is up for grabs by one. */ @@ -844,19 +985,10 @@ struct connectdata { handle */ bool writechannel_inuse; /* whether the write channel is in use by an easy handle */ - bool server_supports_pipelining; /* TRUE if server supports pipelining, - set after first response */ - struct curl_llist *send_pipe; /* List of handles waiting to send on this pipeline */ struct curl_llist *recv_pipe; /* List of handles waiting to read their responses on this pipeline */ - struct curl_llist *pend_pipe; /* List of pending handles on - this pipeline */ - struct curl_llist *done_pipe; /* Handles that are finished, but - still reference this connectdata */ -#define MAX_PIPELINE_LENGTH 5 - char* master_buffer; /* The master buffer allocated on-demand; used for pipelining. */ size_t read_pos; /* Current read position in the master buffer */ @@ -868,15 +1000,21 @@ struct connectdata { /*************** Request - specific items ************/ - /* previously this was in the urldata struct */ - curl_read_callback fread_func; /* function that reads the input */ - void *fread_in; /* pointer to pass to the fread() above */ - +#if defined(USE_NTLM) struct ntlmdata ntlm; /* NTLM differs from other authentication schemes because it authenticates connections, not single requests! */ struct ntlmdata proxyntlm; /* NTLM data for proxy */ +#if defined(NTLM_WB_ENABLED) + /* used for communication with Samba's winbind daemon helper ntlm_auth */ + curl_socket_t ntlm_auth_hlpr_socket; + pid_t ntlm_auth_hlpr_pid; + char* challenge_header; + char* response_header; +#endif +#endif + char syserr_buf [256]; /* buffer for Curl_strerror() */ #ifdef CURLRES_ASYNCH @@ -891,13 +1029,15 @@ struct connectdata { union { struct ftp_conn ftpc; + struct http_conn httpc; struct ssh_conn sshc; struct tftp_state_data *tftpc; struct imap_conn imapc; struct pop3_conn pop3c; struct smtp_conn smtpc; struct rtsp_conn rtspc; - void *generic; + struct smb_conn smbc; + void *generic; /* RTMP and LDAP use this */ } proto; int cselect_bits; /* bitmask of socket events */ @@ -907,8 +1047,27 @@ struct connectdata { int socks5_gssapi_enctype; #endif - long verifypeer; - long verifyhost; + bool verifypeer; + bool verifyhost; + + /* When this connection is created, store the conditions for the local end + bind. This is stored before the actual bind and before any connection is + made and will serve the purpose of being used for comparison reasons so + that subsequent bound-requested connections aren't accidentally re-using + wrong connections. */ + char *localdev; + unsigned short localport; + int localportrange; + + /* tunnel as in tunnel through a HTTP proxy with CONNECT */ + enum { + TUNNEL_INIT, /* init/default/no tunnel state */ + TUNNEL_CONNECT, /* CONNECT has been sent off */ + TUNNEL_COMPLETE /* CONNECT response received completely */ + } tunnel_state[2]; /* two separate ones to allow FTP */ + struct connectbundle *bundle; /* The bundle we are member of */ + + int negnpn; /* APLN or NPN TLS negotiated protocol, CURL_HTTP_VERSION* */ }; /* The end of connectdata. */ @@ -928,8 +1087,8 @@ struct PureInfo { thus made the document NOT get fetched */ long header_size; /* size of read header(s) in bytes */ long request_size; /* the amount of bytes sent in the request(s) */ - long proxyauthavail; /* what proxy auth types were announced */ - long httpauthavail; /* what host auth types were announced */ + unsigned long proxyauthavail; /* what proxy auth types were announced */ + unsigned long httpauthavail; /* what host auth types were announced */ long numconnects; /* how many new connection did libcurl created */ char *contenttype; /* the content type of the object */ char *wouldredirect; /* URL this would've been redirected to if asked to */ @@ -959,8 +1118,8 @@ struct Progress { force redraw at next call */ curl_off_t size_dl; /* total expected size */ curl_off_t size_ul; /* total expected size */ - curl_off_t downloaded; /* transfered so far */ - curl_off_t uploaded; /* transfered so far */ + curl_off_t downloaded; /* transferred so far */ + curl_off_t uploaded; /* transferred so far */ curl_off_t current_speed; /* uses the currently fastest transfer */ @@ -982,6 +1141,8 @@ struct Progress { struct timeval start; struct timeval t_startsingle; + struct timeval t_startop; + struct timeval t_acceptdata; #define CURR_TIME (5+1) /* 6 entries for 5 seconds */ curl_off_t speeder[ CURR_TIME ]; @@ -1026,15 +1187,13 @@ typedef enum { * Session-data MUST be put in the connectdata struct and here. */ #define MAX_CURL_USER_LENGTH 256 #define MAX_CURL_PASSWORD_LENGTH 256 -#define MAX_CURL_USER_LENGTH_TXT "255" -#define MAX_CURL_PASSWORD_LENGTH_TXT "255" struct auth { - long want; /* Bitmask set to the authentication methods wanted by the app - (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */ - long picked; - long avail; /* bitmask for what the server reports to support for this - resource */ + unsigned long want; /* Bitmask set to the authentication methods wanted by + app (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */ + unsigned long picked; + unsigned long avail; /* Bitmask for what the server reports to support for + this resource */ bool done; /* TRUE when the auth phase is done and ready to do the *actual* request */ bool multi; /* TRUE if this is not yet authenticated but within the auth @@ -1043,32 +1202,20 @@ struct auth { be RFC compliant */ }; -struct conncache { - /* 'connects' will be an allocated array with pointers. If the pointer is - set, it holds an allocated connection. */ - struct connectdata **connects; - long num; /* number of entries of the 'connects' array */ - enum { - CONNCACHE_PRIVATE, /* used for an easy handle alone */ - CONNCACHE_MULTI /* shared within a multi handle */ - } type; -}; - - struct UrlState { - enum { - Curl_if_none, - Curl_if_easy, - Curl_if_multi - } used_interface; - struct conncache *connc; /* points to the connection cache this handle - uses */ + /* Points to the connection cache */ + struct conncache *conn_cache; + + /* when curl_easy_perform() is called, the multi handle is "owned" by + the easy handle so curl_easy_cleanup() on such an easy handle will + also close the multi handle! */ + bool multi_owned_by_easy; /* buffers to store authentication data in, as parsed from input options */ struct timeval keeps_speed; /* for the progress meter really */ - long lastconnect; /* index of most recent connect or -1 if undefined */ + struct connectdata *lastconnect; /* The last connection, NULL if undefined */ char *headerbuff; /* allocated buffer to store headers in */ size_t headersize; /* size of the allocation */ @@ -1084,7 +1231,7 @@ struct UrlState { following not keep sending user+password... This is strdup() data. */ - struct curl_ssl_session *session; /* array of 'numsessions' size */ + struct curl_ssl_session *session; /* array of 'max_ssl_sessions' size */ long sessionage; /* number of the most recent session */ char *tempwrite; /* allocated buffer to keep data in when a write callback returns to make the connection paused */ @@ -1105,7 +1252,7 @@ struct UrlState { struct digestdata digest; /* state data for host Digest auth */ struct digestdata proxydigest; /* state data for proxy Digest auth */ -#ifdef HAVE_GSSAPI +#ifdef USE_SPNEGO struct negotiatedata negotiate; /* state data for host Negotiate auth */ struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */ #endif @@ -1115,13 +1262,12 @@ struct UrlState { bool authproblem; /* TRUE if there's some problem authenticating */ -#ifdef USE_ARES - ares_channel areschannel; /* for name resolves */ -#endif + void *resolver; /* resolver state, if it is used in the URL state - + ares_channel f.e. */ -#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H) +#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) ENGINE *engine; -#endif /* USE_SSLEAY */ +#endif /* USE_OPENSSL */ struct timeval expiretime; /* set this with Curl_expire() only */ struct Curl_tree timenode; /* for the splay stuff */ struct curl_llist *timeoutlist; /* list of pending timeouts */ @@ -1148,14 +1294,6 @@ struct UrlState { /* for FTP downloads: how many CRLFs did we converted to LFs? */ curl_off_t crlf_conversions; #endif - /* If set to non-NULL, there's a connection in a shared connection cache - that uses this handle so we can't kill this SessionHandle just yet but - must keep it around and add it to the list of handles to kill once all - its connections are gone */ - void *shared_conn; - bool closed; /* set to TRUE when curl_easy_cleanup() has been called on this - handle, but it is kept around as mentioned for - shared_conn */ char *pathbuffer;/* allocated buffer to store the URL's path part in */ char *path; /* path to use, points to somewhere within the pathbuffer area */ @@ -1173,32 +1311,22 @@ struct UrlState { long rtsp_next_server_CSeq; /* the session's next server CSeq */ long rtsp_CSeq_recv; /* most recent CSeq received */ - /* Protocol specific data. - * - ************************************************************************* - * Note that this data will be REMOVED after each request, so anything that - * should be kept/stored on a per-connection basis and thus live for the - * next request on the same connection MUST be put in the connectdata struct! - *************************************************************************/ - union { - struct HTTP *http; - struct HTTP *https; /* alias, just for the sake of being more readable */ - struct RTSP *rtsp; - struct FTP *ftp; - /* void *tftp; not used */ - struct FILEPROTO *file; - void *telnet; /* private for telnet.c-eyes only */ - void *generic; - struct SSHPROTO *ssh; - struct FTP *imap; - struct FTP *pop3; - struct FTP *smtp; - } proto; - /* current user of this SessionHandle instance, or NULL */ - struct connectdata *current_conn; + curl_off_t infilesize; /* size of file to upload, -1 means unknown. + Copied from set.filesize at start of operation */ - /* if true, force SSL connection retry (workaround for certain servers) */ - bool ssl_connect_retry; + int drain; /* Increased when this stream has data to read, even if its + socket not necessarily is readable. Decreased when + checked. */ + bool done; /* set to FALSE when Curl_do() is called and set to TRUE when + Curl_done() is called, to prevent Curl_done() to get invoked + twice when the multi interface is used. */ + + curl_read_callback fread_func; /* read callback/function */ + void *in; /* CURLOPT_READDATA */ + + struct SessionHandle *stream_depends_on; + bool stream_depends_e; /* set or don't set the Exclusive bit */ + int stream_weight; }; @@ -1228,7 +1356,7 @@ struct DynamicStatic { * the 'DynamicStatic' struct. * Character pointer fields point to dynamic storage, unless otherwise stated. */ -struct Curl_one_easy; /* declared and used only in multi.c */ + struct Curl_multi; /* declared and used only in multi.c */ enum dupstring { @@ -1237,6 +1365,7 @@ enum dupstring { STRING_COOKIE, /* HTTP cookie string to send */ STRING_COOKIEJAR, /* dump all cookies to this file */ STRING_CUSTOMREQUEST, /* HTTP/FTP/RTSP request/method to use */ + STRING_DEFAULT_PROTOCOL, /* Protocol to use when the URL doesn't specify */ STRING_DEVICE, /* local network interface/address to use */ STRING_ENCODING, /* Accept-Encoding string */ STRING_FTP_ACCOUNT, /* ftp account data */ @@ -1248,13 +1377,13 @@ enum dupstring { STRING_KRB_LEVEL, /* krb security level */ STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find $HOME/.netrc */ - STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */ STRING_PROXY, /* proxy to use */ STRING_SET_RANGE, /* range, if used */ STRING_SET_REFERER, /* custom string for the HTTP referer field */ STRING_SET_URL, /* what original URL to work on */ STRING_SSL_CAPATH, /* CA directory name (doesn't work on windows) */ STRING_SSL_CAFILE, /* certificate file to verify peer against */ + STRING_SSL_PINNEDPUBLICKEY, /* public key file to verify peer against */ STRING_SSL_CIPHER_LIST, /* list of ciphers to use */ STRING_SSL_EGDSOCKET, /* path to file containing the EGD daemon socket */ STRING_SSL_RANDOM_FILE, /* path to file containing "random" data */ @@ -1263,6 +1392,7 @@ enum dupstring { STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */ STRING_USERNAME, /* , if used */ STRING_PASSWORD, /* , if used */ + STRING_OPTIONS, /* , if used */ STRING_PROXYUSERNAME, /* Proxy , if used */ STRING_PROXYPASSWORD, /* Proxy , if used */ STRING_NOPROXY, /* List of hosts which should not use the proxy, if @@ -1277,11 +1407,31 @@ enum dupstring { STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */ #endif #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - STRING_SOCKS5_GSSAPI_SERVICE, /* GSSAPI service name */ + STRING_SOCKS5_GSSAPI_SERVICE, /* GSSAPI service name */ + STRING_PROXY_SERVICE_NAME, /* Proxy service name */ + STRING_SERVICE_NAME, /* Service name */ #endif STRING_MAIL_FROM, + STRING_MAIL_AUTH, + +#ifdef USE_TLS_SRP + STRING_TLSAUTH_USERNAME, /* TLS auth */ + STRING_TLSAUTH_PASSWORD, /* TLS auth */ +#endif + STRING_BEARER, /* , if used */ +#ifdef USE_UNIX_SOCKETS + STRING_UNIX_SOCKET_PATH, /* path to Unix socket, if used */ +#endif + + /* -- end of zero-terminated strings -- */ + + STRING_LASTZEROTERMINATED, + + /* -- below this are pointers to binary data that cannot be strdup'ed. + Each such pointer must be added manually to Curl_dupset() --- */ + + STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */ - /* -- end of strings -- */ STRING_LAST /* not used, just an end-of-list marker */ }; @@ -1292,19 +1442,19 @@ struct UserDefined { long proxyport; /* If non-zero, use this port number by default. If the proxy string features a ":[port]" that one will override this. */ - void *out; /* the fetched file goes here */ - void *in; /* the uploaded file is read from here */ + void *out; /* CURLOPT_WRITEDATA */ + void *in_set; /* CURLOPT_READDATA */ void *writeheader; /* write the header to this if non-NULL */ void *rtp_out; /* write RTP to this if non-NULL */ long use_port; /* which port to use (when not using default) */ - long httpauth; /* what kind of HTTP authentication to use (bitmask) */ - long proxyauth; /* what kind of proxy authentication to use (bitmask) */ + unsigned long httpauth; /* kind of HTTP authentication to use (bitmask) */ + unsigned long proxyauth; /* kind of proxy authentication to use (bitmask) */ long followlocation; /* as in HTTP Location: */ long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1 for infinity */ - bool post301; /* Obey RFC 2616/10.3.2 and keep POSTs as POSTs after a - 301 */ - bool post302; /* keep POSTs as POSTs after a 302 */ + + int keep_post; /* keep POSTs as POSTs after a 30x request; each + bit represents a request, from 301 to 303 */ bool free_referer; /* set TRUE if 'referer' points to a string we allocated */ void *postfields; /* if POST, set the fields' values here */ @@ -1318,17 +1468,22 @@ struct UserDefined { curl_write_callback fwrite_func; /* function that stores the output */ curl_write_callback fwrite_header; /* function that stores headers */ curl_write_callback fwrite_rtp; /* function that stores interleaved RTP */ - curl_read_callback fread_func; /* function that reads the input */ + curl_read_callback fread_func_set; /* function that reads the input */ int is_fread_set; /* boolean, has read callback been set to non-NULL? */ int is_fwrite_set; /* boolean, has write callback been set to non-NULL? */ - curl_progress_callback fprogress; /* function for progress information */ + curl_progress_callback fprogress; /* OLD and deprecated progress callback */ + curl_xferinfo_callback fxferinfo; /* progress callback */ curl_debug_callback fdebug; /* function that write informational data */ curl_ioctl_callback ioctl_func; /* function for I/O control */ curl_sockopt_callback fsockopt; /* function for setting socket options */ void *sockopt_client; /* pointer to pass to the socket options callback */ curl_opensocket_callback fopensocket; /* function for checking/translating - the address and opening the socket */ + the address and opening the + socket */ void* opensocket_client; + curl_closesocket_callback fclosesocket; /* function for closing the + socket */ + void* closesocket_client; void *seek_client; /* pointer to pass to the seek callback */ /* the 3 curl_conv_callback functions below are used on non-ASCII hosts */ @@ -1343,16 +1498,21 @@ struct UserDefined { void *ioctl_client; /* pointer to pass to the ioctl callback */ long timeout; /* in milliseconds, 0 means no timeout */ long connecttimeout; /* in milliseconds, 0 means no timeout */ + long accepttimeout; /* in milliseconds, 0 means no timeout */ long server_response_timeout; /* in milliseconds, 0 means no timeout */ - long tftp_blksize ; /* in bytes, 0 means use default */ - curl_off_t infilesize; /* size of file to upload, -1 means unknown */ + long tftp_blksize; /* in bytes, 0 means use default */ + bool tftp_no_options; /* do not send TFTP options requests */ + curl_off_t filesize; /* size of file to upload, -1 means unknown */ long low_speed_limit; /* bytes/second */ long low_speed_time; /* number of seconds */ curl_off_t max_send_speed; /* high speed limit in bytes/second for upload */ - curl_off_t max_recv_speed; /* high speed limit in bytes/second for download */ + curl_off_t max_recv_speed; /* high speed limit in bytes/second for + download */ curl_off_t set_resume_from; /* continue [ftp] transfer from here */ struct curl_slist *headers; /* linked list of extra headers */ + struct curl_slist *proxyheaders; /* linked list of extra CONNECT headers */ struct curl_httppost *httppost; /* linked list of POST data */ + bool sep_headers; /* handle host and proxy headers separately */ bool cookiesession; /* new cookie session? */ bool crlf; /* convert crlf on ftp upload(?) */ struct curl_slist *quote; /* after connection is established */ @@ -1377,12 +1537,6 @@ struct UserDefined { long buffer_size; /* size of receive buffer to use */ void *private_data; /* application-private data */ - struct Curl_one_easy *one_easy; /* When adding an easy handle to a multi - handle, an internal 'Curl_one_easy' - struct is created and this is a pointer - to the particular struct associated with - this SessionHandle */ - struct curl_slist *http200aliases; /* linked list of aliases for http200 */ long ipver; /* the CURL_IPRESOLVE_* defines in the public header file @@ -1411,26 +1565,27 @@ struct UserDefined { bool ftp_list_only; /* switch FTP command for listing directories */ bool ftp_use_port; /* use the FTP PORT command */ bool hide_progress; /* don't use the progress meter */ - bool http_fail_on_error; /* fail on HTTP error codes >= 300 */ + bool http_fail_on_error; /* fail on HTTP error codes >= 400 */ bool http_follow_location; /* follow HTTP redirects */ + bool http_transfer_encoding; /* request compressed HTTP transfer-encoding */ bool http_disable_hostname_check_before_authentication; bool include_header; /* include received protocol headers in data output */ bool http_set_referer; /* is a custom referer used */ bool http_auto_referer; /* set "correct" referer when following location: */ - bool opt_no_body; /* as set with CURLOPT_NO_BODY */ + bool opt_no_body; /* as set with CURLOPT_NOBODY */ bool set_port; /* custom port number used */ bool upload; /* upload request */ enum CURL_NETRC_OPTION use_netrc; /* defined in include/curl.h */ bool verbose; /* output verbosity */ - bool krb; /* kerberos connection requested */ + bool krb; /* Kerberos connection requested */ bool reuse_forbid; /* forbidden to be reused, close after use */ bool reuse_fresh; /* do not re-use an existing connection */ bool ftp_use_epsv; /* if EPSV is to be attempted or not */ bool ftp_use_eprt; /* if EPRT is to be attempted or not */ bool ftp_use_pret; /* if PRET is to be used before PASV or not */ - curl_usessl ftp_ssl; /* if AUTH TLS is to be attempted etc, for FTP or + curl_usessl use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or IMAP or POP3 or others! */ curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */ curl_ftpccc ftp_ccc; /* FTP CCC options */ @@ -1441,6 +1596,9 @@ struct UserDefined { bool ftp_skip_ip; /* skip the IP address the FTP server passes on to us */ bool connect_only; /* make connection, let application use the socket */ + bool ssl_enable_beast; /* especially allow this flaw for interoperability's + sake*/ + bool ssl_no_revoke; /* disable SSL certificate revocation checks */ long ssh_auth_types; /* allowed SSH auth types */ bool http_te_skip; /* pass the raw body data to the user, even when transfer-encoded (chunked, compressed) */ @@ -1451,30 +1609,51 @@ struct UserDefined { bool proxy_transfer_mode; /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */ - unsigned int scope; /* address scope for IPv6 */ + unsigned int scope_id; /* Scope id for IPv6 */ long allowed_protocols; long redir_protocols; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) long socks5_gssapi_nec; /* flag to support nec socks5 server */ #endif struct curl_slist *mail_rcpt; /* linked list of mail recipients */ + bool sasl_ir; /* Enable/disable SASL initial response */ /* Common RTSP header options */ Curl_RtspReq rtspreq; /* RTSP request type */ long rtspversion; /* like httpversion, for RTSP */ bool wildcardmatch; /* enable wildcard matching */ - curl_chunk_bgn_callback chunk_bgn; /* called before part of transfer starts */ + curl_chunk_bgn_callback chunk_bgn; /* called before part of transfer + starts */ curl_chunk_end_callback chunk_end; /* called after part transferring stopped */ curl_fnmatch_callback fnmatch; /* callback to decide which file corresponds to pattern (e.g. if WILDCARDMATCH is on) */ void *fnmatch_data; + + long gssapi_delegation; /* GSS-API credential delegation, see the + documentation of CURLOPT_GSSAPI_DELEGATION */ + + bool tcp_keepalive; /* use TCP keepalives */ + long tcp_keepidle; /* seconds in idle before sending keepalive probe */ + long tcp_keepintvl; /* seconds between TCP keepalive probes */ + + size_t maxconnects; /* Max idle connections in the connection cache */ + + bool ssl_enable_npn; /* TLS NPN extension? */ + bool ssl_enable_alpn; /* TLS ALPN extension? */ + bool path_as_is; /* allow dotdots? */ + bool pipewait; /* wait for pipe/multiplex status before starting a + new connection */ + long expect_100_timeout; /* in milliseconds */ + + struct SessionHandle *stream_depends_on; + bool stream_depends_e; /* set or don't set the Exclusive bit */ + int stream_weight; }; struct Names { struct curl_hash *hostcache; enum { HCACHE_NONE, /* not pointing to anything */ - HCACHE_PRIVATE, /* points to our own */ HCACHE_GLOBAL, /* points to the (shrug) global one */ HCACHE_MULTI, /* points to a shared one in the multi handle */ HCACHE_SHARED /* points to a shared one in a shared object */ @@ -1492,12 +1671,31 @@ struct Names { */ struct SessionHandle { + /* first, two fields for the linked list of these */ + struct SessionHandle *next; + struct SessionHandle *prev; + + struct connectdata *easy_conn; /* the "unit's" connection */ + + CURLMstate mstate; /* the handle's state */ + CURLcode result; /* previous result */ + + struct Curl_message msg; /* A single posted message. */ + + /* Array with the plain socket numbers this handle takes care of, in no + particular order. Note that all sockets are added to the sockhash, where + the state etc are also kept. This array is mostly used to detect when a + socket is to be removed from the hash. See singlesocket(). */ + curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE]; + int numsocks; + struct Names dns; struct Curl_multi *multi; /* if non-NULL, points to the multi handle - struct to which this "belongs" */ - struct Curl_one_easy *multi_pos; /* if non-NULL, points to its position - in multi controlling structure to assist - in removal. */ + struct to which this "belongs" when used by + the multi interface */ + struct Curl_multi *multi_easy; /* if non-NULL, points to the multi handle + struct to which this "belongs" when used + by the easy interface */ struct Curl_share *share; /* Share, handles global variable mutexing */ struct SingleRequest req; /* Request-specific data */ struct UserDefined set; /* values set by the libcurl user */ @@ -1511,6 +1709,8 @@ struct SessionHandle { other dynamic purposes */ struct WildcardData wildcard; /* wildcard download state info */ struct PureInfo info; /* stats, reports and info data */ + struct curl_tlssessioninfo tsi; /* Information about the TLS session, only + valid after a client has asked for it */ #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) iconv_t outbound_cd; /* for translating to the network encoding */ iconv_t inbound_cd; /* for translating from the network encoding */ @@ -1521,4 +1721,4 @@ struct SessionHandle { #define LIBCURL_NAME "libcurl" -#endif +#endif /* HEADER_CURL_URLDATA_H */ diff --git a/project/jni/curl/lib/version.c b/project/jni/curl/lib/version.c index 9ba2e33c1..12924453c 100644 --- a/project/jni/curl/lib/version.c +++ b/project/jni/curl/lib/version.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,26 +20,30 @@ * ***************************************************************************/ -#include "setup.h" - -#include -#include +#include "curl_setup.h" #include #include "urldata.h" -#include "sslgen.h" - -#define _MPRINTF_REPLACE /* use the internal *printf() functions */ -#include +#include "vtls/vtls.h" +#include "http2.h" +#include "curl_printf.h" #ifdef USE_ARES -#include +# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ + (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) +# define CARES_STATICLIB +# endif +# include #endif #ifdef USE_LIBIDN #include #endif +#ifdef USE_LIBPSL +#include +#endif + #if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) #include #endif @@ -60,13 +64,28 @@ #define CURL_LIBSSH2_VERSION LIBSSH2_VERSION #endif +void Curl_version_init(void); + +/* For thread safety purposes this function is called by global_init so that + the static data in both version functions is initialized. */ +void Curl_version_init(void) +{ + curl_version(); + curl_version_info(CURLVERSION_NOW); +} + char *curl_version(void) { + static bool initialized; static char version[200]; - char *ptr=version; + char *ptr = version; size_t len; size_t left = sizeof(version); - strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION ); + + if(initialized) + return version; + + strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION); len = strlen(ptr); left -= len; ptr += len; @@ -99,6 +118,16 @@ char *curl_version(void) ptr += len; } #endif +#ifdef USE_LIBPSL + len = snprintf(ptr, left, " libpsl/%s", psl_get_version()); + left -= len; + ptr += len; +#endif +#ifdef USE_WIN32_IDN + len = snprintf(ptr, left, " WinIDN"); + left -= len; + ptr += len; +#endif #if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) #ifdef _LIBICONV_VERSION len = snprintf(ptr, left, " iconv/%d.%d", @@ -115,27 +144,37 @@ char *curl_version(void) left -= len; ptr += len; #endif +#ifdef USE_NGHTTP2 + len = Curl_http2_ver(ptr, left); + left -= len; + ptr += len; +#endif #ifdef USE_LIBRTMP { char suff[2]; - if (RTMP_LIB_VERSION & 0xff) { + if(RTMP_LIB_VERSION & 0xff) { suff[0] = (RTMP_LIB_VERSION & 0xff) + 'a' - 1; suff[1] = '\0'; - } else { - suff[0] = '\0'; } - len = snprintf(ptr, left, " librtmp/%d.%d%s", - RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff, suff); + else + suff[0] = '\0'; + + snprintf(ptr, left, " librtmp/%d.%d%s", + RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff, + suff); /* If another lib version is added below this one, this code would also have to do: + len = what snprintf() returned + left -= len; ptr += len; */ } #endif + initialized = true; return version; } @@ -175,8 +214,9 @@ static const char * const protocols[] = { #endif #ifndef CURL_DISABLE_LDAP "ldap", -#if (defined(USE_OPENLDAP) && defined(USE_SSL)) || \ - (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)) +#if !defined(CURL_DISABLE_LDAPS) && \ + ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \ + (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL))) "ldaps", #endif #endif @@ -198,6 +238,14 @@ static const char * const protocols[] = { #ifdef USE_LIBSSH2 "sftp", #endif +#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ + (CURL_SIZEOF_CURL_OFF_T > 4) && \ + (!defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)) + "smb", +# ifdef USE_SSL + "smbs", +# endif +#endif #ifndef CURL_DISABLE_SMTP "smtp", #endif @@ -223,24 +271,31 @@ static curl_version_info_data version_info = { #ifdef ENABLE_IPV6 | CURL_VERSION_IPV6 #endif -#ifdef HAVE_KRB4 - | CURL_VERSION_KERBEROS4 -#endif #ifdef USE_SSL | CURL_VERSION_SSL #endif #ifdef USE_NTLM | CURL_VERSION_NTLM #endif +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ + defined(NTLM_WB_ENABLED) + | CURL_VERSION_NTLM_WB +#endif +#ifdef USE_SPNEGO + | CURL_VERSION_SPNEGO +#endif +#ifdef USE_KERBEROS5 + | CURL_VERSION_KERBEROS5 +#endif +#ifdef HAVE_GSSAPI + | CURL_VERSION_GSSAPI +#endif #ifdef USE_WINDOWS_SSPI | CURL_VERSION_SSPI #endif #ifdef HAVE_LIBZ | CURL_VERSION_LIBZ #endif -#ifdef HAVE_GSSAPI - | CURL_VERSION_GSSNEGOTIATE -#endif #ifdef DEBUGBUILD | CURL_VERSION_DEBUG #endif @@ -250,15 +305,24 @@ static curl_version_info_data version_info = { #ifdef CURLRES_ASYNCH | CURL_VERSION_ASYNCHDNS #endif -#ifdef HAVE_SPNEGO - | CURL_VERSION_SPNEGO -#endif #if (CURL_SIZEOF_CURL_OFF_T > 4) && \ ( (SIZEOF_OFF_T > 4) || defined(USE_WIN32_LARGE_FILES) ) | CURL_VERSION_LARGEFILE #endif #if defined(CURL_DOES_CONVERSIONS) | CURL_VERSION_CONV +#endif +#if defined(USE_TLS_SRP) + | CURL_VERSION_TLSAUTH_SRP +#endif +#if defined(USE_NGHTTP2) + | CURL_VERSION_HTTP2 +#endif +#if defined(USE_UNIX_SOCKETS) + | CURL_VERSION_UNIX_SOCKETS +#endif +#if defined(USE_LIBPSL) + | CURL_VERSION_PSL #endif , NULL, /* ssl_version */ @@ -274,12 +338,18 @@ static curl_version_info_data version_info = { curl_version_info_data *curl_version_info(CURLversion stamp) { + static bool initialized; #ifdef USE_LIBSSH2 static char ssh_buffer[80]; #endif - #ifdef USE_SSL static char ssl_buffer[80]; +#endif + + if(initialized) + return &version_info; + +#ifdef USE_SSL Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer)); version_info.ssl_version = ssl_buffer; #endif @@ -301,6 +371,8 @@ curl_version_info_data *curl_version_info(CURLversion stamp) version_info.libidn = stringprep_check_version(LIBIDN_REQUIRED_VERSION); if(version_info.libidn) version_info.features |= CURL_VERSION_IDN; +#elif defined(USE_WIN32_IDN) + version_info.features |= CURL_VERSION_IDN; #endif #if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) @@ -319,5 +391,6 @@ curl_version_info_data *curl_version_info(CURLversion stamp) (void)stamp; /* avoid compiler warnings, we don't use this */ + initialized = true; return &version_info; } diff --git a/project/jni/curl/lib/vtls/axtls.c b/project/jni/curl/lib/vtls/axtls.c new file mode 100644 index 000000000..d9c5f9935 --- /dev/null +++ b/project/jni/curl/lib/vtls/axtls.c @@ -0,0 +1,690 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2010, DirecTV, Contact: Eric Hu, . + * Copyright (C) 2010 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Source file for all axTLS-specific code for the TLS/SSL layer. No code + * but vtls.c should ever call or use these functions. + */ + +#include "curl_setup.h" + +#ifdef USE_AXTLS +#include +#include +#include "axtls.h" + +#include "sendf.h" +#include "inet_pton.h" +#include "vtls.h" +#include "parsedate.h" +#include "connect.h" /* for the connect timeout */ +#include "select.h" +#include "curl_printf.h" +#include "hostcheck.h" +#include + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + + +/* Global axTLS init, called from Curl_ssl_init() */ +int Curl_axtls_init(void) +{ +/* axTLS has no global init. Everything is done through SSL and SSL_CTX + * structs stored in connectdata structure. Perhaps can move to axtls.h. + */ + return 1; +} + +int Curl_axtls_cleanup(void) +{ + /* axTLS has no global cleanup. Perhaps can move this to axtls.h. */ + return 1; +} + +static CURLcode map_error_to_curl(int axtls_err) +{ + switch (axtls_err) { + case SSL_ERROR_NOT_SUPPORTED: + case SSL_ERROR_INVALID_VERSION: + case -70: /* protocol version alert from server */ + return CURLE_UNSUPPORTED_PROTOCOL; + break; + case SSL_ERROR_NO_CIPHER: + return CURLE_SSL_CIPHER; + break; + case SSL_ERROR_BAD_CERTIFICATE: /* this may be bad server cert too */ + case SSL_ERROR_NO_CERT_DEFINED: + case -42: /* bad certificate alert from server */ + case -43: /* unsupported cert alert from server */ + case -44: /* cert revoked alert from server */ + case -45: /* cert expired alert from server */ + case -46: /* cert unknown alert from server */ + return CURLE_SSL_CERTPROBLEM; + break; + case SSL_X509_ERROR(X509_NOT_OK): + case SSL_X509_ERROR(X509_VFY_ERROR_NO_TRUSTED_CERT): + case SSL_X509_ERROR(X509_VFY_ERROR_BAD_SIGNATURE): + case SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID): + case SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED): + case SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED): + case SSL_X509_ERROR(X509_VFY_ERROR_INVALID_CHAIN): + case SSL_X509_ERROR(X509_VFY_ERROR_UNSUPPORTED_DIGEST): + case SSL_X509_ERROR(X509_INVALID_PRIV_KEY): + return CURLE_PEER_FAILED_VERIFICATION; + break; + case -48: /* unknown ca alert from server */ + return CURLE_SSL_CACERT; + break; + case -49: /* access denied alert from server */ + return CURLE_REMOTE_ACCESS_DENIED; + break; + case SSL_ERROR_CONN_LOST: + case SSL_ERROR_SOCK_SETUP_FAILURE: + case SSL_ERROR_INVALID_HANDSHAKE: + case SSL_ERROR_INVALID_PROT_MSG: + case SSL_ERROR_INVALID_HMAC: + case SSL_ERROR_INVALID_SESSION: + case SSL_ERROR_INVALID_KEY: /* it's too bad this doesn't map better */ + case SSL_ERROR_FINISHED_INVALID: + case SSL_ERROR_NO_CLIENT_RENOG: + default: + return CURLE_SSL_CONNECT_ERROR; + break; + } +} + +static Curl_recv axtls_recv; +static Curl_send axtls_send; + +static void free_ssl_structs(struct ssl_connect_data *connssl) +{ + if(connssl->ssl) { + ssl_free (connssl->ssl); + connssl->ssl = NULL; + } + if(connssl->ssl_ctx) { + ssl_ctx_free(connssl->ssl_ctx); + connssl->ssl_ctx = NULL; + } +} + +/* + * For both blocking and non-blocking connects, this function sets up the + * ssl context and state. This function is called after the TCP connect + * has completed. + */ +static CURLcode connect_prep(struct connectdata *conn, int sockindex) +{ + struct SessionHandle *data = conn->data; + SSL_CTX *ssl_ctx; + SSL *ssl = NULL; + int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0}; + int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0}; + int i, ssl_fcn_return; + const uint8_t *ssl_sessionid; + size_t ssl_idsize; + + /* Assuming users will not compile in custom key/cert to axTLS. + * Also, even for blocking connects, use axTLS non-blocking feature. + */ + uint32_t client_option = SSL_NO_DEFAULT_KEY | + SSL_SERVER_VERIFY_LATER | + SSL_CONNECT_IN_PARTS; + + if(conn->ssl[sockindex].state == ssl_connection_complete) + /* to make us tolerant against being called more than once for the + same connection */ + return CURLE_OK; + + /* axTLS only supports TLSv1 */ + /* check to see if we've been told to use an explicit SSL/TLS version */ + switch(data->set.ssl.version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + break; + default: + failf(data, "axTLS only supports TLS 1.0 and 1.1, " + "and it cannot be specified which one to use"); + return CURLE_SSL_CONNECT_ERROR; + } + +#ifdef AXTLSDEBUG + client_option |= SSL_DISPLAY_STATES | SSL_DISPLAY_RSA | SSL_DISPLAY_CERTS; +#endif /* AXTLSDEBUG */ + + /* Allocate an SSL_CTX struct */ + ssl_ctx = ssl_ctx_new(client_option, SSL_DEFAULT_CLNT_SESS); + if(ssl_ctx == NULL) { + failf(data, "unable to create client SSL context"); + return CURLE_SSL_CONNECT_ERROR; + } + + conn->ssl[sockindex].ssl_ctx = ssl_ctx; + conn->ssl[sockindex].ssl = NULL; + + /* Load the trusted CA cert bundle file */ + if(data->set.ssl.CAfile) { + if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, data->set.ssl.CAfile, NULL) + != SSL_OK) { + infof(data, "error reading ca cert file %s \n", + data->set.ssl.CAfile); + if(data->set.ssl.verifypeer) { + return CURLE_SSL_CACERT_BADFILE; + } + } + else + infof(data, "found certificates in %s\n", data->set.ssl.CAfile); + } + + /* gtls.c tasks we're skipping for now: + * 1) certificate revocation list checking + * 2) dns name assignment to host + * 3) set protocol priority. axTLS is TLSv1 only, so can probably ignore + * 4) set certificate priority. axTLS ignores type and sends certs in + * order added. can probably ignore this. + */ + + /* Load client certificate */ + if(data->set.str[STRING_CERT]) { + i=0; + /* Instead of trying to analyze cert type here, let axTLS try them all. */ + while(cert_types[i] != 0) { + ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i], + data->set.str[STRING_CERT], NULL); + if(ssl_fcn_return == SSL_OK) { + infof(data, "successfully read cert file %s \n", + data->set.str[STRING_CERT]); + break; + } + i++; + } + /* Tried all cert types, none worked. */ + if(cert_types[i] == 0) { + failf(data, "%s is not x509 or pkcs12 format", + data->set.str[STRING_CERT]); + return CURLE_SSL_CERTPROBLEM; + } + } + + /* Load client key. + If a pkcs12 file successfully loaded a cert, then there's nothing to do + because the key has already been loaded. */ + if(data->set.str[STRING_KEY] && cert_types[i] != SSL_OBJ_PKCS12) { + i=0; + /* Instead of trying to analyze key type here, let axTLS try them all. */ + while(key_types[i] != 0) { + ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i], + data->set.str[STRING_KEY], NULL); + if(ssl_fcn_return == SSL_OK) { + infof(data, "successfully read key file %s \n", + data->set.str[STRING_KEY]); + break; + } + i++; + } + /* Tried all key types, none worked. */ + if(key_types[i] == 0) { + failf(data, "Failure: %s is not a supported key file", + data->set.str[STRING_KEY]); + return CURLE_SSL_CONNECT_ERROR; + } + } + + /* gtls.c does more here that is being left out for now + * 1) set session credentials. can probably ignore since axtls puts this + * info in the ssl_ctx struct + * 2) setting up callbacks. these seem gnutls specific + */ + + /* In axTLS, handshaking happens inside ssl_client_new. */ + if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)) { + /* we got a session id, use it! */ + infof (data, "SSL re-using session ID\n"); + ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], + ssl_sessionid, (uint8_t)ssl_idsize); + } + else + ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0); + + conn->ssl[sockindex].ssl = ssl; + return CURLE_OK; +} + +/* + * For both blocking and non-blocking connects, this function finalizes the + * SSL connection. + */ +static CURLcode connect_finish(struct connectdata *conn, int sockindex) +{ + struct SessionHandle *data = conn->data; + SSL *ssl = conn->ssl[sockindex].ssl; + const uint8_t *ssl_sessionid; + size_t ssl_idsize; + const char *peer_CN; + uint32_t dns_altname_index; + const char *dns_altname; + int8_t found_subject_alt_names = 0; + int8_t found_subject_alt_name_matching_conn = 0; + + /* Here, gtls.c gets the peer certificates and fails out depending on + * settings in "data." axTLS api doesn't have get cert chain fcn, so omit? + */ + + /* Verify server's certificate */ + if(data->set.ssl.verifypeer) { + if(ssl_verify_cert(ssl) != SSL_OK) { + Curl_axtls_close(conn, sockindex); + failf(data, "server cert verify failed"); + return CURLE_PEER_FAILED_VERIFICATION; + } + } + else + infof(data, "\t server certificate verification SKIPPED\n"); + + /* Here, gtls.c does issuer verification. axTLS has no straightforward + * equivalent, so omitting for now.*/ + + /* Here, gtls.c does the following + * 1) x509 hostname checking per RFC2818. axTLS doesn't support this, but + * it seems useful. This is now implemented, by Oscar Koeroo + * 2) checks cert validity based on time. axTLS does this in ssl_verify_cert + * 3) displays a bunch of cert information. axTLS doesn't support most of + * this, but a couple fields are available. + */ + + /* There is no (DNS) Altnames count in the version 1.4.8 API. There is a + risk of an inifite loop */ + for(dns_altname_index = 0; ; dns_altname_index++) { + dns_altname = ssl_get_cert_subject_alt_dnsname(ssl, dns_altname_index); + if(dns_altname == NULL) { + break; + } + found_subject_alt_names = 1; + + infof(data, "\tComparing subject alt name DNS with hostname: %s <-> %s\n", + dns_altname, conn->host.name); + if(Curl_cert_hostcheck(dns_altname, conn->host.name)) { + found_subject_alt_name_matching_conn = 1; + break; + } + } + + /* RFC2818 checks */ + if(found_subject_alt_names && !found_subject_alt_name_matching_conn) { + if(data->set.ssl.verifyhost) { + /* Break connection ! */ + Curl_axtls_close(conn, sockindex); + failf(data, "\tsubjectAltName(s) do not match %s\n", + conn->host.dispname); + return CURLE_PEER_FAILED_VERIFICATION; + } + else + infof(data, "\tsubjectAltName(s) do not match %s\n", + conn->host.dispname); + } + else if(found_subject_alt_names == 0) { + /* Per RFC2818, when no Subject Alt Names were available, examine the peer + CN as a legacy fallback */ + peer_CN = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME); + if(peer_CN == NULL) { + if(data->set.ssl.verifyhost) { + Curl_axtls_close(conn, sockindex); + failf(data, "unable to obtain common name from peer certificate"); + return CURLE_PEER_FAILED_VERIFICATION; + } + else + infof(data, "unable to obtain common name from peer certificate"); + } + else { + if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) { + if(data->set.ssl.verifyhost) { + /* Break connection ! */ + Curl_axtls_close(conn, sockindex); + failf(data, "\tcommon name \"%s\" does not match \"%s\"\n", + peer_CN, conn->host.dispname); + return CURLE_PEER_FAILED_VERIFICATION; + } + else + infof(data, "\tcommon name \"%s\" does not match \"%s\"\n", + peer_CN, conn->host.dispname); + } + } + } + + /* General housekeeping */ + conn->ssl[sockindex].state = ssl_connection_complete; + conn->recv[sockindex] = axtls_recv; + conn->send[sockindex] = axtls_send; + + /* Put our freshly minted SSL session in cache */ + ssl_idsize = ssl_get_session_id_size(ssl); + ssl_sessionid = ssl_get_session_id(ssl); + if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize) + != CURLE_OK) + infof (data, "failed to add session to cache\n"); + + return CURLE_OK; +} + +/* + * Use axTLS's non-blocking connection feature to open an SSL connection. + * This is called after a TCP connection is already established. + */ +CURLcode Curl_axtls_connect_nonblocking( + struct connectdata *conn, + int sockindex, + bool *done) +{ + CURLcode conn_step; + int ssl_fcn_return; + int i; + + *done = FALSE; + /* connectdata is calloc'd and connecting_state is only changed in this + function, so this is safe, as the state is effectively initialized. */ + if(conn->ssl[sockindex].connecting_state == ssl_connect_1) { + conn_step = connect_prep(conn, sockindex); + if(conn_step != CURLE_OK) { + Curl_axtls_close(conn, sockindex); + return conn_step; + } + conn->ssl[sockindex].connecting_state = ssl_connect_2; + } + + if(conn->ssl[sockindex].connecting_state == ssl_connect_2) { + /* Check to make sure handshake was ok. */ + if(ssl_handshake_status(conn->ssl[sockindex].ssl) != SSL_OK) { + /* Loop to perform more work in between sleeps. This is work around the + fact that axtls does not expose any knowledge about when work needs + to be performed. This can save ~25% of time on SSL handshakes. */ + for(i=0; i<5; i++) { + ssl_fcn_return = ssl_read(conn->ssl[sockindex].ssl, NULL); + if(ssl_fcn_return < 0) { + Curl_axtls_close(conn, sockindex); + ssl_display_error(ssl_fcn_return); /* goes to stdout. */ + return map_error_to_curl(ssl_fcn_return); + } + return CURLE_OK; + } + } + infof (conn->data, "handshake completed successfully\n"); + conn->ssl[sockindex].connecting_state = ssl_connect_3; + } + + if(conn->ssl[sockindex].connecting_state == ssl_connect_3) { + conn_step = connect_finish(conn, sockindex); + if(conn_step != CURLE_OK) { + Curl_axtls_close(conn, sockindex); + return conn_step; + } + + /* Reset connect state */ + conn->ssl[sockindex].connecting_state = ssl_connect_1; + + *done = TRUE; + return CURLE_OK; + } + + /* Unrecognized state. Things are very bad. */ + conn->ssl[sockindex].state = ssl_connection_none; + conn->ssl[sockindex].connecting_state = ssl_connect_1; + /* Return value perhaps not strictly correct, but distinguishes the issue.*/ + return CURLE_BAD_FUNCTION_ARGUMENT; +} + + +/* + * This function is called after the TCP connect has completed. Setup the TLS + * layer and do all necessary magic for a blocking connect. + */ +CURLcode +Curl_axtls_connect(struct connectdata *conn, + int sockindex) + +{ + struct SessionHandle *data = conn->data; + CURLcode conn_step = connect_prep(conn, sockindex); + int ssl_fcn_return; + SSL *ssl = conn->ssl[sockindex].ssl; + long timeout_ms; + + if(conn_step != CURLE_OK) { + Curl_axtls_close(conn, sockindex); + return conn_step; + } + + /* Check to make sure handshake was ok. */ + while(ssl_handshake_status(ssl) != SSL_OK) { + /* check allowed time left */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + ssl_fcn_return = ssl_read(ssl, NULL); + if(ssl_fcn_return < 0) { + Curl_axtls_close(conn, sockindex); + ssl_display_error(ssl_fcn_return); /* goes to stdout. */ + return map_error_to_curl(ssl_fcn_return); + } + /* TODO: avoid polling */ + usleep(10000); + } + infof (conn->data, "handshake completed successfully\n"); + + conn_step = connect_finish(conn, sockindex); + if(conn_step != CURLE_OK) { + Curl_axtls_close(conn, sockindex); + return conn_step; + } + + return CURLE_OK; +} + +/* return number of sent (non-SSL) bytes */ +static ssize_t axtls_send(struct connectdata *conn, + int sockindex, + const void *mem, + size_t len, + CURLcode *err) +{ + /* ssl_write() returns 'int' while write() and send() returns 'size_t' */ + int rc = ssl_write(conn->ssl[sockindex].ssl, mem, (int)len); + + infof(conn->data, " axtls_send\n"); + + if(rc < 0 ) { + *err = map_error_to_curl(rc); + rc = -1; /* generic error code for send failure */ + } + + *err = CURLE_OK; + return rc; +} + +void Curl_axtls_close(struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + infof(conn->data, " Curl_axtls_close\n"); + + /* line from openssl.c: (void)SSL_shutdown(connssl->ssl); + axTLS compat layer does nothing for SSL_shutdown */ + + /* The following line is from openssl.c. There seems to be no axTLS + equivalent. ssl_free and ssl_ctx_free close things. + SSL_set_connect_state(connssl->handle); */ + + free_ssl_structs(connssl); +} + +/* + * This function is called to shut down the SSL layer but keep the + * socket open (CCC - Clear Command Channel) + */ +int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) +{ + /* Outline taken from openssl.c since functions are in axTLS compat layer. + axTLS's error set is much smaller, so a lot of error-handling was removed. + */ + int retval = 0; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct SessionHandle *data = conn->data; + uint8_t *buf; + ssize_t nread; + + infof(conn->data, " Curl_axtls_shutdown\n"); + + /* This has only been tested on the proftpd server, and the mod_tls code + sends a close notify alert without waiting for a close notify alert in + response. Thus we wait for a close notify alert from the server, but + we do not send one. Let's hope other servers do the same... */ + + /* axTLS compat layer does nothing for SSL_shutdown, so we do nothing too + if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) + (void)SSL_shutdown(connssl->ssl); + */ + + if(connssl->ssl) { + int what = Curl_socket_ready(conn->sock[sockindex], + CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + if(what > 0) { + /* Something to read, let's do it and hope that it is the close + notify alert from the server. buf is managed internally by + axTLS and will be released upon calling ssl_free via + free_ssl_structs. */ + nread = (ssize_t)ssl_read(connssl->ssl, &buf); + + if(nread < SSL_OK) { + failf(data, "close notify alert not received during shutdown"); + retval = -1; + } + } + else if(0 == what) { + /* timeout */ + failf(data, "SSL shutdown timeout"); + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + retval = -1; + } + + free_ssl_structs(connssl); + } + return retval; +} + +static ssize_t axtls_recv(struct connectdata *conn, /* connection data */ + int num, /* socketindex */ + char *buf, /* store read data here */ + size_t buffersize, /* max amount to read */ + CURLcode *err) +{ + struct ssl_connect_data *connssl = &conn->ssl[num]; + ssize_t ret = 0; + uint8_t *read_buf; + + infof(conn->data, " axtls_recv\n"); + + *err = CURLE_OK; + if(connssl) { + ret = ssl_read(connssl->ssl, &read_buf); + if(ret > SSL_OK) { + /* ssl_read returns SSL_OK if there is more data to read, so if it is + larger, then all data has been read already. */ + memcpy(buf, read_buf, + (size_t)ret > buffersize ? buffersize : (size_t)ret); + } + else if(ret == SSL_OK) { + /* more data to be read, signal caller to call again */ + *err = CURLE_AGAIN; + ret = -1; + } + else if(ret == -3) { + /* With patched axTLS, SSL_CLOSE_NOTIFY=-3. Hard-coding until axTLS + team approves proposed fix. */ + Curl_axtls_close(conn, num); + } + else { + failf(conn->data, "axTLS recv error (%d)", ret); + *err = map_error_to_curl((int) ret); + ret = -1; + } + } + + return ret; +} + +/* + * Return codes: + * 1 means the connection is still in place + * 0 means the connection has been closed + * -1 means the connection status is unknown + */ +int Curl_axtls_check_cxn(struct connectdata *conn) +{ + /* openssl.c line: rc = SSL_peek(conn->ssl[FIRSTSOCKET].ssl, (void*)&buf, 1); + axTLS compat layer always returns the last argument, so connection is + always alive? */ + + infof(conn->data, " Curl_axtls_check_cxn\n"); + return 1; /* connection still in place */ +} + +void Curl_axtls_session_free(void *ptr) +{ + (void)ptr; + /* free the ID */ + /* both openssl.c and gtls.c do something here, but axTLS's OpenSSL + compatibility layer does nothing, so we do nothing too. */ +} + +size_t Curl_axtls_version(char *buffer, size_t size) +{ + return snprintf(buffer, size, "axTLS/%s", ssl_version()); +} + +int Curl_axtls_random(struct SessionHandle *data, + unsigned char *entropy, + size_t length) +{ + static bool ssl_seeded = FALSE; + (void)data; + if(!ssl_seeded) { + ssl_seeded = TRUE; + /* Initialize the seed if not already done. This call is not exactly thread + * safe (and neither is the ssl_seeded check), but the worst effect of a + * race condition is that some global resources will leak. */ + RNG_initialize(); + } + get_random((int)length, entropy); + return 0; +} + +#endif /* USE_AXTLS */ diff --git a/project/jni/curl/lib/vtls/axtls.h b/project/jni/curl/lib/vtls/axtls.h new file mode 100644 index 000000000..b9d441f1a --- /dev/null +++ b/project/jni/curl/lib/vtls/axtls.h @@ -0,0 +1,71 @@ +#ifndef HEADER_CURL_AXTLS_H +#define HEADER_CURL_AXTLS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2010, DirecTV, Contact: Eric Hu + * Copyright (C) 2010 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#ifdef USE_AXTLS +#include "curl/curl.h" +#include "urldata.h" + +int Curl_axtls_init(void); +int Curl_axtls_cleanup(void); +CURLcode Curl_axtls_connect(struct connectdata *conn, int sockindex); +CURLcode Curl_axtls_connect_nonblocking( + struct connectdata *conn, + int sockindex, + bool *done); + + /* close a SSL connection */ +void Curl_axtls_close(struct connectdata *conn, int sockindex); + +void Curl_axtls_session_free(void *ptr); +size_t Curl_axtls_version(char *buffer, size_t size); +int Curl_axtls_shutdown(struct connectdata *conn, int sockindex); +int Curl_axtls_check_cxn(struct connectdata *conn); +int Curl_axtls_random(struct SessionHandle *data, + unsigned char *entropy, + size_t length); + +/* Set the API backend definition to axTLS */ +#define CURL_SSL_BACKEND CURLSSLBACKEND_AXTLS + +/* API setup for axTLS */ +#define curlssl_init Curl_axtls_init +#define curlssl_cleanup Curl_axtls_cleanup +#define curlssl_connect Curl_axtls_connect +#define curlssl_connect_nonblocking Curl_axtls_connect_nonblocking +#define curlssl_session_free(x) Curl_axtls_session_free(x) +#define curlssl_close_all(x) ((void)x) +#define curlssl_close Curl_axtls_close +#define curlssl_shutdown(x,y) Curl_axtls_shutdown(x,y) +#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN) +#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN) +#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) +#define curlssl_version Curl_axtls_version +#define curlssl_check_cxn(x) Curl_axtls_check_cxn(x) +#define curlssl_data_pending(x,y) ((void)x, (void)y, 0) +#define curlssl_random(x,y,z) Curl_axtls_random(x,y,z) + +#endif /* USE_AXTLS */ +#endif /* HEADER_CURL_AXTLS_H */ + diff --git a/project/jni/curl/lib/vtls/cyassl.c b/project/jni/curl/lib/vtls/cyassl.c new file mode 100644 index 000000000..f6b57af68 --- /dev/null +++ b/project/jni/curl/lib/vtls/cyassl.c @@ -0,0 +1,800 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Source file for all CyaSSL-specific code for the TLS/SSL layer. No code + * but vtls.c should ever call or use these functions. + * + */ + +#include "curl_setup.h" + +#ifdef USE_CYASSL + +#define WOLFSSL_OPTIONS_IGNORE_SYS +/* CyaSSL's version.h, which should contain only the version, should come +before all other CyaSSL includes and be immediately followed by build config +aka options.h. https://curl.haxx.se/mail/lib-2015-04/0069.html */ +#include +#if defined(HAVE_CYASSL_OPTIONS_H) && (LIBCYASSL_VERSION_HEX > 0x03004008) +#if defined(CYASSL_API) || defined(WOLFSSL_API) +/* Safety measure. If either is defined some API include was already included +and that's a problem since options.h hasn't been included yet. */ +#error "CyaSSL API was included before the CyaSSL build options." +#endif +#include +#endif + +#ifdef HAVE_LIMITS_H +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "inet_pton.h" +#include "cyassl.h" +#include "vtls.h" +#include "parsedate.h" +#include "connect.h" /* for the connect timeout */ +#include "select.h" +#include "rawstr.h" +#include "x509asn1.h" +#include "curl_printf.h" + +#include +#ifdef HAVE_CYASSL_ERROR_SSL_H +#include +#else +#include +#endif +#include +#include + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#if LIBCYASSL_VERSION_HEX < 0x02007002 /* < 2.7.2 */ +#define CYASSL_MAX_ERROR_SZ 80 +#endif + +static Curl_recv cyassl_recv; +static Curl_send cyassl_send; + + +static int do_file_type(const char *type) +{ + if(!type || !type[0]) + return SSL_FILETYPE_PEM; + if(Curl_raw_equal(type, "PEM")) + return SSL_FILETYPE_PEM; + if(Curl_raw_equal(type, "DER")) + return SSL_FILETYPE_ASN1; + return -1; +} + +/* + * This function loads all the client/CA certificates and CRLs. Setup the TLS + * layer and do all necessary magic. + */ +static CURLcode +cyassl_connect_step1(struct connectdata *conn, + int sockindex) +{ + char error_buffer[CYASSL_MAX_ERROR_SZ]; + struct SessionHandle *data = conn->data; + struct ssl_connect_data* conssl = &conn->ssl[sockindex]; + SSL_METHOD* req_method = NULL; + void* ssl_sessionid = NULL; + curl_socket_t sockfd = conn->sock[sockindex]; +#ifdef HAVE_SNI + bool sni = FALSE; +#define use_sni(x) sni = (x) +#else +#define use_sni(x) Curl_nop_stmt +#endif + + if(conssl->state == ssl_connection_complete) + return CURLE_OK; + + /* check to see if we've been told to use an explicit SSL/TLS version */ + switch(data->set.ssl.version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: +#if LIBCYASSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */ + /* minimum protocol version is set later after the CTX object is created */ + req_method = SSLv23_client_method(); +#else + infof(data, "CyaSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, " + "TLS 1.0 is used exclusively\n"); + req_method = TLSv1_client_method(); +#endif + use_sni(TRUE); + break; + case CURL_SSLVERSION_TLSv1_0: + req_method = TLSv1_client_method(); + use_sni(TRUE); + break; + case CURL_SSLVERSION_TLSv1_1: + req_method = TLSv1_1_client_method(); + use_sni(TRUE); + break; + case CURL_SSLVERSION_TLSv1_2: + req_method = TLSv1_2_client_method(); + use_sni(TRUE); + break; + case CURL_SSLVERSION_SSLv3: + /* before WolfSSL SSLv3 was enabled by default, and starting in WolfSSL + we check for its presence since it is built without it by default */ +#if !defined(WOLFSSL_VERSION) || defined(HAVE_WOLFSSLV3_CLIENT_METHOD) + req_method = SSLv3_client_method(); + use_sni(FALSE); +#else + failf(data, "No support for SSLv3"); + return CURLE_NOT_BUILT_IN; +#endif + break; + case CURL_SSLVERSION_SSLv2: + failf(data, "CyaSSL does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(!req_method) { + failf(data, "SSL: couldn't create a method!"); + return CURLE_OUT_OF_MEMORY; + } + + if(conssl->ctx) + SSL_CTX_free(conssl->ctx); + conssl->ctx = SSL_CTX_new(req_method); + + if(!conssl->ctx) { + failf(data, "SSL: couldn't create a context!"); + return CURLE_OUT_OF_MEMORY; + } + + switch(data->set.ssl.version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: +#if LIBCYASSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */ + /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is whatever + minimum version of TLS was built in and at least TLS 1.0. For later library + versions that could change (eg TLS 1.0 built in but defaults to TLS 1.1) so + we have this short circuit evaluation to find the minimum supported TLS + version. We use wolfSSL_CTX_SetMinVersion and not CyaSSL_SetMinVersion + because only the former will work before the user's CTX callback is called. + */ + if((wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1) != 1) && + (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_1) != 1) && + (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_2) != 1)) { + failf(data, "SSL: couldn't set the minimum protocol version"); + return CURLE_SSL_CONNECT_ERROR; + } +#endif + break; + } + +#ifndef NO_FILESYSTEM + /* load trusted cacert */ + if(data->set.str[STRING_SSL_CAFILE]) { + if(1 != SSL_CTX_load_verify_locations(conssl->ctx, + data->set.str[STRING_SSL_CAFILE], + data->set.str[STRING_SSL_CAPATH])) { + if(data->set.ssl.verifypeer) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:\n" + " CAfile: %s\n CApath: %s", + data->set.str[STRING_SSL_CAFILE]? + data->set.str[STRING_SSL_CAFILE]: "none", + data->set.str[STRING_SSL_CAPATH]? + data->set.str[STRING_SSL_CAPATH] : "none"); + return CURLE_SSL_CACERT_BADFILE; + } + else { + /* Just continue with a warning if no strict certificate + verification is required. */ + infof(data, "error setting certificate verify locations," + " continuing anyway:\n"); + } + } + else { + /* Everything is fine. */ + infof(data, "successfully set certificate verify locations:\n"); + } + infof(data, + " CAfile: %s\n" + " CApath: %s\n", + data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]: + "none", + data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]: + "none"); + } + + /* Load the client certificate, and private key */ + if(data->set.str[STRING_CERT] && data->set.str[STRING_KEY]) { + int file_type = do_file_type(data->set.str[STRING_CERT_TYPE]); + + if(SSL_CTX_use_certificate_file(conssl->ctx, data->set.str[STRING_CERT], + file_type) != 1) { + failf(data, "unable to use client certificate (no key or wrong pass" + " phrase?)"); + return CURLE_SSL_CONNECT_ERROR; + } + + file_type = do_file_type(data->set.str[STRING_KEY_TYPE]); + if(SSL_CTX_use_PrivateKey_file(conssl->ctx, data->set.str[STRING_KEY], + file_type) != 1) { + failf(data, "unable to set private key"); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif /* !NO_FILESYSTEM */ + + /* SSL always tries to verify the peer, this only says whether it should + * fail to connect if the verification fails, or if it should continue + * anyway. In the latter case the result of the verification is checked with + * SSL_get_verify_result() below. */ + SSL_CTX_set_verify(conssl->ctx, + data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE, + NULL); + +#ifdef HAVE_SNI + if(sni) { + struct in_addr addr4; +#ifdef ENABLE_IPV6 + struct in6_addr addr6; +#endif + size_t hostname_len = strlen(conn->host.name); + if((hostname_len < USHRT_MAX) && + (0 == Curl_inet_pton(AF_INET, conn->host.name, &addr4)) && +#ifdef ENABLE_IPV6 + (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr6)) && +#endif + (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, conn->host.name, + (unsigned short)hostname_len) != 1)) { + infof(data, "WARNING: failed to configure server name indication (SNI) " + "TLS extension\n"); + } + } +#endif + + /* give application a chance to interfere with SSL set up. */ + if(data->set.ssl.fsslctx) { + CURLcode result = CURLE_OK; + result = (*data->set.ssl.fsslctx)(data, conssl->ctx, + data->set.ssl.fsslctxp); + if(result) { + failf(data, "error signaled by ssl ctx callback"); + return result; + } + } +#ifdef NO_FILESYSTEM + else if(data->set.ssl.verifypeer) { + failf(data, "SSL: Certificates couldn't be loaded because CyaSSL was built" + " with \"no filesystem\". Either disable peer verification" + " (insecure) or if you are building an application with libcurl you" + " can load certificates via CURLOPT_SSL_CTX_FUNCTION."); + return CURLE_SSL_CONNECT_ERROR; + } +#endif + + /* Let's make an SSL structure */ + if(conssl->handle) + SSL_free(conssl->handle); + conssl->handle = SSL_new(conssl->ctx); + if(!conssl->handle) { + failf(data, "SSL: couldn't create a context (handle)!"); + return CURLE_OUT_OF_MEMORY; + } + + /* Check if there's a cached ID we can/should use here! */ + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { + /* we got a session id, use it! */ + if(!SSL_set_session(conssl->handle, ssl_sessionid)) { + failf(data, "SSL: SSL_set_session failed: %s", + ERR_error_string(SSL_get_error(conssl->handle, 0), error_buffer)); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof (data, "SSL re-using session ID\n"); + } + + /* pass the raw socket into the SSL layer */ + if(!SSL_set_fd(conssl->handle, (int)sockfd)) { + failf(data, "SSL: SSL_set_fd failed"); + return CURLE_SSL_CONNECT_ERROR; + } + + conssl->connecting_state = ssl_connect_2; + return CURLE_OK; +} + + +static CURLcode +cyassl_connect_step2(struct connectdata *conn, + int sockindex) +{ + int ret = -1; + struct SessionHandle *data = conn->data; + struct ssl_connect_data* conssl = &conn->ssl[sockindex]; + + conn->recv[sockindex] = cyassl_recv; + conn->send[sockindex] = cyassl_send; + + /* Enable RFC2818 checks */ + if(data->set.ssl.verifyhost) { + ret = CyaSSL_check_domain_name(conssl->handle, conn->host.name); + if(ret == SSL_FAILURE) + return CURLE_OUT_OF_MEMORY; + } + + ret = SSL_connect(conssl->handle); + if(ret != 1) { + char error_buffer[CYASSL_MAX_ERROR_SZ]; + int detail = SSL_get_error(conssl->handle, ret); + + if(SSL_ERROR_WANT_READ == detail) { + conssl->connecting_state = ssl_connect_2_reading; + return CURLE_OK; + } + else if(SSL_ERROR_WANT_WRITE == detail) { + conssl->connecting_state = ssl_connect_2_writing; + return CURLE_OK; + } + /* There is no easy way to override only the CN matching. + * This will enable the override of both mismatching SubjectAltNames + * as also mismatching CN fields */ + else if(DOMAIN_NAME_MISMATCH == detail) { +#if 1 + failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n", + conn->host.dispname); + return CURLE_PEER_FAILED_VERIFICATION; +#else + /* When the CyaSSL_check_domain_name() is used and you desire to continue + * on a DOMAIN_NAME_MISMATCH, i.e. 'data->set.ssl.verifyhost == 0', + * CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA error. The only + * way to do this is currently to switch the CyaSSL_check_domain_name() + * in and out based on the 'data->set.ssl.verifyhost' value. */ + if(data->set.ssl.verifyhost) { + failf(data, + "\tsubject alt name(s) or common name do not match \"%s\"\n", + conn->host.dispname); + return CURLE_PEER_FAILED_VERIFICATION; + } + else { + infof(data, + "\tsubject alt name(s) and/or common name do not match \"%s\"\n", + conn->host.dispname); + return CURLE_OK; + } +#endif + } +#if LIBCYASSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */ + else if(ASN_NO_SIGNER_E == detail) { + if(data->set.ssl.verifypeer) { + failf(data, "\tCA signer not available for verification\n"); + return CURLE_SSL_CACERT_BADFILE; + } + else { + /* Just continue with a warning if no strict certificate + verification is required. */ + infof(data, "CA signer not available for verification, " + "continuing anyway\n"); + } + } +#endif + else { + failf(data, "SSL_connect failed with error %d: %s", detail, + ERR_error_string(detail, error_buffer)); + return CURLE_SSL_CONNECT_ERROR; + } + } + + if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { +#if defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \ + defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) + X509 *x509; + const char *x509_der; + int x509_der_len; + curl_X509certificate x509_parsed; + curl_asn1Element *pubkey; + CURLcode result; + + x509 = SSL_get_peer_certificate(conssl->handle); + if(!x509) { + failf(data, "SSL: failed retrieving server certificate"); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + x509_der = (const char *)CyaSSL_X509_get_der(x509, &x509_der_len); + if(!x509_der) { + failf(data, "SSL: failed retrieving ASN.1 server certificate"); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + memset(&x509_parsed, 0, sizeof x509_parsed); + Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len); + + pubkey = &x509_parsed.subjectPublicKeyInfo; + if(!pubkey->header || pubkey->end <= pubkey->header) { + failf(data, "SSL: failed retrieving public key from server certificate"); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + result = Curl_pin_peer_pubkey(data, + data->set.str[STRING_SSL_PINNEDPUBLICKEY], + (const unsigned char *)pubkey->header, + (size_t)(pubkey->end - pubkey->header)); + if(result) { + failf(data, "SSL: public key does not match pinned public key!"); + return result; + } +#else + failf(data, "Library lacks pinning support built-in"); + return CURLE_NOT_BUILT_IN; +#endif + } + + conssl->connecting_state = ssl_connect_3; + infof(data, "SSL connected\n"); + + return CURLE_OK; +} + + +static CURLcode +cyassl_connect_step3(struct connectdata *conn, + int sockindex) +{ + CURLcode result = CURLE_OK; + void *old_ssl_sessionid=NULL; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + bool incache; + SSL_SESSION *our_ssl_sessionid; + + DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); + + our_ssl_sessionid = SSL_get_session(connssl->handle); + + incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); + if(incache) { + if(old_ssl_sessionid != our_ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing\n"); + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + incache = FALSE; + } + } + + if(!incache) { + result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, + 0 /* unknown size */); + if(result) { + failf(data, "failed to store ssl session"); + return result; + } + } + + connssl->connecting_state = ssl_connect_done; + + return result; +} + + +static ssize_t cyassl_send(struct connectdata *conn, + int sockindex, + const void *mem, + size_t len, + CURLcode *curlcode) +{ + char error_buffer[CYASSL_MAX_ERROR_SZ]; + int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; + int rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen); + + if(rc < 0) { + int err = SSL_get_error(conn->ssl[sockindex].handle, rc); + + switch(err) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + /* there's data pending, re-invoke SSL_write() */ + *curlcode = CURLE_AGAIN; + return -1; + default: + failf(conn->data, "SSL write: %s, errno %d", + ERR_error_string(err, error_buffer), + SOCKERRNO); + *curlcode = CURLE_SEND_ERROR; + return -1; + } + } + return rc; +} + +void Curl_cyassl_close(struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *conssl = &conn->ssl[sockindex]; + + if(conssl->handle) { + (void)SSL_shutdown(conssl->handle); + SSL_free (conssl->handle); + conssl->handle = NULL; + } + if(conssl->ctx) { + SSL_CTX_free (conssl->ctx); + conssl->ctx = NULL; + } +} + +static ssize_t cyassl_recv(struct connectdata *conn, + int num, + char *buf, + size_t buffersize, + CURLcode *curlcode) +{ + char error_buffer[CYASSL_MAX_ERROR_SZ]; + int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; + int nread = SSL_read(conn->ssl[num].handle, buf, buffsize); + + if(nread < 0) { + int err = SSL_get_error(conn->ssl[num].handle, nread); + + switch(err) { + case SSL_ERROR_ZERO_RETURN: /* no more data */ + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + /* there's data pending, re-invoke SSL_read() */ + *curlcode = CURLE_AGAIN; + return -1; + default: + failf(conn->data, "SSL read: %s, errno %d", + ERR_error_string(err, error_buffer), + SOCKERRNO); + *curlcode = CURLE_RECV_ERROR; + return -1; + } + } + return nread; +} + + +void Curl_cyassl_session_free(void *ptr) +{ + (void)ptr; + /* CyaSSL reuses sessions on own, no free */ +} + + +size_t Curl_cyassl_version(char *buffer, size_t size) +{ +#ifdef WOLFSSL_VERSION + return snprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION); +#elif defined(CYASSL_VERSION) + return snprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION); +#else + return snprintf(buffer, size, "CyaSSL/%s", "<1.8.8"); +#endif +} + + +int Curl_cyassl_init(void) +{ + return (CyaSSL_Init() == SSL_SUCCESS); +} + + +bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex) +{ + if(conn->ssl[connindex].handle) /* SSL is in use */ + return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE; + else + return FALSE; +} + + +/* + * This function is called to shut down the SSL layer but keep the + * socket open (CCC - Clear Command Channel) + */ +int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex) +{ + int retval = 0; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + if(connssl->handle) { + SSL_free (connssl->handle); + connssl->handle = NULL; + } + return retval; +} + + +static CURLcode +cyassl_connect_common(struct connectdata *conn, + int sockindex, + bool nonblocking, + bool *done) +{ + CURLcode result; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + curl_socket_t sockfd = conn->sock[sockindex]; + long timeout_ms; + int what; + + /* check if the connection has already been established */ + if(ssl_connection_complete == connssl->state) { + *done = TRUE; + return CURLE_OK; + } + + if(ssl_connect_1==connssl->connecting_state) { + /* Find out how much more time we're allowed */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + result = cyassl_connect_step1(conn, sockindex); + if(result) + return result; + } + + while(ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state) { + + /* check allowed time left */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + /* if ssl is expecting something, check if it's available. */ + if(connssl->connecting_state == ssl_connect_2_reading + || connssl->connecting_state == ssl_connect_2_writing) { + + curl_socket_t writefd = ssl_connect_2_writing== + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading== + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + + what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + return CURLE_SSL_CONNECT_ERROR; + } + else if(0 == what) { + if(nonblocking) { + *done = FALSE; + return CURLE_OK; + } + else { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + } + /* socket is readable or writable */ + } + + /* Run transaction, and return to the caller if it failed or if + * this connection is part of a multi handle and this loop would + * execute again. This permits the owner of a multi handle to + * abort a connection attempt before step2 has completed while + * ensuring that a client using select() or epoll() will always + * have a valid fdset to wait on. + */ + result = cyassl_connect_step2(conn, sockindex); + if(result || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return result; + } /* repeat step2 until all transactions are done. */ + + if(ssl_connect_3 == connssl->connecting_state) { + result = cyassl_connect_step3(conn, sockindex); + if(result) + return result; + } + + if(ssl_connect_done == connssl->connecting_state) { + connssl->state = ssl_connection_complete; + conn->recv[sockindex] = cyassl_recv; + conn->send[sockindex] = cyassl_send; + *done = TRUE; + } + else + *done = FALSE; + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + + return CURLE_OK; +} + + +CURLcode +Curl_cyassl_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done) +{ + return cyassl_connect_common(conn, sockindex, TRUE, done); +} + + +CURLcode +Curl_cyassl_connect(struct connectdata *conn, + int sockindex) +{ + CURLcode result; + bool done = FALSE; + + result = cyassl_connect_common(conn, sockindex, FALSE, &done); + if(result) + return result; + + DEBUGASSERT(done); + + return CURLE_OK; +} + +int Curl_cyassl_random(struct SessionHandle *data, + unsigned char *entropy, + size_t length) +{ + RNG rng; + (void)data; + if(InitRng(&rng)) + return 1; + if(length > UINT_MAX) + return 1; + if(RNG_GenerateBlock(&rng, entropy, (unsigned)length)) + return 1; + return 0; +} + +void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum /* output */, + size_t unused) +{ + Sha256 SHA256pw; + (void)unused; + InitSha256(&SHA256pw); + Sha256Update(&SHA256pw, tmp, (word32)tmplen); + Sha256Final(&SHA256pw, sha256sum); +} + +#endif diff --git a/project/jni/curl/lib/vtls/cyassl.h b/project/jni/curl/lib/vtls/cyassl.h new file mode 100644 index 000000000..52a5e15ae --- /dev/null +++ b/project/jni/curl/lib/vtls/cyassl.h @@ -0,0 +1,75 @@ +#ifndef HEADER_CURL_CYASSL_H +#define HEADER_CURL_CYASSL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_CYASSL + +CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex); +bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex); +int Curl_cyassl_shutdown(struct connectdata* conn, int sockindex); + + /* close a SSL connection */ +void Curl_cyassl_close(struct connectdata *conn, int sockindex); + +void Curl_cyassl_session_free(void *ptr); +size_t Curl_cyassl_version(char *buffer, size_t size); +int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex); +int Curl_cyassl_init(void); +CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done); +int Curl_cyassl_random(struct SessionHandle *data, + unsigned char *entropy, + size_t length); +void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum, /* output */ + size_t unused); + +/* Set the API backend definition to Schannel */ +#define CURL_SSL_BACKEND CURLSSLBACKEND_CYASSL + +/* this backend supports CURLOPT_SSL_CTX_* */ +#define have_curlssl_ssl_ctx 1 + +/* API setup for CyaSSL */ +#define curlssl_init Curl_cyassl_init +#define curlssl_cleanup() Curl_nop_stmt +#define curlssl_connect Curl_cyassl_connect +#define curlssl_connect_nonblocking Curl_cyassl_connect_nonblocking +#define curlssl_session_free(x) Curl_cyassl_session_free(x) +#define curlssl_close_all(x) ((void)x) +#define curlssl_close Curl_cyassl_close +#define curlssl_shutdown(x,y) Curl_cyassl_shutdown(x,y) +#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN) +#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN) +#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) +#define curlssl_version Curl_cyassl_version +#define curlssl_check_cxn(x) ((void)x, -1) +#define curlssl_data_pending(x,y) Curl_cyassl_data_pending(x,y) +#define curlssl_random(x,y,z) Curl_cyassl_random(x,y,z) +#define curlssl_sha256sum(a,b,c,d) Curl_cyassl_sha256sum(a,b,c,d) + +#endif /* USE_CYASSL */ +#endif /* HEADER_CURL_CYASSL_H */ diff --git a/project/jni/curl/lib/vtls/darwinssl.c b/project/jni/curl/lib/vtls/darwinssl.c new file mode 100644 index 000000000..ed587eb37 --- /dev/null +++ b/project/jni/curl/lib/vtls/darwinssl.c @@ -0,0 +1,2484 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2012 - 2014, Nick Zitzmann, . + * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Source file for all iOS and Mac OS X SecureTransport-specific code for the + * TLS/SSL layer. No code but vtls.c should ever call or use these functions. + */ + +#include "curl_setup.h" + +#include "urldata.h" /* for the SessionHandle definition */ +#include "curl_base64.h" +#include "strtok.h" + +#ifdef USE_DARWINSSL + +#ifdef HAVE_LIMITS_H +#include +#endif + +#include +#include +#include +#include + +/* The Security framework has changed greatly between iOS and different OS X + versions, and we will try to support as many of them as we can (back to + Leopard and iOS 5) by using macros and weak-linking. + + IMPORTANT: If TLS 1.1 and 1.2 support are important for you on OS X, then + you must build this project against the 10.8 SDK or later. */ +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) + +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050 +#error "The darwinssl back-end requires Leopard or later." +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */ + +#define CURL_BUILD_IOS 0 +#define CURL_BUILD_IOS_7 0 +#define CURL_BUILD_MAC 1 +/* This is the maximum API level we are allowed to use when building: */ +#define CURL_BUILD_MAC_10_5 MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 +#define CURL_BUILD_MAC_10_6 MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 +#define CURL_BUILD_MAC_10_7 MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 +#define CURL_BUILD_MAC_10_8 MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 +#define CURL_BUILD_MAC_10_9 MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 +/* These macros mean "the following code is present to allow runtime backward + compatibility with at least this cat or earlier": + (You set this at build-time by setting the MACOSX_DEPLOYMENT_TARGET + environmental variable.) */ +#define CURL_SUPPORT_MAC_10_5 MAC_OS_X_VERSION_MIN_REQUIRED <= 1050 +#define CURL_SUPPORT_MAC_10_6 MAC_OS_X_VERSION_MIN_REQUIRED <= 1060 +#define CURL_SUPPORT_MAC_10_7 MAC_OS_X_VERSION_MIN_REQUIRED <= 1070 +#define CURL_SUPPORT_MAC_10_8 MAC_OS_X_VERSION_MIN_REQUIRED <= 1080 +#define CURL_SUPPORT_MAC_10_9 MAC_OS_X_VERSION_MIN_REQUIRED <= 1090 + +#elif TARGET_OS_EMBEDDED || TARGET_OS_IPHONE +#define CURL_BUILD_IOS 1 +#define CURL_BUILD_IOS_7 __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 +#define CURL_BUILD_MAC 0 +#define CURL_BUILD_MAC_10_5 0 +#define CURL_BUILD_MAC_10_6 0 +#define CURL_BUILD_MAC_10_7 0 +#define CURL_BUILD_MAC_10_8 0 +#define CURL_SUPPORT_MAC_10_5 0 +#define CURL_SUPPORT_MAC_10_6 0 +#define CURL_SUPPORT_MAC_10_7 0 +#define CURL_SUPPORT_MAC_10_8 0 +#define CURL_SUPPORT_MAC_10_9 0 + +#else +#error "The darwinssl back-end requires iOS or OS X." +#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ + +#if CURL_BUILD_MAC +#include +#endif /* CURL_BUILD_MAC */ + +#include "urldata.h" +#include "sendf.h" +#include "inet_pton.h" +#include "connect.h" +#include "select.h" +#include "vtls.h" +#include "darwinssl.h" +#include "curl_printf.h" + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* From MacTypes.h (which we can't include because it isn't present in iOS: */ +#define ioErr -36 +#define paramErr -50 + +/* The following two functions were ripped from Apple sample code, + * with some modifications: */ +static OSStatus SocketRead(SSLConnectionRef connection, + void *data, /* owned by + * caller, data + * RETURNED */ + size_t *dataLength) /* IN/OUT */ +{ + size_t bytesToGo = *dataLength; + size_t initLen = bytesToGo; + UInt8 *currData = (UInt8 *)data; + /*int sock = *(int *)connection;*/ + struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection; + int sock = connssl->ssl_sockfd; + OSStatus rtn = noErr; + size_t bytesRead; + ssize_t rrtn; + int theErr; + + *dataLength = 0; + + for(;;) { + bytesRead = 0; + rrtn = read(sock, currData, bytesToGo); + if(rrtn <= 0) { + /* this is guesswork... */ + theErr = errno; + if(rrtn == 0) { /* EOF = server hung up */ + /* the framework will turn this into errSSLClosedNoNotify */ + rtn = errSSLClosedGraceful; + } + else /* do the switch */ + switch(theErr) { + case ENOENT: + /* connection closed */ + rtn = errSSLClosedGraceful; + break; + case ECONNRESET: + rtn = errSSLClosedAbort; + break; + case EAGAIN: + rtn = errSSLWouldBlock; + connssl->ssl_direction = false; + break; + default: + rtn = ioErr; + break; + } + break; + } + else { + bytesRead = rrtn; + } + bytesToGo -= bytesRead; + currData += bytesRead; + + if(bytesToGo == 0) { + /* filled buffer with incoming data, done */ + break; + } + } + *dataLength = initLen - bytesToGo; + + return rtn; +} + +static OSStatus SocketWrite(SSLConnectionRef connection, + const void *data, + size_t *dataLength) /* IN/OUT */ +{ + size_t bytesSent = 0; + /*int sock = *(int *)connection;*/ + struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection; + int sock = connssl->ssl_sockfd; + ssize_t length; + size_t dataLen = *dataLength; + const UInt8 *dataPtr = (UInt8 *)data; + OSStatus ortn; + int theErr; + + *dataLength = 0; + + do { + length = write(sock, + (char*)dataPtr + bytesSent, + dataLen - bytesSent); + } while((length > 0) && + ( (bytesSent += length) < dataLen) ); + + if(length <= 0) { + theErr = errno; + if(theErr == EAGAIN) { + ortn = errSSLWouldBlock; + connssl->ssl_direction = true; + } + else { + ortn = ioErr; + } + } + else { + ortn = noErr; + } + *dataLength = bytesSent; + return ortn; +} + +CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher) { + switch (cipher) { + /* SSL version 3.0 */ + case SSL_RSA_WITH_NULL_MD5: + return "SSL_RSA_WITH_NULL_MD5"; + break; + case SSL_RSA_WITH_NULL_SHA: + return "SSL_RSA_WITH_NULL_SHA"; + break; + case SSL_RSA_EXPORT_WITH_RC4_40_MD5: + return "SSL_RSA_EXPORT_WITH_RC4_40_MD5"; + break; + case SSL_RSA_WITH_RC4_128_MD5: + return "SSL_RSA_WITH_RC4_128_MD5"; + break; + case SSL_RSA_WITH_RC4_128_SHA: + return "SSL_RSA_WITH_RC4_128_SHA"; + break; + case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5: + return "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5"; + break; + case SSL_RSA_WITH_IDEA_CBC_SHA: + return "SSL_RSA_WITH_IDEA_CBC_SHA"; + break; + case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA: + return "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"; + break; + case SSL_RSA_WITH_DES_CBC_SHA: + return "SSL_RSA_WITH_DES_CBC_SHA"; + break; + case SSL_RSA_WITH_3DES_EDE_CBC_SHA: + return "SSL_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: + return "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"; + break; + case SSL_DH_DSS_WITH_DES_CBC_SHA: + return "SSL_DH_DSS_WITH_DES_CBC_SHA"; + break; + case SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA: + return "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA"; + break; + case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: + return "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"; + break; + case SSL_DH_RSA_WITH_DES_CBC_SHA: + return "SSL_DH_RSA_WITH_DES_CBC_SHA"; + break; + case SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA: + return "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: + return "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"; + break; + case SSL_DHE_DSS_WITH_DES_CBC_SHA: + return "SSL_DHE_DSS_WITH_DES_CBC_SHA"; + break; + case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA: + return "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"; + break; + case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: + return "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"; + break; + case SSL_DHE_RSA_WITH_DES_CBC_SHA: + return "SSL_DHE_RSA_WITH_DES_CBC_SHA"; + break; + case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + return "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5: + return "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5"; + break; + case SSL_DH_anon_WITH_RC4_128_MD5: + return "SSL_DH_anon_WITH_RC4_128_MD5"; + break; + case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA: + return "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"; + break; + case SSL_DH_anon_WITH_DES_CBC_SHA: + return "SSL_DH_anon_WITH_DES_CBC_SHA"; + break; + case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA: + return "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"; + break; + case SSL_FORTEZZA_DMS_WITH_NULL_SHA: + return "SSL_FORTEZZA_DMS_WITH_NULL_SHA"; + break; + case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA: + return "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA"; + break; + /* TLS 1.0 with AES (RFC 3268) + (Apparently these are used in SSLv3 implementations as well.) */ + case TLS_RSA_WITH_AES_128_CBC_SHA: + return "TLS_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_DH_DSS_WITH_AES_128_CBC_SHA: + return "TLS_DH_DSS_WITH_AES_128_CBC_SHA"; + break; + case TLS_DH_RSA_WITH_AES_128_CBC_SHA: + return "TLS_DH_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: + return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"; + break; + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_DH_anon_WITH_AES_128_CBC_SHA: + return "TLS_DH_anon_WITH_AES_128_CBC_SHA"; + break; + case TLS_RSA_WITH_AES_256_CBC_SHA: + return "TLS_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_DH_DSS_WITH_AES_256_CBC_SHA: + return "TLS_DH_DSS_WITH_AES_256_CBC_SHA"; + break; + case TLS_DH_RSA_WITH_AES_256_CBC_SHA: + return "TLS_DH_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: + return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"; + break; + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_DH_anon_WITH_AES_256_CBC_SHA: + return "TLS_DH_anon_WITH_AES_256_CBC_SHA"; + break; + /* SSL version 2.0 */ + case SSL_RSA_WITH_RC2_CBC_MD5: + return "SSL_RSA_WITH_RC2_CBC_MD5"; + break; + case SSL_RSA_WITH_IDEA_CBC_MD5: + return "SSL_RSA_WITH_IDEA_CBC_MD5"; + break; + case SSL_RSA_WITH_DES_CBC_MD5: + return "SSL_RSA_WITH_DES_CBC_MD5"; + break; + case SSL_RSA_WITH_3DES_EDE_CBC_MD5: + return "SSL_RSA_WITH_3DES_EDE_CBC_MD5"; + break; + } + return "SSL_NULL_WITH_NULL_NULL"; +} + +CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) { + switch(cipher) { + /* TLS 1.0 with AES (RFC 3268) */ + case TLS_RSA_WITH_AES_128_CBC_SHA: + return "TLS_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_DH_DSS_WITH_AES_128_CBC_SHA: + return "TLS_DH_DSS_WITH_AES_128_CBC_SHA"; + break; + case TLS_DH_RSA_WITH_AES_128_CBC_SHA: + return "TLS_DH_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: + return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"; + break; + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_DH_anon_WITH_AES_128_CBC_SHA: + return "TLS_DH_anon_WITH_AES_128_CBC_SHA"; + break; + case TLS_RSA_WITH_AES_256_CBC_SHA: + return "TLS_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_DH_DSS_WITH_AES_256_CBC_SHA: + return "TLS_DH_DSS_WITH_AES_256_CBC_SHA"; + break; + case TLS_DH_RSA_WITH_AES_256_CBC_SHA: + return "TLS_DH_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: + return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"; + break; + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_DH_anon_WITH_AES_256_CBC_SHA: + return "TLS_DH_anon_WITH_AES_256_CBC_SHA"; + break; +#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS + /* TLS 1.0 with ECDSA (RFC 4492) */ + case TLS_ECDH_ECDSA_WITH_NULL_SHA: + return "TLS_ECDH_ECDSA_WITH_NULL_SHA"; + break; + case TLS_ECDH_ECDSA_WITH_RC4_128_SHA: + return "TLS_ECDH_ECDSA_WITH_RC4_128_SHA"; + break; + case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: + return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: + return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_ECDHE_ECDSA_WITH_NULL_SHA: + return "TLS_ECDHE_ECDSA_WITH_NULL_SHA"; + break; + case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: + return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"; + break; + case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: + return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: + return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_ECDH_RSA_WITH_NULL_SHA: + return "TLS_ECDH_RSA_WITH_NULL_SHA"; + break; + case TLS_ECDH_RSA_WITH_RC4_128_SHA: + return "TLS_ECDH_RSA_WITH_RC4_128_SHA"; + break; + case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: + return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: + return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_ECDHE_RSA_WITH_NULL_SHA: + return "TLS_ECDHE_RSA_WITH_NULL_SHA"; + break; + case TLS_ECDHE_RSA_WITH_RC4_128_SHA: + return "TLS_ECDHE_RSA_WITH_RC4_128_SHA"; + break; + case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: + return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: + return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_ECDH_anon_WITH_NULL_SHA: + return "TLS_ECDH_anon_WITH_NULL_SHA"; + break; + case TLS_ECDH_anon_WITH_RC4_128_SHA: + return "TLS_ECDH_anon_WITH_RC4_128_SHA"; + break; + case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA: + return "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: + return "TLS_ECDH_anon_WITH_AES_128_CBC_SHA"; + break; + case TLS_ECDH_anon_WITH_AES_256_CBC_SHA: + return "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"; + break; +#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */ +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS + /* TLS 1.2 (RFC 5246) */ + case TLS_RSA_WITH_NULL_MD5: + return "TLS_RSA_WITH_NULL_MD5"; + break; + case TLS_RSA_WITH_NULL_SHA: + return "TLS_RSA_WITH_NULL_SHA"; + break; + case TLS_RSA_WITH_RC4_128_MD5: + return "TLS_RSA_WITH_RC4_128_MD5"; + break; + case TLS_RSA_WITH_RC4_128_SHA: + return "TLS_RSA_WITH_RC4_128_SHA"; + break; + case TLS_RSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_RSA_WITH_NULL_SHA256: + return "TLS_RSA_WITH_NULL_SHA256"; + break; + case TLS_RSA_WITH_AES_128_CBC_SHA256: + return "TLS_RSA_WITH_AES_128_CBC_SHA256"; + break; + case TLS_RSA_WITH_AES_256_CBC_SHA256: + return "TLS_RSA_WITH_AES_256_CBC_SHA256"; + break; + case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: + return "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: + return "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_DH_DSS_WITH_AES_128_CBC_SHA256: + return "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"; + break; + case TLS_DH_RSA_WITH_AES_128_CBC_SHA256: + return "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"; + break; + case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: + return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"; + break; + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: + return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"; + break; + case TLS_DH_DSS_WITH_AES_256_CBC_SHA256: + return "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"; + break; + case TLS_DH_RSA_WITH_AES_256_CBC_SHA256: + return "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"; + break; + case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: + return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"; + break; + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: + return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"; + break; + case TLS_DH_anon_WITH_RC4_128_MD5: + return "TLS_DH_anon_WITH_RC4_128_MD5"; + break; + case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA: + return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_DH_anon_WITH_AES_128_CBC_SHA256: + return "TLS_DH_anon_WITH_AES_128_CBC_SHA256"; + break; + case TLS_DH_anon_WITH_AES_256_CBC_SHA256: + return "TLS_DH_anon_WITH_AES_256_CBC_SHA256"; + break; + /* TLS 1.2 with AES GCM (RFC 5288) */ + case TLS_RSA_WITH_AES_128_GCM_SHA256: + return "TLS_RSA_WITH_AES_128_GCM_SHA256"; + break; + case TLS_RSA_WITH_AES_256_GCM_SHA384: + return "TLS_RSA_WITH_AES_256_GCM_SHA384"; + break; + case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: + return "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"; + break; + case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: + return "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"; + break; + case TLS_DH_RSA_WITH_AES_128_GCM_SHA256: + return "TLS_DH_RSA_WITH_AES_128_GCM_SHA256"; + break; + case TLS_DH_RSA_WITH_AES_256_GCM_SHA384: + return "TLS_DH_RSA_WITH_AES_256_GCM_SHA384"; + break; + case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: + return "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"; + break; + case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: + return "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384"; + break; + case TLS_DH_DSS_WITH_AES_128_GCM_SHA256: + return "TLS_DH_DSS_WITH_AES_128_GCM_SHA256"; + break; + case TLS_DH_DSS_WITH_AES_256_GCM_SHA384: + return "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"; + break; + case TLS_DH_anon_WITH_AES_128_GCM_SHA256: + return "TLS_DH_anon_WITH_AES_128_GCM_SHA256"; + break; + case TLS_DH_anon_WITH_AES_256_GCM_SHA384: + return "TLS_DH_anon_WITH_AES_256_GCM_SHA384"; + break; + /* TLS 1.2 with elliptic curve ciphers (RFC 5289) */ + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: + return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"; + break; + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: + return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"; + break; + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: + return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256"; + break; + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: + return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384"; + break; + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: + return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"; + break; + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: + return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"; + break; + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: + return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256"; + break; + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: + return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384"; + break; + case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: + return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"; + break; + case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: + return "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"; + break; + case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: + return "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"; + break; + case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: + return "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384"; + break; + case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: + return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"; + break; + case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: + return "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"; + break; + case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: + return "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"; + break; + case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: + return "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384"; + break; + case TLS_EMPTY_RENEGOTIATION_INFO_SCSV: + return "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"; + break; +#else + case SSL_RSA_WITH_NULL_MD5: + return "TLS_RSA_WITH_NULL_MD5"; + break; + case SSL_RSA_WITH_NULL_SHA: + return "TLS_RSA_WITH_NULL_SHA"; + break; + case SSL_RSA_WITH_RC4_128_MD5: + return "TLS_RSA_WITH_RC4_128_MD5"; + break; + case SSL_RSA_WITH_RC4_128_SHA: + return "TLS_RSA_WITH_RC4_128_SHA"; + break; + case SSL_RSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case SSL_DH_anon_WITH_RC4_128_MD5: + return "TLS_DH_anon_WITH_RC4_128_MD5"; + break; + case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA: + return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"; + break; +#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ +#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 + /* TLS PSK (RFC 4279): */ + case TLS_PSK_WITH_RC4_128_SHA: + return "TLS_PSK_WITH_RC4_128_SHA"; + break; + case TLS_PSK_WITH_3DES_EDE_CBC_SHA: + return "TLS_PSK_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_PSK_WITH_AES_128_CBC_SHA: + return "TLS_PSK_WITH_AES_128_CBC_SHA"; + break; + case TLS_PSK_WITH_AES_256_CBC_SHA: + return "TLS_PSK_WITH_AES_256_CBC_SHA"; + break; + case TLS_DHE_PSK_WITH_RC4_128_SHA: + return "TLS_DHE_PSK_WITH_RC4_128_SHA"; + break; + case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: + return "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_DHE_PSK_WITH_AES_128_CBC_SHA: + return "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"; + break; + case TLS_DHE_PSK_WITH_AES_256_CBC_SHA: + return "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"; + break; + case TLS_RSA_PSK_WITH_RC4_128_SHA: + return "TLS_RSA_PSK_WITH_RC4_128_SHA"; + break; + case TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: + return "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_RSA_PSK_WITH_AES_128_CBC_SHA: + return "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"; + break; + case TLS_RSA_PSK_WITH_AES_256_CBC_SHA: + return "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"; + break; + /* More TLS PSK (RFC 4785): */ + case TLS_PSK_WITH_NULL_SHA: + return "TLS_PSK_WITH_NULL_SHA"; + break; + case TLS_DHE_PSK_WITH_NULL_SHA: + return "TLS_DHE_PSK_WITH_NULL_SHA"; + break; + case TLS_RSA_PSK_WITH_NULL_SHA: + return "TLS_RSA_PSK_WITH_NULL_SHA"; + break; + /* Even more TLS PSK (RFC 5487): */ + case TLS_PSK_WITH_AES_128_GCM_SHA256: + return "TLS_PSK_WITH_AES_128_GCM_SHA256"; + break; + case TLS_PSK_WITH_AES_256_GCM_SHA384: + return "TLS_PSK_WITH_AES_256_GCM_SHA384"; + break; + case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256: + return "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256"; + break; + case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384: + return "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384"; + break; + case TLS_RSA_PSK_WITH_AES_128_GCM_SHA256: + return "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256"; + break; + case TLS_RSA_PSK_WITH_AES_256_GCM_SHA384: + return "TLS_PSK_WITH_AES_256_GCM_SHA384"; + break; + case TLS_PSK_WITH_AES_128_CBC_SHA256: + return "TLS_PSK_WITH_AES_128_CBC_SHA256"; + break; + case TLS_PSK_WITH_AES_256_CBC_SHA384: + return "TLS_PSK_WITH_AES_256_CBC_SHA384"; + break; + case TLS_PSK_WITH_NULL_SHA256: + return "TLS_PSK_WITH_NULL_SHA256"; + break; + case TLS_PSK_WITH_NULL_SHA384: + return "TLS_PSK_WITH_NULL_SHA384"; + break; + case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256: + return "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256"; + break; + case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384: + return "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384"; + break; + case TLS_DHE_PSK_WITH_NULL_SHA256: + return "TLS_DHE_PSK_WITH_NULL_SHA256"; + break; + case TLS_DHE_PSK_WITH_NULL_SHA384: + return "TLS_RSA_PSK_WITH_NULL_SHA384"; + break; + case TLS_RSA_PSK_WITH_AES_128_CBC_SHA256: + return "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256"; + break; + case TLS_RSA_PSK_WITH_AES_256_CBC_SHA384: + return "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384"; + break; + case TLS_RSA_PSK_WITH_NULL_SHA256: + return "TLS_RSA_PSK_WITH_NULL_SHA256"; + break; + case TLS_RSA_PSK_WITH_NULL_SHA384: + return "TLS_RSA_PSK_WITH_NULL_SHA384"; + break; +#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ + } + return "TLS_NULL_WITH_NULL_NULL"; +} + +#if CURL_BUILD_MAC +CF_INLINE void GetDarwinVersionNumber(int *major, int *minor) +{ + int mib[2]; + char *os_version; + size_t os_version_len; + char *os_version_major, *os_version_minor/*, *os_version_point*/; + char *tok_buf; + + /* Get the Darwin kernel version from the kernel using sysctl(): */ + mib[0] = CTL_KERN; + mib[1] = KERN_OSRELEASE; + if(sysctl(mib, 2, NULL, &os_version_len, NULL, 0) == -1) + return; + os_version = malloc(os_version_len*sizeof(char)); + if(!os_version) + return; + if(sysctl(mib, 2, os_version, &os_version_len, NULL, 0) == -1) { + free(os_version); + return; + } + + /* Parse the version: */ + os_version_major = strtok_r(os_version, ".", &tok_buf); + os_version_minor = strtok_r(NULL, ".", &tok_buf); + /*os_version_point = strtok_r(NULL, ".", &tok_buf);*/ + *major = atoi(os_version_major); + *minor = atoi(os_version_minor); + free(os_version); +} +#endif /* CURL_BUILD_MAC */ + +/* Apple provides a myriad of ways of getting information about a certificate + into a string. Some aren't available under iOS or newer cats. So here's + a unified function for getting a string describing the certificate that + ought to work in all cats starting with Leopard. */ +CF_INLINE CFStringRef CopyCertSubject(SecCertificateRef cert) +{ + CFStringRef server_cert_summary = CFSTR("(null)"); + +#if CURL_BUILD_IOS + /* iOS: There's only one way to do this. */ + server_cert_summary = SecCertificateCopySubjectSummary(cert); +#else +#if CURL_BUILD_MAC_10_7 + /* Lion & later: Get the long description if we can. */ + if(SecCertificateCopyLongDescription != NULL) + server_cert_summary = + SecCertificateCopyLongDescription(NULL, cert, NULL); + else +#endif /* CURL_BUILD_MAC_10_7 */ +#if CURL_BUILD_MAC_10_6 + /* Snow Leopard: Get the certificate summary. */ + if(SecCertificateCopySubjectSummary != NULL) + server_cert_summary = SecCertificateCopySubjectSummary(cert); + else +#endif /* CURL_BUILD_MAC_10_6 */ + /* Leopard is as far back as we go... */ + (void)SecCertificateCopyCommonName(cert, &server_cert_summary); +#endif /* CURL_BUILD_IOS */ + return server_cert_summary; +} + +#if CURL_SUPPORT_MAC_10_6 +/* The SecKeychainSearch API was deprecated in Lion, and using it will raise + deprecation warnings, so let's not compile this unless it's necessary: */ +static OSStatus CopyIdentityWithLabelOldSchool(char *label, + SecIdentityRef *out_c_a_k) +{ + OSStatus status = errSecItemNotFound; + SecKeychainAttributeList attr_list; + SecKeychainAttribute attr; + SecKeychainSearchRef search = NULL; + SecCertificateRef cert = NULL; + + /* Set up the attribute list: */ + attr_list.count = 1L; + attr_list.attr = &attr; + + /* Set up our lone search criterion: */ + attr.tag = kSecLabelItemAttr; + attr.data = label; + attr.length = (UInt32)strlen(label); + + /* Start searching: */ + status = SecKeychainSearchCreateFromAttributes(NULL, + kSecCertificateItemClass, + &attr_list, + &search); + if(status == noErr) { + status = SecKeychainSearchCopyNext(search, + (SecKeychainItemRef *)&cert); + if(status == noErr && cert) { + /* If we found a certificate, does it have a private key? */ + status = SecIdentityCreateWithCertificate(NULL, cert, out_c_a_k); + CFRelease(cert); + } + } + + if(search) + CFRelease(search); + return status; +} +#endif /* CURL_SUPPORT_MAC_10_6 */ + +static OSStatus CopyIdentityWithLabel(char *label, + SecIdentityRef *out_cert_and_key) +{ + OSStatus status = errSecItemNotFound; + +#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS + /* SecItemCopyMatching() was introduced in iOS and Snow Leopard. + kSecClassIdentity was introduced in Lion. If both exist, let's use them + to find the certificate. */ + if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) { + CFTypeRef keys[4]; + CFTypeRef values[4]; + CFDictionaryRef query_dict; + CFStringRef label_cf = CFStringCreateWithCString(NULL, label, + kCFStringEncodingUTF8); + + /* Set up our search criteria and expected results: */ + values[0] = kSecClassIdentity; /* we want a certificate and a key */ + keys[0] = kSecClass; + values[1] = kCFBooleanTrue; /* we want a reference */ + keys[1] = kSecReturnRef; + values[2] = kSecMatchLimitOne; /* one is enough, thanks */ + keys[2] = kSecMatchLimit; + /* identity searches need a SecPolicyRef in order to work */ + values[3] = SecPolicyCreateSSL(false, label_cf); + keys[3] = kSecMatchPolicy; + query_dict = CFDictionaryCreate(NULL, (const void **)keys, + (const void **)values, 4L, + &kCFCopyStringDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFRelease(values[3]); + CFRelease(label_cf); + + /* Do we have a match? */ + status = SecItemCopyMatching(query_dict, (CFTypeRef *)out_cert_and_key); + CFRelease(query_dict); + } + else { +#if CURL_SUPPORT_MAC_10_6 + /* On Leopard and Snow Leopard, fall back to SecKeychainSearch. */ + status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key); +#endif /* CURL_SUPPORT_MAC_10_7 */ + } +#elif CURL_SUPPORT_MAC_10_6 + /* For developers building on older cats, we have no choice but to fall back + to SecKeychainSearch. */ + status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key); +#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ + return status; +} + +static OSStatus CopyIdentityFromPKCS12File(const char *cPath, + const char *cPassword, + SecIdentityRef *out_cert_and_key) +{ + OSStatus status = errSecItemNotFound; + CFURLRef pkcs_url = CFURLCreateFromFileSystemRepresentation(NULL, + (const UInt8 *)cPath, strlen(cPath), false); + CFStringRef password = cPassword ? CFStringCreateWithCString(NULL, + cPassword, kCFStringEncodingUTF8) : NULL; + CFDataRef pkcs_data = NULL; + + /* We can import P12 files on iOS or OS X 10.7 or later: */ + /* These constants are documented as having first appeared in 10.6 but they + raise linker errors when used on that cat for some reason. */ +#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS + if(CFURLCreateDataAndPropertiesFromResource(NULL, pkcs_url, &pkcs_data, + NULL, NULL, &status)) { + const void *cKeys[] = {kSecImportExportPassphrase}; + const void *cValues[] = {password}; + CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues, + password ? 1L : 0L, NULL, NULL); + CFArrayRef items = NULL; + + /* Here we go: */ + status = SecPKCS12Import(pkcs_data, options, &items); + if(status == noErr && items && CFArrayGetCount(items)) { + CFDictionaryRef identity_and_trust = CFArrayGetValueAtIndex(items, 0L); + const void *temp_identity = CFDictionaryGetValue(identity_and_trust, + kSecImportItemIdentity); + + /* Retain the identity; we don't care about any other data... */ + CFRetain(temp_identity); + *out_cert_and_key = (SecIdentityRef)temp_identity; + } + + if(items) + CFRelease(items); + CFRelease(options); + CFRelease(pkcs_data); + } +#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ + if(password) + CFRelease(password); + CFRelease(pkcs_url); + return status; +} + +/* This code was borrowed from nss.c, with some modifications: + * Determine whether the nickname passed in is a filename that needs to + * be loaded as a PEM or a regular NSS nickname. + * + * returns 1 for a file + * returns 0 for not a file + */ +CF_INLINE bool is_file(const char *filename) +{ + struct_stat st; + + if(filename == NULL) + return false; + + if(stat(filename, &st) == 0) + return S_ISREG(st.st_mode); + return false; +} + +static CURLcode darwinssl_connect_step1(struct connectdata *conn, + int sockindex) +{ + struct SessionHandle *data = conn->data; + curl_socket_t sockfd = conn->sock[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif /* ENABLE_IPV6 */ + size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i; + SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL; + char *ssl_sessionid; + size_t ssl_sessionid_len; + OSStatus err = noErr; +#if CURL_BUILD_MAC + int darwinver_maj = 0, darwinver_min = 0; + + GetDarwinVersionNumber(&darwinver_maj, &darwinver_min); +#endif /* CURL_BUILD_MAC */ + +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS + if(SSLCreateContext != NULL) { /* use the newer API if avaialble */ + if(connssl->ssl_ctx) + CFRelease(connssl->ssl_ctx); + connssl->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType); + if(!connssl->ssl_ctx) { + failf(data, "SSL: couldn't create a context!"); + return CURLE_OUT_OF_MEMORY; + } + } + else { + /* The old ST API does not exist under iOS, so don't compile it: */ +#if CURL_SUPPORT_MAC_10_8 + if(connssl->ssl_ctx) + (void)SSLDisposeContext(connssl->ssl_ctx); + err = SSLNewContext(false, &(connssl->ssl_ctx)); + if(err != noErr) { + failf(data, "SSL: couldn't create a context: OSStatus %d", err); + return CURLE_OUT_OF_MEMORY; + } +#endif /* CURL_SUPPORT_MAC_10_8 */ + } +#else + if(connssl->ssl_ctx) + (void)SSLDisposeContext(connssl->ssl_ctx); + err = SSLNewContext(false, &(connssl->ssl_ctx)); + if(err != noErr) { + failf(data, "SSL: couldn't create a context: OSStatus %d", err); + return CURLE_OUT_OF_MEMORY; + } +#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ + connssl->ssl_write_buffered_length = 0UL; /* reset buffered write length */ + + /* check to see if we've been told to use an explicit SSL/TLS version */ +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS + if(SSLSetProtocolVersionMax != NULL) { + switch(data->set.ssl.version) { + default: + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1); + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12); + break; + case CURL_SSLVERSION_TLSv1_0: + (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1); + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol1); + break; + case CURL_SSLVERSION_TLSv1_1: + (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol11); + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol11); + break; + case CURL_SSLVERSION_TLSv1_2: + (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol12); + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12); + break; + case CURL_SSLVERSION_SSLv3: + err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3); + if(err != noErr) { + failf(data, "Your version of the OS does not support SSLv3"); + return CURLE_SSL_CONNECT_ERROR; + } + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol3); + break; + case CURL_SSLVERSION_SSLv2: + err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol2); + if(err != noErr) { + failf(data, "Your version of the OS does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + } + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol2); + } + } + else { +#if CURL_SUPPORT_MAC_10_8 + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocolAll, + false); + switch (data->set.ssl.version) { + default: + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol1, + true); + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol11, + true); + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol12, + true); + break; + case CURL_SSLVERSION_TLSv1_0: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol1, + true); + break; + case CURL_SSLVERSION_TLSv1_1: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol11, + true); + break; + case CURL_SSLVERSION_TLSv1_2: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol12, + true); + break; + case CURL_SSLVERSION_SSLv3: + err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocol3, + true); + if(err != noErr) { + failf(data, "Your version of the OS does not support SSLv3"); + return CURLE_SSL_CONNECT_ERROR; + } + break; + case CURL_SSLVERSION_SSLv2: + err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocol2, + true); + if(err != noErr) { + failf(data, "Your version of the OS does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + } + break; + } +#endif /* CURL_SUPPORT_MAC_10_8 */ + } +#else + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false); + switch(data->set.ssl.version) { + default: + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + case CURL_SSLVERSION_TLSv1_0: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol1, + true); + break; + case CURL_SSLVERSION_TLSv1_1: + failf(data, "Your version of the OS does not support TLSv1.1"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_TLSv1_2: + failf(data, "Your version of the OS does not support TLSv1.2"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_SSLv2: + err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocol2, + true); + if(err != noErr) { + failf(data, "Your version of the OS does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + } + break; + case CURL_SSLVERSION_SSLv3: + err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocol3, + true); + if(err != noErr) { + failf(data, "Your version of the OS does not support SSLv3"); + return CURLE_SSL_CONNECT_ERROR; + } + break; + } +#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ + + if(data->set.str[STRING_KEY]) { + infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure " + "Transport. The private key must be in the Keychain.\n"); + } + + if(data->set.str[STRING_CERT]) { + SecIdentityRef cert_and_key = NULL; + bool is_cert_file = is_file(data->set.str[STRING_CERT]); + + /* User wants to authenticate with a client cert. Look for it: + If we detect that this is a file on disk, then let's load it. + Otherwise, assume that the user wants to use an identity loaded + from the Keychain. */ + if(is_cert_file) { + if(!data->set.str[STRING_CERT_TYPE]) + infof(data, "WARNING: SSL: Certificate type not set, assuming " + "PKCS#12 format.\n"); + else if(strncmp(data->set.str[STRING_CERT_TYPE], "P12", + strlen(data->set.str[STRING_CERT_TYPE])) != 0) + infof(data, "WARNING: SSL: The Security framework only supports " + "loading identities that are in PKCS#12 format.\n"); + + err = CopyIdentityFromPKCS12File(data->set.str[STRING_CERT], + data->set.str[STRING_KEY_PASSWD], &cert_and_key); + } + else + err = CopyIdentityWithLabel(data->set.str[STRING_CERT], &cert_and_key); + + if(err == noErr) { + SecCertificateRef cert = NULL; + CFTypeRef certs_c[1]; + CFArrayRef certs; + + /* If we found one, print it out: */ + err = SecIdentityCopyCertificate(cert_and_key, &cert); + if(err == noErr) { + CFStringRef cert_summary = CopyCertSubject(cert); + char cert_summary_c[128]; + + if(cert_summary) { + memset(cert_summary_c, 0, 128); + if(CFStringGetCString(cert_summary, + cert_summary_c, + 128, + kCFStringEncodingUTF8)) { + infof(data, "Client certificate: %s\n", cert_summary_c); + } + CFRelease(cert_summary); + CFRelease(cert); + } + } + certs_c[0] = cert_and_key; + certs = CFArrayCreate(NULL, (const void **)certs_c, 1L, + &kCFTypeArrayCallBacks); + err = SSLSetCertificate(connssl->ssl_ctx, certs); + if(certs) + CFRelease(certs); + if(err != noErr) { + failf(data, "SSL: SSLSetCertificate() failed: OSStatus %d", err); + return CURLE_SSL_CERTPROBLEM; + } + CFRelease(cert_and_key); + } + else { + switch(err) { + case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */ + failf(data, "SSL: Incorrect password for the certificate \"%s\" " + "and its private key.", data->set.str[STRING_CERT]); + break; + case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */ + failf(data, "SSL: Couldn't make sense of the data in the " + "certificate \"%s\" and its private key.", + data->set.str[STRING_CERT]); + break; + case -25260: /* errSecPassphraseRequired */ + failf(data, "SSL The certificate \"%s\" requires a password.", + data->set.str[STRING_CERT]); + break; + case errSecItemNotFound: + failf(data, "SSL: Can't find the certificate \"%s\" and its private " + "key in the Keychain.", data->set.str[STRING_CERT]); + break; + default: + failf(data, "SSL: Can't load the certificate \"%s\" and its private " + "key: OSStatus %d", data->set.str[STRING_CERT], err); + break; + } + return CURLE_SSL_CERTPROBLEM; + } + } + + /* SSL always tries to verify the peer, this only says whether it should + * fail to connect if the verification fails, or if it should continue + * anyway. In the latter case the result of the verification is checked with + * SSL_get_verify_result() below. */ +#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS + /* Snow Leopard introduced the SSLSetSessionOption() function, but due to + a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag + works, it doesn't work as expected under Snow Leopard or Lion. + So we need to call SSLSetEnableCertVerify() on those older cats in order + to disable certificate validation if the user turned that off. + (SecureTransport will always validate the certificate chain by + default.) */ + /* (Note: Darwin 12.x.x is Mountain Lion.) */ +#if CURL_BUILD_MAC + if(SSLSetSessionOption != NULL && darwinver_maj >= 12) { +#else + if(SSLSetSessionOption != NULL) { +#endif /* CURL_BUILD_MAC */ + bool break_on_auth = !data->set.ssl.verifypeer || + data->set.str[STRING_SSL_CAFILE]; + err = SSLSetSessionOption(connssl->ssl_ctx, + kSSLSessionOptionBreakOnServerAuth, + break_on_auth); + if(err != noErr) { + failf(data, "SSL: SSLSetSessionOption() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + } + else { +#if CURL_SUPPORT_MAC_10_8 + err = SSLSetEnableCertVerify(connssl->ssl_ctx, + data->set.ssl.verifypeer?true:false); + if(err != noErr) { + failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } +#endif /* CURL_SUPPORT_MAC_10_8 */ + } +#else + err = SSLSetEnableCertVerify(connssl->ssl_ctx, + data->set.ssl.verifypeer?true:false); + if(err != noErr) { + failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } +#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */ + + if(data->set.str[STRING_SSL_CAFILE]) { + bool is_cert_file = is_file(data->set.str[STRING_SSL_CAFILE]); + + if(!is_cert_file) { + failf(data, "SSL: can't load CA certificate file %s", + data->set.str[STRING_SSL_CAFILE]); + return CURLE_SSL_CACERT_BADFILE; + } + if(!data->set.ssl.verifypeer) { + failf(data, "SSL: CA certificate set, but certificate verification " + "is disabled"); + return CURLE_SSL_CONNECT_ERROR; + } + } + + /* Configure hostname check. SNI is used if available. + * Both hostname check and SNI require SSLSetPeerDomainName(). + * Also: the verifyhost setting influences SNI usage */ + if(data->set.ssl.verifyhost) { + err = SSLSetPeerDomainName(connssl->ssl_ctx, conn->host.name, + strlen(conn->host.name)); + + if(err != noErr) { + infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d\n", + err); + } + + if((Curl_inet_pton(AF_INET, conn->host.name, &addr)) + #ifdef ENABLE_IPV6 + || (Curl_inet_pton(AF_INET6, conn->host.name, &addr)) + #endif + ) { + infof(data, "WARNING: using IP address, SNI is being disabled by " + "the OS.\n"); + } + } + + /* Disable cipher suites that ST supports but are not safe. These ciphers + are unlikely to be used in any case since ST gives other ciphers a much + higher priority, but it's probably better that we not connect at all than + to give the user a false sense of security if the server only supports + insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */ + (void)SSLGetNumberSupportedCiphers(connssl->ssl_ctx, &all_ciphers_count); + all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite)); + allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite)); + if(all_ciphers && allowed_ciphers && + SSLGetSupportedCiphers(connssl->ssl_ctx, all_ciphers, + &all_ciphers_count) == noErr) { + for(i = 0UL ; i < all_ciphers_count ; i++) { +#if CURL_BUILD_MAC + /* There's a known bug in early versions of Mountain Lion where ST's ECC + ciphers (cipher suite 0xC001 through 0xC032) simply do not work. + Work around the problem here by disabling those ciphers if we are + running in an affected version of OS X. */ + if(darwinver_maj == 12 && darwinver_min <= 3 && + all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) { + continue; + } +#endif /* CURL_BUILD_MAC */ + switch(all_ciphers[i]) { + /* Disable NULL ciphersuites: */ + case SSL_NULL_WITH_NULL_NULL: + case SSL_RSA_WITH_NULL_MD5: + case SSL_RSA_WITH_NULL_SHA: + case 0x003B: /* TLS_RSA_WITH_NULL_SHA256 */ + case SSL_FORTEZZA_DMS_WITH_NULL_SHA: + case 0xC001: /* TLS_ECDH_ECDSA_WITH_NULL_SHA */ + case 0xC006: /* TLS_ECDHE_ECDSA_WITH_NULL_SHA */ + case 0xC00B: /* TLS_ECDH_RSA_WITH_NULL_SHA */ + case 0xC010: /* TLS_ECDHE_RSA_WITH_NULL_SHA */ + case 0x002C: /* TLS_PSK_WITH_NULL_SHA */ + case 0x002D: /* TLS_DHE_PSK_WITH_NULL_SHA */ + case 0x002E: /* TLS_RSA_PSK_WITH_NULL_SHA */ + case 0x00B0: /* TLS_PSK_WITH_NULL_SHA256 */ + case 0x00B1: /* TLS_PSK_WITH_NULL_SHA384 */ + case 0x00B4: /* TLS_DHE_PSK_WITH_NULL_SHA256 */ + case 0x00B5: /* TLS_DHE_PSK_WITH_NULL_SHA384 */ + case 0x00B8: /* TLS_RSA_PSK_WITH_NULL_SHA256 */ + case 0x00B9: /* TLS_RSA_PSK_WITH_NULL_SHA384 */ + /* Disable anonymous ciphersuites: */ + case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5: + case SSL_DH_anon_WITH_RC4_128_MD5: + case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA: + case SSL_DH_anon_WITH_DES_CBC_SHA: + case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA: + case TLS_DH_anon_WITH_AES_128_CBC_SHA: + case TLS_DH_anon_WITH_AES_256_CBC_SHA: + case 0xC015: /* TLS_ECDH_anon_WITH_NULL_SHA */ + case 0xC016: /* TLS_ECDH_anon_WITH_RC4_128_SHA */ + case 0xC017: /* TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA */ + case 0xC018: /* TLS_ECDH_anon_WITH_AES_128_CBC_SHA */ + case 0xC019: /* TLS_ECDH_anon_WITH_AES_256_CBC_SHA */ + case 0x006C: /* TLS_DH_anon_WITH_AES_128_CBC_SHA256 */ + case 0x006D: /* TLS_DH_anon_WITH_AES_256_CBC_SHA256 */ + case 0x00A6: /* TLS_DH_anon_WITH_AES_128_GCM_SHA256 */ + case 0x00A7: /* TLS_DH_anon_WITH_AES_256_GCM_SHA384 */ + /* Disable weak key ciphersuites: */ + case SSL_RSA_EXPORT_WITH_RC4_40_MD5: + case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5: + case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA: + case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: + case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: + case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: + case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: + case SSL_RSA_WITH_DES_CBC_SHA: + case SSL_DH_DSS_WITH_DES_CBC_SHA: + case SSL_DH_RSA_WITH_DES_CBC_SHA: + case SSL_DHE_DSS_WITH_DES_CBC_SHA: + case SSL_DHE_RSA_WITH_DES_CBC_SHA: + /* Disable IDEA: */ + case SSL_RSA_WITH_IDEA_CBC_SHA: + case SSL_RSA_WITH_IDEA_CBC_MD5: + break; + default: /* enable everything else */ + allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i]; + break; + } + } + err = SSLSetEnabledCiphers(connssl->ssl_ctx, allowed_ciphers, + allowed_ciphers_count); + if(err != noErr) { + failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + } + else { + Curl_safefree(all_ciphers); + Curl_safefree(allowed_ciphers); + failf(data, "SSL: Failed to allocate memory for allowed ciphers"); + return CURLE_OUT_OF_MEMORY; + } + Curl_safefree(all_ciphers); + Curl_safefree(allowed_ciphers); + +#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 + /* We want to enable 1/n-1 when using a CBC cipher unless the user + specifically doesn't want us doing that: */ + if(SSLSetSessionOption != NULL) { + SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionSendOneByteRecord, + !data->set.ssl_enable_beast); + SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionFalseStart, + data->set.ssl.falsestart); /* false start support */ + } +#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ + + /* Check if there's a cached ID we can/should use here! */ + if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid, + &ssl_sessionid_len)) { + /* we got a session id, use it! */ + err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len); + if(err != noErr) { + failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof(data, "SSL re-using session ID\n"); + } + /* If there isn't one, then let's make one up! This has to be done prior + to starting the handshake. */ + else { + CURLcode result; + ssl_sessionid = + aprintf("%s:%d:%d:%s:%hu", data->set.str[STRING_SSL_CAFILE], + data->set.ssl.verifypeer, data->set.ssl.verifyhost, + conn->host.name, conn->remote_port); + ssl_sessionid_len = strlen(ssl_sessionid); + + err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len); + if(err != noErr) { + failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + + result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len); + if(result) { + failf(data, "failed to store ssl session"); + return result; + } + } + + err = SSLSetIOFuncs(connssl->ssl_ctx, SocketRead, SocketWrite); + if(err != noErr) { + failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + + /* pass the raw socket into the SSL layers */ + /* We need to store the FD in a constant memory address, because + * SSLSetConnection() will not copy that address. I've found that + * conn->sock[sockindex] may change on its own. */ + connssl->ssl_sockfd = sockfd; + err = SSLSetConnection(connssl->ssl_ctx, connssl); + if(err != noErr) { + failf(data, "SSL: SSLSetConnection() failed: %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + + connssl->connecting_state = ssl_connect_2; + return CURLE_OK; +} + +static long pem_to_der(const char *in, unsigned char **out, size_t *outlen) +{ + char *sep_start, *sep_end, *cert_start, *cert_end; + size_t i, j, err; + size_t len; + unsigned char *b64; + + /* Jump through the separators at the beginning of the certificate. */ + sep_start = strstr(in, "-----"); + if(sep_start == NULL) + return 0; + cert_start = strstr(sep_start + 1, "-----"); + if(cert_start == NULL) + return -1; + + cert_start += 5; + + /* Find separator after the end of the certificate. */ + cert_end = strstr(cert_start, "-----"); + if(cert_end == NULL) + return -1; + + sep_end = strstr(cert_end + 1, "-----"); + if(sep_end == NULL) + return -1; + sep_end += 5; + + len = cert_end - cert_start; + b64 = malloc(len + 1); + if(!b64) + return -1; + + /* Create base64 string without linefeeds. */ + for(i = 0, j = 0; i < len; i++) { + if(cert_start[i] != '\r' && cert_start[i] != '\n') + b64[j++] = cert_start[i]; + } + b64[j] = '\0'; + + err = Curl_base64_decode((const char *)b64, out, outlen); + free(b64); + if(err) { + free(*out); + return -1; + } + + return sep_end - in; +} + +static int read_cert(const char *file, unsigned char **out, size_t *outlen) +{ + int fd; + ssize_t n, len = 0, cap = 512; + unsigned char buf[cap], *data; + + fd = open(file, 0); + if(fd < 0) + return -1; + + data = malloc(cap); + if(!data) { + close(fd); + return -1; + } + + for(;;) { + n = read(fd, buf, sizeof(buf)); + if(n < 0) { + close(fd); + free(data); + return -1; + } + else if(n == 0) { + close(fd); + break; + } + + if(len + n >= cap) { + cap *= 2; + data = realloc(data, cap); + if(!data) { + close(fd); + return -1; + } + } + + memcpy(data + len, buf, n); + len += n; + } + data[len] = '\0'; + + *out = data; + *outlen = len; + + return 0; +} + +static int sslerr_to_curlerr(struct SessionHandle *data, int err) +{ + switch(err) { + case errSSLXCertChainInvalid: + failf(data, "SSL certificate problem: Invalid certificate chain"); + return CURLE_SSL_CACERT; + case errSSLUnknownRootCert: + failf(data, "SSL certificate problem: Untrusted root certificate"); + return CURLE_SSL_CACERT; + case errSSLNoRootCert: + failf(data, "SSL certificate problem: No root certificate"); + return CURLE_SSL_CACERT; + case errSSLCertExpired: + failf(data, "SSL certificate problem: Certificate chain had an " + "expired certificate"); + return CURLE_SSL_CACERT; + case errSSLBadCert: + failf(data, "SSL certificate problem: Couldn't understand the server " + "certificate format"); + return CURLE_SSL_CONNECT_ERROR; + case errSSLHostNameMismatch: + failf(data, "SSL certificate peer hostname mismatch"); + return CURLE_PEER_FAILED_VERIFICATION; + default: + failf(data, "SSL unexpected certificate error %d", err); + return CURLE_SSL_CACERT; + } +} + +static int append_cert_to_array(struct SessionHandle *data, + unsigned char *buf, size_t buflen, + CFMutableArrayRef array) +{ + CFDataRef certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen); + if(!certdata) { + failf(data, "SSL: failed to allocate array for CA certificate"); + return CURLE_OUT_OF_MEMORY; + } + + SecCertificateRef cacert = + SecCertificateCreateWithData(kCFAllocatorDefault, certdata); + CFRelease(certdata); + if(!cacert) { + failf(data, "SSL: failed to create SecCertificate from CA certificate"); + return CURLE_SSL_CACERT; + } + + /* Check if cacert is valid. */ + CFStringRef subject = CopyCertSubject(cacert); + if(subject) { + char subject_cbuf[128]; + memset(subject_cbuf, 0, 128); + if(!CFStringGetCString(subject, + subject_cbuf, + 128, + kCFStringEncodingUTF8)) { + CFRelease(cacert); + failf(data, "SSL: invalid CA certificate subject"); + return CURLE_SSL_CACERT; + } + CFRelease(subject); + } + else { + CFRelease(cacert); + failf(data, "SSL: invalid CA certificate"); + return CURLE_SSL_CACERT; + } + + CFArrayAppendValue(array, cacert); + CFRelease(cacert); + + return CURLE_OK; +} + +static int verify_cert(const char *cafile, struct SessionHandle *data, + SSLContextRef ctx) +{ + int n = 0, rc; + long res; + unsigned char *certbuf, *der; + size_t buflen, derlen, offset = 0; + + if(read_cert(cafile, &certbuf, &buflen) < 0) { + failf(data, "SSL: failed to read or invalid CA certificate"); + return CURLE_SSL_CACERT; + } + + /* + * Certbuf now contains the contents of the certificate file, which can be + * - a single DER certificate, + * - a single PEM certificate or + * - a bunch of PEM certificates (certificate bundle). + * + * Go through certbuf, and convert any PEM certificate in it into DER + * format. + */ + CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeArrayCallBacks); + if(array == NULL) { + free(certbuf); + failf(data, "SSL: out of memory creating CA certificate array"); + return CURLE_OUT_OF_MEMORY; + } + + while(offset < buflen) { + n++; + + /* + * Check if the certificate is in PEM format, and convert it to DER. If + * this fails, we assume the certificate is in DER format. + */ + res = pem_to_der((const char *)certbuf + offset, &der, &derlen); + if(res < 0) { + free(certbuf); + CFRelease(array); + failf(data, "SSL: invalid CA certificate #%d (offset %d) in bundle", + n, offset); + return CURLE_SSL_CACERT; + } + offset += res; + + if(res == 0 && offset == 0) { + /* This is not a PEM file, probably a certificate in DER format. */ + rc = append_cert_to_array(data, certbuf, buflen, array); + free(certbuf); + if(rc != CURLE_OK) { + CFRelease(array); + return rc; + } + break; + } + else if(res == 0) { + /* No more certificates in the bundle. */ + free(certbuf); + break; + } + + rc = append_cert_to_array(data, der, derlen, array); + free(der); + if(rc != CURLE_OK) { + free(certbuf); + CFRelease(array); + return rc; + } + } + + SecTrustRef trust; + OSStatus ret = SSLCopyPeerTrust(ctx, &trust); + if(trust == NULL) { + failf(data, "SSL: error getting certificate chain"); + CFRelease(array); + return CURLE_OUT_OF_MEMORY; + } + else if(ret != noErr) { + CFRelease(array); + return sslerr_to_curlerr(data, ret); + } + + ret = SecTrustSetAnchorCertificates(trust, array); + if(ret != noErr) { + CFRelease(trust); + return sslerr_to_curlerr(data, ret); + } + ret = SecTrustSetAnchorCertificatesOnly(trust, true); + if(ret != noErr) { + CFRelease(trust); + return sslerr_to_curlerr(data, ret); + } + + SecTrustResultType trust_eval = 0; + ret = SecTrustEvaluate(trust, &trust_eval); + CFRelease(array); + CFRelease(trust); + if(ret != noErr) { + return sslerr_to_curlerr(data, ret); + } + + switch (trust_eval) { + case kSecTrustResultUnspecified: + case kSecTrustResultProceed: + return CURLE_OK; + + case kSecTrustResultRecoverableTrustFailure: + case kSecTrustResultDeny: + default: + failf(data, "SSL: certificate verification failed (result: %d)", + trust_eval); + return CURLE_PEER_FAILED_VERIFICATION; + } +} + +static CURLcode +darwinssl_connect_step2(struct connectdata *conn, int sockindex) +{ + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + OSStatus err; + SSLCipherSuite cipher; + SSLProtocol protocol = 0; + + DEBUGASSERT(ssl_connect_2 == connssl->connecting_state + || ssl_connect_2_reading == connssl->connecting_state + || ssl_connect_2_writing == connssl->connecting_state); + + /* Here goes nothing: */ + err = SSLHandshake(connssl->ssl_ctx); + + if(err != noErr) { + switch (err) { + case errSSLWouldBlock: /* they're not done with us yet */ + connssl->connecting_state = connssl->ssl_direction ? + ssl_connect_2_writing : ssl_connect_2_reading; + return CURLE_OK; + + /* The below is errSSLServerAuthCompleted; it's not defined in + Leopard's headers */ + case -9841: + if(data->set.str[STRING_SSL_CAFILE]) { + int res = verify_cert(data->set.str[STRING_SSL_CAFILE], data, + connssl->ssl_ctx); + if(res != CURLE_OK) + return res; + } + /* the documentation says we need to call SSLHandshake() again */ + return darwinssl_connect_step2(conn, sockindex); + + /* These are all certificate problems with the server: */ + case errSSLXCertChainInvalid: + failf(data, "SSL certificate problem: Invalid certificate chain"); + return CURLE_SSL_CACERT; + case errSSLUnknownRootCert: + failf(data, "SSL certificate problem: Untrusted root certificate"); + return CURLE_SSL_CACERT; + case errSSLNoRootCert: + failf(data, "SSL certificate problem: No root certificate"); + return CURLE_SSL_CACERT; + case errSSLCertExpired: + failf(data, "SSL certificate problem: Certificate chain had an " + "expired certificate"); + return CURLE_SSL_CACERT; + case errSSLBadCert: + failf(data, "SSL certificate problem: Couldn't understand the server " + "certificate format"); + return CURLE_SSL_CONNECT_ERROR; + + /* These are all certificate problems with the client: */ + case errSecAuthFailed: + failf(data, "SSL authentication failed"); + return CURLE_SSL_CONNECT_ERROR; + case errSSLPeerHandshakeFail: + failf(data, "SSL peer handshake failed, the server most likely " + "requires a client certificate to connect"); + return CURLE_SSL_CONNECT_ERROR; + case errSSLPeerUnknownCA: + failf(data, "SSL server rejected the client certificate due to " + "the certificate being signed by an unknown certificate " + "authority"); + return CURLE_SSL_CONNECT_ERROR; + + /* This error is raised if the server's cert didn't match the server's + host name: */ + case errSSLHostNameMismatch: + failf(data, "SSL certificate peer verification failed, the " + "certificate did not match \"%s\"\n", conn->host.dispname); + return CURLE_PEER_FAILED_VERIFICATION; + + /* Generic handshake errors: */ + case errSSLConnectionRefused: + failf(data, "Server dropped the connection during the SSL handshake"); + return CURLE_SSL_CONNECT_ERROR; + case errSSLClosedAbort: + failf(data, "Server aborted the SSL handshake"); + return CURLE_SSL_CONNECT_ERROR; + case errSSLNegotiation: + failf(data, "Could not negotiate an SSL cipher suite with the server"); + return CURLE_SSL_CONNECT_ERROR; + /* Sometimes paramErr happens with buggy ciphers: */ + case paramErr: case errSSLInternal: + failf(data, "Internal SSL engine error encountered during the " + "SSL handshake"); + return CURLE_SSL_CONNECT_ERROR; + case errSSLFatalAlert: + failf(data, "Fatal SSL engine error encountered during the SSL " + "handshake"); + return CURLE_SSL_CONNECT_ERROR; + default: + failf(data, "Unknown SSL protocol error in connection to %s:%d", + conn->host.name, err); + return CURLE_SSL_CONNECT_ERROR; + } + } + else { + /* we have been connected fine, we're not waiting for anything else. */ + connssl->connecting_state = ssl_connect_3; + + /* Informational message */ + (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher); + (void)SSLGetNegotiatedProtocolVersion(connssl->ssl_ctx, &protocol); + switch (protocol) { + case kSSLProtocol2: + infof(data, "SSL 2.0 connection using %s\n", + SSLCipherNameForNumber(cipher)); + break; + case kSSLProtocol3: + infof(data, "SSL 3.0 connection using %s\n", + SSLCipherNameForNumber(cipher)); + break; + case kTLSProtocol1: + infof(data, "TLS 1.0 connection using %s\n", + TLSCipherNameForNumber(cipher)); + break; +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS + case kTLSProtocol11: + infof(data, "TLS 1.1 connection using %s\n", + TLSCipherNameForNumber(cipher)); + break; + case kTLSProtocol12: + infof(data, "TLS 1.2 connection using %s\n", + TLSCipherNameForNumber(cipher)); + break; +#endif + default: + infof(data, "Unknown protocol connection\n"); + break; + } + + return CURLE_OK; + } +} + +static CURLcode +darwinssl_connect_step3(struct connectdata *conn, + int sockindex) +{ + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + CFStringRef server_cert_summary; + char server_cert_summary_c[128]; + CFArrayRef server_certs = NULL; + SecCertificateRef server_cert; + OSStatus err; + CFIndex i, count; + SecTrustRef trust = NULL; + + /* There is no step 3! + * Well, okay, if verbose mode is on, let's print the details of the + * server certificates. */ +#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS +#if CURL_BUILD_IOS +#pragma unused(server_certs) + err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust); + /* For some reason, SSLCopyPeerTrust() can return noErr and yet return + a null trust, so be on guard for that: */ + if(err == noErr && trust) { + count = SecTrustGetCertificateCount(trust); + for(i = 0L ; i < count ; i++) { + server_cert = SecTrustGetCertificateAtIndex(trust, i); + server_cert_summary = CopyCertSubject(server_cert); + memset(server_cert_summary_c, 0, 128); + if(CFStringGetCString(server_cert_summary, + server_cert_summary_c, + 128, + kCFStringEncodingUTF8)) { + infof(data, "Server certificate: %s\n", server_cert_summary_c); + } + CFRelease(server_cert_summary); + } + CFRelease(trust); + } +#else + /* SSLCopyPeerCertificates() is deprecated as of Mountain Lion. + The function SecTrustGetCertificateAtIndex() is officially present + in Lion, but it is unfortunately also present in Snow Leopard as + private API and doesn't work as expected. So we have to look for + a different symbol to make sure this code is only executed under + Lion or later. */ + if(SecTrustEvaluateAsync != NULL) { +#pragma unused(server_certs) + err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust); + /* For some reason, SSLCopyPeerTrust() can return noErr and yet return + a null trust, so be on guard for that: */ + if(err == noErr && trust) { + count = SecTrustGetCertificateCount(trust); + for(i = 0L ; i < count ; i++) { + server_cert = SecTrustGetCertificateAtIndex(trust, i); + server_cert_summary = CopyCertSubject(server_cert); + memset(server_cert_summary_c, 0, 128); + if(CFStringGetCString(server_cert_summary, + server_cert_summary_c, + 128, + kCFStringEncodingUTF8)) { + infof(data, "Server certificate: %s\n", server_cert_summary_c); + } + CFRelease(server_cert_summary); + } + CFRelease(trust); + } + } + else { +#if CURL_SUPPORT_MAC_10_8 + err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs); + /* Just in case SSLCopyPeerCertificates() returns null too... */ + if(err == noErr && server_certs) { + count = CFArrayGetCount(server_certs); + for(i = 0L ; i < count ; i++) { + server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, + i); + + server_cert_summary = CopyCertSubject(server_cert); + memset(server_cert_summary_c, 0, 128); + if(CFStringGetCString(server_cert_summary, + server_cert_summary_c, + 128, + kCFStringEncodingUTF8)) { + infof(data, "Server certificate: %s\n", server_cert_summary_c); + } + CFRelease(server_cert_summary); + } + CFRelease(server_certs); + } +#endif /* CURL_SUPPORT_MAC_10_8 */ + } +#endif /* CURL_BUILD_IOS */ +#else +#pragma unused(trust) + err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs); + if(err == noErr) { + count = CFArrayGetCount(server_certs); + for(i = 0L ; i < count ; i++) { + server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i); + server_cert_summary = CopyCertSubject(server_cert); + memset(server_cert_summary_c, 0, 128); + if(CFStringGetCString(server_cert_summary, + server_cert_summary_c, + 128, + kCFStringEncodingUTF8)) { + infof(data, "Server certificate: %s\n", server_cert_summary_c); + } + CFRelease(server_cert_summary); + } + CFRelease(server_certs); + } +#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ + + connssl->connecting_state = ssl_connect_done; + return CURLE_OK; +} + +static Curl_recv darwinssl_recv; +static Curl_send darwinssl_send; + +static CURLcode +darwinssl_connect_common(struct connectdata *conn, + int sockindex, + bool nonblocking, + bool *done) +{ + CURLcode result; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + curl_socket_t sockfd = conn->sock[sockindex]; + long timeout_ms; + int what; + + /* check if the connection has already been established */ + if(ssl_connection_complete == connssl->state) { + *done = TRUE; + return CURLE_OK; + } + + if(ssl_connect_1==connssl->connecting_state) { + /* Find out how much more time we're allowed */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + result = darwinssl_connect_step1(conn, sockindex); + if(result) + return result; + } + + while(ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state) { + + /* check allowed time left */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + /* if ssl is expecting something, check if it's available. */ + if(connssl->connecting_state == ssl_connect_2_reading || + connssl->connecting_state == ssl_connect_2_writing) { + + curl_socket_t writefd = ssl_connect_2_writing == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + + what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + return CURLE_SSL_CONNECT_ERROR; + } + else if(0 == what) { + if(nonblocking) { + *done = FALSE; + return CURLE_OK; + } + else { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + } + /* socket is readable or writable */ + } + + /* Run transaction, and return to the caller if it failed or if this + * connection is done nonblocking and this loop would execute again. This + * permits the owner of a multi handle to abort a connection attempt + * before step2 has completed while ensuring that a client using select() + * or epoll() will always have a valid fdset to wait on. + */ + result = darwinssl_connect_step2(conn, sockindex); + if(result || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return result; + + } /* repeat step2 until all transactions are done. */ + + + if(ssl_connect_3 == connssl->connecting_state) { + result = darwinssl_connect_step3(conn, sockindex); + if(result) + return result; + } + + if(ssl_connect_done == connssl->connecting_state) { + connssl->state = ssl_connection_complete; + conn->recv[sockindex] = darwinssl_recv; + conn->send[sockindex] = darwinssl_send; + *done = TRUE; + } + else + *done = FALSE; + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + + return CURLE_OK; +} + +CURLcode +Curl_darwinssl_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done) +{ + return darwinssl_connect_common(conn, sockindex, TRUE, done); +} + +CURLcode +Curl_darwinssl_connect(struct connectdata *conn, + int sockindex) +{ + CURLcode result; + bool done = FALSE; + + result = darwinssl_connect_common(conn, sockindex, FALSE, &done); + + if(result) + return result; + + DEBUGASSERT(done); + + return CURLE_OK; +} + +void Curl_darwinssl_close(struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + if(connssl->ssl_ctx) { + (void)SSLClose(connssl->ssl_ctx); +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS + if(SSLCreateContext != NULL) + CFRelease(connssl->ssl_ctx); +#if CURL_SUPPORT_MAC_10_8 + else + (void)SSLDisposeContext(connssl->ssl_ctx); +#endif /* CURL_SUPPORT_MAC_10_8 */ +#else + (void)SSLDisposeContext(connssl->ssl_ctx); +#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ + connssl->ssl_ctx = NULL; + } + connssl->ssl_sockfd = 0; +} + +int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct SessionHandle *data = conn->data; + ssize_t nread; + int what; + int rc; + char buf[120]; + + if(!connssl->ssl_ctx) + return 0; + + if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) + return 0; + + Curl_darwinssl_close(conn, sockindex); + + rc = 0; + + what = Curl_socket_ready(conn->sock[sockindex], + CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + + for(;;) { + if(what < 0) { + /* anything that gets here is fatally bad */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + rc = -1; + break; + } + + if(!what) { /* timeout */ + failf(data, "SSL shutdown timeout"); + break; + } + + /* Something to read, let's do it and hope that it is the close + notify alert from the server. No way to SSL_Read now, so use read(). */ + + nread = read(conn->sock[sockindex], buf, sizeof(buf)); + + if(nread < 0) { + failf(data, "read: %s", strerror(errno)); + rc = -1; + } + + if(nread <= 0) + break; + + what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0); + } + + return rc; +} + +void Curl_darwinssl_session_free(void *ptr) +{ + /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a + cached session ID inside the Security framework. There is a private + function that does this, but I don't want to have to explain to you why I + got your application rejected from the App Store due to the use of a + private API, so the best we can do is free up our own char array that we + created way back in darwinssl_connect_step1... */ + Curl_safefree(ptr); +} + +size_t Curl_darwinssl_version(char *buffer, size_t size) +{ + return snprintf(buffer, size, "SecureTransport"); +} + +/* + * This function uses SSLGetSessionState to determine connection status. + * + * Return codes: + * 1 means the connection is still in place + * 0 means the connection has been closed + * -1 means the connection status is unknown + */ +int Curl_darwinssl_check_cxn(struct connectdata *conn) +{ + struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; + OSStatus err; + SSLSessionState state; + + if(connssl->ssl_ctx) { + err = SSLGetSessionState(connssl->ssl_ctx, &state); + if(err == noErr) + return state == kSSLConnected || state == kSSLHandshake; + return -1; + } + return 0; +} + +bool Curl_darwinssl_data_pending(const struct connectdata *conn, + int connindex) +{ + const struct ssl_connect_data *connssl = &conn->ssl[connindex]; + OSStatus err; + size_t buffer; + + if(connssl->ssl_ctx) { /* SSL is in use */ + err = SSLGetBufferedReadSize(connssl->ssl_ctx, &buffer); + if(err == noErr) + return buffer > 0UL; + return false; + } + else + return false; +} + +int Curl_darwinssl_random(unsigned char *entropy, + size_t length) +{ + /* arc4random_buf() isn't available on cats older than Lion, so let's + do this manually for the benefit of the older cats. */ + size_t i; + u_int32_t random_number = 0; + + for(i = 0 ; i < length ; i++) { + if(i % sizeof(u_int32_t) == 0) + random_number = arc4random(); + entropy[i] = random_number & 0xFF; + random_number >>= 8; + } + i = random_number = 0; + return 0; +} + +void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum, /* output */ + size_t md5len) +{ + (void)md5len; + (void)CC_MD5(tmp, (CC_LONG)tmplen, md5sum); +} + +bool Curl_darwinssl_false_start(void) { +#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 + if(SSLSetSessionOption != NULL) + return TRUE; +#endif + return FALSE; +} + +static ssize_t darwinssl_send(struct connectdata *conn, + int sockindex, + const void *mem, + size_t len, + CURLcode *curlcode) +{ + /*struct SessionHandle *data = conn->data;*/ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + size_t processed = 0UL; + OSStatus err; + + /* The SSLWrite() function works a little differently than expected. The + fourth argument (processed) is currently documented in Apple's + documentation as: "On return, the length, in bytes, of the data actually + written." + + Now, one could interpret that as "written to the socket," but actually, + it returns the amount of data that was written to a buffer internal to + the SSLContextRef instead. So it's possible for SSLWrite() to return + errSSLWouldBlock and a number of bytes "written" because those bytes were + encrypted and written to a buffer, not to the socket. + + So if this happens, then we need to keep calling SSLWrite() over and + over again with no new data until it quits returning errSSLWouldBlock. */ + + /* Do we have buffered data to write from the last time we were called? */ + if(connssl->ssl_write_buffered_length) { + /* Write the buffered data: */ + err = SSLWrite(connssl->ssl_ctx, NULL, 0UL, &processed); + switch (err) { + case noErr: + /* processed is always going to be 0 because we didn't write to + the buffer, so return how much was written to the socket */ + processed = connssl->ssl_write_buffered_length; + connssl->ssl_write_buffered_length = 0UL; + break; + case errSSLWouldBlock: /* argh, try again */ + *curlcode = CURLE_AGAIN; + return -1L; + default: + failf(conn->data, "SSLWrite() returned error %d", err); + *curlcode = CURLE_SEND_ERROR; + return -1L; + } + } + else { + /* We've got new data to write: */ + err = SSLWrite(connssl->ssl_ctx, mem, len, &processed); + if(err != noErr) { + switch (err) { + case errSSLWouldBlock: + /* Data was buffered but not sent, we have to tell the caller + to try sending again, and remember how much was buffered */ + connssl->ssl_write_buffered_length = len; + *curlcode = CURLE_AGAIN; + return -1L; + default: + failf(conn->data, "SSLWrite() returned error %d", err); + *curlcode = CURLE_SEND_ERROR; + return -1L; + } + } + } + return (ssize_t)processed; +} + +static ssize_t darwinssl_recv(struct connectdata *conn, + int num, + char *buf, + size_t buffersize, + CURLcode *curlcode) +{ + /*struct SessionHandle *data = conn->data;*/ + struct ssl_connect_data *connssl = &conn->ssl[num]; + size_t processed = 0UL; + OSStatus err = SSLRead(connssl->ssl_ctx, buf, buffersize, &processed); + + if(err != noErr) { + switch (err) { + case errSSLWouldBlock: /* return how much we read (if anything) */ + if(processed) + return (ssize_t)processed; + *curlcode = CURLE_AGAIN; + return -1L; + break; + + /* errSSLClosedGraceful - server gracefully shut down the SSL session + errSSLClosedNoNotify - server hung up on us instead of sending a + closure alert notice, read() is returning 0 + Either way, inform the caller that the server disconnected. */ + case errSSLClosedGraceful: + case errSSLClosedNoNotify: + *curlcode = CURLE_OK; + return -1L; + break; + + default: + failf(conn->data, "SSLRead() return error %d", err); + *curlcode = CURLE_RECV_ERROR; + return -1L; + break; + } + } + return (ssize_t)processed; +} + +#endif /* USE_DARWINSSL */ diff --git a/project/jni/curl/lib/vtls/darwinssl.h b/project/jni/curl/lib/vtls/darwinssl.h new file mode 100644 index 000000000..8b185b67f --- /dev/null +++ b/project/jni/curl/lib/vtls/darwinssl.h @@ -0,0 +1,76 @@ +#ifndef HEADER_CURL_DARWINSSL_H +#define HEADER_CURL_DARWINSSL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2012 - 2014, Nick Zitzmann, . + * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_DARWINSSL + +CURLcode Curl_darwinssl_connect(struct connectdata *conn, int sockindex); + +CURLcode Curl_darwinssl_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done); + +/* close a SSL connection */ +void Curl_darwinssl_close(struct connectdata *conn, int sockindex); + +void Curl_darwinssl_session_free(void *ptr); +size_t Curl_darwinssl_version(char *buffer, size_t size); +int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex); +int Curl_darwinssl_check_cxn(struct connectdata *conn); +bool Curl_darwinssl_data_pending(const struct connectdata *conn, + int connindex); + +int Curl_darwinssl_random(unsigned char *entropy, + size_t length); +void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum, /* output */ + size_t md5len); +bool Curl_darwinssl_false_start(void); + +/* Set the API backend definition to SecureTransport */ +#define CURL_SSL_BACKEND CURLSSLBACKEND_DARWINSSL + +/* API setup for SecureTransport */ +#define curlssl_init() (1) +#define curlssl_cleanup() Curl_nop_stmt +#define curlssl_connect Curl_darwinssl_connect +#define curlssl_connect_nonblocking Curl_darwinssl_connect_nonblocking +#define curlssl_session_free(x) Curl_darwinssl_session_free(x) +#define curlssl_close_all(x) ((void)x) +#define curlssl_close Curl_darwinssl_close +#define curlssl_shutdown(x,y) 0 +#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN) +#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN) +#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) +#define curlssl_version Curl_darwinssl_version +#define curlssl_check_cxn Curl_darwinssl_check_cxn +#define curlssl_data_pending(x,y) Curl_darwinssl_data_pending(x, y) +#define curlssl_random(x,y,z) ((void)x, Curl_darwinssl_random(y,z)) +#define curlssl_md5sum(a,b,c,d) Curl_darwinssl_md5sum(a,b,c,d) +#define curlssl_false_start() Curl_darwinssl_false_start() + +#endif /* USE_DARWINSSL */ +#endif /* HEADER_CURL_DARWINSSL_H */ diff --git a/project/jni/curl/lib/vtls/gskit.c b/project/jni/curl/lib/vtls/gskit.c new file mode 100644 index 000000000..a9a8a9186 --- /dev/null +++ b/project/jni/curl/lib/vtls/gskit.c @@ -0,0 +1,1069 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_GSKIT + +#include +#include + +/* Some symbols are undefined/unsupported on OS400 versions < V7R1. */ +#ifndef GSK_SSL_EXTN_SERVERNAME_REQUEST +#define GSK_SSL_EXTN_SERVERNAME_REQUEST 230 +#endif + +#ifndef GSK_TLSV10_CIPHER_SPECS +#define GSK_TLSV10_CIPHER_SPECS 236 +#endif + +#ifndef GSK_TLSV11_CIPHER_SPECS +#define GSK_TLSV11_CIPHER_SPECS 237 +#endif + +#ifndef GSK_TLSV12_CIPHER_SPECS +#define GSK_TLSV12_CIPHER_SPECS 238 +#endif + +#ifndef GSK_PROTOCOL_TLSV11 +#define GSK_PROTOCOL_TLSV11 437 +#endif + +#ifndef GSK_PROTOCOL_TLSV12 +#define GSK_PROTOCOL_TLSV12 438 +#endif + +#ifndef GSK_FALSE +#define GSK_FALSE 0 +#endif + +#ifndef GSK_TRUE +#define GSK_TRUE 1 +#endif + + +#ifdef HAVE_LIMITS_H +# include +#endif + +#include +#include "urldata.h" +#include "sendf.h" +#include "gskit.h" +#include "vtls.h" +#include "connect.h" /* for the connect timeout */ +#include "select.h" +#include "strequal.h" +#include "x509asn1.h" +#include "curl_printf.h" + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + + +/* SSL version flags. */ +#define CURL_GSKPROTO_SSLV2 0 +#define CURL_GSKPROTO_SSLV2_MASK (1 << CURL_GSKPROTO_SSLV2) +#define CURL_GSKPROTO_SSLV3 1 +#define CURL_GSKPROTO_SSLV3_MASK (1 << CURL_GSKPROTO_SSLV3) +#define CURL_GSKPROTO_TLSV10 2 +#define CURL_GSKPROTO_TLSV10_MASK (1 << CURL_GSKPROTO_TLSV10) +#define CURL_GSKPROTO_TLSV11 3 +#define CURL_GSKPROTO_TLSV11_MASK (1 << CURL_GSKPROTO_TLSV11) +#define CURL_GSKPROTO_TLSV12 4 +#define CURL_GSKPROTO_TLSV12_MASK (1 << CURL_GSKPROTO_TLSV12) +#define CURL_GSKPROTO_LAST 5 + + +/* Supported ciphers. */ +typedef struct { + const char *name; /* Cipher name. */ + const char *gsktoken; /* Corresponding token for GSKit String. */ + unsigned int versions; /* SSL version flags. */ +} gskit_cipher; + +static const gskit_cipher ciphertable[] = { + { "null-md5", "01", + CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | + CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, + { "null-sha", "02", + CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | + CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, + { "exp-rc4-md5", "03", + CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK }, + { "rc4-md5", "04", + CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | + CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, + { "rc4-sha", "05", + CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | + CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, + { "exp-rc2-cbc-md5", "06", + CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK }, + { "exp-des-cbc-sha", "09", + CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | + CURL_GSKPROTO_TLSV11_MASK }, + { "des-cbc3-sha", "0A", + CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | + CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, + { "aes128-sha", "2F", + CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | + CURL_GSKPROTO_TLSV12_MASK }, + { "aes256-sha", "35", + CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | + CURL_GSKPROTO_TLSV12_MASK }, + { "null-sha256", "3B", CURL_GSKPROTO_TLSV12_MASK }, + { "aes128-sha256", "3C", CURL_GSKPROTO_TLSV12_MASK }, + { "aes256-sha256", "3D", CURL_GSKPROTO_TLSV12_MASK }, + { "aes128-gcm-sha256", + "9C", CURL_GSKPROTO_TLSV12_MASK }, + { "aes256-gcm-sha384", + "9D", CURL_GSKPROTO_TLSV12_MASK }, + { "rc4-md5", "1", CURL_GSKPROTO_SSLV2_MASK }, + { "exp-rc4-md5", "2", CURL_GSKPROTO_SSLV2_MASK }, + { "rc2-md5", "3", CURL_GSKPROTO_SSLV2_MASK }, + { "exp-rc2-md5", "4", CURL_GSKPROTO_SSLV2_MASK }, + { "des-cbc-md5", "6", CURL_GSKPROTO_SSLV2_MASK }, + { "des-cbc3-md5", "7", CURL_GSKPROTO_SSLV2_MASK }, + { (const char *) NULL, (const char *) NULL, 0 } +}; + + +static bool is_separator(char c) +{ + /* Return whether character is a cipher list separator. */ + switch (c) { + case ' ': + case '\t': + case ':': + case ',': + case ';': + return true; + } + return false; +} + + +static CURLcode gskit_status(struct SessionHandle *data, int rc, + const char *procname, CURLcode defcode) +{ + /* Process GSKit status and map it to a CURLcode. */ + switch (rc) { + case GSK_OK: + case GSK_OS400_ASYNCHRONOUS_SOC_INIT: + return CURLE_OK; + case GSK_KEYRING_OPEN_ERROR: + case GSK_OS400_ERROR_NO_ACCESS: + return CURLE_SSL_CACERT_BADFILE; + case GSK_INSUFFICIENT_STORAGE: + return CURLE_OUT_OF_MEMORY; + case GSK_ERROR_BAD_V2_CIPHER: + case GSK_ERROR_BAD_V3_CIPHER: + case GSK_ERROR_NO_CIPHERS: + return CURLE_SSL_CIPHER; + case GSK_OS400_ERROR_NOT_TRUSTED_ROOT: + case GSK_ERROR_CERT_VALIDATION: + return CURLE_PEER_FAILED_VERIFICATION; + case GSK_OS400_ERROR_TIMED_OUT: + return CURLE_OPERATION_TIMEDOUT; + case GSK_WOULD_BLOCK: + return CURLE_AGAIN; + case GSK_OS400_ERROR_NOT_REGISTERED: + break; + case GSK_ERROR_IO: + switch (errno) { + case ENOMEM: + return CURLE_OUT_OF_MEMORY; + default: + failf(data, "%s I/O error: %s", procname, strerror(errno)); + break; + } + break; + default: + failf(data, "%s: %s", procname, gsk_strerror(rc)); + break; + } + return defcode; +} + + +static CURLcode set_enum(struct SessionHandle *data, gsk_handle h, + GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok) +{ + int rc = gsk_attribute_set_enum(h, id, value); + + switch (rc) { + case GSK_OK: + return CURLE_OK; + case GSK_ERROR_IO: + failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno)); + break; + case GSK_ATTRIBUTE_INVALID_ID: + if(unsupported_ok) + return CURLE_UNSUPPORTED_PROTOCOL; + default: + failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc)); + break; + } + return CURLE_SSL_CONNECT_ERROR; +} + + +static CURLcode set_buffer(struct SessionHandle *data, gsk_handle h, + GSK_BUF_ID id, const char *buffer, bool unsupported_ok) +{ + int rc = gsk_attribute_set_buffer(h, id, buffer, 0); + + switch (rc) { + case GSK_OK: + return CURLE_OK; + case GSK_ERROR_IO: + failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno)); + break; + case GSK_ATTRIBUTE_INVALID_ID: + if(unsupported_ok) + return CURLE_UNSUPPORTED_PROTOCOL; + default: + failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc)); + break; + } + return CURLE_SSL_CONNECT_ERROR; +} + + +static CURLcode set_numeric(struct SessionHandle *data, + gsk_handle h, GSK_NUM_ID id, int value) +{ + int rc = gsk_attribute_set_numeric_value(h, id, value); + + switch (rc) { + case GSK_OK: + return CURLE_OK; + case GSK_ERROR_IO: + failf(data, "gsk_attribute_set_numeric_value() I/O error: %s", + strerror(errno)); + break; + default: + failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc)); + break; + } + return CURLE_SSL_CONNECT_ERROR; +} + + +static CURLcode set_callback(struct SessionHandle *data, + gsk_handle h, GSK_CALLBACK_ID id, void *info) +{ + int rc = gsk_attribute_set_callback(h, id, info); + + switch (rc) { + case GSK_OK: + return CURLE_OK; + case GSK_ERROR_IO: + failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno)); + break; + default: + failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc)); + break; + } + return CURLE_SSL_CONNECT_ERROR; +} + + +static CURLcode set_ciphers(struct SessionHandle *data, + gsk_handle h, unsigned int *protoflags) +{ + const char *cipherlist = data->set.str[STRING_SSL_CIPHER_LIST]; + const char *clp; + const gskit_cipher *ctp; + int i; + int l; + bool unsupported; + CURLcode result; + struct { + char *buf; + char *ptr; + } ciphers[CURL_GSKPROTO_LAST]; + + /* Compile cipher list into GSKit-compatible cipher lists. */ + + if(!cipherlist) + return CURLE_OK; + while(is_separator(*cipherlist)) /* Skip initial separators. */ + cipherlist++; + if(!*cipherlist) + return CURLE_OK; + + /* We allocate GSKit buffers of the same size as the input string: since + GSKit tokens are always shorter than their cipher names, allocated buffers + will always be large enough to accomodate the result. */ + l = strlen(cipherlist) + 1; + memset((char *) ciphers, 0, sizeof ciphers); + for(i = 0; i < CURL_GSKPROTO_LAST; i++) { + ciphers[i].buf = malloc(l); + if(!ciphers[i].buf) { + while(i--) + free(ciphers[i].buf); + return CURLE_OUT_OF_MEMORY; + } + ciphers[i].ptr = ciphers[i].buf; + *ciphers[i].ptr = '\0'; + } + + /* Process each cipher in input string. */ + unsupported = FALSE; + result = CURLE_OK; + for(;;) { + for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);) + cipherlist++; + l = cipherlist - clp; + if(!l) + break; + /* Search the cipher in our table. */ + for(ctp = ciphertable; ctp->name; ctp++) + if(strnequal(ctp->name, clp, l) && !ctp->name[l]) + break; + if(!ctp->name) { + failf(data, "Unknown cipher %.*s", l, clp); + result = CURLE_SSL_CIPHER; + } + else { + unsupported |= !(ctp->versions & (CURL_GSKPROTO_SSLV2_MASK | + CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK)); + for(i = 0; i < CURL_GSKPROTO_LAST; i++) { + if(ctp->versions & (1 << i)) { + strcpy(ciphers[i].ptr, ctp->gsktoken); + ciphers[i].ptr += strlen(ctp->gsktoken); + } + } + } + + /* Advance to next cipher name or end of string. */ + while(is_separator(*cipherlist)) + cipherlist++; + } + + /* Disable protocols with empty cipher lists. */ + for(i = 0; i < CURL_GSKPROTO_LAST; i++) { + if(!(*protoflags & (1 << i)) || !ciphers[i].buf[0]) { + *protoflags &= ~(1 << i); + ciphers[i].buf[0] = '\0'; + } + } + + /* Try to set-up TLSv1.1 and TLSv2.1 ciphers. */ + if(*protoflags & CURL_GSKPROTO_TLSV11_MASK) { + result = set_buffer(data, h, GSK_TLSV11_CIPHER_SPECS, + ciphers[CURL_GSKPROTO_TLSV11].buf, TRUE); + if(result == CURLE_UNSUPPORTED_PROTOCOL) { + result = CURLE_OK; + if(unsupported) { + failf(data, "TLSv1.1-only ciphers are not yet supported"); + result = CURLE_SSL_CIPHER; + } + } + } + if(!result && (*protoflags & CURL_GSKPROTO_TLSV12_MASK)) { + result = set_buffer(data, h, GSK_TLSV12_CIPHER_SPECS, + ciphers[CURL_GSKPROTO_TLSV12].buf, TRUE); + if(result == CURLE_UNSUPPORTED_PROTOCOL) { + result = CURLE_OK; + if(unsupported) { + failf(data, "TLSv1.2-only ciphers are not yet supported"); + result = CURLE_SSL_CIPHER; + } + } + } + + /* Try to set-up TLSv1.0 ciphers. If not successful, concatenate them to + the SSLv3 ciphers. OS/400 prior to version 7.1 will understand it. */ + if(!result && (*protoflags & CURL_GSKPROTO_TLSV10_MASK)) { + result = set_buffer(data, h, GSK_TLSV10_CIPHER_SPECS, + ciphers[CURL_GSKPROTO_TLSV10].buf, TRUE); + if(result == CURLE_UNSUPPORTED_PROTOCOL) { + result = CURLE_OK; + strcpy(ciphers[CURL_GSKPROTO_SSLV3].ptr, + ciphers[CURL_GSKPROTO_TLSV10].ptr); + } + } + + /* Set-up other ciphers. */ + if(!result && (*protoflags & CURL_GSKPROTO_SSLV3_MASK)) + result = set_buffer(data, h, GSK_V3_CIPHER_SPECS, + ciphers[CURL_GSKPROTO_SSLV3].buf, FALSE); + if(!result && (*protoflags & CURL_GSKPROTO_SSLV2_MASK)) + result = set_buffer(data, h, GSK_V2_CIPHER_SPECS, + ciphers[CURL_GSKPROTO_SSLV2].buf, FALSE); + + /* Clean-up. */ + for(i = 0; i < CURL_GSKPROTO_LAST; i++) + free(ciphers[i].buf); + + return result; +} + + +int Curl_gskit_init(void) +{ + /* No initialisation needed. */ + + return 1; +} + + +void Curl_gskit_cleanup(void) +{ + /* Nothing to do. */ +} + + +static CURLcode init_environment(struct SessionHandle *data, + gsk_handle *envir, const char *appid, + const char *file, const char *label, + const char *password) +{ + int rc; + CURLcode result; + gsk_handle h; + + /* Creates the GSKit environment. */ + + rc = gsk_environment_open(&h); + switch (rc) { + case GSK_OK: + break; + case GSK_INSUFFICIENT_STORAGE: + return CURLE_OUT_OF_MEMORY; + default: + failf(data, "gsk_environment_open(): %s", gsk_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } + + result = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION, FALSE); + if(!result && appid) + result = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid, FALSE); + if(!result && file) + result = set_buffer(data, h, GSK_KEYRING_FILE, file, FALSE); + if(!result && label) + result = set_buffer(data, h, GSK_KEYRING_LABEL, label, FALSE); + if(!result && password) + result = set_buffer(data, h, GSK_KEYRING_PW, password, FALSE); + + if(!result) { + /* Locate CAs, Client certificate and key according to our settings. + Note: this call may be blocking for some tenths of seconds. */ + result = gskit_status(data, gsk_environment_init(h), + "gsk_environment_init()", CURLE_SSL_CERTPROBLEM); + if(!result) { + *envir = h; + return result; + } + } + /* Error: rollback. */ + gsk_environment_close(&h); + return result; +} + + +static void cancel_async_handshake(struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + Qso_OverlappedIO_t cstat; + + if(QsoCancelOperation(conn->sock[sockindex], 0) > 0) + QsoWaitForIOCompletion(connssl->iocport, &cstat, (struct timeval *) NULL); +} + + +static void close_async_handshake(struct ssl_connect_data *connssl) +{ + QsoDestroyIOCompletionPort(connssl->iocport); + connssl->iocport = -1; +} + + +static void close_one(struct ssl_connect_data *conn, + struct SessionHandle *data) +{ + if(conn->handle) { + gskit_status(data, gsk_secure_soc_close(&conn->handle), + "gsk_secure_soc_close()", 0); + conn->handle = (gsk_handle) NULL; + } + if(conn->iocport >= 0) + close_async_handshake(conn); +} + + +static ssize_t gskit_send(struct connectdata *conn, int sockindex, + const void *mem, size_t len, CURLcode *curlcode) +{ + struct SessionHandle *data = conn->data; + CURLcode cc; + int written; + + cc = gskit_status(data, + gsk_secure_soc_write(conn->ssl[sockindex].handle, + (char *) mem, (int) len, &written), + "gsk_secure_soc_write()", CURLE_SEND_ERROR); + if(cc != CURLE_OK) { + *curlcode = cc; + written = -1; + } + return (ssize_t) written; /* number of bytes */ +} + + +static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf, + size_t buffersize, CURLcode *curlcode) +{ + struct SessionHandle *data = conn->data; + int buffsize; + int nread; + CURLcode cc; + + buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize; + cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle, + buf, buffsize, &nread), + "gsk_secure_soc_read()", CURLE_RECV_ERROR); + if(cc != CURLE_OK) { + *curlcode = cc; + nread = -1; + } + return (ssize_t) nread; +} + + +static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) +{ + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + gsk_handle envir; + CURLcode result; + int rc; + char *keyringfile; + char *keyringpwd; + char *keyringlabel; + char *sni; + unsigned int protoflags; + long timeout; + Qso_OverlappedIO_t commarea; + + /* Create SSL environment, start (preferably asynchronous) handshake. */ + + connssl->handle = (gsk_handle) NULL; + connssl->iocport = -1; + + /* GSKit supports two ways of specifying an SSL context: either by + * application identifier (that should have been defined at the system + * level) or by keyring file, password and certificate label. + * Local certificate name (CURLOPT_SSLCERT) is used to hold either the + * application identifier of the certificate label. + * Key password (CURLOPT_KEYPASSWD) holds the keyring password. + * It is not possible to have different keyrings for the CAs and the + * local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify + * the keyring file. + * If no key password is given and the keyring is the system keyring, + * application identifier mode is tried first, as recommended in IBM doc. + */ + + keyringfile = data->set.str[STRING_SSL_CAFILE]; + keyringpwd = data->set.str[STRING_KEY_PASSWD]; + keyringlabel = data->set.str[STRING_CERT]; + envir = (gsk_handle) NULL; + + if(keyringlabel && *keyringlabel && !keyringpwd && + !strcmp(keyringfile, CURL_CA_BUNDLE)) { + /* Try application identifier mode. */ + init_environment(data, &envir, keyringlabel, (const char *) NULL, + (const char *) NULL, (const char *) NULL); + } + + if(!envir) { + /* Use keyring mode. */ + result = init_environment(data, &envir, (const char *) NULL, + keyringfile, keyringlabel, keyringpwd); + if(result) + return result; + } + + /* Create secure session. */ + result = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle), + "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR); + gsk_environment_close(&envir); + if(result) + return result; + + /* Determine which SSL/TLS version should be enabled. */ + protoflags = CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | + CURL_GSKPROTO_TLSV12_MASK; + sni = conn->host.name; + switch (data->set.ssl.version) { + case CURL_SSLVERSION_SSLv2: + protoflags = CURL_GSKPROTO_SSLV2_MASK; + sni = (char *) NULL; + break; + case CURL_SSLVERSION_SSLv3: + protoflags = CURL_GSKPROTO_SSLV3_MASK; + sni = (char *) NULL; + break; + case CURL_SSLVERSION_TLSv1: + protoflags = CURL_GSKPROTO_TLSV10_MASK | + CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK; + break; + case CURL_SSLVERSION_TLSv1_0: + protoflags = CURL_GSKPROTO_TLSV10_MASK; + break; + case CURL_SSLVERSION_TLSv1_1: + protoflags = CURL_GSKPROTO_TLSV11_MASK; + break; + case CURL_SSLVERSION_TLSv1_2: + protoflags = CURL_GSKPROTO_TLSV12_MASK; + break; + } + + /* Process SNI. Ignore if not supported (on OS400 < V7R1). */ + if(sni) { + result = set_buffer(data, connssl->handle, + GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE); + if(result == CURLE_UNSUPPORTED_PROTOCOL) + result = CURLE_OK; + } + + /* Set session parameters. */ + if(!result) { + /* Compute the handshake timeout. Since GSKit granularity is 1 second, + we round up the required value. */ + timeout = Curl_timeleft(data, NULL, TRUE); + if(timeout < 0) + result = CURLE_OPERATION_TIMEDOUT; + else + result = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT, + (timeout + 999) / 1000); + } + if(!result) + result = set_numeric(data, connssl->handle, GSK_FD, conn->sock[sockindex]); + if(!result) + result = set_ciphers(data, connssl->handle, &protoflags); + if(!protoflags) { + failf(data, "No SSL protocol/cipher combination enabled"); + result = CURLE_SSL_CIPHER; + } + if(!result) + result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV2, + (protoflags & CURL_GSKPROTO_SSLV2_MASK)? + GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE); + if(!result) + result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV3, + (protoflags & CURL_GSKPROTO_SSLV3_MASK)? + GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE); + if(!result) + result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV1, + (protoflags & CURL_GSKPROTO_TLSV10_MASK)? + GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE); + if(!result) { + result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV11, + (protoflags & CURL_GSKPROTO_TLSV11_MASK)? + GSK_TRUE: GSK_FALSE, TRUE); + if(result == CURLE_UNSUPPORTED_PROTOCOL) { + result = CURLE_OK; + if(protoflags == CURL_GSKPROTO_TLSV11_MASK) { + failf(data, "TLS 1.1 not yet supported"); + result = CURLE_SSL_CIPHER; + } + } + } + if(!result) { + result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV12, + (protoflags & CURL_GSKPROTO_TLSV12_MASK)? + GSK_TRUE: GSK_FALSE, TRUE); + if(result == CURLE_UNSUPPORTED_PROTOCOL) { + result = CURLE_OK; + if(protoflags == CURL_GSKPROTO_TLSV12_MASK) { + failf(data, "TLS 1.2 not yet supported"); + result = CURLE_SSL_CIPHER; + } + } + } + if(!result) + result = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE, + data->set.ssl.verifypeer? GSK_SERVER_AUTH_FULL: + GSK_SERVER_AUTH_PASSTHRU, FALSE); + + if(!result) { + /* Start handshake. Try asynchronous first. */ + memset(&commarea, 0, sizeof commarea); + connssl->iocport = QsoCreateIOCompletionPort(); + if(connssl->iocport != -1) { + result = gskit_status(data, + gsk_secure_soc_startInit(connssl->handle, + connssl->iocport, + &commarea), + "gsk_secure_soc_startInit()", + CURLE_SSL_CONNECT_ERROR); + if(!result) { + connssl->connecting_state = ssl_connect_2; + return CURLE_OK; + } + else + close_async_handshake(connssl); + } + else if(errno != ENOBUFS) + result = gskit_status(data, GSK_ERROR_IO, + "QsoCreateIOCompletionPort()", 0); + else { + /* No more completion port available. Use synchronous IO. */ + result = gskit_status(data, gsk_secure_soc_init(connssl->handle), + "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR); + if(!result) { + connssl->connecting_state = ssl_connect_3; + return CURLE_OK; + } + } + } + + /* Error: rollback. */ + close_one(connssl, data); + return result; +} + + +static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex, + bool nonblocking) +{ + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + Qso_OverlappedIO_t cstat; + long timeout_ms; + struct timeval stmv; + CURLcode result; + + /* Poll or wait for end of SSL asynchronous handshake. */ + + for(;;) { + timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE); + if(timeout_ms < 0) + timeout_ms = 0; + stmv.tv_sec = timeout_ms / 1000; + stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000; + switch (QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) { + case 1: /* Operation complete. */ + break; + case -1: /* An error occurred: handshake still in progress. */ + if(errno == EINTR) { + if(nonblocking) + return CURLE_OK; + continue; /* Retry. */ + } + if(errno != ETIME) { + failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno)); + cancel_async_handshake(conn, sockindex); + close_async_handshake(connssl); + return CURLE_SSL_CONNECT_ERROR; + } + /* FALL INTO... */ + case 0: /* Handshake in progress, timeout occurred. */ + if(nonblocking) + return CURLE_OK; + cancel_async_handshake(conn, sockindex); + close_async_handshake(connssl); + return CURLE_OPERATION_TIMEDOUT; + } + break; + } + result = gskit_status(data, cstat.returnValue, "SSL handshake", + CURLE_SSL_CONNECT_ERROR); + if(!result) + connssl->connecting_state = ssl_connect_3; + close_async_handshake(connssl); + return result; +} + + +static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) +{ + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + const gsk_cert_data_elem *cdev; + int cdec; + const gsk_cert_data_elem *p; + const char *cert = (const char *) NULL; + const char *certend; + const char *ptr; + int i; + CURLcode result; + + /* SSL handshake done: gather certificate info and verify host. */ + + if(gskit_status(data, gsk_attribute_get_cert_info(connssl->handle, + GSK_PARTNER_CERT_INFO, + &cdev, &cdec), + "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) == + CURLE_OK) { + infof(data, "Server certificate:\n"); + p = cdev; + for(i = 0; i++ < cdec; p++) + switch (p->cert_data_id) { + case CERT_BODY_DER: + cert = p->cert_data_p; + certend = cert + cdev->cert_data_l; + break; + case CERT_DN_PRINTABLE: + infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p); + break; + case CERT_ISSUER_DN_PRINTABLE: + infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p); + break; + case CERT_VALID_FROM: + infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p); + break; + case CERT_VALID_TO: + infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p); + break; + } + } + + /* Verify host. */ + result = Curl_verifyhost(conn, cert, certend); + if(result) + return result; + + /* The only place GSKit can get the whole CA chain is a validation + callback where no user data pointer is available. Therefore it's not + possible to copy this chain into our structures for CAINFO. + However the server certificate may be available, thus we can return + info about it. */ + if(data->set.ssl.certinfo) { + result = Curl_ssl_init_certinfo(data, 1); + if(result) + return result; + + if(cert) { + result = Curl_extract_certinfo(conn, 0, cert, certend); + if(result) + return result; + } + } + + /* Check pinned public key. */ + ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + if(!result && ptr) { + curl_X509certificate x509; + curl_asn1Element *p; + + if(!cert) + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + Curl_parseX509(&x509, cert, certend); + p = &x509.subjectPublicKeyInfo; + result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header); + if(result) { + failf(data, "SSL: public key does not match pinned public key!"); + return result; + } + } + + connssl->connecting_state = ssl_connect_done; + return CURLE_OK; +} + + +static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex, + bool nonblocking, bool *done) +{ + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + long timeout_ms; + Qso_OverlappedIO_t cstat; + CURLcode result = CURLE_OK; + + *done = connssl->state == ssl_connection_complete; + if(*done) + return CURLE_OK; + + /* Step 1: create session, start handshake. */ + if(connssl->connecting_state == ssl_connect_1) { + /* check allowed time left */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + result = CURLE_OPERATION_TIMEDOUT; + } + else + result = gskit_connect_step1(conn, sockindex); + } + + /* Step 2: check if handshake is over. */ + if(!result && connssl->connecting_state == ssl_connect_2) { + /* check allowed time left */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + result = CURLE_OPERATION_TIMEDOUT; + } + else + result = gskit_connect_step2(conn, sockindex, nonblocking); + } + + /* Step 3: gather certificate info, verify host. */ + if(!result && connssl->connecting_state == ssl_connect_3) + result = gskit_connect_step3(conn, sockindex); + + if(result) + close_one(connssl, data); + else if(connssl->connecting_state == ssl_connect_done) { + connssl->state = ssl_connection_complete; + connssl->connecting_state = ssl_connect_1; + conn->recv[sockindex] = gskit_recv; + conn->send[sockindex] = gskit_send; + *done = TRUE; + } + + return result; +} + + +CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done) +{ + CURLcode result; + + result = gskit_connect_common(conn, sockindex, TRUE, done); + if(*done || result) + conn->ssl[sockindex].connecting_state = ssl_connect_1; + return result; +} + + +CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex) +{ + CURLcode result; + bool done; + + conn->ssl[sockindex].connecting_state = ssl_connect_1; + result = gskit_connect_common(conn, sockindex, FALSE, &done); + if(result) + return result; + + DEBUGASSERT(done); + + return CURLE_OK; +} + + +void Curl_gskit_close(struct connectdata *conn, int sockindex) +{ + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + if(connssl->use) + close_one(connssl, data); +} + + +int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct SessionHandle *data = conn->data; + ssize_t nread; + int what; + int rc; + char buf[120]; + + if(!connssl->handle) + return 0; + + if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) + return 0; + + close_one(connssl, data); + rc = 0; + what = Curl_socket_ready(conn->sock[sockindex], + CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + + for(;;) { + if(what < 0) { + /* anything that gets here is fatally bad */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + rc = -1; + break; + } + + if(!what) { /* timeout */ + failf(data, "SSL shutdown timeout"); + break; + } + + /* Something to read, let's do it and hope that it is the close + notify alert from the server. No way to gsk_secure_soc_read() now, so + use read(). */ + + nread = read(conn->sock[sockindex], buf, sizeof(buf)); + + if(nread < 0) { + failf(data, "read: %s", strerror(errno)); + rc = -1; + } + + if(nread <= 0) + break; + + what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0); + } + + return rc; +} + + +size_t Curl_gskit_version(char *buffer, size_t size) +{ + strncpy(buffer, "GSKit", size); + return strlen(buffer); +} + + +int Curl_gskit_check_cxn(struct connectdata *cxn) +{ + int err; + int errlen; + + /* The only thing that can be tested here is at the socket level. */ + + if(!cxn->ssl[FIRSTSOCKET].handle) + return 0; /* connection has been closed */ + + err = 0; + errlen = sizeof err; + + if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR, + (unsigned char *) &err, &errlen) || + errlen != sizeof err || err) + return 0; /* connection has been closed */ + + return -1; /* connection status unknown */ +} + +#endif /* USE_GSKIT */ diff --git a/project/jni/curl/lib/vtls/gskit.h b/project/jni/curl/lib/vtls/gskit.h new file mode 100644 index 000000000..41483cba6 --- /dev/null +++ b/project/jni/curl/lib/vtls/gskit.h @@ -0,0 +1,71 @@ +#ifndef HEADER_CURL_GSKIT_H +#define HEADER_CURL_GSKIT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curl_setup.h" + +/* + * This header should only be needed to get included by vtls.c and gskit.c + */ + +#include "urldata.h" + +#ifdef USE_GSKIT +int Curl_gskit_init(void); +void Curl_gskit_cleanup(void); +CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex); +CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn, + int sockindex, bool *done); +void Curl_gskit_close(struct connectdata *conn, int sockindex); +int Curl_gskit_shutdown(struct connectdata *conn, int sockindex); + +size_t Curl_gskit_version(char *buffer, size_t size); +int Curl_gskit_check_cxn(struct connectdata *cxn); + +/* Set the API backend definition to GSKit */ +#define CURL_SSL_BACKEND CURLSSLBACKEND_GSKIT + +/* this backend supports CURLOPT_CERTINFO */ +#define have_curlssl_certinfo 1 + +/* API setup for GSKit */ +#define curlssl_init Curl_gskit_init +#define curlssl_cleanup Curl_gskit_cleanup +#define curlssl_connect Curl_gskit_connect +#define curlssl_connect_nonblocking Curl_gskit_connect_nonblocking + +/* No session handling for GSKit */ +#define curlssl_session_free(x) Curl_nop_stmt +#define curlssl_close_all(x) ((void)x) +#define curlssl_close Curl_gskit_close +#define curlssl_shutdown(x,y) Curl_gskit_shutdown(x,y) +#define curlssl_set_engine(x,y) CURLE_NOT_BUILT_IN +#define curlssl_set_engine_default(x) CURLE_NOT_BUILT_IN +#define curlssl_engines_list(x) NULL +#define curlssl_version Curl_gskit_version +#define curlssl_check_cxn(x) Curl_gskit_check_cxn(x) +#define curlssl_data_pending(x,y) 0 +#define curlssl_random(x,y,z) -1 + +#endif /* USE_GSKIT */ + +#endif /* HEADER_CURL_GSKIT_H */ diff --git a/project/jni/curl/lib/vtls/gtls.c b/project/jni/curl/lib/vtls/gtls.c new file mode 100644 index 000000000..1fef54b48 --- /dev/null +++ b/project/jni/curl/lib/vtls/gtls.c @@ -0,0 +1,1627 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code + * but vtls.c should ever call or use these functions. + * + * Note: don't use the GnuTLS' *_t variable type names in this source code, + * since they were not present in 1.0.X. + */ + +#include "curl_setup.h" + +#ifdef USE_GNUTLS + +#include +#include +#include + +#ifdef USE_GNUTLS_NETTLE +#include +#include +#include +#else +#include +#endif + +#include "urldata.h" +#include "sendf.h" +#include "inet_pton.h" +#include "gtls.h" +#include "vtls.h" +#include "parsedate.h" +#include "connect.h" /* for the connect timeout */ +#include "select.h" +#include "rawstr.h" +#include "warnless.h" +#include "x509asn1.h" +#include "curl_printf.h" +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* + Some hackish cast macros based on: + https://developer.gnome.org/glib/unstable/glib-Type-Conversion-Macros.html +*/ +#ifndef GNUTLS_POINTER_TO_INT_CAST +#define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p)) +#endif +#ifndef GNUTLS_INT_TO_POINTER_CAST +#define GNUTLS_INT_TO_POINTER_CAST(i) ((void*) (long) (i)) +#endif + +/* Enable GnuTLS debugging by defining GTLSDEBUG */ +/*#define GTLSDEBUG */ + +#ifdef GTLSDEBUG +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} +#endif +static bool gtls_inited = FALSE; + +#if defined(GNUTLS_VERSION_NUMBER) +# if (GNUTLS_VERSION_NUMBER >= 0x020c00) +# undef gnutls_transport_set_lowat +# define gnutls_transport_set_lowat(A,B) Curl_nop_stmt +# define USE_GNUTLS_PRIORITY_SET_DIRECT 1 +# endif +# if (GNUTLS_VERSION_NUMBER >= 0x020c03) +# define GNUTLS_MAPS_WINSOCK_ERRORS 1 +# endif + +# if (GNUTLS_VERSION_NUMBER >= 0x030200) +# define HAS_ALPN +# endif + +# if (GNUTLS_VERSION_NUMBER >= 0x03020d) +# define HAS_OCSP +# endif + +# if (GNUTLS_VERSION_NUMBER >= 0x030306) +# define HAS_CAPATH +# endif +#endif + +#ifdef HAS_OCSP +# include +#endif + +/* + * Custom push and pull callback functions used by GNU TLS to read and write + * to the socket. These functions are simple wrappers to send() and recv() + * (although here using the sread/swrite macros as defined by + * curl_setup_once.h). + * We use custom functions rather than the GNU TLS defaults because it allows + * us to get specific about the fourth "flags" argument, and to use arbitrary + * private data with gnutls_transport_set_ptr if we wish. + * + * When these custom push and pull callbacks fail, GNU TLS checks its own + * session-specific error variable, and when not set also its own global + * errno variable, in order to take appropriate action. GNU TLS does not + * require that the transport is actually a socket. This implies that for + * Windows builds these callbacks should ideally set the session-specific + * error variable using function gnutls_transport_set_errno or as a last + * resort global errno variable using gnutls_transport_set_global_errno, + * with a transport agnostic error value. This implies that some winsock + * error translation must take place in these callbacks. + * + * Paragraph above applies to GNU TLS versions older than 2.12.3, since + * this version GNU TLS does its own internal winsock error translation + * using system_errno() function. + */ + +#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) +# define gtls_EINTR 4 +# define gtls_EIO 5 +# define gtls_EAGAIN 11 +static int gtls_mapped_sockerrno(void) +{ + switch(SOCKERRNO) { + case WSAEWOULDBLOCK: + return gtls_EAGAIN; + case WSAEINTR: + return gtls_EINTR; + default: + break; + } + return gtls_EIO; +} +#endif + +static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) +{ + ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); +#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) + if(ret < 0) + gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); +#endif + return ret; +} + +static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) +{ + ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len); +#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) + if(ret < 0) + gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); +#endif + return ret; +} + +/* Curl_gtls_init() + * + * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that + * are not thread-safe and thus this function itself is not thread-safe and + * must only be called from within curl_global_init() to keep the thread + * situation under control! + */ +int Curl_gtls_init(void) +{ + int ret = 1; + if(!gtls_inited) { + ret = gnutls_global_init()?0:1; +#ifdef GTLSDEBUG + gnutls_global_set_log_function(tls_log_func); + gnutls_global_set_log_level(2); +#endif + gtls_inited = TRUE; + } + return ret; +} + +int Curl_gtls_cleanup(void) +{ + if(gtls_inited) { + gnutls_global_deinit(); + gtls_inited = FALSE; + } + return 1; +} + +static void showtime(struct SessionHandle *data, + const char *text, + time_t stamp) +{ + struct tm buffer; + const struct tm *tm = &buffer; + CURLcode result = Curl_gmtime(stamp, &buffer); + if(result) + return; + + snprintf(data->state.buffer, + BUFSIZE, + "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT", + text, + Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); + infof(data, "%s\n", data->state.buffer); +} + +static gnutls_datum_t load_file (const char *file) +{ + FILE *f; + gnutls_datum_t loaded_file = { NULL, 0 }; + long filelen; + void *ptr; + + if(!(f = fopen(file, "rb"))) + return loaded_file; + if(fseek(f, 0, SEEK_END) != 0 + || (filelen = ftell(f)) < 0 + || fseek(f, 0, SEEK_SET) != 0 + || !(ptr = malloc((size_t)filelen))) + goto out; + if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) { + free(ptr); + goto out; + } + + loaded_file.data = ptr; + loaded_file.size = (unsigned int)filelen; +out: + fclose(f); + return loaded_file; +} + +static void unload_file(gnutls_datum_t data) { + free(data.data); +} + + +/* this function does a SSL/TLS (re-)handshake */ +static CURLcode handshake(struct connectdata *conn, + int sockindex, + bool duringconnect, + bool nonblocking) +{ + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + gnutls_session_t session = conn->ssl[sockindex].session; + curl_socket_t sockfd = conn->sock[sockindex]; + long timeout_ms; + int rc; + int what; + + for(;;) { + /* check allowed time left */ + timeout_ms = Curl_timeleft(data, NULL, duringconnect); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + /* if ssl is expecting something, check if it's available. */ + if(connssl->connecting_state == ssl_connect_2_reading + || connssl->connecting_state == ssl_connect_2_writing) { + + curl_socket_t writefd = ssl_connect_2_writing== + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading== + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + + what = Curl_socket_ready(readfd, writefd, + nonblocking?0: + timeout_ms?timeout_ms:1000); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + return CURLE_SSL_CONNECT_ERROR; + } + else if(0 == what) { + if(nonblocking) + return CURLE_OK; + else if(timeout_ms) { + /* timeout */ + failf(data, "SSL connection timeout at %ld", timeout_ms); + return CURLE_OPERATION_TIMEDOUT; + } + } + /* socket is readable or writable */ + } + + rc = gnutls_handshake(session); + + if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { + connssl->connecting_state = + gnutls_record_get_direction(session)? + ssl_connect_2_writing:ssl_connect_2_reading; + continue; + } + else if((rc < 0) && !gnutls_error_is_fatal(rc)) { + const char *strerr = NULL; + + if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) { + int alert = gnutls_alert_get(session); + strerr = gnutls_alert_get_name(alert); + } + + if(strerr == NULL) + strerr = gnutls_strerror(rc); + + infof(data, "gnutls_handshake() warning: %s\n", strerr); + continue; + } + else if(rc < 0) { + const char *strerr = NULL; + + if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) { + int alert = gnutls_alert_get(session); + strerr = gnutls_alert_get_name(alert); + } + + if(strerr == NULL) + strerr = gnutls_strerror(rc); + + failf(data, "gnutls_handshake() failed: %s", strerr); + return CURLE_SSL_CONNECT_ERROR; + } + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + return CURLE_OK; + } +} + +static gnutls_x509_crt_fmt_t do_file_type(const char *type) +{ + if(!type || !type[0]) + return GNUTLS_X509_FMT_PEM; + if(Curl_raw_equal(type, "PEM")) + return GNUTLS_X509_FMT_PEM; + if(Curl_raw_equal(type, "DER")) + return GNUTLS_X509_FMT_DER; + return -1; +} + +static CURLcode +gtls_connect_step1(struct connectdata *conn, + int sockindex) +{ + struct SessionHandle *data = conn->data; + gnutls_session_t session; + int rc; + void *ssl_sessionid; + size_t ssl_idsize; + bool sni = TRUE; /* default is SNI enabled */ +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif +#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT + static const int cipher_priority[] = { + /* These two ciphers were added to GnuTLS as late as ver. 3.0.1, + but this code path is only ever used for ver. < 2.12.0. + GNUTLS_CIPHER_AES_128_GCM, + GNUTLS_CIPHER_AES_256_GCM, + */ + GNUTLS_CIPHER_AES_128_CBC, + GNUTLS_CIPHER_AES_256_CBC, + GNUTLS_CIPHER_CAMELLIA_128_CBC, + GNUTLS_CIPHER_CAMELLIA_256_CBC, + GNUTLS_CIPHER_3DES_CBC, + }; + static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; + static int protocol_priority[] = { 0, 0, 0, 0 }; +#else +#define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509" +/* If GnuTLS was compiled without support for SRP it will error out if SRP is + requested in the priority string, so treat it specially + */ +#define GNUTLS_SRP "+SRP" + const char* prioritylist; + const char *err = NULL; +#endif + + if(conn->ssl[sockindex].state == ssl_connection_complete) + /* to make us tolerant against being called more than once for the + same connection */ + return CURLE_OK; + + if(!gtls_inited) + Curl_gtls_init(); + + /* GnuTLS only supports SSLv3 and TLSv1 */ + if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { + failf(data, "GnuTLS does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + } + else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) + sni = FALSE; /* SSLv3 has no SNI */ + + /* allocate a cred struct */ + rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } + +#ifdef USE_TLS_SRP + if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { + infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username); + + rc = gnutls_srp_allocate_client_credentials( + &conn->ssl[sockindex].srp_client_cred); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_srp_allocate_client_cred() failed: %s", + gnutls_strerror(rc)); + return CURLE_OUT_OF_MEMORY; + } + + rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex]. + srp_client_cred, + data->set.ssl.username, + data->set.ssl.password); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_srp_set_client_cred() failed: %s", + gnutls_strerror(rc)); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + } +#endif + + if(data->set.ssl.CAfile) { + /* set the trusted CA cert bundle file */ + gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred, + GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); + + rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, + data->set.ssl.CAfile, + GNUTLS_X509_FMT_PEM); + if(rc < 0) { + infof(data, "error reading ca cert file %s (%s)\n", + data->set.ssl.CAfile, gnutls_strerror(rc)); + if(data->set.ssl.verifypeer) + return CURLE_SSL_CACERT_BADFILE; + } + else + infof(data, "found %d certificates in %s\n", + rc, data->set.ssl.CAfile); + } + +#ifdef HAS_CAPATH + if(data->set.ssl.CApath) { + /* set the trusted CA cert directory */ + rc = gnutls_certificate_set_x509_trust_dir(conn->ssl[sockindex].cred, + data->set.ssl.CApath, + GNUTLS_X509_FMT_PEM); + if(rc < 0) { + infof(data, "error reading ca cert file %s (%s)\n", + data->set.ssl.CAfile, gnutls_strerror(rc)); + if(data->set.ssl.verifypeer) + return CURLE_SSL_CACERT_BADFILE; + } + else + infof(data, "found %d certificates in %s\n", + rc, data->set.ssl.CApath); + } +#endif + +#ifdef CURL_CA_FALLBACK + /* use system ca certificate store as fallback */ + if(data->set.ssl.verifypeer && + !(data->set.ssl.CAfile || data->set.ssl.CApath)) { + gnutls_certificate_set_x509_system_trust(conn->ssl[sockindex].cred); + } +#endif + + if(data->set.ssl.CRLfile) { + /* set the CRL list file */ + rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred, + data->set.ssl.CRLfile, + GNUTLS_X509_FMT_PEM); + if(rc < 0) { + failf(data, "error reading crl file %s (%s)", + data->set.ssl.CRLfile, gnutls_strerror(rc)); + return CURLE_SSL_CRL_BADFILE; + } + else + infof(data, "found %d CRL in %s\n", + rc, data->set.ssl.CRLfile); + } + + /* Initialize TLS session as a client */ + rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_init() failed: %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } + + /* convenient assign */ + session = conn->ssl[sockindex].session; + + if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && +#ifdef ENABLE_IPV6 + (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && +#endif + sni && + (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name, + strlen(conn->host.name)) < 0)) + infof(data, "WARNING: failed to configure server name indication (SNI) " + "TLS extension\n"); + + /* Use default priorities */ + rc = gnutls_set_default_priority(session); + if(rc != GNUTLS_E_SUCCESS) + return CURLE_SSL_CONNECT_ERROR; + +#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT + rc = gnutls_cipher_set_priority(session, cipher_priority); + if(rc != GNUTLS_E_SUCCESS) + return CURLE_SSL_CONNECT_ERROR; + + /* Sets the priority on the certificate types supported by gnutls. Priority + is higher for types specified before others. After specifying the types + you want, you must append a 0. */ + rc = gnutls_certificate_type_set_priority(session, cert_type_priority); + if(rc != GNUTLS_E_SUCCESS) + return CURLE_SSL_CONNECT_ERROR; + + if(data->set.ssl.cipher_list != NULL) { + failf(data, "can't pass a custom cipher list to older GnuTLS" + " versions"); + return CURLE_SSL_CONNECT_ERROR; + } + + switch (data->set.ssl.version) { + case CURL_SSLVERSION_SSLv3: + protocol_priority[0] = GNUTLS_SSL3; + break; + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + protocol_priority[0] = GNUTLS_TLS1_0; + protocol_priority[1] = GNUTLS_TLS1_1; + protocol_priority[2] = GNUTLS_TLS1_2; + break; + case CURL_SSLVERSION_TLSv1_0: + protocol_priority[0] = GNUTLS_TLS1_0; + break; + case CURL_SSLVERSION_TLSv1_1: + protocol_priority[0] = GNUTLS_TLS1_1; + break; + case CURL_SSLVERSION_TLSv1_2: + protocol_priority[0] = GNUTLS_TLS1_2; + break; + case CURL_SSLVERSION_SSLv2: + default: + failf(data, "GnuTLS does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + break; + } + rc = gnutls_protocol_set_priority(session, protocol_priority); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "Did you pass a valid GnuTLS cipher list?"); + return CURLE_SSL_CONNECT_ERROR; + } + +#else + /* Ensure +SRP comes at the *end* of all relevant strings so that it can be + * removed if a run-time error indicates that SRP is not supported by this + * GnuTLS version */ + switch (data->set.ssl.version) { + case CURL_SSLVERSION_SSLv3: + prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0"; + sni = false; + break; + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP; + break; + case CURL_SSLVERSION_TLSv1_0: + prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.0:" GNUTLS_SRP; + break; + case CURL_SSLVERSION_TLSv1_1: + prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.1:" GNUTLS_SRP; + break; + case CURL_SSLVERSION_TLSv1_2: + prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.2:" GNUTLS_SRP; + break; + case CURL_SSLVERSION_SSLv2: + default: + failf(data, "GnuTLS does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + break; + } + rc = gnutls_priority_set_direct(session, prioritylist, &err); + if((rc == GNUTLS_E_INVALID_REQUEST) && err) { + if(!strcmp(err, GNUTLS_SRP)) { + /* This GnuTLS was probably compiled without support for SRP. + * Note that fact and try again without it. */ + int validprioritylen = curlx_uztosi(err - prioritylist); + char *prioritycopy = strdup(prioritylist); + if(!prioritycopy) + return CURLE_OUT_OF_MEMORY; + + infof(data, "This GnuTLS does not support SRP\n"); + if(validprioritylen) + /* Remove the :+SRP */ + prioritycopy[validprioritylen - 1] = 0; + rc = gnutls_priority_set_direct(session, prioritycopy, &err); + free(prioritycopy); + } + } + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "Error %d setting GnuTLS cipher list starting with %s", + rc, err); + return CURLE_SSL_CONNECT_ERROR; + } +#endif + +#ifdef HAS_ALPN + if(data->set.ssl_enable_alpn) { + int cur = 0; + gnutls_datum_t protocols[2]; + +#ifdef USE_NGHTTP2 + if(data->set.httpversion >= CURL_HTTP_VERSION_2) { + protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID; + protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN; + cur++; + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); + } +#endif + + protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1; + protocols[cur].size = ALPN_HTTP_1_1_LENGTH; + cur++; + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + gnutls_alpn_set_protocols(session, protocols, cur, 0); + } +#endif + + if(data->set.str[STRING_CERT]) { + if(data->set.str[STRING_KEY_PASSWD]) { +#if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 + const unsigned int supported_key_encryption_algorithms = + GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR | + GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES | + GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 | + GNUTLS_PKCS_USE_PBES2_AES_256; + rc = gnutls_certificate_set_x509_key_file2( + conn->ssl[sockindex].cred, + data->set.str[STRING_CERT], + data->set.str[STRING_KEY] ? + data->set.str[STRING_KEY] : data->set.str[STRING_CERT], + do_file_type(data->set.str[STRING_CERT_TYPE]), + data->set.str[STRING_KEY_PASSWD], + supported_key_encryption_algorithms); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, + "error reading X.509 potentially-encrypted key file: %s", + gnutls_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } +#else + failf(data, "gnutls lacks support for encrypted key files"); + return CURLE_SSL_CONNECT_ERROR; +#endif + } + else { + rc = gnutls_certificate_set_x509_key_file( + conn->ssl[sockindex].cred, + data->set.str[STRING_CERT], + data->set.str[STRING_KEY] ? + data->set.str[STRING_KEY] : data->set.str[STRING_CERT], + do_file_type(data->set.str[STRING_CERT_TYPE]) ); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "error reading X.509 key or certificate file: %s", + gnutls_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } + } + } + +#ifdef USE_TLS_SRP + /* put the credentials to the current session */ + if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { + rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, + conn->ssl[sockindex].srp_client_cred); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } + } + else +#endif + { + rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, + conn->ssl[sockindex].cred); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } + } + + /* set the connection handle (file descriptor for the socket) */ + gnutls_transport_set_ptr(session, + GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex])); + + /* register callback functions to send and receive data. */ + gnutls_transport_set_push_function(session, Curl_gtls_push); + gnutls_transport_set_pull_function(session, Curl_gtls_pull); + + /* lowat must be set to zero when using custom push and pull functions. */ + gnutls_transport_set_lowat(session, 0); + +#ifdef HAS_OCSP + if(data->set.ssl.verifystatus) { + rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif + + /* This might be a reconnect, so we check for a session ID in the cache + to speed up things */ + + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) { + /* we got a session id, use it! */ + gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); + + /* Informational message */ + infof (data, "SSL re-using session ID\n"); + } + + return CURLE_OK; +} + +static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data, + gnutls_x509_crt_t cert, + const char *pinnedpubkey) +{ + /* Scratch */ + size_t len1 = 0, len2 = 0; + unsigned char *buff1 = NULL; + + gnutls_pubkey_t key = NULL; + + /* Result is returned to caller */ + int ret = 0; + CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + + /* if a path wasn't specified, don't pin */ + if(NULL == pinnedpubkey) + return CURLE_OK; + + if(NULL == cert) + return result; + + do { + /* Begin Gyrations to get the public key */ + gnutls_pubkey_init(&key); + + ret = gnutls_pubkey_import_x509(key, cert, 0); + if(ret < 0) + break; /* failed */ + + ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, NULL, &len1); + if(ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0) + break; /* failed */ + + buff1 = malloc(len1); + if(NULL == buff1) + break; /* failed */ + + len2 = len1; + + ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, buff1, &len2); + if(ret < 0 || len1 != len2) + break; /* failed */ + + /* End Gyrations */ + + /* The one good exit point */ + result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); + } while(0); + + if(NULL != key) + gnutls_pubkey_deinit(key); + + Curl_safefree(buff1); + + return result; +} + +static Curl_recv gtls_recv; +static Curl_send gtls_send; + +static CURLcode +gtls_connect_step3(struct connectdata *conn, + int sockindex) +{ + unsigned int cert_list_size; + const gnutls_datum_t *chainp; + unsigned int verify_status = 0; + gnutls_x509_crt_t x509_cert, x509_issuer; + gnutls_datum_t issuerp; + char certbuf[256] = ""; /* big enough? */ + size_t size; + unsigned int algo; + unsigned int bits; + time_t certclock; + const char *ptr; + struct SessionHandle *data = conn->data; + gnutls_session_t session = conn->ssl[sockindex].session; + int rc; + bool incache; + void *ssl_sessionid; +#ifdef HAS_ALPN + gnutls_datum_t proto; +#endif + CURLcode result = CURLE_OK; + + gnutls_protocol_t version = gnutls_protocol_get_version(session); + + /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */ + ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session), + gnutls_cipher_get(session), + gnutls_mac_get(session)); + + infof(data, "SSL connection using %s / %s\n", + gnutls_protocol_get_name(version), ptr); + + /* This function will return the peer's raw certificate (chain) as sent by + the peer. These certificates are in raw format (DER encoded for + X.509). In case of a X.509 then a certificate list may be present. The + first certificate in the list is the peer's certificate, following the + issuer's certificate, then the issuer's issuer etc. */ + + chainp = gnutls_certificate_get_peers(session, &cert_list_size); + if(!chainp) { + if(data->set.ssl.verifypeer || + data->set.ssl.verifyhost || + data->set.ssl.issuercert) { +#ifdef USE_TLS_SRP + if(data->set.ssl.authtype == CURL_TLSAUTH_SRP + && data->set.ssl.username != NULL + && !data->set.ssl.verifypeer + && gnutls_cipher_get(session)) { + /* no peer cert, but auth is ok if we have SRP user and cipher and no + peer verify */ + } + else { +#endif + failf(data, "failed to get server cert"); + return CURLE_PEER_FAILED_VERIFICATION; +#ifdef USE_TLS_SRP + } +#endif + } + infof(data, "\t common name: WARNING couldn't obtain\n"); + } + + if(data->set.ssl.certinfo && chainp) { + unsigned int i; + + result = Curl_ssl_init_certinfo(data, cert_list_size); + if(result) + return result; + + for(i = 0; i < cert_list_size; i++) { + const char *beg = (const char *) chainp[i].data; + const char *end = beg + chainp[i].size; + + result = Curl_extract_certinfo(conn, i, beg, end); + if(result) + return result; + } + } + + if(data->set.ssl.verifypeer) { + /* This function will try to verify the peer's certificate and return its + status (trusted, invalid etc.). The value of status should be one or + more of the gnutls_certificate_status_t enumerated elements bitwise + or'd. To avoid denial of service attacks some default upper limits + regarding the certificate key size and chain size are set. To override + them use gnutls_certificate_set_verify_limits(). */ + + rc = gnutls_certificate_verify_peers2(session, &verify_status); + if(rc < 0) { + failf(data, "server cert verify failed: %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } + + /* verify_status is a bitmask of gnutls_certificate_status bits */ + if(verify_status & GNUTLS_CERT_INVALID) { + if(data->set.ssl.verifypeer) { + failf(data, "server certificate verification failed. CAfile: %s " + "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none", + data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none"); + return CURLE_SSL_CACERT; + } + else + infof(data, "\t server certificate verification FAILED\n"); + } + else + infof(data, "\t server certificate verification OK\n"); + } + else + infof(data, "\t server certificate verification SKIPPED\n"); + +#ifdef HAS_OCSP + if(data->set.ssl.verifystatus) { + if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) { + gnutls_datum_t status_request; + gnutls_ocsp_resp_t ocsp_resp; + + gnutls_ocsp_cert_status_t status; + gnutls_x509_crl_reason_t reason; + + rc = gnutls_ocsp_status_request_get(session, &status_request); + + infof(data, "\t server certificate status verification FAILED\n"); + + if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + failf(data, "No OCSP response received"); + return CURLE_SSL_INVALIDCERTSTATUS; + } + + if(rc < 0) { + failf(data, "Invalid OCSP response received"); + return CURLE_SSL_INVALIDCERTSTATUS; + } + + gnutls_ocsp_resp_init(&ocsp_resp); + + rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request); + if(rc < 0) { + failf(data, "Invalid OCSP response received"); + return CURLE_SSL_INVALIDCERTSTATUS; + } + + rc = gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL, + &status, NULL, NULL, NULL, &reason); + + switch(status) { + case GNUTLS_OCSP_CERT_GOOD: + break; + + case GNUTLS_OCSP_CERT_REVOKED: { + const char *crl_reason; + + switch(reason) { + default: + case GNUTLS_X509_CRLREASON_UNSPECIFIED: + crl_reason = "unspecified reason"; + break; + + case GNUTLS_X509_CRLREASON_KEYCOMPROMISE: + crl_reason = "private key compromised"; + break; + + case GNUTLS_X509_CRLREASON_CACOMPROMISE: + crl_reason = "CA compromised"; + break; + + case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED: + crl_reason = "affiliation has changed"; + break; + + case GNUTLS_X509_CRLREASON_SUPERSEDED: + crl_reason = "certificate superseded"; + break; + + case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION: + crl_reason = "operation has ceased"; + break; + + case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD: + crl_reason = "certificate is on hold"; + break; + + case GNUTLS_X509_CRLREASON_REMOVEFROMCRL: + crl_reason = "will be removed from delta CRL"; + break; + + case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN: + crl_reason = "privilege withdrawn"; + break; + + case GNUTLS_X509_CRLREASON_AACOMPROMISE: + crl_reason = "AA compromised"; + break; + } + + failf(data, "Server certificate was revoked: %s", crl_reason); + break; + } + + default: + case GNUTLS_OCSP_CERT_UNKNOWN: + failf(data, "Server certificate status is unknown"); + break; + } + + gnutls_ocsp_resp_deinit(ocsp_resp); + + return CURLE_SSL_INVALIDCERTSTATUS; + } + else + infof(data, "\t server certificate status verification OK\n"); + } + else + infof(data, "\t server certificate status verification SKIPPED\n"); +#endif + + /* initialize an X.509 certificate structure. */ + gnutls_x509_crt_init(&x509_cert); + + if(chainp) + /* convert the given DER or PEM encoded Certificate to the native + gnutls_x509_crt_t format */ + gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); + + if(data->set.ssl.issuercert) { + gnutls_x509_crt_init(&x509_issuer); + issuerp = load_file(data->set.ssl.issuercert); + gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); + rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer); + gnutls_x509_crt_deinit(x509_issuer); + unload_file(issuerp); + if(rc <= 0) { + failf(data, "server certificate issuer check failed (IssuerCert: %s)", + data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); + gnutls_x509_crt_deinit(x509_cert); + return CURLE_SSL_ISSUER_ERROR; + } + infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n", + data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); + } + + size=sizeof(certbuf); + rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, + 0, /* the first and only one */ + FALSE, + certbuf, + &size); + if(rc) { + infof(data, "error fetching CN from cert:%s\n", + gnutls_strerror(rc)); + } + + /* This function will check if the given certificate's subject matches the + given hostname. This is a basic implementation of the matching described + in RFC2818 (HTTPS), which takes into account wildcards, and the subject + alternative name PKIX extension. Returns non zero on success, and zero on + failure. */ + rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name); +#if GNUTLS_VERSION_NUMBER < 0x030306 + /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP + addresses. */ + if(!rc) { +#ifdef ENABLE_IPV6 + #define use_addr in6_addr +#else + #define use_addr in_addr +#endif + unsigned char addrbuf[sizeof(struct use_addr)]; + unsigned char certaddr[sizeof(struct use_addr)]; + size_t addrlen = 0, certaddrlen; + int i; + int ret = 0; + + if(Curl_inet_pton(AF_INET, conn->host.name, addrbuf) > 0) + addrlen = 4; +#ifdef ENABLE_IPV6 + else if(Curl_inet_pton(AF_INET6, conn->host.name, addrbuf) > 0) + addrlen = 16; +#endif + + if(addrlen) { + for(i=0; ; i++) { + certaddrlen = sizeof(certaddr); + ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr, + &certaddrlen, NULL); + /* If this happens, it wasn't an IP address. */ + if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER) + continue; + if(ret < 0) + break; + if(ret != GNUTLS_SAN_IPADDRESS) + continue; + if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) { + rc = 1; + break; + } + } + } + } +#endif + if(!rc) { + if(data->set.ssl.verifyhost) { + failf(data, "SSL: certificate subject name (%s) does not match " + "target host name '%s'", certbuf, conn->host.dispname); + gnutls_x509_crt_deinit(x509_cert); + return CURLE_PEER_FAILED_VERIFICATION; + } + else + infof(data, "\t common name: %s (does not match '%s')\n", + certbuf, conn->host.dispname); + } + else + infof(data, "\t common name: %s (matched)\n", certbuf); + + /* Check for time-based validity */ + certclock = gnutls_x509_crt_get_expiration_time(x509_cert); + + if(certclock == (time_t)-1) { + if(data->set.ssl.verifypeer) { + failf(data, "server cert expiration date verify failed"); + gnutls_x509_crt_deinit(x509_cert); + return CURLE_SSL_CONNECT_ERROR; + } + else + infof(data, "\t server certificate expiration date verify FAILED\n"); + } + else { + if(certclock < time(NULL)) { + if(data->set.ssl.verifypeer) { + failf(data, "server certificate expiration date has passed."); + gnutls_x509_crt_deinit(x509_cert); + return CURLE_PEER_FAILED_VERIFICATION; + } + else + infof(data, "\t server certificate expiration date FAILED\n"); + } + else + infof(data, "\t server certificate expiration date OK\n"); + } + + certclock = gnutls_x509_crt_get_activation_time(x509_cert); + + if(certclock == (time_t)-1) { + if(data->set.ssl.verifypeer) { + failf(data, "server cert activation date verify failed"); + gnutls_x509_crt_deinit(x509_cert); + return CURLE_SSL_CONNECT_ERROR; + } + else + infof(data, "\t server certificate activation date verify FAILED\n"); + } + else { + if(certclock > time(NULL)) { + if(data->set.ssl.verifypeer) { + failf(data, "server certificate not activated yet."); + gnutls_x509_crt_deinit(x509_cert); + return CURLE_PEER_FAILED_VERIFICATION; + } + else + infof(data, "\t server certificate activation date FAILED\n"); + } + else + infof(data, "\t server certificate activation date OK\n"); + } + + ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + if(ptr) { + result = pkp_pin_peer_pubkey(data, x509_cert, ptr); + if(result != CURLE_OK) { + failf(data, "SSL: public key does not match pinned public key!"); + gnutls_x509_crt_deinit(x509_cert); + return result; + } + } + + /* Show: + + - subject + - start date + - expire date + - common name + - issuer + + */ + + /* public key algorithm's parameters */ + algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits); + infof(data, "\t certificate public key: %s\n", + gnutls_pk_algorithm_get_name(algo)); + + /* version of the X.509 certificate. */ + infof(data, "\t certificate version: #%d\n", + gnutls_x509_crt_get_version(x509_cert)); + + + size = sizeof(certbuf); + gnutls_x509_crt_get_dn(x509_cert, certbuf, &size); + infof(data, "\t subject: %s\n", certbuf); + + certclock = gnutls_x509_crt_get_activation_time(x509_cert); + showtime(data, "start date", certclock); + + certclock = gnutls_x509_crt_get_expiration_time(x509_cert); + showtime(data, "expire date", certclock); + + size = sizeof(certbuf); + gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size); + infof(data, "\t issuer: %s\n", certbuf); + + gnutls_x509_crt_deinit(x509_cert); + + /* compression algorithm (if any) */ + ptr = gnutls_compression_get_name(gnutls_compression_get(session)); + /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */ + infof(data, "\t compression: %s\n", ptr); + +#ifdef HAS_ALPN + if(data->set.ssl_enable_alpn) { + rc = gnutls_alpn_get_selected_protocol(session, &proto); + if(rc == 0) { + infof(data, "ALPN, server accepted to use %.*s\n", proto.size, + proto.data); + +#ifdef USE_NGHTTP2 + if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN && + !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data, + NGHTTP2_PROTO_VERSION_ID_LEN)) { + conn->negnpn = CURL_HTTP_VERSION_2; + } + else +#endif + if(proto.size == ALPN_HTTP_1_1_LENGTH && + !memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) { + conn->negnpn = CURL_HTTP_VERSION_1_1; + } + } + else + infof(data, "ALPN, server did not agree to a protocol\n"); + } +#endif + + conn->ssl[sockindex].state = ssl_connection_complete; + conn->recv[sockindex] = gtls_recv; + conn->send[sockindex] = gtls_send; + + { + /* we always unconditionally get the session id here, as even if we + already got it from the cache and asked to use it in the connection, it + might've been rejected and then a new one is in use now and we need to + detect that. */ + void *connect_sessionid; + size_t connect_idsize = 0; + + /* get the session ID data size */ + gnutls_session_get_data(session, NULL, &connect_idsize); + connect_sessionid = malloc(connect_idsize); /* get a buffer for it */ + + if(connect_sessionid) { + /* extract session ID to the allocated buffer */ + gnutls_session_get_data(session, connect_sessionid, &connect_idsize); + + incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)); + if(incache) { + /* there was one before in the cache, so instead of risking that the + previous one was rejected, we just kill that and store the new */ + Curl_ssl_delsessionid(conn, ssl_sessionid); + } + + /* store this session id */ + result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize); + if(result) { + free(connect_sessionid); + result = CURLE_OUT_OF_MEMORY; + } + } + else + result = CURLE_OUT_OF_MEMORY; + } + + return result; +} + + +/* + * This function is called after the TCP connect has completed. Setup the TLS + * layer and do all necessary magic. + */ +/* We use connssl->connecting_state to keep track of the connection status; + there are three states: 'ssl_connect_1' (not started yet or complete), + 'ssl_connect_2_reading' (waiting for data from server), and + 'ssl_connect_2_writing' (waiting to be able to write). + */ +static CURLcode +gtls_connect_common(struct connectdata *conn, + int sockindex, + bool nonblocking, + bool *done) +{ + int rc; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + /* Initiate the connection, if not already done */ + if(ssl_connect_1==connssl->connecting_state) { + rc = gtls_connect_step1 (conn, sockindex); + if(rc) + return rc; + } + + rc = handshake(conn, sockindex, TRUE, nonblocking); + if(rc) + /* handshake() sets its own error message with failf() */ + return rc; + + /* Finish connecting once the handshake is done */ + if(ssl_connect_1==connssl->connecting_state) { + rc = gtls_connect_step3(conn, sockindex); + if(rc) + return rc; + } + + *done = ssl_connect_1==connssl->connecting_state; + + return CURLE_OK; +} + +CURLcode +Curl_gtls_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done) +{ + return gtls_connect_common(conn, sockindex, TRUE, done); +} + +CURLcode +Curl_gtls_connect(struct connectdata *conn, + int sockindex) + +{ + CURLcode result; + bool done = FALSE; + + result = gtls_connect_common(conn, sockindex, FALSE, &done); + if(result) + return result; + + DEBUGASSERT(done); + + return CURLE_OK; +} + +static ssize_t gtls_send(struct connectdata *conn, + int sockindex, + const void *mem, + size_t len, + CURLcode *curlcode) +{ + ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len); + + if(rc < 0 ) { + *curlcode = (rc == GNUTLS_E_AGAIN) + ? CURLE_AGAIN + : CURLE_SEND_ERROR; + + rc = -1; + } + + return rc; +} + +static void close_one(struct connectdata *conn, + int idx) +{ + if(conn->ssl[idx].session) { + gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR); + gnutls_deinit(conn->ssl[idx].session); + conn->ssl[idx].session = NULL; + } + if(conn->ssl[idx].cred) { + gnutls_certificate_free_credentials(conn->ssl[idx].cred); + conn->ssl[idx].cred = NULL; + } +#ifdef USE_TLS_SRP + if(conn->ssl[idx].srp_client_cred) { + gnutls_srp_free_client_credentials(conn->ssl[idx].srp_client_cred); + conn->ssl[idx].srp_client_cred = NULL; + } +#endif +} + +void Curl_gtls_close(struct connectdata *conn, int sockindex) +{ + close_one(conn, sockindex); +} + +/* + * This function is called to shut down the SSL layer but keep the + * socket open (CCC - Clear Command Channel) + */ +int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) +{ + ssize_t result; + int retval = 0; + struct SessionHandle *data = conn->data; + int done = 0; + char buf[120]; + + /* This has only been tested on the proftpd server, and the mod_tls code + sends a close notify alert without waiting for a close notify alert in + response. Thus we wait for a close notify alert from the server, but + we do not send one. Let's hope other servers do the same... */ + + if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) + gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR); + + if(conn->ssl[sockindex].session) { + while(!done) { + int what = Curl_socket_ready(conn->sock[sockindex], + CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + if(what > 0) { + /* Something to read, let's do it and hope that it is the close + notify alert from the server */ + result = gnutls_record_recv(conn->ssl[sockindex].session, + buf, sizeof(buf)); + switch(result) { + case 0: + /* This is the expected response. There was no data but only + the close notify alert */ + done = 1; + break; + case GNUTLS_E_AGAIN: + case GNUTLS_E_INTERRUPTED: + infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n"); + break; + default: + retval = -1; + done = 1; + break; + } + } + else if(0 == what) { + /* timeout */ + failf(data, "SSL shutdown timeout"); + done = 1; + break; + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + retval = -1; + done = 1; + } + } + gnutls_deinit(conn->ssl[sockindex].session); + } + gnutls_certificate_free_credentials(conn->ssl[sockindex].cred); + +#ifdef USE_TLS_SRP + if(data->set.ssl.authtype == CURL_TLSAUTH_SRP + && data->set.ssl.username != NULL) + gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred); +#endif + + conn->ssl[sockindex].cred = NULL; + conn->ssl[sockindex].session = NULL; + + return retval; +} + +static ssize_t gtls_recv(struct connectdata *conn, /* connection data */ + int num, /* socketindex */ + char *buf, /* store read data here */ + size_t buffersize, /* max amount to read */ + CURLcode *curlcode) +{ + ssize_t ret; + + ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize); + if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) { + *curlcode = CURLE_AGAIN; + return -1; + } + + if(ret == GNUTLS_E_REHANDSHAKE) { + /* BLOCKING call, this is bad but a work-around for now. Fixing this "the + proper way" takes a whole lot of work. */ + CURLcode result = handshake(conn, num, FALSE, FALSE); + if(result) + /* handshake() writes error message on its own */ + *curlcode = result; + else + *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */ + return -1; + } + + if(ret < 0) { + failf(conn->data, "GnuTLS recv error (%d): %s", + (int)ret, gnutls_strerror((int)ret)); + *curlcode = CURLE_RECV_ERROR; + return -1; + } + + return ret; +} + +void Curl_gtls_session_free(void *ptr) +{ + free(ptr); +} + +size_t Curl_gtls_version(char *buffer, size_t size) +{ + return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL)); +} + +#ifndef USE_GNUTLS_NETTLE +static int Curl_gtls_seed(struct SessionHandle *data) +{ + /* we have the "SSL is seeded" boolean static to prevent multiple + time-consuming seedings in vain */ + static bool ssl_seeded = FALSE; + + /* Quickly add a bit of entropy */ + gcry_fast_random_poll(); + + if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] || + data->set.str[STRING_SSL_EGDSOCKET]) { + + /* TODO: to a good job seeding the RNG + This may involve the gcry_control function and these options: + GCRYCTL_SET_RANDOM_SEED_FILE + GCRYCTL_SET_RNDEGD_SOCKET + */ + ssl_seeded = TRUE; + } + return 0; +} +#endif + +/* data might be NULL! */ +int Curl_gtls_random(struct SessionHandle *data, + unsigned char *entropy, + size_t length) +{ +#if defined(USE_GNUTLS_NETTLE) + (void)data; + gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length); +#elif defined(USE_GNUTLS) + if(data) + Curl_gtls_seed(data); /* Initiate the seed if not already done */ + gcry_randomize(entropy, length, GCRY_STRONG_RANDOM); +#endif + return 0; +} + +void Curl_gtls_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum, /* output */ + size_t md5len) +{ +#if defined(USE_GNUTLS_NETTLE) + struct md5_ctx MD5pw; + md5_init(&MD5pw); + md5_update(&MD5pw, (unsigned int)tmplen, tmp); + md5_digest(&MD5pw, (unsigned int)md5len, md5sum); +#elif defined(USE_GNUTLS) + gcry_md_hd_t MD5pw; + gcry_md_open(&MD5pw, GCRY_MD_MD5, 0); + gcry_md_write(MD5pw, tmp, tmplen); + memcpy(md5sum, gcry_md_read (MD5pw, 0), md5len); + gcry_md_close(MD5pw); +#endif +} + +void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum, /* output */ + size_t sha256len) +{ +#if defined(USE_GNUTLS_NETTLE) + struct sha256_ctx SHA256pw; + sha256_init(&SHA256pw); + sha256_update(&SHA256pw, (unsigned int)tmplen, tmp); + sha256_digest(&SHA256pw, (unsigned int)sha256len, sha256sum); +#elif defined(USE_GNUTLS) + gcry_md_hd_t SHA256pw; + gcry_md_open(&SHA256pw, GCRY_MD_SHA256, 0); + gcry_md_write(SHA256pw, tmp, tmplen); + memcpy(sha256sum, gcry_md_read (SHA256pw, 0), sha256len); + gcry_md_close(SHA256pw); +#endif +} + +bool Curl_gtls_cert_status_request(void) +{ +#ifdef HAS_OCSP + return TRUE; +#else + return FALSE; +#endif +} + +#endif /* USE_GNUTLS */ diff --git a/project/jni/curl/lib/gtls.h b/project/jni/curl/lib/vtls/gtls.h similarity index 53% rename from project/jni/curl/lib/gtls.h rename to project/jni/curl/lib/vtls/gtls.h index 51e0af1f5..965f7cf1f 100644 --- a/project/jni/curl/lib/gtls.h +++ b/project/jni/curl/lib/vtls/gtls.h @@ -1,5 +1,5 @@ -#ifndef __GTLS_H -#define __GTLS_H +#ifndef HEADER_CURL_GTLS_H +#define HEADER_CURL_GTLS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,8 +22,12 @@ * ***************************************************************************/ +#include "curl_setup.h" + #ifdef USE_GNUTLS +#include "urldata.h" + int Curl_gtls_init(void); int Curl_gtls_cleanup(void); CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex); @@ -31,17 +35,34 @@ CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done); -/* tell GnuTLS to close down all open information regarding connections (and - thus session ID caching etc) */ -void Curl_gtls_close_all(struct SessionHandle *data); - /* close a SSL connection */ void Curl_gtls_close(struct connectdata *conn, int sockindex); void Curl_gtls_session_free(void *ptr); size_t Curl_gtls_version(char *buffer, size_t size); int Curl_gtls_shutdown(struct connectdata *conn, int sockindex); -int Curl_gtls_seed(struct SessionHandle *data); +int Curl_gtls_random(struct SessionHandle *data, + unsigned char *entropy, + size_t length); +void Curl_gtls_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum, /* output */ + size_t md5len); +void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum, /* output */ + size_t sha256len); + +bool Curl_gtls_cert_status_request(void); + +/* Set the API backend definition to GnuTLS */ +#define CURL_SSL_BACKEND CURLSSLBACKEND_GNUTLS + +/* this backend supports the CAPATH option */ +#define have_curlssl_ca_path 1 + +/* this backend supports CURLOPT_CERTINFO */ +#define have_curlssl_certinfo 1 /* API setup for GnuTLS */ #define curlssl_init Curl_gtls_init @@ -49,15 +70,19 @@ int Curl_gtls_seed(struct SessionHandle *data); #define curlssl_connect Curl_gtls_connect #define curlssl_connect_nonblocking Curl_gtls_connect_nonblocking #define curlssl_session_free(x) Curl_gtls_session_free(x) -#define curlssl_close_all Curl_gtls_close_all +#define curlssl_close_all(x) ((void)x) #define curlssl_close Curl_gtls_close #define curlssl_shutdown(x,y) Curl_gtls_shutdown(x,y) -#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_FAILED_INIT) -#define curlssl_set_engine_default(x) (x=x, CURLE_FAILED_INIT) -#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL) +#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN) +#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN) +#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) #define curlssl_version Curl_gtls_version -#define curlssl_check_cxn(x) (x=x, -1) -#define curlssl_data_pending(x,y) (x=x, y=y, 0) +#define curlssl_check_cxn(x) ((void)x, -1) +#define curlssl_data_pending(x,y) ((void)x, (void)y, 0) +#define curlssl_random(x,y,z) Curl_gtls_random(x,y,z) +#define curlssl_md5sum(a,b,c,d) Curl_gtls_md5sum(a,b,c,d) +#define curlssl_sha256sum(a,b,c,d) Curl_gtls_sha256sum(a,b,c,d) +#define curlssl_cert_status_request() Curl_gtls_cert_status_request() #endif /* USE_GNUTLS */ -#endif +#endif /* HEADER_CURL_GTLS_H */ diff --git a/project/jni/curl/lib/vtls/mbedtls.c b/project/jni/curl/lib/vtls/mbedtls.c new file mode 100644 index 000000000..f0900a5af --- /dev/null +++ b/project/jni/curl/lib/vtls/mbedtls.c @@ -0,0 +1,871 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2010 - 2011, Hoi-Ho Chan, + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Source file for all mbedTSL-specific code for the TLS/SSL layer. No code + * but vtls.c should ever call or use these functions. + * + */ + +#include "curl_setup.h" + +#ifdef USE_MBEDTLS + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "urldata.h" +#include "sendf.h" +#include "inet_pton.h" +#include "mbedtls.h" +#include "vtls.h" +#include "parsedate.h" +#include "connect.h" /* for the connect timeout */ +#include "select.h" +#include "rawstr.h" +#include "polarssl_threadlock.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* apply threading? */ +#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) +#define THREADING_SUPPORT +#endif + +#if defined(THREADING_SUPPORT) +static mbedtls_entropy_context entropy; + +static int entropy_init_initialized = 0; + +/* start of entropy_init_mutex() */ +static void entropy_init_mutex(mbedtls_entropy_context *ctx) +{ + /* lock 0 = entropy_init_mutex() */ + Curl_polarsslthreadlock_lock_function(0); + if(entropy_init_initialized == 0) { + mbedtls_entropy_init(ctx); + entropy_init_initialized = 1; + } + Curl_polarsslthreadlock_unlock_function(0); +} +/* end of entropy_init_mutex() */ + +/* start of entropy_func_mutex() */ +static int entropy_func_mutex(void *data, unsigned char *output, size_t len) +{ + int ret; + /* lock 1 = entropy_func_mutex() */ + Curl_polarsslthreadlock_lock_function(1); + ret = mbedtls_entropy_func(data, output, len); + Curl_polarsslthreadlock_unlock_function(1); + + return ret; +} +/* end of entropy_func_mutex() */ + +#endif /* THREADING_SUPPORT */ + +/* Define this to enable lots of debugging for mbedTLS */ +#undef MBEDTLS_DEBUG + +#ifdef MBEDTLS_DEBUG +static void mbedtls_debug(void *context, int level, const char *line) +{ + struct SessionHandle *data = NULL; + + if(!context) + return; + + data = (struct SessionHandle *)context; + + infof(data, "%s", line); + (void) level; +} +#else +#endif + +/* ALPN for http2? */ +#ifdef USE_NGHTTP2 +# undef HAS_ALPN +# ifdef MBEDTLS_SSL_ALPN +# define HAS_ALPN +# endif +#endif + + +/* + * profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr = +{ + /* Hashes from SHA-1 and above */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_RIPEMD160 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), + 0xFFFFFFF, /* Any PK alg */ + 0xFFFFFFF, /* Any curve */ + 1024, /* RSA min key len */ +}; + +/* See https://tls.mbed.org/discussions/generic/ + howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der +*/ +#define RSA_PUB_DER_MAX_BYTES (38 + 2 * MBEDTLS_MPI_MAX_SIZE) +#define ECP_PUB_DER_MAX_BYTES (30 + 2 * MBEDTLS_ECP_MAX_BYTES) + +#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ + RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES) + +static Curl_recv mbedtls_recv; +static Curl_send mbedtls_send; + +static CURLcode +mbedtls_connect_step1(struct connectdata *conn, + int sockindex) +{ + struct SessionHandle *data = conn->data; + struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + + bool sni = TRUE; /* default is SNI enabled */ + int ret = -1; +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif + void *old_session = NULL; + size_t old_session_size = 0; + char errorbuf[128]; + errorbuf[0]=0; + + /* mbedTLS only supports SSLv3 and TLSv1 */ + if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { + failf(data, "mbedTLS does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + } + else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) + sni = FALSE; /* SSLv3 has no SNI */ + +#ifdef THREADING_SUPPORT + entropy_init_mutex(&entropy); + mbedtls_ctr_drbg_init(&connssl->ctr_drbg); + + ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, entropy_func_mutex, + &entropy, connssl->ssn.id, + connssl->ssn.id_len); + if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n", + -ret, errorbuf); + } +#else + mbedtls_entropy_init(&connssl->entropy); + mbedtls_ctr_drbg_init(&connssl->ctr_drbg); + + ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, mbedtls_entropy_func, + &connssl->entropy, connssl->ssn.id, + connssl->ssn.id_len); + if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n", + -ret, errorbuf); + } +#endif /* THREADING_SUPPORT */ + + /* Load the trusted CA */ + mbedtls_x509_crt_init(&connssl->cacert); + + if(data->set.str[STRING_SSL_CAFILE]) { + ret = mbedtls_x509_crt_parse_file(&connssl->cacert, + data->set.str[STRING_SSL_CAFILE]); + + if(ret<0) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s", + data->set.str[STRING_SSL_CAFILE], -ret, errorbuf); + + if(data->set.ssl.verifypeer) + return CURLE_SSL_CACERT_BADFILE; + } + } + + if(data->set.str[STRING_SSL_CAPATH]) { + ret = mbedtls_x509_crt_parse_path(&connssl->cacert, + data->set.str[STRING_SSL_CAPATH]); + + if(ret<0) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s", + data->set.str[STRING_SSL_CAPATH], -ret, errorbuf); + + if(data->set.ssl.verifypeer) + return CURLE_SSL_CACERT_BADFILE; + } + } + + /* Load the client certificate */ + mbedtls_x509_crt_init(&connssl->clicert); + + if(data->set.str[STRING_CERT]) { + ret = mbedtls_x509_crt_parse_file(&connssl->clicert, + data->set.str[STRING_CERT]); + + if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s", + data->set.str[STRING_CERT], -ret, errorbuf); + + return CURLE_SSL_CERTPROBLEM; + } + } + + /* Load the client private key */ + mbedtls_pk_init(&connssl->pk); + + if(data->set.str[STRING_KEY]) { + ret = mbedtls_pk_parse_keyfile(&connssl->pk, data->set.str[STRING_KEY], + data->set.str[STRING_KEY_PASSWD]); + if(ret == 0 && !mbedtls_pk_can_do(&connssl->pk, MBEDTLS_PK_RSA)) + ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; + + if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s", + data->set.str[STRING_KEY], -ret, errorbuf); + + return CURLE_SSL_CERTPROBLEM; + } + } + + /* Load the CRL */ + mbedtls_x509_crl_init(&connssl->crl); + + if(data->set.str[STRING_SSL_CRLFILE]) { + ret = mbedtls_x509_crl_parse_file(&connssl->crl, + data->set.str[STRING_SSL_CRLFILE]); + + if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s", + data->set.str[STRING_SSL_CRLFILE], -ret, errorbuf); + + return CURLE_SSL_CRL_BADFILE; + } + } + + infof(data, "mbedTLS: Connecting to %s:%d\n", + conn->host.name, conn->remote_port); + + mbedtls_ssl_config_init(&connssl->config); + + mbedtls_ssl_init(&connssl->ssl); + if(mbedtls_ssl_setup(&connssl->ssl, &connssl->config)) { + failf(data, "mbedTLS: ssl_init failed"); + return CURLE_SSL_CONNECT_ERROR; + } + ret = mbedtls_ssl_config_defaults(&connssl->config, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT); + if(ret) { + failf(data, "mbedTLS: ssl_config failed"); + return CURLE_SSL_CONNECT_ERROR; + } + + /* new profile with RSA min key len = 1024 ... */ + mbedtls_ssl_conf_cert_profile( &connssl->config, + &mbedtls_x509_crt_profile_fr); + + switch(data->set.ssl.version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_1); + infof(data, "mbedTLS: Set min SSL version to TLS 1.0\n"); + break; + case CURL_SSLVERSION_SSLv3: + mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_0); + mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_0); + infof(data, "mbedTLS: Set SSL version to SSLv3\n"); + break; + case CURL_SSLVERSION_TLSv1_0: + mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_1); + mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_1); + infof(data, "mbedTLS: Set SSL version to TLS 1.0\n"); + break; + case CURL_SSLVERSION_TLSv1_1: + mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_2); + mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_2); + infof(data, "mbedTLS: Set SSL version to TLS 1.1\n"); + break; + case CURL_SSLVERSION_TLSv1_2: + mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_3); + mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_3); + infof(data, "mbedTLS: Set SSL version to TLS 1.2\n"); + break; + default: + failf(data, "mbedTLS: Unsupported SSL protocol version"); + return CURLE_SSL_CONNECT_ERROR; + } + + mbedtls_ssl_conf_authmode(&connssl->config, MBEDTLS_SSL_VERIFY_OPTIONAL); + + mbedtls_ssl_conf_rng(&connssl->config, mbedtls_ctr_drbg_random, + &connssl->ctr_drbg); + mbedtls_ssl_set_bio(&connssl->ssl, &conn->sock[sockindex], + mbedtls_net_send, + mbedtls_net_recv, + NULL /* rev_timeout() */); + + mbedtls_ssl_conf_ciphersuites(&connssl->config, + mbedtls_ssl_list_ciphersuites()); + if(!Curl_ssl_getsessionid(conn, &old_session, &old_session_size)) { + memcpy(&connssl->ssn, old_session, old_session_size); + infof(data, "mbedTLS re-using session\n"); + } + + mbedtls_ssl_set_session(&connssl->ssl, + &connssl->ssn); + + mbedtls_ssl_conf_ca_chain(&connssl->config, + &connssl->cacert, + &connssl->crl); + + if(data->set.str[STRING_KEY]) { + mbedtls_ssl_conf_own_cert(&connssl->config, + &connssl->clicert, &connssl->pk); + } + if(!Curl_inet_pton(AF_INET, conn->host.name, &addr) && +#ifdef ENABLE_IPV6 + !Curl_inet_pton(AF_INET6, conn->host.name, &addr) && +#endif + sni && mbedtls_ssl_set_hostname(&connssl->ssl, conn->host.name)) { + infof(data, "WARNING: failed to configure " + "server name indication (SNI) TLS extension\n"); + } + +#ifdef HAS_ALPN + if(data->set.ssl_enable_alpn) { + const char **p = &connssl->protocols[0]; +#ifdef USE_NGHTTP2 + if(data->set.httpversion >= CURL_HTTP_VERSION_2) + *p++ = NGHTTP2_PROTO_VERSION_ID; +#endif + *p++ = ALPN_HTTP_1_1; + *p = NULL; + /* this function doesn't clone the protocols array, which is why we need + to keep it around */ + if(mbedtls_ssl_conf_alpn_protocols(&connssl->config, + &connssl->protocols[0])) { + failf(data, "Failed setting ALPN protocols"); + return CURLE_SSL_CONNECT_ERROR; + } + for(p = &connssl->protocols[0]; *p; ++p) + infof(data, "ALPN, offering %s\n", *p); + } +#endif + +#ifdef MBEDTLS_DEBUG + mbedtls_ssl_conf_dbg(&connssl->ssl, mbedtls_debug, data); +#endif + + connssl->connecting_state = ssl_connect_2; + + return CURLE_OK; +} + +static CURLcode +mbedtls_connect_step2(struct connectdata *conn, + int sockindex) +{ + int ret; + struct SessionHandle *data = conn->data; + struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + const mbedtls_x509_crt *peercert; + +#ifdef HAS_ALPN + const char* next_protocol; +#endif + + char errorbuf[128]; + errorbuf[0] = 0; + + conn->recv[sockindex] = mbedtls_recv; + conn->send[sockindex] = mbedtls_send; + + ret = mbedtls_ssl_handshake(&connssl->ssl); + + if(ret == MBEDTLS_ERR_SSL_WANT_READ) { + connssl->connecting_state = ssl_connect_2_reading; + return CURLE_OK; + } + else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) { + connssl->connecting_state = ssl_connect_2_writing; + return CURLE_OK; + } + else if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s", + -ret, errorbuf); + return CURLE_SSL_CONNECT_ERROR; + } + + infof(data, "mbedTLS: Handshake complete, cipher is %s\n", + mbedtls_ssl_get_ciphersuite(&conn->ssl[sockindex].ssl) + ); + + ret = mbedtls_ssl_get_verify_result(&conn->ssl[sockindex].ssl); + + if(ret && data->set.ssl.verifypeer) { + if(ret & MBEDTLS_X509_BADCERT_EXPIRED) + failf(data, "Cert verify failed: BADCERT_EXPIRED"); + + if(ret & MBEDTLS_X509_BADCERT_REVOKED) { + failf(data, "Cert verify failed: BADCERT_REVOKED"); + return CURLE_SSL_CACERT; + } + + if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH) + failf(data, "Cert verify failed: BADCERT_CN_MISMATCH"); + + if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED) + failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED"); + + return CURLE_PEER_FAILED_VERIFICATION; + } + + peercert = mbedtls_ssl_get_peer_cert(&connssl->ssl); + + if(peercert && data->set.verbose) { + const size_t bufsize = 16384; + char *buffer = malloc(bufsize); + + if(!buffer) + return CURLE_OUT_OF_MEMORY; + + if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0) + infof(data, "Dumping cert info:\n%s\n", buffer); + else + infof(data, "Unable to dump certificate information.\n"); + + free(buffer); + } + + if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { + int size; + CURLcode result; + mbedtls_x509_crt *p; + unsigned char pubkey[PUB_DER_MAX_BYTES]; + + if(!peercert || !peercert->raw.p || !peercert->raw.len) { + failf(data, "Failed due to missing peer certificate"); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + p = calloc(1, sizeof(*p)); + + if(!p) + return CURLE_OUT_OF_MEMORY; + + mbedtls_x509_crt_init(p); + + /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der + needs a non-const key, for now. + https://github.com/ARMmbed/mbedtls/issues/396 */ + if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { + failf(data, "Failed copying peer certificate"); + mbedtls_x509_crt_free(p); + free(p); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); + + if(size <= 0) { + failf(data, "Failed copying public key from peer certificate"); + mbedtls_x509_crt_free(p); + free(p); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */ + result = Curl_pin_peer_pubkey(data, + data->set.str[STRING_SSL_PINNEDPUBLICKEY], + &pubkey[PUB_DER_MAX_BYTES - size], size); + if(result) { + mbedtls_x509_crt_free(p); + free(p); + return result; + } + + mbedtls_x509_crt_free(p); + free(p); + } + +#ifdef HAS_ALPN + if(data->set.ssl_enable_alpn) { + next_protocol = mbedtls_ssl_get_alpn_protocol(&connssl->ssl); + + if(next_protocol) { + infof(data, "ALPN, server accepted to use %s\n", next_protocol); +#ifdef USE_NGHTTP2 + if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID, + NGHTTP2_PROTO_VERSION_ID_LEN) && + !next_protocol[NGHTTP2_PROTO_VERSION_ID_LEN]) { + conn->negnpn = CURL_HTTP_VERSION_2; + } + else +#endif + if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) && + !next_protocol[ALPN_HTTP_1_1_LENGTH]) { + conn->negnpn = CURL_HTTP_VERSION_1_1; + } + } + else { + infof(data, "ALPN, server did not agree to a protocol\n"); + } + } +#endif + + connssl->connecting_state = ssl_connect_3; + infof(data, "SSL connected\n"); + + return CURLE_OK; +} + +static CURLcode +mbedtls_connect_step3(struct connectdata *conn, + int sockindex) +{ + CURLcode retcode = CURLE_OK; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct SessionHandle *data = conn->data; + void *old_ssl_sessionid = NULL; + mbedtls_ssl_session *our_ssl_sessionid = &conn->ssl[sockindex].ssn; + int incache; + + DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); + + /* Save the current session data for possible re-use */ + incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); + if(incache) { + if(old_ssl_sessionid != our_ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing\n"); + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + incache = FALSE; + } + } + if(!incache) { + void *new_session = malloc(sizeof(mbedtls_ssl_session)); + + if(new_session) { + memcpy(new_session, our_ssl_sessionid, + sizeof(mbedtls_ssl_session)); + + retcode = Curl_ssl_addsessionid(conn, new_session, + sizeof(mbedtls_ssl_session)); + } + else { + retcode = CURLE_OUT_OF_MEMORY; + } + + if(retcode) { + failf(data, "failed to store ssl session"); + return retcode; + } + } + + connssl->connecting_state = ssl_connect_done; + + return CURLE_OK; +} + +static ssize_t mbedtls_send(struct connectdata *conn, + int sockindex, + const void *mem, + size_t len, + CURLcode *curlcode) +{ + int ret = -1; + + ret = mbedtls_ssl_write(&conn->ssl[sockindex].ssl, + (unsigned char *)mem, len); + + if(ret < 0) { + *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ? + CURLE_AGAIN : CURLE_SEND_ERROR; + ret = -1; + } + + return ret; +} + +void Curl_mbedtls_close_all(struct SessionHandle *data) +{ + (void)data; +} + +void Curl_mbedtls_close(struct connectdata *conn, int sockindex) +{ + mbedtls_pk_free(&conn->ssl[sockindex].pk); + mbedtls_x509_crt_free(&conn->ssl[sockindex].clicert); + mbedtls_x509_crt_free(&conn->ssl[sockindex].cacert); + mbedtls_x509_crl_free(&conn->ssl[sockindex].crl); + mbedtls_ssl_config_free(&conn->ssl[sockindex].config); + mbedtls_ssl_free(&conn->ssl[sockindex].ssl); + mbedtls_ctr_drbg_free(&conn->ssl[sockindex].ctr_drbg); +#ifndef THREADING_SUPPORT + mbedtls_entropy_free(&conn->ssl[sockindex].entropy); +#endif /* THREADING_SUPPORT */ +} + +static ssize_t mbedtls_recv(struct connectdata *conn, + int num, + char *buf, + size_t buffersize, + CURLcode *curlcode) +{ + int ret = -1; + ssize_t len = -1; + + memset(buf, 0, buffersize); + ret = mbedtls_ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf, + buffersize); + + if(ret <= 0) { + if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) + return 0; + + *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ? + CURLE_AGAIN : CURLE_RECV_ERROR; + return -1; + } + + len = ret; + + return len; +} + +void Curl_mbedtls_session_free(void *ptr) +{ + free(ptr); +} + +size_t Curl_mbedtls_version(char *buffer, size_t size) +{ + unsigned int version = mbedtls_version_get_number(); + return snprintf(buffer, size, "mbedTLS/%d.%d.%d", version>>24, + (version>>16)&0xff, (version>>8)&0xff); +} + +static CURLcode +mbedtls_connect_common(struct connectdata *conn, + int sockindex, + bool nonblocking, + bool *done) +{ + CURLcode retcode; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + curl_socket_t sockfd = conn->sock[sockindex]; + long timeout_ms; + int what; + + /* check if the connection has already been established */ + if(ssl_connection_complete == connssl->state) { + *done = TRUE; + return CURLE_OK; + } + + if(ssl_connect_1==connssl->connecting_state) { + /* Find out how much more time we're allowed */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + retcode = mbedtls_connect_step1(conn, sockindex); + if(retcode) + return retcode; + } + + while(ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state) { + + /* check allowed time left */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + /* if ssl is expecting something, check if it's available. */ + if(connssl->connecting_state == ssl_connect_2_reading + || connssl->connecting_state == ssl_connect_2_writing) { + + curl_socket_t writefd = ssl_connect_2_writing== + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading== + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + + what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + return CURLE_SSL_CONNECT_ERROR; + } + else if(0 == what) { + if(nonblocking) { + *done = FALSE; + return CURLE_OK; + } + else { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + } + /* socket is readable or writable */ + } + + /* Run transaction, and return to the caller if it failed or if + * this connection is part of a multi handle and this loop would + * execute again. This permits the owner of a multi handle to + * abort a connection attempt before step2 has completed while + * ensuring that a client using select() or epoll() will always + * have a valid fdset to wait on. + */ + retcode = mbedtls_connect_step2(conn, sockindex); + if(retcode || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return retcode; + + } /* repeat step2 until all transactions are done. */ + + if(ssl_connect_3==connssl->connecting_state) { + retcode = mbedtls_connect_step3(conn, sockindex); + if(retcode) + return retcode; + } + + if(ssl_connect_done==connssl->connecting_state) { + connssl->state = ssl_connection_complete; + conn->recv[sockindex] = mbedtls_recv; + conn->send[sockindex] = mbedtls_send; + *done = TRUE; + } + else + *done = FALSE; + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + + return CURLE_OK; +} + +CURLcode +Curl_mbedtls_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done) +{ + return mbedtls_connect_common(conn, sockindex, TRUE, done); +} + + +CURLcode +Curl_mbedtls_connect(struct connectdata *conn, + int sockindex) +{ + CURLcode retcode; + bool done = FALSE; + + retcode = mbedtls_connect_common(conn, sockindex, FALSE, &done); + if(retcode) + return retcode; + + DEBUGASSERT(done); + + return CURLE_OK; +} + +/* + * return 0 error initializing SSL + * return 1 SSL initialized successfully + */ +int mbedtls_init(void) +{ + return Curl_polarsslthreadlock_thread_setup(); +} + +void mbedtls_cleanup(void) +{ + (void)Curl_polarsslthreadlock_thread_cleanup(); +} + +#endif /* USE_MBEDTLS */ diff --git a/project/jni/curl/lib/vtls/mbedtls.h b/project/jni/curl/lib/vtls/mbedtls.h new file mode 100644 index 000000000..fcf483ff3 --- /dev/null +++ b/project/jni/curl/lib/vtls/mbedtls.h @@ -0,0 +1,75 @@ +#ifndef HEADER_CURL_MBEDTLS_H +#define HEADER_CURL_MBEDTLS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 2010, Hoi-Ho Chan, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_MBEDTLS + +/* Called on first use mbedTLS, setup threading if supported */ +int mbedtls_init(void); +void mbedtls_cleanup(void); + + +CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex); + +CURLcode Curl_mbedtls_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done); + +/* tell mbedTLS to close down all open information regarding connections (and + thus session ID caching etc) */ +void Curl_mbedtls_close_all(struct SessionHandle *data); + + /* close a SSL connection */ +void Curl_mbedtls_close(struct connectdata *conn, int sockindex); + +void Curl_mbedtls_session_free(void *ptr); +size_t Curl_mbedtls_version(char *buffer, size_t size); +int Curl_mbedtls_shutdown(struct connectdata *conn, int sockindex); + +/* API setup for mbedTLS */ +#define curlssl_init() mbedtls_init() +#define curlssl_cleanup() mbedtls_cleanup() +#define curlssl_connect Curl_mbedtls_connect +#define curlssl_connect_nonblocking Curl_mbedtls_connect_nonblocking +#define curlssl_session_free(x) Curl_mbedtls_session_free(x) +#define curlssl_close_all Curl_mbedtls_close_all +#define curlssl_close Curl_mbedtls_close +#define curlssl_shutdown(x,y) 0 +#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN) +#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN) +#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL) +#define curlssl_version Curl_mbedtls_version +#define curlssl_check_cxn(x) (x=x, -1) +#define curlssl_data_pending(x,y) (x=x, y=y, 0) +#define CURL_SSL_BACKEND CURLSSLBACKEND_MBEDTLS +#define curlssl_sha256sum(a,b,c,d) mbedtls_sha256(a,b,c,0) + +/* This might cause libcurl to use a weeker random! + TODO: implement proper use of Polarssl's CTR-DRBG or HMAC-DRBG and use that +*/ +#define curlssl_random(x,y,z) (x=x, y=y, z=z, CURLE_NOT_BUILT_IN) + +#endif /* USE_MBEDTLS */ +#endif /* HEADER_CURL_MBEDTLS_H */ diff --git a/project/jni/curl/lib/vtls/nss.c b/project/jni/curl/lib/vtls/nss.c new file mode 100644 index 000000000..3922d9c90 --- /dev/null +++ b/project/jni/curl/lib/vtls/nss.c @@ -0,0 +1,2081 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Source file for all NSS-specific code for the TLS/SSL layer. No code + * but vtls.c should ever call or use these functions. + */ + +#include "curl_setup.h" + +#ifdef USE_NSS + +#include "urldata.h" +#include "sendf.h" +#include "formdata.h" /* for the boundary function */ +#include "url.h" /* for the ssl config check function */ +#include "connect.h" +#include "strequal.h" +#include "select.h" +#include "vtls.h" +#include "llist.h" +#include "curl_printf.h" +#include "nssg.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for SECKEY_DestroyPublicKey() */ + +#define NSSVERNUM ((NSS_VMAJOR<<16)|(NSS_VMINOR<<8)|NSS_VPATCH) + +#if NSSVERNUM >= 0x030f00 /* 3.15.0 */ +#include +#endif + +#include "rawstr.h" +#include "warnless.h" +#include "x509asn1.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#define SSL_DIR "/etc/pki/nssdb" + +/* enough to fit the string "PEM Token #[0|1]" */ +#define SLOTSIZE 13 + +PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd); + +PRLock * nss_initlock = NULL; +PRLock * nss_crllock = NULL; +struct curl_llist *nss_crl_list = NULL; +NSSInitContext * nss_context = NULL; + +volatile int initialized = 0; + +typedef struct { + const char *name; + int num; +} cipher_s; + +#define PK11_SETATTRS(_attr, _idx, _type, _val, _len) do { \ + CK_ATTRIBUTE *ptr = (_attr) + ((_idx)++); \ + ptr->type = (_type); \ + ptr->pValue = (_val); \ + ptr->ulValueLen = (_len); \ +} WHILE_FALSE + +#define CERT_NewTempCertificate __CERT_NewTempCertificate + +#define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0]) +static const cipher_s cipherlist[] = { + /* SSL2 cipher suites */ + {"rc4", SSL_EN_RC4_128_WITH_MD5}, + {"rc4-md5", SSL_EN_RC4_128_WITH_MD5}, + {"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5}, + {"rc2", SSL_EN_RC2_128_CBC_WITH_MD5}, + {"rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5}, + {"des", SSL_EN_DES_64_CBC_WITH_MD5}, + {"desede3", SSL_EN_DES_192_EDE3_CBC_WITH_MD5}, + /* SSL3/TLS cipher suites */ + {"rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5}, + {"rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA}, + {"rsa_3des_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA}, + {"rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA}, + {"rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5}, + {"rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5}, + {"rsa_null_md5", SSL_RSA_WITH_NULL_MD5}, + {"rsa_null_sha", SSL_RSA_WITH_NULL_SHA}, + {"fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA}, + {"fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA}, + {"fortezza", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA}, + {"fortezza_rc4_128_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA}, + {"fortezza_null", SSL_FORTEZZA_DMS_WITH_NULL_SHA}, + /* TLS 1.0: Exportable 56-bit Cipher Suites. */ + {"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA}, + {"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA}, + /* AES ciphers. */ + {"dhe_dss_aes_128_cbc_sha", TLS_DHE_DSS_WITH_AES_128_CBC_SHA}, + {"dhe_dss_aes_256_cbc_sha", TLS_DHE_DSS_WITH_AES_256_CBC_SHA}, + {"dhe_rsa_aes_128_cbc_sha", TLS_DHE_RSA_WITH_AES_128_CBC_SHA}, + {"dhe_rsa_aes_256_cbc_sha", TLS_DHE_RSA_WITH_AES_256_CBC_SHA}, + {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA}, + {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA}, + /* ECC ciphers. */ + {"ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA}, + {"ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA}, + {"ecdh_ecdsa_3des_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA}, + {"ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA}, + {"ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA}, + {"ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA}, + {"ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA}, + {"ecdhe_ecdsa_3des_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA}, + {"ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA}, + {"ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}, + {"ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA}, + {"ecdh_rsa_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA}, + {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA}, + {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA}, + {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA}, + {"echde_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA}, + {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA}, + {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA}, + {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, + {"ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, + {"ecdh_anon_null_sha", TLS_ECDH_anon_WITH_NULL_SHA}, + {"ecdh_anon_rc4_128sha", TLS_ECDH_anon_WITH_RC4_128_SHA}, + {"ecdh_anon_3des_sha", TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA}, + {"ecdh_anon_aes_128_sha", TLS_ECDH_anon_WITH_AES_128_CBC_SHA}, + {"ecdh_anon_aes_256_sha", TLS_ECDH_anon_WITH_AES_256_CBC_SHA}, +#ifdef TLS_RSA_WITH_NULL_SHA256 + /* new HMAC-SHA256 cipher suites specified in RFC */ + {"rsa_null_sha_256", TLS_RSA_WITH_NULL_SHA256}, + {"rsa_aes_128_cbc_sha_256", TLS_RSA_WITH_AES_128_CBC_SHA256}, + {"rsa_aes_256_cbc_sha_256", TLS_RSA_WITH_AES_256_CBC_SHA256}, + {"dhe_rsa_aes_128_cbc_sha_256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256}, + {"dhe_rsa_aes_256_cbc_sha_256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256}, + {"ecdhe_ecdsa_aes_128_cbc_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256}, + {"ecdhe_rsa_aes_128_cbc_sha_256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256}, +#endif +#ifdef TLS_RSA_WITH_AES_128_GCM_SHA256 + /* AES GCM cipher suites in RFC 5288 and RFC 5289 */ + {"rsa_aes_128_gcm_sha_256", TLS_RSA_WITH_AES_128_GCM_SHA256}, + {"dhe_rsa_aes_128_gcm_sha_256", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256}, + {"dhe_dss_aes_128_gcm_sha_256", TLS_DHE_DSS_WITH_AES_128_GCM_SHA256}, + {"ecdhe_ecdsa_aes_128_gcm_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, + {"ecdh_ecdsa_aes_128_gcm_sha_256", TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256}, + {"ecdhe_rsa_aes_128_gcm_sha_256", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + {"ecdh_rsa_aes_128_gcm_sha_256", TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256}, +#endif +}; + +static const char* pem_library = "libnsspem.so"; +SECMODModule* mod = NULL; + +/* NSPR I/O layer we use to detect blocking direction during SSL handshake */ +static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER; +static PRIOMethods nspr_io_methods; + +static const char* nss_error_to_name(PRErrorCode code) +{ + const char *name = PR_ErrorToName(code); + if(name) + return name; + + return "unknown error"; +} + +static void nss_print_error_message(struct SessionHandle *data, PRUint32 err) +{ + failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT)); +} + +static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model, + char *cipher_list) +{ + unsigned int i; + PRBool cipher_state[NUM_OF_CIPHERS]; + PRBool found; + char *cipher; + + /* use accessors to avoid dynamic linking issues after an update of NSS */ + const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers(); + const PRUint16 *implemented_ciphers = SSL_GetImplementedCiphers(); + if(!implemented_ciphers) + return SECFailure; + + /* First disable all ciphers. This uses a different max value in case + * NSS adds more ciphers later we don't want them available by + * accident + */ + for(i = 0; i < num_implemented_ciphers; i++) { + SSL_CipherPrefSet(model, implemented_ciphers[i], PR_FALSE); + } + + /* Set every entry in our list to false */ + for(i = 0; i < NUM_OF_CIPHERS; i++) { + cipher_state[i] = PR_FALSE; + } + + cipher = cipher_list; + + while(cipher_list && (cipher_list[0])) { + while((*cipher) && (ISSPACE(*cipher))) + ++cipher; + + if((cipher_list = strchr(cipher, ','))) { + *cipher_list++ = '\0'; + } + + found = PR_FALSE; + + for(i=0; iset.str[cert_kind]; + const char *n; + + if(!is_file(str)) + /* no such file exists, use the string as nickname */ + return strdup(str); + + /* search the first slash; we require at least one slash in a file name */ + n = strchr(str, '/'); + if(!n) { + infof(data, "warning: certificate file name \"%s\" handled as nickname; " + "please use \"./%s\" to force file name\n", str, str); + return strdup(str); + } + + /* we'll use the PEM reader to read the certificate from file */ + return NULL; +} + +/* Call PK11_CreateGenericObject() with the given obj_class and filename. If + * the call succeeds, append the object handle to the list of objects so that + * the object can be destroyed in Curl_nss_close(). */ +static CURLcode nss_create_object(struct ssl_connect_data *ssl, + CK_OBJECT_CLASS obj_class, + const char *filename, bool cacert) +{ + PK11SlotInfo *slot; + PK11GenericObject *obj; + CK_BBOOL cktrue = CK_TRUE; + CK_BBOOL ckfalse = CK_FALSE; + CK_ATTRIBUTE attrs[/* max count of attributes */ 4]; + int attr_cnt = 0; + CURLcode result = (cacert) + ? CURLE_SSL_CACERT_BADFILE + : CURLE_SSL_CERTPROBLEM; + + const int slot_id = (cacert) ? 0 : 1; + char *slot_name = aprintf("PEM Token #%d", slot_id); + if(!slot_name) + return CURLE_OUT_OF_MEMORY; + + slot = PK11_FindSlotByName(slot_name); + free(slot_name); + if(!slot) + return result; + + PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class)); + PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); + PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)filename, + strlen(filename) + 1); + + if(CKO_CERTIFICATE == obj_class) { + CK_BBOOL *pval = (cacert) ? (&cktrue) : (&ckfalse); + PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval)); + } + + obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE); + PK11_FreeSlot(slot); + if(!obj) + return result; + + if(!Curl_llist_insert_next(ssl->obj_list, ssl->obj_list->tail, obj)) { + PK11_DestroyGenericObject(obj); + return CURLE_OUT_OF_MEMORY; + } + + if(!cacert && CKO_CERTIFICATE == obj_class) + /* store reference to a client certificate */ + ssl->obj_clicert = obj; + + return CURLE_OK; +} + +/* Destroy the NSS object whose handle is given by ptr. This function is + * a callback of Curl_llist_alloc() used by Curl_llist_destroy() to destroy + * NSS objects in Curl_nss_close() */ +static void nss_destroy_object(void *user, void *ptr) +{ + PK11GenericObject *obj = (PK11GenericObject *)ptr; + (void) user; + PK11_DestroyGenericObject(obj); +} + +/* same as nss_destroy_object() but for CRL items */ +static void nss_destroy_crl_item(void *user, void *ptr) +{ + SECItem *crl_der = (SECItem *)ptr; + (void) user; + SECITEM_FreeItem(crl_der, PR_TRUE); +} + +static CURLcode nss_load_cert(struct ssl_connect_data *ssl, + const char *filename, PRBool cacert) +{ + CURLcode result = (cacert) + ? CURLE_SSL_CACERT_BADFILE + : CURLE_SSL_CERTPROBLEM; + + /* libnsspem.so leaks memory if the requested file does not exist. For more + * details, go to . */ + if(is_file(filename)) + result = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert); + + if(!result && !cacert) { + /* we have successfully loaded a client certificate */ + CERTCertificate *cert; + char *nickname = NULL; + char *n = strrchr(filename, '/'); + if(n) + n++; + + /* The following undocumented magic helps to avoid a SIGSEGV on call + * of PK11_ReadRawAttribute() from SelectClientCert() when using an + * immature version of libnsspem.so. For more details, go to + * . */ + nickname = aprintf("PEM Token #1:%s", n); + if(nickname) { + cert = PK11_FindCertFromNickname(nickname, NULL); + if(cert) + CERT_DestroyCertificate(cert); + + free(nickname); + } + } + + return result; +} + +/* add given CRL to cache if it is not already there */ +static CURLcode nss_cache_crl(SECItem *crl_der) +{ + CERTCertDBHandle *db = CERT_GetDefaultCertDB(); + CERTSignedCrl *crl = SEC_FindCrlByDERCert(db, crl_der, 0); + if(crl) { + /* CRL already cached */ + SEC_DestroyCrl(crl); + SECITEM_FreeItem(crl_der, PR_TRUE); + return CURLE_OK; + } + + /* acquire lock before call of CERT_CacheCRL() and accessing nss_crl_list */ + PR_Lock(nss_crllock); + + /* store the CRL item so that we can free it in Curl_nss_cleanup() */ + if(!Curl_llist_insert_next(nss_crl_list, nss_crl_list->tail, crl_der)) { + SECITEM_FreeItem(crl_der, PR_TRUE); + PR_Unlock(nss_crllock); + return CURLE_OUT_OF_MEMORY; + } + + if(SECSuccess != CERT_CacheCRL(db, crl_der)) { + /* unable to cache CRL */ + PR_Unlock(nss_crllock); + return CURLE_SSL_CRL_BADFILE; + } + + /* we need to clear session cache, so that the CRL could take effect */ + SSL_ClearSessionCache(); + PR_Unlock(nss_crllock); + return CURLE_OK; +} + +static CURLcode nss_load_crl(const char* crlfilename) +{ + PRFileDesc *infile; + PRFileInfo info; + SECItem filedata = { 0, NULL, 0 }; + SECItem *crl_der = NULL; + char *body; + + infile = PR_Open(crlfilename, PR_RDONLY, 0); + if(!infile) + return CURLE_SSL_CRL_BADFILE; + + if(PR_SUCCESS != PR_GetOpenFileInfo(infile, &info)) + goto fail; + + if(!SECITEM_AllocItem(NULL, &filedata, info.size + /* zero ended */ 1)) + goto fail; + + if(info.size != PR_Read(infile, filedata.data, info.size)) + goto fail; + + crl_der = SECITEM_AllocItem(NULL, NULL, 0U); + if(!crl_der) + goto fail; + + /* place a trailing zero right after the visible data */ + body = (char*)filedata.data; + body[--filedata.len] = '\0'; + + body = strstr(body, "-----BEGIN"); + if(body) { + /* assume ASCII */ + char *trailer; + char *begin = PORT_Strchr(body, '\n'); + if(!begin) + begin = PORT_Strchr(body, '\r'); + if(!begin) + goto fail; + + trailer = strstr(++begin, "-----END"); + if(!trailer) + goto fail; + + /* retrieve DER from ASCII */ + *trailer = '\0'; + if(ATOB_ConvertAsciiToItem(crl_der, begin)) + goto fail; + + SECITEM_FreeItem(&filedata, PR_FALSE); + } + else + /* assume DER */ + *crl_der = filedata; + + PR_Close(infile); + return nss_cache_crl(crl_der); + +fail: + PR_Close(infile); + SECITEM_FreeItem(crl_der, PR_TRUE); + SECITEM_FreeItem(&filedata, PR_FALSE); + return CURLE_SSL_CRL_BADFILE; +} + +static CURLcode nss_load_key(struct connectdata *conn, int sockindex, + char *key_file) +{ + PK11SlotInfo *slot; + SECStatus status; + CURLcode result; + struct ssl_connect_data *ssl = conn->ssl; + + (void)sockindex; /* unused */ + + result = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE); + if(result) { + PR_SetError(SEC_ERROR_BAD_KEY, 0); + return result; + } + + slot = PK11_FindSlotByName("PEM Token #1"); + if(!slot) + return CURLE_SSL_CERTPROBLEM; + + /* This will force the token to be seen as re-inserted */ + SECMOD_WaitForAnyTokenEvent(mod, 0, 0); + PK11_IsPresent(slot); + + status = PK11_Authenticate(slot, PR_TRUE, + conn->data->set.str[STRING_KEY_PASSWD]); + PK11_FreeSlot(slot); + + return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM; +} + +static int display_error(struct connectdata *conn, PRInt32 err, + const char *filename) +{ + switch(err) { + case SEC_ERROR_BAD_PASSWORD: + failf(conn->data, "Unable to load client key: Incorrect password"); + return 1; + case SEC_ERROR_UNKNOWN_CERT: + failf(conn->data, "Unable to load certificate %s", filename); + return 1; + default: + break; + } + return 0; /* The caller will print a generic error */ +} + +static CURLcode cert_stuff(struct connectdata *conn, int sockindex, + char *cert_file, char *key_file) +{ + struct SessionHandle *data = conn->data; + CURLcode result; + + if(cert_file) { + result = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE); + if(result) { + const PRErrorCode err = PR_GetError(); + if(!display_error(conn, err, cert_file)) { + const char *err_name = nss_error_to_name(err); + failf(data, "unable to load client cert: %d (%s)", err, err_name); + } + + return result; + } + } + + if(key_file || (is_file(cert_file))) { + if(key_file) + result = nss_load_key(conn, sockindex, key_file); + else + /* In case the cert file also has the key */ + result = nss_load_key(conn, sockindex, cert_file); + if(result) { + const PRErrorCode err = PR_GetError(); + if(!display_error(conn, err, key_file)) { + const char *err_name = nss_error_to_name(err); + failf(data, "unable to load client key: %d (%s)", err, err_name); + } + + return result; + } + } + + return CURLE_OK; +} + +static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg) +{ + (void)slot; /* unused */ + + if(retry || NULL == arg) + return NULL; + else + return (char *)PORT_Strdup((char *)arg); +} + +/* bypass the default SSL_AuthCertificate() hook in case we do not want to + * verify peer */ +static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig, + PRBool isServer) +{ + struct connectdata *conn = (struct connectdata *)arg; + +#ifdef SSL_ENABLE_OCSP_STAPLING + if(conn->data->set.ssl.verifystatus) { + SECStatus cacheResult; + + const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd); + if(!csa) { + failf(conn->data, "Invalid OCSP response"); + return SECFailure; + } + + if(csa->len == 0) { + failf(conn->data, "No OCSP response received"); + return SECFailure; + } + + cacheResult = CERT_CacheOCSPResponseFromSideChannel( + CERT_GetDefaultCertDB(), SSL_PeerCertificate(fd), + PR_Now(), &csa->items[0], arg + ); + + if(cacheResult != SECSuccess) { + failf(conn->data, "Invalid OCSP response"); + return cacheResult; + } + } +#endif + + if(!conn->data->set.ssl.verifypeer) { + infof(conn->data, "skipping SSL peer certificate verification\n"); + return SECSuccess; + } + + return SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer); +} + +/** + * Inform the application that the handshake is complete. + */ +static void HandshakeCallback(PRFileDesc *sock, void *arg) +{ + struct connectdata *conn = (struct connectdata*) arg; + unsigned int buflenmax = 50; + unsigned char buf[50]; + unsigned int buflen; + SSLNextProtoState state; + + if(!conn->data->set.ssl_enable_npn && !conn->data->set.ssl_enable_alpn) { + return; + } + + if(SSL_GetNextProto(sock, &state, buf, &buflen, buflenmax) == SECSuccess) { + + switch(state) { + case SSL_NEXT_PROTO_NO_SUPPORT: + case SSL_NEXT_PROTO_NO_OVERLAP: + infof(conn->data, "ALPN/NPN, server did not agree to a protocol\n"); + return; +#ifdef SSL_ENABLE_ALPN + case SSL_NEXT_PROTO_SELECTED: + infof(conn->data, "ALPN, server accepted to use %.*s\n", buflen, buf); + break; +#endif + case SSL_NEXT_PROTO_NEGOTIATED: + infof(conn->data, "NPN, server accepted to use %.*s\n", buflen, buf); + break; + } + +#ifdef USE_NGHTTP2 + if(buflen == NGHTTP2_PROTO_VERSION_ID_LEN && + !memcmp(NGHTTP2_PROTO_VERSION_ID, buf, NGHTTP2_PROTO_VERSION_ID_LEN)) { + conn->negnpn = CURL_HTTP_VERSION_2; + } + else +#endif + if(buflen == ALPN_HTTP_1_1_LENGTH && + !memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) { + conn->negnpn = CURL_HTTP_VERSION_1_1; + } + } +} + +#if NSSVERNUM >= 0x030f04 /* 3.15.4 */ +static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data, + PRBool *canFalseStart) +{ + struct connectdata *conn = client_data; + struct SessionHandle *data = conn->data; + + SSLChannelInfo channelInfo; + SSLCipherSuiteInfo cipherInfo; + + SECStatus rv; + PRBool negotiatedExtension; + + *canFalseStart = PR_FALSE; + + if(SSL_GetChannelInfo(sock, &channelInfo, sizeof(channelInfo)) != SECSuccess) + return SECFailure; + + if(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo, + sizeof(cipherInfo)) != SECSuccess) + return SECFailure; + + /* Prevent version downgrade attacks from TLS 1.2, and avoid False Start for + * TLS 1.3 and later. See https://bugzilla.mozilla.org/show_bug.cgi?id=861310 + */ + if(channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2) + goto end; + + /* Only allow ECDHE key exchange algorithm. + * See https://bugzilla.mozilla.org/show_bug.cgi?id=952863 */ + if(cipherInfo.keaType != ssl_kea_ecdh) + goto end; + + /* Prevent downgrade attacks on the symmetric cipher. We do not allow CBC + * mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt + * design. See https://bugzilla.mozilla.org/show_bug.cgi?id=1109766 */ + if(cipherInfo.symCipher != ssl_calg_aes_gcm) + goto end; + + /* Enforce ALPN or NPN to do False Start, as an indicator of server + * compatibility. */ + rv = SSL_HandshakeNegotiatedExtension(sock, ssl_app_layer_protocol_xtn, + &negotiatedExtension); + if(rv != SECSuccess || !negotiatedExtension) { + rv = SSL_HandshakeNegotiatedExtension(sock, ssl_next_proto_nego_xtn, + &negotiatedExtension); + } + + if(rv != SECSuccess || !negotiatedExtension) + goto end; + + *canFalseStart = PR_TRUE; + + infof(data, "Trying TLS False Start\n"); + +end: + return SECSuccess; +} +#endif + +static void display_cert_info(struct SessionHandle *data, + CERTCertificate *cert) +{ + char *subject, *issuer, *common_name; + PRExplodedTime printableTime; + char timeString[256]; + PRTime notBefore, notAfter; + + subject = CERT_NameToAscii(&cert->subject); + issuer = CERT_NameToAscii(&cert->issuer); + common_name = CERT_GetCommonName(&cert->subject); + infof(data, "\tsubject: %s\n", subject); + + CERT_GetCertTimes(cert, ¬Before, ¬After); + PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime); + PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime); + infof(data, "\tstart date: %s\n", timeString); + PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime); + PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime); + infof(data, "\texpire date: %s\n", timeString); + infof(data, "\tcommon name: %s\n", common_name); + infof(data, "\tissuer: %s\n", issuer); + + PR_Free(subject); + PR_Free(issuer); + PR_Free(common_name); +} + +static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock) +{ + CURLcode result = CURLE_OK; + SSLChannelInfo channel; + SSLCipherSuiteInfo suite; + CERTCertificate *cert; + CERTCertificate *cert2; + CERTCertificate *cert3; + PRTime now; + int i; + + if(SSL_GetChannelInfo(sock, &channel, sizeof channel) == + SECSuccess && channel.length == sizeof channel && + channel.cipherSuite) { + if(SSL_GetCipherSuiteInfo(channel.cipherSuite, + &suite, sizeof suite) == SECSuccess) { + infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName); + } + } + + cert = SSL_PeerCertificate(sock); + if(cert) { + infof(conn->data, "Server certificate:\n"); + + if(!conn->data->set.ssl.certinfo) { + display_cert_info(conn->data, cert); + CERT_DestroyCertificate(cert); + } + else { + /* Count certificates in chain. */ + now = PR_Now(); + i = 1; + if(!cert->isRoot) { + cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA); + while(cert2) { + i++; + if(cert2->isRoot) { + CERT_DestroyCertificate(cert2); + break; + } + cert3 = CERT_FindCertIssuer(cert2, now, certUsageSSLCA); + CERT_DestroyCertificate(cert2); + cert2 = cert3; + } + } + + result = Curl_ssl_init_certinfo(conn->data, i); + if(!result) { + for(i = 0; cert; cert = cert2) { + result = Curl_extract_certinfo(conn, i++, (char *)cert->derCert.data, + (char *)cert->derCert.data + + cert->derCert.len); + if(result) + break; + + if(cert->isRoot) { + CERT_DestroyCertificate(cert); + break; + } + + cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA); + CERT_DestroyCertificate(cert); + } + } + } + } + + return result; +} + +static SECStatus BadCertHandler(void *arg, PRFileDesc *sock) +{ + struct connectdata *conn = (struct connectdata *)arg; + struct SessionHandle *data = conn->data; + PRErrorCode err = PR_GetError(); + CERTCertificate *cert; + + /* remember the cert verification result */ + data->set.ssl.certverifyresult = err; + + if(err == SSL_ERROR_BAD_CERT_DOMAIN && !data->set.ssl.verifyhost) + /* we are asked not to verify the host name */ + return SECSuccess; + + /* print only info about the cert, the error is printed off the callback */ + cert = SSL_PeerCertificate(sock); + if(cert) { + infof(data, "Server certificate:\n"); + display_cert_info(data, cert); + CERT_DestroyCertificate(cert); + } + + return SECFailure; +} + +/** + * + * Check that the Peer certificate's issuer certificate matches the one found + * by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the + * issuer check, so we provide comments that mimic the OpenSSL + * X509_check_issued function (in x509v3/v3_purp.c) + */ +static SECStatus check_issuer_cert(PRFileDesc *sock, + char *issuer_nickname) +{ + CERTCertificate *cert, *cert_issuer, *issuer; + SECStatus res=SECSuccess; + void *proto_win = NULL; + + cert = SSL_PeerCertificate(sock); + cert_issuer = CERT_FindCertIssuer(cert, PR_Now(), certUsageObjectSigner); + + proto_win = SSL_RevealPinArg(sock); + issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win); + + if((!cert_issuer) || (!issuer)) + res = SECFailure; + else if(SECITEM_CompareItem(&cert_issuer->derCert, + &issuer->derCert)!=SECEqual) + res = SECFailure; + + CERT_DestroyCertificate(cert); + CERT_DestroyCertificate(issuer); + CERT_DestroyCertificate(cert_issuer); + return res; +} + +static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, + const char *pinnedpubkey) +{ + CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + struct SessionHandle *data = connssl->data; + CERTCertificate *cert; + + if(!pinnedpubkey) + /* no pinned public key specified */ + return CURLE_OK; + + /* get peer certificate */ + cert = SSL_PeerCertificate(connssl->handle); + if(cert) { + /* extract public key from peer certificate */ + SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert); + if(pubkey) { + /* encode the public key as DER */ + SECItem *cert_der = PK11_DEREncodePublicKey(pubkey); + if(cert_der) { + /* compare the public key with the pinned public key */ + result = Curl_pin_peer_pubkey(data, pinnedpubkey, cert_der->data, + cert_der->len); + SECITEM_FreeItem(cert_der, PR_TRUE); + } + SECKEY_DestroyPublicKey(pubkey); + } + CERT_DestroyCertificate(cert); + } + + /* report the resulting status */ + switch(result) { + case CURLE_OK: + infof(data, "pinned public key verified successfully!\n"); + break; + case CURLE_SSL_PINNEDPUBKEYNOTMATCH: + failf(data, "failed to verify pinned public key"); + break; + default: + /* OOM, etc. */ + break; + } + + return result; +} + +/** + * + * Callback to pick the SSL client certificate. + */ +static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, + struct CERTDistNamesStr *caNames, + struct CERTCertificateStr **pRetCert, + struct SECKEYPrivateKeyStr **pRetKey) +{ + struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; + struct SessionHandle *data = connssl->data; + const char *nickname = connssl->client_nickname; + + if(connssl->obj_clicert) { + /* use the cert/key provided by PEM reader */ + static const char pem_slotname[] = "PEM Token #1"; + SECItem cert_der = { 0, NULL, 0 }; + void *proto_win = SSL_RevealPinArg(sock); + struct CERTCertificateStr *cert; + struct SECKEYPrivateKeyStr *key; + + PK11SlotInfo *slot = PK11_FindSlotByName(pem_slotname); + if(NULL == slot) { + failf(data, "NSS: PK11 slot not found: %s", pem_slotname); + return SECFailure; + } + + if(PK11_ReadRawAttribute(PK11_TypeGeneric, connssl->obj_clicert, CKA_VALUE, + &cert_der) != SECSuccess) { + failf(data, "NSS: CKA_VALUE not found in PK11 generic object"); + PK11_FreeSlot(slot); + return SECFailure; + } + + cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win); + SECITEM_FreeItem(&cert_der, PR_FALSE); + if(NULL == cert) { + failf(data, "NSS: client certificate from file not found"); + PK11_FreeSlot(slot); + return SECFailure; + } + + key = PK11_FindPrivateKeyFromCert(slot, cert, NULL); + PK11_FreeSlot(slot); + if(NULL == key) { + failf(data, "NSS: private key from file not found"); + CERT_DestroyCertificate(cert); + return SECFailure; + } + + infof(data, "NSS: client certificate from file\n"); + display_cert_info(data, cert); + + *pRetCert = cert; + *pRetKey = key; + return SECSuccess; + } + + /* use the default NSS hook */ + if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames, + pRetCert, pRetKey) + || NULL == *pRetCert) { + + if(NULL == nickname) + failf(data, "NSS: client certificate not found (nickname not " + "specified)"); + else + failf(data, "NSS: client certificate not found: %s", nickname); + + return SECFailure; + } + + /* get certificate nickname if any */ + nickname = (*pRetCert)->nickname; + if(NULL == nickname) + nickname = "[unknown]"; + + if(NULL == *pRetKey) { + failf(data, "NSS: private key not found for certificate: %s", nickname); + return SECFailure; + } + + infof(data, "NSS: using client certificate: %s\n", nickname); + display_cert_info(data, *pRetCert); + return SECSuccess; +} + +/* update blocking direction in case of PR_WOULD_BLOCK_ERROR */ +static void nss_update_connecting_state(ssl_connect_state state, void *secret) +{ + struct ssl_connect_data *connssl = (struct ssl_connect_data *)secret; + if(PR_GetError() != PR_WOULD_BLOCK_ERROR) + /* an unrelated error is passing by */ + return; + + switch(connssl->connecting_state) { + case ssl_connect_2: + case ssl_connect_2_reading: + case ssl_connect_2_writing: + break; + default: + /* we are not called from an SSL handshake */ + return; + } + + /* update the state accordingly */ + connssl->connecting_state = state; +} + +/* recv() wrapper we use to detect blocking direction during SSL handshake */ +static PRInt32 nspr_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + const PRRecvFN recv_fn = fd->lower->methods->recv; + const PRInt32 rv = recv_fn(fd->lower, buf, amount, flags, timeout); + if(rv < 0) + /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */ + nss_update_connecting_state(ssl_connect_2_reading, fd->secret); + return rv; +} + +/* send() wrapper we use to detect blocking direction during SSL handshake */ +static PRInt32 nspr_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + const PRSendFN send_fn = fd->lower->methods->send; + const PRInt32 rv = send_fn(fd->lower, buf, amount, flags, timeout); + if(rv < 0) + /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */ + nss_update_connecting_state(ssl_connect_2_writing, fd->secret); + return rv; +} + +/* close() wrapper to avoid assertion failure due to fd->secret != NULL */ +static PRStatus nspr_io_close(PRFileDesc *fd) +{ + const PRCloseFN close_fn = PR_GetDefaultIOMethods()->close; + fd->secret = NULL; + return close_fn(fd); +} + +/* data might be NULL */ +static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir) +{ + NSSInitParameters initparams; + + if(nss_context != NULL) + return CURLE_OK; + + memset((void *) &initparams, '\0', sizeof(initparams)); + initparams.length = sizeof(initparams); + + if(cert_dir) { + char *certpath = aprintf("sql:%s", cert_dir); + if(!certpath) + return CURLE_OUT_OF_MEMORY; + + infof(data, "Initializing NSS with certpath: %s\n", certpath); + nss_context = NSS_InitContext(certpath, "", "", "", &initparams, + NSS_INIT_READONLY | NSS_INIT_PK11RELOAD); + free(certpath); + + if(nss_context != NULL) + return CURLE_OK; + + infof(data, "Unable to initialize NSS database\n"); + } + + infof(data, "Initializing NSS with certpath: none\n"); + nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY + | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN + | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD); + if(nss_context != NULL) + return CURLE_OK; + + infof(data, "Unable to initialize NSS\n"); + return CURLE_SSL_CACERT_BADFILE; +} + +/* data might be NULL */ +static CURLcode nss_init(struct SessionHandle *data) +{ + char *cert_dir; + struct_stat st; + CURLcode result; + + if(initialized) + return CURLE_OK; + + /* list of all CRL items we need to destroy in Curl_nss_cleanup() */ + nss_crl_list = Curl_llist_alloc(nss_destroy_crl_item); + if(!nss_crl_list) + return CURLE_OUT_OF_MEMORY; + + /* First we check if $SSL_DIR points to a valid dir */ + cert_dir = getenv("SSL_DIR"); + if(cert_dir) { + if((stat(cert_dir, &st) != 0) || + (!S_ISDIR(st.st_mode))) { + cert_dir = NULL; + } + } + + /* Now we check if the default location is a valid dir */ + if(!cert_dir) { + if((stat(SSL_DIR, &st) == 0) && + (S_ISDIR(st.st_mode))) { + cert_dir = (char *)SSL_DIR; + } + } + + if(nspr_io_identity == PR_INVALID_IO_LAYER) { + /* allocate an identity for our own NSPR I/O layer */ + nspr_io_identity = PR_GetUniqueIdentity("libcurl"); + if(nspr_io_identity == PR_INVALID_IO_LAYER) + return CURLE_OUT_OF_MEMORY; + + /* the default methods just call down to the lower I/O layer */ + memcpy(&nspr_io_methods, PR_GetDefaultIOMethods(), sizeof nspr_io_methods); + + /* override certain methods in the table by our wrappers */ + nspr_io_methods.recv = nspr_io_recv; + nspr_io_methods.send = nspr_io_send; + nspr_io_methods.close = nspr_io_close; + } + + result = nss_init_core(data, cert_dir); + if(result) + return result; + + if(!any_cipher_enabled()) + NSS_SetDomesticPolicy(); + + initialized = 1; + + return CURLE_OK; +} + +/** + * Global SSL init + * + * @retval 0 error initializing SSL + * @retval 1 SSL initialized successfully + */ +int Curl_nss_init(void) +{ + /* curl_global_init() is not thread-safe so this test is ok */ + if(nss_initlock == NULL) { + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256); + nss_initlock = PR_NewLock(); + nss_crllock = PR_NewLock(); + } + + /* We will actually initialize NSS later */ + + return 1; +} + +/* data might be NULL */ +CURLcode Curl_nss_force_init(struct SessionHandle *data) +{ + CURLcode result; + if(!nss_initlock) { + if(data) + failf(data, "unable to initialize NSS, curl_global_init() should have " + "been called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL"); + return CURLE_FAILED_INIT; + } + + PR_Lock(nss_initlock); + result = nss_init(data); + PR_Unlock(nss_initlock); + + return result; +} + +/* Global cleanup */ +void Curl_nss_cleanup(void) +{ + /* This function isn't required to be threadsafe and this is only done + * as a safety feature. + */ + PR_Lock(nss_initlock); + if(initialized) { + /* Free references to client certificates held in the SSL session cache. + * Omitting this hampers destruction of the security module owning + * the certificates. */ + SSL_ClearSessionCache(); + + if(mod && SECSuccess == SECMOD_UnloadUserModule(mod)) { + SECMOD_DestroyModule(mod); + mod = NULL; + } + NSS_ShutdownContext(nss_context); + nss_context = NULL; + } + + /* destroy all CRL items */ + Curl_llist_destroy(nss_crl_list, NULL); + nss_crl_list = NULL; + + PR_Unlock(nss_initlock); + + PR_DestroyLock(nss_initlock); + PR_DestroyLock(nss_crllock); + nss_initlock = NULL; + + initialized = 0; +} + +/* + * This function uses SSL_peek to determine connection status. + * + * Return codes: + * 1 means the connection is still in place + * 0 means the connection has been closed + * -1 means the connection status is unknown + */ +int +Curl_nss_check_cxn(struct connectdata *conn) +{ + int rc; + char buf; + + rc = + PR_Recv(conn->ssl[FIRSTSOCKET].handle, (void *)&buf, 1, PR_MSG_PEEK, + PR_SecondsToInterval(1)); + if(rc > 0) + return 1; /* connection still in place */ + + if(rc == 0) + return 0; /* connection has been closed */ + + return -1; /* connection status unknown */ +} + +/* + * This function is called when an SSL connection is closed. + */ +void Curl_nss_close(struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + if(connssl->handle) { + /* NSS closes the socket we previously handed to it, so we must mark it + as closed to avoid double close */ + fake_sclose(conn->sock[sockindex]); + conn->sock[sockindex] = CURL_SOCKET_BAD; + + if((connssl->client_nickname != NULL) || (connssl->obj_clicert != NULL)) + /* A server might require different authentication based on the + * particular path being requested by the client. To support this + * scenario, we must ensure that a connection will never reuse the + * authentication data from a previous connection. */ + SSL_InvalidateSession(connssl->handle); + + free(connssl->client_nickname); + connssl->client_nickname = NULL; + /* destroy all NSS objects in order to avoid failure of NSS shutdown */ + Curl_llist_destroy(connssl->obj_list, NULL); + connssl->obj_list = NULL; + connssl->obj_clicert = NULL; + + PR_Close(connssl->handle); + connssl->handle = NULL; + } +} + +/* return true if NSS can provide error code (and possibly msg) for the + error */ +static bool is_nss_error(CURLcode err) +{ + switch(err) { + case CURLE_PEER_FAILED_VERIFICATION: + case CURLE_SSL_CACERT: + case CURLE_SSL_CERTPROBLEM: + case CURLE_SSL_CONNECT_ERROR: + case CURLE_SSL_ISSUER_ERROR: + return true; + + default: + return false; + } +} + +/* return true if the given error code is related to a client certificate */ +static bool is_cc_error(PRInt32 err) +{ + switch(err) { + case SSL_ERROR_BAD_CERT_ALERT: + case SSL_ERROR_EXPIRED_CERT_ALERT: + case SSL_ERROR_REVOKED_CERT_ALERT: + return true; + + default: + return false; + } +} + +static Curl_recv nss_recv; +static Curl_send nss_send; + +static CURLcode nss_load_ca_certificates(struct connectdata *conn, + int sockindex) +{ + struct SessionHandle *data = conn->data; + const char *cafile = data->set.ssl.CAfile; + const char *capath = data->set.ssl.CApath; + + if(cafile) { + CURLcode result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE); + if(result) + return result; + } + + if(capath) { + struct_stat st; + if(stat(capath, &st) == -1) + return CURLE_SSL_CACERT_BADFILE; + + if(S_ISDIR(st.st_mode)) { + PRDirEntry *entry; + PRDir *dir = PR_OpenDir(capath); + if(!dir) + return CURLE_SSL_CACERT_BADFILE; + + while((entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN))) { + char *fullpath = aprintf("%s/%s", capath, entry->name); + if(!fullpath) { + PR_CloseDir(dir); + return CURLE_OUT_OF_MEMORY; + } + + if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE)) + /* This is purposefully tolerant of errors so non-PEM files can + * be in the same directory */ + infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath); + + free(fullpath); + } + + PR_CloseDir(dir); + } + else + infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath); + } + + infof(data, " CAfile: %s\n CApath: %s\n", + cafile ? cafile : "none", + capath ? capath : "none"); + + return CURLE_OK; +} + +static CURLcode nss_init_sslver(SSLVersionRange *sslver, + struct SessionHandle *data) +{ + switch(data->set.ssl.version) { + default: + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + sslver->min = SSL_LIBRARY_VERSION_TLS_1_0; +#ifdef SSL_LIBRARY_VERSION_TLS_1_2 + sslver->max = SSL_LIBRARY_VERSION_TLS_1_2; +#elif defined SSL_LIBRARY_VERSION_TLS_1_1 + sslver->max = SSL_LIBRARY_VERSION_TLS_1_1; +#else + sslver->max = SSL_LIBRARY_VERSION_TLS_1_0; +#endif + return CURLE_OK; + + case CURL_SSLVERSION_SSLv2: + sslver->min = SSL_LIBRARY_VERSION_2; + sslver->max = SSL_LIBRARY_VERSION_2; + return CURLE_OK; + + case CURL_SSLVERSION_SSLv3: + sslver->min = SSL_LIBRARY_VERSION_3_0; + sslver->max = SSL_LIBRARY_VERSION_3_0; + return CURLE_OK; + + case CURL_SSLVERSION_TLSv1_0: + sslver->min = SSL_LIBRARY_VERSION_TLS_1_0; + sslver->max = SSL_LIBRARY_VERSION_TLS_1_0; + return CURLE_OK; + + case CURL_SSLVERSION_TLSv1_1: +#ifdef SSL_LIBRARY_VERSION_TLS_1_1 + sslver->min = SSL_LIBRARY_VERSION_TLS_1_1; + sslver->max = SSL_LIBRARY_VERSION_TLS_1_1; + return CURLE_OK; +#endif + break; + + case CURL_SSLVERSION_TLSv1_2: +#ifdef SSL_LIBRARY_VERSION_TLS_1_2 + sslver->min = SSL_LIBRARY_VERSION_TLS_1_2; + sslver->max = SSL_LIBRARY_VERSION_TLS_1_2; + return CURLE_OK; +#endif + break; + } + + failf(data, "TLS minor version cannot be set"); + return CURLE_SSL_CONNECT_ERROR; +} + +static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, + struct SessionHandle *data, + CURLcode curlerr) +{ + PRErrorCode err = 0; + + if(is_nss_error(curlerr)) { + /* read NSPR error code */ + err = PR_GetError(); + if(is_cc_error(err)) + curlerr = CURLE_SSL_CERTPROBLEM; + + /* print the error number and error string */ + infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err)); + + /* print a human-readable message describing the error if available */ + nss_print_error_message(data, err); + } + + /* cleanup on connection failure */ + Curl_llist_destroy(connssl->obj_list, NULL); + connssl->obj_list = NULL; + + return curlerr; +} + +/* Switch the SSL socket into non-blocking mode. */ +static CURLcode nss_set_nonblock(struct ssl_connect_data *connssl, + struct SessionHandle *data) +{ + static PRSocketOptionData sock_opt; + sock_opt.option = PR_SockOpt_Nonblocking; + sock_opt.value.non_blocking = PR_TRUE; + + if(PR_SetSocketOption(connssl->handle, &sock_opt) != PR_SUCCESS) + return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR); + + return CURLE_OK; +} + +static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) +{ + PRFileDesc *model = NULL; + PRFileDesc *nspr_io = NULL; + PRFileDesc *nspr_io_stub = NULL; + PRBool ssl_no_cache; + PRBool ssl_cbc_random_iv; + struct SessionHandle *data = conn->data; + curl_socket_t sockfd = conn->sock[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + CURLcode result; + + SSLVersionRange sslver = { + SSL_LIBRARY_VERSION_TLS_1_0, /* min */ + SSL_LIBRARY_VERSION_TLS_1_0 /* max */ + }; + + connssl->data = data; + + /* list of all NSS objects we need to destroy in Curl_nss_close() */ + connssl->obj_list = Curl_llist_alloc(nss_destroy_object); + if(!connssl->obj_list) + return CURLE_OUT_OF_MEMORY; + + /* FIXME. NSS doesn't support multiple databases open at the same time. */ + PR_Lock(nss_initlock); + result = nss_init(conn->data); + if(result) { + PR_Unlock(nss_initlock); + goto error; + } + + result = CURLE_SSL_CONNECT_ERROR; + + if(!mod) { + char *configstring = aprintf("library=%s name=PEM", pem_library); + if(!configstring) { + PR_Unlock(nss_initlock); + goto error; + } + mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE); + free(configstring); + + if(!mod || !mod->loaded) { + if(mod) { + SECMOD_DestroyModule(mod); + mod = NULL; + } + infof(data, "WARNING: failed to load NSS PEM library %s. Using " + "OpenSSL PEM certificates will not work.\n", pem_library); + } + } + + PK11_SetPasswordFunc(nss_get_password); + PR_Unlock(nss_initlock); + + model = PR_NewTCPSocket(); + if(!model) + goto error; + model = SSL_ImportFD(NULL, model); + + if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess) + goto error; + if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess) + goto error; + if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess) + goto error; + + /* do not use SSL cache if disabled or we are not going to verify peer */ + ssl_no_cache = (conn->ssl_config.sessionid && data->set.ssl.verifypeer) ? + PR_FALSE : PR_TRUE; + if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess) + goto error; + + /* enable/disable the requested SSL version(s) */ + if(nss_init_sslver(&sslver, data) != CURLE_OK) + goto error; + if(SSL_VersionRangeSet(model, &sslver) != SECSuccess) + goto error; + + ssl_cbc_random_iv = !data->set.ssl_enable_beast; +#ifdef SSL_CBC_RANDOM_IV + /* unless the user explicitly asks to allow the protocol vulnerability, we + use the work-around */ + if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess) + infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d\n", + ssl_cbc_random_iv); +#else + if(ssl_cbc_random_iv) + infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n"); +#endif + + if(data->set.ssl.cipher_list) { + if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) { + result = CURLE_SSL_CIPHER; + goto error; + } + } + + if(!data->set.ssl.verifypeer && data->set.ssl.verifyhost) + infof(data, "warning: ignoring value of ssl.verifyhost\n"); + + /* bypass the default SSL_AuthCertificate() hook in case we do not want to + * verify peer */ + if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess) + goto error; + + data->set.ssl.certverifyresult=0; /* not checked yet */ + if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess) + goto error; + + if(SSL_HandshakeCallback(model, HandshakeCallback, conn) != SECSuccess) + goto error; + + if(data->set.ssl.verifypeer) { + const CURLcode rv = nss_load_ca_certificates(conn, sockindex); + if(rv) { + result = rv; + goto error; + } + } + + if(data->set.ssl.CRLfile) { + const CURLcode rv = nss_load_crl(data->set.ssl.CRLfile); + if(rv) { + result = rv; + goto error; + } + infof(data, " CRLfile: %s\n", data->set.ssl.CRLfile); + } + + if(data->set.str[STRING_CERT]) { + char *nickname = dup_nickname(data, STRING_CERT); + if(nickname) { + /* we are not going to use libnsspem.so to read the client cert */ + connssl->obj_clicert = NULL; + } + else { + CURLcode rv = cert_stuff(conn, sockindex, data->set.str[STRING_CERT], + data->set.str[STRING_KEY]); + if(rv) { + /* failf() is already done in cert_stuff() */ + result = rv; + goto error; + } + } + + /* store the nickname for SelectClientCert() called during handshake */ + connssl->client_nickname = nickname; + } + else + connssl->client_nickname = NULL; + + if(SSL_GetClientAuthDataHook(model, SelectClientCert, + (void *)connssl) != SECSuccess) { + result = CURLE_SSL_CERTPROBLEM; + goto error; + } + + /* wrap OS file descriptor by NSPR's file descriptor abstraction */ + nspr_io = PR_ImportTCPSocket(sockfd); + if(!nspr_io) + goto error; + + /* create our own NSPR I/O layer */ + nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods); + if(!nspr_io_stub) { + PR_Close(nspr_io); + goto error; + } + + /* make the per-connection data accessible from NSPR I/O callbacks */ + nspr_io_stub->secret = (void *)connssl; + + /* push our new layer to the NSPR I/O stack */ + if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) { + PR_Close(nspr_io); + PR_Close(nspr_io_stub); + goto error; + } + + /* import our model socket onto the current I/O stack */ + connssl->handle = SSL_ImportFD(model, nspr_io); + if(!connssl->handle) { + PR_Close(nspr_io); + goto error; + } + + PR_Close(model); /* We don't need this any more */ + model = NULL; + + /* This is the password associated with the cert that we're using */ + if(data->set.str[STRING_KEY_PASSWD]) { + SSL_SetPKCS11PinArg(connssl->handle, data->set.str[STRING_KEY_PASSWD]); + } + +#ifdef SSL_ENABLE_OCSP_STAPLING + if(data->set.ssl.verifystatus) { + if(SSL_OptionSet(connssl->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE) + != SECSuccess) + goto error; + } +#endif + +#ifdef SSL_ENABLE_NPN + if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, data->set.ssl_enable_npn + ? PR_TRUE : PR_FALSE) != SECSuccess) + goto error; +#endif + +#ifdef SSL_ENABLE_ALPN + if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, data->set.ssl_enable_alpn + ? PR_TRUE : PR_FALSE) != SECSuccess) + goto error; +#endif + +#if NSSVERNUM >= 0x030f04 /* 3.15.4 */ + if(data->set.ssl.falsestart) { + if(SSL_OptionSet(connssl->handle, SSL_ENABLE_FALSE_START, PR_TRUE) + != SECSuccess) + goto error; + + if(SSL_SetCanFalseStartCallback(connssl->handle, CanFalseStartCallback, + conn) != SECSuccess) + goto error; + } +#endif + +#if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN) + if(data->set.ssl_enable_npn || data->set.ssl_enable_alpn) { + int cur = 0; + unsigned char protocols[128]; + +#ifdef USE_NGHTTP2 + if(data->set.httpversion >= CURL_HTTP_VERSION_2) { + protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; + memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, + NGHTTP2_PROTO_VERSION_ID_LEN); + cur += NGHTTP2_PROTO_VERSION_ID_LEN; + } +#endif + protocols[cur++] = ALPN_HTTP_1_1_LENGTH; + memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); + cur += ALPN_HTTP_1_1_LENGTH; + + if(SSL_SetNextProtoNego(connssl->handle, protocols, cur) != SECSuccess) + goto error; + } +#endif + + + /* Force handshake on next I/O */ + if(SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE) + != SECSuccess) + goto error; + + /* propagate hostname to the TLS layer */ + if(SSL_SetURL(connssl->handle, conn->host.name) != SECSuccess) + goto error; + + /* prevent NSS from re-using the session for a different hostname */ + if(SSL_SetSockPeerID(connssl->handle, conn->host.name) != SECSuccess) + goto error; + + return CURLE_OK; + +error: + if(model) + PR_Close(model); + + return nss_fail_connect(connssl, data, result); +} + +static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct SessionHandle *data = conn->data; + CURLcode result = CURLE_SSL_CONNECT_ERROR; + PRUint32 timeout; + + /* check timeout situation */ + const long time_left = Curl_timeleft(data, NULL, TRUE); + if(time_left < 0L) { + failf(data, "timed out before SSL handshake"); + result = CURLE_OPERATION_TIMEDOUT; + goto error; + } + + /* Force the handshake now */ + timeout = PR_MillisecondsToInterval((PRUint32) time_left); + if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) { + if(PR_GetError() == PR_WOULD_BLOCK_ERROR) + /* blocking direction is updated by nss_update_connecting_state() */ + return CURLE_AGAIN; + else if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) + result = CURLE_PEER_FAILED_VERIFICATION; + else if(conn->data->set.ssl.certverifyresult!=0) + result = CURLE_SSL_CACERT; + goto error; + } + + result = display_conn_info(conn, connssl->handle); + if(result) + goto error; + + if(data->set.str[STRING_SSL_ISSUERCERT]) { + SECStatus ret = SECFailure; + char *nickname = dup_nickname(data, STRING_SSL_ISSUERCERT); + if(nickname) { + /* we support only nicknames in case of STRING_SSL_ISSUERCERT for now */ + ret = check_issuer_cert(connssl->handle, nickname); + free(nickname); + } + + if(SECFailure == ret) { + infof(data, "SSL certificate issuer check failed\n"); + result = CURLE_SSL_ISSUER_ERROR; + goto error; + } + else { + infof(data, "SSL certificate issuer check ok\n"); + } + } + + result = cmp_peer_pubkey(connssl, data->set.str[STRING_SSL_PINNEDPUBLICKEY]); + if(result) + /* status already printed */ + goto error; + + return CURLE_OK; + +error: + return nss_fail_connect(connssl, data, result); +} + +static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, + bool *done) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct SessionHandle *data = conn->data; + const bool blocking = (done == NULL); + CURLcode result; + + if(connssl->state == ssl_connection_complete) + return CURLE_OK; + + if(connssl->connecting_state == ssl_connect_1) { + result = nss_setup_connect(conn, sockindex); + if(result) + /* we do not expect CURLE_AGAIN from nss_setup_connect() */ + return result; + + if(!blocking) { + /* in non-blocking mode, set NSS non-blocking mode before handshake */ + result = nss_set_nonblock(connssl, data); + if(result) + return result; + } + + connssl->connecting_state = ssl_connect_2; + } + + result = nss_do_connect(conn, sockindex); + switch(result) { + case CURLE_OK: + break; + case CURLE_AGAIN: + if(!blocking) + /* CURLE_AGAIN in non-blocking mode is not an error */ + return CURLE_OK; + /* fall through */ + default: + return result; + } + + if(blocking) { + /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */ + result = nss_set_nonblock(connssl, data); + if(result) + return result; + } + else + /* signal completed SSL handshake */ + *done = TRUE; + + connssl->state = ssl_connection_complete; + conn->recv[sockindex] = nss_recv; + conn->send[sockindex] = nss_send; + + /* ssl_connect_done is never used outside, go back to the initial state */ + connssl->connecting_state = ssl_connect_1; + + return CURLE_OK; +} + +CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) +{ + return nss_connect_common(conn, sockindex, /* blocking */ NULL); +} + +CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn, + int sockindex, bool *done) +{ + return nss_connect_common(conn, sockindex, done); +} + +static ssize_t nss_send(struct connectdata *conn, /* connection data */ + int sockindex, /* socketindex */ + const void *mem, /* send this data */ + size_t len, /* amount to write */ + CURLcode *curlcode) +{ + ssize_t rc = PR_Send(conn->ssl[sockindex].handle, mem, (int)len, 0, + PR_INTERVAL_NO_WAIT); + if(rc < 0) { + PRInt32 err = PR_GetError(); + if(err == PR_WOULD_BLOCK_ERROR) + *curlcode = CURLE_AGAIN; + else { + /* print the error number and error string */ + const char *err_name = nss_error_to_name(err); + infof(conn->data, "SSL write: error %d (%s)\n", err, err_name); + + /* print a human-readable message describing the error if available */ + nss_print_error_message(conn->data, err); + + *curlcode = (is_cc_error(err)) + ? CURLE_SSL_CERTPROBLEM + : CURLE_SEND_ERROR; + } + + return -1; + } + + return rc; /* number of bytes */ +} + +static ssize_t nss_recv(struct connectdata * conn, /* connection data */ + int num, /* socketindex */ + char *buf, /* store read data here */ + size_t buffersize, /* max amount to read */ + CURLcode *curlcode) +{ + ssize_t nread = PR_Recv(conn->ssl[num].handle, buf, (int)buffersize, 0, + PR_INTERVAL_NO_WAIT); + if(nread < 0) { + /* failed SSL read */ + PRInt32 err = PR_GetError(); + + if(err == PR_WOULD_BLOCK_ERROR) + *curlcode = CURLE_AGAIN; + else { + /* print the error number and error string */ + const char *err_name = nss_error_to_name(err); + infof(conn->data, "SSL read: errno %d (%s)\n", err, err_name); + + /* print a human-readable message describing the error if available */ + nss_print_error_message(conn->data, err); + + *curlcode = (is_cc_error(err)) + ? CURLE_SSL_CERTPROBLEM + : CURLE_RECV_ERROR; + } + + return -1; + } + + return nread; +} + +size_t Curl_nss_version(char *buffer, size_t size) +{ + return snprintf(buffer, size, "NSS/%s", NSS_VERSION); +} + +/* data might be NULL */ +int Curl_nss_seed(struct SessionHandle *data) +{ + /* make sure that NSS is initialized */ + return !!Curl_nss_force_init(data); +} + +/* data might be NULL */ +int Curl_nss_random(struct SessionHandle *data, + unsigned char *entropy, + size_t length) +{ + Curl_nss_seed(data); /* Initiate the seed if not already done */ + + if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length))) + /* signal a failure */ + return -1; + + return 0; +} + +void Curl_nss_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum, /* output */ + size_t md5len) +{ + PK11Context *MD5pw = PK11_CreateDigestContext(SEC_OID_MD5); + unsigned int MD5out; + + PK11_DigestOp(MD5pw, tmp, curlx_uztoui(tmplen)); + PK11_DigestFinal(MD5pw, md5sum, &MD5out, curlx_uztoui(md5len)); + PK11_DestroyContext(MD5pw, PR_TRUE); +} + +void Curl_nss_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum, /* output */ + size_t sha256len) +{ + PK11Context *SHA256pw = PK11_CreateDigestContext(SEC_OID_SHA256); + unsigned int SHA256out; + + PK11_DigestOp(SHA256pw, tmp, curlx_uztoui(tmplen)); + PK11_DigestFinal(SHA256pw, sha256sum, &SHA256out, curlx_uztoui(sha256len)); + PK11_DestroyContext(SHA256pw, PR_TRUE); +} + +bool Curl_nss_cert_status_request(void) +{ +#ifdef SSL_ENABLE_OCSP_STAPLING + return TRUE; +#else + return FALSE; +#endif +} + +bool Curl_nss_false_start(void) { +#if NSSVERNUM >= 0x030f04 /* 3.15.4 */ + return TRUE; +#else + return FALSE; +#endif +} + +#endif /* USE_NSS */ diff --git a/project/jni/curl/lib/nssg.h b/project/jni/curl/lib/vtls/nssg.h similarity index 50% rename from project/jni/curl/lib/nssg.h rename to project/jni/curl/lib/vtls/nssg.h index f9cc46ae2..601168c21 100644 --- a/project/jni/curl/lib/nssg.h +++ b/project/jni/curl/lib/vtls/nssg.h @@ -1,5 +1,5 @@ -#ifndef __NSSG_H -#define __NSSG_H +#ifndef HEADER_CURL_NSSG_H +#define HEADER_CURL_NSSG_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -21,13 +21,15 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "curl_setup.h" #ifdef USE_NSS /* - * This header should only be needed to get included by sslgen.c and nss.c + * This header should only be needed to get included by vtls.c and nss.c */ #include "urldata.h" + CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex); CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn, int sockindex, @@ -35,10 +37,6 @@ CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn, /* close a SSL connection */ void Curl_nss_close(struct connectdata *conn, int sockindex); -/* tell NSS to close down all open information regarding connections (and - thus session ID caching etc) */ -int Curl_nss_close_all(struct SessionHandle *data); - int Curl_nss_init(void); void Curl_nss_cleanup(void); @@ -49,23 +47,56 @@ int Curl_nss_seed(struct SessionHandle *data); /* initialize NSS library if not already */ CURLcode Curl_nss_force_init(struct SessionHandle *data); +int Curl_nss_random(struct SessionHandle *data, + unsigned char *entropy, + size_t length); + +void Curl_nss_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum, /* output */ + size_t md5len); + +void Curl_nss_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum, /* output */ + size_t sha256len); + +bool Curl_nss_cert_status_request(void); + +bool Curl_nss_false_start(void); + +/* Set the API backend definition to NSS */ +#define CURL_SSL_BACKEND CURLSSLBACKEND_NSS + +/* this backend supports the CAPATH option */ +#define have_curlssl_ca_path 1 + +/* this backend supports CURLOPT_CERTINFO */ +#define have_curlssl_certinfo 1 + /* API setup for NSS */ #define curlssl_init Curl_nss_init #define curlssl_cleanup Curl_nss_cleanup #define curlssl_connect Curl_nss_connect +#define curlssl_connect_nonblocking Curl_nss_connect_nonblocking /* NSS has its own session ID cache */ -#define curlssl_session_free(x) -#define curlssl_close_all Curl_nss_close_all +#define curlssl_session_free(x) Curl_nop_stmt +#define curlssl_close_all(x) ((void)x) #define curlssl_close Curl_nss_close /* NSS has no shutdown function provided and thus always fail */ -#define curlssl_shutdown(x,y) (x=x, y=y, 1) -#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_FAILED_INIT) -#define curlssl_set_engine_default(x) (x=x, CURLE_FAILED_INIT) -#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL) +#define curlssl_shutdown(x,y) ((void)x, (void)y, 1) +#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN) +#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN) +#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) #define curlssl_version Curl_nss_version #define curlssl_check_cxn(x) Curl_nss_check_cxn(x) -#define curlssl_data_pending(x,y) (x=x, y=y, 0) +#define curlssl_data_pending(x,y) ((void)x, (void)y, 0) +#define curlssl_random(x,y,z) Curl_nss_random(x,y,z) +#define curlssl_md5sum(a,b,c,d) Curl_nss_md5sum(a,b,c,d) +#define curlssl_sha256sum(a,b,c,d) Curl_nss_sha256sum(a,b,c,d) +#define curlssl_cert_status_request() Curl_nss_cert_status_request() +#define curlssl_false_start() Curl_nss_false_start() #endif /* USE_NSS */ -#endif +#endif /* HEADER_CURL_NSSG_H */ diff --git a/project/jni/curl/lib/ssluse.c b/project/jni/curl/lib/vtls/openssl.c similarity index 53% rename from project/jni/curl/lib/ssluse.c rename to project/jni/curl/lib/vtls/openssl.c index d8f776018..cbf2d2123 100644 --- a/project/jni/curl/lib/ssluse.c +++ b/project/jni/curl/lib/vtls/openssl.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,7 +22,7 @@ /* * Source file for all OpenSSL-specific code for the TLS/SSL layer. No code - * but sslgen.c should ever call or use these functions. + * but vtls.c should ever call or use these functions. */ /* @@ -30,83 +30,61 @@ * Sampo Kellomaki 1998. */ -#include "setup.h" +#include "curl_setup.h" + +#ifdef USE_OPENSSL -#include -#include -#include #ifdef HAVE_LIMITS_H #include #endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #include "urldata.h" #include "sendf.h" #include "formdata.h" /* for the boundary function */ #include "url.h" /* for the ssl config check function */ #include "inet_pton.h" -#include "ssluse.h" +#include "openssl.h" #include "connect.h" +#include "slist.h" #include "strequal.h" #include "select.h" -#include "sslgen.h" +#include "vtls.h" #include "rawstr.h" +#include "hostcheck.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use the internal *printf() functions */ -#include - -#ifdef USE_SSLEAY - -#ifdef USE_OPENSSL +#include #include #include #include #include #include -#else -#include -#include +#include +#include +#include +#include + +#ifdef HAVE_OPENSSL_PKCS12_H +#include #endif -#include "curl_memory.h" -#include "easyif.h" /* for Curl_convert_from_utf8 prototype */ +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP) +#include +#endif -/* The last #include file should be: */ +#include "warnless.h" +#include "non-ascii.h" /* for Curl_convert_from_utf8 prototype */ + +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" -#if OPENSSL_VERSION_NUMBER >= 0x0090581fL -#define HAVE_SSL_GET1_SESSION 1 -#else -#undef HAVE_SSL_GET1_SESSION +#ifndef OPENSSL_VERSION_NUMBER +#error "OPENSSL_VERSION_NUMBER not defined" #endif -#if OPENSSL_VERSION_NUMBER >= 0x00904100L -#define HAVE_USERDATA_IN_PWD_CALLBACK 1 -#else -#undef HAVE_USERDATA_IN_PWD_CALLBACK -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x00907001L -/* ENGINE_load_private_key() takes four arguments */ -#define HAVE_ENGINE_LOAD_FOUR_ARGS +#if defined(HAVE_OPENSSL_ENGINE_H) #include -#else -/* ENGINE_load_private_key() takes three arguments */ -#undef HAVE_ENGINE_LOAD_FOUR_ARGS -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x00903001L) && defined(HAVE_OPENSSL_PKCS12_H) -/* OpenSSL has PKCS 12 support */ -#define HAVE_PKCS12_SUPPORT -#else -/* OpenSSL/SSLEay does not have PKCS12 support */ -#undef HAVE_PKCS12_SUPPORT -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x00906001L -#define HAVE_ERR_ERROR_STRING_N 1 #endif #if OPENSSL_VERSION_NUMBER >= 0x00909000L @@ -115,11 +93,44 @@ #define SSL_METHOD_QUAL #endif -#if OPENSSL_VERSION_NUMBER >= 0x00907000L -/* 0.9.6 didn't have X509_STORE_set_flags() */ -#define HAVE_X509_STORE_SET_FLAGS 1 +#if (OPENSSL_VERSION_NUMBER >= 0x10000000L) +#define HAVE_ERR_REMOVE_THREAD_STATE 1 +#if (OPENSSL_VERSION_NUMBER >= 0x10100004L) +/* OpenSSL 1.1.0-pre4 removed the argument! */ +#define HAVE_ERR_REMOVE_THREAD_STATE_NOARG 1 +#endif +#endif + +#if !defined(HAVE_SSLV2_CLIENT_METHOD) || \ + OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0+ has no SSLv2 */ +#undef OPENSSL_NO_SSL2 /* undef first to avoid compiler warnings */ +#define OPENSSL_NO_SSL2 +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \ + !defined(LIBRESSL_VERSION_NUMBER) +#define SSLeay_add_ssl_algorithms() SSL_library_init() +#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER +#define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */ +#define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */ +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \ + !defined(LIBRESSL_VERSION_NUMBER) +#define HAVE_X509_GET0_SIGNATURE 1 +#endif + +#if (OPENSSL_VERSION_NUMBER < 0x0090808fL) +/* not present in older OpenSSL */ +#define OPENSSL_load_builtin_modules(x) +#endif + +#if defined(LIBRESSL_VERSION_NUMBER) +#define OSSL_PACKAGE "LibreSSL" +#elif defined(OPENSSL_IS_BORINGSSL) +#define OSSL_PACKAGE "BoringSSL" #else -#define X509_STORE_set_flags(x,y) +#define OSSL_PACKAGE "OpenSSL" #endif /* @@ -130,25 +141,16 @@ */ #define RAND_LOAD_LENGTH 1024 -#ifndef HAVE_USERDATA_IN_PWD_CALLBACK -static char global_passwd[64]; -#endif - -static int passwd_callback(char *buf, int num, int verify -#ifdef HAVE_USERDATA_IN_PWD_CALLBACK - /* This was introduced in 0.9.4, we can set this - using SSL_CTX_set_default_passwd_cb_userdata() - */ - , void *global_passwd -#endif - ) +static int passwd_callback(char *buf, int num, int encrypting, + void *global_passwd) { - if(verify) - fprintf(stderr, "%s\n", buf); - else { - if(num > (int)strlen((char *)global_passwd)) { - strcpy(buf, global_passwd); - return (int)strlen(buf); + DEBUGASSERT(0 == encrypting); + + if(!encrypting) { + int klen = curlx_uztosi(strlen((char *)global_passwd)); + if(num > klen) { + memcpy(buf, global_passwd, klen+1); + return klen; } } return 0; @@ -165,14 +167,14 @@ static int passwd_callback(char *buf, int num, int verify #define seed_enough(x) rand_enough() static bool rand_enough(void) { - return (bool)(0 != RAND_status()); + return (0 != RAND_status()) ? TRUE : FALSE; } #else #define seed_enough(x) rand_enough(x) static bool rand_enough(int nread) { /* this is a very silly decision to make */ - return (bool)(nread > 500); + return (nread > 500) ? TRUE : FALSE; } #endif @@ -224,32 +226,12 @@ static int ossl_seed(struct SessionHandle *data) /* If we get here, it means we need to seed the PRNG using a "silly" approach! */ -#ifdef HAVE_RAND_SCREEN - /* if RAND_screen() is present, it was called during global init */ - nread = 100; /* just a value */ -#else - { - int len; - char *area; - - /* Changed call to RAND_seed to use the underlying RAND_add implementation - * directly. Do this in a loop, with the amount of additional entropy - * being dependent upon the algorithm used by Curl_FormBoundary(): N bytes - * of a 7-bit ascii set. -- Richard Gorton, March 11 2003. - */ - - do { - area = Curl_FormBoundary(); - if(!area) - return 3; /* out of memory */ - - len = (int)strlen(area); - RAND_add(area, len, (len >> 1)); - - free(area); /* now remove the random junk */ - } while(!RAND_status()); - } -#endif + do { + unsigned char randb[64]; + int len = sizeof(randb); + RAND_bytes(randb, len); + RAND_add(randb, len, (len >> 1)); + } while(!RAND_status()); /* generates a default path for the random seed file */ buf[0]=0; /* blank it first */ @@ -265,7 +247,7 @@ static int ossl_seed(struct SessionHandle *data) return nread; } -int Curl_ossl_seed(struct SessionHandle *data) +static void Curl_ossl_seed(struct SessionHandle *data) { /* we have the "SSL is seeded" boolean static to prevent multiple time-consuming seedings in vain */ @@ -276,10 +258,8 @@ int Curl_ossl_seed(struct SessionHandle *data) ossl_seed(data); ssl_seeded = TRUE; } - return 0; } - #ifndef SSL_FILETYPE_ENGINE #define SSL_FILETYPE_ENGINE 42 #endif @@ -301,6 +281,48 @@ static int do_file_type(const char *type) return -1; } +#if defined(HAVE_OPENSSL_ENGINE_H) +/* + * Supply default password to the engine user interface conversation. + * The password is passed by OpenSSL engine from ENGINE_load_private_key() + * last argument to the ui and can be obtained by UI_get0_user_data(ui) here. + */ +static int ssl_ui_reader(UI *ui, UI_STRING *uis) +{ + const char *password; + switch(UI_get_string_type(uis)) { + case UIT_PROMPT: + case UIT_VERIFY: + password = (const char*)UI_get0_user_data(ui); + if(password && (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) { + UI_set_result(ui, uis, password); + return 1; + } + default: + break; + } + return (UI_method_get_reader(UI_OpenSSL()))(ui, uis); +} + +/* + * Suppress interactive request for a default password if available. + */ +static int ssl_ui_writer(UI *ui, UI_STRING *uis) +{ + switch(UI_get_string_type(uis)) { + case UIT_PROMPT: + case UIT_VERIFY: + if(UI_get0_user_data(ui) && + (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) { + return 1; + } + default: + break; + } + return (UI_method_get_writer(UI_OpenSSL()))(ui, uis); +} +#endif + static int cert_stuff(struct connectdata *conn, SSL_CTX* ctx, @@ -313,41 +335,30 @@ int cert_stuff(struct connectdata *conn, int file_type = do_file_type(cert_type); - if(cert_file != NULL || file_type == SSL_FILETYPE_ENGINE) { + if(cert_file || (file_type == SSL_FILETYPE_ENGINE)) { SSL *ssl; X509 *x509; int cert_done = 0; if(data->set.str[STRING_KEY_PASSWD]) { -#ifndef HAVE_USERDATA_IN_PWD_CALLBACK - /* - * If password has been given, we store that in the global - * area (*shudder*) for a while: - */ - size_t len = strlen(data->set.key_passwd); - if(len < sizeof(global_passwd)) - memcpy(global_passwd, data->set.key_passwd, len+1); -#else - /* - * We set the password in the callback userdata - */ + /* set the password in the callback userdata */ SSL_CTX_set_default_passwd_cb_userdata(ctx, data->set.str[STRING_KEY_PASSWD]); -#endif /* Set passwd callback: */ SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); } -#define SSL_CLIENT_CERT_ERR \ - "unable to use client certificate (no key found or wrong pass phrase?)" - switch(file_type) { case SSL_FILETYPE_PEM: /* SSL_CTX_use_certificate_chain_file() only works on PEM files */ if(SSL_CTX_use_certificate_chain_file(ctx, cert_file) != 1) { - failf(data, SSL_CLIENT_CERT_ERR); + failf(data, + "could not load PEM client certificate, " OSSL_PACKAGE + " error %s, " + "(no key found, wrong pass phrase, or wrong file format?)", + ERR_error_string(ERR_get_error(), NULL) ); return 0; } break; @@ -359,7 +370,11 @@ int cert_stuff(struct connectdata *conn, if(SSL_CTX_use_certificate_file(ctx, cert_file, file_type) != 1) { - failf(data, SSL_CLIENT_CERT_ERR); + failf(data, + "could not load ASN1 client certificate, " OSSL_PACKAGE + " error %s, " + "(no key found, wrong pass phrase, or wrong file format?)", + ERR_error_string(ERR_get_error(), NULL) ); return 0; } break; @@ -377,22 +392,22 @@ int cert_stuff(struct connectdata *conn, params.cert = NULL; /* Does the engine supports LOAD_CERT_CTRL ? */ - if (!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME, - 0, (void *)cmd_name, NULL)) { + if(!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME, + 0, (void *)cmd_name, NULL)) { failf(data, "ssl engine does not support loading certificates"); return 0; } /* Load the certificate from the engine */ - if (!ENGINE_ctrl_cmd(data->state.engine, cmd_name, - 0, ¶ms, NULL, 1)) { + if(!ENGINE_ctrl_cmd(data->state.engine, cmd_name, + 0, ¶ms, NULL, 1)) { failf(data, "ssl engine cannot load client cert with id" " '%s' [%s]", cert_file, ERR_error_string(ERR_get_error(), NULL)); return 0; } - if (!params.cert) { + if(!params.cert) { failf(data, "ssl engine didn't initialized the certificate " "properly."); return 0; @@ -418,14 +433,13 @@ int cert_stuff(struct connectdata *conn, case SSL_FILETYPE_PKCS12: { -#ifdef HAVE_PKCS12_SUPPORT +#ifdef HAVE_OPENSSL_PKCS12_H FILE *f; PKCS12 *p12; EVP_PKEY *pri; STACK_OF(X509) *ca = NULL; - int i; - f = fopen(cert_file,"rb"); + f = fopen(cert_file, "rb"); if(!f) { failf(data, "could not open PKCS12 file '%s'", cert_file); return 0; @@ -434,16 +448,17 @@ int cert_stuff(struct connectdata *conn, fclose(f); if(!p12) { - failf(data, "error reading PKCS12 file '%s'", cert_file ); + failf(data, "error reading PKCS12 file '%s'", cert_file); return 0; } PKCS12_PBE_add(); if(!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509, - &ca)) { + &ca)) { failf(data, - "could not parse PKCS12 file, check password, OpenSSL error %s", + "could not parse PKCS12 file, check password, " OSSL_PACKAGE + " error %s", ERR_error_string(ERR_get_error(), NULL) ); PKCS12_free(p12); return 0; @@ -452,48 +467,58 @@ int cert_stuff(struct connectdata *conn, PKCS12_free(p12); if(SSL_CTX_use_certificate(ctx, x509) != 1) { - failf(data, SSL_CLIENT_CERT_ERR); - EVP_PKEY_free(pri); - X509_free(x509); - return 0; + failf(data, + "could not load PKCS12 client certificate, " OSSL_PACKAGE + " error %s", + ERR_error_string(ERR_get_error(), NULL) ); + goto fail; } if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) { failf(data, "unable to use private key from PKCS12 file '%s'", cert_file); - EVP_PKEY_free(pri); - X509_free(x509); - return 0; + goto fail; } - if (!SSL_CTX_check_private_key (ctx)) { + if(!SSL_CTX_check_private_key (ctx)) { failf(data, "private key from PKCS12 file '%s' " "does not match certificate in same file", cert_file); - EVP_PKEY_free(pri); - X509_free(x509); - return 0; + goto fail; } /* Set Certificate Verification chain */ - if (ca && sk_X509_num(ca)) { - for (i = 0; i < sk_X509_num(ca); i++) { - if (!SSL_CTX_add_extra_chain_cert(ctx,sk_X509_value(ca, i))) { + if(ca) { + while(sk_X509_num(ca)) { + /* + * Note that sk_X509_pop() is used below to make sure the cert is + * removed from the stack properly before getting passed to + * SSL_CTX_add_extra_chain_cert(). Previously we used + * sk_X509_value() instead, but then we'd clean it in the subsequent + * sk_X509_pop_free() call. + */ + X509 *x = sk_X509_pop(ca); + if(!SSL_CTX_add_extra_chain_cert(ctx, x)) { + X509_free(x); failf(data, "cannot add certificate to certificate chain"); - EVP_PKEY_free(pri); - X509_free(x509); - return 0; + goto fail; } - if (!SSL_CTX_add_client_CA(ctx, sk_X509_value(ca, i))) { + /* SSL_CTX_add_client_CA() seems to work with either sk_* function, + * presumably because it duplicates what we pass to it. + */ + if(!SSL_CTX_add_client_CA(ctx, x)) { failf(data, "cannot add certificate to client CA list"); - EVP_PKEY_free(pri); - X509_free(x509); - return 0; + goto fail; } } } + cert_done = 1; + fail: EVP_PKEY_free(pri); X509_free(x509); - cert_done = 1; + sk_X509_pop_free(ca, X509_free); + + if(!cert_done) + return 0; /* failure! */ break; #else failf(data, "file type P12 for certificate not supported"); @@ -511,7 +536,7 @@ int cert_stuff(struct connectdata *conn, case SSL_FILETYPE_PEM: if(cert_done) break; - if(key_file == NULL) + if(!key_file) /* cert & key can only be in PEM case in the same file */ key_file=cert_file; case SSL_FILETYPE_ASN1: @@ -526,16 +551,23 @@ int cert_stuff(struct connectdata *conn, { /* XXXX still needs some work */ EVP_PKEY *priv_key = NULL; if(data->state.engine) { -#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS - UI_METHOD *ui_method = UI_OpenSSL(); -#endif + UI_METHOD *ui_method = + UI_create_method((char *)"cURL user interface"); + if(!ui_method) { + failf(data, "unable do create " OSSL_PACKAGE + " user-interface method"); + return 0; + } + UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL())); + UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL())); + UI_method_set_reader(ui_method, ssl_ui_reader); + UI_method_set_writer(ui_method, ssl_ui_writer); /* the typecast below was added to please mingw32 */ priv_key = (EVP_PKEY *) - ENGINE_load_private_key(data->state.engine,key_file, -#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS + ENGINE_load_private_key(data->state.engine, key_file, ui_method, -#endif data->set.str[STRING_KEY_PASSWD]); + UI_destroy_method(ui_method); if(!priv_key) { failf(data, "failed to load private key from crypto engine"); return 0; @@ -569,8 +601,8 @@ int cert_stuff(struct connectdata *conn, } ssl=SSL_new(ctx); - if(NULL == ssl) { - failf(data,"unable to create an SSL structure"); + if(!ssl) { + failf(data, "unable to create an SSL structure"); return 0; } @@ -578,9 +610,9 @@ int cert_stuff(struct connectdata *conn, /* This version was provided by Evan Jordan and is supposed to not leak memory as the previous version: */ - if(x509 != NULL) { + if(x509) { EVP_PKEY *pktmp = X509_get_pubkey(x509); - EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(ssl)); + EVP_PKEY_copy_parameters(pktmp, SSL_get_privatekey(ssl)); EVP_PKEY_free(pktmp); } @@ -596,10 +628,6 @@ int cert_stuff(struct connectdata *conn, failf(data, "Private key does not match the certificate public key"); return 0; } -#ifndef HAVE_USERDATA_IN_PWD_CALLBACK - /* erase it now */ - memset(global_passwd, 0, sizeof(global_passwd)); -#endif } return 1; } @@ -634,36 +662,17 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size) #endif } -static -int cert_verify_callback(int ok, X509_STORE_CTX *ctx) -{ - X509 *err_cert; - char buf[256]; - - err_cert=X509_STORE_CTX_get_current_cert(ctx); - (void)x509_name_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); - return ok; -} - /* Return error string for last OpenSSL error */ static char *SSL_strerror(unsigned long error, char *buf, size_t size) { -#ifdef HAVE_ERR_ERROR_STRING_N /* OpenSSL 0.9.6 and later has a function named - ERRO_error_string_n() that takes the size of the buffer as a + ERR_error_string_n() that takes the size of the buffer as a third argument */ ERR_error_string_n(error, buf, size); -#else - (void) size; - ERR_error_string(error, buf); -#endif return buf; } -#endif /* USE_SSLEAY */ - -#ifdef USE_SSLEAY /** * Global SSL init * @@ -672,10 +681,28 @@ static char *SSL_strerror(unsigned long error, char *buf, size_t size) */ int Curl_ossl_init(void) { + OPENSSL_load_builtin_modules(); + #ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES ENGINE_load_builtin_engines(); #endif + /* OPENSSL_config(NULL); is "strongly recommended" to use but unfortunately + that function makes an exit() call on wrongly formatted config files + which makes it hard to use in some situations. OPENSSL_config() itself + calls CONF_modules_load_file() and we use that instead and we ignore + its return code! */ + + /* CONF_MFLAGS_DEFAULT_SECTION introduced some time between 0.9.8b and + 0.9.8e */ +#ifndef CONF_MFLAGS_DEFAULT_SECTION +#define CONF_MFLAGS_DEFAULT_SECTION 0x0 +#endif + + CONF_modules_load_file(NULL, NULL, + CONF_MFLAGS_DEFAULT_SECTION| + CONF_MFLAGS_IGNORE_MISSING_FILE); + /* Lets get nice error messages */ SSL_load_error_strings(); @@ -685,38 +712,39 @@ int Curl_ossl_init(void) OpenSSL_add_all_algorithms(); -#ifdef HAVE_RAND_SCREEN - /* This one gets a random value by reading the currently shown screen. - RAND_screen() is not thread-safe according to OpenSSL devs - although not - mentioned in documentation. */ - RAND_screen(); -#endif - return 1; } -#endif /* USE_SSLEAY */ - -#ifdef USE_SSLEAY - /* Global cleanup */ void Curl_ossl_cleanup(void) { - /* Free the SSL error strings */ - ERR_free_strings(); - - /* EVP_cleanup() removes all ciphers and digests from the table. */ + /* Free ciphers and digests lists */ EVP_cleanup(); #ifdef HAVE_ENGINE_CLEANUP + /* Free engine list */ ENGINE_cleanup(); #endif #ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA - /* this function was not present in 0.9.6b, but was added sometimes - later */ + /* Free OpenSSL ex_data table */ CRYPTO_cleanup_all_ex_data(); #endif + + /* Free OpenSSL error strings */ + ERR_free_strings(); + + /* Free thread local error state, destroying hash upon zero refcount */ +#ifdef HAVE_ERR_REMOVE_THREAD_STATE_NOARG + ERR_remove_thread_state(); +#elif defined(HAVE_ERR_REMOVE_THREAD_STATE) + ERR_remove_thread_state(NULL); +#else + ERR_remove_state(0); +#endif + + /* Free all memory allocated by all configuration modules */ + CONF_modules_free(); } /* @@ -746,7 +774,7 @@ int Curl_ossl_check_cxn(struct connectdata *conn) */ CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine) { -#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H) +#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) ENGINE *e; #if OPENSSL_VERSION_NUMBER >= 0x00909000L @@ -794,10 +822,12 @@ CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data) #ifdef HAVE_OPENSSL_ENGINE_H if(data->state.engine) { if(ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) { - infof(data,"set default crypto engine '%s'\n", ENGINE_get_id(data->state.engine)); + infof(data, "set default crypto engine '%s'\n", + ENGINE_get_id(data->state.engine)); } else { - failf(data, "set default crypto engine '%s' failed", ENGINE_get_id(data->state.engine)); + failf(data, "set default crypto engine '%s' failed", + ENGINE_get_id(data->state.engine)); return CURLE_SSL_ENGINE_SETFAILED; } } @@ -812,19 +842,17 @@ CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data) struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data) { struct curl_slist *list = NULL; -#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H) - struct curl_slist *beg = NULL; +#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) + struct curl_slist *beg; ENGINE *e; - for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) { - list = curl_slist_append(list, ENGINE_get_id(e)); - if(list == NULL) { - curl_slist_free_all(beg); + for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) { + beg = curl_slist_append(list, ENGINE_get_id(e)); + if(!beg) { + curl_slist_free_all(list); return NULL; } - else if(beg == NULL) { - beg = list; - } + list = beg; } #endif (void) data; @@ -881,7 +909,7 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) buffsize = (int)sizeof(buf); while(!done) { int what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); if(what > 0) { ERR_clear_error(); @@ -910,7 +938,7 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) default: /* openssl/ssl.h says "look at error stack/return value/errno" */ sslerror = ERR_get_error(); - failf(conn->data, "SSL read: %s, errno %d", + failf(conn->data, OSSL_PACKAGE " SSL read: %s, errno %d", ERR_error_string(sslerror, buf), SOCKERRNO); done = 1; @@ -963,19 +991,8 @@ void Curl_ossl_session_free(void *ptr) * This function is called when the 'data' struct is going away. Close * down everything and free all resources! */ -int Curl_ossl_close_all(struct SessionHandle *data) +void Curl_ossl_close_all(struct SessionHandle *data) { - /* - ERR_remove_state() frees the error queue associated with - thread pid. If pid == 0, the current thread will have its - error queue removed. - - Since error queue data structures are allocated - automatically for new threads, they must be freed when - threads are terminated in oder to avoid memory leaks. - */ - ERR_remove_state(0); - #ifdef HAVE_OPENSSL_ENGINE_H if(data->state.engine) { ENGINE_finish(data->state.engine); @@ -985,109 +1002,10 @@ int Curl_ossl_close_all(struct SessionHandle *data) #else (void)data; #endif - return 0; -} - -static int asn1_output(const ASN1_UTCTIME *tm, - char *buf, - size_t sizeofbuf) -{ - const char *asn1_string; - int gmt=FALSE; - int i; - int year=0,month=0,day=0,hour=0,minute=0,second=0; - - i=tm->length; - asn1_string=(const char *)tm->data; - - if(i < 10) - return 1; - if(asn1_string[i-1] == 'Z') - gmt=TRUE; - for (i=0; i<10; i++) - if((asn1_string[i] > '9') || (asn1_string[i] < '0')) - return 2; - - year= (asn1_string[0]-'0')*10+(asn1_string[1]-'0'); - if(year < 50) - year+=100; - - month= (asn1_string[2]-'0')*10+(asn1_string[3]-'0'); - if((month > 12) || (month < 1)) - return 3; - - day= (asn1_string[4]-'0')*10+(asn1_string[5]-'0'); - hour= (asn1_string[6]-'0')*10+(asn1_string[7]-'0'); - minute= (asn1_string[8]-'0')*10+(asn1_string[9]-'0'); - - if((asn1_string[10] >= '0') && (asn1_string[10] <= '9') && - (asn1_string[11] >= '0') && (asn1_string[11] <= '9')) - second= (asn1_string[10]-'0')*10+(asn1_string[11]-'0'); - - snprintf(buf, sizeofbuf, - "%04d-%02d-%02d %02d:%02d:%02d %s", - year+1900, month, day, hour, minute, second, (gmt?"GMT":"")); - - return 0; } /* ====================================================== */ -/* - * Match a hostname against a wildcard pattern. - * E.g. - * "foo.host.com" matches "*.host.com". - * - * We are a bit more liberal than RFC2818 describes in that we - * accept multiple "*" in pattern (similar to what some other browsers do). - * E.g. - * "abc.def.domain.com" should strickly not match "*.domain.com", but we - * don't consider "." to be important in CERT checking. - */ -#define HOST_NOMATCH 0 -#define HOST_MATCH 1 - -static int hostmatch(const char *hostname, const char *pattern) -{ - for(;;) { - char c = *pattern++; - - if(c == '\0') - return (*hostname ? HOST_NOMATCH : HOST_MATCH); - - if(c == '*') { - c = *pattern; - if(c == '\0') /* "*\0" matches anything remaining */ - return HOST_MATCH; - - while(*hostname) { - /* The only recursive function in libcurl! */ - if(hostmatch(hostname++,pattern) == HOST_MATCH) - return HOST_MATCH; - } - break; - } - - if(Curl_raw_toupper(c) != Curl_raw_toupper(*hostname++)) - break; - } - return HOST_NOMATCH; -} - -static int -cert_hostcheck(const char *match_pattern, const char *hostname) -{ - if(!match_pattern || !*match_pattern || - !hostname || !*hostname) /* sanity check */ - return 0; - - if(Curl_raw_equal(hostname, match_pattern)) /* trivial case */ - return 1; - - if(hostmatch(hostname,match_pattern) == HOST_MATCH) - return 1; - return 0; -} /* Quote from RFC2818 section 3.1 "Server Identity" @@ -1110,11 +1028,9 @@ cert_hostcheck(const char *match_pattern, const char *hostname) in the certificate and must exactly match the IP in the URI. */ -static CURLcode verifyhost(struct connectdata *conn, - X509 *server_cert) +static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) { - int matched = -1; /* -1 is no alternative match yet, 1 means match and 0 - means mismatch */ + bool matched = FALSE; int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */ size_t addrlen = 0; struct SessionHandle *data = conn->data; @@ -1124,7 +1040,7 @@ static CURLcode verifyhost(struct connectdata *conn, #else struct in_addr addr; #endif - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; #ifdef ENABLE_IPV6 if(conn->bits.ipv6_ip && @@ -1151,7 +1067,7 @@ static CURLcode verifyhost(struct connectdata *conn, numalts = sk_GENERAL_NAME_num(altnames); /* loop through all alternatives while none has matched */ - for (i=0; (ihost.name)) - matched = 1; - else - matched = 0; + Curl_cert_hostcheck(altptr, conn->host.name)) { + matched = TRUE; + infof(data, + " subjectAltName: host \"%s\" matched cert's \"%s\"\n", + conn->host.dispname, altptr); + } break; case GEN_IPADD: /* IP address comparison */ /* compare alternative IP address if the data chunk is the same size our server IP address is */ - if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) - matched = 1; - else - matched = 0; + if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) { + matched = TRUE; + infof(data, + " subjectAltName: host \"%s\" matched cert's IP address!\n", + conn->host.dispname); + } break; } } @@ -1196,26 +1116,28 @@ static CURLcode verifyhost(struct connectdata *conn, GENERAL_NAMES_free(altnames); } - if(matched == 1) - /* an alternative name matched the server hostname */ - infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname); - else if(matched == 0) { - /* an alternative name field existed, but didn't match and then - we MUST fail */ - infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname); - res = CURLE_PEER_FAILED_VERIFICATION; + if(matched) + /* an alternative name matched */ + ; + else if(altnames) { + /* an alternative name field existed, but didn't match and then we MUST + fail */ + infof(data, " subjectAltName does not match %s\n", conn->host.dispname); + failf(data, "SSL: no alternative certificate subject name matches " + "target host name '%s'", conn->host.dispname); + result = CURLE_PEER_FAILED_VERIFICATION; } else { - /* we have to look to the last occurence of a commonName in the + /* we have to look to the last occurrence of a commonName in the distinguished one to get the most significant one. */ - int j,i=-1 ; + int j, i=-1; -/* The following is done because of a bug in 0.9.6b */ + /* The following is done because of a bug in 0.9.6b */ unsigned char *nulstr = (unsigned char *)""; unsigned char *peer_CN = nulstr; - X509_NAME *name = X509_get_subject_name(server_cert) ; + X509_NAME *name = X509_get_subject_name(server_cert); if(name) while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i))>=0) i=j; @@ -1225,7 +1147,8 @@ static CURLcode verifyhost(struct connectdata *conn, UTF8 etc. */ if(i>=0) { - ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i)); + ASN1_STRING *tmp = + X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input is already UTF-8 encoded. We check for this case and copy the raw @@ -1246,57 +1169,179 @@ static CURLcode verifyhost(struct connectdata *conn, else /* not a UTF8 name */ j = ASN1_STRING_to_UTF8(&peer_CN, tmp); - if(peer_CN && ((int)strlen((char *)peer_CN) != j)) { + if(peer_CN && (curlx_uztosi(strlen((char *)peer_CN)) != j)) { /* there was a terminating zero before the end of string, this cannot match and we return failure! */ failf(data, "SSL: illegal cert name field"); - res = CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; } } } if(peer_CN == nulstr) peer_CN = NULL; -#ifdef CURL_DOES_CONVERSIONS else { /* convert peer_CN from UTF8 */ - size_t rc; - rc = Curl_convert_from_utf8(data, peer_CN, strlen(peer_CN)); + CURLcode rc = Curl_convert_from_utf8(data, peer_CN, strlen(peer_CN)); /* Curl_convert_from_utf8 calls failf if unsuccessful */ - if(rc != CURLE_OK) { + if(rc) { OPENSSL_free(peer_CN); return rc; } } -#endif /* CURL_DOES_CONVERSIONS */ - if(res) + if(result) /* error already detected, pass through */ ; else if(!peer_CN) { failf(data, "SSL: unable to obtain common name from peer certificate"); - res = CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; } - else if(!cert_hostcheck((const char *)peer_CN, conn->host.name)) { - if(data->set.ssl.verifyhost > 1) { - failf(data, "SSL: certificate subject name '%s' does not match " - "target host name '%s'", peer_CN, conn->host.dispname); - res = CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, "\t common name: %s (does not match '%s')\n", - peer_CN, conn->host.dispname); + else if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) { + failf(data, "SSL: certificate subject name '%s' does not match " + "target host name '%s'", peer_CN, conn->host.dispname); + result = CURLE_PEER_FAILED_VERIFICATION; } else { - infof(data, "\t common name: %s (matched)\n", peer_CN); + infof(data, " common name: %s (matched)\n", peer_CN); } if(peer_CN) OPENSSL_free(peer_CN); } - return res; + + return result; } -#endif /* USE_SSLEAY */ + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_NO_OCSP) +static CURLcode verifystatus(struct connectdata *conn, + struct ssl_connect_data *connssl) +{ + int i, ocsp_status; + const unsigned char *p; + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + + OCSP_RESPONSE *rsp = NULL; + OCSP_BASICRESP *br = NULL; + X509_STORE *st = NULL; + STACK_OF(X509) *ch = NULL; + + long len = SSL_get_tlsext_status_ocsp_resp(connssl->handle, &p); + + if(!p) { + failf(data, "No OCSP response received"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + rsp = d2i_OCSP_RESPONSE(NULL, &p, len); + if(!rsp) { + failf(data, "Invalid OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + ocsp_status = OCSP_response_status(rsp); + if(ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + failf(data, "Invalid OCSP response status: %s (%d)", + OCSP_response_status_str(ocsp_status), ocsp_status); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + br = OCSP_response_get1_basic(rsp); + if(!br) { + failf(data, "Invalid OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + ch = SSL_get_peer_cert_chain(connssl->handle); + st = SSL_CTX_get_cert_store(connssl->ctx); + +#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \ + defined(LIBRESSL_VERSION_NUMBER)) + /* The authorized responder cert in the OCSP response MUST be signed by the + peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert, + no problem, but if it's an intermediate cert OpenSSL has a bug where it + expects this issuer to be present in the chain embedded in the OCSP + response. So we add it if necessary. */ + + /* First make sure the peer cert chain includes both a peer and an issuer, + and the OCSP response contains a responder cert. */ + if(sk_X509_num(ch) >= 2 && sk_X509_num(br->certs) >= 1) { + X509 *responder = sk_X509_value(br->certs, sk_X509_num(br->certs) - 1); + + /* Find issuer of responder cert and add it to the OCSP response chain */ + for(i = 0; i < sk_X509_num(ch); i++) { + X509 *issuer = sk_X509_value(ch, i); + if(X509_check_issued(issuer, responder) == X509_V_OK) { + if(!OCSP_basic_add1_cert(br, issuer)) { + failf(data, "Could not add issuer cert to OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + } + } + } +#endif + + if(OCSP_basic_verify(br, ch, st, 0) <= 0) { + failf(data, "OCSP response verification failed"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + for(i = 0; i < OCSP_resp_count(br); i++) { + int cert_status, crl_reason; + OCSP_SINGLERESP *single = NULL; + + ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; + + single = OCSP_resp_get0(br, i); + if(!single) + continue; + + cert_status = OCSP_single_get0_status(single, &crl_reason, &rev, + &thisupd, &nextupd); + + if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) { + failf(data, "OCSP response has expired"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + infof(data, "SSL certificate status: %s (%d)\n", + OCSP_cert_status_str(cert_status), cert_status); + + switch(cert_status) { + case V_OCSP_CERTSTATUS_GOOD: + break; + + case V_OCSP_CERTSTATUS_REVOKED: + result = CURLE_SSL_INVALIDCERTSTATUS; + + failf(data, "SSL certificate revocation reason: %s (%d)", + OCSP_crl_reason_str(crl_reason), crl_reason); + goto end; + + case V_OCSP_CERTSTATUS_UNKNOWN: + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + } + +end: + if(br) OCSP_BASICRESP_free(br); + OCSP_RESPONSE_free(rsp); + + return result; +} +#endif + +#endif /* USE_OPENSSL */ /* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions and thus this cannot be done there. */ @@ -1304,6 +1349,7 @@ static CURLcode verifyhost(struct connectdata *conn, static const char *ssl_msg_type(int ssl_ver, int msg) { +#ifdef SSL2_VERSION_MAJOR if(ssl_ver == SSL2_VERSION_MAJOR) { switch (msg) { case SSL2_MT_ERROR: @@ -1326,7 +1372,9 @@ static const char *ssl_msg_type(int ssl_ver, int msg) return "Client CERT"; } } - else if(ssl_ver == SSL3_VERSION_MAJOR) { + else +#endif + if(ssl_ver == SSL3_VERSION_MAJOR) { switch (msg) { case SSL3_MT_HELLO_REQUEST: return "Hello request"; @@ -1334,8 +1382,12 @@ static const char *ssl_msg_type(int ssl_ver, int msg) return "Client hello"; case SSL3_MT_SERVER_HELLO: return "Server hello"; +#ifdef SSL3_MT_NEWSESSION_TICKET + case SSL3_MT_NEWSESSION_TICKET: + return "Newsession Ticket"; +#endif case SSL3_MT_CERTIFICATE: - return "CERT"; + return "Certificate"; case SSL3_MT_SERVER_KEY_EXCHANGE: return "Server key exchange"; case SSL3_MT_CLIENT_KEY_EXCHANGE: @@ -1348,6 +1400,10 @@ static const char *ssl_msg_type(int ssl_ver, int msg) return "CERT verify"; case SSL3_MT_FINISHED: return "Finished"; +#ifdef SSL3_MT_CERTIFICATE_STATUS + case SSL3_MT_CERTIFICATE_STATUS: + return "Certificate Status"; +#endif } } return "Unknown"; @@ -1355,12 +1411,22 @@ static const char *ssl_msg_type(int ssl_ver, int msg) static const char *tls_rt_type(int type) { - return ( - type == SSL3_RT_CHANGE_CIPHER_SPEC ? "TLS change cipher, " : - type == SSL3_RT_ALERT ? "TLS alert, " : - type == SSL3_RT_HANDSHAKE ? "TLS handshake, " : - type == SSL3_RT_APPLICATION_DATA ? "TLS app data, " : - "TLS Unknown, "); + switch(type) { +#ifdef SSL3_RT_HEADER + case SSL3_RT_HEADER: + return "TLS header"; +#endif + case SSL3_RT_CHANGE_CIPHER_SPEC: + return "TLS change cipher"; + case SSL3_RT_ALERT: + return "TLS alert"; + case SSL3_RT_HANDSHAKE: + return "TLS handshake"; + case SSL3_RT_APPLICATION_DATA: + return "TLS app data"; + default: + return "TLS Unknown"; + } } @@ -1368,38 +1434,77 @@ static const char *tls_rt_type(int type) * Our callback from the SSL/TLS layers. */ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, - const void *buf, size_t len, const SSL *ssl, - struct connectdata *conn) + const void *buf, size_t len, SSL *ssl, + void *userp) { struct SessionHandle *data; const char *msg_name, *tls_rt_name; char ssl_buf[1024]; - int ver, msg_type, txt_len; + char unknown[32]; + int msg_type, txt_len; + const char *verstr = NULL; + struct connectdata *conn = userp; if(!conn || !conn->data || !conn->data->set.fdebug || (direction != 0 && direction != 1)) return; data = conn->data; - ssl_ver >>= 8; - ver = (ssl_ver == SSL2_VERSION_MAJOR ? '2' : - ssl_ver == SSL3_VERSION_MAJOR ? '3' : '?'); - /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL - * always pass-up content-type as 0. But the interesting message-type - * is at 'buf[0]'. - */ - if(ssl_ver == SSL3_VERSION_MAJOR && content_type != 0) - tls_rt_name = tls_rt_type(content_type); - else - tls_rt_name = ""; + switch(ssl_ver) { +#ifdef SSL2_VERSION /* removed in recent versions */ + case SSL2_VERSION: + verstr = "SSLv2"; + break; +#endif +#ifdef SSL3_VERSION + case SSL3_VERSION: + verstr = "SSLv3"; + break; +#endif + case TLS1_VERSION: + verstr = "TLSv1.0"; + break; +#ifdef TLS1_1_VERSION + case TLS1_1_VERSION: + verstr = "TLSv1.1"; + break; +#endif +#ifdef TLS1_2_VERSION + case TLS1_2_VERSION: + verstr = "TLSv1.2"; + break; +#endif + case 0: + break; + default: + snprintf(unknown, sizeof(unknown), "(%x)", ssl_ver); + verstr = unknown; + break; + } - msg_type = *(char*)buf; - msg_name = ssl_msg_type(ssl_ver, msg_type); + if(ssl_ver) { + /* the info given when the version is zero is not that useful for us */ - txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "SSLv%c, %s%s (%d):\n", - ver, tls_rt_name, msg_name, msg_type); - Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL); + ssl_ver >>= 8; /* check the upper 8 bits only below */ + + /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL + * always pass-up content-type as 0. But the interesting message-type + * is at 'buf[0]'. + */ + if(ssl_ver == SSL3_VERSION_MAJOR && content_type) + tls_rt_name = tls_rt_type(content_type); + else + tls_rt_name = ""; + + msg_type = *(char*)buf; + msg_name = ssl_msg_type(ssl_ver, msg_type); + + txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n", + verstr, direction?"OUT":"IN", + tls_rt_name, msg_name, msg_type); + Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL); + } Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT : CURLINFO_SSL_DATA_IN, (char *)buf, len, NULL); @@ -1407,27 +1512,124 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, } #endif -#ifdef USE_SSLEAY +#ifdef USE_OPENSSL /* ====================================================== */ #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME # define use_sni(x) sni = (x) #else -# define use_sni(x) do { } while (0) +# define use_sni(x) Curl_nop_stmt #endif -static CURLcode -ossl_connect_step1(struct connectdata *conn, - int sockindex) -{ - CURLcode retcode = CURLE_OK; +/* Check for OpenSSL 1.0.2 which has ALPN support. */ +#undef HAS_ALPN +#if OPENSSL_VERSION_NUMBER >= 0x10002000L \ + && !defined(OPENSSL_NO_TLSEXT) +# define HAS_ALPN 1 +#endif +/* Check for OpenSSL 1.0.1 which has NPN support. */ +#undef HAS_NPN +#if OPENSSL_VERSION_NUMBER >= 0x10001000L \ + && !defined(OPENSSL_NO_TLSEXT) \ + && !defined(OPENSSL_NO_NEXTPROTONEG) +# define HAS_NPN 1 +#endif + +#ifdef HAS_NPN + +/* + * in is a list of lenght prefixed strings. this function has to select + * the protocol we want to use from the list and write its string into out. + */ + +static int +select_next_protocol(unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, + const char *key, unsigned int keylen) +{ + unsigned int i; + for(i = 0; i + keylen <= inlen; i += in[i] + 1) { + if(memcmp(&in[i + 1], key, keylen) == 0) { + *out = (unsigned char *) &in[i + 1]; + *outlen = in[i]; + return 0; + } + } + return -1; +} + +static int +select_next_proto_cb(SSL *ssl, + unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, + void *arg) +{ + struct connectdata *conn = (struct connectdata*) arg; + + (void)ssl; + +#ifdef USE_NGHTTP2 + if(conn->data->set.httpversion >= CURL_HTTP_VERSION_2 && + !select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_VERSION_ID, + NGHTTP2_PROTO_VERSION_ID_LEN)) { + infof(conn->data, "NPN, negotiated HTTP2 (%s)\n", + NGHTTP2_PROTO_VERSION_ID); + conn->negnpn = CURL_HTTP_VERSION_2; + return SSL_TLSEXT_ERR_OK; + } +#endif + + if(!select_next_protocol(out, outlen, in, inlen, ALPN_HTTP_1_1, + ALPN_HTTP_1_1_LENGTH)) { + infof(conn->data, "NPN, negotiated HTTP1.1\n"); + conn->negnpn = CURL_HTTP_VERSION_1_1; + return SSL_TLSEXT_ERR_OK; + } + + infof(conn->data, "NPN, no overlap, use HTTP1.1\n"); + *out = (unsigned char *)ALPN_HTTP_1_1; + *outlen = ALPN_HTTP_1_1_LENGTH; + conn->negnpn = CURL_HTTP_VERSION_1_1; + + return SSL_TLSEXT_ERR_OK; +} +#endif /* HAS_NPN */ + +static const char * +get_ssl_version_txt(SSL *ssl) +{ + if(!ssl) + return ""; + + switch(SSL_version(ssl)) { +#if OPENSSL_VERSION_NUMBER >= 0x1000100FL + case TLS1_2_VERSION: + return "TLSv1.2"; + case TLS1_1_VERSION: + return "TLSv1.1"; +#endif + case TLS1_VERSION: + return "TLSv1.0"; + case SSL3_VERSION: + return "SSLv3"; + case SSL2_VERSION: + return "SSLv2"; + } + return "unknown"; +} + +static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) +{ + CURLcode result = CURLE_OK; + char *ciphers; struct SessionHandle *data = conn->data; - SSL_METHOD_QUAL SSL_METHOD *req_method=NULL; - void *ssl_sessionid=NULL; - X509_LOOKUP *lookup=NULL; + SSL_METHOD_QUAL SSL_METHOD *req_method = NULL; + void *ssl_sessionid = NULL; + X509_LOOKUP *lookup = NULL; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + long ctx_options; #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME bool sni; #ifdef ENABLE_IPV6 @@ -1442,26 +1644,52 @@ ossl_connect_step1(struct connectdata *conn, /* Make funny stuff to get random input */ Curl_ossl_seed(data); + data->set.ssl.certverifyresult = !X509_V_OK; + /* check to see if we've been told to use an explicit SSL/TLS version */ + switch(data->set.ssl.version) { default: case CURL_SSLVERSION_DEFAULT: - /* we try to figure out version */ - req_method = SSLv23_client_method(); - use_sni(TRUE); - break; case CURL_SSLVERSION_TLSv1: - req_method = TLSv1_client_method(); + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: + case CURL_SSLVERSION_TLSv1_2: + /* it will be handled later with the context options */ +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ + !defined(LIBRESSL_VERSION_NUMBER) + req_method = TLS_client_method(); +#else + req_method = SSLv23_client_method(); +#endif use_sni(TRUE); break; case CURL_SSLVERSION_SSLv2: +#ifdef OPENSSL_NO_SSL2 + failf(data, OSSL_PACKAGE " was built without SSLv2 support"); + return CURLE_NOT_BUILT_IN; +#else +#ifdef USE_TLS_SRP + if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) + return CURLE_SSL_CONNECT_ERROR; +#endif req_method = SSLv2_client_method(); use_sni(FALSE); break; +#endif case CURL_SSLVERSION_SSLv3: +#ifdef OPENSSL_NO_SSL3_METHOD + failf(data, OSSL_PACKAGE " was built without SSLv3 support"); + return CURLE_NOT_BUILT_IN; +#else +#ifdef USE_TLS_SRP + if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) + return CURLE_SSL_CONNECT_ERROR; +#endif req_method = SSLv3_client_method(); use_sni(FALSE); break; +#endif } if(connssl->ctx) @@ -1469,22 +1697,20 @@ ossl_connect_step1(struct connectdata *conn, connssl->ctx = SSL_CTX_new(req_method); if(!connssl->ctx) { - failf(data, "SSL: couldn't create a context!"); + failf(data, "SSL: couldn't create a context: %s", + ERR_error_string(ERR_peek_error(), NULL)); return CURLE_OUT_OF_MEMORY; } +#ifdef SSL_MODE_RELEASE_BUFFERS + SSL_CTX_set_mode(connssl->ctx, SSL_MODE_RELEASE_BUFFERS); +#endif + #ifdef SSL_CTRL_SET_MSG_CALLBACK if(data->set.fdebug && data->set.verbose) { - /* the SSL trace callback is only used for verbose logging so we only - inform about failures of setting it */ - if(!SSL_CTX_callback_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK, - (void (*)(void))ssl_tls_trace)) { - infof(data, "SSL: couldn't set callback!\n"); - } - else if(!SSL_CTX_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, - conn)) { - infof(data, "SSL: couldn't set callback argument!\n"); - } + /* the SSL trace callback is only used for verbose logging */ + SSL_CTX_set_msg_callback(connssl->ctx, ssl_tls_trace); + SSL_CTX_set_msg_callback_arg(connssl->ctx, conn); } #endif @@ -1497,7 +1723,7 @@ ossl_connect_step1(struct connectdata *conn, The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to disable "rfc4507bis session ticket support". rfc4507bis was later turned - into the proper RFC5077 it seems: http://tools.ietf.org/html/rfc5077 + into the proper RFC5077 it seems: https://tools.ietf.org/html/rfc5077 The enabled extension concerns the session management. I wonder how often libcurl stops a connection and then resumes a TLS session. also, sending @@ -1507,29 +1733,140 @@ ossl_connect_step1(struct connectdata *conn, If someone writes an application with libcurl and openssl who wants to enable the feature, one can do this in the SSL callback. + SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper + interoperability with web server Netscape Enterprise Server 2.0.1 which + was released back in 1996. + + Due to CVE-2010-4180, option SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG has + become ineffective as of OpenSSL 0.9.8q and 1.0.0c. In order to mitigate + CVE-2010-4180 when using previous OpenSSL versions we no longer enable + this option regardless of OpenSSL version and SSL_OP_ALL definition. + + OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability + (https://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to + SSL_OP_ALL that _disables_ that work-around despite the fact that + SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to + keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit + must not be set. */ + + ctx_options = SSL_OP_ALL; + #ifdef SSL_OP_NO_TICKET - /* expect older openssl releases to not have this define so only use it if - present */ -#define CURL_CTX_OPTIONS SSL_OP_ALL|SSL_OP_NO_TICKET -#else -#define CURL_CTX_OPTIONS SSL_OP_ALL + ctx_options |= SSL_OP_NO_TICKET; #endif - SSL_CTX_set_options(connssl->ctx, CURL_CTX_OPTIONS); +#ifdef SSL_OP_NO_COMPRESSION + ctx_options |= SSL_OP_NO_COMPRESSION; +#endif - /* disable SSLv2 in the default case (i.e. allow SSLv3 and TLSv1) */ - if(data->set.ssl.version == CURL_SSLVERSION_DEFAULT) - SSL_CTX_set_options(connssl->ctx, SSL_OP_NO_SSLv2); +#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG + /* mitigate CVE-2010-4180 */ + ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; +#endif -#if 0 - /* - * Not sure it's needed to tell SSL_connect() that socket is - * non-blocking. It doesn't seem to care, but just return with - * SSL_ERROR_WANT_x. - */ - if(data->state.used_interface == Curl_if_multi) - SSL_CTX_ctrl(connssl->ctx, BIO_C_SET_NBIO, 1, NULL); +#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS + /* unless the user explicitly ask to allow the protocol vulnerability we + use the work-around */ + if(!conn->data->set.ssl_enable_beast) + ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; +#endif + + switch(data->set.ssl.version) { + case CURL_SSLVERSION_SSLv3: +#ifdef USE_TLS_SRP + if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { + infof(data, "Set version TLSv1.x for SRP authorisation\n"); + } +#endif + ctx_options |= SSL_OP_NO_SSLv2; + ctx_options |= SSL_OP_NO_TLSv1; +#if OPENSSL_VERSION_NUMBER >= 0x1000100FL + ctx_options |= SSL_OP_NO_TLSv1_1; + ctx_options |= SSL_OP_NO_TLSv1_2; +#endif + break; + + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + ctx_options |= SSL_OP_NO_SSLv2; + ctx_options |= SSL_OP_NO_SSLv3; + break; + + case CURL_SSLVERSION_TLSv1_0: + ctx_options |= SSL_OP_NO_SSLv2; + ctx_options |= SSL_OP_NO_SSLv3; +#if OPENSSL_VERSION_NUMBER >= 0x1000100FL + ctx_options |= SSL_OP_NO_TLSv1_1; + ctx_options |= SSL_OP_NO_TLSv1_2; +#endif + break; + +#if OPENSSL_VERSION_NUMBER >= 0x1000100FL + case CURL_SSLVERSION_TLSv1_1: + ctx_options |= SSL_OP_NO_SSLv2; + ctx_options |= SSL_OP_NO_SSLv3; + ctx_options |= SSL_OP_NO_TLSv1; + ctx_options |= SSL_OP_NO_TLSv1_2; + break; + + case CURL_SSLVERSION_TLSv1_2: + ctx_options |= SSL_OP_NO_SSLv2; + ctx_options |= SSL_OP_NO_SSLv3; + ctx_options |= SSL_OP_NO_TLSv1; + ctx_options |= SSL_OP_NO_TLSv1_1; + break; +#endif + +#ifndef OPENSSL_NO_SSL2 + case CURL_SSLVERSION_SSLv2: + ctx_options |= SSL_OP_NO_SSLv3; + ctx_options |= SSL_OP_NO_TLSv1; +#if OPENSSL_VERSION_NUMBER >= 0x1000100FL + ctx_options |= SSL_OP_NO_TLSv1_1; + ctx_options |= SSL_OP_NO_TLSv1_2; +#endif + break; +#endif + + default: + failf(data, "Unsupported SSL protocol version"); + return CURLE_SSL_CONNECT_ERROR; + } + + SSL_CTX_set_options(connssl->ctx, ctx_options); + +#ifdef HAS_NPN + if(data->set.ssl_enable_npn) + SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb, conn); +#endif + +#ifdef HAS_ALPN + if(data->set.ssl_enable_alpn) { + int cur = 0; + unsigned char protocols[128]; + +#ifdef USE_NGHTTP2 + if(data->set.httpversion >= CURL_HTTP_VERSION_2) { + protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; + + memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, + NGHTTP2_PROTO_VERSION_ID_LEN); + cur += NGHTTP2_PROTO_VERSION_ID_LEN; + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); + } +#endif + + protocols[cur++] = ALPN_HTTP_1_1_LENGTH; + memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); + cur += ALPN_HTTP_1_1_LENGTH; + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + /* expects length prefixed preference ordered list of protocols in wire + * format + */ + SSL_CTX_set_alpn_protos(connssl->ctx, protocols, cur); + } #endif if(data->set.str[STRING_CERT] || data->set.str[STRING_CERT_TYPE]) { @@ -1544,14 +1881,37 @@ ossl_connect_step1(struct connectdata *conn, } } - if(data->set.str[STRING_SSL_CIPHER_LIST]) { - if(!SSL_CTX_set_cipher_list(connssl->ctx, - data->set.str[STRING_SSL_CIPHER_LIST])) { - failf(data, "failed setting cipher list"); - return CURLE_SSL_CIPHER; + ciphers = data->set.str[STRING_SSL_CIPHER_LIST]; + if(!ciphers) + ciphers = (char *)DEFAULT_CIPHER_SELECTION; + if(!SSL_CTX_set_cipher_list(connssl->ctx, ciphers)) { + failf(data, "failed setting cipher list: %s", ciphers); + return CURLE_SSL_CIPHER; + } + infof(data, "Cipher selection: %s\n", ciphers); + +#ifdef USE_TLS_SRP + if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { + infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username); + + if(!SSL_CTX_set_srp_username(connssl->ctx, data->set.ssl.username)) { + failf(data, "Unable to set SRP user name"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!SSL_CTX_set_srp_password(connssl->ctx, data->set.ssl.password)) { + failf(data, "failed setting SRP password"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!data->set.str[STRING_SSL_CIPHER_LIST]) { + infof(data, "Setting cipher list SRP\n"); + + if(!SSL_CTX_set_cipher_list(connssl->ctx, "SRP")) { + failf(data, "failed setting SRP cipher list"); + return CURLE_SSL_CIPHER; + } } } - +#endif if(data->set.str[STRING_SSL_CAFILE] || data->set.str[STRING_SSL_CAPATH]) { /* tell SSL where to find CA certificates that are used to verify the servers certificate. */ @@ -1560,8 +1920,8 @@ ossl_connect_step1(struct connectdata *conn, data->set.str[STRING_SSL_CAPATH])) { if(data->set.ssl.verifypeer) { /* Fail if we insist on successfully verifying the server. */ - failf(data,"error setting certificate verify locations:\n" - " CAfile: %s\n CApath: %s\n", + failf(data, "error setting certificate verify locations:\n" + " CAfile: %s\n CApath: %s", data->set.str[STRING_SSL_CAFILE]? data->set.str[STRING_SSL_CAFILE]: "none", data->set.str[STRING_SSL_CAPATH]? @@ -1587,22 +1947,30 @@ ossl_connect_step1(struct connectdata *conn, data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]: "none"); } +#ifdef CURL_CA_FALLBACK + else if(data->set.ssl.verifypeer) { + /* verfying the peer without any CA certificates won't + work so use openssl's built in default as fallback */ + SSL_CTX_set_default_verify_paths(connssl->ctx); + } +#endif - if (data->set.str[STRING_SSL_CRLFILE]) { + if(data->set.str[STRING_SSL_CRLFILE]) { /* tell SSL where to find CRL file that is used to check certificate * revocation */ - lookup=X509_STORE_add_lookup(connssl->ctx->cert_store,X509_LOOKUP_file()); - if ( !lookup || - (!X509_load_crl_file(lookup,data->set.str[STRING_SSL_CRLFILE], - X509_FILETYPE_PEM)) ) { - failf(data,"error loading CRL file: %s\n", + lookup=X509_STORE_add_lookup(SSL_CTX_get_cert_store(connssl->ctx), + X509_LOOKUP_file()); + if(!lookup || + (!X509_load_crl_file(lookup, data->set.str[STRING_SSL_CRLFILE], + X509_FILETYPE_PEM)) ) { + failf(data, "error loading CRL file: %s", data->set.str[STRING_SSL_CRLFILE]); return CURLE_SSL_CRL_BADFILE; } else { /* Everything is fine. */ infof(data, "successfully load CRL file:\n"); - X509_STORE_set_flags(connssl->ctx->cert_store, + X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx), X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); } infof(data, @@ -1610,21 +1978,35 @@ ossl_connect_step1(struct connectdata *conn, data->set.str[STRING_SSL_CRLFILE]: "none"); } + /* Try building a chain using issuers in the trusted store first to avoid + problems with server-sent legacy intermediates. + Newer versions of OpenSSL do alternate chain checking by default which + gives us the same fix without as much of a performance hit (slight), so we + prefer that if available. + https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest + */ +#if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS) + if(data->set.ssl.verifypeer) { + X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx), + X509_V_FLAG_TRUSTED_FIRST); + } +#endif + /* SSL always tries to verify the peer, this only says whether it should * fail to connect if the verification fails, or if it should continue * anyway. In the latter case the result of the verification is checked with * SSL_get_verify_result() below. */ SSL_CTX_set_verify(connssl->ctx, data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE, - cert_verify_callback); + NULL); /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { - retcode = (*data->set.ssl.fsslctx)(data, connssl->ctx, - data->set.ssl.fsslctxp); - if(retcode) { - failf(data,"error signaled by ssl ctx callback"); - return retcode; + result = (*data->set.ssl.fsslctx)(data, connssl->ctx, + data->set.ssl.fsslctxp); + if(result) { + failf(data, "error signaled by ssl ctx callback"); + return result; } } @@ -1636,17 +2018,24 @@ ossl_connect_step1(struct connectdata *conn, failf(data, "SSL: couldn't create a context (handle)!"); return CURLE_OUT_OF_MEMORY; } + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_NO_OCSP) + if(data->set.ssl.verifystatus) + SSL_set_tlsext_status_type(connssl->handle, TLSEXT_STATUSTYPE_ocsp); +#endif + SSL_set_connect_state(connssl->handle); connssl->server_cert = 0x0; #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - if ((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && + if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && #ifdef ENABLE_IPV6 - (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && + (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && #endif - sni && - !SSL_set_tlsext_host_name(connssl->handle, conn->host.name)) + sni && + !SSL_set_tlsext_host_name(connssl->handle, conn->host.name)) infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); #endif @@ -1656,7 +2045,7 @@ ossl_connect_step1(struct connectdata *conn, /* we got a session id, use it! */ if(!SSL_set_session(connssl->handle, ssl_sessionid)) { failf(data, "SSL: SSL_set_session failed: %s", - ERR_error_string(ERR_get_error(),NULL)); + ERR_error_string(ERR_get_error(), NULL)); return CURLE_SSL_CONNECT_ERROR; } /* Informational message */ @@ -1665,22 +2054,21 @@ ossl_connect_step1(struct connectdata *conn, /* pass the raw socket into the SSL layers */ if(!SSL_set_fd(connssl->handle, (int)sockfd)) { - failf(data, "SSL: SSL_set_fd failed: %s", - ERR_error_string(ERR_get_error(),NULL)); - return CURLE_SSL_CONNECT_ERROR; + failf(data, "SSL: SSL_set_fd failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + return CURLE_SSL_CONNECT_ERROR; } connssl->connecting_state = ssl_connect_2; + return CURLE_OK; } -static CURLcode -ossl_connect_step2(struct connectdata *conn, int sockindex) +static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) { struct SessionHandle *data = conn->data; int err; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - DEBUGASSERT(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state); @@ -1706,38 +2094,42 @@ ossl_connect_step2(struct connectdata *conn, int sockindex) else { /* untreated error */ unsigned long errdetail; - char error_buffer[256]; /* OpenSSL documents that this must be at least - 256 bytes long. */ - CURLcode rc; - const char *cert_problem = NULL; + char error_buffer[256]=""; /* OpenSSL documents that this must be at + least 256 bytes long. */ + CURLcode result; + long lerr; + int lib; + int reason; - connssl->connecting_state = ssl_connect_2; /* the connection failed, - we're not waiting for - anything else. */ + /* the connection failed, we're not waiting for anything else. */ + connssl->connecting_state = ssl_connect_2; - errdetail = ERR_get_error(); /* Gets the earliest error code from the - thread's error queue and removes the - entry. */ + /* Get the earliest error code from the thread's error queue and removes + the entry. */ + errdetail = ERR_get_error(); - switch(errdetail) { - case 0x1407E086: - /* 1407E086: - SSL routines: - SSL2_SET_CERTIFICATE: - certificate verify failed */ - /* fall-through */ - case 0x14090086: - /* 14090086: - SSL routines: - SSL3_GET_SERVER_CERTIFICATE: - certificate verify failed */ - cert_problem = "SSL certificate problem, verify that the CA cert is" - " OK. Details:\n"; - rc = CURLE_SSL_CACERT; - break; - default: - rc = CURLE_SSL_CONNECT_ERROR; - break; + /* Extract which lib and reason */ + lib = ERR_GET_LIB(errdetail); + reason = ERR_GET_REASON(errdetail); + + if((lib == ERR_LIB_SSL) && + (reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) { + result = CURLE_SSL_CACERT; + + lerr = SSL_get_verify_result(connssl->handle); + if(lerr != X509_V_OK) { + snprintf(error_buffer, sizeof(error_buffer), + "SSL certificate problem: %s", + X509_verify_cert_error_string(lerr)); + } + else + /* strcpy() is fine here as long as the string fits within + error_buffer */ + strcpy(error_buffer, "SSL certificate verification failed"); + } + else { + result = CURLE_SSL_CONNECT_ERROR; + SSL_strerror(errdetail, error_buffer, sizeof(error_buffer)); } /* detail is already set to the SSL error above */ @@ -1746,16 +2138,16 @@ ossl_connect_step2(struct connectdata *conn, int sockindex) * (RST connection etc.), OpenSSL gives no explanation whatsoever and * the SO_ERROR is also lost. */ - if(CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) { + if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) { failf(data, "Unknown SSL protocol error in connection to %s:%ld ", - conn->host.name, conn->port); - return rc; + conn->host.name, conn->remote_port); + return result; } - /* Could be a CERT problem */ - SSL_strerror(errdetail, error_buffer, sizeof(error_buffer)); - failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer); - return rc; + /* Could be a CERT problem */ + failf(data, "%s", error_buffer); + + return result; } } else { @@ -1763,8 +2155,37 @@ ossl_connect_step2(struct connectdata *conn, int sockindex) connssl->connecting_state = ssl_connect_3; /* Informational message */ - infof (data, "SSL connection using %s\n", - SSL_get_cipher(connssl->handle)); + infof(data, "SSL connection using %s / %s\n", + get_ssl_version_txt(connssl->handle), + SSL_get_cipher(connssl->handle)); + +#ifdef HAS_ALPN + /* Sets data and len to negotiated protocol, len is 0 if no protocol was + * negotiated + */ + if(data->set.ssl_enable_alpn) { + const unsigned char* neg_protocol; + unsigned int len; + SSL_get0_alpn_selected(connssl->handle, &neg_protocol, &len); + if(len != 0) { + infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol); + +#ifdef USE_NGHTTP2 + if(len == NGHTTP2_PROTO_VERSION_ID_LEN && + !memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len)) { + conn->negnpn = CURL_HTTP_VERSION_2; + } + else +#endif + if(len == ALPN_HTTP_1_1_LENGTH && + !memcmp(ALPN_HTTP_1_1, neg_protocol, ALPN_HTTP_1_1_LENGTH)) { + conn->negnpn = CURL_HTTP_VERSION_1_1; + } + } + else + infof(data, "ALPN, server did not agree to a protocol\n"); + } +#endif return CURLE_OK; } @@ -1785,95 +2206,36 @@ static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) return 0; } -static CURLcode push_certinfo_len(struct SessionHandle *data, - int certnum, - const char *label, - const char *value, - size_t valuelen) -{ - struct curl_certinfo *ci = &data->info.certs; - char *output; - struct curl_slist *nl; - CURLcode res = CURLE_OK; - size_t labellen = strlen(label); - size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */ - - output = malloc(outlen); - if(!output) - return CURLE_OUT_OF_MEMORY; - - /* sprintf the label and colon */ - snprintf(output, outlen, "%s:", label); - - /* memcpy the value (it might not be zero terminated) */ - memcpy(&output[labellen+1], value, valuelen); - - /* zero terminate the output */ - output[labellen + 1 + valuelen] = 0; - - /* TODO: we should rather introduce an internal API that can do the - equivalent of curl_slist_append but doesn't strdup() the given data as - like in this place the extra malloc/free is totally pointless */ - nl = curl_slist_append(ci->certinfo[certnum], output); - if(!nl) { - curl_slist_free_all(ci->certinfo[certnum]); - res = CURLE_OUT_OF_MEMORY; - } - else - ci->certinfo[certnum] = nl; - - free(output); - - return res; -} - -/* this is a convenience function for push_certinfo_len that takes a zero - terminated value */ -static CURLcode push_certinfo(struct SessionHandle *data, - int certnum, - const char *label, - const char *value) -{ - size_t valuelen = strlen(value); - - return push_certinfo_len(data, certnum, label, value, valuelen); -} +#define push_certinfo(_label, _num) \ +do { \ + long info_len = BIO_get_mem_data(mem, &ptr); \ + Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \ + if(1!=BIO_reset(mem)) \ + break; \ +} WHILE_FALSE static void pubkey_show(struct SessionHandle *data, + BIO *mem, int num, const char *type, const char *name, - unsigned char *raw, - int len) + BIGNUM *bn) { - char buffer[1024]; - size_t left = sizeof(buffer); - int i; - char *ptr=buffer; + char *ptr; char namebuf[32]; snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); - for(i=0; i< len; i++) { - snprintf(ptr, left, "%02x:", raw[i]); - ptr += 3; - left -= 3; - } - infof(data, " %s: %s\n", namebuf, buffer); - push_certinfo(data, num, namebuf, buffer); + BN_print(mem, bn); + push_certinfo(namebuf, num); } #define print_pubkey_BN(_type, _name, _num) \ do { \ - if (pubkey->pkey._type->_name != NULL) { \ - int len = BN_num_bytes(pubkey->pkey._type->_name); \ - if(len < (int)sizeof(buf)) { \ - BN_bn2bin(pubkey->pkey._type->_name, (unsigned char*)buf); \ - buf[len] = 0; \ - pubkey_show(data, _num, #_type, #_name, (unsigned char*)buf, len); \ - } \ + if(_type->_name) { \ + pubkey_show(data, mem, _num, #_type, #_name, _type->_name); \ } \ -} while (0) +} WHILE_FALSE static int X509V3_ext(struct SessionHandle *data, int certnum, @@ -1882,11 +2244,11 @@ static int X509V3_ext(struct SessionHandle *data, int i; size_t j; - if(sk_X509_EXTENSION_num(exts) <= 0) + if((int)sk_X509_EXTENSION_num(exts) <= 0) /* no extensions, bail out */ return 1; - for (i=0; ivalue); + ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext)); BIO_get_mem_ptr(bio_out, &biomem); - /* biomem->length bytes at biomem->data, this little loop here is only - done for the infof() call, we send the "raw" data to the certinfo - function */ - for(j=0; j<(size_t)biomem->length; j++) { + for(j = 0; j < (size_t)biomem->length; j++) { const char *sep=""; if(biomem->data[j] == '\n') { sep=", "; j++; /* skip the newline */ }; - while((biomem->data[j] == ' ') && (j<(size_t)biomem->length)) + while((j<(size_t)biomem->length) && (biomem->data[j] == ' ')) j++; if(j<(size_t)biomem->length) - ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep, biomem->data[j]); + ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep, + biomem->data[j]); } - infof(data, " %s\n", buf); - push_certinfo(data, certnum, namebuf, buf); + Curl_ssl_push_certinfo(data, certnum, namebuf, buf); BIO_free(bio_out); @@ -1934,170 +2290,113 @@ static int X509V3_ext(struct SessionHandle *data, return 0; /* all is fine */ } - -static void X509_signature(struct SessionHandle *data, - int numcert, - ASN1_STRING *sig) -{ - char buf[1024]; - char *ptr = buf; - int i; - for (i=0; ilength; i++) - ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%02x:", sig->data[i]); - - infof(data, " Signature: %s\n", buf); - push_certinfo(data, numcert, "Signature", buf); -} - -static void dumpcert(struct SessionHandle *data, X509 *x, int numcert) -{ - BIO *bio_out = BIO_new(BIO_s_mem()); - BUF_MEM *biomem; - - /* this outputs the cert in this 64 column wide style with newlines and - -----BEGIN CERTIFICATE----- texts and more */ - PEM_write_bio_X509(bio_out, x); - - BIO_get_mem_ptr(bio_out, &biomem); - - infof(data, "%s\n", biomem->data); - - push_certinfo_len(data, numcert, "Cert", biomem->data, biomem->length); - - BIO_free(bio_out); - -} - - -static int init_certinfo(struct SessionHandle *data, - int num) -{ - struct curl_certinfo *ci = &data->info.certs; - struct curl_slist **table; - - Curl_ssl_free_certinfo(data); - - ci->num_of_certs = num; - table = calloc((size_t)num, sizeof(struct curl_slist *)); - if(!table) - return 1; - - ci->certinfo = table; - return 0; -} - static CURLcode get_cert_chain(struct connectdata *conn, struct ssl_connect_data *connssl) { + CURLcode result; STACK_OF(X509) *sk; int i; - char buf[512]; struct SessionHandle *data = conn->data; int numcerts; + BIO *mem; sk = SSL_get_peer_cert_chain(connssl->handle); - - if(!sk) + if(!sk) { return CURLE_OUT_OF_MEMORY; + } numcerts = sk_X509_num(sk); - if(init_certinfo(data, numcerts)) - return CURLE_OUT_OF_MEMORY; + result = Curl_ssl_init_certinfo(data, numcerts); + if(result) { + return result; + } - infof(data, "--- Certificate chain\n"); - for (i=0; ilength <= 4) { - value = ASN1_INTEGER_get(num); - infof(data," Serial Number: %ld (0x%lx)\n", value, value); - snprintf(buf, sizeof(buf), "%lx", value); - } - else { + num = X509_get_serialNumber(x); + if(num->type == V_ASN1_NEG_INTEGER) + BIO_puts(mem, "-"); + for(j = 0; j < num->length; j++) + BIO_printf(mem, "%02x", num->data[j]); + push_certinfo("Serial Number", i); - ptr = buf; - *ptr++ = 0; - if(num->type == V_ASN1_NEG_INTEGER) - *ptr++='-'; - - for (j=0; jlength; j++) { - /* TODO: length restrictions */ - snprintf(ptr, 3, "%02x%c",num->data[j], - ((j+1 == num->length)?'\n':':')); - ptr += 3; +#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS) + { + X509_ALGOR *palg; + ASN1_STRING *a = ASN1_STRING_new(); + if(a) { + X509_get0_signature(&psig, &palg, x); + X509_signature_print(mem, palg, a); + ASN1_STRING_free(a); } - if(num->length) - infof(data," Serial Number: %s\n", buf); - else - buf[0]=0; + i2a_ASN1_OBJECT(mem, palg->algorithm); + push_certinfo("Public Key Algorithm", i); + + X509V3_ext(data, i, X509_get0_extensions(x)); } - if(buf[0]) - push_certinfo(data, i, "Serial Number", buf); /* hex */ +#else + { + /* before OpenSSL 1.0.2 */ + X509_CINF *cinf = x->cert_info; - cinf = x->cert_info; + i2a_ASN1_OBJECT(mem, cinf->signature->algorithm); + push_certinfo("Signature Algorithm", i); - j = asn1_object_dump(cinf->signature->algorithm, buf, sizeof(buf)); - if(!j) { - infof(data, " Signature Algorithm: %s\n", buf); - push_certinfo(data, i, "Signature Algorithm", buf); + i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm); + push_certinfo("Public Key Algorithm", i); + + X509V3_ext(data, i, cinf->extensions); + + psig = x->signature; } +#endif - certdate = X509_get_notBefore(x); - asn1_output(certdate, buf, sizeof(buf)); - infof(data, " Start date: %s\n", buf); - push_certinfo(data, i, "Start date", buf); + ASN1_TIME_print(mem, X509_get_notBefore(x)); + push_certinfo("Start date", i); - certdate = X509_get_notAfter(x); - asn1_output(certdate, buf, sizeof(buf)); - infof(data, " Expire date: %s\n", buf); - push_certinfo(data, i, "Expire date", buf); - - j = asn1_object_dump(cinf->key->algor->algorithm, buf, sizeof(buf)); - if(!j) { - infof(data, " Public Key Algorithm: %s\n", buf); - push_certinfo(data, i, "Public Key Algorithm", buf); - } + ASN1_TIME_print(mem, X509_get_notAfter(x)); + push_certinfo("Expire date", i); pubkey = X509_get_pubkey(x); if(!pubkey) infof(data, " Unable to load public key\n"); else { - switch(pubkey->type) { + int pktype; +#ifdef HAVE_OPAQUE_EVP_PKEY + pktype = EVP_PKEY_id(pubkey); +#else + pktype = pubkey->type; +#endif + switch(pktype) { case EVP_PKEY_RSA: - infof(data, " RSA Public Key (%d bits)\n", - BN_num_bits(pubkey->pkey.rsa->n)); - snprintf(buf, sizeof(buf), "%d", BN_num_bits(pubkey->pkey.rsa->n)); - push_certinfo(data, i, "RSA Public Key", buf); + { + RSA *rsa; +#ifdef HAVE_OPAQUE_EVP_PKEY + rsa = EVP_PKEY_get0_RSA(pubkey); +#else + rsa = pubkey->pkey.rsa; +#endif + BIO_printf(mem, "%d", BN_num_bits(rsa->n)); + push_certinfo("RSA Public Key", i); print_pubkey_BN(rsa, n, i); print_pubkey_BN(rsa, e, i); @@ -2108,19 +2407,36 @@ static CURLcode get_cert_chain(struct connectdata *conn, print_pubkey_BN(rsa, dmq1, i); print_pubkey_BN(rsa, iqmp, i); break; + } case EVP_PKEY_DSA: + { + DSA *dsa; +#ifdef HAVE_OPAQUE_EVP_PKEY + dsa = EVP_PKEY_get0_DSA(pubkey); +#else + dsa = pubkey->pkey.dsa; +#endif print_pubkey_BN(dsa, p, i); print_pubkey_BN(dsa, q, i); print_pubkey_BN(dsa, g, i); print_pubkey_BN(dsa, priv_key, i); print_pubkey_BN(dsa, pub_key, i); break; + } case EVP_PKEY_DH: + { + DH *dh; +#ifdef HAVE_OPAQUE_EVP_PKEY + dh = EVP_PKEY_get0_DH(pubkey); +#else + dh = pubkey->pkey.dh; +#endif print_pubkey_BN(dh, p, i); print_pubkey_BN(dh, g, i); print_pubkey_BN(dh, priv_key, i); print_pubkey_BN(dh, pub_key, i); break; + } #if 0 case EVP_PKEY_EC: /* symbol not present in OpenSSL 0.9.6 */ /* left TODO */ @@ -2130,16 +2446,79 @@ static CURLcode get_cert_chain(struct connectdata *conn, EVP_PKEY_free(pubkey); } - X509V3_ext(data, i, cinf->extensions); + for(j = 0; j < psig->length; j++) + BIO_printf(mem, "%02x:", psig->data[j]); + push_certinfo("Signature", i); - X509_signature(data, i, x->signature); - - dumpcert(data, x, i); + PEM_write_bio_X509(mem, x); + push_certinfo("Cert", i); } + BIO_free(mem); + return CURLE_OK; } +/* + * Heavily modified from: + * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL + */ +static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data, X509* cert, + const char *pinnedpubkey) +{ + /* Scratch */ + int len1 = 0, len2 = 0; + unsigned char *buff1 = NULL, *temp = NULL; + + /* Result is returned to caller */ + CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + + /* if a path wasn't specified, don't pin */ + if(!pinnedpubkey) + return CURLE_OK; + + if(!cert) + return result; + + do { + /* Begin Gyrations to get the subjectPublicKeyInfo */ + /* Thanks to Viktor Dukhovni on the OpenSSL mailing list */ + + /* https://groups.google.com/group/mailing.openssl.users/browse_thread + /thread/d61858dae102c6c7 */ + len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL); + if(len1 < 1) + break; /* failed */ + + /* https://www.openssl.org/docs/crypto/buffer.html */ + buff1 = temp = OPENSSL_malloc(len1); + if(!buff1) + break; /* failed */ + + /* https://www.openssl.org/docs/crypto/d2i_X509.html */ + len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp); + + /* + * These checks are verifying we got back the same values as when we + * sized the buffer. It's pretty weak since they should always be the + * same. But it gives us something to test. + */ + if((len1 != len2) || !temp || ((temp - buff1) != len1)) + break; /* failed */ + + /* End Gyrations */ + + /* The one good exit point */ + result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); + } while(0); + + /* https://www.openssl.org/docs/crypto/buffer.html */ + if(buff1) + OPENSSL_free(buff1); + + return result; +} + /* * Get the server cert, verify it and show it etc, only call failf() if the * 'strict' argument is TRUE as otherwise all this is for informational @@ -2152,107 +2531,112 @@ static CURLcode servercert(struct connectdata *conn, struct ssl_connect_data *connssl, bool strict) { - CURLcode retcode = CURLE_OK; + CURLcode result = CURLE_OK; int rc; - long lerr; - ASN1_TIME *certdate; + long lerr, len; struct SessionHandle *data = conn->data; X509 *issuer; FILE *fp; - char buffer[256]; + char *buffer = data->state.buffer; + const char *ptr; + BIO *mem = BIO_new(BIO_s_mem()); if(data->set.ssl.certinfo) /* we've been asked to gather certificate info! */ (void)get_cert_chain(conn, connssl); - data->set.ssl.certverifyresult = !X509_V_OK; - connssl->server_cert = SSL_get_peer_certificate(connssl->handle); if(!connssl->server_cert) { - if(strict) - failf(data, "SSL: couldn't get peer certificate!"); + if(!strict) + return CURLE_OK; + + failf(data, "SSL: couldn't get peer certificate!"); return CURLE_PEER_FAILED_VERIFICATION; } - infof (data, "Server certificate:\n"); + + infof(data, "Server certificate:\n"); rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert), - buffer, sizeof(buffer)); - if(rc) { - if(strict) - failf(data, "SSL: couldn't get X509-subject!"); - X509_free(connssl->server_cert); - connssl->server_cert = NULL; - return CURLE_SSL_CONNECT_ERROR; - } - infof(data, "\t subject: %s\n", buffer); + buffer, BUFSIZE); + infof(data, " subject: %s\n", rc?"[NONE]":buffer); - certdate = X509_get_notBefore(connssl->server_cert); - asn1_output(certdate, buffer, sizeof(buffer)); - infof(data, "\t start date: %s\n", buffer); + ASN1_TIME_print(mem, X509_get_notBefore(connssl->server_cert)); + len = BIO_get_mem_data(mem, (char **) &ptr); + infof(data, " start date: %.*s\n", len, ptr); + rc = BIO_reset(mem); - certdate = X509_get_notAfter(connssl->server_cert); - asn1_output(certdate, buffer, sizeof(buffer)); - infof(data, "\t expire date: %s\n", buffer); + ASN1_TIME_print(mem, X509_get_notAfter(connssl->server_cert)); + len = BIO_get_mem_data(mem, (char **) &ptr); + infof(data, " expire date: %.*s\n", len, ptr); + rc = BIO_reset(mem); + + BIO_free(mem); if(data->set.ssl.verifyhost) { - retcode = verifyhost(conn, connssl->server_cert); - if(retcode) { + result = verifyhost(conn, connssl->server_cert); + if(result) { X509_free(connssl->server_cert); connssl->server_cert = NULL; - return retcode; + return result; } } rc = x509_name_oneline(X509_get_issuer_name(connssl->server_cert), - buffer, sizeof(buffer)); + buffer, BUFSIZE); if(rc) { if(strict) failf(data, "SSL: couldn't get X509-issuer name!"); - retcode = CURLE_SSL_CONNECT_ERROR; + result = CURLE_SSL_CONNECT_ERROR; } else { - infof(data, "\t issuer: %s\n", buffer); + infof(data, " issuer: %s\n", buffer); /* We could do all sorts of certificate verification stuff here before deallocating the certificate. */ /* e.g. match issuer name with provided issuer certificate */ - if (data->set.str[STRING_SSL_ISSUERCERT]) { - if (! (fp=fopen(data->set.str[STRING_SSL_ISSUERCERT],"r"))) { - if (strict) - failf(data, "SSL: Unable to open issuer cert (%s)\n", + if(data->set.str[STRING_SSL_ISSUERCERT]) { + fp = fopen(data->set.str[STRING_SSL_ISSUERCERT], FOPEN_READTEXT); + if(!fp) { + if(strict) + failf(data, "SSL: Unable to open issuer cert (%s)", data->set.str[STRING_SSL_ISSUERCERT]); X509_free(connssl->server_cert); connssl->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } - issuer = PEM_read_X509(fp,NULL,ZERO_NULL,NULL); - if (!issuer) { - if (strict) - failf(data, "SSL: Unable to read issuer cert (%s)\n", + + issuer = PEM_read_X509(fp, NULL, ZERO_NULL, NULL); + if(!issuer) { + if(strict) + failf(data, "SSL: Unable to read issuer cert (%s)", data->set.str[STRING_SSL_ISSUERCERT]); X509_free(connssl->server_cert); X509_free(issuer); fclose(fp); return CURLE_SSL_ISSUER_ERROR; } + fclose(fp); - if (X509_check_issued(issuer,connssl->server_cert) != X509_V_OK) { - if (strict) - failf(data, "SSL: Certificate issuer check failed (%s)\n", + + if(X509_check_issued(issuer, connssl->server_cert) != X509_V_OK) { + if(strict) + failf(data, "SSL: Certificate issuer check failed (%s)", data->set.str[STRING_SSL_ISSUERCERT]); X509_free(connssl->server_cert); X509_free(issuer); connssl->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } - infof(data, "\t SSL certificate issuer check ok (%s)\n", + + infof(data, " SSL certificate issuer check ok (%s)\n", data->set.str[STRING_SSL_ISSUERCERT]); X509_free(issuer); } - lerr = data->set.ssl.certverifyresult= + lerr = data->set.ssl.certverifyresult = SSL_get_verify_result(connssl->handle); + if(data->set.ssl.certverifyresult != X509_V_OK) { if(data->set.ssl.verifypeer) { /* We probably never reach this, because SSL_connect() will fail @@ -2260,75 +2644,81 @@ static CURLcode servercert(struct connectdata *conn, if(strict) failf(data, "SSL certificate verify result: %s (%ld)", X509_verify_cert_error_string(lerr), lerr); - retcode = CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; } else - infof(data, "\t SSL certificate verify result: %s (%ld)," + infof(data, " SSL certificate verify result: %s (%ld)," " continuing anyway.\n", X509_verify_cert_error_string(lerr), lerr); } else - infof(data, "\t SSL certificate verify ok.\n"); + infof(data, " SSL certificate verify ok.\n"); + } + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_NO_OCSP) + if(data->set.ssl.verifystatus) { + result = verifystatus(conn, connssl); + if(result) { + X509_free(connssl->server_cert); + connssl->server_cert = NULL; + return result; + } + } +#endif + + if(!strict) + /* when not strict, we don't bother about the verify cert problems */ + result = CURLE_OK; + + ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + if(!result && ptr) { + result = pkp_pin_peer_pubkey(data, connssl->server_cert, ptr); + if(result) + failf(data, "SSL: public key does not match pinned public key!"); } X509_free(connssl->server_cert); connssl->server_cert = NULL; connssl->connecting_state = ssl_connect_done; - return retcode; + return result; } - -static CURLcode -ossl_connect_step3(struct connectdata *conn, - int sockindex) +static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) { - CURLcode retcode = CURLE_OK; - void *old_ssl_sessionid=NULL; + CURLcode result = CURLE_OK; + void *old_ssl_sessionid = NULL; struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - int incache; + bool incache; SSL_SESSION *our_ssl_sessionid; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); -#ifdef HAVE_SSL_GET1_SESSION our_ssl_sessionid = SSL_get1_session(connssl->handle); - /* SSL_get1_session() will increment the reference - count and the session will stay in memory until explicitly freed with - SSL_SESSION_free(3), regardless of its state. - This function was introduced in openssl 0.9.5a. */ -#else - our_ssl_sessionid = SSL_get_session(connssl->handle); - - /* if SSL_get1_session() is unavailable, use SSL_get_session(). - This is an inferior option because the session can be flushed - at any time by openssl. It is included only so curl compiles - under versions of openssl < 0.9.5a. - - WARNING: How curl behaves if it's session is flushed is - untested. - */ -#endif + /* SSL_get1_session() will increment the reference count and the session + will stay in memory until explicitly freed with SSL_SESSION_free(3), + regardless of its state. */ incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); - if (incache) { - if (old_ssl_sessionid != our_ssl_sessionid) { + if(incache) { + if(old_ssl_sessionid != our_ssl_sessionid) { infof(data, "old SSL session ID is stale, removing\n"); Curl_ssl_delsessionid(conn, old_ssl_sessionid); incache = FALSE; } } - if (!incache) { - retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */); - if(retcode) { + + if(!incache) { + result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, + 0 /* unknown size */); + if(result) { failf(data, "failed to store ssl session"); - return retcode; + return result; } } -#ifdef HAVE_SSL_GET1_SESSION else { /* Session was incache, so refcount already incremented earlier. * Avoid further increments with each SSL_get1_session() call. @@ -2336,7 +2726,6 @@ ossl_connect_step3(struct connectdata *conn, */ SSL_SESSION_free(our_ssl_sessionid); } -#endif /* * We check certificates to authenticate the server; otherwise we risk @@ -2345,26 +2734,24 @@ ossl_connect_step3(struct connectdata *conn, * operations. */ - if(!data->set.ssl.verifypeer) - (void)servercert(conn, connssl, FALSE); - else - retcode = servercert(conn, connssl, TRUE); + result = servercert(conn, connssl, + (data->set.ssl.verifypeer || data->set.ssl.verifyhost)); - if(CURLE_OK == retcode) + if(!result) connssl->connecting_state = ssl_connect_done; - return retcode; + + return result; } static Curl_recv ossl_recv; static Curl_send ossl_send; -static CURLcode -ossl_connect_common(struct connectdata *conn, - int sockindex, - bool nonblocking, - bool *done) +static CURLcode ossl_connect_common(struct connectdata *conn, + int sockindex, + bool nonblocking, + bool *done) { - CURLcode retcode; + CURLcode result; struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; @@ -2377,18 +2764,19 @@ ossl_connect_common(struct connectdata *conn, return CURLE_OK; } - if(ssl_connect_1==connssl->connecting_state) { + if(ssl_connect_1 == connssl->connecting_state) { /* Find out how much more time we're allowed */ - timeout_ms = Curl_timeleft(conn, NULL, TRUE); + timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } - retcode = ossl_connect_step1(conn, sockindex); - if(retcode) - return retcode; + + result = ossl_connect_step1(conn, sockindex); + if(result) + return result; } while(ssl_connect_2 == connssl->connecting_state || @@ -2396,7 +2784,7 @@ ossl_connect_common(struct connectdata *conn, ssl_connect_2_writing == connssl->connecting_state) { /* check allowed time left */ - timeout_ms = Curl_timeleft(conn, NULL, TRUE); + timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ @@ -2405,16 +2793,15 @@ ossl_connect_common(struct connectdata *conn, } /* if ssl is expecting something, check if it's available. */ - if(connssl->connecting_state == ssl_connect_2_reading - || connssl->connecting_state == ssl_connect_2_writing) { + if(connssl->connecting_state == ssl_connect_2_reading || + connssl->connecting_state == ssl_connect_2_writing) { curl_socket_t writefd = ssl_connect_2_writing== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, - nonblocking?0:(int)timeout_ms); + what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -2440,23 +2827,22 @@ ossl_connect_common(struct connectdata *conn, * before step2 has completed while ensuring that a client using select() * or epoll() will always have a valid fdset to wait on. */ - retcode = ossl_connect_step2(conn, sockindex); - if(retcode || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) - return retcode; + result = ossl_connect_step2(conn, sockindex); + if(result || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return result; } /* repeat step2 until all transactions are done. */ - - if(ssl_connect_3==connssl->connecting_state) { - retcode = ossl_connect_step3(conn, sockindex); - if(retcode) - return retcode; + if(ssl_connect_3 == connssl->connecting_state) { + result = ossl_connect_step3(conn, sockindex); + if(result) + return result; } - if(ssl_connect_done==connssl->connecting_state) { + if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; conn->recv[sockindex] = ossl_recv; conn->send[sockindex] = ossl_send; @@ -2471,36 +2857,32 @@ ossl_connect_common(struct connectdata *conn, return CURLE_OK; } -CURLcode -Curl_ossl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) +CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done) { return ossl_connect_common(conn, sockindex, TRUE, done); } -CURLcode -Curl_ossl_connect(struct connectdata *conn, - int sockindex) +CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex) { - CURLcode retcode; + CURLcode result; bool done = FALSE; - retcode = ossl_connect_common(conn, sockindex, FALSE, &done); - if(retcode) - return retcode; + result = ossl_connect_common(conn, sockindex, FALSE, &done); + if(result) + return result; DEBUGASSERT(done); return CURLE_OK; } -bool Curl_ossl_data_pending(const struct connectdata *conn, - int connindex) +bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex) { if(conn->ssl[connindex].handle) /* SSL is in use */ - return (bool)(0 != SSL_pending(conn->ssl[connindex].handle)); + return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE; else return FALSE; } @@ -2525,14 +2907,14 @@ static ssize_t ossl_send(struct connectdata *conn, memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen); - if(rc < 0) { + if(rc <= 0) { err = SSL_get_error(conn->ssl[sockindex].handle, rc); switch(err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* The operation did not complete; the same TLS/SSL I/O function - should be called again later. This is basicly an EWOULDBLOCK + should be called again later. This is basically an EWOULDBLOCK equivalent. */ *curlcode = CURLE_AGAIN; return -1; @@ -2555,6 +2937,7 @@ static ssize_t ossl_send(struct connectdata *conn, *curlcode = CURLE_SEND_ERROR; return -1; } + *curlcode = CURLE_OK; return (ssize_t)rc; /* number of bytes */ } @@ -2574,7 +2957,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, buffsize); - if(nread < 0) { + if(nread <= 0) { /* failed SSL_read */ int err = SSL_get_error(conn->ssl[num].handle, (int)nread); @@ -2588,13 +2971,19 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ *curlcode = CURLE_AGAIN; return -1; default: - /* openssl/ssl.h says "look at error stack/return value/errno" */ + /* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return + value/errno" */ + /* https://www.openssl.org/docs/crypto/ERR_get_error.html */ sslerror = ERR_get_error(); - failf(conn->data, "SSL read: %s, errno %d", - ERR_error_string(sslerror, error_buffer), - SOCKERRNO); - *curlcode = CURLE_RECV_ERROR; - return -1; + if((nread < 0) || sslerror) { + /* If the return code was negative or there actually is an error in the + queue */ + failf(conn->data, "SSL read: %s, errno %d", + ERR_error_string(sslerror, error_buffer), + SOCKERRNO); + *curlcode = CURLE_RECV_ERROR; + return -1; + } } } return nread; @@ -2602,63 +2991,87 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ size_t Curl_ossl_version(char *buffer, size_t size) { -#ifdef YASSL_VERSION - /* yassl provides an OpenSSL API compatiblity layer so it looks identical - to OpenSSL in all other aspects */ - return snprintf(buffer, size, "yassl/%s", YASSL_VERSION); -#else /* YASSL_VERSION */ - -#if(SSLEAY_VERSION_NUMBER >= 0x905000) - { - char sub[2]; - unsigned long ssleay_value; - sub[1]='\0'; - ssleay_value=SSLeay(); - if(ssleay_value < 0x906000) { - ssleay_value=SSLEAY_VERSION_NUMBER; - sub[0]='\0'; - } - else { - if(ssleay_value&0xff0) { +#ifdef OPENSSL_IS_BORINGSSL + return snprintf(buffer, size, OSSL_PACKAGE); +#else /* OPENSSL_IS_BORINGSSL */ + char sub[3]; + unsigned long ssleay_value; + sub[2]='\0'; + sub[1]='\0'; + ssleay_value=SSLeay(); + if(ssleay_value < 0x906000) { + ssleay_value=SSLEAY_VERSION_NUMBER; + sub[0]='\0'; + } + else { + if(ssleay_value&0xff0) { + int minor_ver = (ssleay_value >> 4) & 0xff; + if(minor_ver > 26) { + /* handle extended version introduced for 0.9.8za */ + sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1); + sub[0] = 'z'; + } + else { sub[0]=(char)(((ssleay_value>>4)&0xff) + 'a' -1); } - else - sub[0]='\0'; - } - - return snprintf(buffer, size, "OpenSSL/%lx.%lx.%lx%s", - (ssleay_value>>28)&0xf, - (ssleay_value>>20)&0xff, - (ssleay_value>>12)&0xff, - sub); - } - -#else /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */ - -#if(SSLEAY_VERSION_NUMBER >= 0x900000) - return snprintf(buffer, size, "OpenSSL/%lx.%lx.%lx", - (SSLEAY_VERSION_NUMBER>>28)&0xff, - (SSLEAY_VERSION_NUMBER>>20)&0xff, - (SSLEAY_VERSION_NUMBER>>12)&0xf); - -#else /* (SSLEAY_VERSION_NUMBER >= 0x900000) */ - { - char sub[2]; - sub[1]='\0'; - if(SSLEAY_VERSION_NUMBER&0x0f) { - sub[0]=(SSLEAY_VERSION_NUMBER&0x0f) + 'a' -1; } else sub[0]='\0'; - - return snprintf(buffer, size, "SSL/%x.%x.%x%s", - (SSLEAY_VERSION_NUMBER>>12)&0xff, - (SSLEAY_VERSION_NUMBER>>8)&0xf, - (SSLEAY_VERSION_NUMBER>>4)&0xf, sub); } -#endif /* (SSLEAY_VERSION_NUMBER >= 0x900000) */ -#endif /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */ -#endif /* YASSL_VERSION */ + return snprintf(buffer, size, "%s/%lx.%lx.%lx%s", + OSSL_PACKAGE, + (ssleay_value>>28)&0xf, + (ssleay_value>>20)&0xff, + (ssleay_value>>12)&0xff, + sub); +#endif /* OPENSSL_IS_BORINGSSL */ } -#endif /* USE_SSLEAY */ + +/* can be called with data == NULL */ +int Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy, + size_t length) +{ + if(data) { + Curl_ossl_seed(data); /* Initiate the seed if not already done */ + } + RAND_bytes(entropy, curlx_uztosi(length)); + return 0; /* 0 as in no problem */ +} + +void Curl_ossl_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum /* output */, + size_t unused) +{ + MD5_CTX MD5pw; + (void)unused; + MD5_Init(&MD5pw); + MD5_Update(&MD5pw, tmp, tmplen); + MD5_Final(md5sum, &MD5pw); +} + +#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) +void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum /* output */, + size_t unused) +{ + SHA256_CTX SHA256pw; + (void)unused; + SHA256_Init(&SHA256pw); + SHA256_Update(&SHA256pw, tmp, tmplen); + SHA256_Final(sha256sum, &SHA256pw); +} +#endif + +bool Curl_ossl_cert_status_request(void) +{ +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_NO_OCSP) + return TRUE; +#else + return FALSE; +#endif +} +#endif /* USE_OPENSSL */ diff --git a/project/jni/curl/lib/ssluse.h b/project/jni/curl/lib/vtls/openssl.h similarity index 62% rename from project/jni/curl/lib/ssluse.h rename to project/jni/curl/lib/vtls/openssl.h index 2ac0ad2ec..c8e32af0b 100644 --- a/project/jni/curl/lib/ssluse.h +++ b/project/jni/curl/lib/vtls/openssl.h @@ -1,5 +1,5 @@ -#ifndef __SSLUSE_H -#define __SSLUSE_H +#ifndef HEADER_CURL_SSLUSE_H +#define HEADER_CURL_SSLUSE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,12 +22,15 @@ * ***************************************************************************/ -#ifdef USE_SSLEAY +#include "curl_setup.h" + +#ifdef USE_OPENSSL /* - * This header should only be needed to get included by sslgen.c and ssluse.c + * This header should only be needed to get included by vtls.c and openssl.c */ #include "urldata.h" + CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex); CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn, int sockindex, @@ -38,7 +41,7 @@ void Curl_ossl_close(struct connectdata *conn, int sockindex); /* tell OpenSSL to close down all open information regarding connections (and thus session ID caching etc) */ -int Curl_ossl_close_all(struct SessionHandle *data); +void Curl_ossl_close_all(struct SessionHandle *data); /* Sets an OpenSSL engine */ CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine); @@ -58,12 +61,36 @@ void Curl_ossl_cleanup(void); size_t Curl_ossl_version(char *buffer, size_t size); int Curl_ossl_check_cxn(struct connectdata *cxn); -int Curl_ossl_seed(struct SessionHandle *data); - int Curl_ossl_shutdown(struct connectdata *conn, int sockindex); bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex); +/* return 0 if a find random is filled in */ +int Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy, + size_t length); +void Curl_ossl_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum /* output */, + size_t unused); +void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum /* output */, + size_t unused); + +bool Curl_ossl_cert_status_request(void); + +/* Set the API backend definition to OpenSSL */ +#define CURL_SSL_BACKEND CURLSSLBACKEND_OPENSSL + +/* this backend supports the CAPATH option */ +#define have_curlssl_ca_path 1 + +/* this backend supports CURLOPT_CERTINFO */ +#define have_curlssl_certinfo 1 + +/* this backend suppots CURLOPT_SSL_CTX_* */ +#define have_curlssl_ssl_ctx 1 + /* API setup for OpenSSL */ #define curlssl_init Curl_ossl_init #define curlssl_cleanup Curl_ossl_cleanup @@ -79,6 +106,15 @@ bool Curl_ossl_data_pending(const struct connectdata *conn, #define curlssl_version Curl_ossl_version #define curlssl_check_cxn Curl_ossl_check_cxn #define curlssl_data_pending(x,y) Curl_ossl_data_pending(x,y) +#define curlssl_random(x,y,z) Curl_ossl_random(x,y,z) +#define curlssl_md5sum(a,b,c,d) Curl_ossl_md5sum(a,b,c,d) +#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) +#define curlssl_sha256sum(a,b,c,d) Curl_ossl_sha256sum(a,b,c,d) +#endif +#define curlssl_cert_status_request() Curl_ossl_cert_status_request() -#endif /* USE_SSLEAY */ -#endif /* __SSLUSE_H */ +#define DEFAULT_CIPHER_SELECTION \ + "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH" + +#endif /* USE_OPENSSL */ +#endif /* HEADER_CURL_SSLUSE_H */ diff --git a/project/jni/curl/lib/vtls/polarssl.c b/project/jni/curl/lib/vtls/polarssl.c new file mode 100644 index 000000000..fcce60f05 --- /dev/null +++ b/project/jni/curl/lib/vtls/polarssl.c @@ -0,0 +1,753 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2010 - 2011, Hoi-Ho Chan, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Source file for all PolarSSL-specific code for the TLS/SSL layer. No code + * but vtls.c should ever call or use these functions. + * + */ + +#include "curl_setup.h" + +#ifdef USE_POLARSSL + +#include +#include +#include +#include +#include + +#if POLARSSL_VERSION_NUMBER < 0x01030000 +#error too old PolarSSL +#endif + +#include +#include +#include + +#include "urldata.h" +#include "sendf.h" +#include "inet_pton.h" +#include "polarssl.h" +#include "vtls.h" +#include "parsedate.h" +#include "connect.h" /* for the connect timeout */ +#include "select.h" +#include "rawstr.h" +#include "polarssl_threadlock.h" +#include "curl_printf.h" +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* apply threading? */ +#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) +#define THREADING_SUPPORT +#endif + +#if defined(THREADING_SUPPORT) +static entropy_context entropy; + +static int entropy_init_initialized = 0; + +/* start of entropy_init_mutex() */ +static void entropy_init_mutex(entropy_context *ctx) +{ + /* lock 0 = entropy_init_mutex() */ + Curl_polarsslthreadlock_lock_function(0); + if(entropy_init_initialized == 0) { + entropy_init(ctx); + entropy_init_initialized = 1; + } + Curl_polarsslthreadlock_unlock_function(0); +} +/* end of entropy_init_mutex() */ + +/* start of entropy_func_mutex() */ +static int entropy_func_mutex(void *data, unsigned char *output, size_t len) +{ + int ret; + /* lock 1 = entropy_func_mutex() */ + Curl_polarsslthreadlock_lock_function(1); + ret = entropy_func(data, output, len); + Curl_polarsslthreadlock_unlock_function(1); + + return ret; +} +/* end of entropy_func_mutex() */ + +#endif /* THREADING_SUPPORT */ + +/* Define this to enable lots of debugging for PolarSSL */ +#undef POLARSSL_DEBUG + +#ifdef POLARSSL_DEBUG +static void polarssl_debug(void *context, int level, const char *line) +{ + struct SessionHandle *data = NULL; + + if(!context) + return; + + data = (struct SessionHandle *)context; + + infof(data, "%s", line); + (void) level; +} +#else +#endif + +/* ALPN for http2? */ +#ifdef POLARSSL_SSL_ALPN +# define HAS_ALPN +#endif + +static Curl_recv polarssl_recv; +static Curl_send polarssl_send; + + +static CURLcode +polarssl_connect_step1(struct connectdata *conn, + int sockindex) +{ + struct SessionHandle *data = conn->data; + struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + + bool sni = TRUE; /* default is SNI enabled */ + int ret = -1; +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif + void *old_session = NULL; + size_t old_session_size = 0; + char errorbuf[128]; + errorbuf[0]=0; + + /* PolarSSL only supports SSLv3 and TLSv1 */ + if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { + failf(data, "PolarSSL does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + } + else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) + sni = FALSE; /* SSLv3 has no SNI */ + +#ifdef THREADING_SUPPORT + entropy_init_mutex(&entropy); + + if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func_mutex, &entropy, + connssl->ssn.id, connssl->ssn.length)) != 0) { +#ifdef POLARSSL_ERROR_C + error_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* POLARSSL_ERROR_C */ + failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", + -ret, errorbuf); + } +#else + entropy_init(&connssl->entropy); + + if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func, &connssl->entropy, + connssl->ssn.id, connssl->ssn.length)) != 0) { +#ifdef POLARSSL_ERROR_C + error_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* POLARSSL_ERROR_C */ + failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", + -ret, errorbuf); + } +#endif /* THREADING_SUPPORT */ + + /* Load the trusted CA */ + memset(&connssl->cacert, 0, sizeof(x509_crt)); + + if(data->set.str[STRING_SSL_CAFILE]) { + ret = x509_crt_parse_file(&connssl->cacert, + data->set.str[STRING_SSL_CAFILE]); + + if(ret<0) { +#ifdef POLARSSL_ERROR_C + error_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* POLARSSL_ERROR_C */ + failf(data, "Error reading ca cert file %s - PolarSSL: (-0x%04X) %s", + data->set.str[STRING_SSL_CAFILE], -ret, errorbuf); + + if(data->set.ssl.verifypeer) + return CURLE_SSL_CACERT_BADFILE; + } + } + + if(data->set.str[STRING_SSL_CAPATH]) { + ret = x509_crt_parse_path(&connssl->cacert, + data->set.str[STRING_SSL_CAPATH]); + + if(ret<0) { +#ifdef POLARSSL_ERROR_C + error_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* POLARSSL_ERROR_C */ + failf(data, "Error reading ca cert path %s - PolarSSL: (-0x%04X) %s", + data->set.str[STRING_SSL_CAPATH], -ret, errorbuf); + + if(data->set.ssl.verifypeer) + return CURLE_SSL_CACERT_BADFILE; + } + } + + /* Load the client certificate */ + memset(&connssl->clicert, 0, sizeof(x509_crt)); + + if(data->set.str[STRING_CERT]) { + ret = x509_crt_parse_file(&connssl->clicert, + data->set.str[STRING_CERT]); + + if(ret) { +#ifdef POLARSSL_ERROR_C + error_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* POLARSSL_ERROR_C */ + failf(data, "Error reading client cert file %s - PolarSSL: (-0x%04X) %s", + data->set.str[STRING_CERT], -ret, errorbuf); + + return CURLE_SSL_CERTPROBLEM; + } + } + + /* Load the client private key */ + if(data->set.str[STRING_KEY]) { + pk_context pk; + pk_init(&pk); + ret = pk_parse_keyfile(&pk, data->set.str[STRING_KEY], + data->set.str[STRING_KEY_PASSWD]); + if(ret == 0 && !pk_can_do(&pk, POLARSSL_PK_RSA)) + ret = POLARSSL_ERR_PK_TYPE_MISMATCH; + if(ret == 0) + rsa_copy(&connssl->rsa, pk_rsa(pk)); + else + rsa_free(&connssl->rsa); + pk_free(&pk); + + if(ret) { +#ifdef POLARSSL_ERROR_C + error_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* POLARSSL_ERROR_C */ + failf(data, "Error reading private key %s - PolarSSL: (-0x%04X) %s", + data->set.str[STRING_KEY], -ret, errorbuf); + + return CURLE_SSL_CERTPROBLEM; + } + } + + /* Load the CRL */ + memset(&connssl->crl, 0, sizeof(x509_crl)); + + if(data->set.str[STRING_SSL_CRLFILE]) { + ret = x509_crl_parse_file(&connssl->crl, + data->set.str[STRING_SSL_CRLFILE]); + + if(ret) { +#ifdef POLARSSL_ERROR_C + error_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* POLARSSL_ERROR_C */ + failf(data, "Error reading CRL file %s - PolarSSL: (-0x%04X) %s", + data->set.str[STRING_SSL_CRLFILE], -ret, errorbuf); + + return CURLE_SSL_CRL_BADFILE; + } + } + + infof(data, "PolarSSL: Connecting to %s:%d\n", + conn->host.name, conn->remote_port); + + if(ssl_init(&connssl->ssl)) { + failf(data, "PolarSSL: ssl_init failed"); + return CURLE_SSL_CONNECT_ERROR; + } + + switch(data->set.ssl.version) { + default: + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_1); + break; + case CURL_SSLVERSION_SSLv3: + ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_0); + ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_0); + infof(data, "PolarSSL: Forced min. SSL Version to be SSLv3\n"); + break; + case CURL_SSLVERSION_TLSv1_0: + ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_1); + ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_1); + infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.0\n"); + break; + case CURL_SSLVERSION_TLSv1_1: + ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_2); + ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_2); + infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.1\n"); + break; + case CURL_SSLVERSION_TLSv1_2: + ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_3); + ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_3); + infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.2\n"); + break; + } + + ssl_set_endpoint(&connssl->ssl, SSL_IS_CLIENT); + ssl_set_authmode(&connssl->ssl, SSL_VERIFY_OPTIONAL); + + ssl_set_rng(&connssl->ssl, ctr_drbg_random, + &connssl->ctr_drbg); + ssl_set_bio(&connssl->ssl, + net_recv, &conn->sock[sockindex], + net_send, &conn->sock[sockindex]); + + ssl_set_ciphersuites(&connssl->ssl, ssl_list_ciphersuites()); + if(!Curl_ssl_getsessionid(conn, &old_session, &old_session_size)) { + memcpy(&connssl->ssn, old_session, old_session_size); + infof(data, "PolarSSL re-using session\n"); + } + + ssl_set_session(&connssl->ssl, + &connssl->ssn); + + ssl_set_ca_chain(&connssl->ssl, + &connssl->cacert, + &connssl->crl, + conn->host.name); + + ssl_set_own_cert_rsa(&connssl->ssl, + &connssl->clicert, &connssl->rsa); + + if(!Curl_inet_pton(AF_INET, conn->host.name, &addr) && +#ifdef ENABLE_IPV6 + !Curl_inet_pton(AF_INET6, conn->host.name, &addr) && +#endif + sni && ssl_set_hostname(&connssl->ssl, conn->host.name)) { + infof(data, "WARNING: failed to configure " + "server name indication (SNI) TLS extension\n"); + } + +#ifdef HAS_ALPN + if(data->set.ssl_enable_alpn) { + static const char* protocols[3]; + int cur = 0; + +#ifdef USE_NGHTTP2 + if(data->set.httpversion >= CURL_HTTP_VERSION_2) { + protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); + } +#endif + + protocols[cur++] = ALPN_HTTP_1_1; + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + protocols[cur] = NULL; + + ssl_set_alpn_protocols(&connssl->ssl, protocols); + } +#endif + +#ifdef POLARSSL_DEBUG + ssl_set_dbg(&connssl->ssl, polarssl_debug, data); +#endif + + connssl->connecting_state = ssl_connect_2; + + return CURLE_OK; +} + +static CURLcode +polarssl_connect_step2(struct connectdata *conn, + int sockindex) +{ + int ret; + struct SessionHandle *data = conn->data; + struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + char buffer[1024]; + + char errorbuf[128]; + errorbuf[0] = 0; + + conn->recv[sockindex] = polarssl_recv; + conn->send[sockindex] = polarssl_send; + + ret = ssl_handshake(&connssl->ssl); + + switch(ret) { + case 0: + break; + + case POLARSSL_ERR_NET_WANT_READ: + connssl->connecting_state = ssl_connect_2_reading; + return CURLE_OK; + + case POLARSSL_ERR_NET_WANT_WRITE: + connssl->connecting_state = ssl_connect_2_writing; + return CURLE_OK; + + default: +#ifdef POLARSSL_ERROR_C + error_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* POLARSSL_ERROR_C */ + failf(data, "ssl_handshake returned - PolarSSL: (-0x%04X) %s", + -ret, errorbuf); + return CURLE_SSL_CONNECT_ERROR; + } + + infof(data, "PolarSSL: Handshake complete, cipher is %s\n", + ssl_get_ciphersuite(&conn->ssl[sockindex].ssl) ); + + ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl); + + if(ret && data->set.ssl.verifypeer) { + if(ret & BADCERT_EXPIRED) + failf(data, "Cert verify failed: BADCERT_EXPIRED"); + + if(ret & BADCERT_REVOKED) { + failf(data, "Cert verify failed: BADCERT_REVOKED"); + return CURLE_SSL_CACERT; + } + + if(ret & BADCERT_CN_MISMATCH) + failf(data, "Cert verify failed: BADCERT_CN_MISMATCH"); + + if(ret & BADCERT_NOT_TRUSTED) + failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED"); + + return CURLE_PEER_FAILED_VERIFICATION; + } + + if(ssl_get_peer_cert(&(connssl->ssl))) { + /* If the session was resumed, there will be no peer certs */ + memset(buffer, 0, sizeof(buffer)); + + if(x509_crt_info(buffer, sizeof(buffer), (char *)"* ", + ssl_get_peer_cert(&(connssl->ssl))) != -1) + infof(data, "Dumping cert info:\n%s\n", buffer); + } + +#ifdef HAS_ALPN + if(data->set.ssl_enable_alpn) { + const char *next_protocol = ssl_get_alpn_protocol(&connssl->ssl); + + if(next_protocol != NULL) { + infof(data, "ALPN, server accepted to use %s\n", next_protocol); + +#ifdef USE_NGHTTP2 + if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID, + NGHTTP2_PROTO_VERSION_ID_LEN)) { + conn->negnpn = CURL_HTTP_VERSION_2; + } + else +#endif + if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) { + conn->negnpn = CURL_HTTP_VERSION_1_1; + } + } + else + infof(data, "ALPN, server did not agree to a protocol\n"); + } +#endif + + connssl->connecting_state = ssl_connect_3; + infof(data, "SSL connected\n"); + + return CURLE_OK; +} + +static CURLcode +polarssl_connect_step3(struct connectdata *conn, + int sockindex) +{ + CURLcode result = CURLE_OK; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct SessionHandle *data = conn->data; + void *old_ssl_sessionid = NULL; + ssl_session *our_ssl_sessionid = &conn->ssl[sockindex].ssn; + bool incache; + + DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); + + /* Save the current session data for possible re-use */ + incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); + if(incache) { + if(old_ssl_sessionid != our_ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing\n"); + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + incache = FALSE; + } + } + + if(!incache) { + void *new_session = malloc(sizeof(ssl_session)); + + if(new_session) { + memcpy(new_session, our_ssl_sessionid, sizeof(ssl_session)); + + result = Curl_ssl_addsessionid(conn, new_session, sizeof(ssl_session)); + } + else + result = CURLE_OUT_OF_MEMORY; + + if(result) { + failf(data, "failed to store ssl session"); + return result; + } + } + + connssl->connecting_state = ssl_connect_done; + + return CURLE_OK; +} + +static ssize_t polarssl_send(struct connectdata *conn, + int sockindex, + const void *mem, + size_t len, + CURLcode *curlcode) +{ + int ret = -1; + + ret = ssl_write(&conn->ssl[sockindex].ssl, + (unsigned char *)mem, len); + + if(ret < 0) { + *curlcode = (ret == POLARSSL_ERR_NET_WANT_WRITE) ? + CURLE_AGAIN : CURLE_SEND_ERROR; + ret = -1; + } + + return ret; +} + +void Curl_polarssl_close(struct connectdata *conn, int sockindex) +{ + rsa_free(&conn->ssl[sockindex].rsa); + x509_crt_free(&conn->ssl[sockindex].clicert); + x509_crt_free(&conn->ssl[sockindex].cacert); + x509_crl_free(&conn->ssl[sockindex].crl); + ssl_free(&conn->ssl[sockindex].ssl); +} + +static ssize_t polarssl_recv(struct connectdata *conn, + int num, + char *buf, + size_t buffersize, + CURLcode *curlcode) +{ + int ret = -1; + ssize_t len = -1; + + memset(buf, 0, buffersize); + ret = ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf, buffersize); + + if(ret <= 0) { + if(ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) + return 0; + + *curlcode = (ret == POLARSSL_ERR_NET_WANT_READ) ? + CURLE_AGAIN : CURLE_RECV_ERROR; + return -1; + } + + len = ret; + + return len; +} + +void Curl_polarssl_session_free(void *ptr) +{ + free(ptr); +} + +/* 1.3.10 was the first rebranded version. All new releases (in 1.3 branch and + higher) will be mbed TLS branded.. */ + +size_t Curl_polarssl_version(char *buffer, size_t size) +{ + unsigned int version = version_get_number(); + return snprintf(buffer, size, "%s/%d.%d.%d", + version >= 0x01030A00?"mbedTLS":"PolarSSL", + version>>24, (version>>16)&0xff, (version>>8)&0xff); +} + +static CURLcode +polarssl_connect_common(struct connectdata *conn, + int sockindex, + bool nonblocking, + bool *done) +{ + CURLcode result; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + curl_socket_t sockfd = conn->sock[sockindex]; + long timeout_ms; + int what; + + /* check if the connection has already been established */ + if(ssl_connection_complete == connssl->state) { + *done = TRUE; + return CURLE_OK; + } + + if(ssl_connect_1 == connssl->connecting_state) { + /* Find out how much more time we're allowed */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + result = polarssl_connect_step1(conn, sockindex); + if(result) + return result; + } + + while(ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state) { + + /* check allowed time left */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + /* if ssl is expecting something, check if it's available. */ + if(connssl->connecting_state == ssl_connect_2_reading || + connssl->connecting_state == ssl_connect_2_writing) { + + curl_socket_t writefd = ssl_connect_2_writing== + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading== + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + + what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + return CURLE_SSL_CONNECT_ERROR; + } + else if(0 == what) { + if(nonblocking) { + *done = FALSE; + return CURLE_OK; + } + else { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + } + /* socket is readable or writable */ + } + + /* Run transaction, and return to the caller if it failed or if + * this connection is part of a multi handle and this loop would + * execute again. This permits the owner of a multi handle to + * abort a connection attempt before step2 has completed while + * ensuring that a client using select() or epoll() will always + * have a valid fdset to wait on. + */ + result = polarssl_connect_step2(conn, sockindex); + if(result || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return result; + + } /* repeat step2 until all transactions are done. */ + + if(ssl_connect_3 == connssl->connecting_state) { + result = polarssl_connect_step3(conn, sockindex); + if(result) + return result; + } + + if(ssl_connect_done == connssl->connecting_state) { + connssl->state = ssl_connection_complete; + conn->recv[sockindex] = polarssl_recv; + conn->send[sockindex] = polarssl_send; + *done = TRUE; + } + else + *done = FALSE; + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + + return CURLE_OK; +} + +CURLcode +Curl_polarssl_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done) +{ + return polarssl_connect_common(conn, sockindex, TRUE, done); +} + + +CURLcode +Curl_polarssl_connect(struct connectdata *conn, + int sockindex) +{ + CURLcode result; + bool done = FALSE; + + result = polarssl_connect_common(conn, sockindex, FALSE, &done); + if(result) + return result; + + DEBUGASSERT(done); + + return CURLE_OK; +} + +/* + * return 0 error initializing SSL + * return 1 SSL initialized successfully + */ +int Curl_polarssl_init(void) +{ + return Curl_polarsslthreadlock_thread_setup(); +} + +void Curl_polarssl_cleanup(void) +{ + (void)Curl_polarsslthreadlock_thread_cleanup(); +} + +#endif /* USE_POLARSSL */ diff --git a/project/jni/curl/lib/polarssl.h b/project/jni/curl/lib/vtls/polarssl.h similarity index 55% rename from project/jni/curl/lib/polarssl.h rename to project/jni/curl/lib/vtls/polarssl.h index 964af1728..1ab5a841f 100644 --- a/project/jni/curl/lib/polarssl.h +++ b/project/jni/curl/lib/vtls/polarssl.h @@ -7,11 +7,12 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * + * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. * Copyright (C) 2010, Hoi-Ho Chan, * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,16 +21,21 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * - * $Id: polarssl.h,v 1.10 2009-02-12 20:48:43 danf Exp $ ***************************************************************************/ +#include "curl_setup.h" #ifdef USE_POLARSSL +/* Called on first use PolarSSL, setup threading if supported */ +int Curl_polarssl_init(void); +void Curl_polarssl_cleanup(void); + + CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex); -/* tell PolarSSL to close down all open information regarding connections (and - thus session ID caching etc) */ -void Curl_polarssl_close_all(struct SessionHandle *data); +CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done); /* close a SSL connection */ void Curl_polarssl_close(struct connectdata *conn, int sockindex); @@ -38,20 +44,32 @@ void Curl_polarssl_session_free(void *ptr); size_t Curl_polarssl_version(char *buffer, size_t size); int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex); +/* Set the API backend definition to PolarSSL */ +#define CURL_SSL_BACKEND CURLSSLBACKEND_POLARSSL + +/* this backend supports the CAPATH option */ +#define have_curlssl_ca_path 1 + /* API setup for PolarSSL */ -#define curlssl_init() (1) -#define curlssl_cleanup() +#define curlssl_init() Curl_polarssl_init() +#define curlssl_cleanup() Curl_polarssl_cleanup() #define curlssl_connect Curl_polarssl_connect +#define curlssl_connect_nonblocking Curl_polarssl_connect_nonblocking #define curlssl_session_free(x) Curl_polarssl_session_free(x) -#define curlssl_close_all Curl_polarssl_close_all +#define curlssl_close_all(x) ((void)x) #define curlssl_close Curl_polarssl_close #define curlssl_shutdown(x,y) 0 -#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_FAILED_INIT) -#define curlssl_set_engine_default(x) (x=x, CURLE_FAILED_INIT) -#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL) +#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN) +#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN) +#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) #define curlssl_version Curl_polarssl_version -#define curlssl_check_cxn(x) (x=x, -1) -#define curlssl_data_pending(x,y) (x=x, y=y, 0) +#define curlssl_check_cxn(x) ((void)x, -1) +#define curlssl_data_pending(x,y) ((void)x, (void)y, 0) + +/* This might cause libcurl to use a weeker random! + TODO: implement proper use of Polarssl's CTR-DRBG or HMAC-DRBG and use that +*/ +#define curlssl_random(x,y,z) ((void)x, (void)y, (void)z, CURLE_NOT_BUILT_IN) #endif /* USE_POLARSSL */ #endif /* HEADER_CURL_POLARSSL_H */ diff --git a/project/jni/curl/lib/vtls/polarssl_threadlock.c b/project/jni/curl/lib/vtls/polarssl_threadlock.c new file mode 100644 index 000000000..3b0ebf886 --- /dev/null +++ b/project/jni/curl/lib/vtls/polarssl_threadlock.c @@ -0,0 +1,153 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2013-2015, Daniel Stenberg, , et al. + * Copyright (C) 2010, 2011, Hoi-Ho Chan, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curl_setup.h" + +#if (defined(USE_POLARSSL) || defined(USE_MBEDTLS)) && \ + (defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)) + +#if defined(USE_THREADS_POSIX) +# ifdef HAVE_PTHREAD_H +# include +# endif +#elif defined(USE_THREADS_WIN32) +# ifdef HAVE_PROCESS_H +# include +# endif +#endif + +#include "polarssl_threadlock.h" +#include "curl_printf.h" +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* number of thread locks */ +#define NUMT 2 + +/* This array will store all of the mutexes available to PolarSSL. */ +static POLARSSL_MUTEX_T *mutex_buf = NULL; + +int Curl_polarsslthreadlock_thread_setup(void) +{ + int i; + int ret; + + mutex_buf = malloc(NUMT * sizeof(POLARSSL_MUTEX_T)); + if(!mutex_buf) + return 0; /* error, no number of threads defined */ + +#ifdef HAVE_PTHREAD_H + for(i = 0; i < NUMT; i++) { + ret = pthread_mutex_init(&mutex_buf[i], NULL); + if(ret) + return 0; /* pthread_mutex_init failed */ + } +#elif defined(HAVE_PROCESS_H) + for(i = 0; i < NUMT; i++) { + mutex_buf[i] = CreateMutex(0, FALSE, 0); + if(mutex_buf[i] == 0) + return 0; /* CreateMutex failed */ + } +#endif /* HAVE_PTHREAD_H */ + + return 1; /* OK */ +} + +int Curl_polarsslthreadlock_thread_cleanup(void) +{ + int i; + int ret; + + if(!mutex_buf) + return 0; /* error, no threads locks defined */ + +#ifdef HAVE_PTHREAD_H + for(i = 0; i < NUMT; i++) { + ret = pthread_mutex_destroy(&mutex_buf[i]); + if(ret) + return 0; /* pthread_mutex_destroy failed */ + } +#elif defined(HAVE_PROCESS_H) + for(i = 0; i < NUMT; i++) { + ret = CloseHandle(mutex_buf[i]); + if(!ret) + return 0; /* CloseHandle failed */ + } +#endif /* HAVE_PTHREAD_H */ + free(mutex_buf); + mutex_buf = NULL; + + return 1; /* OK */ +} + +int Curl_polarsslthreadlock_lock_function(int n) +{ + int ret; +#ifdef HAVE_PTHREAD_H + if(n < NUMT) { + ret = pthread_mutex_lock(&mutex_buf[n]); + if(ret) { + DEBUGF(fprintf(stderr, + "Error: polarsslthreadlock_lock_function failed\n")); + return 0; /* pthread_mutex_lock failed */ + } + } +#elif defined(HAVE_PROCESS_H) + if(n < NUMT) { + ret = (WaitForSingleObject(mutex_buf[n], INFINITE)==WAIT_FAILED?1:0); + if(ret) { + DEBUGF(fprintf(stderr, + "Error: polarsslthreadlock_lock_function failed\n")); + return 0; /* pthread_mutex_lock failed */ + } + } +#endif /* HAVE_PTHREAD_H */ + return 1; /* OK */ +} + +int Curl_polarsslthreadlock_unlock_function(int n) +{ + int ret; +#ifdef HAVE_PTHREAD_H + if(n < NUMT) { + ret = pthread_mutex_unlock(&mutex_buf[n]); + if(ret) { + DEBUGF(fprintf(stderr, + "Error: polarsslthreadlock_unlock_function failed\n")); + return 0; /* pthread_mutex_unlock failed */ + } + } +#elif defined(HAVE_PROCESS_H) + if(n < NUMT) { + ret = ReleaseMutex(mutex_buf[n]); + if(!ret) { + DEBUGF(fprintf(stderr, + "Error: polarsslthreadlock_unlock_function failed\n")); + return 0; /* pthread_mutex_lock failed */ + } + } +#endif /* HAVE_PTHREAD_H */ + return 1; /* OK */ +} + +#endif /* USE_POLARSSL || USE_MBEDTLS */ diff --git a/project/jni/curl/lib/vtls/polarssl_threadlock.h b/project/jni/curl/lib/vtls/polarssl_threadlock.h new file mode 100644 index 000000000..dda5359b8 --- /dev/null +++ b/project/jni/curl/lib/vtls/polarssl_threadlock.h @@ -0,0 +1,53 @@ +#ifndef HEADER_CURL_POLARSSL_THREADLOCK_H +#define HEADER_CURL_POLARSSL_THREADLOCK_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2013-2015, Daniel Stenberg, , et al. + * Copyright (C) 2010, Hoi-Ho Chan, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curl_setup.h" + +#if (defined USE_POLARSSL) || (defined USE_MBEDTLS) + +#if defined(USE_THREADS_POSIX) +# define POLARSSL_MUTEX_T pthread_mutex_t +#elif defined(USE_THREADS_WIN32) +# define POLARSSL_MUTEX_T HANDLE +#endif + +#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) + +int Curl_polarsslthreadlock_thread_setup(void); +int Curl_polarsslthreadlock_thread_cleanup(void); +int Curl_polarsslthreadlock_lock_function(int n); +int Curl_polarsslthreadlock_unlock_function(int n); + +#else + +#define Curl_polarsslthreadlock_thread_setup() 1 +#define Curl_polarsslthreadlock_thread_cleanup() 1 +#define Curl_polarsslthreadlock_lock_function(x) 1 +#define Curl_polarsslthreadlock_unlock_function(x) 1 + +#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */ + +#endif /* USE_POLARSSL */ + +#endif /* HEADER_CURL_POLARSSL_THREADLOCK_H */ diff --git a/project/jni/curl/lib/vtls/schannel.c b/project/jni/curl/lib/vtls/schannel.c new file mode 100644 index 000000000..7f7bd357d --- /dev/null +++ b/project/jni/curl/lib/vtls/schannel.c @@ -0,0 +1,1519 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2012 - 2015, Marc Hoersken, + * Copyright (C) 2012, Mark Salisbury, + * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Source file for all SChannel-specific code for the TLS/SSL layer. No code + * but vtls.c should ever call or use these functions. + * + */ + +/* + * Based upon the PolarSSL implementation in polarssl.c and polarssl.h: + * Copyright (C) 2010, 2011, Hoi-Ho Chan, + * + * Based upon the CyaSSL implementation in cyassl.c and cyassl.h: + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * + * Thanks for code and inspiration! + */ + +#include "curl_setup.h" + +#ifdef USE_SCHANNEL + +#ifndef USE_WINDOWS_SSPI +# error "Can't compile SCHANNEL support without SSPI." +#endif + +#include "curl_sspi.h" +#include "schannel.h" +#include "vtls.h" +#include "sendf.h" +#include "connect.h" /* for the connect timeout */ +#include "strerror.h" +#include "select.h" /* for the socket readyness */ +#include "inet_pton.h" /* for IP addr SNI check */ +#include "curl_multibyte.h" +#include "warnless.h" +#include "curl_printf.h" +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + +/* Uncomment to force verbose output + * #define infof(x, y, ...) printf(y, __VA_ARGS__) + * #define failf(x, y, ...) printf(y, __VA_ARGS__) + */ + +static Curl_recv schannel_recv; +static Curl_send schannel_send; + +#ifdef _WIN32_WCE +static CURLcode verify_certificate(struct connectdata *conn, int sockindex); +#endif + +static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType, + void *BufDataPtr, unsigned long BufByteSize) +{ + buffer->cbBuffer = BufByteSize; + buffer->BufferType = BufType; + buffer->pvBuffer = BufDataPtr; +} + +static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr, + unsigned long NumArrElem) +{ + desc->ulVersion = SECBUFFER_VERSION; + desc->pBuffers = BufArr; + desc->cBuffers = NumArrElem; +} + +static CURLcode +schannel_connect_step1(struct connectdata *conn, int sockindex) +{ + ssize_t written = -1; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + SecBuffer outbuf; + SecBufferDesc outbuf_desc; + SCHANNEL_CRED schannel_cred; + SECURITY_STATUS sspi_status = SEC_E_OK; + struct curl_schannel_cred *old_cred = NULL; + struct in_addr addr; +#ifdef ENABLE_IPV6 + struct in6_addr addr6; +#endif + TCHAR *host_name; + CURLcode result; + + infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n", + conn->host.name, conn->remote_port); + + /* check for an existing re-usable credential handle */ + if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)) { + connssl->cred = old_cred; + infof(data, "schannel: re-using existing credential handle\n"); + } + else { + /* setup Schannel API options */ + memset(&schannel_cred, 0, sizeof(schannel_cred)); + schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; + + if(data->set.ssl.verifypeer) { +#ifdef _WIN32_WCE + /* certificate validation on CE doesn't seem to work right; we'll + do it following a more manual process. */ + schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | + SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE; +#else + schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION; + if(data->set.ssl_no_revoke) + schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE; + else + schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN; +#endif + if(data->set.ssl_no_revoke) + infof(data, "schannel: disabled server certificate revocation " + "checks\n"); + else + infof(data, "schannel: checking server certificate revocation\n"); + } + else { + schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | + SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE; + infof(data, "schannel: disabled server certificate revocation checks\n"); + } + + if(!data->set.ssl.verifyhost) { + schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK; + infof(data, "schannel: verifyhost setting prevents Schannel from " + "comparing the supplied target name with the subject " + "names in server certificates. Also disables SNI.\n"); + } + + switch(data->set.ssl.version) { + default: + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT | + SP_PROT_TLS1_1_CLIENT | + SP_PROT_TLS1_2_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_0: + schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_1: + schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_1_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_2: + schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT; + break; + case CURL_SSLVERSION_SSLv3: + schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT; + break; + case CURL_SSLVERSION_SSLv2: + schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT; + break; + } + + /* allocate memory for the re-usable credential handle */ + connssl->cred = (struct curl_schannel_cred *) + malloc(sizeof(struct curl_schannel_cred)); + if(!connssl->cred) { + failf(data, "schannel: unable to allocate memory"); + return CURLE_OUT_OF_MEMORY; + } + memset(connssl->cred, 0, sizeof(struct curl_schannel_cred)); + + /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx + */ + sspi_status = + s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, + SECPKG_CRED_OUTBOUND, NULL, + &schannel_cred, NULL, NULL, + &connssl->cred->cred_handle, + &connssl->cred->time_stamp); + + if(sspi_status != SEC_E_OK) { + if(sspi_status == SEC_E_WRONG_PRINCIPAL) + failf(data, "schannel: SNI or certificate check failed: %s", + Curl_sspi_strerror(conn, sspi_status)); + else + failf(data, "schannel: AcquireCredentialsHandle failed: %s", + Curl_sspi_strerror(conn, sspi_status)); + Curl_safefree(connssl->cred); + return CURLE_SSL_CONNECT_ERROR; + } + } + + /* Warn if SNI is disabled due to use of an IP address */ + if(Curl_inet_pton(AF_INET, conn->host.name, &addr) +#ifdef ENABLE_IPV6 + || Curl_inet_pton(AF_INET6, conn->host.name, &addr6) +#endif + ) { + infof(data, "schannel: using IP address, SNI is not supported by OS.\n"); + } + + /* setup output buffer */ + InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&outbuf_desc, &outbuf, 1); + + /* setup request flags */ + connssl->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | + ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | + ISC_REQ_STREAM; + + /* allocate memory for the security context handle */ + connssl->ctxt = (struct curl_schannel_ctxt *) + malloc(sizeof(struct curl_schannel_ctxt)); + if(!connssl->ctxt) { + failf(data, "schannel: unable to allocate memory"); + return CURLE_OUT_OF_MEMORY; + } + memset(connssl->ctxt, 0, sizeof(struct curl_schannel_ctxt)); + + host_name = Curl_convert_UTF8_to_tchar(conn->host.name); + if(!host_name) + return CURLE_OUT_OF_MEMORY; + + /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */ + + sspi_status = s_pSecFn->InitializeSecurityContext( + &connssl->cred->cred_handle, NULL, host_name, + connssl->req_flags, 0, 0, NULL, 0, &connssl->ctxt->ctxt_handle, + &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp); + + Curl_unicodefree(host_name); + + if(sspi_status != SEC_I_CONTINUE_NEEDED) { + if(sspi_status == SEC_E_WRONG_PRINCIPAL) + failf(data, "schannel: SNI or certificate check failed: %s", + Curl_sspi_strerror(conn, sspi_status)); + else + failf(data, "schannel: initial InitializeSecurityContext failed: %s", + Curl_sspi_strerror(conn, sspi_status)); + Curl_safefree(connssl->ctxt); + return CURLE_SSL_CONNECT_ERROR; + } + + infof(data, "schannel: sending initial handshake data: " + "sending %lu bytes...\n", outbuf.cbBuffer); + + /* send initial handshake data which is now stored in output buffer */ + result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer, + outbuf.cbBuffer, &written); + s_pSecFn->FreeContextBuffer(outbuf.pvBuffer); + if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) { + failf(data, "schannel: failed to send initial handshake data: " + "sent %zd of %lu bytes", written, outbuf.cbBuffer); + return CURLE_SSL_CONNECT_ERROR; + } + + infof(data, "schannel: sent initial handshake data: " + "sent %zd bytes\n", written); + + connssl->recv_unrecoverable_err = CURLE_OK; + connssl->recv_sspi_close_notify = false; + connssl->recv_connection_closed = false; + + /* continue to second handshake step */ + connssl->connecting_state = ssl_connect_2; + + return CURLE_OK; +} + +static CURLcode +schannel_connect_step2(struct connectdata *conn, int sockindex) +{ + int i; + ssize_t nread = -1, written = -1; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + unsigned char *reallocated_buffer; + size_t reallocated_length; + SecBuffer outbuf[3]; + SecBufferDesc outbuf_desc; + SecBuffer inbuf[2]; + SecBufferDesc inbuf_desc; + SECURITY_STATUS sspi_status = SEC_E_OK; + TCHAR *host_name; + CURLcode result; + bool doread; + + doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE; + + infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n", + conn->host.name, conn->remote_port); + + if(!connssl->cred || !connssl->ctxt) + return CURLE_SSL_CONNECT_ERROR; + + /* buffer to store previously received and decrypted data */ + if(connssl->decdata_buffer == NULL) { + connssl->decdata_offset = 0; + connssl->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; + connssl->decdata_buffer = malloc(connssl->decdata_length); + if(connssl->decdata_buffer == NULL) { + failf(data, "schannel: unable to allocate memory"); + return CURLE_OUT_OF_MEMORY; + } + } + + /* buffer to store previously received and encrypted data */ + if(connssl->encdata_buffer == NULL) { + connssl->encdata_offset = 0; + connssl->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; + connssl->encdata_buffer = malloc(connssl->encdata_length); + if(connssl->encdata_buffer == NULL) { + failf(data, "schannel: unable to allocate memory"); + return CURLE_OUT_OF_MEMORY; + } + } + + /* if we need a bigger buffer to read a full message, increase buffer now */ + if(connssl->encdata_length - connssl->encdata_offset < + CURL_SCHANNEL_BUFFER_FREE_SIZE) { + /* increase internal encrypted data buffer */ + reallocated_length = connssl->encdata_offset + + CURL_SCHANNEL_BUFFER_FREE_SIZE; + reallocated_buffer = realloc(connssl->encdata_buffer, + reallocated_length); + + if(reallocated_buffer == NULL) { + failf(data, "schannel: unable to re-allocate memory"); + return CURLE_OUT_OF_MEMORY; + } + else { + connssl->encdata_buffer = reallocated_buffer; + connssl->encdata_length = reallocated_length; + } + } + + for(;;) { + if(doread) { + /* read encrypted handshake data from socket */ + result = Curl_read_plain(conn->sock[sockindex], + (char *) (connssl->encdata_buffer + + connssl->encdata_offset), + connssl->encdata_length - + connssl->encdata_offset, + &nread); + if(result == CURLE_AGAIN) { + if(connssl->connecting_state != ssl_connect_2_writing) + connssl->connecting_state = ssl_connect_2_reading; + infof(data, "schannel: failed to receive handshake, " + "need more data\n"); + return CURLE_OK; + } + else if((result != CURLE_OK) || (nread == 0)) { + failf(data, "schannel: failed to receive handshake, " + "SSL/TLS connection failed"); + return CURLE_SSL_CONNECT_ERROR; + } + + /* increase encrypted data buffer offset */ + connssl->encdata_offset += nread; + } + + infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", + connssl->encdata_offset, connssl->encdata_length); + + /* setup input buffers */ + InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(connssl->encdata_offset), + curlx_uztoul(connssl->encdata_offset)); + InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&inbuf_desc, inbuf, 2); + + /* setup output buffers */ + InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0); + InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0); + InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&outbuf_desc, outbuf, 3); + + if(inbuf[0].pvBuffer == NULL) { + failf(data, "schannel: unable to allocate memory"); + return CURLE_OUT_OF_MEMORY; + } + + /* copy received handshake data into input buffer */ + memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer, + connssl->encdata_offset); + + host_name = Curl_convert_UTF8_to_tchar(conn->host.name); + if(!host_name) + return CURLE_OUT_OF_MEMORY; + + /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx + */ + sspi_status = s_pSecFn->InitializeSecurityContext( + &connssl->cred->cred_handle, &connssl->ctxt->ctxt_handle, + host_name, connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL, + &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp); + + Curl_unicodefree(host_name); + + /* free buffer for received handshake data */ + Curl_safefree(inbuf[0].pvBuffer); + + /* check if the handshake was incomplete */ + if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { + connssl->connecting_state = ssl_connect_2_reading; + infof(data, "schannel: received incomplete message, need more data\n"); + return CURLE_OK; + } + + /* If the server has requested a client certificate, attempt to continue + the handshake without one. This will allow connections to servers which + request a client certificate but do not require it. */ + if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS && + !(connssl->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { + connssl->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; + connssl->connecting_state = ssl_connect_2_writing; + infof(data, "schannel: a client certificate has been requested\n"); + return CURLE_OK; + } + + /* check if the handshake needs to be continued */ + if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) { + for(i = 0; i < 3; i++) { + /* search for handshake tokens that need to be send */ + if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) { + infof(data, "schannel: sending next handshake data: " + "sending %lu bytes...\n", outbuf[i].cbBuffer); + + /* send handshake token to server */ + result = Curl_write_plain(conn, conn->sock[sockindex], + outbuf[i].pvBuffer, outbuf[i].cbBuffer, + &written); + if((result != CURLE_OK) || + (outbuf[i].cbBuffer != (size_t) written)) { + failf(data, "schannel: failed to send next handshake data: " + "sent %zd of %lu bytes", written, outbuf[i].cbBuffer); + return CURLE_SSL_CONNECT_ERROR; + } + } + + /* free obsolete buffer */ + if(outbuf[i].pvBuffer != NULL) { + s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer); + } + } + } + else { + if(sspi_status == SEC_E_WRONG_PRINCIPAL) + failf(data, "schannel: SNI or certificate check failed: %s", + Curl_sspi_strerror(conn, sspi_status)); + else + failf(data, "schannel: next InitializeSecurityContext failed: %s", + Curl_sspi_strerror(conn, sspi_status)); + return CURLE_SSL_CONNECT_ERROR; + } + + /* check if there was additional remaining encrypted data */ + if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) { + infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer); + /* + There are two cases where we could be getting extra data here: + 1) If we're renegotiating a connection and the handshake is already + complete (from the server perspective), it can encrypted app data + (not handshake data) in an extra buffer at this point. + 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a + connection and this extra data is part of the handshake. + We should process the data immediately; waiting for the socket to + be ready may fail since the server is done sending handshake data. + */ + /* check if the remaining data is less than the total amount + and therefore begins after the already processed data */ + if(connssl->encdata_offset > inbuf[1].cbBuffer) { + memmove(connssl->encdata_buffer, + (connssl->encdata_buffer + connssl->encdata_offset) - + inbuf[1].cbBuffer, inbuf[1].cbBuffer); + connssl->encdata_offset = inbuf[1].cbBuffer; + if(sspi_status == SEC_I_CONTINUE_NEEDED) { + doread = FALSE; + continue; + } + } + } + else { + connssl->encdata_offset = 0; + } + break; + } + + /* check if the handshake needs to be continued */ + if(sspi_status == SEC_I_CONTINUE_NEEDED) { + connssl->connecting_state = ssl_connect_2_reading; + return CURLE_OK; + } + + /* check if the handshake is complete */ + if(sspi_status == SEC_E_OK) { + connssl->connecting_state = ssl_connect_3; + infof(data, "schannel: SSL/TLS handshake complete\n"); + } + +#ifdef _WIN32_WCE + /* Windows CE doesn't do any server certificate validation. + We have to do it manually. */ + if(data->set.ssl.verifypeer) + return verify_certificate(conn, sockindex); +#endif + + return CURLE_OK; +} + +static CURLcode +schannel_connect_step3(struct connectdata *conn, int sockindex) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct curl_schannel_cred *old_cred = NULL; + bool incache; + + DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); + + infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n", + conn->host.name, conn->remote_port); + + if(!connssl->cred) + return CURLE_SSL_CONNECT_ERROR; + + /* check if the required context attributes are met */ + if(connssl->ret_flags != connssl->req_flags) { + if(!(connssl->ret_flags & ISC_RET_SEQUENCE_DETECT)) + failf(data, "schannel: failed to setup sequence detection"); + if(!(connssl->ret_flags & ISC_RET_REPLAY_DETECT)) + failf(data, "schannel: failed to setup replay detection"); + if(!(connssl->ret_flags & ISC_RET_CONFIDENTIALITY)) + failf(data, "schannel: failed to setup confidentiality"); + if(!(connssl->ret_flags & ISC_RET_ALLOCATED_MEMORY)) + failf(data, "schannel: failed to setup memory allocation"); + if(!(connssl->ret_flags & ISC_RET_STREAM)) + failf(data, "schannel: failed to setup stream orientation"); + return CURLE_SSL_CONNECT_ERROR; + } + + /* increment the reference counter of the credential/session handle */ + if(connssl->cred && connssl->ctxt) { + connssl->cred->refcount++; + infof(data, "schannel: incremented credential handle refcount = %d\n", + connssl->cred->refcount); + } + + /* save the current session data for possible re-use */ + incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)); + if(incache) { + if(old_cred != connssl->cred) { + infof(data, "schannel: old credential handle is stale, removing\n"); + Curl_ssl_delsessionid(conn, (void *)old_cred); + incache = FALSE; + } + } + + if(!incache) { + result = Curl_ssl_addsessionid(conn, (void *)connssl->cred, + sizeof(struct curl_schannel_cred)); + if(result) { + failf(data, "schannel: failed to store credential handle"); + return result; + } + else { + connssl->cred->cached = TRUE; + infof(data, "schannel: stored credential handle in session cache\n"); + } + } + + connssl->connecting_state = ssl_connect_done; + + return CURLE_OK; +} + +static CURLcode +schannel_connect_common(struct connectdata *conn, int sockindex, + bool nonblocking, bool *done) +{ + CURLcode result; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + curl_socket_t sockfd = conn->sock[sockindex]; + long timeout_ms; + int what; + + /* check if the connection has already been established */ + if(ssl_connection_complete == connssl->state) { + *done = TRUE; + return CURLE_OK; + } + + if(ssl_connect_1 == connssl->connecting_state) { + /* check out how much more time we're allowed */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL/TLS connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + result = schannel_connect_step1(conn, sockindex); + if(result) + return result; + } + + while(ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state) { + + /* check out how much more time we're allowed */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL/TLS connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + /* if ssl is expecting something, check if it's available. */ + if(connssl->connecting_state == ssl_connect_2_reading + || connssl->connecting_state == ssl_connect_2_writing) { + + curl_socket_t writefd = ssl_connect_2_writing == + connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading == + connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; + + what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO); + return CURLE_SSL_CONNECT_ERROR; + } + else if(0 == what) { + if(nonblocking) { + *done = FALSE; + return CURLE_OK; + } + else { + /* timeout */ + failf(data, "SSL/TLS connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + } + /* socket is readable or writable */ + } + + /* Run transaction, and return to the caller if it failed or if + * this connection is part of a multi handle and this loop would + * execute again. This permits the owner of a multi handle to + * abort a connection attempt before step2 has completed while + * ensuring that a client using select() or epoll() will always + * have a valid fdset to wait on. + */ + result = schannel_connect_step2(conn, sockindex); + if(result || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return result; + + } /* repeat step2 until all transactions are done. */ + + if(ssl_connect_3 == connssl->connecting_state) { + result = schannel_connect_step3(conn, sockindex); + if(result) + return result; + } + + if(ssl_connect_done == connssl->connecting_state) { + connssl->state = ssl_connection_complete; + conn->recv[sockindex] = schannel_recv; + conn->send[sockindex] = schannel_send; + *done = TRUE; + } + else + *done = FALSE; + + /* reset our connection state machine */ + connssl->connecting_state = ssl_connect_1; + + return CURLE_OK; +} + +static ssize_t +schannel_send(struct connectdata *conn, int sockindex, + const void *buf, size_t len, CURLcode *err) +{ + ssize_t written = -1; + size_t data_len = 0; + unsigned char *data = NULL; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + SecBuffer outbuf[4]; + SecBufferDesc outbuf_desc; + SECURITY_STATUS sspi_status = SEC_E_OK; + CURLcode result; + + /* check if the maximum stream sizes were queried */ + if(connssl->stream_sizes.cbMaximumMessage == 0) { + sspi_status = s_pSecFn->QueryContextAttributes( + &connssl->ctxt->ctxt_handle, + SECPKG_ATTR_STREAM_SIZES, + &connssl->stream_sizes); + if(sspi_status != SEC_E_OK) { + *err = CURLE_SEND_ERROR; + return -1; + } + } + + /* check if the buffer is longer than the maximum message length */ + if(len > connssl->stream_sizes.cbMaximumMessage) { + *err = CURLE_SEND_ERROR; + return -1; + } + + /* calculate the complete message length and allocate a buffer for it */ + data_len = connssl->stream_sizes.cbHeader + len + + connssl->stream_sizes.cbTrailer; + data = (unsigned char *) malloc(data_len); + if(data == NULL) { + *err = CURLE_OUT_OF_MEMORY; + return -1; + } + + /* setup output buffers (header, data, trailer, empty) */ + InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER, + data, connssl->stream_sizes.cbHeader); + InitSecBuffer(&outbuf[1], SECBUFFER_DATA, + data + connssl->stream_sizes.cbHeader, curlx_uztoul(len)); + InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER, + data + connssl->stream_sizes.cbHeader + len, + connssl->stream_sizes.cbTrailer); + InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&outbuf_desc, outbuf, 4); + + /* copy data into output buffer */ + memcpy(outbuf[1].pvBuffer, buf, len); + + /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */ + sspi_status = s_pSecFn->EncryptMessage(&connssl->ctxt->ctxt_handle, 0, + &outbuf_desc, 0); + + /* check if the message was encrypted */ + if(sspi_status == SEC_E_OK) { + written = 0; + + /* send the encrypted message including header, data and trailer */ + len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; + + /* + It's important to send the full message which includes the header, + encrypted payload, and trailer. Until the client receives all the + data a coherent message has not been delivered and the client + can't read any of it. + + If we wanted to buffer the unwritten encrypted bytes, we would + tell the client that all data it has requested to be sent has been + sent. The unwritten encrypted bytes would be the first bytes to + send on the next invocation. + Here's the catch with this - if we tell the client that all the + bytes have been sent, will the client call this method again to + send the buffered data? Looking at who calls this function, it + seems the answer is NO. + */ + + /* send entire message or fail */ + while(len > (size_t)written) { + ssize_t this_write; + long timeleft; + int what; + + this_write = 0; + + timeleft = Curl_timeleft(conn->data, NULL, FALSE); + if(timeleft < 0) { + /* we already got the timeout */ + failf(conn->data, "schannel: timed out sending data " + "(bytes sent: %zd)", written); + *err = CURLE_OPERATION_TIMEDOUT; + written = -1; + break; + } + + what = Curl_socket_ready(CURL_SOCKET_BAD, conn->sock[sockindex], + timeleft); + if(what < 0) { + /* fatal error */ + failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + *err = CURLE_SEND_ERROR; + written = -1; + break; + } + else if(0 == what) { + failf(conn->data, "schannel: timed out sending data " + "(bytes sent: %zd)", written); + *err = CURLE_OPERATION_TIMEDOUT; + written = -1; + break; + } + /* socket is writable */ + + result = Curl_write_plain(conn, conn->sock[sockindex], data + written, + len - written, &this_write); + if(result == CURLE_AGAIN) + continue; + else if(result != CURLE_OK) { + *err = result; + written = -1; + break; + } + + written += this_write; + } + } + else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) { + *err = CURLE_OUT_OF_MEMORY; + } + else{ + *err = CURLE_SEND_ERROR; + } + + Curl_safefree(data); + + if(len == (size_t)written) + /* Encrypted message including header, data and trailer entirely sent. + The return value is the number of unencrypted bytes that were sent. */ + written = outbuf[1].cbBuffer; + + return written; +} + +static ssize_t +schannel_recv(struct connectdata *conn, int sockindex, + char *buf, size_t len, CURLcode *err) +{ + size_t size = 0; + ssize_t nread = -1; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + unsigned char *reallocated_buffer; + size_t reallocated_length; + bool done = FALSE; + SecBuffer inbuf[4]; + SecBufferDesc inbuf_desc; + SECURITY_STATUS sspi_status = SEC_E_OK; + /* we want the length of the encrypted buffer to be at least large enough + that it can hold all the bytes requested and some TLS record overhead. */ + size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE; + + /**************************************************************************** + * Don't return or set connssl->recv_unrecoverable_err unless in the cleanup. + * The pattern for return error is set *err, optional infof, goto cleanup. + * + * Our priority is to always return as much decrypted data to the caller as + * possible, even if an error occurs. The state of the decrypted buffer must + * always be valid. Transfer of decrypted data to the caller's buffer is + * handled in the cleanup. + */ + + infof(data, "schannel: client wants to read %zu bytes\n", len); + *err = CURLE_OK; + + if(len && len <= connssl->decdata_offset) { + infof(data, "schannel: enough decrypted data is already available\n"); + goto cleanup; + } + else if(connssl->recv_unrecoverable_err) { + *err = connssl->recv_unrecoverable_err; + infof(data, "schannel: an unrecoverable error occurred in a prior call\n"); + goto cleanup; + } + else if(connssl->recv_sspi_close_notify) { + /* once a server has indicated shutdown there is no more encrypted data */ + infof(data, "schannel: server indicated shutdown in a prior call\n"); + goto cleanup; + } + else if(!len) { + /* It's debatable what to return when !len. Regardless we can't return + immediately because there may be data to decrypt (in the case we want to + decrypt all encrypted cached data) so handle !len later in cleanup. + */ + ; /* do nothing */ + } + else if(!connssl->recv_connection_closed) { + /* increase enc buffer in order to fit the requested amount of data */ + size = connssl->encdata_length - connssl->encdata_offset; + if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE || + connssl->encdata_length < min_encdata_length) { + reallocated_length = connssl->encdata_offset + + CURL_SCHANNEL_BUFFER_FREE_SIZE; + if(reallocated_length < min_encdata_length) { + reallocated_length = min_encdata_length; + } + reallocated_buffer = realloc(connssl->encdata_buffer, + reallocated_length); + if(reallocated_buffer == NULL) { + *err = CURLE_OUT_OF_MEMORY; + failf(data, "schannel: unable to re-allocate memory"); + goto cleanup; + } + + connssl->encdata_buffer = reallocated_buffer; + connssl->encdata_length = reallocated_length; + size = connssl->encdata_length - connssl->encdata_offset; + infof(data, "schannel: encdata_buffer resized %zu\n", + connssl->encdata_length); + } + + infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", + connssl->encdata_offset, connssl->encdata_length); + + /* read encrypted data from socket */ + *err = Curl_read_plain(conn->sock[sockindex], + (char *)(connssl->encdata_buffer + + connssl->encdata_offset), + size, &nread); + if(*err) { + nread = -1; + if(*err == CURLE_AGAIN) + infof(data, "schannel: Curl_read_plain returned CURLE_AGAIN\n"); + else if(*err == CURLE_RECV_ERROR) + infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n"); + else + infof(data, "schannel: Curl_read_plain returned error %d\n", *err); + } + else if(nread == 0) { + connssl->recv_connection_closed = true; + infof(data, "schannel: server closed the connection\n"); + } + else if(nread > 0) { + connssl->encdata_offset += (size_t)nread; + infof(data, "schannel: encrypted data got %zd\n", nread); + } + } + + infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", + connssl->encdata_offset, connssl->encdata_length); + + /* decrypt loop */ + while(connssl->encdata_offset > 0 && sspi_status == SEC_E_OK && + (!len || connssl->decdata_offset < len || + connssl->recv_connection_closed)) { + /* prepare data buffer for DecryptMessage call */ + InitSecBuffer(&inbuf[0], SECBUFFER_DATA, connssl->encdata_buffer, + curlx_uztoul(connssl->encdata_offset)); + + /* we need 3 more empty input buffers for possible output */ + InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); + InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0); + InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&inbuf_desc, inbuf, 4); + + /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx + */ + sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle, + &inbuf_desc, 0, NULL); + + /* check if everything went fine (server may want to renegotiate + or shutdown the connection context) */ + if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE || + sspi_status == SEC_I_CONTEXT_EXPIRED) { + /* check for successfully decrypted data, even before actual + renegotiation or shutdown of the connection context */ + if(inbuf[1].BufferType == SECBUFFER_DATA) { + infof(data, "schannel: decrypted data length: %lu\n", + inbuf[1].cbBuffer); + + /* increase buffer in order to fit the received amount of data */ + size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ? + inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE; + if(connssl->decdata_length - connssl->decdata_offset < size || + connssl->decdata_length < len) { + /* increase internal decrypted data buffer */ + reallocated_length = connssl->decdata_offset + size; + /* make sure that the requested amount of data fits */ + if(reallocated_length < len) { + reallocated_length = len; + } + reallocated_buffer = realloc(connssl->decdata_buffer, + reallocated_length); + if(reallocated_buffer == NULL) { + *err = CURLE_OUT_OF_MEMORY; + failf(data, "schannel: unable to re-allocate memory"); + goto cleanup; + } + connssl->decdata_buffer = reallocated_buffer; + connssl->decdata_length = reallocated_length; + } + + /* copy decrypted data to internal buffer */ + size = inbuf[1].cbBuffer; + if(size) { + memcpy(connssl->decdata_buffer + connssl->decdata_offset, + inbuf[1].pvBuffer, size); + connssl->decdata_offset += size; + } + + infof(data, "schannel: decrypted data added: %zu\n", size); + infof(data, "schannel: decrypted data cached: offset %zu length %zu\n", + connssl->decdata_offset, connssl->decdata_length); + } + + /* check for remaining encrypted data */ + if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) { + infof(data, "schannel: encrypted data length: %lu\n", + inbuf[3].cbBuffer); + + /* check if the remaining data is less than the total amount + * and therefore begins after the already processed data + */ + if(connssl->encdata_offset > inbuf[3].cbBuffer) { + /* move remaining encrypted data forward to the beginning of + buffer */ + memmove(connssl->encdata_buffer, + (connssl->encdata_buffer + connssl->encdata_offset) - + inbuf[3].cbBuffer, inbuf[3].cbBuffer); + connssl->encdata_offset = inbuf[3].cbBuffer; + } + + infof(data, "schannel: encrypted data cached: offset %zu length %zu\n", + connssl->encdata_offset, connssl->encdata_length); + } + else { + /* reset encrypted buffer offset, because there is no data remaining */ + connssl->encdata_offset = 0; + } + + /* check if server wants to renegotiate the connection context */ + if(sspi_status == SEC_I_RENEGOTIATE) { + infof(data, "schannel: remote party requests renegotiation\n"); + if(*err && *err != CURLE_AGAIN) { + infof(data, "schannel: can't renogotiate, an error is pending\n"); + goto cleanup; + } + if(connssl->encdata_offset) { + *err = CURLE_RECV_ERROR; + infof(data, "schannel: can't renogotiate, " + "encrypted data available\n"); + goto cleanup; + } + /* begin renegotiation */ + infof(data, "schannel: renegotiating SSL/TLS connection\n"); + connssl->state = ssl_connection_negotiating; + connssl->connecting_state = ssl_connect_2_writing; + *err = schannel_connect_common(conn, sockindex, FALSE, &done); + if(*err) { + infof(data, "schannel: renegotiation failed\n"); + goto cleanup; + } + /* now retry receiving data */ + sspi_status = SEC_E_OK; + infof(data, "schannel: SSL/TLS connection renegotiated\n"); + continue; + } + /* check if the server closed the connection */ + else if(sspi_status == SEC_I_CONTEXT_EXPIRED) { + /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not + returned so we have to work around that in cleanup. */ + connssl->recv_sspi_close_notify = true; + if(!connssl->recv_connection_closed) { + connssl->recv_connection_closed = true; + infof(data, "schannel: server closed the connection\n"); + } + goto cleanup; + } + } + else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { + if(!*err) + *err = CURLE_AGAIN; + infof(data, "schannel: failed to decrypt data, need more data\n"); + goto cleanup; + } + else { + *err = CURLE_RECV_ERROR; + infof(data, "schannel: failed to read data from server: %s\n", + Curl_sspi_strerror(conn, sspi_status)); + goto cleanup; + } + } + + infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", + connssl->encdata_offset, connssl->encdata_length); + + infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n", + connssl->decdata_offset, connssl->decdata_length); + +cleanup: + /* Warning- there is no guarantee the encdata state is valid at this point */ + infof(data, "schannel: schannel_recv cleanup\n"); + + /* Error if the connection has closed without a close_notify. + Behavior here is a matter of debate. We don't want to be vulnerable to a + truncation attack however there's some browser precedent for ignoring the + close_notify for compatibility reasons. + Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't + return close_notify. In that case if the connection was closed we assume it + was graceful (close_notify) since there doesn't seem to be a way to tell. + */ + if(len && !connssl->decdata_offset && connssl->recv_connection_closed && + !connssl->recv_sspi_close_notify) { + bool isWin2k = FALSE; + +#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ + (_WIN32_WINNT < _WIN32_WINNT_WIN2K) + OSVERSIONINFO osver; + + memset(&osver, 0, sizeof(osver)); + osver.dwOSVersionInfoSize = sizeof(osver); + + /* Find out the Windows version */ + if(GetVersionEx(&osver)) { + /* Verify the version number is 5.0 */ + if(osver.dwMajorVersion == 5 && osver.dwMinorVersion == 0) + isWin2k = TRUE; + } +#else + ULONGLONG cm; + OSVERSIONINFOEX osver; + + memset(&osver, 0, sizeof(osver)); + osver.dwOSVersionInfoSize = sizeof(osver); + osver.dwMajorVersion = 5; + + cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); + cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_EQUAL); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); + + if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), + cm)) + isWin2k = TRUE; +#endif + + if(isWin2k && sspi_status == SEC_E_OK) + connssl->recv_sspi_close_notify = true; + else { + *err = CURLE_RECV_ERROR; + infof(data, "schannel: server closed abruptly (missing close_notify)\n"); + } + } + + /* Any error other than CURLE_AGAIN is an unrecoverable error. */ + if(*err && *err != CURLE_AGAIN) + connssl->recv_unrecoverable_err = *err; + + size = len < connssl->decdata_offset ? len : connssl->decdata_offset; + if(size) { + memcpy(buf, connssl->decdata_buffer, size); + memmove(connssl->decdata_buffer, connssl->decdata_buffer + size, + connssl->decdata_offset - size); + connssl->decdata_offset -= size; + + infof(data, "schannel: decrypted data returned %zu\n", size); + infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n", + connssl->decdata_offset, connssl->decdata_length); + *err = CURLE_OK; + return (ssize_t)size; + } + + if(!*err && !connssl->recv_connection_closed) + *err = CURLE_AGAIN; + + /* It's debatable what to return when !len. We could return whatever error we + got from decryption but instead we override here so the return is consistent. + */ + if(!len) + *err = CURLE_OK; + + return *err ? -1 : 0; +} + +CURLcode +Curl_schannel_connect_nonblocking(struct connectdata *conn, int sockindex, + bool *done) +{ + return schannel_connect_common(conn, sockindex, TRUE, done); +} + +CURLcode +Curl_schannel_connect(struct connectdata *conn, int sockindex) +{ + CURLcode result; + bool done = FALSE; + + result = schannel_connect_common(conn, sockindex, FALSE, &done); + if(result) + return result; + + DEBUGASSERT(done); + + return CURLE_OK; +} + +bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex) +{ + const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + if(connssl->use) /* SSL/TLS is in use */ + return (connssl->encdata_offset > 0 || + connssl->decdata_offset > 0 ) ? TRUE : FALSE; + else + return FALSE; +} + +void Curl_schannel_close(struct connectdata *conn, int sockindex) +{ + if(conn->ssl[sockindex].use) + /* if the SSL/TLS channel hasn't been shut down yet, do that now. */ + Curl_ssl_shutdown(conn, sockindex); +} + +int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) +{ + /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx + * Shutting Down an Schannel Connection + */ + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n", + conn->host.name, conn->remote_port); + + if(connssl->cred && connssl->ctxt) { + SecBufferDesc BuffDesc; + SecBuffer Buffer; + SECURITY_STATUS sspi_status; + SecBuffer outbuf; + SecBufferDesc outbuf_desc; + CURLcode result; + TCHAR *host_name; + DWORD dwshut = SCHANNEL_SHUTDOWN; + + InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut)); + InitSecBufferDesc(&BuffDesc, &Buffer, 1); + + sspi_status = s_pSecFn->ApplyControlToken(&connssl->ctxt->ctxt_handle, + &BuffDesc); + + if(sspi_status != SEC_E_OK) + failf(data, "schannel: ApplyControlToken failure: %s", + Curl_sspi_strerror(conn, sspi_status)); + + host_name = Curl_convert_UTF8_to_tchar(conn->host.name); + if(!host_name) + return CURLE_OUT_OF_MEMORY; + + /* setup output buffer */ + InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&outbuf_desc, &outbuf, 1); + + sspi_status = s_pSecFn->InitializeSecurityContext( + &connssl->cred->cred_handle, + &connssl->ctxt->ctxt_handle, + host_name, + connssl->req_flags, + 0, + 0, + NULL, + 0, + &connssl->ctxt->ctxt_handle, + &outbuf_desc, + &connssl->ret_flags, + &connssl->ctxt->time_stamp); + + Curl_unicodefree(host_name); + + if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) { + /* send close message which is in output buffer */ + ssize_t written; + result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer, + outbuf.cbBuffer, &written); + + s_pSecFn->FreeContextBuffer(outbuf.pvBuffer); + if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) { + infof(data, "schannel: failed to send close msg: %s" + " (bytes written: %zd)\n", curl_easy_strerror(result), written); + } + } + } + + /* free SSPI Schannel API security context handle */ + if(connssl->ctxt) { + infof(data, "schannel: clear security context handle\n"); + s_pSecFn->DeleteSecurityContext(&connssl->ctxt->ctxt_handle); + Curl_safefree(connssl->ctxt); + } + + /* free SSPI Schannel API credential handle */ + if(connssl->cred) { + /* decrement the reference counter of the credential/session handle */ + if(connssl->cred->refcount > 0) { + connssl->cred->refcount--; + infof(data, "schannel: decremented credential handle refcount = %d\n", + connssl->cred->refcount); + } + + /* if the handle was not cached and the refcount is zero */ + if(!connssl->cred->cached && connssl->cred->refcount == 0) { + infof(data, "schannel: clear credential handle\n"); + s_pSecFn->FreeCredentialsHandle(&connssl->cred->cred_handle); + Curl_safefree(connssl->cred); + } + } + + /* free internal buffer for received encrypted data */ + if(connssl->encdata_buffer != NULL) { + Curl_safefree(connssl->encdata_buffer); + connssl->encdata_length = 0; + connssl->encdata_offset = 0; + } + + /* free internal buffer for received decrypted data */ + if(connssl->decdata_buffer != NULL) { + Curl_safefree(connssl->decdata_buffer); + connssl->decdata_length = 0; + connssl->decdata_offset = 0; + } + + return CURLE_OK; +} + +void Curl_schannel_session_free(void *ptr) +{ + struct curl_schannel_cred *cred = ptr; + + if(cred && cred->cached) { + if(cred->refcount == 0) { + s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); + Curl_safefree(cred); + } + else { + cred->cached = FALSE; + } + } +} + +int Curl_schannel_init(void) +{ + return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0); +} + +void Curl_schannel_cleanup(void) +{ + Curl_sspi_global_cleanup(); +} + +size_t Curl_schannel_version(char *buffer, size_t size) +{ + size = snprintf(buffer, size, "WinSSL"); + + return size; +} + +int Curl_schannel_random(unsigned char *entropy, size_t length) +{ + HCRYPTPROV hCryptProv = 0; + + if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + return 1; + + if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) { + CryptReleaseContext(hCryptProv, 0UL); + return 1; + } + + CryptReleaseContext(hCryptProv, 0UL); + return 0; +} + +#ifdef _WIN32_WCE +static CURLcode verify_certificate(struct connectdata *conn, int sockindex) +{ + SECURITY_STATUS status; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + CURLcode result = CURLE_OK; + CERT_CONTEXT *pCertContextServer = NULL; + const CERT_CHAIN_CONTEXT *pChainContext = NULL; + + status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, + SECPKG_ATTR_REMOTE_CERT_CONTEXT, + &pCertContextServer); + + if((status != SEC_E_OK) || (pCertContextServer == NULL)) { + failf(data, "schannel: Failed to read remote certificate context: %s", + Curl_sspi_strerror(conn, status)); + result = CURLE_PEER_FAILED_VERIFICATION; + } + + if(result == CURLE_OK) { + CERT_CHAIN_PARA ChainPara; + memset(&ChainPara, 0, sizeof(ChainPara)); + ChainPara.cbSize = sizeof(ChainPara); + + if(!CertGetCertificateChain(NULL, + pCertContextServer, + NULL, + pCertContextServer->hCertStore, + &ChainPara, + (data->set.ssl_no_revoke ? 0 : + CERT_CHAIN_REVOCATION_CHECK_CHAIN), + NULL, + &pChainContext)) { + failf(data, "schannel: CertGetCertificateChain failed: %s", + Curl_sspi_strerror(conn, GetLastError())); + pChainContext = NULL; + result = CURLE_PEER_FAILED_VERIFICATION; + } + + if(result == CURLE_OK) { + CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0]; + DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED); + dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus; + if(dwTrustErrorMask) { + if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED) + failf(data, "schannel: CertGetCertificateChain trust error" + " CERT_TRUST_IS_REVOKED"); + else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN) + failf(data, "schannel: CertGetCertificateChain trust error" + " CERT_TRUST_IS_PARTIAL_CHAIN"); + else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT) + failf(data, "schannel: CertGetCertificateChain trust error" + " CERT_TRUST_IS_UNTRUSTED_ROOT"); + else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID) + failf(data, "schannel: CertGetCertificateChain trust error" + " CERT_TRUST_IS_NOT_TIME_VALID"); + else + failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x", + dwTrustErrorMask); + result = CURLE_PEER_FAILED_VERIFICATION; + } + } + } + + if(result == CURLE_OK) { + if(data->set.ssl.verifyhost) { + TCHAR cert_hostname_buff[128]; + xcharp_u hostname; + xcharp_u cert_hostname; + DWORD len; + + cert_hostname.const_tchar_ptr = cert_hostname_buff; + hostname.tchar_ptr = Curl_convert_UTF8_to_tchar(conn->host.name); + + /* TODO: Fix this for certificates with multiple alternative names. + Right now we're only asking for the first preferred alternative name. + Instead we'd need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG + (if WinCE supports that?) and run this section in a loop for each. + https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx + curl: (51) schannel: CertGetNameString() certificate hostname + (.google.com) did not match connection (google.com) + */ + len = CertGetNameString(pCertContextServer, + CERT_NAME_DNS_TYPE, + 0, + NULL, + cert_hostname.tchar_ptr, + 128); + if(len > 0 && *cert_hostname.tchar_ptr == '*') { + /* this is a wildcard cert. try matching the last len - 1 chars */ + int hostname_len = strlen(conn->host.name); + cert_hostname.tchar_ptr++; + if(_tcsicmp(cert_hostname.const_tchar_ptr, + hostname.const_tchar_ptr + hostname_len - len + 2) != 0) + result = CURLE_PEER_FAILED_VERIFICATION; + } + else if(len == 0 || _tcsicmp(hostname.const_tchar_ptr, + cert_hostname.const_tchar_ptr) != 0) { + result = CURLE_PEER_FAILED_VERIFICATION; + } + if(result == CURLE_PEER_FAILED_VERIFICATION) { + char *_cert_hostname; + _cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname.tchar_ptr); + failf(data, "schannel: CertGetNameString() certificate hostname " + "(%s) did not match connection (%s)", + _cert_hostname, conn->host.name); + Curl_unicodefree(_cert_hostname); + } + Curl_unicodefree(hostname.tchar_ptr); + } + } + + if(pChainContext) + CertFreeCertificateChain(pChainContext); + + if(pCertContextServer) + CertFreeCertificateContext(pCertContextServer); + + return result; +} +#endif /* _WIN32_WCE */ + +#endif /* USE_SCHANNEL */ diff --git a/project/jni/curl/lib/vtls/schannel.h b/project/jni/curl/lib/vtls/schannel.h new file mode 100644 index 000000000..a314b34f9 --- /dev/null +++ b/project/jni/curl/lib/vtls/schannel.h @@ -0,0 +1,118 @@ +#ifndef HEADER_CURL_SCHANNEL_H +#define HEADER_CURL_SCHANNEL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2012, Marc Hoersken, , et al. + * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_SCHANNEL + +#include "urldata.h" + +#ifndef UNISP_NAME_A +#define UNISP_NAME_A "Microsoft Unified Security Protocol Provider" +#endif + +#ifndef UNISP_NAME_W +#define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider" +#endif + +#ifndef UNISP_NAME +#ifdef UNICODE +#define UNISP_NAME UNISP_NAME_W +#else +#define UNISP_NAME UNISP_NAME_A +#endif +#endif + +#ifndef SP_PROT_SSL2_CLIENT +#define SP_PROT_SSL2_CLIENT 0x00000008 +#endif + +#ifndef SP_PROT_SSL3_CLIENT +#define SP_PROT_SSL3_CLIENT 0x00000008 +#endif + +#ifndef SP_PROT_TLS1_CLIENT +#define SP_PROT_TLS1_CLIENT 0x00000080 +#endif + +#ifndef SP_PROT_TLS1_0_CLIENT +#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT +#endif + +#ifndef SP_PROT_TLS1_1_CLIENT +#define SP_PROT_TLS1_1_CLIENT 0x00000200 +#endif + +#ifndef SP_PROT_TLS1_2_CLIENT +#define SP_PROT_TLS1_2_CLIENT 0x00000800 +#endif + +#ifndef SECBUFFER_ALERT +#define SECBUFFER_ALERT 17 +#endif + +/* Both schannel buffer sizes must be > 0 */ +#define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096 +#define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024 + + +CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex); + +CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done); + +bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex); +void Curl_schannel_close(struct connectdata *conn, int sockindex); +int Curl_schannel_shutdown(struct connectdata *conn, int sockindex); +void Curl_schannel_session_free(void *ptr); + +int Curl_schannel_init(void); +void Curl_schannel_cleanup(void); +size_t Curl_schannel_version(char *buffer, size_t size); + +int Curl_schannel_random(unsigned char *entropy, size_t length); + +/* Set the API backend definition to Schannel */ +#define CURL_SSL_BACKEND CURLSSLBACKEND_SCHANNEL + +/* API setup for Schannel */ +#define curlssl_init Curl_schannel_init +#define curlssl_cleanup Curl_schannel_cleanup +#define curlssl_connect Curl_schannel_connect +#define curlssl_connect_nonblocking Curl_schannel_connect_nonblocking +#define curlssl_session_free Curl_schannel_session_free +#define curlssl_close_all(x) ((void)x) +#define curlssl_close Curl_schannel_close +#define curlssl_shutdown Curl_schannel_shutdown +#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN) +#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN) +#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) +#define curlssl_version Curl_schannel_version +#define curlssl_check_cxn(x) ((void)x, -1) +#define curlssl_data_pending Curl_schannel_data_pending +#define curlssl_random(x,y,z) ((void)x, Curl_schannel_random(y,z)) + +#endif /* USE_SCHANNEL */ +#endif /* HEADER_CURL_SCHANNEL_H */ diff --git a/project/jni/curl/lib/vtls/vtls.c b/project/jni/curl/lib/vtls/vtls.c new file mode 100644 index 000000000..36465a7f6 --- /dev/null +++ b/project/jni/curl/lib/vtls/vtls.c @@ -0,0 +1,965 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* This file is for implementing all "generic" SSL functions that all libcurl + internals should use. It is then responsible for calling the proper + "backend" function. + + SSL-functions in libcurl should call functions in this source file, and not + to any specific SSL-layer. + + Curl_ssl_ - prefix for generic ones + Curl_ossl_ - prefix for OpenSSL ones + Curl_gtls_ - prefix for GnuTLS ones + Curl_nss_ - prefix for NSS ones + Curl_gskit_ - prefix for GSKit ones + Curl_polarssl_ - prefix for PolarSSL ones + Curl_cyassl_ - prefix for CyaSSL ones + Curl_schannel_ - prefix for Schannel SSPI ones + Curl_darwinssl_ - prefix for SecureTransport (Darwin) ones + + Note that this source code uses curlssl_* functions, and they are all + defines/macros #defined by the lib-specific header files. + + "SSL/TLS Strong Encryption: An Introduction" + https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html +*/ + +#include "curl_setup.h" + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif + +#include "urldata.h" + +#include "vtls.h" /* generic SSL protos etc */ +#include "slist.h" +#include "sendf.h" +#include "rawstr.h" +#include "url.h" +#include "progress.h" +#include "share.h" +#include "timeval.h" +#include "curl_md5.h" +#include "warnless.h" +#include "curl_base64.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* convenience macro to check if this handle is using a shared SSL session */ +#define SSLSESSION_SHARED(data) (data->share && \ + (data->share->specifier & \ + (1<version == needle->version) && + (data->verifypeer == needle->verifypeer) && + (data->verifyhost == needle->verifyhost) && + safe_strequal(data->CApath, needle->CApath) && + safe_strequal(data->CAfile, needle->CAfile) && + safe_strequal(data->random_file, needle->random_file) && + safe_strequal(data->egdsocket, needle->egdsocket) && + safe_strequal(data->cipher_list, needle->cipher_list)) + return TRUE; + + return FALSE; +} + +bool +Curl_clone_ssl_config(struct ssl_config_data *source, + struct ssl_config_data *dest) +{ + dest->sessionid = source->sessionid; + dest->verifyhost = source->verifyhost; + dest->verifypeer = source->verifypeer; + dest->version = source->version; + + if(source->CAfile) { + dest->CAfile = strdup(source->CAfile); + if(!dest->CAfile) + return FALSE; + } + else + dest->CAfile = NULL; + + if(source->CApath) { + dest->CApath = strdup(source->CApath); + if(!dest->CApath) + return FALSE; + } + else + dest->CApath = NULL; + + if(source->cipher_list) { + dest->cipher_list = strdup(source->cipher_list); + if(!dest->cipher_list) + return FALSE; + } + else + dest->cipher_list = NULL; + + if(source->egdsocket) { + dest->egdsocket = strdup(source->egdsocket); + if(!dest->egdsocket) + return FALSE; + } + else + dest->egdsocket = NULL; + + if(source->random_file) { + dest->random_file = strdup(source->random_file); + if(!dest->random_file) + return FALSE; + } + else + dest->random_file = NULL; + + return TRUE; +} + +void Curl_free_ssl_config(struct ssl_config_data* sslc) +{ + Curl_safefree(sslc->CAfile); + Curl_safefree(sslc->CApath); + Curl_safefree(sslc->cipher_list); + Curl_safefree(sslc->egdsocket); + Curl_safefree(sslc->random_file); +} + + +/* + * Curl_rand() returns a random unsigned integer, 32bit. + * + * This non-SSL function is put here only because this file is the only one + * with knowledge of what the underlying SSL libraries provide in terms of + * randomizers. + * + * NOTE: 'data' may be passed in as NULL when coming from external API without + * easy handle! + * + */ + +unsigned int Curl_rand(struct SessionHandle *data) +{ + unsigned int r = 0; + static unsigned int randseed; + static bool seeded = FALSE; + +#ifdef CURLDEBUG + char *force_entropy = getenv("CURL_ENTROPY"); + if(force_entropy) { + if(!seeded) { + size_t elen = strlen(force_entropy); + size_t clen = sizeof(randseed); + size_t min = elen < clen ? elen : clen; + memcpy((char *)&randseed, force_entropy, min); + seeded = TRUE; + } + else + randseed++; + return randseed; + } +#endif + + /* data may be NULL! */ + if(!Curl_ssl_random(data, (unsigned char *)&r, sizeof(r))) + return r; + + /* If Curl_ssl_random() returns non-zero it couldn't offer randomness and we + instead perform a "best effort" */ + +#ifdef RANDOM_FILE + if(!seeded) { + /* if there's a random file to read a seed from, use it */ + int fd = open(RANDOM_FILE, O_RDONLY); + if(fd > -1) { + /* read random data into the randseed variable */ + ssize_t nread = read(fd, &randseed, sizeof(randseed)); + if(nread == sizeof(randseed)) + seeded = TRUE; + close(fd); + } + } +#endif + + if(!seeded) { + struct timeval now = curlx_tvnow(); + infof(data, "WARNING: Using weak random seed\n"); + randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec; + randseed = randseed * 1103515245 + 12345; + randseed = randseed * 1103515245 + 12345; + randseed = randseed * 1103515245 + 12345; + seeded = TRUE; + } + + /* Return an unsigned 32-bit pseudo-random number. */ + r = randseed = randseed * 1103515245 + 12345; + return (r << 16) | ((r >> 16) & 0xFFFF); +} + +int Curl_ssl_backend(void) +{ + return (int)CURL_SSL_BACKEND; +} + +#ifdef USE_SSL + +/* "global" init done? */ +static bool init_ssl=FALSE; + +/** + * Global SSL init + * + * @retval 0 error initializing SSL + * @retval 1 SSL initialized successfully + */ +int Curl_ssl_init(void) +{ + /* make sure this is only done once */ + if(init_ssl) + return 1; + init_ssl = TRUE; /* never again */ + + return curlssl_init(); +} + + +/* Global cleanup */ +void Curl_ssl_cleanup(void) +{ + if(init_ssl) { + /* only cleanup if we did a previous init */ + curlssl_cleanup(); + init_ssl = FALSE; + } +} + +static bool ssl_prefs_check(struct SessionHandle *data) +{ + /* check for CURLOPT_SSLVERSION invalid parameter value */ + if((data->set.ssl.version < 0) + || (data->set.ssl.version >= CURL_SSLVERSION_LAST)) { + failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION"); + return FALSE; + } + return TRUE; +} + +CURLcode +Curl_ssl_connect(struct connectdata *conn, int sockindex) +{ + CURLcode result; + + if(!ssl_prefs_check(conn->data)) + return CURLE_SSL_CONNECT_ERROR; + + /* mark this is being ssl-enabled from here on. */ + conn->ssl[sockindex].use = TRUE; + conn->ssl[sockindex].state = ssl_connection_negotiating; + + result = curlssl_connect(conn, sockindex); + + if(!result) + Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ + + return result; +} + +CURLcode +Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, + bool *done) +{ + CURLcode result; + + if(!ssl_prefs_check(conn->data)) + return CURLE_SSL_CONNECT_ERROR; + + /* mark this is being ssl requested from here on. */ + conn->ssl[sockindex].use = TRUE; +#ifdef curlssl_connect_nonblocking + result = curlssl_connect_nonblocking(conn, sockindex, done); +#else + *done = TRUE; /* fallback to BLOCKING */ + result = curlssl_connect(conn, sockindex); +#endif /* non-blocking connect support */ + if(!result && *done) + Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ + return result; +} + +/* + * Check if there's a session ID for the given connection in the cache, and if + * there's one suitable, it is provided. Returns TRUE when no entry matched. + */ +bool Curl_ssl_getsessionid(struct connectdata *conn, + void **ssl_sessionid, + size_t *idsize) /* set 0 if unknown */ +{ + struct curl_ssl_session *check; + struct SessionHandle *data = conn->data; + size_t i; + long *general_age; + bool no_match = TRUE; + + *ssl_sessionid = NULL; + + if(!conn->ssl_config.sessionid) + /* session ID re-use is disabled */ + return TRUE; + + /* Lock if shared */ + if(SSLSESSION_SHARED(data)) { + Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); + general_age = &data->share->sessionage; + } + else + general_age = &data->state.sessionage; + + for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) { + check = &data->state.session[i]; + if(!check->sessionid) + /* not session ID means blank entry */ + continue; + if(Curl_raw_equal(conn->host.name, check->name) && + (conn->remote_port == check->remote_port) && + Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) { + /* yes, we have a session ID! */ + (*general_age)++; /* increase general age */ + check->age = *general_age; /* set this as used in this age */ + *ssl_sessionid = check->sessionid; + if(idsize) + *idsize = check->idsize; + no_match = FALSE; + break; + } + } + + /* Unlock */ + if(SSLSESSION_SHARED(data)) + Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); + + return no_match; +} + +/* + * Kill a single session ID entry in the cache. + */ +void Curl_ssl_kill_session(struct curl_ssl_session *session) +{ + if(session->sessionid) { + /* defensive check */ + + /* free the ID the SSL-layer specific way */ + curlssl_session_free(session->sessionid); + + session->sessionid = NULL; + session->age = 0; /* fresh */ + + Curl_free_ssl_config(&session->ssl_config); + + Curl_safefree(session->name); + } +} + +/* + * Delete the given session ID from the cache. + */ +void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) +{ + size_t i; + struct SessionHandle *data=conn->data; + + if(SSLSESSION_SHARED(data)) + Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); + + for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) { + struct curl_ssl_session *check = &data->state.session[i]; + + if(check->sessionid == ssl_sessionid) { + Curl_ssl_kill_session(check); + break; + } + } + + if(SSLSESSION_SHARED(data)) + Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); +} + +/* + * Store session id in the session cache. The ID passed on to this function + * must already have been extracted and allocated the proper way for the SSL + * layer. Curl_XXXX_session_free() will be called to free/kill the session ID + * later on. + */ +CURLcode Curl_ssl_addsessionid(struct connectdata *conn, + void *ssl_sessionid, + size_t idsize) +{ + size_t i; + struct SessionHandle *data=conn->data; /* the mother of all structs */ + struct curl_ssl_session *store = &data->state.session[0]; + long oldest_age=data->state.session[0].age; /* zero if unused */ + char *clone_host; + long *general_age; + + /* Even though session ID re-use might be disabled, that only disables USING + IT. We still store it here in case the re-using is again enabled for an + upcoming transfer */ + + clone_host = strdup(conn->host.name); + if(!clone_host) + return CURLE_OUT_OF_MEMORY; /* bail out */ + + /* Now we should add the session ID and the host name to the cache, (remove + the oldest if necessary) */ + + /* If using shared SSL session, lock! */ + if(SSLSESSION_SHARED(data)) { + Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); + general_age = &data->share->sessionage; + } + else { + general_age = &data->state.sessionage; + } + + /* find an empty slot for us, or find the oldest */ + for(i = 1; (i < data->set.ssl.max_ssl_sessions) && + data->state.session[i].sessionid; i++) { + if(data->state.session[i].age < oldest_age) { + oldest_age = data->state.session[i].age; + store = &data->state.session[i]; + } + } + if(i == data->set.ssl.max_ssl_sessions) + /* cache is full, we must "kill" the oldest entry! */ + Curl_ssl_kill_session(store); + else + store = &data->state.session[i]; /* use this slot */ + + /* now init the session struct wisely */ + store->sessionid = ssl_sessionid; + store->idsize = idsize; + store->age = *general_age; /* set current age */ + /* free it if there's one already present */ + free(store->name); + store->name = clone_host; /* clone host name */ + store->remote_port = conn->remote_port; /* port number */ + + + /* Unlock */ + if(SSLSESSION_SHARED(data)) + Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); + + if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) { + store->sessionid = NULL; /* let caller free sessionid */ + free(clone_host); + return CURLE_OUT_OF_MEMORY; + } + + return CURLE_OK; +} + + +void Curl_ssl_close_all(struct SessionHandle *data) +{ + size_t i; + /* kill the session ID cache if not shared */ + if(data->state.session && !SSLSESSION_SHARED(data)) { + for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) + /* the single-killer function handles empty table slots */ + Curl_ssl_kill_session(&data->state.session[i]); + + /* free the cache data */ + Curl_safefree(data->state.session); + } + + curlssl_close_all(data); +} + +void Curl_ssl_close(struct connectdata *conn, int sockindex) +{ + DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); + curlssl_close(conn, sockindex); +} + +CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex) +{ + if(curlssl_shutdown(conn, sockindex)) + return CURLE_SSL_SHUTDOWN_FAILED; + + conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */ + conn->ssl[sockindex].state = ssl_connection_none; + + conn->recv[sockindex] = Curl_recv_plain; + conn->send[sockindex] = Curl_send_plain; + + return CURLE_OK; +} + +/* Selects an SSL crypto engine + */ +CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine) +{ + return curlssl_set_engine(data, engine); +} + +/* Selects the default SSL crypto engine + */ +CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data) +{ + return curlssl_set_engine_default(data); +} + +/* Return list of OpenSSL crypto engine names. */ +struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data) +{ + return curlssl_engines_list(data); +} + +/* + * This sets up a session ID cache to the specified size. Make sure this code + * is agnostic to what underlying SSL technology we use. + */ +CURLcode Curl_ssl_initsessions(struct SessionHandle *data, size_t amount) +{ + struct curl_ssl_session *session; + + if(data->state.session) + /* this is just a precaution to prevent multiple inits */ + return CURLE_OK; + + session = calloc(amount, sizeof(struct curl_ssl_session)); + if(!session) + return CURLE_OUT_OF_MEMORY; + + /* store the info in the SSL section */ + data->set.ssl.max_ssl_sessions = amount; + data->state.session = session; + data->state.sessionage = 1; /* this is brand new */ + return CURLE_OK; +} + +size_t Curl_ssl_version(char *buffer, size_t size) +{ + return curlssl_version(buffer, size); +} + +/* + * This function tries to determine connection status. + * + * Return codes: + * 1 means the connection is still in place + * 0 means the connection has been closed + * -1 means the connection status is unknown + */ +int Curl_ssl_check_cxn(struct connectdata *conn) +{ + return curlssl_check_cxn(conn); +} + +bool Curl_ssl_data_pending(const struct connectdata *conn, + int connindex) +{ + return curlssl_data_pending(conn, connindex); +} + +void Curl_ssl_free_certinfo(struct SessionHandle *data) +{ + int i; + struct curl_certinfo *ci = &data->info.certs; + + if(ci->num_of_certs) { + /* free all individual lists used */ + for(i=0; inum_of_certs; i++) { + curl_slist_free_all(ci->certinfo[i]); + ci->certinfo[i] = NULL; + } + + free(ci->certinfo); /* free the actual array too */ + ci->certinfo = NULL; + ci->num_of_certs = 0; + } +} + +CURLcode Curl_ssl_init_certinfo(struct SessionHandle *data, int num) +{ + struct curl_certinfo *ci = &data->info.certs; + struct curl_slist **table; + + /* Free any previous certificate information structures */ + Curl_ssl_free_certinfo(data); + + /* Allocate the required certificate information structures */ + table = calloc((size_t) num, sizeof(struct curl_slist *)); + if(!table) + return CURLE_OUT_OF_MEMORY; + + ci->num_of_certs = num; + ci->certinfo = table; + + return CURLE_OK; +} + +/* + * 'value' is NOT a zero terminated string + */ +CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle *data, + int certnum, + const char *label, + const char *value, + size_t valuelen) +{ + struct curl_certinfo * ci = &data->info.certs; + char * output; + struct curl_slist * nl; + CURLcode result = CURLE_OK; + size_t labellen = strlen(label); + size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */ + + output = malloc(outlen); + if(!output) + return CURLE_OUT_OF_MEMORY; + + /* sprintf the label and colon */ + snprintf(output, outlen, "%s:", label); + + /* memcpy the value (it might not be zero terminated) */ + memcpy(&output[labellen+1], value, valuelen); + + /* zero terminate the output */ + output[labellen + 1 + valuelen] = 0; + + nl = Curl_slist_append_nodup(ci->certinfo[certnum], output); + if(!nl) { + free(output); + curl_slist_free_all(ci->certinfo[certnum]); + result = CURLE_OUT_OF_MEMORY; + } + + ci->certinfo[certnum] = nl; + return result; +} + +/* + * This is a convenience function for push_certinfo_len that takes a zero + * terminated value. + */ +CURLcode Curl_ssl_push_certinfo(struct SessionHandle *data, + int certnum, + const char *label, + const char *value) +{ + size_t valuelen = strlen(value); + + return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen); +} + +int Curl_ssl_random(struct SessionHandle *data, + unsigned char *entropy, + size_t length) +{ + return curlssl_random(data, entropy, length); +} + +/* + * Public key pem to der conversion + */ + +static CURLcode pubkey_pem_to_der(const char *pem, + unsigned char **der, size_t *der_len) +{ + char *stripped_pem, *begin_pos, *end_pos; + size_t pem_count, stripped_pem_count = 0, pem_len; + CURLcode result; + + /* if no pem, exit. */ + if(!pem) + return CURLE_BAD_CONTENT_ENCODING; + + begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----"); + if(!begin_pos) + return CURLE_BAD_CONTENT_ENCODING; + + pem_count = begin_pos - pem; + /* Invalid if not at beginning AND not directly following \n */ + if(0 != pem_count && '\n' != pem[pem_count - 1]) + return CURLE_BAD_CONTENT_ENCODING; + + /* 26 is length of "-----BEGIN PUBLIC KEY-----" */ + pem_count += 26; + + /* Invalid if not directly following \n */ + end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----"); + if(!end_pos) + return CURLE_BAD_CONTENT_ENCODING; + + pem_len = end_pos - pem; + + stripped_pem = malloc(pem_len - pem_count + 1); + if(!stripped_pem) + return CURLE_OUT_OF_MEMORY; + + /* + * Here we loop through the pem array one character at a time between the + * correct indices, and place each character that is not '\n' or '\r' + * into the stripped_pem array, which should represent the raw base64 string + */ + while(pem_count < pem_len) { + if('\n' != pem[pem_count] && '\r' != pem[pem_count]) + stripped_pem[stripped_pem_count++] = pem[pem_count]; + ++pem_count; + } + /* Place the null terminator in the correct place */ + stripped_pem[stripped_pem_count] = '\0'; + + result = Curl_base64_decode(stripped_pem, der, der_len); + + Curl_safefree(stripped_pem); + + return result; +} + +/* + * Generic pinned public key check. + */ + +CURLcode Curl_pin_peer_pubkey(struct SessionHandle *data, + const char *pinnedpubkey, + const unsigned char *pubkey, size_t pubkeylen) +{ + FILE *fp; + unsigned char *buf = NULL, *pem_ptr = NULL; + long filesize; + size_t size, pem_len; + CURLcode pem_read; + CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; +#ifdef curlssl_sha256sum + CURLcode encode; + size_t encodedlen, pinkeylen; + char *encoded, *pinkeycopy, *begin_pos, *end_pos; + unsigned char *sha256sumdigest = NULL; +#endif + + /* if a path wasn't specified, don't pin */ + if(!pinnedpubkey) + return CURLE_OK; + if(!pubkey || !pubkeylen) + return result; + +#ifdef curlssl_sha256sum + /* only do this if pinnedpubkey starts with "sha256//", length 8 */ + if(strncmp(pinnedpubkey, "sha256//", 8) == 0) { + /* compute sha256sum of public key */ + sha256sumdigest = malloc(SHA256_DIGEST_LENGTH); + if(!sha256sumdigest) + return CURLE_OUT_OF_MEMORY; + curlssl_sha256sum(pubkey, pubkeylen, + sha256sumdigest, SHA256_DIGEST_LENGTH); + encode = Curl_base64_encode(data, (char *)sha256sumdigest, + SHA256_DIGEST_LENGTH, &encoded, &encodedlen); + Curl_safefree(sha256sumdigest); + + if(encode) + return encode; + + infof(data, "\t public key hash: sha256//%s\n", encoded); + + /* it starts with sha256//, copy so we can modify it */ + pinkeylen = strlen(pinnedpubkey) + 1; + pinkeycopy = malloc(pinkeylen); + if(!pinkeycopy) { + Curl_safefree(encoded); + return CURLE_OUT_OF_MEMORY; + } + memcpy(pinkeycopy, pinnedpubkey, pinkeylen); + /* point begin_pos to the copy, and start extracting keys */ + begin_pos = pinkeycopy; + do { + end_pos = strstr(begin_pos, ";sha256//"); + /* + * if there is an end_pos, null terminate, + * otherwise it'll go to the end of the original string + */ + if(end_pos) + end_pos[0] = '\0'; + + /* compare base64 sha256 digests, 8 is the length of "sha256//" */ + if(encodedlen == strlen(begin_pos + 8) && + !memcmp(encoded, begin_pos + 8, encodedlen)) { + result = CURLE_OK; + break; + } + + /* + * change back the null-terminator we changed earlier, + * and look for next begin + */ + if(end_pos) { + end_pos[0] = ';'; + begin_pos = strstr(end_pos, "sha256//"); + } + } while(end_pos && begin_pos); + Curl_safefree(encoded); + Curl_safefree(pinkeycopy); + return result; + } +#else + (void)data; +#endif + + fp = fopen(pinnedpubkey, "rb"); + if(!fp) + return result; + + do { + /* Determine the file's size */ + if(fseek(fp, 0, SEEK_END)) + break; + filesize = ftell(fp); + if(fseek(fp, 0, SEEK_SET)) + break; + if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE) + break; + + /* + * if the size of our certificate is bigger than the file + * size then it can't match + */ + size = curlx_sotouz((curl_off_t) filesize); + if(pubkeylen > size) + break; + + /* + * Allocate buffer for the pinned key + * With 1 additional byte for null terminator in case of PEM key + */ + buf = malloc(size + 1); + if(!buf) + break; + + /* Returns number of elements read, which should be 1 */ + if((int) fread(buf, size, 1, fp) != 1) + break; + + /* If the sizes are the same, it can't be base64 encoded, must be der */ + if(pubkeylen == size) { + if(!memcmp(pubkey, buf, pubkeylen)) + result = CURLE_OK; + break; + } + + /* + * Otherwise we will assume it's PEM and try to decode it + * after placing null terminator + */ + buf[size] = '\0'; + pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len); + /* if it wasn't read successfully, exit */ + if(pem_read) + break; + + /* + * if the size of our certificate doesn't match the size of + * the decoded file, they can't be the same, otherwise compare + */ + if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen)) + result = CURLE_OK; + } while(0); + + Curl_safefree(buf); + Curl_safefree(pem_ptr); + fclose(fp); + + return result; +} + +#ifndef CURL_DISABLE_CRYPTO_AUTH +CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum, /* output */ + size_t md5len) +{ +#ifdef curlssl_md5sum + curlssl_md5sum(tmp, tmplen, md5sum, md5len); +#else + MD5_context *MD5pw; + + (void) md5len; + + MD5pw = Curl_MD5_init(Curl_DIGEST_MD5); + if(!MD5pw) + return CURLE_OUT_OF_MEMORY; + Curl_MD5_update(MD5pw, tmp, curlx_uztoui(tmplen)); + Curl_MD5_final(MD5pw, md5sum); +#endif + return CURLE_OK; +} +#endif + +/* + * Check whether the SSL backend supports the status_request extension. + */ +bool Curl_ssl_cert_status_request(void) +{ +#ifdef curlssl_cert_status_request + return curlssl_cert_status_request(); +#else + return FALSE; +#endif +} + +/* + * Check whether the SSL backend supports false start. + */ +bool Curl_ssl_false_start(void) +{ +#ifdef curlssl_false_start + return curlssl_false_start(); +#else + return FALSE; +#endif +} + +#endif /* USE_SSL */ diff --git a/project/jni/curl/lib/vtls/vtls.h b/project/jni/curl/lib/vtls/vtls.h new file mode 100644 index 000000000..b6c66bfa3 --- /dev/null +++ b/project/jni/curl/lib/vtls/vtls.h @@ -0,0 +1,159 @@ +#ifndef HEADER_CURL_VTLS_H +#define HEADER_CURL_VTLS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "curl_setup.h" + +#include "openssl.h" /* OpenSSL versions */ +#include "gtls.h" /* GnuTLS versions */ +#include "nssg.h" /* NSS versions */ +#include "gskit.h" /* Global Secure ToolKit versions */ +#include "polarssl.h" /* PolarSSL versions */ +#include "axtls.h" /* axTLS versions */ +#include "cyassl.h" /* CyaSSL versions */ +#include "schannel.h" /* Schannel SSPI version */ +#include "darwinssl.h" /* SecureTransport (Darwin) version */ +#include "mbedtls.h" /* mbedTLS versions */ + +#ifndef MAX_PINNED_PUBKEY_SIZE +#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */ +#endif + +#ifndef MD5_DIGEST_LENGTH +#define MD5_DIGEST_LENGTH 16 /* fixed size */ +#endif + +#ifndef SHA256_DIGEST_LENGTH +#define SHA256_DIGEST_LENGTH 32 /* fixed size */ +#endif + +/* see https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */ +#define ALPN_HTTP_1_1_LENGTH 8 +#define ALPN_HTTP_1_1 "http/1.1" + +bool Curl_ssl_config_matches(struct ssl_config_data* data, + struct ssl_config_data* needle); +bool Curl_clone_ssl_config(struct ssl_config_data* source, + struct ssl_config_data* dest); +void Curl_free_ssl_config(struct ssl_config_data* sslc); + +unsigned int Curl_rand(struct SessionHandle *); + +int Curl_ssl_backend(void); + +#ifdef USE_SSL +int Curl_ssl_init(void); +void Curl_ssl_cleanup(void); +CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex); +CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done); +/* tell the SSL stuff to close down all open information regarding + connections (and thus session ID caching etc) */ +void Curl_ssl_close_all(struct SessionHandle *data); +void Curl_ssl_close(struct connectdata *conn, int sockindex); +CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex); +CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine); +/* Sets engine as default for all SSL operations */ +CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data); +struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data); + +/* init the SSL session ID cache */ +CURLcode Curl_ssl_initsessions(struct SessionHandle *, size_t); +size_t Curl_ssl_version(char *buffer, size_t size); +bool Curl_ssl_data_pending(const struct connectdata *conn, + int connindex); +int Curl_ssl_check_cxn(struct connectdata *conn); + +/* Certificate information list handling. */ + +void Curl_ssl_free_certinfo(struct SessionHandle *data); +CURLcode Curl_ssl_init_certinfo(struct SessionHandle * data, int num); +CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle * data, int certnum, + const char * label, const char * value, + size_t valuelen); +CURLcode Curl_ssl_push_certinfo(struct SessionHandle * data, int certnum, + const char * label, const char * value); + +/* Functions to be used by SSL library adaptation functions */ + +/* extract a session ID */ +bool Curl_ssl_getsessionid(struct connectdata *conn, + void **ssl_sessionid, + size_t *idsize) /* set 0 if unknown */; +/* add a new session ID */ +CURLcode Curl_ssl_addsessionid(struct connectdata *conn, + void *ssl_sessionid, + size_t idsize); +/* Kill a single session ID entry in the cache */ +void Curl_ssl_kill_session(struct curl_ssl_session *session); +/* delete a session from the cache */ +void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid); + +/* get N random bytes into the buffer, return 0 if a find random is filled + in */ +int Curl_ssl_random(struct SessionHandle *data, unsigned char *buffer, + size_t length); +CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum, /* output */ + size_t md5len); +/* Check pinned public key. */ +CURLcode Curl_pin_peer_pubkey(struct SessionHandle *data, + const char *pinnedpubkey, + const unsigned char *pubkey, size_t pubkeylen); + +bool Curl_ssl_cert_status_request(void); + +bool Curl_ssl_false_start(void); + +#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */ + +#else +/* Set the API backend definition to none */ +#define CURL_SSL_BACKEND CURLSSLBACKEND_NONE + +/* When SSL support is not present, just define away these function calls */ +#define Curl_ssl_init() 1 +#define Curl_ssl_cleanup() Curl_nop_stmt +#define Curl_ssl_connect(x,y) CURLE_NOT_BUILT_IN +#define Curl_ssl_close_all(x) Curl_nop_stmt +#define Curl_ssl_close(x,y) Curl_nop_stmt +#define Curl_ssl_shutdown(x,y) CURLE_NOT_BUILT_IN +#define Curl_ssl_set_engine(x,y) CURLE_NOT_BUILT_IN +#define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN +#define Curl_ssl_engines_list(x) NULL +#define Curl_ssl_send(a,b,c,d,e) -1 +#define Curl_ssl_recv(a,b,c,d,e) -1 +#define Curl_ssl_initsessions(x,y) CURLE_OK +#define Curl_ssl_version(x,y) 0 +#define Curl_ssl_data_pending(x,y) 0 +#define Curl_ssl_check_cxn(x) 0 +#define Curl_ssl_free_certinfo(x) Curl_nop_stmt +#define Curl_ssl_connect_nonblocking(x,y,z) CURLE_NOT_BUILT_IN +#define Curl_ssl_kill_session(x) Curl_nop_stmt +#define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN) +#define Curl_ssl_cert_status_request() FALSE +#define Curl_ssl_false_start() FALSE +#endif + +#endif /* HEADER_CURL_VTLS_H */ diff --git a/project/jni/curl/lib/warnless.c b/project/jni/curl/lib/warnless.c index bc29d28df..ed06c99a7 100644 --- a/project/jni/curl/lib/warnless.c +++ b/project/jni/curl/lib/warnless.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,7 +20,20 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" + +#if defined(__INTEL_COMPILER) && defined(__unix__) + +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif + +#endif /* __INTEL_COMPILER && __unix__ */ + +#define BUILDING_WARNLESS_C 1 #include "warnless.h" @@ -115,6 +128,7 @@ unsigned short curlx_ultous(unsigned long ulnum) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif + DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_USHORT); return (unsigned short)(ulnum & (unsigned long) CURL_MASK_USHORT); #ifdef __INTEL_COMPILER @@ -133,6 +147,7 @@ unsigned char curlx_ultouc(unsigned long ulnum) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif + DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_UCHAR); return (unsigned char)(ulnum & (unsigned long) CURL_MASK_UCHAR); #ifdef __INTEL_COMPILER @@ -140,6 +155,44 @@ unsigned char curlx_ultouc(unsigned long ulnum) #endif } +/* +** unsigned long to signed int +*/ + +int curlx_ultosi(unsigned long ulnum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_SINT); + return (int)(ulnum & (unsigned long) CURL_MASK_SINT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** unsigned size_t to signed curl_off_t +*/ + +curl_off_t curlx_uztoso(size_t uznum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(uznum <= (size_t) CURL_MASK_SCOFFT); + return (curl_off_t)(uznum & (size_t) CURL_MASK_SCOFFT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + /* ** unsigned size_t to signed int */ @@ -151,6 +204,7 @@ int curlx_uztosi(size_t uznum) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif + DEBUGASSERT(uznum <= (size_t) CURL_MASK_SINT); return (int)(uznum & (size_t) CURL_MASK_SINT); #ifdef __INTEL_COMPILER @@ -158,6 +212,48 @@ int curlx_uztosi(size_t uznum) #endif } +/* +** unsigned size_t to unsigned long +*/ + +unsigned long curlx_uztoul(size_t uznum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + +#if (CURL_SIZEOF_LONG < SIZEOF_SIZE_T) + DEBUGASSERT(uznum <= (size_t) CURL_MASK_ULONG); +#endif + return (unsigned long)(uznum & (size_t) CURL_MASK_ULONG); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** unsigned size_t to unsigned int +*/ + +unsigned int curlx_uztoui(size_t uznum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + +#if (SIZEOF_INT < SIZEOF_SIZE_T) + DEBUGASSERT(uznum <= (size_t) CURL_MASK_UINT); +#endif + return (unsigned int)(uznum & (size_t) CURL_MASK_UINT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + /* ** signed long to signed int */ @@ -170,6 +266,9 @@ int curlx_sltosi(long slnum) #endif DEBUGASSERT(slnum >= 0); +#if (SIZEOF_INT < CURL_SIZEOF_LONG) + DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_SINT); +#endif return (int)(slnum & (long) CURL_MASK_SINT); #ifdef __INTEL_COMPILER @@ -189,6 +288,9 @@ unsigned int curlx_sltoui(long slnum) #endif DEBUGASSERT(slnum >= 0); +#if (SIZEOF_INT < CURL_SIZEOF_LONG) + DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_UINT); +#endif return (unsigned int)(slnum & (long) CURL_MASK_UINT); #ifdef __INTEL_COMPILER @@ -208,6 +310,7 @@ unsigned short curlx_sltous(long slnum) #endif DEBUGASSERT(slnum >= 0); + DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_USHORT); return (unsigned short)(slnum & (long) CURL_MASK_USHORT); #ifdef __INTEL_COMPILER @@ -226,6 +329,7 @@ ssize_t curlx_uztosz(size_t uznum) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif + DEBUGASSERT(uznum <= (size_t) CURL_MASK_SSIZE_T); return (ssize_t)(uznum & (size_t) CURL_MASK_SSIZE_T); #ifdef __INTEL_COMPILER @@ -251,3 +355,132 @@ size_t curlx_sotouz(curl_off_t sonum) # pragma warning(pop) #endif } + +/* +** signed ssize_t to signed int +*/ + +int curlx_sztosi(ssize_t sznum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(sznum >= 0); +#if (SIZEOF_INT < SIZEOF_SIZE_T) + DEBUGASSERT((size_t) sznum <= (size_t) CURL_MASK_SINT); +#endif + return (int)(sznum & (ssize_t) CURL_MASK_SINT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** signed int to unsigned size_t +*/ + +size_t curlx_sitouz(int sinum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(sinum >= 0); + return (size_t) sinum; + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +#ifdef USE_WINSOCK + +/* +** curl_socket_t to signed int +*/ + +int curlx_sktosi(curl_socket_t s) +{ + return (int)((ssize_t) s); +} + +/* +** signed int to curl_socket_t +*/ + +curl_socket_t curlx_sitosk(int i) +{ + return (curl_socket_t)((ssize_t) i); +} + +#endif /* USE_WINSOCK */ + +#if defined(WIN32) || defined(_WIN32) + +ssize_t curlx_read(int fd, void *buf, size_t count) +{ + return (ssize_t)read(fd, buf, curlx_uztoui(count)); +} + +ssize_t curlx_write(int fd, const void *buf, size_t count) +{ + return (ssize_t)write(fd, buf, curlx_uztoui(count)); +} + +#endif /* WIN32 || _WIN32 */ + +#if defined(__INTEL_COMPILER) && defined(__unix__) + +int curlx_FD_ISSET(int fd, fd_set *fdset) +{ + #pragma warning(push) + #pragma warning(disable:1469) /* clobber ignored */ + return FD_ISSET(fd, fdset); + #pragma warning(pop) +} + +void curlx_FD_SET(int fd, fd_set *fdset) +{ + #pragma warning(push) + #pragma warning(disable:1469) /* clobber ignored */ + FD_SET(fd, fdset); + #pragma warning(pop) +} + +void curlx_FD_ZERO(fd_set *fdset) +{ + #pragma warning(push) + #pragma warning(disable:593) /* variable was set but never used */ + FD_ZERO(fdset); + #pragma warning(pop) +} + +unsigned short curlx_htons(unsigned short usnum) +{ +#if (__INTEL_COMPILER == 910) && defined(__i386__) + return (unsigned short)(((usnum << 8) & 0xFF00) | ((usnum >> 8) & 0x00FF)); +#else + #pragma warning(push) + #pragma warning(disable:810) /* conversion may lose significant bits */ + return htons(usnum); + #pragma warning(pop) +#endif +} + +unsigned short curlx_ntohs(unsigned short usnum) +{ +#if (__INTEL_COMPILER == 910) && defined(__i386__) + return (unsigned short)(((usnum << 8) & 0xFF00) | ((usnum >> 8) & 0x00FF)); +#else + #pragma warning(push) + #pragma warning(disable:810) /* conversion may lose significant bits */ + return ntohs(usnum); + #pragma warning(pop) +#endif +} + +#endif /* __INTEL_COMPILER && __unix__ */ diff --git a/project/jni/curl/lib/warnless.h b/project/jni/curl/lib/warnless.h index 7b9bd3c7f..499d0a0ab 100644 --- a/project/jni/curl/lib/warnless.h +++ b/project/jni/curl/lib/warnless.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -22,12 +22,24 @@ * ***************************************************************************/ +#ifdef USE_WINSOCK +#include /* for curl_socket_t */ +#endif + unsigned short curlx_ultous(unsigned long ulnum); unsigned char curlx_ultouc(unsigned long ulnum); +int curlx_ultosi(unsigned long ulnum); + int curlx_uztosi(size_t uznum); +curl_off_t curlx_uztoso(size_t uznum); + +unsigned long curlx_uztoul(size_t uznum); + +unsigned int curlx_uztoui(size_t uznum); + int curlx_sltosi(long slnum); unsigned int curlx_sltoui(long slnum); @@ -38,4 +50,58 @@ ssize_t curlx_uztosz(size_t uznum); size_t curlx_sotouz(curl_off_t sonum); +int curlx_sztosi(ssize_t sznum); + +size_t curlx_sitouz(int sinum); + +#ifdef USE_WINSOCK + +int curlx_sktosi(curl_socket_t s); + +curl_socket_t curlx_sitosk(int i); + +#endif /* USE_WINSOCK */ + +#if defined(WIN32) || defined(_WIN32) + +ssize_t curlx_read(int fd, void *buf, size_t count); + +ssize_t curlx_write(int fd, const void *buf, size_t count); + +#ifndef BUILDING_WARNLESS_C +# undef read +# define read(fd, buf, count) curlx_read(fd, buf, count) +# undef write +# define write(fd, buf, count) curlx_write(fd, buf, count) +#endif + +#endif /* WIN32 || _WIN32 */ + +#if defined(__INTEL_COMPILER) && defined(__unix__) + +int curlx_FD_ISSET(int fd, fd_set *fdset); + +void curlx_FD_SET(int fd, fd_set *fdset); + +void curlx_FD_ZERO(fd_set *fdset); + +unsigned short curlx_htons(unsigned short usnum); + +unsigned short curlx_ntohs(unsigned short usnum); + +#ifndef BUILDING_WARNLESS_C +# undef FD_ISSET +# define FD_ISSET(a,b) curlx_FD_ISSET((a),(b)) +# undef FD_SET +# define FD_SET(a,b) curlx_FD_SET((a),(b)) +# undef FD_ZERO +# define FD_ZERO(a) curlx_FD_ZERO((a)) +# undef htons +# define htons(a) curlx_htons((a)) +# undef ntohs +# define ntohs(a) curlx_ntohs((a)) +#endif + +#endif /* __INTEL_COMPILER && __unix__ */ + #endif /* HEADER_CURL_WARNLESS_H */ diff --git a/project/jni/curl/lib/wildcard.c b/project/jni/curl/lib/wildcard.c index 9fe5d5135..216307304 100644 --- a/project/jni/curl/lib/wildcard.c +++ b/project/jni/curl/lib/wildcard.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -20,14 +20,12 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" + #include "wildcard.h" #include "llist.h" #include "fileinfo.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -61,15 +59,10 @@ void Curl_wildcard_dtor(struct WildcardData *wc) wc->filelist = NULL; } - if(wc->path) { - free(wc->path); - wc->path = NULL; - } - - if(wc->pattern) { - free(wc->pattern); - wc->pattern = NULL; - } + free(wc->path); + wc->path = NULL; + free(wc->pattern); + wc->pattern = NULL; wc->customptr = NULL; wc->state = CURLWC_INIT; diff --git a/project/jni/curl/lib/wildcard.h b/project/jni/curl/lib/wildcard.h index 8f732d106..7d66992b1 100644 --- a/project/jni/curl/lib/wildcard.h +++ b/project/jni/curl/lib/wildcard.h @@ -7,11 +7,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2010, Daniel Stenberg, , et al. + * Copyright (C) 2010 - 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -33,8 +33,8 @@ typedef enum { CURLWC_CLEAN, /* deallocate resources and reset settings */ CURLWC_SKIP, /* skip over concrete file */ CURLWC_ERROR, /* error cases */ - CURLWC_DONE /* if is wildcard->state == CURLWC_DONE wildcard loop in - Curl_perform() will end */ + CURLWC_DONE /* if is wildcard->state == CURLWC_DONE wildcard loop + will end */ } curl_wildcard_states; typedef void (*curl_wildcard_tmp_dtor)(void *ptr); diff --git a/project/jni/curl/lib/x509asn1.c b/project/jni/curl/lib/x509asn1.c new file mode 100644 index 000000000..dbe57c7b7 --- /dev/null +++ b/project/jni/curl/lib/x509asn1.c @@ -0,0 +1,1184 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ + defined(USE_CYASSL) + +#include +#include "urldata.h" +#include "strequal.h" +#include "hostcheck.h" +#include "vtls/vtls.h" +#include "sendf.h" +#include "inet_pton.h" +#include "curl_base64.h" +#include "x509asn1.h" +#include "curl_printf.h" +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + + +/* ASN.1 OIDs. */ +static const char cnOID[] = "2.5.4.3"; /* Common name. */ +static const char sanOID[] = "2.5.29.17"; /* Subject alternative name. */ + +static const curl_OID OIDtable[] = { + { "1.2.840.10040.4.1", "dsa" }, + { "1.2.840.10040.4.3", "dsa-with-sha1" }, + { "1.2.840.10045.2.1", "ecPublicKey" }, + { "1.2.840.10045.3.0.1", "c2pnb163v1" }, + { "1.2.840.10045.4.1", "ecdsa-with-SHA1" }, + { "1.2.840.10046.2.1", "dhpublicnumber" }, + { "1.2.840.113549.1.1.1", "rsaEncryption" }, + { "1.2.840.113549.1.1.2", "md2WithRSAEncryption" }, + { "1.2.840.113549.1.1.4", "md5WithRSAEncryption" }, + { "1.2.840.113549.1.1.5", "sha1WithRSAEncryption" }, + { "1.2.840.113549.1.1.10", "RSASSA-PSS" }, + { "1.2.840.113549.1.1.14", "sha224WithRSAEncryption" }, + { "1.2.840.113549.1.1.11", "sha256WithRSAEncryption" }, + { "1.2.840.113549.1.1.12", "sha384WithRSAEncryption" }, + { "1.2.840.113549.1.1.13", "sha512WithRSAEncryption" }, + { "1.2.840.113549.2.2", "md2" }, + { "1.2.840.113549.2.5", "md5" }, + { "1.3.14.3.2.26", "sha1" }, + { cnOID, "CN" }, + { "2.5.4.4", "SN" }, + { "2.5.4.5", "serialNumber" }, + { "2.5.4.6", "C" }, + { "2.5.4.7", "L" }, + { "2.5.4.8", "ST" }, + { "2.5.4.9", "streetAddress" }, + { "2.5.4.10", "O" }, + { "2.5.4.11", "OU" }, + { "2.5.4.12", "title" }, + { "2.5.4.13", "description" }, + { "2.5.4.17", "postalCode" }, + { "2.5.4.41", "name" }, + { "2.5.4.42", "givenName" }, + { "2.5.4.43", "initials" }, + { "2.5.4.44", "generationQualifier" }, + { "2.5.4.45", "X500UniqueIdentifier" }, + { "2.5.4.46", "dnQualifier" }, + { "2.5.4.65", "pseudonym" }, + { "1.2.840.113549.1.9.1", "emailAddress" }, + { "2.5.4.72", "role" }, + { sanOID, "subjectAltName" }, + { "2.5.29.18", "issuerAltName" }, + { "2.5.29.19", "basicConstraints" }, + { "2.16.840.1.101.3.4.2.4", "sha224" }, + { "2.16.840.1.101.3.4.2.1", "sha256" }, + { "2.16.840.1.101.3.4.2.2", "sha384" }, + { "2.16.840.1.101.3.4.2.3", "sha512" }, + { (const char *) NULL, (const char *) NULL } +}; + +/* + * Lightweight ASN.1 parser. + * In particular, it does not check for syntactic/lexical errors. + * It is intended to support certificate information gathering for SSL backends + * that offer a mean to get certificates as a whole, but do not supply + * entry points to get particular certificate sub-fields. + * Please note there is no pretention here to rewrite a full SSL library. + */ + + +const char * Curl_getASN1Element(curl_asn1Element * elem, + const char * beg, const char * end) +{ + unsigned char b; + unsigned long len; + curl_asn1Element lelem; + + /* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg' + ending at `end'. + Returns a pointer in source string after the parsed element, or NULL + if an error occurs. */ + + if(beg >= end || !*beg) + return (const char *) NULL; + + /* Process header byte. */ + elem->header = beg; + b = (unsigned char) *beg++; + elem->constructed = (b & 0x20) != 0; + elem->class = (b >> 6) & 3; + b &= 0x1F; + if(b == 0x1F) + return (const char *) NULL; /* Long tag values not supported here. */ + elem->tag = b; + + /* Process length. */ + if(beg >= end) + return (const char *) NULL; + b = (unsigned char) *beg++; + if(!(b & 0x80)) + len = b; + else if(!(b &= 0x7F)) { + /* Unspecified length. Since we have all the data, we can determine the + effective length by skipping element until an end element is found. */ + if(!elem->constructed) + return (const char *) NULL; + elem->beg = beg; + while(beg < end && *beg) { + beg = Curl_getASN1Element(&lelem, beg, end); + if(!beg) + return (const char *) NULL; + } + if(beg >= end) + return (const char *) NULL; + elem->end = beg; + return beg + 1; + } + else if(beg + b > end) + return (const char *) NULL; /* Does not fit in source. */ + else { + /* Get long length. */ + len = 0; + do { + if(len & 0xFF000000L) + return (const char *) NULL; /* Lengths > 32 bits are not supported. */ + len = (len << 8) | (unsigned char) *beg++; + } while(--b); + } + if((unsigned long) (end - beg) < len) + return (const char *) NULL; /* Element data does not fit in source. */ + elem->beg = beg; + elem->end = beg + len; + return elem->end; +} + +static const curl_OID * searchOID(const char * oid) +{ + const curl_OID * op; + + /* Search the null terminated OID or OID identifier in local table. + Return the table entry pointer or NULL if not found. */ + + for(op = OIDtable; op->numoid; op++) + if(!strcmp(op->numoid, oid) || curl_strequal(op->textoid, oid)) + return op; + + return (const curl_OID *) NULL; +} + +static const char * bool2str(const char * beg, const char * end) +{ + /* Convert an ASN.1 Boolean value into its string representation. + Return the dynamically allocated string, or NULL if source is not an + ASN.1 Boolean value. */ + + if(end - beg != 1) + return (const char *) NULL; + return strdup(*beg? "TRUE": "FALSE"); +} + +static const char * octet2str(const char * beg, const char * end) +{ + size_t n = end - beg; + char * buf; + + /* Convert an ASN.1 octet string to a printable string. + Return the dynamically allocated string, or NULL if an error occurs. */ + + buf = malloc(3 * n + 1); + if(buf) + for(n = 0; beg < end; n += 3) + snprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++); + return buf; +} + +static const char * bit2str(const char * beg, const char * end) +{ + /* Convert an ASN.1 bit string to a printable string. + Return the dynamically allocated string, or NULL if an error occurs. */ + + if(++beg > end) + return (const char *) NULL; + return octet2str(beg, end); +} + +static const char * int2str(const char * beg, const char * end) +{ + long val = 0; + size_t n = end - beg; + + /* Convert an ASN.1 integer value into its string representation. + Return the dynamically allocated string, or NULL if source is not an + ASN.1 integer value. */ + + if(!n) + return (const char *) NULL; + + if(n > 4) + return octet2str(beg, end); + + /* Represent integers <= 32-bit as a single value. */ + if(*beg & 0x80) + val = ~val; + + do + val = (val << 8) | *(const unsigned char *) beg++; + while(beg < end); + return curl_maprintf("%s%lx", (val < 0 || val >= 10)? "0x": "", val); +} + +static ssize_t +utf8asn1str(char * * to, int type, const char * from, const char * end) +{ + size_t inlength = end - from; + int size = 1; + size_t outlength; + int charsize; + unsigned int wc; + char * buf; + + /* Perform a lazy conversion from an ASN.1 typed string to UTF8. Allocate the + destination buffer dynamically. The allocation size will normally be too + large: this is to avoid buffer overflows. + Terminate the string with a nul byte and return the converted + string length. */ + + *to = (char *) NULL; + switch (type) { + case CURL_ASN1_BMP_STRING: + size = 2; + break; + case CURL_ASN1_UNIVERSAL_STRING: + size = 4; + break; + case CURL_ASN1_NUMERIC_STRING: + case CURL_ASN1_PRINTABLE_STRING: + case CURL_ASN1_TELETEX_STRING: + case CURL_ASN1_IA5_STRING: + case CURL_ASN1_VISIBLE_STRING: + case CURL_ASN1_UTF8_STRING: + break; + default: + return -1; /* Conversion not supported. */ + } + + if(inlength % size) + return -1; /* Length inconsistent with character size. */ + buf = malloc(4 * (inlength / size) + 1); + if(!buf) + return -1; /* Not enough memory. */ + + if(type == CURL_ASN1_UTF8_STRING) { + /* Just copy. */ + outlength = inlength; + if(outlength) + memcpy(buf, from, outlength); + } + else { + for(outlength = 0; from < end;) { + wc = 0; + switch (size) { + case 4: + wc = (wc << 8) | *(const unsigned char *) from++; + wc = (wc << 8) | *(const unsigned char *) from++; + /* fallthrough */ + case 2: + wc = (wc << 8) | *(const unsigned char *) from++; + /* fallthrough */ + default: /* case 1: */ + wc = (wc << 8) | *(const unsigned char *) from++; + } + charsize = 1; + if(wc >= 0x00000080) { + if(wc >= 0x00000800) { + if(wc >= 0x00010000) { + if(wc >= 0x00200000) { + free(buf); + return -1; /* Invalid char. size for target encoding. */ + } + buf[outlength + 3] = (char) (0x80 | (wc & 0x3F)); + wc = (wc >> 6) | 0x00010000; + charsize++; + } + buf[outlength + 2] = (char) (0x80 | (wc & 0x3F)); + wc = (wc >> 6) | 0x00000800; + charsize++; + } + buf[outlength + 1] = (char) (0x80 | (wc & 0x3F)); + wc = (wc >> 6) | 0x000000C0; + charsize++; + } + buf[outlength] = (char) wc; + outlength += charsize; + } + } + buf[outlength] = '\0'; + *to = buf; + return outlength; +} + +static const char * string2str(int type, const char * beg, const char * end) +{ + char * buf; + + /* Convert an ASN.1 String into its UTF-8 string representation. + Return the dynamically allocated string, or NULL if an error occurs. */ + + if(utf8asn1str(&buf, type, beg, end) < 0) + return (const char *) NULL; + return buf; +} + +static int encodeUint(char * buf, int n, unsigned int x) +{ + int i = 0; + unsigned int y = x / 10; + + /* Decimal ASCII encode unsigned integer `x' in the `n'-byte buffer at `buf'. + Return the total number of encoded digits, even if larger than `n'. */ + + if(y) { + i += encodeUint(buf, n, y); + x -= y * 10; + } + if(i < n) + buf[i] = (char) ('0' + x); + i++; + if(i < n) + buf[i] = '\0'; /* Store a terminator if possible. */ + return i; +} + +static int encodeOID(char * buf, int n, const char * beg, const char * end) +{ + int i = 0; + unsigned int x; + unsigned int y; + + /* Convert an ASN.1 OID into its dotted string representation. + Store the result in th `n'-byte buffer at `buf'. + Return the converted string length, or -1 if an error occurs. */ + + /* Process the first two numbers. */ + y = *(const unsigned char *) beg++; + x = y / 40; + y -= x * 40; + i += encodeUint(buf + i, n - i, x); + if(i < n) + buf[i] = '.'; + i++; + i += encodeUint(buf + i, n - i, y); + + /* Process the trailing numbers. */ + while(beg < end) { + if(i < n) + buf[i] = '.'; + i++; + x = 0; + do { + if(x & 0xFF000000) + return -1; + y = *(const unsigned char *) beg++; + x = (x << 7) | (y & 0x7F); + } while(y & 0x80); + i += encodeUint(buf + i, n - i, x); + } + if(i < n) + buf[i] = '\0'; + return i; +} + +static const char * OID2str(const char * beg, const char * end, bool symbolic) +{ + char * buf = (char *) NULL; + const curl_OID * op; + int n; + + /* Convert an ASN.1 OID into its dotted or symbolic string representation. + Return the dynamically allocated string, or NULL if an error occurs. */ + + if(beg < end) { + n = encodeOID((char *) NULL, -1, beg, end); + if(n >= 0) { + buf = malloc(n + 1); + if(buf) { + encodeOID(buf, n, beg, end); + buf[n] = '\0'; + + if(symbolic) { + op = searchOID(buf); + if(op) { + free(buf); + buf = strdup(op->textoid); + } + } + } + } + } + return buf; +} + +static const char * GTime2str(const char * beg, const char * end) +{ + const char * tzp; + const char * fracp; + char sec1, sec2; + size_t fracl; + size_t tzl; + const char * sep = ""; + + /* Convert an ASN.1 Generalized time to a printable string. + Return the dynamically allocated string, or NULL if an error occurs. */ + + for(fracp = beg; fracp < end && *fracp >= '0' && *fracp <= '9'; fracp++) + ; + + /* Get seconds digits. */ + sec1 = '0'; + switch (fracp - beg - 12) { + case 0: + sec2 = '0'; + break; + case 2: + sec1 = fracp[-2]; + case 1: + sec2 = fracp[-1]; + break; + default: + return (const char *) NULL; + } + + /* Scan for timezone, measure fractional seconds. */ + tzp = fracp; + fracl = 0; + if(fracp < end && (*fracp == '.' || *fracp == ',')) { + fracp++; + do + tzp++; + while(tzp < end && *tzp >= '0' && *tzp <= '9'); + /* Strip leading zeroes in fractional seconds. */ + for(fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--) + ; + } + + /* Process timezone. */ + if(tzp >= end) + ; /* Nothing to do. */ + else if(*tzp == 'Z') { + tzp = " GMT"; + end = tzp + 4; + } + else { + sep = " "; + tzp++; + } + + tzl = end - tzp; + return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s", + beg, beg + 4, beg + 6, + beg + 8, beg + 10, sec1, sec2, + fracl? ".": "", fracl, fracp, + sep, tzl, tzp); +} + +static const char * UTime2str(const char * beg, const char * end) +{ + const char * tzp; + size_t tzl; + const char * sec; + + /* Convert an ASN.1 UTC time to a printable string. + Return the dynamically allocated string, or NULL if an error occurs. */ + + for(tzp = beg; tzp < end && *tzp >= '0' && *tzp <= '9'; tzp++) + ; + /* Get the seconds. */ + sec = beg + 10; + switch (tzp - sec) { + case 0: + sec = "00"; + case 2: + break; + default: + return (const char *) NULL; + } + + /* Process timezone. */ + if(tzp >= end) + return (const char *) NULL; + if(*tzp == 'Z') { + tzp = "GMT"; + end = tzp + 3; + } + else + tzp++; + + tzl = end - tzp; + return curl_maprintf("%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s", + 20 - (*beg >= '5'), beg, beg + 2, beg + 4, + beg + 6, beg + 8, sec, + tzl, tzp); +} + +const char * Curl_ASN1tostr(curl_asn1Element * elem, int type) +{ + /* Convert an ASN.1 element to a printable string. + Return the dynamically allocated string, or NULL if an error occurs. */ + + if(elem->constructed) + return (const char *) NULL; /* No conversion of structured elements. */ + + if(!type) + type = elem->tag; /* Type not forced: use element tag as type. */ + + switch (type) { + case CURL_ASN1_BOOLEAN: + return bool2str(elem->beg, elem->end); + case CURL_ASN1_INTEGER: + case CURL_ASN1_ENUMERATED: + return int2str(elem->beg, elem->end); + case CURL_ASN1_BIT_STRING: + return bit2str(elem->beg, elem->end); + case CURL_ASN1_OCTET_STRING: + return octet2str(elem->beg, elem->end); + case CURL_ASN1_NULL: + return strdup(""); + case CURL_ASN1_OBJECT_IDENTIFIER: + return OID2str(elem->beg, elem->end, TRUE); + case CURL_ASN1_UTC_TIME: + return UTime2str(elem->beg, elem->end); + case CURL_ASN1_GENERALIZED_TIME: + return GTime2str(elem->beg, elem->end); + case CURL_ASN1_UTF8_STRING: + case CURL_ASN1_NUMERIC_STRING: + case CURL_ASN1_PRINTABLE_STRING: + case CURL_ASN1_TELETEX_STRING: + case CURL_ASN1_IA5_STRING: + case CURL_ASN1_VISIBLE_STRING: + case CURL_ASN1_UNIVERSAL_STRING: + case CURL_ASN1_BMP_STRING: + return string2str(type, elem->beg, elem->end); + } + + return (const char *) NULL; /* Unsupported. */ +} + +static ssize_t encodeDN(char * buf, size_t n, curl_asn1Element * dn) +{ + curl_asn1Element rdn; + curl_asn1Element atv; + curl_asn1Element oid; + curl_asn1Element value; + size_t l = 0; + const char * p1; + const char * p2; + const char * p3; + const char * str; + + /* ASCII encode distinguished name at `dn' into the `n'-byte buffer at `buf'. + Return the total string length, even if larger than `n'. */ + + for(p1 = dn->beg; p1 < dn->end;) { + p1 = Curl_getASN1Element(&rdn, p1, dn->end); + for(p2 = rdn.beg; p2 < rdn.end;) { + p2 = Curl_getASN1Element(&atv, p2, rdn.end); + p3 = Curl_getASN1Element(&oid, atv.beg, atv.end); + Curl_getASN1Element(&value, p3, atv.end); + str = Curl_ASN1tostr(&oid, 0); + if(!str) + return -1; + + /* Encode delimiter. + If attribute has a short uppercase name, delimiter is ", ". */ + if(l) { + for(p3 = str; isupper(*p3); p3++) + ; + for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) { + if(l < n) + buf[l] = *p3; + l++; + } + } + + /* Encode attribute name. */ + for(p3 = str; *p3; p3++) { + if(l < n) + buf[l] = *p3; + l++; + } + free((char *) str); + + /* Generate equal sign. */ + if(l < n) + buf[l] = '='; + l++; + + /* Generate value. */ + str = Curl_ASN1tostr(&value, 0); + if(!str) + return -1; + for(p3 = str; *p3; p3++) { + if(l < n) + buf[l] = *p3; + l++; + } + free((char *) str); + } + } + + return l; +} + +const char * Curl_DNtostr(curl_asn1Element * dn) +{ + char * buf = (char *) NULL; + ssize_t n = encodeDN(buf, 0, dn); + + /* Convert an ASN.1 distinguished name into a printable string. + Return the dynamically allocated string, or NULL if an error occurs. */ + + if(n >= 0) { + buf = malloc(n + 1); + if(buf) { + encodeDN(buf, n + 1, dn); + buf[n] = '\0'; + } + } + return (const char *) buf; +} + +/* + * X509 parser. + */ + +void Curl_parseX509(curl_X509certificate * cert, + const char * beg, const char * end) +{ + curl_asn1Element elem; + curl_asn1Element tbsCertificate; + const char * ccp; + static const char defaultVersion = 0; /* v1. */ + + /* ASN.1 parse an X509 certificate into structure subfields. + Syntax is assumed to have already been checked by the SSL backend. + See RFC 5280. */ + + cert->certificate.header = NULL; + cert->certificate.beg = beg; + cert->certificate.end = end; + + /* Get the sequence content. */ + Curl_getASN1Element(&elem, beg, end); + beg = elem.beg; + end = elem.end; + + /* Get tbsCertificate. */ + beg = Curl_getASN1Element(&tbsCertificate, beg, end); + /* Skip the signatureAlgorithm. */ + beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end); + /* Get the signatureValue. */ + Curl_getASN1Element(&cert->signature, beg, end); + + /* Parse TBSCertificate. */ + beg = tbsCertificate.beg; + end = tbsCertificate.end; + /* Get optional version, get serialNumber. */ + cert->version.header = NULL; + cert->version.beg = &defaultVersion; + cert->version.end = &defaultVersion + sizeof defaultVersion;; + beg = Curl_getASN1Element(&elem, beg, end); + if(elem.tag == 0) { + Curl_getASN1Element(&cert->version, elem.beg, elem.end); + beg = Curl_getASN1Element(&elem, beg, end); + } + cert->serialNumber = elem; + /* Get signature algorithm. */ + beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end); + /* Get issuer. */ + beg = Curl_getASN1Element(&cert->issuer, beg, end); + /* Get notBefore and notAfter. */ + beg = Curl_getASN1Element(&elem, beg, end); + ccp = Curl_getASN1Element(&cert->notBefore, elem.beg, elem.end); + Curl_getASN1Element(&cert->notAfter, ccp, elem.end); + /* Get subject. */ + beg = Curl_getASN1Element(&cert->subject, beg, end); + /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */ + beg = Curl_getASN1Element(&cert->subjectPublicKeyInfo, beg, end); + ccp = Curl_getASN1Element(&cert->subjectPublicKeyAlgorithm, + cert->subjectPublicKeyInfo.beg, + cert->subjectPublicKeyInfo.end); + Curl_getASN1Element(&cert->subjectPublicKey, ccp, + cert->subjectPublicKeyInfo.end); + /* Get optional issuerUiqueID, subjectUniqueID and extensions. */ + cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0; + cert->extensions.tag = elem.tag = 0; + cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL; + cert->issuerUniqueID.beg = cert->issuerUniqueID.end = ""; + cert->subjectUniqueID.beg = cert->subjectUniqueID.end = ""; + cert->extensions.header = NULL; + cert->extensions.beg = cert->extensions.end = ""; + if(beg < end) + beg = Curl_getASN1Element(&elem, beg, end); + if(elem.tag == 1) { + cert->issuerUniqueID = elem; + if(beg < end) + beg = Curl_getASN1Element(&elem, beg, end); + } + if(elem.tag == 2) { + cert->subjectUniqueID = elem; + if(beg < end) + beg = Curl_getASN1Element(&elem, beg, end); + } + if(elem.tag == 3) + Curl_getASN1Element(&cert->extensions, elem.beg, elem.end); +} + +static size_t copySubstring(char * to, const char * from) +{ + size_t i; + + /* Copy at most 64-characters, terminate with a newline and returns the + effective number of stored characters. */ + + for(i = 0; i < 64; i++) { + to[i] = *from; + if(!*from++) + break; + } + + to[i++] = '\n'; + return i; +} + +static const char * dumpAlgo(curl_asn1Element * param, + const char * beg, const char * end) +{ + curl_asn1Element oid; + + /* Get algorithm parameters and return algorithm name. */ + + beg = Curl_getASN1Element(&oid, beg, end); + param->header = NULL; + param->tag = 0; + param->beg = param->end = end; + if(beg < end) + Curl_getASN1Element(param, beg, end); + return OID2str(oid.beg, oid.end, TRUE); +} + +static void do_pubkey_field(struct SessionHandle * data, int certnum, + const char * label, curl_asn1Element * elem) +{ + const char * output; + + /* Generate a certificate information record for the public key. */ + + output = Curl_ASN1tostr(elem, 0); + if(output) { + if(data->set.ssl.certinfo) + Curl_ssl_push_certinfo(data, certnum, label, output); + if(!certnum) + infof(data, " %s: %s\n", label, output); + free((char *) output); + } +} + +static void do_pubkey(struct SessionHandle * data, int certnum, + const char * algo, curl_asn1Element * param, + curl_asn1Element * pubkey) +{ + curl_asn1Element elem; + curl_asn1Element pk; + const char * p; + const char * q; + unsigned long len; + unsigned int i; + + /* Generate all information records for the public key. */ + + /* Get the public key (single element). */ + Curl_getASN1Element(&pk, pubkey->beg + 1, pubkey->end); + + if(curl_strequal(algo, "rsaEncryption")) { + p = Curl_getASN1Element(&elem, pk.beg, pk.end); + /* Compute key length. */ + for(q = elem.beg; !*q && q < elem.end; q++) + ; + len = (unsigned long)((elem.end - q) * 8); + if(len) + for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1) + len--; + if(len > 32) + elem.beg = q; /* Strip leading zero bytes. */ + if(!certnum) + infof(data, " RSA Public Key (%lu bits)\n", len); + if(data->set.ssl.certinfo) { + q = curl_maprintf("%lu", len); + if(q) { + Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q); + free((char *) q); + } + } + /* Generate coefficients. */ + do_pubkey_field(data, certnum, "rsa(n)", &elem); + Curl_getASN1Element(&elem, p, pk.end); + do_pubkey_field(data, certnum, "rsa(e)", &elem); + } + else if(curl_strequal(algo, "dsa")) { + p = Curl_getASN1Element(&elem, param->beg, param->end); + do_pubkey_field(data, certnum, "dsa(p)", &elem); + p = Curl_getASN1Element(&elem, p, param->end); + do_pubkey_field(data, certnum, "dsa(q)", &elem); + Curl_getASN1Element(&elem, p, param->end); + do_pubkey_field(data, certnum, "dsa(g)", &elem); + do_pubkey_field(data, certnum, "dsa(pub_key)", &pk); + } + else if(curl_strequal(algo, "dhpublicnumber")) { + p = Curl_getASN1Element(&elem, param->beg, param->end); + do_pubkey_field(data, certnum, "dh(p)", &elem); + Curl_getASN1Element(&elem, param->beg, param->end); + do_pubkey_field(data, certnum, "dh(g)", &elem); + do_pubkey_field(data, certnum, "dh(pub_key)", &pk); + } +#if 0 /* Patent-encumbered. */ + else if(curl_strequal(algo, "ecPublicKey")) { + /* Left TODO. */ + } +#endif +} + +CURLcode Curl_extract_certinfo(struct connectdata * conn, + int certnum, + const char * beg, + const char * end) +{ + curl_X509certificate cert; + struct SessionHandle * data = conn->data; + curl_asn1Element param; + const char * ccp; + char * cp1; + size_t cl1; + char * cp2; + CURLcode result; + unsigned long version; + size_t i; + size_t j; + + if(!data->set.ssl.certinfo) + if(certnum) + return CURLE_OK; + + /* Prepare the certificate information for curl_easy_getinfo(). */ + + /* Extract the certificate ASN.1 elements. */ + Curl_parseX509(&cert, beg, end); + + /* Subject. */ + ccp = Curl_DNtostr(&cert.subject); + if(!ccp) + return CURLE_OUT_OF_MEMORY; + if(data->set.ssl.certinfo) + Curl_ssl_push_certinfo(data, certnum, "Subject", ccp); + if(!certnum) + infof(data, "%2d Subject: %s\n", certnum, ccp); + free((char *) ccp); + + /* Issuer. */ + ccp = Curl_DNtostr(&cert.issuer); + if(!ccp) + return CURLE_OUT_OF_MEMORY; + if(data->set.ssl.certinfo) + Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp); + if(!certnum) + infof(data, " Issuer: %s\n", ccp); + free((char *) ccp); + + /* Version (always fits in less than 32 bits). */ + version = 0; + for(ccp = cert.version.beg; ccp < cert.version.end; ccp++) + version = (version << 8) | *(const unsigned char *) ccp; + if(data->set.ssl.certinfo) { + ccp = curl_maprintf("%lx", version); + if(!ccp) + return CURLE_OUT_OF_MEMORY; + Curl_ssl_push_certinfo(data, certnum, "Version", ccp); + free((char *) ccp); + } + if(!certnum) + infof(data, " Version: %lu (0x%lx)\n", version + 1, version); + + /* Serial number. */ + ccp = Curl_ASN1tostr(&cert.serialNumber, 0); + if(!ccp) + return CURLE_OUT_OF_MEMORY; + if(data->set.ssl.certinfo) + Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp); + if(!certnum) + infof(data, " Serial Number: %s\n", ccp); + free((char *) ccp); + + /* Signature algorithm .*/ + ccp = dumpAlgo(¶m, cert.signatureAlgorithm.beg, + cert.signatureAlgorithm.end); + if(!ccp) + return CURLE_OUT_OF_MEMORY; + if(data->set.ssl.certinfo) + Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp); + if(!certnum) + infof(data, " Signature Algorithm: %s\n", ccp); + free((char *) ccp); + + /* Start Date. */ + ccp = Curl_ASN1tostr(&cert.notBefore, 0); + if(!ccp) + return CURLE_OUT_OF_MEMORY; + if(data->set.ssl.certinfo) + Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp); + if(!certnum) + infof(data, " Start Date: %s\n", ccp); + free((char *) ccp); + + /* Expire Date. */ + ccp = Curl_ASN1tostr(&cert.notAfter, 0); + if(!ccp) + return CURLE_OUT_OF_MEMORY; + if(data->set.ssl.certinfo) + Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp); + if(!certnum) + infof(data, " Expire Date: %s\n", ccp); + free((char *) ccp); + + /* Public Key Algorithm. */ + ccp = dumpAlgo(¶m, cert.subjectPublicKeyAlgorithm.beg, + cert.subjectPublicKeyAlgorithm.end); + if(!ccp) + return CURLE_OUT_OF_MEMORY; + if(data->set.ssl.certinfo) + Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp); + if(!certnum) + infof(data, " Public Key Algorithm: %s\n", ccp); + do_pubkey(data, certnum, ccp, ¶m, &cert.subjectPublicKey); + free((char *) ccp); + +/* TODO: extensions. */ + + /* Signature. */ + ccp = Curl_ASN1tostr(&cert.signature, 0); + if(!ccp) + return CURLE_OUT_OF_MEMORY; + if(data->set.ssl.certinfo) + Curl_ssl_push_certinfo(data, certnum, "Signature", ccp); + if(!certnum) + infof(data, " Signature: %s\n", ccp); + free((char *) ccp); + + /* Generate PEM certificate. */ + result = Curl_base64_encode(data, cert.certificate.beg, + cert.certificate.end - cert.certificate.beg, + &cp1, &cl1); + if(result) + return result; + /* Compute the number of characters in final certificate string. Format is: + -----BEGIN CERTIFICATE-----\n + \n + . + . + . + -----END CERTIFICATE-----\n + */ + i = 28 + cl1 + (cl1 + 64 - 1) / 64 + 26; + cp2 = malloc(i + 1); + if(!cp2) { + free(cp1); + return CURLE_OUT_OF_MEMORY; + } + /* Build the certificate string. */ + i = copySubstring(cp2, "-----BEGIN CERTIFICATE-----"); + for(j = 0; j < cl1; j += 64) + i += copySubstring(cp2 + i, cp1 + j); + i += copySubstring(cp2 + i, "-----END CERTIFICATE-----"); + cp2[i] = '\0'; + free(cp1); + if(data->set.ssl.certinfo) + Curl_ssl_push_certinfo(data, certnum, "Cert", cp2); + if(!certnum) + infof(data, "%s\n", cp2); + free(cp2); + return CURLE_OK; +} + +#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL */ + +#if defined(USE_GSKIT) + +static const char * checkOID(const char * beg, const char * end, + const char * oid) +{ + curl_asn1Element e; + const char * ccp; + const char * p; + bool matched; + + /* Check if first ASN.1 element at `beg' is the given OID. + Return a pointer in the source after the OID if found, else NULL. */ + + ccp = Curl_getASN1Element(&e, beg, end); + if(!ccp || e.tag != CURL_ASN1_OBJECT_IDENTIFIER) + return (const char *) NULL; + + p = OID2str(e.beg, e.end, FALSE); + if(!p) + return (const char *) NULL; + + matched = !strcmp(p, oid); + free((char *) p); + return matched? ccp: (const char *) NULL; +} + +CURLcode Curl_verifyhost(struct connectdata * conn, + const char * beg, const char * end) +{ + struct SessionHandle * data = conn->data; + curl_X509certificate cert; + curl_asn1Element dn; + curl_asn1Element elem; + curl_asn1Element ext; + curl_asn1Element name; + const char * p; + const char * q; + char * dnsname; + int matched = -1; + size_t addrlen = (size_t) -1; + ssize_t len; +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif + + /* Verify that connection server matches info in X509 certificate at + `beg'..`end'. */ + + if(!data->set.ssl.verifyhost) + return CURLE_OK; + + if(!beg) + return CURLE_PEER_FAILED_VERIFICATION; + Curl_parseX509(&cert, beg, end); + + /* Get the server IP address. */ +#ifdef ENABLE_IPV6 + if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, conn->host.name, &addr)) + addrlen = sizeof(struct in6_addr); + else +#endif + if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) + addrlen = sizeof(struct in_addr); + + /* Process extensions. */ + for(p = cert.extensions.beg; p < cert.extensions.end && matched != 1;) { + p = Curl_getASN1Element(&ext, p, cert.extensions.end); + /* Check if extension is a subjectAlternativeName. */ + ext.beg = checkOID(ext.beg, ext.end, sanOID); + if(ext.beg) { + ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end); + /* Skip critical if present. */ + if(elem.tag == CURL_ASN1_BOOLEAN) + ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end); + /* Parse the octet string contents: is a single sequence. */ + Curl_getASN1Element(&elem, elem.beg, elem.end); + /* Check all GeneralNames. */ + for(q = elem.beg; matched != 1 && q < elem.end;) { + q = Curl_getASN1Element(&name, q, elem.end); + switch (name.tag) { + case 2: /* DNS name. */ + len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING, + name.beg, name.end); + if(len > 0 && (size_t)len == strlen(dnsname)) + matched = Curl_cert_hostcheck(dnsname, conn->host.name); + else + matched = 0; + free(dnsname); + break; + + case 7: /* IP address. */ + matched = (size_t) (name.end - q) == addrlen && + !memcmp(&addr, q, addrlen); + break; + } + } + } + } + + switch (matched) { + case 1: + /* an alternative name matched the server hostname */ + infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname); + return CURLE_OK; + case 0: + /* an alternative name field existed, but didn't match and then + we MUST fail */ + infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname); + return CURLE_PEER_FAILED_VERIFICATION; + } + + /* Process subject. */ + name.header = NULL; + name.beg = name.end = ""; + q = cert.subject.beg; + /* we have to look to the last occurrence of a commonName in the + distinguished one to get the most significant one. */ + while(q < cert.subject.end) { + q = Curl_getASN1Element(&dn, q, cert.subject.end); + for(p = dn.beg; p < dn.end;) { + p = Curl_getASN1Element(&elem, p, dn.end); + /* We have a DN's AttributeTypeAndValue: check it in case it's a CN. */ + elem.beg = checkOID(elem.beg, elem.end, cnOID); + if(elem.beg) + name = elem; /* Latch CN. */ + } + } + + /* Check the CN if found. */ + if(!Curl_getASN1Element(&elem, name.beg, name.end)) + failf(data, "SSL: unable to obtain common name from peer certificate"); + else { + len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end); + if(len < 0) { + free(dnsname); + return CURLE_OUT_OF_MEMORY; + } + if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */ + failf(data, "SSL: illegal cert name field"); + else if(Curl_cert_hostcheck((const char *) dnsname, conn->host.name)) { + infof(data, "\t common name: %s (matched)\n", dnsname); + free(dnsname); + return CURLE_OK; + } + else + failf(data, "SSL: certificate subject name '%s' does not match " + "target host name '%s'", dnsname, conn->host.dispname); + free(dnsname); + } + + return CURLE_PEER_FAILED_VERIFICATION; +} + +#endif /* USE_GSKIT */ diff --git a/project/jni/curl/lib/x509asn1.h b/project/jni/curl/lib/x509asn1.h new file mode 100644 index 000000000..e6a1e2444 --- /dev/null +++ b/project/jni/curl/lib/x509asn1.h @@ -0,0 +1,132 @@ +#ifndef HEADER_CURL_X509ASN1_H +#define HEADER_CURL_X509ASN1_H + +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ + defined(USE_CYASSL) + +#include "urldata.h" + +/* + * Constants. + */ + +/* ASN.1 classes. */ +#define CURL_ASN1_UNIVERSAL 0 +#define CURL_ASN1_APPLICATION 1 +#define CURL_ASN1_CONTEXT_SPECIFIC 2 +#define CURL_ASN1_PRIVATE 3 + +/* ASN.1 types. */ +#define CURL_ASN1_BOOLEAN 1 +#define CURL_ASN1_INTEGER 2 +#define CURL_ASN1_BIT_STRING 3 +#define CURL_ASN1_OCTET_STRING 4 +#define CURL_ASN1_NULL 5 +#define CURL_ASN1_OBJECT_IDENTIFIER 6 +#define CURL_ASN1_OBJECT_DESCRIPTOR 7 +#define CURL_ASN1_INSTANCE_OF 8 +#define CURL_ASN1_REAL 9 +#define CURL_ASN1_ENUMERATED 10 +#define CURL_ASN1_EMBEDDED 11 +#define CURL_ASN1_UTF8_STRING 12 +#define CURL_ASN1_RELATIVE_OID 13 +#define CURL_ASN1_SEQUENCE 16 +#define CURL_ASN1_SET 17 +#define CURL_ASN1_NUMERIC_STRING 18 +#define CURL_ASN1_PRINTABLE_STRING 19 +#define CURL_ASN1_TELETEX_STRING 20 +#define CURL_ASN1_VIDEOTEX_STRING 21 +#define CURL_ASN1_IA5_STRING 22 +#define CURL_ASN1_UTC_TIME 23 +#define CURL_ASN1_GENERALIZED_TIME 24 +#define CURL_ASN1_GRAPHIC_STRING 25 +#define CURL_ASN1_VISIBLE_STRING 26 +#define CURL_ASN1_GENERAL_STRING 27 +#define CURL_ASN1_UNIVERSAL_STRING 28 +#define CURL_ASN1_CHARACTER_STRING 29 +#define CURL_ASN1_BMP_STRING 30 + + +/* + * Types. + */ + +/* ASN.1 parsed element. */ +typedef struct { + const char * header; /* Pointer to header byte. */ + const char * beg; /* Pointer to element data. */ + const char * end; /* Pointer to 1st byte after element. */ + unsigned char class; /* ASN.1 element class. */ + unsigned char tag; /* ASN.1 element tag. */ + bool constructed; /* Element is constructed. */ +} curl_asn1Element; + + +/* ASN.1 OID table entry. */ +typedef struct { + const char * numoid; /* Dotted-numeric OID. */ + const char * textoid; /* OID name. */ +} curl_OID; + + +/* X509 certificate: RFC 5280. */ +typedef struct { + curl_asn1Element certificate; + curl_asn1Element version; + curl_asn1Element serialNumber; + curl_asn1Element signatureAlgorithm; + curl_asn1Element signature; + curl_asn1Element issuer; + curl_asn1Element notBefore; + curl_asn1Element notAfter; + curl_asn1Element subject; + curl_asn1Element subjectPublicKeyInfo; + curl_asn1Element subjectPublicKeyAlgorithm; + curl_asn1Element subjectPublicKey; + curl_asn1Element issuerUniqueID; + curl_asn1Element subjectUniqueID; + curl_asn1Element extensions; +} curl_X509certificate; + + +/* + * Prototypes. + */ + +const char * Curl_getASN1Element(curl_asn1Element * elem, + const char * beg, const char * end); +const char * Curl_ASN1tostr(curl_asn1Element * elem, int type); +const char * Curl_DNtostr(curl_asn1Element * dn); +void Curl_parseX509(curl_X509certificate * cert, + const char * beg, const char * end); +CURLcode Curl_extract_certinfo(struct connectdata * conn, int certnum, + const char * beg, const char * end); +CURLcode Curl_verifyhost(struct connectdata * conn, + const char * beg, const char * end); + +#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL */ +#endif /* HEADER_CURL_X509ASN1_H */ diff --git a/project/jni/ssl b/project/jni/ssl index fc538edfe..4eadeea9a 120000 --- a/project/jni/ssl +++ b/project/jni/ssl @@ -1 +1 @@ -openssl \ No newline at end of file +boringssl \ No newline at end of file