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