4#include "Stroika/Foundation/StroikaPreComp.h"
6#if qStroika_HasComponent_OpenSSL
7#include <openssl/evp.h>
8#include <openssl/pem.h>
13#include "Stroika/Foundation/Cryptography/Providers/OpenSSL/PrivateKey.h"
16#include "Stroika/Foundation/Execution/Exceptions.h"
18#include "Certificate.h"
23using namespace Stroika::Foundation::Cryptography;
24using namespace Stroika::Foundation::Cryptography::PKI::Certificate;
25using namespace Stroika::Foundation::Cryptography::Providers;
26using namespace Stroika::Foundation::Cryptography::Providers::OpenSSL;
27using namespace Stroika::Foundation::Debug;
32#if qStroika_HasComponent_OpenSSL
34 struct Rep_ : OpenSSL::Certificate::IRep {
36 OpenSSL::Certificate::LibRepType fCert_;
39 Rep_ (
const Rep_&) =
delete;
40 Rep_ (Rep_&&) =
default;
41 Rep_ (OpenSSL::Certificate::LibRepType&& p)
50 Exception::ThrowLastErrorIfFailed (::ASN1_TIME_to_tm (X509_get_notBefore (fCert_.get ()), &from));
51 Exception::ThrowLastErrorIfFailed (::ASN1_TIME_to_tm (X509_get_notAfter (fCert_.get ()), &to));
52 return Range<DateTime>{DateTime{from, Timezone::kUTC}, DateTime{to, Timezone::kUTC}};
57 X509_NAME* subject = ::X509_get_subject_name (fCert_.get ());
58 int numEntries = ::X509_NAME_entry_count (subject);
59 for (
int i = 0; i < numEntries; ++i) {
60 X509_NAME_ENTRY* entry = ::X509_NAME_get_entry (subject, i);
61 ASN1_OBJECT* nid = ::X509_NAME_ENTRY_get_object (entry);
62 if (::OBJ_cmp (nid, ::OBJ_nid2obj (NID_commonName)) == 0) {
63 unsigned char* cn = X509_NAME_ENTRY_get_data (entry)->data;
64 result.fCommonName = String::FromUTF8 ((
const char*)cn);
66 else if (::OBJ_cmp (nid, ::OBJ_nid2obj (NID_countryName)) == 0) {
67 unsigned char* cn = ::X509_NAME_ENTRY_get_data (entry)->data;
68 result.fCountry = String::FromUTF8 ((
const char*)cn);
70 else if (::OBJ_cmp (nid, ::OBJ_nid2obj (NID_organizationName)) == 0) {
71 unsigned char* cn = ::X509_NAME_ENTRY_get_data (entry)->data;
72 result.fOrganization = String::FromUTF8 ((
const char*)cn);
77 virtual X509* Get_X509 ()
const override
85#if qStroika_HasComponent_OpenSSL
91auto OpenSSL::Certificate::New (LibRepType&& x509) -> Ptr
93 return make_shared<Rep_> (move (x509));
96auto OpenSSL::Certificate::New (
const SelfSignedCertParams& params) -> tuple<OpenSSL::PrivateKey::Ptr, Ptr>
99 PrivateKey::LibRepType pkey{::EVP_RSA_gen (2048)};
101 LibRepType newCert{X509_new ()};
103 Exception::ThrowLastErrorIfFailed (::ASN1_INTEGER_set (::X509_get_serialNumber (newCert.get ()), 1));
105 ::ASN1_TIME_set (::X509_get_notBefore (newCert.get ()), params.fValidDates.GetLowerBound ().AsUTC ().As<time_t> ());
106 ::ASN1_TIME_set (::X509_get_notAfter (newCert.get ()), params.fValidDates.GetUpperBound ().AsUTC ().As<time_t> ());
109 Exception::ThrowLastErrorIfFailed (::X509_set_pubkey (newCert.get (), pkey.get ()));
111 X509_NAME* name = ::X509_get_subject_name (newCert.get ());
112 u8string org = params.fSubject.fOrganization.AsUTF8 ();
113 u8string cn = params.fSubject.fCommonName.AsUTF8 ();
114 u8string country = params.fSubject.fCountry.AsUTF8 ();
116 Exception::ThrowLastErrorIfFailed (::X509_NAME_add_entry_by_txt (name,
"C", MBSTRING_UTF8, (
unsigned char*)country.c_str (), -1, -1, 0));
117 Exception::ThrowLastErrorIfFailed (::X509_NAME_add_entry_by_txt (name,
"O", MBSTRING_UTF8, (
unsigned char*)org.c_str (), -1, -1, 0));
118 Exception::ThrowLastErrorIfFailed (::X509_NAME_add_entry_by_txt (name,
"CN", MBSTRING_UTF8, (
unsigned char*)cn.c_str (), -1, -1, 0));
121 Exception::ThrowLastErrorIfFailed (::X509_set_issuer_name (newCert.get (), name));
124 Exception::ThrowLastErrorIfFailed (::X509_sign (newCert.get (), pkey.get (), ::EVP_sha1 ()));
125 return make_tuple (OpenSSL::PrivateKey::New (move (pkey)), New (move (newCert)));
data used to create a self-signed certificate.