]> WPIA git - cassiopeia.git/blob - src/crypto/CRL.cpp
fix: be able to load CAs without private key
[cassiopeia.git] / src / crypto / CRL.cpp
1 #include "CRL.h"
2
3 #include <openssl/ssl.h>
4 #include <log/logger.hpp>
5 #include <exception>
6
7 CRL::CRL( std::string path ) {
8     std::shared_ptr<BIO> bio( BIO_new_file( path.c_str(), "r" ), BIO_free );
9     crl = std::shared_ptr<X509_CRL>( PEM_read_bio_X509_CRL( bio.get(), 0, NULL, 0 ), X509_CRL_free );
10
11     if( !crl ) {
12         crl = std::shared_ptr<X509_CRL>( X509_CRL_new(), X509_CRL_free );
13     }
14 }
15
16 std::string CRL::revoke( std::string serial, std::string time ) {
17     BIGNUM* serBN = 0;
18
19     logger::note("parsing serial");
20     if( ! BN_hex2bn( &serBN, serial.c_str() ) ) {
21         throw std::runtime_error("hex2bn malloc fail");
22     }
23
24     std::shared_ptr<BIGNUM> serBNP( serBN, BN_free );
25     std::shared_ptr<ASN1_INTEGER> ser( BN_to_ASN1_INTEGER( serBN, NULL ), ASN1_INTEGER_free );
26
27     if( !ser ) {
28         throw std::runtime_error("BN Malloc fail");
29     }
30
31     logger::note("building current time");
32     std::shared_ptr<ASN1_TIME> tmptm( ASN1_TIME_new(), ASN1_TIME_free );
33
34     if( !tmptm ) {
35         throw std::runtime_error("ASN1-Time Malloc fail");
36     }
37
38     X509_gmtime_adj( tmptm.get(), 0 );
39
40     logger::note("creating entry");
41     X509_REVOKED* rev = X509_REVOKED_new();
42     X509_REVOKED_set_serialNumber( rev, ser.get() );
43
44     if( time != "" ) {
45       ASN1_TIME_set_string( tmptm.get(), time.data() );
46     }
47     X509_REVOKED_set_revocationDate( rev, tmptm.get() );
48
49     X509_CRL_add0_revoked( crl.get(), rev );
50
51     int len = i2d_ASN1_TIME( tmptm.get(), NULL );
52     unsigned char* buffer = ( unsigned char* ) OPENSSL_malloc( len );
53     unsigned char* pos = buffer;
54     i2d_ASN1_TIME( tmptm.get(), &pos );
55     std::string rettime = std::string( ( char* ) buffer, len );
56     OPENSSL_free( buffer );
57     return rettime;
58 }
59
60 void CRL::sign( std::shared_ptr<CAConfig> ca ) {
61     if(!ca->caKey){
62         throw new std::invalid_argument("Cannot sign CRL with CA " + ca->name + " because it has no private key.");
63     }
64
65     // Updating necessary CRL props
66     std::shared_ptr<ASN1_TIME> tmptm( ASN1_TIME_new(), ASN1_TIME_free );
67
68     if( !tmptm ) {
69         throw std::runtime_error("ASN1-Time Malloc fail");
70     }
71
72     X509_gmtime_adj( tmptm.get(), 0 );
73
74     logger::note("setting issuer");
75     if( !X509_CRL_set_issuer_name( crl.get(), X509_get_subject_name( ca->ca.get() ) ) ) {
76         throw std::runtime_error("Setting issuer failed");
77     }
78
79     logger::note("setting update");
80     X509_CRL_set_lastUpdate( crl.get(), tmptm.get() );
81
82     if( !X509_time_adj_ex( tmptm.get(), 1, 10, NULL ) ) {
83         throw std::runtime_error("Updating time failed");
84     }
85
86     logger::note("setting next update");
87     X509_CRL_set_nextUpdate( crl.get(), tmptm.get() );
88
89     logger::note("sorting");
90     // Sorting and signing
91     X509_CRL_sort( crl.get() );
92     logger::note("signing");
93     X509_CRL_sign( crl.get(), ca->caKey.get(), EVP_sha256() );
94 }
95
96 bool CRL::verify( std::shared_ptr<CAConfig> ca ) {
97     std::shared_ptr<EVP_PKEY> pk( X509_get_pubkey( ca->ca.get() ), EVP_PKEY_free );
98     return X509_CRL_verify( crl.get(), pk.get() ) > 0;
99 }
100
101 std::string CRL::toString() {
102     // Write out the new CRL
103     std::shared_ptr<BIO> mem( BIO_new( BIO_s_mem() ), BIO_free );
104     PEM_write_bio_X509_CRL( mem.get(), crl.get() );
105     BUF_MEM* bptr;
106     BIO_get_mem_ptr( mem.get(), &bptr );
107     std::string newCRL( bptr->data, bptr->length );
108     return newCRL;
109 }
110
111 std::string CRL::getSignature() {
112     const X509_ALGOR *palg;
113     const ASN1_BIT_STRING *psig;
114
115     X509_CRL_get0_signature(crl.get(), &psig, &palg);
116     int len = i2d_X509_ALGOR( const_cast<X509_ALGOR*>(palg), NULL );
117     len += i2d_ASN1_BIT_STRING( const_cast<ASN1_BIT_STRING*>(psig), NULL );
118     len += i2d_ASN1_TIME( const_cast<ASN1_TIME*>(X509_CRL_get0_lastUpdate(crl.get())), NULL );
119     len += i2d_ASN1_TIME( const_cast<ASN1_TIME*>(X509_CRL_get0_nextUpdate(crl.get())), NULL );
120
121     unsigned char* buffer = ( unsigned char* ) OPENSSL_malloc( len );
122     unsigned char* pos = buffer;
123     i2d_X509_ALGOR( const_cast<X509_ALGOR*>(palg), &pos );
124     i2d_ASN1_BIT_STRING( const_cast<ASN1_BIT_STRING*>(psig), &pos );
125     i2d_ASN1_TIME( const_cast<ASN1_TIME*>(X509_CRL_get0_lastUpdate(crl.get())), &pos );
126     i2d_ASN1_TIME( const_cast<ASN1_TIME*>(X509_CRL_get0_nextUpdate(crl.get())), &pos );
127     std::string res = std::string( ( char* ) buffer, len );
128     OPENSSL_free( buffer );
129
130     return res;
131 }
132
133 void CRL::setSignature( std::string signature ) {
134     X509_CRL_sort( crl.get() );
135     X509_ALGOR *palg;
136     ASN1_BIT_STRING *psig;
137     // this is not intended use of the OPENSSL-API but API-limitations leave us with no other options.
138     X509_CRL_get0_signature(crl.get(), const_cast<const ASN1_BIT_STRING **>(&psig), const_cast<const X509_ALGOR**>(&palg));
139
140     const unsigned char* data = ( unsigned char* )( signature.data() );
141     const unsigned char* buffer = data;
142     X509_ALGOR *alg = d2i_X509_ALGOR( NULL, &buffer, signature.size() );
143     ASN1_BIT_STRING *sig = d2i_ASN1_BIT_STRING( NULL, &buffer, signature.size() + data - buffer );
144     ASN1_TIME *a1 = d2i_ASN1_TIME( NULL, &buffer, signature.size() + data - buffer );
145     ASN1_TIME *a2 = d2i_ASN1_TIME( NULL, &buffer, signature.size() + data - buffer );
146     std::swap(*palg, *alg);
147     std::swap(*psig, *sig);
148     X509_CRL_set1_lastUpdate( crl.get(), a1);
149     X509_CRL_set1_nextUpdate( crl.get(), a2);
150
151     X509_ALGOR_free(alg);
152     ASN1_BIT_STRING_free(sig);
153     ASN1_TIME_free(a1);
154     ASN1_TIME_free(a2);
155 }
156
157 bool CRL::needsResign() {
158     time_t current;
159     time( &current );
160     current += 60 * 60;// 1 hour
161     auto time = X509_CRL_get0_nextUpdate( crl.get() );
162
163     if( !time ) {
164         return true;
165     }
166
167     int cmp =  X509_cmp_time( time, &current );
168     return cmp < 0;
169 }