-->

Setting up TLS1.2 connection which supports SNI

2019-02-17 23:03发布

问题:

We are trying to setup TLS1.2 connection. Have downloaded the latest OpenSSL in the Macbook. Using this code to create the TLS1.2 connection.
However this particular line is possibly causing the issue. It uses TLSv1.

  /* ---------------------------------------------------------- *
   * Set SSLv2 client hello, also announce SSLv3 and TLSv1      *
   * ---------------------------------------------------------- */
  method = SSLv23_client_method();

Tried TLSv1_2_client_method() method, but it gives below linking error:

Undefined symbols for architecture x86_64: "_TLSv1_2_client_method", referenced from: _main in sslconnect-7aa462.o

It would be a great help, if someone can assist in creating TLS1.2 connection and then calling from the objective C (if some special treatment required for socket programming).

[Kindly note that, I am not an iOS person. I am helping a team to fix a problem. Also newbie to socket programming myself, though the team has some experience.]

回答1:

Tried TLSv1_2_client_method() method, but it gives below linking error:

Undefined symbols for architecture x86_64: "_TLSv1_2_client_method", referenced from: _main in sslconnect-7aa462.o

OK, it sounds like you are linking against x86_64, but you need iOS. You can verify the architecture with the following two commands:

xcrun -sdk iphoneos lipo -info libcrypto.a
xcrun -sdk iphoneos lipo -info libssl.a

For example:

$ xcrun -sdk iphoneos lipo -info /usr/local/ssl/ios/lib/libcrypto.a 
Architectures in the fat file: /usr/local/ssl/ios/lib/libcrypto.a are: armv7 armv7s arm64 i386 

The first three architectures are self explanatory; while i386 is for the iOS debugger.

Note: /usr/local/ssl/ios/ is where I installed OpenSSL for iOS after I built it. Apple does not provide it.

If you don't have the four iOS architectures, then you have two options. First, you can build based on the iOS procedures in the User Guide for the OpenSSL FIPS Object Module, Appendix E.2, page 122.

Second is to download a prebuilt version from a GitHub. Here's a GitHub by noloader with OpenSSL 1.0.1h built using OpenSSL's procedures. Here's another one from Stefan Arentz that seems to be pretty popular, but its OpenSSL 1.0.1g.


and then calling from the objective C

C works fine with Objective C. There's nothing special about calling it.


...supports SNI for an iPhone application

On clients, you will need to set the server name with SSL_set_tlsext_host_name.

On servers, its more involved because you deal with a callback. For an example, see Serving multiple domains in one box with SNI.


A quick comment on this:

method = SSLv23_client_method();

... Tried TLSv1_2_client_method() method

Ideally, you perofrm something like this:

SSL_library_init();
SSL_load_error_strings();

const SSL_METHOD* method = SSLv23_method();
if(NULL == method) handleFailure();

SSL_CTX* ctx = SSL_CTX_new(method);
if(ctx == NULL) handleFailure();

/* Cannot fail ??? */
const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
SSL_CTX_set_options(ctx, flags);

...

The SSLv23_method gets you SSLv2 and above. Then you remove what you don't want, like SSLv2, SSLv3 and compression. That leaves you with TLS 1.0 and above (TLS 1.3 is around the corner, so you get it with no source code changes). You will get the highest protocol that the server supports (for example, TLS 1.2).

On the other hand, this will get you only TLS 1.2:

SSL_library_init();
SSL_load_error_strings();

const SSL_METHOD* method = TLSv1_2_client_method();
if(NULL == method) handleFailure();

That means you won't be able to connect to servers running TLS 1.0 (like many IIS servers). And if you connect to a Google server using ECC, then you need to ensure compression is disabled. Otherwise, you will fail because Google has an odd requirement that compression must be disabled when using TLS 1.2 with ECC.

In the case of your comment:

/* ---------------------------------------------------------- *
 * Set SSLv2 client hello, also announce SSLv3 and TLSv1      *
 * ---------------------------------------------------------- */

You would use the following, though I don't recommend it:

long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_TLS1_1 | SSL_OP_NO_TLS1_2;

I don't recommend it because it disables TLS 1.2 and TLS 1.1; and it enables SSLv3. There's no reason for SSLv3 in 2014.


Yet another comment....

Be sure to set your cipher suites with SSL_CTX_set_cipher_list. Pick 16 or so of your favorite, and ignore the rest. For the docs on it (and the names of the cipher suites like DHE-RSA-AES256-SHA), see SSL_CTX_set_cipher_list(3) and ciphers(1).

Choosing 16 or so cipher suites achieves two goals. First, it ensures you get exactly what you want. Second, it ensures older appliances like an F5 or an IronPort does not choke. The older appliances use a fixed size buffer, and that buffer is too small for a ClientHello with 80+ cipher suites. The ClientHello passes if there are 16 or 20 cipher suites.


And one last comment....

OpenSSL prior to 1.1.0 does not perform hostname matching. However, it does perform the other customary checks. So if you are usong 1.0.2 or below, you will have to perform the hostname matching. For information on the checks, see SSL/TLS Client on the OpenSSL wiki.