ssl.cpp

来自「MySQL源码文件5.X系列, 可自已编译到服务器」· C++ 代码 · 共 1,633 行 · 第 1/3 页

CPP
1,633
字号
/*   Copyright (C) 2000-2007 MySQL AB   This program 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; version 2 of the License.   This program 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; see the file COPYING. If not, write to the   Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,   MA  02110-1301  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);                mySTL::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);                mySTL::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){    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*/int SSL_set_compression(SSL* ssl){    return ssl->SetCompression();}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?