1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
|
Index: mozilla/security/nss/lib/ssl/sslimpl.h
===================================================================
RCS file: /cvsroot/mozilla/security/nss/lib/ssl/sslimpl.h,v
retrieving revision 1.106
diff -u -p -r1.106 sslimpl.h
--- mozilla/security/nss/lib/ssl/sslimpl.h 14 Jun 2012 19:03:29 -0000 1.106
+++ mozilla/security/nss/lib/ssl/sslimpl.h 17 Aug 2012 02:10:02 -0000
@@ -251,6 +251,8 @@ struct sslSocketOpsStr {
#define ssl_SEND_FLAG_NO_BUFFER 0x20000000
#define ssl_SEND_FLAG_USE_EPOCH 0x10000000 /* DTLS only */
#define ssl_SEND_FLAG_NO_RETRANSMIT 0x08000000 /* DTLS only */
+#define ssl_SEND_FLAG_CAP_RECORD_VERSION \
+ 0x04000000 /* TLS only */
#define ssl_SEND_FLAG_MASK 0x7f000000
/*
@@ -1327,6 +1329,7 @@ extern SECStatus
ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec,
PRBool isServer,
PRBool isDTLS,
+ PRBool capRecordVersion,
SSL3ContentType type,
const SSL3Opaque * pIn,
PRUint32 contentLen,
Index: mozilla/security/nss/lib/ssl/ssl3con.c
===================================================================
RCS file: /cvsroot/mozilla/security/nss/lib/ssl/ssl3con.c,v
retrieving revision 1.186
diff -u -p -r1.186 ssl3con.c
--- mozilla/security/nss/lib/ssl/ssl3con.c 30 Jul 2012 00:47:36 -0000 1.186
+++ mozilla/security/nss/lib/ssl/ssl3con.c 17 Aug 2012 02:10:02 -0000
@@ -2060,6 +2060,7 @@ SECStatus
ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec,
PRBool isServer,
PRBool isDTLS,
+ PRBool capRecordVersion,
SSL3ContentType type,
const SSL3Opaque * pIn,
PRUint32 contentLen,
@@ -2219,8 +2220,13 @@ ssl3_CompressMACEncryptRecord(ssl3Cipher
wrBuf->buf[11] = MSB(cipherBytes);
wrBuf->buf[12] = LSB(cipherBytes);
} else {
- wrBuf->buf[1] = MSB(cwSpec->version);
- wrBuf->buf[2] = LSB(cwSpec->version);
+ SSL3ProtocolVersion version = cwSpec->version;
+
+ if (capRecordVersion) {
+ version = PR_MIN(SSL_LIBRARY_VERSION_TLS_1_0, version);
+ }
+ wrBuf->buf[1] = MSB(version);
+ wrBuf->buf[2] = LSB(version);
wrBuf->buf[3] = MSB(cipherBytes);
wrBuf->buf[4] = LSB(cipherBytes);
}
@@ -2250,7 +2256,14 @@ ssl3_CompressMACEncryptRecord(ssl3Cipher
* all ciphertext into the pending ciphertext buffer.
* ssl_SEND_FLAG_USE_EPOCH (for DTLS)
* Forces the use of the provided epoch
- *
+ * ssl_SEND_FLAG_CAP_RECORD_VERSION
+ * Caps the record layer version number of TLS ClientHello to { 3, 1 }
+ * (TLS 1.0). Some TLS 1.0 servers (which seem to use F5 BIG-IP) ignore
+ * ClientHello.client_version and use the record layer version number
+ * (TLSPlaintext.version) instead when negotiating protocol versions. In
+ * addition, if the record layer version number of ClientHello is { 3, 2 }
+ * (TLS 1.1) or higher, these servers reset the TCP connections. Set this
+ * flag to work around such servers.
*/
PRInt32
ssl3_SendRecord( sslSocket * ss,
@@ -2263,6 +2276,7 @@ ssl3_SendRecord( sslSocket * ss
sslBuffer * wrBuf = &ss->sec.writeBuf;
SECStatus rv;
PRInt32 totalSent = 0;
+ PRBool capRecordVersion;
SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d",
SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type),
@@ -2271,6 +2285,17 @@ ssl3_SendRecord( sslSocket * ss
PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
+ capRecordVersion = ((flags & ssl_SEND_FLAG_CAP_RECORD_VERSION) != 0);
+
+ if (capRecordVersion) {
+ /* ssl_SEND_FLAG_CAP_RECORD_VERSION can only be used with the
+ * TLS initial ClientHello. */
+ PORT_Assert(!IS_DTLS(ss));
+ PORT_Assert(!ss->firstHsDone);
+ PORT_Assert(type == content_handshake);
+ PORT_Assert(ss->ssl3.hs.ws == wait_server_hello);
+ }
+
if (ss->ssl3.initialized == PR_FALSE) {
/* This can happen on a server if the very first incoming record
** looks like a defective ssl3 record (e.g. too long), and we're
@@ -2327,7 +2352,8 @@ ssl3_SendRecord( sslSocket * ss
rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
ss->sec.isServer, IS_DTLS(ss),
- type, pIn, 1, wrBuf);
+ capRecordVersion, type, pIn,
+ 1, wrBuf);
if (rv != SECSuccess)
goto spec_locked_loser;
@@ -2340,7 +2366,8 @@ ssl3_SendRecord( sslSocket * ss
rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
ss->sec.isServer, IS_DTLS(ss),
- type, pIn + 1, contentLen - 1,
+ capRecordVersion, type,
+ pIn + 1, contentLen - 1,
&secondRecord);
if (rv == SECSuccess) {
PRINT_BUF(50, (ss, "send (encrypted) record data [2/2]:",
@@ -2352,6 +2379,7 @@ ssl3_SendRecord( sslSocket * ss
rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
ss->sec.isServer,
IS_DTLS(ss),
+ capRecordVersion,
type, pIn,
contentLen, wrBuf);
} else {
@@ -2563,6 +2591,8 @@ ssl3_FlushHandshake(sslSocket *ss, PRInt
static SECStatus
ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags)
{
+ static const PRInt32 allowedFlags = ssl_SEND_FLAG_FORCE_INTO_BUFFER |
+ ssl_SEND_FLAG_CAP_RECORD_VERSION;
PRInt32 rv = SECSuccess;
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
@@ -2571,9 +2601,9 @@ ssl3_FlushHandshakeMessages(sslSocket *s
if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len)
return rv;
- /* only this flag is allowed */
- PORT_Assert(!(flags & ~ssl_SEND_FLAG_FORCE_INTO_BUFFER));
- if ((flags & ~ssl_SEND_FLAG_FORCE_INTO_BUFFER) != 0) {
+ /* only these flags are allowed */
+ PORT_Assert(!(flags & ~allowedFlags));
+ if ((flags & ~allowedFlags) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
} else {
@@ -4000,8 +4030,10 @@ ssl3_SendClientHello(sslSocket *ss, PRBo
int num_suites;
int actual_count = 0;
PRBool isTLS = PR_FALSE;
+ PRBool requestingResume = PR_FALSE;
PRInt32 total_exten_len = 0;
unsigned numCompressionMethods;
+ PRInt32 flags;
SSL_TRC(3, ("%d: SSL3[%d]: send client_hello handshake", SSL_GETPID(),
ss->fd));
@@ -4090,6 +4122,7 @@ ssl3_SendClientHello(sslSocket *ss, PRBo
}
if (sid) {
+ requestingResume = PR_TRUE;
SSL_AtomicIncrementLong(& ssl3stats.sch_sid_cache_hits );
/* Are we attempting a stateless session resume? */
@@ -4325,7 +4358,11 @@ ssl3_SendClientHello(sslSocket *ss, PRBo
ssl_renegotiation_info_xtn;
}
- rv = ssl3_FlushHandshake(ss, 0);
+ flags = 0;
+ if (!ss->firstHsDone && !requestingResume && !IS_DTLS(ss)) {
+ flags |= ssl_SEND_FLAG_CAP_RECORD_VERSION;
+ }
+ rv = ssl3_FlushHandshake(ss, flags);
if (rv != SECSuccess) {
return rv; /* error code set by ssl3_FlushHandshake */
}
Index: mozilla/security/nss/lib/ssl/dtlscon.c
===================================================================
RCS file: /cvsroot/mozilla/security/nss/lib/ssl/dtlscon.c,v
retrieving revision 1.3
diff -u -p -r1.3 dtlscon.c
--- mozilla/security/nss/lib/ssl/dtlscon.c 4 Jul 2012 15:21:47 -0000 1.3
+++ mozilla/security/nss/lib/ssl/dtlscon.c 17 Aug 2012 02:10:02 -0000
@@ -802,7 +802,8 @@ dtls_CompressMACEncryptRecord(sslSocket
if (cwSpec) {
rv = ssl3_CompressMACEncryptRecord(cwSpec, ss->sec.isServer, PR_TRUE,
- type, pIn, contentLen, wrBuf);
+ PR_FALSE, type, pIn, contentLen,
+ wrBuf);
} else {
PR_NOT_REACHED("Couldn't find a cipher spec matching epoch");
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|