📄 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.
*
* 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 <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
#endif
namespace yaSSL {
using mySTL::min;
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<opaque*>(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 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;
}
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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -