diff options
Diffstat (limited to 'comm/third_party/botan/doc/api_ref/x509.rst')
-rw-r--r-- | comm/third_party/botan/doc/api_ref/x509.rst | 914 |
1 files changed, 914 insertions, 0 deletions
diff --git a/comm/third_party/botan/doc/api_ref/x509.rst b/comm/third_party/botan/doc/api_ref/x509.rst new file mode 100644 index 0000000000..cbf3d531e1 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/x509.rst @@ -0,0 +1,914 @@ +.. _x509_certificates: + +X.509 Certificates and CRLs +================================= + +A certificate is a binding between some identifying information +(called a *subject*) and a public key. This binding is asserted by a +signature on the certificate, which is placed there by some authority +(the *issuer*) that at least claims that it knows the subject named in +the certificate really "owns" the private key corresponding to the +public key in the certificate. + +The major certificate format in use today is X.509v3, used for instance in the +:doc:`tls` protocol. A X.509 certificate is represented by the class +``X509_Certificate``. The data of an X.509 certificate is stored as a +``shared_ptr`` to a structure containing the decoded information. So copying +``X509_Certificate`` objects is quite cheap. + + +.. cpp:class:: X509_Certificate + + .. cpp:function:: X509_Certificate(const std::string& filename) + + Load a certificate from a file. PEM or DER is accepted. + + .. cpp:function:: X509_Certificate(const std::vector<uint8_t>& in) + + Load a certificate from a byte string. + + .. cpp:function:: X509_Certificate(DataSource& source) + + Load a certificate from an abstract ``DataSource``. + + .. cpp:function:: X509_DN subject_dn() const + + Returns the distinguished name (DN) of the certificate's subject. This is + the primary place where information about the subject of the certificate is + stored. However "modern" information that doesn't fit in the X.500 + framework, such as DNS name, email, IP address, or XMPP address, appears + instead in the subject alternative name. + + .. cpp:function:: X509_DN issuer_dn() const + + Returns the distinguished name (DN) of the certificate's issuer, ie the CA + that issued this certificate. + + .. cpp:function:: const AlternativeName& subject_alt_name() const + + Return the subjects alternative name. This is used to store + values like associated URIs, DNS addresses, and email addresses. + + .. cpp:function:: const AlternativeName& issuer_alt_name() const + + Return alternative names for the issuer. + + .. cpp:function:: std::unique_ptr<Public_Key> load_subject_public_key() const + + Deserialize the stored public key and return a new object. This + might throw, if it happens that the public key object stored in + the certificate is malformed in some way, or in the case that the + public key algorithm used is not supported by the library. + + See :ref:`serializing_public_keys` for more information about what to do + with the returned object. It may be any type of key, in principle, though + RSA and ECDSA are most common. + + .. cpp:function:: std::vector<uint8_t> subject_public_key_bits() const + + Return the binary encoding of the subject public key. This value (or a hash of + it) is used in various protocols, eg for public key pinning. + + .. cpp:function:: AlgorithmIdentifier subject_public_key_algo() const + + Return an algorithm identifier that identifies the algorithm used in the + subject's public key. + + .. cpp:function:: std::vector<uint8_t> serial_number() const + + Return the certificates serial number. The tuple of issuer DN and + serial number should be unique. + + .. cpp:function:: std::vector<uint8> raw_subject_dn() const + + Return the binary encoding of the subject DN. + + .. cpp:function:: std::vector<uint8> raw_issuer_dn() const + + Return the binary encoding of the issuer DN. + + .. cpp:function:: X509_Time not_before() const + + Returns the point in time the certificate becomes valid + + .. cpp:function:: X509_Time not_after() const + + Returns the point in time the certificate expires + + .. cpp:function:: const Extensions& v3_extensions() const + + Returns all extensions of this certificate. You can use this + to examine any extension data associated with the certificate, + including custom extensions the library doesn't know about. + + .. cpp:function:: std::vector<uint8_t> authority_key_id() const + + Return the authority key id, if set. This is an arbitrary string; in the + issuing certificate this will be the subject key id. + + .. cpp:function:: std::vector<uint8_t> subject_key_id() const + + Return the subject key id, if set. + + .. cpp:function:: bool allowed_extended_usage(const OID& usage) const + + Return true if and only if the usage OID appears in the extended key usage + extension. Also will return true if the extended key usage extension is + not used in the current certificate. + + .. cpp:function:: std::vector<OID> extended_key_usage() const + + Return the list of extended key usages. May be empty. + + .. cpp:function:: std::string fingerprint(const std::string& hash_fn = "SHA-1") const + + Return a fingerprint for the certificate, which is basically just a hash + of the binary contents. Normally SHA-1 or SHA-256 is used, but any hash + function is allowed. + + .. cpp:function:: Key_Constraints constraints() const + + Returns either an enumeration listing key constraints (what the + associated key can be used for) or ``NO_CONSTRAINTS`` if the + relevant extension was not included. Example values are + ``DIGITAL_SIGNATURE`` and ``KEY_CERT_SIGN``. More than one value + might be specified. + + .. cpp:function:: bool matches_dns_name(const std::string& name) const + + Check if the certificate's subject alternative name DNS fields + match ``name``. This function also handles wildcard certificates. + + .. cpp:function:: std::string to_string() const + + Returns a free-form human readable string describing the certificate. + + .. cpp:function:: std::string PEM_encode() const + + Returns the PEM encoding of the certificate + + .. cpp:function:: std::vector<uint8_t> BER_encode() const + + Returns the DER/BER encoding of the certificate + +X.509 Distinguished Names +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. cpp:class:: X509_DN + + .. cpp:function:: bool has_field(const std::string& attr) const + + Returns true if ``get_attribute`` or ``get_first_attribute`` will return a value. + + .. cpp:function:: std::vector<std::string> get_attribute(const std::string& attr) const + + Return all attributes associated with a certain attribute type. + + .. cpp:function:: std::string get_first_attribute(const std::string& attr) const + + Like ``get_attribute`` but returns just the first attribute, or + empty if the DN has no attribute of the specified type. + + .. cpp:function:: std::multimap<OID, std::string> get_attributes() const + + Get all attributes of the DN. The OID maps to a DN component such as + 2.5.4.10 ("Organization"), and the strings are UTF-8 encoded. + + .. cpp:function:: std::multimap<std::string, std::string> contents() const + + Similar to ``get_attributes``, but the OIDs are decoded to strings. + + .. cpp:function:: void add_attribute(const std::string& key, const std::string& val) + + Add an attribute to a DN. + + .. cpp:function:: void add_attribute(const OID& oid, const std::string& val) + + Add an attribute to a DN using an OID instead of string-valued attribute type. + +The ``X509_DN`` type also supports iostream extraction and insertion operators, +for formatted input and output. + +X.509v3 Extensions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +X.509v3 specifies a large number of possible extensions. Botan supports some, +but by no means all of them. The following listing lists which X.509v3 +extensions are supported and notes areas where there may be problems with the +handling. + + - Key Usage and Extended Key Usage: No problems known. + + - Basic Constraints: No problems known. A self-signed v1 certificate + is assumed to be a CA, while a v3 certificate is marked as a CA if + and only if the basic constraints extension is present and set for + a CA cert. + + - Subject Alternative Names: Only the "rfc822Name", "dNSName", and + "uniformResourceIdentifier" and raw IPv4 fields will be stored; all + others are ignored. + + - Issuer Alternative Names: Same restrictions as the Subject + Alternative Names extension. New certificates generated by Botan + never include the issuer alternative name. + + - Authority Key Identifier: Only the version using KeyIdentifier is + supported. If the GeneralNames version is used and the extension is + critical, an exception is thrown. If both the KeyIdentifier and GeneralNames + versions are present, then the KeyIdentifier will be used, and the + GeneralNames ignored. + + - Subject Key Identifier: No problems known. + + - Name Constraints: No problems known (though encoding is not supported). + +Any unknown critical extension in a certificate will lead to an +exception during path validation. + +Extensions are handled by a special class taking care of encoding +and decoding. It also supports encoding and decoding of custom extensions. +To do this, it internally keeps two lists of extensions. Different lookup +functions are provided to search them. + +.. note:: + + Validation of custom extensions during path validation is currently not supported. + +.. cpp:class:: Extensions + + .. cpp:function:: void add(Certificate_Extension* extn, bool critical = false) + + Adds a new extension to the extensions object. If an extension of the same + type already exists, ``extn`` will replace it. If ``critical`` is true the + extension will be marked as critical in the encoding. + + .. cpp:function:: bool add_new(Certificate_Extension* extn, bool critical = false) + + Like ``add`` but an existing extension will not be replaced. Returns true if the + extension was used, false if an extension of the same type was already in place. + + .. cpp:function:: void replace(Certificate_Extension* extn, bool critical = false) + + Adds an extension to the list or replaces it, if the same + extension was already added + + .. cpp:function:: std::unique_ptr<Certificate_Extension> get(const OID& oid) const + + Searches for an extension by OID and returns the result + + .. cpp:function:: template<typename T> \ + std::unique_ptr<T> get_raw(const OID& oid) + + Searches for an extension by OID and returns the result. + Only the unknown extensions, that is, extensions types that are not + listed above, are searched for by this function. + + .. cpp:function:: std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> extensions() const + + Returns the list of extensions together with the corresponding + criticality flag. Only contains the supported extension types + listed above. + + .. cpp:function:: std::map<OID, std::pair<std::vector<uint8_t>, bool>> extensions_raw() const + + Returns the list of extensions as raw, encoded bytes + together with the corresponding criticality flag. + Contains all extensions, known as well as unknown extensions. + +Certificate Revocation Lists +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It will occasionally happen that a certificate must be revoked before +its expiration date. Examples of this happening include the private +key being compromised, or the user to which it has been assigned +leaving an organization. Certificate revocation lists are an answer to +this problem (though online certificate validation techniques are +starting to become somewhat more popular). Every once in a while the +CA will release a new CRL, listing all certificates that have been +revoked. Also included is various pieces of information like what time +a particular certificate was revoked, and for what reason. In most +systems, it is wise to support some form of certificate revocation, +and CRLs handle this easily. + +For most users, processing a CRL is quite easy. All you have to do is +call the constructor, which will take a filename (or a +``DataSource&``). The CRLs can either be in raw BER/DER, or in PEM +format; the constructor will figure out which format without any extra +information. For example:: + + X509_CRL crl1("crl1.der"); + + DataSource_Stream in("crl2.pem"); + X509_CRL crl2(in); + +After that, pass the ``X509_CRL`` object to a ``Certificate_Store`` object +with + +.. cpp:function:: void Certificate_Store::add_crl(const X509_CRL& crl) + +and all future verifications will take into account the provided CRL. + +Certificate Stores +---------------------------------------- + +An object of type ``Certificate_Store`` is a generalized interface to +an external source for certificates (and CRLs). Examples of such a +store would be one that looked up the certificates in a SQL database, +or by contacting a CGI script running on a HTTP server. There are +currently three mechanisms for looking up a certificate, and one for +retrieving CRLs. By default, most of these mechanisms will return an +empty ``std::shared_ptr`` of ``X509_Certificate``. This storage mechanism +is *only* queried when doing certificate validation: it allows you to +distribute only the root key with an application, and let some online +method handle getting all the other certificates that are needed to +validate an end entity certificate. In particular, the search routines +will not attempt to access the external database. + +The certificate lookup methods are ``find_cert`` (by Subject +Distinguished Name and optional Subject Key Identifier) and +``find_cert_by_pubkey_sha1`` (by SHA-1 hash of the certificate's +public key). The Subject Distinguished Name is given as a ``X509_DN``, +while the SKID parameter takes a ``std::vector<uint8_t>`` containing +the subject key identifier in raw binary. Both lookup methods are +mandatory to implement. + +Finally, there is a method for finding a CRL, called ``find_crl_for``, +that takes an ``X509_Certificate`` object, and returns a +``std::shared_ptr`` of ``X509_CRL``. The ``std::shared_ptr`` return +type makes it easy to return no CRLs by returning ``nullptr`` +(eg, if the certificate store doesn't support retrieving CRLs). +Implementing the function is optional, and by default will return +``nullptr``. + +Certificate stores are used in the :doc:`tls` module to store a +list of trusted certificate authorities. + +In Memory Certificate Store +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The in memory certificate store keeps all objects in memory only. +Certificates can be loaded from disk initially, but also added +later. + +.. cpp:class:: Certificate_Store_In_Memory + + .. cpp:function:: Certificate_Store_In_Memory(const std::string& dir) + + Attempt to parse all files in ``dir`` (including subdirectories) + as certificates. Ignores errors. + + .. cpp:function:: Certificate_Store_In_Memory(const X509_Certificate& cert) + + Adds given certificate to the store + + .. cpp:function:: Certificate_Store_In_Memory() + + Create an empty store + + .. cpp:function:: void add_certificate(const X509_Certificate& cert) + + Add a certificate to the store + + .. cpp:function:: void add_certificate(std::shared_ptr<const X509_Certificate> cert) + + Add a certificate already in a shared_ptr to the store + + .. cpp:function:: void add_crl(const X509_CRL& crl) + + Add a certificate revocation list (CRL) to the store. + + .. cpp:function:: void add_crl(std::shared_ptr<const X509_CRL> crl) + + Add a certificate revocation list (CRL) to the store as a shared_ptr + +SQL-backed Certificate Stores +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The SQL-backed certificate stores store all objects in an SQL database. They +also additionally provide private key storage and revocation of individual +certificates. + +.. cpp:class:: Certificate_Store_In_SQL + + .. cpp:function:: Certificate_Store_In_SQL(const std::shared_ptr<SQL_Database> db, \ + const std::string& passwd, RandomNumberGenerator& rng, const std::string& table_prefix = "") + + Create or open an existing certificate store from an SQL database. + The password in ``passwd`` will be used to encrypt private keys. + + .. cpp:function:: bool insert_cert(const X509_Certificate& cert) + + Inserts ``cert`` into the store. Returns `false` if the certificate is + already known and `true` if insertion was successful. + + .. cpp:function:: remove_cert(const X509_Certificate& cert) + + Removes ``cert`` from the store. Returns `false` if the certificate could not + be found and `true` if removal was successful. + + .. cpp:function:: std::shared_ptr<const Private_Key> find_key(const X509_Certificate&) const + + Returns the private key for "cert" or an empty shared_ptr if none was found + + .. cpp:function:: std::vector<std::shared_ptr<const X509_Certificate>> \ + find_certs_for_key(const Private_Key& key) const + + Returns all certificates for private key ``key`` + + .. cpp:function:: bool insert_key(const X509_Certificate& cert, const Private_Key& key) + + Inserts ``key`` for ``cert`` into the store, returns `false` if the key is + already known and `true` if insertion was successful. + + .. cpp:function:: void remove_key(const Private_Key& key) + + Removes ``key`` from the store + + .. cpp:function:: void revoke_cert(const X509_Certificate&, CRL_Code, \ + const X509_Time& time = X509_Time()) + + Marks ``cert`` as revoked starting from ``time`` + + .. cpp:function:: void affirm_cert(const X509_Certificate&) + + Reverses the revocation for ``cert`` + + .. cpp:function:: std::vector<X509_CRL> generate_crls() const + + Generates CRLs for all certificates marked as revoked. + A CRL is returned for each unique issuer DN. + +The ``Certificate_Store_In_SQL`` class operates on an abstract ``SQL_Database`` +object. If support for sqlite3 was enabled at build time, Botan includes an +implementation of this interface for sqlite3, and a subclass of +``Certificate_Store_In_SQL`` which creates or opens a sqlite3 database. + +.. cpp:class:: Certificate_Store_In_SQLite + + .. cpp:function:: Certificate_Store_In_SQLite(const std::string& db_path, \ + const std::string& passwd, RandomNumberGenerator& rng, const std::string& table_prefix = "") + + Create or open an existing certificate store from an sqlite database file. + The password in ``passwd`` will be used to encrypt private keys. + +Path Validation +---------------------------------------- + +The process of validating a certificate chain up to a trusted root is +called `path validation`, and in botan that operation is handled by a +set of functions in ``x509path.h`` named ``x509_path_validate``: + +.. cpp:function:: Path_Validation_Result \ + x509_path_validate(const X509_Certificate& end_cert, \ + const Path_Validation_Restrictions& restrictions, \ + const Certificate_Store& store, const std::string& hostname = "", \ + Usage_Type usage = Usage_Type::UNSPECIFIED, \ + std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), \ + std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), \ + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp = std::vector<std::shared_ptr<const OCSP::Response>>()) + + The last five parameters are optional. ``hostname`` specifies a hostname which is + matched against the subject DN in ``end_cert`` according to RFC 6125. + An empty hostname disables hostname validation. + ``usage`` specifies key usage restrictions that are compared + to the key usage fields in `end_cert` according to RFC 5280, if not set to + ``UNSPECIFIED``. ``validation_time`` allows setting the time point at which all certificates + are validated. This is really only useful for testing. The default is the + current system clock's current time. ``ocsp_timeout`` sets the timeout for + OCSP requests. The default of 0 disables OCSP checks completely. + ``ocsp_resp`` allows adding additional OCSP responses retrieved from outside + of the path validation. Note that OCSP online checks are done only + as long as the http_util module was compiled in. Availability of online + OCSP checks can be checked using the macro BOTAN_HAS_ONLINE_REVOCATION_CHECKS. + + For the different flavors of ``x509_path_validate``, check ``x509path.h``. + +The result of the validation is returned as a class: + +.. cpp:class:: Path_Validation_Result + + Specifies the result of the validation + + .. cpp:function:: bool successful_validation() const + + Returns true if a certificate path from *end_cert* to a trusted + root was found and all path validation checks passed. + + .. cpp:function:: std::string result_string() const + + Returns a descriptive string of the validation status (for + instance "Verified", "Certificate is not yet valid", or + "Signature error"). This is the string value of + the `result` function below. + + .. cpp:function:: const X509_Certificate& trust_root() const + + If the validation was successful, returns the certificate which + is acting as the trust root for *end_cert*. + + .. cpp:function:: const std::vector<X509_Certificate>& cert_path() const + + Returns the full certificate path starting with the end entity + certificate and ending in the trust root. + + .. cpp:function:: Certificate_Status_Code result() const + + Returns the 'worst' error that occurred during validation. For + instance, we do not want an expired certificate with an invalid + signature to be reported to the user as being simply expired (a + relatively innocuous and common error) when the signature isn't + even valid. + + .. cpp:function:: const std::vector<std::set<Certificate_Status_Code>>& all_statuses() const + + For each certificate in the chain, returns a set of status which + indicate all errors which occurred during validation. This is + primarily useful for diagnostic purposes. + + .. cpp:function:: std::set<std::string> trusted_hashes() const + + Returns the set of all cryptographic hash functions which are + implicitly trusted for this validation to be correct. + + +A ``Path_Validation_Restrictions`` is passed to the path +validator and specifies restrictions and options for the validation +step. The two constructors are: + + .. cpp:function:: Path_Validation_Restrictions(bool require_rev, \ + size_t minimum_key_strength, \ + bool ocsp_all_intermediates, \ + const std::set<std::string>& trusted_hashes) + + If `require_rev` is true, then any path without revocation + information (CRL or OCSP check) is rejected with the code + `NO_REVOCATION_DATA`. The `minimum_key_strength` parameter + specifies the minimum strength of public key signature we will + accept is. The set of hash names `trusted_hashes` indicates which + hash functions we'll accept for cryptographic signatures. Any + untrusted hash will cause the error case `UNTRUSTED_HASH`. + + .. cpp:function:: Path_Validation_Restrictions(bool require_rev = false, \ + size_t minimum_key_strength = 80, \ + bool ocsp_all_intermediates = false) + + A variant of the above with some convenient defaults. The current + default `minimum_key_strength` of 80 roughly corresponds to 1024 + bit RSA. The set of trusted hashes is set to all SHA-2 variants, + and, if `minimum_key_strength` is less than or equal to 80, then + SHA-1 signatures will also be accepted. + +Creating New Certificates +--------------------------------- + +A CA is represented by the type ``X509_CA``, which can be found in +``x509_ca.h``. A CA always needs its own certificate, which can either +be a self-signed certificate (see below on how to create one) or one +issued by another CA (see the section on PKCS #10 requests). Creating +a CA object is done by the following constructor: + +.. cpp:function:: X509_CA::X509_CA(const X509_Certificate& cert, \ + const Private_Key& key, \ + const std::string& hash_fn, \ + RandomNumberGenerator& rng) + +The private ``key`` is the private key corresponding to the public key in the +CA's certificate. ``hash_fn`` is the name of the hash function to use +for signing, e.g., `SHA-256`. ``rng`` is queried for random during signing. + +There is an alternative constructor that lets you set additional options, namely +the padding scheme that will be used by the X509_CA object to sign certificates +and certificate revocation lists. If the padding is not set explicitly, the CA +will use the padding scheme that was used when signing the CA certificate. + +.. cpp:function:: X509_CA::X509_CA(const X509_Certificate& cert, \ + const Private_Key& key, \ + const std::map<std::string,std::string>& opts, \ + const std::string& hash_fn, \ + RandomNumberGenerator& rng) + +The only option valid at this moment is "padding". The supported padding schemes +can be found in src/lib/pubkey/padding.cpp. Some alternative names for the +padding schemes are understood, as well. + +Requests for new certificates are supplied to a CA in the form of PKCS +#10 certificate requests (called a ``PKCS10_Request`` object in +Botan). These are decoded in a similar manner to +certificates/CRLs/etc. A request is vetted by humans (who somehow +verify that the name in the request corresponds to the name of the +entity who requested it), and then signed by a CA key, generating a +new certificate: + +.. cpp:function:: X509_Certificate \ + X509_CA::sign_request(const PKCS10_Request& req, \ + RandomNumberGenerator& rng, \ + const X509_Time& not_before, \ + const X509_Time& not_after) + +Generating CRLs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As mentioned previously, the ability to process CRLs is highly +important in many PKI systems. In fact, according to strict X.509 +rules, you must not validate any certificate if the appropriate CRLs +are not available (though hardly any systems are that strict). In any +case, a CA should have a valid CRL available at all times. + +Of course, you might be wondering what to do if no certificates have +been revoked. Never fear; empty CRLs, which revoke nothing at all, can +be issued. To generate a new, empty CRL, just call + +.. cpp:function:: X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng, \ + uint32_t next_update = 0) + + This function will return a new, empty CRL. The ``next_update`` parameter is + the number of seconds before the CRL expires. If it is set to the (default) + value of zero, then a reasonable default (currently 7 days) will be used. + +On the other hand, you may have issued a CRL before. In that case, you will +want to issue a new CRL that contains all previously revoked +certificates, along with any new ones. This is done by calling + +.. cpp:function:: X509_CRL X509_CA::update_crl(const X509_CRL& last_crl, \ + std::vector<CRL_Entry> new_entries, RandomNumberGenerator& rng, \ + size_t next_update = 0) + + Where ``last_crl`` is the last CRL this CA issued, and + ``new_entries`` is a list of any newly revoked certificates. The + function returns a new ``X509_CRL`` to make available for + clients. + +The ``CRL_Entry`` type is a structure that contains, at a minimum, the serial +number of the revoked certificate. As serial numbers are never repeated, the +pairing of an issuer and a serial number (should) distinctly identify any +certificate. In this case, we represent the serial number as a +``secure_vector<uint8_t>`` called ``serial``. There are two additional (optional) +values, an enumeration called ``CRL_Code`` that specifies the reason for +revocation (``reason``), and an object that represents the time that the +certificate became invalid (if this information is known). + +If you wish to remove an old entry from the CRL, insert a new entry for the +same cert, with a ``reason`` code of ``REMOVE_FROM_CRL``. For example, if a +revoked certificate has expired 'normally', there is no reason to continue to +explicitly revoke it, since clients will reject the cert as expired in any +case. + +Self-Signed Certificates +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Generating a new self-signed certificate can often be useful, for +example when setting up a new root CA, or for use in specialized +protocols. The library provides a utility function for this: + +.. cpp:function:: X509_Certificate create_self_signed_cert( \ + const X509_Cert_Options& opts, const Private_Key& key, \ + const std::string& hash_fn, RandomNumberGenerator& rng) + + Where ``key`` is the private key you wish to use (the public key, + used in the certificate itself is extracted from the private key), + and ``opts`` is an structure that has various bits of information + that will be used in creating the certificate (this structure, and + its use, is discussed below). + +Creating PKCS #10 Requests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Also in ``x509self.h``, there is a function for generating new PKCS #10 +certificate requests: + +.. cpp:function:: PKCS10_Request create_cert_req( \ + const X509_Cert_Options& opts, const Private_Key& key, \ + const std::string& hash_fn, RandomNumberGenerator& rng) + +This function acts quite similarly to +:cpp:func:`create_self_signed_cert`, except it instead returns a PKCS +#10 certificate request. After creating it, one would typically +transmit it to a CA, who signs it and returns a freshly minted X.509 +certificate. + +.. cpp:function:: PKCS10_Request PKCS10_Request::create(const Private_Key& key, \ + const X509_DN& subject_dn, \ + const Extensions& extensions, \ + const std::string& hash_fn, \ + RandomNumberGenerator& rng, \ + const std::string& padding_scheme = "", \ + const std::string& challenge = "") + + This function (added in 2.5) is similar to ``create_cert_req`` but allows + specifying all the parameters directly. In fact ``create_cert_req`` just + creates the DN and extensions from the options, then uses this call to + actually create the ``PKCS10_Request`` object. + + +Certificate Options +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +What is this ``X509_Cert_Options`` thing we've been passing around? +It's a class representing a bunch of information that will end up +being stored into the certificate. This information comes in 3 major +flavors: information about the subject (CA or end-user), the validity +period of the certificate, and restrictions on the usage of the +certificate. For special cases, you can also add custom X.509v3 +extensions. + +First and foremost is a number of ``std::string`` members, which +contains various bits of information about the user: ``common_name``, +``serial_number``, ``country``, ``organization``, ``org_unit``, +``locality``, ``state``, ``email``, ``dns_name``, and ``uri``. As many +of these as possible should be filled it (especially an email +address), though the only required ones are ``common_name`` and +``country``. + +Additionally there are a small selection of ``std::vector<std::string>`` +members, which allow space for repeating elements: +``more_org_units`` and ``more_dns``. + +There is another value that is only useful when creating a PKCS #10 +request, which is called ``challenge``. This is a challenge password, +which you can later use to request certificate revocation (*if* the CA +supports doing revocations in this manner). + +Then there is the validity period; these are set with ``not_before`` +and ``not_after``. Both of these functions also take a +``std::string``, which specifies when the certificate should start +being valid, and when it should stop being valid. If you don't set the +starting validity period, it will automatically choose the current +time. If you don't set the ending time, it will choose the starting +time plus a default time period. The arguments to these functions +specify the time in the following format: "2002/11/27 1:50:14". The +time is in 24-hour format, and the date is encoded as +year/month/day. The date must be specified, but you can omit the time +or trailing parts of it, for example "2002/11/27 1:50" or +"2002/11/27". + +Third, you can set constraints on a key. The one you're mostly likely +to want to use is to create (or request) a CA certificate, which can +be done by calling the member function ``CA_key``. This should only be +used when needed. + +Moreover, you can specify the padding scheme to be used when digital signatures +are computed by calling function ``set_padding_scheme`` with a string +representing the padding scheme. This way, you can control the padding scheme +for self-signed certificates and PKCS #10 requests. The padding scheme used by +a CA when building a certificate or a certificate revocation list can be set in +the ``X509_CA`` constructor. The supported padding schemes can be found in +src/lib/pubkey/padding.cpp. Some alternative names for the padding schemes are +understood, as well. + +Other constraints can be set by calling the member functions +``add_constraints`` and ``add_ex_constraints``. The first takes a +``Key_Constraints`` value, and replaces any previously set value. If +no value is set, then the certificate key is marked as being valid for +any usage. You can set it to any of the following (for more than one +usage, OR them together): ``DIGITAL_SIGNATURE``, ``NON_REPUDIATION``, +``KEY_ENCIPHERMENT``, ``DATA_ENCIPHERMENT``, ``KEY_AGREEMENT``, +``KEY_CERT_SIGN``, ``CRL_SIGN``, ``ENCIPHER_ONLY``, +``DECIPHER_ONLY``. Many of these have quite special semantics, so you +should either consult the appropriate standards document (such as RFC +5280), or just not call ``add_constraints``, in which case the +appropriate values will be chosen for you. + +The second function, ``add_ex_constraints``, allows you to specify an +OID that has some meaning with regards to restricting the key to +particular usages. You can, if you wish, specify any OID you like, but +there is a set of standard ones that other applications will be able +to understand. These are the ones specified by the PKIX standard, and +are named "PKIX.ServerAuth" (for TLS server authentication), +"PKIX.ClientAuth" (for TLS client authentication), "PKIX.CodeSigning", +"PKIX.EmailProtection" (most likely for use with S/MIME), +"PKIX.IPsecUser", "PKIX.IPsecTunnel", "PKIX.IPsecEndSystem", and +"PKIX.TimeStamping". You can call "add_ex_constraints" any number of +times - each new OID will be added to the list to include in the +certificate. + +Lastly, you can add any X.509v3 extensions in the `extensions` member, which is +useful if you want to encode a custom extension, or encode an extension in a way +differently from how Botan defaults. + +OCSP Requests +---------------------------------------- + +A client makes an OCSP request to what is termed an 'OCSP responder'. This +responder returns a signed response attesting that the certificate in question +has not been revoked. The most recent OCSP specification is as of this +writing :rfc:`6960`. + +Normally OCSP validation happens automatically as part of X.509 certificate +validation, as long as OCSP is enabled (by setting a non-zero ``ocsp_timeout`` +in the call to ``x509_path_validate``, or for TLS by implementing the related +``tls_verify_cert_chain_ocsp_timeout`` callback and returning a non-zero value +from that). So most applications should not need to directly manipulate OCSP +request and response objects. + +For those that do, the primary ocsp interface is in ``ocsp.h``. First a request +must be formed, using information contained in the subject certificate and in +the subject's issuing certificate. + +.. cpp:class:: OCSP::Request + + .. cpp:function:: OCSP::Request(const X509_Certificate& issuer_cert, \ + const BigInt& subject_serial) + + Create a new OCSP request + + .. cpp:function:: OCSP::Request(const X509_Certificate& issuer_cert, \ + const X509_Certificate& subject_cert) + + Variant of the above, using serial number from ``subject_cert``. + + .. cpp:function:: std::vector<uint8_t> BER_encode() const + + Encode the current OCSP request as a binary string. + + .. cpp:function:: std::string base64_encode() const + + Encode the current OCSP request as a base64 string. + +Then the response is parsed and validated, and if valid, can be consulted +for certificate status information. + +.. cpp:class:: OCSP::Response + + .. cpp:function:: OCSP::Response(const uint8_t response_bits[], size_t response_bits_len) + + Attempts to parse ``response_bits`` as an OCSP response. Throws an + exception if parsing fails. Note that this does not verify that the OCSP + response is valid (ie that the signature is correct), merely that the + ASN.1 structure matches an OCSP response. + + .. cpp:function:: Certificate_Status_Code check_signature( \ + const std::vector<Certificate_Store*>& trust_roots, \ + const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path = const std::vector<std::shared<const X509_Certificate>>()) const + + Find the issuing certificate of the OCSP response, and check the signature. + + If possible, pass the full certificate path being validated in + the optional ``cert_path`` argument: this additional information + helps locate the OCSP signer's certificate in some cases. If this + does not return ``Certificate_Status_Code::OCSP_SIGNATURE_OK``, + then the request must not be be used further. + + .. cpp:function:: Certificate_Status_Code verify_signature(const X509_Certificate& issuing_cert) const + + If the certificate that issued the OCSP response is already known (eg, + because in some specific application all the OCSP responses will always + be signed by a single trusted issuer whose cert is baked into the code) + this provides an alternate version of `check_signature`. + + .. cpp:function:: Certificate_Status_Code status_for(const X509_Certificate& issuer, \ + const X509_Certificate& subject, \ + std::chrono::system_clock::time_point ref_time = std::chrono::system_clock::now()) const + + Assuming the signature is valid, returns the status for the subject certificate. + Make sure to get the ordering of the issuer and subject certificates correct. + + The ``ref_time`` is normally just the system clock, but can be used if + validation against some other reference time is desired (such as for + testing, to verify an old previously valid OCSP response, or to use an + alternate time source such as the Roughtime protocol instead of the local + client system clock). + + .. cpp:function:: const X509_Time& produced_at() const + + Return the time this OCSP response was (claimed to be) produced at. + + .. cpp:function:: const X509_DN& signer_name() const + + Return the distinguished name of the signer. This is used to help + find the issuing certificate. + + This field is optional in OCSP responses, and may not be set. + + .. cpp:function:: const std::vector<uint8_t>& signer_key_hash() const + + Return the SHA-1 hash of the public key of the signer. This is used to + help find the issuing certificate. The ``Certificate_Store`` API + ``find_cert_by_pubkey_sha1`` can search on this value. + + This field is optional in OCSP responses, and may not be set. + + .. cpp:function:: const std::vector<uint8_t>& raw_bits() const + + Return the entire raw ASN.1 blob (for debugging or specialized decoding needs) + +One common way of making OCSP requests is via HTTP, see :rfc:`2560` +Appendix A for details. A basic implementation of this is the function +``online_check``, which is available as long as the ``http_util`` module +was compiled in; check by testing for the macro ``BOTAN_HAS_HTTP_UTIL``. + +.. cpp:function:: OCSP::Response online_check(const X509_Certificate& issuer, \ + const BigInt& subject_serial, \ + const std::string& ocsp_responder, \ + const Certificate_Store* trusted_roots) + + Assemble a OCSP request for serial number ``subject_serial`` and attempt to request + it to responder at URI ``ocsp_responder`` over a new HTTP socket, parses and returns + the response. If trusted_roots is not null, then the response is additionally + validated using OCSP response API ``check_signature``. Otherwise, this call must be + performed later by the application. + +.. cpp:function:: OCSP::Response online_check(const X509_Certificate& issuer, \ + const X509_Certificate& subject, \ + const Certificate_Store* trusted_roots) + + Variant of the above but uses serial number and OCSP responder URI from ``subject``. |