]> WPIA git - cassiopeia.git/blobdiff - src/X509.cpp
add: Basic Unit Test setup using Boost UTF
[cassiopeia.git] / src / X509.cpp
index 5d38e3cb241547561a1336b6281fafbed2330165..92d7773f22f4cbff36b0b5cb4a179f030018087a 100644 (file)
@@ -1,5 +1,6 @@
 #include "X509.h"
 
+#include <fstream>
 #include <iostream>
 
 #include <openssl/ssl.h>
@@ -17,7 +18,33 @@ X509Req::X509Req( X509_REQ* csr ) {
     pk = std::shared_ptr<EVP_PKEY>( pkt, EVP_PKEY_free );
 }
 
+X509Req::X509Req( std::string spkac ) {
+    if( spkac.compare( 0, 6, "SPKAC=" ) != 0 ) {
+        throw "Error: not a SPKAC";
+    }
+
+    spkac = spkac.substr( 6 );
+    NETSCAPE_SPKI* spki_p = NETSCAPE_SPKI_b64_decode( spkac.c_str(), spkac.size() );
+
+    if( !spki_p ) {
+        throw "Error: decode failed";
+    }
+
+    spki = std::shared_ptr<NETSCAPE_SPKI>( spki_p, NETSCAPE_SPKI_free );
+    EVP_PKEY* pkt_p = NETSCAPE_SPKI_get_pubkey( spki.get() );
+
+    if( !pkt_p ) {
+        throw "Error: reading SPKAC Pubkey failed";
+    }
+
+    pk = std::shared_ptr<EVP_PKEY>( pkt_p, EVP_PKEY_free );
+}
+
 int X509Req::verify() {
+    if( !req ) {
+        return NETSCAPE_SPKI_verify( spki.get(), pk.get() );
+    }
+
     return X509_REQ_verify( req.get(), pk.get() );
 }
 
@@ -36,6 +63,10 @@ std::shared_ptr<X509Req> X509Req::parse( std::string filename ) {
     return std::shared_ptr<X509Req>( new X509Req( req ) );
 }
 
+std::shared_ptr<X509Req> X509Req::parseSPKAC( std::string content ) {
+    return std::shared_ptr<X509Req>( new X509Req( content ) );
+}
+
 int add_ext( std::shared_ptr<X509> issuer, std::shared_ptr<X509> subj, int nid, const char* value ) {
     X509_EXTENSION* ex;
     X509V3_CTX ctx;
@@ -72,6 +103,20 @@ X509Cert::X509Cert() {
     if( !X509_set_version( c, 2 ) ) {
         throw "Setting X509-version to 3 failed";
     }
+
+    X509_NAME* subjectP = X509_NAME_new();
+
+    if( !subjectP ) {
+        throw "malloc failure";
+    }
+
+    subject = std::shared_ptr<X509_NAME>( subjectP, X509_NAME_free );
+}
+
+void X509Cert::addRDN( int nid, std::string data ) {
+    if( ! X509_NAME_add_entry_by_NID( subject.get(), nid, MBSTRING_UTF8, ( unsigned char* )const_cast<char*>( data.data() ), data.size(), -1, 0 ) ) {
+        throw "malloc failure";
+    }
 }
 
 void X509Cert::setIssuerNameFrom( std::shared_ptr<X509> caCert ) {
@@ -88,11 +133,11 @@ void X509Cert::setPubkeyFrom( std::shared_ptr<X509Req> req ) {
     }
 }
 
-void X509Cert::setSerialNumber( int num ) {
-    ASN1_INTEGER_set( target.get()->cert_info->serialNumber, num );
+void X509Cert::setSerialNumber( BIGNUM* num ) {
+    BN_to_ASN1_INTEGER( num , target->cert_info->serialNumber );
 }
 
-void X509Cert::setTimes( long before, long after ) {
+void X509Cert::setTimes( uint32_t before, uint32_t after ) {
     X509_gmtime_adj( X509_get_notBefore( target.get() ), before );
     X509_gmtime_adj( X509_get_notAfter( target.get() ), after );
 }
@@ -139,6 +184,10 @@ void X509Cert::setExtensions( std::shared_ptr<X509> caCert, std::vector<std::sha
     add_ext( caCert, target, NID_info_access, "OCSP;URI:http://ocsp.cacert.org" );
     add_ext( caCert, target, NID_crl_distribution_points, "URI:http://crl.cacert.org/class3-revoke.crl" );
 
+    if( sans.size() == 0 ) {
+        return;
+    }
+
     std::shared_ptr<GENERAL_NAMES> gens = std::shared_ptr<GENERAL_NAMES>(
         sk_GENERAL_NAME_new_null(),
         []( GENERAL_NAMES * ref ) {
@@ -172,17 +221,41 @@ void X509Cert::setExtensions( std::shared_ptr<X509> caCert, std::vector<std::sha
     X509_EXTENSION_free( ext );
 }
 
-std::string X509Cert::sign( std::shared_ptr<EVP_PKEY> caKey ) {
-    if( !X509_sign( target.get(), caKey.get(), EVP_sha512() ) ) {
+std::shared_ptr<SignedCertificate> X509Cert::sign( std::shared_ptr<EVP_PKEY> caKey, std::string signAlg ) {
+    if( !X509_set_subject_name( target.get(), subject.get() ) ) {
+        throw "error setting subject";
+    }
+
+    const EVP_MD* md;
+
+    if( signAlg == "sha512" ) {
+        md = EVP_sha512();
+    } else if( signAlg == "sha384" ) {
+        md = EVP_sha384();
+    } else if( signAlg == "sha256" ) {
+        md = EVP_sha256();
+    } else if( signAlg == "sha1" ) {
+        md = EVP_sha1();
+    } else {
+        throw "Unknown md-type";
+    }
+
+    if( !X509_sign( target.get(), caKey.get(), md ) ) {
         throw "Signing failed.";
     }
 
-    X509_print_fp( stdout, target.get() );
+    //X509_print_fp( stdout, target.get() );
 
     std::shared_ptr<BIO> mem = std::shared_ptr<BIO>( BIO_new( BIO_s_mem() ), BIO_free );
     PEM_write_bio_X509( mem.get(), target.get() );
     BUF_MEM* buf;
     BIO_get_mem_ptr( mem.get(), &buf );
-    std::string output( buf->data, buf->data + buf->length );
-    return output;
+    std::shared_ptr<SignedCertificate> res = std::shared_ptr<SignedCertificate>( new SignedCertificate() );
+    res->certificate = std::string( buf->data, buf->data + buf->length );
+    BIGNUM* ser = ASN1_INTEGER_to_BN( target->cert_info->serialNumber, NULL );
+    char* serStr = BN_bn2hex( ser );
+    res->serial = std::string( serStr );
+    OPENSSL_free( serStr );
+    BN_free( ser );
+    return res;
 }