6 #include <openssl/ssl.h>
7 #include <openssl/bio.h>
8 #include <openssl/x509v3.h>
10 X509Req::X509Req( X509_REQ* csr ) : req( csr, X509_REQ_free ) {
11 EVP_PKEY* pkt = X509_REQ_get_pubkey( req.get() );
14 throw "Error extracting public key";
17 pk = std::shared_ptr<EVP_PKEY>( pkt, EVP_PKEY_free );
20 X509Req::X509Req( std::string spkac ) {
21 if( spkac.compare( 0, 6, "SPKAC=" ) != 0 ) {
22 throw "Error: not a SPKAC";
25 spkac = spkac.substr( 6 );
26 NETSCAPE_SPKI* spki_p = NETSCAPE_SPKI_b64_decode( spkac.c_str(), spkac.size() );
29 throw "Error: decode failed";
32 spki = std::shared_ptr<NETSCAPE_SPKI>( spki_p, NETSCAPE_SPKI_free );
33 EVP_PKEY* pkt_p = NETSCAPE_SPKI_get_pubkey( spki.get() );
36 throw "Error: reading SPKAC Pubkey failed";
39 pk = std::shared_ptr<EVP_PKEY>( pkt_p, EVP_PKEY_free );
42 int X509Req::verify() {
44 return NETSCAPE_SPKI_verify( spki.get(), pk.get() );
47 return X509_REQ_verify( req.get(), pk.get() );
50 std::shared_ptr<EVP_PKEY> X509Req::getPkey() const {
54 std::shared_ptr<X509Req> X509Req::parseCSR( std::string content ) {
55 std::shared_ptr<BIO> in = std::shared_ptr<BIO>( BIO_new_mem_buf( const_cast<char*>( content.c_str() ), -1 ), BIO_free );
56 X509_REQ* req = PEM_read_bio_X509_REQ( in.get(), NULL, NULL, NULL );
59 throw "Error parsing CSR";
62 return std::shared_ptr<X509Req>( new X509Req( req )); // TODO ask
65 std::shared_ptr<X509Req> X509Req::parseSPKAC( std::string content ) {
66 return std::shared_ptr<X509Req>( new X509Req( content ) );
69 int add_ext( std::shared_ptr<X509> issuer, std::shared_ptr<X509> subj, int nid, const char* value ) {
73 /* This sets the 'context' of the extensions. */
74 /* No configuration database */
75 X509V3_set_ctx_nodb( &ctx );
77 /* Issuer and subject certs: both the target since it is self signed,
78 * no request and no CRL
80 X509V3_set_ctx( &ctx, issuer.get(), subj.get(), NULL, NULL, 0 );
81 ex = X509V3_EXT_conf_nid( NULL, &ctx, nid, const_cast<char*>( value ) );
87 X509_add_ext( subj.get(), ex, -1 );
88 X509_EXTENSION_free( ex );
93 X509Cert::X509Cert() {
97 throw "malloc failed";
100 target = std::shared_ptr<X509>( c, X509_free );
102 if( !X509_set_version( c, 2 ) ) {
103 throw "Setting X509-version to 3 failed";
106 X509_NAME* subjectP = X509_NAME_new();
109 throw "malloc failure in construct.";
112 subject = std::shared_ptr<X509_NAME>( subjectP, X509_NAME_free );
115 void X509Cert::addRDN( int nid, std::string data ) {
116 if( ! X509_NAME_add_entry_by_NID( subject.get(), nid, MBSTRING_UTF8, ( unsigned char* )const_cast<char*>( data.data() ), data.size(), -1, 0 ) ) {
117 throw "malloc failure in RDN";
121 void X509Cert::setIssuerNameFrom( std::shared_ptr<X509> caCert ) {
122 if( !X509_set_issuer_name( target.get(), X509_get_subject_name( caCert.get() ) ) ) {
123 throw "Error setting Issuer name";
127 void X509Cert::setPubkeyFrom( std::shared_ptr<X509Req> req ) {
128 std::shared_ptr<EVP_PKEY> pktmp = req->getPkey();
130 if( !X509_set_pubkey( target.get(), pktmp.get() ) ) {
131 throw "Setting public key failed.";
135 void X509Cert::setSerialNumber( BIGNUM* num ) {
136 BN_to_ASN1_INTEGER( num , target->cert_info->serialNumber );
139 void X509Cert::setTimes( uint32_t before, uint32_t after ) {
140 ASN1_TIME_set( X509_get_notBefore( target.get() ), before );
141 ASN1_TIME_set( X509_get_notAfter( target.get() ), after );
144 static X509_EXTENSION* do_ext_i2d( int ext_nid, int crit, ASN1_VALUE* ext_struc ) {
145 unsigned char* ext_der;
147 ASN1_OCTET_STRING* ext_oct;
149 /* Convert internal representation to DER */
151 ext_len = ASN1_item_i2d( ext_struc, &ext_der, ASN1_ITEM_ptr( ASN1_ITEM_ref( GENERAL_NAMES ) ) );
157 if( !( ext_oct = M_ASN1_OCTET_STRING_new() ) ) {
161 ext_oct->data = ext_der;
162 ext_oct->length = ext_len;
164 ext = X509_EXTENSION_create_by_NID( NULL, ext_nid, crit, ext_oct );
170 M_ASN1_OCTET_STRING_free( ext_oct );
177 void X509Cert::setExtensions( std::shared_ptr<X509> caCert, std::vector<std::shared_ptr<SAN>>& sans, Profile& prof, std::string crlURL, std::string crtURL ) {
178 add_ext( caCert, target, NID_basic_constraints, "critical,CA:FALSE" );
179 add_ext( caCert, target, NID_subject_key_identifier, "hash" );
180 add_ext( caCert, target, NID_authority_key_identifier, "keyid,issuer:always" );
181 std::string ku = std::string( "critical," ) + prof.ku;
182 add_ext( caCert, target, NID_key_usage, ku.c_str() );
183 add_ext( caCert, target, NID_ext_key_usage, prof.eku.c_str() );
184 add_ext( caCert, target, NID_info_access, ("OCSP;URI:http://ocsp.cacert.org,caIssuers;URI:" + crtURL).c_str() );
185 add_ext( caCert, target, NID_crl_distribution_points, ("URI:" + crlURL).c_str() );
191 std::shared_ptr<GENERAL_NAMES> gens = std::shared_ptr<GENERAL_NAMES>(
192 sk_GENERAL_NAME_new_null(),
193 []( GENERAL_NAMES * ref ) {
195 sk_GENERAL_NAME_pop_free( ref, GENERAL_NAME_free );
199 for( auto& name : sans ) {
200 GENERAL_NAME* gen = GENERAL_NAME_new();
203 throw "Malloc failure.";
206 gen->type = name->type == "DNS" ? GEN_DNS : name->type == "email" ? GEN_EMAIL : 0; // GEN_EMAIL;
209 || !( gen->d.ia5 = M_ASN1_IA5STRING_new() )
210 || !ASN1_STRING_set( gen->d.ia5, name->content.data(), name->content.size() ) ) {
211 GENERAL_NAME_free( gen );
212 throw "initing iasting5 failed";
215 sk_GENERAL_NAME_push( gens.get(), gen );
218 X509_EXTENSION* ext = do_ext_i2d( NID_subject_alt_name, 0/*critical*/, ( ASN1_VALUE* )gens.get() );
220 X509_add_ext( target.get(), ext, -1 );
221 X509_EXTENSION_free( ext );
224 std::shared_ptr<SignedCertificate> X509Cert::sign( std::shared_ptr<EVP_PKEY> caKey, std::string signAlg ) {
225 if( !X509_set_subject_name( target.get(), subject.get() ) ) {
226 throw "error setting subject";
231 if( signAlg == "sha512" ) {
233 } else if( signAlg == "sha384" ) {
235 } else if( signAlg == "sha256" ) {
237 } else if( signAlg == "sha1" ) {
240 throw "Unknown md-type";
243 if( !X509_sign( target.get(), caKey.get(), md ) ) {
244 throw "Signing failed.";
247 //X509_print_fp( stdout, target.get() );
249 std::shared_ptr<BIO> mem = std::shared_ptr<BIO>( BIO_new( BIO_s_mem() ), BIO_free );
252 throw "Failed to allocate memory for the signed certificate.";
255 PEM_write_bio_X509( mem.get(), target.get() );
258 BIO_get_mem_ptr( mem.get(), &buf );
260 auto res = std::make_shared<SignedCertificate>();
261 res->certificate = std::string( buf->data, buf->data + buf->length );
263 std::shared_ptr<BIGNUM> ser( ASN1_INTEGER_to_BN( target->cert_info->serialNumber, NULL ), BN_free );
266 throw "Failed to retrieve certificate serial of signed certificate.";
269 std::shared_ptr<char> serStr(
270 BN_bn2hex( ser.get() ),
273 } ); // OPENSSL_free is a macro...
274 res->serial = serStr ? std::string( serStr.get() ) : "";