by allowing debugging messages just by increasing the level.
- The diffie Hellman ciphersuites are now of higher priority than
the plain RSA.
+- The RSA premaster secret version check can no longer be disabled.
+- Implemented the counter measure discussed in the paper "Attacking
+ RSA-based Sessions in SSL/TLS", against the attack discussed in the
+ same paper.
+- Added the functions: gnutls_handshake_get_last_in(),
+ gnutls_handshake_get_last_out().
Version 0.9.2 (15/03/2003)
- Some corrections in the memory mapping code (file is unmapped after
/*
- * Copyright (C) 2000,2001,2002,2003 Nikos Mavroyanopoulos
+ * Copyright (C) 2000,2001,2002,2003 Nikos Mavroyanopoulos
*
- * This file is part of GNUTLS.
+ * This file is part of GNUTLS.
*
* The GNUTLS library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
int _gnutls_proc_rsa_client_kx(gnutls_session session, opaque * data, size_t _data_size)
{
- gnutls_sdatum plaintext;
+ gnutls_sdatum plaintext = { NULL, 0 };
gnutls_datum ciphertext;
int ret, dsize;
GNUTLS_MPI *params;
int params_len;
+ int randomize_key = 0;
ssize_t data_size = _data_size;
if (gnutls_protocol_get_version(session) == GNUTLS_SSL3) {
- /* SSL 3.0 */
+ /* SSL 3.0
+ */
ciphertext.data = data;
ciphertext.size = data_size;
- } else { /* TLS 1 */
+ } else {
+ /* TLS 1.0
+ */
DECR_LEN( data_size, 2);
ciphertext.data = &data[2];
dsize = _gnutls_read_uint16(data);
params_len, 2); /* btype==2 */
if (ret < 0 || plaintext.size != TLS_MASTER_SIZE) {
- /* in case decryption fails then don't inform
+ /* In case decryption fails then don't inform
* the peer. Just use a random key. (in order to avoid
* attack against pkcs-1 formating).
*/
- ret = 0;
gnutls_assert();
- _gnutls_x509_log("auth_rsa: Possible PKCS-1 format attack\n");
+ _gnutls_x509_log("auth_rsa: Possible PKCS #1 format attack\n");
+ randomize_key = 1;
+ } else {
+ /* If the secret was properly formatted, then
+ * check the version number.
+ */
+ if (_gnutls_get_adv_version_major(session) != plaintext.data[0]
+ || _gnutls_get_adv_version_minor(session) != plaintext.data[1])
+ {
+ /* No error is returned here, if the version number check
+ * fails. We proceed normally.
+ * That is to defend against the attack described in the paper
+ * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima,
+ * Ondej Pokorny and Tomas Rosa.
+ */
+ gnutls_assert();
+ _gnutls_x509_log("auth_rsa: Possible PKCS #1 version check format attack\n");
+ }
+ }
+
+ if (randomize_key != 0) {
+ /* if the pkcs1 padding check failed, no need for
+ * that. That's why it has been initialized to zero.
+ */
+ _gnutls_free_datum( &plaintext);
RANDOMIZE_KEY(session->key->key,
- gnutls_secure_malloc, GNUTLS_WEAK_RANDOM);
- } else {
- ret = 0;
- if (session->internals.rsa_pms_check==0)
- if (_gnutls_get_adv_version_major(session) !=
- plaintext.data[0]
- || _gnutls_get_adv_version_minor(session) !=
- plaintext.data[1]) {
- gnutls_assert();
- ret = GNUTLS_E_DECRYPTION_FAILED;
- }
+ gnutls_secure_malloc, GNUTLS_STRONG_RANDOM);
+ } else {
session->key->key.data = plaintext.data;
session->key->key.size = plaintext.size;
}
- return ret;
+ /* This is here to avoid the version check attack
+ * discussed above.
+ */
+ session->key->key.data[0] = _gnutls_get_adv_version_major(session);
+ session->key->key.data[1] = _gnutls_get_adv_version_minor(session);
+
+ return 0;
}
ver = _gnutls_get_adv_version(session);
- session->key->key.data[0] = _gnutls_version_get_major(ver);
- session->key->key.data[1] = _gnutls_version_get_minor(ver);
+ if (session->internals.rsa_pms_version[0] == 0) {
+ session->key->key.data[0] = _gnutls_version_get_major(ver);
+ session->key->key.data[1] = _gnutls_version_get_minor(ver);
+ } else { /* use the version provided */
+ session->key->key.data[0] = session->internals.rsa_pms_version[0];
+ session->key->key.data[1] = session->internals.rsa_pms_version[1];
+ }
/* move RSA parameters to key (session).
*/
typedef enum gnutls_alert_level { GNUTLS_AL_WARNING=1, GNUTLS_AL_FATAL } gnutls_alert_level;
-typedef enum gnutls_alert_description { GNUTLS_A_CLOSE_NOTIFY, GNUTLS_A_UNEXPECTED_MESSAGE=10, GNUTLS_A_BAD_RECORD_MAC=20,
- GNUTLS_A_DECRYPTION_FAILED, GNUTLS_A_RECORD_OVERFLOW, GNUTLS_A_DECOMPRESSION_FAILURE=30,
+typedef enum gnutls_alert_description { GNUTLS_A_CLOSE_NOTIFY,
+ GNUTLS_A_UNEXPECTED_MESSAGE=10, GNUTLS_A_BAD_RECORD_MAC=20,
+ GNUTLS_A_DECRYPTION_FAILED, GNUTLS_A_RECORD_OVERFLOW, GNUTLS_A_DECOMPRESSION_FAILURE=30,
GNUTLS_A_HANDSHAKE_FAILURE=40, GNUTLS_A_SSL3_NO_CERTIFICATE=41,
GNUTLS_A_BAD_CERTIFICATE=42, GNUTLS_A_UNSUPPORTED_CERTIFICATE,
GNUTLS_A_CERTIFICATE_REVOKED, GNUTLS_A_CERTIFICATE_EXPIRED, GNUTLS_A_CERTIFICATE_UNKNOWN,
GNUTLS_A_CERTIFICATE_UNOBTAINABLE=111, GNUTLS_A_UNRECOGNIZED_NAME=112
} gnutls_alert_description;
+typedef enum gnutls_handshake_description { GNUTLS_HANDSHAKE_HELLO_REQUEST,
+ GNUTLS_HANDSHAKE_CLIENT_HELLO, GNUTLS_HANDSHAKE_SERVER_HELLO,
+ GNUTLS_HANDSHAKE_CERTIFICATE_PKT=11, GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE,
+ GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST, GNUTLS_HANDSHAKE_SERVER_HELLO_DONE,
+ GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY, GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE,
+ GNUTLS_HANDSHAKE_FINISHED=20
+} gnutls_handshake_description;
+
typedef enum gnutls_certificate_status {
GNUTLS_CERT_NOT_TRUSTED=2,
GNUTLS_CERT_INVALID=4,
/* Semi-internal functions.
*/
void gnutls_handshake_set_private_extensions(gnutls_session session, int allow);
-void gnutls_record_set_cbc_protection(gnutls_session session, int prot);
void gnutls_handshake_set_rsa_pms_check(gnutls_session session, int check);
+gnutls_handshake_description gnutls_handshake_get_last_out( gnutls_session session);
+gnutls_handshake_description gnutls_handshake_get_last_in( gnutls_session session);
+
+void gnutls_record_set_cbc_protection(gnutls_session session, int prot);
/* Record layer functions.
*/
/*
* Copyright (C) 2000,2001,2002,2003 Nikos Mavroyanopoulos
*
- * This file is part of GNUTLS.
+ * This file is part of GNUTLS.
*
* The GNUTLS library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
extern const ASN1_ARRAY_TYPE pkix_asn1_tab[];
LOG_FUNC _gnutls_log_func;
-int _gnutls_log_level = 2; /* default log level */
+int _gnutls_log_level = 1; /* default log level */
static ASN1_TYPE PKIX1_ASN;
static ASN1_TYPE GNUTLS_ASN;
/*
- * Copyright (C) 2000,2001,2002,2003 Nikos Mavroyanopoulos
+ * Copyright (C) 2000,2001,2002,2003 Nikos Mavroyanopoulos
*
- * This file is part of GNUTLS.
+ * This file is part of GNUTLS.
*
* The GNUTLS library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
return ret;
}
+ session->internals.last_handshake_out = type;
+
ret =
_gnutls_handshake_io_send_int(session, GNUTLS_HANDSHAKE, type,
data, datasize);
return ret;
}
+ session->internals.last_handshake_in = recv_type;
length32 = ret;
int _gnutls_generate_session_id(char *session_id, uint8 * len)
{
char buf[64];
- opaque rand[TLS_RANDOM_SIZE];
- if (_gnutls_get_random(rand, TLS_RANDOM_SIZE, GNUTLS_WEAK_RANDOM) <
+ *len = TLS_RANDOM_SIZE;
+
+ if (_gnutls_get_random(session_id, *len, GNUTLS_WEAK_RANDOM) <
0) {
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
- memcpy(session_id, rand, TLS_RANDOM_SIZE);
- *len = TLS_RANDOM_SIZE;
_gnutls_handshake_log("HSK: Generated SessionID: %s\n",
- _gnutls_bin2hex(session_id, TLS_RANDOM_SIZE, buf, sizeof(buf)));
+ _gnutls_bin2hex(session_id, *len, buf, sizeof(buf)));
return 0;
}
_gnutls_get_adv_version_minor( session));
}
+/**
+ * gnutls_handshake_get_last_in - Returns the last handshake message received.
+ * @session: is a &gnutls_session structure.
+ *
+ * Returns the last handshake message received. This function is only useful
+ * to check where the last performed handshake failed. If the previous handshake
+ * succeed or was not performed at all then no meaningful value will be returned.
+ *
+ * Check gnutls.h for the available handshake descriptions.
+ **/
+gnutls_handshake_description gnutls_handshake_get_last_in( gnutls_session session)
+{
+ return session->internals.last_handshake_in;
+}
+
+/**
+ * gnutls_handshake_get_last_out - Returns the last handshake message sent.
+ * @session: is a &gnutls_session structure.
+ *
+ * Returns the last handshake message sent. This function is only useful
+ * to check where the last performed handshake failed. If the previous handshake
+ * succeed or was not performed at all then no meaningful value will be returned.
+ *
+ * Check gnutls.h for the available handshake descriptions.
+ *
+ **/
+gnutls_handshake_description gnutls_handshake_get_last_out( gnutls_session session)
+{
+ return session->internals.last_handshake_out;
+}
+
GNUTLS_CERTIFICATE_VERIFY, GNUTLS_CLIENT_KEY_EXCHANGE,
GNUTLS_FINISHED=20 } HandshakeType;
+typedef HandshakeType gnutls_handshake_description;
+
typedef struct {
opaque * data;
unsigned int size;
int may_write;
int last_alert; /* last alert received */
+
+ /* The last handshake messages sent or received.
+ */
+ int last_handshake_in;
+ int last_handshake_out;
+
/* this is the compression method we are going to use */
gnutls_compression_method compression_method;
/* priorities */
int cbc_protection_hack;
- int rsa_pms_check; /* 0 means enabled */
-
void* user_ptr;
int enable_private;/* non zero to
*/
int ignore_rdn_sequence;
+ /* This is used to set an arbitary version in the RSA
+ * PMS secret. Can be used by clients to test whether the
+ * server checks that version.
+ */
+ opaque rsa_pms_version[2];
+
/* If you add anything here, check _gnutls_handshake_internal_state_clear().
*/
} GNUTLS_INTERNALS;
#include <gnutls_random.h>
#include <gnutls_datum.h>
#include <gnutls_global.h>
+#include <gnutls_num.h>
#include "debug.h"
static int _gnutls_pk_encrypt(int algo, GNUTLS_MPI * resarr, GNUTLS_MPI data, GNUTLS_MPI * pkey, int pkey_len);
return GNUTLS_E_INTERNAL_ERROR;
}
- if ( (ret=_gnutls_get_random(ps, psize, GNUTLS_WEAK_RANDOM)) < 0) {
+ if ( (ret=_gnutls_get_random(ps, psize, GNUTLS_STRONG_RANDOM)) < 0) {
gnutls_assert();
return ret;
}
for (i = 0; i < psize; i++) {
- if (ps[i] == 0)
- ps[i] = 0xff;
+ opaque rnd[3];
+
+ /* Read three random bytes that will be
+ * used to replace the zeros.
+ */
+ if ( (ret=_gnutls_get_random( rnd, 3, GNUTLS_STRONG_RANDOM)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ /* use non zero values for
+ * the first two.
+ */
+ if (rnd[0]==0) rnd[0] = 0xaf;
+ if (rnd[1]==0) rnd[1] = 0xae;
+
+ if (ps[i] == 0) {
+ /* If the first one is zero then set it to rnd[0].
+ * If the second one is zero then set it to rnd[1].
+ * Otherwise add (mod 256) the two previous ones plus rnd[3], or use
+ * rnd[1] if the value == 0.
+ */
+ if (i<2) ps[i] = rnd[i];
+ else ps[i] = GMAX( rnd[3] + ps[i-1] + ps[i-2], rnd[1]);
+ }
}
break;
case 1:
session->internals.adv_version_minor = 0;
session->internals.direction = 0;
+ /* use out of band data for the last
+ * handshake messages received.
+ */
+ session->internals.last_handshake_in = -1;
+ session->internals.last_handshake_out = -1;
+
session->internals.resumable = RESUME_TRUE;
}
session->internals.enable_private = allow;
}
-/**
- * gnutls_handshake_set_rsa_pms_check - Used to disable the RSA PMS check
- * @session: is a &gnutls_session structure.
- * @prot: is an integer (0 or 1)
- *
- * The TLS 1.0 handshake protocol includes a check in the in the RSA
- * encrypted data (only in the case of RSA key exchange), which allows
- * to detect version roll back attacks.
- *
- * However it seems that some broken TLS clients exist which do not
- * use this check properly. The only solution is to disable this
- * check completely.
- *
- * if check == 0 then the check is enabled (default), otherwise it
- * is disabled.
- *
- **/
-void gnutls_handshake_set_rsa_pms_check(gnutls_session session, int check)
-{
- session->internals.rsa_pms_check = check;
-}
-
inline
static void _gnutls_cal_PRF_A( gnutls_mac_algorithm algorithm, const void *secret, int secret_size, const void *seed, int seed_size, void* result)
{
return session->internals.direction;
}
+/*-
+ * _gnutls_rsa_pms_set_version - Sets a version to be used at the RSA PMS
+ * @session: is a &gnutls_session structure.
+ * @major: is the major version to use
+ * @minor: is the minor version to use
+ *
+ * This function will set the given version number to be used at the
+ * RSA PMS secret. This is only useful to clients, which want to
+ * test server's capabilities.
+ *
+ -*/
+void _gnutls_rsa_pms_set_version(gnutls_session session, unsigned char major,
+ unsigned char minor)
+{
+ session->internals.rsa_pms_version[0] = major;
+ session->internals.rsa_pms_version[1] = minor;
+}
static char session_id[32];
static int session_data_size=0, session_id_size=0;
static int sfree=0;
+static int handshake_output = 0;
int do_handshake( gnutls_session session) {
int ret, alert;
ret = gnutls_handshake(session);
} while (ret == GNUTLS_E_INTERRUPTED
|| ret == GNUTLS_E_AGAIN);
+
+ handshake_output = ret;
if (ret < 0 && more_info != 0) {
printf("\n");
* and we connect using a 3.1 client hello version,
* and a 3.0 record version. Some implementations
* are buggy (and vulnerable to man in the middle
- * attacks) and this connection will fail.
+ * attacks which allow a version downgrade) and this
+ * connection will fail.
*/
ADD_ALL_CIPHERS(session);
ADD_ALL_COMP(session);
return SUCCEED;
}
+void _gnutls_rsa_pms_set_version(gnutls_session session, unsigned char major,
+ unsigned char minor);
+
+int test_rsa_pms_version_check( gnutls_session session)
+{
+int ret;
+ /* here we use an arbitary version in the RSA PMS
+ * to see whether to server will check this version.
+ *
+ * A normal server would abort this handshake.
+ */
+ ADD_ALL_CIPHERS(session);
+ ADD_ALL_COMP(session);
+ ADD_ALL_CERTTYPES(session);
+ ADD_ALL_PROTOCOLS(session);
+ ADD_ALL_MACS(session);
+ ADD_ALL_KX(session);
+ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
+ _gnutls_rsa_pms_set_version( session, 5, 5); /* use SSL 5.5 version */
+
+ ret = do_handshake( session);
+ return ret;
+
+}
+
int test_anonymous( gnutls_session session) {
int ret;
int test_certificate( gnutls_session state);
int test_server_cas( gnutls_session state);
int test_session_resume2( gnutls_session state);
+int test_rsa_pms_version_check( gnutls_session session);
#define GERR(ret) fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret))
* buggy */
{ "whether we need to disable TLS 1.0", test_tls1_2, "no", "yes", "dunno" },
+ { "whether the server ignores the RSA PMS version", test_rsa_pms_version_check, "yes", "no", "dunno"},
{ "whether the server can accept Hello Extensions", test_hello_extension, "yes", "no", "dunno"},
{ "whether the server can accept cipher suites not in SSL 3.0 spec", test_unknown_ciphersuites, "yes", "no", "dunno"},
{ "for certificate information", test_certificate, "", "", "" },