Named parameters are less extensible
The named parameters approach looks nice, as it is a language feature. However, it requires C++20, only works on aggregates, and if you ever want to add more members to SSLctxInit you will break the ABI. I would therefore give a preference to the builder pattern in this case, which can avoid all these issues.
Simplify the builder pattern
You can simplify the builder pattern a little bit. Instead of having a builder object that build()s an SSLctx, I would just have an object representing a set of context parameters that can be modified, and then pass that to the constructor of SSLctx. So in the end you would write:
SSLctx ctx(SSLctxInit(SSLMethodType::Server)
.setProtocolInfo({TLS_1_0, TLS_1_2})
.addCertifcateAuthorityFiles("path1", "path2", "path3")
.addDefaultCertifcateAuthorityDir()
);
Actually, SSLctxInit can still be an aggregate struct, so you could support both the builder pattern and named parameters this way.
Alternatives
I see that in OpenSSL's own API, SSL_CTX_new() only needs the method type, you set other parameters later. So you can mirror that in your interface, and let SSLctx itself implement the builder pattern:
auto ctx = SSLctx(SSLMethodType::Server)
.setProtocolInfo({TLS_1_0, TLS_1_2})
.addCertifcateAuthorityFiles("path1", "path2", "path3")
.addDefaultCertifcateAuthorityDir();
Another completely different possibility is to have a variadic constructor, where you can pass whatever information you want in arbitrary order:
class SSLctx
{
…
template<typename Param...> Params>
SSLctx(SSLMethodType methodType, Param&&Params&&... params);
…
};
And then use it like so:
SSLctx ctx(SSLMethodType::Server,
ProtocolInfo(TLS_1_0, TLS_1_2),
CertifcateAuthorityDataInfo<File>CertifcateAuthorityFiles("path1", "path2", "path3"),
DefaultCertificateAuthorityDir()
);