]> WPIA git - cassiopeia.git/blob - src/X509.cpp
chg: Split off X509-related API
[cassiopeia.git] / src / X509.cpp
1 #include "X509.h"
2
3 #include <openssl/ssl.h>
4 #include <openssl/bio.h>
5 #include <openssl/x509v3.h>
6
7 X509Req::X509Req( X509_REQ* csr ) {
8     req = std::shared_ptr<X509_REQ>( csr, X509_REQ_free );
9     EVP_PKEY* pkt = X509_REQ_get_pubkey( req.get() );
10
11     if( !pkt ) {
12         throw "Error extracting public key";
13     }
14
15     pk = std::shared_ptr<EVP_PKEY>( pkt, EVP_PKEY_free );
16 }
17
18 int X509Req::verify() {
19     return X509_REQ_verify( req.get(), pk.get() );
20 }
21
22 std::shared_ptr<EVP_PKEY> X509Req::getPkey() {
23     return pk;
24 }
25
26 std::shared_ptr<X509Req> X509Req::parse( std::string filename ) {
27     std::shared_ptr<BIO> in = std::shared_ptr<BIO>( BIO_new_mem_buf( const_cast<char*>( filename.c_str() ), -1 ), BIO_free );
28     X509_REQ* req = PEM_read_bio_X509_REQ( in.get(), NULL, NULL, NULL );
29
30     if( !req ) {
31         throw "Error parsing CSR";
32     }
33
34     return std::shared_ptr<X509Req>( new X509Req( req ) );
35 }
36
37 int add_ext( std::shared_ptr<X509> issuer, std::shared_ptr<X509> subj, int nid, const char* value ) {
38     X509_EXTENSION* ex;
39     X509V3_CTX ctx;
40
41     /* This sets the 'context' of the extensions. */
42     /* No configuration database */
43     X509V3_set_ctx_nodb( &ctx );
44
45     /* Issuer and subject certs: both the target since it is self signed,
46      * no request and no CRL
47      */
48     X509V3_set_ctx( &ctx, issuer.get(), subj.get(), NULL, NULL, 0 );
49     ex = X509V3_EXT_conf_nid( NULL, &ctx, nid, const_cast<char*>( value ) );
50
51     if( !ex ) {
52         return 0;
53     }
54
55     X509_add_ext( subj.get(), ex, -1 );
56     X509_EXTENSION_free( ex );
57
58     return 1;
59 }
60
61 X509Cert::X509Cert() {
62     X509* c = X509_new();
63
64     if( !c ) {
65         throw "malloc failed";
66     }
67
68     target = std::shared_ptr<X509>( c, X509_free );
69
70     if( !X509_set_version( c, 2 ) ) {
71         throw "Setting X509-version to 3 failed";
72     }
73 }
74
75 void X509Cert::setIssuerNameFrom( std::shared_ptr<X509> caCert ) {
76     if( !X509_set_issuer_name( target.get(), X509_get_subject_name( caCert.get() ) ) ) {
77         throw "Error setting Issuer name";
78     }
79 }
80
81 void X509Cert::setPubkeyFrom( std::shared_ptr<X509Req> req ) {
82     std::shared_ptr<EVP_PKEY> pktmp = req->getPkey();
83
84     if( !X509_set_pubkey( target.get(), pktmp.get() ) ) {
85         throw "Setting public key failed.";
86     }
87 }
88
89 void X509Cert::setSerialNumber( int num ) {
90     ASN1_INTEGER_set( target.get()->cert_info->serialNumber, num );
91 }
92
93 void X509Cert::setTimes( long before, long after ) {
94     X509_gmtime_adj( X509_get_notBefore( target.get() ), before );
95     X509_gmtime_adj( X509_get_notAfter( target.get() ), after );
96 }
97
98 void X509Cert::setExtensions( std::shared_ptr<X509> caCert ) {
99     add_ext( caCert, target, NID_basic_constraints, "critical,CA:FALSE" );
100     add_ext( caCert, target, NID_subject_key_identifier, "hash" );
101     add_ext( caCert, target, NID_authority_key_identifier, "keyid,issuer:always" );
102     add_ext( caCert, target, NID_key_usage, "critical,nonRepudiation,digitalSignature,keyEncipherment" );
103     add_ext( caCert, target, NID_ext_key_usage, "clientAuth, serverAuth" );
104     add_ext( caCert, target, NID_info_access, "OCSP;URI:http://ocsp.cacert.org" );
105     add_ext( caCert, target, NID_crl_distribution_points, "URI:http://crl.cacert.org/class3-revoke.crl" );
106 }
107
108 std::string X509Cert::sign( std::shared_ptr<EVP_PKEY> caKey ) {
109     if( !X509_sign( target.get(), caKey.get(), EVP_sha512() ) ) {
110         throw "Signing failed.";
111     }
112
113     X509_print_fp( stdout, target.get() );
114     std::shared_ptr<BIO> mem = std::shared_ptr<BIO>( BIO_new( BIO_s_mem() ), BIO_free );
115     PEM_write_bio_X509( mem.get(), target.get() );
116     BUF_MEM* buf;
117     BIO_get_mem_ptr( mem.get(), &buf );
118     std::string output( buf->data, buf->data + buf->length );
119     return output;
120 }