mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-10-06 00:30:10 -06:00
Core: SSL support for Socket, finishing touches...
git-svn-id: svn://ultimatepp.org/upp/trunk@4785 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
8aace300c4
commit
eef7c20270
12 changed files with 474 additions and 392 deletions
|
|
@ -1,208 +1,208 @@
|
|||
#include "SSL.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
String SslBuffer::Get() const
|
||||
{
|
||||
if(IsEmpty())
|
||||
return String::GetVoid();
|
||||
return String(buf_mem->data, buf_mem->length);
|
||||
}
|
||||
|
||||
bool SslBuffer::Grow(int length)
|
||||
{
|
||||
return !IsEmpty() && BUF_MEM_grow(buf_mem, length);
|
||||
}
|
||||
|
||||
bool SslBuffer::Set(const String& d)
|
||||
{
|
||||
if(!buf_mem && !Create())
|
||||
return false;
|
||||
int len = d.GetLength();
|
||||
if((int)buf_mem->max < len && !Grow(len))
|
||||
return false;
|
||||
ASSERT((int)buf_mem->max >= len);
|
||||
buf_mem->length = len;
|
||||
memcpy(buf_mem, d, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SslStream::OpenBuffer(const char *data, int length)
|
||||
{
|
||||
return Set(BIO_new_mem_buf(const_cast<char *>(data), length));
|
||||
}
|
||||
|
||||
bool SslStream::CreateBuffer()
|
||||
{
|
||||
Clear();
|
||||
SslBuffer buf;
|
||||
if(!buf.Create() || !Create(BIO_s_mem()))
|
||||
return false;
|
||||
BIO_set_mem_buf(bio, buf.Detach(), BIO_CLOSE);
|
||||
return true;
|
||||
}
|
||||
|
||||
String SslStream::GetResult() const
|
||||
{
|
||||
if(IsEmpty())
|
||||
return String::GetVoid();
|
||||
BUF_MEM *bm = NULL;
|
||||
BIO_get_mem_ptr(bio, &bm);
|
||||
if(!bm)
|
||||
return String::GetVoid();
|
||||
return String(bm->data, bm->length);
|
||||
}
|
||||
|
||||
bool SslKey::Load(const String& data)
|
||||
{
|
||||
Clear();
|
||||
SslStream strm;
|
||||
if(!strm.OpenBuffer(data.Begin(), data.GetLength()))
|
||||
return false;
|
||||
return Set(PEM_read_bio_PrivateKey(strm, NULL, NULL, NULL));
|
||||
}
|
||||
|
||||
bool SslCertificate::Load(const String& data, bool asn1)
|
||||
{
|
||||
Clear();
|
||||
SslStream in, pem, *sio = ∈
|
||||
if(!in.OpenBuffer(data, data.GetLength()))
|
||||
return false;
|
||||
if(!asn1)
|
||||
{
|
||||
if(!pem.Create(BIO_f_base64()))
|
||||
return false;
|
||||
BIO_push(pem, in);
|
||||
sio = &pem;
|
||||
}
|
||||
return Set(d2i_X509_bio(*sio, NULL));
|
||||
}
|
||||
|
||||
String SslCertificate::Save(bool asn1) const
|
||||
{
|
||||
if(IsEmpty())
|
||||
return String::GetVoid();
|
||||
SslStream out, pem, *sio = &out;
|
||||
if(!out.CreateBuffer())
|
||||
return String::GetVoid();
|
||||
if(!asn1)
|
||||
{
|
||||
if(!pem.Create(BIO_f_base64()))
|
||||
return String::GetVoid();
|
||||
BIO_push(pem, out);
|
||||
sio = &pem;
|
||||
}
|
||||
i2d_X509_bio(*sio, cert);
|
||||
return out.GetResult();
|
||||
}
|
||||
|
||||
String SslCertificate::GetSubjectName() const
|
||||
{
|
||||
ASSERT(!IsEmpty());
|
||||
return SslToString(X509_get_subject_name(cert));
|
||||
}
|
||||
|
||||
String SslCertificate::GetIssuerName() const
|
||||
{
|
||||
ASSERT(!IsEmpty());
|
||||
return SslToString(X509_get_issuer_name(cert));
|
||||
}
|
||||
|
||||
Date SslCertificate::GetNotBefore() const
|
||||
{
|
||||
ASSERT(!IsEmpty());
|
||||
return ASN1ToDate(X509_get_notBefore(cert));
|
||||
}
|
||||
|
||||
Date SslCertificate::GetNotAfter() const
|
||||
{
|
||||
ASSERT(!IsEmpty());
|
||||
return ASN1ToDate(X509_get_notAfter(cert));
|
||||
}
|
||||
|
||||
int SslCertificate::GetVersion() const
|
||||
{
|
||||
ASSERT(!IsEmpty());
|
||||
return X509_get_version(cert);
|
||||
}
|
||||
|
||||
String SslCertificate::GetSerialNumber() const
|
||||
{
|
||||
ASSERT(!IsEmpty());
|
||||
return ASN1ToString(X509_get_serialNumber(cert));
|
||||
}
|
||||
|
||||
SslContext::SslContext(SSL_CTX *c)
|
||||
: ssl_ctx(c)
|
||||
{
|
||||
SslInitThread();
|
||||
}
|
||||
|
||||
bool SslContext::CipherList(const char *list)
|
||||
{
|
||||
ASSERT(ssl_ctx);
|
||||
return SSL_CTX_set_cipher_list(ssl_ctx, list);
|
||||
}
|
||||
|
||||
bool SslContext::UseCertificate(String certdata, String pkeydata, bool cert_asn1)
|
||||
{
|
||||
ASSERT(ssl_ctx);
|
||||
if(IsNull(certdata) || IsNull(pkeydata))
|
||||
return false;
|
||||
SslCertificate cert;
|
||||
SslKey pkey;
|
||||
if(!cert.Load(certdata, cert_asn1) || !pkey.Load(pkeydata))
|
||||
return false;
|
||||
if(!SSL_CTX_use_certificate(ssl_ctx, cert) || !SSL_CTX_use_PrivateKey(ssl_ctx, pkey))
|
||||
return false;
|
||||
if(!SSL_CTX_check_private_key(ssl_ctx))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SslContext::VerifyPeer(bool verify, int depth)
|
||||
{
|
||||
ASSERT(ssl_ctx);
|
||||
SSL_CTX_set_verify(ssl_ctx, verify ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
|
||||
SSL_CTX_set_verify_depth(ssl_ctx, depth);
|
||||
}
|
||||
|
||||
String SslGetLastError(int& code)
|
||||
{
|
||||
char errbuf[150];
|
||||
ERR_error_string(code = ERR_get_error(), errbuf);
|
||||
return errbuf;
|
||||
}
|
||||
|
||||
String SslGetLastError()
|
||||
{
|
||||
int dummy;
|
||||
return SslGetLastError(dummy);
|
||||
}
|
||||
|
||||
String SslToString(X509_NAME *name)
|
||||
{
|
||||
char buffer[500];
|
||||
return X509_NAME_oneline(name, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
Date ASN1ToDate(ASN1_STRING *time)
|
||||
{
|
||||
if(!time) return Null;
|
||||
int digit = 0;
|
||||
while(digit < time->length && IsDigit(time->data[digit]))
|
||||
digit++;
|
||||
if(digit < 6)
|
||||
return Null;
|
||||
int year2 = time->data[0] * 10 + time->data[1] - 11 * '0';
|
||||
int month = time->data[2] * 10 + time->data[3] - 11 * '0';
|
||||
int day = time->data[4] * 10 + time->data[5] - 11 * '0';
|
||||
return Date(year2 + (year2 < 90 ? 2000 : 1900), month, day);
|
||||
}
|
||||
|
||||
String ASN1ToString(ASN1_STRING *s)
|
||||
{
|
||||
return String(s->data, s->length);
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
#include "SSL.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
String SslBuffer::Get() const
|
||||
{
|
||||
if(IsEmpty())
|
||||
return String::GetVoid();
|
||||
return String(buf_mem->data, buf_mem->length);
|
||||
}
|
||||
|
||||
bool SslBuffer::Grow(int length)
|
||||
{
|
||||
return !IsEmpty() && BUF_MEM_grow(buf_mem, length);
|
||||
}
|
||||
|
||||
bool SslBuffer::Set(const String& d)
|
||||
{
|
||||
if(!buf_mem && !Create())
|
||||
return false;
|
||||
int len = d.GetLength();
|
||||
if((int)buf_mem->max < len && !Grow(len))
|
||||
return false;
|
||||
ASSERT((int)buf_mem->max >= len);
|
||||
buf_mem->length = len;
|
||||
memcpy(buf_mem, d, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SslStream::OpenBuffer(const char *data, int length)
|
||||
{
|
||||
return Set(BIO_new_mem_buf(const_cast<char *>(data), length));
|
||||
}
|
||||
|
||||
bool SslStream::CreateBuffer()
|
||||
{
|
||||
Clear();
|
||||
SslBuffer buf;
|
||||
if(!buf.Create() || !Create(BIO_s_mem()))
|
||||
return false;
|
||||
BIO_set_mem_buf(bio, buf.Detach(), BIO_CLOSE);
|
||||
return true;
|
||||
}
|
||||
|
||||
String SslStream::GetResult() const
|
||||
{
|
||||
if(IsEmpty())
|
||||
return String::GetVoid();
|
||||
BUF_MEM *bm = NULL;
|
||||
BIO_get_mem_ptr(bio, &bm);
|
||||
if(!bm)
|
||||
return String::GetVoid();
|
||||
return String(bm->data, bm->length);
|
||||
}
|
||||
|
||||
bool SslKey::Load(const String& data)
|
||||
{
|
||||
Clear();
|
||||
SslStream strm;
|
||||
if(!strm.OpenBuffer(data.Begin(), data.GetLength()))
|
||||
return false;
|
||||
return Set(PEM_read_bio_PrivateKey(strm, NULL, NULL, NULL));
|
||||
}
|
||||
|
||||
bool SslCertificate::Load(const String& data, bool asn1)
|
||||
{
|
||||
Clear();
|
||||
SslStream in, pem, *sio = ∈
|
||||
if(!in.OpenBuffer(data, data.GetLength()))
|
||||
return false;
|
||||
if(!asn1)
|
||||
{
|
||||
if(!pem.Create(BIO_f_base64()))
|
||||
return false;
|
||||
BIO_push(pem, in);
|
||||
sio = &pem;
|
||||
}
|
||||
return Set(d2i_X509_bio(*sio, NULL));
|
||||
}
|
||||
|
||||
String SslCertificate::Save(bool asn1) const
|
||||
{
|
||||
if(IsEmpty())
|
||||
return String::GetVoid();
|
||||
SslStream out, pem, *sio = &out;
|
||||
if(!out.CreateBuffer())
|
||||
return String::GetVoid();
|
||||
if(!asn1)
|
||||
{
|
||||
if(!pem.Create(BIO_f_base64()))
|
||||
return String::GetVoid();
|
||||
BIO_push(pem, out);
|
||||
sio = &pem;
|
||||
}
|
||||
i2d_X509_bio(*sio, cert);
|
||||
return out.GetResult();
|
||||
}
|
||||
|
||||
String SslCertificate::GetSubjectName() const
|
||||
{
|
||||
ASSERT(!IsEmpty());
|
||||
return SslToString(X509_get_subject_name(cert));
|
||||
}
|
||||
|
||||
String SslCertificate::GetIssuerName() const
|
||||
{
|
||||
ASSERT(!IsEmpty());
|
||||
return SslToString(X509_get_issuer_name(cert));
|
||||
}
|
||||
|
||||
Date SslCertificate::GetNotBefore() const
|
||||
{
|
||||
ASSERT(!IsEmpty());
|
||||
return Asn1ToDate(X509_get_notBefore(cert));
|
||||
}
|
||||
|
||||
Date SslCertificate::GetNotAfter() const
|
||||
{
|
||||
ASSERT(!IsEmpty());
|
||||
return Asn1ToDate(X509_get_notAfter(cert));
|
||||
}
|
||||
|
||||
int SslCertificate::GetVersion() const
|
||||
{
|
||||
ASSERT(!IsEmpty());
|
||||
return X509_get_version(cert);
|
||||
}
|
||||
|
||||
String SslCertificate::GetSerialNumber() const
|
||||
{
|
||||
ASSERT(!IsEmpty());
|
||||
return Asn1ToString(X509_get_serialNumber(cert));
|
||||
}
|
||||
|
||||
SslContext::SslContext(SSL_CTX *c)
|
||||
: ssl_ctx(c)
|
||||
{
|
||||
SslInitThread();
|
||||
}
|
||||
|
||||
bool SslContext::CipherList(const char *list)
|
||||
{
|
||||
ASSERT(ssl_ctx);
|
||||
return SSL_CTX_set_cipher_list(ssl_ctx, list);
|
||||
}
|
||||
|
||||
bool SslContext::UseCertificate(String certdata, String pkeydata, bool cert_asn1)
|
||||
{
|
||||
ASSERT(ssl_ctx);
|
||||
if(IsNull(certdata) || IsNull(pkeydata))
|
||||
return false;
|
||||
SslCertificate cert;
|
||||
SslKey pkey;
|
||||
if(!cert.Load(certdata, cert_asn1) || !pkey.Load(pkeydata))
|
||||
return false;
|
||||
if(!SSL_CTX_use_certificate(ssl_ctx, cert) || !SSL_CTX_use_PrivateKey(ssl_ctx, pkey))
|
||||
return false;
|
||||
if(!SSL_CTX_check_private_key(ssl_ctx))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SslContext::VerifyPeer(bool verify, int depth)
|
||||
{
|
||||
ASSERT(ssl_ctx);
|
||||
SSL_CTX_set_verify(ssl_ctx, verify ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
|
||||
SSL_CTX_set_verify_depth(ssl_ctx, depth);
|
||||
}
|
||||
|
||||
String SslGetLastError(int& code)
|
||||
{
|
||||
char errbuf[150];
|
||||
ERR_error_string(code = ERR_get_error(), errbuf);
|
||||
return errbuf;
|
||||
}
|
||||
|
||||
String SslGetLastError()
|
||||
{
|
||||
int dummy;
|
||||
return SslGetLastError(dummy);
|
||||
}
|
||||
|
||||
String SslToString(X509_NAME *name)
|
||||
{
|
||||
char buffer[500];
|
||||
return X509_NAME_oneline(name, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
Date Asn1ToDate(ASN1_STRING *time)
|
||||
{
|
||||
if(!time) return Null;
|
||||
int digit = 0;
|
||||
while(digit < time->length && IsDigit(time->data[digit]))
|
||||
digit++;
|
||||
if(digit < 6)
|
||||
return Null;
|
||||
int year2 = time->data[0] * 10 + time->data[1] - 11 * '0';
|
||||
int month = time->data[2] * 10 + time->data[3] - 11 * '0';
|
||||
int day = time->data[4] * 10 + time->data[5] - 11 * '0';
|
||||
return Date(year2 + (year2 < 90 ? 2000 : 1900), month, day);
|
||||
}
|
||||
|
||||
String Asn1ToString(ASN1_STRING *s)
|
||||
{
|
||||
return String(s->data, s->length);
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
|
|||
Loading…
Reference in a new issue