Bug in GnuTLS 3.0.11 signature_algorithms extension and others

Matthew Hall mhall at mhcomputing.net
Fri Feb 24 23:33:26 CET 2012


Hello GnuTLS team,

I believe I found a problem in the server-side implementation of the TLS 1.2 
Signature Algorithms extension in GnuTLS 3.0.11. Here I provide some source 
code, gdb output, and gnutls-serv full debug output to explain what I believe 
is happening.

When the client enables the signature_algorithms extension and sends the 
supported_signature_algorithms list, the session negotiation will always fail 
because GnuTLS's internal representation of its own 
supported_signature_algorithms list is always empty (this is stored in 
session->internals.priorities.sign_algo.algorithms).

This causes the TLS 1.2 negotiation to fail when checking the 
CertificateVerify's DigitallySigned SignatureAndHashAlgorithm field because 
GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM will always be returned from 
_gnutls_session_sign_algo_enabled.

My code and Wireshark notice that your CertificateRequest has a blank 
supported_signature_algorithms field, which I'm assuming is also copied from 
the session->internals.priorities.sign_algo.

The same client code successfully connects to Java 7 JDK / JRE JSSE TLS 1.2 
implementation without any issue, and Java successfully supports the 
extension. GnuTLS also works again, when I disable the extension. I think this 
narrows down the problem area.

I think the code should either copy out the client algorithms which it also 
supports and which are allowed according to the Cipher String into the 
session->internals.priorities.sign_algo.algorithms.

Or it could fill this sign_algo structure with some static data about every 
combination which it allows (this is what Java 7 does, when the user 
initializes the Cipher Suites / Export Rules / SSL Context).

This will allow the handshake to proceed because something besides 
GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM will be returned.

I also have a second problem I cannot email publicly because I think it could 
be used to create an exploit against the library. Do you have a PGP key I 
could use to send this other bug, and where should I send it?

Regards,
Matthew Hall

P.S.: Another problem I found in lib/gnutls_int.h. This comment here is not 
accurate because many more debug messages appear when these defines are 
uncommented:

/*
 * They are not needed any more. You can simply enable
 * the gnutls_log callback to get error descriptions.
 */

#define BUFFERS_DEBUG
#define WRITE_DEBUG
#define READ_DEBUG
#define HANDSHAKE_DEBUG // Prints some information on handshake 
#define COMPRESSION_DEBUG
#define DEBUG

TLS 1.2 RFC:

7.4.1.4.1.  Signature Algorithms

   The client uses the "signature_algorithms" extension to indicate to
   the server which signature/hash algorithm pairs may be used in
   digital signatures.  The "extension_data" field of this extension
   contains a "supported_signature_algorithms" value.

      enum {
          none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
          sha512(6), (255)
      } HashAlgorithm;

      enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) }
        SignatureAlgorithm;

      struct {
            HashAlgorithm hash;
            SignatureAlgorithm signature;
      } SignatureAndHashAlgorithm;

      SignatureAndHashAlgorithm
        supported_signature_algorithms<2..2^16-2>;

PROBLEMATIC FUNCTION:

/* Check if the given signature algorithm is supported.
 * This means that it is enabled by the priority functions,
 * and in case of a server a matching certificate exists.
 */
int
_gnutls_session_sign_algo_enabled (gnutls_session_t session,
                                   gnutls_sign_algorithm_t sig)
{
  unsigned i;
  int ret;
  gnutls_protocol_t ver = gnutls_protocol_get_version (session);
  sig_ext_st *priv;
  extension_priv_data_t epriv;

  ret =
    _gnutls_ext_get_session_data (session,
                                  GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS,
                                  &epriv);
  if (ret < 0)
    {
      gnutls_assert ();
      return 0;
    }
  priv = epriv.ptr;

  if (!_gnutls_version_has_selectable_sighash (ver)
      || priv->sign_algorithms_size == 0)
    /* none set, allow all */
    {
      return 0;
    }

  for (i = 0; i < session->internals.priorities.sign_algo.algorithms; i++)
    {
      if (session->internals.priorities.sign_algo.priority[i] == sig)
        {
          return 0;             /* ok */
        }
    }

  return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
}

GDB OUTPUT:

(gdb) print session->internals.priorities.sign_algo
$15 = {priority = {0 <repeats 32 times>}, algorithms = 0}
(gdb) 

(gdb) print *priv
$16 = {sign_algorithms = {GNUTLS_SIGN_RSA_MD5, GNUTLS_SIGN_RSA_SHA1, 
    GNUTLS_SIGN_RSA_SHA256, GNUTLS_SIGN_UNKNOWN <repeats 13 times>}, 
  sign_algorithms_size = 3}
(gdb) 

(gdb) print session->internals.priorities
$17 = {cipher = {priority = {4, 7, 93, 5, 8, 94, 3, 2, 1, 
      0 <repeats 23 times>}, algorithms = 9}, mac = {priority = {3, 6, 7, 200, 
      2, 0 <repeats 27 times>}, algorithms = 5}, kx = {priority = {13, 12, 3, 
      2, 1, 0 <repeats 27 times>}, algorithms = 5}, compression = {priority = {
      1, 0 <repeats 31 times>}, algorithms = 1}, protocol = {priority = {4, 3, 
      2, 1, 5, 0 <repeats 27 times>}, algorithms = 5}, cert_type = {
    priority = {0 <repeats 32 times>}, algorithms = 0}, sign_algo = {
    priority = {0 <repeats 32 times>}, algorithms = 0}, supported_ecc = {
    priority = {5, 1, 2, 3, 4, 0 <repeats 27 times>}, algorithms = 5}, 
  no_extensions = 0, no_padding = 0, allow_large_records = 0, sr = SR_PARTIAL, 
  ssl3_record_version = 0, server_precedence = 0, additional_verify_flags = 0}
(gdb) 

GNUTLS-SERV DEBUG LOG:

/usr/local/bin/gnutls-serv --priority NONE:+CIPHER-ALL:+NULL:+KX-ALL:+MAC-ALL:+COMP-NULL:+VERS-TLS-ALL:+CURVE-ALL:%LATEST_RECORD_VERSION --dhparams /home/mhall/certs/dhparams.pem --port 31337 --x509certfile /home/mhall/certs/server-cert.pem --x509keyfile /home/mhall/certs/server-key.pem --nodb --noticket --debug 2147483647 --echo
|<2>| ASSERT: mpi.c:255
|<2>| ASSERT: gnutls_dh_primes.c:293
Read Diffie-Hellman parameters.
Echo Server listening on IPv4 0.0.0.0 port 31337...done
Echo Server listening on IPv6 :: port 31337...bind() failed: Address already in use
|<4>| REC[0x8b1f770]: Allocating epoch #0
* Accepted connection from IPv4 127.0.0.1 port 55214 on Fri Feb 24 14:17:41 2012
|<2>| ASSERT: gnutls_constate.c:716
|<4>| REC[0x8b1f770]: Allocating epoch #1
|<2>| ASSERT: gnutls_buffers.c:959
|<7>| READ: Got 5 bytes from 0x5
|<7>| READ: read 5 bytes from 0x5
|<7>| RB: Have 0 bytes into buffer. Adding 5 bytes.
|<7>| RB: Requested 5 bytes
|<4>| REC[0x8b1f770]: SSL 3.3 Handshake packet received. Length: 59
|<4>| REC[0x8b1f770]: Expected Packet Handshake(22)
|<4>| REC[0x8b1f770]: Received Packet Handshake(22) with length: 59
|<7>| READ: Got 59 bytes from 0x5
|<7>| READ: read 59 bytes from 0x5
|<7>| RB: Have 5 bytes into buffer. Adding 59 bytes.
|<7>| RB: Requested 64 bytes
|<4>| REC[0x8b1f770]: Decrypted Packet[0] Handshake(22) with length: 59
|<6>| BUF[REC]: Inserted 59 bytes of Data(22)
|<3>| HSK[0x8b1f770]: CLIENT HELLO was received. Length 55[55], frag offset 0, frag length: 55, sequence: 0
|<3>| HSK[0x8b1f770]: Client's version: 3.3
|<2>| ASSERT: gnutls_db.c:289
|<3>| EXT[0x8b1f770]: Parsing extension 'SIGNATURE ALGORITHMS/13' (8 bytes)
|<3>| EXT[0x8b1f770]: rcvd signature algo (1.1) RSA-MD5
|<3>| EXT[0x8b1f770]: rcvd signature algo (2.1) RSA-SHA1
|<3>| EXT[0x8b1f770]: rcvd signature algo (4.1) RSA-SHA256
|<2>| ASSERT: server_name.c:301
|<3>| HSK[0x8b1f770]: Requested PK algorithm: RSA (1) -- ctype: X.509 (1)
|<3>| HSK[0x8b1f770]: certificate[0] PK algorithm: RSA (1) - ctype: X.509 (1)
|<3>| HSK[0x8b1f770]: Removing ciphersuite: ECDHE_ECDSA_AES_128_CBC_SHA1
|<3>| HSK[0x8b1f770]: Removing ciphersuite: ECDHE_ECDSA_AES_128_CBC_SHA256
|<3>| HSK[0x8b1f770]: Removing ciphersuite: ECDHE_ECDSA_AES_128_GCM_SHA256
|<3>| HSK[0x8b1f770]: Removing ciphersuite: ECDHE_ECDSA_AES_256_CBC_SHA1
|<3>| HSK[0x8b1f770]: Removing ciphersuite: ECDHE_ECDSA_AES_256_CBC_SHA384
|<3>| HSK[0x8b1f770]: Removing ciphersuite: ECDHE_ECDSA_AES_256_GCM_SHA384
|<3>| HSK[0x8b1f770]: Removing ciphersuite: ECDHE_ECDSA_3DES_EDE_CBC_SHA1
|<3>| HSK[0x8b1f770]: Removing ciphersuite: ECDHE_ECDSA_NULL_SHA1
|<3>| HSK[0x8b1f770]: Removing ciphersuite: ECDHE_RSA_AES_128_CBC_SHA1
|<3>| HSK[0x8b1f770]: Removing ciphersuite: ECDHE_RSA_AES_128_CBC_SHA256
|<3>| HSK[0x8b1f770]: Removing ciphersuite: ECDHE_RSA_AES_128_GCM_SHA256
|<3>| HSK[0x8b1f770]: Removing ciphersuite: ECDHE_RSA_AES_256_CBC_SHA1
|<3>| HSK[0x8b1f770]: Removing ciphersuite: ECDHE_RSA_AES_256_GCM_SHA384
|<3>| HSK[0x8b1f770]: Removing ciphersuite: ECDHE_RSA_3DES_EDE_CBC_SHA1
|<3>| HSK[0x8b1f770]: Removing ciphersuite: ECDHE_RSA_NULL_SHA1
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: DHE_RSA_AES_128_CBC_SHA1
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: DHE_RSA_AES_128_CBC_SHA256
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: DHE_RSA_CAMELLIA_128_CBC_SHA1
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: DHE_RSA_AES_128_GCM_SHA256
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: DHE_RSA_AES_256_CBC_SHA1
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: DHE_RSA_AES_256_CBC_SHA256
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: DHE_RSA_CAMELLIA_256_CBC_SHA1
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: DHE_RSA_3DES_EDE_CBC_SHA1
|<3>| HSK[0x8b1f770]: Removing ciphersuite: DHE_DSS_AES_128_CBC_SHA1
|<3>| HSK[0x8b1f770]: Removing ciphersuite: DHE_DSS_AES_128_CBC_SHA256
|<3>| HSK[0x8b1f770]: Removing ciphersuite: DHE_DSS_CAMELLIA_128_CBC_SHA1
|<3>| HSK[0x8b1f770]: Removing ciphersuite: DHE_DSS_AES_128_GCM_SHA256
|<3>| HSK[0x8b1f770]: Removing ciphersuite: DHE_DSS_AES_256_CBC_SHA1
|<3>| HSK[0x8b1f770]: Removing ciphersuite: DHE_DSS_AES_256_CBC_SHA256
|<3>| HSK[0x8b1f770]: Removing ciphersuite: DHE_DSS_CAMELLIA_256_CBC_SHA1
|<3>| HSK[0x8b1f770]: Removing ciphersuite: DHE_DSS_3DES_EDE_CBC_SHA1
|<3>| HSK[0x8b1f770]: Removing ciphersuite: DHE_DSS_ARCFOUR_SHA1
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: RSA_AES_128_CBC_SHA1
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: RSA_AES_128_CBC_SHA256
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: RSA_CAMELLIA_128_CBC_SHA1
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: RSA_AES_128_GCM_SHA256
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: RSA_AES_256_CBC_SHA1
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: RSA_AES_256_CBC_SHA256
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: RSA_CAMELLIA_256_CBC_SHA1
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: RSA_3DES_EDE_CBC_SHA1
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: RSA_ARCFOUR_SHA1
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: RSA_ARCFOUR_MD5
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: RSA_NULL_SHA1
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: RSA_NULL_SHA256
|<3>| HSK[0x8b1f770]: Keeping ciphersuite: RSA_NULL_MD5
|<3>| HSK[0x8b1f770]: Requested cipher suites[size: 2]: 
|<3>| 	0x00, 0x02 RSA_NULL_SHA1
|<3>| HSK[0x8b1f770]: Selected cipher suite: RSA_NULL_SHA1
|<3>| HSK[0x8b1f770]: Selected Compression Method: NULL
|<3>| HSK[0x8b1f770]: Allowing unsafe initial negotiation
|<3>| HSK[0x8b1f770]: SessionID: 6e491dd2f408fe81012c9fb7e864730e93035104c772de66830d4d2678c2d90c
|<3>| HSK[0x8b1f770]: SERVER HELLO was queued [74 bytes]
|<7>| HWRITE: enqueued [SERVER HELLO] 74. Total 74 bytes.
|<3>| HSK[0x8b1f770]: CERTIFICATE was queued [830 bytes]
|<7>| HWRITE: enqueued [CERTIFICATE] 830. Total 904 bytes.
|<3>| HSK[0x8b1f770]: CERTIFICATE REQUEST was queued [12 bytes]
|<7>| HWRITE: enqueued [CERTIFICATE REQUEST] 12. Total 916 bytes.
|<3>| HSK[0x8b1f770]: SERVER HELLO DONE was queued [4 bytes]
|<7>| HWRITE: enqueued [SERVER HELLO DONE] 4. Total 920 bytes.
|<7>| HWRITE FLUSH: 920 bytes in buffer.
|<4>| REC[0x8b1f770]: Preparing Packet Handshake(22) with length: 74
|<9>| ENC[0x8b1f770]: cipher: NULL, MAC: MAC-NULL, Epoch: 0
|<7>| WRITE: enqueued 79 bytes for 0x5. Total 79 bytes.
|<4>| REC[0x8b1f770]: Sent Packet[1] Handshake(22) with length: 79
|<7>| HWRITE: wrote 1 bytes, 846 bytes left.
|<4>| REC[0x8b1f770]: Preparing Packet Handshake(22) with length: 830
|<9>| ENC[0x8b1f770]: cipher: NULL, MAC: MAC-NULL, Epoch: 0
|<7>| WRITE: enqueued 835 bytes for 0x5. Total 914 bytes.
|<4>| REC[0x8b1f770]: Sent Packet[2] Handshake(22) with length: 835
|<7>| HWRITE: wrote 1 bytes, 16 bytes left.
|<4>| REC[0x8b1f770]: Preparing Packet Handshake(22) with length: 12
|<9>| ENC[0x8b1f770]: cipher: NULL, MAC: MAC-NULL, Epoch: 0
|<7>| WRITE: enqueued 17 bytes for 0x5. Total 931 bytes.
|<4>| REC[0x8b1f770]: Sent Packet[3] Handshake(22) with length: 17
|<7>| HWRITE: wrote 1 bytes, 4 bytes left.
|<4>| REC[0x8b1f770]: Preparing Packet Handshake(22) with length: 4
|<9>| ENC[0x8b1f770]: cipher: NULL, MAC: MAC-NULL, Epoch: 0
|<7>| WRITE: enqueued 9 bytes for 0x5. Total 940 bytes.
|<4>| REC[0x8b1f770]: Sent Packet[4] Handshake(22) with length: 9
|<7>| HWRITE: wrote 1 bytes, 0 bytes left.
|<7>| WRITE FLUSH: 940 bytes in buffer.
|<7>| WRITE: wrote 940 bytes, 0 bytes left.
|<2>| ASSERT: gnutls_buffers.c:959
|<7>| READ: -1 returned from 0x5, errno=11 gerrno=0
|<2>| ASSERT: gnutls_buffers.c:959
|<7>| READ: Got 5 bytes from 0x5
|<7>| READ: read 5 bytes from 0x5
|<7>| RB: Have 0 bytes into buffer. Adding 5 bytes.
|<7>| RB: Requested 5 bytes
|<4>| REC[0x8b1f770]: SSL 3.3 Handshake packet received. Length: 693
|<4>| REC[0x8b1f770]: Expected Packet Handshake(22)
|<4>| REC[0x8b1f770]: Received Packet Handshake(22) with length: 693
|<7>| READ: Got 693 bytes from 0x5
|<7>| READ: read 693 bytes from 0x5
|<7>| RB: Have 5 bytes into buffer. Adding 693 bytes.
|<7>| RB: Requested 698 bytes
|<4>| REC[0x8b1f770]: Decrypted Packet[1] Handshake(22) with length: 693
|<6>| BUF[REC]: Inserted 693 bytes of Data(22)
|<3>| HSK[0x8b1f770]: CERTIFICATE was received. Length 689[689], frag offset 0, frag length: 689, sequence: 0
|<2>| ASSERT: gnutls_buffers.c:959
|<7>| READ: -1 returned from 0x5, errno=11 gerrno=0
|<2>| ASSERT: gnutls_buffers.c:959
|<7>| READ: Got 5 bytes from 0x5
|<7>| READ: read 5 bytes from 0x5
|<7>| RB: Have 0 bytes into buffer. Adding 5 bytes.
|<7>| RB: Requested 5 bytes
|<4>| REC[0x8b1f770]: SSL 3.3 Handshake packet received. Length: 134
|<4>| REC[0x8b1f770]: Expected Packet Handshake(22)
|<4>| REC[0x8b1f770]: Received Packet Handshake(22) with length: 134
|<7>| READ: Got 134 bytes from 0x5
|<7>| READ: read 134 bytes from 0x5
|<7>| RB: Have 5 bytes into buffer. Adding 134 bytes.
|<7>| RB: Requested 139 bytes
|<4>| REC[0x8b1f770]: Decrypted Packet[2] Handshake(22) with length: 134
|<6>| BUF[REC]: Inserted 134 bytes of Data(22)
|<3>| HSK[0x8b1f770]: CLIENT KEY EXCHANGE was received. Length 130[130], frag offset 0, frag length: 130, sequence: 0
|<2>| ASSERT: gnutls_buffers.c:959
|<7>| READ: -1 returned from 0x5, errno=11 gerrno=0
|<2>| ASSERT: gnutls_buffers.c:959
|<7>| READ: Got 5 bytes from 0x5
|<7>| READ: read 5 bytes from 0x5
|<7>| RB: Have 0 bytes into buffer. Adding 5 bytes.
|<7>| RB: Requested 5 bytes
|<4>| REC[0x8b1f770]: SSL 3.3 Handshake packet received. Length: 136
|<4>| REC[0x8b1f770]: Expected Packet Handshake(22)
|<4>| REC[0x8b1f770]: Received Packet Handshake(22) with length: 136
|<7>| READ: Got 136 bytes from 0x5
|<7>| READ: read 136 bytes from 0x5
|<7>| RB: Have 5 bytes into buffer. Adding 136 bytes.
|<7>| RB: Requested 141 bytes
|<4>| REC[0x8b1f770]: Decrypted Packet[3] Handshake(22) with length: 136
|<6>| BUF[REC]: Inserted 136 bytes of Data(22)
|<3>| HSK[0x8b1f770]: CERTIFICATE VERIFY was received. Length 132[132], frag offset 0, frag length: 132, sequence: 0
|<2>| ASSERT: cert.c:1696
|<2>| ASSERT: gnutls_handshake.c:2810
|<3>| HSK[0x8b1f770]: recv client certificate verify (-106)
Error in handshake
Error: The signature algorithm is not supported.
|<4>| REC: Sending Alert[2|40] - Handshake failed
|<4>| REC[0x8b1f770]: Preparing Packet Alert(21) with length: 2
|<9>| ENC[0x8b1f770]: cipher: NULL, MAC: MAC-NULL, Epoch: 0
|<7>| WRITE: enqueued 7 bytes for 0x5. Total 7 bytes.
|<7>| WRITE FLUSH: 7 bytes in buffer.
|<7>| WRITE: wrote 7 bytes, 0 bytes left.
|<4>| REC[0x8b1f770]: Sent Packet[5] Alert(21) with length: 7
|<2>| ASSERT: gnutls_record.c:234
|<4>| REC[0x8b1f770]: Start of epoch cleanup
|<4>| REC[0x8b1f770]: End of epoch cleanup
|<4>| REC[0x8b1f770]: Epoch #0 freed
|<4>| REC[0x8b1f770]: Epoch #1 freed




More information about the Gnutls-devel mailing list