I did some investigation and found the following:
The struct ProtocolVersion can contain a single protocol version (by major and minor version number).
The struct WOLFSSL_METHOD reflects the negotiation method and contains the following fields,
/* wolfSSL method type */
struct WOLFSSL_METHOD {
ProtocolVersion version;
byte side; /* connection side, server or client */
byte downgrade; /* whether to downgrade version, default no */
};
The (much larger) struct Options contains a field `downgrade` (one bit) and a byte field `minDowngrade` which is
the minimum minor version of the protocol that will be negotiated (or so it seems from the source code).
The function `void InitSSL_Method(WOLFSSL_METHOD* method, ProtocolVersion pv)` initializes
the `WOLFSSL_METHOD` passed with the `ProtocolVersion` passed and sets `side` to `WOLFSSL_CLIENT_END`
and `downgrade` to 0.
The following functions set the byte field of struct WOLFSSL_METHOD called `downgrade` to 1 and leave
the `side` field at `WOLFSSL_CLIENT_END` (as opposed to setting it to `WOLFSSL_SERVER_END`):
wolfSSLv23_client_method()
wolfTLS_client_method()
wolfDTLS_client_method()
Note that (apart from horrible code duplication) `wolfTLS_client_method()` initializes the `ProtocolVersion` field with TLS 1.0, 1.1, 1.2 or 1.3, whichever version is the highest that is compiled into the library. While `wolfSSLv23_client_method()` initializes the `ProtocolVersion` field with TLS 1.1, 1.2 or 1.3, whichever version is the highest compiled in - and if none is compiled in it simply leaves the structure uninitialized for a nice crash or other undefined behavior.
Assuming nobody in their right mind will compile wolfssl without support for TLS 1.3 for now, both functions do the exact same thing; but it seems to me that `wolfSSLv23_client_method`is broken in multiple ways.
The struct WOLFSSL_CTX also has a `minDowngrade` field. This field is copied to WOLFSSL->options.minDowngrade in `SetSSL_CTX`. It is also set in `dtls_export_load` which I will ignore. Finally options.minDowngrade seems to be changed by `SetMinVersionHelper` when called from `wolfSSL_SetMinVersion` (https://www.wolfssl.com/doxygen/group__ … 92e0c5c4f5) [Note the outdated / incorrect documentation there: there is no mention of wolfTLS_client_method() or wolfDTLS_client_method()].
Likewise it is possible to change the `minDowngrade` field in the WOLFSSL_CTX struct with `wolfSSL_CTX_SetMinVersion`.
In summary, my conclusion is that the answer to okba.zoueghi's question is that one has to use `ctx = wolfSSL_CTX_new(wolfTLS_client_method())` and then either call `wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1_1)` prior to creating a WOLFSSL with `ssl = wolfSSL_new(ctx)`, or call wolfSSL_SetMinVersion(ssl, WOLFSSL_TLSV1_1) afterwards.
Here is a snippet of my test code:
/* declare wolfSSL objects */
WOLFSSL_CTX* ctx;
/* Create and initialize WOLFSSL_CTX */
if ((ctx = wolfSSL_CTX_new(wolfTLS_client_method())) == NULL) {
fprintf(stderr, "ERROR: failed to create WOLFSSL_CTX\n");
goto init_cleanup;
}
// Demand at least TLS version 1.2.
wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1_2);
Which should try to negotiate TLS 1.3 and if that fails try TLS 1.2 and if that fails give up.