📄 ssl.cpp
字号:
/* 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. * * There are special exceptions to the terms and conditions of the GPL as it * is applied to yaSSL. View the full text of the exception in the file * FLOSS-EXCEPTIONS in the directory of this software distribution. * * 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 "md4.hpp" // for TaoCrypt MD4 size assert#include "file.hpp" // for TaoCrypt Source#include "coding.hpp" // HexDecoder#include "helpers.hpp" // for placement new hack#include <stdio.h>#ifdef _WIN32 #include <windows.h> // FindFirstFile etc..#else #include <sys/types.h> // file helper #include <sys/stat.h> // stat #include <dirent.h> // opendir#endifnamespace yaSSL {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) { // may have a bunch of CAs x509* ptr; while ( (ptr = PemToDer(input, Cert)) ) ctx->AddCA(ptr); if (!feof(input)) { fclose(input); return SSL_BAD_FILE; } } 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 { EncryptedInfo info; x = PemToDer(input, type, &info); if (!x) { fclose(input); return SSL_BAD_FILE; } if (info.set) { // decrypt char password[80]; pem_password_cb cb = ctx->GetPasswordCb(); if (!cb) { fclose(input); return SSL_BAD_FILE; } int passwordSz = cb(password, sizeof(password), 0, ctx->GetUserData()); byte key[AES_256_KEY_SZ]; // max sizes byte iv[AES_IV_SZ]; // use file's salt for key derivation, but not real iv TaoCrypt::Source source(info.iv, info.ivSz); TaoCrypt::HexDecoder dec(source); memcpy(info.iv, source.get_buffer(), min((uint)sizeof(info.iv), source.size())); EVP_BytesToKey(info.name, "MD5", info.iv, (byte*)password, passwordSz, 1, key, iv); STL::auto_ptr<BulkCipher> cipher; if (strncmp(info.name, "DES-CBC", 7) == 0) cipher.reset(NEW_YS DES); else if (strncmp(info.name, "DES-EDE3-CBC", 13) == 0) cipher.reset(NEW_YS DES_EDE); else if (strncmp(info.name, "AES-128-CBC", 13) == 0) cipher.reset(NEW_YS AES(AES_128_KEY_SZ)); else if (strncmp(info.name, "AES-192-CBC", 13) == 0) cipher.reset(NEW_YS AES(AES_192_KEY_SZ)); else if (strncmp(info.name, "AES-256-CBC", 13) == 0) cipher.reset(NEW_YS AES(AES_256_KEY_SZ)); else { fclose(input); return SSL_BAD_FILE; } cipher->set_decryptKey(key, info.iv); STL::auto_ptr<x509> newx(NEW_YS x509(x->get_length())); cipher->decrypt(newx->use_buffer(), x->get_buffer(), x->get_length()); ysDelete(x); x = newx.release(); } } } 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* TLSv1_1_server_method(){ return NEW_YS SSL_METHOD(server_end, ProtocolVersion(3,2));}SSL_METHOD* TLSv1_1_client_method(){ return NEW_YS SSL_METHOD(client_end, ProtocolVersion(3,2));}SSL_METHOD* SSLv23_server_method(){ // compatibility only, no version 2 support, but does SSL 3 and TLS 1 return NEW_YS SSL_METHOD(server_end, ProtocolVersion(3,2), true);}SSL_METHOD* SSLv23_client_method(){ // compatibility only, no version 2 support, but does SSL 3 and TLS 1 // though it sends TLS1 hello not SSLv2 so SSLv3 only servers will decline // TODO: maybe add support to send SSLv2 hello ??? return NEW_YS SSL_METHOD(client_end, ProtocolVersion(3,2), true);}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){ if (ssl->GetError() == YasslError(SSL_ERROR_WANT_READ)) ssl->SetError(no_error); ClientState neededState; switch (ssl->getStates().GetConnect()) { case CONNECT_BEGIN : sendClientHello(*ssl); if (!ssl->GetError()) ssl->useStates().UseConnect() = CLIENT_HELLO_SENT; case CLIENT_HELLO_SENT : neededState = ssl->getSecurity().get_resuming() ? serverFinishedComplete : serverHelloDoneComplete; while (ssl->getStates().getClient() < neededState) { if (ssl->GetError()) break; processReply(*ssl); } if (!ssl->GetError()) ssl->useStates().UseConnect() = FIRST_REPLY_DONE; case FIRST_REPLY_DONE : 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->GetError()) ssl->useStates().UseConnect() = FINISHED_DONE; case FINISHED_DONE : if (!ssl->getSecurity().get_resuming()) while (ssl->getStates().getClient() < serverFinishedComplete) { if (ssl->GetError()) break; processReply(*ssl); } if (!ssl->GetError()) ssl->useStates().UseConnect() = SECOND_REPLY_DONE; case SECOND_REPLY_DONE : ssl->verifyState(serverFinishedComplete); ssl->useLog().ShowTCP(ssl->getSocket().get_fd()); if (ssl->GetError()) { GetErrors().Add(ssl->GetError()); return SSL_FATAL_ERROR; } return SSL_SUCCESS; default : return SSL_FATAL_ERROR; // unkown state }}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<opaque*>(buffer)); return receiveData(*ssl, data);}int SSL_accept(SSL* ssl){ if (ssl->GetError() == YasslError(SSL_ERROR_WANT_READ)) ssl->SetError(no_error); switch (ssl->getStates().GetAccept()) { case ACCEPT_BEGIN : processReply(*ssl); if (!ssl->GetError()) ssl->useStates().UseAccept() = ACCEPT_FIRST_REPLY_DONE; case ACCEPT_FIRST_REPLY_DONE : 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(); } if (!ssl->GetError()) ssl->useStates().UseAccept() = SERVER_HELLO_DONE; case SERVER_HELLO_DONE : if (!ssl->getSecurity().get_resuming()) { while (ssl->getStates().getServer() < clientFinishedComplete) { if (ssl->GetError()) break; processReply(*ssl); } } if (!ssl->GetError()) ssl->useStates().UseAccept() = ACCEPT_SECOND_REPLY_DONE; case ACCEPT_SECOND_REPLY_DONE : sendChangeCipher(*ssl); sendFinished(*ssl, server_end); ssl->flushBuffer(); if (!ssl->GetError()) ssl->useStates().UseAccept() = ACCEPT_FINISHED_DONE; case ACCEPT_FINISHED_DONE : if (ssl->getSecurity().get_resuming()) { while (ssl->getStates().getServer() < clientFinishedComplete) { if (ssl->GetError()) break; processReply(*ssl); } } if (!ssl->GetError()) ssl->useStates().UseAccept() = ACCEPT_THIRD_REPLY_DONE; case ACCEPT_THIRD_REPLY_DONE : ssl->useLog().ShowTCP(ssl->getSocket().get_fd()); if (ssl->GetError()) { GetErrors().Add(ssl->GetError()); return SSL_FATAL_ERROR; } return SSL_SUCCESS; default: return SSL_FATAL_ERROR; // unknown state }}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(); GetErrors().Remove(); return SSL_SUCCESS;}int SSL_shutdown(SSL* ssl){ Alert alert(warning, close_notify); sendAlert(*ssl, alert); ssl->useLog().ShowTCP(ssl->getSocket().get_fd(), true); GetErrors().Remove(); return SSL_SUCCESS;}/* on by default but allow user to turn off */long SSL_CTX_set_session_cache_mode(SSL_CTX* ctx, long mode){ if (mode == SSL_SESS_CACHE_OFF) ctx->SetSessionCacheOff(); return SSL_SUCCESS;}SSL_SESSION* SSL_get_session(SSL* ssl){ if (ssl->getSecurity().GetContext()->GetSessionCacheOff()) return 0; return GetSessions().lookup( ssl->getSecurity().get_connection().sessionID_);}int SSL_set_session(SSL* ssl, SSL_SESSION* session){ if (ssl->getSecurity().GetContext()->GetSessionCacheOff()) return SSL_FAILURE; 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 implementedchar* 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();}/* turn on yaSSL zlib compression returns 0 for success, else error (not built in) only need to turn on for client, becuase server on by default if built in but calling for server will tell you whether it's available or not*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -