| 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 |