Enabling TLSv1.2 on CentOS 5

18 June 2018

We have a legacy IVR (Interactive Voice Response) software running an Asterisk PBX Server. It executes AGI (Asterisk Gateway Interface) compliant protocol to launch external programs written in Python to control telephony channel, play audio, read DTMF (Dual Tone Multi Frequency) digits, etc. We ran into an issue when the payment gateway stopped supporting lower versions of TLS (Transport Layer Security). It requires TLSv1.2 as minimum version.

Issue

$ curl -Ivvv https://secure.payment.com
* About to connect() to secure.payment.com port 443
*   Trying 185.n.n.n... connected
* Connected to secure.payment.com (185.n.n.n) port 443
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* SSLv2, Client hello (1):
Unknown SSL protocol error in connection to secure.payment.com:443 
* Closing connection #0
curl: (35) Unknown SSL protocol error in connection to secure.payment.com:443

Workaround

You need to build OpenSSL and cURL using your current CentOS.

$ wget https://www.openssl.org/source/openssl-1.0.2a.tar.gz --no-check-certificate

Resolving www.openssl.org... 23.214.162.69, 2a02:26f0:f6:199::c1e, 2a02:26f0:f6:1be::c1e
Connecting to www.openssl.org|23.214.162.69|:443... connected.
WARNING: cannot verify www.openssl.org's certificate, issued by `/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3':
  Unable to locally verify the issuer's authority.
HTTP request sent, awaiting response... 200 OK
Length: 5262089 (5.0M) [application/x-gzip]
Saving to: `openssl-1.0.2a.tar.gz'

100%[============================================================>] 5,262,089   3.14M/s   in 1.6s    
$ wget http://curl.haxx.se/download/curl-7.42.1.tar.gz

Resolving curl.haxx.se (curl.haxx.se)... 151.101.2.49, 151.101.66.49, 151.101.130.49, ...
Connecting to curl.haxx.se (curl.haxx.se)|151.101.2.49|:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: https://curl.haxx.se/download/curl-7.42.1.tar.gz [following]

Connecting to curl.haxx.se (curl.haxx.se)|151.101.2.49|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 4291533 (4.1M) [application/x-gzip]
Saving to: ‘curl-7.42.1.tar.gz’

100%[===========================================================>]   4.09M  4.33MB/s    in 0.9s

Build OpenSSL

$ ./config -fpic shared
Operating system: x86_64-whatever-linux2
Configuring for linux-x86_64
Configuring for linux-x86_64
    no-ec_nistp_64_gcc_128 [default]  OPENSSL_NO_EC_NISTP_64_GCC_128 (skip dir)
    no-gmp          [default]  OPENSSL_NO_GMP (skip dir)
    no-jpake        [experimental] OPENSSL_NO_JPAKE (skip dir)
    no-krb5         [krb5-flavor not specified] OPENSSL_NO_KRB5
    no-libunbound   [experimental] OPENSSL_NO_LIBUNBOUND (skip dir)
    no-md2          [default]  OPENSSL_NO_MD2 (skip dir)
    no-rc5          [default]  OPENSSL_NO_RC5 (skip dir)
    no-rfc3779      [default]  OPENSSL_NO_RFC3779 (skip dir)
    no-sctp         [default]  OPENSSL_NO_SCTP (skip dir)
    no-ssl-trace    [default]  OPENSSL_NO_SSL_TRACE (skip dir)
    no-store        [experimental] OPENSSL_NO_STORE (skip dir)
    no-unit-test    [default]  OPENSSL_NO_UNIT_TEST (skip dir)
    no-zlib         [default] 
    no-zlib-dynamic [default] 
...
Configured for linux-x86_64.
$ sudo make && make build
...
cp libcrypto.pc /usr/local/ssl/lib/pkgconfig
chmod 644 /usr/local/ssl/lib/pkgconfig/libcrypto.pc
cp libssl.pc /usr/local/ssl/lib/pkgconfig
chmod 644 /usr/local/ssl/lib/pkgconfig/libssl.pc
cp openssl.pc /usr/local/ssl/lib/pkgconfig
chmod 644 /usr/local/ssl/lib/pkgconfig/openssl.pc

$ sudo /sbin/ldconfig

Build cURL

$ sudo ./configure --with-ssl=/usr/local/ssl
...
configure: Configured to build curl/libcurl:

  curl version:     7.42.1
  Host setup:       x86_64-unknown-linux-gnu
  Install prefix:   /usr/local
  Compiler:         gcc
  SSL support:      enabled (OpenSSL)
  SSH support:      no      (--with-libssh2)
  zlib support:     enabled
  GSS-API support:  no      (--with-gssapi)
  TLS-SRP support:  enabled
  resolver:         default (--enable-ares / --enable-threaded-resolver)
  IPv6 support:     no      (--enable-ipv6)
  Unix sockets support: enabled
  IDN support:      no      (--with-{libidn,winidn})
  Build libcurl:    Shared=yes, Static=yes
  Built-in manual:  enabled
  --libcurl option: enabled (--disable-libcurl-option)
  Verbose errors:   enabled (--disable-verbose)
  SSPI support:     no      (--enable-sspi)
  ca cert bundle:   /etc/pki/tls/certs/ca-bundle.crt
  ca cert path:     no
  LDAP support:     no      (--enable-ldap / --with-ldap-lib / --with-lber-lib)
  LDAPS support:    no      (--enable-ldaps)
  RTSP support:     enabled
  RTMP support:     no      (--with-librtmp)
  metalink support: no      (--with-libmetalink)
  HTTP2 support:    disabled (--with-nghttp2)
  Protocols:        DICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS POP3 POP3S RTSP SMB SMBS SMTP SMTPS TELNET TFTP

$ sudo make && make install

Test the workaround

curl -Ivvv https://secure.payment.com
*   Trying 185.n.n.n...
* Connected to secure.payment.com (185.n.n.n) port 443 (#0)
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* TLSv1.2, TLS Unknown, Unknown (22):
* TLSv1.2, TLS handshake, Client hello (1):
* SSLv2, Unknown (22):
* TLSv1.2, TLS handshake, Server hello (2):
* SSLv2, Unknown (22):
* TLSv1.2, TLS handshake, CERT (11):
* SSLv2, Unknown (22):
* TLSv1.2, TLS handshake, Server key exchange (12):
* SSLv2, Unknown (22):
* TLSv1.2, TLS handshake, Server finished (14):
* SSLv2, Unknown (22):
* TLSv1.2, TLS handshake, Client key exchange (16):
* SSLv2, Unknown (20):
* TLSv1.2, TLS change cipher, Client hello (1):
* SSLv2, Unknown (22):
* TLSv1.2, TLS handshake, Finished (20):
* SSLv2, Unknown (20):
* TLSv1.2, TLS change cipher, Client hello (1):
* SSLv2, Unknown (22):
* TLSv1.2, TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use http/1.1
* Server certificate:
*    subject: jurisdictionC=GB; businessCategory=Private Organization; serialNumber=03539217; C=GB; ST=London; L=London; O=Pay360 Limited; CN=secure.payment.com
*    start date: 2017-03-16 00:00:00 GMT
*    expire date: 2019-03-16 23:59:59 GMT
*    subjectAltName: secure.payment.com matched
*    issuer: C=US; O=Symantec Corporation; OU=Symantec Trust Network; CN=Symantec Class 3 EV SSL CA - G3
*    SSL certificate verify ok.

Next challenge is updating Python. Having curl working can be a good fallback if Python 2.7.9 upgrade fails.

Credit goes to this blog