diff options
Diffstat (limited to 'src/cert/x509self')
-rw-r--r-- | src/cert/x509self/x509opt.cpp | 107 | ||||
-rw-r--r-- | src/cert/x509self/x509self.cpp | 166 | ||||
-rw-r--r-- | src/cert/x509self/x509self.h | 202 |
3 files changed, 475 insertions, 0 deletions
diff --git a/src/cert/x509self/x509opt.cpp b/src/cert/x509self/x509opt.cpp new file mode 100644 index 000000000..0702ebf19 --- /dev/null +++ b/src/cert/x509self/x509opt.cpp @@ -0,0 +1,107 @@ +/* +* X.509 Certificate Options +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/x509self.h> +#include <botan/oids.h> +#include <botan/parsing.h> +#include <botan/time.h> + +namespace Botan { + +/* +* Set when the certificate should become valid +*/ +void X509_Cert_Options::not_before(const std::string& time_string) + { + start = X509_Time(time_string); + } + +/* +* Set when the certificate should expire +*/ +void X509_Cert_Options::not_after(const std::string& time_string) + { + end = X509_Time(time_string); + } + +/* +* Set key constraint information +*/ +void X509_Cert_Options::add_constraints(Key_Constraints usage) + { + constraints = usage; + } + +/* +* Set key constraint information +*/ +void X509_Cert_Options::add_ex_constraint(const OID& oid) + { + ex_constraints.push_back(oid); + } + +/* +* Set key constraint information +*/ +void X509_Cert_Options::add_ex_constraint(const std::string& oid_str) + { + ex_constraints.push_back(OIDS::lookup(oid_str)); + } + +/* +* Mark this certificate for CA usage +*/ +void X509_Cert_Options::CA_key(u32bit limit) + { + is_CA = true; + path_limit = limit; + } + +/* +* Do basic sanity checks +*/ +void X509_Cert_Options::sanity_check() const + { + if(common_name == "" || country == "") + throw Encoding_Error("X.509 certificate: name and country MUST be set"); + if(country.size() != 2) + throw Encoding_Error("Invalid ISO country code: " + country); + if(start >= end) + throw Encoding_Error("X509_Cert_Options: invalid time constraints"); + } + +/* +* Initialize the certificate options +*/ +X509_Cert_Options::X509_Cert_Options(const std::string& initial_opts, + u32bit expiration_time_in_seconds) + { + is_CA = false; + path_limit = 0; + constraints = NO_CONSTRAINTS; + + const u64bit now = system_time(); + + start = X509_Time(now); + end = X509_Time(now + expiration_time_in_seconds); + + if(initial_opts == "") + return; + + std::vector<std::string> parsed = split_on(initial_opts, '/'); + + if(parsed.size() > 4) + throw Invalid_Argument("X.509 cert options: Too many names: " + + initial_opts); + + if(parsed.size() >= 1) common_name = parsed[0]; + if(parsed.size() >= 2) country = parsed[1]; + if(parsed.size() >= 3) organization = parsed[2]; + if(parsed.size() == 4) org_unit = parsed[3]; + } + +} diff --git a/src/cert/x509self/x509self.cpp b/src/cert/x509self/x509self.cpp new file mode 100644 index 000000000..e420ca503 --- /dev/null +++ b/src/cert/x509self/x509self.cpp @@ -0,0 +1,166 @@ +/* +* PKCS #10/Self Signed Cert Creation +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/x509self.h> +#include <botan/x509_ext.h> +#include <botan/x509_ca.h> +#include <botan/der_enc.h> +#include <botan/oids.h> +#include <botan/pipe.h> +#include <memory> + +namespace Botan { + +namespace { + +/* +* Load information from the X509_Cert_Options +*/ +void load_info(const X509_Cert_Options& opts, X509_DN& subject_dn, + AlternativeName& subject_alt) + { + subject_dn.add_attribute("X520.CommonName", opts.common_name); + subject_dn.add_attribute("X520.Country", opts.country); + subject_dn.add_attribute("X520.State", opts.state); + subject_dn.add_attribute("X520.Locality", opts.locality); + subject_dn.add_attribute("X520.Organization", opts.organization); + subject_dn.add_attribute("X520.OrganizationalUnit", opts.org_unit); + subject_dn.add_attribute("X520.SerialNumber", opts.serial_number); + subject_alt = AlternativeName(opts.email, opts.uri, opts.dns, opts.ip); + subject_alt.add_othername(OIDS::lookup("PKIX.XMPPAddr"), + opts.xmpp, UTF8_STRING); + } + +} + +namespace X509 { + +/* +* Create a new self-signed X.509 certificate +*/ +X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng) + { + AlgorithmIdentifier sig_algo; + X509_DN subject_dn; + AlternativeName subject_alt; + + opts.sanity_check(); + + MemoryVector<byte> pub_key = X509::BER_encode(key); + std::auto_ptr<PK_Signer> signer(choose_sig_format(key, hash_fn, sig_algo)); + load_info(opts, subject_dn, subject_alt); + + Key_Constraints constraints; + if(opts.is_CA) + constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); + else + constraints = find_constraints(key, opts.constraints); + + Extensions extensions; + + extensions.add( + new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit), + true); + + extensions.add(new Cert_Extension::Key_Usage(constraints), true); + + extensions.add(new Cert_Extension::Subject_Key_ID(pub_key)); + + extensions.add( + new Cert_Extension::Subject_Alternative_Name(subject_alt)); + + extensions.add( + new Cert_Extension::Extended_Key_Usage(opts.ex_constraints)); + + return X509_CA::make_cert(signer.get(), rng, sig_algo, pub_key, + opts.start, opts.end, + subject_dn, subject_dn, + extensions); + } + +/* +* Create a PKCS #10 certificate request +*/ +PKCS10_Request create_cert_req(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng) + { + AlgorithmIdentifier sig_algo; + X509_DN subject_dn; + AlternativeName subject_alt; + + opts.sanity_check(); + + MemoryVector<byte> pub_key = X509::BER_encode(key); + std::auto_ptr<PK_Signer> signer(choose_sig_format(key, hash_fn, sig_algo)); + load_info(opts, subject_dn, subject_alt); + + const u32bit PKCS10_VERSION = 0; + + Extensions extensions; + + extensions.add( + new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit)); + extensions.add( + new Cert_Extension::Key_Usage( + opts.is_CA ? Key_Constraints(KEY_CERT_SIGN | CRL_SIGN) : + find_constraints(key, opts.constraints) + ) + ); + extensions.add( + new Cert_Extension::Extended_Key_Usage(opts.ex_constraints)); + extensions.add( + new Cert_Extension::Subject_Alternative_Name(subject_alt)); + + DER_Encoder tbs_req; + + tbs_req.start_cons(SEQUENCE) + .encode(PKCS10_VERSION) + .encode(subject_dn) + .raw_bytes(pub_key) + .start_explicit(0); + + if(opts.challenge != "") + { + ASN1_String challenge(opts.challenge, DIRECTORY_STRING); + + tbs_req.encode( + Attribute("PKCS9.ChallengePassword", + DER_Encoder().encode(challenge).get_contents() + ) + ); + } + + tbs_req.encode( + Attribute("PKCS9.ExtensionRequest", + DER_Encoder() + .start_cons(SEQUENCE) + .encode(extensions) + .end_cons() + .get_contents() + ) + ) + .end_explicit() + .end_cons(); + + DataSource_Memory source( + X509_Object::make_signed(signer.get(), + rng, + sig_algo, + tbs_req.get_contents()) + ); + + return PKCS10_Request(source); + } + +} + +} diff --git a/src/cert/x509self/x509self.h b/src/cert/x509self/x509self.h new file mode 100644 index 000000000..df5731050 --- /dev/null +++ b/src/cert/x509self/x509self.h @@ -0,0 +1,202 @@ +/* +* X.509 Self-Signed Certificate +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_X509_SELF_H__ +#define BOTAN_X509_SELF_H__ + +#include <botan/x509cert.h> +#include <botan/pkcs8.h> +#include <botan/pkcs10.h> + +namespace Botan { + +/** +* Options for X.509 certificates. +*/ +class BOTAN_DLL X509_Cert_Options + { + public: + /** + * the subject common name + */ + std::string common_name; + + /** + * the subject counry + */ + std::string country; + + /** + * the subject organization + */ + std::string organization; + + /** + * the subject organizational unit + */ + std::string org_unit; + + /** + * the subject locality + */ + std::string locality; + + /** + * the subject state + */ + std::string state; + + /** + * the subject serial number + */ + std::string serial_number; + + /** + * the subject email adress + */ + std::string email; + + /** + * the subject URI + */ + std::string uri; + + /** + * the subject IPv4 address + */ + std::string ip; + + /** + * the subject DNS + */ + std::string dns; + + /** + * the subject XMPP + */ + std::string xmpp; + + /** + * the subject challenge password + */ + std::string challenge; + + /** + * the subject notBefore + */ + X509_Time start; + /** + * the subject notAfter + */ + X509_Time end; + + /** + * Indicates whether the certificate request + */ + bool is_CA; + + /** + * Indicates the BasicConstraints path limit + */ + u32bit path_limit; + + /** + * The key constraints for the subject public key + */ + Key_Constraints constraints; + + /** + * The key extended constraints for the subject public key + */ + std::vector<OID> ex_constraints; + + /** + * Check the options set in this object for validity. + */ + void sanity_check() const; + + /** + * Mark the certificate as a CA certificate and set the path limit. + * @param limit the path limit to be set in the BasicConstraints extension. + */ + void CA_key(u32bit limit = 1); + + /** + * Set the notBefore of the certificate. + * @param time the notBefore value of the certificate + */ + void not_before(const std::string& time); + + /** + * Set the notAfter of the certificate. + * @param time the notAfter value of the certificate + */ + void not_after(const std::string& time); + + /** + * Add the key constraints of the KeyUsage extension. + * @param constr the constraints to set + */ + void add_constraints(Key_Constraints constr); + + /** + * Add constraints to the ExtendedKeyUsage extension. + * @param oid the oid to add + */ + void add_ex_constraint(const OID& oid); + + /** + * Add constraints to the ExtendedKeyUsage extension. + * @param name the name to look up the oid to add + */ + void add_ex_constraint(const std::string& name); + + /** + * Construct a new options object + * @param opts define the common name of this object. An example for this + * parameter would be "common_name/country/organization/organizational_unit". + * @param expire_time the expiration time (from the current clock in seconds) + */ + X509_Cert_Options(const std::string& opts = "", + u32bit expire_time = 365 * 24 * 60 * 60); + }; + +namespace X509 { + +/** +* Create a self-signed X.509 certificate. +* @param opts the options defining the certificate to create +* @param key the private key used for signing, i.e. the key +* associated with this self-signed certificate +* @param hash_fn the hash function to use +* @param rng the rng to use +* @return newly created self-signed certificate +*/ +BOTAN_DLL X509_Certificate +create_self_signed_cert(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng); + +/** +* Create a PKCS#10 certificate request. +* @param opts the options defining the request to create +* @param key the key used to sign this request +* @param rng the rng to use +* @param hash_fn the hash function to use +* @return newly created PKCS#10 request +*/ +BOTAN_DLL PKCS10_Request create_cert_req(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng); + +} + +} + +#endif |