Skip to content
 

OpenSSL vs. GnuTLS cipher names

Some distro (notably Ubuntu in this case) "cleverly" link some (not all) SSL-aware applications against the GnuTLS library rather than OpenSSL.

While this works fine most of the time, it creates some problems in those configuration files where you want to specify an explicit name for a cipher or cipher group. It turns out that the two libraries use different (and rigorously incompatible) names for the same ciphers. In this specific case, the problem was that a GnuTLS-OpenLDAP daemon was complaining at this (OpenSSL syntax) directive in slapd.conf:

TLSCipherSuite HIGH:MEDIUM:-SSLv2

HIGH, MEDIUM and SSLv2 are OpenSSL specific shortcut words to indicate a whole list of ciphers; GnuTLS apparently does not support them. Even if you were to replace them with the actual list of ciphers, that still wouldn't work because OpenSSL and GnuTLS use different names for the same ciphers.

You can see that by requesting the list of supported ciphers with the two tools:

# openssl ciphers -v
DHE-RSA-AES256-SHA      SSLv3 Kx=DH       Au=RSA  Enc=AES(256)  Mac=SHA1
DHE-DSS-AES256-SHA      SSLv3 Kx=DH       Au=DSS  Enc=AES(256)  Mac=SHA1
AES256-SHA              SSLv3 Kx=RSA      Au=RSA  Enc=AES(256)  Mac=SHA1
...
# gnutls-cli --list
Cipher suites:
TLS_ANON_DH_ARCFOUR_MD5                                 0x00, 0x18      SSL 3.0
TLS_ANON_DH_3DES_EDE_CBC_SHA1                           0x00, 0x1b      SSL 3.0
TLS_ANON_DH_AES_128_CBC_SHA1                            0x00, 0x34      SSL 3.0
...
Certificate types: X.509, OPENPGP
Protocols: SSL 3.0, TLS 1.0, TLS 1.1, TLS 1.2
Ciphers: AES 256 CBC, AES 128 CBC, 3DES 168 CBC, DES CBC, ARCFOUR 128, ARCFOUR 40, RC2 40, NULL
MACs: SHA, MD5, SHA256, SHA384, SHA512, MD2, RIPEMD160, NULL
Key exchange algorithms: Anon DH, RSA, RSA EXPORT, DHE RSA, DHE DSS, SRP DSS, SRP RSA, SRP, PSK, DHE PSK
Compression: LZO, DEFLATE, NULL

More comprehensive lists can be found here (GnuTLS) and here (OpenSSL). Don't be deceived by the fact that GnuTLS names look similar to those used in the official specifications (those listed in the OpenSSL page); in reality they differ (and the names used by OpenSSL differ from both). For example, whereas the official cipher name is TLS_RSA_WITH_NULL_MD5, GnuTLS uses TLS_RSA_NULL_MD5, but OpenSSL uses NULL-MD5; or whereas the official name is TLS_DHE_RSA_WITH_AES_128_CBC_SHA, GnuTLS uses TLS_DHE_RSA_AES_128_CBC_SHA1, OpenSSL uses DHE-RSA-AES128-SHA; for the official TLS_DHE_DSS_WITH_RC4_128_SHA, GnuTLS offers TLS_DHE_DSS_ARCFOUR_SHA1 while OpenSSL uses DHE-DSS-RC4-SHA; and so on and so forth. Nor there seem to be a predictable way to derive one given one of the two other. Nice, uh?

GnuTLS only supports SSL 3.0 and later (TLS) algorithms, while OpenSSL still supports older SSL versions (in addition to SSL 3.0 and TLS, of course). However, for all practical purposes, SSL versions prior to 3.0 should not be used anyway. Also, to further complicate things, what OpenSSL calls "SSLv3" is effectively SSLv3 plus TLS (this is from the documentation: "...description of protocol version (SSLv2 or SSLv3; the latter includes TLS)").

After a bit of research, I realized that 99% of the configuration file documentation you can find on the Internet refers to SSL cipher and cipher group names using OpenSSL conventions (which kind of makes sense, given that that's what 99% of the distros do). However, it seems that no ready-made tool or table exists to easily convert between the two syntaxes, so I decided to hack my own.

Disclaimer: what follows is just something that "Works For Me (tm)". I make no guarantees that it will work for you, or even that it's correct at all.

After writing down all the names, and doing a painful comparison by hand of the crypto, hash, key exchange etc. algorithm used by each, I came up with the following (incomplete) equivalence table:

Standard name                       GnuTLS name                    OpenSSL name
----------------------------------------------------------------------------------
TLS_DH_anon_EXPORT_WITH_RC4_40_MD5  TLS_RSA_EXPORT_ARCFOUR_40_MD5  EXP-ADH-RC4-MD5
TLS_DHE_DSS_WITH_RC4_128_SHA        TLS_DHE_DSS_ARCFOUR_SHA1       DHE-DSS-RC4-SHA
SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA   TLS_DHE_DSS_3DES_EDE_CBC_SHA1  EDH-DSS-DES-CBC3-SHA
SSL_DHE_RSA_WITH_DES_CBC_SHA        TLS_DHE_RSA_3DES_EDE_CBC_SHA1  EDH-RSA-DES-CBC3-SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA    TLS_DHE_DSS_AES_128_CBC_SHA1   DHE-DSS-AES128-SHA
TLS_DHE_DSS_WITH_AES_256_CBC_SHA    TLS_DHE_DSS_AES_256_CBC_SHA1   DHE-DSS-AES256-SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA    TLS_DHE_RSA_AES_128_CBC_SHA1   DHE-RSA-AES128-SHA
TLS_DHE_RSA_WITH_AES_256_CBC_SHA    TLS_DHE_RSA_AES_256_CBC_SHA1   DHE-RSA-AES256-SHA
TLS_RSA_WITH_AES_128_CBC_SHA        TLS_RSA_AES_128_CBC_SHA1       AES128-SHA
TLS_RSA_WITH_AES_256_CBC_SHA        TLS_RSA_AES_256_CBC_SHA1       AES256-SHA
TLS_RSA_WITH_RC4_128_MD5            TLS_RSA_ARCFOUR_MD5            RC4-MD5
TLS_RSA_WITH_RC4_128_SHA            TLS_RSA_ARCFOUR_SHA1           RC4-SHA
TLS_DH_anon_WITH_RC4_128_MD5        TLS_ANON_DH_ARCFOUR_MD5        ADH-RC4-MD5
TLS_DH_anon_WITH_3DES_EDE_CBC_SHA   TLS_ANON_DH_3DES_EDE_CBC_SHA1  ADH-DES-CBC3-SHA
TLS_RSA_WITH_NULL_MD5               TLS_RSA_NULL_MD5               NULL-MD5
TLS_DH_anon_WITH_AES_128_CBC_SHA    TLS_ANON_DH_AES_128_CBC_SHA1   ADH-AES128-SHA
TLS_DH_anon_WITH_AES_256_CBC_SHA    TLS_ANON_DH_AES_256_CBC_SHA1   ADH-AES256-SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA       TLS_RSA_3DES_EDE_CBC_SHA1      DES-CBC3-SHA

There are some cipher suites only supported by OpenSSL (like the camellia-based ones), and some only supported by GnuTLS (for example the *_PSK_* or the *_SRP_* ones); those do not appear in the table above. While the table is incomplete, those that do appear seem to cover the majority of the commonly used ciphers.

Now, having that table is not enough yet; if you're migrating a config file in OpenSSL format that uses cipher suite strings, like HIGH, MEDIUM etc., you would first have to expand those to their component ciphers, and then find the GnuTLS equivalents. Now that we have the above table, this can be automated, and here is a simple script that will do that:

#!/bin/bash

# ssl_cipher_convert: given a list of ciphersuites as understood by
# OpenSSL, outputs the equivalent list on GnuTLS format.

usage() {
  echo "Usage: $0 [ -h ] [ -t convtable ]" >&2
  echo "" >&2
  echo "Example: openssl ciphers -v 'HIGH:MEDIUM' | $0 -t /path/to/convtable.txt" >&2
}

# default equivalence table location
convtable=/home/waldner/convtable.txt

while [ $# -gt 0 ]; do
  case "$1" in
    -h)
      usage
      exit 1
      ;;
    -t)
      convtable=$2
      shift 2
      ;;
     *)
      echo "Unknown option $1" >&2
      usage
      exit 1
      ;;
  esac
done

# sanity checks
if [ ! -f "$convtable" ]; then
  echo "Conversion table $convtable not found!" >&2
  usage
  exit 1
fi

# Do the conversion
awk '
NR==FNR {
  # skip header lines
  if(FNR>2) eq[$3]=$2
  next
}
{
  # nobody is perfect!
  print ($1 in eq)?eq[$1]:"Not in table!"
}
' "$convtable" -

exit 0

Let's test it:

$ openssl ciphers -v 'HIGH:MEDIUM:-SSLv2' | ssl_cipher_convert
TLS_ANON_DH_AES_256_CBC_SHA1
TLS_DHE_RSA_AES_256_CBC_SHA1
TLS_DHE_DSS_AES_256_CBC_SHA1
TLS_RSA_AES_256_CBC_SHA1
TLS_ANON_DH_AES_128_CBC_SHA1
TLS_DHE_RSA_AES_128_CBC_SHA1
TLS_DHE_DSS_AES_128_CBC_SHA1
TLS_RSA_AES_128_CBC_SHA1
TLS_ANON_DH_3DES_EDE_CBC_SHA1
TLS_DHE_RSA_3DES_EDE_CBC_SHA1
TLS_DHE_DSS_3DES_EDE_CBC_SHA1
TLS_RSA_3DES_EDE_CBC_SHA1
TLS_ANON_DH_ARCFOUR_MD5
TLS_RSA_ARCFOUR_SHA1
TLS_RSA_ARCFOUR_MD5

$ openssl ciphers -v 'HIGH:-SSLv2:@STRENGTH' | ssl_cipher_convert
TLS_ANON_DH_AES_256_CBC_SHA1
TLS_DHE_RSA_AES_256_CBC_SHA1
TLS_DHE_DSS_AES_256_CBC_SHA1
TLS_RSA_AES_256_CBC_SHA1
TLS_ANON_DH_3DES_EDE_CBC_SHA1
TLS_DHE_RSA_3DES_EDE_CBC_SHA1
TLS_DHE_DSS_3DES_EDE_CBC_SHA1
TLS_RSA_3DES_EDE_CBC_SHA1
TLS_ANON_DH_AES_128_CBC_SHA1
TLS_DHE_RSA_AES_128_CBC_SHA1
TLS_DHE_DSS_AES_128_CBC_SHA1
TLS_RSA_AES_128_CBC_SHA1

$ openssl ciphers -v '3DES:+RSA' | ssl_cipher_convert
TLS_ANON_DH_3DES_EDE_CBC_SHA1
TLS_DHE_RSA_3DES_EDE_CBC_SHA1
TLS_DHE_DSS_3DES_EDE_CBC_SHA1
TLS_RSA_3DES_EDE_CBC_SHA1
Not in table!

# nobody's perfect, as I said

And there you have it. Even if you happen to give it a cipher string that expands to some ciphers that are not in the table, I think it could still be useful for finding a common subset (ie, take only those that are found). For the problem at hand, GnuTLS-OpenLDAP requires the ciphers to be in a colon-separated string, so a little postprocessing is necessary:

$ openssl ciphers -v 'HIGH:MEDIUM:-SSLv2' | ssl_cipher_convert | awk '{printf "%s%s", s, $0;s=":"}END{print""}'
TLS_ANON_DH_AES_256_CBC_SHA1:TLS_DHE_RSA_AES_256_CBC_SHA1:TLS_DHE_DSS_AES_256_CBC_SHA1:TLS_RSA_AES_256_CBC_SHA1:TLS_ANON_DH_AES_128_CBC_SHA1:TLS_DHE_RSA_AES_128_CBC_SHA1:TLS_DHE_DSS_AES_128_CBC_SHA1:TLS_RSA_AES_128_CBC_SHA1:TLS_ANON_DH_3DES_EDE_CBC_SHA1:TLS_DHE_RSA_3DES_EDE_CBC_SHA1:TLS_DHE_DSS_3DES_EDE_CBC_SHA1:TLS_RSA_3DES_EDE_CBC_SHA1:TLS_ANON_DH_ARCFOUR_MD5:TLS_RSA_ARCFOUR_SHA1:TLS_RSA_ARCFOUR_MD5

ready to be copied and pasted into the TLSCipherSuite directive in slapd.conf.

3 Comments

  1. Jens says:

    Hey,
    I made a small script depending on openssl and gnutls-cli for automatic conversion from openssl to gnutls:
    ---
    #!/bin/bash

    OPENSSL_CIPHERS_DEFAULT="ALL:-ADH:-RC4+RSA:+HIGH:-MEDIUM:-LOW:-SSLv2:-EXP"
    OPENSSL_CIPHERS=${1:-OPENSSL_CIPHERS_DEFAULT}

    HEX_IDS=$(openssl ciphers -V 'ALL:-ADH:-RC4+RSA:+HIGH:-MEDIUM:-LOW:-SSLv2:-EXP' | awk '{print $1;}' | tr '[:upper:]' '[:lower:]')

    GNUTLS_CIPHERS=""
    for ID in ${HEX_IDS}; do
    ID=$(echo $ID | sed 's/,/, /g')
    GNUTLS=$(gnutls-cli --list | grep "$ID" | awk '{print $1;}')
    if test "${GNUTLS}" = ""; then
    echo "Unsupported: $ID"
    else
    GNUTLS_CIPHERS="${GNUTLS_CIPHERS}:${GNUTLS}"
    fi
    done

    echo "OpenSSL-Ciphers: ${OPENSSL_CIPHERS}"
    echo "GnuTLS-Ciphers: ${GNUTLS_CIPHERS}"
    ---

    • waldner says:

      Hey, this is really nice and helpful! Thanks!

      • waldner says:

        I've taken the liberty of making some minor changes to the script. Here it is.

        #!/bin/bash
          
        OPENSSL_CIPHERS_DEFAULT="ALL:-ADH:-RC4+RSA:+HIGH:-MEDIUM:-LOW:-SSLv2:-EXP"
        OPENSSL_CIPHERS=${1:-"$OPENSSL_CIPHERS_DEFAULT"}
        
        HEX_IDS=$(openssl ciphers -V "$OPENSSL_CIPHERS" | awk '{ print tolower($1)}')
        
        GNUTLS_CIPHERS=""
        while IFS= read -r ID; do
          ID=${ID/,/, }
          GNUTLS=$(gnutls-cli --list | awk -v id="$ID" '($2 " "$3) == id {print $1}')
          if test "${GNUTLS}" = ""; then
            echo "Unsupported: $ID"
          else
            GNUTLS_CIPHERS="${GNUTLS_CIPHERS}${SEP}${GNUTLS}"
            SEP=":"
          fi
        done <<< "$HEX_IDS"
        
        echo "OpenSSL-Ciphers: ${OPENSSL_CIPHERS}"
        echo "GnuTLS-Ciphers: ${GNUTLS_CIPHERS}"