31#ifndef ASYNC_SSL_X509_INCLUDED
32#define ASYNC_SSL_X509_INCLUDED
41#include <openssl/x509.h>
42#include <openssl/bn.h>
147 : m_cert(cert), m_managed(managed)
162 : m_cert(X509_STORE_CTX_get_current_cert(&ctx)), m_managed(false)
176 set(other.m_cert, other.m_managed);
183 other.m_cert =
nullptr;
184 other.m_managed =
true;
194 set(other.m_cert, other.m_managed);
201 other.m_cert =
nullptr;
202 other.m_managed =
true;
235 void set(X509* cert,
bool managed=
true)
237 if (m_managed && (m_cert !=
nullptr))
253 if (m_managed && (m_cert !=
nullptr))
264 bool isNull(
void)
const {
return m_cert ==
nullptr; }
278 assert(m_cert !=
nullptr);
279#if OPENSSL_VERSION_MAJOR >= 3
280 return (X509_set_issuer_name(m_cert, name) == 1);
282 auto n = X509_NAME_dup(
const_cast<X509_NAME*
>(name));
283 int ret = X509_set_issuer_name(m_cert, n);
295 assert(m_cert !=
nullptr);
296 return X509_get_issuer_name(m_cert);
306 assert(m_cert !=
nullptr);
307#if OPENSSL_VERSION_MAJOR >= 3
308 return (X509_set_subject_name(m_cert, name) == 1);
310 auto n = X509_NAME_dup(
const_cast<X509_NAME*
>(name));
311 int ret = X509_set_subject_name(m_cert, n);
323 assert(m_cert !=
nullptr);
324 return X509_get_subject_name(m_cert);
331 operator const X509*(void)
const {
return m_cert; }
348#if OPENSSL_VERSION_MAJOR >= 3
349 int lastpos = X509_NAME_get_index_by_NID(subj, NID_commonName, -1);
351 auto s = X509_NAME_dup(
const_cast<X509_NAME*
>(subj));
352 int lastpos = X509_NAME_get_index_by_NID(s, NID_commonName, -1);
357 X509_NAME_ENTRY *e = X509_NAME_get_entry(subj, lastpos);
358 ASN1_STRING *d = X509_NAME_ENTRY_get_data(e);
359 cn =
reinterpret_cast<const char*
>(ASN1_STRING_get0_data(d));
371 assert(m_cert !=
nullptr);
372 return (X509_verify(m_cert, keypair) == 1);
382 BIO *mem = BIO_new(BIO_s_mem());
383 BIO_puts(mem,
pem.c_str());
384 if (m_managed && (m_cert !=
nullptr))
388 m_cert = PEM_read_bio_X509(mem,
nullptr,
nullptr,
nullptr);
390 return (m_cert !=
nullptr);
397 std::string
pem(
void)
const
399 assert(m_cert !=
nullptr);
400 BIO *mem = BIO_new(BIO_s_mem());
401 int ret = PEM_write_bio_X509(mem, m_cert);
404 int len = BIO_read(mem, buf,
sizeof(buf));
407 return std::string(buf, len);
417 FILE *p_file = fopen(filename.c_str(),
"r");
418 if (p_file ==
nullptr)
424 if (m_managed && (m_cert !=
nullptr))
428 m_cert = PEM_read_X509(p_file,
nullptr,
nullptr,
nullptr);
430 return (m_cert !=
nullptr);
440 assert(m_cert !=
nullptr);
447 int ret = PEM_write_X509(f, m_cert);
481 return (X509_set_version(m_cert,
version) == 1);
488 long version(
void)
const {
return X509_get_version(m_cert); }
496 X509_time_adj_ex(X509_get_notBefore(m_cert), 0L, 0L, &in_time);
505 ASN1_TIME* epoch = ASN1_TIME_set(
nullptr, 0);
506 const ASN1_TIME* not_before = X509_get0_notBefore(m_cert);
508 ASN1_TIME_diff(&pday, &psec, epoch, not_before);
509 ASN1_STRING_free(epoch);
510 return static_cast<std::time_t
>(pday)*24*3600 + psec;
519 const ASN1_TIME* t = X509_get_notBefore(m_cert);
520 int len = ASN1_STRING_length(t);
523 return std::string();
525 const unsigned char* data = ASN1_STRING_get0_data(t);
526 return std::string(data, data+len);
536 std::ostringstream ss;
537 ss << std::put_time(std::localtime(&t),
"%c");
547 X509_time_adj_ex(X509_get_notAfter(m_cert), 0L, 0L, &in_time);
556 ASN1_TIME* epoch = ASN1_TIME_set(
nullptr, 0);
557 const ASN1_TIME* not_after = X509_get0_notAfter(m_cert);
559 ASN1_TIME_diff(&pday, &psec, epoch, not_after);
560 ASN1_STRING_free(epoch);
561 return static_cast<std::time_t
>(pday)*24*3600 + psec;
570 const ASN1_TIME* t = X509_get_notAfter(m_cert);
571 const unsigned char* data = ASN1_STRING_get0_data(t);
572 int len = ASN1_STRING_length(t);
575 return std::string();
577 return std::string(data, data+len);
587 std::ostringstream ss;
588 ss << std::put_time(std::localtime(&t),
"%c");
599 std::time_t validity_secs = days * 24 * 60 * 60;
600 std::time_t tnow = time(NULL);
601 tnow += offset_days * 24 * 60 * 60;
602 if (std::numeric_limits<time_t>::max() - validity_secs < tnow)
604 validity_secs = std::numeric_limits<time_t>::max() - tnow;
617 const ASN1_TIME* not_before = X509_get_notBefore(m_cert);
618 const ASN1_TIME* not_after = X509_get_notAfter(m_cert);
619 ASN1_TIME_diff(&days, &seconds, not_before, not_after);
629 std::time_t tend=time(NULL))
const
631 const ASN1_TIME* not_before = X509_get_notBefore(m_cert);
632 const ASN1_TIME* not_after = X509_get_notAfter(m_cert);
633 return ((not_before ==
nullptr) ||
634 (X509_cmp_time(not_before, &tbegin) == -1)) &&
635 ((not_after ==
nullptr) ||
636 (X509_cmp_time(not_after, &tend) == 1));
648 return X509_get_signature_type(m_cert);
660 ASN1_INTEGER *p_serial_number = ASN1_INTEGER_new();
661 if (serial_number < 0)
663 randSerial(p_serial_number);
667 ASN1_INTEGER_set(p_serial_number, serial_number);
669 X509_set_serialNumber(m_cert, p_serial_number);
670 ASN1_INTEGER_free(p_serial_number);
679 const ASN1_INTEGER* i = X509_get0_serialNumber(m_cert);
682 return std::string();
684 BIGNUM *bn = ASN1_INTEGER_to_BN(i,
nullptr);
687 return std::string();
689 char *hex = BN_bn2hex(bn);
693 return std::string();
695 std::string ret(hex, hex+strlen(hex));
696 ret = std::string(
"0x") + ret;
714 assert(m_cert !=
nullptr);
715 X509_NAME* name = X509_get_issuer_name(m_cert);
718 name = X509_NAME_new();
720 assert(name !=
nullptr);
721 int ret = X509_NAME_add_entry_by_txt(name, field.c_str(), MBSTRING_UTF8,
722 reinterpret_cast<const unsigned char*
>(value.c_str()),
723 value.size(), -1, 0);
725 ret = X509_set_issuer_name(m_cert, name);
737 assert(m_cert !=
nullptr);
738 X509_NAME* name = X509_get_subject_name(m_cert);
741 name = X509_NAME_new();
743 assert(name !=
nullptr);
744 int ret = X509_NAME_add_entry_by_txt(name, field.c_str(), MBSTRING_UTF8,
745 reinterpret_cast<const unsigned char*
>(value.c_str()),
746 value.size(), -1, 0);
748 ret = X509_set_subject_name(m_cert, name);
762 BIO *mem = BIO_new(BIO_s_mem());
763 assert(mem !=
nullptr);
765 int len = X509_NAME_print_ex(mem, nm, 0,
766 XN_FLAG_ONELINE & ~ASN1_STRFLGS_ESC_MSB);
770 len = BIO_read(mem, buf,
sizeof(buf));
773 str = std::string(buf, len);
791 BIO *mem = BIO_new(BIO_s_mem());
792 assert(mem !=
nullptr);
794 int len = X509_NAME_print_ex(mem, nm, 0,
795 XN_FLAG_ONELINE & ~ASN1_STRFLGS_ESC_MSB);
799 len = BIO_read(mem, buf,
sizeof(buf));
802 str = std::string(buf, len);
816 for (
int i=0; i<X509v3_get_ext_count(exts); ++i)
818 auto ext = X509v3_get_ext(exts, i);
819 X509_add_ext(m_cert, ext, -1);
829 assert(m_cert !=
nullptr);
840 return (X509_set_pubkey(m_cert, pkey) == 1);
850 auto md = EVP_sha256();
851 auto md_size = EVP_MD_size(md);
852 return (X509_sign(m_cert, pkey, md) != md_size);
859 std::vector<unsigned char>
digest(
void)
const
861 assert(m_cert !=
nullptr);
862 std::vector<unsigned char> md(EVP_MAX_MD_SIZE);
863 unsigned int len = md.size();
864 if (X509_digest(m_cert, EVP_sha256(), md.data(), &len) != 1)
873 int certificateType(
void)
const
875 auto pkey = X509_get0_pubkey(m_cert);
880 return X509_certificate_type(m_cert, pkey);
891 int chk = X509_check_host(m_cert, name.c_str(), name.size(), 0,
nullptr);
902 int chk = X509_check_ip_asc(m_cert, ip.
toString().c_str(), 0);
910 void print(
const std::string& prefix=
"")
const
914 std::cout <<
"NULL" << std::endl;
918 int ext_idx = X509_get_ext_by_NID(m_cert, NID_subject_alt_name, -1);
919 auto ext = X509_get_ext(m_cert, ext_idx);
927 << prefix <<
"Not Before : "
929 << prefix <<
"Not After : "
935 std::cout << prefix <<
"Subject Alt Name : " << sanstr <<
"\n";
946 std::cout << std::flush;
952 X509* m_cert =
nullptr;
953 bool m_managed =
true;
955 int randSerial(ASN1_INTEGER *ai)
957 BIGNUM *p_bignum = NULL;
960 if (NULL == (p_bignum = BN_new())) {
964 if (!BN_rand(p_bignum, 159, 0, 0)) {
968 if (ai && !BN_to_ASN1_INTEGER(p_bignum, ai)) {
Represent private and public keys.
A class representing X.509 v3 extensions.
A class for representing an IP address in an OS independent way.
std::string toString(void) const
Return the string representation of the IP address.
A class representing private and public keys.
A class representing the X.509 Subject Alternative Name extension.
std::string toString(int type=-1) const
Convert all SANs to a string.
A class representing X.509 extensions.
A class representing an X.509 certificate.
std::string serialNumberString(void) const
Get the serial number as a string.
void setValidityTime(unsigned days, int offset_days=0)
Set the validity time relative to current time.
bool appendPemFile(const std::string &filename)
Append this certificate to file in PEM format.
bool readPemFile(const std::string &filename)
Initialize this object with PEM data read from given file.
bool matchHost(const std::string &name) const
Check if the given hostname match this certificate.
std::string commonName(void) const
Get the common name of the subject.
void addSubjectName(const std::string &field, const std::string &value)
Add a name to the subject distinguished name.
void addIssuerName(const std::string &field, const std::string &value)
Add a name to the issuer distinguished name.
SslKeypair publicKey(void) const
Get the public key @retrun Returns the public key.
std::time_t notBefore(void) const
Get the date and time from which this certificate is valid.
SslX509(X509_STORE_CTX &ctx)
Constructor.
long version(void) const
Get the version of this certificate.
SslX509 & operator=(const SslX509 &)=delete
Disallow use of the copy assignment operator.
void validityTime(int &days, int &seconds) const
The duration that this certificate is valid.
SslX509(void)
Default constructor.
int signatureType(void) const
Get the signature type.
bool writePemFile(const std::string &filename)
Write this certificate to file in PEM format.
void print(const std::string &prefix="") const
Print this certificate to std::cout.
void setSerialNumber(long serial_number=-1)
Set the serial number of the certificate.
bool setPublicKey(SslKeypair &pkey)
Set the public key for this certificate.
~SslX509(void)
Constructor taking PEM data.
bool verify(SslKeypair &keypair)
Verify that this certificate is signed by the given key.
const X509_NAME * subjectName(void) const
Get the subject distinguished name.
std::string subjectNameString(void) const
Get the subject distinguished name as a string.
std::string notAfterString(void) const
Get the date and time up to which this certificate is valid.
bool timeIsWithinRange(std::time_t tbegin=time(NULL), std::time_t tend=time(NULL)) const
Check if the certificate is valid within the given range.
bool readPem(const std::string &pem)
Initialize this certificate from a string containing PEM data.
SslX509(const SslX509 &)=delete
Don't allow copy construction.
bool setSubjectName(const X509_NAME *name)
Set the subject distinguished name.
SslX509 & operator=(SslX509 &&other)
Move assignment operator.
bool isNull(void) const
Check if this object is empty.
void set(X509 *cert, bool managed=true)
Set the internal X509 object to use.
std::time_t notAfter(void) const
Get the date and time up to which this certificate is valid.
bool writePemFile(FILE *f)
Write this certificate to file in PEM format.
bool matchIp(const IpAddress &ip) const
Check if the given IP address match this certificate.
bool setIssuerName(const X509_NAME *name)
Set the issuer distinguished name.
void addExtensions(const SslX509Extensions &exts)
Add v3 extensions to this certificate.
std::string issuerNameString(void) const
Get the issuer distinguished name as a string.
SslX509(X509 *cert, bool managed=true)
Constructor.
bool sign(SslKeypair &pkey)
Sign this certificate using the given key.
std::string notBeforeString(void) const
Get the date and time from which this certificate is valid.
std::string pem(void) const
Get this certificate as PEM data.
const X509_NAME * issuerName(void) const
Get the issuer distinguished name.
void clear(void)
Set this object to empty.
void setNotBefore(std::time_t in_time)
Set the date and time from which this certificate is valid.
SslX509(SslX509 &&other)
Move constructor.
void setNotAfter(std::time_t in_time)
Set the date and time up to which this certificate is valid.
std::vector< unsigned char > digest(void) const
Get the digest of this certificate.
std::string notAfterLocaltimeString(void) const
Get the date and time up to which this certificate is valid.
std::string notBeforeLocaltimeString(void) const
Get the date and time from which this certificate is valid.
bool setVersion(long version)
Set the version of this certificate.
Namespace for the asynchronous programming classes.