450 lines
18 KiB
ReStructuredText
450 lines
18 KiB
ReStructuredText
Botan 2.x to 3.x Migration
|
|
==============================
|
|
|
|
This is a guide on migrating applications from Botan 2.x to 3.0.
|
|
|
|
This guide attempts to be, but is not, complete. If you run into a problem while
|
|
converting code that does not seem to be described here, please open an issue on
|
|
Github.
|
|
|
|
Headers
|
|
--------
|
|
|
|
Many headers have been removed from the public API.
|
|
|
|
In some cases, such as ``datastor.h`` or ``tls_blocking.h``, the functionality
|
|
presented was entirely deprecated, in which case it has been removed.
|
|
|
|
In other cases (such as ``loadstor.h`` or ``rotate.h``) the header was really an
|
|
implementation header of the library and not intended to be consumed as a public
|
|
API. In these cases the header is still used internally, but not installed for
|
|
application use.
|
|
|
|
However in most cases there is a better way of performing the same operations,
|
|
which usually works in both 2.x and 3.x. For example, in 3.0 all of the
|
|
algorithm headers (such as ``aes.h``) have been removed. Instead you should
|
|
create objects via the factory methods (in the case of AES,
|
|
``BlockCipher::create``) which works in both 2.x and 3.0
|
|
|
|
Build Artifacts
|
|
---------------
|
|
|
|
For consistency with other platforms the DLL is now suffixed with the library's
|
|
major version on Windows as well.
|
|
|
|
TLS
|
|
---
|
|
|
|
Starting with Botan 3.0 TLS 1.3 is supported.
|
|
This development required a number of backward-incompatible changes to
|
|
accomodate the protocol differences to TLS 1.2, which is still supported.
|
|
|
|
Build modules
|
|
^^^^^^^^^^^^^
|
|
|
|
The build module ``tls`` is now internal and contains common TLS helpers. Users
|
|
have to explicitly enable ``tls12`` and/or ``tls13``. Note that for Botan 3.0 it
|
|
is not (yet) possible to exclusively enable TLS 1.3 at build time.
|
|
|
|
Removed Functionality
|
|
^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Functionality removed from the TLS implementation includes
|
|
|
|
* TLS 1.0, 1.1 and DTLS 1.0
|
|
* DSA ciphersuites
|
|
* anonymous ciphersuites
|
|
* SRP ciphersuites
|
|
* SEED ciphersuites
|
|
* Camellia CBC ciphersuites
|
|
* AES-128 OCB ciphersuites
|
|
* DHE_PSK ciphersuites
|
|
* CECPQ1 ciphersuites
|
|
|
|
enum classes
|
|
^^^^^^^^^^^^
|
|
|
|
The publicly available C++ enums in the TLS namespace are now `enum class` and
|
|
their member naming scheme was converted from `SHOUTING_SNAKE_CASE` to
|
|
`CamelCase`.
|
|
|
|
Callbacks
|
|
^^^^^^^^^
|
|
|
|
A number of new callbacks were added with TLS 1.3. None of those new callbacks
|
|
is mandatory to implement by applications, though. Additionally there are a few
|
|
backward incompatible changes in callbacks that might require attention by some
|
|
applications:
|
|
|
|
tls_record_received() / tls_emit_data()
|
|
"""""""""""""""""""""""""""""""""""""""
|
|
|
|
Those callbacks now take `std::span<const uint8_t>` instead of `const uint8_t*`
|
|
with a `size_t` buffer length.
|
|
|
|
tls_session_established()
|
|
"""""""""""""""""""""""""
|
|
|
|
This callback provides a summary of the just-negotiated connection. It used to
|
|
have a bool return value letting an application decide to store or discard the
|
|
connection's resumption information. This use case is now provided via:
|
|
`tls_should_persist_resumption_information()` which might be called more than
|
|
once for a single TLS 1.3 connection.
|
|
|
|
`tls_session_established` is not a mandatory callback anymore but still allows
|
|
applications to abort a connection given a summary of the negotiated
|
|
characteristics. Note that this summary is not a persistable `Session` anymore.
|
|
|
|
tls_verify_cert_chain()
|
|
"""""""""""""""""""""""
|
|
|
|
The parameter `ocsp_responses`, which was previously
|
|
`std::shared_ptr<OCSP::Response>`, is now `std::optional<OCSP::Response>`.
|
|
|
|
tls_modify_extensions() / tls_examine_extensions()
|
|
""""""""""""""""""""""""""""""""""""""""""""""""""
|
|
|
|
These callbacks now have an additional parameter of type `Handshake_Type` that
|
|
identify the TLS handshake message the extensions in question are residing in.
|
|
TLS 1.3 makes much heavier use of such extensions in a wider range of messages
|
|
to implement core protocol functionality.
|
|
|
|
tls_dh_agree() / tls_ecdh_agree() / tls_decode_group_param()
|
|
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
|
|
|
These callbacks were used as customization points for the TLS 1.2 key exchange
|
|
in the TLS client. To allow similar (and more) customizations with the
|
|
introduction of TLS 1.3, these callbacks were replaced with a more generic
|
|
approach.
|
|
|
|
Key agreement is split into two callbacks, namely `tls_generate_ephemeral_key()`
|
|
and `tls_ephemeral_key_agreement()`. Those are used in both clients and servers
|
|
and in all protocol versions. `tls_decode_group_param()` is removed as it became
|
|
obsolete by the replacement of the other two callbacks.
|
|
|
|
Policy
|
|
^^^^^^
|
|
|
|
choose_key_exchange_group()
|
|
"""""""""""""""""""""""""""
|
|
|
|
The new parameter `offered_by_peer` identifies the key exchange groups a peer
|
|
has sent public exchange offerings for (in TLS 1.3 handshakes only).
|
|
Choosing a key exchange group that is not listed is legal but will result in an
|
|
additional network round trip (cf. "Hello Retry Request").
|
|
In TLS 1.2, this vector is always empty and can be ignored.
|
|
|
|
session_ticket_lifetime()
|
|
"""""""""""""""""""""""""
|
|
|
|
Now returns `std::chrono::seconds` rather than a bare `uint32_t`.
|
|
|
|
Credentials Manager
|
|
^^^^^^^^^^^^^^^^^^^
|
|
|
|
find_cert_chain(), cert_chain() and cert_chain_single_type()
|
|
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
|
|
|
These methods now have a `cert_signature_schemes` parameter that identifies
|
|
a list of signature schemes the peer is willing to accept for signatures
|
|
in certificates.
|
|
Notably, this *does not necessarily* mean that the leaf certificate must feature
|
|
a public key type able to generate one of those schemes.
|
|
|
|
private_key_for()
|
|
"""""""""""""""""
|
|
|
|
Applications must now provide a `std::shared_ptr<>` to the requested private key
|
|
object instead of a raw pointer to better communicate the implementation's
|
|
life-time expectations of this private key object.
|
|
|
|
.. _tls_session_manager_migration:
|
|
|
|
Session and Ticket Handling
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Old (pre-Botan 3.0) sessions won't load in Botan 3.0 anymore and should be
|
|
discarded.
|
|
For applications using `Session_Manager_SQL` or `Session_Manager_SQLite`
|
|
discarding happens automatically on first access after the update.
|
|
|
|
With Botan 3.0 the session manager now is responsible for stateful session
|
|
handling (backed by a database) and creation and management of stateless session
|
|
tickets.
|
|
The latter was previously handled transparently by the TLS implementation itself.
|
|
|
|
Therefore, TLS server applications that relied on Botan's default session
|
|
management implementations (most notably `Session_Manager_SQLite` or
|
|
`Session_Manager_In_Memory`) are advised to re-evaluate their choice.
|
|
Have a look at `Session_Manager_Hybrid` to retain support for both stateful and
|
|
stateless TLS sessions.
|
|
TLS client applications may safely keep relying on the above-mentioned default
|
|
implementations.
|
|
|
|
Applications implementing their own `Session_Manager` will need to adapt to the
|
|
new base class API.
|
|
|
|
New API of Session Manager
|
|
""""""""""""""""""""""""""
|
|
|
|
TLS 1.3 removed the legacy resumption procedures based on session IDs or session
|
|
tickets and combined them under the protocol's Pre-Shared Key mechanism.
|
|
This new approach allows TLS servers to handle sessions both stateless (as
|
|
self-contained encrypted and authenticated tickets) and stateful (identified
|
|
with unique database handles).
|
|
|
|
To accomodates this flexibility the `Session_Manager` base class API has changed
|
|
drastically and is now responsible for creation, storage and management of both
|
|
stateful sessions and stateless session tickets.
|
|
Sub-classes therefore gain full control over the session ticket's structure and
|
|
content.
|
|
|
|
API details are documented in the class' doxygen comments.
|
|
|
|
The Session Object and its Handle
|
|
"""""""""""""""""""""""""""""""""
|
|
|
|
Objects of class `Session` are not aware of their "session ID" or their "session
|
|
ticket" anymore.
|
|
Instead, the new class `Session_Handle` encapsulates the session's identifier or
|
|
ticket and accompanies the `Session` object where necessary.
|
|
|
|
Algorithms Removed
|
|
-------------------
|
|
|
|
The algorithms CAST-256, MISTY1, Kasumi, DESX, XTEA, PBKDF1, MCEIES, CBC-MAC,
|
|
Tiger, CECPQ1, and NewHope have been removed.
|
|
|
|
Certificate API shared_ptr
|
|
----------------------------
|
|
|
|
Previously the certificate store used ``shared_ptr<X509_Certificate>`` in
|
|
various APIs. However starting in 2.4.0, ``X509_Certificate`` itself is a pimpl
|
|
to a ``shared_ptr``, making the outer shared pointer pointless. In 3.0 the
|
|
certificate interfaces have changed to just consume and return ``X509_Certificate``.
|
|
|
|
All Or Nothing Package Transform
|
|
----------------------------------
|
|
|
|
This code was deprecated and has been removed.
|
|
|
|
Exception Changes
|
|
-------------------
|
|
|
|
Several exceptions, mostly ones not used by the library, were removed.
|
|
|
|
A few others that were very specific (such as Illegal_Point) were replaced
|
|
by throws of their immediate base class exception type.
|
|
|
|
The base class of Encoding_Error and Decoding_Error changed from
|
|
Invalid_Argument to Exception. If you are explicitly catching Invalid_Argument,
|
|
verify that you do not need to now also explicitly catch Encoding_Error and/or
|
|
Decoding_Error.
|
|
|
|
X.509 Certificate Info Access
|
|
-------------------------------
|
|
|
|
Previously ``X509_Certificate::subject_info`` and ``issuer_info`` could be used
|
|
to query information about extensions. This is not longer the case; instead you
|
|
should either call a specific function on ``X509_Certificate`` which returns the
|
|
same information, or lacking that, iterate over the result of
|
|
``X509_Certificate::v3_extensions``.
|
|
|
|
OCSP Response Validation
|
|
------------------------
|
|
|
|
After mitigating CVE-2022-43705 the OCSP response signature validation was refactored.
|
|
This led to the removal of the `OCSP::Response::check_signature()` method. If you
|
|
must validate OCSP responses directly in your application please use the new method
|
|
`OCSP::Response::find_signing_certificate()` and `OCSP::Response::verify_signature()`.
|
|
|
|
Use of ``enum class``
|
|
--------------------------------
|
|
|
|
Several enumerations where modified to become ``enum class``, including
|
|
``DL_Group::Format``, ``CRL_Code``, ``EC_Group_Encoding``, ``Signature_Format``,
|
|
``Cipher_Dir``, ``TLS::Extension_Code``, ``TLS::Connection_Side``,
|
|
``TLS::Record_Type``, and ``TLS::Handshake_Type``
|
|
|
|
In many cases the enumeration values were renamed from ``SHOUTING_CASE`` to
|
|
``CamelCase``. In some cases where the enumeration was commonly used by
|
|
applications (for example ``Signature_Format`` and ``Cipher_Dir``) the old
|
|
enumeration names are retained as deprecated variants.
|
|
|
|
ASN.1 enums
|
|
---------------
|
|
|
|
The enum ``ASN1_Tag`` has been split into ``ASN1_Type`` and ``ASN1_Class``.
|
|
Unlike ``ASN1_Tag``, these new enums are ``enum class``. The members of the
|
|
enums have changed from ``SHOUTING_CASE`` to ``CamelCase``, eg ``CONSTRUCTED``
|
|
is now ``Constructed``.
|
|
|
|
Also an important change related to ``ASN1_Tag::PRIVATE``. This enum value was
|
|
incorrect, and actually was used for explicitly tagged context specific values.
|
|
Now, ``ASN1_Class::Private`` refers to the correct class, but would lead to a
|
|
different encoding vs 2.x's ``ASN1_Tag::PRIVATE``. The correct value to use in
|
|
3.0 to match ``ASN1_Tag::PRIVATE`` is ``ASN1_Class::ExplicitContextSpecific``.
|
|
|
|
Cipher Mode Granularity
|
|
-------------------------
|
|
|
|
Previously Cipher_Mode::update_granularity specified the minimum buffer size
|
|
that must be provided during processing. However the value returned was often
|
|
much larger than what was strictly required. In particular some modes can easily
|
|
accept inputs as small as 1 byte, but their update_granularity was much larger
|
|
to encourage best performance.
|
|
|
|
Now update_granularity returns the true minimum value, and the new
|
|
Cipher_Mode::ideal_granularity returns a value which is a multiple of
|
|
update_granularity sized for good performance.
|
|
|
|
If you are sizing buffers on the basis of update_granularity consider
|
|
using ideal_granularity instead. Otherwise you may encounter performance
|
|
regressions due to creating and processing very small buffers.
|
|
|
|
"SHA-160" and "SHA1"
|
|
---------------------
|
|
|
|
Previously the library accepted "SHA-160" and "SHA1" alternative names
|
|
for "SHA-1". This is no longer the case, you must use "SHA-1". Botan
|
|
2.x also recognizes "SHA-1".
|
|
|
|
PointGFp
|
|
------------
|
|
|
|
This type is now named ``EC_Point``
|
|
|
|
X509::load_key
|
|
-------------------
|
|
|
|
Previously these functions returned a raw pointer. They now return
|
|
a std::unique_ptr
|
|
|
|
PKCS11_Request::subject_public_key and X509_Certificate::subject_public_key
|
|
-----------------------------------------------------------------------------
|
|
|
|
These functions now return a unique_ptr
|
|
|
|
choose_sig_format removed
|
|
---------------------------
|
|
|
|
The freestanding functions choose_sig_format have been removed.
|
|
Use X509_Object::choose_sig_format
|
|
|
|
DLIES Constructors
|
|
--------------------
|
|
|
|
Previously the constructors to the DLIES classes took raw pointers,
|
|
and retained ownership of them. They now consume std::unique_ptrs
|
|
|
|
Credentials_Manager::private_key_for
|
|
-------------------------------------
|
|
|
|
Previously this function returned a raw pointer, which the Credentials_Manager
|
|
implementation had to keep alive "forever", since there was no way for it to
|
|
know when or if the TLS layer had completed using the returned key.
|
|
|
|
Now this function returns std::shared_ptr<Private_Key>
|
|
|
|
OID operator+
|
|
------------------------
|
|
|
|
OID operator+ allowed concatenating new fields onto an object identifier. This
|
|
was not used at all within the library or the tests, and seems of marginal
|
|
value, so it was removed.
|
|
|
|
If necessary in your application, this can be done by retrieving the
|
|
vector of components from your source OID, push the new element onto the vector
|
|
and create an OID from the result.
|
|
|
|
RSA with "EMSA1" padding
|
|
-------------------------
|
|
|
|
EMSA1 indicates that effectively the plain hash is signed, with no other
|
|
padding. It is typically used for algorithms like ECSDA, but was allowed for
|
|
RSA. This is now no longer implemented.
|
|
|
|
If you must generate such signatures for some horrible reason, you can pre-hash
|
|
the message using a hash function as usual, and then sign using a "Raw" padding,
|
|
which will allow you to sign any arbitrary bits with no preprocessing.
|
|
|
|
ECDSA/DSA with "EMSA1" padding
|
|
---------------------------------
|
|
|
|
Previous versions of Botan required using a hash specifier like "EMSA1(SHA-256)"
|
|
when generating or verifying ECDSA/DSA signatures, with the specified hash. The
|
|
"EMSA1" was a reference to a now obsolete IEEE standard.
|
|
|
|
In Botan 3 the "EMSA1" notation is still accepted, but now also it is possible
|
|
to simply use the name of the hash, eg "EMSA1(SHA-256)" becomes "SHA-256".
|
|
|
|
Signature Algorithm OIDs
|
|
-----------------------------
|
|
|
|
In line with the previous entries, previously Botan used a string like
|
|
"ECDSA/EMSA1(SHA-256)" to identify the OID 1.2.840.10045.4.3.2. Now it
|
|
uses the string "ECDSA/SHA-256" instead, and does not recognize the
|
|
EMSA1 variant at all (for example in ``OID::from_string``).
|
|
|
|
Public Key Signature Padding
|
|
-----------------------------
|
|
|
|
In previous versions Botan was somewhat lenient about allowing the application
|
|
to specify using a hash which was in fact incompatible with the algorithm. For
|
|
example, Ed25519 signatures are *always* generated using SHA-512; there is no
|
|
choice in the matter. In the past, requesting using some other hash, say
|
|
SHA-256, would be silently ignored. Now an exception is thrown, indicating the
|
|
desired hash is not compatible with the algorithm.
|
|
|
|
In previous versions, various APIs required that the application specify the
|
|
hash function to be used. In most cases this can now be omitted (passing an
|
|
empty string) and a suitable default will be chosen.
|
|
|
|
Discrete Logarithm Key Changes
|
|
--------------------------------
|
|
|
|
Keys based on the discrete logarithm problem no longer derive from the
|
|
DL_Scheme_PrivateKey and DL_Scheme_PublicKey classes; these classes
|
|
have been removed.
|
|
|
|
Functions to access DL algorithm internal fields (such as the integer value of
|
|
the private key using ``get_x``) have been removed. If you need access to this
|
|
information you can use the new ``get_int_field`` function.
|
|
|
|
The constructors of the DL scheme private keys have changed. Previously, loading
|
|
and creating a key used the same constructor, namely one taking arguments
|
|
``(DL_Group, RandomNumberGenerator&, BigInt x = 0)`` and then the behavior of
|
|
the constructor depend on if ``x`` was zero (in which case a new key was
|
|
created) or otherwise if ``x`` was non-zero then it was taken as the private
|
|
key. Now there are two constructors, one taking a random number generator and a
|
|
group, which generates a new key, and a second taking a group and an integer,
|
|
which loads an existing key.
|
|
|
|
XMSS Signature Changes
|
|
------------------------
|
|
|
|
The logic to derive WOTS+ private keys from the seed contained in the XMSS
|
|
private key has been updated according to the recommendations in
|
|
NIST SP 800-208. While signatures created with old private keys are still valid using
|
|
the old public key, new valid signatures cannot be created. To still support legacy
|
|
private XMSS keys, they can be used by passing ``WOTS_Derivation_Method::Botan2x`` to
|
|
the constructor of the ``XMSS_PrivateKey``.
|
|
|
|
Private XMSS keys created this way use the old derivation logic and can therefore
|
|
generate new valid signatures. It is recommended to use
|
|
``WOTS_Derivation_Method::NIST_SP800_208`` (default) when creating new XMSS keys.
|
|
|
|
Random Number Generator
|
|
-----------------------
|
|
|
|
Fetching a large number of bytes via `randomize_with_input()` from a stateful
|
|
RNG will now incorporate the provided "input" data in the first request to the
|
|
underlying DRBG only. This applies to such DRBGs that pose a limit on the number
|
|
of bytes per request (most notable ``HMAC_DRBG`` with a 64kB default). Botan 2.x
|
|
(erroneously) applied the input to *all* underlying DRBG requests in such cases.
|
|
|
|
Applications that rely on a static seed for deterministic RNG output might
|
|
observe a different byte stream in such cases. As a workaround, users are
|
|
advised to "mimick" the legacy behaviour by manually pulling from the RNG in
|
|
"byte limit"-sized chunks and provide the "input" with each invocation.
|