| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 /* | 
|  | 2  * SSL3 Protocol | 
|  | 3  * | 
|  | 4  * ***** BEGIN LICENSE BLOCK ***** | 
|  | 5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | 
|  | 6  * | 
|  | 7  * The contents of this file are subject to the Mozilla Public License Version | 
|  | 8  * 1.1 (the "License"); you may not use this file except in compliance with | 
|  | 9  * the License. You may obtain a copy of the License at | 
|  | 10  * http://www.mozilla.org/MPL/ | 
|  | 11  * | 
|  | 12  * Software distributed under the License is distributed on an "AS IS" basis, | 
|  | 13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | 
|  | 14  * for the specific language governing rights and limitations under the | 
|  | 15  * License. | 
|  | 16  * | 
|  | 17  * The Original Code is the Netscape security libraries. | 
|  | 18  * | 
|  | 19  * The Initial Developer of the Original Code is | 
|  | 20  * Netscape Communications Corporation. | 
|  | 21  * Portions created by the Initial Developer are Copyright (C) 1994-2000 | 
|  | 22  * the Initial Developer. All Rights Reserved. | 
|  | 23  * | 
|  | 24  * Contributor(s): | 
|  | 25  *   Dr Vipul Gupta <vipul.gupta@sun.com> and | 
|  | 26  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories | 
|  | 27  *   Nagendra Modadugu <ngm@google.com>, Google Inc. | 
|  | 28  * | 
|  | 29  * Alternatively, the contents of this file may be used under the terms of | 
|  | 30  * either the GNU General Public License Version 2 or later (the "GPL"), or | 
|  | 31  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), | 
|  | 32  * in which case the provisions of the GPL or the LGPL are applicable instead | 
|  | 33  * of those above. If you wish to allow use of your version of this file only | 
|  | 34  * under the terms of either the GPL or the LGPL, and not to allow others to | 
|  | 35  * use your version of this file under the terms of the MPL, indicate your | 
|  | 36  * decision by deleting the provisions above and replace them with the notice | 
|  | 37  * and other provisions required by the GPL or the LGPL. If you do not delete | 
|  | 38  * the provisions above, a recipient may use your version of this file under | 
|  | 39  * the terms of any one of the MPL, the GPL or the LGPL. | 
|  | 40  * | 
|  | 41  * ***** END LICENSE BLOCK ***** */ | 
|  | 42 | 
|  | 43 /* TLS extension code moved here from ssl3ecc.c */ | 
|  | 44 /* $Id: ssl3ext.c,v 1.5 2009/11/07 18:23:06 wtc%google.com Exp $ */ | 
|  | 45 | 
|  | 46 #include "nssrenam.h" | 
|  | 47 #include "nss.h" | 
|  | 48 #include "ssl.h" | 
|  | 49 #include "sslimpl.h" | 
|  | 50 #include "pk11pub.h" | 
|  | 51 #include "blapi.h" | 
|  | 52 #include "prinit.h" | 
|  | 53 | 
|  | 54 static unsigned char  key_name[SESS_TICKET_KEY_NAME_LEN]; | 
|  | 55 static PK11SymKey    *session_ticket_enc_key_pkcs11 = NULL; | 
|  | 56 static PK11SymKey    *session_ticket_mac_key_pkcs11 = NULL; | 
|  | 57 | 
|  | 58 static unsigned char  session_ticket_enc_key[32]; | 
|  | 59 static unsigned char  session_ticket_mac_key[SHA256_LENGTH]; | 
|  | 60 | 
|  | 61 static PRBool         session_ticket_keys_initialized = PR_FALSE; | 
|  | 62 static PRCallOnceType generate_session_keys_once; | 
|  | 63 | 
|  | 64 static PRInt32 ssl3_SendServerNameXtn(sslSocket * ss, | 
|  | 65     PRBool append, PRUint32 maxBytes); | 
|  | 66 static SECStatus ssl3_ParseEncryptedSessionTicket(sslSocket *ss, | 
|  | 67     SECItem *data, EncryptedSessionTicket *enc_session_ticket); | 
|  | 68 static SECStatus ssl3_AppendToItem(SECItem *item, const unsigned char *buf, | 
|  | 69     PRUint32 bytes); | 
|  | 70 static SECStatus ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, | 
|  | 71     PRInt32 lenSize); | 
|  | 72 static SECStatus ssl3_GetSessionTicketKeysPKCS11(sslSocket *ss, | 
|  | 73     PK11SymKey **aes_key, PK11SymKey **mac_key); | 
|  | 74 static SECStatus ssl3_GetSessionTicketKeys(const unsigned char **aes_key, | 
|  | 75     PRUint32 *aes_key_length, const unsigned char **mac_key, | 
|  | 76     PRUint32 *mac_key_length); | 
|  | 77 | 
|  | 78 /* | 
|  | 79  * Write bytes.  Using this function means the SECItem structure | 
|  | 80  * cannot be freed.  The caller is expected to call this function | 
|  | 81  * on a shallow copy of the structure. | 
|  | 82  */ | 
|  | 83 static SECStatus | 
|  | 84 ssl3_AppendToItem(SECItem *item, const unsigned char *buf, PRUint32 bytes) | 
|  | 85 { | 
|  | 86     if (bytes > item->len) | 
|  | 87         return SECFailure; | 
|  | 88 | 
|  | 89     PORT_Memcpy(item->data, buf, bytes); | 
|  | 90     item->data += bytes; | 
|  | 91     item->len -= bytes; | 
|  | 92     return SECSuccess; | 
|  | 93 } | 
|  | 94 | 
|  | 95 /* | 
|  | 96  * Write a number in network byte order. Using this function means the | 
|  | 97  * SECItem structure cannot be freed.  The caller is expected to call | 
|  | 98  * this function on a shallow copy of the structure. | 
|  | 99  */ | 
|  | 100 static SECStatus | 
|  | 101 ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, PRInt32 lenSize) | 
|  | 102 { | 
|  | 103     SECStatus rv; | 
|  | 104     uint8     b[4]; | 
|  | 105     uint8 *   p = b; | 
|  | 106 | 
|  | 107     switch (lenSize) { | 
|  | 108     case 4: | 
|  | 109         *p++ = (uint8) (num >> 24); | 
|  | 110     case 3: | 
|  | 111         *p++ = (uint8) (num >> 16); | 
|  | 112     case 2: | 
|  | 113         *p++ = (uint8) (num >> 8); | 
|  | 114     case 1: | 
|  | 115         *p = (uint8) num; | 
|  | 116     } | 
|  | 117     rv = ssl3_AppendToItem(item, &b[0], lenSize); | 
|  | 118     return rv; | 
|  | 119 } | 
|  | 120 | 
|  | 121 static SECStatus ssl3_SessionTicketShutdown(void* appData, void* nssData) | 
|  | 122 { | 
|  | 123     if (session_ticket_enc_key_pkcs11) { | 
|  | 124         PK11_FreeSymKey(session_ticket_enc_key_pkcs11); | 
|  | 125         session_ticket_enc_key_pkcs11 = NULL; | 
|  | 126     } | 
|  | 127     if (session_ticket_mac_key_pkcs11) { | 
|  | 128         PK11_FreeSymKey(session_ticket_mac_key_pkcs11); | 
|  | 129         session_ticket_mac_key_pkcs11 = NULL; | 
|  | 130     } | 
|  | 131     PORT_Memset(&generate_session_keys_once, 0, | 
|  | 132         sizeof(generate_session_keys_once)); | 
|  | 133     return SECSuccess; | 
|  | 134 } | 
|  | 135 | 
|  | 136 | 
|  | 137 static PRStatus | 
|  | 138 ssl3_GenerateSessionTicketKeysPKCS11(void *data) | 
|  | 139 { | 
|  | 140     SECStatus rv; | 
|  | 141     sslSocket *ss = (sslSocket *)data; | 
|  | 142     SECKEYPrivateKey *svrPrivKey = ss->serverCerts[kt_rsa].SERVERKEY; | 
|  | 143     SECKEYPublicKey *svrPubKey = ss->serverCerts[kt_rsa].serverKeyPair->pubKey; | 
|  | 144 | 
|  | 145     if (svrPrivKey == NULL || svrPubKey == NULL) { | 
|  | 146         SSL_DBG(("%d: SSL[%d]: Pub or priv key(s) is NULL.", | 
|  | 147                         SSL_GETPID(), ss->fd)); | 
|  | 148         goto loser; | 
|  | 149     } | 
|  | 150 | 
|  | 151     /* Get a copy of the session keys from shared memory. */ | 
|  | 152     PORT_Memcpy(key_name, SESS_TICKET_KEY_NAME_PREFIX, | 
|  | 153         sizeof(SESS_TICKET_KEY_NAME_PREFIX)); | 
|  | 154     if (!ssl_GetSessionTicketKeysPKCS11(svrPrivKey, svrPubKey, | 
|  | 155             ss->pkcs11PinArg, &key_name[SESS_TICKET_KEY_NAME_PREFIX_LEN], | 
|  | 156             &session_ticket_enc_key_pkcs11, &session_ticket_mac_key_pkcs11)) | 
|  | 157         return PR_FAILURE; | 
|  | 158 | 
|  | 159     rv = NSS_RegisterShutdown(ssl3_SessionTicketShutdown, NULL); | 
|  | 160     if (rv != SECSuccess) | 
|  | 161         goto loser; | 
|  | 162 | 
|  | 163     return PR_SUCCESS; | 
|  | 164 | 
|  | 165 loser: | 
|  | 166     ssl3_SessionTicketShutdown(NULL, NULL); | 
|  | 167     return PR_FAILURE; | 
|  | 168 } | 
|  | 169 | 
|  | 170 static SECStatus | 
|  | 171 ssl3_GetSessionTicketKeysPKCS11(sslSocket *ss, PK11SymKey **aes_key, | 
|  | 172                                 PK11SymKey **mac_key) | 
|  | 173 { | 
|  | 174     if (PR_CallOnceWithArg(&generate_session_keys_once, | 
|  | 175             ssl3_GenerateSessionTicketKeysPKCS11, ss) != PR_SUCCESS) | 
|  | 176         return SECFailure; | 
|  | 177 | 
|  | 178     if (session_ticket_enc_key_pkcs11 == NULL || | 
|  | 179         session_ticket_mac_key_pkcs11 == NULL) | 
|  | 180         return SECFailure; | 
|  | 181 | 
|  | 182     *aes_key = session_ticket_enc_key_pkcs11; | 
|  | 183     *mac_key = session_ticket_mac_key_pkcs11; | 
|  | 184     return SECSuccess; | 
|  | 185 } | 
|  | 186 | 
|  | 187 static PRStatus | 
|  | 188 ssl3_GenerateSessionTicketKeys(void) | 
|  | 189 { | 
|  | 190     PORT_Memcpy(key_name, SESS_TICKET_KEY_NAME_PREFIX, | 
|  | 191         sizeof(SESS_TICKET_KEY_NAME_PREFIX)); | 
|  | 192 | 
|  | 193     if (!ssl_GetSessionTicketKeys(&key_name[SESS_TICKET_KEY_NAME_PREFIX_LEN], | 
|  | 194             session_ticket_enc_key, session_ticket_mac_key)) | 
|  | 195         return PR_FAILURE; | 
|  | 196 | 
|  | 197     session_ticket_keys_initialized = PR_TRUE; | 
|  | 198     return PR_SUCCESS; | 
|  | 199 } | 
|  | 200 | 
|  | 201 static SECStatus | 
|  | 202 ssl3_GetSessionTicketKeys(const unsigned char **aes_key, | 
|  | 203     PRUint32 *aes_key_length, const unsigned char **mac_key, | 
|  | 204     PRUint32 *mac_key_length) | 
|  | 205 { | 
|  | 206     if (PR_CallOnce(&generate_session_keys_once, | 
|  | 207             ssl3_GenerateSessionTicketKeys) != SECSuccess) | 
|  | 208         return SECFailure; | 
|  | 209 | 
|  | 210     if (!session_ticket_keys_initialized) | 
|  | 211         return SECFailure; | 
|  | 212 | 
|  | 213     *aes_key = session_ticket_enc_key; | 
|  | 214     *aes_key_length = sizeof(session_ticket_enc_key); | 
|  | 215     *mac_key = session_ticket_mac_key; | 
|  | 216     *mac_key_length = sizeof(session_ticket_mac_key); | 
|  | 217 | 
|  | 218     return SECSuccess; | 
|  | 219 } | 
|  | 220 | 
|  | 221 /* Table of handlers for received TLS hello extensions, one per extension. | 
|  | 222  * In the second generation, this table will be dynamic, and functions | 
|  | 223  * will be registered here. | 
|  | 224  */ | 
|  | 225 static const ssl3HelloExtensionHandler clientHelloHandlers[] = { | 
|  | 226     { server_name_xtn, &ssl3_HandleServerNameXtn }, | 
|  | 227 #ifdef NSS_ENABLE_ECC | 
|  | 228     { elliptic_curves_xtn, &ssl3_HandleSupportedCurvesXtn }, | 
|  | 229     { ec_point_formats_xtn, &ssl3_HandleSupportedPointFormatsXtn }, | 
|  | 230 #endif | 
|  | 231     { session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn }, | 
|  | 232     { -1, NULL } | 
|  | 233 }; | 
|  | 234 | 
|  | 235 static const ssl3HelloExtensionHandler serverHelloHandlers[] = { | 
|  | 236     { server_name_xtn, &ssl3_HandleServerNameXtn }, | 
|  | 237     /* TODO: add a handler for ec_point_formats_xtn */ | 
|  | 238     { session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn }, | 
|  | 239     { -1, NULL } | 
|  | 240 }; | 
|  | 241 | 
|  | 242 /* Table of functions to format TLS hello extensions, one per extension. | 
|  | 243  * This static table is for the formatting of client hello extensions. | 
|  | 244  * The server's table of hello senders is dynamic, in the socket struct, | 
|  | 245  * and sender functions are registered there. | 
|  | 246  */ | 
|  | 247 static const | 
|  | 248 ssl3HelloExtensionSender clientHelloSenders[MAX_EXTENSIONS] = { | 
|  | 249     { server_name_xtn, &ssl3_SendServerNameXtn }, | 
|  | 250 #ifdef NSS_ENABLE_ECC | 
|  | 251     { elliptic_curves_xtn, &ssl3_SendSupportedCurvesXtn }, | 
|  | 252     { ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn }, | 
|  | 253 #else | 
|  | 254     { -1, NULL }, | 
|  | 255     { -1, NULL }, | 
|  | 256 #endif | 
|  | 257     { session_ticket_xtn, ssl3_SendSessionTicketXtn } | 
|  | 258 }; | 
|  | 259 | 
|  | 260 static PRBool | 
|  | 261 arrayContainsExtension(const PRUint16 *array, PRUint32 len, PRUint16 ex_type) | 
|  | 262 { | 
|  | 263     int i; | 
|  | 264     for (i = 0; i < len; i++) { | 
|  | 265         if (ex_type == array[i]) | 
|  | 266             return PR_TRUE; | 
|  | 267     } | 
|  | 268     return PR_FALSE; | 
|  | 269 } | 
|  | 270 | 
|  | 271 PRBool | 
|  | 272 ssl3_ExtensionNegotiated(sslSocket *ss, PRUint16 ex_type) { | 
|  | 273     TLSExtensionData *xtnData = &ss->xtnData; | 
|  | 274     return arrayContainsExtension(xtnData->negotiated, | 
|  | 275                                   xtnData->numNegotiated, ex_type); | 
|  | 276 } | 
|  | 277 | 
|  | 278 static PRBool | 
|  | 279 ssl3_ClientExtensionAdvertised(sslSocket *ss, PRUint16 ex_type) { | 
|  | 280     TLSExtensionData *xtnData = &ss->xtnData; | 
|  | 281     return arrayContainsExtension(xtnData->advertised, | 
|  | 282                                   xtnData->numAdvertised, ex_type); | 
|  | 283 } | 
|  | 284 | 
|  | 285 /* Format an SNI extension, using the name from the socket's URL, | 
|  | 286  * unless that name is a dotted decimal string. | 
|  | 287  */ | 
|  | 288 static PRInt32 | 
|  | 289 ssl3_SendServerNameXtn( | 
|  | 290                         sslSocket * ss, | 
|  | 291                         PRBool      append, | 
|  | 292                         PRUint32    maxBytes) | 
|  | 293 { | 
|  | 294     PRUint32 len; | 
|  | 295     PRNetAddr netAddr; | 
|  | 296 | 
|  | 297     /* must have a hostname */ | 
|  | 298     if (!ss || !ss->url || !ss->url[0]) | 
|  | 299         return 0; | 
|  | 300     /* must not be an IPv4 or IPv6 address */ | 
|  | 301     if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) { | 
|  | 302         /* is an IP address (v4 or v6) */ | 
|  | 303         return 0; | 
|  | 304     } | 
|  | 305     len  = PORT_Strlen(ss->url); | 
|  | 306     if (append && maxBytes >= len + 9) { | 
|  | 307         SECStatus rv; | 
|  | 308         /* extension_type */ | 
|  | 309         rv = ssl3_AppendHandshakeNumber(ss, server_name_xtn, 2); | 
|  | 310         if (rv != SECSuccess) return -1; | 
|  | 311         /* length of extension_data */ | 
|  | 312         rv = ssl3_AppendHandshakeNumber(ss, len + 5, 2); | 
|  | 313         if (rv != SECSuccess) return -1; | 
|  | 314         /* length of server_name_list */ | 
|  | 315         rv = ssl3_AppendHandshakeNumber(ss, len + 3, 2); | 
|  | 316         if (rv != SECSuccess) return -1; | 
|  | 317         /* Name Type (host_name) */ | 
|  | 318         rv = ssl3_AppendHandshake(ss,       "\0",    1); | 
|  | 319         if (rv != SECSuccess) return -1; | 
|  | 320         /* HostName (length and value) */ | 
|  | 321         rv = ssl3_AppendHandshakeVariable(ss, (unsigned char *)ss->url, len, 2); | 
|  | 322         if (rv != SECSuccess) return -1; | 
|  | 323         if (!ss->sec.isServer) { | 
|  | 324             TLSExtensionData *xtnData = &ss->xtnData; | 
|  | 325             xtnData->advertised[xtnData->numAdvertised++] = server_name_xtn; | 
|  | 326         } | 
|  | 327     } | 
|  | 328     return len + 9; | 
|  | 329 } | 
|  | 330 | 
|  | 331 /* handle an incoming SNI extension, by ignoring it. */ | 
|  | 332 SECStatus | 
|  | 333 ssl3_HandleServerNameXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) | 
|  | 334 { | 
|  | 335     /* TODO: if client, should verify extension_data is empty. */ | 
|  | 336     /* TODO: if server, should send empty extension_data. */ | 
|  | 337     /* For now, we ignore this, as if we didn't understand it. :-)  */ | 
|  | 338     return SECSuccess; | 
|  | 339 } | 
|  | 340 | 
|  | 341 /* Called by both clients and servers. | 
|  | 342  * Clients sends a filled in session ticket if one is available, and otherwise | 
|  | 343  * sends an empty ticket.  Servers always send empty tickets. | 
|  | 344  */ | 
|  | 345 PRInt32 | 
|  | 346 ssl3_SendSessionTicketXtn( | 
|  | 347                         sslSocket * ss, | 
|  | 348                         PRBool      append, | 
|  | 349                         PRUint32    maxBytes) | 
|  | 350 { | 
|  | 351     PRInt32 extension_length; | 
|  | 352     NewSessionTicket *session_ticket = NULL; | 
|  | 353 | 
|  | 354     /* Ignore the SessionTicket extension if processing is disabled. */ | 
|  | 355     if (!ss->opt.enableSessionTickets) | 
|  | 356         return 0; | 
|  | 357 | 
|  | 358     /* Empty extension length = extension_type (2-bytes) + | 
|  | 359      * length(extension_data) (2-bytes) | 
|  | 360      */ | 
|  | 361     extension_length = 4; | 
|  | 362 | 
|  | 363     /* If we are a client then send a session ticket if one is availble. | 
|  | 364      * Servers that support the extension and are willing to negotiate the | 
|  | 365      * the extension always respond with an empty extension. | 
|  | 366      */ | 
|  | 367     if (!ss->sec.isServer) { | 
|  | 368         sslSessionID *sid = ss->sec.ci.sid; | 
|  | 369         session_ticket = &sid->u.ssl3.sessionTicket; | 
|  | 370         if (session_ticket->ticket.data) { | 
|  | 371             if (ss->xtnData.ticketTimestampVerified) { | 
|  | 372                 extension_length += session_ticket->ticket.len; | 
|  | 373             } else if (!append && | 
|  | 374                 (session_ticket->ticket_lifetime_hint == 0 || | 
|  | 375                 (session_ticket->ticket_lifetime_hint + | 
|  | 376                     session_ticket->received_timestamp > ssl_Time()))) { | 
|  | 377                 extension_length += session_ticket->ticket.len; | 
|  | 378                 ss->xtnData.ticketTimestampVerified = PR_TRUE; | 
|  | 379             } | 
|  | 380         } | 
|  | 381     } | 
|  | 382 | 
|  | 383     if (append && maxBytes >= extension_length) { | 
|  | 384         SECStatus rv; | 
|  | 385         /* extension_type */ | 
|  | 386         rv = ssl3_AppendHandshakeNumber(ss, session_ticket_xtn, 2); | 
|  | 387         if (rv != SECSuccess) | 
|  | 388             goto loser; | 
|  | 389         if (session_ticket && session_ticket->ticket.data && | 
|  | 390             ss->xtnData.ticketTimestampVerified) { | 
|  | 391             rv = ssl3_AppendHandshakeVariable(ss, session_ticket->ticket.data, | 
|  | 392                 session_ticket->ticket.len, 2); | 
|  | 393             ss->xtnData.ticketTimestampVerified = PR_FALSE; | 
|  | 394         } else { | 
|  | 395             rv = ssl3_AppendHandshakeNumber(ss, 0, 2); | 
|  | 396         } | 
|  | 397         if (rv != SECSuccess) | 
|  | 398             goto loser; | 
|  | 399 | 
|  | 400         if (!ss->sec.isServer) { | 
|  | 401             TLSExtensionData *xtnData = &ss->xtnData; | 
|  | 402             xtnData->advertised[xtnData->numAdvertised++] = session_ticket_xtn; | 
|  | 403         } | 
|  | 404     } else if (maxBytes < extension_length) { | 
|  | 405         PORT_Assert(0); | 
|  | 406         return 0; | 
|  | 407     } | 
|  | 408     return extension_length; | 
|  | 409 | 
|  | 410  loser: | 
|  | 411     ss->xtnData.ticketTimestampVerified = PR_FALSE; | 
|  | 412     return -1; | 
|  | 413 } | 
|  | 414 | 
|  | 415 /* | 
|  | 416  * NewSessionTicket | 
|  | 417  * Called from ssl3_HandleFinished | 
|  | 418  */ | 
|  | 419 SECStatus | 
|  | 420 ssl3_SendNewSessionTicket(sslSocket *ss) | 
|  | 421 { | 
|  | 422     int                  i; | 
|  | 423     SECStatus            rv; | 
|  | 424     NewSessionTicket     ticket; | 
|  | 425     SECItem              plaintext; | 
|  | 426     SECItem              plaintext_item = {0, NULL, 0}; | 
|  | 427     SECItem              ciphertext     = {0, NULL, 0}; | 
|  | 428     PRUint32             ciphertext_length; | 
|  | 429     PRBool               ms_is_wrapped; | 
|  | 430     unsigned char        wrapped_ms[SSL3_MASTER_SECRET_LENGTH]; | 
|  | 431     SECItem              ms_item = {0, NULL, 0}; | 
|  | 432     SSL3KEAType          effectiveExchKeyType = ssl_kea_null; | 
|  | 433     PRUint32             padding_length; | 
|  | 434     PRUint32             message_length; | 
|  | 435     PRUint32             cert_length; | 
|  | 436     uint8                length_buf[4]; | 
|  | 437     PRUint32             now; | 
|  | 438     PK11SymKey          *aes_key_pkcs11; | 
|  | 439     PK11SymKey          *mac_key_pkcs11; | 
|  | 440     const unsigned char *aes_key; | 
|  | 441     const unsigned char *mac_key; | 
|  | 442     PRUint32             aes_key_length; | 
|  | 443     PRUint32             mac_key_length; | 
|  | 444     PRUint64             aes_ctx_buf[MAX_CIPHER_CONTEXT_LLONGS]; | 
|  | 445     AESContext          *aes_ctx; | 
|  | 446     CK_MECHANISM_TYPE    cipherMech = CKM_AES_CBC; | 
|  | 447     PK11Context         *aes_ctx_pkcs11; | 
|  | 448     const SECHashObject *hashObj = NULL; | 
|  | 449     PRUint64             hmac_ctx_buf[MAX_MAC_CONTEXT_LLONGS]; | 
|  | 450     HMACContext         *hmac_ctx; | 
|  | 451     CK_MECHANISM_TYPE    macMech = CKM_SHA256_HMAC; | 
|  | 452     PK11Context         *hmac_ctx_pkcs11; | 
|  | 453     unsigned char        computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH]; | 
|  | 454     unsigned int         computed_mac_length; | 
|  | 455     unsigned char        iv[AES_BLOCK_SIZE]; | 
|  | 456     SECItem              ivItem; | 
|  | 457     CK_MECHANISM_TYPE    msWrapMech = 0; /* dummy default value, | 
|  | 458                                           * must be >= 0 */ | 
|  | 459 | 
|  | 460     SSL_TRC(3, ("%d: SSL3[%d]: send session_ticket handshake", | 
|  | 461                 SSL_GETPID(), ss->fd)); | 
|  | 462 | 
|  | 463     PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); | 
|  | 464     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); | 
|  | 465 | 
|  | 466     ticket.ticket_lifetime_hint = TLS_EX_SESS_TICKET_LIFETIME_HINT; | 
|  | 467     cert_length = (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) ? | 
|  | 468         3 + ss->sec.ci.sid->peerCert->derCert.len : 0; | 
|  | 469 | 
|  | 470     /* Get IV and encryption keys */ | 
|  | 471     ivItem.data = iv; | 
|  | 472     ivItem.len = sizeof(iv); | 
|  | 473     rv = PK11_GenerateRandom(iv, sizeof(iv)); | 
|  | 474     if (rv != SECSuccess) goto loser; | 
|  | 475 | 
|  | 476     if (ss->opt.bypassPKCS11) { | 
|  | 477         rv = ssl3_GetSessionTicketKeys(&aes_key, &aes_key_length, | 
|  | 478             &mac_key, &mac_key_length); | 
|  | 479     } else { | 
|  | 480         rv = ssl3_GetSessionTicketKeysPKCS11(ss, &aes_key_pkcs11, | 
|  | 481             &mac_key_pkcs11); | 
|  | 482     } | 
|  | 483     if (rv != SECSuccess) goto loser; | 
|  | 484 | 
|  | 485     if (ss->ssl3.pwSpec->msItem.len && ss->ssl3.pwSpec->msItem.data) { | 
|  | 486         /* The master secret is available unwrapped. */ | 
|  | 487         ms_item.data = ss->ssl3.pwSpec->msItem.data; | 
|  | 488         ms_item.len = ss->ssl3.pwSpec->msItem.len; | 
|  | 489         ms_is_wrapped = PR_FALSE; | 
|  | 490     } else { | 
|  | 491         /* Extract the master secret wrapped. */ | 
|  | 492         sslSessionID sid; | 
|  | 493         PORT_Memset(&sid, 0, sizeof(sslSessionID)); | 
|  | 494 | 
|  | 495         if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) { | 
|  | 496             effectiveExchKeyType = kt_rsa; | 
|  | 497         } else { | 
|  | 498             effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType; | 
|  | 499         } | 
|  | 500 | 
|  | 501         rv = ssl3_CacheWrappedMasterSecret(ss, &sid, ss->ssl3.pwSpec, | 
|  | 502             effectiveExchKeyType); | 
|  | 503         if (rv == SECSuccess) { | 
|  | 504             if (sid.u.ssl3.keys.wrapped_master_secret_len > sizeof(wrapped_ms)) | 
|  | 505                 goto loser; | 
|  | 506             memcpy(wrapped_ms, sid.u.ssl3.keys.wrapped_master_secret, | 
|  | 507                 sid.u.ssl3.keys.wrapped_master_secret_len); | 
|  | 508             ms_item.data = wrapped_ms; | 
|  | 509             ms_item.len = sid.u.ssl3.keys.wrapped_master_secret_len; | 
|  | 510             msWrapMech = sid.u.ssl3.masterWrapMech; | 
|  | 511         } else { | 
|  | 512             /* TODO: else send an empty ticket. */ | 
|  | 513             goto loser; | 
|  | 514         } | 
|  | 515         ms_is_wrapped = PR_TRUE; | 
|  | 516     } | 
|  | 517 | 
|  | 518     ciphertext_length = | 
|  | 519         sizeof(PRUint16)                     /* ticket_version */ | 
|  | 520         + sizeof(SSL3ProtocolVersion)        /* ssl_version */ | 
|  | 521         + sizeof(ssl3CipherSuite)            /* ciphersuite */ | 
|  | 522         + 1                                  /* compression */ | 
|  | 523         + 10                                 /* cipher spec parameters */ | 
|  | 524         + 1                                  /* SessionTicket.ms_is_wrapped */ | 
|  | 525         + 1                                  /* effectiveExchKeyType */ | 
|  | 526         + 4                                  /* msWrapMech */ | 
|  | 527         + 2                                  /* master_secret.length */ | 
|  | 528         + ms_item.len                        /* master_secret */ | 
|  | 529         + 1                                  /* client_auth_type */ | 
|  | 530         + cert_length                        /* cert */ | 
|  | 531         + sizeof(ticket.ticket_lifetime_hint); | 
|  | 532     padding_length =  AES_BLOCK_SIZE - | 
|  | 533         (ciphertext_length % AES_BLOCK_SIZE); | 
|  | 534     ciphertext_length += padding_length; | 
|  | 535 | 
|  | 536     message_length = | 
|  | 537         sizeof(ticket.ticket_lifetime_hint)    /* ticket_lifetime_hint */ | 
|  | 538         + 2 /* length field for NewSessionTicket.ticket */ | 
|  | 539         + SESS_TICKET_KEY_NAME_LEN             /* key_name */ | 
|  | 540         + AES_BLOCK_SIZE                       /* iv */ | 
|  | 541         + 2 /* length field for NewSessionTicket.ticket.encrypted_state */ | 
|  | 542         + ciphertext_length                    /* encrypted_state */ | 
|  | 543         + TLS_EX_SESS_TICKET_MAC_LENGTH;       /* mac */ | 
|  | 544 | 
|  | 545     if (SECITEM_AllocItem(NULL, &plaintext_item, ciphertext_length) == NULL) | 
|  | 546         goto loser; | 
|  | 547 | 
|  | 548     plaintext = plaintext_item; | 
|  | 549 | 
|  | 550     /* ticket_version */ | 
|  | 551     rv = ssl3_AppendNumberToItem(&plaintext, TLS_EX_SESS_TICKET_VERSION, | 
|  | 552         sizeof(PRUint16)); | 
|  | 553     if (rv != SECSuccess) goto loser; | 
|  | 554 | 
|  | 555     /* ssl_version */ | 
|  | 556     rv = ssl3_AppendNumberToItem(&plaintext, ss->version, | 
|  | 557         sizeof(SSL3ProtocolVersion)); | 
|  | 558     if (rv != SECSuccess) goto loser; | 
|  | 559 | 
|  | 560     /* ciphersuite */ | 
|  | 561     rv = ssl3_AppendNumberToItem(&plaintext, ss->ssl3.hs.cipher_suite, | 
|  | 562         sizeof(ssl3CipherSuite)); | 
|  | 563     if (rv != SECSuccess) goto loser; | 
|  | 564 | 
|  | 565     /* compression */ | 
|  | 566     rv = ssl3_AppendNumberToItem(&plaintext, ss->ssl3.hs.compression, 1); | 
|  | 567     if (rv != SECSuccess) goto loser; | 
|  | 568 | 
|  | 569     /* cipher spec parameters */ | 
|  | 570     rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authAlgorithm, 1); | 
|  | 571     if (rv != SECSuccess) goto loser; | 
|  | 572     rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authKeyBits, 4); | 
|  | 573     if (rv != SECSuccess) goto loser; | 
|  | 574     rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaType, 1); | 
|  | 575     if (rv != SECSuccess) goto loser; | 
|  | 576     rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaKeyBits, 4); | 
|  | 577     if (rv != SECSuccess) goto loser; | 
|  | 578 | 
|  | 579     /* master_secret */ | 
|  | 580     rv = ssl3_AppendNumberToItem(&plaintext, ms_is_wrapped, 1); | 
|  | 581     if (rv != SECSuccess) goto loser; | 
|  | 582     rv = ssl3_AppendNumberToItem(&plaintext, effectiveExchKeyType, 1); | 
|  | 583     if (rv != SECSuccess) goto loser; | 
|  | 584     rv = ssl3_AppendNumberToItem(&plaintext, msWrapMech, 4); | 
|  | 585     if (rv != SECSuccess) goto loser; | 
|  | 586     rv = ssl3_AppendNumberToItem(&plaintext, ms_item.len, 2); | 
|  | 587     if (rv != SECSuccess) goto loser; | 
|  | 588     rv = ssl3_AppendToItem(&plaintext, ms_item.data, ms_item.len); | 
|  | 589     if (rv != SECSuccess) goto loser; | 
|  | 590 | 
|  | 591     /* client_identity */ | 
|  | 592     if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) { | 
|  | 593         rv = ssl3_AppendNumberToItem(&plaintext, CLIENT_AUTH_CERTIFICATE, 1); | 
|  | 594         if (rv != SECSuccess) goto loser; | 
|  | 595         rv = ssl3_AppendNumberToItem(&plaintext, | 
|  | 596             ss->sec.ci.sid->peerCert->derCert.len, 3); | 
|  | 597         if (rv != SECSuccess) goto loser; | 
|  | 598         rv = ssl3_AppendToItem(&plaintext, | 
|  | 599             ss->sec.ci.sid->peerCert->derCert.data, | 
|  | 600             ss->sec.ci.sid->peerCert->derCert.len); | 
|  | 601         if (rv != SECSuccess) goto loser; | 
|  | 602     } else { | 
|  | 603         rv = ssl3_AppendNumberToItem(&plaintext, 0, 1); | 
|  | 604         if (rv != SECSuccess) goto loser; | 
|  | 605     } | 
|  | 606 | 
|  | 607     /* timestamp */ | 
|  | 608     now = ssl_Time(); | 
|  | 609     rv = ssl3_AppendNumberToItem(&plaintext, now, | 
|  | 610         sizeof(ticket.ticket_lifetime_hint)); | 
|  | 611     if (rv != SECSuccess) goto loser; | 
|  | 612 | 
|  | 613     PORT_Assert(plaintext.len == padding_length); | 
|  | 614     for (i = 0; i < padding_length; i++) | 
|  | 615         plaintext.data[i] = (unsigned char)padding_length; | 
|  | 616 | 
|  | 617     if (SECITEM_AllocItem(NULL, &ciphertext, ciphertext_length) == NULL) { | 
|  | 618         rv = SECFailure; | 
|  | 619         goto loser; | 
|  | 620     } | 
|  | 621 | 
|  | 622     /* Generate encrypted portion of ticket. */ | 
|  | 623     if (ss->opt.bypassPKCS11) { | 
|  | 624         aes_ctx = (AESContext *)aes_ctx_buf; | 
|  | 625         rv = AES_InitContext(aes_ctx, aes_key, aes_key_length, iv, | 
|  | 626             NSS_AES_CBC, 1, AES_BLOCK_SIZE); | 
|  | 627         if (rv != SECSuccess) goto loser; | 
|  | 628 | 
|  | 629         rv = AES_Encrypt(aes_ctx, ciphertext.data, &ciphertext.len, | 
|  | 630             ciphertext.len, plaintext_item.data, | 
|  | 631             plaintext_item.len); | 
|  | 632         if (rv != SECSuccess) goto loser; | 
|  | 633     } else { | 
|  | 634         aes_ctx_pkcs11 = PK11_CreateContextBySymKey(cipherMech, | 
|  | 635             CKA_ENCRYPT, aes_key_pkcs11, &ivItem); | 
|  | 636         if (!aes_ctx_pkcs11) | 
|  | 637             goto loser; | 
|  | 638 | 
|  | 639         rv = PK11_CipherOp(aes_ctx_pkcs11, ciphertext.data, | 
|  | 640             (int *)&ciphertext.len, ciphertext.len, | 
|  | 641             plaintext_item.data, plaintext_item.len); | 
|  | 642         PK11_Finalize(aes_ctx_pkcs11); | 
|  | 643         PK11_DestroyContext(aes_ctx_pkcs11, PR_TRUE); | 
|  | 644         if (rv != SECSuccess) goto loser; | 
|  | 645     } | 
|  | 646 | 
|  | 647     /* Convert ciphertext length to network order. */ | 
|  | 648     length_buf[0] = (ciphertext.len >> 8) & 0xff; | 
|  | 649     length_buf[1] = (ciphertext.len     ) & 0xff; | 
|  | 650 | 
|  | 651     /* Compute MAC. */ | 
|  | 652     if (ss->opt.bypassPKCS11) { | 
|  | 653         hmac_ctx = (HMACContext *)hmac_ctx_buf; | 
|  | 654         hashObj = HASH_GetRawHashObject(HASH_AlgSHA256); | 
|  | 655         if (HMAC_Init(hmac_ctx, hashObj, mac_key, | 
|  | 656                 mac_key_length, PR_FALSE) != SECSuccess) | 
|  | 657             goto loser; | 
|  | 658 | 
|  | 659         HMAC_Begin(hmac_ctx); | 
|  | 660         HMAC_Update(hmac_ctx, key_name, SESS_TICKET_KEY_NAME_LEN); | 
|  | 661         HMAC_Update(hmac_ctx, iv, sizeof(iv)); | 
|  | 662         HMAC_Update(hmac_ctx, (unsigned char *)length_buf, 2); | 
|  | 663         HMAC_Update(hmac_ctx, ciphertext.data, ciphertext.len); | 
|  | 664         HMAC_Finish(hmac_ctx, computed_mac, &computed_mac_length, | 
|  | 665             sizeof(computed_mac)); | 
|  | 666     } else { | 
|  | 667         SECItem macParam; | 
|  | 668         macParam.data = NULL; | 
|  | 669         macParam.len = 0; | 
|  | 670         hmac_ctx_pkcs11 = PK11_CreateContextBySymKey(macMech, | 
|  | 671             CKA_SIGN, mac_key_pkcs11, &macParam); | 
|  | 672         if (!hmac_ctx_pkcs11) | 
|  | 673             goto loser; | 
|  | 674 | 
|  | 675         rv = PK11_DigestBegin(hmac_ctx_pkcs11); | 
|  | 676         rv = PK11_DigestOp(hmac_ctx_pkcs11, key_name, | 
|  | 677             SESS_TICKET_KEY_NAME_LEN); | 
|  | 678         rv = PK11_DigestOp(hmac_ctx_pkcs11, iv, sizeof(iv)); | 
|  | 679         rv = PK11_DigestOp(hmac_ctx_pkcs11, (unsigned char *)length_buf, 2); | 
|  | 680         rv = PK11_DigestOp(hmac_ctx_pkcs11, ciphertext.data, ciphertext.len); | 
|  | 681         rv = PK11_DigestFinal(hmac_ctx_pkcs11, computed_mac, | 
|  | 682             &computed_mac_length, sizeof(computed_mac)); | 
|  | 683         PK11_DestroyContext(hmac_ctx_pkcs11, PR_TRUE); | 
|  | 684         if (rv != SECSuccess) goto loser; | 
|  | 685     } | 
|  | 686 | 
|  | 687     /* Serialize the handshake message. */ | 
|  | 688     rv = ssl3_AppendHandshakeHeader(ss, new_session_ticket, message_length); | 
|  | 689     if (rv != SECSuccess) goto loser; | 
|  | 690 | 
|  | 691     rv = ssl3_AppendHandshakeNumber(ss, ticket.ticket_lifetime_hint, | 
|  | 692         sizeof(ticket.ticket_lifetime_hint)); | 
|  | 693     if (rv != SECSuccess) goto loser; | 
|  | 694 | 
|  | 695     rv = ssl3_AppendHandshakeNumber(ss, | 
|  | 696         message_length - sizeof(ticket.ticket_lifetime_hint) - 2, 2); | 
|  | 697     if (rv != SECSuccess) goto loser; | 
|  | 698 | 
|  | 699     rv = ssl3_AppendHandshake(ss, key_name, SESS_TICKET_KEY_NAME_LEN); | 
|  | 700     if (rv != SECSuccess) goto loser; | 
|  | 701 | 
|  | 702     rv = ssl3_AppendHandshake(ss, iv, sizeof(iv)); | 
|  | 703     if (rv != SECSuccess) goto loser; | 
|  | 704 | 
|  | 705     rv = ssl3_AppendHandshakeVariable(ss, ciphertext.data, ciphertext.len, 2); | 
|  | 706     if (rv != SECSuccess) goto loser; | 
|  | 707 | 
|  | 708     rv = ssl3_AppendHandshake(ss, computed_mac, computed_mac_length); | 
|  | 709     if (rv != SECSuccess) goto loser; | 
|  | 710 | 
|  | 711 loser: | 
|  | 712     if (plaintext_item.data) | 
|  | 713         SECITEM_FreeItem(&plaintext_item, PR_FALSE); | 
|  | 714     if (ciphertext.data) | 
|  | 715         SECITEM_FreeItem(&ciphertext, PR_FALSE); | 
|  | 716 | 
|  | 717     return rv; | 
|  | 718 } | 
|  | 719 | 
|  | 720 /* When a client receives a SessionTicket extension a NewSessionTicket | 
|  | 721  * message is expected during the handshake. | 
|  | 722  */ | 
|  | 723 SECStatus | 
|  | 724 ssl3_ClientHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, | 
|  | 725                                   SECItem *data) | 
|  | 726 { | 
|  | 727     if (data->len != 0) | 
|  | 728         return SECFailure; | 
|  | 729 | 
|  | 730     /* Keep track of negotiated extensions. */ | 
|  | 731     ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; | 
|  | 732     return SECSuccess; | 
|  | 733 } | 
|  | 734 | 
|  | 735 SECStatus | 
|  | 736 ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, | 
|  | 737                                   SECItem *data) | 
|  | 738 { | 
|  | 739     SECStatus rv; | 
|  | 740     SECItem *decrypted_state = NULL; | 
|  | 741     SessionTicket *parsed_session_ticket = NULL; | 
|  | 742     sslSessionID *sid = NULL; | 
|  | 743     SSL3Statistics *ssl3stats; | 
|  | 744 | 
|  | 745     /* Ignore the SessionTicket extension if processing is disabled. */ | 
|  | 746     if (!ss->opt.enableSessionTickets) | 
|  | 747         return SECSuccess; | 
|  | 748 | 
|  | 749     /* Keep track of negotiated extensions. */ | 
|  | 750     ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; | 
|  | 751 | 
|  | 752     /* Parse the received ticket sent in by the client.  We are | 
|  | 753      * lenient about some parse errors, falling back to a fullshake | 
|  | 754      * instead of terminating the current connection. | 
|  | 755      */ | 
|  | 756     if (data->len == 0) { | 
|  | 757         ss->xtnData.emptySessionTicket = PR_TRUE; | 
|  | 758     } else { | 
|  | 759         int                    i; | 
|  | 760         SECItem                extension_data; | 
|  | 761         EncryptedSessionTicket enc_session_ticket; | 
|  | 762         unsigned char          computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH]; | 
|  | 763         unsigned int           computed_mac_length; | 
|  | 764         const SECHashObject   *hashObj; | 
|  | 765         const unsigned char   *aes_key; | 
|  | 766         const unsigned char   *mac_key; | 
|  | 767         PK11SymKey            *aes_key_pkcs11; | 
|  | 768         PK11SymKey            *mac_key_pkcs11; | 
|  | 769         PRUint32               aes_key_length; | 
|  | 770         PRUint32               mac_key_length; | 
|  | 771         PRUint64               hmac_ctx_buf[MAX_MAC_CONTEXT_LLONGS]; | 
|  | 772         HMACContext           *hmac_ctx; | 
|  | 773         PK11Context           *hmac_ctx_pkcs11; | 
|  | 774         CK_MECHANISM_TYPE      macMech = CKM_SHA256_HMAC; | 
|  | 775         PRUint64               aes_ctx_buf[MAX_CIPHER_CONTEXT_LLONGS]; | 
|  | 776         AESContext            *aes_ctx; | 
|  | 777         PK11Context           *aes_ctx_pkcs11; | 
|  | 778         CK_MECHANISM_TYPE      cipherMech = CKM_AES_CBC; | 
|  | 779         unsigned char *        padding; | 
|  | 780         PRUint32               padding_length; | 
|  | 781         unsigned char         *buffer; | 
|  | 782         unsigned int           buffer_len; | 
|  | 783         PRInt32                temp; | 
|  | 784         SECItem                cert_item; | 
|  | 785 | 
|  | 786         /* Turn off stateless session resumption if the client sends a | 
|  | 787          * SessionTicket extension, even if the extension turns out to be | 
|  | 788          * malformed (ss->sec.ci.sid is non-NULL when doing session | 
|  | 789          * renegotiation.) | 
|  | 790          */ | 
|  | 791         if (ss->sec.ci.sid != NULL) { | 
|  | 792             ss->sec.uncache(ss->sec.ci.sid); | 
|  | 793             ssl_FreeSID(ss->sec.ci.sid); | 
|  | 794             ss->sec.ci.sid = NULL; | 
|  | 795         } | 
|  | 796 | 
|  | 797         extension_data.data = data->data; /* Keep a copy for future use. */ | 
|  | 798         extension_data.len = data->len; | 
|  | 799 | 
|  | 800         if (ssl3_ParseEncryptedSessionTicket(ss, data, &enc_session_ticket) | 
|  | 801             != SECSuccess) | 
|  | 802             return SECFailure; | 
|  | 803 | 
|  | 804         /* Get session ticket keys. */ | 
|  | 805         if (ss->opt.bypassPKCS11) { | 
|  | 806             rv = ssl3_GetSessionTicketKeys(&aes_key, &aes_key_length, | 
|  | 807                 &mac_key, &mac_key_length); | 
|  | 808         } else { | 
|  | 809             rv = ssl3_GetSessionTicketKeysPKCS11(ss, &aes_key_pkcs11, | 
|  | 810                 &mac_key_pkcs11); | 
|  | 811         } | 
|  | 812         if (rv != SECSuccess) { | 
|  | 813             SSL_DBG(("%d: SSL[%d]: Unable to get/generate session ticket keys.", | 
|  | 814                         SSL_GETPID(), ss->fd)); | 
|  | 815             goto loser; | 
|  | 816         } | 
|  | 817 | 
|  | 818         /* If the ticket sent by the client was generated under a key different | 
|  | 819          * from the one we have, bypass ticket processing. | 
|  | 820          */ | 
|  | 821         if (PORT_Memcmp(enc_session_ticket.key_name, key_name, | 
|  | 822                 SESS_TICKET_KEY_NAME_LEN) != 0) { | 
|  | 823             SSL_DBG(("%d: SSL[%d]: Session ticket key_name sent mismatch.", | 
|  | 824                         SSL_GETPID(), ss->fd)); | 
|  | 825             goto no_ticket; | 
|  | 826         } | 
|  | 827 | 
|  | 828         /* Verify the MAC on the ticket.  MAC verification may also | 
|  | 829          * fail if the MAC key has been recently refreshed. | 
|  | 830          */ | 
|  | 831         if (ss->opt.bypassPKCS11) { | 
|  | 832             hmac_ctx = (HMACContext *)hmac_ctx_buf; | 
|  | 833             hashObj = HASH_GetRawHashObject(HASH_AlgSHA256); | 
|  | 834             if (HMAC_Init(hmac_ctx, hashObj, mac_key, | 
|  | 835                     sizeof(session_ticket_mac_key), PR_FALSE) != SECSuccess) | 
|  | 836                 goto no_ticket; | 
|  | 837             HMAC_Begin(hmac_ctx); | 
|  | 838             HMAC_Update(hmac_ctx, extension_data.data, | 
|  | 839                 extension_data.len - TLS_EX_SESS_TICKET_MAC_LENGTH); | 
|  | 840             if (HMAC_Finish(hmac_ctx, computed_mac, &computed_mac_length, | 
|  | 841                     sizeof(computed_mac)) != SECSuccess) | 
|  | 842                 goto no_ticket; | 
|  | 843         } else { | 
|  | 844             SECItem macParam; | 
|  | 845             macParam.data = NULL; | 
|  | 846             macParam.len = 0; | 
|  | 847             hmac_ctx_pkcs11 = PK11_CreateContextBySymKey(macMech, | 
|  | 848                 CKA_SIGN, mac_key_pkcs11, &macParam); | 
|  | 849             if (!hmac_ctx_pkcs11) { | 
|  | 850                 SSL_DBG(("%d: SSL[%d]: Unable to create HMAC context: %d.", | 
|  | 851                             SSL_GETPID(), ss->fd, PORT_GetError())); | 
|  | 852                 goto no_ticket; | 
|  | 853             } else { | 
|  | 854                 SSL_DBG(("%d: SSL[%d]: Successfully created HMAC context.", | 
|  | 855                             SSL_GETPID(), ss->fd)); | 
|  | 856             } | 
|  | 857             rv = PK11_DigestBegin(hmac_ctx_pkcs11); | 
|  | 858             rv = PK11_DigestOp(hmac_ctx_pkcs11, extension_data.data, | 
|  | 859                 extension_data.len - TLS_EX_SESS_TICKET_MAC_LENGTH); | 
|  | 860             if (rv != SECSuccess) { | 
|  | 861                 PK11_DestroyContext(hmac_ctx_pkcs11, PR_TRUE); | 
|  | 862                 goto no_ticket; | 
|  | 863             } | 
|  | 864             rv = PK11_DigestFinal(hmac_ctx_pkcs11, computed_mac, | 
|  | 865                 &computed_mac_length, sizeof(computed_mac)); | 
|  | 866             PK11_DestroyContext(hmac_ctx_pkcs11, PR_TRUE); | 
|  | 867             if (rv != SECSuccess) | 
|  | 868                 goto no_ticket; | 
|  | 869         } | 
|  | 870         if (NSS_SecureMemcmp(computed_mac, enc_session_ticket.mac, | 
|  | 871                 computed_mac_length) != 0) { | 
|  | 872             SSL_DBG(("%d: SSL[%d]: Session ticket MAC mismatch.", | 
|  | 873                         SSL_GETPID(), ss->fd)); | 
|  | 874             goto no_ticket; | 
|  | 875         } | 
|  | 876 | 
|  | 877         /* We ignore key_name for now. | 
|  | 878          * This is ok as MAC verification succeeded. | 
|  | 879          */ | 
|  | 880 | 
|  | 881         /* Decrypt the ticket. */ | 
|  | 882 | 
|  | 883         /* Plaintext is shorter than the ciphertext due to padding. */ | 
|  | 884         decrypted_state = SECITEM_AllocItem(NULL, NULL, | 
|  | 885             enc_session_ticket.encrypted_state.len); | 
|  | 886 | 
|  | 887         if (ss->opt.bypassPKCS11) { | 
|  | 888             aes_ctx = (AESContext *)aes_ctx_buf; | 
|  | 889             rv = AES_InitContext(aes_ctx, aes_key, | 
|  | 890                 sizeof(session_ticket_enc_key), enc_session_ticket.iv, | 
|  | 891                 NSS_AES_CBC, 0,AES_BLOCK_SIZE); | 
|  | 892             if (rv != SECSuccess) { | 
|  | 893                 SSL_DBG(("%d: SSL[%d]: Unable to create AES context.", | 
|  | 894                             SSL_GETPID(), ss->fd)); | 
|  | 895                 goto no_ticket; | 
|  | 896             } | 
|  | 897 | 
|  | 898             rv = AES_Decrypt(aes_ctx, decrypted_state->data, | 
|  | 899                 &decrypted_state->len, decrypted_state->len, | 
|  | 900                 enc_session_ticket.encrypted_state.data, | 
|  | 901                 enc_session_ticket.encrypted_state.len); | 
|  | 902             if (rv != SECSuccess) | 
|  | 903                 goto no_ticket; | 
|  | 904         } else { | 
|  | 905             SECItem ivItem; | 
|  | 906             ivItem.data = enc_session_ticket.iv; | 
|  | 907             ivItem.len = AES_BLOCK_SIZE; | 
|  | 908             aes_ctx_pkcs11 = PK11_CreateContextBySymKey(cipherMech, | 
|  | 909                 CKA_DECRYPT, aes_key_pkcs11, &ivItem); | 
|  | 910             if (!aes_ctx_pkcs11) { | 
|  | 911                 SSL_DBG(("%d: SSL[%d]: Unable to create AES context.", | 
|  | 912                             SSL_GETPID(), ss->fd)); | 
|  | 913                 goto no_ticket; | 
|  | 914             } | 
|  | 915 | 
|  | 916             rv = PK11_CipherOp(aes_ctx_pkcs11, decrypted_state->data, | 
|  | 917                 (int *)&decrypted_state->len, decrypted_state->len, | 
|  | 918                 enc_session_ticket.encrypted_state.data, | 
|  | 919                 enc_session_ticket.encrypted_state.len); | 
|  | 920             PK11_Finalize(aes_ctx_pkcs11); | 
|  | 921             PK11_DestroyContext(aes_ctx_pkcs11, PR_TRUE); | 
|  | 922             if (rv != SECSuccess) | 
|  | 923                 goto no_ticket; | 
|  | 924         } | 
|  | 925 | 
|  | 926         /* Check padding. */ | 
|  | 927         padding_length = | 
|  | 928             (PRUint32)decrypted_state->data[decrypted_state->len - 1]; | 
|  | 929         if (padding_length == 0 || padding_length > AES_BLOCK_SIZE) | 
|  | 930             goto no_ticket; | 
|  | 931 | 
|  | 932         padding = &decrypted_state->data[decrypted_state->len - padding_length]; | 
|  | 933         for (i = 0; i < padding_length; i++, padding++) { | 
|  | 934             if (padding_length != (PRUint32)*padding) | 
|  | 935                 goto no_ticket; | 
|  | 936         } | 
|  | 937 | 
|  | 938         /* Deserialize session state. */ | 
|  | 939         buffer = decrypted_state->data; | 
|  | 940         buffer_len = decrypted_state->len; | 
|  | 941 | 
|  | 942         parsed_session_ticket = PORT_ZAlloc(sizeof(SessionTicket)); | 
|  | 943         if (parsed_session_ticket == NULL) { | 
|  | 944             rv = SECFailure; | 
|  | 945             goto loser; | 
|  | 946         } | 
|  | 947 | 
|  | 948         /* Read ticket_version (which is ignored for now.) */ | 
|  | 949         temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len); | 
|  | 950         if (temp < 0) goto no_ticket; | 
|  | 951         parsed_session_ticket->ticket_version = (SSL3ProtocolVersion)temp; | 
|  | 952 | 
|  | 953         /* Read SSLVersion. */ | 
|  | 954         temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len); | 
|  | 955         if (temp < 0) goto no_ticket; | 
|  | 956         parsed_session_ticket->ssl_version = (SSL3ProtocolVersion)temp; | 
|  | 957 | 
|  | 958         /* Read cipher_suite. */ | 
|  | 959         temp =  ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len); | 
|  | 960         if (temp < 0) goto no_ticket; | 
|  | 961         parsed_session_ticket->cipher_suite = (ssl3CipherSuite)temp; | 
|  | 962 | 
|  | 963         /* Read compression_method. */ | 
|  | 964         temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); | 
|  | 965         if (temp < 0) goto no_ticket; | 
|  | 966         parsed_session_ticket->compression_method = (SSLCompressionMethod)temp; | 
|  | 967 | 
|  | 968         /* Read cipher spec parameters. */ | 
|  | 969         temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); | 
|  | 970         if (temp < 0) goto no_ticket; | 
|  | 971         parsed_session_ticket->authAlgorithm = (SSLSignType)temp; | 
|  | 972         temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len); | 
|  | 973         if (temp < 0) goto no_ticket; | 
|  | 974         parsed_session_ticket->authKeyBits = (PRUint32)temp; | 
|  | 975         temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); | 
|  | 976         if (temp < 0) goto no_ticket; | 
|  | 977         parsed_session_ticket->keaType = (SSLKEAType)temp; | 
|  | 978         temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len); | 
|  | 979         if (temp < 0) goto no_ticket; | 
|  | 980         parsed_session_ticket->keaKeyBits = (PRUint32)temp; | 
|  | 981 | 
|  | 982         /* Read wrapped master_secret. */ | 
|  | 983         temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); | 
|  | 984         if (temp < 0) goto no_ticket; | 
|  | 985         parsed_session_ticket->ms_is_wrapped = (PRBool)temp; | 
|  | 986 | 
|  | 987         temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); | 
|  | 988         if (temp < 0) goto no_ticket; | 
|  | 989         parsed_session_ticket->exchKeyType = (SSL3KEAType)temp; | 
|  | 990 | 
|  | 991         temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len); | 
|  | 992         if (temp < 0) goto no_ticket; | 
|  | 993         parsed_session_ticket->msWrapMech = (CK_MECHANISM_TYPE)temp; | 
|  | 994 | 
|  | 995         temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len); | 
|  | 996         if (temp < 0) goto no_ticket; | 
|  | 997         parsed_session_ticket->ms_length = (PRUint16)temp; | 
|  | 998         if (parsed_session_ticket->ms_length == 0 ||  /* sanity check MS. */ | 
|  | 999             parsed_session_ticket->ms_length > | 
|  | 1000             sizeof(parsed_session_ticket->master_secret)) | 
|  | 1001             goto no_ticket; | 
|  | 1002 | 
|  | 1003         /* Allow for the wrapped master secret to be longer. */ | 
|  | 1004         if (buffer_len < sizeof(SSL3_MASTER_SECRET_LENGTH)) | 
|  | 1005             goto no_ticket; | 
|  | 1006         PORT_Memcpy(parsed_session_ticket->master_secret, buffer, | 
|  | 1007             parsed_session_ticket->ms_length); | 
|  | 1008         buffer += parsed_session_ticket->ms_length; | 
|  | 1009         buffer_len -= parsed_session_ticket->ms_length; | 
|  | 1010 | 
|  | 1011         /* Read client_identity */ | 
|  | 1012         temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); | 
|  | 1013         if (temp < 0) | 
|  | 1014             goto no_ticket; | 
|  | 1015         parsed_session_ticket->client_identity.client_auth_type = | 
|  | 1016             (ClientAuthenticationType)temp; | 
|  | 1017         switch(parsed_session_ticket->client_identity.client_auth_type) { | 
|  | 1018             case CLIENT_AUTH_ANONYMOUS: | 
|  | 1019                 break; | 
|  | 1020             case CLIENT_AUTH_CERTIFICATE: | 
|  | 1021                 rv = ssl3_ConsumeHandshakeVariable(ss, &cert_item, 3, | 
|  | 1022                     &buffer, &buffer_len); | 
|  | 1023                 if (rv != SECSuccess) goto no_ticket; | 
|  | 1024                 rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->peer_cert, | 
|  | 1025                     &cert_item); | 
|  | 1026                 if (rv != SECSuccess) goto no_ticket; | 
|  | 1027                 break; | 
|  | 1028             default: | 
|  | 1029                 goto no_ticket; | 
|  | 1030         } | 
|  | 1031         /* Read timestamp. */ | 
|  | 1032         temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len); | 
|  | 1033         if (temp < 0) | 
|  | 1034             goto no_ticket; | 
|  | 1035         parsed_session_ticket->timestamp = (PRUint32)temp; | 
|  | 1036 | 
|  | 1037         /* Done parsing.  Check that all bytes have been consumed. */ | 
|  | 1038         if (buffer_len != padding_length) | 
|  | 1039             goto no_ticket; | 
|  | 1040 | 
|  | 1041         /* Use the ticket if it has not expired, otherwise free the allocated | 
|  | 1042          * memory since the ticket is of no use. | 
|  | 1043          */ | 
|  | 1044         if (parsed_session_ticket->timestamp != 0 && | 
|  | 1045             parsed_session_ticket->timestamp + | 
|  | 1046             TLS_EX_SESS_TICKET_LIFETIME_HINT > ssl_Time()) { | 
|  | 1047 | 
|  | 1048             sid = ssl3_NewSessionID(ss, PR_TRUE); | 
|  | 1049             if (sid == NULL) { | 
|  | 1050                 rv = SECFailure; | 
|  | 1051                 goto loser; | 
|  | 1052             } | 
|  | 1053 | 
|  | 1054             /* Copy over parameters. */ | 
|  | 1055             sid->version = parsed_session_ticket->ssl_version; | 
|  | 1056             sid->u.ssl3.cipherSuite = parsed_session_ticket->cipher_suite; | 
|  | 1057             sid->u.ssl3.compression = parsed_session_ticket->compression_method; | 
|  | 1058             sid->authAlgorithm = parsed_session_ticket->authAlgorithm; | 
|  | 1059             sid->authKeyBits = parsed_session_ticket->authKeyBits; | 
|  | 1060             sid->keaType = parsed_session_ticket->keaType; | 
|  | 1061             sid->keaKeyBits = parsed_session_ticket->keaKeyBits; | 
|  | 1062 | 
|  | 1063             /* Copy master secret. */ | 
|  | 1064             if (ss->opt.bypassPKCS11 && | 
|  | 1065                     parsed_session_ticket->ms_is_wrapped) | 
|  | 1066                 goto no_ticket; | 
|  | 1067             if (parsed_session_ticket->ms_length > | 
|  | 1068                     sizeof(sid->u.ssl3.keys.wrapped_master_secret)) | 
|  | 1069                 goto no_ticket; | 
|  | 1070             PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret, | 
|  | 1071                 parsed_session_ticket->master_secret, | 
|  | 1072                 parsed_session_ticket->ms_length); | 
|  | 1073             sid->u.ssl3.keys.wrapped_master_secret_len = | 
|  | 1074                 parsed_session_ticket->ms_length; | 
|  | 1075             sid->u.ssl3.exchKeyType = parsed_session_ticket->exchKeyType; | 
|  | 1076             sid->u.ssl3.masterWrapMech = parsed_session_ticket->msWrapMech; | 
|  | 1077             sid->u.ssl3.keys.msIsWrapped = | 
|  | 1078                 parsed_session_ticket->ms_is_wrapped; | 
|  | 1079             sid->u.ssl3.masterValid    = PR_TRUE; | 
|  | 1080             sid->u.ssl3.keys.resumable = PR_TRUE; | 
|  | 1081 | 
|  | 1082             /* Copy over client cert from session ticket if there is one. */ | 
|  | 1083             if (parsed_session_ticket->peer_cert.data != NULL) { | 
|  | 1084                 if (sid->peerCert != NULL) | 
|  | 1085                     CERT_DestroyCertificate(sid->peerCert); | 
|  | 1086                 sid->peerCert = CERT_NewTempCertificate(ss->dbHandle, | 
|  | 1087                     &parsed_session_ticket->peer_cert, NULL, PR_FALSE, PR_TRUE); | 
|  | 1088                 if (sid->peerCert == NULL) { | 
|  | 1089                     rv = SECFailure; | 
|  | 1090                     goto loser; | 
|  | 1091                 } | 
|  | 1092             } | 
|  | 1093             ss->statelessResume = PR_TRUE; | 
|  | 1094             ss->sec.ci.sid = sid; | 
|  | 1095         } | 
|  | 1096     } | 
|  | 1097 | 
|  | 1098     if (0) { | 
|  | 1099 no_ticket: | 
|  | 1100         SSL_DBG(("%d: SSL[%d]: Session ticket parsing failed.", | 
|  | 1101                         SSL_GETPID(), ss->fd)); | 
|  | 1102         ssl3stats = SSL_GetStatistics(); | 
|  | 1103         SSL_AtomicIncrementLong(& ssl3stats->hch_sid_ticket_parse_failures ); | 
|  | 1104         if (sid) { | 
|  | 1105             ssl_FreeSID(sid); | 
|  | 1106             sid = NULL; | 
|  | 1107         } | 
|  | 1108     } | 
|  | 1109     rv = SECSuccess; | 
|  | 1110 | 
|  | 1111 loser: | 
|  | 1112     if (decrypted_state != NULL) { | 
|  | 1113         SECITEM_FreeItem(decrypted_state, PR_TRUE); | 
|  | 1114         decrypted_state = NULL; | 
|  | 1115     } | 
|  | 1116 | 
|  | 1117     if (parsed_session_ticket != NULL) { | 
|  | 1118         if (parsed_session_ticket->peer_cert.data) { | 
|  | 1119             SECITEM_FreeItem(&parsed_session_ticket->peer_cert, PR_FALSE); | 
|  | 1120         } | 
|  | 1121         PORT_ZFree(parsed_session_ticket, sizeof(SessionTicket)); | 
|  | 1122     } | 
|  | 1123 | 
|  | 1124     return rv; | 
|  | 1125 } | 
|  | 1126 | 
|  | 1127 /* | 
|  | 1128  * Read bytes.  Using this function means the SECItem structure | 
|  | 1129  * cannot be freed.  The caller is expected to call this function | 
|  | 1130  * on a shallow copy of the structure. | 
|  | 1131  */ | 
|  | 1132 static SECStatus | 
|  | 1133 ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes) | 
|  | 1134 { | 
|  | 1135     if (bytes > item->len) | 
|  | 1136         return SECFailure; | 
|  | 1137 | 
|  | 1138     *buf = item->data; | 
|  | 1139     item->data += bytes; | 
|  | 1140     item->len -= bytes; | 
|  | 1141     return SECSuccess; | 
|  | 1142 } | 
|  | 1143 | 
|  | 1144 static SECStatus | 
|  | 1145 ssl3_ParseEncryptedSessionTicket(sslSocket *ss, SECItem *data, | 
|  | 1146                                  EncryptedSessionTicket *enc_session_ticket) | 
|  | 1147 { | 
|  | 1148     if (ssl3_ConsumeFromItem(data, &enc_session_ticket->key_name, | 
|  | 1149             SESS_TICKET_KEY_NAME_LEN) != SECSuccess) | 
|  | 1150         return SECFailure; | 
|  | 1151     if (ssl3_ConsumeFromItem(data, &enc_session_ticket->iv, | 
|  | 1152             AES_BLOCK_SIZE) != SECSuccess) | 
|  | 1153         return SECFailure; | 
|  | 1154     if (ssl3_ConsumeHandshakeVariable(ss, &enc_session_ticket->encrypted_state, | 
|  | 1155             2, &data->data, &data->len) != SECSuccess) | 
|  | 1156         return SECFailure; | 
|  | 1157     if (ssl3_ConsumeFromItem(data, &enc_session_ticket->mac, | 
|  | 1158             TLS_EX_SESS_TICKET_MAC_LENGTH) != SECSuccess) | 
|  | 1159         return SECFailure; | 
|  | 1160     if (data->len != 0)  /* Make sure that we have consumed all bytes. */ | 
|  | 1161         return SECFailure; | 
|  | 1162 | 
|  | 1163     return SECSuccess; | 
|  | 1164 } | 
|  | 1165 | 
|  | 1166 /* go through hello extensions in buffer "b". | 
|  | 1167  * For each one, find the extension handler in the table, and | 
|  | 1168  * if present, invoke that handler. | 
|  | 1169  * Servers ignore any extensions with unknown extension types. | 
|  | 1170  * Clients reject any extensions with unadvertised extension types. | 
|  | 1171  */ | 
|  | 1172 SECStatus | 
|  | 1173 ssl3_HandleHelloExtensions(sslSocket *ss, SSL3Opaque **b, PRUint32 *length) | 
|  | 1174 { | 
|  | 1175     const ssl3HelloExtensionHandler * handlers = | 
|  | 1176         ss->sec.isServer ? clientHelloHandlers : serverHelloHandlers; | 
|  | 1177 | 
|  | 1178     while (*length) { | 
|  | 1179         const ssl3HelloExtensionHandler * handler; | 
|  | 1180         SECStatus rv; | 
|  | 1181         PRInt32   extension_type; | 
|  | 1182         SECItem   extension_data; | 
|  | 1183 | 
|  | 1184         /* Get the extension's type field */ | 
|  | 1185         extension_type = ssl3_ConsumeHandshakeNumber(ss, 2, b, length); | 
|  | 1186         if (extension_type < 0)  /* failure to decode extension_type */ | 
|  | 1187             return SECFailure;   /* alert already sent */ | 
|  | 1188 | 
|  | 1189         /* get the data for this extension, so we can pass it or skip it. */ | 
|  | 1190         rv = ssl3_ConsumeHandshakeVariable(ss, &extension_data, 2, b, length); | 
|  | 1191         if (rv != SECSuccess) | 
|  | 1192             return rv; | 
|  | 1193 | 
|  | 1194         /* Check whether the server sent an extension which was not advertised | 
|  | 1195          * in the ClientHello. | 
|  | 1196          */ | 
|  | 1197         if (!ss->sec.isServer && | 
|  | 1198             !ssl3_ClientExtensionAdvertised(ss, extension_type)) | 
|  | 1199             return SECFailure;  /* TODO: send unsupported_extension alert */ | 
|  | 1200 | 
|  | 1201         /* Check whether an extension has been sent multiple times. */ | 
|  | 1202         if (ssl3_ExtensionNegotiated(ss, extension_type)) | 
|  | 1203             return SECFailure; | 
|  | 1204 | 
|  | 1205         /* find extension_type in table of Hello Extension Handlers */ | 
|  | 1206         for (handler = handlers; handler->ex_type >= 0; handler++) { | 
|  | 1207             /* if found, call this handler */ | 
|  | 1208             if (handler->ex_type == extension_type) { | 
|  | 1209                 rv = (*handler->ex_handler)(ss, (PRUint16)extension_type, | 
|  | 1210                                                         &extension_data); | 
|  | 1211                 /* Ignore this result */ | 
|  | 1212                 /* Treat all bad extensions as unrecognized types. */ | 
|  | 1213                 break; | 
|  | 1214             } | 
|  | 1215         } | 
|  | 1216     } | 
|  | 1217     return SECSuccess; | 
|  | 1218 } | 
|  | 1219 | 
|  | 1220 /* Add a callback function to the table of senders of server hello extensions. | 
|  | 1221  */ | 
|  | 1222 SECStatus | 
|  | 1223 ssl3_RegisterServerHelloExtensionSender(sslSocket *ss, PRUint16 ex_type, | 
|  | 1224                                         ssl3HelloExtensionSenderFunc cb) | 
|  | 1225 { | 
|  | 1226     int i; | 
|  | 1227     ssl3HelloExtensionSender *sender = &ss->xtnData.serverSenders[0]; | 
|  | 1228 | 
|  | 1229     for (i = 0; i < MAX_EXTENSIONS; ++i, ++sender) { | 
|  | 1230         if (!sender->ex_sender) { | 
|  | 1231             sender->ex_type   = ex_type; | 
|  | 1232             sender->ex_sender = cb; | 
|  | 1233             return SECSuccess; | 
|  | 1234         } | 
|  | 1235         /* detect duplicate senders */ | 
|  | 1236         PORT_Assert(sender->ex_type != ex_type); | 
|  | 1237         if (sender->ex_type == ex_type) { | 
|  | 1238             /* duplicate */ | 
|  | 1239             break; | 
|  | 1240         } | 
|  | 1241     } | 
|  | 1242     PORT_Assert(i < MAX_EXTENSIONS); /* table needs to grow */ | 
|  | 1243     PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | 
|  | 1244     return SECFailure; | 
|  | 1245 } | 
|  | 1246 | 
|  | 1247 /* call each of the extension senders and return the accumulated length */ | 
|  | 1248 PRInt32 | 
|  | 1249 ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, | 
|  | 1250                                const ssl3HelloExtensionSender *sender) | 
|  | 1251 { | 
|  | 1252     PRInt32 total_exten_len = 0; | 
|  | 1253     int i; | 
|  | 1254 | 
|  | 1255     if (!sender) | 
|  | 1256         sender = &clientHelloSenders[0]; | 
|  | 1257 | 
|  | 1258     for (i = 0; i < MAX_EXTENSIONS; ++i, ++sender) { | 
|  | 1259         if (sender->ex_sender) { | 
|  | 1260             PRInt32 extLen = (*sender->ex_sender)(ss, append, maxBytes); | 
|  | 1261             if (extLen < 0) | 
|  | 1262                 return -1; | 
|  | 1263             maxBytes        -= extLen; | 
|  | 1264             total_exten_len += extLen; | 
|  | 1265         } | 
|  | 1266     } | 
|  | 1267     return total_exten_len; | 
|  | 1268 } | 
| OLD | NEW | 
|---|