#At file:///Users/kgeorge/mysql/work/B57648-ossl-trunk/ based on revid:marc.alff@stripped
3749 Georgi Kodinov 2011-03-28
Bug #11764778: server feature request - expose ssl certificate details
in show global st
There was no easy way to get the expiration dates of the server's
certificate.
Implemented two session status variables (Ssl_server_not_before and
Ssl_server_not_after) with the same scope as e.g. Ssl_verify_depth to
return the two dates in a format similar to OpenSSL's ASN1_TIME_print.
Since yaSSL doesn't preserve the parsed server certificate beyond
reading it, the diff extends yaSSL to preserve it and return it
through SSL_get_certificate(). Also fixed the storage of the
certificate expiration dates to have the ASN1_TIME subtype.
Implemented an yaSSL specific extension function
yaSSL_ASN1_TIME_to_string() to return the string representation of the
date in an ASN1_TIME in a format similar to OpenSSL's format.
Created a wrapper in MySQL to call either ASN1_TIME_print() or
yaSSL_ASN1_TIME_to_string() depending on the library type.
Did some type cleanups of some of the internal yaSSL functions.
Test case added.
modified:
extra/yassl/include/cert_wrapper.hpp
extra/yassl/include/openssl/prefix_ssl.h
extra/yassl/include/openssl/ssl.h
extra/yassl/include/yassl_int.hpp
extra/yassl/src/cert_wrapper.cpp
extra/yassl/src/ssl.cpp
extra/yassl/src/yassl_int.cpp
extra/yassl/taocrypt/include/asn.hpp
extra/yassl/taocrypt/src/asn.cpp
mysql-test/r/ssl.result
mysql-test/t/ssl.test
sql/mysqld.cc
=== modified file 'extra/yassl/include/cert_wrapper.hpp'
--- a/extra/yassl/include/cert_wrapper.hpp 2008-11-18 16:45:44 +0000
+++ b/extra/yassl/include/cert_wrapper.hpp 2011-03-28 12:29:22 +0000
@@ -78,6 +78,7 @@ class CertManager {
CertList peerList_; // peer
input_buffer peerPublicKey_;
X509* peerX509_; // peer's openSSL X509
+ X509* selfX509_; // our own openSSL X509
SignatureAlgorithm keyType_; // self key type
SignatureAlgorithm peerKeyType_; // peer's key type
@@ -104,6 +105,7 @@ public:
const opaque* get_peerKey() const;
const opaque* get_privateKey() const;
X509* get_peerX509() const;
+ X509* get_selfX509() const;
SignatureAlgorithm get_keyType() const;
SignatureAlgorithm get_peerKeyType() const;
=== modified file 'extra/yassl/include/openssl/prefix_ssl.h'
--- a/extra/yassl/include/openssl/prefix_ssl.h 2010-12-28 23:47:05 +0000
+++ b/extra/yassl/include/openssl/prefix_ssl.h 2011-03-28 12:29:22 +0000
@@ -178,6 +178,7 @@
#define SSL_get1_session yaSSL_get1_session
#define X509_get_notBefore yaX509_get_notBefore
#define X509_get_notAfter yaX509_get_notAfter
+#define yaSSL_ASN1_TIME_to_string ya_SSL_ASN1_TIME_to_string
#define MD4_Init yaMD4_Init
#define MD4_Update yaMD4_Update
#define MD4_Final yaMD4_Final
=== modified file 'extra/yassl/include/openssl/ssl.h'
--- a/extra/yassl/include/openssl/ssl.h 2008-12-08 17:45:48 +0000
+++ b/extra/yassl/include/openssl/ssl.h 2011-03-28 12:29:22 +0000
@@ -541,6 +541,8 @@ void MD5_Final(unsigned char*, MD5_CTX*)
/* yaSSL adds */
int SSL_set_compression(SSL*); /* turn on yaSSL zlib compression */
+char *yaSSL_ASN1_TIME_to_string(ASN1_TIME *time, char *buf, size_t len);
+
=== modified file 'extra/yassl/include/yassl_int.hpp'
--- a/extra/yassl/include/yassl_int.hpp 2010-07-15 11:13:30 +0000
+++ b/extra/yassl/include/yassl_int.hpp 2011-03-28 12:29:22 +0000
@@ -187,7 +187,7 @@ private:
class StringHolder {
ASN1_STRING asnString_;
public:
- StringHolder(const char* str, int sz);
+ StringHolder(const char* str, int sz, byte type= 0);
~StringHolder();
ASN1_STRING* GetString();
@@ -205,7 +205,7 @@ class X509 {
StringHolder afterDate_; // not valid after
public:
X509(const char* i, size_t, const char* s, size_t,
- const char* b, int, const char* a, int);
+ ASN1_STRING *b, ASN1_STRING *a);
~X509() {}
X509_NAME* GetIssuer();
=== modified file 'extra/yassl/src/cert_wrapper.cpp'
--- a/extra/yassl/src/cert_wrapper.cpp 2009-02-13 16:41:47 +0000
+++ b/extra/yassl/src/cert_wrapper.cpp 2011-03-28 12:29:22 +0000
@@ -90,7 +90,7 @@ opaque* x509::use_buffer()
//CertManager
CertManager::CertManager()
- : peerX509_(0), verifyPeer_(false), verifyNone_(false), failNoCert_(false),
+ : peerX509_(0), selfX509_(0), verifyPeer_(false), verifyNone_(false), failNoCert_(false),
sendVerify_(false), verifyCallback_(0)
{}
@@ -98,6 +98,7 @@ CertManager::CertManager()
CertManager::~CertManager()
{
ysDelete(peerX509_);
+ ysDelete(selfX509_);
STL::for_each(signers_.begin(), signers_.end(), del_ptr_zero()) ;
@@ -209,6 +210,12 @@ X509* CertManager::get_peerX509() const
}
+X509* CertManager::get_selfX509() const
+{
+ return selfX509_;
+}
+
+
SignatureAlgorithm CertManager::get_peerKeyType() const
{
return peerKeyType_;
@@ -279,11 +286,15 @@ int CertManager::Validate()
size_t iSz = strlen(cert.GetIssuer()) + 1;
size_t sSz = strlen(cert.GetCommonName()) + 1;
- int bSz = (int)strlen(cert.GetBeforeDate()) + 1;
- int aSz = (int)strlen(cert.GetAfterDate()) + 1;
+ ASN1_STRING beforeDate, afterDate;
+ beforeDate.data= (unsigned char *) cert.GetBeforeDate();
+ beforeDate.type= cert.GetBeforeDateType();
+ beforeDate.length= strlen((char *) beforeDate.data) + 1;
+ afterDate.data= (unsigned char *) cert.GetAfterDate();
+ afterDate.type= cert.GetAfterDateType();
+ afterDate.length= strlen((char *) afterDate.data) + 1;
peerX509_ = NEW_YS X509(cert.GetIssuer(), iSz, cert.GetCommonName(),
- sSz, cert.GetBeforeDate(), bSz,
- cert.GetAfterDate(), aSz);
+ sSz, &beforeDate, &afterDate);
if (err == TaoCrypt::SIG_OTHER_E && verifyCallback_) {
X509_STORE_CTX store;
@@ -318,6 +329,18 @@ int CertManager::SetPrivateKey(const x50
keyType_ = rsa_sa_algo;
else
keyType_ = dsa_sa_algo;
+
+ size_t iSz = strlen(cd.GetIssuer()) + 1;
+ size_t sSz = strlen(cd.GetCommonName()) + 1;
+ ASN1_STRING beforeDate, afterDate;
+ beforeDate.data= (unsigned char *) cd.GetBeforeDate();
+ beforeDate.type= cd.GetBeforeDateType();
+ beforeDate.length= strlen((char *) beforeDate.data) + 1;
+ afterDate.data= (unsigned char *) cd.GetAfterDate();
+ afterDate.type= cd.GetAfterDateType();
+ afterDate.length= strlen((char *) afterDate.data) + 1;
+ selfX509_ = NEW_YS X509(cd.GetIssuer(), iSz, cd.GetCommonName(),
+ sSz, &beforeDate, &afterDate);
}
return 0;
}
@@ -335,8 +358,7 @@ void CertManager::setPeerX509(X509* x)
ASN1_STRING* after = x->GetAfter();
peerX509_ = NEW_YS X509(issuer->GetName(), issuer->GetLength(),
- subject->GetName(), subject->GetLength(), (const char*) before->data,
- before->length, (const char*) after->data, after->length);
+ subject->GetName(), subject->GetLength(), before, after);
}
=== modified file 'extra/yassl/src/ssl.cpp'
--- a/extra/yassl/src/ssl.cpp 2010-02-22 13:23:47 +0000
+++ b/extra/yassl/src/ssl.cpp 2011-03-28 12:29:22 +0000
@@ -1174,8 +1174,7 @@ void SSL_CTX_set_default_passwd_cb_userd
X509* SSL_get_certificate(SSL* ssl)
{
- // only used to pass to get_privatekey which isn't used
- return 0;
+ return ssl->getCrypto().get_certManager().get_selfX509();
}
@@ -1667,6 +1666,25 @@ unsigned long ERR_get_error()
// end stunnel needs
+ char *yaSSL_ASN1_TIME_to_string(ASN1_TIME *time, char *buf, size_t len)
+ {
+ tm t;
+ static const char *month_names[12]=
+ {
+ "Jan","Feb","Mar","Apr","May","Jun",
+ "Jul","Aug","Sep","Oct","Nov","Dec"
+ };
+
+ TaoCrypt::ASN1_TIME_extract(time->data, time->type, &t);
+ snprintf(buf, len, "%s %2d %02d:%02d:%02d %d GMT",
+ month_names[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min,
+ t.tm_sec, t.tm_year + 1900);
+ return buf;
+ }
+
+
+
+
} // extern "C"
} // namespace
=== modified file 'extra/yassl/src/yassl_int.cpp'
--- a/extra/yassl/src/yassl_int.cpp 2009-09-23 13:21:29 +0000
+++ b/extra/yassl/src/yassl_int.cpp 2011-03-28 12:29:22 +0000
@@ -1440,12 +1440,12 @@ void SSL_SESSION::CopyX509(X509* x)
X509_NAME* issuer = x->GetIssuer();
X509_NAME* subject = x->GetSubject();
- ASN1_STRING* before = x->GetBefore();
- ASN1_STRING* after = x->GetAfter();
+ ASN1_TIME* before = x->GetBefore();
+ ASN1_TIME* after = x->GetAfter();
peerX509_ = NEW_YS X509(issuer->GetName(), issuer->GetLength(),
- subject->GetName(), subject->GetLength(), (const char*) before->data,
- before->length, (const char*) after->data, after->length);
+ subject->GetName(), subject->GetLength(),
+ before, after);
}
@@ -2378,9 +2378,10 @@ size_t X509_NAME::GetLength() const
X509::X509(const char* i, size_t iSz, const char* s, size_t sSz,
- const char* b, int bSz, const char* a, int aSz)
+ ASN1_STRING *b, ASN1_STRING *a)
: issuer_(i, iSz), subject_(s, sSz),
- beforeDate_(b, bSz), afterDate_(a, aSz)
+ beforeDate_((char *) b->data, b->length, b->type),
+ afterDate_((char *) a->data, a->length, a->type)
{}
@@ -2396,13 +2397,13 @@ X509_NAME* X509::GetSubject()
}
-ASN1_STRING* X509::GetBefore()
+ASN1_TIME* X509::GetBefore()
{
return beforeDate_.GetString();
}
-ASN1_STRING* X509::GetAfter()
+ASN1_TIME* X509::GetAfter()
{
return afterDate_.GetString();
}
@@ -2430,12 +2431,12 @@ ASN1_STRING* X509_NAME::GetEntry(int i)
}
-StringHolder::StringHolder(const char* str, int sz)
+StringHolder::StringHolder(const char* str, int sz, byte type)
{
asnString_.length = sz;
asnString_.data = NEW_YS byte[sz + 1];
memcpy(asnString_.data, str, sz);
- asnString_.type = 0; // not used for now
+ asnString_.type = type;
}
=== modified file 'extra/yassl/taocrypt/include/asn.hpp'
--- a/extra/yassl/taocrypt/include/asn.hpp 2010-02-20 17:08:35 +0000
+++ b/extra/yassl/taocrypt/include/asn.hpp 2011-03-28 12:29:22 +0000
@@ -33,6 +33,9 @@
#include "list.hpp"
#endif
+/* forward declaration for ASN1_TIME_extract */
+struct tm;
+
namespace STL = STL_NAMESPACE;
@@ -278,7 +281,9 @@ public:
const char* GetCommonName() const { return subject_; }
const byte* GetHash() const { return subjectHash_; }
const char* GetBeforeDate() const { return beforeDate_; }
+ byte GetBeforeDateType() const { return beforeDateType_; }
const char* GetAfterDate() const { return afterDate_; }
+ byte GetAfterDateType() const { return afterDateType_; }
void DecodeToKey();
private:
@@ -294,7 +299,9 @@ private:
char issuer_[ASN_NAME_MAX]; // Names
char subject_[ASN_NAME_MAX]; // Names
char beforeDate_[MAX_DATE_SZ]; // valid before date
+ byte beforeDateType_; // beforeDate time type
char afterDate_[MAX_DATE_SZ]; // valid after date
+ byte afterDateType_; // afterDate time type
bool verify_; // Default to yes, but could be off
void ReadHeader();
@@ -367,6 +374,9 @@ int GetCert(Source&);
// Get Cert in PEM format from pkcs12 file
int GetPKCS_Cert(const char* password, Source&);
+void ASN1_TIME_extract(const unsigned char* date, unsigned char format,
+ ::tm *parsed_time);
+
} // namespace
=== modified file 'extra/yassl/taocrypt/src/asn.cpp'
--- a/extra/yassl/taocrypt/src/asn.cpp 2010-02-26 13:16:46 +0000
+++ b/extra/yassl/taocrypt/src/asn.cpp 2011-03-28 12:29:22 +0000
@@ -36,6 +36,51 @@
namespace TaoCrypt {
+// like atoi but only use first byte
+word32 btoi(byte b)
+{
+ return b - 0x30;
+}
+
+
+// two byte date/time, add to value
+void GetTime(int *value, const byte* date, int& i)
+{
+ *value += btoi(date[i++]) * 10;
+ *value += btoi(date[i++]);
+}
+
+
+void ASN1_TIME_extract(const unsigned char* date, unsigned char format,
+ tm *t)
+{
+ int i = 0;
+ memset(t, 0, sizeof (tm));
+
+ assert(format == UTC_TIME || format == GENERALIZED_TIME);
+
+ if (format == UTC_TIME) {
+ if (btoi(date[0]) >= 5)
+ t->tm_year = 1900;
+ else
+ t->tm_year = 2000;
+ }
+ else { // format == GENERALIZED_TIME
+ t->tm_year += btoi(date[i++]) * 1000;
+ t->tm_year += btoi(date[i++]) * 100;
+ }
+
+ GetTime(&t->tm_year, date, i); t->tm_year -= 1900; // adjust
+ GetTime(&t->tm_mon, date, i); t->tm_mon -= 1; // adjust
+ GetTime(&t->tm_mday, date, i);
+ GetTime(&t->tm_hour, date, i);
+ GetTime(&t->tm_min, date, i);
+ GetTime(&t->tm_sec, date, i);
+
+ assert(date[i] == 'Z'); // only Zulu supported for this profile
+}
+
+
namespace { // locals
@@ -70,51 +115,15 @@ bool operator<(tm& a, tm&b)
}
-// like atoi but only use first byte
-word32 btoi(byte b)
-{
- return b - 0x30;
-}
-
-
-// two byte date/time, add to value
-void GetTime(int& value, const byte* date, int& i)
-{
- value += btoi(date[i++]) * 10;
- value += btoi(date[i++]);
-}
-
-
// Make sure before and after dates are valid
bool ValidateDate(const byte* date, byte format, CertDecoder::DateType dt)
{
tm certTime;
- memset(&certTime, 0, sizeof(certTime));
- int i = 0;
-
- if (format == UTC_TIME) {
- if (btoi(date[0]) >= 5)
- certTime.tm_year = 1900;
- else
- certTime.tm_year = 2000;
- }
- else { // format == GENERALIZED_TIME
- certTime.tm_year += btoi(date[i++]) * 1000;
- certTime.tm_year += btoi(date[i++]) * 100;
- }
-
- GetTime(certTime.tm_year, date, i); certTime.tm_year -= 1900; // adjust
- GetTime(certTime.tm_mon, date, i); certTime.tm_mon -= 1; // adjust
- GetTime(certTime.tm_mday, date, i);
- GetTime(certTime.tm_hour, date, i);
- GetTime(certTime.tm_min, date, i);
- GetTime(certTime.tm_sec, date, i);
-
- assert(date[i] == 'Z'); // only Zulu supported for this profile
-
time_t ltime = time(0);
tm* localTime = gmtime(<ime);
+ ASN1_TIME_extract(date, format, &certTime);
+
if (dt == CertDecoder::BEFORE) {
if (*localTime < certTime)
return false;
@@ -805,10 +814,12 @@ void CertDecoder::GetDate(DateType dt)
if (dt == BEFORE) {
memcpy(beforeDate_, date, length);
beforeDate_[length] = 0;
+ beforeDateType_= b;
}
else { // after
memcpy(afterDate_, date, length);
afterDate_[length] = 0;
+ afterDateType_= b;
}
}
=== modified file 'mysql-test/r/ssl.result'
--- a/mysql-test/r/ssl.result 2010-11-30 13:37:51 +0000
+++ b/mysql-test/r/ssl.result 2011-03-28 12:29:22 +0000
@@ -1,6 +1,12 @@
SHOW STATUS LIKE 'Ssl_cipher';
Variable_name Value
Ssl_cipher DHE-RSA-AES256-SHA
+SHOW STATUS LIKE 'Ssl_server_not_before';
+Variable_name Value
+Ssl_server_not_before Jan 29 11:56:49 2010 GMT
+SHOW STATUS LIKE 'Ssl_server_not_after';
+Variable_name Value
+Ssl_server_not_after Jan 28 11:56:49 2015 GMT
drop table if exists t1,t2,t3,t4;
CREATE TABLE t1 (
Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL,
=== modified file 'mysql-test/t/ssl.test'
--- a/mysql-test/t/ssl.test 2010-04-13 15:04:45 +0000
+++ b/mysql-test/t/ssl.test 2011-03-28 12:29:22 +0000
@@ -11,6 +11,10 @@ connect (ssl_con,localhost,root,,,,,SSL)
# Check ssl turned on
SHOW STATUS LIKE 'Ssl_cipher';
+# Check ssl expiration
+SHOW STATUS LIKE 'Ssl_server_not_before';
+SHOW STATUS LIKE 'Ssl_server_not_after';
+
# Source select test case
-- source include/common-tests.inc
=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc 2011-03-10 10:08:09 +0000
+++ b/sql/mysqld.cc 2011-03-28 12:29:22 +0000
@@ -6700,6 +6700,110 @@ static int show_ssl_get_cipher_list(THD
return 0;
}
+
+#ifdef HAVE_YASSL
+
+static char *
+my_asn1_time_to_string(ASN1_TIME *time, char *buf, size_t len)
+{
+ return yaSSL_ASN1_TIME_to_string(time, buf, len);
+}
+
+#else /* openssl */
+
+static char *
+my_asn1_time_to_string(ASN1_TIME *time, char *buf, size_t len)
+{
+ int n_read;
+ char *res= NULL;
+ BIO *bio= BIO_new(BIO_s_mem());
+
+ if (bio == NULL)
+ return NULL;
+
+ if (!ASN1_TIME_print(bio, time))
+ goto end;
+
+ n_read= BIO_read(bio, buf, (int) (len - 1));
+
+ if (n_read > 0)
+ {
+ buf[n_read]= 0;
+ res= buf;
+ }
+
+end:
+ BIO_free(bio);
+ return res;
+}
+
+#endif
+
+
+/**
+ Handler function for the 'ssl_get_server_not_before' variable
+
+ @param thd the mysql thread structure
+ @param var the data for the variable
+ @param[out] buf the string to put the value of the variable into
+
+ @return status
+ @retval 0 success
+*/
+
+static int
+show_ssl_get_server_not_before(THD *thd, SHOW_VAR *var, char *buff)
+{
+ var->type= SHOW_CHAR;
+ if(thd->vio_ok() && thd->net.vio->ssl_arg)
+ {
+ SSL *ssl= (SSL*) thd->net.vio->ssl_arg;
+ X509 *cert= SSL_get_certificate(ssl);
+ ASN1_TIME *not_before= X509_get_notBefore(cert);
+
+ var->value= my_asn1_time_to_string(not_before, buff,
+ SHOW_VAR_FUNC_BUFF_SIZE);
+ if (!var->value)
+ return 1;
+ var->value= buff;
+ }
+ else
+ var->value= empty_c_string;
+ return 0;
+}
+
+
+/**
+ Handler function for the 'ssl_get_server_not_after' variable
+
+ @param thd the mysql thread structure
+ @param var the data for the variable
+ @param[out] buf the string to put the value of the variable into
+
+ @return status
+ @retval 0 success
+*/
+
+static int
+show_ssl_get_server_not_after(THD *thd, SHOW_VAR *var, char *buff)
+{
+ var->type= SHOW_CHAR;
+ if(thd->vio_ok() && thd->net.vio->ssl_arg)
+ {
+ SSL *ssl= (SSL*) thd->net.vio->ssl_arg;
+ X509 *cert= SSL_get_certificate(ssl);
+ ASN1_TIME *not_after= X509_get_notAfter(cert);
+
+ var->value= my_asn1_time_to_string(not_after, buff,
+ SHOW_VAR_FUNC_BUFF_SIZE);
+ if (!var->value)
+ return 1;
+ }
+ else
+ var->value= empty_c_string;
+ return 0;
+}
+
#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
@@ -6818,6 +6922,10 @@ SHOW_VAR status_vars[]= {
{"Ssl_verify_depth", (char*) &show_ssl_get_verify_depth, SHOW_FUNC},
{"Ssl_verify_mode", (char*) &show_ssl_get_verify_mode, SHOW_FUNC},
{"Ssl_version", (char*) &show_ssl_get_version, SHOW_FUNC},
+ {"Ssl_server_not_before", (char*) &show_ssl_get_server_not_before,
+ SHOW_FUNC},
+ {"Ssl_server_not_after", (char*) &show_ssl_get_server_not_after,
+ SHOW_FUNC},
#endif
#endif /* HAVE_OPENSSL */
{"Table_locks_immediate", (char*) &locks_immediate, SHOW_LONG},
Attachment: [text/bzr-bundle] bzr/georgi.kodinov@oracle.com-20110328122922-fg64w2g6nya5ri13.bundle