/************************************************* * PKCS #10/Self Signed Cert Creation Source File * * (C) 1999-2006 The Botan Project * *************************************************/ #include #include #include #include #include #include #include #include namespace Botan { namespace { /************************************************* * Shared setup for self-signed items * *************************************************/ MemoryVector shared_setup(const X509_Cert_Options& opts, const PKCS8_PrivateKey& key) { const PKCS8_PrivateKey* key_pointer = &key; if(!dynamic_cast(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); subject_alt.add_othername(OIDS::lookup("PKIX.XMPPAddr"), opts.xmpp, UTF8_STRING); } /************************************************* * Choose a signing format for the key * *************************************************/ PK_Signer* choose_sig_format(const PKCS8_PrivateKey& key, AlgorithmIdentifier& sig_algo) { std::string padding; Signature_Format format; Config::choose_sig_format(key.algo_name(), padding, format); sig_algo.oid = OIDS::lookup(key.algo_name() + "/" + padding); sig_algo.parameters = key.DER_encode_params(); const PK_Signing_Key& sig_key = dynamic_cast(key); return get_pk_signer(sig_key, padding, format); } } namespace X509 { /************************************************* * Create a new self-signed X.509 certificate * *************************************************/ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, const PKCS8_PrivateKey& key) { AlgorithmIdentifier sig_algo; X509_DN subject_dn; AlternativeName subject_alt; MemoryVector pub_key = shared_setup(opts, key); std::auto_ptr 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); return X509_CA::make_cert(signer.get(), sig_algo, pub_key, MemoryVector(), opts.start, opts.end, subject_dn, subject_dn, opts.is_CA, opts.path_limit, subject_alt, subject_alt, constraints, opts.ex_constraints); } /************************************************* * Create a PKCS #10 certificate request * *************************************************/ PKCS10_Request create_cert_req(const X509_Cert_Options& opts, const PKCS8_PrivateKey& key) { AlgorithmIdentifier sig_algo; X509_DN subject_dn; AlternativeName subject_alt; MemoryVector pub_key = shared_setup(opts, key); std::auto_ptr 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::Alternative_Name(subject_alt, "X509v3.SubjectAlternativeName", "subject_alternative_name") ); DER_Encoder tbs_req; tbs_req.start_sequence() .encode(PKCS10_VERSION) .encode(subject_dn) .add_raw_octets(pub_key) .start_explicit(ASN1_Tag(0)); if(opts.challenge != "") { ASN1_String challenge(opts.challenge, DIRECTORY_STRING); #if 0 DER_Encoder attr_encoder; attr_encoder.encode(challenge); tbs_req.encode( Attribute("PKCS9.ChallengePassword", attr_encoder.get_contents()) ); #else tbs_req.encode( Attribute("PKCS9.ChallengePassword", DER_Encoder().encode(challenge).get_contents() ) ); #endif } tbs_req.encode( Attribute("PKCS9.ExtensionRequest", DER_Encoder() .start_sequence() .encode(extensions) .end_sequence() .get_contents() ) ) .end_explicit(ASN1_Tag(0)) .end_sequence(); MemoryVector tbs_bits = tbs_req.get_contents(); MemoryVector sig = signer->sign_message(tbs_bits); DataSource_Memory source( DER_Encoder() .start_sequence() .add_raw_octets(tbs_bits) .encode(sig_algo) .encode(sig, BIT_STRING) .end_sequence() .get_contents() ); return PKCS10_Request(source); } } }