aboutsummaryrefslogtreecommitdiffstats
path: root/src/cert/x509
diff options
context:
space:
mode:
authorlloyd <[email protected]>2012-02-06 19:30:38 +0000
committerlloyd <[email protected]>2012-02-06 19:30:38 +0000
commitf1a2b5a7b5f35322927446d1b9a381f05cc677df (patch)
tree905b125d9173a32c4a3b758ae124ded0d045d635 /src/cert/x509
parentcd58927000ef86eacc9de5b80f361d4d05e71731 (diff)
All of the X509 modules were actually mutually dependent. Ideally this
would be fixed but it's quite hard to do, makes more sense for now to merge then back into one big x509 blog.
Diffstat (limited to 'src/cert/x509')
-rw-r--r--src/cert/x509/certstor.cpp101
-rw-r--r--src/cert/x509/certstor.h82
-rw-r--r--src/cert/x509/crl_ent.cpp104
-rw-r--r--src/cert/x509/crl_ent.h94
-rw-r--r--src/cert/x509/info.txt5
-rw-r--r--src/cert/x509/pkcs10.cpp199
-rw-r--r--src/cert/x509/pkcs10.h102
-rw-r--r--src/cert/x509/x509_ca.cpp253
-rw-r--r--src/cert/x509/x509_ca.h130
-rw-r--r--src/cert/x509/x509_crl.cpp185
-rw-r--r--src/cert/x509/x509_crl.h101
-rw-r--r--src/cert/x509/x509_ext.cpp584
-rw-r--r--src/cert/x509/x509_ext.h340
-rw-r--r--src/cert/x509/x509_obj.cpp241
-rw-r--r--src/cert/x509/x509_obj.h113
-rw-r--r--src/cert/x509/x509cert.cpp481
-rw-r--r--src/cert/x509/x509cert.h193
-rw-r--r--src/cert/x509/x509opt.cpp107
-rw-r--r--src/cert/x509/x509path.cpp211
-rw-r--r--src/cert/x509/x509path.h110
-rw-r--r--src/cert/x509/x509self.cpp166
-rw-r--r--src/cert/x509/x509self.h202
22 files changed, 4104 insertions, 0 deletions
diff --git a/src/cert/x509/certstor.cpp b/src/cert/x509/certstor.cpp
new file mode 100644
index 000000000..de27361ed
--- /dev/null
+++ b/src/cert/x509/certstor.cpp
@@ -0,0 +1,101 @@
+/*
+* Certificate Store
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/certstor.h>
+
+namespace Botan {
+
+bool Certificate_Store::certificate_known(const X509_Certificate& cert) const
+ {
+ std::vector<X509_Certificate> found =
+ find_cert_by_subject_and_key_id(cert.subject_dn(),
+ cert.subject_key_id());
+
+ return (found.size() > 0);
+ }
+
+void Certificate_Store_In_Memory::add_certificate(const X509_Certificate& cert)
+ {
+ for(size_t i = 0; i != certs.size(); ++i)
+ {
+ if(certs[i] == cert)
+ return;
+ }
+
+ certs.push_back(cert);
+ }
+
+std::vector<X509_Certificate>
+Certificate_Store_In_Memory::find_cert_by_subject_and_key_id(
+ const X509_DN& subject_dn,
+ const MemoryRegion<byte>& key_id) const
+ {
+ std::vector<X509_Certificate> result;
+
+ for(size_t i = 0; i != certs.size(); ++i)
+ {
+ // Only compare key ids if set in both call and in the cert
+ if(key_id.size())
+ {
+ MemoryVector<byte> skid = certs[i].subject_key_id();
+
+ if(skid.size() && skid != key_id) // no match
+ continue;
+ }
+
+ if(certs[i].subject_dn() == subject_dn)
+ result.push_back(certs[i]);
+ }
+
+ return result;
+ }
+
+void Certificate_Store_In_Memory::add_crl(const X509_CRL& crl)
+ {
+ X509_DN crl_issuer = crl.issuer_dn();
+
+ for(size_t i = 0; i != crls.size(); ++i)
+ {
+ // Found an update of a previously existing one; replace it
+ if(crls[i].issuer_dn() == crl_issuer)
+ {
+ if(crls[i].this_update() <= crl.this_update())
+ crls[i] = crl;
+ return;
+ }
+ }
+
+ // Totally new CRL, add to the list
+ crls.push_back(crl);
+ }
+
+std::vector<X509_CRL>
+Certificate_Store_In_Memory::find_crl_by_issuer_and_key_id(
+ const X509_DN& issuer_dn,
+ const MemoryRegion<byte>& key_id) const
+ {
+ std::vector<X509_CRL> result;
+
+ for(size_t i = 0; i != crls.size(); ++i)
+ {
+ // Only compare key ids if set in both call and in the CRL
+ if(key_id.size())
+ {
+ MemoryVector<byte> akid = crls[i].authority_key_id();
+
+ if(akid.size() && akid != key_id) // no match
+ continue;
+ }
+
+ if(crls[i].issuer_dn() == issuer_dn)
+ result.push_back(crls[i]);
+ }
+
+ return result;
+ }
+
+}
diff --git a/src/cert/x509/certstor.h b/src/cert/x509/certstor.h
new file mode 100644
index 000000000..e2727c569
--- /dev/null
+++ b/src/cert/x509/certstor.h
@@ -0,0 +1,82 @@
+/*
+* Certificate Store
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_CERT_STORE_H__
+#define BOTAN_CERT_STORE_H__
+
+#include <botan/x509cert.h>
+#include <botan/x509_crl.h>
+
+namespace Botan {
+
+/**
+* Certificate Store Interface
+*/
+class BOTAN_DLL Certificate_Store
+ {
+ public:
+ virtual ~Certificate_Store() {}
+
+ /**
+ * Add a certificate; this may fail if the store is write-only
+ */
+ virtual void add_certificate(const X509_Certificate& cert) = 0;
+
+ /**
+ * Add a CRL; this may fail if the store is write-only
+ */
+ virtual void add_crl(const X509_CRL& crl) = 0;
+
+ bool certificate_known(const X509_Certificate& cert) const;
+
+ /**
+ * Subject DN and (optionally) key identifier
+ */
+ virtual std::vector<X509_Certificate>
+ find_cert_by_subject_and_key_id(
+ const X509_DN& subject_dn,
+ const MemoryRegion<byte>& key_id) const = 0;
+
+ /**
+ * Find CRLs by the DN and key id of the issuer
+ */
+ virtual std::vector<X509_CRL>
+ find_crl_by_issuer_and_key_id(
+ const X509_DN& issuer_dn,
+ const MemoryRegion<byte>& key_id) const = 0;
+ };
+
+/**
+* In Memory Certificate Store
+*/
+class BOTAN_DLL Certificate_Store_In_Memory : public Certificate_Store
+ {
+ public:
+ void add_certificate(const X509_Certificate& cert);
+
+ void add_crl(const X509_CRL& crl);
+
+ std::vector<X509_Certificate> find_cert_by_subject_and_key_id(
+ const X509_DN& subject_dn,
+ const MemoryRegion<byte>& key_id) const;
+
+ std::vector<X509_CRL> find_crl_by_issuer_and_key_id(
+ const X509_DN& issuer_dn,
+ const MemoryRegion<byte>& key_id) const;
+
+ Certificate_Store_In_Memory() {}
+ private:
+ // TODO: Add indexing on the DN and key id to avoid linear search
+ std::vector<X509_Certificate> certs;
+ std::vector<X509_CRL> crls;
+ };
+
+// TODO: file-backed store
+
+}
+
+#endif
diff --git a/src/cert/x509/crl_ent.cpp b/src/cert/x509/crl_ent.cpp
new file mode 100644
index 000000000..d566637f6
--- /dev/null
+++ b/src/cert/x509/crl_ent.cpp
@@ -0,0 +1,104 @@
+/*
+* CRL Entry
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/crl_ent.h>
+#include <botan/x509_ext.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/bigint.h>
+#include <botan/oids.h>
+#include <botan/time.h>
+
+namespace Botan {
+
+/*
+* Create a CRL_Entry
+*/
+CRL_Entry::CRL_Entry(bool t_on_unknown_crit) :
+ throw_on_unknown_critical(t_on_unknown_crit)
+ {
+ reason = UNSPECIFIED;
+ }
+
+/*
+* Create a CRL_Entry
+*/
+CRL_Entry::CRL_Entry(const X509_Certificate& cert, CRL_Code why) :
+ throw_on_unknown_critical(false)
+ {
+ serial = cert.serial_number();
+ time = X509_Time(system_time());
+ reason = why;
+ }
+
+/*
+* Compare two CRL_Entrys for equality
+*/
+bool operator==(const CRL_Entry& a1, const CRL_Entry& a2)
+ {
+ if(a1.serial_number() != a2.serial_number())
+ return false;
+ if(a1.expire_time() != a2.expire_time())
+ return false;
+ if(a1.reason_code() != a2.reason_code())
+ return false;
+ return true;
+ }
+
+/*
+* Compare two CRL_Entrys for inequality
+*/
+bool operator!=(const CRL_Entry& a1, const CRL_Entry& a2)
+ {
+ return !(a1 == a2);
+ }
+
+/*
+* DER encode a CRL_Entry
+*/
+void CRL_Entry::encode_into(DER_Encoder& der) const
+ {
+ Extensions extensions;
+
+ extensions.add(new Cert_Extension::CRL_ReasonCode(reason));
+
+ der.start_cons(SEQUENCE)
+ .encode(BigInt::decode(serial))
+ .encode(time)
+ .start_cons(SEQUENCE)
+ .encode(extensions)
+ .end_cons()
+ .end_cons();
+ }
+
+/*
+* Decode a BER encoded CRL_Entry
+*/
+void CRL_Entry::decode_from(BER_Decoder& source)
+ {
+ BigInt serial_number_bn;
+ reason = UNSPECIFIED;
+
+ BER_Decoder entry = source.start_cons(SEQUENCE);
+
+ entry.decode(serial_number_bn).decode(time);
+
+ if(entry.more_items())
+ {
+ Extensions extensions(throw_on_unknown_critical);
+ entry.decode(extensions);
+ Data_Store info;
+ extensions.contents_to(info, info);
+ reason = CRL_Code(info.get1_u32bit("X509v3.CRLReasonCode"));
+ }
+
+ entry.end_cons();
+
+ serial = BigInt::encode(serial_number_bn);
+ }
+
+}
diff --git a/src/cert/x509/crl_ent.h b/src/cert/x509/crl_ent.h
new file mode 100644
index 000000000..ae9535484
--- /dev/null
+++ b/src/cert/x509/crl_ent.h
@@ -0,0 +1,94 @@
+/*
+* CRL Entry
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_CRL_ENTRY_H__
+#define BOTAN_CRL_ENTRY_H__
+
+#include <botan/x509cert.h>
+
+namespace Botan {
+
+/**
+* X.509v2 CRL Reason Code.
+*/
+enum CRL_Code {
+ UNSPECIFIED = 0,
+ KEY_COMPROMISE = 1,
+ CA_COMPROMISE = 2,
+ AFFILIATION_CHANGED = 3,
+ SUPERSEDED = 4,
+ CESSATION_OF_OPERATION = 5,
+ CERTIFICATE_HOLD = 6,
+ REMOVE_FROM_CRL = 8,
+ PRIVLEDGE_WITHDRAWN = 9,
+ AA_COMPROMISE = 10,
+
+ DELETE_CRL_ENTRY = 0xFF00,
+ OCSP_GOOD = 0xFF01,
+ OCSP_UNKNOWN = 0xFF02
+};
+
+/**
+* This class represents CRL entries
+*/
+class BOTAN_DLL CRL_Entry : public ASN1_Object
+ {
+ public:
+ void encode_into(class DER_Encoder&) const;
+ void decode_from(class BER_Decoder&);
+
+ /**
+ * Get the serial number of the certificate associated with this entry.
+ * @return certificate's serial number
+ */
+ MemoryVector<byte> serial_number() const { return serial; }
+
+ /**
+ * Get the revocation date of the certificate associated with this entry
+ * @return certificate's revocation date
+ */
+ X509_Time expire_time() const { return time; }
+
+ /**
+ * Get the entries reason code
+ * @return reason code
+ */
+ CRL_Code reason_code() const { return reason; }
+
+ /**
+ * Construct an empty CRL entry.
+ */
+ CRL_Entry(bool throw_on_unknown_critical_extension = false);
+
+ /**
+ * Construct an CRL entry.
+ * @param cert the certificate to revoke
+ * @param reason the reason code to set in the entry
+ */
+ CRL_Entry(const X509_Certificate& cert,
+ CRL_Code reason = UNSPECIFIED);
+
+ private:
+ bool throw_on_unknown_critical;
+ MemoryVector<byte> serial;
+ X509_Time time;
+ CRL_Code reason;
+ };
+
+/**
+* Test two CRL entries for equality in all fields.
+*/
+BOTAN_DLL bool operator==(const CRL_Entry&, const CRL_Entry&);
+
+/**
+* Test two CRL entries for inequality in at least one field.
+*/
+BOTAN_DLL bool operator!=(const CRL_Entry&, const CRL_Entry&);
+
+}
+
+#endif
diff --git a/src/cert/x509/info.txt b/src/cert/x509/info.txt
new file mode 100644
index 000000000..c994dab8f
--- /dev/null
+++ b/src/cert/x509/info.txt
@@ -0,0 +1,5 @@
+define X509_CERTIFICATES
+
+<requires>
+datastor
+</requires>
diff --git a/src/cert/x509/pkcs10.cpp b/src/cert/x509/pkcs10.cpp
new file mode 100644
index 000000000..784318d3d
--- /dev/null
+++ b/src/cert/x509/pkcs10.cpp
@@ -0,0 +1,199 @@
+/*
+* PKCS #10
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/pkcs10.h>
+#include <botan/x509_ext.h>
+#include <botan/x509cert.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/parsing.h>
+#include <botan/oids.h>
+#include <botan/pem.h>
+
+namespace Botan {
+
+/*
+* PKCS10_Request Constructor
+*/
+PKCS10_Request::PKCS10_Request(DataSource& in) :
+ X509_Object(in, "CERTIFICATE REQUEST/NEW CERTIFICATE REQUEST")
+ {
+ do_decode();
+ }
+
+/*
+* PKCS10_Request Constructor
+*/
+PKCS10_Request::PKCS10_Request(const std::string& in) :
+ X509_Object(in, "CERTIFICATE REQUEST/NEW CERTIFICATE REQUEST")
+ {
+ do_decode();
+ }
+
+/*
+* Deocde the CertificateRequestInfo
+*/
+void PKCS10_Request::force_decode()
+ {
+ BER_Decoder cert_req_info(tbs_bits);
+
+ size_t version;
+ cert_req_info.decode(version);
+ if(version != 0)
+ throw Decoding_Error("Unknown version code in PKCS #10 request: " +
+ to_string(version));
+
+ X509_DN dn_subject;
+ cert_req_info.decode(dn_subject);
+
+ info.add(dn_subject.contents());
+
+ BER_Object public_key = cert_req_info.get_next_object();
+ if(public_key.type_tag != SEQUENCE || public_key.class_tag != CONSTRUCTED)
+ throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for public key",
+ public_key.type_tag, public_key.class_tag);
+
+ info.add("X509.Certificate.public_key",
+ PEM_Code::encode(
+ ASN1::put_in_sequence(public_key.value),
+ "PUBLIC KEY"
+ )
+ );
+
+ BER_Object attr_bits = cert_req_info.get_next_object();
+
+ if(attr_bits.type_tag == 0 &&
+ attr_bits.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
+ {
+ BER_Decoder attributes(attr_bits.value);
+ while(attributes.more_items())
+ {
+ Attribute attr;
+ attributes.decode(attr);
+ handle_attribute(attr);
+ }
+ attributes.verify_end();
+ }
+ else if(attr_bits.type_tag != NO_OBJECT)
+ throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for attributes",
+ attr_bits.type_tag, attr_bits.class_tag);
+
+ cert_req_info.verify_end();
+
+ if(!this->check_signature(subject_public_key()))
+ throw Decoding_Error("PKCS #10 request: Bad signature detected");
+ }
+
+/*
+* Handle attributes in a PKCS #10 request
+*/
+void PKCS10_Request::handle_attribute(const Attribute& attr)
+ {
+ BER_Decoder value(attr.parameters);
+
+ if(attr.oid == OIDS::lookup("PKCS9.EmailAddress"))
+ {
+ ASN1_String email;
+ value.decode(email);
+ info.add("RFC822", email.value());
+ }
+ else if(attr.oid == OIDS::lookup("PKCS9.ChallengePassword"))
+ {
+ ASN1_String challenge_password;
+ value.decode(challenge_password);
+ info.add("PKCS9.ChallengePassword", challenge_password.value());
+ }
+ else if(attr.oid == OIDS::lookup("PKCS9.ExtensionRequest"))
+ {
+ Extensions extensions;
+ value.decode(extensions).verify_end();
+
+ Data_Store issuer_info;
+ extensions.contents_to(info, issuer_info);
+ }
+ }
+
+/*
+* Return the challenge password (if any)
+*/
+std::string PKCS10_Request::challenge_password() const
+ {
+ return info.get1("PKCS9.ChallengePassword");
+ }
+
+/*
+* Return the name of the requestor
+*/
+X509_DN PKCS10_Request::subject_dn() const
+ {
+ return create_dn(info);
+ }
+
+/*
+* Return the public key of the requestor
+*/
+MemoryVector<byte> PKCS10_Request::raw_public_key() const
+ {
+ DataSource_Memory source(info.get1("X509.Certificate.public_key"));
+ return PEM_Code::decode_check_label(source, "PUBLIC KEY");
+ }
+
+/*
+* Return the public key of the requestor
+*/
+Public_Key* PKCS10_Request::subject_public_key() const
+ {
+ DataSource_Memory source(info.get1("X509.Certificate.public_key"));
+ return X509::load_key(source);
+ }
+
+/*
+* Return the alternative names of the requestor
+*/
+AlternativeName PKCS10_Request::subject_alt_name() const
+ {
+ return create_alt_name(info);
+ }
+
+/*
+* Return the key constraints (if any)
+*/
+Key_Constraints PKCS10_Request::constraints() const
+ {
+ return Key_Constraints(info.get1_u32bit("X509v3.KeyUsage", NO_CONSTRAINTS));
+ }
+
+/*
+* Return the extendend key constraints (if any)
+*/
+std::vector<OID> PKCS10_Request::ex_constraints() const
+ {
+ std::vector<std::string> oids = info.get("X509v3.ExtendedKeyUsage");
+
+ std::vector<OID> result;
+ for(size_t i = 0; i != oids.size(); ++i)
+ result.push_back(OID(oids[i]));
+ return result;
+ }
+
+/*
+* Return is a CA certificate is requested
+*/
+bool PKCS10_Request::is_CA() const
+ {
+ return (info.get1_u32bit("X509v3.BasicConstraints.is_ca") > 0);
+ }
+
+/*
+* Return the desired path limit (if any)
+*/
+u32bit PKCS10_Request::path_limit() const
+ {
+ return info.get1_u32bit("X509v3.BasicConstraints.path_constraint", 0);
+ }
+
+}
diff --git a/src/cert/x509/pkcs10.h b/src/cert/x509/pkcs10.h
new file mode 100644
index 000000000..bd01fb6b5
--- /dev/null
+++ b/src/cert/x509/pkcs10.h
@@ -0,0 +1,102 @@
+/*
+* PKCS #10
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_PKCS10_H__
+#define BOTAN_PKCS10_H__
+
+#include <botan/x509_obj.h>
+#include <botan/x509_dn.h>
+#include <botan/pkcs8.h>
+#include <botan/datastor.h>
+#include <vector>
+
+namespace Botan {
+
+/**
+* PKCS #10 Certificate Request.
+*/
+class BOTAN_DLL PKCS10_Request : public X509_Object
+ {
+ public:
+ /**
+ * Get the subject public key.
+ * @return subject public key
+ */
+ Public_Key* subject_public_key() const;
+
+ /**
+ * Get the raw DER encoded public key.
+ * @return raw DER encoded public key
+ */
+ MemoryVector<byte> raw_public_key() const;
+
+ /**
+ * Get the subject DN.
+ * @return subject DN
+ */
+ X509_DN subject_dn() const;
+
+ /**
+ * Get the subject alternative name.
+ * @return subject alternative name.
+ */
+ AlternativeName subject_alt_name() const;
+
+ /**
+ * Get the key constraints for the key associated with this
+ * PKCS#10 object.
+ * @return key constraints
+ */
+ Key_Constraints constraints() const;
+
+ /**
+ * Get the extendend key constraints (if any).
+ * @return extended key constraints
+ */
+ std::vector<OID> ex_constraints() const;
+
+ /**
+ * Find out whether this is a CA request.
+ * @result true if it is a CA request, false otherwise.
+ */
+ bool is_CA() const;
+
+ /**
+ * Return the constraint on the path length defined
+ * in the BasicConstraints extension.
+ * @return path limit
+ */
+ u32bit path_limit() const;
+
+ /**
+ * Get the challenge password for this request
+ * @return challenge password for this request
+ */
+ std::string challenge_password() const;
+
+ /**
+ * Create a PKCS#10 Request from a data source.
+ * @param source the data source providing the DER encoded request
+ */
+ PKCS10_Request(DataSource& source);
+
+ /**
+ * Create a PKCS#10 Request from a file.
+ * @param filename the name of the file containing the DER or PEM
+ * encoded request file
+ */
+ PKCS10_Request(const std::string& filename);
+ private:
+ void force_decode();
+ void handle_attribute(const Attribute&);
+
+ Data_Store info;
+ };
+
+}
+
+#endif
diff --git a/src/cert/x509/x509_ca.cpp b/src/cert/x509/x509_ca.cpp
new file mode 100644
index 000000000..40f2e3b3a
--- /dev/null
+++ b/src/cert/x509/x509_ca.cpp
@@ -0,0 +1,253 @@
+/*
+* X.509 Certificate Authority
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/x509_ca.h>
+#include <botan/pubkey.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/bigint.h>
+#include <botan/parsing.h>
+#include <botan/lookup.h>
+#include <botan/oids.h>
+#include <botan/time.h>
+#include <algorithm>
+#include <typeinfo>
+#include <iterator>
+#include <memory>
+#include <set>
+
+namespace Botan {
+
+/*
+* Load the certificate and private key
+*/
+X509_CA::X509_CA(const X509_Certificate& c,
+ const Private_Key& key,
+ const std::string& hash_fn) : cert(c)
+ {
+ if(!cert.is_CA_cert())
+ throw Invalid_Argument("X509_CA: This certificate is not for a CA");
+
+ signer = choose_sig_format(key, hash_fn, ca_sig_algo);
+ }
+
+/*
+* X509_CA Destructor
+*/
+X509_CA::~X509_CA()
+ {
+ delete signer;
+ }
+
+/*
+* Sign a PKCS #10 certificate request
+*/
+X509_Certificate X509_CA::sign_request(const PKCS10_Request& req,
+ RandomNumberGenerator& rng,
+ const X509_Time& not_before,
+ const X509_Time& not_after)
+ {
+ Key_Constraints constraints;
+ if(req.is_CA())
+ constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN);
+ else
+ {
+ std::auto_ptr<Public_Key> key(req.subject_public_key());
+ constraints = X509::find_constraints(*key, req.constraints());
+ }
+
+ Extensions extensions;
+
+ extensions.add(
+ new Cert_Extension::Basic_Constraints(req.is_CA(), req.path_limit()),
+ true);
+
+ extensions.add(new Cert_Extension::Key_Usage(constraints), true);
+
+ extensions.add(new Cert_Extension::Authority_Key_ID(cert.subject_key_id()));
+ extensions.add(new Cert_Extension::Subject_Key_ID(req.raw_public_key()));
+
+ extensions.add(
+ new Cert_Extension::Subject_Alternative_Name(req.subject_alt_name()));
+
+ extensions.add(
+ new Cert_Extension::Extended_Key_Usage(req.ex_constraints()));
+
+ return make_cert(signer, rng, ca_sig_algo,
+ req.raw_public_key(),
+ not_before, not_after,
+ cert.subject_dn(), req.subject_dn(),
+ extensions);
+ }
+
+/*
+* Create a new certificate
+*/
+X509_Certificate X509_CA::make_cert(PK_Signer* signer,
+ RandomNumberGenerator& rng,
+ const AlgorithmIdentifier& sig_algo,
+ const MemoryRegion<byte>& pub_key,
+ const X509_Time& not_before,
+ const X509_Time& not_after,
+ const X509_DN& issuer_dn,
+ const X509_DN& subject_dn,
+ const Extensions& extensions)
+ {
+ const size_t X509_CERT_VERSION = 3;
+ const size_t SERIAL_BITS = 128;
+
+ BigInt serial_no(rng, SERIAL_BITS);
+
+ DataSource_Memory source(X509_Object::make_signed(signer, rng, sig_algo,
+ DER_Encoder().start_cons(SEQUENCE)
+ .start_explicit(0)
+ .encode(X509_CERT_VERSION-1)
+ .end_explicit()
+
+ .encode(serial_no)
+
+ .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(RandomNumberGenerator& rng,
+ u32bit next_update) const
+ {
+ std::vector<CRL_Entry> empty;
+ return make_crl(empty, 1, next_update, rng);
+ }
+
+/*
+* Update a CRL with new entries
+*/
+X509_CRL X509_CA::update_crl(const X509_CRL& crl,
+ const std::vector<CRL_Entry>& new_revoked,
+ RandomNumberGenerator& rng,
+ u32bit next_update) const
+ {
+ std::vector<CRL_Entry> revoked = crl.get_revoked();
+
+ std::copy(new_revoked.begin(), new_revoked.end(),
+ std::back_inserter(revoked));
+
+ return make_crl(revoked, crl.crl_number() + 1, next_update, rng);
+ }
+
+/*
+* Create a CRL
+*/
+X509_CRL X509_CA::make_crl(const std::vector<CRL_Entry>& revoked,
+ u32bit crl_number, u32bit next_update,
+ RandomNumberGenerator& rng) const
+ {
+ const size_t X509_CRL_VERSION = 2;
+
+ if(next_update == 0)
+ next_update = timespec_to_u32bit("7d");
+
+ // Totally stupid: ties encoding logic to the return of std::time!!
+ 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(X509_Object::make_signed(signer, rng, 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;
+ }
+
+/*
+* Choose a signing format for the key
+*/
+PK_Signer* choose_sig_format(const Private_Key& key,
+ const std::string& hash_fn,
+ AlgorithmIdentifier& sig_algo)
+ {
+ std::string padding;
+
+ const std::string algo_name = key.algo_name();
+
+ const HashFunction* proto_hash = retrieve_hash(hash_fn);
+ if(!proto_hash)
+ throw Algorithm_Not_Found(hash_fn);
+
+ if(key.max_input_bits() < proto_hash->output_length()*8)
+ throw Invalid_Argument("Key is too small for chosen hash function");
+
+ if(algo_name == "RSA")
+ padding = "EMSA3";
+ else if(algo_name == "DSA")
+ padding = "EMSA1";
+ else if(algo_name == "ECDSA")
+ padding = "EMSA1_BSI";
+ else
+ throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name);
+
+ Signature_Format format =
+ (key.message_parts() > 1) ? DER_SEQUENCE : IEEE_1363;
+
+ padding = padding + '(' + proto_hash->name() + ')';
+
+ sig_algo.oid = OIDS::lookup(algo_name + "/" + padding);
+ sig_algo.parameters = key.algorithm_identifier().parameters;
+
+ return new PK_Signer(key, padding, format);
+ }
+
+}
diff --git a/src/cert/x509/x509_ca.h b/src/cert/x509/x509_ca.h
new file mode 100644
index 000000000..97be6a415
--- /dev/null
+++ b/src/cert/x509/x509_ca.h
@@ -0,0 +1,130 @@
+/*
+* X.509 Certificate Authority
+* (C) 1999-2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_X509_CA_H__
+#define BOTAN_X509_CA_H__
+
+#include <botan/x509cert.h>
+#include <botan/x509_crl.h>
+#include <botan/x509_ext.h>
+#include <botan/pkcs8.h>
+#include <botan/pkcs10.h>
+#include <botan/pubkey.h>
+
+namespace Botan {
+
+/**
+* This class represents X.509 Certificate Authorities (CAs).
+*/
+class BOTAN_DLL X509_CA
+ {
+ public:
+
+ /**
+ * Sign a PKCS#10 Request.
+ * @param req the request to sign
+ * @param rng the rng to use
+ * @param not_before the starting time for the certificate
+ * @param not_after the expiration time for the certificate
+ * @return resulting certificate
+ */
+ X509_Certificate sign_request(const PKCS10_Request& req,
+ RandomNumberGenerator& rng,
+ const X509_Time& not_before,
+ const X509_Time& not_after);
+
+ /**
+ * Get the certificate of this CA.
+ * @return CA certificate
+ */
+ X509_Certificate ca_certificate() const;
+
+ /**
+ * Create a new and empty CRL for this CA.
+ * @param rng the random number generator to use
+ * @param next_update the time to set in next update in seconds
+ * as the offset from the current time
+ * @return new CRL
+ */
+ X509_CRL new_crl(RandomNumberGenerator& rng,
+ u32bit next_update = 0) const;
+
+ /**
+ * Create a new CRL by with additional entries.
+ * @param last_crl the last CRL of this CA to add the new entries to
+ * @param new_entries contains the new CRL entries to be added to the CRL
+ * @param rng the random number generator to use
+ * @param next_update the time to set in next update in seconds
+ * as the offset from the current time
+ */
+ X509_CRL update_crl(const X509_CRL& last_crl,
+ const std::vector<CRL_Entry>& new_entries,
+ RandomNumberGenerator& rng,
+ u32bit next_update = 0) const;
+
+ /**
+ * Interface for creating new certificates
+ * @param signer a signing object
+ * @param rng a random number generator
+ * @param sig_algo the signature algorithm identifier
+ * @param pub_key the serialized public key
+ * @param not_before the start time of the certificate
+ * @param not_after the end time of the certificate
+ * @param issuer_dn the DN of the issuer
+ * @param subject_dn the DN of the subject
+ * @param extensions an optional list of certificate extensions
+ * @returns newly minted certificate
+ */
+ static X509_Certificate make_cert(PK_Signer* signer,
+ RandomNumberGenerator& rng,
+ const AlgorithmIdentifier& sig_algo,
+ const MemoryRegion<byte>& pub_key,
+ const X509_Time& not_before,
+ const X509_Time& not_after,
+ const X509_DN& issuer_dn,
+ const X509_DN& subject_dn,
+ const Extensions& extensions);
+
+ /**
+ * Create a new CA object.
+ * @param ca_certificate the certificate of the CA
+ * @param key the private key of the CA
+ * @param hash_fn name of a hash function to use for signing
+ */
+ X509_CA(const X509_Certificate& ca_certificate,
+ const Private_Key& key,
+ const std::string& hash_fn);
+
+ ~X509_CA();
+ private:
+ X509_CA(const X509_CA&) {}
+ X509_CA& operator=(const X509_CA&) { return (*this); }
+
+ X509_CRL make_crl(const std::vector<CRL_Entry>& entries,
+ u32bit crl_number, u32bit next_update,
+ RandomNumberGenerator& rng) const;
+
+ AlgorithmIdentifier ca_sig_algo;
+ X509_Certificate cert;
+ PK_Signer* signer;
+ };
+
+/**
+* Choose the default signature format for a certain public key signature
+* scheme.
+* @param key will be the key to choose a padding scheme for
+* @param hash_fn is the desired hash function
+* @param alg_id will be set to the chosen scheme
+* @return A PK_Signer object for generating signatures
+*/
+BOTAN_DLL PK_Signer* choose_sig_format(const Private_Key& key,
+ const std::string& hash_fn,
+ AlgorithmIdentifier& alg_id);
+
+}
+
+#endif
diff --git a/src/cert/x509/x509_crl.cpp b/src/cert/x509/x509_crl.cpp
new file mode 100644
index 000000000..9c6b891c7
--- /dev/null
+++ b/src/cert/x509/x509_crl.cpp
@@ -0,0 +1,185 @@
+/*
+* X.509 CRL
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/x509_crl.h>
+#include <botan/x509_ext.h>
+#include <botan/x509cert.h>
+#include <botan/ber_dec.h>
+#include <botan/parsing.h>
+#include <botan/bigint.h>
+#include <botan/oids.h>
+
+namespace Botan {
+
+/*
+* Load a X.509 CRL
+*/
+X509_CRL::X509_CRL(DataSource& in, bool touc) :
+ X509_Object(in, "X509 CRL/CRL"), throw_on_unknown_critical(touc)
+ {
+ do_decode();
+ }
+
+/*
+* Load a X.509 CRL
+*/
+X509_CRL::X509_CRL(const std::string& in, bool touc) :
+ X509_Object(in, "CRL/X509 CRL"), throw_on_unknown_critical(touc)
+ {
+ do_decode();
+ }
+
+/**
+* Check if this particular certificate is listed in the CRL
+*/
+bool X509_CRL::is_revoked(const X509_Certificate& cert) const
+ {
+ /*
+ If the cert wasn't issued by the CRL issuer, it's possible the cert
+ is revoked, but not by this CRL. Maybe throw an exception instead?
+ */
+ if(cert.issuer_dn() != issuer_dn())
+ return false;
+
+ MemoryVector<byte> crl_akid = authority_key_id();
+ MemoryVector<byte> cert_akid = cert.authority_key_id();
+
+ if(!crl_akid.empty() && !cert_akid.empty())
+ if(crl_akid != cert_akid)
+ return false;
+
+ MemoryVector<byte> cert_serial = cert.serial_number();
+
+ bool is_revoked = false;
+
+ for(size_t i = 0; i != revoked.size(); ++i)
+ {
+ if(cert_serial == revoked[i].serial_number())
+ {
+ if(revoked[i].reason_code() == REMOVE_FROM_CRL)
+ is_revoked = false;
+ else
+ is_revoked = true;
+ }
+ }
+
+ return is_revoked;
+ }
+
+/*
+* Decode the TBSCertList data
+*/
+void X509_CRL::force_decode()
+ {
+ BER_Decoder tbs_crl(tbs_bits);
+
+ size_t version;
+ tbs_crl.decode_optional(version, INTEGER, UNIVERSAL);
+
+ if(version != 0 && version != 1)
+ throw X509_CRL_Error("Unknown X.509 CRL version " +
+ to_string(version+1));
+
+ AlgorithmIdentifier sig_algo_inner;
+ tbs_crl.decode(sig_algo_inner);
+
+ if(sig_algo != sig_algo_inner)
+ throw X509_CRL_Error("Algorithm identifier mismatch");
+
+ X509_DN dn_issuer;
+ tbs_crl.decode(dn_issuer);
+ info.add(dn_issuer.contents());
+
+ X509_Time start, end;
+ tbs_crl.decode(start).decode(end);
+ info.add("X509.CRL.start", start.readable_string());
+ info.add("X509.CRL.end", end.readable_string());
+
+ BER_Object next = tbs_crl.get_next_object();
+
+ if(next.type_tag == SEQUENCE && next.class_tag == CONSTRUCTED)
+ {
+ BER_Decoder cert_list(next.value);
+
+ while(cert_list.more_items())
+ {
+ CRL_Entry entry(throw_on_unknown_critical);
+ cert_list.decode(entry);
+ revoked.push_back(entry);
+ }
+ next = tbs_crl.get_next_object();
+ }
+
+ if(next.type_tag == 0 &&
+ next.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
+ {
+ BER_Decoder crl_options(next.value);
+
+ Extensions extensions(throw_on_unknown_critical);
+
+ crl_options.decode(extensions).verify_end();
+
+ extensions.contents_to(info, info);
+
+ next = tbs_crl.get_next_object();
+ }
+
+ if(next.type_tag != NO_OBJECT)
+ throw X509_CRL_Error("Unknown tag in CRL");
+
+ tbs_crl.verify_end();
+ }
+
+/*
+* Return the list of revoked certificates
+*/
+std::vector<CRL_Entry> X509_CRL::get_revoked() const
+ {
+ return revoked;
+ }
+
+/*
+* Return the distinguished name of the issuer
+*/
+X509_DN X509_CRL::issuer_dn() const
+ {
+ return create_dn(info);
+ }
+
+/*
+* Return the key identifier of the issuer
+*/
+MemoryVector<byte> X509_CRL::authority_key_id() const
+ {
+ return info.get1_memvec("X509v3.AuthorityKeyIdentifier");
+ }
+
+/*
+* Return the CRL number of this CRL
+*/
+u32bit X509_CRL::crl_number() const
+ {
+ return info.get1_u32bit("X509v3.CRLNumber");
+ }
+
+/*
+* Return the issue data of the CRL
+*/
+X509_Time X509_CRL::this_update() const
+ {
+ return info.get1("X509.CRL.start");
+ }
+
+/*
+* Return the date when a new CRL will be issued
+*/
+X509_Time X509_CRL::next_update() const
+ {
+ return info.get1("X509.CRL.end");
+ }
+
+}
diff --git a/src/cert/x509/x509_crl.h b/src/cert/x509/x509_crl.h
new file mode 100644
index 000000000..55eb8424b
--- /dev/null
+++ b/src/cert/x509/x509_crl.h
@@ -0,0 +1,101 @@
+/*
+* X.509 CRL
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_X509_CRL_H__
+#define BOTAN_X509_CRL_H__
+
+#include <botan/x509_obj.h>
+#include <botan/crl_ent.h>
+#include <vector>
+
+namespace Botan {
+
+class X509_Certificate;
+
+/**
+* This class represents X.509 Certificate Revocation Lists (CRLs).
+*/
+class BOTAN_DLL X509_CRL : public X509_Object
+ {
+ public:
+ /**
+ * This class represents CRL related errors.
+ */
+ struct BOTAN_DLL X509_CRL_Error : public Exception
+ {
+ X509_CRL_Error(const std::string& error) :
+ Exception("X509_CRL: " + error) {}
+ };
+
+ /**
+ * Check if this particular certificate is listed in the CRL
+ */
+ bool is_revoked(const X509_Certificate& cert) const;
+
+ /**
+ * Get the entries of this CRL in the form of a vector.
+ * @return vector containing the entries of this CRL.
+ */
+ std::vector<CRL_Entry> get_revoked() const;
+
+ /**
+ * Get the issuer DN of this CRL.
+ * @return CRLs issuer DN
+ */
+ X509_DN issuer_dn() const;
+
+ /**
+ * Get the AuthorityKeyIdentifier of this CRL.
+ * @return this CRLs AuthorityKeyIdentifier
+ */
+ MemoryVector<byte> authority_key_id() const;
+
+ /**
+ * Get the serial number of this CRL.
+ * @return CRLs serial number
+ */
+ u32bit crl_number() const;
+
+ /**
+ * Get the CRL's thisUpdate value.
+ * @return CRLs thisUpdate
+ */
+ X509_Time this_update() const;
+
+ /**
+ * Get the CRL's nextUpdate value.
+ * @return CRLs nextdUpdate
+ */
+ X509_Time next_update() const;
+
+ /**
+ * Construct a CRL from a data source.
+ * @param source the data source providing the DER or PEM encoded CRL.
+ * @param throw_on_unknown_critical should we throw an exception
+ * if an unknown CRL extension marked as critical is encountered.
+ */
+ X509_CRL(DataSource& source, bool throw_on_unknown_critical = false);
+
+ /**
+ * Construct a CRL from a file containing the DER or PEM encoded CRL.
+ * @param filename the name of the CRL file
+ * @param throw_on_unknown_critical should we throw an exception
+ * if an unknown CRL extension marked as critical is encountered.
+ */
+ X509_CRL(const std::string& filename,
+ bool throw_on_unknown_critical = false);
+ private:
+ void force_decode();
+
+ bool throw_on_unknown_critical;
+ std::vector<CRL_Entry> revoked;
+ Data_Store info;
+ };
+
+}
+
+#endif
diff --git a/src/cert/x509/x509_ext.cpp b/src/cert/x509/x509_ext.cpp
new file mode 100644
index 000000000..6e0befaf3
--- /dev/null
+++ b/src/cert/x509/x509_ext.cpp
@@ -0,0 +1,584 @@
+/*
+* X.509 Certificate Extensions
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/x509_ext.h>
+#include <botan/sha160.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/oids.h>
+#include <botan/internal/bit_ops.h>
+#include <algorithm>
+#include <memory>
+
+namespace Botan {
+
+/*
+* List of X.509 Certificate Extensions
+*/
+Certificate_Extension* Extensions::get_extension(const OID& oid)
+ {
+#define X509_EXTENSION(NAME, TYPE) \
+ if(OIDS::name_of(oid, NAME)) \
+ return new Cert_Extension::TYPE();
+
+ X509_EXTENSION("X509v3.KeyUsage", Key_Usage);
+ X509_EXTENSION("X509v3.BasicConstraints", Basic_Constraints);
+ X509_EXTENSION("X509v3.SubjectKeyIdentifier", Subject_Key_ID);
+ X509_EXTENSION("X509v3.AuthorityKeyIdentifier", Authority_Key_ID);
+ X509_EXTENSION("X509v3.ExtendedKeyUsage", Extended_Key_Usage);
+ X509_EXTENSION("X509v3.IssuerAlternativeName", Issuer_Alternative_Name);
+ X509_EXTENSION("X509v3.SubjectAlternativeName", Subject_Alternative_Name);
+ X509_EXTENSION("X509v3.CRLNumber", CRL_Number);
+ X509_EXTENSION("X509v3.CertificatePolicies", Certificate_Policies);
+ X509_EXTENSION("X509v3.ReasonCode", CRL_ReasonCode);
+
+ return 0;
+ }
+
+/*
+* Extensions Copy Constructor
+*/
+Extensions::Extensions(const Extensions& extensions) : ASN1_Object()
+ {
+ *this = extensions;
+ }
+
+/*
+* Extensions Assignment Operator
+*/
+Extensions& Extensions::operator=(const Extensions& other)
+ {
+ for(size_t i = 0; i != extensions.size(); ++i)
+ delete extensions[i].first;
+ extensions.clear();
+
+ for(size_t i = 0; i != other.extensions.size(); ++i)
+ extensions.push_back(
+ std::make_pair(other.extensions[i].first->copy(),
+ other.extensions[i].second));
+
+ return (*this);
+ }
+
+/*
+* Return the OID of this extension
+*/
+OID Certificate_Extension::oid_of() const
+ {
+ return OIDS::lookup(oid_name());
+ }
+
+void Extensions::add(Certificate_Extension* extn, bool critical)
+ {
+ extensions.push_back(std::make_pair(extn, critical));
+ }
+
+/*
+* Encode an Extensions list
+*/
+void Extensions::encode_into(DER_Encoder& to_object) const
+ {
+ for(size_t i = 0; i != extensions.size(); ++i)
+ {
+ const Certificate_Extension* ext = extensions[i].first;
+ const bool is_critical = extensions[i].second;
+
+ const bool should_encode = ext->should_encode();
+
+ if(should_encode)
+ {
+ to_object.start_cons(SEQUENCE)
+ .encode(ext->oid_of())
+ .encode_optional(is_critical, false)
+ .encode(ext->encode_inner(), OCTET_STRING)
+ .end_cons();
+ }
+ }
+ }
+
+/*
+* Decode a list of Extensions
+*/
+void Extensions::decode_from(BER_Decoder& from_source)
+ {
+ for(size_t i = 0; i != extensions.size(); ++i)
+ delete extensions[i].first;
+ extensions.clear();
+
+ BER_Decoder sequence = from_source.start_cons(SEQUENCE);
+
+ while(sequence.more_items())
+ {
+ OID oid;
+ MemoryVector<byte> value;
+ bool critical;
+
+ sequence.start_cons(SEQUENCE)
+ .decode(oid)
+ .decode_optional(critical, BOOLEAN, UNIVERSAL, false)
+ .decode(value, OCTET_STRING)
+ .verify_end()
+ .end_cons();
+
+ Certificate_Extension* ext = get_extension(oid);
+
+ if(!ext)
+ {
+ if(!critical || !should_throw)
+ continue;
+
+ throw Decoding_Error("Encountered unknown X.509 extension marked "
+ "as critical; OID = " + oid.as_string());
+ }
+
+ ext->decode_inner(value);
+
+ extensions.push_back(std::make_pair(ext, critical));
+ }
+ sequence.verify_end();
+ }
+
+/*
+* Write the extensions to an info store
+*/
+void Extensions::contents_to(Data_Store& subject_info,
+ Data_Store& issuer_info) const
+ {
+ for(size_t i = 0; i != extensions.size(); ++i)
+ extensions[i].first->contents_to(subject_info, issuer_info);
+ }
+
+/*
+* Delete an Extensions list
+*/
+Extensions::~Extensions()
+ {
+ for(size_t i = 0; i != extensions.size(); ++i)
+ delete extensions[i].first;
+ }
+
+namespace Cert_Extension {
+
+/*
+* Checked accessor for the path_limit member
+*/
+size_t Basic_Constraints::get_path_limit() const
+ {
+ if(!is_ca)
+ throw Invalid_State("Basic_Constraints::get_path_limit: Not a CA");
+ return path_limit;
+ }
+
+/*
+* Encode the extension
+*/
+MemoryVector<byte> Basic_Constraints::encode_inner() const
+ {
+ return DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode_if(is_ca,
+ DER_Encoder()
+ .encode(is_ca)
+ .encode_optional(path_limit, NO_CERT_PATH_LIMIT)
+ )
+ .end_cons()
+ .get_contents();
+ }
+
+/*
+* Decode the extension
+*/
+void Basic_Constraints::decode_inner(const MemoryRegion<byte>& in)
+ {
+ BER_Decoder(in)
+ .start_cons(SEQUENCE)
+ .decode_optional(is_ca, BOOLEAN, UNIVERSAL, false)
+ .decode_optional(path_limit, INTEGER, UNIVERSAL, NO_CERT_PATH_LIMIT)
+ .verify_end()
+ .end_cons();
+
+ if(is_ca == false)
+ path_limit = 0;
+ }
+
+/*
+* Return a textual representation
+*/
+void Basic_Constraints::contents_to(Data_Store& subject, Data_Store&) const
+ {
+ subject.add("X509v3.BasicConstraints.is_ca", (is_ca ? 1 : 0));
+ subject.add("X509v3.BasicConstraints.path_constraint", path_limit);
+ }
+
+/*
+* Encode the extension
+*/
+MemoryVector<byte> Key_Usage::encode_inner() const
+ {
+ if(constraints == NO_CONSTRAINTS)
+ throw Encoding_Error("Cannot encode zero usage constraints");
+
+ const size_t unused_bits = low_bit(constraints) - 1;
+
+ MemoryVector<byte> der;
+ der.push_back(BIT_STRING);
+ der.push_back(2 + ((unused_bits < 8) ? 1 : 0));
+ der.push_back(unused_bits % 8);
+ der.push_back((constraints >> 8) & 0xFF);
+ if(constraints & 0xFF)
+ der.push_back(constraints & 0xFF);
+
+ return der;
+ }
+
+/*
+* Decode the extension
+*/
+void Key_Usage::decode_inner(const MemoryRegion<byte>& in)
+ {
+ BER_Decoder ber(in);
+
+ BER_Object obj = ber.get_next_object();
+
+ if(obj.type_tag != BIT_STRING || obj.class_tag != UNIVERSAL)
+ throw BER_Bad_Tag("Bad tag for usage constraint",
+ obj.type_tag, obj.class_tag);
+
+ if(obj.value.size() != 2 && obj.value.size() != 3)
+ throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint");
+
+ if(obj.value[0] >= 8)
+ throw BER_Decoding_Error("Invalid unused bits in usage constraint");
+
+ obj.value[obj.value.size()-1] &= (0xFF << obj.value[0]);
+
+ u16bit usage = 0;
+ for(size_t i = 1; i != obj.value.size(); ++i)
+ usage = (obj.value[i] << 8) | usage;
+
+ constraints = Key_Constraints(usage);
+ }
+
+/*
+* Return a textual representation
+*/
+void Key_Usage::contents_to(Data_Store& subject, Data_Store&) const
+ {
+ subject.add("X509v3.KeyUsage", constraints);
+ }
+
+/*
+* Encode the extension
+*/
+MemoryVector<byte> Subject_Key_ID::encode_inner() const
+ {
+ return DER_Encoder().encode(key_id, OCTET_STRING).get_contents();
+ }
+
+/*
+* Decode the extension
+*/
+void Subject_Key_ID::decode_inner(const MemoryRegion<byte>& in)
+ {
+ BER_Decoder(in).decode(key_id, OCTET_STRING).verify_end();
+ }
+
+/*
+* Return a textual representation
+*/
+void Subject_Key_ID::contents_to(Data_Store& subject, Data_Store&) const
+ {
+ subject.add("X509v3.SubjectKeyIdentifier", key_id);
+ }
+
+/*
+* Subject_Key_ID Constructor
+*/
+Subject_Key_ID::Subject_Key_ID(const MemoryRegion<byte>& pub_key)
+ {
+ SHA_160 hash;
+ key_id = hash.process(pub_key);
+ }
+
+/*
+* Encode the extension
+*/
+MemoryVector<byte> Authority_Key_ID::encode_inner() const
+ {
+ return DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode(key_id, OCTET_STRING, ASN1_Tag(0), CONTEXT_SPECIFIC)
+ .end_cons()
+ .get_contents();
+ }
+
+/*
+* Decode the extension
+*/
+void Authority_Key_ID::decode_inner(const MemoryRegion<byte>& in)
+ {
+ BER_Decoder(in)
+ .start_cons(SEQUENCE)
+ .decode_optional_string(key_id, OCTET_STRING, 0);
+ }
+
+/*
+* Return a textual representation
+*/
+void Authority_Key_ID::contents_to(Data_Store&, Data_Store& issuer) const
+ {
+ if(key_id.size())
+ issuer.add("X509v3.AuthorityKeyIdentifier", key_id);
+ }
+
+/*
+* Encode the extension
+*/
+MemoryVector<byte> Alternative_Name::encode_inner() const
+ {
+ return DER_Encoder().encode(alt_name).get_contents();
+ }
+
+/*
+* Decode the extension
+*/
+void Alternative_Name::decode_inner(const MemoryRegion<byte>& in)
+ {
+ BER_Decoder(in).decode(alt_name);
+ }
+
+/*
+* Return a textual representation
+*/
+void Alternative_Name::contents_to(Data_Store& subject_info,
+ Data_Store& issuer_info) const
+ {
+ std::multimap<std::string, std::string> contents =
+ get_alt_name().contents();
+
+ if(oid_name_str == "X509v3.SubjectAlternativeName")
+ subject_info.add(contents);
+ else if(oid_name_str == "X509v3.IssuerAlternativeName")
+ issuer_info.add(contents);
+ else
+ throw Internal_Error("In Alternative_Name, unknown type " +
+ oid_name_str);
+ }
+
+/*
+* Alternative_Name Constructor
+*/
+Alternative_Name::Alternative_Name(const AlternativeName& alt_name,
+ const std::string& oid_name_str,
+ const std::string& config_name_str)
+ {
+ this->alt_name = alt_name;
+ this->oid_name_str = oid_name_str;
+ this->config_name_str = config_name_str;
+ }
+
+/*
+* Subject_Alternative_Name Constructor
+*/
+Subject_Alternative_Name::Subject_Alternative_Name(
+ const AlternativeName& name) :
+
+ Alternative_Name(name, "X509v3.SubjectAlternativeName",
+ "subject_alternative_name")
+ {
+ }
+
+/*
+* Issuer_Alternative_Name Constructor
+*/
+Issuer_Alternative_Name::Issuer_Alternative_Name(const AlternativeName& name) :
+ Alternative_Name(name, "X509v3.IssuerAlternativeName",
+ "issuer_alternative_name")
+ {
+ }
+
+/*
+* Encode the extension
+*/
+MemoryVector<byte> Extended_Key_Usage::encode_inner() const
+ {
+ return DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode_list(oids)
+ .end_cons()
+ .get_contents();
+ }
+
+/*
+* Decode the extension
+*/
+void Extended_Key_Usage::decode_inner(const MemoryRegion<byte>& in)
+ {
+ BER_Decoder(in)
+ .start_cons(SEQUENCE)
+ .decode_list(oids)
+ .end_cons();
+ }
+
+/*
+* Return a textual representation
+*/
+void Extended_Key_Usage::contents_to(Data_Store& subject, Data_Store&) const
+ {
+ for(size_t i = 0; i != oids.size(); ++i)
+ subject.add("X509v3.ExtendedKeyUsage", oids[i].as_string());
+ }
+
+namespace {
+
+/*
+* A policy specifier
+*/
+class Policy_Information : public ASN1_Object
+ {
+ public:
+ OID oid;
+
+ Policy_Information() {}
+ Policy_Information(const OID& oid) : oid(oid) {}
+
+ void encode_into(DER_Encoder& codec) const
+ {
+ codec.start_cons(SEQUENCE)
+ .encode(oid)
+ .end_cons();
+ }
+
+ void decode_from(BER_Decoder& codec)
+ {
+ codec.start_cons(SEQUENCE)
+ .decode(oid)
+ .discard_remaining()
+ .end_cons();
+ }
+ };
+
+}
+
+/*
+* Encode the extension
+*/
+MemoryVector<byte> Certificate_Policies::encode_inner() const
+ {
+ std::vector<Policy_Information> policies;
+
+ for(size_t i = 0; i != oids.size(); ++i)
+ policies.push_back(oids[i]);
+
+ return DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode_list(policies)
+ .end_cons()
+ .get_contents();
+ }
+
+/*
+* Decode the extension
+*/
+void Certificate_Policies::decode_inner(const MemoryRegion<byte>& in)
+ {
+ std::vector<Policy_Information> policies;
+
+ BER_Decoder(in)
+ .start_cons(SEQUENCE)
+ .decode_list(policies)
+ .end_cons();
+
+ oids.clear();
+ for(size_t i = 0; i != policies.size(); ++i)
+ oids.push_back(policies[i].oid);
+ }
+
+/*
+* Return a textual representation
+*/
+void Certificate_Policies::contents_to(Data_Store& info, Data_Store&) const
+ {
+ for(size_t i = 0; i != oids.size(); ++i)
+ info.add("X509v3.ExtendedKeyUsage", oids[i].as_string());
+ }
+
+/*
+* Checked accessor for the crl_number member
+*/
+size_t CRL_Number::get_crl_number() const
+ {
+ if(!has_value)
+ throw Invalid_State("CRL_Number::get_crl_number: Not set");
+ return crl_number;
+ }
+
+/*
+* Copy a CRL_Number extension
+*/
+CRL_Number* CRL_Number::copy() const
+ {
+ if(!has_value)
+ throw Invalid_State("CRL_Number::copy: Not set");
+ return new CRL_Number(crl_number);
+ }
+
+/*
+* Encode the extension
+*/
+MemoryVector<byte> CRL_Number::encode_inner() const
+ {
+ return DER_Encoder().encode(crl_number).get_contents();
+ }
+
+/*
+* Decode the extension
+*/
+void CRL_Number::decode_inner(const MemoryRegion<byte>& in)
+ {
+ BER_Decoder(in).decode(crl_number);
+ }
+
+/*
+* Return a textual representation
+*/
+void CRL_Number::contents_to(Data_Store& info, Data_Store&) const
+ {
+ info.add("X509v3.CRLNumber", crl_number);
+ }
+
+/*
+* Encode the extension
+*/
+MemoryVector<byte> CRL_ReasonCode::encode_inner() const
+ {
+ return DER_Encoder()
+ .encode(static_cast<size_t>(reason), ENUMERATED, UNIVERSAL)
+ .get_contents();
+ }
+
+/*
+* Decode the extension
+*/
+void CRL_ReasonCode::decode_inner(const MemoryRegion<byte>& in)
+ {
+ size_t reason_code = 0;
+ BER_Decoder(in).decode(reason_code, ENUMERATED, UNIVERSAL);
+ reason = static_cast<CRL_Code>(reason_code);
+ }
+
+/*
+* Return a textual representation
+*/
+void CRL_ReasonCode::contents_to(Data_Store& info, Data_Store&) const
+ {
+ info.add("X509v3.CRLReasonCode", reason);
+ }
+
+}
+
+}
diff --git a/src/cert/x509/x509_ext.h b/src/cert/x509/x509_ext.h
new file mode 100644
index 000000000..714e29562
--- /dev/null
+++ b/src/cert/x509/x509_ext.h
@@ -0,0 +1,340 @@
+/*
+* X.509 Certificate Extensions
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_X509_EXTENSIONS_H__
+#define BOTAN_X509_EXTENSIONS_H__
+
+#include <botan/asn1_int.h>
+#include <botan/asn1_oid.h>
+#include <botan/asn1_obj.h>
+#include <botan/datastor.h>
+#include <botan/crl_ent.h>
+
+namespace Botan {
+
+/**
+* X.509 Certificate Extension
+*/
+class BOTAN_DLL Certificate_Extension
+ {
+ public:
+ /**
+ * @return OID representing this extension
+ */
+ OID oid_of() const;
+
+ /**
+ * Make a copy of this extension
+ * @return copy of this
+ */
+ virtual Certificate_Extension* copy() const = 0;
+
+ /*
+ * Add the contents of this extension into the information
+ * for the subject and/or issuer, as necessary.
+ * @param subject the subject info
+ * @param issuer the issuer info
+ */
+ virtual void contents_to(Data_Store& subject,
+ Data_Store& issuer) const = 0;
+
+ /*
+ * @return short readable name
+ */
+ virtual std::string config_id() const = 0;
+
+ /*
+ * @return specific OID name
+ */
+ virtual std::string oid_name() const = 0;
+
+ virtual ~Certificate_Extension() {}
+ protected:
+ friend class Extensions;
+ virtual bool should_encode() const { return true; }
+ virtual MemoryVector<byte> encode_inner() const = 0;
+ virtual void decode_inner(const MemoryRegion<byte>&) = 0;
+ };
+
+/**
+* X.509 Certificate Extension List
+*/
+class BOTAN_DLL Extensions : public ASN1_Object
+ {
+ public:
+ void encode_into(class DER_Encoder&) const;
+ void decode_from(class BER_Decoder&);
+
+ void contents_to(Data_Store&, Data_Store&) const;
+
+ void add(Certificate_Extension* extn, bool critical = false);
+
+ Extensions& operator=(const Extensions&);
+
+ Extensions(const Extensions&);
+ Extensions(bool st = true) : should_throw(st) {}
+ ~Extensions();
+ private:
+ static Certificate_Extension* get_extension(const OID&);
+
+ std::vector<std::pair<Certificate_Extension*, bool> > extensions;
+ bool should_throw;
+ };
+
+namespace Cert_Extension {
+
+static const size_t NO_CERT_PATH_LIMIT = 0xFFFFFFF0;
+
+/**
+* Basic Constraints Extension
+*/
+class BOTAN_DLL Basic_Constraints : public Certificate_Extension
+ {
+ public:
+ Basic_Constraints* copy() const
+ { return new Basic_Constraints(is_ca, path_limit); }
+
+ Basic_Constraints(bool ca = false, size_t limit = 0) :
+ is_ca(ca), path_limit(limit) {}
+
+ bool get_is_ca() const { return is_ca; }
+ size_t get_path_limit() const;
+ private:
+ std::string config_id() const { return "basic_constraints"; }
+ std::string oid_name() const { return "X509v3.BasicConstraints"; }
+
+ MemoryVector<byte> encode_inner() const;
+ void decode_inner(const MemoryRegion<byte>&);
+ void contents_to(Data_Store&, Data_Store&) const;
+
+ bool is_ca;
+ size_t path_limit;
+ };
+
+/**
+* Key Usage Constraints Extension
+*/
+class BOTAN_DLL Key_Usage : public Certificate_Extension
+ {
+ public:
+ Key_Usage* copy() const { return new Key_Usage(constraints); }
+
+ Key_Usage(Key_Constraints c = NO_CONSTRAINTS) : constraints(c) {}
+
+ Key_Constraints get_constraints() const { return constraints; }
+ private:
+ std::string config_id() const { return "key_usage"; }
+ std::string oid_name() const { return "X509v3.KeyUsage"; }
+
+ bool should_encode() const { return (constraints != NO_CONSTRAINTS); }
+ MemoryVector<byte> encode_inner() const;
+ void decode_inner(const MemoryRegion<byte>&);
+ void contents_to(Data_Store&, Data_Store&) const;
+
+ Key_Constraints constraints;
+ };
+
+/**
+* Subject Key Identifier Extension
+*/
+class BOTAN_DLL Subject_Key_ID : public Certificate_Extension
+ {
+ public:
+ Subject_Key_ID* copy() const { return new Subject_Key_ID(key_id); }
+
+ Subject_Key_ID() {}
+ Subject_Key_ID(const MemoryRegion<byte>&);
+
+ MemoryVector<byte> get_key_id() const { return key_id; }
+ private:
+ std::string config_id() const { return "subject_key_id"; }
+ std::string oid_name() const { return "X509v3.SubjectKeyIdentifier"; }
+
+ bool should_encode() const { return (key_id.size() > 0); }
+ MemoryVector<byte> encode_inner() const;
+ void decode_inner(const MemoryRegion<byte>&);
+ void contents_to(Data_Store&, Data_Store&) const;
+
+ MemoryVector<byte> key_id;
+ };
+
+/**
+* Authority Key Identifier Extension
+*/
+class BOTAN_DLL Authority_Key_ID : public Certificate_Extension
+ {
+ public:
+ Authority_Key_ID* copy() const { return new Authority_Key_ID(key_id); }
+
+ Authority_Key_ID() {}
+ Authority_Key_ID(const MemoryRegion<byte>& k) : key_id(k) {}
+
+ MemoryVector<byte> get_key_id() const { return key_id; }
+ private:
+ std::string config_id() const { return "authority_key_id"; }
+ std::string oid_name() const { return "X509v3.AuthorityKeyIdentifier"; }
+
+ bool should_encode() const { return (key_id.size() > 0); }
+ MemoryVector<byte> encode_inner() const;
+ void decode_inner(const MemoryRegion<byte>&);
+ void contents_to(Data_Store&, Data_Store&) const;
+
+ MemoryVector<byte> key_id;
+ };
+
+/**
+* Alternative Name Extension Base Class
+*/
+class BOTAN_DLL Alternative_Name : public Certificate_Extension
+ {
+ public:
+ AlternativeName get_alt_name() const { return alt_name; }
+
+ protected:
+ Alternative_Name(const AlternativeName&,
+ const std::string&, const std::string&);
+
+ Alternative_Name(const std::string&, const std::string&);
+ private:
+ std::string config_id() const { return config_name_str; }
+ std::string oid_name() const { return oid_name_str; }
+
+ bool should_encode() const { return alt_name.has_items(); }
+ MemoryVector<byte> encode_inner() const;
+ void decode_inner(const MemoryRegion<byte>&);
+ void contents_to(Data_Store&, Data_Store&) const;
+
+ std::string config_name_str, oid_name_str;
+ AlternativeName alt_name;
+ };
+
+/**
+* Subject Alternative Name Extension
+*/
+class BOTAN_DLL Subject_Alternative_Name : public Alternative_Name
+ {
+ public:
+ Subject_Alternative_Name* copy() const
+ { return new Subject_Alternative_Name(get_alt_name()); }
+
+ Subject_Alternative_Name(const AlternativeName& = AlternativeName());
+ };
+
+/**
+* Issuer Alternative Name Extension
+*/
+class BOTAN_DLL Issuer_Alternative_Name : public Alternative_Name
+ {
+ public:
+ Issuer_Alternative_Name* copy() const
+ { return new Issuer_Alternative_Name(get_alt_name()); }
+
+ Issuer_Alternative_Name(const AlternativeName& = AlternativeName());
+ };
+
+/**
+* Extended Key Usage Extension
+*/
+class BOTAN_DLL Extended_Key_Usage : public Certificate_Extension
+ {
+ public:
+ Extended_Key_Usage* copy() const { return new Extended_Key_Usage(oids); }
+
+ Extended_Key_Usage() {}
+ Extended_Key_Usage(const std::vector<OID>& o) : oids(o) {}
+
+ std::vector<OID> get_oids() const { return oids; }
+ private:
+ std::string config_id() const { return "extended_key_usage"; }
+ std::string oid_name() const { return "X509v3.ExtendedKeyUsage"; }
+
+ bool should_encode() const { return (oids.size() > 0); }
+ MemoryVector<byte> encode_inner() const;
+ void decode_inner(const MemoryRegion<byte>&);
+ void contents_to(Data_Store&, Data_Store&) const;
+
+ std::vector<OID> oids;
+ };
+
+/**
+* Certificate Policies Extension
+*/
+class BOTAN_DLL Certificate_Policies : public Certificate_Extension
+ {
+ public:
+ Certificate_Policies* copy() const
+ { return new Certificate_Policies(oids); }
+
+ Certificate_Policies() {}
+ Certificate_Policies(const std::vector<OID>& o) : oids(o) {}
+
+ std::vector<OID> get_oids() const { return oids; }
+ private:
+ std::string config_id() const { return "policy_info"; }
+ std::string oid_name() const { return "X509v3.CertificatePolicies"; }
+
+ bool should_encode() const { return (oids.size() > 0); }
+ MemoryVector<byte> encode_inner() const;
+ void decode_inner(const MemoryRegion<byte>&);
+ void contents_to(Data_Store&, Data_Store&) const;
+
+ std::vector<OID> oids;
+ };
+
+/**
+* CRL Number Extension
+*/
+class BOTAN_DLL CRL_Number : public Certificate_Extension
+ {
+ public:
+ CRL_Number* copy() const;
+
+ CRL_Number() : has_value(false), crl_number(0) {}
+ CRL_Number(size_t n) : has_value(true), crl_number(n) {}
+
+ size_t get_crl_number() const;
+ private:
+ std::string config_id() const { return "crl_number"; }
+ std::string oid_name() const { return "X509v3.CRLNumber"; }
+
+ bool should_encode() const { return has_value; }
+ MemoryVector<byte> encode_inner() const;
+ void decode_inner(const MemoryRegion<byte>&);
+ void contents_to(Data_Store&, Data_Store&) const;
+
+ bool has_value;
+ size_t crl_number;
+ };
+
+/**
+* CRL Entry Reason Code Extension
+*/
+class BOTAN_DLL CRL_ReasonCode : public Certificate_Extension
+ {
+ public:
+ CRL_ReasonCode* copy() const { return new CRL_ReasonCode(reason); }
+
+ CRL_ReasonCode(CRL_Code r = UNSPECIFIED) : reason(r) {}
+
+ CRL_Code get_reason() const { return reason; }
+ private:
+ std::string config_id() const { return "crl_reason"; }
+ std::string oid_name() const { return "X509v3.ReasonCode"; }
+
+ bool should_encode() const { return (reason != UNSPECIFIED); }
+ MemoryVector<byte> encode_inner() const;
+ void decode_inner(const MemoryRegion<byte>&);
+ void contents_to(Data_Store&, Data_Store&) const;
+
+ CRL_Code reason;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/cert/x509/x509_obj.cpp b/src/cert/x509/x509_obj.cpp
new file mode 100644
index 000000000..c58081225
--- /dev/null
+++ b/src/cert/x509/x509_obj.cpp
@@ -0,0 +1,241 @@
+/*
+* X.509 SIGNED Object
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/x509_obj.h>
+#include <botan/x509_key.h>
+#include <botan/pubkey.h>
+#include <botan/oids.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/parsing.h>
+#include <botan/pem.h>
+#include <algorithm>
+#include <memory>
+
+#include <stdio.h>
+
+namespace Botan {
+
+/*
+* Create a generic X.509 object
+*/
+X509_Object::X509_Object(DataSource& stream, const std::string& labels)
+ {
+ init(stream, labels);
+ }
+
+/*
+* Createa a generic X.509 object
+*/
+X509_Object::X509_Object(const std::string& file, const std::string& labels)
+ {
+ DataSource_Stream stream(file, true);
+ init(stream, labels);
+ }
+
+/*
+* Read a PEM or BER X.509 object
+*/
+void X509_Object::init(DataSource& in, const std::string& labels)
+ {
+ PEM_labels_allowed = split_on(labels, '/');
+ if(PEM_labels_allowed.size() < 1)
+ throw Invalid_Argument("Bad labels argument to X509_Object");
+
+ PEM_label_pref = PEM_labels_allowed[0];
+ std::sort(PEM_labels_allowed.begin(), PEM_labels_allowed.end());
+
+ try {
+ if(ASN1::maybe_BER(in) && !PEM_Code::matches(in))
+ decode_info(in);
+ else
+ {
+ std::string got_label;
+ DataSource_Memory ber(PEM_Code::decode(in, got_label));
+
+ if(!std::binary_search(PEM_labels_allowed.begin(),
+ PEM_labels_allowed.end(), got_label))
+ throw Decoding_Error("Invalid PEM label: " + got_label);
+ decode_info(ber);
+ }
+ }
+ catch(Decoding_Error& e)
+ {
+ throw Decoding_Error(PEM_label_pref + " decoding failed: " + e.what());
+ }
+ }
+
+/*
+* Read a BER encoded X.509 object
+*/
+void X509_Object::decode_info(DataSource& source)
+ {
+ BER_Decoder(source)
+ .start_cons(SEQUENCE)
+ .start_cons(SEQUENCE)
+ .raw_bytes(tbs_bits)
+ .end_cons()
+ .decode(sig_algo)
+ .decode(sig, BIT_STRING)
+ .verify_end()
+ .end_cons();
+ }
+
+/*
+* Return a BER or PEM encoded X.509 object
+*/
+void X509_Object::encode(Pipe& out, X509_Encoding encoding) const
+ {
+ if(encoding == PEM)
+ out.write(this->PEM_encode());
+ else
+ out.write(this->BER_encode());
+ }
+
+/*
+* Return a BER encoded X.509 object
+*/
+MemoryVector<byte> X509_Object::BER_encode() const
+ {
+ return DER_Encoder()
+ .start_cons(SEQUENCE)
+ .start_cons(SEQUENCE)
+ .raw_bytes(tbs_bits)
+ .end_cons()
+ .encode(sig_algo)
+ .encode(sig, BIT_STRING)
+ .end_cons()
+ .get_contents();
+ }
+
+/*
+* Return a PEM encoded X.509 object
+*/
+std::string X509_Object::PEM_encode() const
+ {
+ return PEM_Code::encode(BER_encode(), PEM_label_pref);
+ }
+
+/*
+* Return the TBS data
+*/
+MemoryVector<byte> X509_Object::tbs_data() const
+ {
+ return ASN1::put_in_sequence(tbs_bits);
+ }
+
+/*
+* Return the signature of this object
+*/
+MemoryVector<byte> X509_Object::signature() const
+ {
+ return sig;
+ }
+
+/*
+* Return the algorithm used to sign this object
+*/
+AlgorithmIdentifier X509_Object::signature_algorithm() const
+ {
+ return sig_algo;
+ }
+
+/*
+* Return the hash used in generating the signature
+*/
+std::string X509_Object::hash_used_for_signature() const
+ {
+ std::vector<std::string> sig_info =
+ split_on(OIDS::lookup(sig_algo.oid), '/');
+
+ if(sig_info.size() != 2)
+ throw Internal_Error("Invalid name format found for " +
+ sig_algo.oid.as_string());
+
+ std::vector<std::string> pad_and_hash =
+ parse_algorithm_name(sig_info[1]);
+
+ if(pad_and_hash.size() != 2)
+ throw Internal_Error("Invalid name format " + sig_info[1]);
+
+ return pad_and_hash[1];
+ }
+
+/*
+* Check the signature on an object
+*/
+bool X509_Object::check_signature(Public_Key* pub_key) const
+ {
+ std::auto_ptr<Public_Key> key(pub_key);
+ return check_signature(*key);
+ }
+
+/*
+* Check the signature on an object
+*/
+bool X509_Object::check_signature(Public_Key& pub_key) const
+ {
+ try {
+ std::vector<std::string> sig_info =
+ split_on(OIDS::lookup(sig_algo.oid), '/');
+
+ if(sig_info.size() != 2 || sig_info[0] != pub_key.algo_name())
+ return false;
+
+ std::string padding = sig_info[1];
+ Signature_Format format =
+ (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363;
+
+ PK_Verifier verifier(pub_key, padding, format);
+
+ return verifier.verify_message(tbs_data(), signature());
+ }
+ catch(std::exception& e)
+ {
+ printf("Failure during validation %s\n", e.what());
+ return false;
+ }
+ }
+
+/*
+* Apply the X.509 SIGNED macro
+*/
+MemoryVector<byte> X509_Object::make_signed(PK_Signer* signer,
+ RandomNumberGenerator& rng,
+ const AlgorithmIdentifier& algo,
+ const MemoryRegion<byte>& tbs_bits)
+ {
+ return DER_Encoder()
+ .start_cons(SEQUENCE)
+ .raw_bytes(tbs_bits)
+ .encode(algo)
+ .encode(signer->sign_message(tbs_bits, rng), BIT_STRING)
+ .end_cons()
+ .get_contents();
+ }
+
+/*
+* Try to decode the actual information
+*/
+void X509_Object::do_decode()
+ {
+ try {
+ force_decode();
+ }
+ catch(Decoding_Error& e)
+ {
+ throw Decoding_Error(PEM_label_pref + " decoding failed (" +
+ e.what() + ")");
+ }
+ catch(Invalid_Argument& e)
+ {
+ throw Decoding_Error(PEM_label_pref + " decoding failed (" +
+ e.what() + ")");
+ }
+ }
+
+}
diff --git a/src/cert/x509/x509_obj.h b/src/cert/x509/x509_obj.h
new file mode 100644
index 000000000..570b00f51
--- /dev/null
+++ b/src/cert/x509/x509_obj.h
@@ -0,0 +1,113 @@
+/*
+* X.509 SIGNED Object
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_X509_OBJECT_H__
+#define BOTAN_X509_OBJECT_H__
+
+#include <botan/asn1_obj.h>
+#include <botan/pipe.h>
+#include <botan/pubkey_enums.h>
+#include <botan/rng.h>
+#include <vector>
+
+namespace Botan {
+
+/**
+* This class represents abstract X.509 signed objects as
+* in the X.500 SIGNED macro
+*/
+class BOTAN_DLL X509_Object
+ {
+ public:
+ /**
+ * The underlying data that is to be or was signed
+ * @return data that is or was signed
+ */
+ MemoryVector<byte> tbs_data() const;
+
+ /**
+ * @return signature on tbs_data()
+ */
+ MemoryVector<byte> signature() const;
+
+ /**
+ * @return signature algorithm that was used to generate signature
+ */
+ AlgorithmIdentifier signature_algorithm() const;
+
+ /**
+ * @return hash algorithm that was used to generate signature
+ */
+ std::string hash_used_for_signature() const;
+
+ /**
+ * Create a signed X509 object.
+ * @param signer the signer used to sign the object
+ * @param rng the random number generator to use
+ * @param alg_id the algorithm identifier of the signature scheme
+ * @param tbs the tbs bits to be signed
+ * @return signed X509 object
+ */
+ static MemoryVector<byte> make_signed(class PK_Signer* signer,
+ RandomNumberGenerator& rng,
+ const AlgorithmIdentifier& alg_id,
+ const MemoryRegion<byte>& tbs);
+
+ /**
+ * Check the signature on this data
+ * @param key the public key purportedly used to sign this data
+ * @return true if the signature is valid, otherwise false
+ */
+ bool check_signature(class Public_Key& key) const;
+
+ /**
+ * Check the signature on this data
+ * @param key the public key purportedly used to sign this data
+ * the pointer will be deleted after use
+ * @return true if the signature is valid, otherwise false
+ */
+ bool check_signature(class Public_Key* key) const;
+
+ /**
+ * @return BER encoding of this
+ */
+ MemoryVector<byte> BER_encode() const;
+
+ /**
+ * @return PEM encoding of this
+ */
+ std::string PEM_encode() const;
+
+ /**
+ * Encode this to a pipe
+ * @deprecated use BER_encode or PEM_encode instead
+ * @param out the pipe to write to
+ * @param encoding the encoding to use
+ */
+ BOTAN_DEPRECATED("Use BER_encode or PEM_encode")
+ void encode(Pipe& out, X509_Encoding encoding = PEM) const;
+
+ virtual ~X509_Object() {}
+ protected:
+ X509_Object(DataSource& src, const std::string& pem_labels);
+ X509_Object(const std::string& file, const std::string& pem_labels);
+
+ void do_decode();
+ X509_Object() {}
+ AlgorithmIdentifier sig_algo;
+ MemoryVector<byte> tbs_bits, sig;
+ private:
+ virtual void force_decode() = 0;
+ void init(DataSource&, const std::string&);
+ void decode_info(DataSource&);
+ std::vector<std::string> PEM_labels_allowed;
+ std::string PEM_label_pref;
+ };
+
+}
+
+#endif
diff --git a/src/cert/x509/x509cert.cpp b/src/cert/x509/x509cert.cpp
new file mode 100644
index 000000000..52115a1a8
--- /dev/null
+++ b/src/cert/x509/x509cert.cpp
@@ -0,0 +1,481 @@
+/*
+* X.509 Certificates
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/x509cert.h>
+#include <botan/x509_ext.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/internal/stl_util.h>
+#include <botan/parsing.h>
+#include <botan/bigint.h>
+#include <botan/oids.h>
+#include <botan/pem.h>
+#include <botan/hex.h>
+#include <algorithm>
+#include <iterator>
+#include <sstream>
+
+namespace Botan {
+
+namespace {
+
+/*
+* Lookup each OID in the vector
+*/
+std::vector<std::string> lookup_oids(const std::vector<std::string>& in)
+ {
+ std::vector<std::string> out;
+
+ std::vector<std::string>::const_iterator i = in.begin();
+ while(i != in.end())
+ {
+ out.push_back(OIDS::lookup(OID(*i)));
+ ++i;
+ }
+ return out;
+ }
+
+}
+
+/*
+* X509_Certificate Constructor
+*/
+X509_Certificate::X509_Certificate(DataSource& in) :
+ X509_Object(in, "CERTIFICATE/X509 CERTIFICATE")
+ {
+ self_signed = false;
+ do_decode();
+ }
+
+/*
+* X509_Certificate Constructor
+*/
+X509_Certificate::X509_Certificate(const std::string& in) :
+ X509_Object(in, "CERTIFICATE/X509 CERTIFICATE")
+ {
+ self_signed = false;
+ do_decode();
+ }
+
+/*
+* Decode the TBSCertificate data
+*/
+void X509_Certificate::force_decode()
+ {
+ size_t version;
+ BigInt serial_bn;
+ AlgorithmIdentifier sig_algo_inner;
+ X509_DN dn_issuer, dn_subject;
+ X509_Time start, end;
+
+ BER_Decoder tbs_cert(tbs_bits);
+
+ tbs_cert.decode_optional(version, ASN1_Tag(0),
+ ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
+ .decode(serial_bn)
+ .decode(sig_algo_inner)
+ .decode(dn_issuer)
+ .start_cons(SEQUENCE)
+ .decode(start)
+ .decode(end)
+ .verify_end()
+ .end_cons()
+ .decode(dn_subject);
+
+ if(version > 2)
+ throw Decoding_Error("Unknown X.509 cert version " + Botan::to_string(version));
+ if(sig_algo != sig_algo_inner)
+ throw Decoding_Error("Algorithm identifier mismatch");
+
+ self_signed = (dn_subject == dn_issuer);
+
+ subject.add(dn_subject.contents());
+ issuer.add(dn_issuer.contents());
+
+ BER_Object public_key = tbs_cert.get_next_object();
+ if(public_key.type_tag != SEQUENCE || public_key.class_tag != CONSTRUCTED)
+ throw BER_Bad_Tag("X509_Certificate: Unexpected tag for public key",
+ public_key.type_tag, public_key.class_tag);
+
+ MemoryVector<byte> v2_issuer_key_id, v2_subject_key_id;
+
+ tbs_cert.decode_optional_string(v2_issuer_key_id, BIT_STRING, 1);
+ tbs_cert.decode_optional_string(v2_subject_key_id, BIT_STRING, 2);
+
+ BER_Object v3_exts_data = tbs_cert.get_next_object();
+ if(v3_exts_data.type_tag == 3 &&
+ v3_exts_data.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
+ {
+ Extensions extensions;
+
+ BER_Decoder(v3_exts_data.value).decode(extensions).verify_end();
+
+ extensions.contents_to(subject, issuer);
+ }
+ else if(v3_exts_data.type_tag != NO_OBJECT)
+ throw BER_Bad_Tag("Unknown tag in X.509 cert",
+ v3_exts_data.type_tag, v3_exts_data.class_tag);
+
+ if(tbs_cert.more_items())
+ throw Decoding_Error("TBSCertificate has more items that expected");
+
+ subject.add("X509.Certificate.version", version);
+ subject.add("X509.Certificate.serial", BigInt::encode(serial_bn));
+ subject.add("X509.Certificate.start", start.readable_string());
+ subject.add("X509.Certificate.end", end.readable_string());
+
+ issuer.add("X509.Certificate.v2.key_id", v2_issuer_key_id);
+ subject.add("X509.Certificate.v2.key_id", v2_subject_key_id);
+
+ subject.add("X509.Certificate.public_key",
+ PEM_Code::encode(
+ ASN1::put_in_sequence(public_key.value),
+ "PUBLIC KEY"
+ )
+ );
+
+ if(is_CA_cert() &&
+ !subject.has_value("X509v3.BasicConstraints.path_constraint"))
+ {
+ const size_t limit = (x509_version() < 3) ?
+ Cert_Extension::NO_CERT_PATH_LIMIT : 0;
+
+ subject.add("X509v3.BasicConstraints.path_constraint", limit);
+ }
+ }
+
+/*
+* Return the X.509 version in use
+*/
+u32bit X509_Certificate::x509_version() const
+ {
+ return (subject.get1_u32bit("X509.Certificate.version") + 1);
+ }
+
+/*
+* Return the time this cert becomes valid
+*/
+std::string X509_Certificate::start_time() const
+ {
+ return subject.get1("X509.Certificate.start");
+ }
+
+/*
+* Return the time this cert becomes invalid
+*/
+std::string X509_Certificate::end_time() const
+ {
+ return subject.get1("X509.Certificate.end");
+ }
+
+/*
+* Return information about the subject
+*/
+std::vector<std::string>
+X509_Certificate::subject_info(const std::string& what) const
+ {
+ return subject.get(X509_DN::deref_info_field(what));
+ }
+
+/*
+* Return information about the issuer
+*/
+std::vector<std::string>
+X509_Certificate::issuer_info(const std::string& what) const
+ {
+ return issuer.get(X509_DN::deref_info_field(what));
+ }
+
+/*
+* Return the public key in this certificate
+*/
+Public_Key* X509_Certificate::subject_public_key() const
+ {
+ DataSource_Memory source(subject.get1("X509.Certificate.public_key"));
+ return X509::load_key(source);
+ }
+
+/*
+* Check if the certificate is for a CA
+*/
+bool X509_Certificate::is_CA_cert() const
+ {
+ if(!subject.get1_u32bit("X509v3.BasicConstraints.is_ca"))
+ return false;
+
+ return allowed_usage(KEY_CERT_SIGN);
+ }
+
+bool X509_Certificate::allowed_usage(Key_Constraints restriction) const
+ {
+ if(constraints() == NO_CONSTRAINTS)
+ return true;
+ return (constraints() & restriction);
+ }
+
+/*
+* Return the path length constraint
+*/
+u32bit X509_Certificate::path_limit() const
+ {
+ return subject.get1_u32bit("X509v3.BasicConstraints.path_constraint", 0);
+ }
+
+/*
+* Return the key usage constraints
+*/
+Key_Constraints X509_Certificate::constraints() const
+ {
+ return Key_Constraints(subject.get1_u32bit("X509v3.KeyUsage",
+ NO_CONSTRAINTS));
+ }
+
+/*
+* Return the list of extended key usage OIDs
+*/
+std::vector<std::string> X509_Certificate::ex_constraints() const
+ {
+ return lookup_oids(subject.get("X509v3.ExtendedKeyUsage"));
+ }
+
+/*
+* Return the list of certificate policies
+*/
+std::vector<std::string> X509_Certificate::policies() const
+ {
+ return lookup_oids(subject.get("X509v3.CertificatePolicies"));
+ }
+
+/*
+* Return the authority key id
+*/
+MemoryVector<byte> X509_Certificate::authority_key_id() const
+ {
+ return issuer.get1_memvec("X509v3.AuthorityKeyIdentifier");
+ }
+
+/*
+* Return the subject key id
+*/
+MemoryVector<byte> X509_Certificate::subject_key_id() const
+ {
+ return subject.get1_memvec("X509v3.SubjectKeyIdentifier");
+ }
+
+/*
+* Return the certificate serial number
+*/
+MemoryVector<byte> X509_Certificate::serial_number() const
+ {
+ return subject.get1_memvec("X509.Certificate.serial");
+ }
+
+/*
+* Return the distinguished name of the issuer
+*/
+X509_DN X509_Certificate::issuer_dn() const
+ {
+ return create_dn(issuer);
+ }
+
+/*
+* Return the distinguished name of the subject
+*/
+X509_DN X509_Certificate::subject_dn() const
+ {
+ return create_dn(subject);
+ }
+
+/*
+* Compare two certificates for equality
+*/
+bool X509_Certificate::operator==(const X509_Certificate& other) const
+ {
+ return (sig == other.sig &&
+ sig_algo == other.sig_algo &&
+ self_signed == other.self_signed &&
+ issuer == other.issuer &&
+ subject == other.subject);
+ }
+
+/*
+* X.509 Certificate Comparison
+*/
+bool operator!=(const X509_Certificate& cert1, const X509_Certificate& cert2)
+ {
+ return !(cert1 == cert2);
+ }
+
+std::string X509_Certificate::to_string() const
+ {
+ const char* dn_fields[] = { "Name",
+ "Email",
+ "Organization",
+ "Organizational Unit",
+ "Locality",
+ "State",
+ "Country",
+ "IP",
+ "DNS",
+ "URI",
+ "PKIX.XMPPAddr",
+ 0 };
+
+ std::ostringstream out;
+
+ for(size_t i = 0; dn_fields[i]; ++i)
+ {
+ const std::vector<std::string> vals = this->subject_info(dn_fields[i]);
+
+ if(vals.empty())
+ continue;
+
+ out << "Subject " << dn_fields[i] << ":";
+ for(size_t j = 0; j != vals.size(); ++j)
+ out << " " << vals[j];
+ out << "\n";
+ }
+
+ for(size_t i = 0; dn_fields[i]; ++i)
+ {
+ const std::vector<std::string> vals = this->issuer_info(dn_fields[i]);
+
+ if(vals.empty())
+ continue;
+
+ out << "Issuer " << dn_fields[i] << ":";
+ for(size_t j = 0; j != vals.size(); ++j)
+ out << " " << vals[j];
+ out << "\n";
+ }
+
+ out << "Version: " << this->x509_version() << "\n";
+
+ out << "Not valid before: " << this->start_time() << "\n";
+ out << "Not valid after: " << this->end_time() << "\n";
+
+ out << "Constraints:\n";
+ Key_Constraints constraints = this->constraints();
+ if(constraints == NO_CONSTRAINTS)
+ out << " None\n";
+ else
+ {
+ if(constraints & DIGITAL_SIGNATURE)
+ out << " Digital Signature\n";
+ if(constraints & NON_REPUDIATION)
+ out << " Non-Repuidation\n";
+ if(constraints & KEY_ENCIPHERMENT)
+ out << " Key Encipherment\n";
+ if(constraints & DATA_ENCIPHERMENT)
+ out << " Data Encipherment\n";
+ if(constraints & KEY_AGREEMENT)
+ out << " Key Agreement\n";
+ if(constraints & KEY_CERT_SIGN)
+ out << " Cert Sign\n";
+ if(constraints & CRL_SIGN)
+ out << " CRL Sign\n";
+ }
+
+ std::vector<std::string> policies = this->policies();
+ if(policies.size())
+ {
+ out << "Policies: " << "\n";
+ for(size_t i = 0; i != policies.size(); i++)
+ out << " " << policies[i] << "\n";
+ }
+
+ std::vector<std::string> ex_constraints = this->ex_constraints();
+ if(ex_constraints.size())
+ {
+ out << "Extended Constraints:\n";
+ for(size_t i = 0; i != ex_constraints.size(); i++)
+ out << " " << ex_constraints[i] << "\n";
+ }
+
+ out << "Signature algorithm: " <<
+ OIDS::lookup(this->signature_algorithm().oid) << "\n";
+
+ out << "Serial number: " << hex_encode(this->serial_number()) << "\n";
+
+ if(this->authority_key_id().size())
+ out << "Authority keyid: " << hex_encode(this->authority_key_id()) << "\n";
+
+ if(this->subject_key_id().size())
+ out << "Subject keyid: " << hex_encode(this->subject_key_id()) << "\n";
+
+ X509_PublicKey* pubkey = this->subject_public_key();
+ out << "Public Key:\n" << X509::PEM_encode(*pubkey);
+ delete pubkey;
+
+ return out.str();
+ }
+
+/*
+* Create and populate a X509_DN
+*/
+X509_DN create_dn(const Data_Store& info)
+ {
+ class DN_Matcher : public Data_Store::Matcher
+ {
+ public:
+ bool operator()(const std::string& key, const std::string&) const
+ {
+ if(key.find("X520.") != std::string::npos)
+ return true;
+ return false;
+ }
+ };
+
+ std::multimap<std::string, std::string> names =
+ info.search_with(DN_Matcher());
+
+ X509_DN dn;
+
+ std::multimap<std::string, std::string>::iterator i;
+ for(i = names.begin(); i != names.end(); ++i)
+ dn.add_attribute(i->first, i->second);
+
+ return dn;
+ }
+
+/*
+* Create and populate an AlternativeName
+*/
+AlternativeName create_alt_name(const Data_Store& info)
+ {
+ class AltName_Matcher : public Data_Store::Matcher
+ {
+ public:
+ bool operator()(const std::string& key, const std::string&) const
+ {
+ for(size_t i = 0; i != matches.size(); ++i)
+ if(key.compare(matches[i]) == 0)
+ return true;
+ return false;
+ }
+
+ AltName_Matcher(const std::string& match_any_of)
+ {
+ matches = split_on(match_any_of, '/');
+ }
+ private:
+ std::vector<std::string> matches;
+ };
+
+ std::multimap<std::string, std::string> names =
+ info.search_with(AltName_Matcher("RFC822/DNS/URI/IP"));
+
+ AlternativeName alt_name;
+
+ std::multimap<std::string, std::string>::iterator i;
+ for(i = names.begin(); i != names.end(); ++i)
+ alt_name.add_attribute(i->first, i->second);
+
+ return alt_name;
+ }
+
+}
diff --git a/src/cert/x509/x509cert.h b/src/cert/x509/x509cert.h
new file mode 100644
index 000000000..d25b97694
--- /dev/null
+++ b/src/cert/x509/x509cert.h
@@ -0,0 +1,193 @@
+/*
+* X.509 Certificates
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_X509_CERTS_H__
+#define BOTAN_X509_CERTS_H__
+
+#include <botan/x509_obj.h>
+#include <botan/x509_dn.h>
+#include <botan/x509_key.h>
+#include <botan/datastor.h>
+#include <botan/pubkey_enums.h>
+#include <map>
+
+namespace Botan {
+
+/**
+* This class represents X.509 Certificate
+*/
+class BOTAN_DLL X509_Certificate : public X509_Object
+ {
+ public:
+ /**
+ * Get the public key associated with this certificate.
+ * @return subject public key of this certificate
+ */
+ Public_Key* subject_public_key() const;
+
+ /**
+ * Get the issuer certificate DN.
+ * @return issuer DN of this certificate
+ */
+ X509_DN issuer_dn() const;
+
+ /**
+ * Get the subject certificate DN.
+ * @return subject DN of this certificate
+ */
+ X509_DN subject_dn() const;
+
+ /**
+ * Get a value for a specific subject_info parameter name.
+ * @param name the name of the paramter to look up. Possible names are
+ * "X509.Certificate.version", "X509.Certificate.serial",
+ * "X509.Certificate.start", "X509.Certificate.end",
+ * "X509.Certificate.v2.key_id", "X509.Certificate.public_key",
+ * "X509v3.BasicConstraints.path_constraint",
+ * "X509v3.BasicConstraints.is_ca", "X509v3.ExtendedKeyUsage",
+ * "X509v3.CertificatePolicies", "X509v3.SubjectKeyIdentifier" or
+ * "X509.Certificate.serial".
+ * @return value(s) of the specified parameter
+ */
+ std::vector<std::string> subject_info(const std::string& name) const;
+
+ /**
+ * Get a value for a specific subject_info parameter name.
+ * @param name the name of the paramter to look up. Possible names are
+ * "X509.Certificate.v2.key_id" or "X509v3.AuthorityKeyIdentifier".
+ * @return value(s) of the specified parameter
+ */
+ std::vector<std::string> issuer_info(const std::string& name) const;
+
+ /**
+ * Get the notBefore of the certificate.
+ * @return notBefore of the certificate
+ */
+ std::string start_time() const;
+
+ /**
+ * Get the notAfter of the certificate.
+ * @return notAfter of the certificate
+ */
+ std::string end_time() const;
+
+ /**
+ * Get the X509 version of this certificate object.
+ * @return X509 version
+ */
+ u32bit x509_version() const;
+
+ /**
+ * Get the serial number of this certificate.
+ * @return certificates serial number
+ */
+ MemoryVector<byte> serial_number() const;
+
+ /**
+ * Get the DER encoded AuthorityKeyIdentifier of this certificate.
+ * @return DER encoded AuthorityKeyIdentifier
+ */
+ MemoryVector<byte> authority_key_id() const;
+
+ /**
+ * Get the DER encoded SubjectKeyIdentifier of this certificate.
+ * @return DER encoded SubjectKeyIdentifier
+ */
+ MemoryVector<byte> subject_key_id() const;
+
+ /**
+ * Check whether this certificate is self signed.
+ * @return true if this certificate is self signed
+ */
+ bool is_self_signed() const { return self_signed; }
+
+ /**
+ * Check whether this certificate is a CA certificate.
+ * @return true if this certificate is a CA certificate
+ */
+ bool is_CA_cert() const;
+
+ bool allowed_usage(Key_Constraints restriction) const;
+
+ /**
+ * Get the path limit as defined in the BasicConstraints extension of
+ * this certificate.
+ * @return path limit
+ */
+ u32bit path_limit() const;
+
+ /**
+ * Get the key constraints as defined in the KeyUsage extension of this
+ * certificate.
+ * @return key constraints
+ */
+ Key_Constraints constraints() const;
+
+ /**
+ * Get the key constraints as defined in the ExtendedKeyUsage
+ * extension of this
+ * certificate.
+ * @return key constraints
+ */
+ std::vector<std::string> ex_constraints() const;
+
+ /**
+ * Get the policies as defined in the CertificatePolicies extension
+ * of this certificate.
+ * @return certificate policies
+ */
+ std::vector<std::string> policies() const;
+
+ /**
+ * @return a string describing the certificate
+ */
+ std::string to_string() const;
+
+ /**
+ * Check to certificates for equality.
+ * @return true both certificates are (binary) equal
+ */
+ bool operator==(const X509_Certificate& other) const;
+
+ /**
+ * Create a certificate from a data source providing the DER or
+ * PEM encoded certificate.
+ * @param source the data source
+ */
+ X509_Certificate(DataSource& source);
+
+ /**
+ * Create a certificate from a file containing the DER or PEM
+ * encoded certificate.
+ * @param filename the name of the certificate file
+ */
+ X509_Certificate(const std::string& filename);
+ private:
+ void force_decode();
+ friend class X509_CA;
+ X509_Certificate() {}
+
+ Data_Store subject, issuer;
+ bool self_signed;
+ };
+
+/**
+* Check two certificates for inequality
+* @return true if the arguments represent different certificates,
+* false if they are binary identical
+*/
+BOTAN_DLL bool operator!=(const X509_Certificate&, const X509_Certificate&);
+
+/*
+* Data Store Extraction Operations
+*/
+BOTAN_DLL X509_DN create_dn(const Data_Store&);
+BOTAN_DLL AlternativeName create_alt_name(const Data_Store&);
+
+}
+
+#endif
diff --git a/src/cert/x509/x509opt.cpp b/src/cert/x509/x509opt.cpp
new file mode 100644
index 000000000..345df1fe0
--- /dev/null
+++ b/src/cert/x509/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(size_t 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/x509/x509path.cpp b/src/cert/x509/x509path.cpp
new file mode 100644
index 000000000..a9b8150ae
--- /dev/null
+++ b/src/cert/x509/x509path.cpp
@@ -0,0 +1,211 @@
+/*
+* X.509 Certificate Path Validation
+* (C) 2010-2011 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/x509path.h>
+#include <botan/parsing.h>
+#include <botan/pubkey.h>
+#include <botan/oids.h>
+#include <botan/time.h>
+#include <algorithm>
+#include <memory>
+
+namespace Botan {
+
+namespace {
+
+class PKIX_Validation_Failure : public std::exception
+ {
+ public:
+ PKIX_Validation_Failure(X509_Path_Validation_Code code) : m_code(code) {}
+
+ X509_Path_Validation_Code code() const { return m_code; }
+
+ const char* what() { return "PKIX validation failed"; }
+ private:
+ X509_Path_Validation_Code m_code;
+ };
+
+X509_Certificate find_issuing_cert(const X509_Certificate& cert,
+ const std::vector<Certificate_Store*>& certstores)
+ {
+ const X509_DN issuer_dn = cert.issuer_dn();
+ const MemoryVector<byte> auth_key_id = cert.authority_key_id();
+
+ for(size_t i = 0; i != certstores.size(); ++i)
+ {
+ std::vector<X509_Certificate> certs =
+ certstores[i]->find_cert_by_subject_and_key_id(issuer_dn, auth_key_id);
+
+ if(certs.size() == 0)
+ throw PKIX_Validation_Failure(CERT_ISSUER_NOT_FOUND);
+ else if(certs.size() > 1)
+ throw PKIX_Validation_Failure(CERT_MULTIPLE_ISSUERS_FOUND);
+
+ return certs[0];
+ }
+
+ throw PKIX_Validation_Failure(CERT_ISSUER_NOT_FOUND);
+ }
+
+std::vector<X509_CRL> find_crls_from(const X509_Certificate& cert,
+ const std::vector<Certificate_Store*>& certstores)
+ {
+ const X509_DN issuer_dn = cert.subject_dn();
+ const MemoryVector<byte> auth_key_id = cert.subject_key_id();
+
+ for(size_t i = 0; i != certstores.size(); ++i)
+ {
+ std::vector<X509_CRL> crl =
+ certstores[i]->find_crl_by_issuer_and_key_id(issuer_dn, auth_key_id);
+
+ if(!crl.empty())
+ return crl;
+ }
+
+ return std::vector<X509_CRL>();
+ }
+
+}
+
+const X509_Certificate& Path_Validation_Result::trust_root() const
+ {
+ return m_cert_path[m_cert_path.size()-1];
+ }
+
+std::set<std::string> Path_Validation_Result::trusted_hashes() const
+ {
+ std::set<std::string> hashes;
+ for(size_t i = 0; i != m_cert_path.size(); ++i)
+ hashes.insert(m_cert_path[i].hash_used_for_signature());
+ return hashes;
+ }
+
+Path_Validation_Result x509_path_validate(
+ const X509_Certificate& end_cert,
+ const std::vector<Certificate_Store*>& certstores)
+ {
+ std::vector<X509_Certificate> certs;
+ certs.push_back(end_cert);
+ return x509_path_validate(certs, certstores);
+ }
+
+Path_Validation_Result x509_path_validate(
+ const std::vector<X509_Certificate>& end_certs,
+ Certificate_Store& store)
+ {
+ std::vector<Certificate_Store*> certstores;
+ certstores.push_back(&store);
+
+ return x509_path_validate(end_certs, certstores);
+ }
+
+Path_Validation_Result x509_path_validate(
+ const X509_Certificate& end_cert,
+ Certificate_Store& store)
+ {
+ std::vector<X509_Certificate> certs;
+ certs.push_back(end_cert);
+
+ std::vector<Certificate_Store*> certstores;
+ certstores.push_back(&store);
+
+ return x509_path_validate(certs, certstores);
+ }
+
+Path_Validation_Result
+x509_path_validate(const std::vector<X509_Certificate>& end_certs,
+ const std::vector<Certificate_Store*>& certstores)
+ {
+ Path_Validation_Result r;
+
+ r.m_cert_path = end_certs;
+
+ std::vector<X509_Certificate>& cert_path = r.m_cert_path;
+
+ try
+ {
+ // iterate until we reach a root or cannot find the issuer
+ while(!cert_path.back().is_self_signed())
+ {
+ cert_path.push_back(
+ find_issuing_cert(cert_path.back(), certstores)
+ );
+ }
+
+ const bool self_signed_ee_cert = (cert_path.size() == 1);
+
+ X509_Time current_time(system_time());
+
+ for(size_t i = 0; i != cert_path.size(); ++i)
+ {
+ const X509_Certificate& subject = cert_path[i];
+
+ // Check all certs for valid time range
+ if(current_time < X509_Time(subject.start_time()))
+ throw PKIX_Validation_Failure(CERT_NOT_YET_VALID);
+
+ if(current_time > X509_Time(subject.end_time()))
+ throw PKIX_Validation_Failure(CERT_HAS_EXPIRED);
+
+ const bool at_self_signed_root = (i == cert_path.size() - 1);
+
+ const X509_Certificate& issuer =
+ cert_path[at_self_signed_root ? (i) : (i + 1)];
+
+ // Check issuer constraints
+
+ // Don't require CA bit set on self-signed end entity cert
+ if(!issuer.is_CA_cert() && !self_signed_ee_cert)
+ throw PKIX_Validation_Failure(CA_CERT_NOT_FOR_CERT_ISSUER);
+
+ if(issuer.path_limit() < i)
+ throw PKIX_Validation_Failure(CERT_CHAIN_TOO_LONG);
+
+ if(subject.check_signature(issuer.subject_public_key()) == false)
+ throw PKIX_Validation_Failure(SIGNATURE_ERROR);
+ }
+
+ for(size_t i = 1; i != cert_path.size(); ++i)
+ {
+ const X509_Certificate& subject = cert_path[i-1];
+ const X509_Certificate& ca = cert_path[i];
+
+ std::vector<X509_CRL> crls = find_crls_from(ca, certstores);
+
+ if(crls.empty())
+ //throw PKIX_Validation_Failure(CRL_NOT_FOUND);
+ continue;
+
+ const X509_CRL& crl = crls[0];
+
+ if(!ca.allowed_usage(CRL_SIGN))
+ throw PKIX_Validation_Failure(CA_CERT_NOT_FOR_CRL_ISSUER);
+
+ if(current_time < X509_Time(crl.this_update()))
+ throw PKIX_Validation_Failure(CRL_NOT_YET_VALID);
+
+ if(current_time > X509_Time(crl.next_update()))
+ throw PKIX_Validation_Failure(CRL_HAS_EXPIRED);
+
+ if(crl.check_signature(ca.subject_public_key()) == false)
+ throw PKIX_Validation_Failure(SIGNATURE_ERROR);
+
+ if(crl.is_revoked(subject))
+ throw PKIX_Validation_Failure(CERT_IS_REVOKED);
+ }
+
+ r.set_result(self_signed_ee_cert ? CANNOT_ESTABLISH_TRUST : VERIFIED);
+ }
+ catch(PKIX_Validation_Failure& e)
+ {
+ r.set_result(e.code());
+ }
+
+ return r;
+ }
+
+}
diff --git a/src/cert/x509/x509path.h b/src/cert/x509/x509path.h
new file mode 100644
index 000000000..c389431d8
--- /dev/null
+++ b/src/cert/x509/x509path.h
@@ -0,0 +1,110 @@
+/*
+* X.509 Cert Path Validation
+* (C) 2010-2011 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_X509_CERT_PATH_VALIDATION_H__
+#define BOTAN_X509_CERT_PATH_VALIDATION_H__
+
+#include <botan/x509cert.h>
+#include <botan/certstor.h>
+#include <set>
+
+namespace Botan {
+
+/**
+* X.509 Certificate Validation Result
+*/
+enum X509_Path_Validation_Code {
+ VERIFIED,
+ UNKNOWN_X509_ERROR,
+ CANNOT_ESTABLISH_TRUST,
+ CERT_CHAIN_TOO_LONG,
+ SIGNATURE_ERROR,
+ POLICY_ERROR,
+ INVALID_USAGE,
+
+ CERT_MULTIPLE_ISSUERS_FOUND,
+
+ CERT_FORMAT_ERROR,
+ CERT_ISSUER_NOT_FOUND,
+ CERT_NOT_YET_VALID,
+ CERT_HAS_EXPIRED,
+ CERT_IS_REVOKED,
+
+ CRL_NOT_FOUND,
+ CRL_FORMAT_ERROR,
+ CRL_ISSUER_NOT_FOUND,
+ CRL_NOT_YET_VALID,
+ CRL_HAS_EXPIRED,
+
+ CA_CERT_CANNOT_SIGN,
+ CA_CERT_NOT_FOR_CERT_ISSUER,
+ CA_CERT_NOT_FOR_CRL_ISSUER
+};
+
+enum Usage_Restrictions {
+ NO_RESTRICTIONS = 0x00,
+ TLS_SERVER = 0x01,
+ TLS_CLIENT = 0x02,
+ CODE_SIGNING = 0x04,
+ EMAIL_PROTECTION = 0x08,
+ TIME_STAMPING = 0x10,
+ CRL_SIGNING = 0x20
+};
+
+class BOTAN_DLL Path_Validation_Result
+ {
+ public:
+ Path_Validation_Result() :
+ m_result(UNKNOWN_X509_ERROR),
+ m_usages(NO_RESTRICTIONS)
+ {}
+
+ /**
+ * Returns the set of hash functions you are implicitly
+ * trusting by trusting this result.
+ */
+ std::set<std::string> trusted_hashes() const;
+
+ const X509_Certificate& trust_root() const;
+
+ const std::vector<X509_Certificate>& cert_path() const { return m_cert_path; }
+
+ bool successful_validation() const { return result() == VERIFIED; }
+
+ X509_Path_Validation_Code result() const { return m_result; }
+ private:
+ friend Path_Validation_Result x509_path_validate(
+ const std::vector<X509_Certificate>& end_certs,
+ const std::vector<Certificate_Store*>& certstores);
+
+ void set_result(X509_Path_Validation_Code result) { m_result = result; }
+
+ X509_Path_Validation_Code m_result;
+ Usage_Restrictions m_usages;
+
+ std::vector<X509_Certificate> m_cert_path;
+ };
+
+Path_Validation_Result BOTAN_DLL x509_path_validate(
+ const std::vector<X509_Certificate>& end_certs,
+ const std::vector<Certificate_Store*>& certstores);
+
+Path_Validation_Result BOTAN_DLL x509_path_validate(
+ const X509_Certificate& end_cert,
+ const std::vector<Certificate_Store*>& certstores);
+
+Path_Validation_Result BOTAN_DLL x509_path_validate(
+ const X509_Certificate& end_cert,
+ Certificate_Store& store);
+
+Path_Validation_Result BOTAN_DLL x509_path_validate(
+ const std::vector<X509_Certificate>& end_certs,
+ Certificate_Store& store);
+
+}
+
+#endif
diff --git a/src/cert/x509/x509self.cpp b/src/cert/x509/x509self.cpp
new file mode 100644
index 000000000..a2f89159f
--- /dev/null
+++ b/src/cert/x509/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 size_t 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/x509/x509self.h b/src/cert/x509/x509self.h
new file mode 100644
index 000000000..2850096c8
--- /dev/null
+++ b/src/cert/x509/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
+ */
+ size_t 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(size_t 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