Aha, thanks Matt. The code I resorted to using does SSL_CTX_new(), SSL_new(), SSL_CTX_set_cipher_list(), and then iterates through SSL_get1_supported_ciphers() looking for anything with 3DES/RC4. So it seems I can simplify that down to just SSL_CTX_new() and SSL_CTX_set_cipher_list().
I know that supporting obsolete, insecure crypto isn't a high priority for OpenSSL (though unfortunately a necessary one for OpenConnect), but it does seem that having a simple general-purpose API for checking "is this cipher(suite) known and can we actually use it?" would be a desirable feature. This particular case was a bit frustrating to me because with OpenSSL 1.0.x, there is a much simpler way to check if particular ciphers can be instantiated with the SSL_METHOD API exposed… /* XX: Based on my reading of the SSL_METHOD API * ( https://github.com/openssl/openssl/blob/5a5530a29abcf5d7ab7194d73b3807d568b06cbd/ssl/ssl_local.h ) * and the constants in the ssl3.h header * ( https://github.com/openssl/openssl/blob/master/include/openssl/ssl3.h#L45-L50 ), * as well as the way that the 3DES/RC4 ciphers do or don't get compiled in * (https://github.com/openssl/openssl/blob/master/ssl/s3_lib.c#L166-L182) * * This is the most reasonable way to figure out whether the library can * actually instantiate a cipher. The other would be to iterate through * the ciphers (using m->num_ciphers() and m->get_cipher(num)) and * compare them by name. */ int can_enable_insecure_crypto() { const SSL_METHOD *m = SSLv23_client_method(); unsigned char ch_SSL3_CK_RSA_DES_192_CBC3_SHA[2] = { 0x00, 0x0a }; unsigned char ch_SSL3_CK_RSA_RC4_128_SHA[2] = { 0x00, 0x05 }; if (!m) return -ENOMEM; /* XX: static, should never happen */ if (m->get_cipher_by_char(ch_SSL3_CK_RSA_DES_192_CBC3_SHA) && m->get_cipher_by_char(ch_SSL3_CK_RSA_RC4_128_SHA)) return 0; return -ENOENT; } On Sun, May 24, 2020 at 2:49 PM Matt Caswell <m...@openssl.org> wrote: > > > On 23/05/2020 21:08, Daniel Lenski wrote: > > When OpenConnect is explicitly requested to connect to an ancient > > server, what I am currently trying to do is > > SSL_CTX_set_cipher_list(ctx, "DEFAULT:+3DES:+RC4"). However, this > > fails silently on subsequent connection if 3DES/RC4 support isn't > > available. > > As long as at least one cipher is successfully set then this command > will succeed. By setting "DEFAULT" you're getting all the ciphersuites > in the default list and hence the command succeeds. If you want to test > if you have any 3DES ciphersuites available then you can try this: > > SSL_CTX_set_cipher_list(ctx, "3DES") > > This will succeed if at least one 3DES cipersuite is available, and fail > otherwise. Or you could do: > > SSL_CTX_set_cipher_list(ctx, "3DES:RC4") > > Which will succeed if there is at least one ciphersuite based on 3DES or > RC4 available, and fail otherwise. > > > > It was suggested that I should try EVP_get_ciphername(). > > > The ciphers available via the EVP API are only indirectly related to the > ciphersuites available in libssl. If there are no 3DES based ciphers > available via EVP then there won't be any libssl 3DES based > ciphersuites. But the reverse is not true, i.e. 3DES may not be > available in libssl, but it is via EVP. So this is not a great test for > your purposes. > > Matt >