/* ssl.cpp * * Copyright (C) 2003 Sawtooth Consulting Ltd. * * This file is part of yaSSL. * * yaSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * yaSSL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* SSL source implements all openssl compatibility API functions * * TODO: notes are mostly api additions to allow compilation with mysql * they don't affect normal modes but should be provided for completeness * stunnel functions at end of file */ /* see man pages for function descriptions */ #include "runtime.hpp" #include "openssl/ssl.h" #include "handshake.hpp" #include "yassl_int.hpp" #include "md5.hpp" // for TaoCrypt MD5 size assert #include #ifdef _WIN32 #include // FindFirstFile etc.. #else #include // file helper #include // stat #include // opendir #endif namespace yaSSL { using mySTL::min; int read_file(SSL_CTX* ctx, const char* file, int format, CertType type) { if (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM) return SSL_BAD_FILETYPE; FILE* input = fopen(file, "rb"); if (!input) return SSL_BAD_FILE; if (type == CA) { x509* ptr = PemToDer(file, Cert); if (!ptr) { fclose(input); return SSL_BAD_FILE; } ctx->AddCA(ptr); // takes ownership } else { x509*& x = (type == Cert) ? ctx->certificate_ : ctx->privateKey_; if (format == SSL_FILETYPE_ASN1) { fseek(input, 0, SEEK_END); long sz = ftell(input); rewind(input); x = NEW_YS x509(sz); // takes ownership size_t bytes = fread(x->use_buffer(), sz, 1, input); if (bytes != 1) { fclose(input); return SSL_BAD_FILE; } } else { x = PemToDer(file, type); if (!x) { fclose(input); return SSL_BAD_FILE; } } } fclose(input); return SSL_SUCCESS; } extern "C" { SSL_METHOD* SSLv3_method() { return SSLv3_client_method(); } SSL_METHOD* SSLv3_server_method() { return NEW_YS SSL_METHOD(server_end, ProtocolVersion(3,0)); } SSL_METHOD* SSLv3_client_method() { return NEW_YS SSL_METHOD(client_end, ProtocolVersion(3,0)); } SSL_METHOD* TLSv1_server_method() { return NEW_YS SSL_METHOD(server_end, ProtocolVersion(3,1)); } SSL_METHOD* TLSv1_client_method() { return NEW_YS SSL_METHOD(client_end, ProtocolVersion(3,1)); } SSL_METHOD* SSLv23_server_method() { // compatibility only, no version 2 support return SSLv3_server_method(); } SSL_CTX* SSL_CTX_new(SSL_METHOD* method) { return NEW_YS SSL_CTX(method); } void SSL_CTX_free(SSL_CTX* ctx) { ysDelete(ctx); } SSL* SSL_new(SSL_CTX* ctx) { return NEW_YS SSL(ctx); } void SSL_free(SSL* ssl) { ysDelete(ssl); } int SSL_set_fd(SSL* ssl, int fd) { ssl->useSocket().set_fd(fd); return SSL_SUCCESS; } int SSL_connect(SSL* ssl) { sendClientHello(*ssl); ClientState neededState = ssl->getSecurity().get_resuming() ? serverFinishedComplete : serverHelloDoneComplete; while (ssl->getStates().getClient() < neededState) { if (ssl->GetError()) break; processReply(*ssl); } if(ssl->getCrypto().get_certManager().sendVerify()) sendCertificate(*ssl); if (!ssl->getSecurity().get_resuming()) sendClientKeyExchange(*ssl); if(ssl->getCrypto().get_certManager().sendVerify()) sendCertificateVerify(*ssl); sendChangeCipher(*ssl); sendFinished(*ssl, client_end); ssl->flushBuffer(); if (!ssl->getSecurity().get_resuming()) while (ssl->getStates().getClient() < serverFinishedComplete) { if (ssl->GetError()) break; processReply(*ssl); } ssl->verifyState(serverFinishedComplete); ssl->useLog().ShowTCP(ssl->getSocket().get_fd()); if (ssl->GetError()) return SSL_FATAL_ERROR; return SSL_SUCCESS; } int SSL_write(SSL* ssl, const void* buffer, int sz) { return sendData(*ssl, buffer, sz); } int SSL_read(SSL* ssl, void* buffer, int sz) { Data data(min(sz, MAX_RECORD_SIZE), static_cast(buffer)); return receiveData(*ssl, data); } int SSL_accept(SSL* ssl) { processReply(*ssl); sendServerHello(*ssl); if (!ssl->getSecurity().get_resuming()) { sendCertificate(*ssl); if (ssl->getSecurity().get_connection().send_server_key_) sendServerKeyExchange(*ssl); if(ssl->getCrypto().get_certManager().verifyPeer()) sendCertificateRequest(*ssl); sendServerHelloDone(*ssl); ssl->flushBuffer(); while (ssl->getStates().getServer() < clientFinishedComplete) { if (ssl->GetError()) break; processReply(*ssl); } } sendChangeCipher(*ssl); sendFinished(*ssl, server_end); ssl->flushBuffer(); if (ssl->getSecurity().get_resuming()) { while (ssl->getStates().getServer() < clientFinishedComplete) { if (ssl->GetError()) break; processReply(*ssl); } } ssl->useLog().ShowTCP(ssl->getSocket().get_fd()); if (ssl->GetError()) return SSL_FATAL_ERROR; return SSL_SUCCESS; } int SSL_do_handshake(SSL* ssl) { if (ssl->getSecurity().get_parms().entity_ == client_end) return SSL_connect(ssl); else return SSL_accept(ssl); } int SSL_clear(SSL* ssl) { ssl->useSocket().closeSocket(); return SSL_SUCCESS; } int SSL_shutdown(SSL* ssl) { Alert alert(warning, close_notify); sendAlert(*ssl, alert); ssl->useLog().ShowTCP(ssl->getSocket().get_fd(), true); ssl->useSocket().closeSocket(); return SSL_SUCCESS; } SSL_SESSION* SSL_get_session(SSL* ssl) { return GetSessions().lookup( ssl->getSecurity().get_connection().sessionID_); } int SSL_set_session(SSL* ssl, SSL_SESSION* session) { ssl->set_session(session); return SSL_SUCCESS; } int SSL_session_reused(SSL* ssl) { return ssl->getSecurity().get_resuming(); } long SSL_SESSION_set_timeout(SSL_SESSION* sess, long t) { if (!sess) return SSL_ERROR_NONE; sess->SetTimeOut(t); return SSL_SUCCESS; } long SSL_get_default_timeout(SSL* /*ssl*/) { return DEFAULT_TIMEOUT; } const char* SSL_get_cipher_name(SSL* ssl) { return SSL_get_cipher(ssl); } const char* SSL_get_cipher(SSL* ssl) { return ssl->getSecurity().get_parms().cipher_name_; } // SSLv2 only, not implemented char* SSL_get_shared_ciphers(SSL* /*ssl*/, char* buf, int len) { return strncpy(buf, "Not Implemented, SSLv2 only", len); } const char* SSL_get_cipher_list(SSL* ssl, int priority) { if (priority < 0 || priority >= MAX_CIPHERS) return 0; if (ssl->getSecurity().get_parms().cipher_list_[priority][0]) return ssl->getSecurity().get_parms().cipher_list_[priority]; return 0; } int SSL_CTX_set_cipher_list(SSL_CTX* ctx, const char* list) { if (ctx->SetCipherList(list)) return SSL_SUCCESS; else return SSL_FAILURE; } const char* SSL_get_version(SSL* ssl) { static const char* version3 = "SSLv3"; static const char* version31 = "TLSv1"; return ssl->isTLS() ? version31 : version3; } const char* SSLeay_version(int) { static const char* version = "SSLeay yaSSL compatibility"; return version; } int SSL_get_error(SSL* ssl, int /*previous*/) { return ssl->getStates().What(); } X509* SSL_get_peer_certificate(SSL* ssl) { return ssl->getCrypto().get_certManager().get_peerX509(); } void X509_free(X509* /*x*/) { // peer cert set for deletion during destruction // no need to delete now } X509* X509_STORE_CTX_get_current_cert(X509_STORE_CTX* ctx) { return ctx->current_cert; } int X509_STORE_CTX_get_error(X509_STORE_CTX* ctx) { return ctx->error; } int X509_STORE_CTX_get_error_depth(X509_STORE_CTX* ctx) { return ctx->error_depth; } // copy name into buffer, at most sz bytes, if buffer is null // will malloc buffer, caller responsible for freeing char* X509_NAME_oneline(X509_NAME* name, char* buffer, int sz) { if (!name->GetName()) return buffer; int len = strlen(name->GetName()) + 1; int copySz = min(len, sz); if (!buffer) { buffer = (char*)malloc(len); if (!buffer) return buffer; copySz = len; } if (copySz == 0) return buffer; memcpy(buffer, name->GetName(), copySz - 1); buffer[copySz - 1] = 0; return buffer; } X509_NAME* X509_get_issuer_name(X509* x) { return x->GetIssuer(); } X509_NAME* X509_get_subject_name(X509* x) { return x->GetSubject(); } void SSL_load_error_strings() // compatibility only {} void SSL_set_connect_state(SSL*) { // already a client by default } void SSL_set_accept_state(SSL* ssl) { ssl->useSecurity().use_parms().entity_ = server_end; } long SSL_get_verify_result(SSL*) { // won't get here if not OK return X509_V_OK; } long SSL_CTX_sess_set_cache_size(SSL_CTX* /*ctx*/, long /*sz*/) { // unlimited size, can't set for now return 0; } long SSL_CTX_get_session_cache_mode(SSL_CTX*) { // always 0, unlimited size for now return 0; } long SSL_CTX_set_tmp_dh(SSL_CTX* ctx, DH* dh) { if (ctx->SetDH(*dh)) return SSL_SUCCESS; else return SSL_FAILURE; } int SSL_CTX_use_certificate_file(SSL_CTX* ctx, const char* file, int format) { return read_file(ctx, file, format, Cert); } int SSL_CTX_use_PrivateKey_file(SSL_CTX* ctx, const char* file, int format) { return read_file(ctx, file, format, PrivateKey); } void SSL_CTX_set_verify(SSL_CTX* ctx, int mode, VerifyCallback /*vc*/) { if (mode & SSL_VERIFY_PEER) ctx->setVerifyPeer(); if (mode == SSL_VERIFY_NONE) ctx->setVerifyNone(); if (mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) ctx->setFailNoCert(); } int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, const char* path) { int ret = SSL_SUCCESS; const int HALF_PATH = 128; if (file) ret = read_file(ctx, file, SSL_FILETYPE_PEM, CA); if (ret == SSL_SUCCESS && path) { // call read_file for each reqular file in path #ifdef _WIN32 WIN32_FIND_DATA FindFileData; HANDLE hFind; char name[MAX_PATH + 1]; // directory specification strncpy(name, path, MAX_PATH - 3); strncat(name, "\\*", 3); hFind = FindFirstFile(name, &FindFileData); if (hFind == INVALID_HANDLE_VALUE) return SSL_BAD_PATH; do { if (FindFileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY) { strncpy(name, path, MAX_PATH - 2 - HALF_PATH); strncat(name, "\\", 2); strncat(name, FindFileData.cFileName, HALF_PATH); ret = read_file(ctx, name, SSL_FILETYPE_PEM, CA); } } while (ret == SSL_SUCCESS && FindNextFile(hFind, &FindFileData)); FindClose(hFind); #else // _WIN32 const int MAX_PATH = 260; DIR* dir = opendir(path); if (!dir) return SSL_BAD_PATH; struct dirent* entry; struct stat buf; char name[MAX_PATH + 1]; while (ret == SSL_SUCCESS && (entry = readdir(dir))) { strncpy(name, path, MAX_PATH - 1 - HALF_PATH); strncat(name, "/", 1); strncat(name, entry->d_name, HALF_PATH); if (stat(name, &buf) < 0) return SSL_BAD_STAT; if (S_ISREG(buf.st_mode)) ret = read_file(ctx, name, SSL_FILETYPE_PEM, CA); } closedir(dir); #endif } return ret; } int SSL_CTX_set_default_verify_paths(SSL_CTX* /*ctx*/) { // TODO: figure out way to set/store default path, then call load_verify return SSL_NOT_IMPLEMENTED; } int SSL_CTX_set_session_id_context(SSL_CTX*, const unsigned char*, unsigned int) { // No application specific context needed for yaSSL return SSL_SUCCESS; } int SSL_CTX_check_private_key(SSL_CTX* /*ctx*/) { // TODO: check private against public for RSA match return SSL_NOT_IMPLEMENTED; } // TODO: all session stats long SSL_CTX_sess_accept(SSL_CTX* ctx) { return ctx->GetStats().accept_; } long SSL_CTX_sess_connect(SSL_CTX* ctx) { return ctx->GetStats().connect_; } long SSL_CTX_sess_accept_good(SSL_CTX* ctx) { return ctx->GetStats().acceptGood_; } long SSL_CTX_sess_connect_good(SSL_CTX* ctx) { return ctx->GetStats().connectGood_; } long SSL_CTX_sess_accept_renegotiate(SSL_CTX* ctx) { return ctx->GetStats().acceptRenegotiate_; } long SSL_CTX_sess_connect_renegotiate(SSL_CTX* ctx) { return ctx->GetStats().connectRenegotiate_; } long SSL_CTX_sess_hits(SSL_CTX* ctx) { return ctx->GetStats().hits_; } long SSL_CTX_sess_cb_hits(SSL_CTX* ctx) { return ctx->GetStats().cbHits_; } long SSL_CTX_sess_cache_full(SSL_CTX* ctx) { return ctx->GetStats().cacheFull_; } long SSL_CTX_sess_misses(SSL_CTX* ctx) { return ctx->GetStats().misses_; } long SSL_CTX_sess_timeouts(SSL_CTX* ctx) { return ctx->GetStats().timeouts_; } long SSL_CTX_sess_number(SSL_CTX* ctx) { return ctx->GetStats().number_; } long SSL_CTX_sess_get_cache_size(SSL_CTX* ctx) { return ctx->GetStats().getCacheSize_; } // end session stats TODO: int SSL_CTX_get_verify_mode(SSL_CTX* ctx) { return ctx->GetStats().verifyMode_; } int SSL_get_verify_mode(SSL* ssl) { return ssl->getSecurity().GetContext()->GetStats().verifyMode_; } int SSL_CTX_get_verify_depth(SSL_CTX* ctx) { return ctx->GetStats().verifyDepth_; } int SSL_get_verify_depth(SSL* ssl) { return ssl->getSecurity().GetContext()->GetStats().verifyDepth_; } long SSL_CTX_set_options(SSL_CTX*, long) { // TDOD: return SSL_SUCCESS; } void SSL_CTX_set_info_callback(SSL_CTX*, void (*)()) { // TDOD: } void OpenSSL_add_all_algorithms() // compatibility only {} int SSL_library_init() // compatiblity only { return 1; } DH* DH_new(void) { DH* dh = NEW_YS DH; if (dh) dh->p = dh->g = 0; return dh; } void DH_free(DH* dh) { ysDelete(dh->g); ysDelete(dh->p); ysDelete(dh); } // convert positive big-endian num of length sz into retVal, which may need to // be created BIGNUM* BN_bin2bn(const unsigned char* num, int sz, BIGNUM* retVal) { using mySTL::auto_ptr; bool created = false; auto_ptr bn(ysDelete); if (!retVal) { created = true; bn.reset(NEW_YS BIGNUM); retVal = bn.get(); } retVal->assign(num, sz); if (created) return bn.release(); else return retVal; } unsigned long ERR_get_error_line_data(const char**, int*, const char**, int *) { //return SSL_NOT_IMPLEMENTED; return 0; } void ERR_print_errors_fp(FILE* /*fp*/) { // need ssl access to implement TODO: //fprintf(fp, "%s", ssl.get_states().errorString_.c_str()); } char* ERR_error_string(unsigned long errNumber, char* buffer) { static char* msg = "Please supply a buffer for error string"; if (buffer) { SetErrorString(YasslError(errNumber), buffer); return buffer; } return msg; } const char* X509_verify_cert_error_string(long /* error */) { // TODO: static const char* msg = "Not Implemented"; return msg; } const EVP_MD* EVP_md5(void) { return GetCryptProvider().NewMd5(); } const EVP_CIPHER* EVP_des_ede3_cbc(void) { return GetCryptProvider().NewDesEde(); } int EVP_BytesToKey(const EVP_CIPHER* type, const EVP_MD* md, const byte* salt, const byte* data, int sz, int count, byte* key, byte* iv) { EVP_MD* myMD = const_cast(md); uint digestSz = myMD->get_digestSize(); byte digest[SHA_LEN]; // max size int keyLen = type->get_keySize(); int ivLen = type->get_ivSize(); int keyLeft = keyLen; int ivLeft = ivLen; int keyOutput = 0; while (keyOutput < (keyLen + ivLen)) { int digestLeft = digestSz; // D_(i - 1) if (keyOutput) // first time D_0 is empty myMD->update(digest, digestSz); // data myMD->update(data, sz); // salt if (salt) myMD->update(salt, EVP_SALT_SZ); myMD->get_digest(digest); // count for (int j = 1; j < count; j++) { myMD->update(digest, digestSz); myMD->get_digest(digest); } if (keyLeft) { int store = min(keyLeft, static_cast(digestSz)); memcpy(&key[keyLen - keyLeft], digest, store); keyOutput += store; keyLeft -= store; digestLeft -= store; } if (ivLeft && digestLeft) { int store = min(ivLeft, digestLeft); memcpy(&iv[ivLen - ivLeft], digest, store); keyOutput += store; ivLeft -= store; } } assert(keyOutput == (keyLen + ivLen)); return keyOutput; } void DES_set_key_unchecked(const_DES_cblock* key, DES_key_schedule* schedule) { memcpy(schedule, key, sizeof(const_DES_cblock)); } void DES_ede3_cbc_encrypt(const byte* input, byte* output, long sz, DES_key_schedule* ks1, DES_key_schedule* ks2, DES_key_schedule* ks3, DES_cblock* ivec, int enc) { DES_EDE des; byte key[DES_EDE_KEY_SZ]; memcpy(key, *ks1, DES_BLOCK); memcpy(&key[DES_BLOCK], *ks2, DES_BLOCK); memcpy(&key[DES_BLOCK * 2], *ks3, DES_BLOCK); if (enc) { des.set_encryptKey(key, *ivec); des.encrypt(output, input, sz); } else { des.set_decryptKey(key, *ivec); des.decrypt(output, input, sz); } } // functions for libcurl int RAND_status() { return 1; /* TaoCrypt provides enough seed */ } int DES_set_key(const_DES_cblock* key, DES_key_schedule* schedule) { memcpy(schedule, key, sizeof(const_DES_cblock)); return 1; } void DES_set_odd_parity(DES_cblock* key) { // not needed now for TaoCrypt } void DES_ecb_encrypt(DES_cblock* input, DES_cblock* output, DES_key_schedule* key, int enc) { DES des; if (enc) { des.set_encryptKey(*key, 0); des.encrypt(*output, *input, DES_BLOCK); } else { des.set_decryptKey(*key, 0); des.decrypt(*output, *input, DES_BLOCK); } } void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX*, void* userdata) { // yaSSL doesn't support yet, unencrypt your PEM file with userdata // before handing off to yaSSL } X509* SSL_get_certificate(SSL* ssl) { // only used to pass to get_privatekey which isn't used return 0; } EVP_PKEY* SSL_get_privatekey(SSL* ssl) { // only called, not used return 0; } void SSL_SESSION_free(SSL_SESSION* session) { // managed by singleton } EVP_PKEY* X509_get_pubkey(X509* x) { // called, not used though return 0; } int EVP_PKEY_copy_parameters(EVP_PKEY* to, const EVP_PKEY* from) { // called, not used though return 0; } void EVP_PKEY_free(EVP_PKEY* pkey) { // never allocated from above } void ERR_error_string_n(unsigned long e, char *buf, size_t len) { if (len) ERR_error_string(e, buf); } void ERR_free_strings(void) { // handled internally } void EVP_cleanup(void) { // nothing to do yet } ASN1_TIME* X509_get_notBefore(X509* x) { if (x) return x->GetBefore(); return 0; } ASN1_TIME* X509_get_notAfter(X509* x) { if (x) return x->GetAfter(); return 0; } SSL_METHOD* SSLv23_client_method(void) /* doesn't actually roll back */ { return SSLv3_client_method(); } SSL_METHOD* SSLv2_client_method(void) /* will never work, no v 2 */ { return 0; } SSL_SESSION* SSL_get1_session(SSL* ssl) /* what's ref count */ { return SSL_get_session(ssl); } void GENERAL_NAMES_free(STACK_OF(GENERAL_NAME) *x) { // no extension names supported yet } int sk_GENERAL_NAME_num(STACK_OF(GENERAL_NAME) *x) { // no extension names supported yet return 0; } GENERAL_NAME* sk_GENERAL_NAME_value(STACK_OF(GENERAL_NAME) *x, int i) { // no extension names supported yet return 0; } unsigned char* ASN1_STRING_data(ASN1_STRING* x) { if (x) return x->data; return 0; } int ASN1_STRING_length(ASN1_STRING* x) { if (x) return x->length; return 0; } int ASN1_STRING_type(ASN1_STRING *x) { if (x) return x->type; return 0; } int X509_NAME_get_index_by_NID(X509_NAME* name,int nid, int lastpos) { int idx = -1; // not found const char* start = &name->GetName()[lastpos + 1]; switch (nid) { case NID_commonName: const char* found = strstr(start, "/CN="); if (found) { found += 4; // advance to str idx = found - start + lastpos + 1; } break; } return idx; } ASN1_STRING* X509_NAME_ENTRY_get_data(X509_NAME_ENTRY* ne) { // the same in yaSSL return ne; } X509_NAME_ENTRY* X509_NAME_get_entry(X509_NAME* name, int loc) { return name->GetEntry(loc); } // already formatted, caller responsible for freeing *out int ASN1_STRING_to_UTF8(unsigned char** out, ASN1_STRING* in) { if (!in) return 0; *out = (unsigned char*)malloc(in->length + 1); if (*out) { memcpy(*out, in->data, in->length); (*out)[in->length] = 0; } return in->length; } void* X509_get_ext_d2i(X509* x, int nid, int* crit, int* idx) { // no extensions supported yet return 0; } void MD4_Init(MD4_CTX* md4) { assert(0); // not yet supported, build compat. only } void MD4_Update(MD4_CTX* md4, const void* data, unsigned long sz) { } void MD4_Final(unsigned char* hash, MD4_CTX* md4) { } void MD5_Init(MD5_CTX* md5) { // make sure we have a big enough buffer typedef char ok[sizeof(md5->buffer) >= sizeof(TaoCrypt::MD5) ? 1 : -1]; (void) sizeof(ok); // using TaoCrypt since no dynamic memory allocated // and no destructor will be called new (reinterpret_cast(md5->buffer)) TaoCrypt::MD5(); } void MD5_Update(MD5_CTX* md5, const void* data, unsigned long sz) { reinterpret_cast(md5->buffer)->Update( static_cast(data), static_cast(sz)); } void MD5_Final(unsigned char* hash, MD5_CTX* md5) { reinterpret_cast(md5->buffer)->Final(hash); } // functions for stunnel void RAND_screen() { // TODO: } const char* RAND_file_name(char*, size_t) { // TODO: return 0; } int RAND_write_file(const char*) { // TODO: return 0; } int RAND_load_file(const char*, long) { // TODO: return 0; } void RSA_free(RSA*) { // TODO: } RSA* RSA_generate_key(int, unsigned long, void(*)(int, int, void*), void*) { // TODO: return 0; } int X509_LOOKUP_add_dir(X509_LOOKUP*, const char*, long) { // TODO: return SSL_SUCCESS; } int X509_LOOKUP_load_file(X509_LOOKUP*, const char*, long) { // TODO: return SSL_SUCCESS; } X509_LOOKUP_METHOD* X509_LOOKUP_hash_dir(void) { // TODO: return 0; } X509_LOOKUP_METHOD* X509_LOOKUP_file(void) { // TODO: return 0; } X509_LOOKUP* X509_STORE_add_lookup(X509_STORE*, X509_LOOKUP_METHOD*) { // TODO: return 0; } int X509_STORE_get_by_subject(X509_STORE_CTX*, int, X509_NAME*, X509_OBJECT*) { // TODO: return SSL_SUCCESS; } X509_STORE* X509_STORE_new(void) { // TODO: return 0; } char* SSL_alert_type_string_long(int) { // TODO: return 0; } char* SSL_alert_desc_string_long(int) { // TODO: return 0; } char* SSL_state_string_long(SSL*) { // TODO: return 0; } void SSL_CTX_set_tmp_rsa_callback(SSL_CTX*, RSA*(*)(SSL*, int, int)) { // TDOD: } long SSL_CTX_set_session_cache_mode(SSL_CTX*, long) { // TDOD: return SSL_SUCCESS; } long SSL_CTX_set_timeout(SSL_CTX*, long) { // TDOD: return SSL_SUCCESS; } int SSL_CTX_use_certificate_chain_file(SSL_CTX*, const char*) { // TDOD: return SSL_SUCCESS; } void SSL_CTX_set_default_passwd_cb(SSL_CTX*, pem_password_cb) { // TDOD: } int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX*, const char*, int) { // TDOD: return SSL_SUCCESS; } int SSL_set_rfd(SSL*, int) { return SSL_SUCCESS; // TODO: } int SSL_set_wfd(SSL*, int) { return SSL_SUCCESS; // TODO: } int SSL_pending(SSL*) { return SSL_SUCCESS; // TODO: } int SSL_want_read(SSL*) { return 0; // TODO: } int SSL_want_write(SSL*) { return 0; // TODO: } void SSL_set_shutdown(SSL*, int) { // TODO: } SSL_CIPHER* SSL_get_current_cipher(SSL*) { // TODO: return 0; } char* SSL_CIPHER_description(SSL_CIPHER*, char*, int) { // TODO: return 0; } int SSLeay_add_ssl_algorithms() // compatibility only { return 1; } void ERR_remove_state(unsigned long) { // TODO: } int ERR_GET_REASON(int l) { return l & 0xfff; } unsigned long ERR_peek_error() { return 0; // TODO: } unsigned long ERR_get_error() { return ERR_peek_error(); } // end stunnel needs } // extern "C" } // namespace