security/nss/lib/ssl/sslcon.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*
michael@0 2 * SSL v2 handshake functions, and functions common to SSL2 and SSL3.
michael@0 3 *
michael@0 4 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 5 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 7
michael@0 8 #include "nssrenam.h"
michael@0 9 #include "cert.h"
michael@0 10 #include "secitem.h"
michael@0 11 #include "sechash.h"
michael@0 12 #include "cryptohi.h" /* for SGN_ funcs */
michael@0 13 #include "keyhi.h" /* for SECKEY_ high level functions. */
michael@0 14 #include "ssl.h"
michael@0 15 #include "sslimpl.h"
michael@0 16 #include "sslproto.h"
michael@0 17 #include "ssl3prot.h"
michael@0 18 #include "sslerr.h"
michael@0 19 #include "pk11func.h"
michael@0 20 #include "prinit.h"
michael@0 21 #include "prtime.h" /* for PR_Now() */
michael@0 22
michael@0 23 static PRBool policyWasSet;
michael@0 24
michael@0 25 /* This ordered list is indexed by (SSL_CK_xx * 3) */
michael@0 26 /* Second and third bytes are MSB and LSB of master key length. */
michael@0 27 static const PRUint8 allCipherSuites[] = {
michael@0 28 0, 0, 0,
michael@0 29 SSL_CK_RC4_128_WITH_MD5, 0x00, 0x80,
michael@0 30 SSL_CK_RC4_128_EXPORT40_WITH_MD5, 0x00, 0x80,
michael@0 31 SSL_CK_RC2_128_CBC_WITH_MD5, 0x00, 0x80,
michael@0 32 SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, 0x00, 0x80,
michael@0 33 SSL_CK_IDEA_128_CBC_WITH_MD5, 0x00, 0x80,
michael@0 34 SSL_CK_DES_64_CBC_WITH_MD5, 0x00, 0x40,
michael@0 35 SSL_CK_DES_192_EDE3_CBC_WITH_MD5, 0x00, 0xC0,
michael@0 36 0, 0, 0
michael@0 37 };
michael@0 38
michael@0 39 #define ssl2_NUM_SUITES_IMPLEMENTED 6
michael@0 40
michael@0 41 /* This list is sent back to the client when the client-hello message
michael@0 42 * contains no overlapping ciphers, so the client can report what ciphers
michael@0 43 * are supported by the server. Unlike allCipherSuites (above), this list
michael@0 44 * is sorted by descending preference, not by cipherSuite number.
michael@0 45 */
michael@0 46 static const PRUint8 implementedCipherSuites[ssl2_NUM_SUITES_IMPLEMENTED * 3] = {
michael@0 47 SSL_CK_RC4_128_WITH_MD5, 0x00, 0x80,
michael@0 48 SSL_CK_RC2_128_CBC_WITH_MD5, 0x00, 0x80,
michael@0 49 SSL_CK_DES_192_EDE3_CBC_WITH_MD5, 0x00, 0xC0,
michael@0 50 SSL_CK_DES_64_CBC_WITH_MD5, 0x00, 0x40,
michael@0 51 SSL_CK_RC4_128_EXPORT40_WITH_MD5, 0x00, 0x80,
michael@0 52 SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, 0x00, 0x80
michael@0 53 };
michael@0 54
michael@0 55 typedef struct ssl2SpecsStr {
michael@0 56 PRUint8 nkm; /* do this many hashes to generate key material. */
michael@0 57 PRUint8 nkd; /* size of readKey and writeKey in bytes. */
michael@0 58 PRUint8 blockSize;
michael@0 59 PRUint8 blockShift;
michael@0 60 CK_MECHANISM_TYPE mechanism;
michael@0 61 PRUint8 keyLen; /* cipher symkey size in bytes. */
michael@0 62 PRUint8 pubLen; /* publicly reveal this many bytes of key. */
michael@0 63 PRUint8 ivLen; /* length of IV data at *ca. */
michael@0 64 } ssl2Specs;
michael@0 65
michael@0 66 static const ssl2Specs ssl_Specs[] = {
michael@0 67 /* NONE */
michael@0 68 { 0, 0, 0, 0, },
michael@0 69 /* SSL_CK_RC4_128_WITH_MD5 */
michael@0 70 { 2, 16, 1, 0, CKM_RC4, 16, 0, 0, },
michael@0 71 /* SSL_CK_RC4_128_EXPORT40_WITH_MD5 */
michael@0 72 { 2, 16, 1, 0, CKM_RC4, 16, 11, 0, },
michael@0 73 /* SSL_CK_RC2_128_CBC_WITH_MD5 */
michael@0 74 { 2, 16, 8, 3, CKM_RC2_CBC, 16, 0, 8, },
michael@0 75 /* SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5 */
michael@0 76 { 2, 16, 8, 3, CKM_RC2_CBC, 16, 11, 8, },
michael@0 77 /* SSL_CK_IDEA_128_CBC_WITH_MD5 */
michael@0 78 { 0, 0, 0, 0, },
michael@0 79 /* SSL_CK_DES_64_CBC_WITH_MD5 */
michael@0 80 { 1, 8, 8, 3, CKM_DES_CBC, 8, 0, 8, },
michael@0 81 /* SSL_CK_DES_192_EDE3_CBC_WITH_MD5 */
michael@0 82 { 3, 24, 8, 3, CKM_DES3_CBC, 24, 0, 8, },
michael@0 83 };
michael@0 84
michael@0 85 #define SET_ERROR_CODE /* reminder */
michael@0 86 #define TEST_FOR_FAILURE /* reminder */
michael@0 87
michael@0 88 /*
michael@0 89 ** Put a string tag in the library so that we can examine an executable
michael@0 90 ** and see what kind of security it supports.
michael@0 91 */
michael@0 92 const char *ssl_version = "SECURITY_VERSION:"
michael@0 93 " +us"
michael@0 94 " +export"
michael@0 95 #ifdef TRACE
michael@0 96 " +trace"
michael@0 97 #endif
michael@0 98 #ifdef DEBUG
michael@0 99 " +debug"
michael@0 100 #endif
michael@0 101 ;
michael@0 102
michael@0 103 const char * const ssl_cipherName[] = {
michael@0 104 "unknown",
michael@0 105 "RC4",
michael@0 106 "RC4-Export",
michael@0 107 "RC2-CBC",
michael@0 108 "RC2-CBC-Export",
michael@0 109 "IDEA-CBC",
michael@0 110 "DES-CBC",
michael@0 111 "DES-EDE3-CBC",
michael@0 112 "unknown",
michael@0 113 "unknown", /* was fortezza, NO LONGER USED */
michael@0 114 };
michael@0 115
michael@0 116
michael@0 117 /* bit-masks, showing which SSLv2 suites are allowed.
michael@0 118 * lsb corresponds to first cipher suite in allCipherSuites[].
michael@0 119 */
michael@0 120 static PRUint16 allowedByPolicy; /* all off by default */
michael@0 121 static PRUint16 maybeAllowedByPolicy; /* all off by default */
michael@0 122 static PRUint16 chosenPreference = 0xff; /* all on by default */
michael@0 123
michael@0 124 /* bit values for the above two bit masks */
michael@0 125 #define SSL_CB_RC4_128_WITH_MD5 (1 << SSL_CK_RC4_128_WITH_MD5)
michael@0 126 #define SSL_CB_RC4_128_EXPORT40_WITH_MD5 (1 << SSL_CK_RC4_128_EXPORT40_WITH_MD5)
michael@0 127 #define SSL_CB_RC2_128_CBC_WITH_MD5 (1 << SSL_CK_RC2_128_CBC_WITH_MD5)
michael@0 128 #define SSL_CB_RC2_128_CBC_EXPORT40_WITH_MD5 (1 << SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5)
michael@0 129 #define SSL_CB_IDEA_128_CBC_WITH_MD5 (1 << SSL_CK_IDEA_128_CBC_WITH_MD5)
michael@0 130 #define SSL_CB_DES_64_CBC_WITH_MD5 (1 << SSL_CK_DES_64_CBC_WITH_MD5)
michael@0 131 #define SSL_CB_DES_192_EDE3_CBC_WITH_MD5 (1 << SSL_CK_DES_192_EDE3_CBC_WITH_MD5)
michael@0 132 #define SSL_CB_IMPLEMENTED \
michael@0 133 (SSL_CB_RC4_128_WITH_MD5 | \
michael@0 134 SSL_CB_RC4_128_EXPORT40_WITH_MD5 | \
michael@0 135 SSL_CB_RC2_128_CBC_WITH_MD5 | \
michael@0 136 SSL_CB_RC2_128_CBC_EXPORT40_WITH_MD5 | \
michael@0 137 SSL_CB_DES_64_CBC_WITH_MD5 | \
michael@0 138 SSL_CB_DES_192_EDE3_CBC_WITH_MD5)
michael@0 139
michael@0 140
michael@0 141 /* Construct a socket's list of cipher specs from the global default values.
michael@0 142 */
michael@0 143 static SECStatus
michael@0 144 ssl2_ConstructCipherSpecs(sslSocket *ss)
michael@0 145 {
michael@0 146 PRUint8 * cs = NULL;
michael@0 147 unsigned int allowed;
michael@0 148 unsigned int count;
michael@0 149 int ssl3_count = 0;
michael@0 150 int final_count;
michael@0 151 int i;
michael@0 152 SECStatus rv;
michael@0 153
michael@0 154 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 155
michael@0 156 count = 0;
michael@0 157 PORT_Assert(ss != 0);
michael@0 158 allowed = !ss->opt.enableSSL2 ? 0 :
michael@0 159 (ss->allowedByPolicy & ss->chosenPreference & SSL_CB_IMPLEMENTED);
michael@0 160 while (allowed) {
michael@0 161 if (allowed & 1)
michael@0 162 ++count;
michael@0 163 allowed >>= 1;
michael@0 164 }
michael@0 165
michael@0 166 /* Call ssl3_config_match_init() once here,
michael@0 167 * instead of inside ssl3_ConstructV2CipherSpecsHack(),
michael@0 168 * because the latter gets called twice below,
michael@0 169 * and then again in ssl2_BeginClientHandshake().
michael@0 170 */
michael@0 171 ssl3_config_match_init(ss);
michael@0 172
michael@0 173 /* ask SSL3 how many cipher suites it has. */
michael@0 174 rv = ssl3_ConstructV2CipherSpecsHack(ss, NULL, &ssl3_count);
michael@0 175 if (rv < 0)
michael@0 176 return rv;
michael@0 177 count += ssl3_count;
michael@0 178
michael@0 179 /* Allocate memory to hold cipher specs */
michael@0 180 if (count > 0)
michael@0 181 cs = (PRUint8*) PORT_Alloc(count * 3);
michael@0 182 else
michael@0 183 PORT_SetError(SSL_ERROR_SSL_DISABLED);
michael@0 184 if (cs == NULL)
michael@0 185 return SECFailure;
michael@0 186
michael@0 187 if (ss->cipherSpecs != NULL) {
michael@0 188 PORT_Free(ss->cipherSpecs);
michael@0 189 }
michael@0 190 ss->cipherSpecs = cs;
michael@0 191 ss->sizeCipherSpecs = count * 3;
michael@0 192
michael@0 193 /* fill in cipher specs for SSL2 cipher suites */
michael@0 194 allowed = !ss->opt.enableSSL2 ? 0 :
michael@0 195 (ss->allowedByPolicy & ss->chosenPreference & SSL_CB_IMPLEMENTED);
michael@0 196 for (i = 0; i < ssl2_NUM_SUITES_IMPLEMENTED * 3; i += 3) {
michael@0 197 const PRUint8 * hs = implementedCipherSuites + i;
michael@0 198 int ok = allowed & (1U << hs[0]);
michael@0 199 if (ok) {
michael@0 200 cs[0] = hs[0];
michael@0 201 cs[1] = hs[1];
michael@0 202 cs[2] = hs[2];
michael@0 203 cs += 3;
michael@0 204 }
michael@0 205 }
michael@0 206
michael@0 207 /* now have SSL3 add its suites onto the end */
michael@0 208 rv = ssl3_ConstructV2CipherSpecsHack(ss, cs, &final_count);
michael@0 209
michael@0 210 /* adjust for any difference between first pass and second pass */
michael@0 211 ss->sizeCipherSpecs -= (ssl3_count - final_count) * 3;
michael@0 212
michael@0 213 return rv;
michael@0 214 }
michael@0 215
michael@0 216 /* This function is called immediately after ssl2_ConstructCipherSpecs()
michael@0 217 ** at the beginning of a handshake. It detects cases where a protocol
michael@0 218 ** (e.g. SSL2 or SSL3) is logically enabled, but all its cipher suites
michael@0 219 ** for that protocol have been disabled. If such cases, it clears the
michael@0 220 ** enable bit for the protocol. If no protocols remain enabled, or
michael@0 221 ** if no cipher suites are found, it sets the error code and returns
michael@0 222 ** SECFailure, otherwise it returns SECSuccess.
michael@0 223 */
michael@0 224 static SECStatus
michael@0 225 ssl2_CheckConfigSanity(sslSocket *ss)
michael@0 226 {
michael@0 227 unsigned int allowed;
michael@0 228 int ssl3CipherCount = 0;
michael@0 229 SECStatus rv;
michael@0 230
michael@0 231 /* count the SSL2 and SSL3 enabled ciphers.
michael@0 232 * if either is zero, clear the socket's enable for that protocol.
michael@0 233 */
michael@0 234 if (!ss->cipherSpecs)
michael@0 235 goto disabled;
michael@0 236
michael@0 237 allowed = ss->allowedByPolicy & ss->chosenPreference;
michael@0 238 if (! allowed)
michael@0 239 ss->opt.enableSSL2 = PR_FALSE; /* not really enabled if no ciphers */
michael@0 240
michael@0 241 /* ssl3_config_match_init was called in ssl2_ConstructCipherSpecs(). */
michael@0 242 /* Ask how many ssl3 CipherSuites were enabled. */
michael@0 243 rv = ssl3_ConstructV2CipherSpecsHack(ss, NULL, &ssl3CipherCount);
michael@0 244 if (rv != SECSuccess || ssl3CipherCount <= 0) {
michael@0 245 /* SSL3/TLS not really enabled if no ciphers */
michael@0 246 ss->vrange.min = SSL_LIBRARY_VERSION_NONE;
michael@0 247 ss->vrange.max = SSL_LIBRARY_VERSION_NONE;
michael@0 248 }
michael@0 249
michael@0 250 if (!ss->opt.enableSSL2 && SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
michael@0 251 SSL_DBG(("%d: SSL[%d]: Can't handshake! all versions disabled.",
michael@0 252 SSL_GETPID(), ss->fd));
michael@0 253 disabled:
michael@0 254 PORT_SetError(SSL_ERROR_SSL_DISABLED);
michael@0 255 return SECFailure;
michael@0 256 }
michael@0 257 return SECSuccess;
michael@0 258 }
michael@0 259
michael@0 260 /*
michael@0 261 * Since this is a global (not per-socket) setting, we cannot use the
michael@0 262 * HandshakeLock to protect this. Probably want a global lock.
michael@0 263 */
michael@0 264 SECStatus
michael@0 265 ssl2_SetPolicy(PRInt32 which, PRInt32 policy)
michael@0 266 {
michael@0 267 PRUint32 bitMask;
michael@0 268 SECStatus rv = SECSuccess;
michael@0 269
michael@0 270 which &= 0x000f;
michael@0 271 bitMask = 1 << which;
michael@0 272
michael@0 273 if (!(bitMask & SSL_CB_IMPLEMENTED)) {
michael@0 274 PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
michael@0 275 return SECFailure;
michael@0 276 }
michael@0 277
michael@0 278 if (policy == SSL_ALLOWED) {
michael@0 279 allowedByPolicy |= bitMask;
michael@0 280 maybeAllowedByPolicy |= bitMask;
michael@0 281 } else if (policy == SSL_RESTRICTED) {
michael@0 282 allowedByPolicy &= ~bitMask;
michael@0 283 maybeAllowedByPolicy |= bitMask;
michael@0 284 } else {
michael@0 285 allowedByPolicy &= ~bitMask;
michael@0 286 maybeAllowedByPolicy &= ~bitMask;
michael@0 287 }
michael@0 288 allowedByPolicy &= SSL_CB_IMPLEMENTED;
michael@0 289 maybeAllowedByPolicy &= SSL_CB_IMPLEMENTED;
michael@0 290
michael@0 291 policyWasSet = PR_TRUE;
michael@0 292 return rv;
michael@0 293 }
michael@0 294
michael@0 295 SECStatus
michael@0 296 ssl2_GetPolicy(PRInt32 which, PRInt32 *oPolicy)
michael@0 297 {
michael@0 298 PRUint32 bitMask;
michael@0 299 PRInt32 policy;
michael@0 300
michael@0 301 which &= 0x000f;
michael@0 302 bitMask = 1 << which;
michael@0 303
michael@0 304 /* Caller assures oPolicy is not null. */
michael@0 305 if (!(bitMask & SSL_CB_IMPLEMENTED)) {
michael@0 306 PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
michael@0 307 *oPolicy = SSL_NOT_ALLOWED;
michael@0 308 return SECFailure;
michael@0 309 }
michael@0 310
michael@0 311 if (maybeAllowedByPolicy & bitMask) {
michael@0 312 policy = (allowedByPolicy & bitMask) ? SSL_ALLOWED : SSL_RESTRICTED;
michael@0 313 } else {
michael@0 314 policy = SSL_NOT_ALLOWED;
michael@0 315 }
michael@0 316
michael@0 317 *oPolicy = policy;
michael@0 318 return SECSuccess;
michael@0 319 }
michael@0 320
michael@0 321 /*
michael@0 322 * Since this is a global (not per-socket) setting, we cannot use the
michael@0 323 * HandshakeLock to protect this. Probably want a global lock.
michael@0 324 * Called from SSL_CipherPrefSetDefault in sslsock.c
michael@0 325 * These changes have no effect on any sslSockets already created.
michael@0 326 */
michael@0 327 SECStatus
michael@0 328 ssl2_CipherPrefSetDefault(PRInt32 which, PRBool enabled)
michael@0 329 {
michael@0 330 PRUint32 bitMask;
michael@0 331
michael@0 332 which &= 0x000f;
michael@0 333 bitMask = 1 << which;
michael@0 334
michael@0 335 if (!(bitMask & SSL_CB_IMPLEMENTED)) {
michael@0 336 PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
michael@0 337 return SECFailure;
michael@0 338 }
michael@0 339
michael@0 340 if (enabled)
michael@0 341 chosenPreference |= bitMask;
michael@0 342 else
michael@0 343 chosenPreference &= ~bitMask;
michael@0 344 chosenPreference &= SSL_CB_IMPLEMENTED;
michael@0 345
michael@0 346 return SECSuccess;
michael@0 347 }
michael@0 348
michael@0 349 SECStatus
michael@0 350 ssl2_CipherPrefGetDefault(PRInt32 which, PRBool *enabled)
michael@0 351 {
michael@0 352 PRBool rv = PR_FALSE;
michael@0 353 PRUint32 bitMask;
michael@0 354
michael@0 355 which &= 0x000f;
michael@0 356 bitMask = 1 << which;
michael@0 357
michael@0 358 if (!(bitMask & SSL_CB_IMPLEMENTED)) {
michael@0 359 PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
michael@0 360 *enabled = PR_FALSE;
michael@0 361 return SECFailure;
michael@0 362 }
michael@0 363
michael@0 364 rv = (PRBool)((chosenPreference & bitMask) != 0);
michael@0 365 *enabled = rv;
michael@0 366 return SECSuccess;
michael@0 367 }
michael@0 368
michael@0 369 SECStatus
michael@0 370 ssl2_CipherPrefSet(sslSocket *ss, PRInt32 which, PRBool enabled)
michael@0 371 {
michael@0 372 PRUint32 bitMask;
michael@0 373
michael@0 374 which &= 0x000f;
michael@0 375 bitMask = 1 << which;
michael@0 376
michael@0 377 if (!(bitMask & SSL_CB_IMPLEMENTED)) {
michael@0 378 PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
michael@0 379 return SECFailure;
michael@0 380 }
michael@0 381
michael@0 382 if (enabled)
michael@0 383 ss->chosenPreference |= bitMask;
michael@0 384 else
michael@0 385 ss->chosenPreference &= ~bitMask;
michael@0 386 ss->chosenPreference &= SSL_CB_IMPLEMENTED;
michael@0 387
michael@0 388 return SECSuccess;
michael@0 389 }
michael@0 390
michael@0 391 SECStatus
michael@0 392 ssl2_CipherPrefGet(sslSocket *ss, PRInt32 which, PRBool *enabled)
michael@0 393 {
michael@0 394 PRBool rv = PR_FALSE;
michael@0 395 PRUint32 bitMask;
michael@0 396
michael@0 397 which &= 0x000f;
michael@0 398 bitMask = 1 << which;
michael@0 399
michael@0 400 if (!(bitMask & SSL_CB_IMPLEMENTED)) {
michael@0 401 PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
michael@0 402 *enabled = PR_FALSE;
michael@0 403 return SECFailure;
michael@0 404 }
michael@0 405
michael@0 406 rv = (PRBool)((ss->chosenPreference & bitMask) != 0);
michael@0 407 *enabled = rv;
michael@0 408 return SECSuccess;
michael@0 409 }
michael@0 410
michael@0 411
michael@0 412 /* copy global default policy into socket. */
michael@0 413 void
michael@0 414 ssl2_InitSocketPolicy(sslSocket *ss)
michael@0 415 {
michael@0 416 ss->allowedByPolicy = allowedByPolicy;
michael@0 417 ss->maybeAllowedByPolicy = maybeAllowedByPolicy;
michael@0 418 ss->chosenPreference = chosenPreference;
michael@0 419 }
michael@0 420
michael@0 421
michael@0 422 /************************************************************************/
michael@0 423
michael@0 424 /* Called from ssl2_CreateSessionCypher(), which already holds handshake lock.
michael@0 425 */
michael@0 426 static SECStatus
michael@0 427 ssl2_CreateMAC(sslSecurityInfo *sec, SECItem *readKey, SECItem *writeKey,
michael@0 428 int cipherChoice)
michael@0 429 {
michael@0 430 switch (cipherChoice) {
michael@0 431
michael@0 432 case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:
michael@0 433 case SSL_CK_RC2_128_CBC_WITH_MD5:
michael@0 434 case SSL_CK_RC4_128_EXPORT40_WITH_MD5:
michael@0 435 case SSL_CK_RC4_128_WITH_MD5:
michael@0 436 case SSL_CK_DES_64_CBC_WITH_MD5:
michael@0 437 case SSL_CK_DES_192_EDE3_CBC_WITH_MD5:
michael@0 438 sec->hash = HASH_GetHashObject(HASH_AlgMD5);
michael@0 439 SECITEM_CopyItem(0, &sec->sendSecret, writeKey);
michael@0 440 SECITEM_CopyItem(0, &sec->rcvSecret, readKey);
michael@0 441 break;
michael@0 442
michael@0 443 default:
michael@0 444 PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
michael@0 445 return SECFailure;
michael@0 446 }
michael@0 447 sec->hashcx = (*sec->hash->create)();
michael@0 448 if (sec->hashcx == NULL)
michael@0 449 return SECFailure;
michael@0 450 return SECSuccess;
michael@0 451 }
michael@0 452
michael@0 453 /************************************************************************
michael@0 454 * All the Send functions below must acquire and release the socket's
michael@0 455 * xmitBufLock.
michael@0 456 */
michael@0 457
michael@0 458 /* Called from all the Send* functions below. */
michael@0 459 static SECStatus
michael@0 460 ssl2_GetSendBuffer(sslSocket *ss, unsigned int len)
michael@0 461 {
michael@0 462 SECStatus rv = SECSuccess;
michael@0 463
michael@0 464 PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
michael@0 465
michael@0 466 if (len < 128) {
michael@0 467 len = 128;
michael@0 468 }
michael@0 469 if (len > ss->sec.ci.sendBuf.space) {
michael@0 470 rv = sslBuffer_Grow(&ss->sec.ci.sendBuf, len);
michael@0 471 if (rv != SECSuccess) {
michael@0 472 SSL_DBG(("%d: SSL[%d]: ssl2_GetSendBuffer failed, tried to get %d bytes",
michael@0 473 SSL_GETPID(), ss->fd, len));
michael@0 474 rv = SECFailure;
michael@0 475 }
michael@0 476 }
michael@0 477 return rv;
michael@0 478 }
michael@0 479
michael@0 480 /* Called from:
michael@0 481 * ssl2_ClientSetupSessionCypher() <- ssl2_HandleServerHelloMessage()
michael@0 482 * ssl2_HandleRequestCertificate() <- ssl2_HandleMessage() <-
michael@0 483 ssl_Do1stHandshake()
michael@0 484 * ssl2_HandleMessage() <- ssl_Do1stHandshake()
michael@0 485 * ssl2_HandleServerHelloMessage() <- ssl_Do1stHandshake()
michael@0 486 after ssl2_BeginClientHandshake()
michael@0 487 * ssl2_HandleClientHelloMessage() <- ssl_Do1stHandshake()
michael@0 488 after ssl2_BeginServerHandshake()
michael@0 489 *
michael@0 490 * Acquires and releases the socket's xmitBufLock.
michael@0 491 */
michael@0 492 int
michael@0 493 ssl2_SendErrorMessage(sslSocket *ss, int error)
michael@0 494 {
michael@0 495 int rv;
michael@0 496 PRUint8 msg[SSL_HL_ERROR_HBYTES];
michael@0 497
michael@0 498 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 499
michael@0 500 msg[0] = SSL_MT_ERROR;
michael@0 501 msg[1] = MSB(error);
michael@0 502 msg[2] = LSB(error);
michael@0 503
michael@0 504 ssl_GetXmitBufLock(ss); /***************************************/
michael@0 505
michael@0 506 SSL_TRC(3, ("%d: SSL[%d]: sending error %d", SSL_GETPID(), ss->fd, error));
michael@0 507
michael@0 508 ss->handshakeBegun = 1;
michael@0 509 rv = (*ss->sec.send)(ss, msg, sizeof(msg), 0);
michael@0 510 if (rv >= 0) {
michael@0 511 rv = SECSuccess;
michael@0 512 }
michael@0 513 ssl_ReleaseXmitBufLock(ss); /***************************************/
michael@0 514 return rv;
michael@0 515 }
michael@0 516
michael@0 517 /* Called from ssl2_TryToFinish().
michael@0 518 * Acquires and releases the socket's xmitBufLock.
michael@0 519 */
michael@0 520 static SECStatus
michael@0 521 ssl2_SendClientFinishedMessage(sslSocket *ss)
michael@0 522 {
michael@0 523 SECStatus rv = SECSuccess;
michael@0 524 int sent;
michael@0 525 PRUint8 msg[1 + SSL_CONNECTIONID_BYTES];
michael@0 526
michael@0 527 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 528
michael@0 529 ssl_GetXmitBufLock(ss); /***************************************/
michael@0 530
michael@0 531 if (ss->sec.ci.sentFinished == 0) {
michael@0 532 ss->sec.ci.sentFinished = 1;
michael@0 533
michael@0 534 SSL_TRC(3, ("%d: SSL[%d]: sending client-finished",
michael@0 535 SSL_GETPID(), ss->fd));
michael@0 536
michael@0 537 msg[0] = SSL_MT_CLIENT_FINISHED;
michael@0 538 PORT_Memcpy(msg+1, ss->sec.ci.connectionID,
michael@0 539 sizeof(ss->sec.ci.connectionID));
michael@0 540
michael@0 541 DUMP_MSG(29, (ss, msg, 1 + sizeof(ss->sec.ci.connectionID)));
michael@0 542 sent = (*ss->sec.send)(ss, msg, 1 + sizeof(ss->sec.ci.connectionID), 0);
michael@0 543 rv = (sent >= 0) ? SECSuccess : (SECStatus)sent;
michael@0 544 }
michael@0 545 ssl_ReleaseXmitBufLock(ss); /***************************************/
michael@0 546 return rv;
michael@0 547 }
michael@0 548
michael@0 549 /* Called from
michael@0 550 * ssl2_HandleClientSessionKeyMessage() <- ssl2_HandleClientHelloMessage()
michael@0 551 * ssl2_HandleClientHelloMessage() <- ssl_Do1stHandshake()
michael@0 552 after ssl2_BeginServerHandshake()
michael@0 553 * Acquires and releases the socket's xmitBufLock.
michael@0 554 */
michael@0 555 static SECStatus
michael@0 556 ssl2_SendServerVerifyMessage(sslSocket *ss)
michael@0 557 {
michael@0 558 PRUint8 * msg;
michael@0 559 int sendLen;
michael@0 560 int sent;
michael@0 561 SECStatus rv;
michael@0 562
michael@0 563 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 564
michael@0 565 ssl_GetXmitBufLock(ss); /***************************************/
michael@0 566
michael@0 567 sendLen = 1 + SSL_CHALLENGE_BYTES;
michael@0 568 rv = ssl2_GetSendBuffer(ss, sendLen);
michael@0 569 if (rv != SECSuccess) {
michael@0 570 goto done;
michael@0 571 }
michael@0 572
michael@0 573 msg = ss->sec.ci.sendBuf.buf;
michael@0 574 msg[0] = SSL_MT_SERVER_VERIFY;
michael@0 575 PORT_Memcpy(msg+1, ss->sec.ci.clientChallenge, SSL_CHALLENGE_BYTES);
michael@0 576
michael@0 577 DUMP_MSG(29, (ss, msg, sendLen));
michael@0 578 sent = (*ss->sec.send)(ss, msg, sendLen, 0);
michael@0 579
michael@0 580 rv = (sent >= 0) ? SECSuccess : (SECStatus)sent;
michael@0 581
michael@0 582 done:
michael@0 583 ssl_ReleaseXmitBufLock(ss); /***************************************/
michael@0 584 return rv;
michael@0 585 }
michael@0 586
michael@0 587 /* Called from ssl2_TryToFinish().
michael@0 588 * Acquires and releases the socket's xmitBufLock.
michael@0 589 */
michael@0 590 static SECStatus
michael@0 591 ssl2_SendServerFinishedMessage(sslSocket *ss)
michael@0 592 {
michael@0 593 sslSessionID * sid;
michael@0 594 PRUint8 * msg;
michael@0 595 int sendLen, sent;
michael@0 596 SECStatus rv = SECSuccess;
michael@0 597
michael@0 598 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 599
michael@0 600 ssl_GetXmitBufLock(ss); /***************************************/
michael@0 601
michael@0 602 if (ss->sec.ci.sentFinished == 0) {
michael@0 603 ss->sec.ci.sentFinished = 1;
michael@0 604 PORT_Assert(ss->sec.ci.sid != 0);
michael@0 605 sid = ss->sec.ci.sid;
michael@0 606
michael@0 607 SSL_TRC(3, ("%d: SSL[%d]: sending server-finished",
michael@0 608 SSL_GETPID(), ss->fd));
michael@0 609
michael@0 610 sendLen = 1 + sizeof(sid->u.ssl2.sessionID);
michael@0 611 rv = ssl2_GetSendBuffer(ss, sendLen);
michael@0 612 if (rv != SECSuccess) {
michael@0 613 goto done;
michael@0 614 }
michael@0 615
michael@0 616 msg = ss->sec.ci.sendBuf.buf;
michael@0 617 msg[0] = SSL_MT_SERVER_FINISHED;
michael@0 618 PORT_Memcpy(msg+1, sid->u.ssl2.sessionID,
michael@0 619 sizeof(sid->u.ssl2.sessionID));
michael@0 620
michael@0 621 DUMP_MSG(29, (ss, msg, sendLen));
michael@0 622 sent = (*ss->sec.send)(ss, msg, sendLen, 0);
michael@0 623
michael@0 624 if (sent < 0) {
michael@0 625 /* If send failed, it is now a bogus session-id */
michael@0 626 if (ss->sec.uncache)
michael@0 627 (*ss->sec.uncache)(sid);
michael@0 628 rv = (SECStatus)sent;
michael@0 629 } else if (!ss->opt.noCache) {
michael@0 630 if (sid->cached == never_cached) {
michael@0 631 (*ss->sec.cache)(sid);
michael@0 632 }
michael@0 633 rv = SECSuccess;
michael@0 634 }
michael@0 635 ssl_FreeSID(sid);
michael@0 636 ss->sec.ci.sid = 0;
michael@0 637 }
michael@0 638 done:
michael@0 639 ssl_ReleaseXmitBufLock(ss); /***************************************/
michael@0 640 return rv;
michael@0 641 }
michael@0 642
michael@0 643 /* Called from ssl2_ClientSetupSessionCypher() <-
michael@0 644 * ssl2_HandleServerHelloMessage()
michael@0 645 * after ssl2_BeginClientHandshake()
michael@0 646 * Acquires and releases the socket's xmitBufLock.
michael@0 647 */
michael@0 648 static SECStatus
michael@0 649 ssl2_SendSessionKeyMessage(sslSocket *ss, int cipher, int keySize,
michael@0 650 PRUint8 *ca, int caLen,
michael@0 651 PRUint8 *ck, int ckLen,
michael@0 652 PRUint8 *ek, int ekLen)
michael@0 653 {
michael@0 654 PRUint8 * msg;
michael@0 655 int sendLen;
michael@0 656 int sent;
michael@0 657 SECStatus rv;
michael@0 658
michael@0 659 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 660
michael@0 661 ssl_GetXmitBufLock(ss); /***************************************/
michael@0 662
michael@0 663 sendLen = SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen + ekLen + caLen;
michael@0 664 rv = ssl2_GetSendBuffer(ss, sendLen);
michael@0 665 if (rv != SECSuccess)
michael@0 666 goto done;
michael@0 667
michael@0 668 SSL_TRC(3, ("%d: SSL[%d]: sending client-session-key",
michael@0 669 SSL_GETPID(), ss->fd));
michael@0 670
michael@0 671 msg = ss->sec.ci.sendBuf.buf;
michael@0 672 msg[0] = SSL_MT_CLIENT_MASTER_KEY;
michael@0 673 msg[1] = cipher;
michael@0 674 msg[2] = MSB(keySize);
michael@0 675 msg[3] = LSB(keySize);
michael@0 676 msg[4] = MSB(ckLen);
michael@0 677 msg[5] = LSB(ckLen);
michael@0 678 msg[6] = MSB(ekLen);
michael@0 679 msg[7] = LSB(ekLen);
michael@0 680 msg[8] = MSB(caLen);
michael@0 681 msg[9] = LSB(caLen);
michael@0 682 PORT_Memcpy(msg+SSL_HL_CLIENT_MASTER_KEY_HBYTES, ck, ckLen);
michael@0 683 PORT_Memcpy(msg+SSL_HL_CLIENT_MASTER_KEY_HBYTES+ckLen, ek, ekLen);
michael@0 684 PORT_Memcpy(msg+SSL_HL_CLIENT_MASTER_KEY_HBYTES+ckLen+ekLen, ca, caLen);
michael@0 685
michael@0 686 DUMP_MSG(29, (ss, msg, sendLen));
michael@0 687 sent = (*ss->sec.send)(ss, msg, sendLen, 0);
michael@0 688 rv = (sent >= 0) ? SECSuccess : (SECStatus)sent;
michael@0 689 done:
michael@0 690 ssl_ReleaseXmitBufLock(ss); /***************************************/
michael@0 691 return rv;
michael@0 692 }
michael@0 693
michael@0 694 /* Called from ssl2_TriggerNextMessage() <- ssl2_HandleMessage()
michael@0 695 * Acquires and releases the socket's xmitBufLock.
michael@0 696 */
michael@0 697 static SECStatus
michael@0 698 ssl2_SendCertificateRequestMessage(sslSocket *ss)
michael@0 699 {
michael@0 700 PRUint8 * msg;
michael@0 701 int sent;
michael@0 702 int sendLen;
michael@0 703 SECStatus rv;
michael@0 704
michael@0 705 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 706
michael@0 707 ssl_GetXmitBufLock(ss); /***************************************/
michael@0 708
michael@0 709 sendLen = SSL_HL_REQUEST_CERTIFICATE_HBYTES + SSL_CHALLENGE_BYTES;
michael@0 710 rv = ssl2_GetSendBuffer(ss, sendLen);
michael@0 711 if (rv != SECSuccess)
michael@0 712 goto done;
michael@0 713
michael@0 714 SSL_TRC(3, ("%d: SSL[%d]: sending certificate request",
michael@0 715 SSL_GETPID(), ss->fd));
michael@0 716
michael@0 717 /* Generate random challenge for client to encrypt */
michael@0 718 PK11_GenerateRandom(ss->sec.ci.serverChallenge, SSL_CHALLENGE_BYTES);
michael@0 719
michael@0 720 msg = ss->sec.ci.sendBuf.buf;
michael@0 721 msg[0] = SSL_MT_REQUEST_CERTIFICATE;
michael@0 722 msg[1] = SSL_AT_MD5_WITH_RSA_ENCRYPTION;
michael@0 723 PORT_Memcpy(msg + SSL_HL_REQUEST_CERTIFICATE_HBYTES,
michael@0 724 ss->sec.ci.serverChallenge, SSL_CHALLENGE_BYTES);
michael@0 725
michael@0 726 DUMP_MSG(29, (ss, msg, sendLen));
michael@0 727 sent = (*ss->sec.send)(ss, msg, sendLen, 0);
michael@0 728 rv = (sent >= 0) ? SECSuccess : (SECStatus)sent;
michael@0 729 done:
michael@0 730 ssl_ReleaseXmitBufLock(ss); /***************************************/
michael@0 731 return rv;
michael@0 732 }
michael@0 733
michael@0 734 /* Called from ssl2_HandleRequestCertificate() <- ssl2_HandleMessage()
michael@0 735 * Acquires and releases the socket's xmitBufLock.
michael@0 736 */
michael@0 737 static int
michael@0 738 ssl2_SendCertificateResponseMessage(sslSocket *ss, SECItem *cert,
michael@0 739 SECItem *encCode)
michael@0 740 {
michael@0 741 PRUint8 *msg;
michael@0 742 int rv, sendLen;
michael@0 743
michael@0 744 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 745
michael@0 746 ssl_GetXmitBufLock(ss); /***************************************/
michael@0 747
michael@0 748 sendLen = SSL_HL_CLIENT_CERTIFICATE_HBYTES + encCode->len + cert->len;
michael@0 749 rv = ssl2_GetSendBuffer(ss, sendLen);
michael@0 750 if (rv)
michael@0 751 goto done;
michael@0 752
michael@0 753 SSL_TRC(3, ("%d: SSL[%d]: sending certificate response",
michael@0 754 SSL_GETPID(), ss->fd));
michael@0 755
michael@0 756 msg = ss->sec.ci.sendBuf.buf;
michael@0 757 msg[0] = SSL_MT_CLIENT_CERTIFICATE;
michael@0 758 msg[1] = SSL_CT_X509_CERTIFICATE;
michael@0 759 msg[2] = MSB(cert->len);
michael@0 760 msg[3] = LSB(cert->len);
michael@0 761 msg[4] = MSB(encCode->len);
michael@0 762 msg[5] = LSB(encCode->len);
michael@0 763 PORT_Memcpy(msg + SSL_HL_CLIENT_CERTIFICATE_HBYTES, cert->data, cert->len);
michael@0 764 PORT_Memcpy(msg + SSL_HL_CLIENT_CERTIFICATE_HBYTES + cert->len,
michael@0 765 encCode->data, encCode->len);
michael@0 766
michael@0 767 DUMP_MSG(29, (ss, msg, sendLen));
michael@0 768 rv = (*ss->sec.send)(ss, msg, sendLen, 0);
michael@0 769 if (rv >= 0) {
michael@0 770 rv = SECSuccess;
michael@0 771 }
michael@0 772 done:
michael@0 773 ssl_ReleaseXmitBufLock(ss); /***************************************/
michael@0 774 return rv;
michael@0 775 }
michael@0 776
michael@0 777 /********************************************************************
michael@0 778 ** Send functions above this line must aquire & release the socket's
michael@0 779 ** xmitBufLock.
michael@0 780 ** All the ssl2_Send functions below this line are called vis ss->sec.send
michael@0 781 ** and require that the caller hold the xmitBufLock.
michael@0 782 */
michael@0 783
michael@0 784 /*
michael@0 785 ** Called from ssl2_SendStream, ssl2_SendBlock, but not from ssl2_SendClear.
michael@0 786 */
michael@0 787 static SECStatus
michael@0 788 ssl2_CalcMAC(PRUint8 * result,
michael@0 789 sslSecurityInfo * sec,
michael@0 790 const PRUint8 * data,
michael@0 791 unsigned int dataLen,
michael@0 792 unsigned int paddingLen)
michael@0 793 {
michael@0 794 const PRUint8 * secret = sec->sendSecret.data;
michael@0 795 unsigned int secretLen = sec->sendSecret.len;
michael@0 796 unsigned long sequenceNumber = sec->sendSequence;
michael@0 797 unsigned int nout;
michael@0 798 PRUint8 seq[4];
michael@0 799 PRUint8 padding[32];/* XXX max blocksize? */
michael@0 800
michael@0 801 if (!sec->hash || !sec->hash->length)
michael@0 802 return SECSuccess;
michael@0 803 if (!sec->hashcx)
michael@0 804 return SECFailure;
michael@0 805
michael@0 806 /* Reset hash function */
michael@0 807 (*sec->hash->begin)(sec->hashcx);
michael@0 808
michael@0 809 /* Feed hash the data */
michael@0 810 (*sec->hash->update)(sec->hashcx, secret, secretLen);
michael@0 811 (*sec->hash->update)(sec->hashcx, data, dataLen);
michael@0 812 PORT_Memset(padding, paddingLen, paddingLen);
michael@0 813 (*sec->hash->update)(sec->hashcx, padding, paddingLen);
michael@0 814
michael@0 815 seq[0] = (PRUint8) (sequenceNumber >> 24);
michael@0 816 seq[1] = (PRUint8) (sequenceNumber >> 16);
michael@0 817 seq[2] = (PRUint8) (sequenceNumber >> 8);
michael@0 818 seq[3] = (PRUint8) (sequenceNumber);
michael@0 819
michael@0 820 PRINT_BUF(60, (0, "calc-mac secret:", secret, secretLen));
michael@0 821 PRINT_BUF(60, (0, "calc-mac data:", data, dataLen));
michael@0 822 PRINT_BUF(60, (0, "calc-mac padding:", padding, paddingLen));
michael@0 823 PRINT_BUF(60, (0, "calc-mac seq:", seq, 4));
michael@0 824
michael@0 825 (*sec->hash->update)(sec->hashcx, seq, 4);
michael@0 826
michael@0 827 /* Get result */
michael@0 828 (*sec->hash->end)(sec->hashcx, result, &nout, sec->hash->length);
michael@0 829
michael@0 830 return SECSuccess;
michael@0 831 }
michael@0 832
michael@0 833 /*
michael@0 834 ** Maximum transmission amounts. These are tiny bit smaller than they
michael@0 835 ** need to be (they account for the MAC length plus some padding),
michael@0 836 ** assuming the MAC is 16 bytes long and the padding is a max of 7 bytes
michael@0 837 ** long. This gives an additional 9 bytes of slop to work within.
michael@0 838 */
michael@0 839 #define MAX_STREAM_CYPHER_LEN 0x7fe0
michael@0 840 #define MAX_BLOCK_CYPHER_LEN 0x3fe0
michael@0 841
michael@0 842 /*
michael@0 843 ** Send some data in the clear.
michael@0 844 ** Package up data with the length header and send it.
michael@0 845 **
michael@0 846 ** Return count of bytes successfully written, or negative number (failure).
michael@0 847 */
michael@0 848 static PRInt32
michael@0 849 ssl2_SendClear(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags)
michael@0 850 {
michael@0 851 PRUint8 * out;
michael@0 852 int rv;
michael@0 853 int amount;
michael@0 854 int count = 0;
michael@0 855
michael@0 856 PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
michael@0 857
michael@0 858 SSL_TRC(10, ("%d: SSL[%d]: sending %d bytes in the clear",
michael@0 859 SSL_GETPID(), ss->fd, len));
michael@0 860 PRINT_BUF(50, (ss, "clear data:", (PRUint8*) in, len));
michael@0 861
michael@0 862 while (len) {
michael@0 863 amount = PR_MIN( len, MAX_STREAM_CYPHER_LEN );
michael@0 864 if (amount + 2 > ss->sec.writeBuf.space) {
michael@0 865 rv = sslBuffer_Grow(&ss->sec.writeBuf, amount + 2);
michael@0 866 if (rv != SECSuccess) {
michael@0 867 count = rv;
michael@0 868 break;
michael@0 869 }
michael@0 870 }
michael@0 871 out = ss->sec.writeBuf.buf;
michael@0 872
michael@0 873 /*
michael@0 874 ** Construct message.
michael@0 875 */
michael@0 876 out[0] = 0x80 | MSB(amount);
michael@0 877 out[1] = LSB(amount);
michael@0 878 PORT_Memcpy(&out[2], in, amount);
michael@0 879
michael@0 880 /* Now send the data */
michael@0 881 rv = ssl_DefSend(ss, out, amount + 2, flags & ~ssl_SEND_FLAG_MASK);
michael@0 882 if (rv < 0) {
michael@0 883 if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) {
michael@0 884 rv = 0;
michael@0 885 } else {
michael@0 886 /* Return short write if some data already went out... */
michael@0 887 if (count == 0)
michael@0 888 count = rv;
michael@0 889 break;
michael@0 890 }
michael@0 891 }
michael@0 892
michael@0 893 if ((unsigned)rv < (amount + 2)) {
michael@0 894 /* Short write. Save the data and return. */
michael@0 895 if (ssl_SaveWriteData(ss, out + rv, amount + 2 - rv)
michael@0 896 == SECFailure) {
michael@0 897 count = SECFailure;
michael@0 898 } else {
michael@0 899 count += amount;
michael@0 900 ss->sec.sendSequence++;
michael@0 901 }
michael@0 902 break;
michael@0 903 }
michael@0 904
michael@0 905 ss->sec.sendSequence++;
michael@0 906 in += amount;
michael@0 907 count += amount;
michael@0 908 len -= amount;
michael@0 909 }
michael@0 910
michael@0 911 return count;
michael@0 912 }
michael@0 913
michael@0 914 /*
michael@0 915 ** Send some data, when using a stream cipher. Stream ciphers have a
michael@0 916 ** block size of 1. Package up the data with the length header
michael@0 917 ** and send it.
michael@0 918 */
michael@0 919 static PRInt32
michael@0 920 ssl2_SendStream(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags)
michael@0 921 {
michael@0 922 PRUint8 * out;
michael@0 923 int rv;
michael@0 924 int count = 0;
michael@0 925
michael@0 926 int amount;
michael@0 927 PRUint8 macLen;
michael@0 928 int nout;
michael@0 929 int buflen;
michael@0 930
michael@0 931 PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
michael@0 932
michael@0 933 SSL_TRC(10, ("%d: SSL[%d]: sending %d bytes using stream cipher",
michael@0 934 SSL_GETPID(), ss->fd, len));
michael@0 935 PRINT_BUF(50, (ss, "clear data:", (PRUint8*) in, len));
michael@0 936
michael@0 937 while (len) {
michael@0 938 ssl_GetSpecReadLock(ss); /*************************************/
michael@0 939
michael@0 940 macLen = ss->sec.hash->length;
michael@0 941 amount = PR_MIN( len, MAX_STREAM_CYPHER_LEN );
michael@0 942 buflen = amount + 2 + macLen;
michael@0 943 if (buflen > ss->sec.writeBuf.space) {
michael@0 944 rv = sslBuffer_Grow(&ss->sec.writeBuf, buflen);
michael@0 945 if (rv != SECSuccess) {
michael@0 946 goto loser;
michael@0 947 }
michael@0 948 }
michael@0 949 out = ss->sec.writeBuf.buf;
michael@0 950 nout = amount + macLen;
michael@0 951 out[0] = 0x80 | MSB(nout);
michael@0 952 out[1] = LSB(nout);
michael@0 953
michael@0 954 /* Calculate MAC */
michael@0 955 rv = ssl2_CalcMAC(out+2, /* put MAC here */
michael@0 956 &ss->sec,
michael@0 957 in, amount, /* input addr & length */
michael@0 958 0); /* no padding */
michael@0 959 if (rv != SECSuccess)
michael@0 960 goto loser;
michael@0 961
michael@0 962 /* Encrypt MAC */
michael@0 963 rv = (*ss->sec.enc)(ss->sec.writecx, out+2, &nout, macLen, out+2, macLen);
michael@0 964 if (rv) goto loser;
michael@0 965
michael@0 966 /* Encrypt data from caller */
michael@0 967 rv = (*ss->sec.enc)(ss->sec.writecx, out+2+macLen, &nout, amount, in, amount);
michael@0 968 if (rv) goto loser;
michael@0 969
michael@0 970 ssl_ReleaseSpecReadLock(ss); /*************************************/
michael@0 971
michael@0 972 PRINT_BUF(50, (ss, "encrypted data:", out, buflen));
michael@0 973
michael@0 974 rv = ssl_DefSend(ss, out, buflen, flags & ~ssl_SEND_FLAG_MASK);
michael@0 975 if (rv < 0) {
michael@0 976 if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) {
michael@0 977 SSL_TRC(50, ("%d: SSL[%d]: send stream would block, "
michael@0 978 "saving data", SSL_GETPID(), ss->fd));
michael@0 979 rv = 0;
michael@0 980 } else {
michael@0 981 SSL_TRC(10, ("%d: SSL[%d]: send stream error %d",
michael@0 982 SSL_GETPID(), ss->fd, PORT_GetError()));
michael@0 983 /* Return short write if some data already went out... */
michael@0 984 if (count == 0)
michael@0 985 count = rv;
michael@0 986 goto done;
michael@0 987 }
michael@0 988 }
michael@0 989
michael@0 990 if ((unsigned)rv < buflen) {
michael@0 991 /* Short write. Save the data and return. */
michael@0 992 if (ssl_SaveWriteData(ss, out + rv, buflen - rv) == SECFailure) {
michael@0 993 count = SECFailure;
michael@0 994 } else {
michael@0 995 count += amount;
michael@0 996 ss->sec.sendSequence++;
michael@0 997 }
michael@0 998 goto done;
michael@0 999 }
michael@0 1000
michael@0 1001 ss->sec.sendSequence++;
michael@0 1002 in += amount;
michael@0 1003 count += amount;
michael@0 1004 len -= amount;
michael@0 1005 }
michael@0 1006
michael@0 1007 done:
michael@0 1008 return count;
michael@0 1009
michael@0 1010 loser:
michael@0 1011 ssl_ReleaseSpecReadLock(ss);
michael@0 1012 return SECFailure;
michael@0 1013 }
michael@0 1014
michael@0 1015 /*
michael@0 1016 ** Send some data, when using a block cipher. Package up the data with
michael@0 1017 ** the length header and send it.
michael@0 1018 */
michael@0 1019 /* XXX assumes blocksize is > 7 */
michael@0 1020 static PRInt32
michael@0 1021 ssl2_SendBlock(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags)
michael@0 1022 {
michael@0 1023 PRUint8 * out; /* begining of output buffer. */
michael@0 1024 PRUint8 * op; /* next output byte goes here. */
michael@0 1025 int rv; /* value from funcs we called. */
michael@0 1026 int count = 0; /* this function's return value. */
michael@0 1027
michael@0 1028 unsigned int hlen; /* output record hdr len, 2 or 3 */
michael@0 1029 unsigned int macLen; /* MAC is this many bytes long. */
michael@0 1030 int amount; /* of plaintext to go in record. */
michael@0 1031 unsigned int padding; /* add this many padding byte. */
michael@0 1032 int nout; /* ciphertext size after header. */
michael@0 1033 int buflen; /* size of generated record. */
michael@0 1034
michael@0 1035 PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
michael@0 1036
michael@0 1037 SSL_TRC(10, ("%d: SSL[%d]: sending %d bytes using block cipher",
michael@0 1038 SSL_GETPID(), ss->fd, len));
michael@0 1039 PRINT_BUF(50, (ss, "clear data:", in, len));
michael@0 1040
michael@0 1041 while (len) {
michael@0 1042 ssl_GetSpecReadLock(ss); /*************************************/
michael@0 1043
michael@0 1044 macLen = ss->sec.hash->length;
michael@0 1045 /* Figure out how much to send, including mac and padding */
michael@0 1046 amount = PR_MIN( len, MAX_BLOCK_CYPHER_LEN );
michael@0 1047 nout = amount + macLen;
michael@0 1048 padding = nout & (ss->sec.blockSize - 1);
michael@0 1049 if (padding) {
michael@0 1050 hlen = 3;
michael@0 1051 padding = ss->sec.blockSize - padding;
michael@0 1052 nout += padding;
michael@0 1053 } else {
michael@0 1054 hlen = 2;
michael@0 1055 }
michael@0 1056 buflen = hlen + nout;
michael@0 1057 if (buflen > ss->sec.writeBuf.space) {
michael@0 1058 rv = sslBuffer_Grow(&ss->sec.writeBuf, buflen);
michael@0 1059 if (rv != SECSuccess) {
michael@0 1060 goto loser;
michael@0 1061 }
michael@0 1062 }
michael@0 1063 out = ss->sec.writeBuf.buf;
michael@0 1064
michael@0 1065 /* Construct header */
michael@0 1066 op = out;
michael@0 1067 if (padding) {
michael@0 1068 *op++ = MSB(nout);
michael@0 1069 *op++ = LSB(nout);
michael@0 1070 *op++ = padding;
michael@0 1071 } else {
michael@0 1072 *op++ = 0x80 | MSB(nout);
michael@0 1073 *op++ = LSB(nout);
michael@0 1074 }
michael@0 1075
michael@0 1076 /* Calculate MAC */
michael@0 1077 rv = ssl2_CalcMAC(op, /* MAC goes here. */
michael@0 1078 &ss->sec,
michael@0 1079 in, amount, /* intput addr, len */
michael@0 1080 padding);
michael@0 1081 if (rv != SECSuccess)
michael@0 1082 goto loser;
michael@0 1083 op += macLen;
michael@0 1084
michael@0 1085 /* Copy in the input data */
michael@0 1086 /* XXX could eliminate the copy by folding it into the encryption */
michael@0 1087 PORT_Memcpy(op, in, amount);
michael@0 1088 op += amount;
michael@0 1089 if (padding) {
michael@0 1090 PORT_Memset(op, padding, padding);
michael@0 1091 op += padding;
michael@0 1092 }
michael@0 1093
michael@0 1094 /* Encrypt result */
michael@0 1095 rv = (*ss->sec.enc)(ss->sec.writecx, out+hlen, &nout, buflen-hlen,
michael@0 1096 out+hlen, op - (out + hlen));
michael@0 1097 if (rv)
michael@0 1098 goto loser;
michael@0 1099
michael@0 1100 ssl_ReleaseSpecReadLock(ss); /*************************************/
michael@0 1101
michael@0 1102 PRINT_BUF(50, (ss, "final xmit data:", out, op - out));
michael@0 1103
michael@0 1104 rv = ssl_DefSend(ss, out, op - out, flags & ~ssl_SEND_FLAG_MASK);
michael@0 1105 if (rv < 0) {
michael@0 1106 if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) {
michael@0 1107 rv = 0;
michael@0 1108 } else {
michael@0 1109 SSL_TRC(10, ("%d: SSL[%d]: send block error %d",
michael@0 1110 SSL_GETPID(), ss->fd, PORT_GetError()));
michael@0 1111 /* Return short write if some data already went out... */
michael@0 1112 if (count == 0)
michael@0 1113 count = rv;
michael@0 1114 goto done;
michael@0 1115 }
michael@0 1116 }
michael@0 1117
michael@0 1118 if (rv < (op - out)) {
michael@0 1119 /* Short write. Save the data and return. */
michael@0 1120 if (ssl_SaveWriteData(ss, out + rv, op - out - rv) == SECFailure) {
michael@0 1121 count = SECFailure;
michael@0 1122 } else {
michael@0 1123 count += amount;
michael@0 1124 ss->sec.sendSequence++;
michael@0 1125 }
michael@0 1126 goto done;
michael@0 1127 }
michael@0 1128
michael@0 1129 ss->sec.sendSequence++;
michael@0 1130 in += amount;
michael@0 1131 count += amount;
michael@0 1132 len -= amount;
michael@0 1133 }
michael@0 1134
michael@0 1135 done:
michael@0 1136 return count;
michael@0 1137
michael@0 1138 loser:
michael@0 1139 ssl_ReleaseSpecReadLock(ss);
michael@0 1140 return SECFailure;
michael@0 1141 }
michael@0 1142
michael@0 1143 /*
michael@0 1144 ** Called from: ssl2_HandleServerHelloMessage,
michael@0 1145 ** ssl2_HandleClientSessionKeyMessage,
michael@0 1146 ** ssl2_HandleClientHelloMessage,
michael@0 1147 **
michael@0 1148 */
michael@0 1149 static void
michael@0 1150 ssl2_UseEncryptedSendFunc(sslSocket *ss)
michael@0 1151 {
michael@0 1152 ssl_GetXmitBufLock(ss);
michael@0 1153 PORT_Assert(ss->sec.hashcx != 0);
michael@0 1154
michael@0 1155 ss->gs.encrypted = 1;
michael@0 1156 ss->sec.send = (ss->sec.blockSize > 1) ? ssl2_SendBlock : ssl2_SendStream;
michael@0 1157 ssl_ReleaseXmitBufLock(ss);
michael@0 1158 }
michael@0 1159
michael@0 1160 /* Called while initializing socket in ssl_CreateSecurityInfo().
michael@0 1161 ** This function allows us to keep the name of ssl2_SendClear static.
michael@0 1162 */
michael@0 1163 void
michael@0 1164 ssl2_UseClearSendFunc(sslSocket *ss)
michael@0 1165 {
michael@0 1166 ss->sec.send = ssl2_SendClear;
michael@0 1167 }
michael@0 1168
michael@0 1169 /************************************************************************
michael@0 1170 ** END of Send functions. *
michael@0 1171 *************************************************************************/
michael@0 1172
michael@0 1173 /***********************************************************************
michael@0 1174 * For SSL3, this gathers in and handles records/messages until either
michael@0 1175 * the handshake is complete or application data is available.
michael@0 1176 *
michael@0 1177 * For SSL2, this gathers in only the next SSLV2 record.
michael@0 1178 *
michael@0 1179 * Called from ssl_Do1stHandshake() via function pointer ss->handshake.
michael@0 1180 * Caller must hold handshake lock.
michael@0 1181 * This function acquires and releases the RecvBufLock.
michael@0 1182 *
michael@0 1183 * returns SECSuccess for success.
michael@0 1184 * returns SECWouldBlock when that value is returned by ssl2_GatherRecord() or
michael@0 1185 * ssl3_GatherCompleteHandshake().
michael@0 1186 * returns SECFailure on all other errors.
michael@0 1187 *
michael@0 1188 * The gather functions called by ssl_GatherRecord1stHandshake are expected
michael@0 1189 * to return values interpreted as follows:
michael@0 1190 * 1 : the function completed without error.
michael@0 1191 * 0 : the function read EOF.
michael@0 1192 * -1 : read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error.
michael@0 1193 * -2 : the function wants ssl_GatherRecord1stHandshake to be called again
michael@0 1194 * immediately, by ssl_Do1stHandshake.
michael@0 1195 *
michael@0 1196 * This code is similar to, and easily confused with, DoRecv() in sslsecur.c
michael@0 1197 *
michael@0 1198 * This function is called from ssl_Do1stHandshake().
michael@0 1199 * The following functions put ssl_GatherRecord1stHandshake into ss->handshake:
michael@0 1200 * ssl2_HandleMessage
michael@0 1201 * ssl2_HandleVerifyMessage
michael@0 1202 * ssl2_HandleServerHelloMessage
michael@0 1203 * ssl2_BeginClientHandshake
michael@0 1204 * ssl2_HandleClientSessionKeyMessage
michael@0 1205 * ssl3_RestartHandshakeAfterCertReq
michael@0 1206 * ssl3_RestartHandshakeAfterServerCert
michael@0 1207 * ssl2_HandleClientHelloMessage
michael@0 1208 * ssl2_BeginServerHandshake
michael@0 1209 */
michael@0 1210 SECStatus
michael@0 1211 ssl_GatherRecord1stHandshake(sslSocket *ss)
michael@0 1212 {
michael@0 1213 int rv;
michael@0 1214
michael@0 1215 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 1216
michael@0 1217 ssl_GetRecvBufLock(ss);
michael@0 1218
michael@0 1219 /* The special case DTLS logic is needed here because the SSL/TLS
michael@0 1220 * version wants to auto-detect SSL2 vs. SSL3 on the initial handshake
michael@0 1221 * (ss->version == 0) but with DTLS it gets confused, so we force the
michael@0 1222 * SSL3 version.
michael@0 1223 */
michael@0 1224 if ((ss->version >= SSL_LIBRARY_VERSION_3_0) || IS_DTLS(ss)) {
michael@0 1225 /* Wait for handshake to complete, or application data to arrive. */
michael@0 1226 rv = ssl3_GatherCompleteHandshake(ss, 0);
michael@0 1227 } else {
michael@0 1228 /* See if we have a complete record */
michael@0 1229 rv = ssl2_GatherRecord(ss, 0);
michael@0 1230 }
michael@0 1231 SSL_TRC(10, ("%d: SSL[%d]: handshake gathering, rv=%d",
michael@0 1232 SSL_GETPID(), ss->fd, rv));
michael@0 1233
michael@0 1234 ssl_ReleaseRecvBufLock(ss);
michael@0 1235
michael@0 1236 if (rv <= 0) {
michael@0 1237 if (rv == SECWouldBlock) {
michael@0 1238 /* Progress is blocked waiting for callback completion. */
michael@0 1239 SSL_TRC(10, ("%d: SSL[%d]: handshake blocked (need %d)",
michael@0 1240 SSL_GETPID(), ss->fd, ss->gs.remainder));
michael@0 1241 return SECWouldBlock;
michael@0 1242 }
michael@0 1243 if (rv == 0) {
michael@0 1244 /* EOF. Loser */
michael@0 1245 PORT_SetError(PR_END_OF_FILE_ERROR);
michael@0 1246 }
michael@0 1247 return SECFailure; /* rv is < 0 here. */
michael@0 1248 }
michael@0 1249
michael@0 1250 SSL_TRC(10, ("%d: SSL[%d]: got handshake record of %d bytes",
michael@0 1251 SSL_GETPID(), ss->fd, ss->gs.recordLen));
michael@0 1252
michael@0 1253 ss->handshake = 0; /* makes ssl_Do1stHandshake call ss->nextHandshake.*/
michael@0 1254 return SECSuccess;
michael@0 1255 }
michael@0 1256
michael@0 1257 /************************************************************************/
michael@0 1258
michael@0 1259 /* Called from ssl2_ServerSetupSessionCypher()
michael@0 1260 * ssl2_ClientSetupSessionCypher()
michael@0 1261 */
michael@0 1262 static SECStatus
michael@0 1263 ssl2_FillInSID(sslSessionID * sid,
michael@0 1264 int cipher,
michael@0 1265 PRUint8 *keyData,
michael@0 1266 int keyLen,
michael@0 1267 PRUint8 *ca,
michael@0 1268 int caLen,
michael@0 1269 int keyBits,
michael@0 1270 int secretKeyBits,
michael@0 1271 SSLSignType authAlgorithm,
michael@0 1272 PRUint32 authKeyBits,
michael@0 1273 SSLKEAType keaType,
michael@0 1274 PRUint32 keaKeyBits)
michael@0 1275 {
michael@0 1276 PORT_Assert(sid->references == 1);
michael@0 1277 PORT_Assert(sid->cached == never_cached);
michael@0 1278 PORT_Assert(sid->u.ssl2.masterKey.data == 0);
michael@0 1279 PORT_Assert(sid->u.ssl2.cipherArg.data == 0);
michael@0 1280
michael@0 1281 sid->version = SSL_LIBRARY_VERSION_2;
michael@0 1282
michael@0 1283 sid->u.ssl2.cipherType = cipher;
michael@0 1284 sid->u.ssl2.masterKey.data = (PRUint8*) PORT_Alloc(keyLen);
michael@0 1285 if (!sid->u.ssl2.masterKey.data) {
michael@0 1286 return SECFailure;
michael@0 1287 }
michael@0 1288 PORT_Memcpy(sid->u.ssl2.masterKey.data, keyData, keyLen);
michael@0 1289 sid->u.ssl2.masterKey.len = keyLen;
michael@0 1290 sid->u.ssl2.keyBits = keyBits;
michael@0 1291 sid->u.ssl2.secretKeyBits = secretKeyBits;
michael@0 1292 sid->authAlgorithm = authAlgorithm;
michael@0 1293 sid->authKeyBits = authKeyBits;
michael@0 1294 sid->keaType = keaType;
michael@0 1295 sid->keaKeyBits = keaKeyBits;
michael@0 1296 sid->lastAccessTime = sid->creationTime = ssl_Time();
michael@0 1297 sid->expirationTime = sid->creationTime + ssl_sid_timeout;
michael@0 1298
michael@0 1299 if (caLen) {
michael@0 1300 sid->u.ssl2.cipherArg.data = (PRUint8*) PORT_Alloc(caLen);
michael@0 1301 if (!sid->u.ssl2.cipherArg.data) {
michael@0 1302 return SECFailure;
michael@0 1303 }
michael@0 1304 sid->u.ssl2.cipherArg.len = caLen;
michael@0 1305 PORT_Memcpy(sid->u.ssl2.cipherArg.data, ca, caLen);
michael@0 1306 }
michael@0 1307 return SECSuccess;
michael@0 1308 }
michael@0 1309
michael@0 1310 /*
michael@0 1311 ** Construct session keys given the masterKey (tied to the session-id),
michael@0 1312 ** the client's challenge and the server's nonce.
michael@0 1313 **
michael@0 1314 ** Called from ssl2_CreateSessionCypher() <-
michael@0 1315 */
michael@0 1316 static SECStatus
michael@0 1317 ssl2_ProduceKeys(sslSocket * ss,
michael@0 1318 SECItem * readKey,
michael@0 1319 SECItem * writeKey,
michael@0 1320 SECItem * masterKey,
michael@0 1321 PRUint8 * challenge,
michael@0 1322 PRUint8 * nonce,
michael@0 1323 int cipherType)
michael@0 1324 {
michael@0 1325 PK11Context * cx = 0;
michael@0 1326 unsigned nkm = 0; /* number of hashes to generate key mat. */
michael@0 1327 unsigned nkd = 0; /* size of readKey and writeKey. */
michael@0 1328 unsigned part;
michael@0 1329 unsigned i;
michael@0 1330 unsigned off;
michael@0 1331 SECStatus rv;
michael@0 1332 PRUint8 countChar;
michael@0 1333 PRUint8 km[3*16]; /* buffer for key material. */
michael@0 1334
michael@0 1335 readKey->data = 0;
michael@0 1336 writeKey->data = 0;
michael@0 1337
michael@0 1338 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 1339
michael@0 1340 rv = SECSuccess;
michael@0 1341 cx = PK11_CreateDigestContext(SEC_OID_MD5);
michael@0 1342 if (cx == NULL) {
michael@0 1343 ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
michael@0 1344 return SECFailure;
michael@0 1345 }
michael@0 1346
michael@0 1347 nkm = ssl_Specs[cipherType].nkm;
michael@0 1348 nkd = ssl_Specs[cipherType].nkd;
michael@0 1349
michael@0 1350 readKey->data = (PRUint8*) PORT_Alloc(nkd);
michael@0 1351 if (!readKey->data)
michael@0 1352 goto loser;
michael@0 1353 readKey->len = nkd;
michael@0 1354
michael@0 1355 writeKey->data = (PRUint8*) PORT_Alloc(nkd);
michael@0 1356 if (!writeKey->data)
michael@0 1357 goto loser;
michael@0 1358 writeKey->len = nkd;
michael@0 1359
michael@0 1360 /* Produce key material */
michael@0 1361 countChar = '0';
michael@0 1362 for (i = 0, off = 0; i < nkm; i++, off += 16) {
michael@0 1363 rv = PK11_DigestBegin(cx);
michael@0 1364 rv |= PK11_DigestOp(cx, masterKey->data, masterKey->len);
michael@0 1365 rv |= PK11_DigestOp(cx, &countChar, 1);
michael@0 1366 rv |= PK11_DigestOp(cx, challenge, SSL_CHALLENGE_BYTES);
michael@0 1367 rv |= PK11_DigestOp(cx, nonce, SSL_CONNECTIONID_BYTES);
michael@0 1368 rv |= PK11_DigestFinal(cx, km+off, &part, MD5_LENGTH);
michael@0 1369 if (rv != SECSuccess) {
michael@0 1370 ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
michael@0 1371 rv = SECFailure;
michael@0 1372 goto loser;
michael@0 1373 }
michael@0 1374 countChar++;
michael@0 1375 }
michael@0 1376
michael@0 1377 /* Produce keys */
michael@0 1378 PORT_Memcpy(readKey->data, km, nkd);
michael@0 1379 PORT_Memcpy(writeKey->data, km + nkd, nkd);
michael@0 1380
michael@0 1381 loser:
michael@0 1382 PK11_DestroyContext(cx, PR_TRUE);
michael@0 1383 return rv;
michael@0 1384 }
michael@0 1385
michael@0 1386 /* Called from ssl2_ServerSetupSessionCypher()
michael@0 1387 ** <- ssl2_HandleClientSessionKeyMessage()
michael@0 1388 ** <- ssl2_HandleClientHelloMessage()
michael@0 1389 ** and from ssl2_ClientSetupSessionCypher()
michael@0 1390 ** <- ssl2_HandleServerHelloMessage()
michael@0 1391 */
michael@0 1392 static SECStatus
michael@0 1393 ssl2_CreateSessionCypher(sslSocket *ss, sslSessionID *sid, PRBool isClient)
michael@0 1394 {
michael@0 1395 SECItem * rk = NULL;
michael@0 1396 SECItem * wk = NULL;
michael@0 1397 SECItem * param;
michael@0 1398 SECStatus rv;
michael@0 1399 int cipherType = sid->u.ssl2.cipherType;
michael@0 1400 PK11SlotInfo * slot = NULL;
michael@0 1401 CK_MECHANISM_TYPE mechanism;
michael@0 1402 SECItem readKey;
michael@0 1403 SECItem writeKey;
michael@0 1404
michael@0 1405 void *readcx = 0;
michael@0 1406 void *writecx = 0;
michael@0 1407 readKey.data = 0;
michael@0 1408 writeKey.data = 0;
michael@0 1409
michael@0 1410 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 1411 if (ss->sec.ci.sid == 0)
michael@0 1412 goto sec_loser; /* don't crash if asserts are off */
michael@0 1413
michael@0 1414 /* Trying to cut down on all these switch statements that should be tables.
michael@0 1415 * So, test cipherType once, here, and then use tables below.
michael@0 1416 */
michael@0 1417 switch (cipherType) {
michael@0 1418 case SSL_CK_RC4_128_EXPORT40_WITH_MD5:
michael@0 1419 case SSL_CK_RC4_128_WITH_MD5:
michael@0 1420 case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:
michael@0 1421 case SSL_CK_RC2_128_CBC_WITH_MD5:
michael@0 1422 case SSL_CK_DES_64_CBC_WITH_MD5:
michael@0 1423 case SSL_CK_DES_192_EDE3_CBC_WITH_MD5:
michael@0 1424 break;
michael@0 1425
michael@0 1426 default:
michael@0 1427 SSL_DBG(("%d: SSL[%d]: ssl2_CreateSessionCypher: unknown cipher=%d",
michael@0 1428 SSL_GETPID(), ss->fd, cipherType));
michael@0 1429 PORT_SetError(isClient ? SSL_ERROR_BAD_SERVER : SSL_ERROR_BAD_CLIENT);
michael@0 1430 goto sec_loser;
michael@0 1431 }
michael@0 1432
michael@0 1433 rk = isClient ? &readKey : &writeKey;
michael@0 1434 wk = isClient ? &writeKey : &readKey;
michael@0 1435
michael@0 1436 /* Produce the keys for this session */
michael@0 1437 rv = ssl2_ProduceKeys(ss, &readKey, &writeKey, &sid->u.ssl2.masterKey,
michael@0 1438 ss->sec.ci.clientChallenge, ss->sec.ci.connectionID,
michael@0 1439 cipherType);
michael@0 1440 if (rv != SECSuccess)
michael@0 1441 goto loser;
michael@0 1442 PRINT_BUF(7, (ss, "Session read-key: ", rk->data, rk->len));
michael@0 1443 PRINT_BUF(7, (ss, "Session write-key: ", wk->data, wk->len));
michael@0 1444
michael@0 1445 PORT_Memcpy(ss->sec.ci.readKey, readKey.data, readKey.len);
michael@0 1446 PORT_Memcpy(ss->sec.ci.writeKey, writeKey.data, writeKey.len);
michael@0 1447 ss->sec.ci.keySize = readKey.len;
michael@0 1448
michael@0 1449 /* Setup the MAC */
michael@0 1450 rv = ssl2_CreateMAC(&ss->sec, rk, wk, cipherType);
michael@0 1451 if (rv != SECSuccess)
michael@0 1452 goto loser;
michael@0 1453
michael@0 1454 /* First create the session key object */
michael@0 1455 SSL_TRC(3, ("%d: SSL[%d]: using %s", SSL_GETPID(), ss->fd,
michael@0 1456 ssl_cipherName[cipherType]));
michael@0 1457
michael@0 1458
michael@0 1459 mechanism = ssl_Specs[cipherType].mechanism;
michael@0 1460
michael@0 1461 /* set destructer before we call loser... */
michael@0 1462 ss->sec.destroy = (void (*)(void*, PRBool)) PK11_DestroyContext;
michael@0 1463 slot = PK11_GetBestSlot(mechanism, ss->pkcs11PinArg);
michael@0 1464 if (slot == NULL)
michael@0 1465 goto loser;
michael@0 1466
michael@0 1467 param = PK11_ParamFromIV(mechanism, &sid->u.ssl2.cipherArg);
michael@0 1468 if (param == NULL)
michael@0 1469 goto loser;
michael@0 1470 readcx = PK11_CreateContextByRawKey(slot, mechanism, PK11_OriginUnwrap,
michael@0 1471 CKA_DECRYPT, rk, param,
michael@0 1472 ss->pkcs11PinArg);
michael@0 1473 SECITEM_FreeItem(param, PR_TRUE);
michael@0 1474 if (readcx == NULL)
michael@0 1475 goto loser;
michael@0 1476
michael@0 1477 /* build the client context */
michael@0 1478 param = PK11_ParamFromIV(mechanism, &sid->u.ssl2.cipherArg);
michael@0 1479 if (param == NULL)
michael@0 1480 goto loser;
michael@0 1481 writecx = PK11_CreateContextByRawKey(slot, mechanism, PK11_OriginUnwrap,
michael@0 1482 CKA_ENCRYPT, wk, param,
michael@0 1483 ss->pkcs11PinArg);
michael@0 1484 SECITEM_FreeItem(param,PR_TRUE);
michael@0 1485 if (writecx == NULL)
michael@0 1486 goto loser;
michael@0 1487 PK11_FreeSlot(slot);
michael@0 1488
michael@0 1489 rv = SECSuccess;
michael@0 1490 ss->sec.enc = (SSLCipher) PK11_CipherOp;
michael@0 1491 ss->sec.dec = (SSLCipher) PK11_CipherOp;
michael@0 1492 ss->sec.readcx = (void *) readcx;
michael@0 1493 ss->sec.writecx = (void *) writecx;
michael@0 1494 ss->sec.blockSize = ssl_Specs[cipherType].blockSize;
michael@0 1495 ss->sec.blockShift = ssl_Specs[cipherType].blockShift;
michael@0 1496 ss->sec.cipherType = sid->u.ssl2.cipherType;
michael@0 1497 ss->sec.keyBits = sid->u.ssl2.keyBits;
michael@0 1498 ss->sec.secretKeyBits = sid->u.ssl2.secretKeyBits;
michael@0 1499 goto done;
michael@0 1500
michael@0 1501 loser:
michael@0 1502 if (ss->sec.destroy) {
michael@0 1503 if (readcx) (*ss->sec.destroy)(readcx, PR_TRUE);
michael@0 1504 if (writecx) (*ss->sec.destroy)(writecx, PR_TRUE);
michael@0 1505 }
michael@0 1506 ss->sec.destroy = NULL;
michael@0 1507 if (slot) PK11_FreeSlot(slot);
michael@0 1508
michael@0 1509 sec_loser:
michael@0 1510 rv = SECFailure;
michael@0 1511
michael@0 1512 done:
michael@0 1513 if (rk) {
michael@0 1514 SECITEM_ZfreeItem(rk, PR_FALSE);
michael@0 1515 }
michael@0 1516 if (wk) {
michael@0 1517 SECITEM_ZfreeItem(wk, PR_FALSE);
michael@0 1518 }
michael@0 1519 return rv;
michael@0 1520 }
michael@0 1521
michael@0 1522 /*
michael@0 1523 ** Setup the server ciphers given information from a CLIENT-MASTER-KEY
michael@0 1524 ** message.
michael@0 1525 ** "ss" pointer to the ssl-socket object
michael@0 1526 ** "cipher" the cipher type to use
michael@0 1527 ** "keyBits" the size of the final cipher key
michael@0 1528 ** "ck" the clear-key data
michael@0 1529 ** "ckLen" the number of bytes of clear-key data
michael@0 1530 ** "ek" the encrypted-key data
michael@0 1531 ** "ekLen" the number of bytes of encrypted-key data
michael@0 1532 ** "ca" the cipher-arg data
michael@0 1533 ** "caLen" the number of bytes of cipher-arg data
michael@0 1534 **
michael@0 1535 ** The MASTER-KEY is constructed by first decrypting the encrypted-key
michael@0 1536 ** data. This produces the SECRET-KEY-DATA. The MASTER-KEY is composed by
michael@0 1537 ** concatenating the clear-key data with the SECRET-KEY-DATA. This code
michael@0 1538 ** checks to make sure that the client didn't send us an improper amount
michael@0 1539 ** of SECRET-KEY-DATA (it restricts the length of that data to match the
michael@0 1540 ** spec).
michael@0 1541 **
michael@0 1542 ** Called from ssl2_HandleClientSessionKeyMessage().
michael@0 1543 */
michael@0 1544 static SECStatus
michael@0 1545 ssl2_ServerSetupSessionCypher(sslSocket *ss, int cipher, unsigned int keyBits,
michael@0 1546 PRUint8 *ck, unsigned int ckLen,
michael@0 1547 PRUint8 *ek, unsigned int ekLen,
michael@0 1548 PRUint8 *ca, unsigned int caLen)
michael@0 1549 {
michael@0 1550 PRUint8 * dk = NULL; /* decrypted master key */
michael@0 1551 sslSessionID * sid;
michael@0 1552 sslServerCerts * sc = ss->serverCerts + kt_rsa;
michael@0 1553 PRUint8 * kbuf = 0; /* buffer for RSA decrypted data. */
michael@0 1554 unsigned int ddLen; /* length of RSA decrypted data in kbuf */
michael@0 1555 unsigned int keySize;
michael@0 1556 unsigned int dkLen; /* decrypted key length in bytes */
michael@0 1557 int modulusLen;
michael@0 1558 SECStatus rv;
michael@0 1559 PRUint16 allowed; /* cipher kinds enabled and allowed by policy */
michael@0 1560 PRUint8 mkbuf[SSL_MAX_MASTER_KEY_BYTES];
michael@0 1561
michael@0 1562 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 1563 PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
michael@0 1564 PORT_Assert((sc->SERVERKEY != 0));
michael@0 1565 PORT_Assert((ss->sec.ci.sid != 0));
michael@0 1566 sid = ss->sec.ci.sid;
michael@0 1567
michael@0 1568 /* Trying to cut down on all these switch statements that should be tables.
michael@0 1569 * So, test cipherType once, here, and then use tables below.
michael@0 1570 */
michael@0 1571 switch (cipher) {
michael@0 1572 case SSL_CK_RC4_128_EXPORT40_WITH_MD5:
michael@0 1573 case SSL_CK_RC4_128_WITH_MD5:
michael@0 1574 case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:
michael@0 1575 case SSL_CK_RC2_128_CBC_WITH_MD5:
michael@0 1576 case SSL_CK_DES_64_CBC_WITH_MD5:
michael@0 1577 case SSL_CK_DES_192_EDE3_CBC_WITH_MD5:
michael@0 1578 break;
michael@0 1579
michael@0 1580 default:
michael@0 1581 SSL_DBG(("%d: SSL[%d]: ssl2_ServerSetupSessionCypher: unknown cipher=%d",
michael@0 1582 SSL_GETPID(), ss->fd, cipher));
michael@0 1583 PORT_SetError(SSL_ERROR_BAD_CLIENT);
michael@0 1584 goto loser;
michael@0 1585 }
michael@0 1586
michael@0 1587 allowed = ss->allowedByPolicy & ss->chosenPreference & SSL_CB_IMPLEMENTED;
michael@0 1588 if (!(allowed & (1 << cipher))) {
michael@0 1589 /* client chose a kind we don't allow! */
michael@0 1590 SSL_DBG(("%d: SSL[%d]: disallowed cipher=%d",
michael@0 1591 SSL_GETPID(), ss->fd, cipher));
michael@0 1592 PORT_SetError(SSL_ERROR_BAD_CLIENT);
michael@0 1593 goto loser;
michael@0 1594 }
michael@0 1595
michael@0 1596 keySize = ssl_Specs[cipher].keyLen;
michael@0 1597 if (keyBits != keySize * BPB) {
michael@0 1598 SSL_DBG(("%d: SSL[%d]: invalid master secret key length=%d (bits)!",
michael@0 1599 SSL_GETPID(), ss->fd, keyBits));
michael@0 1600 PORT_SetError(SSL_ERROR_BAD_CLIENT);
michael@0 1601 goto loser;
michael@0 1602 }
michael@0 1603
michael@0 1604 if (ckLen != ssl_Specs[cipher].pubLen) {
michael@0 1605 SSL_DBG(("%d: SSL[%d]: invalid clear key length, ckLen=%d (bytes)!",
michael@0 1606 SSL_GETPID(), ss->fd, ckLen));
michael@0 1607 PORT_SetError(SSL_ERROR_BAD_CLIENT);
michael@0 1608 goto loser;
michael@0 1609 }
michael@0 1610
michael@0 1611 if (caLen != ssl_Specs[cipher].ivLen) {
michael@0 1612 SSL_DBG(("%d: SSL[%d]: invalid key args length, caLen=%d (bytes)!",
michael@0 1613 SSL_GETPID(), ss->fd, caLen));
michael@0 1614 PORT_SetError(SSL_ERROR_BAD_CLIENT);
michael@0 1615 goto loser;
michael@0 1616 }
michael@0 1617
michael@0 1618 modulusLen = PK11_GetPrivateModulusLen(sc->SERVERKEY);
michael@0 1619 if (modulusLen == -1) {
michael@0 1620 /* XXX If the key is bad, then PK11_PubDecryptRaw will fail below. */
michael@0 1621 modulusLen = ekLen;
michael@0 1622 }
michael@0 1623 if (ekLen > modulusLen || ekLen + ckLen < keySize) {
michael@0 1624 SSL_DBG(("%d: SSL[%d]: invalid encrypted key length, ekLen=%d (bytes)!",
michael@0 1625 SSL_GETPID(), ss->fd, ekLen));
michael@0 1626 PORT_SetError(SSL_ERROR_BAD_CLIENT);
michael@0 1627 goto loser;
michael@0 1628 }
michael@0 1629
michael@0 1630 /* allocate the buffer to hold the decrypted portion of the key. */
michael@0 1631 kbuf = (PRUint8*)PORT_Alloc(modulusLen);
michael@0 1632 if (!kbuf) {
michael@0 1633 goto loser;
michael@0 1634 }
michael@0 1635 dkLen = keySize - ckLen;
michael@0 1636 dk = kbuf + modulusLen - dkLen;
michael@0 1637
michael@0 1638 /* Decrypt encrypted half of the key.
michael@0 1639 ** NOTE: PK11_PubDecryptRaw will barf on a non-RSA key. This is
michael@0 1640 ** desired behavior here.
michael@0 1641 */
michael@0 1642 rv = PK11_PubDecryptRaw(sc->SERVERKEY, kbuf, &ddLen, modulusLen, ek, ekLen);
michael@0 1643 if (rv != SECSuccess)
michael@0 1644 goto hide_loser;
michael@0 1645
michael@0 1646 /* Is the length of the decrypted data (ddLen) the expected value? */
michael@0 1647 if (modulusLen != ddLen)
michael@0 1648 goto hide_loser;
michael@0 1649
michael@0 1650 /* Cheaply verify that PKCS#1 was used to format the encryption block */
michael@0 1651 if ((kbuf[0] != 0x00) || (kbuf[1] != 0x02) || (dk[-1] != 0x00)) {
michael@0 1652 SSL_DBG(("%d: SSL[%d]: strange encryption block",
michael@0 1653 SSL_GETPID(), ss->fd));
michael@0 1654 PORT_SetError(SSL_ERROR_BAD_CLIENT);
michael@0 1655 goto hide_loser;
michael@0 1656 }
michael@0 1657
michael@0 1658 /* Make sure we're not subject to a version rollback attack. */
michael@0 1659 if (!SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
michael@0 1660 static const PRUint8 threes[8] = { 0x03, 0x03, 0x03, 0x03,
michael@0 1661 0x03, 0x03, 0x03, 0x03 };
michael@0 1662
michael@0 1663 if (PORT_Memcmp(dk - 8 - 1, threes, 8) == 0) {
michael@0 1664 PORT_SetError(SSL_ERROR_BAD_CLIENT);
michael@0 1665 goto hide_loser;
michael@0 1666 }
michael@0 1667 }
michael@0 1668 if (0) {
michael@0 1669 hide_loser:
michael@0 1670 /* Defense against the Bleichenbacher attack.
michael@0 1671 * Provide the client with NO CLUES that the decrypted master key
michael@0 1672 * was erroneous. Don't send any error messages.
michael@0 1673 * Instead, Generate a completely bogus master key .
michael@0 1674 */
michael@0 1675 PK11_GenerateRandom(dk, dkLen);
michael@0 1676 }
michael@0 1677
michael@0 1678 /*
michael@0 1679 ** Construct master key out of the pieces.
michael@0 1680 */
michael@0 1681 if (ckLen) {
michael@0 1682 PORT_Memcpy(mkbuf, ck, ckLen);
michael@0 1683 }
michael@0 1684 PORT_Memcpy(mkbuf + ckLen, dk, dkLen);
michael@0 1685
michael@0 1686 /* Fill in session-id */
michael@0 1687 rv = ssl2_FillInSID(sid, cipher, mkbuf, keySize, ca, caLen,
michael@0 1688 keyBits, keyBits - (ckLen<<3),
michael@0 1689 ss->sec.authAlgorithm, ss->sec.authKeyBits,
michael@0 1690 ss->sec.keaType, ss->sec.keaKeyBits);
michael@0 1691 if (rv != SECSuccess) {
michael@0 1692 goto loser;
michael@0 1693 }
michael@0 1694
michael@0 1695 /* Create session ciphers */
michael@0 1696 rv = ssl2_CreateSessionCypher(ss, sid, PR_FALSE);
michael@0 1697 if (rv != SECSuccess) {
michael@0 1698 goto loser;
michael@0 1699 }
michael@0 1700
michael@0 1701 SSL_TRC(1, ("%d: SSL[%d]: server, using %s cipher, clear=%d total=%d",
michael@0 1702 SSL_GETPID(), ss->fd, ssl_cipherName[cipher],
michael@0 1703 ckLen<<3, keySize<<3));
michael@0 1704 rv = SECSuccess;
michael@0 1705 goto done;
michael@0 1706
michael@0 1707 loser:
michael@0 1708 rv = SECFailure;
michael@0 1709
michael@0 1710 done:
michael@0 1711 PORT_Free(kbuf);
michael@0 1712 return rv;
michael@0 1713 }
michael@0 1714
michael@0 1715 /************************************************************************/
michael@0 1716
michael@0 1717 /*
michael@0 1718 ** Rewrite the incoming cipher specs, comparing to list of specs we support,
michael@0 1719 ** (ss->cipherSpecs) and eliminating anything we don't support
michael@0 1720 **
michael@0 1721 * Note: Our list may contain SSL v3 ciphers.
michael@0 1722 * We MUST NOT match on any of those.
michael@0 1723 * Fortunately, this is easy to detect because SSLv3 ciphers have zero
michael@0 1724 * in the first byte, and none of the SSLv2 ciphers do.
michael@0 1725 *
michael@0 1726 * Called from ssl2_HandleClientHelloMessage().
michael@0 1727 * Returns the number of bytes of "qualified cipher specs",
michael@0 1728 * which is typically a multiple of 3, but will be zero if there are none.
michael@0 1729 */
michael@0 1730 static int
michael@0 1731 ssl2_QualifyCypherSpecs(sslSocket *ss,
michael@0 1732 PRUint8 * cs, /* cipher specs in client hello msg. */
michael@0 1733 int csLen)
michael@0 1734 {
michael@0 1735 PRUint8 * ms;
michael@0 1736 PRUint8 * hs;
michael@0 1737 PRUint8 * qs;
michael@0 1738 int mc;
michael@0 1739 int hc;
michael@0 1740 PRUint8 qualifiedSpecs[ssl2_NUM_SUITES_IMPLEMENTED * 3];
michael@0 1741
michael@0 1742 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 1743 PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
michael@0 1744
michael@0 1745 if (!ss->cipherSpecs) {
michael@0 1746 SECStatus rv = ssl2_ConstructCipherSpecs(ss);
michael@0 1747 if (rv != SECSuccess || !ss->cipherSpecs)
michael@0 1748 return 0;
michael@0 1749 }
michael@0 1750
michael@0 1751 PRINT_BUF(10, (ss, "specs from client:", cs, csLen));
michael@0 1752 qs = qualifiedSpecs;
michael@0 1753 ms = ss->cipherSpecs;
michael@0 1754 for (mc = ss->sizeCipherSpecs; mc > 0; mc -= 3, ms += 3) {
michael@0 1755 if (ms[0] == 0)
michael@0 1756 continue;
michael@0 1757 for (hs = cs, hc = csLen; hc > 0; hs += 3, hc -= 3) {
michael@0 1758 if ((hs[0] == ms[0]) &&
michael@0 1759 (hs[1] == ms[1]) &&
michael@0 1760 (hs[2] == ms[2])) {
michael@0 1761 /* Copy this cipher spec into the "keep" section */
michael@0 1762 qs[0] = hs[0];
michael@0 1763 qs[1] = hs[1];
michael@0 1764 qs[2] = hs[2];
michael@0 1765 qs += 3;
michael@0 1766 break;
michael@0 1767 }
michael@0 1768 }
michael@0 1769 }
michael@0 1770 hc = qs - qualifiedSpecs;
michael@0 1771 PRINT_BUF(10, (ss, "qualified specs from client:", qualifiedSpecs, hc));
michael@0 1772 PORT_Memcpy(cs, qualifiedSpecs, hc);
michael@0 1773 return hc;
michael@0 1774 }
michael@0 1775
michael@0 1776 /*
michael@0 1777 ** Pick the best cipher we can find, given the array of server cipher
michael@0 1778 ** specs. Returns cipher number (e.g. SSL_CK_*), or -1 for no overlap.
michael@0 1779 ** If successful, stores the master key size (bytes) in *pKeyLen.
michael@0 1780 **
michael@0 1781 ** This is correct only for the client side, but presently
michael@0 1782 ** this function is only called from
michael@0 1783 ** ssl2_ClientSetupSessionCypher() <- ssl2_HandleServerHelloMessage()
michael@0 1784 **
michael@0 1785 ** Note that most servers only return a single cipher suite in their
michael@0 1786 ** ServerHello messages. So, the code below for finding the "best" cipher
michael@0 1787 ** suite usually has only one choice. The client and server should send
michael@0 1788 ** their cipher suite lists sorted in descending order by preference.
michael@0 1789 */
michael@0 1790 static int
michael@0 1791 ssl2_ChooseSessionCypher(sslSocket *ss,
michael@0 1792 int hc, /* number of cs's in hs. */
michael@0 1793 PRUint8 * hs, /* server hello's cipher suites. */
michael@0 1794 int * pKeyLen) /* out: sym key size in bytes. */
michael@0 1795 {
michael@0 1796 PRUint8 * ms;
michael@0 1797 unsigned int i;
michael@0 1798 int bestKeySize;
michael@0 1799 int bestRealKeySize;
michael@0 1800 int bestCypher;
michael@0 1801 int keySize;
michael@0 1802 int realKeySize;
michael@0 1803 PRUint8 * ohs = hs;
michael@0 1804 const PRUint8 * preferred;
michael@0 1805 static const PRUint8 noneSuch[3] = { 0, 0, 0 };
michael@0 1806
michael@0 1807 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 1808 PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
michael@0 1809
michael@0 1810 if (!ss->cipherSpecs) {
michael@0 1811 SECStatus rv = ssl2_ConstructCipherSpecs(ss);
michael@0 1812 if (rv != SECSuccess || !ss->cipherSpecs)
michael@0 1813 goto loser;
michael@0 1814 }
michael@0 1815
michael@0 1816 if (!ss->preferredCipher) {
michael@0 1817 unsigned int allowed = ss->allowedByPolicy & ss->chosenPreference &
michael@0 1818 SSL_CB_IMPLEMENTED;
michael@0 1819 if (allowed) {
michael@0 1820 preferred = implementedCipherSuites;
michael@0 1821 for (i = ssl2_NUM_SUITES_IMPLEMENTED; i > 0; --i) {
michael@0 1822 if (0 != (allowed & (1U << preferred[0]))) {
michael@0 1823 ss->preferredCipher = preferred;
michael@0 1824 break;
michael@0 1825 }
michael@0 1826 preferred += 3;
michael@0 1827 }
michael@0 1828 }
michael@0 1829 }
michael@0 1830 preferred = ss->preferredCipher ? ss->preferredCipher : noneSuch;
michael@0 1831 /*
michael@0 1832 ** Scan list of ciphers received from peer and look for a match in
michael@0 1833 ** our list.
michael@0 1834 * Note: Our list may contain SSL v3 ciphers.
michael@0 1835 * We MUST NOT match on any of those.
michael@0 1836 * Fortunately, this is easy to detect because SSLv3 ciphers have zero
michael@0 1837 * in the first byte, and none of the SSLv2 ciphers do.
michael@0 1838 */
michael@0 1839 bestKeySize = bestRealKeySize = 0;
michael@0 1840 bestCypher = -1;
michael@0 1841 while (--hc >= 0) {
michael@0 1842 for (i = 0, ms = ss->cipherSpecs; i < ss->sizeCipherSpecs; i += 3, ms += 3) {
michael@0 1843 if ((hs[0] == preferred[0]) &&
michael@0 1844 (hs[1] == preferred[1]) &&
michael@0 1845 (hs[2] == preferred[2]) &&
michael@0 1846 hs[0] != 0) {
michael@0 1847 /* Pick this cipher immediately! */
michael@0 1848 *pKeyLen = (((hs[1] << 8) | hs[2]) + 7) >> 3;
michael@0 1849 return hs[0];
michael@0 1850 }
michael@0 1851 if ((hs[0] == ms[0]) && (hs[1] == ms[1]) && (hs[2] == ms[2]) &&
michael@0 1852 hs[0] != 0) {
michael@0 1853 /* Found a match */
michael@0 1854
michael@0 1855 /* Use secret keySize to determine which cipher is best */
michael@0 1856 realKeySize = (hs[1] << 8) | hs[2];
michael@0 1857 switch (hs[0]) {
michael@0 1858 case SSL_CK_RC4_128_EXPORT40_WITH_MD5:
michael@0 1859 case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:
michael@0 1860 keySize = 40;
michael@0 1861 break;
michael@0 1862 default:
michael@0 1863 keySize = realKeySize;
michael@0 1864 break;
michael@0 1865 }
michael@0 1866 if (keySize > bestKeySize) {
michael@0 1867 bestCypher = hs[0];
michael@0 1868 bestKeySize = keySize;
michael@0 1869 bestRealKeySize = realKeySize;
michael@0 1870 }
michael@0 1871 }
michael@0 1872 }
michael@0 1873 hs += 3;
michael@0 1874 }
michael@0 1875 if (bestCypher < 0) {
michael@0 1876 /*
michael@0 1877 ** No overlap between server and client. Re-examine server list
michael@0 1878 ** to see what kind of ciphers it does support so that we can set
michael@0 1879 ** the error code appropriately.
michael@0 1880 */
michael@0 1881 if ((ohs[0] == SSL_CK_RC4_128_WITH_MD5) ||
michael@0 1882 (ohs[0] == SSL_CK_RC2_128_CBC_WITH_MD5)) {
michael@0 1883 PORT_SetError(SSL_ERROR_US_ONLY_SERVER);
michael@0 1884 } else if ((ohs[0] == SSL_CK_RC4_128_EXPORT40_WITH_MD5) ||
michael@0 1885 (ohs[0] == SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5)) {
michael@0 1886 PORT_SetError(SSL_ERROR_EXPORT_ONLY_SERVER);
michael@0 1887 } else {
michael@0 1888 PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
michael@0 1889 }
michael@0 1890 SSL_DBG(("%d: SSL[%d]: no cipher overlap", SSL_GETPID(), ss->fd));
michael@0 1891 goto loser;
michael@0 1892 }
michael@0 1893 *pKeyLen = (bestRealKeySize + 7) >> 3;
michael@0 1894 return bestCypher;
michael@0 1895
michael@0 1896 loser:
michael@0 1897 return -1;
michael@0 1898 }
michael@0 1899
michael@0 1900 static SECStatus
michael@0 1901 ssl2_ClientHandleServerCert(sslSocket *ss, PRUint8 *certData, int certLen)
michael@0 1902 {
michael@0 1903 CERTCertificate *cert = NULL;
michael@0 1904 SECItem certItem;
michael@0 1905
michael@0 1906 certItem.data = certData;
michael@0 1907 certItem.len = certLen;
michael@0 1908
michael@0 1909 /* decode the certificate */
michael@0 1910 cert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL,
michael@0 1911 PR_FALSE, PR_TRUE);
michael@0 1912
michael@0 1913 if (cert == NULL) {
michael@0 1914 SSL_DBG(("%d: SSL[%d]: decode of server certificate fails",
michael@0 1915 SSL_GETPID(), ss->fd));
michael@0 1916 PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
michael@0 1917 return SECFailure;
michael@0 1918 }
michael@0 1919
michael@0 1920 #ifdef TRACE
michael@0 1921 {
michael@0 1922 if (ssl_trace >= 1) {
michael@0 1923 char *issuer;
michael@0 1924 char *subject;
michael@0 1925 issuer = CERT_NameToAscii(&cert->issuer);
michael@0 1926 subject = CERT_NameToAscii(&cert->subject);
michael@0 1927 SSL_TRC(1,("%d: server certificate issuer: '%s'",
michael@0 1928 SSL_GETPID(), issuer ? issuer : "OOPS"));
michael@0 1929 SSL_TRC(1,("%d: server name: '%s'",
michael@0 1930 SSL_GETPID(), subject ? subject : "OOPS"));
michael@0 1931 PORT_Free(issuer);
michael@0 1932 PORT_Free(subject);
michael@0 1933 }
michael@0 1934 }
michael@0 1935 #endif
michael@0 1936
michael@0 1937 ss->sec.peerCert = cert;
michael@0 1938 return SECSuccess;
michael@0 1939 }
michael@0 1940
michael@0 1941
michael@0 1942 /*
michael@0 1943 * Format one block of data for public/private key encryption using
michael@0 1944 * the rules defined in PKCS #1. SSL2 does this itself to handle the
michael@0 1945 * rollback detection.
michael@0 1946 */
michael@0 1947 #define RSA_BLOCK_MIN_PAD_LEN 8
michael@0 1948 #define RSA_BLOCK_FIRST_OCTET 0x00
michael@0 1949 #define RSA_BLOCK_AFTER_PAD_OCTET 0x00
michael@0 1950 #define RSA_BLOCK_PUBLIC_OCTET 0x02
michael@0 1951 unsigned char *
michael@0 1952 ssl_FormatSSL2Block(unsigned modulusLen, SECItem *data)
michael@0 1953 {
michael@0 1954 unsigned char *block;
michael@0 1955 unsigned char *bp;
michael@0 1956 int padLen;
michael@0 1957 SECStatus rv;
michael@0 1958 int i;
michael@0 1959
michael@0 1960 if (modulusLen < data->len + (3 + RSA_BLOCK_MIN_PAD_LEN)) {
michael@0 1961 PORT_SetError(SEC_ERROR_BAD_KEY);
michael@0 1962 return NULL;
michael@0 1963 }
michael@0 1964 block = (unsigned char *) PORT_Alloc(modulusLen);
michael@0 1965 if (block == NULL)
michael@0 1966 return NULL;
michael@0 1967
michael@0 1968 bp = block;
michael@0 1969
michael@0 1970 /*
michael@0 1971 * All RSA blocks start with two octets:
michael@0 1972 * 0x00 || BlockType
michael@0 1973 */
michael@0 1974 *bp++ = RSA_BLOCK_FIRST_OCTET;
michael@0 1975 *bp++ = RSA_BLOCK_PUBLIC_OCTET;
michael@0 1976
michael@0 1977 /*
michael@0 1978 * 0x00 || BT || Pad || 0x00 || ActualData
michael@0 1979 * 1 1 padLen 1 data->len
michael@0 1980 * Pad is all non-zero random bytes.
michael@0 1981 */
michael@0 1982 padLen = modulusLen - data->len - 3;
michael@0 1983 PORT_Assert (padLen >= RSA_BLOCK_MIN_PAD_LEN);
michael@0 1984 rv = PK11_GenerateRandom(bp, padLen);
michael@0 1985 if (rv == SECFailure) goto loser;
michael@0 1986 /* replace all the 'zero' bytes */
michael@0 1987 for (i = 0; i < padLen; i++) {
michael@0 1988 while (bp[i] == RSA_BLOCK_AFTER_PAD_OCTET) {
michael@0 1989 rv = PK11_GenerateRandom(bp+i, 1);
michael@0 1990 if (rv == SECFailure) goto loser;
michael@0 1991 }
michael@0 1992 }
michael@0 1993 bp += padLen;
michael@0 1994 *bp++ = RSA_BLOCK_AFTER_PAD_OCTET;
michael@0 1995 PORT_Memcpy (bp, data->data, data->len);
michael@0 1996
michael@0 1997 return block;
michael@0 1998 loser:
michael@0 1999 if (block) PORT_Free(block);
michael@0 2000 return NULL;
michael@0 2001 }
michael@0 2002
michael@0 2003 /*
michael@0 2004 ** Given the server's public key and cipher specs, generate a session key
michael@0 2005 ** that is ready to use for encrypting/decrypting the byte stream. At
michael@0 2006 ** the same time, generate the SSL_MT_CLIENT_MASTER_KEY message and
michael@0 2007 ** send it to the server.
michael@0 2008 **
michael@0 2009 ** Called from ssl2_HandleServerHelloMessage()
michael@0 2010 */
michael@0 2011 static SECStatus
michael@0 2012 ssl2_ClientSetupSessionCypher(sslSocket *ss, PRUint8 *cs, int csLen)
michael@0 2013 {
michael@0 2014 sslSessionID * sid;
michael@0 2015 PRUint8 * ca; /* points to iv data, or NULL if none. */
michael@0 2016 PRUint8 * ekbuf = 0;
michael@0 2017 CERTCertificate * cert = 0;
michael@0 2018 SECKEYPublicKey * serverKey = 0;
michael@0 2019 unsigned modulusLen = 0;
michael@0 2020 SECStatus rv;
michael@0 2021 int cipher;
michael@0 2022 int keyLen; /* cipher symkey size in bytes. */
michael@0 2023 int ckLen; /* publicly reveal this many bytes of key. */
michael@0 2024 int caLen; /* length of IV data at *ca. */
michael@0 2025 int nc;
michael@0 2026
michael@0 2027 unsigned char *eblock; /* holds unencrypted PKCS#1 formatted key. */
michael@0 2028 SECItem rek; /* holds portion of symkey to be encrypted. */
michael@0 2029
michael@0 2030 PRUint8 keyData[SSL_MAX_MASTER_KEY_BYTES];
michael@0 2031 PRUint8 iv [8];
michael@0 2032
michael@0 2033 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 2034
michael@0 2035 eblock = NULL;
michael@0 2036
michael@0 2037 sid = ss->sec.ci.sid;
michael@0 2038 PORT_Assert(sid != 0);
michael@0 2039
michael@0 2040 cert = ss->sec.peerCert;
michael@0 2041
michael@0 2042 serverKey = CERT_ExtractPublicKey(cert);
michael@0 2043 if (!serverKey) {
michael@0 2044 SSL_DBG(("%d: SSL[%d]: extract public key failed: error=%d",
michael@0 2045 SSL_GETPID(), ss->fd, PORT_GetError()));
michael@0 2046 PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
michael@0 2047 rv = SECFailure;
michael@0 2048 goto loser2;
michael@0 2049 }
michael@0 2050
michael@0 2051 ss->sec.authAlgorithm = ssl_sign_rsa;
michael@0 2052 ss->sec.keaType = ssl_kea_rsa;
michael@0 2053 ss->sec.keaKeyBits = \
michael@0 2054 ss->sec.authKeyBits = SECKEY_PublicKeyStrengthInBits(serverKey);
michael@0 2055
michael@0 2056 /* Choose a compatible cipher with the server */
michael@0 2057 nc = csLen / 3;
michael@0 2058 cipher = ssl2_ChooseSessionCypher(ss, nc, cs, &keyLen);
michael@0 2059 if (cipher < 0) {
michael@0 2060 /* ssl2_ChooseSessionCypher has set error code. */
michael@0 2061 ssl2_SendErrorMessage(ss, SSL_PE_NO_CYPHERS);
michael@0 2062 goto loser;
michael@0 2063 }
michael@0 2064
michael@0 2065 /* Generate the random keys */
michael@0 2066 PK11_GenerateRandom(keyData, sizeof(keyData));
michael@0 2067
michael@0 2068 /*
michael@0 2069 ** Next, carve up the keys into clear and encrypted portions. The
michael@0 2070 ** clear data is taken from the start of keyData and the encrypted
michael@0 2071 ** portion from the remainder. Note that each of these portions is
michael@0 2072 ** carved in half, one half for the read-key and one for the
michael@0 2073 ** write-key.
michael@0 2074 */
michael@0 2075 ca = 0;
michael@0 2076
michael@0 2077 /* We know that cipher is a legit value here, because
michael@0 2078 * ssl2_ChooseSessionCypher doesn't return bogus values.
michael@0 2079 */
michael@0 2080 ckLen = ssl_Specs[cipher].pubLen; /* cleartext key length. */
michael@0 2081 caLen = ssl_Specs[cipher].ivLen; /* IV length. */
michael@0 2082 if (caLen) {
michael@0 2083 PORT_Assert(sizeof iv >= caLen);
michael@0 2084 PK11_GenerateRandom(iv, caLen);
michael@0 2085 ca = iv;
michael@0 2086 }
michael@0 2087
michael@0 2088 /* Fill in session-id */
michael@0 2089 rv = ssl2_FillInSID(sid, cipher, keyData, keyLen,
michael@0 2090 ca, caLen, keyLen << 3, (keyLen - ckLen) << 3,
michael@0 2091 ss->sec.authAlgorithm, ss->sec.authKeyBits,
michael@0 2092 ss->sec.keaType, ss->sec.keaKeyBits);
michael@0 2093 if (rv != SECSuccess) {
michael@0 2094 goto loser;
michael@0 2095 }
michael@0 2096
michael@0 2097 SSL_TRC(1, ("%d: SSL[%d]: client, using %s cipher, clear=%d total=%d",
michael@0 2098 SSL_GETPID(), ss->fd, ssl_cipherName[cipher],
michael@0 2099 ckLen<<3, keyLen<<3));
michael@0 2100
michael@0 2101 /* Now setup read and write ciphers */
michael@0 2102 rv = ssl2_CreateSessionCypher(ss, sid, PR_TRUE);
michael@0 2103 if (rv != SECSuccess) {
michael@0 2104 goto loser;
michael@0 2105 }
michael@0 2106
michael@0 2107 /*
michael@0 2108 ** Fill in the encryption buffer with some random bytes. Then
michael@0 2109 ** copy in the portion of the session key we are encrypting.
michael@0 2110 */
michael@0 2111 modulusLen = SECKEY_PublicKeyStrength(serverKey);
michael@0 2112 rek.data = keyData + ckLen;
michael@0 2113 rek.len = keyLen - ckLen;
michael@0 2114 eblock = ssl_FormatSSL2Block(modulusLen, &rek);
michael@0 2115 if (eblock == NULL)
michael@0 2116 goto loser;
michael@0 2117
michael@0 2118 /* Set up the padding for version 2 rollback detection. */
michael@0 2119 /* XXX We should really use defines here */
michael@0 2120 if (!SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
michael@0 2121 PORT_Assert((modulusLen - rek.len) > 12);
michael@0 2122 PORT_Memset(eblock + modulusLen - rek.len - 8 - 1, 0x03, 8);
michael@0 2123 }
michael@0 2124 ekbuf = (PRUint8*) PORT_Alloc(modulusLen);
michael@0 2125 if (!ekbuf)
michael@0 2126 goto loser;
michael@0 2127 PRINT_BUF(10, (ss, "master key encryption block:",
michael@0 2128 eblock, modulusLen));
michael@0 2129
michael@0 2130 /* Encrypt ekitem */
michael@0 2131 rv = PK11_PubEncryptRaw(serverKey, ekbuf, eblock, modulusLen,
michael@0 2132 ss->pkcs11PinArg);
michael@0 2133 if (rv)
michael@0 2134 goto loser;
michael@0 2135
michael@0 2136 /* Now we have everything ready to send */
michael@0 2137 rv = ssl2_SendSessionKeyMessage(ss, cipher, keyLen << 3, ca, caLen,
michael@0 2138 keyData, ckLen, ekbuf, modulusLen);
michael@0 2139 if (rv != SECSuccess) {
michael@0 2140 goto loser;
michael@0 2141 }
michael@0 2142 rv = SECSuccess;
michael@0 2143 goto done;
michael@0 2144
michael@0 2145 loser:
michael@0 2146 rv = SECFailure;
michael@0 2147
michael@0 2148 loser2:
michael@0 2149 done:
michael@0 2150 PORT_Memset(keyData, 0, sizeof(keyData));
michael@0 2151 PORT_ZFree(ekbuf, modulusLen);
michael@0 2152 PORT_ZFree(eblock, modulusLen);
michael@0 2153 SECKEY_DestroyPublicKey(serverKey);
michael@0 2154 return rv;
michael@0 2155 }
michael@0 2156
michael@0 2157 /************************************************************************/
michael@0 2158
michael@0 2159 /*
michael@0 2160 * Called from ssl2_HandleMessage in response to SSL_MT_SERVER_FINISHED message.
michael@0 2161 * Caller holds recvBufLock and handshakeLock
michael@0 2162 */
michael@0 2163 static void
michael@0 2164 ssl2_ClientRegSessionID(sslSocket *ss, PRUint8 *s)
michael@0 2165 {
michael@0 2166 sslSessionID *sid = ss->sec.ci.sid;
michael@0 2167
michael@0 2168 /* Record entry in nonce cache */
michael@0 2169 if (sid->peerCert == NULL) {
michael@0 2170 PORT_Memcpy(sid->u.ssl2.sessionID, s, sizeof(sid->u.ssl2.sessionID));
michael@0 2171 sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);
michael@0 2172
michael@0 2173 }
michael@0 2174 if (!ss->opt.noCache && sid->cached == never_cached)
michael@0 2175 (*ss->sec.cache)(sid);
michael@0 2176 }
michael@0 2177
michael@0 2178 /* Called from ssl2_HandleMessage() */
michael@0 2179 static SECStatus
michael@0 2180 ssl2_TriggerNextMessage(sslSocket *ss)
michael@0 2181 {
michael@0 2182 SECStatus rv;
michael@0 2183
michael@0 2184 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 2185
michael@0 2186 if ((ss->sec.ci.requiredElements & CIS_HAVE_CERTIFICATE) &&
michael@0 2187 !(ss->sec.ci.sentElements & CIS_HAVE_CERTIFICATE)) {
michael@0 2188 ss->sec.ci.sentElements |= CIS_HAVE_CERTIFICATE;
michael@0 2189 rv = ssl2_SendCertificateRequestMessage(ss);
michael@0 2190 return rv;
michael@0 2191 }
michael@0 2192 return SECSuccess;
michael@0 2193 }
michael@0 2194
michael@0 2195 /* See if it's time to send our finished message, or if the handshakes are
michael@0 2196 ** complete. Send finished message if appropriate.
michael@0 2197 ** Returns SECSuccess unless anything goes wrong.
michael@0 2198 **
michael@0 2199 ** Called from ssl2_HandleMessage,
michael@0 2200 ** ssl2_HandleVerifyMessage
michael@0 2201 ** ssl2_HandleServerHelloMessage
michael@0 2202 ** ssl2_HandleClientSessionKeyMessage
michael@0 2203 */
michael@0 2204 static SECStatus
michael@0 2205 ssl2_TryToFinish(sslSocket *ss)
michael@0 2206 {
michael@0 2207 SECStatus rv;
michael@0 2208 char e, ef;
michael@0 2209
michael@0 2210 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 2211
michael@0 2212 e = ss->sec.ci.elements;
michael@0 2213 ef = e | CIS_HAVE_FINISHED;
michael@0 2214 if ((ef & ss->sec.ci.requiredElements) == ss->sec.ci.requiredElements) {
michael@0 2215 if (ss->sec.isServer) {
michael@0 2216 /* Send server finished message if we already didn't */
michael@0 2217 rv = ssl2_SendServerFinishedMessage(ss);
michael@0 2218 } else {
michael@0 2219 /* Send client finished message if we already didn't */
michael@0 2220 rv = ssl2_SendClientFinishedMessage(ss);
michael@0 2221 }
michael@0 2222 if (rv != SECSuccess) {
michael@0 2223 return rv;
michael@0 2224 }
michael@0 2225 if ((e & ss->sec.ci.requiredElements) == ss->sec.ci.requiredElements) {
michael@0 2226 /* Totally finished */
michael@0 2227 ss->handshake = 0;
michael@0 2228 return SECSuccess;
michael@0 2229 }
michael@0 2230 }
michael@0 2231 return SECSuccess;
michael@0 2232 }
michael@0 2233
michael@0 2234 /*
michael@0 2235 ** Called from ssl2_HandleRequestCertificate
michael@0 2236 */
michael@0 2237 static SECStatus
michael@0 2238 ssl2_SignResponse(sslSocket *ss,
michael@0 2239 SECKEYPrivateKey *key,
michael@0 2240 SECItem *response)
michael@0 2241 {
michael@0 2242 SGNContext * sgn = NULL;
michael@0 2243 PRUint8 * challenge;
michael@0 2244 unsigned int len;
michael@0 2245 SECStatus rv = SECFailure;
michael@0 2246
michael@0 2247 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 2248
michael@0 2249 challenge = ss->sec.ci.serverChallenge;
michael@0 2250 len = ss->sec.ci.serverChallengeLen;
michael@0 2251
michael@0 2252 /* Sign the expected data... */
michael@0 2253 sgn = SGN_NewContext(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,key);
michael@0 2254 if (!sgn)
michael@0 2255 goto done;
michael@0 2256 rv = SGN_Begin(sgn);
michael@0 2257 if (rv != SECSuccess)
michael@0 2258 goto done;
michael@0 2259 rv = SGN_Update(sgn, ss->sec.ci.readKey, ss->sec.ci.keySize);
michael@0 2260 if (rv != SECSuccess)
michael@0 2261 goto done;
michael@0 2262 rv = SGN_Update(sgn, ss->sec.ci.writeKey, ss->sec.ci.keySize);
michael@0 2263 if (rv != SECSuccess)
michael@0 2264 goto done;
michael@0 2265 rv = SGN_Update(sgn, challenge, len);
michael@0 2266 if (rv != SECSuccess)
michael@0 2267 goto done;
michael@0 2268 rv = SGN_Update(sgn, ss->sec.peerCert->derCert.data,
michael@0 2269 ss->sec.peerCert->derCert.len);
michael@0 2270 if (rv != SECSuccess)
michael@0 2271 goto done;
michael@0 2272 rv = SGN_End(sgn, response);
michael@0 2273 if (rv != SECSuccess)
michael@0 2274 goto done;
michael@0 2275
michael@0 2276 done:
michael@0 2277 SGN_DestroyContext(sgn, PR_TRUE);
michael@0 2278 return rv == SECSuccess ? SECSuccess : SECFailure;
michael@0 2279 }
michael@0 2280
michael@0 2281 /*
michael@0 2282 ** Try to handle a request-certificate message. Get client's certificate
michael@0 2283 ** and private key and sign a message for the server to see.
michael@0 2284 ** Caller must hold handshakeLock
michael@0 2285 **
michael@0 2286 ** Called from ssl2_HandleMessage().
michael@0 2287 */
michael@0 2288 static int
michael@0 2289 ssl2_HandleRequestCertificate(sslSocket *ss)
michael@0 2290 {
michael@0 2291 CERTCertificate * cert = NULL; /* app-selected client cert. */
michael@0 2292 SECKEYPrivateKey *key = NULL; /* priv key for cert. */
michael@0 2293 SECStatus rv;
michael@0 2294 SECItem response;
michael@0 2295 int ret = 0;
michael@0 2296 PRUint8 authType;
michael@0 2297
michael@0 2298
michael@0 2299 /*
michael@0 2300 * These things all need to be initialized before we can "goto loser".
michael@0 2301 */
michael@0 2302 response.data = NULL;
michael@0 2303
michael@0 2304 /* get challenge info from connectionInfo */
michael@0 2305 authType = ss->sec.ci.authType;
michael@0 2306
michael@0 2307 if (authType != SSL_AT_MD5_WITH_RSA_ENCRYPTION) {
michael@0 2308 SSL_TRC(7, ("%d: SSL[%d]: unsupported auth type 0x%x", SSL_GETPID(),
michael@0 2309 ss->fd, authType));
michael@0 2310 goto no_cert_error;
michael@0 2311 }
michael@0 2312
michael@0 2313 /* Get certificate and private-key from client */
michael@0 2314 if (!ss->getClientAuthData) {
michael@0 2315 SSL_TRC(7, ("%d: SSL[%d]: client doesn't support client-auth",
michael@0 2316 SSL_GETPID(), ss->fd));
michael@0 2317 goto no_cert_error;
michael@0 2318 }
michael@0 2319 ret = (*ss->getClientAuthData)(ss->getClientAuthDataArg, ss->fd,
michael@0 2320 NULL, &cert, &key);
michael@0 2321 if ( ret == SECWouldBlock ) {
michael@0 2322 PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
michael@0 2323 ret = -1;
michael@0 2324 goto loser;
michael@0 2325 }
michael@0 2326
michael@0 2327 if (ret) {
michael@0 2328 goto no_cert_error;
michael@0 2329 }
michael@0 2330
michael@0 2331 /* check what the callback function returned */
michael@0 2332 if ((!cert) || (!key)) {
michael@0 2333 /* we are missing either the key or cert */
michael@0 2334 if (cert) {
michael@0 2335 /* got a cert, but no key - free it */
michael@0 2336 CERT_DestroyCertificate(cert);
michael@0 2337 cert = NULL;
michael@0 2338 }
michael@0 2339 if (key) {
michael@0 2340 /* got a key, but no cert - free it */
michael@0 2341 SECKEY_DestroyPrivateKey(key);
michael@0 2342 key = NULL;
michael@0 2343 }
michael@0 2344 goto no_cert_error;
michael@0 2345 }
michael@0 2346
michael@0 2347 rv = ssl2_SignResponse(ss, key, &response);
michael@0 2348 if ( rv != SECSuccess ) {
michael@0 2349 ret = -1;
michael@0 2350 goto loser;
michael@0 2351 }
michael@0 2352
michael@0 2353 /* Send response message */
michael@0 2354 ret = ssl2_SendCertificateResponseMessage(ss, &cert->derCert, &response);
michael@0 2355
michael@0 2356 /* Now, remember the cert we sent. But first, forget any previous one. */
michael@0 2357 if (ss->sec.localCert) {
michael@0 2358 CERT_DestroyCertificate(ss->sec.localCert);
michael@0 2359 }
michael@0 2360 ss->sec.localCert = CERT_DupCertificate(cert);
michael@0 2361 PORT_Assert(!ss->sec.ci.sid->localCert);
michael@0 2362 if (ss->sec.ci.sid->localCert) {
michael@0 2363 CERT_DestroyCertificate(ss->sec.ci.sid->localCert);
michael@0 2364 }
michael@0 2365 ss->sec.ci.sid->localCert = cert;
michael@0 2366 cert = NULL;
michael@0 2367
michael@0 2368 goto done;
michael@0 2369
michael@0 2370 no_cert_error:
michael@0 2371 SSL_TRC(7, ("%d: SSL[%d]: no certificate (ret=%d)", SSL_GETPID(),
michael@0 2372 ss->fd, ret));
michael@0 2373 ret = ssl2_SendErrorMessage(ss, SSL_PE_NO_CERTIFICATE);
michael@0 2374
michael@0 2375 loser:
michael@0 2376 done:
michael@0 2377 if ( cert ) {
michael@0 2378 CERT_DestroyCertificate(cert);
michael@0 2379 }
michael@0 2380 if ( key ) {
michael@0 2381 SECKEY_DestroyPrivateKey(key);
michael@0 2382 }
michael@0 2383 if ( response.data ) {
michael@0 2384 PORT_Free(response.data);
michael@0 2385 }
michael@0 2386
michael@0 2387 return ret;
michael@0 2388 }
michael@0 2389
michael@0 2390 /*
michael@0 2391 ** Called from ssl2_HandleMessage for SSL_MT_CLIENT_CERTIFICATE message.
michael@0 2392 ** Caller must hold HandshakeLock and RecvBufLock, since cd and response
michael@0 2393 ** are contained in the gathered input data.
michael@0 2394 */
michael@0 2395 static SECStatus
michael@0 2396 ssl2_HandleClientCertificate(sslSocket * ss,
michael@0 2397 PRUint8 certType, /* XXX unused */
michael@0 2398 PRUint8 * cd,
michael@0 2399 unsigned int cdLen,
michael@0 2400 PRUint8 * response,
michael@0 2401 unsigned int responseLen)
michael@0 2402 {
michael@0 2403 CERTCertificate *cert = NULL;
michael@0 2404 SECKEYPublicKey *pubKey = NULL;
michael@0 2405 VFYContext * vfy = NULL;
michael@0 2406 SECItem * derCert;
michael@0 2407 SECStatus rv = SECFailure;
michael@0 2408 SECItem certItem;
michael@0 2409 SECItem rep;
michael@0 2410
michael@0 2411 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 2412 PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
michael@0 2413
michael@0 2414 /* Extract the certificate */
michael@0 2415 certItem.data = cd;
michael@0 2416 certItem.len = cdLen;
michael@0 2417
michael@0 2418 cert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL,
michael@0 2419 PR_FALSE, PR_TRUE);
michael@0 2420 if (cert == NULL) {
michael@0 2421 goto loser;
michael@0 2422 }
michael@0 2423
michael@0 2424 /* save the certificate, since the auth routine will need it */
michael@0 2425 ss->sec.peerCert = cert;
michael@0 2426
michael@0 2427 /* Extract the public key */
michael@0 2428 pubKey = CERT_ExtractPublicKey(cert);
michael@0 2429 if (!pubKey)
michael@0 2430 goto loser;
michael@0 2431
michael@0 2432 /* Verify the response data... */
michael@0 2433 rep.data = response;
michael@0 2434 rep.len = responseLen;
michael@0 2435 /* SSL 2.0 only supports RSA certs, so we don't have to worry about
michael@0 2436 * DSA here. */
michael@0 2437 vfy = VFY_CreateContext(pubKey, &rep, SEC_OID_PKCS1_RSA_ENCRYPTION,
michael@0 2438 ss->pkcs11PinArg);
michael@0 2439 if (!vfy)
michael@0 2440 goto loser;
michael@0 2441 rv = VFY_Begin(vfy);
michael@0 2442 if (rv)
michael@0 2443 goto loser;
michael@0 2444
michael@0 2445 rv = VFY_Update(vfy, ss->sec.ci.readKey, ss->sec.ci.keySize);
michael@0 2446 if (rv)
michael@0 2447 goto loser;
michael@0 2448 rv = VFY_Update(vfy, ss->sec.ci.writeKey, ss->sec.ci.keySize);
michael@0 2449 if (rv)
michael@0 2450 goto loser;
michael@0 2451 rv = VFY_Update(vfy, ss->sec.ci.serverChallenge, SSL_CHALLENGE_BYTES);
michael@0 2452 if (rv)
michael@0 2453 goto loser;
michael@0 2454
michael@0 2455 derCert = &ss->serverCerts[kt_rsa].serverCert->derCert;
michael@0 2456 rv = VFY_Update(vfy, derCert->data, derCert->len);
michael@0 2457 if (rv)
michael@0 2458 goto loser;
michael@0 2459 rv = VFY_End(vfy);
michael@0 2460 if (rv)
michael@0 2461 goto loser;
michael@0 2462
michael@0 2463 /* Now ask the server application if it likes the certificate... */
michael@0 2464 rv = (SECStatus) (*ss->authCertificate)(ss->authCertificateArg,
michael@0 2465 ss->fd, PR_TRUE, PR_TRUE);
michael@0 2466 /* Hey, it liked it. */
michael@0 2467 if (SECSuccess == rv)
michael@0 2468 goto done;
michael@0 2469
michael@0 2470 loser:
michael@0 2471 ss->sec.peerCert = NULL;
michael@0 2472 CERT_DestroyCertificate(cert);
michael@0 2473
michael@0 2474 done:
michael@0 2475 VFY_DestroyContext(vfy, PR_TRUE);
michael@0 2476 SECKEY_DestroyPublicKey(pubKey);
michael@0 2477 return rv;
michael@0 2478 }
michael@0 2479
michael@0 2480 /*
michael@0 2481 ** Handle remaining messages between client/server. Process finished
michael@0 2482 ** messages from either side and any authentication requests.
michael@0 2483 ** This should only be called for SSLv2 handshake messages,
michael@0 2484 ** not for application data records.
michael@0 2485 ** Caller must hold handshake lock.
michael@0 2486 **
michael@0 2487 ** Called from ssl_Do1stHandshake().
michael@0 2488 **
michael@0 2489 */
michael@0 2490 static SECStatus
michael@0 2491 ssl2_HandleMessage(sslSocket *ss)
michael@0 2492 {
michael@0 2493 PRUint8 * data;
michael@0 2494 PRUint8 * cid;
michael@0 2495 unsigned len, certType, certLen, responseLen;
michael@0 2496 int rv;
michael@0 2497 int rv2;
michael@0 2498
michael@0 2499 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 2500
michael@0 2501 ssl_GetRecvBufLock(ss);
michael@0 2502
michael@0 2503 data = ss->gs.buf.buf + ss->gs.recordOffset;
michael@0 2504
michael@0 2505 if (ss->gs.recordLen < 1) {
michael@0 2506 goto bad_peer;
michael@0 2507 }
michael@0 2508 SSL_TRC(3, ("%d: SSL[%d]: received %d message",
michael@0 2509 SSL_GETPID(), ss->fd, data[0]));
michael@0 2510 DUMP_MSG(29, (ss, data, ss->gs.recordLen));
michael@0 2511
michael@0 2512 switch (data[0]) {
michael@0 2513 case SSL_MT_CLIENT_FINISHED:
michael@0 2514 if (ss->sec.ci.elements & CIS_HAVE_FINISHED) {
michael@0 2515 SSL_DBG(("%d: SSL[%d]: dup client-finished message",
michael@0 2516 SSL_GETPID(), ss->fd));
michael@0 2517 goto bad_peer;
michael@0 2518 }
michael@0 2519
michael@0 2520 /* See if nonce matches */
michael@0 2521 len = ss->gs.recordLen - 1;
michael@0 2522 cid = data + 1;
michael@0 2523 if ((len != sizeof(ss->sec.ci.connectionID)) ||
michael@0 2524 (PORT_Memcmp(ss->sec.ci.connectionID, cid, len) != 0)) {
michael@0 2525 SSL_DBG(("%d: SSL[%d]: bad connection-id", SSL_GETPID(), ss->fd));
michael@0 2526 PRINT_BUF(5, (ss, "sent connection-id",
michael@0 2527 ss->sec.ci.connectionID,
michael@0 2528 sizeof(ss->sec.ci.connectionID)));
michael@0 2529 PRINT_BUF(5, (ss, "rcvd connection-id", cid, len));
michael@0 2530 goto bad_peer;
michael@0 2531 }
michael@0 2532
michael@0 2533 SSL_TRC(5, ("%d: SSL[%d]: got client finished, waiting for 0x%d",
michael@0 2534 SSL_GETPID(), ss->fd,
michael@0 2535 ss->sec.ci.requiredElements ^ ss->sec.ci.elements));
michael@0 2536 ss->sec.ci.elements |= CIS_HAVE_FINISHED;
michael@0 2537 break;
michael@0 2538
michael@0 2539 case SSL_MT_SERVER_FINISHED:
michael@0 2540 if (ss->sec.ci.elements & CIS_HAVE_FINISHED) {
michael@0 2541 SSL_DBG(("%d: SSL[%d]: dup server-finished message",
michael@0 2542 SSL_GETPID(), ss->fd));
michael@0 2543 goto bad_peer;
michael@0 2544 }
michael@0 2545
michael@0 2546 if (ss->gs.recordLen - 1 != SSL2_SESSIONID_BYTES) {
michael@0 2547 SSL_DBG(("%d: SSL[%d]: bad server-finished message, len=%d",
michael@0 2548 SSL_GETPID(), ss->fd, ss->gs.recordLen));
michael@0 2549 goto bad_peer;
michael@0 2550 }
michael@0 2551 ssl2_ClientRegSessionID(ss, data+1);
michael@0 2552 SSL_TRC(5, ("%d: SSL[%d]: got server finished, waiting for 0x%d",
michael@0 2553 SSL_GETPID(), ss->fd,
michael@0 2554 ss->sec.ci.requiredElements ^ ss->sec.ci.elements));
michael@0 2555 ss->sec.ci.elements |= CIS_HAVE_FINISHED;
michael@0 2556 break;
michael@0 2557
michael@0 2558 case SSL_MT_REQUEST_CERTIFICATE:
michael@0 2559 len = ss->gs.recordLen - 2;
michael@0 2560 if ((len < SSL_MIN_CHALLENGE_BYTES) ||
michael@0 2561 (len > SSL_MAX_CHALLENGE_BYTES)) {
michael@0 2562 /* Bad challenge */
michael@0 2563 SSL_DBG(("%d: SSL[%d]: bad cert request message: code len=%d",
michael@0 2564 SSL_GETPID(), ss->fd, len));
michael@0 2565 goto bad_peer;
michael@0 2566 }
michael@0 2567
michael@0 2568 /* save auth request info */
michael@0 2569 ss->sec.ci.authType = data[1];
michael@0 2570 ss->sec.ci.serverChallengeLen = len;
michael@0 2571 PORT_Memcpy(ss->sec.ci.serverChallenge, data + 2, len);
michael@0 2572
michael@0 2573 rv = ssl2_HandleRequestCertificate(ss);
michael@0 2574 if (rv == SECWouldBlock) {
michael@0 2575 SSL_TRC(3, ("%d: SSL[%d]: async cert request",
michael@0 2576 SSL_GETPID(), ss->fd));
michael@0 2577 /* someone is handling this asynchronously */
michael@0 2578 ssl_ReleaseRecvBufLock(ss);
michael@0 2579 return SECWouldBlock;
michael@0 2580 }
michael@0 2581 if (rv) {
michael@0 2582 SET_ERROR_CODE
michael@0 2583 goto loser;
michael@0 2584 }
michael@0 2585 break;
michael@0 2586
michael@0 2587 case SSL_MT_CLIENT_CERTIFICATE:
michael@0 2588 if (!ss->authCertificate) {
michael@0 2589 /* Server asked for authentication and can't handle it */
michael@0 2590 PORT_SetError(SSL_ERROR_BAD_SERVER);
michael@0 2591 goto loser;
michael@0 2592 }
michael@0 2593 if (ss->gs.recordLen < SSL_HL_CLIENT_CERTIFICATE_HBYTES) {
michael@0 2594 SET_ERROR_CODE
michael@0 2595 goto loser;
michael@0 2596 }
michael@0 2597 certType = data[1];
michael@0 2598 certLen = (data[2] << 8) | data[3];
michael@0 2599 responseLen = (data[4] << 8) | data[5];
michael@0 2600 if (certType != SSL_CT_X509_CERTIFICATE) {
michael@0 2601 PORT_SetError(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
michael@0 2602 goto loser;
michael@0 2603 }
michael@0 2604 if (certLen + responseLen + SSL_HL_CLIENT_CERTIFICATE_HBYTES
michael@0 2605 > ss->gs.recordLen) {
michael@0 2606 /* prevent overflow crash. */
michael@0 2607 rv = SECFailure;
michael@0 2608 } else
michael@0 2609 rv = ssl2_HandleClientCertificate(ss, data[1],
michael@0 2610 data + SSL_HL_CLIENT_CERTIFICATE_HBYTES,
michael@0 2611 certLen,
michael@0 2612 data + SSL_HL_CLIENT_CERTIFICATE_HBYTES + certLen,
michael@0 2613 responseLen);
michael@0 2614 if (rv) {
michael@0 2615 rv2 = ssl2_SendErrorMessage(ss, SSL_PE_BAD_CERTIFICATE);
michael@0 2616 SET_ERROR_CODE
michael@0 2617 goto loser;
michael@0 2618 }
michael@0 2619 ss->sec.ci.elements |= CIS_HAVE_CERTIFICATE;
michael@0 2620 break;
michael@0 2621
michael@0 2622 case SSL_MT_ERROR:
michael@0 2623 rv = (data[1] << 8) | data[2];
michael@0 2624 SSL_TRC(2, ("%d: SSL[%d]: got error message, error=0x%x",
michael@0 2625 SSL_GETPID(), ss->fd, rv));
michael@0 2626
michael@0 2627 /* Convert protocol error number into API error number */
michael@0 2628 switch (rv) {
michael@0 2629 case SSL_PE_NO_CYPHERS:
michael@0 2630 rv = SSL_ERROR_NO_CYPHER_OVERLAP;
michael@0 2631 break;
michael@0 2632 case SSL_PE_NO_CERTIFICATE:
michael@0 2633 rv = SSL_ERROR_NO_CERTIFICATE;
michael@0 2634 break;
michael@0 2635 case SSL_PE_BAD_CERTIFICATE:
michael@0 2636 rv = SSL_ERROR_BAD_CERTIFICATE;
michael@0 2637 break;
michael@0 2638 case SSL_PE_UNSUPPORTED_CERTIFICATE_TYPE:
michael@0 2639 rv = SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE;
michael@0 2640 break;
michael@0 2641 default:
michael@0 2642 goto bad_peer;
michael@0 2643 }
michael@0 2644 /* XXX make certificate-request optionally fail... */
michael@0 2645 PORT_SetError(rv);
michael@0 2646 goto loser;
michael@0 2647
michael@0 2648 default:
michael@0 2649 SSL_DBG(("%d: SSL[%d]: unknown message %d",
michael@0 2650 SSL_GETPID(), ss->fd, data[0]));
michael@0 2651 goto loser;
michael@0 2652 }
michael@0 2653
michael@0 2654 SSL_TRC(3, ("%d: SSL[%d]: handled %d message, required=0x%x got=0x%x",
michael@0 2655 SSL_GETPID(), ss->fd, data[0],
michael@0 2656 ss->sec.ci.requiredElements, ss->sec.ci.elements));
michael@0 2657
michael@0 2658 rv = ssl2_TryToFinish(ss);
michael@0 2659 if (rv != SECSuccess)
michael@0 2660 goto loser;
michael@0 2661
michael@0 2662 ss->gs.recordLen = 0;
michael@0 2663 ssl_ReleaseRecvBufLock(ss);
michael@0 2664
michael@0 2665 if (ss->handshake == 0) {
michael@0 2666 return SECSuccess;
michael@0 2667 }
michael@0 2668
michael@0 2669 ss->handshake = ssl_GatherRecord1stHandshake;
michael@0 2670 ss->nextHandshake = ssl2_HandleMessage;
michael@0 2671 return ssl2_TriggerNextMessage(ss);
michael@0 2672
michael@0 2673 bad_peer:
michael@0 2674 PORT_SetError(ss->sec.isServer ? SSL_ERROR_BAD_CLIENT : SSL_ERROR_BAD_SERVER);
michael@0 2675 /* FALL THROUGH */
michael@0 2676
michael@0 2677 loser:
michael@0 2678 ssl_ReleaseRecvBufLock(ss);
michael@0 2679 return SECFailure;
michael@0 2680 }
michael@0 2681
michael@0 2682 /************************************************************************/
michael@0 2683
michael@0 2684 /* Called from ssl_Do1stHandshake, after ssl2_HandleServerHelloMessage.
michael@0 2685 */
michael@0 2686 static SECStatus
michael@0 2687 ssl2_HandleVerifyMessage(sslSocket *ss)
michael@0 2688 {
michael@0 2689 PRUint8 * data;
michael@0 2690 SECStatus rv;
michael@0 2691
michael@0 2692 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 2693 ssl_GetRecvBufLock(ss);
michael@0 2694
michael@0 2695 data = ss->gs.buf.buf + ss->gs.recordOffset;
michael@0 2696 DUMP_MSG(29, (ss, data, ss->gs.recordLen));
michael@0 2697 if ((ss->gs.recordLen != 1 + SSL_CHALLENGE_BYTES) ||
michael@0 2698 (data[0] != SSL_MT_SERVER_VERIFY) ||
michael@0 2699 NSS_SecureMemcmp(data+1, ss->sec.ci.clientChallenge,
michael@0 2700 SSL_CHALLENGE_BYTES)) {
michael@0 2701 /* Bad server */
michael@0 2702 PORT_SetError(SSL_ERROR_BAD_SERVER);
michael@0 2703 goto loser;
michael@0 2704 }
michael@0 2705 ss->sec.ci.elements |= CIS_HAVE_VERIFY;
michael@0 2706
michael@0 2707 SSL_TRC(5, ("%d: SSL[%d]: got server-verify, required=0x%d got=0x%x",
michael@0 2708 SSL_GETPID(), ss->fd, ss->sec.ci.requiredElements,
michael@0 2709 ss->sec.ci.elements));
michael@0 2710
michael@0 2711 rv = ssl2_TryToFinish(ss);
michael@0 2712 if (rv)
michael@0 2713 goto loser;
michael@0 2714
michael@0 2715 ss->gs.recordLen = 0;
michael@0 2716 ssl_ReleaseRecvBufLock(ss);
michael@0 2717
michael@0 2718 if (ss->handshake == 0) {
michael@0 2719 return SECSuccess;
michael@0 2720 }
michael@0 2721 ss->handshake = ssl_GatherRecord1stHandshake;
michael@0 2722 ss->nextHandshake = ssl2_HandleMessage;
michael@0 2723 return SECSuccess;
michael@0 2724
michael@0 2725
michael@0 2726 loser:
michael@0 2727 ssl_ReleaseRecvBufLock(ss);
michael@0 2728 return SECFailure;
michael@0 2729 }
michael@0 2730
michael@0 2731 /* Not static because ssl2_GatherData() tests ss->nextHandshake for this value.
michael@0 2732 * ICK!
michael@0 2733 * Called from ssl_Do1stHandshake after ssl2_BeginClientHandshake()
michael@0 2734 */
michael@0 2735 SECStatus
michael@0 2736 ssl2_HandleServerHelloMessage(sslSocket *ss)
michael@0 2737 {
michael@0 2738 sslSessionID * sid;
michael@0 2739 PRUint8 * cert;
michael@0 2740 PRUint8 * cs;
michael@0 2741 PRUint8 * data;
michael@0 2742 SECStatus rv;
michael@0 2743 int needed, sidHit, certLen, csLen, cidLen, certType, err;
michael@0 2744
michael@0 2745 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 2746
michael@0 2747 if (!ss->opt.enableSSL2) {
michael@0 2748 PORT_SetError(SSL_ERROR_SSL2_DISABLED);
michael@0 2749 return SECFailure;
michael@0 2750 }
michael@0 2751
michael@0 2752 ssl_GetRecvBufLock(ss);
michael@0 2753
michael@0 2754 PORT_Assert(ss->sec.ci.sid != 0);
michael@0 2755 sid = ss->sec.ci.sid;
michael@0 2756
michael@0 2757 data = ss->gs.buf.buf + ss->gs.recordOffset;
michael@0 2758 DUMP_MSG(29, (ss, data, ss->gs.recordLen));
michael@0 2759
michael@0 2760 /* Make sure first message has some data and is the server hello message */
michael@0 2761 if ((ss->gs.recordLen < SSL_HL_SERVER_HELLO_HBYTES)
michael@0 2762 || (data[0] != SSL_MT_SERVER_HELLO)) {
michael@0 2763 if ((data[0] == SSL_MT_ERROR) && (ss->gs.recordLen == 3)) {
michael@0 2764 err = (data[1] << 8) | data[2];
michael@0 2765 if (err == SSL_PE_NO_CYPHERS) {
michael@0 2766 PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
michael@0 2767 goto loser;
michael@0 2768 }
michael@0 2769 }
michael@0 2770 goto bad_server;
michael@0 2771 }
michael@0 2772
michael@0 2773 sidHit = data[1];
michael@0 2774 certType = data[2];
michael@0 2775 ss->version = (data[3] << 8) | data[4];
michael@0 2776 certLen = (data[5] << 8) | data[6];
michael@0 2777 csLen = (data[7] << 8) | data[8];
michael@0 2778 cidLen = (data[9] << 8) | data[10];
michael@0 2779 cert = data + SSL_HL_SERVER_HELLO_HBYTES;
michael@0 2780 cs = cert + certLen;
michael@0 2781
michael@0 2782 SSL_TRC(5,
michael@0 2783 ("%d: SSL[%d]: server-hello, hit=%d vers=%x certLen=%d csLen=%d cidLen=%d",
michael@0 2784 SSL_GETPID(), ss->fd, sidHit, ss->version, certLen,
michael@0 2785 csLen, cidLen));
michael@0 2786 if (ss->version != SSL_LIBRARY_VERSION_2) {
michael@0 2787 if (ss->version < SSL_LIBRARY_VERSION_2) {
michael@0 2788 SSL_TRC(3, ("%d: SSL[%d]: demoting self (%x) to server version (%x)",
michael@0 2789 SSL_GETPID(), ss->fd, SSL_LIBRARY_VERSION_2,
michael@0 2790 ss->version));
michael@0 2791 } else {
michael@0 2792 SSL_TRC(1, ("%d: SSL[%d]: server version is %x (we are %x)",
michael@0 2793 SSL_GETPID(), ss->fd, ss->version, SSL_LIBRARY_VERSION_2));
michael@0 2794 /* server claims to be newer but does not follow protocol */
michael@0 2795 PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
michael@0 2796 goto loser;
michael@0 2797 }
michael@0 2798 }
michael@0 2799
michael@0 2800 if ((SSL_HL_SERVER_HELLO_HBYTES + certLen + csLen + cidLen
michael@0 2801 > ss->gs.recordLen)
michael@0 2802 || (csLen % 3) != 0
michael@0 2803 /* || cidLen < SSL_CONNECTIONID_BYTES || cidLen > 32 */
michael@0 2804 ) {
michael@0 2805 goto bad_server;
michael@0 2806 }
michael@0 2807
michael@0 2808 /* Save connection-id.
michael@0 2809 ** This code only saves the first 16 byte of the connectionID.
michael@0 2810 ** If the connectionID is shorter than 16 bytes, it is zero-padded.
michael@0 2811 */
michael@0 2812 if (cidLen < sizeof ss->sec.ci.connectionID)
michael@0 2813 memset(ss->sec.ci.connectionID, 0, sizeof ss->sec.ci.connectionID);
michael@0 2814 cidLen = PR_MIN(cidLen, sizeof ss->sec.ci.connectionID);
michael@0 2815 PORT_Memcpy(ss->sec.ci.connectionID, cs + csLen, cidLen);
michael@0 2816
michael@0 2817 /* See if session-id hit */
michael@0 2818 needed = CIS_HAVE_MASTER_KEY | CIS_HAVE_FINISHED | CIS_HAVE_VERIFY;
michael@0 2819 if (sidHit) {
michael@0 2820 if (certLen || csLen) {
michael@0 2821 /* Uh oh - bogus server */
michael@0 2822 SSL_DBG(("%d: SSL[%d]: client, huh? hit=%d certLen=%d csLen=%d",
michael@0 2823 SSL_GETPID(), ss->fd, sidHit, certLen, csLen));
michael@0 2824 goto bad_server;
michael@0 2825 }
michael@0 2826
michael@0 2827 /* Total winner. */
michael@0 2828 SSL_TRC(1, ("%d: SSL[%d]: client, using nonce for peer=0x%08x "
michael@0 2829 "port=0x%04x",
michael@0 2830 SSL_GETPID(), ss->fd, ss->sec.ci.peer, ss->sec.ci.port));
michael@0 2831 ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
michael@0 2832 ss->sec.authAlgorithm = sid->authAlgorithm;
michael@0 2833 ss->sec.authKeyBits = sid->authKeyBits;
michael@0 2834 ss->sec.keaType = sid->keaType;
michael@0 2835 ss->sec.keaKeyBits = sid->keaKeyBits;
michael@0 2836 rv = ssl2_CreateSessionCypher(ss, sid, PR_TRUE);
michael@0 2837 if (rv != SECSuccess) {
michael@0 2838 goto loser;
michael@0 2839 }
michael@0 2840 } else {
michael@0 2841 if (certType != SSL_CT_X509_CERTIFICATE) {
michael@0 2842 PORT_SetError(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
michael@0 2843 goto loser;
michael@0 2844 }
michael@0 2845 if (csLen == 0) {
michael@0 2846 PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
michael@0 2847 SSL_DBG(("%d: SSL[%d]: no cipher overlap",
michael@0 2848 SSL_GETPID(), ss->fd));
michael@0 2849 goto loser;
michael@0 2850 }
michael@0 2851 if (certLen == 0) {
michael@0 2852 SSL_DBG(("%d: SSL[%d]: client, huh? certLen=%d csLen=%d",
michael@0 2853 SSL_GETPID(), ss->fd, certLen, csLen));
michael@0 2854 goto bad_server;
michael@0 2855 }
michael@0 2856
michael@0 2857 if (sid->cached != never_cached) {
michael@0 2858 /* Forget our session-id - server didn't like it */
michael@0 2859 SSL_TRC(7, ("%d: SSL[%d]: server forgot me, uncaching session-id",
michael@0 2860 SSL_GETPID(), ss->fd));
michael@0 2861 if (ss->sec.uncache)
michael@0 2862 (*ss->sec.uncache)(sid);
michael@0 2863 ssl_FreeSID(sid);
michael@0 2864 ss->sec.ci.sid = sid = PORT_ZNew(sslSessionID);
michael@0 2865 if (!sid) {
michael@0 2866 goto loser;
michael@0 2867 }
michael@0 2868 sid->references = 1;
michael@0 2869 sid->addr = ss->sec.ci.peer;
michael@0 2870 sid->port = ss->sec.ci.port;
michael@0 2871 }
michael@0 2872
michael@0 2873 /* decode the server's certificate */
michael@0 2874 rv = ssl2_ClientHandleServerCert(ss, cert, certLen);
michael@0 2875 if (rv != SECSuccess) {
michael@0 2876 if (PORT_GetError() == SSL_ERROR_BAD_CERTIFICATE) {
michael@0 2877 (void) ssl2_SendErrorMessage(ss, SSL_PE_BAD_CERTIFICATE);
michael@0 2878 }
michael@0 2879 goto loser;
michael@0 2880 }
michael@0 2881
michael@0 2882 /* Setup new session cipher */
michael@0 2883 rv = ssl2_ClientSetupSessionCypher(ss, cs, csLen);
michael@0 2884 if (rv != SECSuccess) {
michael@0 2885 if (PORT_GetError() == SSL_ERROR_BAD_CERTIFICATE) {
michael@0 2886 (void) ssl2_SendErrorMessage(ss, SSL_PE_BAD_CERTIFICATE);
michael@0 2887 }
michael@0 2888 goto loser;
michael@0 2889 }
michael@0 2890 }
michael@0 2891
michael@0 2892 /* Build up final list of required elements */
michael@0 2893 ss->sec.ci.elements = CIS_HAVE_MASTER_KEY;
michael@0 2894 ss->sec.ci.requiredElements = needed;
michael@0 2895
michael@0 2896 if (!sidHit) {
michael@0 2897 /* verify the server's certificate. if sidHit, don't check signatures */
michael@0 2898 rv = (* ss->authCertificate)(ss->authCertificateArg, ss->fd,
michael@0 2899 (PRBool)(!sidHit), PR_FALSE);
michael@0 2900 if (rv) {
michael@0 2901 if (ss->handleBadCert) {
michael@0 2902 rv = (*ss->handleBadCert)(ss->badCertArg, ss->fd);
michael@0 2903 if ( rv ) {
michael@0 2904 if ( rv == SECWouldBlock ) {
michael@0 2905 SSL_DBG(("%d: SSL[%d]: SSL2 bad cert handler returned "
michael@0 2906 "SECWouldBlock", SSL_GETPID(), ss->fd));
michael@0 2907 PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
michael@0 2908 rv = SECFailure;
michael@0 2909 } else {
michael@0 2910 /* cert is bad */
michael@0 2911 SSL_DBG(("%d: SSL[%d]: server certificate is no good: error=%d",
michael@0 2912 SSL_GETPID(), ss->fd, PORT_GetError()));
michael@0 2913 }
michael@0 2914 goto loser;
michael@0 2915 }
michael@0 2916 /* cert is good */
michael@0 2917 } else {
michael@0 2918 SSL_DBG(("%d: SSL[%d]: server certificate is no good: error=%d",
michael@0 2919 SSL_GETPID(), ss->fd, PORT_GetError()));
michael@0 2920 goto loser;
michael@0 2921 }
michael@0 2922 }
michael@0 2923 }
michael@0 2924 /*
michael@0 2925 ** At this point we have a completed session key and our session
michael@0 2926 ** cipher is setup and ready to go. Switch to encrypted write routine
michael@0 2927 ** as all future message data is to be encrypted.
michael@0 2928 */
michael@0 2929 ssl2_UseEncryptedSendFunc(ss);
michael@0 2930
michael@0 2931 rv = ssl2_TryToFinish(ss);
michael@0 2932 if (rv != SECSuccess)
michael@0 2933 goto loser;
michael@0 2934
michael@0 2935 ss->gs.recordLen = 0;
michael@0 2936
michael@0 2937 ssl_ReleaseRecvBufLock(ss);
michael@0 2938
michael@0 2939 if (ss->handshake == 0) {
michael@0 2940 return SECSuccess;
michael@0 2941 }
michael@0 2942
michael@0 2943 SSL_TRC(5, ("%d: SSL[%d]: got server-hello, required=0x%d got=0x%x",
michael@0 2944 SSL_GETPID(), ss->fd, ss->sec.ci.requiredElements,
michael@0 2945 ss->sec.ci.elements));
michael@0 2946 ss->handshake = ssl_GatherRecord1stHandshake;
michael@0 2947 ss->nextHandshake = ssl2_HandleVerifyMessage;
michael@0 2948 return SECSuccess;
michael@0 2949
michael@0 2950 bad_server:
michael@0 2951 PORT_SetError(SSL_ERROR_BAD_SERVER);
michael@0 2952 /* FALL THROUGH */
michael@0 2953
michael@0 2954 loser:
michael@0 2955 ssl_ReleaseRecvBufLock(ss);
michael@0 2956 return SECFailure;
michael@0 2957 }
michael@0 2958
michael@0 2959 /* Sends out the initial client Hello message on the connection.
michael@0 2960 * Acquires and releases the socket's xmitBufLock.
michael@0 2961 */
michael@0 2962 SECStatus
michael@0 2963 ssl2_BeginClientHandshake(sslSocket *ss)
michael@0 2964 {
michael@0 2965 sslSessionID *sid;
michael@0 2966 PRUint8 *msg;
michael@0 2967 PRUint8 *cp;
michael@0 2968 PRUint8 *localCipherSpecs = NULL;
michael@0 2969 unsigned int localCipherSize;
michael@0 2970 unsigned int i;
michael@0 2971 int sendLen, sidLen = 0;
michael@0 2972 SECStatus rv;
michael@0 2973 TLSExtensionData *xtnData;
michael@0 2974
michael@0 2975 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 2976
michael@0 2977 ss->sec.isServer = 0;
michael@0 2978 ss->sec.sendSequence = 0;
michael@0 2979 ss->sec.rcvSequence = 0;
michael@0 2980 ssl_ChooseSessionIDProcs(&ss->sec);
michael@0 2981
michael@0 2982 if (!ss->cipherSpecs) {
michael@0 2983 rv = ssl2_ConstructCipherSpecs(ss);
michael@0 2984 if (rv != SECSuccess)
michael@0 2985 goto loser;
michael@0 2986 }
michael@0 2987
michael@0 2988 /* count the SSL2 and SSL3 enabled ciphers.
michael@0 2989 * if either is zero, clear the socket's enable for that protocol.
michael@0 2990 */
michael@0 2991 rv = ssl2_CheckConfigSanity(ss);
michael@0 2992 if (rv != SECSuccess)
michael@0 2993 goto loser;
michael@0 2994
michael@0 2995 /* Get peer name of server */
michael@0 2996 rv = ssl_GetPeerInfo(ss);
michael@0 2997 if (rv < 0) {
michael@0 2998 #ifdef HPUX11
michael@0 2999 /*
michael@0 3000 * On some HP-UX B.11.00 systems, getpeername() occasionally
michael@0 3001 * fails with ENOTCONN after a successful completion of
michael@0 3002 * non-blocking connect. I found that if we do a write()
michael@0 3003 * and then retry getpeername(), it will work.
michael@0 3004 */
michael@0 3005 if (PR_GetError() == PR_NOT_CONNECTED_ERROR) {
michael@0 3006 char dummy;
michael@0 3007 (void) PR_Write(ss->fd->lower, &dummy, 0);
michael@0 3008 rv = ssl_GetPeerInfo(ss);
michael@0 3009 if (rv < 0) {
michael@0 3010 goto loser;
michael@0 3011 }
michael@0 3012 }
michael@0 3013 #else
michael@0 3014 goto loser;
michael@0 3015 #endif
michael@0 3016 }
michael@0 3017
michael@0 3018 SSL_TRC(3, ("%d: SSL[%d]: sending client-hello", SSL_GETPID(), ss->fd));
michael@0 3019
michael@0 3020 /* Try to find server in our session-id cache */
michael@0 3021 if (ss->opt.noCache) {
michael@0 3022 sid = NULL;
michael@0 3023 } else {
michael@0 3024 sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID,
michael@0 3025 ss->url);
michael@0 3026 }
michael@0 3027 while (sid) { /* this isn't really a loop */
michael@0 3028 PRBool sidVersionEnabled =
michael@0 3029 (!SSL3_ALL_VERSIONS_DISABLED(&ss->vrange) &&
michael@0 3030 sid->version >= ss->vrange.min &&
michael@0 3031 sid->version <= ss->vrange.max) ||
michael@0 3032 (sid->version < SSL_LIBRARY_VERSION_3_0 && ss->opt.enableSSL2);
michael@0 3033
michael@0 3034 /* if we're not doing this SID's protocol any more, drop it. */
michael@0 3035 if (!sidVersionEnabled) {
michael@0 3036 if (ss->sec.uncache)
michael@0 3037 ss->sec.uncache(sid);
michael@0 3038 ssl_FreeSID(sid);
michael@0 3039 sid = NULL;
michael@0 3040 break;
michael@0 3041 }
michael@0 3042 if (sid->version < SSL_LIBRARY_VERSION_3_0) {
michael@0 3043 /* If the cipher in this sid is not enabled, drop it. */
michael@0 3044 for (i = 0; i < ss->sizeCipherSpecs; i += 3) {
michael@0 3045 if (ss->cipherSpecs[i] == sid->u.ssl2.cipherType)
michael@0 3046 break;
michael@0 3047 }
michael@0 3048 if (i >= ss->sizeCipherSpecs) {
michael@0 3049 if (ss->sec.uncache)
michael@0 3050 ss->sec.uncache(sid);
michael@0 3051 ssl_FreeSID(sid);
michael@0 3052 sid = NULL;
michael@0 3053 break;
michael@0 3054 }
michael@0 3055 }
michael@0 3056 sidLen = sizeof(sid->u.ssl2.sessionID);
michael@0 3057 PRINT_BUF(4, (ss, "client, found session-id:", sid->u.ssl2.sessionID,
michael@0 3058 sidLen));
michael@0 3059 ss->version = sid->version;
michael@0 3060 PORT_Assert(!ss->sec.localCert);
michael@0 3061 if (ss->sec.localCert) {
michael@0 3062 CERT_DestroyCertificate(ss->sec.localCert);
michael@0 3063 }
michael@0 3064 ss->sec.localCert = CERT_DupCertificate(sid->localCert);
michael@0 3065 break; /* this isn't really a loop */
michael@0 3066 }
michael@0 3067 if (!sid) {
michael@0 3068 sidLen = 0;
michael@0 3069 sid = PORT_ZNew(sslSessionID);
michael@0 3070 if (!sid) {
michael@0 3071 goto loser;
michael@0 3072 }
michael@0 3073 sid->references = 1;
michael@0 3074 sid->cached = never_cached;
michael@0 3075 sid->addr = ss->sec.ci.peer;
michael@0 3076 sid->port = ss->sec.ci.port;
michael@0 3077 if (ss->peerID != NULL) {
michael@0 3078 sid->peerID = PORT_Strdup(ss->peerID);
michael@0 3079 }
michael@0 3080 if (ss->url != NULL) {
michael@0 3081 sid->urlSvrName = PORT_Strdup(ss->url);
michael@0 3082 }
michael@0 3083 }
michael@0 3084 ss->sec.ci.sid = sid;
michael@0 3085
michael@0 3086 PORT_Assert(sid != NULL);
michael@0 3087
michael@0 3088 if ((sid->version >= SSL_LIBRARY_VERSION_3_0 || !ss->opt.v2CompatibleHello) &&
michael@0 3089 !SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
michael@0 3090 ss->gs.state = GS_INIT;
michael@0 3091 ss->handshake = ssl_GatherRecord1stHandshake;
michael@0 3092
michael@0 3093 /* ssl3_SendClientHello will override this if it succeeds. */
michael@0 3094 ss->version = SSL_LIBRARY_VERSION_3_0;
michael@0 3095
michael@0 3096 ssl_GetSSL3HandshakeLock(ss);
michael@0 3097 ssl_GetXmitBufLock(ss);
michael@0 3098 rv = ssl3_SendClientHello(ss, PR_FALSE);
michael@0 3099 ssl_ReleaseXmitBufLock(ss);
michael@0 3100 ssl_ReleaseSSL3HandshakeLock(ss);
michael@0 3101
michael@0 3102 return rv;
michael@0 3103 }
michael@0 3104 #ifndef NSS_DISABLE_ECC
michael@0 3105 /* ensure we don't neogtiate ECC cipher suites with SSL2 hello */
michael@0 3106 ssl3_DisableECCSuites(ss, NULL); /* disable all ECC suites */
michael@0 3107 if (ss->cipherSpecs != NULL) {
michael@0 3108 PORT_Free(ss->cipherSpecs);
michael@0 3109 ss->cipherSpecs = NULL;
michael@0 3110 ss->sizeCipherSpecs = 0;
michael@0 3111 }
michael@0 3112 #endif /* NSS_DISABLE_ECC */
michael@0 3113
michael@0 3114 if (!ss->cipherSpecs) {
michael@0 3115 rv = ssl2_ConstructCipherSpecs(ss);
michael@0 3116 if (rv < 0) {
michael@0 3117 return rv;
michael@0 3118 }
michael@0 3119 }
michael@0 3120 localCipherSpecs = ss->cipherSpecs;
michael@0 3121 localCipherSize = ss->sizeCipherSpecs;
michael@0 3122
michael@0 3123 /* Add 3 for SCSV */
michael@0 3124 sendLen = SSL_HL_CLIENT_HELLO_HBYTES + localCipherSize + 3 + sidLen +
michael@0 3125 SSL_CHALLENGE_BYTES;
michael@0 3126
michael@0 3127 /* Generate challenge bytes for server */
michael@0 3128 PK11_GenerateRandom(ss->sec.ci.clientChallenge, SSL_CHALLENGE_BYTES);
michael@0 3129
michael@0 3130 ssl_GetXmitBufLock(ss); /***************************************/
michael@0 3131
michael@0 3132 rv = ssl2_GetSendBuffer(ss, sendLen);
michael@0 3133 if (rv)
michael@0 3134 goto unlock_loser;
michael@0 3135
michael@0 3136 /* Construct client-hello message */
michael@0 3137 cp = msg = ss->sec.ci.sendBuf.buf;
michael@0 3138 msg[0] = SSL_MT_CLIENT_HELLO;
michael@0 3139 ss->clientHelloVersion = SSL3_ALL_VERSIONS_DISABLED(&ss->vrange) ?
michael@0 3140 SSL_LIBRARY_VERSION_2 : ss->vrange.max;
michael@0 3141
michael@0 3142 msg[1] = MSB(ss->clientHelloVersion);
michael@0 3143 msg[2] = LSB(ss->clientHelloVersion);
michael@0 3144 /* Add 3 for SCSV */
michael@0 3145 msg[3] = MSB(localCipherSize + 3);
michael@0 3146 msg[4] = LSB(localCipherSize + 3);
michael@0 3147 msg[5] = MSB(sidLen);
michael@0 3148 msg[6] = LSB(sidLen);
michael@0 3149 msg[7] = MSB(SSL_CHALLENGE_BYTES);
michael@0 3150 msg[8] = LSB(SSL_CHALLENGE_BYTES);
michael@0 3151 cp += SSL_HL_CLIENT_HELLO_HBYTES;
michael@0 3152 PORT_Memcpy(cp, localCipherSpecs, localCipherSize);
michael@0 3153 cp += localCipherSize;
michael@0 3154 /*
michael@0 3155 * Add SCSV. SSL 2.0 cipher suites are listed before SSL 3.0 cipher
michael@0 3156 * suites in localCipherSpecs for compatibility with SSL 2.0 servers.
michael@0 3157 * Since SCSV looks like an SSL 3.0 cipher suite, we can't add it at
michael@0 3158 * the beginning.
michael@0 3159 */
michael@0 3160 cp[0] = 0x00;
michael@0 3161 cp[1] = 0x00;
michael@0 3162 cp[2] = 0xff;
michael@0 3163 cp += 3;
michael@0 3164 if (sidLen) {
michael@0 3165 PORT_Memcpy(cp, sid->u.ssl2.sessionID, sidLen);
michael@0 3166 cp += sidLen;
michael@0 3167 }
michael@0 3168 PORT_Memcpy(cp, ss->sec.ci.clientChallenge, SSL_CHALLENGE_BYTES);
michael@0 3169
michael@0 3170 /* Send it to the server */
michael@0 3171 DUMP_MSG(29, (ss, msg, sendLen));
michael@0 3172 ss->handshakeBegun = 1;
michael@0 3173 rv = (*ss->sec.send)(ss, msg, sendLen, 0);
michael@0 3174
michael@0 3175 ssl_ReleaseXmitBufLock(ss); /***************************************/
michael@0 3176
michael@0 3177 if (rv < 0) {
michael@0 3178 goto loser;
michael@0 3179 }
michael@0 3180
michael@0 3181 rv = ssl3_StartHandshakeHash(ss, msg, sendLen);
michael@0 3182 if (rv < 0) {
michael@0 3183 goto loser;
michael@0 3184 }
michael@0 3185
michael@0 3186 /*
michael@0 3187 * Since we sent the SCSV, pretend we sent empty RI extension. We need
michael@0 3188 * to record the extension has been advertised after ssl3_InitState has
michael@0 3189 * been called, which ssl3_StartHandshakeHash took care for us above.
michael@0 3190 */
michael@0 3191 xtnData = &ss->xtnData;
michael@0 3192 xtnData->advertised[xtnData->numAdvertised++] = ssl_renegotiation_info_xtn;
michael@0 3193
michael@0 3194 /* Setup to receive servers hello message */
michael@0 3195 ssl_GetRecvBufLock(ss);
michael@0 3196 ss->gs.recordLen = 0;
michael@0 3197 ssl_ReleaseRecvBufLock(ss);
michael@0 3198
michael@0 3199 ss->handshake = ssl_GatherRecord1stHandshake;
michael@0 3200 ss->nextHandshake = ssl2_HandleServerHelloMessage;
michael@0 3201 return SECSuccess;
michael@0 3202
michael@0 3203 unlock_loser:
michael@0 3204 ssl_ReleaseXmitBufLock(ss);
michael@0 3205 loser:
michael@0 3206 return SECFailure;
michael@0 3207 }
michael@0 3208
michael@0 3209 /************************************************************************/
michael@0 3210
michael@0 3211 /* Handle the CLIENT-MASTER-KEY message.
michael@0 3212 ** Acquires and releases RecvBufLock.
michael@0 3213 ** Called from ssl2_HandleClientHelloMessage().
michael@0 3214 */
michael@0 3215 static SECStatus
michael@0 3216 ssl2_HandleClientSessionKeyMessage(sslSocket *ss)
michael@0 3217 {
michael@0 3218 PRUint8 * data;
michael@0 3219 unsigned int caLen;
michael@0 3220 unsigned int ckLen;
michael@0 3221 unsigned int ekLen;
michael@0 3222 unsigned int keyBits;
michael@0 3223 int cipher;
michael@0 3224 SECStatus rv;
michael@0 3225
michael@0 3226
michael@0 3227 ssl_GetRecvBufLock(ss);
michael@0 3228
michael@0 3229 data = ss->gs.buf.buf + ss->gs.recordOffset;
michael@0 3230 DUMP_MSG(29, (ss, data, ss->gs.recordLen));
michael@0 3231
michael@0 3232 if ((ss->gs.recordLen < SSL_HL_CLIENT_MASTER_KEY_HBYTES)
michael@0 3233 || (data[0] != SSL_MT_CLIENT_MASTER_KEY)) {
michael@0 3234 goto bad_client;
michael@0 3235 }
michael@0 3236 cipher = data[1];
michael@0 3237 keyBits = (data[2] << 8) | data[3];
michael@0 3238 ckLen = (data[4] << 8) | data[5];
michael@0 3239 ekLen = (data[6] << 8) | data[7];
michael@0 3240 caLen = (data[8] << 8) | data[9];
michael@0 3241
michael@0 3242 SSL_TRC(5, ("%d: SSL[%d]: session-key, cipher=%d keyBits=%d ckLen=%d ekLen=%d caLen=%d",
michael@0 3243 SSL_GETPID(), ss->fd, cipher, keyBits, ckLen, ekLen, caLen));
michael@0 3244
michael@0 3245 if (ss->gs.recordLen <
michael@0 3246 SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen + ekLen + caLen) {
michael@0 3247 SSL_DBG(("%d: SSL[%d]: protocol size mismatch dataLen=%d",
michael@0 3248 SSL_GETPID(), ss->fd, ss->gs.recordLen));
michael@0 3249 goto bad_client;
michael@0 3250 }
michael@0 3251
michael@0 3252 /* Use info from client to setup session key */
michael@0 3253 rv = ssl2_ServerSetupSessionCypher(ss, cipher, keyBits,
michael@0 3254 data + SSL_HL_CLIENT_MASTER_KEY_HBYTES, ckLen,
michael@0 3255 data + SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen, ekLen,
michael@0 3256 data + SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen + ekLen, caLen);
michael@0 3257 ss->gs.recordLen = 0; /* we're done with this record. */
michael@0 3258
michael@0 3259 ssl_ReleaseRecvBufLock(ss);
michael@0 3260
michael@0 3261 if (rv != SECSuccess) {
michael@0 3262 goto loser;
michael@0 3263 }
michael@0 3264 ss->sec.ci.elements |= CIS_HAVE_MASTER_KEY;
michael@0 3265 ssl2_UseEncryptedSendFunc(ss);
michael@0 3266
michael@0 3267 /* Send server verify message now that keys are established */
michael@0 3268 rv = ssl2_SendServerVerifyMessage(ss);
michael@0 3269 if (rv != SECSuccess)
michael@0 3270 goto loser;
michael@0 3271
michael@0 3272 rv = ssl2_TryToFinish(ss);
michael@0 3273 if (rv != SECSuccess)
michael@0 3274 goto loser;
michael@0 3275 if (ss->handshake == 0) {
michael@0 3276 return SECSuccess;
michael@0 3277 }
michael@0 3278
michael@0 3279 SSL_TRC(5, ("%d: SSL[%d]: server: waiting for elements=0x%d",
michael@0 3280 SSL_GETPID(), ss->fd,
michael@0 3281 ss->sec.ci.requiredElements ^ ss->sec.ci.elements));
michael@0 3282 ss->handshake = ssl_GatherRecord1stHandshake;
michael@0 3283 ss->nextHandshake = ssl2_HandleMessage;
michael@0 3284
michael@0 3285 return ssl2_TriggerNextMessage(ss);
michael@0 3286
michael@0 3287 bad_client:
michael@0 3288 ssl_ReleaseRecvBufLock(ss);
michael@0 3289 PORT_SetError(SSL_ERROR_BAD_CLIENT);
michael@0 3290 /* FALLTHROUGH */
michael@0 3291
michael@0 3292 loser:
michael@0 3293 return SECFailure;
michael@0 3294 }
michael@0 3295
michael@0 3296 /*
michael@0 3297 ** Handle the initial hello message from the client
michael@0 3298 **
michael@0 3299 ** not static because ssl2_GatherData() tests ss->nextHandshake for this value.
michael@0 3300 */
michael@0 3301 SECStatus
michael@0 3302 ssl2_HandleClientHelloMessage(sslSocket *ss)
michael@0 3303 {
michael@0 3304 sslSessionID *sid;
michael@0 3305 sslServerCerts * sc;
michael@0 3306 CERTCertificate *serverCert;
michael@0 3307 PRUint8 *msg;
michael@0 3308 PRUint8 *data;
michael@0 3309 PRUint8 *cs;
michael@0 3310 PRUint8 *sd;
michael@0 3311 PRUint8 *cert = NULL;
michael@0 3312 PRUint8 *challenge;
michael@0 3313 unsigned int challengeLen;
michael@0 3314 SECStatus rv;
michael@0 3315 int csLen;
michael@0 3316 int sendLen;
michael@0 3317 int sdLen;
michael@0 3318 int certLen;
michael@0 3319 int pid;
michael@0 3320 int sent;
michael@0 3321 int gotXmitBufLock = 0;
michael@0 3322 #if defined(SOLARIS) && defined(i386)
michael@0 3323 volatile PRUint8 hit;
michael@0 3324 #else
michael@0 3325 int hit;
michael@0 3326 #endif
michael@0 3327 PRUint8 csImpl[sizeof implementedCipherSuites];
michael@0 3328
michael@0 3329 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
michael@0 3330
michael@0 3331 sc = ss->serverCerts + kt_rsa;
michael@0 3332 serverCert = sc->serverCert;
michael@0 3333
michael@0 3334 ssl_GetRecvBufLock(ss);
michael@0 3335
michael@0 3336
michael@0 3337 data = ss->gs.buf.buf + ss->gs.recordOffset;
michael@0 3338 DUMP_MSG(29, (ss, data, ss->gs.recordLen));
michael@0 3339
michael@0 3340 /* Make sure first message has some data and is the client hello message */
michael@0 3341 if ((ss->gs.recordLen < SSL_HL_CLIENT_HELLO_HBYTES)
michael@0 3342 || (data[0] != SSL_MT_CLIENT_HELLO)) {
michael@0 3343 goto bad_client;
michael@0 3344 }
michael@0 3345
michael@0 3346 /* Get peer name of client */
michael@0 3347 rv = ssl_GetPeerInfo(ss);
michael@0 3348 if (rv != SECSuccess) {
michael@0 3349 goto loser;
michael@0 3350 }
michael@0 3351
michael@0 3352 /* Examine version information */
michael@0 3353 /*
michael@0 3354 * See if this might be a V2 client hello asking to use the V3 protocol
michael@0 3355 */
michael@0 3356 if ((data[0] == SSL_MT_CLIENT_HELLO) &&
michael@0 3357 (data[1] >= MSB(SSL_LIBRARY_VERSION_3_0)) &&
michael@0 3358 !SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
michael@0 3359 rv = ssl3_HandleV2ClientHello(ss, data, ss->gs.recordLen);
michael@0 3360 if (rv != SECFailure) { /* Success */
michael@0 3361 ss->handshake = NULL;
michael@0 3362 ss->nextHandshake = ssl_GatherRecord1stHandshake;
michael@0 3363 ss->securityHandshake = NULL;
michael@0 3364 ss->gs.state = GS_INIT;
michael@0 3365
michael@0 3366 /* ssl3_HandleV3ClientHello has set ss->version,
michael@0 3367 ** and has gotten us a brand new sid.
michael@0 3368 */
michael@0 3369 ss->sec.ci.sid->version = ss->version;
michael@0 3370 }
michael@0 3371 ssl_ReleaseRecvBufLock(ss);
michael@0 3372 return rv;
michael@0 3373 }
michael@0 3374 /* Previously, there was a test here to see if SSL2 was enabled.
michael@0 3375 ** If not, an error code was set, and SECFailure was returned,
michael@0 3376 ** without sending any error code to the other end of the connection.
michael@0 3377 ** That test has been removed. If SSL2 has been disabled, there
michael@0 3378 ** should be no SSL2 ciphers enabled, and consequently, the code
michael@0 3379 ** below should send the ssl2 error message SSL_PE_NO_CYPHERS.
michael@0 3380 ** We now believe this is the correct thing to do, even when SSL2
michael@0 3381 ** has been explicitly disabled by the application.
michael@0 3382 */
michael@0 3383
michael@0 3384 /* Extract info from message */
michael@0 3385 ss->version = (data[1] << 8) | data[2];
michael@0 3386
michael@0 3387 /* If some client thinks ssl v2 is 2.0 instead of 0.2, we'll allow it. */
michael@0 3388 if (ss->version >= SSL_LIBRARY_VERSION_3_0) {
michael@0 3389 ss->version = SSL_LIBRARY_VERSION_2;
michael@0 3390 }
michael@0 3391
michael@0 3392 csLen = (data[3] << 8) | data[4];
michael@0 3393 sdLen = (data[5] << 8) | data[6];
michael@0 3394 challengeLen = (data[7] << 8) | data[8];
michael@0 3395 cs = data + SSL_HL_CLIENT_HELLO_HBYTES;
michael@0 3396 sd = cs + csLen;
michael@0 3397 challenge = sd + sdLen;
michael@0 3398 PRINT_BUF(7, (ss, "server, client session-id value:", sd, sdLen));
michael@0 3399
michael@0 3400 if (!csLen || (csLen % 3) != 0 ||
michael@0 3401 (sdLen != 0 && sdLen != SSL2_SESSIONID_BYTES) ||
michael@0 3402 challengeLen < SSL_MIN_CHALLENGE_BYTES ||
michael@0 3403 challengeLen > SSL_MAX_CHALLENGE_BYTES ||
michael@0 3404 (unsigned)ss->gs.recordLen !=
michael@0 3405 SSL_HL_CLIENT_HELLO_HBYTES + csLen + sdLen + challengeLen) {
michael@0 3406 SSL_DBG(("%d: SSL[%d]: bad client hello message, len=%d should=%d",
michael@0 3407 SSL_GETPID(), ss->fd, ss->gs.recordLen,
michael@0 3408 SSL_HL_CLIENT_HELLO_HBYTES+csLen+sdLen+challengeLen));
michael@0 3409 goto bad_client;
michael@0 3410 }
michael@0 3411
michael@0 3412 SSL_TRC(3, ("%d: SSL[%d]: client version is %x",
michael@0 3413 SSL_GETPID(), ss->fd, ss->version));
michael@0 3414 if (ss->version != SSL_LIBRARY_VERSION_2) {
michael@0 3415 if (ss->version > SSL_LIBRARY_VERSION_2) {
michael@0 3416 /*
michael@0 3417 ** Newer client than us. Things are ok because new clients
michael@0 3418 ** are required to be backwards compatible with old servers.
michael@0 3419 ** Change version number to our version number so that client
michael@0 3420 ** knows whats up.
michael@0 3421 */
michael@0 3422 ss->version = SSL_LIBRARY_VERSION_2;
michael@0 3423 } else {
michael@0 3424 SSL_TRC(1, ("%d: SSL[%d]: client version is %x (we are %x)",
michael@0 3425 SSL_GETPID(), ss->fd, ss->version, SSL_LIBRARY_VERSION_2));
michael@0 3426 PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
michael@0 3427 goto loser;
michael@0 3428 }
michael@0 3429 }
michael@0 3430
michael@0 3431 /* Qualify cipher specs before returning them to client */
michael@0 3432 csLen = ssl2_QualifyCypherSpecs(ss, cs, csLen);
michael@0 3433 if (csLen == 0) {
michael@0 3434 /* no overlap, send client our list of supported SSL v2 ciphers. */
michael@0 3435 cs = csImpl;
michael@0 3436 csLen = sizeof implementedCipherSuites;
michael@0 3437 PORT_Memcpy(cs, implementedCipherSuites, csLen);
michael@0 3438 csLen = ssl2_QualifyCypherSpecs(ss, cs, csLen);
michael@0 3439 if (csLen == 0) {
michael@0 3440 /* We don't support any SSL v2 ciphers! */
michael@0 3441 ssl2_SendErrorMessage(ss, SSL_PE_NO_CYPHERS);
michael@0 3442 PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
michael@0 3443 goto loser;
michael@0 3444 }
michael@0 3445 /* Since this handhsake is going to fail, don't cache it. */
michael@0 3446 ss->opt.noCache = 1;
michael@0 3447 }
michael@0 3448
michael@0 3449 /* Squirrel away the challenge for later */
michael@0 3450 PORT_Memcpy(ss->sec.ci.clientChallenge, challenge, challengeLen);
michael@0 3451
michael@0 3452 /* Examine message and see if session-id is good */
michael@0 3453 ss->sec.ci.elements = 0;
michael@0 3454 if (sdLen > 0 && !ss->opt.noCache) {
michael@0 3455 SSL_TRC(7, ("%d: SSL[%d]: server, lookup client session-id for 0x%08x%08x%08x%08x",
michael@0 3456 SSL_GETPID(), ss->fd, ss->sec.ci.peer.pr_s6_addr32[0],
michael@0 3457 ss->sec.ci.peer.pr_s6_addr32[1],
michael@0 3458 ss->sec.ci.peer.pr_s6_addr32[2],
michael@0 3459 ss->sec.ci.peer.pr_s6_addr32[3]));
michael@0 3460 sid = (*ssl_sid_lookup)(&ss->sec.ci.peer, sd, sdLen, ss->dbHandle);
michael@0 3461 } else {
michael@0 3462 sid = NULL;
michael@0 3463 }
michael@0 3464 if (sid) {
michael@0 3465 /* Got a good session-id. Short cut! */
michael@0 3466 SSL_TRC(1, ("%d: SSL[%d]: server, using session-id for 0x%08x (age=%d)",
michael@0 3467 SSL_GETPID(), ss->fd, ss->sec.ci.peer,
michael@0 3468 ssl_Time() - sid->creationTime));
michael@0 3469 PRINT_BUF(1, (ss, "session-id value:", sd, sdLen));
michael@0 3470 ss->sec.ci.sid = sid;
michael@0 3471 ss->sec.ci.elements = CIS_HAVE_MASTER_KEY;
michael@0 3472 hit = 1;
michael@0 3473 certLen = 0;
michael@0 3474 csLen = 0;
michael@0 3475
michael@0 3476 ss->sec.authAlgorithm = sid->authAlgorithm;
michael@0 3477 ss->sec.authKeyBits = sid->authKeyBits;
michael@0 3478 ss->sec.keaType = sid->keaType;
michael@0 3479 ss->sec.keaKeyBits = sid->keaKeyBits;
michael@0 3480
michael@0 3481 rv = ssl2_CreateSessionCypher(ss, sid, PR_FALSE);
michael@0 3482 if (rv != SECSuccess) {
michael@0 3483 goto loser;
michael@0 3484 }
michael@0 3485 } else {
michael@0 3486 SECItem * derCert = &serverCert->derCert;
michael@0 3487
michael@0 3488 SSL_TRC(7, ("%d: SSL[%d]: server, lookup nonce missed",
michael@0 3489 SSL_GETPID(), ss->fd));
michael@0 3490 if (!serverCert) {
michael@0 3491 SET_ERROR_CODE
michael@0 3492 goto loser;
michael@0 3493 }
michael@0 3494 hit = 0;
michael@0 3495 sid = PORT_ZNew(sslSessionID);
michael@0 3496 if (!sid) {
michael@0 3497 goto loser;
michael@0 3498 }
michael@0 3499 sid->references = 1;
michael@0 3500 sid->addr = ss->sec.ci.peer;
michael@0 3501 sid->port = ss->sec.ci.port;
michael@0 3502
michael@0 3503 /* Invent a session-id */
michael@0 3504 ss->sec.ci.sid = sid;
michael@0 3505 PK11_GenerateRandom(sid->u.ssl2.sessionID+2, SSL2_SESSIONID_BYTES-2);
michael@0 3506
michael@0 3507 pid = SSL_GETPID();
michael@0 3508 sid->u.ssl2.sessionID[0] = MSB(pid);
michael@0 3509 sid->u.ssl2.sessionID[1] = LSB(pid);
michael@0 3510 cert = derCert->data;
michael@0 3511 certLen = derCert->len;
michael@0 3512
michael@0 3513 /* pretend that server sids remember the local cert. */
michael@0 3514 PORT_Assert(!sid->localCert);
michael@0 3515 if (sid->localCert) {
michael@0 3516 CERT_DestroyCertificate(sid->localCert);
michael@0 3517 }
michael@0 3518 sid->localCert = CERT_DupCertificate(serverCert);
michael@0 3519
michael@0 3520 ss->sec.authAlgorithm = ssl_sign_rsa;
michael@0 3521 ss->sec.keaType = ssl_kea_rsa;
michael@0 3522 ss->sec.keaKeyBits = \
michael@0 3523 ss->sec.authKeyBits = ss->serverCerts[kt_rsa].serverKeyBits;
michael@0 3524 }
michael@0 3525
michael@0 3526 /* server sids don't remember the local cert, so whether we found
michael@0 3527 ** a sid or not, just "remember" we used the rsa server cert.
michael@0 3528 */
michael@0 3529 if (ss->sec.localCert) {
michael@0 3530 CERT_DestroyCertificate(ss->sec.localCert);
michael@0 3531 }
michael@0 3532 ss->sec.localCert = CERT_DupCertificate(serverCert);
michael@0 3533
michael@0 3534 /* Build up final list of required elements */
michael@0 3535 ss->sec.ci.requiredElements = CIS_HAVE_MASTER_KEY | CIS_HAVE_FINISHED;
michael@0 3536 if (ss->opt.requestCertificate) {
michael@0 3537 ss->sec.ci.requiredElements |= CIS_HAVE_CERTIFICATE;
michael@0 3538 }
michael@0 3539 ss->sec.ci.sentElements = 0;
michael@0 3540
michael@0 3541 /* Send hello message back to client */
michael@0 3542 sendLen = SSL_HL_SERVER_HELLO_HBYTES + certLen + csLen
michael@0 3543 + SSL_CONNECTIONID_BYTES;
michael@0 3544
michael@0 3545 ssl_GetXmitBufLock(ss); gotXmitBufLock = 1;
michael@0 3546 rv = ssl2_GetSendBuffer(ss, sendLen);
michael@0 3547 if (rv != SECSuccess) {
michael@0 3548 goto loser;
michael@0 3549 }
michael@0 3550
michael@0 3551 SSL_TRC(3, ("%d: SSL[%d]: sending server-hello (%d)",
michael@0 3552 SSL_GETPID(), ss->fd, sendLen));
michael@0 3553
michael@0 3554 msg = ss->sec.ci.sendBuf.buf;
michael@0 3555 msg[0] = SSL_MT_SERVER_HELLO;
michael@0 3556 msg[1] = hit;
michael@0 3557 msg[2] = SSL_CT_X509_CERTIFICATE;
michael@0 3558 msg[3] = MSB(ss->version);
michael@0 3559 msg[4] = LSB(ss->version);
michael@0 3560 msg[5] = MSB(certLen);
michael@0 3561 msg[6] = LSB(certLen);
michael@0 3562 msg[7] = MSB(csLen);
michael@0 3563 msg[8] = LSB(csLen);
michael@0 3564 msg[9] = MSB(SSL_CONNECTIONID_BYTES);
michael@0 3565 msg[10] = LSB(SSL_CONNECTIONID_BYTES);
michael@0 3566 if (certLen) {
michael@0 3567 PORT_Memcpy(msg+SSL_HL_SERVER_HELLO_HBYTES, cert, certLen);
michael@0 3568 }
michael@0 3569 if (csLen) {
michael@0 3570 PORT_Memcpy(msg+SSL_HL_SERVER_HELLO_HBYTES+certLen, cs, csLen);
michael@0 3571 }
michael@0 3572 PORT_Memcpy(msg+SSL_HL_SERVER_HELLO_HBYTES+certLen+csLen,
michael@0 3573 ss->sec.ci.connectionID, SSL_CONNECTIONID_BYTES);
michael@0 3574
michael@0 3575 DUMP_MSG(29, (ss, msg, sendLen));
michael@0 3576
michael@0 3577 ss->handshakeBegun = 1;
michael@0 3578 sent = (*ss->sec.send)(ss, msg, sendLen, 0);
michael@0 3579 if (sent < 0) {
michael@0 3580 goto loser;
michael@0 3581 }
michael@0 3582 ssl_ReleaseXmitBufLock(ss); gotXmitBufLock = 0;
michael@0 3583
michael@0 3584 ss->gs.recordLen = 0;
michael@0 3585 ss->handshake = ssl_GatherRecord1stHandshake;
michael@0 3586 if (hit) {
michael@0 3587 /* Old SID Session key is good. Go encrypted */
michael@0 3588 ssl2_UseEncryptedSendFunc(ss);
michael@0 3589
michael@0 3590 /* Send server verify message now that keys are established */
michael@0 3591 rv = ssl2_SendServerVerifyMessage(ss);
michael@0 3592 if (rv != SECSuccess)
michael@0 3593 goto loser;
michael@0 3594
michael@0 3595 ss->nextHandshake = ssl2_HandleMessage;
michael@0 3596 ssl_ReleaseRecvBufLock(ss);
michael@0 3597 rv = ssl2_TriggerNextMessage(ss);
michael@0 3598 return rv;
michael@0 3599 }
michael@0 3600 ss->nextHandshake = ssl2_HandleClientSessionKeyMessage;
michael@0 3601 ssl_ReleaseRecvBufLock(ss);
michael@0 3602 return SECSuccess;
michael@0 3603
michael@0 3604 bad_client:
michael@0 3605 PORT_SetError(SSL_ERROR_BAD_CLIENT);
michael@0 3606 /* FALLTHROUGH */
michael@0 3607
michael@0 3608 loser:
michael@0 3609 if (gotXmitBufLock) {
michael@0 3610 ssl_ReleaseXmitBufLock(ss); gotXmitBufLock = 0;
michael@0 3611 }
michael@0 3612 SSL_TRC(10, ("%d: SSL[%d]: server, wait for client-hello lossage",
michael@0 3613 SSL_GETPID(), ss->fd));
michael@0 3614 ssl_ReleaseRecvBufLock(ss);
michael@0 3615 return SECFailure;
michael@0 3616 }
michael@0 3617
michael@0 3618 SECStatus
michael@0 3619 ssl2_BeginServerHandshake(sslSocket *ss)
michael@0 3620 {
michael@0 3621 SECStatus rv;
michael@0 3622 sslServerCerts * rsaAuth = ss->serverCerts + kt_rsa;
michael@0 3623
michael@0 3624 ss->sec.isServer = 1;
michael@0 3625 ssl_ChooseSessionIDProcs(&ss->sec);
michael@0 3626 ss->sec.sendSequence = 0;
michael@0 3627 ss->sec.rcvSequence = 0;
michael@0 3628
michael@0 3629 /* don't turn on SSL2 if we don't have an RSA key and cert */
michael@0 3630 if (!rsaAuth->serverKeyPair || !rsaAuth->SERVERKEY ||
michael@0 3631 !rsaAuth->serverCert) {
michael@0 3632 ss->opt.enableSSL2 = PR_FALSE;
michael@0 3633 }
michael@0 3634
michael@0 3635 if (!ss->cipherSpecs) {
michael@0 3636 rv = ssl2_ConstructCipherSpecs(ss);
michael@0 3637 if (rv != SECSuccess)
michael@0 3638 goto loser;
michael@0 3639 }
michael@0 3640
michael@0 3641 /* count the SSL2 and SSL3 enabled ciphers.
michael@0 3642 * if either is zero, clear the socket's enable for that protocol.
michael@0 3643 */
michael@0 3644 rv = ssl2_CheckConfigSanity(ss);
michael@0 3645 if (rv != SECSuccess)
michael@0 3646 goto loser;
michael@0 3647
michael@0 3648 /*
michael@0 3649 ** Generate connection-id. Always do this, even if things fail
michael@0 3650 ** immediately. This way the random number generator is always
michael@0 3651 ** rolling around, every time we get a connection.
michael@0 3652 */
michael@0 3653 PK11_GenerateRandom(ss->sec.ci.connectionID,
michael@0 3654 sizeof(ss->sec.ci.connectionID));
michael@0 3655
michael@0 3656 ss->gs.recordLen = 0;
michael@0 3657 ss->handshake = ssl_GatherRecord1stHandshake;
michael@0 3658 ss->nextHandshake = ssl2_HandleClientHelloMessage;
michael@0 3659 return SECSuccess;
michael@0 3660
michael@0 3661 loser:
michael@0 3662 return SECFailure;
michael@0 3663 }
michael@0 3664
michael@0 3665 /* This function doesn't really belong in this file.
michael@0 3666 ** It's here to keep AIX compilers from optimizing it away,
michael@0 3667 ** and not including it in the DSO.
michael@0 3668 */
michael@0 3669
michael@0 3670 #include "nss.h"
michael@0 3671 extern const char __nss_ssl_rcsid[];
michael@0 3672 extern const char __nss_ssl_sccsid[];
michael@0 3673
michael@0 3674 PRBool
michael@0 3675 NSSSSL_VersionCheck(const char *importedVersion)
michael@0 3676 {
michael@0 3677 /*
michael@0 3678 * This is the secret handshake algorithm.
michael@0 3679 *
michael@0 3680 * This release has a simple version compatibility
michael@0 3681 * check algorithm. This release is not backward
michael@0 3682 * compatible with previous major releases. It is
michael@0 3683 * not compatible with future major, minor, or
michael@0 3684 * patch releases.
michael@0 3685 */
michael@0 3686 volatile char c; /* force a reference that won't get optimized away */
michael@0 3687
michael@0 3688 c = __nss_ssl_rcsid[0] + __nss_ssl_sccsid[0];
michael@0 3689 return NSS_VersionCheck(importedVersion);
michael@0 3690 }
michael@0 3691
michael@0 3692 const char *
michael@0 3693 NSSSSL_GetVersion(void)
michael@0 3694 {
michael@0 3695 return NSS_VERSION;
michael@0 3696 }

mercurial