diff options
Diffstat (limited to 'src/x509/x509self.cpp')
-rw-r--r-- | src/x509/x509self.cpp | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/src/x509/x509self.cpp b/src/x509/x509self.cpp new file mode 100644 index 000000000..6c3baae9b --- /dev/null +++ b/src/x509/x509self.cpp @@ -0,0 +1,174 @@ +/************************************************* +* PKCS #10/Self Signed Cert Creation Source File * +* (C) 1999-2008 Jack Lloyd * +*************************************************/ + +#include <botan/x509self.h> +#include <botan/x509_ext.h> +#include <botan/x509_ca.h> +#include <botan/der_enc.h> +#include <botan/look_pk.h> +#include <botan/oids.h> +#include <botan/pipe.h> +#include <memory> + +namespace Botan { + +namespace { + +/************************************************* +* Shared setup for self-signed items * +*************************************************/ +MemoryVector<byte> shared_setup(const X509_Cert_Options& opts, + const Private_Key& key) + { + const Private_Key* key_pointer = &key; + if(!dynamic_cast<const PK_Signing_Key*>(key_pointer)) + throw Invalid_Argument("Key type " + key.algo_name() + " cannot sign"); + + opts.sanity_check(); + + Pipe key_encoder; + key_encoder.start_msg(); + X509::encode(key, key_encoder, RAW_BER); + key_encoder.end_msg(); + + return key_encoder.read_all(); + } + +/************************************************* +* 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, + RandomNumberGenerator& rng) + { + AlgorithmIdentifier sig_algo; + X509_DN subject_dn; + AlternativeName subject_alt; + + MemoryVector<byte> pub_key = shared_setup(opts, key); + std::auto_ptr<PK_Signer> signer(choose_sig_format(key, 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::Subject_Key_ID(pub_key)); + extensions.add(new Cert_Extension::Key_Usage(constraints)); + extensions.add( + new Cert_Extension::Extended_Key_Usage(opts.ex_constraints)); + extensions.add( + new Cert_Extension::Subject_Alternative_Name(subject_alt)); + extensions.add( + new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit)); + + 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, + RandomNumberGenerator& rng) + { + AlgorithmIdentifier sig_algo; + X509_DN subject_dn; + AlternativeName subject_alt; + + MemoryVector<byte> pub_key = shared_setup(opts, key); + std::auto_ptr<PK_Signer> signer(choose_sig_format(key, 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); + } + +} + +} |