/************************************************* * X.509 Certificate Authority Source File * * (C) 1999-2006 The Botan Project * *************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Botan { namespace { // FIXME: move elsewhere MemoryVector make_signed(PK_Signer* signer, const AlgorithmIdentifier& sig_algo, const MemoryRegion& tbs_bits) { return DER_Encoder().start_cons(SEQUENCE) .raw_bytes(tbs_bits) .encode(sig_algo) .encode(signer->sign_message(tbs_bits), BIT_STRING) .end_cons() .get_contents(); } } /************************************************* * Load the certificate and private key * *************************************************/ X509_CA::X509_CA(const X509_Certificate& c, const PKCS8_PrivateKey& key) : cert(c) { const PKCS8_PrivateKey* key_pointer = &key; if(!dynamic_cast(key_pointer)) throw Invalid_Argument("X509_CA: " + key.algo_name() + " cannot sign"); #if 0 // FIXME! if(!cert.is_CA_cert()) throw Invalid_Argument("X509_CA: This certificate is not for a CA"); #endif std::string padding; Signature_Format format; Config::choose_sig_format(key.algo_name(), padding, format); ca_sig_algo.oid = OIDS::lookup(key.algo_name() + "/" + padding); ca_sig_algo.parameters = key.DER_encode_params(); const PK_Signing_Key& sig_key = dynamic_cast(key); signer = get_pk_signer(sig_key, padding, format); } /************************************************* * Sign a PKCS #10 certificate request * *************************************************/ X509_Certificate X509_CA::sign_request(const PKCS10_Request& req, u32bit expire_time) const { if(req.is_CA() && !Config::get_bool("x509/ca/allow_ca")) throw Policy_Violation("X509_CA: Attempted to sign new CA certificate"); Key_Constraints constraints; if(req.is_CA()) constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); else { std::auto_ptr key(req.subject_public_key()); constraints = X509::find_constraints(*key, req.constraints()); } if(expire_time == 0) expire_time = Config::get_time("x509/ca/default_expire"); const u64bit current_time = system_time(); X509_Time not_before(current_time); X509_Time not_after(current_time + expire_time); return make_cert(signer, ca_sig_algo, req.raw_public_key(), cert.subject_key_id(), not_before, not_after, cert.subject_dn(), req.subject_dn(), req.is_CA(), req.path_limit(), req.subject_alt_name(), AlternativeName(), constraints, req.ex_constraints()); } /************************************************* * Create a new certificate * *************************************************/ X509_Certificate X509_CA::make_cert(PK_Signer* signer, const AlgorithmIdentifier& sig_algo, const MemoryRegion& pub_key, const MemoryRegion& auth_key_id, const X509_Time& not_before, const X509_Time& not_after, const X509_DN& issuer_dn, const X509_DN& subject_dn, bool is_CA, u32bit path_limit, const AlternativeName& subject_alt, const AlternativeName& issuer_alt, Key_Constraints constraints, const std::vector& ex_constraints) { Extensions extensions; // POLICY: which extensions extensions.add(new Cert_Extension::Subject_Key_ID(pub_key)); extensions.add(new Cert_Extension::Authority_Key_ID(auth_key_id)); extensions.add( new Cert_Extension::Basic_Constraints(is_CA, path_limit)); extensions.add(new Cert_Extension::Key_Usage(constraints)); extensions.add( new Cert_Extension::Extended_Key_Usage(ex_constraints)); extensions.add( new Cert_Extension::Alternative_Name(subject_alt, "X509v3.SubjectAlternativeName", "subject_alternative_name") ); extensions.add( new Cert_Extension::Alternative_Name(issuer_alt, "X509v3.IssuerAlternativeName", "issuer_alternative_name") ); const u32bit X509_CERT_VERSION = 3; const u32bit SERIAL_BITS = 128; DataSource_Memory source(make_signed(signer, sig_algo, DER_Encoder().start_cons(SEQUENCE) .start_explicit(0) .encode(X509_CERT_VERSION-1) .end_explicit() .encode(random_integer(SERIAL_BITS)) .encode(sig_algo) .encode(issuer_dn) .start_cons(SEQUENCE) .encode(not_before) .encode(not_after) .end_cons() .encode(subject_dn) .raw_bytes(pub_key) .start_explicit(3) .start_cons(SEQUENCE) .encode(extensions) .end_cons() .end_explicit() .end_cons() .get_contents() )); return X509_Certificate(source); } /************************************************* * Create a new, empty CRL * *************************************************/ X509_CRL X509_CA::new_crl(u32bit next_update) const { std::vector empty; return make_crl(empty, 1, next_update); } /************************************************* * Update a CRL with new entries * *************************************************/ X509_CRL X509_CA::update_crl(const X509_CRL& crl, const std::vector& new_revoked, u32bit next_update) const { std::vector already_revoked = crl.get_revoked(); std::vector all_revoked; X509_Store store; store.add_cert(cert, true); if(store.add_crl(crl) != VERIFIED) throw Invalid_Argument("X509_CA::update_crl: Invalid CRL provided"); std::set > removed_from_crl; for(u32bit j = 0; j != new_revoked.size(); ++j) { if(new_revoked[j].reason == DELETE_CRL_ENTRY) removed_from_crl.insert(new_revoked[j].serial); else all_revoked.push_back(new_revoked[j]); } for(u32bit j = 0; j != already_revoked.size(); ++j) { std::set >::const_iterator i; i = removed_from_crl.find(already_revoked[j].serial); if(i == removed_from_crl.end()) all_revoked.push_back(already_revoked[j]); } std::sort(all_revoked.begin(), all_revoked.end()); std::vector cert_list; std::unique_copy(all_revoked.begin(), all_revoked.end(), std::back_inserter(cert_list)); return make_crl(cert_list, crl.crl_number() + 1, next_update); } /************************************************* * Create a CRL * *************************************************/ X509_CRL X509_CA::make_crl(const std::vector& revoked, u32bit crl_number, u32bit next_update) const { const u32bit X509_CRL_VERSION = 2; if(next_update == 0) next_update = Config::get_time("x509/crl/next_update"); const u64bit current_time = system_time(); Extensions extensions; extensions.add( new Cert_Extension::Authority_Key_ID(cert.subject_key_id())); extensions.add(new Cert_Extension::CRL_Number(crl_number)); DataSource_Memory source(make_signed(signer, ca_sig_algo, DER_Encoder().start_cons(SEQUENCE) .encode(X509_CRL_VERSION-1) .encode(ca_sig_algo) .encode(cert.issuer_dn()) .encode(X509_Time(current_time)) .encode(X509_Time(current_time + next_update)) .encode_if(revoked.size() > 0, DER_Encoder() .start_cons(SEQUENCE) .encode_list(revoked) .end_cons() ) .start_explicit(0) .start_cons(SEQUENCE) .encode(extensions) .end_cons() .end_explicit() .end_cons() .get_contents() )); return X509_CRL(source); } /************************************************* * Return the CA's certificate * *************************************************/ X509_Certificate X509_CA::ca_certificate() const { return cert; } /************************************************* * X509_CA Destructor * *************************************************/ X509_CA::~X509_CA() { delete signer; } }