📄 pssl.cxx
字号:
}
///////////////////////////////////////////////////////////////////////////////
PSSLCertificate::PSSLCertificate()
{
certificate = NULL;
}
PSSLCertificate::PSSLCertificate(const PFilePath & certFile, PSSLFileTypes fileType)
{
certificate = NULL;
Load(certFile, fileType);
}
PSSLCertificate::PSSLCertificate(const BYTE * certData, PINDEX certSize)
{
#if P_SSL_USE_CONST
certificate = d2i_X509(NULL, &certData, certSize);
#else
certificate = d2i_X509(NULL, (unsigned char **)&certData, certSize);
#endif
}
PSSLCertificate::PSSLCertificate(const PBYTEArray & certData)
{
const BYTE * certPtr = certData;
#if P_SSL_USE_CONST
certificate = d2i_X509(NULL, &certPtr, certData.GetSize());
#else
certificate = d2i_X509(NULL, (unsigned char **)&certPtr, certData.GetSize());
#endif
}
PSSLCertificate::PSSLCertificate(const PString & certStr)
{
PBYTEArray certData;
PBase64::Decode(certStr, certData);
if (certData.GetSize() > 0) {
const BYTE * certPtr = certData;
#if P_SSL_USE_CONST
certificate = d2i_X509(NULL, &certPtr, certData.GetSize());
#else
certificate = d2i_X509(NULL, (unsigned char **)&certPtr, certData.GetSize());
#endif
}
else
certificate = NULL;
}
PSSLCertificate::PSSLCertificate(const PSSLCertificate & cert)
{
if (cert.certificate == NULL)
certificate = NULL;
else
certificate = X509_dup(cert.certificate);
}
PSSLCertificate & PSSLCertificate::operator=(const PSSLCertificate & cert)
{
if (certificate != NULL)
X509_free(certificate);
if (cert.certificate == NULL)
certificate = NULL;
else
certificate = X509_dup(cert.certificate);
return *this;
}
PSSLCertificate::~PSSLCertificate()
{
if (certificate != NULL)
X509_free(certificate);
}
BOOL PSSLCertificate::CreateRoot(const PString & subject,
const PSSLPrivateKey & privateKey)
{
if (certificate != NULL) {
X509_free(certificate);
certificate = NULL;
}
if (privateKey == NULL)
return FALSE;
POrdinalToString info;
PStringArray fields = subject.Tokenise('/', FALSE);
PINDEX i;
for (i = 0; i < fields.GetSize(); i++) {
PString field = fields[i];
PINDEX equals = field.Find('=');
if (equals != P_MAX_INDEX) {
int nid = OBJ_txt2nid((char *)(const char *)field.Left(equals));
if (nid != NID_undef)
info.SetAt(nid, field.Mid(equals+1));
}
}
if (info.IsEmpty())
return FALSE;
certificate = X509_new();
if (certificate == NULL)
return FALSE;
if (X509_set_version(certificate, 2)) {
/* Set version to V3 */
ASN1_INTEGER_set(X509_get_serialNumber(certificate), 0L);
X509_NAME * name = X509_NAME_new();
for (i = 0; i < info.GetSize(); i++)
X509_NAME_add_entry_by_NID(name,
info.GetKeyAt(i),
MBSTRING_ASC,
(unsigned char *)(const char *)info.GetDataAt(i),
-1,-1, 0);
X509_set_issuer_name(certificate, name);
X509_set_subject_name(certificate, name);
X509_NAME_free(name);
X509_gmtime_adj(X509_get_notBefore(certificate), 0);
X509_gmtime_adj(X509_get_notAfter(certificate), (long)60*60*24*365*5);
X509_PUBKEY * pubkey = X509_PUBKEY_new();
if (pubkey != NULL) {
X509_PUBKEY_set(&pubkey, privateKey);
EVP_PKEY * pkey = X509_PUBKEY_get(pubkey);
X509_set_pubkey(certificate, pkey);
EVP_PKEY_free(pkey);
X509_PUBKEY_free(pubkey);
if (X509_sign(certificate, privateKey, EVP_md5()) > 0)
return TRUE;
}
}
X509_free(certificate);
certificate = NULL;
return FALSE;
}
PBYTEArray PSSLCertificate::GetData() const
{
PBYTEArray data;
if (certificate != NULL) {
BYTE * certPtr = data.GetPointer(i2d_X509(certificate, NULL));
i2d_X509(certificate, &certPtr);
}
return data;
}
PString PSSLCertificate::AsString() const
{
return PBase64::Encode(GetData());
}
BOOL PSSLCertificate::Load(const PFilePath & certFile, PSSLFileTypes fileType)
{
if (certificate != NULL) {
X509_free(certificate);
certificate = NULL;
}
PSSL_BIO in;
if (!in.OpenRead(certFile)) {
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,ERR_R_SYS_LIB);
return FALSE;
}
if (fileType == PSSLFileTypeDEFAULT)
fileType = certFile.GetType() == ".pem" ? PSSLFileTypePEM : PSSLFileTypeASN1;
switch (fileType) {
case PSSLFileTypeASN1 :
certificate = d2i_X509_bio(in, NULL);
if (certificate != NULL)
return TRUE;
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_ASN1_LIB);
break;
case PSSLFileTypePEM :
certificate = PEM_read_bio_X509(in, NULL, NULL, NULL);
if (certificate != NULL)
return TRUE;
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PEM_LIB);
break;
default :
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,SSL_R_BAD_SSL_FILETYPE);
}
return FALSE;
}
BOOL PSSLCertificate::Save(const PFilePath & certFile, BOOL append, PSSLFileTypes fileType)
{
if (certificate == NULL)
return FALSE;
PSSL_BIO out;
if (!(append ? out.OpenAppend(certFile) : out.OpenWrite(certFile))) {
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,ERR_R_SYS_LIB);
return FALSE;
}
if (fileType == PSSLFileTypeDEFAULT)
fileType = certFile.GetType() == ".pem" ? PSSLFileTypePEM : PSSLFileTypeASN1;
switch (fileType) {
case PSSLFileTypeASN1 :
if (i2d_X509_bio(out, certificate))
return TRUE;
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_ASN1_LIB);
break;
case PSSLFileTypePEM :
if (PEM_write_bio_X509(out, certificate))
return TRUE;
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PEM_LIB);
break;
default :
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,SSL_R_BAD_SSL_FILETYPE);
}
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
PSSLDiffieHellman::PSSLDiffieHellman()
{
dh = NULL;
}
PSSLDiffieHellman::PSSLDiffieHellman(const PFilePath & dhFile,
PSSLFileTypes fileType)
{
dh = NULL;
Load(dhFile, fileType);
}
PSSLDiffieHellman::PSSLDiffieHellman(const BYTE * pData, PINDEX pSize,
const BYTE * gData, PINDEX gSize)
{
dh = DH_new();
if (dh == NULL)
return;
dh->p = BN_bin2bn(pData, pSize, NULL);
dh->g = BN_bin2bn(gData, gSize, NULL);
if (dh->p != NULL && dh->g != NULL)
return;
DH_free(dh);
dh = NULL;
}
PSSLDiffieHellman::PSSLDiffieHellman(const PSSLDiffieHellman & diffie)
{
dh = diffie.dh;
}
PSSLDiffieHellman & PSSLDiffieHellman::operator=(const PSSLDiffieHellman & diffie)
{
if (dh != NULL)
DH_free(dh);
dh = diffie.dh;
return *this;
}
PSSLDiffieHellman::~PSSLDiffieHellman()
{
if (dh != NULL)
DH_free(dh);
}
#if defined(__BEOS__) || defined(__APPLE__)
// 2/21/04 Yuri Kiryanov - fix for compiler choke on BeOS for usage of
// SSL function d2i_DHparams_bio below in PSSLDiffieHellman::Load
// 5/26/06 Hannes Friederich - Mac OS X seems to need that fix too...
#undef d2i_DHparams_bio
#define d2i_DHparams_bio(bp,x) \
(DH *)ASN1_d2i_bio( \
(char *(*)(...))(void *)DH_new, \
(char *(*)(...))(void *)d2i_DHparams, \
(bp), \
(unsigned char **)(x) \
)
#endif
BOOL PSSLDiffieHellman::Load(const PFilePath & dhFile,
PSSLFileTypes fileType)
{
if (dh != NULL) {
DH_free(dh);
dh = NULL;
}
PSSL_BIO in;
if (!in.OpenRead(dhFile)) {
SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE,ERR_R_SYS_LIB);
return FALSE;
}
if (fileType == PSSLFileTypeDEFAULT)
fileType = dhFile.GetType() == ".pem" ? PSSLFileTypePEM : PSSLFileTypeASN1;
switch (fileType) {
case PSSLFileTypeASN1 :
dh = d2i_DHparams_bio(in, NULL);
if (dh != NULL)
return TRUE;
SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_ASN1_LIB);
break;
case PSSLFileTypePEM :
dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL);
if (dh != NULL)
return TRUE;
SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_PEM_LIB);
break;
default :
SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE,SSL_R_BAD_SSL_FILETYPE);
}
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
static void LockingCallback(int mode, int n, const char * /*file*/, int /*line*/)
{
static PSSLMutexArray mutexes;
if ((mode & CRYPTO_LOCK) != 0)
mutexes[n].Wait();
else
mutexes[n].Signal();
}
static int VerifyCallBack(int ok, X509_STORE_CTX * ctx)
{
X509 * err_cert = X509_STORE_CTX_get_current_cert(ctx);
//int err = X509_STORE_CTX_get_error(ctx);
// get the subject name, just for verification
char buf[256];
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
PTRACE(1, "SSL\tVerify callback depth "
<< X509_STORE_CTX_get_error_depth(ctx)
<< " : cert name = " << buf);
return ok;
}
static void PSSLAssert(const char * msg)
{
char buf[256];
strcpy(buf, msg);
ERR_error_string(ERR_peek_error(), &buf[strlen(msg)]);
PTRACE(1, "SSL\t" << buf);
PAssertAlways(buf);
}
PSSLContext::PSSLContext(const void * sessionId, PINDEX idSize)
{
static PMutex InitialisationMutex;
InitialisationMutex.Wait();
static BOOL needInitialisation = TRUE;
if (needInitialisation) {
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
// Seed the random number generator
BYTE seed[128];
for (size_t i = 0; i < sizeof(seed); i++)
seed[i] = (BYTE)rand();
RAND_seed(seed, sizeof(seed));
// set up multithread stuff
CRYPTO_set_locking_callback(LockingCallback);
needInitialisation = FALSE;
}
InitialisationMutex.Signal();
// create the new SSL context
SSL_METHOD * meth = SSLv23_method();
context = SSL_CTX_new(meth);
if (context == NULL)
PSSLAssert("Error creating context: ");
// Shutdown
SSL_CTX_set_quiet_shutdown(context, 1);
// Set default locations
if (!SSL_CTX_load_verify_locations(context, NULL, ".") ||
!SSL_CTX_set_default_verify_paths(context))
PSSLAssert("Cannot set CAfile and path: ");
if (sessionId != NULL) {
if (idSize == 0)
idSize = ::strlen((const char *)sessionId)+1;
SSL_CTX_set_session_id_context(context, (const BYTE *)sessionId, idSize);
SSL_CTX_sess_set_cache_size(context, 128);
}
// set default verify mode
SSL_CTX_set_verify(context, SSL_VERIFY_NONE, VerifyCallBack);
}
PSSLContext::~PSSLContext()
{
SSL_CTX_free(context);
}
BOOL PSSLContext::SetCAPath(const PDirectory & caPath)
{
PString path = caPath.Left(caPath.GetLength()-1);
if (!SSL_CTX_load_verify_locations(context, NULL, path))
return FALSE;
return SSL_CTX_set_default_verify_paths(context);
}
BOOL PSSLContext::SetCAFile(const PFilePath & caFile)
{
if (!SSL_CTX_load_verify_locations(context, caFile, NULL))
return FALSE;
return SSL_CTX_set_default_verify_paths(context);
}
BOOL PSSLContext::UseCertificate(const PSSLCertificate & certificate)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -