OLD | NEW |
| (Empty) |
1 From 0c2f72b38711abdd4ada08ae8d7e96dce79a672b Mon Sep 17 00:00:00 2001 | |
2 From: Adam Langley <agl@chromium.org> | |
3 Date: Mon, 3 Oct 2011 12:19:28 -0400 | |
4 Subject: [PATCH 01/15] nextproto.patch | |
5 | |
6 --- | |
7 mozilla/security/nss/lib/ssl/ssl.def | 8 ++ | |
8 mozilla/security/nss/lib/ssl/ssl.h | 51 ++++++++++++ | |
9 mozilla/security/nss/lib/ssl/ssl3con.c | 58 +++++++++++++ | |
10 mozilla/security/nss/lib/ssl/ssl3ext.c | 104 ++++++++++++++++++++++++- | |
11 mozilla/security/nss/lib/ssl/ssl3prot.h | 3 +- | |
12 mozilla/security/nss/lib/ssl/sslerr.h | 2 + | |
13 mozilla/security/nss/lib/ssl/sslimpl.h | 21 +++++ | |
14 mozilla/security/nss/lib/ssl/sslsock.c | 134 +++++++++++++++++++++++++++++++ | |
15 mozilla/security/nss/lib/ssl/sslt.h | 3 +- | |
16 9 files changed, 381 insertions(+), 3 deletions(-) | |
17 | |
18 diff --git a/mozilla/security/nss/lib/ssl/ssl.def b/mozilla/security/nss/lib/ssl
/ssl.def | |
19 index d3f455c..6ea48c0 100644 | |
20 --- a/mozilla/security/nss/lib/ssl/ssl.def | |
21 +++ b/mozilla/security/nss/lib/ssl/ssl.def | |
22 @@ -152,3 +152,11 @@ SSL_SNISocketConfigHook; | |
23 ;+ local: | |
24 ;+*; | |
25 ;+}; | |
26 +;+NSS_CHROMIUM { | |
27 +;+ global: | |
28 +SSL_GetNextProto; | |
29 +SSL_SetNextProtoCallback; | |
30 +SSL_SetNextProtoNego; | |
31 +;+ local: | |
32 +;+*; | |
33 +;+}; | |
34 diff --git a/mozilla/security/nss/lib/ssl/ssl.h b/mozilla/security/nss/lib/ssl/s
sl.h | |
35 index 4a9e89d..f54eb09 100644 | |
36 --- a/mozilla/security/nss/lib/ssl/ssl.h | |
37 +++ b/mozilla/security/nss/lib/ssl/ssl.h | |
38 @@ -153,6 +153,57 @@ SSL_IMPORT SECStatus SSL_OptionSetDefault(PRInt32 option, P
RBool on); | |
39 SSL_IMPORT SECStatus SSL_OptionGetDefault(PRInt32 option, PRBool *on); | |
40 SSL_IMPORT SECStatus SSL_CertDBHandleSet(PRFileDesc *fd, CERTCertDBHandle *dbHa
ndle); | |
41 | |
42 +/* SSLNextProtoCallback is called, during the handshake, when the server has | |
43 + * sent a Next Protocol Negotiation extension. |protos| and |protosLen| define | |
44 + * a buffer which contains the server's advertisement. This data is guaranteed | |
45 + * to be well formed per the NPN spec. |protoOut| is a buffer provided by the | |
46 + * caller, of length 255 (the maximum allowed by the protocol). | |
47 + * On successful return, the protocol to be announced to the server will be in | |
48 + * |protoOut| and its length in |*protoOutLen|. */ | |
49 +typedef SECStatus (PR_CALLBACK *SSLNextProtoCallback)( | |
50 + void *arg, | |
51 + PRFileDesc *fd, | |
52 + const unsigned char* protos, | |
53 + unsigned int protosLen, | |
54 + unsigned char* protoOut, | |
55 + unsigned int* protoOutLen); | |
56 + | |
57 +/* SSL_SetNextProtoCallback sets a callback function to handle Next Protocol | |
58 + * Negotiation. It causes a client to advertise NPN. */ | |
59 +SSL_IMPORT SECStatus SSL_SetNextProtoCallback(PRFileDesc *fd, | |
60 + SSLNextProtoCallback callback, | |
61 + void *arg); | |
62 + | |
63 +/* SSL_SetNextProtoNego can be used as an alternative to | |
64 + * SSL_SetNextProtoCallback. It also causes a client to advertise NPN and | |
65 + * installs a default callback function which selects the first supported | |
66 + * protocol in server-preference order. If no matching protocol is found it | |
67 + * selects the first supported protocol. | |
68 + * | |
69 + * The supported protocols are specified in |data| in wire-format (8-bit | |
70 + * length-prefixed). For example: "\010http/1.1\006spdy/2". */ | |
71 +SSL_IMPORT SECStatus SSL_SetNextProtoNego(PRFileDesc *fd, | |
72 + const unsigned char *data, | |
73 + unsigned int length); | |
74 +/* SSL_GetNextProto can be used after a handshake on a socket where | |
75 + * SSL_SetNextProtoNego was called to retrieve the result of the Next Protocol | |
76 + * negotiation. | |
77 + * | |
78 + * state is set to one of the SSL_NEXT_PROTO_* constants. The negotiated | |
79 + * protocol, if any, is written into buf, which must be at least buf_len bytes | |
80 + * long. If the negotiated protocol is longer than this, it is truncated. The | |
81 + * number of bytes copied is written into *length. */ | |
82 +SSL_IMPORT SECStatus SSL_GetNextProto(PRFileDesc *fd, | |
83 + int *state, | |
84 + unsigned char *buf, | |
85 + unsigned int *length, | |
86 + unsigned int buf_len); | |
87 + | |
88 +/* TODO(wtc): it may be a good idea to define these as an enum type. */ | |
89 +#define SSL_NEXT_PROTO_NO_SUPPORT 0 /* No peer support */ | |
90 +#define SSL_NEXT_PROTO_NEGOTIATED 1 /* Mutual agreement */ | |
91 +#define SSL_NEXT_PROTO_NO_OVERLAP 2 /* No protocol overlap found */ | |
92 + | |
93 /* | |
94 ** Control ciphers that SSL uses. If on is non-zero then the named cipher | |
95 ** is enabled, otherwise it is disabled. | |
96 diff --git a/mozilla/security/nss/lib/ssl/ssl3con.c b/mozilla/security/nss/lib/s
sl/ssl3con.c | |
97 index 8048913..d2d4f91 100644 | |
98 --- a/mozilla/security/nss/lib/ssl/ssl3con.c | |
99 +++ b/mozilla/security/nss/lib/ssl/ssl3con.c | |
100 @@ -81,6 +81,7 @@ static SECStatus ssl3_InitState( sslSocket *ss); | |
101 static SECStatus ssl3_SendCertificate( sslSocket *ss); | |
102 static SECStatus ssl3_SendEmptyCertificate( sslSocket *ss); | |
103 static SECStatus ssl3_SendCertificateRequest(sslSocket *ss); | |
104 +static SECStatus ssl3_SendNextProto( sslSocket *ss); | |
105 static SECStatus ssl3_SendFinished( sslSocket *ss, PRInt32 flags); | |
106 static SECStatus ssl3_SendServerHello( sslSocket *ss); | |
107 static SECStatus ssl3_SendServerHelloDone( sslSocket *ss); | |
108 @@ -5742,6 +5743,16 @@ ssl3_HandleServerHelloDone(sslSocket *ss) | |
109 if (rv != SECSuccess) { | |
110 goto loser; /* err code was set. */ | |
111 } | |
112 + | |
113 + /* We don't send NPN in a renegotiation as it's explicitly disallowed by | |
114 + * the spec. */ | |
115 + if (!ss->firstHsDone) { | |
116 + rv = ssl3_SendNextProto(ss); | |
117 + if (rv != SECSuccess) { | |
118 + goto loser; /* err code was set. */ | |
119 + } | |
120 + } | |
121 + | |
122 rv = ssl3_SendFinished(ss, 0); | |
123 if (rv != SECSuccess) { | |
124 goto loser; /* err code was set. */ | |
125 @@ -8169,6 +8180,40 @@ ssl3_ComputeTLSFinished(ssl3CipherSpec *spec, | |
126 } | |
127 | |
128 /* called from ssl3_HandleServerHelloDone | |
129 + */ | |
130 +static SECStatus | |
131 +ssl3_SendNextProto(sslSocket *ss) | |
132 +{ | |
133 + SECStatus rv; | |
134 + int padding_len; | |
135 + static const unsigned char padding[32] = {0}; | |
136 + | |
137 + if (ss->ssl3.nextProto.len == 0) | |
138 + return SECSuccess; | |
139 + | |
140 + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); | |
141 + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); | |
142 + | |
143 + padding_len = 32 - ((ss->ssl3.nextProto.len + 2) % 32); | |
144 + | |
145 + rv = ssl3_AppendHandshakeHeader(ss, next_proto, ss->ssl3.nextProto.len + | |
146 + 2 + padding_len); | |
147 + if (rv != SECSuccess) { | |
148 + return rv; /* error code set by AppendHandshakeHeader */ | |
149 + } | |
150 + rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.nextProto.data, | |
151 + ss->ssl3.nextProto.len, 1); | |
152 + if (rv != SECSuccess) { | |
153 + return rv; /* error code set by AppendHandshake */ | |
154 + } | |
155 + rv = ssl3_AppendHandshakeVariable(ss, padding, padding_len, 1); | |
156 + if (rv != SECSuccess) { | |
157 + return rv; /* error code set by AppendHandshake */ | |
158 + } | |
159 + return rv; | |
160 +} | |
161 + | |
162 +/* called from ssl3_HandleServerHelloDone | |
163 * ssl3_HandleClientHello | |
164 * ssl3_HandleFinished | |
165 */ | |
166 @@ -8421,6 +8466,14 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint3
2 length, | |
167 if (doStepUp || ss->writerThread == PR_GetCurrentThread()) { | |
168 flags = ssl_SEND_FLAG_FORCE_INTO_BUFFER; | |
169 } | |
170 + | |
171 + if (!isServer && !ss->firstHsDone) { | |
172 + rv = ssl3_SendNextProto(ss); | |
173 + if (rv != SECSuccess) { | |
174 + goto xmit_loser; /* err code was set. */ | |
175 + } | |
176 + } | |
177 + | |
178 rv = ssl3_SendFinished(ss, flags); | |
179 if (rv != SECSuccess) { | |
180 goto xmit_loser; /* err is set. */ | |
181 @@ -9488,6 +9541,11 @@ ssl3_DestroySSL3Info(sslSocket *ss) | |
182 ssl3_DestroyCipherSpec(&ss->ssl3.specs[1], PR_TRUE/*freeSrvName*/); | |
183 | |
184 ss->ssl3.initialized = PR_FALSE; | |
185 + | |
186 + if (ss->ssl3.nextProto.data) { | |
187 + PORT_Free(ss->ssl3.nextProto.data); | |
188 + ss->ssl3.nextProto.data = NULL; | |
189 + } | |
190 } | |
191 | |
192 /* End of ssl3con.c */ | |
193 diff --git a/mozilla/security/nss/lib/ssl/ssl3ext.c b/mozilla/security/nss/lib/s
sl/ssl3ext.c | |
194 index becbfe9..711cad0 100644 | |
195 --- a/mozilla/security/nss/lib/ssl/ssl3ext.c | |
196 +++ b/mozilla/security/nss/lib/ssl/ssl3ext.c | |
197 @@ -235,6 +235,7 @@ static const ssl3HelloExtensionHandler clientHelloHandlers[]
= { | |
198 #endif | |
199 { ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn }, | |
200 { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, | |
201 + { ssl_next_proto_neg_xtn, &ssl3_ServerHandleNextProtoNegoXtn }, | |
202 { -1, NULL } | |
203 }; | |
204 | |
205 @@ -245,6 +246,7 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTL
S[] = { | |
206 /* TODO: add a handler for ssl_ec_point_formats_xtn */ | |
207 { ssl_session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn }, | |
208 { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, | |
209 + { ssl_next_proto_neg_xtn, &ssl3_ClientHandleNextProtoNegoXtn }, | |
210 { -1, NULL } | |
211 }; | |
212 | |
213 @@ -267,7 +269,8 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTEN
SIONS] = { | |
214 { ssl_elliptic_curves_xtn, &ssl3_SendSupportedCurvesXtn }, | |
215 { ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn }, | |
216 #endif | |
217 - { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn } | |
218 + { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn }, | |
219 + { ssl_next_proto_neg_xtn, &ssl3_ClientSendNextProtoNegoXtn } | |
220 /* any extra entries will appear as { 0, NULL } */ | |
221 }; | |
222 | |
223 @@ -534,6 +537,105 @@ ssl3_SendSessionTicketXtn( | |
224 return -1; | |
225 } | |
226 | |
227 +/* handle an incoming Next Protocol Negotiation extension. */ | |
228 +SECStatus | |
229 +ssl3_ServerHandleNextProtoNegoXtn(sslSocket * ss, PRUint16 ex_type, SECItem *da
ta) | |
230 +{ | |
231 + if (data->len != 0) { | |
232 + /* Clients MUST send an empty NPN extension, if any. */ | |
233 + return SECFailure; | |
234 + } | |
235 + | |
236 + return SECSuccess; | |
237 +} | |
238 + | |
239 +/* ssl3_ValidateNextProtoNego checks that the given block of data is valid: non
e | |
240 + * of the lengths may be 0 and the sum of the lengths must equal the length of | |
241 + * the block. */ | |
242 +SECStatus | |
243 +ssl3_ValidateNextProtoNego(const unsigned char* data, unsigned short length) | |
244 +{ | |
245 + unsigned int offset = 0; | |
246 + | |
247 + while (offset < length) { | |
248 + if (data[offset] == 0) { | |
249 + PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); | |
250 + return SECFailure; | |
251 + } | |
252 + offset += (unsigned int)data[offset] + 1; | |
253 + } | |
254 + | |
255 + if (offset > length) { | |
256 + PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); | |
257 + return SECFailure; | |
258 + } | |
259 + | |
260 + return SECSuccess; | |
261 +} | |
262 + | |
263 +SECStatus | |
264 +ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type, | |
265 + SECItem *data) | |
266 +{ | |
267 + SECStatus rv; | |
268 + unsigned char result[255]; | |
269 + unsigned int result_len; | |
270 + | |
271 + rv = ssl3_ValidateNextProtoNego(data->data, data->len); | |
272 + if (rv != SECSuccess) | |
273 + return rv; | |
274 + | |
275 + rv = ss->nextProtoCallback(ss->nextProtoArg, ss->fd, | |
276 + data->data, data->len, | |
277 + result, &result_len); | |
278 + if (rv != SECSuccess) | |
279 + return rv; | |
280 + /* If the callback wrote more than allowed to |result| it has corrupted our | |
281 + * stack. */ | |
282 + PORT_Assert(result_len <= sizeof(result)); | |
283 + | |
284 + if (ss->ssl3.nextProto.data) | |
285 + PORT_Free(ss->ssl3.nextProto.data); | |
286 + ss->ssl3.nextProto.data = PORT_Alloc(result_len); | |
287 + PORT_Memcpy(ss->ssl3.nextProto.data, result, result_len); | |
288 + ss->ssl3.nextProto.len = result_len; | |
289 + return SECSuccess; | |
290 +} | |
291 + | |
292 +PRInt32 | |
293 +ssl3_ClientSendNextProtoNegoXtn(sslSocket * ss, | |
294 + PRBool append, | |
295 + PRUint32 maxBytes) | |
296 +{ | |
297 + PRInt32 extension_length; | |
298 + | |
299 + /* Renegotiations do not send this extension. */ | |
300 + if (!ss->nextProtoCallback || ss->firstHsDone) { | |
301 + return 0; | |
302 + } | |
303 + | |
304 + extension_length = 4; | |
305 + | |
306 + if (append && maxBytes >= extension_length) { | |
307 + SECStatus rv; | |
308 + rv = ssl3_AppendHandshakeNumber(ss, ssl_next_proto_neg_xtn, 2); | |
309 + if (rv != SECSuccess) | |
310 + goto loser; | |
311 + rv = ssl3_AppendHandshakeNumber(ss, 0, 2); | |
312 + if (rv != SECSuccess) | |
313 + goto loser; | |
314 + ss->xtnData.advertised[ss->xtnData.numAdvertised++] = | |
315 + ssl_next_proto_neg_xtn; | |
316 + } else if (maxBytes < extension_length) { | |
317 + return 0; | |
318 + } | |
319 + | |
320 + return extension_length; | |
321 + | |
322 + loser: | |
323 + return -1; | |
324 +} | |
325 + | |
326 /* | |
327 * NewSessionTicket | |
328 * Called from ssl3_HandleFinished | |
329 diff --git a/mozilla/security/nss/lib/ssl/ssl3prot.h b/mozilla/security/nss/lib/
ssl/ssl3prot.h | |
330 index 4702fcc..f3c950e 100644 | |
331 --- a/mozilla/security/nss/lib/ssl/ssl3prot.h | |
332 +++ b/mozilla/security/nss/lib/ssl/ssl3prot.h | |
333 @@ -157,7 +157,8 @@ typedef enum { | |
334 server_hello_done = 14, | |
335 certificate_verify = 15, | |
336 client_key_exchange = 16, | |
337 - finished = 20 | |
338 + finished = 20, | |
339 + next_proto = 67 | |
340 } SSL3HandshakeType; | |
341 | |
342 typedef struct { | |
343 diff --git a/mozilla/security/nss/lib/ssl/sslerr.h b/mozilla/security/nss/lib/ss
l/sslerr.h | |
344 index a2f6524..c76ffa9 100644 | |
345 --- a/mozilla/security/nss/lib/ssl/sslerr.h | |
346 +++ b/mozilla/security/nss/lib/ssl/sslerr.h | |
347 @@ -203,6 +203,8 @@ SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD = (SSL_ERROR_BAS
E + 114), | |
348 | |
349 SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY = (SSL_ERROR_BASE + 115), | |
350 | |
351 +SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID = (SSL_ERROR_BASE + 117), | |
352 + | |
353 SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ | |
354 } SSLErrorCodes; | |
355 #endif /* NO_SECURITY_ERROR_ENUM */ | |
356 diff --git a/mozilla/security/nss/lib/ssl/sslimpl.h b/mozilla/security/nss/lib/s
sl/sslimpl.h | |
357 index 9af471d..199c573 100644 | |
358 --- a/mozilla/security/nss/lib/ssl/sslimpl.h | |
359 +++ b/mozilla/security/nss/lib/ssl/sslimpl.h | |
360 @@ -313,6 +313,10 @@ typedef struct { | |
361 #endif /* NSS_ENABLE_ECC */ | |
362 | |
363 typedef struct sslOptionsStr { | |
364 + /* If SSL_SetNextProtoNego has been called, then this contains the | |
365 + * list of supported protocols. */ | |
366 + SECItem nextProtoNego; | |
367 + | |
368 unsigned int useSecurity : 1; /* 1 */ | |
369 unsigned int useSocks : 1; /* 2 */ | |
370 unsigned int requestCertificate : 1; /* 3 */ | |
371 @@ -827,6 +831,13 @@ struct ssl3StateStr { | |
372 PRBool initialized; | |
373 SSL3HandshakeState hs; | |
374 ssl3CipherSpec specs[2]; /* one is current, one is pending. */ | |
375 + | |
376 + /* In a client: if the server supports Next Protocol Negotiation, then | |
377 + * this is the protocol that was negotiated. | |
378 + * | |
379 + * If the data pointer is non-NULL, then it is malloced data. */ | |
380 + SECItem nextProto; | |
381 + int nextProtoState; /* See NEXT_PROTO_* defines */ | |
382 }; | |
383 | |
384 typedef struct { | |
385 @@ -1058,6 +1069,8 @@ const unsigned char * preferredCipher; | |
386 SSLHandshakeCallback handshakeCallback; | |
387 void *handshakeCallbackData; | |
388 void *pkcs11PinArg; | |
389 + SSLNextProtoCallback nextProtoCallback; | |
390 + void *nextProtoArg; | |
391 | |
392 PRIntervalTime rTimeout; /* timeout for NSPR I/O */ | |
393 PRIntervalTime wTimeout; /* timeout for NSPR I/O */ | |
394 @@ -1494,8 +1507,12 @@ extern SECStatus ssl3_HandleSupportedPointFormatsXtn(sslS
ocket * ss, | |
395 PRUint16 ex_type, SECItem *data); | |
396 extern SECStatus ssl3_ClientHandleSessionTicketXtn(sslSocket *ss, | |
397 PRUint16 ex_type, SECItem *data); | |
398 +extern SECStatus ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, | |
399 + PRUint16 ex_type, SECItem *data); | |
400 extern SECStatus ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, | |
401 PRUint16 ex_type, SECItem *data); | |
402 +extern SECStatus ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss, | |
403 + PRUint16 ex_type, SECItem *data); | |
404 | |
405 /* ClientHello and ServerHello extension senders. | |
406 * Note that not all extension senders are exposed here; only those that | |
407 @@ -1526,6 +1543,10 @@ extern PRInt32 ssl3_SendSupportedCurvesXtn(sslSocket *ss, | |
408 extern PRInt32 ssl3_SendSupportedPointFormatsXtn(sslSocket *ss, | |
409 PRBool append, PRUint32 maxBytes); | |
410 #endif | |
411 +extern PRInt32 ssl3_ClientSendNextProtoNegoXtn(sslSocket *ss, PRBool append, | |
412 + PRUint32 maxBytes); | |
413 +extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char* data, | |
414 + unsigned short length); | |
415 | |
416 /* call the registered extension handlers. */ | |
417 extern SECStatus ssl3_HandleHelloExtensions(sslSocket *ss, | |
418 diff --git a/mozilla/security/nss/lib/ssl/sslsock.c b/mozilla/security/nss/lib/s
sl/sslsock.c | |
419 index bc770a1..829103b 100644 | |
420 --- a/mozilla/security/nss/lib/ssl/sslsock.c | |
421 +++ b/mozilla/security/nss/lib/ssl/sslsock.c | |
422 @@ -163,6 +163,7 @@ static const sslSocketOps ssl_secure_ops = { /* SSL.
*/ | |
423 ** default settings for socket enables | |
424 */ | |
425 static sslOptions ssl_defaults = { | |
426 + { siBuffer, NULL, 0 }, /* nextProtoNego */ | |
427 PR_TRUE, /* useSecurity */ | |
428 PR_FALSE, /* useSocks */ | |
429 PR_FALSE, /* requestCertificate */ | |
430 @@ -438,6 +439,10 @@ ssl_DestroySocketContents(sslSocket *ss) | |
431 ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair); | |
432 ss->ephemeralECDHKeyPair = NULL; | |
433 } | |
434 + if (ss->opt.nextProtoNego.data) { | |
435 + PORT_Free(ss->opt.nextProtoNego.data); | |
436 + ss->opt.nextProtoNego.data = NULL; | |
437 + } | |
438 PORT_Assert(!ss->xtnData.sniNameArr); | |
439 if (ss->xtnData.sniNameArr) { | |
440 PORT_Free(ss->xtnData.sniNameArr); | |
441 @@ -1266,6 +1271,135 @@ SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd) | |
442 return fd; | |
443 } | |
444 | |
445 +SECStatus | |
446 +SSL_SetNextProtoCallback(PRFileDesc *fd, | |
447 + SSLNextProtoCallback callback, | |
448 + void *arg) { | |
449 + sslSocket *ss = ssl_FindSocket(fd); | |
450 + | |
451 + if (!ss) { | |
452 + SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetNextProtoNego", SSL_GETPID()
, | |
453 + fd)); | |
454 + PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
455 + return SECFailure; | |
456 + } | |
457 + | |
458 + ssl_GetSSL3HandshakeLock(ss); | |
459 + ss->nextProtoCallback = callback; | |
460 + ss->nextProtoArg = arg; | |
461 + ssl_ReleaseSSL3HandshakeLock(ss); | |
462 + return SECSuccess; | |
463 +} | |
464 + | |
465 +/* NextProtoStandardCallback is set as an NPN callback for the case when the | |
466 + * user of the sockets wants the standard selection algorithm. */ | |
467 +static SECStatus | |
468 +NextProtoStandardCallback(void *arg, | |
469 + PRFileDesc *fd, | |
470 + const unsigned char *protos, | |
471 + unsigned int protos_len, | |
472 + unsigned char *protoOut, | |
473 + unsigned int *protoOutLen) | |
474 +{ | |
475 + unsigned int i, j; | |
476 + const unsigned char *result; | |
477 + | |
478 + sslSocket *ss = ssl_FindSocket(fd); | |
479 + PORT_Assert(ss); | |
480 + | |
481 + if (protos_len == 0) { | |
482 + /* The server supports the extension, but doesn't have any protocols | |
483 + * configured. In this case we request our favoured protocol. */ | |
484 + goto pick_first; | |
485 + } | |
486 + | |
487 + /* For each protocol in server preference, see if we support it. */ | |
488 + for (i = 0; i < protos_len; ) { | |
489 + for (j = 0; j < ss->opt.nextProtoNego.len; ) { | |
490 + if (protos[i] == ss->opt.nextProtoNego.data[j] && | |
491 + memcmp(&protos[i+1], &ss->opt.nextProtoNego.data[j+1], | |
492 + protos[i]) == 0) { | |
493 + /* We found a match. */ | |
494 + ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NEGOTIATED; | |
495 + result = &protos[i]; | |
496 + goto found; | |
497 + } | |
498 + j += (unsigned int)ss->opt.nextProtoNego.data[j] + 1; | |
499 + } | |
500 + i += (unsigned int)protos[i] + 1; | |
501 + } | |
502 + | |
503 +pick_first: | |
504 + ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NO_OVERLAP; | |
505 + result = ss->opt.nextProtoNego.data; | |
506 + | |
507 +found: | |
508 + memcpy(protoOut, result + 1, result[0]); | |
509 + *protoOutLen = result[0]; | |
510 + return SECSuccess; | |
511 +} | |
512 + | |
513 +SECStatus | |
514 +SSL_SetNextProtoNego(PRFileDesc *fd, const unsigned char *data, | |
515 + unsigned int length) | |
516 +{ | |
517 + SECStatus rv; | |
518 + | |
519 + sslSocket *ss = ssl_FindSocket(fd); | |
520 + | |
521 + if (!ss) { | |
522 + SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetNextProtoNego", | |
523 + SSL_GETPID(), fd)); | |
524 + PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
525 + return SECFailure; | |
526 + } | |
527 + | |
528 + if (ssl3_ValidateNextProtoNego(data, length) != SECSuccess) | |
529 + return SECFailure; | |
530 + | |
531 + ssl_GetSSL3HandshakeLock(ss); | |
532 + if (ss->opt.nextProtoNego.data) | |
533 + PORT_Free(ss->opt.nextProtoNego.data); | |
534 + ss->opt.nextProtoNego.data = PORT_Alloc(length); | |
535 + if (!ss->opt.nextProtoNego.data) { | |
536 + ssl_ReleaseSSL3HandshakeLock(ss); | |
537 + return SECFailure; | |
538 + } | |
539 + memcpy(ss->opt.nextProtoNego.data, data, length); | |
540 + ss->opt.nextProtoNego.len = length; | |
541 + ss->opt.nextProtoNego.type = siBuffer; | |
542 + ssl_ReleaseSSL3HandshakeLock(ss); | |
543 + | |
544 + return SSL_SetNextProtoCallback(fd, NextProtoStandardCallback, NULL); | |
545 +} | |
546 + | |
547 +SECStatus | |
548 +SSL_GetNextProto(PRFileDesc *fd, int *state, unsigned char *buf, | |
549 + unsigned int *length, unsigned int buf_len) | |
550 +{ | |
551 + sslSocket *ss = ssl_FindSocket(fd); | |
552 + | |
553 + if (!ss) { | |
554 + SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetNextProto", SSL_GETPID(), | |
555 + fd)); | |
556 + return SECFailure; | |
557 + } | |
558 + | |
559 + *state = ss->ssl3.nextProtoState; | |
560 + | |
561 + if (ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT && | |
562 + ss->ssl3.nextProto.data) { | |
563 + *length = ss->ssl3.nextProto.len; | |
564 + if (*length > buf_len) | |
565 + *length = buf_len; | |
566 + PORT_Memcpy(buf, ss->ssl3.nextProto.data, *length); | |
567 + } else { | |
568 + *length = 0; | |
569 + } | |
570 + | |
571 + return SECSuccess; | |
572 +} | |
573 + | |
574 PRFileDesc * | |
575 SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) | |
576 { | |
577 diff --git a/mozilla/security/nss/lib/ssl/sslt.h b/mozilla/security/nss/lib/ssl/
sslt.h | |
578 index c7d4553..f6e0b62 100644 | |
579 --- a/mozilla/security/nss/lib/ssl/sslt.h | |
580 +++ b/mozilla/security/nss/lib/ssl/sslt.h | |
581 @@ -203,9 +203,10 @@ typedef enum { | |
582 ssl_ec_point_formats_xtn = 11, | |
583 #endif | |
584 ssl_session_ticket_xtn = 35, | |
585 + ssl_next_proto_neg_xtn = 13172, | |
586 ssl_renegotiation_info_xtn = 0xff01 /* experimental number */ | |
587 } SSLExtensionType; | |
588 | |
589 -#define SSL_MAX_EXTENSIONS 5 | |
590 +#define SSL_MAX_EXTENSIONS 6 | |
591 | |
592 #endif /* __sslt_h_ */ | |
OLD | NEW |