summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/nss/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/third_party/nss/ssl')
-rw-r--r--chromium/net/third_party/nss/ssl/Makefile63
-rw-r--r--chromium/net/third_party/nss/ssl/SSLerrs.h423
-rw-r--r--chromium/net/third_party/nss/ssl/authcert.c89
-rw-r--r--chromium/net/third_party/nss/ssl/bodge/nssrenam.h47
-rw-r--r--chromium/net/third_party/nss/ssl/bodge/secitem_array.c151
-rw-r--r--chromium/net/third_party/nss/ssl/cmpcert.c90
-rw-r--r--chromium/net/third_party/nss/ssl/derive.c896
-rw-r--r--chromium/net/third_party/nss/ssl/dtlscon.c1139
-rw-r--r--chromium/net/third_party/nss/ssl/exports_win.def60
-rw-r--r--chromium/net/third_party/nss/ssl/manifest.mn53
-rw-r--r--chromium/net/third_party/nss/ssl/notes.txt134
-rw-r--r--chromium/net/third_party/nss/ssl/os2_err.c280
-rw-r--r--chromium/net/third_party/nss/ssl/os2_err.h53
-rw-r--r--chromium/net/third_party/nss/ssl/preenc.h113
-rw-r--r--chromium/net/third_party/nss/ssl/prelib.c34
-rw-r--r--chromium/net/third_party/nss/ssl/ssl.h1110
-rw-r--r--chromium/net/third_party/nss/ssl/ssl.rc68
-rw-r--r--chromium/net/third_party/nss/ssl/ssl3con.c12310
-rw-r--r--chromium/net/third_party/nss/ssl/ssl3ecc.c1280
-rw-r--r--chromium/net/third_party/nss/ssl/ssl3ext.c2299
-rw-r--r--chromium/net/third_party/nss/ssl/ssl3gthr.c413
-rw-r--r--chromium/net/third_party/nss/ssl/ssl3prot.h363
-rw-r--r--chromium/net/third_party/nss/ssl/sslauth.c332
-rw-r--r--chromium/net/third_party/nss/ssl/sslcon.c3696
-rw-r--r--chromium/net/third_party/nss/ssl/ssldef.c210
-rw-r--r--chromium/net/third_party/nss/ssl/sslenum.c150
-rw-r--r--chromium/net/third_party/nss/ssl/sslerr.c41
-rw-r--r--chromium/net/third_party/nss/ssl/sslerr.h204
-rw-r--r--chromium/net/third_party/nss/ssl/sslerrstrs.c34
-rw-r--r--chromium/net/third_party/nss/ssl/sslgathr.c453
-rw-r--r--chromium/net/third_party/nss/ssl/sslimpl.h1941
-rw-r--r--chromium/net/third_party/nss/ssl/sslinfo.c413
-rw-r--r--chromium/net/third_party/nss/ssl/sslinit.c28
-rw-r--r--chromium/net/third_party/nss/ssl/sslmutex.c640
-rw-r--r--chromium/net/third_party/nss/ssl/sslmutex.h125
-rw-r--r--chromium/net/third_party/nss/ssl/sslnonce.c508
-rw-r--r--chromium/net/third_party/nss/ssl/sslplatf.c732
-rw-r--r--chromium/net/third_party/nss/ssl/sslproto.h231
-rw-r--r--chromium/net/third_party/nss/ssl/sslreveal.c112
-rw-r--r--chromium/net/third_party/nss/ssl/sslsecur.c1598
-rw-r--r--chromium/net/third_party/nss/ssl/sslsnce.c2213
-rw-r--r--chromium/net/third_party/nss/ssl/sslsock.c3128
-rw-r--r--chromium/net/third_party/nss/ssl/sslt.h208
-rw-r--r--chromium/net/third_party/nss/ssl/ssltrace.c243
-rw-r--r--chromium/net/third_party/nss/ssl/sslver.c24
-rw-r--r--chromium/net/third_party/nss/ssl/unix_err.c517
-rw-r--r--chromium/net/third_party/nss/ssl/unix_err.h57
-rw-r--r--chromium/net/third_party/nss/ssl/win32err.c343
-rw-r--r--chromium/net/third_party/nss/ssl/win32err.h51
49 files changed, 39700 insertions, 0 deletions
diff --git a/chromium/net/third_party/nss/ssl/Makefile b/chromium/net/third_party/nss/ssl/Makefile
new file mode 100644
index 00000000000..d56cbf29ead
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/Makefile
@@ -0,0 +1,63 @@
+#! gmake
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY). #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL). #
+#######################################################################
+
+include config.mk
+
+ifeq (,$(filter-out WIN%,$(OS_TARGET)))
+CSRCS += win32err.c
+DEFINES += -DIN_LIBSSL
+else
+ifeq ($(OS_TARGET),OS2)
+CSRCS += os2_err.c
+else
+CSRCS += unix_err.c
+endif
+endif
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL). #
+#######################################################################
+
+export:: private_export
+
+ifndef NSS_NO_PKCS11_BYPASS
+# indicates dependency on freebl static lib
+$(SHARED_LIBRARY): $(CRYPTOLIB)
+endif
diff --git a/chromium/net/third_party/nss/ssl/SSLerrs.h b/chromium/net/third_party/nss/ssl/SSLerrs.h
new file mode 100644
index 00000000000..c0d26ccfadc
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/SSLerrs.h
@@ -0,0 +1,423 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* SSL-specific security error codes */
+/* caller must include "sslerr.h" */
+
+ER3(SSL_ERROR_EXPORT_ONLY_SERVER, SSL_ERROR_BASE + 0,
+"Unable to communicate securely. Peer does not support high-grade encryption.")
+
+ER3(SSL_ERROR_US_ONLY_SERVER, SSL_ERROR_BASE + 1,
+"Unable to communicate securely. Peer requires high-grade encryption which is not supported.")
+
+ER3(SSL_ERROR_NO_CYPHER_OVERLAP, SSL_ERROR_BASE + 2,
+"Cannot communicate securely with peer: no common encryption algorithm(s).")
+
+ER3(SSL_ERROR_NO_CERTIFICATE, SSL_ERROR_BASE + 3,
+"Unable to find the certificate or key necessary for authentication.")
+
+ER3(SSL_ERROR_BAD_CERTIFICATE, SSL_ERROR_BASE + 4,
+"Unable to communicate securely with peer: peers's certificate was rejected.")
+
+ER3(SSL_ERROR_UNUSED_5, SSL_ERROR_BASE + 5,
+"Unrecognized SSL error code.")
+
+ER3(SSL_ERROR_BAD_CLIENT, SSL_ERROR_BASE + 6,
+"The server has encountered bad data from the client.")
+
+ER3(SSL_ERROR_BAD_SERVER, SSL_ERROR_BASE + 7,
+"The client has encountered bad data from the server.")
+
+ER3(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE, SSL_ERROR_BASE + 8,
+"Unsupported certificate type.")
+
+ER3(SSL_ERROR_UNSUPPORTED_VERSION, SSL_ERROR_BASE + 9,
+"Peer using unsupported version of security protocol.")
+
+ER3(SSL_ERROR_UNUSED_10, SSL_ERROR_BASE + 10,
+"Unrecognized SSL error code.")
+
+ER3(SSL_ERROR_WRONG_CERTIFICATE, SSL_ERROR_BASE + 11,
+"Client authentication failed: private key in key database does not match public key in certificate database.")
+
+ER3(SSL_ERROR_BAD_CERT_DOMAIN, SSL_ERROR_BASE + 12,
+"Unable to communicate securely with peer: requested domain name does not match the server's certificate.")
+
+ER3(SSL_ERROR_POST_WARNING, SSL_ERROR_BASE + 13,
+"Unrecognized SSL error code.")
+
+ER3(SSL_ERROR_SSL2_DISABLED, (SSL_ERROR_BASE + 14),
+"Peer only supports SSL version 2, which is locally disabled.")
+
+
+ER3(SSL_ERROR_BAD_MAC_READ, (SSL_ERROR_BASE + 15),
+"SSL received a record with an incorrect Message Authentication Code.")
+
+ER3(SSL_ERROR_BAD_MAC_ALERT, (SSL_ERROR_BASE + 16),
+"SSL peer reports incorrect Message Authentication Code.")
+
+ER3(SSL_ERROR_BAD_CERT_ALERT, (SSL_ERROR_BASE + 17),
+"SSL peer cannot verify your certificate.")
+
+ER3(SSL_ERROR_REVOKED_CERT_ALERT, (SSL_ERROR_BASE + 18),
+"SSL peer rejected your certificate as revoked.")
+
+ER3(SSL_ERROR_EXPIRED_CERT_ALERT, (SSL_ERROR_BASE + 19),
+"SSL peer rejected your certificate as expired.")
+
+ER3(SSL_ERROR_SSL_DISABLED, (SSL_ERROR_BASE + 20),
+"Cannot connect: SSL is disabled.")
+
+ER3(SSL_ERROR_FORTEZZA_PQG, (SSL_ERROR_BASE + 21),
+"Cannot connect: SSL peer is in another FORTEZZA domain.")
+
+ER3(SSL_ERROR_UNKNOWN_CIPHER_SUITE , (SSL_ERROR_BASE + 22),
+"An unknown SSL cipher suite has been requested.")
+
+ER3(SSL_ERROR_NO_CIPHERS_SUPPORTED , (SSL_ERROR_BASE + 23),
+"No cipher suites are present and enabled in this program.")
+
+ER3(SSL_ERROR_BAD_BLOCK_PADDING , (SSL_ERROR_BASE + 24),
+"SSL received a record with bad block padding.")
+
+ER3(SSL_ERROR_RX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 25),
+"SSL received a record that exceeded the maximum permissible length.")
+
+ER3(SSL_ERROR_TX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 26),
+"SSL attempted to send a record that exceeded the maximum permissible length.")
+
+/*
+ * Received a malformed (too long or short or invalid content) SSL handshake.
+ */
+ER3(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST , (SSL_ERROR_BASE + 27),
+"SSL received a malformed Hello Request handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO , (SSL_ERROR_BASE + 28),
+"SSL received a malformed Client Hello handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_SERVER_HELLO , (SSL_ERROR_BASE + 29),
+"SSL received a malformed Server Hello handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_CERTIFICATE , (SSL_ERROR_BASE + 30),
+"SSL received a malformed Certificate handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 31),
+"SSL received a malformed Server Key Exchange handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_CERT_REQUEST , (SSL_ERROR_BASE + 32),
+"SSL received a malformed Certificate Request handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_HELLO_DONE , (SSL_ERROR_BASE + 33),
+"SSL received a malformed Server Hello Done handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_CERT_VERIFY , (SSL_ERROR_BASE + 34),
+"SSL received a malformed Certificate Verify handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 35),
+"SSL received a malformed Client Key Exchange handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_FINISHED , (SSL_ERROR_BASE + 36),
+"SSL received a malformed Finished handshake message.")
+
+/*
+ * Received a malformed (too long or short) SSL record.
+ */
+ER3(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER , (SSL_ERROR_BASE + 37),
+"SSL received a malformed Change Cipher Spec record.")
+
+ER3(SSL_ERROR_RX_MALFORMED_ALERT , (SSL_ERROR_BASE + 38),
+"SSL received a malformed Alert record.")
+
+ER3(SSL_ERROR_RX_MALFORMED_HANDSHAKE , (SSL_ERROR_BASE + 39),
+"SSL received a malformed Handshake record.")
+
+ER3(SSL_ERROR_RX_MALFORMED_APPLICATION_DATA , (SSL_ERROR_BASE + 40),
+"SSL received a malformed Application Data record.")
+
+/*
+ * Received an SSL handshake that was inappropriate for the state we're in.
+ * E.g. Server received message from server, or wrong state in state machine.
+ */
+ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST , (SSL_ERROR_BASE + 41),
+"SSL received an unexpected Hello Request handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO , (SSL_ERROR_BASE + 42),
+"SSL received an unexpected Client Hello handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO , (SSL_ERROR_BASE + 43),
+"SSL received an unexpected Server Hello handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CERTIFICATE , (SSL_ERROR_BASE + 44),
+"SSL received an unexpected Certificate handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 45),
+"SSL received an unexpected Server Key Exchange handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST , (SSL_ERROR_BASE + 46),
+"SSL received an unexpected Certificate Request handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE , (SSL_ERROR_BASE + 47),
+"SSL received an unexpected Server Hello Done handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY , (SSL_ERROR_BASE + 48),
+"SSL received an unexpected Certificate Verify handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 49),
+"SSL received an unexpected Client Key Exchange handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_FINISHED , (SSL_ERROR_BASE + 50),
+"SSL received an unexpected Finished handshake message.")
+
+/*
+ * Received an SSL record that was inappropriate for the state we're in.
+ */
+ER3(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER , (SSL_ERROR_BASE + 51),
+"SSL received an unexpected Change Cipher Spec record.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 52),
+"SSL received an unexpected Alert record.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE , (SSL_ERROR_BASE + 53),
+"SSL received an unexpected Handshake record.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA, (SSL_ERROR_BASE + 54),
+"SSL received an unexpected Application Data record.")
+
+/*
+ * Received record/message with unknown discriminant.
+ */
+ER3(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE , (SSL_ERROR_BASE + 55),
+"SSL received a record with an unknown content type.")
+
+ER3(SSL_ERROR_RX_UNKNOWN_HANDSHAKE , (SSL_ERROR_BASE + 56),
+"SSL received a handshake message with an unknown message type.")
+
+ER3(SSL_ERROR_RX_UNKNOWN_ALERT , (SSL_ERROR_BASE + 57),
+"SSL received an alert record with an unknown alert description.")
+
+/*
+ * Received an alert reporting what we did wrong. (more alerts above)
+ */
+ER3(SSL_ERROR_CLOSE_NOTIFY_ALERT , (SSL_ERROR_BASE + 58),
+"SSL peer has closed this connection.")
+
+ER3(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 59),
+"SSL peer was not expecting a handshake message it received.")
+
+ER3(SSL_ERROR_DECOMPRESSION_FAILURE_ALERT , (SSL_ERROR_BASE + 60),
+"SSL peer was unable to successfully decompress an SSL record it received.")
+
+ER3(SSL_ERROR_HANDSHAKE_FAILURE_ALERT , (SSL_ERROR_BASE + 61),
+"SSL peer was unable to negotiate an acceptable set of security parameters.")
+
+ER3(SSL_ERROR_ILLEGAL_PARAMETER_ALERT , (SSL_ERROR_BASE + 62),
+"SSL peer rejected a handshake message for unacceptable content.")
+
+ER3(SSL_ERROR_UNSUPPORTED_CERT_ALERT , (SSL_ERROR_BASE + 63),
+"SSL peer does not support certificates of the type it received.")
+
+ER3(SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT , (SSL_ERROR_BASE + 64),
+"SSL peer had some unspecified issue with the certificate it received.")
+
+
+ER3(SSL_ERROR_GENERATE_RANDOM_FAILURE , (SSL_ERROR_BASE + 65),
+"SSL experienced a failure of its random number generator.")
+
+ER3(SSL_ERROR_SIGN_HASHES_FAILURE , (SSL_ERROR_BASE + 66),
+"Unable to digitally sign data required to verify your certificate.")
+
+ER3(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE , (SSL_ERROR_BASE + 67),
+"SSL was unable to extract the public key from the peer's certificate.")
+
+ER3(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 68),
+"Unspecified failure while processing SSL Server Key Exchange handshake.")
+
+ER3(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 69),
+"Unspecified failure while processing SSL Client Key Exchange handshake.")
+
+ER3(SSL_ERROR_ENCRYPTION_FAILURE , (SSL_ERROR_BASE + 70),
+"Bulk data encryption algorithm failed in selected cipher suite.")
+
+ER3(SSL_ERROR_DECRYPTION_FAILURE , (SSL_ERROR_BASE + 71),
+"Bulk data decryption algorithm failed in selected cipher suite.")
+
+ER3(SSL_ERROR_SOCKET_WRITE_FAILURE , (SSL_ERROR_BASE + 72),
+"Attempt to write encrypted data to underlying socket failed.")
+
+ER3(SSL_ERROR_MD5_DIGEST_FAILURE , (SSL_ERROR_BASE + 73),
+"MD5 digest function failed.")
+
+ER3(SSL_ERROR_SHA_DIGEST_FAILURE , (SSL_ERROR_BASE + 74),
+"SHA-1 digest function failed.")
+
+ER3(SSL_ERROR_MAC_COMPUTATION_FAILURE , (SSL_ERROR_BASE + 75),
+"MAC computation failed.")
+
+ER3(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE , (SSL_ERROR_BASE + 76),
+"Failure to create Symmetric Key context.")
+
+ER3(SSL_ERROR_SYM_KEY_UNWRAP_FAILURE , (SSL_ERROR_BASE + 77),
+"Failure to unwrap the Symmetric key in Client Key Exchange message.")
+
+ER3(SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED , (SSL_ERROR_BASE + 78),
+"SSL Server attempted to use domestic-grade public key with export cipher suite.")
+
+ER3(SSL_ERROR_IV_PARAM_FAILURE , (SSL_ERROR_BASE + 79),
+"PKCS11 code failed to translate an IV into a param.")
+
+ER3(SSL_ERROR_INIT_CIPHER_SUITE_FAILURE , (SSL_ERROR_BASE + 80),
+"Failed to initialize the selected cipher suite.")
+
+ER3(SSL_ERROR_SESSION_KEY_GEN_FAILURE , (SSL_ERROR_BASE + 81),
+"Client failed to generate session keys for SSL session.")
+
+ER3(SSL_ERROR_NO_SERVER_KEY_FOR_ALG , (SSL_ERROR_BASE + 82),
+"Server has no key for the attempted key exchange algorithm.")
+
+ER3(SSL_ERROR_TOKEN_INSERTION_REMOVAL , (SSL_ERROR_BASE + 83),
+"PKCS#11 token was inserted or removed while operation was in progress.")
+
+ER3(SSL_ERROR_TOKEN_SLOT_NOT_FOUND , (SSL_ERROR_BASE + 84),
+"No PKCS#11 token could be found to do a required operation.")
+
+ER3(SSL_ERROR_NO_COMPRESSION_OVERLAP , (SSL_ERROR_BASE + 85),
+"Cannot communicate securely with peer: no common compression algorithm(s).")
+
+ER3(SSL_ERROR_HANDSHAKE_NOT_COMPLETED , (SSL_ERROR_BASE + 86),
+"Cannot perform the operation until the handshake is complete.")
+
+ER3(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE , (SSL_ERROR_BASE + 87),
+"Received incorrect handshakes hash values from peer.")
+
+ER3(SSL_ERROR_CERT_KEA_MISMATCH , (SSL_ERROR_BASE + 88),
+"The certificate provided cannot be used with the selected key exchange algorithm.")
+
+ER3(SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA , (SSL_ERROR_BASE + 89),
+"No certificate authority is trusted for SSL client authentication.")
+
+ER3(SSL_ERROR_SESSION_NOT_FOUND , (SSL_ERROR_BASE + 90),
+"Client's SSL session ID not found in server's session cache.")
+
+ER3(SSL_ERROR_DECRYPTION_FAILED_ALERT , (SSL_ERROR_BASE + 91),
+"Peer was unable to decrypt an SSL record it received.")
+
+ER3(SSL_ERROR_RECORD_OVERFLOW_ALERT , (SSL_ERROR_BASE + 92),
+"Peer received an SSL record that was longer than is permitted.")
+
+ER3(SSL_ERROR_UNKNOWN_CA_ALERT , (SSL_ERROR_BASE + 93),
+"Peer does not recognize and trust the CA that issued your certificate.")
+
+ER3(SSL_ERROR_ACCESS_DENIED_ALERT , (SSL_ERROR_BASE + 94),
+"Peer received a valid certificate, but access was denied.")
+
+ER3(SSL_ERROR_DECODE_ERROR_ALERT , (SSL_ERROR_BASE + 95),
+"Peer could not decode an SSL handshake message.")
+
+ER3(SSL_ERROR_DECRYPT_ERROR_ALERT , (SSL_ERROR_BASE + 96),
+"Peer reports failure of signature verification or key exchange.")
+
+ER3(SSL_ERROR_EXPORT_RESTRICTION_ALERT , (SSL_ERROR_BASE + 97),
+"Peer reports negotiation not in compliance with export regulations.")
+
+ER3(SSL_ERROR_PROTOCOL_VERSION_ALERT , (SSL_ERROR_BASE + 98),
+"Peer reports incompatible or unsupported protocol version.")
+
+ER3(SSL_ERROR_INSUFFICIENT_SECURITY_ALERT , (SSL_ERROR_BASE + 99),
+"Server requires ciphers more secure than those supported by client.")
+
+ER3(SSL_ERROR_INTERNAL_ERROR_ALERT , (SSL_ERROR_BASE + 100),
+"Peer reports it experienced an internal error.")
+
+ER3(SSL_ERROR_USER_CANCELED_ALERT , (SSL_ERROR_BASE + 101),
+"Peer user canceled handshake.")
+
+ER3(SSL_ERROR_NO_RENEGOTIATION_ALERT , (SSL_ERROR_BASE + 102),
+"Peer does not permit renegotiation of SSL security parameters.")
+
+ER3(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED , (SSL_ERROR_BASE + 103),
+"SSL server cache not configured and not disabled for this socket.")
+
+ER3(SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT , (SSL_ERROR_BASE + 104),
+"SSL peer does not support requested TLS hello extension.")
+
+ER3(SSL_ERROR_CERTIFICATE_UNOBTAINABLE_ALERT , (SSL_ERROR_BASE + 105),
+"SSL peer could not obtain your certificate from the supplied URL.")
+
+ER3(SSL_ERROR_UNRECOGNIZED_NAME_ALERT , (SSL_ERROR_BASE + 106),
+"SSL peer has no certificate for the requested DNS name.")
+
+ER3(SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT , (SSL_ERROR_BASE + 107),
+"SSL peer was unable to get an OCSP response for its certificate.")
+
+ER3(SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT , (SSL_ERROR_BASE + 108),
+"SSL peer reported bad certificate hash value.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET, (SSL_ERROR_BASE + 109),
+"SSL received an unexpected New Session Ticket handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET, (SSL_ERROR_BASE + 110),
+"SSL received a malformed New Session Ticket handshake message.")
+
+ER3(SSL_ERROR_DECOMPRESSION_FAILURE, (SSL_ERROR_BASE + 111),
+"SSL received a compressed record that could not be decompressed.")
+
+ER3(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, (SSL_ERROR_BASE + 112),
+"Renegotiation is not allowed on this SSL socket.")
+
+ER3(SSL_ERROR_UNSAFE_NEGOTIATION, (SSL_ERROR_BASE + 113),
+"Peer attempted old style (potentially vulnerable) handshake.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD, (SSL_ERROR_BASE + 114),
+"SSL received an unexpected uncompressed record.")
+
+ER3(SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY, (SSL_ERROR_BASE + 115),
+"SSL received a weak ephemeral Diffie-Hellman key in Server Key Exchange handshake message.")
+
+ER3(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID, (SSL_ERROR_BASE + 116),
+"SSL received invalid NPN extension data.")
+
+ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2, (SSL_ERROR_BASE + 117),
+"SSL feature not supported for SSL 2.0 connections.")
+
+ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS, (SSL_ERROR_BASE + 118),
+"SSL feature not supported for servers.")
+
+ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_CLIENTS, (SSL_ERROR_BASE + 119),
+"SSL feature not supported for clients.")
+
+ER3(SSL_ERROR_INVALID_VERSION_RANGE, (SSL_ERROR_BASE + 120),
+"SSL version range is not valid.")
+
+ER3(SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION, (SSL_ERROR_BASE + 121),
+"SSL peer selected a cipher suite disallowed for the selected protocol version.")
+
+ER3(SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST, (SSL_ERROR_BASE + 122),
+"SSL received a malformed Hello Verify Request handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST, (SSL_ERROR_BASE + 123),
+"SSL received an unexpected Hello Verify Request handshake message.")
+
+ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION, (SSL_ERROR_BASE + 124),
+"SSL feature not supported for the protocol version.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CERT_STATUS, (SSL_ERROR_BASE + 125),
+"SSL received an unexpected Certificate Status handshake message.")
+
+ER3(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM, (SSL_ERROR_BASE + 126),
+"Unsupported hash algorithm used by TLS peer.")
+
+ER3(SSL_ERROR_DIGEST_FAILURE, (SSL_ERROR_BASE + 127),
+"Digest function failed.")
+
+ER3(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, (SSL_ERROR_BASE + 128),
+"Incorrect signature algorithm specified in a digitally-signed element.")
+
+ER3(SSL_ERROR_BAD_CHANNEL_ID_DATA, (SSL_ERROR_BASE + 129),
+"SSL received a malformed TLS Channel ID extension.")
+
+ER3(SSL_ERROR_INVALID_CHANNEL_ID_KEY, (SSL_ERROR_BASE + 130),
+"The application provided an invalid TLS Channel ID key.")
+
+ER3(SSL_ERROR_GET_CHANNEL_ID_FAILED, (SSL_ERROR_BASE + 131),
+"The application could not get a TLS Channel ID.")
diff --git a/chromium/net/third_party/nss/ssl/authcert.c b/chromium/net/third_party/nss/ssl/authcert.c
new file mode 100644
index 00000000000..bd0f6ed49a2
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/authcert.c
@@ -0,0 +1,89 @@
+/*
+ * NSS utility functions
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <stdio.h>
+#include <string.h>
+#include "prerror.h"
+#include "secitem.h"
+#include "prnetdb.h"
+#include "cert.h"
+#include "nspr.h"
+#include "secder.h"
+#include "key.h"
+#include "nss.h"
+#include "ssl.h"
+#include "pk11func.h" /* for PK11_ function calls */
+
+/*
+ * This callback used by SSL to pull client sertificate upon
+ * server request
+ */
+SECStatus
+NSS_GetClientAuthData(void * arg,
+ PRFileDesc * socket,
+ struct CERTDistNamesStr * caNames,
+ struct CERTCertificateStr ** pRetCert,
+ struct SECKEYPrivateKeyStr **pRetKey)
+{
+ CERTCertificate * cert = NULL;
+ SECKEYPrivateKey * privkey = NULL;
+ char * chosenNickName = (char *)arg; /* CONST */
+ void * proto_win = NULL;
+ SECStatus rv = SECFailure;
+
+ proto_win = SSL_RevealPinArg(socket);
+
+ if (chosenNickName) {
+ cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
+ chosenNickName, certUsageSSLClient,
+ PR_FALSE, proto_win);
+ if ( cert ) {
+ privkey = PK11_FindKeyByAnyCert(cert, proto_win);
+ if ( privkey ) {
+ rv = SECSuccess;
+ } else {
+ CERT_DestroyCertificate(cert);
+ }
+ }
+ } else { /* no name given, automatically find the right cert. */
+ CERTCertNicknames * names;
+ int i;
+
+ names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(),
+ SEC_CERT_NICKNAMES_USER, proto_win);
+ if (names != NULL) {
+ for (i = 0; i < names->numnicknames; i++) {
+ cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
+ names->nicknames[i], certUsageSSLClient,
+ PR_FALSE, proto_win);
+ if ( !cert )
+ continue;
+ /* Only check unexpired certs */
+ if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) !=
+ secCertTimeValid ) {
+ CERT_DestroyCertificate(cert);
+ continue;
+ }
+ rv = NSS_CmpCertChainWCANames(cert, caNames);
+ if ( rv == SECSuccess ) {
+ privkey = PK11_FindKeyByAnyCert(cert, proto_win);
+ if ( privkey )
+ break;
+ }
+ rv = SECFailure;
+ CERT_DestroyCertificate(cert);
+ }
+ CERT_FreeNicknames(names);
+ }
+ }
+ if (rv == SECSuccess) {
+ *pRetCert = cert;
+ *pRetKey = privkey;
+ }
+ return rv;
+}
+
diff --git a/chromium/net/third_party/nss/ssl/bodge/nssrenam.h b/chromium/net/third_party/nss/ssl/bodge/nssrenam.h
new file mode 100644
index 00000000000..156646cdd2d
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/bodge/nssrenam.h
@@ -0,0 +1,47 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __nssrenam_h_
+#define __nssrenam_h_
+
+#define CERT_AddTempCertToPerm __CERT_AddTempCertToPerm
+#define PK11_CreateContextByRawKey __PK11_CreateContextByRawKey
+#define CERT_ClosePermCertDB __CERT_ClosePermCertDB
+#define CERT_DecodeDERCertificate __CERT_DecodeDERCertificate
+#define CERT_TraversePermCertsForNickname __CERT_TraversePermCertsForNickname
+#define CERT_TraversePermCertsForSubject __CERT_TraversePermCertsForSubject
+
+#endif /* __nssrenam_h_ */
diff --git a/chromium/net/third_party/nss/ssl/bodge/secitem_array.c b/chromium/net/third_party/nss/ssl/bodge/secitem_array.c
new file mode 100644
index 00000000000..2acd5f8e24a
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/bodge/secitem_array.c
@@ -0,0 +1,151 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Support routines for SECItemArray data structure.
+ */
+
+#include "nssutil.h"
+#include "seccomon.h"
+#include "secitem.h"
+#include "secerr.h"
+#include "secport.h"
+
+#define NSSUTIL_VERSION_NUM \
+ (NSSUTIL_VMAJOR * 10000 + NSSUTIL_VMINOR * 100 + NSSUTIL_VPATCH)
+#if NSSUTIL_VERSION_NUM < 31500
+// Added in NSS 3.15.
+typedef struct SECItemArrayStr SECItemArray;
+
+struct SECItemArrayStr {
+ SECItem *items;
+ unsigned int len;
+};
+#endif
+
+SECItemArray *
+SECITEM_AllocArray(PLArenaPool *arena, SECItemArray *array, unsigned int len)
+{
+ SECItemArray *result = NULL;
+ void *mark = NULL;
+
+ if (arena != NULL) {
+ mark = PORT_ArenaMark(arena);
+ }
+
+ if (array == NULL) {
+ if (arena != NULL) {
+ result = PORT_ArenaZAlloc(arena, sizeof(SECItemArray));
+ } else {
+ result = PORT_ZAlloc(sizeof(SECItemArray));
+ }
+ if (result == NULL) {
+ goto loser;
+ }
+ } else {
+ PORT_Assert(array->items == NULL);
+ result = array;
+ }
+
+ result->len = len;
+ if (len) {
+ if (arena != NULL) {
+ result->items = PORT_ArenaZNewArray(arena, SECItem, len);
+ } else {
+ result->items = PORT_ZNewArray(SECItem, len);
+ }
+ if (result->items == NULL) {
+ goto loser;
+ }
+ } else {
+ result->items = NULL;
+ }
+
+ if (mark) {
+ PORT_ArenaUnmark(arena, mark);
+ }
+ return(result);
+
+loser:
+ if ( arena != NULL ) {
+ if (mark) {
+ PORT_ArenaRelease(arena, mark);
+ }
+ if (array != NULL) {
+ array->items = NULL;
+ array->len = 0;
+ }
+ } else {
+ if (result != NULL && array == NULL) {
+ PORT_Free(result);
+ }
+ /*
+ * If array is not NULL, the above has set array->data and
+ * array->len to 0.
+ */
+ }
+ return(NULL);
+}
+
+static void
+secitem_FreeArray(SECItemArray *array, PRBool zero_items, PRBool freeit)
+{
+ unsigned int i;
+
+ if (!array || !array->len || !array->items)
+ return;
+
+ for (i=0; i<array->len; ++i) {
+ SECItem *item = &array->items[i];
+
+ if (item->data) {
+ if (zero_items) {
+ SECITEM_ZfreeItem(item, PR_FALSE);
+ } else {
+ SECITEM_FreeItem(item, PR_FALSE);
+ }
+ }
+ }
+ PORT_Free(array->items);
+ array->items = NULL;
+ array->len = 0;
+
+ if (freeit)
+ PORT_Free(array);
+}
+
+void SECITEM_FreeArray(SECItemArray *array, PRBool freeit)
+{
+ secitem_FreeArray(array, PR_FALSE, freeit);
+}
+
+void SECITEM_ZfreeArray(SECItemArray *array, PRBool freeit)
+{
+ secitem_FreeArray(array, PR_TRUE, freeit);
+}
+
+SECItemArray *
+SECITEM_DupArray(PLArenaPool *arena, const SECItemArray *from)
+{
+ SECItemArray *result;
+ unsigned int i;
+
+ if (!from || !from->items || !from->len)
+ return NULL;
+
+ result = SECITEM_AllocArray(arena, NULL, from->len);
+ if (!result)
+ return NULL;
+
+ for (i=0; i<from->len; ++i) {
+ SECStatus rv = SECITEM_CopyItem(arena,
+ &result->items[i], &from->items[i]);
+ if (rv != SECSuccess) {
+ SECITEM_ZfreeArray(result, PR_TRUE);
+ return NULL;
+ }
+ }
+
+ return result;
+}
diff --git a/chromium/net/third_party/nss/ssl/cmpcert.c b/chromium/net/third_party/nss/ssl/cmpcert.c
new file mode 100644
index 00000000000..6d8423822d5
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/cmpcert.c
@@ -0,0 +1,90 @@
+/*
+ * NSS utility functions
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <stdio.h>
+#include <string.h>
+#include "prerror.h"
+#include "secitem.h"
+#include "prnetdb.h"
+#include "cert.h"
+#include "nspr.h"
+#include "secder.h"
+#include "key.h"
+#include "nss.h"
+
+/*
+ * Look to see if any of the signers in the cert chain for "cert" are found
+ * in the list of caNames.
+ * Returns SECSuccess if so, SECFailure if not.
+ */
+SECStatus
+NSS_CmpCertChainWCANames(CERTCertificate *cert, CERTDistNames *caNames)
+{
+ SECItem * caname;
+ CERTCertificate * curcert;
+ CERTCertificate * oldcert;
+ PRInt32 contentlen;
+ int j;
+ int headerlen;
+ int depth;
+ SECStatus rv;
+ SECItem issuerName;
+ SECItem compatIssuerName;
+
+ if (!cert || !caNames || !caNames->nnames || !caNames->names ||
+ !caNames->names->data)
+ return SECFailure;
+ depth=0;
+ curcert = CERT_DupCertificate(cert);
+
+ while( curcert ) {
+ issuerName = curcert->derIssuer;
+
+ /* compute an alternate issuer name for compatibility with 2.0
+ * enterprise server, which send the CA names without
+ * the outer layer of DER header
+ */
+ rv = DER_Lengths(&issuerName, &headerlen, (PRUint32 *)&contentlen);
+ if ( rv == SECSuccess ) {
+ compatIssuerName.data = &issuerName.data[headerlen];
+ compatIssuerName.len = issuerName.len - headerlen;
+ } else {
+ compatIssuerName.data = NULL;
+ compatIssuerName.len = 0;
+ }
+
+ for (j = 0; j < caNames->nnames; j++) {
+ caname = &caNames->names[j];
+ if (SECITEM_CompareItem(&issuerName, caname) == SECEqual) {
+ rv = SECSuccess;
+ CERT_DestroyCertificate(curcert);
+ goto done;
+ } else if (SECITEM_CompareItem(&compatIssuerName, caname) == SECEqual) {
+ rv = SECSuccess;
+ CERT_DestroyCertificate(curcert);
+ goto done;
+ }
+ }
+ if ( ( depth <= 20 ) &&
+ ( SECITEM_CompareItem(&curcert->derIssuer, &curcert->derSubject)
+ != SECEqual ) ) {
+ oldcert = curcert;
+ curcert = CERT_FindCertByName(curcert->dbhandle,
+ &curcert->derIssuer);
+ CERT_DestroyCertificate(oldcert);
+ depth++;
+ } else {
+ CERT_DestroyCertificate(curcert);
+ curcert = NULL;
+ }
+ }
+ rv = SECFailure;
+
+done:
+ return rv;
+}
+
diff --git a/chromium/net/third_party/nss/ssl/derive.c b/chromium/net/third_party/nss/ssl/derive.c
new file mode 100644
index 00000000000..35cfe25122f
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/derive.c
@@ -0,0 +1,896 @@
+/*
+ * Key Derivation that doesn't use PKCS11
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ssl.h" /* prereq to sslimpl.h */
+#include "certt.h" /* prereq to sslimpl.h */
+#include "keythi.h" /* prereq to sslimpl.h */
+#include "sslimpl.h"
+#ifndef NO_PKCS11_BYPASS
+#include "blapi.h"
+#endif
+
+#include "keyhi.h"
+#include "pk11func.h"
+#include "secasn1.h"
+#include "cert.h"
+#include "secmodt.h"
+
+#include "sslproto.h"
+#include "sslerr.h"
+
+#ifndef NO_PKCS11_BYPASS
+/* make this a macro! */
+#ifdef NOT_A_MACRO
+static void
+buildSSLKey(unsigned char * keyBlock, unsigned int keyLen, SECItem * result,
+ const char * label)
+{
+ result->type = siBuffer;
+ result->data = keyBlock;
+ result->len = keyLen;
+ PRINT_BUF(100, (NULL, label, keyBlock, keyLen));
+}
+#else
+#define buildSSLKey(keyBlock, keyLen, result, label) \
+{ \
+ (result)->type = siBuffer; \
+ (result)->data = keyBlock; \
+ (result)->len = keyLen; \
+ PRINT_BUF(100, (NULL, label, keyBlock, keyLen)); \
+}
+#endif
+
+/*
+ * SSL Key generation given pre master secret
+ */
+#ifndef NUM_MIXERS
+#define NUM_MIXERS 9
+#endif
+static const char * const mixers[NUM_MIXERS] = {
+ "A",
+ "BB",
+ "CCC",
+ "DDDD",
+ "EEEEE",
+ "FFFFFF",
+ "GGGGGGG",
+ "HHHHHHHH",
+ "IIIIIIIII"
+};
+
+
+SECStatus
+ssl3_KeyAndMacDeriveBypass(
+ ssl3CipherSpec * pwSpec,
+ const unsigned char * cr,
+ const unsigned char * sr,
+ PRBool isTLS,
+ PRBool isExport)
+{
+ const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def;
+ unsigned char * key_block = pwSpec->key_block;
+ unsigned char * key_block2 = NULL;
+ unsigned int block_bytes = 0;
+ unsigned int block_needed = 0;
+ unsigned int i;
+ unsigned int keySize; /* actual size of cipher keys */
+ unsigned int effKeySize; /* effective size of cipher keys */
+ unsigned int macSize; /* size of MAC secret */
+ unsigned int IVSize; /* size of IV */
+ PRBool explicitIV = PR_FALSE;
+ SECStatus rv = SECFailure;
+ SECStatus status = SECSuccess;
+ PRBool isFIPS = PR_FALSE;
+ PRBool isTLS12 = pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2;
+
+ SECItem srcr;
+ SECItem crsr;
+
+ unsigned char srcrdata[SSL3_RANDOM_LENGTH * 2];
+ unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2];
+ PRUint64 md5buf[22];
+ PRUint64 shabuf[40];
+
+#define md5Ctx ((MD5Context *)md5buf)
+#define shaCtx ((SHA1Context *)shabuf)
+
+ static const SECItem zed = { siBuffer, NULL, 0 };
+
+ if (pwSpec->msItem.data == NULL ||
+ pwSpec->msItem.len != SSL3_MASTER_SECRET_LENGTH) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return rv;
+ }
+
+ PRINT_BUF(100, (NULL, "Master Secret", pwSpec->msItem.data,
+ pwSpec->msItem.len));
+
+ /* figure out how much is needed */
+ macSize = pwSpec->mac_size;
+ keySize = cipher_def->key_size;
+ effKeySize = cipher_def->secret_key_size;
+ IVSize = cipher_def->iv_size;
+ if (keySize == 0) {
+ effKeySize = IVSize = 0; /* only MACing */
+ }
+ if (cipher_def->type == type_block &&
+ pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
+ /* Block ciphers in >= TLS 1.1 use a per-record, explicit IV. */
+ explicitIV = PR_TRUE;
+ }
+ block_needed =
+ 2 * (macSize + effKeySize + ((!isExport && !explicitIV) * IVSize));
+
+ /*
+ * clear out our returned keys so we can recover on failure
+ */
+ pwSpec->client.write_key_item = zed;
+ pwSpec->client.write_mac_key_item = zed;
+ pwSpec->server.write_key_item = zed;
+ pwSpec->server.write_mac_key_item = zed;
+
+ /* initialize the server random, client random block */
+ srcr.type = siBuffer;
+ srcr.data = srcrdata;
+ srcr.len = sizeof srcrdata;
+ PORT_Memcpy(srcrdata, sr, SSL3_RANDOM_LENGTH);
+ PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, cr, SSL3_RANDOM_LENGTH);
+
+ /* initialize the client random, server random block */
+ crsr.type = siBuffer;
+ crsr.data = crsrdata;
+ crsr.len = sizeof crsrdata;
+ PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH);
+ PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH);
+ PRINT_BUF(100, (NULL, "Key & MAC CRSR", crsr.data, crsr.len));
+
+ /*
+ * generate the key material:
+ */
+ if (isTLS) {
+ SECItem keyblk;
+
+ keyblk.type = siBuffer;
+ keyblk.data = key_block;
+ keyblk.len = block_needed;
+
+ if (isTLS12) {
+ status = TLS_P_hash(HASH_AlgSHA256, &pwSpec->msItem,
+ "key expansion", &srcr, &keyblk, isFIPS);
+ } else {
+ status = TLS_PRF(&pwSpec->msItem, "key expansion", &srcr, &keyblk,
+ isFIPS);
+ }
+ if (status != SECSuccess) {
+ goto key_and_mac_derive_fail;
+ }
+ block_bytes = keyblk.len;
+ } else {
+ /* key_block =
+ * MD5(master_secret + SHA('A' + master_secret +
+ * ServerHello.random + ClientHello.random)) +
+ * MD5(master_secret + SHA('BB' + master_secret +
+ * ServerHello.random + ClientHello.random)) +
+ * MD5(master_secret + SHA('CCC' + master_secret +
+ * ServerHello.random + ClientHello.random)) +
+ * [...];
+ */
+ unsigned int made = 0;
+ for (i = 0; made < block_needed && i < NUM_MIXERS; ++i) {
+ unsigned int outLen;
+ unsigned char sha_out[SHA1_LENGTH];
+
+ SHA1_Begin(shaCtx);
+ SHA1_Update(shaCtx, (unsigned char*)(mixers[i]), i+1);
+ SHA1_Update(shaCtx, pwSpec->msItem.data, pwSpec->msItem.len);
+ SHA1_Update(shaCtx, srcr.data, srcr.len);
+ SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH);
+ PORT_Assert(outLen == SHA1_LENGTH);
+
+ MD5_Begin(md5Ctx);
+ MD5_Update(md5Ctx, pwSpec->msItem.data, pwSpec->msItem.len);
+ MD5_Update(md5Ctx, sha_out, outLen);
+ MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH);
+ PORT_Assert(outLen == MD5_LENGTH);
+ made += MD5_LENGTH;
+ }
+ block_bytes = made;
+ }
+ PORT_Assert(block_bytes >= block_needed);
+ PORT_Assert(block_bytes <= sizeof pwSpec->key_block);
+ PRINT_BUF(100, (NULL, "key block", key_block, block_bytes));
+
+ /*
+ * Put the key material where it goes.
+ */
+ key_block2 = key_block + block_bytes;
+ i = 0; /* now shows how much consumed */
+
+ /*
+ * The key_block is partitioned as follows:
+ * client_write_MAC_secret[CipherSpec.hash_size]
+ */
+ buildSSLKey(&key_block[i],macSize, &pwSpec->client.write_mac_key_item, \
+ "Client Write MAC Secret");
+ i += macSize;
+
+ /*
+ * server_write_MAC_secret[CipherSpec.hash_size]
+ */
+ buildSSLKey(&key_block[i],macSize, &pwSpec->server.write_mac_key_item, \
+ "Server Write MAC Secret");
+ i += macSize;
+
+ if (!keySize) {
+ /* only MACing */
+ buildSSLKey(NULL, 0, &pwSpec->client.write_key_item, \
+ "Client Write Key (MAC only)");
+ buildSSLKey(NULL, 0, &pwSpec->server.write_key_item, \
+ "Server Write Key (MAC only)");
+ buildSSLKey(NULL, 0, &pwSpec->client.write_iv_item, \
+ "Client Write IV (MAC only)");
+ buildSSLKey(NULL, 0, &pwSpec->server.write_iv_item, \
+ "Server Write IV (MAC only)");
+ } else if (!isExport) {
+ /*
+ ** Generate Domestic write keys and IVs.
+ ** client_write_key[CipherSpec.key_material]
+ */
+ buildSSLKey(&key_block[i], keySize, &pwSpec->client.write_key_item, \
+ "Domestic Client Write Key");
+ i += keySize;
+
+ /*
+ ** server_write_key[CipherSpec.key_material]
+ */
+ buildSSLKey(&key_block[i], keySize, &pwSpec->server.write_key_item, \
+ "Domestic Server Write Key");
+ i += keySize;
+
+ if (IVSize > 0) {
+ if (explicitIV) {
+ static unsigned char zero_block[32];
+ PORT_Assert(IVSize <= sizeof zero_block);
+ buildSSLKey(&zero_block[0], IVSize, \
+ &pwSpec->client.write_iv_item, \
+ "Domestic Client Write IV");
+ buildSSLKey(&zero_block[0], IVSize, \
+ &pwSpec->server.write_iv_item, \
+ "Domestic Server Write IV");
+ } else {
+ /*
+ ** client_write_IV[CipherSpec.IV_size]
+ */
+ buildSSLKey(&key_block[i], IVSize, \
+ &pwSpec->client.write_iv_item, \
+ "Domestic Client Write IV");
+ i += IVSize;
+
+ /*
+ ** server_write_IV[CipherSpec.IV_size]
+ */
+ buildSSLKey(&key_block[i], IVSize, \
+ &pwSpec->server.write_iv_item, \
+ "Domestic Server Write IV");
+ i += IVSize;
+ }
+ }
+ PORT_Assert(i <= block_bytes);
+ } else if (!isTLS) {
+ /*
+ ** Generate SSL3 Export write keys and IVs.
+ */
+ unsigned int outLen;
+
+ /*
+ ** client_write_key[CipherSpec.key_material]
+ ** final_client_write_key = MD5(client_write_key +
+ ** ClientHello.random + ServerHello.random);
+ */
+ MD5_Begin(md5Ctx);
+ MD5_Update(md5Ctx, &key_block[i], effKeySize);
+ MD5_Update(md5Ctx, crsr.data, crsr.len);
+ MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
+ i += effKeySize;
+ buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item, \
+ "SSL3 Export Client Write Key");
+ key_block2 += keySize;
+
+ /*
+ ** server_write_key[CipherSpec.key_material]
+ ** final_server_write_key = MD5(server_write_key +
+ ** ServerHello.random + ClientHello.random);
+ */
+ MD5_Begin(md5Ctx);
+ MD5_Update(md5Ctx, &key_block[i], effKeySize);
+ MD5_Update(md5Ctx, srcr.data, srcr.len);
+ MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
+ i += effKeySize;
+ buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item, \
+ "SSL3 Export Server Write Key");
+ key_block2 += keySize;
+ PORT_Assert(i <= block_bytes);
+
+ if (IVSize) {
+ /*
+ ** client_write_IV =
+ ** MD5(ClientHello.random + ServerHello.random);
+ */
+ MD5_Begin(md5Ctx);
+ MD5_Update(md5Ctx, crsr.data, crsr.len);
+ MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
+ buildSSLKey(key_block2, IVSize, &pwSpec->client.write_iv_item, \
+ "SSL3 Export Client Write IV");
+ key_block2 += IVSize;
+
+ /*
+ ** server_write_IV =
+ ** MD5(ServerHello.random + ClientHello.random);
+ */
+ MD5_Begin(md5Ctx);
+ MD5_Update(md5Ctx, srcr.data, srcr.len);
+ MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
+ buildSSLKey(key_block2, IVSize, &pwSpec->server.write_iv_item, \
+ "SSL3 Export Server Write IV");
+ key_block2 += IVSize;
+ }
+
+ PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block);
+ } else {
+ /*
+ ** Generate TLS Export write keys and IVs.
+ */
+ SECItem secret ;
+ SECItem keyblk ;
+
+ secret.type = siBuffer;
+ keyblk.type = siBuffer;
+ /*
+ ** client_write_key[CipherSpec.key_material]
+ ** final_client_write_key = PRF(client_write_key,
+ ** "client write key",
+ ** client_random + server_random);
+ */
+ secret.data = &key_block[i];
+ secret.len = effKeySize;
+ i += effKeySize;
+ keyblk.data = key_block2;
+ keyblk.len = keySize;
+ status = TLS_PRF(&secret, "client write key", &crsr, &keyblk, isFIPS);
+ if (status != SECSuccess) {
+ goto key_and_mac_derive_fail;
+ }
+ buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item, \
+ "TLS Export Client Write Key");
+ key_block2 += keySize;
+
+ /*
+ ** server_write_key[CipherSpec.key_material]
+ ** final_server_write_key = PRF(server_write_key,
+ ** "server write key",
+ ** client_random + server_random);
+ */
+ secret.data = &key_block[i];
+ secret.len = effKeySize;
+ i += effKeySize;
+ keyblk.data = key_block2;
+ keyblk.len = keySize;
+ status = TLS_PRF(&secret, "server write key", &crsr, &keyblk, isFIPS);
+ if (status != SECSuccess) {
+ goto key_and_mac_derive_fail;
+ }
+ buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item, \
+ "TLS Export Server Write Key");
+ key_block2 += keySize;
+
+ /*
+ ** iv_block = PRF("", "IV block", client_random + server_random);
+ ** client_write_IV[SecurityParameters.IV_size]
+ ** server_write_IV[SecurityParameters.IV_size]
+ */
+ if (IVSize) {
+ secret.data = NULL;
+ secret.len = 0;
+ keyblk.data = key_block2;
+ keyblk.len = 2 * IVSize;
+ status = TLS_PRF(&secret, "IV block", &crsr, &keyblk, isFIPS);
+ if (status != SECSuccess) {
+ goto key_and_mac_derive_fail;
+ }
+ buildSSLKey(key_block2, IVSize, \
+ &pwSpec->client.write_iv_item, \
+ "TLS Export Client Write IV");
+ buildSSLKey(key_block2 + IVSize, IVSize, \
+ &pwSpec->server.write_iv_item, \
+ "TLS Export Server Write IV");
+ key_block2 += 2 * IVSize;
+ }
+ PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block);
+ }
+ rv = SECSuccess;
+
+key_and_mac_derive_fail:
+
+ MD5_DestroyContext(md5Ctx, PR_FALSE);
+ SHA1_DestroyContext(shaCtx, PR_FALSE);
+
+ if (rv != SECSuccess) {
+ PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
+ }
+
+ return rv;
+}
+
+
+/* derive the Master Secret from the PMS */
+/* Presently, this is only done wtih RSA PMS, and only on the server side,
+ * so isRSA is always true.
+ */
+SECStatus
+ssl3_MasterKeyDeriveBypass(
+ ssl3CipherSpec * pwSpec,
+ const unsigned char * cr,
+ const unsigned char * sr,
+ const SECItem * pms,
+ PRBool isTLS,
+ PRBool isRSA)
+{
+ unsigned char * key_block = pwSpec->key_block;
+ SECStatus rv = SECSuccess;
+ PRBool isFIPS = PR_FALSE;
+ PRBool isTLS12 = pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2;
+
+ SECItem crsr;
+
+ unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2];
+ PRUint64 md5buf[22];
+ PRUint64 shabuf[40];
+
+#define md5Ctx ((MD5Context *)md5buf)
+#define shaCtx ((SHA1Context *)shabuf)
+
+ /* first do the consistancy checks */
+ if (isRSA) {
+ PORT_Assert(pms->len == SSL3_RSA_PMS_LENGTH);
+ if (pms->len != SSL3_RSA_PMS_LENGTH) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ /* caller must test PMS version for rollback */
+ }
+
+ /* initialize the client random, server random block */
+ crsr.type = siBuffer;
+ crsr.data = crsrdata;
+ crsr.len = sizeof crsrdata;
+ PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH);
+ PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH);
+ PRINT_BUF(100, (NULL, "Master Secret CRSR", crsr.data, crsr.len));
+
+ /* finally do the key gen */
+ if (isTLS) {
+ SECItem master = { siBuffer, NULL, 0 };
+
+ master.data = key_block;
+ master.len = SSL3_MASTER_SECRET_LENGTH;
+
+ if (isTLS12) {
+ rv = TLS_P_hash(HASH_AlgSHA256, pms, "master secret", &crsr,
+ &master, isFIPS);
+ } else {
+ rv = TLS_PRF(pms, "master secret", &crsr, &master, isFIPS);
+ }
+ if (rv != SECSuccess) {
+ PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
+ }
+ } else {
+ int i;
+ unsigned int made = 0;
+ for (i = 0; i < 3; i++) {
+ unsigned int outLen;
+ unsigned char sha_out[SHA1_LENGTH];
+
+ SHA1_Begin(shaCtx);
+ SHA1_Update(shaCtx, (unsigned char*) mixers[i], i+1);
+ SHA1_Update(shaCtx, pms->data, pms->len);
+ SHA1_Update(shaCtx, crsr.data, crsr.len);
+ SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH);
+ PORT_Assert(outLen == SHA1_LENGTH);
+
+ MD5_Begin(md5Ctx);
+ MD5_Update(md5Ctx, pms->data, pms->len);
+ MD5_Update(md5Ctx, sha_out, outLen);
+ MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH);
+ PORT_Assert(outLen == MD5_LENGTH);
+ made += outLen;
+ }
+ }
+
+ /* store the results */
+ PORT_Memcpy(pwSpec->raw_master_secret, key_block,
+ SSL3_MASTER_SECRET_LENGTH);
+ pwSpec->msItem.data = pwSpec->raw_master_secret;
+ pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH;
+ PRINT_BUF(100, (NULL, "Master Secret", pwSpec->msItem.data,
+ pwSpec->msItem.len));
+
+ return rv;
+}
+
+static SECStatus
+ssl_canExtractMS(PK11SymKey *pms, PRBool isTLS, PRBool isDH, PRBool *pcbp)
+{ SECStatus rv;
+ PK11SymKey * ms = NULL;
+ SECItem params = {siBuffer, NULL, 0};
+ CK_SSL3_MASTER_KEY_DERIVE_PARAMS master_params;
+ unsigned char rand[SSL3_RANDOM_LENGTH];
+ CK_VERSION pms_version;
+ CK_MECHANISM_TYPE master_derive;
+ CK_MECHANISM_TYPE key_derive;
+ CK_FLAGS keyFlags;
+
+ if (pms == NULL)
+ return(SECFailure);
+
+ PORT_Memset(rand, 0, SSL3_RANDOM_LENGTH);
+
+ if (isTLS) {
+ if(isDH) master_derive = CKM_TLS_MASTER_KEY_DERIVE_DH;
+ else master_derive = CKM_TLS_MASTER_KEY_DERIVE;
+ key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
+ keyFlags = CKF_SIGN | CKF_VERIFY;
+ } else {
+ if (isDH) master_derive = CKM_SSL3_MASTER_KEY_DERIVE_DH;
+ else master_derive = CKM_SSL3_MASTER_KEY_DERIVE;
+ key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE;
+ keyFlags = 0;
+ }
+
+ master_params.pVersion = &pms_version;
+ master_params.RandomInfo.pClientRandom = rand;
+ master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
+ master_params.RandomInfo.pServerRandom = rand;
+ master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
+
+ params.data = (unsigned char *) &master_params;
+ params.len = sizeof master_params;
+
+ ms = PK11_DeriveWithFlags(pms, master_derive, &params, key_derive,
+ CKA_DERIVE, 0, keyFlags);
+ if (ms == NULL)
+ return(SECFailure);
+
+ rv = PK11_ExtractKeyValue(ms);
+ *pcbp = (rv == SECSuccess);
+ PK11_FreeSymKey(ms);
+
+ return(rv);
+
+}
+#endif /* !NO_PKCS11_BYPASS */
+
+/* Check the key exchange algorithm for each cipher in the list to see if
+ * a master secret key can be extracted. If the KEA will use keys from the
+ * specified cert make sure the extract operation is attempted from the slot
+ * where the private key resides.
+ * If MS can be extracted for all ciphers, (*pcanbypass) is set to TRUE and
+ * SECSuccess is returned. In all other cases but one (*pcanbypass) is
+ * set to FALSE and SECFailure is returned.
+ * In that last case Derive() has been called successfully but the MS is null,
+ * CanBypass sets (*pcanbypass) to FALSE and returns SECSuccess indicating the
+ * arguments were all valid but the slot cannot be bypassed.
+ */
+
+/* XXX Add SSL_CBP_TLS1_1 and test it in protocolmask when setting isTLS. */
+
+SECStatus
+SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey,
+ PRUint32 protocolmask, PRUint16 *ciphersuites, int nsuites,
+ PRBool *pcanbypass, void *pwArg)
+{
+#ifdef NO_PKCS11_BYPASS
+ if (!pcanbypass) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ *pcanbypass = PR_FALSE;
+ return SECSuccess;
+#else
+ SECStatus rv;
+ int i;
+ PRUint16 suite;
+ PK11SymKey * pms = NULL;
+ SECKEYPublicKey * srvPubkey = NULL;
+ KeyType privKeytype;
+ PK11SlotInfo * slot = NULL;
+ SECItem param;
+ CK_VERSION version;
+ CK_MECHANISM_TYPE mechanism_array[2];
+ SECItem enc_pms = {siBuffer, NULL, 0};
+ PRBool isTLS = PR_FALSE;
+ SSLCipherSuiteInfo csdef;
+ PRBool testrsa = PR_FALSE;
+ PRBool testrsa_export = PR_FALSE;
+ PRBool testecdh = PR_FALSE;
+ PRBool testecdhe = PR_FALSE;
+#ifdef NSS_ENABLE_ECC
+ SECKEYECParams ecParams = { siBuffer, NULL, 0 };
+#endif
+
+ if (!cert || !srvPrivkey || !ciphersuites || !pcanbypass) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ srvPubkey = CERT_ExtractPublicKey(cert);
+ if (!srvPubkey)
+ return SECFailure;
+
+ *pcanbypass = PR_TRUE;
+ rv = SECFailure;
+
+ /* determine which KEAs to test */
+ /* 0 (SSL_NULL_WITH_NULL_NULL) is used as a list terminator because
+ * SSL3 and TLS specs forbid negotiating that cipher suite number.
+ */
+ for (i=0; i < nsuites && (suite = *ciphersuites++) != 0; i++) {
+ /* skip SSL2 cipher suites and ones NSS doesn't support */
+ if (SSL_GetCipherSuiteInfo(suite, &csdef, sizeof(csdef)) != SECSuccess
+ || SSL_IS_SSL2_CIPHER(suite) )
+ continue;
+ switch (csdef.keaType) {
+ case ssl_kea_rsa:
+ switch (csdef.cipherSuite) {
+ case TLS_RSA_EXPORT1024_WITH_RC4_56_SHA:
+ case TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA:
+ case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
+ case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
+ testrsa_export = PR_TRUE;
+ }
+ if (!testrsa_export)
+ testrsa = PR_TRUE;
+ break;
+ case ssl_kea_ecdh:
+ if (strcmp(csdef.keaTypeName, "ECDHE") == 0) /* ephemeral? */
+ testecdhe = PR_TRUE;
+ else
+ testecdh = PR_TRUE;
+ break;
+ case ssl_kea_dh:
+ /* this is actually DHE */
+ default:
+ continue;
+ }
+ }
+
+ /* For each protocol try to derive and extract an MS.
+ * Failure of function any function except MS extract means
+ * continue with the next cipher test. Stop testing when the list is
+ * exhausted or when the first MS extract--not derive--fails.
+ */
+ privKeytype = SECKEY_GetPrivateKeyType(srvPrivkey);
+ protocolmask &= SSL_CBP_SSL3|SSL_CBP_TLS1_0;
+ while (protocolmask) {
+ if (protocolmask & SSL_CBP_SSL3) {
+ isTLS = PR_FALSE;
+ protocolmask ^= SSL_CBP_SSL3;
+ } else {
+ isTLS = PR_TRUE;
+ protocolmask ^= SSL_CBP_TLS1_0;
+ }
+
+ if (privKeytype == rsaKey && testrsa_export) {
+ if (PK11_GetPrivateModulusLen(srvPrivkey) > EXPORT_RSA_KEY_LENGTH) {
+ *pcanbypass = PR_FALSE;
+ rv = SECSuccess;
+ break;
+ } else
+ testrsa = PR_TRUE;
+ }
+ for (; privKeytype == rsaKey && testrsa; ) {
+ /* TLS_RSA */
+ unsigned char rsaPmsBuf[SSL3_RSA_PMS_LENGTH];
+ unsigned int outLen = 0;
+ CK_MECHANISM_TYPE target;
+ SECStatus irv;
+
+ mechanism_array[0] = CKM_SSL3_PRE_MASTER_KEY_GEN;
+ mechanism_array[1] = CKM_RSA_PKCS;
+
+ slot = PK11_GetBestSlotMultiple(mechanism_array, 2, pwArg);
+ if (slot == NULL) {
+ PORT_SetError(SSL_ERROR_TOKEN_SLOT_NOT_FOUND);
+ break;
+ }
+
+ /* Generate the pre-master secret ... (client side) */
+ version.major = 3 /*MSB(clientHelloVersion)*/;
+ version.minor = 0 /*LSB(clientHelloVersion)*/;
+ param.data = (unsigned char *)&version;
+ param.len = sizeof version;
+ pms = PK11_KeyGen(slot, CKM_SSL3_PRE_MASTER_KEY_GEN, &param, 0, pwArg);
+ PK11_FreeSlot(slot);
+ if (!pms)
+ break;
+ /* now wrap it */
+ enc_pms.len = SECKEY_PublicKeyStrength(srvPubkey);
+ enc_pms.data = (unsigned char*)PORT_Alloc(enc_pms.len);
+ if (enc_pms.data == NULL) {
+ PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
+ break;
+ }
+ irv = PK11_PubWrapSymKey(CKM_RSA_PKCS, srvPubkey, pms, &enc_pms);
+ if (irv != SECSuccess)
+ break;
+ PK11_FreeSymKey(pms);
+ pms = NULL;
+ /* now do the server side--check the triple bypass first */
+ rv = PK11_PrivDecryptPKCS1(srvPrivkey, rsaPmsBuf, &outLen,
+ sizeof rsaPmsBuf,
+ (unsigned char *)enc_pms.data,
+ enc_pms.len);
+ /* if decrypt worked we're done with the RSA test */
+ if (rv == SECSuccess) {
+ *pcanbypass = PR_TRUE;
+ break;
+ }
+ /* check for fallback to double bypass */
+ target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE
+ : CKM_SSL3_MASTER_KEY_DERIVE;
+ pms = PK11_PubUnwrapSymKey(srvPrivkey, &enc_pms,
+ target, CKA_DERIVE, 0);
+ rv = ssl_canExtractMS(pms, isTLS, PR_FALSE, pcanbypass);
+ if (rv == SECSuccess && *pcanbypass == PR_FALSE)
+ goto done;
+ break;
+ }
+
+ /* Check for NULL to avoid double free.
+ * SECItem_FreeItem sets data NULL in secitem.c#265
+ */
+ if (enc_pms.data != NULL) {
+ SECITEM_FreeItem(&enc_pms, PR_FALSE);
+ }
+#ifdef NSS_ENABLE_ECC
+ for (; (privKeytype == ecKey && ( testecdh || testecdhe)) ||
+ (privKeytype == rsaKey && testecdhe); ) {
+ CK_MECHANISM_TYPE target;
+ SECKEYPublicKey *keapub = NULL;
+ SECKEYPrivateKey *keapriv;
+ SECKEYPublicKey *cpub = NULL; /* client's ephemeral ECDH keys */
+ SECKEYPrivateKey *cpriv = NULL;
+ SECKEYECParams *pecParams = NULL;
+
+ if (privKeytype == ecKey && testecdhe) {
+ /* TLS_ECDHE_ECDSA */
+ pecParams = &srvPubkey->u.ec.DEREncodedParams;
+ } else if (privKeytype == rsaKey && testecdhe) {
+ /* TLS_ECDHE_RSA */
+ ECName ec_curve;
+ int serverKeyStrengthInBits;
+ int signatureKeyStrength;
+ int requiredECCbits;
+
+ /* find a curve of equivalent strength to the RSA key's */
+ requiredECCbits = PK11_GetPrivateModulusLen(srvPrivkey);
+ if (requiredECCbits < 0)
+ break;
+ requiredECCbits *= BPB;
+ serverKeyStrengthInBits = srvPubkey->u.rsa.modulus.len;
+ if (srvPubkey->u.rsa.modulus.data[0] == 0) {
+ serverKeyStrengthInBits--;
+ }
+ /* convert to strength in bits */
+ serverKeyStrengthInBits *= BPB;
+
+ signatureKeyStrength =
+ SSL_RSASTRENGTH_TO_ECSTRENGTH(serverKeyStrengthInBits);
+
+ if ( requiredECCbits > signatureKeyStrength )
+ requiredECCbits = signatureKeyStrength;
+
+ ec_curve =
+ ssl3_GetCurveWithECKeyStrength(
+ ssl3_GetSupportedECCurveMask(NULL),
+ requiredECCbits);
+ rv = ssl3_ECName2Params(NULL, ec_curve, &ecParams);
+ if (rv == SECFailure) {
+ break;
+ }
+ pecParams = &ecParams;
+ }
+
+ if (testecdhe) {
+ /* generate server's ephemeral keys */
+ keapriv = SECKEY_CreateECPrivateKey(pecParams, &keapub, NULL);
+ if (!keapriv || !keapub) {
+ if (keapriv)
+ SECKEY_DestroyPrivateKey(keapriv);
+ if (keapub)
+ SECKEY_DestroyPublicKey(keapub);
+ PORT_SetError(SEC_ERROR_KEYGEN_FAIL);
+ rv = SECFailure;
+ break;
+ }
+ } else {
+ /* TLS_ECDH_ECDSA */
+ keapub = srvPubkey;
+ keapriv = srvPrivkey;
+ pecParams = &srvPubkey->u.ec.DEREncodedParams;
+ }
+
+ /* perform client side ops */
+ /* generate a pair of ephemeral keys using server's parms */
+ cpriv = SECKEY_CreateECPrivateKey(pecParams, &cpub, NULL);
+ if (!cpriv || !cpub) {
+ if (testecdhe) {
+ SECKEY_DestroyPrivateKey(keapriv);
+ SECKEY_DestroyPublicKey(keapub);
+ }
+ PORT_SetError(SEC_ERROR_KEYGEN_FAIL);
+ rv = SECFailure;
+ break;
+ }
+ /* now do the server side */
+ /* determine the PMS using client's public value */
+ target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE_DH
+ : CKM_SSL3_MASTER_KEY_DERIVE_DH;
+ pms = PK11_PubDeriveWithKDF(keapriv, cpub, PR_FALSE, NULL, NULL,
+ CKM_ECDH1_DERIVE,
+ target,
+ CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
+ rv = ssl_canExtractMS(pms, isTLS, PR_TRUE, pcanbypass);
+ SECKEY_DestroyPrivateKey(cpriv);
+ SECKEY_DestroyPublicKey(cpub);
+ if (testecdhe) {
+ SECKEY_DestroyPrivateKey(keapriv);
+ SECKEY_DestroyPublicKey(keapub);
+ }
+ if (rv == SECSuccess && *pcanbypass == PR_FALSE)
+ goto done;
+ break;
+ }
+ /* Check for NULL to avoid double free. */
+ if (ecParams.data != NULL) {
+ PORT_Free(ecParams.data);
+ ecParams.data = NULL;
+ }
+#endif /* NSS_ENABLE_ECC */
+ if (pms)
+ PK11_FreeSymKey(pms);
+ }
+
+ /* *pcanbypass has been set */
+ rv = SECSuccess;
+
+ done:
+ if (pms)
+ PK11_FreeSymKey(pms);
+
+ /* Check for NULL to avoid double free.
+ * SECItem_FreeItem sets data NULL in secitem.c#265
+ */
+ if (enc_pms.data != NULL) {
+ SECITEM_FreeItem(&enc_pms, PR_FALSE);
+ }
+#ifdef NSS_ENABLE_ECC
+ if (ecParams.data != NULL) {
+ PORT_Free(ecParams.data);
+ ecParams.data = NULL;
+ }
+#endif /* NSS_ENABLE_ECC */
+
+ if (srvPubkey) {
+ SECKEY_DestroyPublicKey(srvPubkey);
+ srvPubkey = NULL;
+ }
+
+
+ return rv;
+#endif /* NO_PKCS11_BYPASS */
+}
+
diff --git a/chromium/net/third_party/nss/ssl/dtlscon.c b/chromium/net/third_party/nss/ssl/dtlscon.c
new file mode 100644
index 00000000000..e86ae01ddbe
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/dtlscon.c
@@ -0,0 +1,1139 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * DTLS Protocol
+ */
+
+#include "ssl.h"
+#include "sslimpl.h"
+#include "sslproto.h"
+
+#ifndef PR_ARRAY_SIZE
+#define PR_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+#endif
+
+static SECStatus dtls_TransmitMessageFlight(sslSocket *ss);
+static void dtls_RetransmitTimerExpiredCb(sslSocket *ss);
+static SECStatus dtls_SendSavedWriteData(sslSocket *ss);
+
+/* -28 adjusts for the IP/UDP header */
+static const PRUint16 COMMON_MTU_VALUES[] = {
+ 1500 - 28, /* Ethernet MTU */
+ 1280 - 28, /* IPv6 minimum MTU */
+ 576 - 28, /* Common assumption */
+ 256 - 28 /* We're in serious trouble now */
+};
+
+#define DTLS_COOKIE_BYTES 32
+
+/* List copied from ssl3con.c:cipherSuites */
+static const ssl3CipherSuite nonDTLSSuites[] = {
+ /* XXX Make AES-GCM work with DTLS. */
+#ifdef NSS_ENABLE_ECC
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+#endif /* NSS_ENABLE_ECC */
+ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+#ifdef NSS_ENABLE_ECC
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+#endif /* NSS_ENABLE_ECC */
+ TLS_DHE_DSS_WITH_RC4_128_SHA,
+#ifdef NSS_ENABLE_ECC
+ TLS_ECDH_RSA_WITH_RC4_128_SHA,
+ TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+#endif /* NSS_ENABLE_ECC */
+ SSL_RSA_WITH_RC4_128_MD5,
+ SSL_RSA_WITH_RC4_128_SHA,
+ TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,
+ SSL_RSA_EXPORT_WITH_RC4_40_MD5,
+ 0 /* End of list marker */
+};
+
+/* Map back and forth between TLS and DTLS versions in wire format.
+ * Mapping table is:
+ *
+ * TLS DTLS
+ * 1.1 (0302) 1.0 (feff)
+ */
+SSL3ProtocolVersion
+dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv)
+{
+ /* Anything other than TLS 1.1 is an error, so return
+ * the invalid version ffff. */
+ if (tlsv != SSL_LIBRARY_VERSION_TLS_1_1)
+ return 0xffff;
+
+ return SSL_LIBRARY_VERSION_DTLS_1_0_WIRE;
+}
+
+/* Map known DTLS versions to known TLS versions.
+ * - Invalid versions (< 1.0) return a version of 0
+ * - Versions > known return a version one higher than we know of
+ * to accomodate a theoretically newer version */
+SSL3ProtocolVersion
+dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv)
+{
+ if (MSB(dtlsv) == 0xff) {
+ return 0;
+ }
+
+ if (dtlsv == SSL_LIBRARY_VERSION_DTLS_1_0_WIRE)
+ return SSL_LIBRARY_VERSION_TLS_1_1;
+
+ /* Return a fictional higher version than we know of */
+ return SSL_LIBRARY_VERSION_TLS_1_1 + 1;
+}
+
+/* On this socket, Disable non-DTLS cipher suites in the argument's list */
+SECStatus
+ssl3_DisableNonDTLSSuites(sslSocket * ss)
+{
+ const ssl3CipherSuite * suite;
+
+ for (suite = nonDTLSSuites; *suite; ++suite) {
+ SECStatus rv = ssl3_CipherPrefSet(ss, *suite, PR_FALSE);
+
+ PORT_Assert(rv == SECSuccess); /* else is coding error */
+ }
+ return SECSuccess;
+}
+
+/* Allocate a DTLSQueuedMessage.
+ *
+ * Called from dtls_QueueMessage()
+ */
+static DTLSQueuedMessage *
+dtls_AllocQueuedMessage(PRUint16 epoch, SSL3ContentType type,
+ const unsigned char *data, PRUint32 len)
+{
+ DTLSQueuedMessage *msg = NULL;
+
+ msg = PORT_ZAlloc(sizeof(DTLSQueuedMessage));
+ if (!msg)
+ return NULL;
+
+ msg->data = PORT_Alloc(len);
+ if (!msg->data) {
+ PORT_Free(msg);
+ return NULL;
+ }
+ PORT_Memcpy(msg->data, data, len);
+
+ msg->len = len;
+ msg->epoch = epoch;
+ msg->type = type;
+
+ return msg;
+}
+
+/*
+ * Free a handshake message
+ *
+ * Called from dtls_FreeHandshakeMessages()
+ */
+static void
+dtls_FreeHandshakeMessage(DTLSQueuedMessage *msg)
+{
+ if (!msg)
+ return;
+
+ PORT_ZFree(msg->data, msg->len);
+ PORT_Free(msg);
+}
+
+/*
+ * Free a list of handshake messages
+ *
+ * Called from:
+ * dtls_HandleHandshake()
+ * ssl3_DestroySSL3Info()
+ */
+void
+dtls_FreeHandshakeMessages(PRCList *list)
+{
+ PRCList *cur_p;
+
+ while (!PR_CLIST_IS_EMPTY(list)) {
+ cur_p = PR_LIST_TAIL(list);
+ PR_REMOVE_LINK(cur_p);
+ dtls_FreeHandshakeMessage((DTLSQueuedMessage *)cur_p);
+ }
+}
+
+/* Called only from ssl3_HandleRecord, for each (deciphered) DTLS record.
+ * origBuf is the decrypted ssl record content and is expected to contain
+ * complete handshake records
+ * Caller must hold the handshake and RecvBuf locks.
+ *
+ * Note that this code uses msg_len for two purposes:
+ *
+ * (1) To pass the length to ssl3_HandleHandshakeMessage()
+ * (2) To carry the length of a message currently being reassembled
+ *
+ * However, unlike ssl3_HandleHandshake(), it is not used to carry
+ * the state of reassembly (i.e., whether one is in progress). That
+ * is carried in recvdHighWater and recvdFragments.
+ */
+#define OFFSET_BYTE(o) (o/8)
+#define OFFSET_MASK(o) (1 << (o%8))
+
+SECStatus
+dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
+{
+ /* XXX OK for now.
+ * This doesn't work properly with asynchronous certificate validation.
+ * because that returns a WOULDBLOCK error. The current DTLS
+ * applications do not need asynchronous validation, but in the
+ * future we will need to add this.
+ */
+ sslBuffer buf = *origBuf;
+ SECStatus rv = SECSuccess;
+
+ PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ while (buf.len > 0) {
+ PRUint8 type;
+ PRUint32 message_length;
+ PRUint16 message_seq;
+ PRUint32 fragment_offset;
+ PRUint32 fragment_length;
+ PRUint32 offset;
+
+ if (buf.len < 12) {
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
+ rv = SECFailure;
+ break;
+ }
+
+ /* Parse the header */
+ type = buf.buf[0];
+ message_length = (buf.buf[1] << 16) | (buf.buf[2] << 8) | buf.buf[3];
+ message_seq = (buf.buf[4] << 8) | buf.buf[5];
+ fragment_offset = (buf.buf[6] << 16) | (buf.buf[7] << 8) | buf.buf[8];
+ fragment_length = (buf.buf[9] << 16) | (buf.buf[10] << 8) | buf.buf[11];
+
+#define MAX_HANDSHAKE_MSG_LEN 0x1ffff /* 128k - 1 */
+ if (message_length > MAX_HANDSHAKE_MSG_LEN) {
+ (void)ssl3_DecodeError(ss);
+ PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
+ return SECFailure;
+ }
+#undef MAX_HANDSHAKE_MSG_LEN
+
+ buf.buf += 12;
+ buf.len -= 12;
+
+ /* This fragment must be complete */
+ if (buf.len < fragment_length) {
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
+ rv = SECFailure;
+ break;
+ }
+
+ /* Sanity check the packet contents */
+ if ((fragment_length + fragment_offset) > message_length) {
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
+ rv = SECFailure;
+ break;
+ }
+
+ /* There are three ways we could not be ready for this packet.
+ *
+ * 1. It's a partial next message.
+ * 2. It's a partial or complete message beyond the next
+ * 3. It's a message we've already seen
+ *
+ * If it's the complete next message we accept it right away.
+ * This is the common case for short messages
+ */
+ if ((message_seq == ss->ssl3.hs.recvMessageSeq)
+ && (fragment_offset == 0)
+ && (fragment_length == message_length)) {
+ /* Complete next message. Process immediately */
+ ss->ssl3.hs.msg_type = (SSL3HandshakeType)type;
+ ss->ssl3.hs.msg_len = message_length;
+
+ /* At this point we are advancing our state machine, so
+ * we can free our last flight of messages */
+ dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight);
+ ss->ssl3.hs.recvdHighWater = -1;
+ dtls_CancelTimer(ss);
+
+ /* Reset the timer to the initial value if the retry counter
+ * is 0, per Sec. 4.2.4.1 */
+ if (ss->ssl3.hs.rtRetries == 0) {
+ ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS;
+ }
+
+ rv = ssl3_HandleHandshakeMessage(ss, buf.buf, ss->ssl3.hs.msg_len);
+ if (rv == SECFailure) {
+ /* Do not attempt to process rest of messages in this record */
+ break;
+ }
+ } else {
+ if (message_seq < ss->ssl3.hs.recvMessageSeq) {
+ /* Case 3: we do an immediate retransmit if we're
+ * in a waiting state*/
+ if (ss->ssl3.hs.rtTimerCb == NULL) {
+ /* Ignore */
+ } else if (ss->ssl3.hs.rtTimerCb ==
+ dtls_RetransmitTimerExpiredCb) {
+ SSL_TRC(30, ("%d: SSL3[%d]: Retransmit detected",
+ SSL_GETPID(), ss->fd));
+ /* Check to see if we retransmitted recently. If so,
+ * suppress the triggered retransmit. This avoids
+ * retransmit wars after packet loss.
+ * This is not in RFC 5346 but should be
+ */
+ if ((PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted) >
+ (ss->ssl3.hs.rtTimeoutMs / 4)) {
+ SSL_TRC(30,
+ ("%d: SSL3[%d]: Shortcutting retransmit timer",
+ SSL_GETPID(), ss->fd));
+
+ /* Cancel the timer and call the CB,
+ * which re-arms the timer */
+ dtls_CancelTimer(ss);
+ dtls_RetransmitTimerExpiredCb(ss);
+ rv = SECSuccess;
+ break;
+ } else {
+ SSL_TRC(30,
+ ("%d: SSL3[%d]: We just retransmitted. Ignoring.",
+ SSL_GETPID(), ss->fd));
+ rv = SECSuccess;
+ break;
+ }
+ } else if (ss->ssl3.hs.rtTimerCb == dtls_FinishedTimerCb) {
+ /* Retransmit the messages and re-arm the timer
+ * Note that we are not backing off the timer here.
+ * The spec isn't clear and my reasoning is that this
+ * may be a re-ordered packet rather than slowness,
+ * so let's be aggressive. */
+ dtls_CancelTimer(ss);
+ rv = dtls_TransmitMessageFlight(ss);
+ if (rv == SECSuccess) {
+ rv = dtls_StartTimer(ss, dtls_FinishedTimerCb);
+ }
+ if (rv != SECSuccess)
+ return rv;
+ break;
+ }
+ } else if (message_seq > ss->ssl3.hs.recvMessageSeq) {
+ /* Case 2
+ *
+ * Ignore this message. This means we don't handle out of
+ * order complete messages that well, but we're still
+ * compliant and this probably does not happen often
+ *
+ * XXX OK for now. Maybe do something smarter at some point?
+ */
+ } else {
+ /* Case 1
+ *
+ * Buffer the fragment for reassembly
+ */
+ /* Make room for the message */
+ if (ss->ssl3.hs.recvdHighWater == -1) {
+ PRUint32 map_length = OFFSET_BYTE(message_length) + 1;
+
+ rv = sslBuffer_Grow(&ss->ssl3.hs.msg_body, message_length);
+ if (rv != SECSuccess)
+ break;
+ /* Make room for the fragment map */
+ rv = sslBuffer_Grow(&ss->ssl3.hs.recvdFragments,
+ map_length);
+ if (rv != SECSuccess)
+ break;
+
+ /* Reset the reassembly map */
+ ss->ssl3.hs.recvdHighWater = 0;
+ PORT_Memset(ss->ssl3.hs.recvdFragments.buf, 0,
+ ss->ssl3.hs.recvdFragments.space);
+ ss->ssl3.hs.msg_type = (SSL3HandshakeType)type;
+ ss->ssl3.hs.msg_len = message_length;
+ }
+
+ /* If we have a message length mismatch, abandon the reassembly
+ * in progress and hope that the next retransmit will give us
+ * something sane
+ */
+ if (message_length != ss->ssl3.hs.msg_len) {
+ ss->ssl3.hs.recvdHighWater = -1;
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
+ rv = SECFailure;
+ break;
+ }
+
+ /* Now copy this fragment into the buffer */
+ PORT_Assert((fragment_offset + fragment_length) <=
+ ss->ssl3.hs.msg_body.space);
+ PORT_Memcpy(ss->ssl3.hs.msg_body.buf + fragment_offset,
+ buf.buf, fragment_length);
+
+ /* This logic is a bit tricky. We have two values for
+ * reassembly state:
+ *
+ * - recvdHighWater contains the highest contiguous number of
+ * bytes received
+ * - recvdFragments contains a bitmask of packets received
+ * above recvdHighWater
+ *
+ * This avoids having to fill in the bitmask in the common
+ * case of adjacent fragments received in sequence
+ */
+ if (fragment_offset <= ss->ssl3.hs.recvdHighWater) {
+ /* Either this is the adjacent fragment or an overlapping
+ * fragment */
+ ss->ssl3.hs.recvdHighWater = fragment_offset +
+ fragment_length;
+ } else {
+ for (offset = fragment_offset;
+ offset < fragment_offset + fragment_length;
+ offset++) {
+ ss->ssl3.hs.recvdFragments.buf[OFFSET_BYTE(offset)] |=
+ OFFSET_MASK(offset);
+ }
+ }
+
+ /* Now figure out the new high water mark if appropriate */
+ for (offset = ss->ssl3.hs.recvdHighWater;
+ offset < ss->ssl3.hs.msg_len; offset++) {
+ /* Note that this loop is not efficient, since it counts
+ * bit by bit. If we have a lot of out-of-order packets,
+ * we should optimize this */
+ if (ss->ssl3.hs.recvdFragments.buf[OFFSET_BYTE(offset)] &
+ OFFSET_MASK(offset)) {
+ ss->ssl3.hs.recvdHighWater++;
+ } else {
+ break;
+ }
+ }
+
+ /* If we have all the bytes, then we are good to go */
+ if (ss->ssl3.hs.recvdHighWater == ss->ssl3.hs.msg_len) {
+ ss->ssl3.hs.recvdHighWater = -1;
+
+ rv = ssl3_HandleHandshakeMessage(ss,
+ ss->ssl3.hs.msg_body.buf,
+ ss->ssl3.hs.msg_len);
+ if (rv == SECFailure)
+ break; /* Skip rest of record */
+
+ /* At this point we are advancing our state machine, so
+ * we can free our last flight of messages */
+ dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight);
+ dtls_CancelTimer(ss);
+
+ /* If there have been no retries this time, reset the
+ * timer value to the default per Section 4.2.4.1 */
+ if (ss->ssl3.hs.rtRetries == 0) {
+ ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS;
+ }
+ }
+ }
+ }
+
+ buf.buf += fragment_length;
+ buf.len -= fragment_length;
+ }
+
+ origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */
+
+ /* XXX OK for now. In future handle rv == SECWouldBlock safely in order
+ * to deal with asynchronous certificate verification */
+ return rv;
+}
+
+/* Enqueue a message (either handshake or CCS)
+ *
+ * Called from:
+ * dtls_StageHandshakeMessage()
+ * ssl3_SendChangeCipherSpecs()
+ */
+SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type,
+ const SSL3Opaque *pIn, PRInt32 nIn)
+{
+ SECStatus rv = SECSuccess;
+ DTLSQueuedMessage *msg = NULL;
+
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+
+ msg = dtls_AllocQueuedMessage(ss->ssl3.cwSpec->epoch, type, pIn, nIn);
+
+ if (!msg) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ rv = SECFailure;
+ } else {
+ PR_APPEND_LINK(&msg->link, &ss->ssl3.hs.lastMessageFlight);
+ }
+
+ return rv;
+}
+
+/* Add DTLS handshake message to the pending queue
+ * Empty the sendBuf buffer.
+ * This function returns SECSuccess or SECFailure, never SECWouldBlock.
+ * Always set sendBuf.len to 0, even when returning SECFailure.
+ *
+ * Called from:
+ * ssl3_AppendHandshakeHeader()
+ * dtls_FlushHandshake()
+ */
+SECStatus
+dtls_StageHandshakeMessage(sslSocket *ss)
+{
+ SECStatus rv = SECSuccess;
+
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+
+ /* This function is sometimes called when no data is actually to
+ * be staged, so just return SECSuccess. */
+ if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len)
+ return rv;
+
+ rv = dtls_QueueMessage(ss, content_handshake,
+ ss->sec.ci.sendBuf.buf, ss->sec.ci.sendBuf.len);
+
+ /* Whether we succeeded or failed, toss the old handshake data. */
+ ss->sec.ci.sendBuf.len = 0;
+ return rv;
+}
+
+/* Enqueue the handshake message in sendBuf (if any) and then
+ * transmit the resulting flight of handshake messages.
+ *
+ * Called from:
+ * ssl3_FlushHandshake()
+ */
+SECStatus
+dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags)
+{
+ SECStatus rv = SECSuccess;
+
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+
+ rv = dtls_StageHandshakeMessage(ss);
+ if (rv != SECSuccess)
+ return rv;
+
+ if (!(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) {
+ rv = dtls_TransmitMessageFlight(ss);
+ if (rv != SECSuccess)
+ return rv;
+
+ if (!(flags & ssl_SEND_FLAG_NO_RETRANSMIT)) {
+ ss->ssl3.hs.rtRetries = 0;
+ rv = dtls_StartTimer(ss, dtls_RetransmitTimerExpiredCb);
+ }
+ }
+
+ return rv;
+}
+
+/* The callback for when the retransmit timer expires
+ *
+ * Called from:
+ * dtls_CheckTimer()
+ * dtls_HandleHandshake()
+ */
+static void
+dtls_RetransmitTimerExpiredCb(sslSocket *ss)
+{
+ SECStatus rv = SECFailure;
+
+ ss->ssl3.hs.rtRetries++;
+
+ if (!(ss->ssl3.hs.rtRetries % 3)) {
+ /* If one of the messages was potentially greater than > MTU,
+ * then downgrade. Do this every time we have retransmitted a
+ * message twice, per RFC 6347 Sec. 4.1.1 */
+ dtls_SetMTU(ss, ss->ssl3.hs.maxMessageSent - 1);
+ }
+
+ rv = dtls_TransmitMessageFlight(ss);
+ if (rv == SECSuccess) {
+
+ /* Re-arm the timer */
+ rv = dtls_RestartTimer(ss, PR_TRUE, dtls_RetransmitTimerExpiredCb);
+ }
+
+ if (rv == SECFailure) {
+ /* XXX OK for now. In future maybe signal the stack that we couldn't
+ * transmit. For now, let the read handle any real network errors */
+ }
+}
+
+/* Transmit a flight of handshake messages, stuffing them
+ * into as few records as seems reasonable
+ *
+ * Called from:
+ * dtls_FlushHandshake()
+ * dtls_RetransmitTimerExpiredCb()
+ */
+static SECStatus
+dtls_TransmitMessageFlight(sslSocket *ss)
+{
+ SECStatus rv = SECSuccess;
+ PRCList *msg_p;
+ PRUint16 room_left = ss->ssl3.mtu;
+ PRInt32 sent;
+
+ ssl_GetXmitBufLock(ss);
+ ssl_GetSpecReadLock(ss);
+
+ /* DTLS does not buffer its handshake messages in
+ * ss->pendingBuf, but rather in the lastMessageFlight
+ * structure. This is just a sanity check that
+ * some programming error hasn't inadvertantly
+ * stuffed something in ss->pendingBuf
+ */
+ PORT_Assert(!ss->pendingBuf.len);
+ for (msg_p = PR_LIST_HEAD(&ss->ssl3.hs.lastMessageFlight);
+ msg_p != &ss->ssl3.hs.lastMessageFlight;
+ msg_p = PR_NEXT_LINK(msg_p)) {
+ DTLSQueuedMessage *msg = (DTLSQueuedMessage *)msg_p;
+
+ /* The logic here is:
+ *
+ * 1. If this is a message that will not fit into the remaining
+ * space, then flush.
+ * 2. If the message will now fit into the remaining space,
+ * encrypt, buffer, and loop.
+ * 3. If the message will not fit, then fragment.
+ *
+ * At the end of the function, flush.
+ */
+ if ((msg->len + SSL3_BUFFER_FUDGE) > room_left) {
+ /* The message will not fit into the remaining space, so flush */
+ rv = dtls_SendSavedWriteData(ss);
+ if (rv != SECSuccess)
+ break;
+
+ room_left = ss->ssl3.mtu;
+ }
+
+ if ((msg->len + SSL3_BUFFER_FUDGE) <= room_left) {
+ /* The message will fit, so encrypt and then continue with the
+ * next packet */
+ sent = ssl3_SendRecord(ss, msg->epoch, msg->type,
+ msg->data, msg->len,
+ ssl_SEND_FLAG_FORCE_INTO_BUFFER |
+ ssl_SEND_FLAG_USE_EPOCH);
+ if (sent != msg->len) {
+ rv = SECFailure;
+ if (sent != -1) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ }
+ break;
+ }
+
+ room_left = ss->ssl3.mtu - ss->pendingBuf.len;
+ } else {
+ /* The message will not fit, so fragment.
+ *
+ * XXX OK for now. Arrange to coalesce the last fragment
+ * of this message with the next message if possible.
+ * That would be more efficient.
+ */
+ PRUint32 fragment_offset = 0;
+ unsigned char fragment[DTLS_MAX_MTU]; /* >= than largest
+ * plausible MTU */
+
+ /* Assert that we have already flushed */
+ PORT_Assert(room_left == ss->ssl3.mtu);
+
+ /* Case 3: We now need to fragment this message
+ * DTLS only supports fragmenting handshaking messages */
+ PORT_Assert(msg->type == content_handshake);
+
+ /* The headers consume 12 bytes so the smalles possible
+ * message (i.e., an empty one) is 12 bytes
+ */
+ PORT_Assert(msg->len >= 12);
+
+ while ((fragment_offset + 12) < msg->len) {
+ PRUint32 fragment_len;
+ const unsigned char *content = msg->data + 12;
+ PRUint32 content_len = msg->len - 12;
+
+ /* The reason we use 8 here is that that's the length of
+ * the new DTLS data that we add to the header */
+ fragment_len = PR_MIN(room_left - (SSL3_BUFFER_FUDGE + 8),
+ content_len - fragment_offset);
+ PORT_Assert(fragment_len < DTLS_MAX_MTU - 12);
+ /* Make totally sure that we are within the buffer.
+ * Note that the only way that fragment len could get
+ * adjusted here is if
+ *
+ * (a) we are in release mode so the PORT_Assert is compiled out
+ * (b) either the MTU table is inconsistent with DTLS_MAX_MTU
+ * or ss->ssl3.mtu has become corrupt.
+ */
+ fragment_len = PR_MIN(fragment_len, DTLS_MAX_MTU - 12);
+
+ /* Construct an appropriate-sized fragment */
+ /* Type, length, sequence */
+ PORT_Memcpy(fragment, msg->data, 6);
+
+ /* Offset */
+ fragment[6] = (fragment_offset >> 16) & 0xff;
+ fragment[7] = (fragment_offset >> 8) & 0xff;
+ fragment[8] = (fragment_offset) & 0xff;
+
+ /* Fragment length */
+ fragment[9] = (fragment_len >> 16) & 0xff;
+ fragment[10] = (fragment_len >> 8) & 0xff;
+ fragment[11] = (fragment_len) & 0xff;
+
+ PORT_Memcpy(fragment + 12, content + fragment_offset,
+ fragment_len);
+
+ /*
+ * Send the record. We do this in two stages
+ * 1. Encrypt
+ */
+ sent = ssl3_SendRecord(ss, msg->epoch, msg->type,
+ fragment, fragment_len + 12,
+ ssl_SEND_FLAG_FORCE_INTO_BUFFER |
+ ssl_SEND_FLAG_USE_EPOCH);
+ if (sent != (fragment_len + 12)) {
+ rv = SECFailure;
+ if (sent != -1) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ }
+ break;
+ }
+
+ /* 2. Flush */
+ rv = dtls_SendSavedWriteData(ss);
+ if (rv != SECSuccess)
+ break;
+
+ fragment_offset += fragment_len;
+ }
+ }
+ }
+
+ /* Finally, we need to flush */
+ if (rv == SECSuccess)
+ rv = dtls_SendSavedWriteData(ss);
+
+ /* Give up the locks */
+ ssl_ReleaseSpecReadLock(ss);
+ ssl_ReleaseXmitBufLock(ss);
+
+ return rv;
+}
+
+/* Flush the data in the pendingBuf and update the max message sent
+ * so we can adjust the MTU estimate if we need to.
+ * Wrapper for ssl_SendSavedWriteData.
+ *
+ * Called from dtls_TransmitMessageFlight()
+ */
+static
+SECStatus dtls_SendSavedWriteData(sslSocket *ss)
+{
+ PRInt32 sent;
+
+ sent = ssl_SendSavedWriteData(ss);
+ if (sent < 0)
+ return SECFailure;
+
+ /* We should always have complete writes b/c datagram sockets
+ * don't really block */
+ if (ss->pendingBuf.len > 0) {
+ ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE);
+ return SECFailure;
+ }
+
+ /* Update the largest message sent so we can adjust the MTU
+ * estimate if necessary */
+ if (sent > ss->ssl3.hs.maxMessageSent)
+ ss->ssl3.hs.maxMessageSent = sent;
+
+ return SECSuccess;
+}
+
+/* Compress, MAC, encrypt a DTLS record. Allows specification of
+ * the epoch using epoch value. If use_epoch is PR_TRUE then
+ * we use the provided epoch. If use_epoch is PR_FALSE then
+ * whatever the current value is in effect is used.
+ *
+ * Called from ssl3_SendRecord()
+ */
+SECStatus
+dtls_CompressMACEncryptRecord(sslSocket * ss,
+ DTLSEpoch epoch,
+ PRBool use_epoch,
+ SSL3ContentType type,
+ const SSL3Opaque * pIn,
+ PRUint32 contentLen,
+ sslBuffer * wrBuf)
+{
+ SECStatus rv = SECFailure;
+ ssl3CipherSpec * cwSpec;
+
+ ssl_GetSpecReadLock(ss); /********************************/
+
+ /* The reason for this switch-hitting code is that we might have
+ * a flight of records spanning an epoch boundary, e.g.,
+ *
+ * ClientKeyExchange (epoch = 0)
+ * ChangeCipherSpec (epoch = 0)
+ * Finished (epoch = 1)
+ *
+ * Thus, each record needs a different cipher spec. The information
+ * about which epoch to use is carried with the record.
+ */
+ if (use_epoch) {
+ if (ss->ssl3.cwSpec->epoch == epoch)
+ cwSpec = ss->ssl3.cwSpec;
+ else if (ss->ssl3.pwSpec->epoch == epoch)
+ cwSpec = ss->ssl3.pwSpec;
+ else
+ cwSpec = NULL;
+ } else {
+ cwSpec = ss->ssl3.cwSpec;
+ }
+
+ if (cwSpec) {
+ rv = ssl3_CompressMACEncryptRecord(cwSpec, ss->sec.isServer, PR_TRUE,
+ PR_FALSE, type, pIn, contentLen,
+ wrBuf);
+ } else {
+ PR_NOT_REACHED("Couldn't find a cipher spec matching epoch");
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ }
+ ssl_ReleaseSpecReadLock(ss); /************************************/
+
+ return rv;
+}
+
+/* Start a timer
+ *
+ * Called from:
+ * dtls_HandleHandshake()
+ * dtls_FlushHAndshake()
+ * dtls_RestartTimer()
+ */
+SECStatus
+dtls_StartTimer(sslSocket *ss, DTLSTimerCb cb)
+{
+ PORT_Assert(ss->ssl3.hs.rtTimerCb == NULL);
+
+ ss->ssl3.hs.rtTimerStarted = PR_IntervalNow();
+ ss->ssl3.hs.rtTimerCb = cb;
+
+ return SECSuccess;
+}
+
+/* Restart a timer with optional backoff
+ *
+ * Called from dtls_RetransmitTimerExpiredCb()
+ */
+SECStatus
+dtls_RestartTimer(sslSocket *ss, PRBool backoff, DTLSTimerCb cb)
+{
+ if (backoff) {
+ ss->ssl3.hs.rtTimeoutMs *= 2;
+ if (ss->ssl3.hs.rtTimeoutMs > MAX_DTLS_TIMEOUT_MS)
+ ss->ssl3.hs.rtTimeoutMs = MAX_DTLS_TIMEOUT_MS;
+ }
+
+ return dtls_StartTimer(ss, cb);
+}
+
+/* Cancel a pending timer
+ *
+ * Called from:
+ * dtls_HandleHandshake()
+ * dtls_CheckTimer()
+ */
+void
+dtls_CancelTimer(sslSocket *ss)
+{
+ PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
+
+ ss->ssl3.hs.rtTimerCb = NULL;
+}
+
+/* Check the pending timer and fire the callback if it expired
+ *
+ * Called from ssl3_GatherCompleteHandshake()
+ */
+void
+dtls_CheckTimer(sslSocket *ss)
+{
+ if (!ss->ssl3.hs.rtTimerCb)
+ return;
+
+ if ((PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted) >
+ PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs)) {
+ /* Timer has expired */
+ DTLSTimerCb cb = ss->ssl3.hs.rtTimerCb;
+
+ /* Cancel the timer so that we can call the CB safely */
+ dtls_CancelTimer(ss);
+
+ /* Now call the CB */
+ cb(ss);
+ }
+}
+
+/* The callback to fire when the holddown timer for the Finished
+ * message expires and we can delete it
+ *
+ * Called from dtls_CheckTimer()
+ */
+void
+dtls_FinishedTimerCb(sslSocket *ss)
+{
+ ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE);
+}
+
+/* Cancel the Finished hold-down timer and destroy the
+ * pending cipher spec. Note that this means that
+ * successive rehandshakes will fail if the Finished is
+ * lost.
+ *
+ * XXX OK for now. Figure out how to handle the combination
+ * of Finished lost and rehandshake
+ */
+void
+dtls_RehandshakeCleanup(sslSocket *ss)
+{
+ dtls_CancelTimer(ss);
+ ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE);
+ ss->ssl3.hs.sendMessageSeq = 0;
+ ss->ssl3.hs.recvMessageSeq = 0;
+}
+
+/* Set the MTU to the next step less than or equal to the
+ * advertised value. Also used to downgrade the MTU by
+ * doing dtls_SetMTU(ss, biggest packet set).
+ *
+ * Passing 0 means set this to the largest MTU known
+ * (effectively resetting the PMTU backoff value).
+ *
+ * Called by:
+ * ssl3_InitState()
+ * dtls_RetransmitTimerExpiredCb()
+ */
+void
+dtls_SetMTU(sslSocket *ss, PRUint16 advertised)
+{
+ int i;
+
+ if (advertised == 0) {
+ ss->ssl3.mtu = COMMON_MTU_VALUES[0];
+ SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu));
+ return;
+ }
+
+ for (i = 0; i < PR_ARRAY_SIZE(COMMON_MTU_VALUES); i++) {
+ if (COMMON_MTU_VALUES[i] <= advertised) {
+ ss->ssl3.mtu = COMMON_MTU_VALUES[i];
+ SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu));
+ return;
+ }
+ }
+
+ /* Fallback */
+ ss->ssl3.mtu = COMMON_MTU_VALUES[PR_ARRAY_SIZE(COMMON_MTU_VALUES)-1];
+ SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu));
+}
+
+/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a
+ * DTLS hello_verify_request
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+SECStatus
+dtls_HandleHelloVerifyRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+ int errCode = SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST;
+ SECStatus rv;
+ PRInt32 temp;
+ SECItem cookie = {siBuffer, NULL, 0};
+ SSL3AlertDescription desc = illegal_parameter;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: handle hello_verify_request handshake",
+ SSL_GETPID(), ss->fd));
+ PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ if (ss->ssl3.hs.ws != wait_server_hello) {
+ errCode = SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST;
+ desc = unexpected_message;
+ goto alert_loser;
+ }
+
+ /* The version */
+ temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
+ if (temp < 0) {
+ goto loser; /* alert has been sent */
+ }
+
+ if (temp != SSL_LIBRARY_VERSION_DTLS_1_0_WIRE) {
+ /* Note: this will need adjustment for DTLS 1.2 per Section 4.2.1 */
+ goto alert_loser;
+ }
+
+ /* The cookie */
+ rv = ssl3_ConsumeHandshakeVariable(ss, &cookie, 1, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* alert has been sent */
+ }
+ if (cookie.len > DTLS_COOKIE_BYTES) {
+ desc = decode_error;
+ goto alert_loser; /* malformed. */
+ }
+
+ PORT_Memcpy(ss->ssl3.hs.cookie, cookie.data, cookie.len);
+ ss->ssl3.hs.cookieLen = cookie.len;
+
+
+ ssl_GetXmitBufLock(ss); /*******************************/
+
+ /* Now re-send the client hello */
+ rv = ssl3_SendClientHello(ss, PR_TRUE);
+
+ ssl_ReleaseXmitBufLock(ss); /*******************************/
+
+ if (rv == SECSuccess)
+ return rv;
+
+alert_loser:
+ (void)SSL3_SendAlert(ss, alert_fatal, desc);
+
+loser:
+ errCode = ssl_MapLowLevelError(errCode);
+ return SECFailure;
+}
+
+/* Initialize the DTLS anti-replay window
+ *
+ * Called from:
+ * ssl3_SetupPendingCipherSpec()
+ * ssl3_InitCipherSpec()
+ */
+void
+dtls_InitRecvdRecords(DTLSRecvdRecords *records)
+{
+ PORT_Memset(records->data, 0, sizeof(records->data));
+ records->left = 0;
+ records->right = DTLS_RECVD_RECORDS_WINDOW - 1;
+}
+
+/*
+ * Has this DTLS record been received? Return values are:
+ * -1 -- out of range to the left
+ * 0 -- not received yet
+ * 1 -- replay
+ *
+ * Called from: dtls_HandleRecord()
+ */
+int
+dtls_RecordGetRecvd(DTLSRecvdRecords *records, PRUint64 seq)
+{
+ PRUint64 offset;
+
+ /* Out of range to the left */
+ if (seq < records->left) {
+ return -1;
+ }
+
+ /* Out of range to the right; since we advance the window on
+ * receipt, that means that this packet has not been received
+ * yet */
+ if (seq > records->right)
+ return 0;
+
+ offset = seq % DTLS_RECVD_RECORDS_WINDOW;
+
+ return !!(records->data[offset / 8] & (1 << (offset % 8)));
+}
+
+/* Update the DTLS anti-replay window
+ *
+ * Called from ssl3_HandleRecord()
+ */
+void
+dtls_RecordSetRecvd(DTLSRecvdRecords *records, PRUint64 seq)
+{
+ PRUint64 offset;
+
+ if (seq < records->left)
+ return;
+
+ if (seq > records->right) {
+ PRUint64 new_left;
+ PRUint64 new_right;
+ PRUint64 right;
+
+ /* Slide to the right; this is the tricky part
+ *
+ * 1. new_top is set to have room for seq, on the
+ * next byte boundary by setting the right 8
+ * bits of seq
+ * 2. new_left is set to compensate.
+ * 3. Zero all bits between top and new_top. Since
+ * this is a ring, this zeroes everything as-yet
+ * unseen. Because we always operate on byte
+ * boundaries, we can zero one byte at a time
+ */
+ new_right = seq | 0x07;
+ new_left = (new_right - DTLS_RECVD_RECORDS_WINDOW) + 1;
+
+ for (right = records->right + 8; right <= new_right; right += 8) {
+ offset = right % DTLS_RECVD_RECORDS_WINDOW;
+ records->data[offset / 8] = 0;
+ }
+
+ records->right = new_right;
+ records->left = new_left;
+ }
+
+ offset = seq % DTLS_RECVD_RECORDS_WINDOW;
+
+ records->data[offset / 8] |= (1 << (offset % 8));
+}
+
+SECStatus
+DTLS_GetHandshakeTimeout(PRFileDesc *socket, PRIntervalTime *timeout)
+{
+ sslSocket * ss = NULL;
+ PRIntervalTime elapsed;
+ PRIntervalTime desired;
+
+ ss = ssl_FindSocket(socket);
+
+ if (!ss)
+ return SECFailure;
+
+ if (!IS_DTLS(ss))
+ return SECFailure;
+
+ if (!ss->ssl3.hs.rtTimerCb)
+ return SECFailure;
+
+ elapsed = PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted;
+ desired = PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs);
+ if (elapsed > desired) {
+ /* Timer expired */
+ *timeout = PR_INTERVAL_NO_WAIT;
+ } else {
+ *timeout = desired - elapsed;
+ }
+
+ return SECSuccess;
+}
diff --git a/chromium/net/third_party/nss/ssl/exports_win.def b/chromium/net/third_party/nss/ssl/exports_win.def
new file mode 100644
index 00000000000..09c70b0b410
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/exports_win.def
@@ -0,0 +1,60 @@
+; Copyright (c) 2013 The Chromium Authors. All rights reserved.
+; Use of this source code is governed by a BSD-style license that can be
+; found in the LICENSE file.
+
+LIBRARY CRSSL
+EXPORTS
+
+NSS_CmpCertChainWCANames
+NSS_FindCertKEAType
+NSS_GetClientAuthData
+NSS_SetDomesticPolicy
+SSL_AuthCertificate
+SSL_AuthCertificateHook
+SSL_CipherPolicyGet
+SSL_CipherPolicySet
+SSL_CipherPrefGet
+SSL_CipherPrefGetDefault
+SSL_CipherPrefSet
+SSL_CipherPrefSetDefault
+SSL_ClearSessionCache
+SSL_ConfigSecureServer
+SSL_ConfigServerSessionIDCache
+SSL_ForceHandshake
+SSL_GetClientAuthDataHook
+SSL_GetSessionID
+SSL_HandshakeCallback
+SSL_ImportFD
+SSL_InvalidateSession
+SSL_OptionGet
+SSL_OptionGetDefault
+SSL_OptionSet
+SSL_OptionSetDefault
+SSL_PeerCertificate
+SSL_PeerStapledOCSPResponses
+SSL_ResetHandshake
+SSL_SetSockPeerID
+SSL_SetURL
+SSL_GetChannelInfo
+SSL_GetCipherSuiteInfo
+SSL_ShutdownServerSessionIDCache
+SSL_GetImplementedCiphers
+SSL_GetNumImplementedCiphers
+SSL_HandshakeNegotiatedExtension
+SSL_SetNextProtoCallback
+SSL_SetNextProtoNego
+SSL_GetNextProto
+DTLS_GetHandshakeTimeout
+DTLS_ImportFD
+SSL_ExportKeyingMaterial
+SSL_VersionRangeSet
+SSL_GetSRTPCipher
+SSL_SetSRTPCiphers
+
+; Chromium patches
+SSL_PeerCertificateChain
+SSL_SetClientChannelIDCallback
+SSL_GetPlatformClientAuthDataHook
+SSL_HandshakeResumedSession
+SSL_RestartHandshakeAfterChannelIDReq
+SSL_GetChannelBinding
diff --git a/chromium/net/third_party/nss/ssl/manifest.mn b/chromium/net/third_party/nss/ssl/manifest.mn
new file mode 100644
index 00000000000..4d46d46b86b
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/manifest.mn
@@ -0,0 +1,53 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+CORE_DEPTH = ../..
+
+# DEFINES = -DTRACE
+
+EXPORTS = \
+ ssl.h \
+ sslt.h \
+ sslerr.h \
+ sslproto.h \
+ preenc.h \
+ $(NULL)
+
+MODULE = nss
+MAPFILE = $(OBJDIR)/ssl.def
+
+CSRCS = \
+ derive.c \
+ dtlscon.c \
+ prelib.c \
+ ssl3con.c \
+ ssl3gthr.c \
+ sslauth.c \
+ sslcon.c \
+ ssldef.c \
+ sslenum.c \
+ sslerr.c \
+ sslerrstrs.c \
+ sslinit.c \
+ ssl3ext.c \
+ sslgathr.c \
+ sslmutex.c \
+ sslnonce.c \
+ sslreveal.c \
+ sslsecur.c \
+ sslsnce.c \
+ sslsock.c \
+ ssltrace.c \
+ sslver.c \
+ authcert.c \
+ cmpcert.c \
+ sslinfo.c \
+ ssl3ecc.c \
+ $(NULL)
+
+LIBRARY_NAME = ssl
+LIBRARY_VERSION = 3
+
+# This part of the code, including all sub-dirs, can be optimized for size
+export ALLOW_OPT_CODE_SIZE = 1
diff --git a/chromium/net/third_party/nss/ssl/notes.txt b/chromium/net/third_party/nss/ssl/notes.txt
new file mode 100644
index 00000000000..a71c08ef2a5
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/notes.txt
@@ -0,0 +1,134 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SSL's Buffers: enumerated and explained.
+
+---------------------------------------------------------------------------
+incoming:
+
+gs = ss->gather
+hs = ss->ssl3->hs
+
+gs->inbuf SSL3 only: incoming (encrypted) ssl records are placed here,
+ and then decrypted (or copied) to gs->buf.
+
+gs->buf SSL2: incoming SSL records are put here, and then decrypted
+ in place.
+ SSL3: ssl3_HandleHandshake puts decrypted ssl records here.
+
+hs.msg_body (SSL3 only) When an incoming handshake message spans more
+ than one ssl record, the first part(s) of it are accumulated
+ here until it all arrives.
+
+hs.msgState (SSL3 only) an alternative set of pointers/lengths for gs->buf.
+ Used only when a handleHandshake function returns SECWouldBlock.
+ ssl3_HandleHandshake remembers how far it previously got by
+ using these pointers instead of gs->buf when it is called
+ after a previous SECWouldBlock return.
+
+---------------------------------------------------------------------------
+outgoing:
+
+sec = ss->sec
+ci = ss->sec->ci /* connect info */
+
+ci->sendBuf Outgoing handshake messages are appended to this buffer.
+ This buffer will then be sent as a single SSL record.
+
+sec->writeBuf outgoing ssl records are constructed here and encrypted in
+ place before being written or copied to pendingBuf.
+
+ss->pendingBuf contains outgoing ciphertext that was saved after a write
+ attempt to the socket failed, e.g. EWouldBlock.
+ Generally empty with blocking sockets (should be no incomplete
+ writes).
+
+ss->saveBuf Used only by socks code. Intended to be used to buffer
+ outgoing data until a socks handshake completes. However,
+ this buffer is always empty. There is no code to put
+ anything into it.
+
+---------------------------------------------------------------------------
+
+SECWouldBlock means that the function cannot make progress because it is
+waiting for some event OTHER THAN socket I/O completion (e.g. waiting for
+user dialog to finish). It is not the same as EWOULDBLOCK.
+
+---------------------------------------------------------------------------
+
+Rank (order) of locks
+
+recvLock ->\ firstHandshake -> recvbuf -> ssl3Handshake -> xmitbuf -> "spec"
+sendLock ->/
+
+crypto and hash Data that must be protected while turning plaintext into
+ciphertext:
+
+SSL2: (in ssl2_Send*)
+ sec->hash*
+ sec->hashcx (ptr and data)
+ sec->enc
+ sec->writecx* (ptr and content)
+ sec->sendSecret*(ptr and content)
+ sec->sendSequence locked by xmitBufLock
+ sec->blockSize
+ sec->writeBuf* (ptr & content) locked by xmitBufLock
+ "in" locked by xmitBufLock
+
+SSl3: (in ssl3_SendPlainText)
+ ss->ssl3 (the pointer)
+ ss->ssl3->current_write* (the pointer and the data in the spec
+ and any data referenced by the spec.
+
+ ss->sec->isServer
+ ss->sec->writebuf* (ptr & content) locked by xmitBufLock
+ "buf" locked by xmitBufLock
+
+crypto and hash data that must be protected while turning ciphertext into
+plaintext:
+
+SSL2: (in ssl2_GatherData)
+ gs->* (locked by recvBufLock )
+ sec->dec
+ sec->readcx
+ sec->hash* (ptr and data)
+ sec->hashcx (ptr and data)
+
+SSL3: (in ssl3_HandleRecord )
+ ssl3->current_read* (the pointer and all data refernced)
+ ss->sec->isServer
+
+
+Data that must be protected while being used by a "writer":
+
+ss->pendingBuf.*
+ss->saveBuf.* (which is dead)
+
+in ssl3_sendPlainText
+
+ss->ssl3->current_write-> (spec)
+ss->sec->writeBuf.*
+ss->sec->isServer
+
+in SendBlock
+
+ss->sec->hash->length
+ss->sec->blockSize
+ss->sec->writeBuf.*
+ss->sec->sendSecret
+ss->sec->sendSequence
+ss->sec->writecx *
+ss->pendingBuf
+
+--------------------------------------------------------------------------
+
+Data variables (not const) protected by the "sslGlobalDataLock".
+Note, this really should be a reader/writer lock.
+
+allowedByPolicy sslcon.c
+maybeAllowedByPolicy sslcon.c
+chosenPreference sslcon.c
+policyWasSet sslcon.c
+
+cipherSuites[] ssl3con.c
diff --git a/chromium/net/third_party/nss/ssl/os2_err.c b/chromium/net/third_party/nss/ssl/os2_err.c
new file mode 100644
index 00000000000..a69ca91d9ce
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/os2_err.c
@@ -0,0 +1,280 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * This file essentially replicates NSPR's source for the functions that
+ * map system-specific error codes to NSPR error codes. We would use
+ * NSPR's functions, instead of duplicating them, but they're private.
+ * As long as SSL's server session cache code must do platform native I/O
+ * to accomplish its job, and NSPR's error mapping functions remain private,
+ * this code will continue to need to be replicated.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prerror.h"
+#include "prlog.h"
+#include <errno.h>
+
+
+/*
+ * Based on win32err.c
+ * OS2TODO Stub everything for now to build. HCT
+ */
+
+/* forward declaration. */
+void nss_MD_os2_map_default_error(PRInt32 err);
+
+void nss_MD_os2_map_opendir_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_closedir_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_readdir_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_delete_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+/* The error code for stat() is in errno. */
+void nss_MD_os2_map_stat_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_fstat_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_rename_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+/* The error code for access() is in errno. */
+void nss_MD_os2_map_access_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_mkdir_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_rmdir_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_read_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_transmitfile_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_write_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_lseek_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_fsync_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+/*
+ * For both CloseHandle() and closesocket().
+ */
+void nss_MD_os2_map_close_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_socket_error(PRInt32 err)
+{
+// PR_ASSERT(err != WSANOTINITIALISED);
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_recv_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_recvfrom_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_send_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+// case WSAEMSGSIZE: prError = PR_INVALID_ARGUMENT_ERROR; break;
+ default: nss_MD_os2_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_os2_map_sendto_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+// case WSAEMSGSIZE: prError = PR_INVALID_ARGUMENT_ERROR; break;
+ default: nss_MD_os2_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_os2_map_accept_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+// case WSAEOPNOTSUPP: prError = PR_NOT_TCP_SOCKET_ERROR; break;
+// case WSAEINVAL: prError = PR_INVALID_STATE_ERROR; break;
+ default: nss_MD_os2_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_os2_map_acceptex_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_connect_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+// case WSAEWOULDBLOCK: prError = PR_IN_PROGRESS_ERROR; break;
+// case WSAEINVAL: prError = PR_ALREADY_INITIATED_ERROR; break;
+// case WSAETIMEDOUT: prError = PR_IO_TIMEOUT_ERROR; break;
+ default: nss_MD_os2_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_os2_map_bind_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+// case WSAEINVAL: prError = PR_SOCKET_ADDRESS_IS_BOUND_ERROR; break;
+ default: nss_MD_os2_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_os2_map_listen_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+// case WSAEOPNOTSUPP: prError = PR_NOT_TCP_SOCKET_ERROR; break;
+// case WSAEINVAL: prError = PR_INVALID_STATE_ERROR; break;
+ default: nss_MD_os2_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_os2_map_shutdown_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_getsockname_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+// case WSAEINVAL: prError = PR_INVALID_STATE_ERROR; break;
+ default: nss_MD_os2_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_os2_map_getpeername_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_getsockopt_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_setsockopt_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_open_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+void nss_MD_os2_map_gethostname_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+/* Win32 select() only works on sockets. So in this
+** context, WSAENOTSOCK is equivalent to EBADF on Unix.
+*/
+void nss_MD_os2_map_select_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+// case WSAENOTSOCK: prError = PR_BAD_DESCRIPTOR_ERROR; break;
+ default: nss_MD_os2_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_os2_map_lockf_error(PRInt32 err)
+{
+ nss_MD_os2_map_default_error(err);
+}
+
+
+
+void nss_MD_os2_map_default_error(PRInt32 err)
+{
+ PRErrorCode prError;
+
+ switch (err) {
+// case ENOENT: prError = PR_FILE_NOT_FOUND_ERROR; break;
+// case ERROR_ACCESS_DENIED: prError = PR_NO_ACCESS_RIGHTS_ERROR; break;
+// case ERROR_ALREADY_EXISTS: prError = PR_FILE_EXISTS_ERROR; break;
+// case ERROR_DISK_CORRUPT: prError = PR_IO_ERROR; break;
+// case ERROR_DISK_FULL: prError = PR_NO_DEVICE_SPACE_ERROR; break;
+// case ERROR_DISK_OPERATION_FAILED: prError = PR_IO_ERROR; break;
+// case ERROR_DRIVE_LOCKED: prError = PR_FILE_IS_LOCKED_ERROR; break;
+// case ERROR_FILENAME_EXCED_RANGE: prError = PR_NAME_TOO_LONG_ERROR; break;
+// case ERROR_FILE_CORRUPT: prError = PR_IO_ERROR; break;
+// case ERROR_FILE_EXISTS: prError = PR_FILE_EXISTS_ERROR; break;
+// case ERROR_FILE_INVALID: prError = PR_BAD_DESCRIPTOR_ERROR; break;
+#if ERROR_FILE_NOT_FOUND != ENOENT
+// case ERROR_FILE_NOT_FOUND: prError = PR_FILE_NOT_FOUND_ERROR; break;
+#endif
+ default: prError = PR_UNKNOWN_ERROR; break;
+ }
+ PR_SetError(prError, err);
+}
+
diff --git a/chromium/net/third_party/nss/ssl/os2_err.h b/chromium/net/third_party/nss/ssl/os2_err.h
new file mode 100644
index 00000000000..3052d54a7af
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/os2_err.h
@@ -0,0 +1,53 @@
+/*
+ * This file essentially replicates NSPR's source for the functions that
+ * map system-specific error codes to NSPR error codes. We would use
+ * NSPR's functions, instead of duplicating them, but they're private.
+ * As long as SSL's server session cache code must do platform native I/O
+ * to accomplish its job, and NSPR's error mapping functions remain private,
+ * This code will continue to need to be replicated.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* NSPR doesn't make these functions public, so we have to duplicate
+** them in NSS.
+*/
+
+//HCT Based on Win32err.h
+extern void nss_MD_os2_map_accept_error(PRInt32 err);
+extern void nss_MD_os2_map_acceptex_error(PRInt32 err);
+extern void nss_MD_os2_map_access_error(PRInt32 err);
+extern void nss_MD_os2_map_bind_error(PRInt32 err);
+extern void nss_MD_os2_map_close_error(PRInt32 err);
+extern void nss_MD_os2_map_closedir_error(PRInt32 err);
+extern void nss_MD_os2_map_connect_error(PRInt32 err);
+extern void nss_MD_os2_map_default_error(PRInt32 err);
+extern void nss_MD_os2_map_delete_error(PRInt32 err);
+extern void nss_MD_os2_map_fstat_error(PRInt32 err);
+extern void nss_MD_os2_map_fsync_error(PRInt32 err);
+extern void nss_MD_os2_map_gethostname_error(PRInt32 err);
+extern void nss_MD_os2_map_getpeername_error(PRInt32 err);
+extern void nss_MD_os2_map_getsockname_error(PRInt32 err);
+extern void nss_MD_os2_map_getsockopt_error(PRInt32 err);
+extern void nss_MD_os2_map_listen_error(PRInt32 err);
+extern void nss_MD_os2_map_lockf_error(PRInt32 err);
+extern void nss_MD_os2_map_lseek_error(PRInt32 err);
+extern void nss_MD_os2_map_mkdir_error(PRInt32 err);
+extern void nss_MD_os2_map_open_error(PRInt32 err);
+extern void nss_MD_os2_map_opendir_error(PRInt32 err);
+extern void nss_MD_os2_map_read_error(PRInt32 err);
+extern void nss_MD_os2_map_readdir_error(PRInt32 err);
+extern void nss_MD_os2_map_recv_error(PRInt32 err);
+extern void nss_MD_os2_map_recvfrom_error(PRInt32 err);
+extern void nss_MD_os2_map_rename_error(PRInt32 err);
+extern void nss_MD_os2_map_rmdir_error(PRInt32 err);
+extern void nss_MD_os2_map_select_error(PRInt32 err);
+extern void nss_MD_os2_map_send_error(PRInt32 err);
+extern void nss_MD_os2_map_sendto_error(PRInt32 err);
+extern void nss_MD_os2_map_setsockopt_error(PRInt32 err);
+extern void nss_MD_os2_map_shutdown_error(PRInt32 err);
+extern void nss_MD_os2_map_socket_error(PRInt32 err);
+extern void nss_MD_os2_map_stat_error(PRInt32 err);
+extern void nss_MD_os2_map_transmitfile_error(PRInt32 err);
+extern void nss_MD_os2_map_write_error(PRInt32 err);
diff --git a/chromium/net/third_party/nss/ssl/preenc.h b/chromium/net/third_party/nss/ssl/preenc.h
new file mode 100644
index 00000000000..af2475ddd2b
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/preenc.h
@@ -0,0 +1,113 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+
+/*
+ * Fortezza support is removed.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Fortezza support is removed.
+ * This file remains so that old programs will continue to compile,
+ * But this functionality is no longer supported or implemented.
+ */
+
+#include "seccomon.h"
+#include "prio.h"
+
+typedef struct PEHeaderStr PEHeader;
+
+#define PE_MIME_TYPE "application/pre-encrypted"
+
+typedef struct PEFortezzaHeaderStr PEFortezzaHeader;
+typedef struct PEFortezzaGeneratedHeaderStr PEFortezzaGeneratedHeader;
+typedef struct PEFixedKeyHeaderStr PEFixedKeyHeader;
+typedef struct PERSAKeyHeaderStr PERSAKeyHeader;
+
+struct PEFortezzaHeaderStr {
+ unsigned char key[12];
+ unsigned char iv[24];
+ unsigned char hash[20];
+ unsigned char serial[8];
+};
+
+struct PEFortezzaGeneratedHeaderStr {
+ unsigned char key[12];
+ unsigned char iv[24];
+ unsigned char hash[20];
+ unsigned char Ra[128];
+ unsigned char Y[128];
+};
+
+struct PEFixedKeyHeaderStr {
+ unsigned char pkcs11Mech[4];
+ unsigned char labelLen[2];
+ unsigned char keyIDLen[2];
+ unsigned char ivLen[2];
+ unsigned char keyLen[2];
+ unsigned char data[1];
+};
+
+struct PERSAKeyHeaderStr {
+ unsigned char pkcs11Mech[4];
+ unsigned char issuerLen[2];
+ unsigned char serialLen[2];
+ unsigned char ivLen[2];
+ unsigned char keyLen[2];
+ unsigned char data[1];
+};
+
+#define PEFIXED_Label(header) (header->data)
+#define PEFIXED_KeyID(header) (&header->data[GetInt2(header->labelLen)])
+#define PEFIXED_IV(header) (&header->data[GetInt2(header->labelLen)\
+ +GetInt2(header->keyIDLen)])
+#define PEFIXED_Key(header) (&header->data[GetInt2(header->labelLen)\
+ +GetInt2(header->keyIDLen)+GetInt2(header->keyLen)])
+#define PERSA_Issuer(header) (header->data)
+#define PERSA_Serial(header) (&header->data[GetInt2(header->issuerLen)])
+#define PERSA_IV(header) (&header->data[GetInt2(header->issuerLen)\
+ +GetInt2(header->serialLen)])
+#define PERSA_Key(header) (&header->data[GetInt2(header->issuerLen)\
+ +GetInt2(header->serialLen)+GetInt2(header->keyLen)])
+struct PEHeaderStr {
+ unsigned char magic [2];
+ unsigned char len [2];
+ unsigned char type [2];
+ unsigned char version[2];
+ union {
+ PEFortezzaHeader fortezza;
+ PEFortezzaGeneratedHeader g_fortezza;
+ PEFixedKeyHeader fixed;
+ PERSAKeyHeader rsa;
+ } u;
+};
+
+#define PE_CRYPT_INTRO_LEN 8
+#define PE_INTRO_LEN 4
+#define PE_BASE_HEADER_LEN 8
+
+#define PRE_BLOCK_SIZE 8
+
+
+#define GetInt2(c) ((c[0] << 8) | c[1])
+#define GetInt4(c) (((unsigned long)c[0] << 24)|((unsigned long)c[1] << 16)\
+ |((unsigned long)c[2] << 8)| ((unsigned long)c[3]))
+#define PutInt2(c,i) ((c[1] = (i) & 0xff), (c[0] = ((i) >> 8) & 0xff))
+#define PutInt4(c,i) ((c[0]=((i) >> 24) & 0xff),(c[1]=((i) >> 16) & 0xff),\
+ (c[2] = ((i) >> 8) & 0xff), (c[3] = (i) & 0xff))
+
+#define PRE_MAGIC 0xc0de
+#define PRE_VERSION 0x1010
+#define PRE_FORTEZZA_FILE 0x00ff
+#define PRE_FORTEZZA_STREAM 0x00f5
+#define PRE_FORTEZZA_GEN_STREAM 0x00f6
+#define PRE_FIXED_FILE 0x000f
+#define PRE_RSA_FILE 0x001f
+#define PRE_FIXED_STREAM 0x0005
+
+PEHeader *SSL_PreencryptedStreamToFile(PRFileDesc *fd, PEHeader *,
+ int *headerSize);
+
+PEHeader *SSL_PreencryptedFileToStream(PRFileDesc *fd, PEHeader *,
+ int *headerSize);
+
diff --git a/chromium/net/third_party/nss/ssl/prelib.c b/chromium/net/third_party/nss/ssl/prelib.c
new file mode 100644
index 00000000000..a15174a31b1
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/prelib.c
@@ -0,0 +1,34 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+
+/*
+ * Functions used by https servers to send (download) pre-encrypted files
+ * over SSL connections that use Fortezza ciphersuites.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cert.h"
+#include "ssl.h"
+#include "keyhi.h"
+#include "secitem.h"
+#include "sslimpl.h"
+#include "pkcs11t.h"
+#include "preenc.h"
+#include "pk11func.h"
+
+PEHeader *SSL_PreencryptedStreamToFile(PRFileDesc *fd, PEHeader *inHeader,
+ int *headerSize)
+{
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return NULL;
+}
+
+PEHeader *SSL_PreencryptedFileToStream(PRFileDesc *fd, PEHeader *header,
+ int *headerSize)
+{
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return NULL;
+}
+
+
diff --git a/chromium/net/third_party/nss/ssl/ssl.h b/chromium/net/third_party/nss/ssl/ssl.h
new file mode 100644
index 00000000000..c083a6b2a60
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/ssl.h
@@ -0,0 +1,1110 @@
+/*
+ * This file contains prototypes for the public SSL functions.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __ssl_h_
+#define __ssl_h_
+
+#include "prtypes.h"
+#include "prerror.h"
+#include "prio.h"
+#include "seccomon.h"
+#include "cert.h"
+#include "keyt.h"
+
+#include "sslt.h" /* public ssl data types */
+
+#if defined(_WIN32) && !defined(IN_LIBSSL) && !defined(NSS_USE_STATIC_LIBS)
+#define SSL_IMPORT extern __declspec(dllimport)
+#else
+#define SSL_IMPORT extern
+#endif
+
+SEC_BEGIN_PROTOS
+
+/* constant table enumerating all implemented SSL 2 and 3 cipher suites. */
+SSL_IMPORT const PRUint16 SSL_ImplementedCiphers[];
+
+/* the same as the above, but is a function */
+SSL_IMPORT const PRUint16 *SSL_GetImplementedCiphers(void);
+
+/* number of entries in the above table. */
+SSL_IMPORT const PRUint16 SSL_NumImplementedCiphers;
+
+/* the same as the above, but is a function */
+SSL_IMPORT PRUint16 SSL_GetNumImplementedCiphers(void);
+
+/* Macro to tell which ciphers in table are SSL2 vs SSL3/TLS. */
+#define SSL_IS_SSL2_CIPHER(which) (((which) & 0xfff0) == 0xff00)
+
+/*
+** Imports fd into SSL, returning a new socket. Copies SSL configuration
+** from model.
+*/
+SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd);
+
+/*
+** Imports fd into DTLS, returning a new socket. Copies DTLS configuration
+** from model.
+*/
+SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
+
+/*
+** Enable/disable an ssl mode
+**
+** SSL_SECURITY:
+** enable/disable use of SSL security protocol before connect
+**
+** SSL_SOCKS:
+** enable/disable use of socks before connect
+** (No longer supported).
+**
+** SSL_REQUEST_CERTIFICATE:
+** require a certificate during secure connect
+*/
+/* options */
+#define SSL_SECURITY 1 /* (on by default) */
+#define SSL_SOCKS 2 /* (off by default) */
+#define SSL_REQUEST_CERTIFICATE 3 /* (off by default) */
+#define SSL_HANDSHAKE_AS_CLIENT 5 /* force accept to hs as client */
+ /* (off by default) */
+#define SSL_HANDSHAKE_AS_SERVER 6 /* force connect to hs as server */
+ /* (off by default) */
+
+/* OBSOLETE: SSL v2 is obsolete and may be removed soon. */
+#define SSL_ENABLE_SSL2 7 /* enable ssl v2 (off by default) */
+
+/* OBSOLETE: See "SSL Version Range API" below for the replacement and a
+** description of the non-obvious semantics of using SSL_ENABLE_SSL3.
+*/
+#define SSL_ENABLE_SSL3 8 /* enable ssl v3 (on by default) */
+
+#define SSL_NO_CACHE 9 /* don't use the session cache */
+ /* (off by default) */
+#define SSL_REQUIRE_CERTIFICATE 10 /* (SSL_REQUIRE_FIRST_HANDSHAKE */
+ /* by default) */
+#define SSL_ENABLE_FDX 11 /* permit simultaneous read/write */
+ /* (off by default) */
+
+/* OBSOLETE: SSL v2 compatible hellos are not accepted by some TLS servers
+** and cannot negotiate extensions. SSL v2 is obsolete. This option may be
+** removed soon.
+*/
+#define SSL_V2_COMPATIBLE_HELLO 12 /* send v3 client hello in v2 fmt */
+ /* (off by default) */
+
+/* OBSOLETE: See "SSL Version Range API" below for the replacement and a
+** description of the non-obvious semantics of using SSL_ENABLE_TLS.
+*/
+#define SSL_ENABLE_TLS 13 /* enable TLS (on by default) */
+
+#define SSL_ROLLBACK_DETECTION 14 /* for compatibility, default: on */
+#define SSL_NO_STEP_DOWN 15 /* Disable export cipher suites */
+ /* if step-down keys are needed. */
+ /* default: off, generate */
+ /* step-down keys if needed. */
+#define SSL_BYPASS_PKCS11 16 /* use PKCS#11 for pub key only */
+#define SSL_NO_LOCKS 17 /* Don't use locks for protection */
+#define SSL_ENABLE_SESSION_TICKETS 18 /* Enable TLS SessionTicket */
+ /* extension (off by default) */
+#define SSL_ENABLE_DEFLATE 19 /* Enable TLS compression with */
+ /* DEFLATE (off by default) */
+#define SSL_ENABLE_RENEGOTIATION 20 /* Values below (default: never) */
+#define SSL_REQUIRE_SAFE_NEGOTIATION 21 /* Peer must send Signaling */
+ /* Cipher Suite Value (SCSV) or */
+ /* Renegotiation Info (RI) */
+ /* extension in ALL handshakes. */
+ /* default: off */
+#define SSL_ENABLE_FALSE_START 22 /* Enable SSL false start (off by */
+ /* default, applies only to */
+ /* clients). False start is a */
+/* mode where an SSL client will start sending application data before */
+/* verifying the server's Finished message. This means that we could end up */
+/* sending data to an imposter. However, the data will be encrypted and */
+/* only the true server can derive the session key. Thus, so long as the */
+/* cipher isn't broken this is safe. Because of this, False Start will only */
+/* occur on RSA or DH ciphersuites where the cipher's key length is >= 80 */
+/* bits. The advantage of False Start is that it saves a round trip for */
+/* client-speaks-first protocols when performing a full handshake. */
+
+/* For SSL 3.0 and TLS 1.0, by default we prevent chosen plaintext attacks
+ * on SSL CBC mode cipher suites (see RFC 4346 Section F.3) by splitting
+ * non-empty application_data records into two records; the first record has
+ * only the first byte of plaintext, and the second has the rest.
+ *
+ * This only prevents the attack in the sending direction; the connection may
+ * still be vulnerable to such attacks if the peer does not implement a similar
+ * countermeasure.
+ *
+ * This protection mechanism is on by default; the default can be overridden by
+ * setting NSS_SSL_CBC_RANDOM_IV=0 in the environment prior to execution,
+ * and/or by the application setting the option SSL_CBC_RANDOM_IV to PR_FALSE.
+ *
+ * The per-record IV in TLS 1.1 and later adds one block of overhead per
+ * record, whereas this hack will add at least two blocks of overhead per
+ * record, so TLS 1.1+ will always be more efficient.
+ *
+ * Other implementations (e.g. some versions of OpenSSL, in some
+ * configurations) prevent the same attack by prepending an empty
+ * application_data record to every application_data record they send; we do
+ * not do that because some implementations cannot handle empty
+ * application_data records. Also, we only split application_data records and
+ * not other types of records, because some implementations will not accept
+ * fragmented records of some other types (e.g. some versions of NSS do not
+ * accept fragmented alerts).
+ */
+#define SSL_CBC_RANDOM_IV 23
+#define SSL_ENABLE_OCSP_STAPLING 24 /* Request OCSP stapling (client) */
+
+#ifdef SSL_DEPRECATED_FUNCTION
+/* Old deprecated function names */
+SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRBool on);
+SSL_IMPORT SECStatus SSL_EnableDefault(int option, PRBool on);
+#endif
+
+/* New function names */
+SSL_IMPORT SECStatus SSL_OptionSet(PRFileDesc *fd, PRInt32 option, PRBool on);
+SSL_IMPORT SECStatus SSL_OptionGet(PRFileDesc *fd, PRInt32 option, PRBool *on);
+SSL_IMPORT SECStatus SSL_OptionSetDefault(PRInt32 option, PRBool on);
+SSL_IMPORT SECStatus SSL_OptionGetDefault(PRInt32 option, PRBool *on);
+SSL_IMPORT SECStatus SSL_CertDBHandleSet(PRFileDesc *fd, CERTCertDBHandle *dbHandle);
+
+/* SSLNextProtoCallback is called during the handshake for the client, when a
+ * Next Protocol Negotiation (NPN) extension has been received from the server.
+ * |protos| and |protosLen| define a buffer which contains the server's
+ * advertisement. This data is guaranteed to be well formed per the NPN spec.
+ * |protoOut| is a buffer provided by the caller, of length 255 (the maximum
+ * allowed by the protocol). On successful return, the protocol to be announced
+ * to the server will be in |protoOut| and its length in |*protoOutLen|.
+ *
+ * The callback must return SECFailure or SECSuccess (not SECWouldBlock).
+ */
+typedef SECStatus (PR_CALLBACK *SSLNextProtoCallback)(
+ void *arg,
+ PRFileDesc *fd,
+ const unsigned char* protos,
+ unsigned int protosLen,
+ unsigned char* protoOut,
+ unsigned int* protoOutLen,
+ unsigned int protoMaxOut);
+
+/* SSL_SetNextProtoCallback sets a callback function to handle Next Protocol
+ * Negotiation. It causes a client to advertise NPN. */
+SSL_IMPORT SECStatus SSL_SetNextProtoCallback(PRFileDesc *fd,
+ SSLNextProtoCallback callback,
+ void *arg);
+
+/* SSL_SetNextProtoNego can be used as an alternative to
+ * SSL_SetNextProtoCallback. It also causes a client to advertise NPN and
+ * installs a default callback function which selects the first supported
+ * protocol in server-preference order. If no matching protocol is found it
+ * selects the first supported protocol.
+ *
+ * Using this function also allows the client to transparently support ALPN.
+ * The same set of protocols will be advertised via ALPN and, if the server
+ * uses ALPN to select a protocol, SSL_GetNextProto will return
+ * SSL_NEXT_PROTO_SELECTED as the state.
+ *
+ * Since NPN uses the first protocol as the fallback protocol, when sending an
+ * ALPN extension, the first protocol is moved to the end of the list. This
+ * indicates that the fallback protocol is the least preferred. The other
+ * protocols should be in preference order.
+ *
+ * The supported protocols are specified in |data| in wire-format (8-bit
+ * length-prefixed). For example: "\010http/1.1\006spdy/2". */
+SSL_IMPORT SECStatus SSL_SetNextProtoNego(PRFileDesc *fd,
+ const unsigned char *data,
+ unsigned int length);
+
+typedef enum SSLNextProtoState {
+ SSL_NEXT_PROTO_NO_SUPPORT = 0, /* No peer support */
+ SSL_NEXT_PROTO_NEGOTIATED = 1, /* Mutual agreement */
+ SSL_NEXT_PROTO_NO_OVERLAP = 2, /* No protocol overlap found */
+ SSL_NEXT_PROTO_SELECTED = 3 /* Server selected proto (ALPN) */
+} SSLNextProtoState;
+
+/* SSL_GetNextProto can be used in the HandshakeCallback or any time after
+ * a handshake to retrieve the result of the Next Protocol negotiation.
+ *
+ * The length of the negotiated protocol, if any, is written into *bufLen.
+ * If the negotiated protocol is longer than bufLenMax, then SECFailure is
+ * returned. Otherwise, the negotiated protocol, if any, is written into buf,
+ * and SECSuccess is returned. */
+SSL_IMPORT SECStatus SSL_GetNextProto(PRFileDesc *fd,
+ SSLNextProtoState *state,
+ unsigned char *buf,
+ unsigned int *bufLen,
+ unsigned int bufLenMax);
+
+/*
+** Control ciphers that SSL uses. If on is non-zero then the named cipher
+** is enabled, otherwise it is disabled.
+** The "cipher" values are defined in sslproto.h (the SSL_EN_* values).
+** EnableCipher records user preferences.
+** SetPolicy sets the policy according to the policy module.
+*/
+#ifdef SSL_DEPRECATED_FUNCTION
+/* Old deprecated function names */
+SSL_IMPORT SECStatus SSL_EnableCipher(long which, PRBool enabled);
+SSL_IMPORT SECStatus SSL_SetPolicy(long which, int policy);
+#endif
+
+/* New function names */
+SSL_IMPORT SECStatus SSL_CipherPrefSet(PRFileDesc *fd, PRInt32 cipher, PRBool enabled);
+SSL_IMPORT SECStatus SSL_CipherPrefGet(PRFileDesc *fd, PRInt32 cipher, PRBool *enabled);
+SSL_IMPORT SECStatus SSL_CipherPrefSetDefault(PRInt32 cipher, PRBool enabled);
+SSL_IMPORT SECStatus SSL_CipherPrefGetDefault(PRInt32 cipher, PRBool *enabled);
+SSL_IMPORT SECStatus SSL_CipherPolicySet(PRInt32 cipher, PRInt32 policy);
+SSL_IMPORT SECStatus SSL_CipherPolicyGet(PRInt32 cipher, PRInt32 *policy);
+
+/* SSLChannelBindingType enumerates the types of supported channel binding
+ * values. See RFC 5929. */
+typedef enum SSLChannelBindingType {
+ SSL_CHANNEL_BINDING_TLS_UNIQUE = 1,
+} SSLChannelBindingType;
+
+/* SSL_GetChannelBinding copies the requested channel binding value, as defined
+ * in RFC 5929, into |out|. The full length of the binding value is written
+ * into |*outLen|.
+ *
+ * At most |outLenMax| bytes of data are copied. If |outLenMax| is
+ * insufficient then the function returns SECFailure and sets the error to
+ * SEC_ERROR_OUTPUT_LEN, but |*outLen| is still set.
+ *
+ * This call will fail if made during a renegotiation. */
+SSL_IMPORT SECStatus SSL_GetChannelBinding(PRFileDesc *fd,
+ SSLChannelBindingType binding_type,
+ unsigned char *out,
+ unsigned int *outLen,
+ unsigned int outLenMax);
+
+/* SSL Version Range API
+**
+** This API should be used to control SSL 3.0 & TLS support instead of the
+** older SSL_Option* API; however, the SSL_Option* API MUST still be used to
+** control SSL 2.0 support. In this version of libssl, SSL 3.0 and TLS 1.0 are
+** enabled by default. Future versions of libssl may change which versions of
+** the protocol are enabled by default.
+**
+** The SSLProtocolVariant enum indicates whether the protocol is of type
+** stream or datagram. This must be provided to the functions that do not
+** take an fd. Functions which take an fd will get the variant from the fd,
+** which is typed.
+**
+** Using the new version range API in conjunction with the older
+** SSL_OptionSet-based API for controlling the enabled protocol versions may
+** cause unexpected results. Going forward, we guarantee only the following:
+**
+** SSL_OptionGet(SSL_ENABLE_TLS) will return PR_TRUE if *ANY* versions of TLS
+** are enabled.
+**
+** SSL_OptionSet(SSL_ENABLE_TLS, PR_FALSE) will disable *ALL* versions of TLS,
+** including TLS 1.0 and later.
+**
+** The above two properties provide compatibility for applications that use
+** SSL_OptionSet to implement the insecure fallback from TLS 1.x to SSL 3.0.
+**
+** SSL_OptionSet(SSL_ENABLE_TLS, PR_TRUE) will enable TLS 1.0, and may also
+** enable some later versions of TLS, if it is necessary to do so in order to
+** keep the set of enabled versions contiguous. For example, if TLS 1.2 is
+** enabled, then after SSL_OptionSet(SSL_ENABLE_TLS, PR_TRUE), TLS 1.0,
+** TLS 1.1, and TLS 1.2 will be enabled, and the call will have no effect on
+** whether SSL 3.0 is enabled. If no later versions of TLS are enabled at the
+** time SSL_OptionSet(SSL_ENABLE_TLS, PR_TRUE) is called, then no later
+** versions of TLS will be enabled by the call.
+**
+** SSL_OptionSet(SSL_ENABLE_SSL3, PR_FALSE) will disable SSL 3.0, and will not
+** change the set of TLS versions that are enabled.
+**
+** SSL_OptionSet(SSL_ENABLE_SSL3, PR_TRUE) will enable SSL 3.0, and may also
+** enable some versions of TLS if TLS 1.1 or later is enabled at the time of
+** the call, the same way SSL_OptionSet(SSL_ENABLE_TLS, PR_TRUE) works, in
+** order to keep the set of enabled versions contiguous.
+*/
+
+/* Returns, in |*vrange|, the range of SSL3/TLS versions supported for the
+** given protocol variant by the version of libssl linked-to at runtime.
+*/
+SSL_IMPORT SECStatus SSL_VersionRangeGetSupported(
+ SSLProtocolVariant protocolVariant, SSLVersionRange *vrange);
+
+/* Returns, in |*vrange|, the range of SSL3/TLS versions enabled by default
+** for the given protocol variant.
+*/
+SSL_IMPORT SECStatus SSL_VersionRangeGetDefault(
+ SSLProtocolVariant protocolVariant, SSLVersionRange *vrange);
+
+/* Sets the range of enabled-by-default SSL3/TLS versions for the given
+** protocol variant to |*vrange|.
+*/
+SSL_IMPORT SECStatus SSL_VersionRangeSetDefault(
+ SSLProtocolVariant protocolVariant, const SSLVersionRange *vrange);
+
+/* Returns, in |*vrange|, the range of enabled SSL3/TLS versions for |fd|. */
+SSL_IMPORT SECStatus SSL_VersionRangeGet(PRFileDesc *fd,
+ SSLVersionRange *vrange);
+
+/* Sets the range of enabled SSL3/TLS versions for |fd| to |*vrange|. */
+SSL_IMPORT SECStatus SSL_VersionRangeSet(PRFileDesc *fd,
+ const SSLVersionRange *vrange);
+
+
+/* Values for "policy" argument to SSL_PolicySet */
+/* Values returned by SSL_CipherPolicyGet. */
+#define SSL_NOT_ALLOWED 0 /* or invalid or unimplemented */
+#define SSL_ALLOWED 1
+#define SSL_RESTRICTED 2 /* only with "Step-Up" certs. */
+
+/* Values for "on" with SSL_REQUIRE_CERTIFICATE. */
+#define SSL_REQUIRE_NEVER ((PRBool)0)
+#define SSL_REQUIRE_ALWAYS ((PRBool)1)
+#define SSL_REQUIRE_FIRST_HANDSHAKE ((PRBool)2)
+#define SSL_REQUIRE_NO_ERROR ((PRBool)3)
+
+/* Values for "on" with SSL_ENABLE_RENEGOTIATION */
+/* Never renegotiate at all. */
+#define SSL_RENEGOTIATE_NEVER ((PRBool)0)
+/* Renegotiate without restriction, whether or not the peer's client hello */
+/* bears the renegotiation info extension. Vulnerable, as in the past. */
+#define SSL_RENEGOTIATE_UNRESTRICTED ((PRBool)1)
+/* Only renegotiate if the peer's hello bears the TLS renegotiation_info */
+/* extension. This is safe renegotiation. */
+#define SSL_RENEGOTIATE_REQUIRES_XTN ((PRBool)2)
+/* Disallow unsafe renegotiation in server sockets only, but allow clients */
+/* to continue to renegotiate with vulnerable servers. */
+/* This value should only be used during the transition period when few */
+/* servers have been upgraded. */
+#define SSL_RENEGOTIATE_TRANSITIONAL ((PRBool)3)
+
+/*
+** Reset the handshake state for fd. This will make the complete SSL
+** handshake protocol execute from the ground up on the next i/o
+** operation.
+*/
+SSL_IMPORT SECStatus SSL_ResetHandshake(PRFileDesc *fd, PRBool asServer);
+
+/*
+** Force the handshake for fd to complete immediately. This blocks until
+** the complete SSL handshake protocol is finished.
+*/
+SSL_IMPORT SECStatus SSL_ForceHandshake(PRFileDesc *fd);
+
+/*
+** Same as above, but with an I/O timeout.
+ */
+SSL_IMPORT SECStatus SSL_ForceHandshakeWithTimeout(PRFileDesc *fd,
+ PRIntervalTime timeout);
+
+SSL_IMPORT SECStatus SSL_RestartHandshakeAfterCertReq(PRFileDesc *fd,
+ CERTCertificate *cert,
+ SECKEYPrivateKey *key,
+ CERTCertificateList *certChain);
+
+/*
+** Query security status of socket. *on is set to one if security is
+** enabled. *keySize will contain the stream key size used. *issuer will
+** contain the RFC1485 verison of the name of the issuer of the
+** certificate at the other end of the connection. For a client, this is
+** the issuer of the server's certificate; for a server, this is the
+** issuer of the client's certificate (if any). Subject is the subject of
+** the other end's certificate. The pointers can be zero if the desired
+** data is not needed. All strings returned by this function are owned
+** by the caller, and need to be freed with PORT_Free.
+*/
+SSL_IMPORT SECStatus SSL_SecurityStatus(PRFileDesc *fd, int *on, char **cipher,
+ int *keySize, int *secretKeySize,
+ char **issuer, char **subject);
+
+/* Values for "on" */
+#define SSL_SECURITY_STATUS_NOOPT -1
+#define SSL_SECURITY_STATUS_OFF 0
+#define SSL_SECURITY_STATUS_ON_HIGH 1
+#define SSL_SECURITY_STATUS_ON_LOW 2
+#define SSL_SECURITY_STATUS_FORTEZZA 3 /* NO LONGER SUPPORTED */
+
+/*
+** Return the certificate for our SSL peer. If the client calls this
+** it will always return the server's certificate. If the server calls
+** this, it may return NULL if client authentication is not enabled or
+** if the client had no certificate when asked.
+** "fd" the socket "file" descriptor
+*/
+SSL_IMPORT CERTCertificate *SSL_PeerCertificate(PRFileDesc *fd);
+
+/* SSL_PeerStapledOCSPResponses returns the OCSP responses that were provided
+ * by the TLS server. The return value is a pointer to an internal SECItemArray
+ * that contains the returned OCSP responses; it is only valid until the
+ * callback function that calls SSL_PeerStapledOCSPResponses returns.
+ *
+ * If no OCSP responses were given by the server then the result will be empty.
+ * If there was an error, then the result will be NULL.
+ *
+ * You must set the SSL_ENABLE_OCSP_STAPLING option to enable OCSP stapling.
+ * to be provided by a server.
+ *
+ * libssl does not do any validation of the OCSP response itself; the
+ * authenticate certificate hook is responsible for doing so. The default
+ * authenticate certificate hook, SSL_AuthCertificate, does not implement
+ * any OCSP stapling funtionality, but this may change in future versions.
+ */
+SSL_IMPORT const SECItemArray * SSL_PeerStapledOCSPResponses(PRFileDesc *fd);
+
+/* SSL_SetStapledOCSPResponses stores an array of one or multiple OCSP responses
+ * in the fd's data, which may be sent as part of a server side cert_status
+ * handshake message. Parameter |responses| is for the server certificate of
+ * the key exchange type |kea|.
+ * The function will duplicate the responses array.
+ */
+SSL_IMPORT SECStatus
+SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses,
+ SSLKEAType kea);
+
+/*
+** Return references to the certificates presented by the SSL peer.
+** |maxNumCerts| must contain the size of the |certs| array. On successful
+** return, |*numCerts| contains the number of certificates available and
+** |certs| will contain references to as many certificates as would fit.
+** Therefore if |*numCerts| contains a value less than or equal to
+** |maxNumCerts|, then all certificates were returned.
+*/
+SSL_IMPORT SECStatus SSL_PeerCertificateChain(
+ PRFileDesc *fd, CERTCertificate **certs,
+ unsigned int *numCerts, unsigned int maxNumCerts);
+
+/*
+** Authenticate certificate hook. Called when a certificate comes in
+** (because of SSL_REQUIRE_CERTIFICATE in SSL_Enable) to authenticate the
+** certificate.
+**
+** The authenticate certificate hook must return SECSuccess to indicate the
+** certificate is valid, SECFailure to indicate the certificate is invalid,
+** or SECWouldBlock if the application will authenticate the certificate
+** asynchronously. SECWouldBlock is only supported for non-blocking sockets.
+**
+** If the authenticate certificate hook returns SECFailure, then the bad cert
+** hook will be called. The bad cert handler is NEVER called if the
+** authenticate certificate hook returns SECWouldBlock. If the application
+** needs to handle and/or override a bad cert, it should do so before it
+** calls SSL_AuthCertificateComplete (modifying the error it passes to
+** SSL_AuthCertificateComplete as needed).
+**
+** See the documentation for SSL_AuthCertificateComplete for more information
+** about the asynchronous behavior that occurs when the authenticate
+** certificate hook returns SECWouldBlock.
+**
+** RFC 6066 says that clients should send the bad_certificate_status_response
+** alert when they encounter an error processing the stapled OCSP response.
+** libssl does not provide a way for the authenticate certificate hook to
+** indicate that an OCSP error (SEC_ERROR_OCSP_*) that it returns is an error
+** in the stapled OCSP response or an error in some other OCSP response.
+** Further, NSS does not provide a convenient way to control or determine
+** which OCSP response(s) were used to validate a certificate chain.
+** Consequently, the current version of libssl does not ever send the
+** bad_certificate_status_response alert. This may change in future releases.
+*/
+typedef SECStatus (PR_CALLBACK *SSLAuthCertificate)(void *arg, PRFileDesc *fd,
+ PRBool checkSig,
+ PRBool isServer);
+
+SSL_IMPORT SECStatus SSL_AuthCertificateHook(PRFileDesc *fd,
+ SSLAuthCertificate f,
+ void *arg);
+
+/* An implementation of the certificate authentication hook */
+SSL_IMPORT SECStatus SSL_AuthCertificate(void *arg, PRFileDesc *fd,
+ PRBool checkSig, PRBool isServer);
+
+/*
+ * Prototype for SSL callback to get client auth data from the application.
+ * arg - application passed argument
+ * caNames - pointer to distinguished names of CAs that the server likes
+ * pRetCert - pointer to pointer to cert, for return of cert
+ * pRetKey - pointer to key pointer, for return of key
+ */
+typedef SECStatus (PR_CALLBACK *SSLGetClientAuthData)(void *arg,
+ PRFileDesc *fd,
+ CERTDistNames *caNames,
+ CERTCertificate **pRetCert,/*return */
+ SECKEYPrivateKey **pRetKey);/* return */
+
+/*
+ * Set the client side callback for SSL to retrieve user's private key
+ * and certificate.
+ * fd - the file descriptor for the connection in question
+ * f - the application's callback that delivers the key and cert
+ * a - application specific data
+ */
+SSL_IMPORT SECStatus SSL_GetClientAuthDataHook(PRFileDesc *fd,
+ SSLGetClientAuthData f, void *a);
+
+/*
+ * Prototype for SSL callback to get client auth data from the application,
+ * optionally using the underlying platform's cryptographic primitives.
+ * To use the platform cryptographic primitives, caNames and pRetCerts
+ * should be set. To use NSS, pRetNSSCert and pRetNSSKey should be set.
+ * Returning SECFailure will cause the socket to send no client certificate.
+ * arg - application passed argument
+ * caNames - pointer to distinguished names of CAs that the server likes
+ * pRetCerts - pointer to pointer to list of certs, with the first being
+ * the client cert, and any following being used for chain
+ * building
+ * pRetKey - pointer to native key pointer, for return of key
+ * - Windows: A pointer to a PCERT_KEY_CONTEXT that was allocated
+ * via PORT_Alloc(). Ownership of the PCERT_KEY_CONTEXT
+ * is transferred to NSS, which will free via
+ * PORT_Free().
+ * - Mac OS X: A pointer to a SecKeyRef. Ownership is
+ * transferred to NSS, which will free via CFRelease().
+ * pRetNSSCert - pointer to pointer to NSS cert, for return of cert.
+ * pRetNSSKey - pointer to NSS key pointer, for return of key.
+ */
+typedef SECStatus (PR_CALLBACK *SSLGetPlatformClientAuthData)(void *arg,
+ PRFileDesc *fd,
+ CERTDistNames *caNames,
+ CERTCertList **pRetCerts,/*return */
+ void **pRetKey,/* return */
+ CERTCertificate **pRetNSSCert,/*return */
+ SECKEYPrivateKey **pRetNSSKey);/* return */
+
+/*
+ * Set the client side callback for SSL to retrieve user's private key
+ * and certificate.
+ * Note: If a platform client auth callback is set, the callback configured by
+ * SSL_GetClientAuthDataHook, if any, will not be called.
+ *
+ * fd - the file descriptor for the connection in question
+ * f - the application's callback that delivers the key and cert
+ * a - application specific data
+ */
+SSL_IMPORT SECStatus
+SSL_GetPlatformClientAuthDataHook(PRFileDesc *fd,
+ SSLGetPlatformClientAuthData f, void *a);
+
+/*
+** SNI extension processing callback function.
+** It is called when SSL socket receives SNI extension in ClientHello message.
+** Upon this callback invocation, application is responsible to reconfigure the
+** socket with the data for a particular server name.
+** There are three potential outcomes of this function invocation:
+** * application does not recognize the name or the type and wants the
+** "unrecognized_name" alert be sent to the client. In this case the callback
+** function must return SSL_SNI_SEND_ALERT status.
+** * application does not recognize the name, but wants to continue with
+** the handshake using the current socket configuration. In this case,
+** no socket reconfiguration is needed and the function should return
+** SSL_SNI_CURRENT_CONFIG_IS_USED.
+** * application recognizes the name and reconfigures the socket with
+** appropriate certs, key, etc. There are many ways to reconfigure. NSS
+** provides SSL_ReconfigFD function that can be used to update the socket
+** data from model socket. To continue with the rest of the handshake, the
+** implementation function should return an index of a name it has chosen.
+** LibSSL will ignore any SNI extension received in a ClientHello message
+** if application does not register a SSLSNISocketConfig callback.
+** Each type field of SECItem indicates the name type.
+** NOTE: currently RFC3546 defines only one name type: sni_host_name.
+** Client is allowed to send only one name per known type. LibSSL will
+** send an "unrecognized_name" alert if SNI extension name list contains more
+** then one name of a type.
+*/
+typedef PRInt32 (PR_CALLBACK *SSLSNISocketConfig)(PRFileDesc *fd,
+ const SECItem *srvNameArr,
+ PRUint32 srvNameArrSize,
+ void *arg);
+
+/*
+** SSLSNISocketConfig should return an index within 0 and srvNameArrSize-1
+** when it has reconfigured the socket fd to use certs and keys, etc
+** for a specific name. There are two other allowed return values. One
+** tells libSSL to use the default cert and key. The other tells libSSL
+** to send the "unrecognized_name" alert. These values are:
+**/
+#define SSL_SNI_CURRENT_CONFIG_IS_USED -1
+#define SSL_SNI_SEND_ALERT -2
+
+/*
+** Set application implemented SNISocketConfig callback.
+*/
+SSL_IMPORT SECStatus SSL_SNISocketConfigHook(PRFileDesc *fd,
+ SSLSNISocketConfig f,
+ void *arg);
+
+/*
+** Reconfigure fd SSL socket with model socket parameters. Sets
+** server certs and keys, list of trust anchor, socket options
+** and all SSL socket call backs and parameters.
+*/
+SSL_IMPORT PRFileDesc *SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd);
+
+/*
+ * Set the client side argument for SSL to retrieve PKCS #11 pin.
+ * fd - the file descriptor for the connection in question
+ * a - pkcs11 application specific data
+ */
+SSL_IMPORT SECStatus SSL_SetPKCS11PinArg(PRFileDesc *fd, void *a);
+
+/*
+** This is a callback for dealing with server certs that are not authenticated
+** by the client. The client app can decide that it actually likes the
+** cert by some external means and restart the connection.
+**
+** The bad cert hook must return SECSuccess to override the result of the
+** authenticate certificate hook, SECFailure if the certificate should still be
+** considered invalid, or SECWouldBlock if the application will authenticate
+** the certificate asynchronously. SECWouldBlock is only supported for
+** non-blocking sockets.
+**
+** See the documentation for SSL_AuthCertificateComplete for more information
+** about the asynchronous behavior that occurs when the bad cert hook returns
+** SECWouldBlock.
+*/
+typedef SECStatus (PR_CALLBACK *SSLBadCertHandler)(void *arg, PRFileDesc *fd);
+SSL_IMPORT SECStatus SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f,
+ void *arg);
+
+/*
+** Configure SSL socket for running a secure server. Needs the
+** certificate for the server and the servers private key. The arguments
+** are copied.
+*/
+SSL_IMPORT SECStatus SSL_ConfigSecureServer(
+ PRFileDesc *fd, CERTCertificate *cert,
+ SECKEYPrivateKey *key, SSLKEAType kea);
+
+/*
+** Allows SSL socket configuration with caller-supplied certificate chain.
+** If certChainOpt is NULL, tries to find one.
+*/
+SSL_IMPORT SECStatus
+SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert,
+ const CERTCertificateList *certChainOpt,
+ SECKEYPrivateKey *key, SSLKEAType kea);
+
+/*
+** Configure a secure server's session-id cache. Define the maximum number
+** of entries in the cache, the longevity of the entires, and the directory
+** where the cache files will be placed. These values can be zero, and
+** if so, the implementation will choose defaults.
+** This version of the function is for use in applications that have only one
+** process that uses the cache (even if that process has multiple threads).
+*/
+SSL_IMPORT SECStatus SSL_ConfigServerSessionIDCache(int maxCacheEntries,
+ PRUint32 timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory);
+
+/* Configure a secure server's session-id cache. Depends on value of
+ * enableMPCache, configures malti-proc or single proc cache. */
+SSL_IMPORT SECStatus SSL_ConfigServerSessionIDCacheWithOpt(
+ PRUint32 timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory,
+ int maxCacheEntries,
+ int maxCertCacheEntries,
+ int maxSrvNameCacheEntries,
+ PRBool enableMPCache);
+
+/*
+** Like SSL_ConfigServerSessionIDCache, with one important difference.
+** If the application will run multiple processes (as opposed to, or in
+** addition to multiple threads), then it must call this function, instead
+** of calling SSL_ConfigServerSessionIDCache().
+** This has nothing to do with the number of processORs, only processEs.
+** This function sets up a Server Session ID (SID) cache that is safe for
+** access by multiple processes on the same system.
+*/
+SSL_IMPORT SECStatus SSL_ConfigMPServerSIDCache(int maxCacheEntries,
+ PRUint32 timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory);
+
+/* Get and set the configured maximum number of mutexes used for the
+** server's store of SSL sessions. This value is used by the server
+** session ID cache initialization functions shown above. Note that on
+** some platforms, these mutexes are actually implemented with POSIX
+** semaphores, or with unnamed pipes. The default value varies by platform.
+** An attempt to set a too-low maximum will return an error and the
+** configured value will not be changed.
+*/
+SSL_IMPORT PRUint32 SSL_GetMaxServerCacheLocks(void);
+SSL_IMPORT SECStatus SSL_SetMaxServerCacheLocks(PRUint32 maxLocks);
+
+/* environment variable set by SSL_ConfigMPServerSIDCache, and queried by
+ * SSL_InheritMPServerSIDCache when envString is NULL.
+ */
+#define SSL_ENV_VAR_NAME "SSL_INHERITANCE"
+
+/* called in child to inherit SID Cache variables.
+ * If envString is NULL, this function will use the value of the environment
+ * variable "SSL_INHERITANCE", otherwise the string value passed in will be
+ * used.
+ */
+SSL_IMPORT SECStatus SSL_InheritMPServerSIDCache(const char * envString);
+
+/*
+** Set the callback on a particular socket that gets called when we finish
+** performing a handshake.
+*/
+typedef void (PR_CALLBACK *SSLHandshakeCallback)(PRFileDesc *fd,
+ void *client_data);
+SSL_IMPORT SECStatus SSL_HandshakeCallback(PRFileDesc *fd,
+ SSLHandshakeCallback cb, void *client_data);
+
+/*
+** For the server, request a new handshake. For the client, begin a new
+** handshake. If flushCache is non-zero, the SSL3 cache entry will be
+** flushed first, ensuring that a full SSL handshake will be done.
+** If flushCache is zero, and an SSL connection is established, it will
+** do the much faster session restart handshake. This will change the
+** session keys without doing another private key operation.
+*/
+SSL_IMPORT SECStatus SSL_ReHandshake(PRFileDesc *fd, PRBool flushCache);
+
+/*
+** Same as above, but with an I/O timeout.
+ */
+SSL_IMPORT SECStatus SSL_ReHandshakeWithTimeout(PRFileDesc *fd,
+ PRBool flushCache,
+ PRIntervalTime timeout);
+
+/* Returns a SECItem containing the certificate_types field of the
+** CertificateRequest message. Each byte of the data is a TLS
+** ClientCertificateType value, and they are ordered from most preferred to
+** least. This function should only be called from the
+** SSL_GetClientAuthDataHook callback, and will return NULL if called at any
+** other time. The returned value is valid only until the callback returns, and
+** should not be freed.
+*/
+SSL_IMPORT const SECItem *
+SSL_GetRequestedClientCertificateTypes(PRFileDesc *fd);
+
+#ifdef SSL_DEPRECATED_FUNCTION
+/* deprecated!
+** For the server, request a new handshake. For the client, begin a new
+** handshake. Flushes SSL3 session cache entry first, ensuring that a
+** full handshake will be done.
+** This call is equivalent to SSL_ReHandshake(fd, PR_TRUE)
+*/
+SSL_IMPORT SECStatus SSL_RedoHandshake(PRFileDesc *fd);
+#endif
+
+/*
+ * Allow the application to pass a URL or hostname into the SSL library.
+ */
+SSL_IMPORT SECStatus SSL_SetURL(PRFileDesc *fd, const char *url);
+
+/*
+ * Allow an application to define a set of trust anchors for peer
+ * cert validation.
+ */
+SSL_IMPORT SECStatus SSL_SetTrustAnchors(PRFileDesc *fd, CERTCertList *list);
+
+/*
+** Return the number of bytes that SSL has waiting in internal buffers.
+** Return 0 if security is not enabled.
+*/
+SSL_IMPORT int SSL_DataPending(PRFileDesc *fd);
+
+/*
+** Invalidate the SSL session associated with fd.
+*/
+SSL_IMPORT SECStatus SSL_InvalidateSession(PRFileDesc *fd);
+
+/*
+** Return a SECItem containing the SSL session ID associated with the fd.
+*/
+SSL_IMPORT SECItem *SSL_GetSessionID(PRFileDesc *fd);
+
+/*
+** Clear out the client's SSL session cache, not the server's session cache.
+*/
+SSL_IMPORT void SSL_ClearSessionCache(void);
+
+/*
+** Close the server's SSL session cache.
+*/
+SSL_IMPORT SECStatus SSL_ShutdownServerSessionIDCache(void);
+
+/*
+** Set peer information so we can correctly look up SSL session later.
+** You only have to do this if you're tunneling through a proxy.
+*/
+SSL_IMPORT SECStatus SSL_SetSockPeerID(PRFileDesc *fd, const char *peerID);
+
+/*
+** Reveal the security information for the peer.
+*/
+SSL_IMPORT CERTCertificate * SSL_RevealCert(PRFileDesc * socket);
+SSL_IMPORT void * SSL_RevealPinArg(PRFileDesc * socket);
+SSL_IMPORT char * SSL_RevealURL(PRFileDesc * socket);
+
+/* This callback may be passed to the SSL library via a call to
+ * SSL_GetClientAuthDataHook() for each SSL client socket.
+ * It will be invoked when SSL needs to know what certificate and private key
+ * (if any) to use to respond to a request for client authentication.
+ * If arg is non-NULL, it is a pointer to a NULL-terminated string containing
+ * the nickname of the cert/key pair to use.
+ * If arg is NULL, this function will search the cert and key databases for
+ * a suitable match and send it if one is found.
+ */
+SSL_IMPORT SECStatus
+NSS_GetClientAuthData(void * arg,
+ PRFileDesc * socket,
+ struct CERTDistNamesStr * caNames,
+ struct CERTCertificateStr ** pRetCert,
+ struct SECKEYPrivateKeyStr **pRetKey);
+
+/*
+** Configure DTLS-SRTP (RFC 5764) cipher suite preferences.
+** Input is a list of ciphers in descending preference order and a length
+** of the list. As a side effect, this causes the use_srtp extension to be
+** negotiated.
+**
+** Invalid or unimplemented cipher suites in |ciphers| are ignored. If at
+** least one cipher suite in |ciphers| is implemented, returns SECSuccess.
+** Otherwise returns SECFailure.
+*/
+SSL_IMPORT SECStatus SSL_SetSRTPCiphers(PRFileDesc *fd,
+ const PRUint16 *ciphers,
+ unsigned int numCiphers);
+
+/*
+** Get the selected DTLS-SRTP cipher suite (if any).
+** To be called after the handshake completes.
+** Returns SECFailure if not negotiated.
+*/
+SSL_IMPORT SECStatus SSL_GetSRTPCipher(PRFileDesc *fd,
+ PRUint16 *cipher);
+
+/*
+ * Look to see if any of the signers in the cert chain for "cert" are found
+ * in the list of caNames.
+ * Returns SECSuccess if so, SECFailure if not.
+ * Used by NSS_GetClientAuthData. May be used by other callback functions.
+ */
+SSL_IMPORT SECStatus NSS_CmpCertChainWCANames(CERTCertificate *cert,
+ CERTDistNames *caNames);
+
+/*
+ * Returns key exchange type of the keys in an SSL server certificate.
+ */
+SSL_IMPORT SSLKEAType NSS_FindCertKEAType(CERTCertificate * cert);
+
+/* Set cipher policies to a predefined Domestic (U.S.A.) policy.
+ * This essentially enables all supported ciphers.
+ */
+SSL_IMPORT SECStatus NSS_SetDomesticPolicy(void);
+
+/* Set cipher policies to a predefined Policy that is exportable from the USA
+ * according to present U.S. policies as we understand them.
+ * See documentation for the list.
+ * Note that your particular application program may be able to obtain
+ * an export license with more or fewer capabilities than those allowed
+ * by this function. In that case, you should use SSL_SetPolicy()
+ * to explicitly allow those ciphers you may legally export.
+ */
+SSL_IMPORT SECStatus NSS_SetExportPolicy(void);
+
+/* Set cipher policies to a predefined Policy that is exportable from the USA
+ * according to present U.S. policies as we understand them, and that the
+ * nation of France will permit to be imported into their country.
+ * See documentation for the list.
+ */
+SSL_IMPORT SECStatus NSS_SetFrancePolicy(void);
+
+SSL_IMPORT SSL3Statistics * SSL_GetStatistics(void);
+
+/* Report more information than SSL_SecurityStatus.
+** Caller supplies the info struct. Function fills it in.
+*/
+SSL_IMPORT SECStatus SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info,
+ PRUintn len);
+SSL_IMPORT SECStatus SSL_GetCipherSuiteInfo(PRUint16 cipherSuite,
+ SSLCipherSuiteInfo *info, PRUintn len);
+
+/* Returnes negotiated through SNI host info. */
+SSL_IMPORT SECItem *SSL_GetNegotiatedHostInfo(PRFileDesc *fd);
+
+/* Export keying material according to RFC 5705.
+** fd must correspond to a TLS 1.0 or higher socket and out must
+** already be allocated. If hasContext is false, it uses the no-context
+** construction from the RFC and ignores the context and contextLen
+** arguments.
+*/
+SSL_IMPORT SECStatus SSL_ExportKeyingMaterial(PRFileDesc *fd,
+ const char *label,
+ unsigned int labelLen,
+ PRBool hasContext,
+ const unsigned char *context,
+ unsigned int contextLen,
+ unsigned char *out,
+ unsigned int outLen);
+
+/*
+** Return a new reference to the certificate that was most recently sent
+** to the peer on this SSL/TLS connection, or NULL if none has been sent.
+*/
+SSL_IMPORT CERTCertificate * SSL_LocalCertificate(PRFileDesc *fd);
+
+/* Test an SSL configuration to see if SSL_BYPASS_PKCS11 can be turned on.
+** Check the key exchange algorithm for each cipher in the list to see if
+** a master secret key can be extracted after being derived with the mechanism
+** required by the protocolmask argument. If the KEA will use keys from the
+** specified cert make sure the extract operation is attempted from the slot
+** where the private key resides.
+** If MS can be extracted for all ciphers, (*pcanbypass) is set to TRUE and
+** SECSuccess is returned. In all other cases but one (*pcanbypass) is
+** set to FALSE and SECFailure is returned.
+** In that last case Derive() has been called successfully but the MS is null,
+** CanBypass sets (*pcanbypass) to FALSE and returns SECSuccess indicating the
+** arguments were all valid but the slot cannot be bypassed.
+**
+** Note: A TRUE return code from CanBypass means "Your configuration will perform
+** NO WORSE with the bypass enabled than without"; it does NOT mean that every
+** cipher suite listed will work properly with the selected protocols.
+**
+** Caveat: If export cipher suites are included in the argument list Canbypass
+** will return FALSE.
+**/
+
+/* protocol mask bits */
+#define SSL_CBP_SSL3 0x0001 /* test SSL v3 mechanisms */
+#define SSL_CBP_TLS1_0 0x0002 /* test TLS v1.0 mechanisms */
+
+SSL_IMPORT SECStatus SSL_CanBypass(CERTCertificate *cert,
+ SECKEYPrivateKey *privKey,
+ PRUint32 protocolmask,
+ PRUint16 *ciphers, int nciphers,
+ PRBool *pcanbypass, void *pwArg);
+
+/*
+** Did the handshake with the peer negotiate the given extension?
+** Output parameter valid only if function returns SECSuccess
+*/
+SSL_IMPORT SECStatus SSL_HandshakeNegotiatedExtension(PRFileDesc * socket,
+ SSLExtensionType extId,
+ PRBool *yes);
+
+SSL_IMPORT SECStatus SSL_HandshakeResumedSession(PRFileDesc *fd,
+ PRBool *last_handshake_resumed);
+
+/* See SSL_SetClientChannelIDCallback for usage. If the callback returns
+ * SECWouldBlock then SSL_RestartHandshakeAfterChannelIDReq should be called in
+ * the future to restart the handshake. On SECSuccess, the callback must have
+ * written a P-256, EC key pair to |*out_public_key| and |*out_private_key|. */
+typedef SECStatus (PR_CALLBACK *SSLClientChannelIDCallback)(
+ void *arg,
+ PRFileDesc *fd,
+ SECKEYPublicKey **out_public_key,
+ SECKEYPrivateKey **out_private_key);
+
+/* SSL_RestartHandshakeAfterChannelIDReq attempts to restart the handshake
+ * after a ChannelID callback returned SECWouldBlock.
+ *
+ * This function takes ownership of |channelIDPub| and |channelID|. */
+SSL_IMPORT SECStatus SSL_RestartHandshakeAfterChannelIDReq(
+ PRFileDesc *fd,
+ SECKEYPublicKey *channelIDPub,
+ SECKEYPrivateKey *channelID);
+
+/* SSL_SetClientChannelIDCallback sets a callback function that will be called
+ * once the server's ServerHello has been processed. This is only applicable to
+ * a client socket and setting this callback causes the TLS Channel ID
+ * extension to be advertised. */
+SSL_IMPORT SECStatus SSL_SetClientChannelIDCallback(
+ PRFileDesc *fd,
+ SSLClientChannelIDCallback callback,
+ void *arg);
+
+/*
+** How long should we wait before retransmitting the next flight of
+** the DTLS handshake? Returns SECFailure if not DTLS or not in a
+** handshake.
+*/
+SSL_IMPORT SECStatus DTLS_GetHandshakeTimeout(PRFileDesc *socket,
+ PRIntervalTime *timeout);
+
+/*
+ * Return a boolean that indicates whether the underlying library
+ * will perform as the caller expects.
+ *
+ * The only argument is a string, which should be the version
+ * identifier of the NSS library. That string will be compared
+ * against a string that represents the actual build version of
+ * the SSL library.
+ */
+extern PRBool NSSSSL_VersionCheck(const char *importedVersion);
+
+/*
+ * Returns a const string of the SSL library version.
+ */
+extern const char *NSSSSL_GetVersion(void);
+
+/* Restart an SSL connection that was paused to do asynchronous certificate
+ * chain validation (when the auth certificate hook or bad cert handler
+ * returned SECWouldBlock).
+ *
+ * This function only works for non-blocking sockets; Do not use it for
+ * blocking sockets. Currently, this function works only for the client role of
+ * a connection; it does not work for the server role.
+ *
+ * The application must call SSL_AuthCertificateComplete with 0 as the value of
+ * the error parameter after it has successfully validated the peer's
+ * certificate, in order to continue the SSL handshake.
+ *
+ * The application may call SSL_AuthCertificateComplete with a non-zero value
+ * for error (e.g. SEC_ERROR_REVOKED_CERTIFICATE) when certificate validation
+ * fails, before it closes the connection. If the application does so, an
+ * alert corresponding to the error (e.g. certificate_revoked) will be sent to
+ * the peer. See the source code of the internal function
+ * ssl3_SendAlertForCertError for the current mapping of error to alert. This
+ * mapping may change in future versions of libssl.
+ *
+ * This function will not complete the entire handshake. The application must
+ * call SSL_ForceHandshake, PR_Recv, PR_Send, etc. after calling this function
+ * to force the handshake to complete.
+ *
+ * On the first handshake of a connection, libssl will wait for the peer's
+ * certificate to be authenticated before calling the handshake callback,
+ * sending a client certificate, sending any application data, or returning
+ * any application data to the application. On subsequent (renegotiation)
+ * handshakes, libssl will block the handshake unconditionally while the
+ * certificate is being validated.
+ *
+ * libssl may send and receive handshake messages while waiting for the
+ * application to call SSL_AuthCertificateComplete, and it may call other
+ * callbacks (e.g, the client auth data hook) before
+ * SSL_AuthCertificateComplete has been called.
+ *
+ * An application that uses this asynchronous mechanism will usually have lower
+ * handshake latency if it has to do public key operations on the certificate
+ * chain and/or CRL/OCSP/cert fetching during the authentication, especially if
+ * it does so in parallel on another thread. However, if the application can
+ * authenticate the peer's certificate quickly then it may be more efficient
+ * to use the synchronous mechanism (i.e. returning SECFailure/SECSuccess
+ * instead of SECWouldBlock from the authenticate certificate hook).
+ *
+ * Be careful about converting an application from synchronous cert validation
+ * to asynchronous certificate validation. A naive conversion is likely to
+ * result in deadlocks; e.g. the application will wait in PR_Poll for network
+ * I/O on the connection while all network I/O on the connection is blocked
+ * waiting for this function to be called.
+ *
+ * Returns SECFailure on failure, SECSuccess on success. Never returns
+ * SECWouldBlock. Note that SSL_AuthCertificateComplete will (usually) return
+ * SECSuccess; do not interpret the return value of SSL_AuthCertificateComplete
+ * as an indicator of whether it is OK to continue using the connection. For
+ * example, SSL_AuthCertificateComplete(fd, SEC_ERROR_REVOKED_CERTIFICATE) will
+ * return SECSuccess (normally), but that does not mean that the application
+ * should continue using the connection. If the application passes a non-zero
+ * value for second argument (error), or if SSL_AuthCertificateComplete returns
+ * anything other than SECSuccess, then the application should close the
+ * connection.
+ */
+SSL_IMPORT SECStatus SSL_AuthCertificateComplete(PRFileDesc *fd,
+ PRErrorCode error);
+SEC_END_PROTOS
+
+#endif /* __ssl_h_ */
diff --git a/chromium/net/third_party/nss/ssl/ssl.rc b/chromium/net/third_party/nss/ssl/ssl.rc
new file mode 100644
index 00000000000..809a07e5ffd
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/ssl.rc
@@ -0,0 +1,68 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nss.h"
+#include <winver.h>
+
+#define MY_LIBNAME "ssl"
+#define MY_FILEDESCRIPTION "NSS SSL Library"
+
+#define STRINGIZE(x) #x
+#define STRINGIZE2(x) STRINGIZE(x)
+#define NSS_VMAJOR_STR STRINGIZE2(NSS_VMAJOR)
+
+#ifdef _DEBUG
+#define MY_DEBUG_STR " (debug)"
+#define MY_FILEFLAGS_1 VS_FF_DEBUG
+#else
+#define MY_DEBUG_STR ""
+#define MY_FILEFLAGS_1 0x0L
+#endif
+#if NSS_BETA
+#define MY_FILEFLAGS_2 MY_FILEFLAGS_1|VS_FF_PRERELEASE
+#else
+#define MY_FILEFLAGS_2 MY_FILEFLAGS_1
+#endif
+
+#ifdef WINNT
+#define MY_FILEOS VOS_NT_WINDOWS32
+#else
+#define MY_FILEOS VOS__WINDOWS32
+#endif
+
+#define MY_INTERNAL_NAME MY_LIBNAME NSS_VMAJOR_STR
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version-information resource
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION NSS_VMAJOR,NSS_VMINOR,NSS_VPATCH,NSS_VBUILD
+ PRODUCTVERSION NSS_VMAJOR,NSS_VMINOR,NSS_VPATCH,NSS_VBUILD
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS MY_FILEFLAGS_2
+ FILEOS MY_FILEOS
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0x0L // not used
+
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904B0" // Lang=US English, CharSet=Unicode
+ BEGIN
+ VALUE "CompanyName", "Mozilla Foundation\0"
+ VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0"
+ VALUE "FileVersion", NSS_VERSION "\0"
+ VALUE "InternalName", MY_INTERNAL_NAME "\0"
+ VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0"
+ VALUE "ProductName", "Network Security Services\0"
+ VALUE "ProductVersion", NSS_VERSION "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/chromium/net/third_party/nss/ssl/ssl3con.c b/chromium/net/third_party/nss/ssl/ssl3con.c
new file mode 100644
index 00000000000..e614eab2bde
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/ssl3con.c
@@ -0,0 +1,12310 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * SSL3 Protocol
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* TODO(ekr): Implement HelloVerifyRequest on server side. OK for now. */
+
+#include "cert.h"
+#include "ssl.h"
+#include "cryptohi.h" /* for DSAU_ stuff */
+#include "keyhi.h"
+#include "secder.h"
+#include "secitem.h"
+#include "sechash.h"
+
+#include "sslimpl.h"
+#include "sslproto.h"
+#include "sslerr.h"
+#include "prtime.h"
+#include "prinrval.h"
+#include "prerror.h"
+#include "pratom.h"
+#include "prthread.h"
+
+#include "pk11func.h"
+#include "secmod.h"
+#ifndef NO_PKCS11_BYPASS
+#include "blapi.h"
+#endif
+
+/* This is a bodge to allow this code to be compiled against older NSS headers
+ * that don't contain the TLS 1.2 changes. */
+#ifndef CKM_NSS_TLS_PRF_GENERAL_SHA256
+#define CKM_NSS_TLS_PRF_GENERAL_SHA256 (CKM_NSS + 21)
+#define CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256 (CKM_NSS + 22)
+#define CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256 (CKM_NSS + 23)
+#define CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 (CKM_NSS + 24)
+#endif
+
+#include <stdio.h>
+#ifdef NSS_ENABLE_ZLIB
+#include "zlib.h"
+#endif
+#ifdef LINUX
+#include <dlfcn.h>
+#endif
+
+#ifndef PK11_SETATTRS
+#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
+ (x)->pValue=(v); (x)->ulValueLen = (l);
+#endif
+
+static SECStatus ssl3_AuthCertificate(sslSocket *ss);
+static void ssl3_CleanupPeerCerts(sslSocket *ss);
+static void ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid);
+static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec,
+ PK11SlotInfo * serverKeySlot);
+static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms);
+static SECStatus ssl3_DeriveConnectionKeysPKCS11(sslSocket *ss);
+static SECStatus ssl3_HandshakeFailure( sslSocket *ss);
+static SECStatus ssl3_InitState( sslSocket *ss);
+static SECStatus ssl3_SendCertificate( sslSocket *ss);
+static SECStatus ssl3_SendCertificateStatus( sslSocket *ss);
+static SECStatus ssl3_SendEmptyCertificate( sslSocket *ss);
+static SECStatus ssl3_SendCertificateRequest(sslSocket *ss);
+static SECStatus ssl3_SendNextProto( sslSocket *ss);
+static SECStatus ssl3_SendEncryptedExtensions(sslSocket *ss);
+static SECStatus ssl3_SendFinished( sslSocket *ss, PRInt32 flags);
+static SECStatus ssl3_SendServerHello( sslSocket *ss);
+static SECStatus ssl3_SendServerHelloDone( sslSocket *ss);
+static SECStatus ssl3_SendServerKeyExchange( sslSocket *ss);
+static SECStatus ssl3_UpdateHandshakeHashes( sslSocket *ss,
+ const unsigned char *b,
+ unsigned int l);
+static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
+static int ssl3_OIDToTLSHashAlgorithm(SECOidTag oid);
+
+static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
+ int maxOutputLen, const unsigned char *input,
+ int inputLen);
+#ifndef NO_PKCS11_BYPASS
+static SECStatus ssl3_AESGCMBypass(ssl3KeyMaterial *keys, PRBool doDecrypt,
+ unsigned char *out, int *outlen, int maxout,
+ const unsigned char *in, int inlen,
+ SSL3ContentType type,
+ SSL3ProtocolVersion version,
+ SSL3SequenceNumber seq_num);
+#endif
+
+#define MAX_SEND_BUF_LENGTH 32000 /* watch for 16-bit integer overflow */
+#define MIN_SEND_BUF_LENGTH 4000
+
+/* This list of SSL3 cipher suites is sorted in descending order of
+ * precedence (desirability). It only includes cipher suites we implement.
+ * This table is modified by SSL3_SetPolicy(). The ordering of cipher suites
+ * in this table must match the ordering in SSL_ImplementedCiphers (sslenum.c)
+ */
+static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
+ /* cipher_suite policy enabled is_present*/
+#ifdef NSS_ENABLE_ECC
+ { TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+#endif /* NSS_ENABLE_ECC */
+ { TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+ { TLS_RSA_WITH_AES_128_GCM_SHA256, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+
+#ifdef NSS_ENABLE_ECC
+ { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+#endif /* NSS_ENABLE_ECC */
+ { TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_DHE_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+ { TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+ { TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+#ifdef NSS_ENABLE_ECC
+ { TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+#endif /* NSS_ENABLE_ECC */
+ { TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+ { TLS_RSA_WITH_AES_256_CBC_SHA256, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+
+#ifdef NSS_ENABLE_ECC
+ { TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+#endif /* NSS_ENABLE_ECC */
+ { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_DHE_DSS_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_DHE_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+ { TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+ { TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+#ifdef NSS_ENABLE_ECC
+ { TLS_ECDH_RSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_ECDH_ECDSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+#endif /* NSS_ENABLE_ECC */
+ { TLS_RSA_WITH_SEED_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { SSL_RSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+ { SSL_RSA_WITH_RC4_128_MD5, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE},
+ { TLS_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+ { TLS_RSA_WITH_AES_128_CBC_SHA256, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+
+#ifdef NSS_ENABLE_ECC
+ { TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+#endif /* NSS_ENABLE_ECC */
+ { SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+ { SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+#ifdef NSS_ENABLE_ECC
+ { TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+#endif /* NSS_ENABLE_ECC */
+ { SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE},
+ { SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE},
+
+
+ { SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { SSL_RSA_FIPS_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE},
+ { SSL_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE},
+ { TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE},
+ { TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE},
+
+ { SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE},
+ { SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE},
+
+#ifdef NSS_ENABLE_ECC
+ { TLS_ECDHE_ECDSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE},
+ { TLS_ECDHE_RSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE},
+ { TLS_ECDH_RSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE},
+ { TLS_ECDH_ECDSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE},
+#endif /* NSS_ENABLE_ECC */
+ { SSL_RSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_RSA_WITH_NULL_SHA256, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { SSL_RSA_WITH_NULL_MD5, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+
+};
+
+/* This list of SSL3 compression methods is sorted in descending order of
+ * precedence (desirability). It only includes compression methods we
+ * implement.
+ */
+static const /*SSLCompressionMethod*/ PRUint8 compressions [] = {
+#ifdef NSS_ENABLE_ZLIB
+ ssl_compression_deflate,
+#endif
+ ssl_compression_null
+};
+
+static const int compressionMethodsCount =
+ sizeof(compressions) / sizeof(compressions[0]);
+
+/* compressionEnabled returns true iff the compression algorithm is enabled
+ * for the given SSL socket. */
+static PRBool
+compressionEnabled(sslSocket *ss, SSLCompressionMethod compression)
+{
+ switch (compression) {
+ case ssl_compression_null:
+ return PR_TRUE; /* Always enabled */
+#ifdef NSS_ENABLE_ZLIB
+ case ssl_compression_deflate:
+ return ss->opt.enableDeflate;
+#endif
+ default:
+ return PR_FALSE;
+ }
+}
+
+static const /*SSL3ClientCertificateType */ PRUint8 certificate_types [] = {
+ ct_RSA_sign,
+#ifdef NSS_ENABLE_ECC
+ ct_ECDSA_sign,
+#endif /* NSS_ENABLE_ECC */
+ ct_DSS_sign,
+};
+
+/* This block is the contents of the supported_signature_algorithms field of
+ * our TLS 1.2 CertificateRequest message, in wire format. See
+ * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+ *
+ * This block contains only sha256 entries because we only support TLS 1.2
+ * CertificateVerify messages that use the handshake hash. */
+static const PRUint8 supported_signature_algorithms[] = {
+ tls_hash_sha256, tls_sig_rsa,
+#ifdef NSS_ENABLE_ECC
+ tls_hash_sha256, tls_sig_ecdsa,
+#endif
+ tls_hash_sha256, tls_sig_dsa,
+};
+
+#define EXPORT_RSA_KEY_LENGTH 64 /* bytes */
+
+
+/* This global item is used only in servers. It is is initialized by
+** SSL_ConfigSecureServer(), and is used in ssl3_SendCertificateRequest().
+*/
+CERTDistNames *ssl3_server_ca_list = NULL;
+static SSL3Statistics ssl3stats;
+
+/* indexed by SSL3BulkCipher */
+static const ssl3BulkCipherDef bulk_cipher_defs[] = {
+ /* |--------- Lengths --------| */
+ /* cipher calg k s type i b t n */
+ /* e e v l a o */
+ /* y c | o g n */
+ /* | r | c | c */
+ /* | e | k | e */
+ /* | t | | | | */
+ {cipher_null, calg_null, 0, 0, type_stream, 0, 0, 0, 0},
+ {cipher_rc4, calg_rc4, 16,16, type_stream, 0, 0, 0, 0},
+ {cipher_rc4_40, calg_rc4, 16, 5, type_stream, 0, 0, 0, 0},
+ {cipher_rc4_56, calg_rc4, 16, 7, type_stream, 0, 0, 0, 0},
+ {cipher_rc2, calg_rc2, 16,16, type_block, 8, 8, 0, 0},
+ {cipher_rc2_40, calg_rc2, 16, 5, type_block, 8, 8, 0, 0},
+ {cipher_des, calg_des, 8, 8, type_block, 8, 8, 0, 0},
+ {cipher_3des, calg_3des, 24,24, type_block, 8, 8, 0, 0},
+ {cipher_des40, calg_des, 8, 5, type_block, 8, 8, 0, 0},
+ {cipher_idea, calg_idea, 16,16, type_block, 8, 8, 0, 0},
+ {cipher_aes_128, calg_aes, 16,16, type_block, 16,16, 0, 0},
+ {cipher_aes_256, calg_aes, 32,32, type_block, 16,16, 0, 0},
+ {cipher_camellia_128, calg_camellia, 16,16, type_block, 16,16, 0, 0},
+ {cipher_camellia_256, calg_camellia, 32,32, type_block, 16,16, 0, 0},
+ {cipher_seed, calg_seed, 16,16, type_block, 16,16, 0, 0},
+ {cipher_aes_128_gcm, calg_aes_gcm, 16,16, type_aead, 4, 0,16, 8},
+ {cipher_missing, calg_null, 0, 0, type_stream, 0, 0, 0, 0},
+};
+
+static const ssl3KEADef kea_defs[] =
+{ /* indexed by SSL3KeyExchangeAlgorithm */
+ /* kea exchKeyType signKeyType is_limited limit tls_keygen */
+ {kea_null, kt_null, sign_null, PR_FALSE, 0, PR_FALSE},
+ {kea_rsa, kt_rsa, sign_rsa, PR_FALSE, 0, PR_FALSE},
+ {kea_rsa_export, kt_rsa, sign_rsa, PR_TRUE, 512, PR_FALSE},
+ {kea_rsa_export_1024,kt_rsa, sign_rsa, PR_TRUE, 1024, PR_FALSE},
+ {kea_dh_dss, kt_dh, sign_dsa, PR_FALSE, 0, PR_FALSE},
+ {kea_dh_dss_export, kt_dh, sign_dsa, PR_TRUE, 512, PR_FALSE},
+ {kea_dh_rsa, kt_dh, sign_rsa, PR_FALSE, 0, PR_FALSE},
+ {kea_dh_rsa_export, kt_dh, sign_rsa, PR_TRUE, 512, PR_FALSE},
+ {kea_dhe_dss, kt_dh, sign_dsa, PR_FALSE, 0, PR_FALSE},
+ {kea_dhe_dss_export, kt_dh, sign_dsa, PR_TRUE, 512, PR_FALSE},
+ {kea_dhe_rsa, kt_dh, sign_rsa, PR_FALSE, 0, PR_FALSE},
+ {kea_dhe_rsa_export, kt_dh, sign_rsa, PR_TRUE, 512, PR_FALSE},
+ {kea_dh_anon, kt_dh, sign_null, PR_FALSE, 0, PR_FALSE},
+ {kea_dh_anon_export, kt_dh, sign_null, PR_TRUE, 512, PR_FALSE},
+ {kea_rsa_fips, kt_rsa, sign_rsa, PR_FALSE, 0, PR_TRUE },
+#ifdef NSS_ENABLE_ECC
+ {kea_ecdh_ecdsa, kt_ecdh, sign_ecdsa, PR_FALSE, 0, PR_FALSE},
+ {kea_ecdhe_ecdsa, kt_ecdh, sign_ecdsa, PR_FALSE, 0, PR_FALSE},
+ {kea_ecdh_rsa, kt_ecdh, sign_rsa, PR_FALSE, 0, PR_FALSE},
+ {kea_ecdhe_rsa, kt_ecdh, sign_rsa, PR_FALSE, 0, PR_FALSE},
+ {kea_ecdh_anon, kt_ecdh, sign_null, PR_FALSE, 0, PR_FALSE},
+#endif /* NSS_ENABLE_ECC */
+};
+
+/* must use ssl_LookupCipherSuiteDef to access */
+static const ssl3CipherSuiteDef cipher_suite_defs[] =
+{
+/* cipher_suite bulk_cipher_alg mac_alg key_exchange_alg */
+
+ {SSL_NULL_WITH_NULL_NULL, cipher_null, mac_null, kea_null},
+ {SSL_RSA_WITH_NULL_MD5, cipher_null, mac_md5, kea_rsa},
+ {SSL_RSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_rsa},
+ {TLS_RSA_WITH_NULL_SHA256, cipher_null, hmac_sha256, kea_rsa},
+ {SSL_RSA_EXPORT_WITH_RC4_40_MD5,cipher_rc4_40, mac_md5, kea_rsa_export},
+ {SSL_RSA_WITH_RC4_128_MD5, cipher_rc4, mac_md5, kea_rsa},
+ {SSL_RSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_rsa},
+ {SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
+ cipher_rc2_40, mac_md5, kea_rsa_export},
+#if 0 /* not implemented */
+ {SSL_RSA_WITH_IDEA_CBC_SHA, cipher_idea, mac_sha, kea_rsa},
+ {SSL_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ cipher_des40, mac_sha, kea_rsa_export},
+#endif
+ {SSL_RSA_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_rsa},
+ {SSL_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_rsa},
+ {SSL_DHE_DSS_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_dhe_dss},
+ {SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ cipher_3des, mac_sha, kea_dhe_dss},
+ {TLS_DHE_DSS_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_dhe_dss},
+#if 0 /* not implemented */
+ {SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
+ cipher_des40, mac_sha, kea_dh_dss_export},
+ {SSL_DH_DSS_DES_CBC_SHA, cipher_des, mac_sha, kea_dh_dss},
+ {SSL_DH_DSS_3DES_CBC_SHA, cipher_3des, mac_sha, kea_dh_dss},
+ {SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ cipher_des40, mac_sha, kea_dh_rsa_export},
+ {SSL_DH_RSA_DES_CBC_SHA, cipher_des, mac_sha, kea_dh_rsa},
+ {SSL_DH_RSA_3DES_CBC_SHA, cipher_3des, mac_sha, kea_dh_rsa},
+ {SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
+ cipher_des40, mac_sha, kea_dh_dss_export},
+ {SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ cipher_des40, mac_sha, kea_dh_rsa_export},
+#endif
+ {SSL_DHE_RSA_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_dhe_rsa},
+ {SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ cipher_3des, mac_sha, kea_dhe_rsa},
+#if 0
+ {SSL_DH_ANON_EXPORT_RC4_40_MD5, cipher_rc4_40, mac_md5, kea_dh_anon_export},
+ {SSL_DH_ANON_EXPORT_WITH_DES40_CBC_SHA,
+ cipher_des40, mac_sha, kea_dh_anon_export},
+ {SSL_DH_ANON_DES_CBC_SHA, cipher_des, mac_sha, kea_dh_anon},
+ {SSL_DH_ANON_3DES_CBC_SHA, cipher_3des, mac_sha, kea_dh_anon},
+#endif
+
+
+/* New TLS cipher suites */
+ {TLS_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_rsa},
+ {TLS_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_rsa},
+ {TLS_DHE_DSS_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dhe_dss},
+ {TLS_DHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dhe_rsa},
+ {TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_dhe_rsa},
+ {TLS_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_rsa},
+ {TLS_RSA_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_rsa},
+ {TLS_DHE_DSS_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dhe_dss},
+ {TLS_DHE_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dhe_rsa},
+ {TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_dhe_rsa},
+#if 0
+ {TLS_DH_DSS_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dh_dss},
+ {TLS_DH_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dh_rsa},
+ {TLS_DH_ANON_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dh_anon},
+ {TLS_DH_DSS_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dh_dss},
+ {TLS_DH_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dh_rsa},
+ {TLS_DH_ANON_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dh_anon},
+#endif
+
+ {TLS_RSA_WITH_SEED_CBC_SHA, cipher_seed, mac_sha, kea_rsa},
+
+ {TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, cipher_camellia_128, mac_sha, kea_rsa},
+ {TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
+ cipher_camellia_128, mac_sha, kea_dhe_dss},
+ {TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
+ cipher_camellia_128, mac_sha, kea_dhe_rsa},
+ {TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, cipher_camellia_256, mac_sha, kea_rsa},
+ {TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,
+ cipher_camellia_256, mac_sha, kea_dhe_dss},
+ {TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
+ cipher_camellia_256, mac_sha, kea_dhe_rsa},
+
+ {TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,
+ cipher_des, mac_sha,kea_rsa_export_1024},
+ {TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,
+ cipher_rc4_56, mac_sha,kea_rsa_export_1024},
+
+ {SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_rsa_fips},
+ {SSL_RSA_FIPS_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_rsa_fips},
+
+ {TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_null, kea_dhe_rsa},
+ {TLS_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_null, kea_rsa},
+ {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_null, kea_ecdhe_rsa},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_null, kea_ecdhe_ecdsa},
+
+#ifdef NSS_ENABLE_ECC
+ {TLS_ECDH_ECDSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdh_ecdsa},
+ {TLS_ECDH_ECDSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdh_ecdsa},
+ {TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_ecdsa},
+ {TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_ecdsa},
+ {TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_ecdsa},
+
+ {TLS_ECDHE_ECDSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdhe_ecdsa},
+ {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdhe_ecdsa},
+ {TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdhe_ecdsa},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_ecdsa},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_ecdhe_ecdsa},
+ {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdhe_ecdsa},
+
+ {TLS_ECDH_RSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdh_rsa},
+ {TLS_ECDH_RSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdh_rsa},
+ {TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_rsa},
+ {TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_rsa},
+ {TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_rsa},
+
+ {TLS_ECDHE_RSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdhe_rsa},
+ {TLS_ECDHE_RSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdhe_rsa},
+ {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdhe_rsa},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_rsa},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_ecdhe_rsa},
+ {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdhe_rsa},
+
+#if 0
+ {TLS_ECDH_anon_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdh_anon},
+ {TLS_ECDH_anon_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdh_anon},
+ {TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_anon},
+ {TLS_ECDH_anon_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_anon},
+ {TLS_ECDH_anon_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_anon},
+#endif
+#endif /* NSS_ENABLE_ECC */
+};
+
+static const CK_MECHANISM_TYPE kea_alg_defs[] = {
+ 0x80000000L,
+ CKM_RSA_PKCS,
+ CKM_DH_PKCS_DERIVE,
+ CKM_KEA_KEY_DERIVE,
+ CKM_ECDH1_DERIVE
+};
+
+typedef struct SSLCipher2MechStr {
+ SSLCipherAlgorithm calg;
+ CK_MECHANISM_TYPE cmech;
+} SSLCipher2Mech;
+
+/* indexed by type SSLCipherAlgorithm */
+static const SSLCipher2Mech alg2Mech[] = {
+ /* calg, cmech */
+ { calg_null , (CK_MECHANISM_TYPE)0x80000000L },
+ { calg_rc4 , CKM_RC4 },
+ { calg_rc2 , CKM_RC2_CBC },
+ { calg_des , CKM_DES_CBC },
+ { calg_3des , CKM_DES3_CBC },
+ { calg_idea , CKM_IDEA_CBC },
+ { calg_fortezza , CKM_SKIPJACK_CBC64 },
+ { calg_aes , CKM_AES_CBC },
+ { calg_camellia , CKM_CAMELLIA_CBC },
+ { calg_seed , CKM_SEED_CBC },
+ { calg_aes_gcm , CKM_AES_GCM },
+/* { calg_init , (CK_MECHANISM_TYPE)0x7fffffffL } */
+};
+
+#define mmech_null (CK_MECHANISM_TYPE)0x80000000L
+#define mmech_md5 CKM_SSL3_MD5_MAC
+#define mmech_sha CKM_SSL3_SHA1_MAC
+#define mmech_md5_hmac CKM_MD5_HMAC
+#define mmech_sha_hmac CKM_SHA_1_HMAC
+#define mmech_sha256_hmac CKM_SHA256_HMAC
+
+static const ssl3MACDef mac_defs[] = { /* indexed by SSL3MACAlgorithm */
+ /* pad_size is only used for SSL 3.0 MAC. See RFC 6101 Sec. 5.2.3.1. */
+ /* mac mmech pad_size mac_size */
+ { mac_null, mmech_null, 0, 0 },
+ { mac_md5, mmech_md5, 48, MD5_LENGTH },
+ { mac_sha, mmech_sha, 40, SHA1_LENGTH},
+ {hmac_md5, mmech_md5_hmac, 0, MD5_LENGTH },
+ {hmac_sha, mmech_sha_hmac, 0, SHA1_LENGTH},
+ {hmac_sha256, mmech_sha256_hmac, 0, SHA256_LENGTH},
+};
+
+/* indexed by SSL3BulkCipher */
+const char * const ssl3_cipherName[] = {
+ "NULL",
+ "RC4",
+ "RC4-40",
+ "RC4-56",
+ "RC2-CBC",
+ "RC2-CBC-40",
+ "DES-CBC",
+ "3DES-EDE-CBC",
+ "DES-CBC-40",
+ "IDEA-CBC",
+ "AES-128",
+ "AES-256",
+ "Camellia-128",
+ "Camellia-256",
+ "SEED-CBC",
+ "AES-128-GCM",
+ "missing"
+};
+
+#ifdef NSS_ENABLE_ECC
+/* The ECCWrappedKeyInfo structure defines how various pieces of
+ * information are laid out within wrappedSymmetricWrappingkey
+ * for ECDH key exchange. Since wrappedSymmetricWrappingkey is
+ * a 512-byte buffer (see sslimpl.h), the variable length field
+ * in ECCWrappedKeyInfo can be at most (512 - 8) = 504 bytes.
+ *
+ * XXX For now, NSS only supports named elliptic curves of size 571 bits
+ * or smaller. The public value will fit within 145 bytes and EC params
+ * will fit within 12 bytes. We'll need to revisit this when NSS
+ * supports arbitrary curves.
+ */
+#define MAX_EC_WRAPPED_KEY_BUFLEN 504
+
+typedef struct ECCWrappedKeyInfoStr {
+ PRUint16 size; /* EC public key size in bits */
+ PRUint16 encodedParamLen; /* length (in bytes) of DER encoded EC params */
+ PRUint16 pubValueLen; /* length (in bytes) of EC public value */
+ PRUint16 wrappedKeyLen; /* length (in bytes) of the wrapped key */
+ PRUint8 var[MAX_EC_WRAPPED_KEY_BUFLEN]; /* this buffer contains the */
+ /* EC public-key params, the EC public value and the wrapped key */
+} ECCWrappedKeyInfo;
+#endif /* NSS_ENABLE_ECC */
+
+#if defined(TRACE)
+
+static char *
+ssl3_DecodeHandshakeType(int msgType)
+{
+ char * rv;
+ static char line[40];
+
+ switch(msgType) {
+ case hello_request: rv = "hello_request (0)"; break;
+ case client_hello: rv = "client_hello (1)"; break;
+ case server_hello: rv = "server_hello (2)"; break;
+ case hello_verify_request: rv = "hello_verify_request (3)"; break;
+ case certificate: rv = "certificate (11)"; break;
+ case server_key_exchange: rv = "server_key_exchange (12)"; break;
+ case certificate_request: rv = "certificate_request (13)"; break;
+ case server_hello_done: rv = "server_hello_done (14)"; break;
+ case certificate_verify: rv = "certificate_verify (15)"; break;
+ case client_key_exchange: rv = "client_key_exchange (16)"; break;
+ case finished: rv = "finished (20)"; break;
+ default:
+ sprintf(line, "*UNKNOWN* handshake type! (%d)", msgType);
+ rv = line;
+ }
+ return rv;
+}
+
+static char *
+ssl3_DecodeContentType(int msgType)
+{
+ char * rv;
+ static char line[40];
+
+ switch(msgType) {
+ case content_change_cipher_spec:
+ rv = "change_cipher_spec (20)"; break;
+ case content_alert: rv = "alert (21)"; break;
+ case content_handshake: rv = "handshake (22)"; break;
+ case content_application_data:
+ rv = "application_data (23)"; break;
+ default:
+ sprintf(line, "*UNKNOWN* record type! (%d)", msgType);
+ rv = line;
+ }
+ return rv;
+}
+
+#endif
+
+SSL3Statistics *
+SSL_GetStatistics(void)
+{
+ return &ssl3stats;
+}
+
+typedef struct tooLongStr {
+#if defined(IS_LITTLE_ENDIAN)
+ PRInt32 low;
+ PRInt32 high;
+#else
+ PRInt32 high;
+ PRInt32 low;
+#endif
+} tooLong;
+
+void SSL_AtomicIncrementLong(long * x)
+{
+ if ((sizeof *x) == sizeof(PRInt32)) {
+ PR_ATOMIC_INCREMENT((PRInt32 *)x);
+ } else {
+ tooLong * tl = (tooLong *)x;
+ if (PR_ATOMIC_INCREMENT(&tl->low) == 0)
+ PR_ATOMIC_INCREMENT(&tl->high);
+ }
+}
+
+static PRBool
+ssl3_CipherSuiteAllowedForVersion(ssl3CipherSuite cipherSuite,
+ SSL3ProtocolVersion version)
+{
+ switch (cipherSuite) {
+ /* See RFC 4346 A.5. Export cipher suites must not be used in TLS 1.1 or
+ * later. This set of cipher suites is similar to, but different from, the
+ * set of cipher suites considered exportable by SSL_IsExportCipherSuite.
+ */
+ case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
+ case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
+ /* SSL_RSA_EXPORT_WITH_DES40_CBC_SHA: never implemented
+ * SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: never implemented
+ * SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: never implemented
+ * SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: never implemented
+ * SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: never implemented
+ * SSL_DH_ANON_EXPORT_WITH_RC4_40_MD5: never implemented
+ * SSL_DH_ANON_EXPORT_WITH_DES40_CBC_SHA: never implemented
+ */
+ return version <= SSL_LIBRARY_VERSION_TLS_1_0;
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ case TLS_RSA_WITH_AES_256_CBC_SHA256:
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case TLS_RSA_WITH_AES_128_CBC_SHA256:
+ case TLS_RSA_WITH_AES_128_GCM_SHA256:
+ case TLS_RSA_WITH_NULL_SHA256:
+ return version >= SSL_LIBRARY_VERSION_TLS_1_2;
+ default:
+ return PR_TRUE;
+ }
+}
+
+/* return pointer to ssl3CipherSuiteDef for suite, or NULL */
+/* XXX This does a linear search. A binary search would be better. */
+static const ssl3CipherSuiteDef *
+ssl_LookupCipherSuiteDef(ssl3CipherSuite suite)
+{
+ int cipher_suite_def_len =
+ sizeof(cipher_suite_defs) / sizeof(cipher_suite_defs[0]);
+ int i;
+
+ for (i = 0; i < cipher_suite_def_len; i++) {
+ if (cipher_suite_defs[i].cipher_suite == suite)
+ return &cipher_suite_defs[i];
+ }
+ PORT_Assert(PR_FALSE); /* We should never get here. */
+ PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
+ return NULL;
+}
+
+/* Find the cipher configuration struct associate with suite */
+/* XXX This does a linear search. A binary search would be better. */
+static ssl3CipherSuiteCfg *
+ssl_LookupCipherSuiteCfg(ssl3CipherSuite suite, ssl3CipherSuiteCfg *suites)
+{
+ int i;
+
+ for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
+ if (suites[i].cipher_suite == suite)
+ return &suites[i];
+ }
+ /* return NULL and let the caller handle it. */
+ PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
+ return NULL;
+}
+
+
+/* Initialize the suite->isPresent value for config_match
+ * Returns count of enabled ciphers supported by extant tokens,
+ * regardless of policy or user preference.
+ * If this returns zero, the user cannot do SSL v3.
+ */
+int
+ssl3_config_match_init(sslSocket *ss)
+{
+ ssl3CipherSuiteCfg * suite;
+ const ssl3CipherSuiteDef *cipher_def;
+ SSLCipherAlgorithm cipher_alg;
+ CK_MECHANISM_TYPE cipher_mech;
+ SSL3KEAType exchKeyType;
+ int i;
+ int numPresent = 0;
+ int numEnabled = 0;
+ PRBool isServer;
+ sslServerCerts *svrAuth;
+
+ PORT_Assert(ss);
+ if (!ss) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return 0;
+ }
+ if (SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
+ return 0;
+ }
+ isServer = (PRBool)(ss->sec.isServer != 0);
+
+ for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
+ suite = &ss->cipherSuites[i];
+ if (suite->enabled) {
+ ++numEnabled;
+ /* We need the cipher defs to see if we have a token that can handle
+ * this cipher. It isn't part of the static definition.
+ */
+ cipher_def = ssl_LookupCipherSuiteDef(suite->cipher_suite);
+ if (!cipher_def) {
+ suite->isPresent = PR_FALSE;
+ continue;
+ }
+ cipher_alg = bulk_cipher_defs[cipher_def->bulk_cipher_alg].calg;
+ PORT_Assert( alg2Mech[cipher_alg].calg == cipher_alg);
+ cipher_mech = alg2Mech[cipher_alg].cmech;
+ exchKeyType =
+ kea_defs[cipher_def->key_exchange_alg].exchKeyType;
+#ifndef NSS_ENABLE_ECC
+ svrAuth = ss->serverCerts + exchKeyType;
+#else
+ /* XXX SSLKEAType isn't really a good choice for
+ * indexing certificates. It doesn't work for
+ * (EC)DHE-* ciphers. Here we use a hack to ensure
+ * that the server uses an RSA cert for (EC)DHE-RSA.
+ */
+ switch (cipher_def->key_exchange_alg) {
+ case kea_ecdhe_rsa:
+#if NSS_SERVER_DHE_IMPLEMENTED
+ /* XXX NSS does not yet implement the server side of _DHE_
+ * cipher suites. Correcting the computation for svrAuth,
+ * as the case below does, causes NSS SSL servers to begin to
+ * negotiate cipher suites they do not implement. So, until
+ * server side _DHE_ is implemented, keep this disabled.
+ */
+ case kea_dhe_rsa:
+#endif
+ svrAuth = ss->serverCerts + kt_rsa;
+ break;
+ case kea_ecdh_ecdsa:
+ case kea_ecdh_rsa:
+ /*
+ * XXX We ought to have different indices for
+ * ECDSA- and RSA-signed EC certificates so
+ * we could support both key exchange mechanisms
+ * simultaneously. For now, both of them use
+ * whatever is in the certificate slot for kt_ecdh
+ */
+ default:
+ svrAuth = ss->serverCerts + exchKeyType;
+ break;
+ }
+#endif /* NSS_ENABLE_ECC */
+
+ /* Mark the suites that are backed by real tokens, certs and keys */
+ suite->isPresent = (PRBool)
+ (((exchKeyType == kt_null) ||
+ ((!isServer || (svrAuth->serverKeyPair &&
+ svrAuth->SERVERKEY &&
+ svrAuth->serverCertChain)) &&
+ PK11_TokenExists(kea_alg_defs[exchKeyType]))) &&
+ ((cipher_alg == calg_null) || PK11_TokenExists(cipher_mech)));
+ if (suite->isPresent)
+ ++numPresent;
+ }
+ }
+ PORT_Assert(numPresent > 0 || numEnabled == 0);
+ if (numPresent <= 0) {
+ PORT_SetError(SSL_ERROR_NO_CIPHERS_SUPPORTED);
+ }
+ return numPresent;
+}
+
+
+/* return PR_TRUE if suite matches policy and enabled state */
+/* It would be a REALLY BAD THING (tm) if we ever permitted the use
+** of a cipher that was NOT_ALLOWED. So, if this is ever called with
+** policy == SSL_NOT_ALLOWED, report no match.
+*/
+/* adjust suite enabled to the availability of a token that can do the
+ * cipher suite. */
+static PRBool
+config_match(ssl3CipherSuiteCfg *suite, int policy, PRBool enabled)
+{
+ PORT_Assert(policy != SSL_NOT_ALLOWED && enabled != PR_FALSE);
+ if (policy == SSL_NOT_ALLOWED || !enabled)
+ return PR_FALSE;
+ return (PRBool)(suite->enabled &&
+ suite->isPresent &&
+ suite->policy != SSL_NOT_ALLOWED &&
+ suite->policy <= policy);
+}
+
+/* return number of cipher suites that match policy and enabled state */
+/* called from ssl3_SendClientHello and ssl3_ConstructV2CipherSpecsHack */
+static int
+count_cipher_suites(sslSocket *ss, int policy, PRBool enabled)
+{
+ int i, count = 0;
+
+ if (SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
+ return 0;
+ }
+ for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
+ if (config_match(&ss->cipherSuites[i], policy, enabled))
+ count++;
+ }
+ if (count <= 0) {
+ PORT_SetError(SSL_ERROR_SSL_DISABLED);
+ }
+ return count;
+}
+
+/*
+ * Null compression, mac and encryption functions
+ */
+
+static SECStatus
+Null_Cipher(void *ctx, unsigned char *output, int *outputLen, int maxOutputLen,
+ const unsigned char *input, int inputLen)
+{
+ *outputLen = inputLen;
+ if (input != output)
+ PORT_Memcpy(output, input, inputLen);
+ return SECSuccess;
+}
+
+/*
+ * SSL3 Utility functions
+ */
+
+/* allowLargerPeerVersion controls whether the function will select the
+ * highest enabled SSL version or fail when peerVersion is greater than the
+ * highest enabled version.
+ *
+ * If allowLargerPeerVersion is true, peerVersion is the peer's highest
+ * enabled version rather than the peer's selected version.
+ */
+SECStatus
+ssl3_NegotiateVersion(sslSocket *ss, SSL3ProtocolVersion peerVersion,
+ PRBool allowLargerPeerVersion)
+{
+ if (SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
+ PORT_SetError(SSL_ERROR_SSL_DISABLED);
+ return SECFailure;
+ }
+
+ if (peerVersion < ss->vrange.min ||
+ (peerVersion > ss->vrange.max && !allowLargerPeerVersion)) {
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+ return SECFailure;
+ }
+
+ ss->version = PR_MIN(peerVersion, ss->vrange.max);
+ PORT_Assert(ssl3_VersionIsSupported(ss->protocolVariant, ss->version));
+
+ return SECSuccess;
+}
+
+static SECStatus
+ssl3_GetNewRandom(SSL3Random *random)
+{
+ PRUint32 gmt = ssl_Time();
+ SECStatus rv;
+
+ random->rand[0] = (unsigned char)(gmt >> 24);
+ random->rand[1] = (unsigned char)(gmt >> 16);
+ random->rand[2] = (unsigned char)(gmt >> 8);
+ random->rand[3] = (unsigned char)(gmt);
+
+ /* first 4 bytes are reserverd for time */
+ rv = PK11_GenerateRandom(&random->rand[4], SSL3_RANDOM_LENGTH - 4);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE);
+ }
+ return rv;
+}
+
+/* Called by ssl3_SendServerKeyExchange and ssl3_SendCertificateVerify */
+SECStatus
+ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf,
+ PRBool isTLS)
+{
+ SECStatus rv = SECFailure;
+ PRBool doDerEncode = PR_FALSE;
+ int signatureLen;
+ SECItem hashItem;
+
+ buf->data = NULL;
+
+ switch (key->keyType) {
+ case rsaKey:
+ hashItem.data = hash->u.raw;
+ hashItem.len = hash->len;
+ break;
+ case dsaKey:
+ doDerEncode = isTLS;
+ /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash.
+ * In that case, we use just the SHA1 part. */
+ if (hash->hashAlg == SEC_OID_UNKNOWN) {
+ hashItem.data = hash->u.s.sha;
+ hashItem.len = sizeof(hash->u.s.sha);
+ } else {
+ hashItem.data = hash->u.raw;
+ hashItem.len = hash->len;
+ }
+ break;
+#ifdef NSS_ENABLE_ECC
+ case ecKey:
+ doDerEncode = PR_TRUE;
+ /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash.
+ * In that case, we use just the SHA1 part. */
+ if (hash->hashAlg == SEC_OID_UNKNOWN) {
+ hashItem.data = hash->u.s.sha;
+ hashItem.len = sizeof(hash->u.s.sha);
+ } else {
+ hashItem.data = hash->u.raw;
+ hashItem.len = hash->len;
+ }
+ break;
+#endif /* NSS_ENABLE_ECC */
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ goto done;
+ }
+ PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len));
+
+ if (hash->hashAlg == SEC_OID_UNKNOWN) {
+ signatureLen = PK11_SignatureLen(key);
+ if (signatureLen <= 0) {
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ goto done;
+ }
+
+ buf->len = (unsigned)signatureLen;
+ buf->data = (unsigned char *)PORT_Alloc(signatureLen);
+ if (!buf->data)
+ goto done; /* error code was set. */
+
+ rv = PK11_Sign(key, buf, &hashItem);
+ } else {
+ rv = SGN_Digest(key, hash->hashAlg, buf, &hashItem);
+ }
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
+ } else if (doDerEncode) {
+ SECItem derSig = {siBuffer, NULL, 0};
+
+ /* This also works for an ECDSA signature */
+ rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len);
+ if (rv == SECSuccess) {
+ PORT_Free(buf->data); /* discard unencoded signature. */
+ *buf = derSig; /* give caller encoded signature. */
+ } else if (derSig.data) {
+ PORT_Free(derSig.data);
+ }
+ }
+
+ PRINT_BUF(60, (NULL, "signed hashes", (unsigned char*)buf->data, buf->len));
+done:
+ if (rv != SECSuccess && buf->data) {
+ PORT_Free(buf->data);
+ buf->data = NULL;
+ }
+ return rv;
+}
+
+/* Called from ssl3_HandleServerKeyExchange, ssl3_HandleCertificateVerify */
+SECStatus
+ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert,
+ SECItem *buf, PRBool isTLS, void *pwArg)
+{
+ SECKEYPublicKey * key;
+ SECItem * signature = NULL;
+ SECStatus rv;
+ SECItem hashItem;
+ SECOidTag encAlg;
+ SECOidTag hashAlg;
+
+
+ PRINT_BUF(60, (NULL, "check signed hashes",
+ buf->data, buf->len));
+
+ key = CERT_ExtractPublicKey(cert);
+ if (key == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
+ return SECFailure;
+ }
+
+ hashAlg = hash->hashAlg;
+ switch (key->keyType) {
+ case rsaKey:
+ encAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
+ hashItem.data = hash->u.raw;
+ hashItem.len = hash->len;
+ break;
+ case dsaKey:
+ encAlg = SEC_OID_ANSIX9_DSA_SIGNATURE;
+ /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash.
+ * In that case, we use just the SHA1 part. */
+ if (hash->hashAlg == SEC_OID_UNKNOWN) {
+ hashItem.data = hash->u.s.sha;
+ hashItem.len = sizeof(hash->u.s.sha);
+ } else {
+ hashItem.data = hash->u.raw;
+ hashItem.len = hash->len;
+ }
+ /* Allow DER encoded DSA signatures in SSL 3.0 */
+ if (isTLS || buf->len != SECKEY_SignatureLen(key)) {
+ signature = DSAU_DecodeDerSig(buf);
+ if (!signature) {
+ PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+ return SECFailure;
+ }
+ buf = signature;
+ }
+ break;
+
+#ifdef NSS_ENABLE_ECC
+ case ecKey:
+ encAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
+ /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash.
+ * In that case, we use just the SHA1 part.
+ * ECDSA signatures always encode the integers r and s using ASN.1
+ * (unlike DSA where ASN.1 encoding is used with TLS but not with
+ * SSL3). So we can use VFY_VerifyDigestDirect for ECDSA.
+ */
+ if (hash->hashAlg == SEC_OID_UNKNOWN) {
+ hashAlg = SEC_OID_SHA1;
+ hashItem.data = hash->u.s.sha;
+ hashItem.len = sizeof(hash->u.s.sha);
+ } else {
+ hashItem.data = hash->u.raw;
+ hashItem.len = hash->len;
+ }
+ break;
+#endif /* NSS_ENABLE_ECC */
+
+ default:
+ SECKEY_DestroyPublicKey(key);
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+ return SECFailure;
+ }
+
+ PRINT_BUF(60, (NULL, "hash(es) to be verified",
+ hashItem.data, hashItem.len));
+
+ if (hashAlg == SEC_OID_UNKNOWN || key->keyType == dsaKey) {
+ /* VFY_VerifyDigestDirect requires DSA signatures to be DER-encoded.
+ * DSA signatures are DER-encoded in TLS but not in SSL3 and the code
+ * above always removes the DER encoding of DSA signatures when
+ * present. Thus DSA signatures are always verified with PK11_Verify.
+ */
+ rv = PK11_Verify(key, buf, &hashItem, pwArg);
+ } else {
+ rv = VFY_VerifyDigestDirect(&hashItem, key, buf, encAlg, hashAlg,
+ pwArg);
+ }
+ SECKEY_DestroyPublicKey(key);
+ if (signature) {
+ SECITEM_FreeItem(signature, PR_TRUE);
+ }
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+ }
+ return rv;
+}
+
+
+/* Caller must set hiLevel error code. */
+/* Called from ssl3_ComputeExportRSAKeyHash
+ * ssl3_ComputeDHKeyHash
+ * which are called from ssl3_HandleServerKeyExchange.
+ *
+ * hashAlg: either the OID for a hash algorithm or SEC_OID_UNKNOWN to specify
+ * the pre-1.2, MD5/SHA1 combination hash.
+ */
+SECStatus
+ssl3_ComputeCommonKeyHash(SECOidTag hashAlg,
+ PRUint8 * hashBuf, unsigned int bufLen,
+ SSL3Hashes *hashes, PRBool bypassPKCS11)
+{
+ SECStatus rv = SECSuccess;
+
+#ifndef NO_PKCS11_BYPASS
+ if (bypassPKCS11) {
+ if (hashAlg == SEC_OID_UNKNOWN) {
+ MD5_HashBuf (hashes->u.s.md5, hashBuf, bufLen);
+ SHA1_HashBuf(hashes->u.s.sha, hashBuf, bufLen);
+ hashes->len = MD5_LENGTH + SHA1_LENGTH;
+ } else if (hashAlg == SEC_OID_SHA1) {
+ SHA1_HashBuf(hashes->u.raw, hashBuf, bufLen);
+ hashes->len = SHA1_LENGTH;
+ } else if (hashAlg == SEC_OID_SHA256) {
+ SHA256_HashBuf(hashes->u.raw, hashBuf, bufLen);
+ hashes->len = SHA256_LENGTH;
+ } else if (hashAlg == SEC_OID_SHA384) {
+ SHA384_HashBuf(hashes->u.raw, hashBuf, bufLen);
+ hashes->len = SHA384_LENGTH;
+ } else if (hashAlg == SEC_OID_SHA512) {
+ SHA512_HashBuf(hashes->u.raw, hashBuf, bufLen);
+ hashes->len = SHA512_LENGTH;
+ } else {
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
+ return SECFailure;
+ }
+ } else
+#endif
+ {
+ if (hashAlg == SEC_OID_UNKNOWN) {
+ rv = PK11_HashBuf(SEC_OID_MD5, hashes->u.s.md5, hashBuf, bufLen);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
+ rv = SECFailure;
+ goto done;
+ }
+
+ rv = PK11_HashBuf(SEC_OID_SHA1, hashes->u.s.sha, hashBuf, bufLen);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ rv = SECFailure;
+ }
+ hashes->len = MD5_LENGTH + SHA1_LENGTH;
+ } else {
+ hashes->len = HASH_ResultLenByOidTag(hashAlg);
+ if (hashes->len > sizeof(hashes->u.raw)) {
+ ssl_MapLowLevelError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
+ rv = SECFailure;
+ goto done;
+ }
+ rv = PK11_HashBuf(hashAlg, hashes->u.raw, hashBuf, bufLen);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+ rv = SECFailure;
+ }
+ }
+ }
+ hashes->hashAlg = hashAlg;
+
+done:
+ return rv;
+}
+
+/* Caller must set hiLevel error code.
+** Called from ssl3_SendServerKeyExchange and
+** ssl3_HandleServerKeyExchange.
+*/
+static SECStatus
+ssl3_ComputeExportRSAKeyHash(SECOidTag hashAlg,
+ SECItem modulus, SECItem publicExponent,
+ SSL3Random *client_rand, SSL3Random *server_rand,
+ SSL3Hashes *hashes, PRBool bypassPKCS11)
+{
+ PRUint8 * hashBuf;
+ PRUint8 * pBuf;
+ SECStatus rv = SECSuccess;
+ unsigned int bufLen;
+ PRUint8 buf[2*SSL3_RANDOM_LENGTH + 2 + 4096/8 + 2 + 4096/8];
+
+ bufLen = 2*SSL3_RANDOM_LENGTH + 2 + modulus.len + 2 + publicExponent.len;
+ if (bufLen <= sizeof buf) {
+ hashBuf = buf;
+ } else {
+ hashBuf = PORT_Alloc(bufLen);
+ if (!hashBuf) {
+ return SECFailure;
+ }
+ }
+
+ memcpy(hashBuf, client_rand, SSL3_RANDOM_LENGTH);
+ pBuf = hashBuf + SSL3_RANDOM_LENGTH;
+ memcpy(pBuf, server_rand, SSL3_RANDOM_LENGTH);
+ pBuf += SSL3_RANDOM_LENGTH;
+ pBuf[0] = (PRUint8)(modulus.len >> 8);
+ pBuf[1] = (PRUint8)(modulus.len);
+ pBuf += 2;
+ memcpy(pBuf, modulus.data, modulus.len);
+ pBuf += modulus.len;
+ pBuf[0] = (PRUint8)(publicExponent.len >> 8);
+ pBuf[1] = (PRUint8)(publicExponent.len);
+ pBuf += 2;
+ memcpy(pBuf, publicExponent.data, publicExponent.len);
+ pBuf += publicExponent.len;
+ PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen);
+
+ rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes,
+ bypassPKCS11);
+
+ PRINT_BUF(95, (NULL, "RSAkey hash: ", hashBuf, bufLen));
+ if (hashAlg == SEC_OID_UNKNOWN) {
+ PRINT_BUF(95, (NULL, "RSAkey hash: MD5 result",
+ hashes->u.s.md5, MD5_LENGTH));
+ PRINT_BUF(95, (NULL, "RSAkey hash: SHA1 result",
+ hashes->u.s.sha, SHA1_LENGTH));
+ } else {
+ PRINT_BUF(95, (NULL, "RSAkey hash: result",
+ hashes->u.raw, hashes->len));
+ }
+
+ if (hashBuf != buf && hashBuf != NULL)
+ PORT_Free(hashBuf);
+ return rv;
+}
+
+/* Caller must set hiLevel error code. */
+/* Called from ssl3_HandleServerKeyExchange. */
+static SECStatus
+ssl3_ComputeDHKeyHash(SECOidTag hashAlg,
+ SECItem dh_p, SECItem dh_g, SECItem dh_Ys,
+ SSL3Random *client_rand, SSL3Random *server_rand,
+ SSL3Hashes *hashes, PRBool bypassPKCS11)
+{
+ PRUint8 * hashBuf;
+ PRUint8 * pBuf;
+ SECStatus rv = SECSuccess;
+ unsigned int bufLen;
+ PRUint8 buf[2*SSL3_RANDOM_LENGTH + 2 + 4096/8 + 2 + 4096/8];
+
+ bufLen = 2*SSL3_RANDOM_LENGTH + 2 + dh_p.len + 2 + dh_g.len + 2 + dh_Ys.len;
+ if (bufLen <= sizeof buf) {
+ hashBuf = buf;
+ } else {
+ hashBuf = PORT_Alloc(bufLen);
+ if (!hashBuf) {
+ return SECFailure;
+ }
+ }
+
+ memcpy(hashBuf, client_rand, SSL3_RANDOM_LENGTH);
+ pBuf = hashBuf + SSL3_RANDOM_LENGTH;
+ memcpy(pBuf, server_rand, SSL3_RANDOM_LENGTH);
+ pBuf += SSL3_RANDOM_LENGTH;
+ pBuf[0] = (PRUint8)(dh_p.len >> 8);
+ pBuf[1] = (PRUint8)(dh_p.len);
+ pBuf += 2;
+ memcpy(pBuf, dh_p.data, dh_p.len);
+ pBuf += dh_p.len;
+ pBuf[0] = (PRUint8)(dh_g.len >> 8);
+ pBuf[1] = (PRUint8)(dh_g.len);
+ pBuf += 2;
+ memcpy(pBuf, dh_g.data, dh_g.len);
+ pBuf += dh_g.len;
+ pBuf[0] = (PRUint8)(dh_Ys.len >> 8);
+ pBuf[1] = (PRUint8)(dh_Ys.len);
+ pBuf += 2;
+ memcpy(pBuf, dh_Ys.data, dh_Ys.len);
+ pBuf += dh_Ys.len;
+ PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen);
+
+ rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes,
+ bypassPKCS11);
+
+ PRINT_BUF(95, (NULL, "DHkey hash: ", hashBuf, bufLen));
+ if (hashAlg == SEC_OID_UNKNOWN) {
+ PRINT_BUF(95, (NULL, "DHkey hash: MD5 result",
+ hashes->u.s.md5, MD5_LENGTH));
+ PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result",
+ hashes->u.s.sha, SHA1_LENGTH));
+ } else {
+ PRINT_BUF(95, (NULL, "DHkey hash: result",
+ hashes->u.raw, hashes->len));
+ }
+
+ if (hashBuf != buf && hashBuf != NULL)
+ PORT_Free(hashBuf);
+ return rv;
+}
+
+static void
+ssl3_BumpSequenceNumber(SSL3SequenceNumber *num)
+{
+ num->low++;
+ if (num->low == 0)
+ num->high++;
+}
+
+/* Called twice, only from ssl3_DestroyCipherSpec (immediately below). */
+static void
+ssl3_CleanupKeyMaterial(ssl3KeyMaterial *mat)
+{
+ if (mat->write_key != NULL) {
+ PK11_FreeSymKey(mat->write_key);
+ mat->write_key = NULL;
+ }
+ if (mat->write_mac_key != NULL) {
+ PK11_FreeSymKey(mat->write_mac_key);
+ mat->write_mac_key = NULL;
+ }
+ if (mat->write_mac_context != NULL) {
+ PK11_DestroyContext(mat->write_mac_context, PR_TRUE);
+ mat->write_mac_context = NULL;
+ }
+}
+
+/* Called from ssl3_SendChangeCipherSpecs() and
+** ssl3_HandleChangeCipherSpecs()
+** ssl3_DestroySSL3Info
+** Caller must hold SpecWriteLock.
+*/
+void
+ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName)
+{
+ PRBool freeit = (PRBool)(!spec->bypassCiphers);
+/* PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); Don't have ss! */
+ if (spec->destroy) {
+ spec->destroy(spec->encodeContext, freeit);
+ spec->destroy(spec->decodeContext, freeit);
+ spec->encodeContext = NULL; /* paranoia */
+ spec->decodeContext = NULL;
+ }
+ if (spec->destroyCompressContext && spec->compressContext) {
+ spec->destroyCompressContext(spec->compressContext, 1);
+ spec->compressContext = NULL;
+ }
+ if (spec->destroyDecompressContext && spec->decompressContext) {
+ spec->destroyDecompressContext(spec->decompressContext, 1);
+ spec->decompressContext = NULL;
+ }
+ if (freeSrvName && spec->srvVirtName.data) {
+ SECITEM_FreeItem(&spec->srvVirtName, PR_FALSE);
+ }
+ if (spec->master_secret != NULL) {
+ PK11_FreeSymKey(spec->master_secret);
+ spec->master_secret = NULL;
+ }
+ spec->msItem.data = NULL;
+ spec->msItem.len = 0;
+ ssl3_CleanupKeyMaterial(&spec->client);
+ ssl3_CleanupKeyMaterial(&spec->server);
+ spec->bypassCiphers = PR_FALSE;
+ spec->destroy=NULL;
+ spec->destroyCompressContext = NULL;
+ spec->destroyDecompressContext = NULL;
+}
+
+/* Fill in the pending cipher spec with info from the selected ciphersuite.
+** This is as much initialization as we can do without having key material.
+** Called from ssl3_HandleServerHello(), ssl3_SendServerHello()
+** Caller must hold the ssl3 handshake lock.
+** Acquires & releases SpecWriteLock.
+*/
+static SECStatus
+ssl3_SetupPendingCipherSpec(sslSocket *ss)
+{
+ ssl3CipherSpec * pwSpec;
+ ssl3CipherSpec * cwSpec;
+ ssl3CipherSuite suite = ss->ssl3.hs.cipher_suite;
+ SSL3MACAlgorithm mac;
+ SSL3BulkCipher cipher;
+ SSL3KeyExchangeAlgorithm kea;
+ const ssl3CipherSuiteDef *suite_def;
+ PRBool isTLS;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ ssl_GetSpecWriteLock(ss); /*******************************/
+
+ pwSpec = ss->ssl3.pwSpec;
+ PORT_Assert(pwSpec == ss->ssl3.prSpec);
+
+ /* This hack provides maximal interoperability with SSL 3 servers. */
+ cwSpec = ss->ssl3.cwSpec;
+ if (cwSpec->mac_def->mac == mac_null) {
+ /* SSL records are not being MACed. */
+ cwSpec->version = ss->version;
+ }
+
+ pwSpec->version = ss->version;
+ isTLS = (PRBool)(pwSpec->version > SSL_LIBRARY_VERSION_3_0);
+
+ SSL_TRC(3, ("%d: SSL3[%d]: Set XXX Pending Cipher Suite to 0x%04x",
+ SSL_GETPID(), ss->fd, suite));
+
+ suite_def = ssl_LookupCipherSuiteDef(suite);
+ if (suite_def == NULL) {
+ ssl_ReleaseSpecWriteLock(ss);
+ return SECFailure; /* error code set by ssl_LookupCipherSuiteDef */
+ }
+
+ if (IS_DTLS(ss)) {
+ /* Double-check that we did not pick an RC4 suite */
+ PORT_Assert((suite_def->bulk_cipher_alg != cipher_rc4) &&
+ (suite_def->bulk_cipher_alg != cipher_rc4_40) &&
+ (suite_def->bulk_cipher_alg != cipher_rc4_56));
+ }
+
+ cipher = suite_def->bulk_cipher_alg;
+ kea = suite_def->key_exchange_alg;
+ mac = suite_def->mac_alg;
+ if (mac <= ssl_mac_sha && mac != ssl_mac_null && isTLS)
+ mac += 2;
+
+ ss->ssl3.hs.suite_def = suite_def;
+ ss->ssl3.hs.kea_def = &kea_defs[kea];
+ PORT_Assert(ss->ssl3.hs.kea_def->kea == kea);
+
+ pwSpec->cipher_def = &bulk_cipher_defs[cipher];
+ PORT_Assert(pwSpec->cipher_def->cipher == cipher);
+
+ pwSpec->mac_def = &mac_defs[mac];
+ PORT_Assert(pwSpec->mac_def->mac == mac);
+
+ ss->sec.keyBits = pwSpec->cipher_def->key_size * BPB;
+ ss->sec.secretKeyBits = pwSpec->cipher_def->secret_key_size * BPB;
+ ss->sec.cipherType = cipher;
+
+ pwSpec->encodeContext = NULL;
+ pwSpec->decodeContext = NULL;
+
+ pwSpec->mac_size = pwSpec->mac_def->mac_size;
+
+ pwSpec->compression_method = ss->ssl3.hs.compression;
+ pwSpec->compressContext = NULL;
+ pwSpec->decompressContext = NULL;
+
+ ssl_ReleaseSpecWriteLock(ss); /*******************************/
+ return SECSuccess;
+}
+
+#ifdef NSS_ENABLE_ZLIB
+#define SSL3_DEFLATE_CONTEXT_SIZE sizeof(z_stream)
+
+static SECStatus
+ssl3_MapZlibError(int zlib_error)
+{
+ switch (zlib_error) {
+ case Z_OK:
+ return SECSuccess;
+ default:
+ return SECFailure;
+ }
+}
+
+static SECStatus
+ssl3_DeflateInit(void *void_context)
+{
+ z_stream *context = void_context;
+ context->zalloc = NULL;
+ context->zfree = NULL;
+ context->opaque = NULL;
+
+ return ssl3_MapZlibError(deflateInit(context, Z_DEFAULT_COMPRESSION));
+}
+
+static SECStatus
+ssl3_InflateInit(void *void_context)
+{
+ z_stream *context = void_context;
+ context->zalloc = NULL;
+ context->zfree = NULL;
+ context->opaque = NULL;
+ context->next_in = NULL;
+ context->avail_in = 0;
+
+ return ssl3_MapZlibError(inflateInit(context));
+}
+
+static SECStatus
+ssl3_DeflateCompress(void *void_context, unsigned char *out, int *out_len,
+ int maxout, const unsigned char *in, int inlen)
+{
+ z_stream *context = void_context;
+
+ if (!inlen) {
+ *out_len = 0;
+ return SECSuccess;
+ }
+
+ context->next_in = (unsigned char*) in;
+ context->avail_in = inlen;
+ context->next_out = out;
+ context->avail_out = maxout;
+ if (deflate(context, Z_SYNC_FLUSH) != Z_OK) {
+ return SECFailure;
+ }
+ if (context->avail_out == 0) {
+ /* We ran out of space! */
+ SSL_TRC(3, ("%d: SSL3[%d] Ran out of buffer while compressing",
+ SSL_GETPID()));
+ return SECFailure;
+ }
+
+ *out_len = maxout - context->avail_out;
+ return SECSuccess;
+}
+
+static SECStatus
+ssl3_DeflateDecompress(void *void_context, unsigned char *out, int *out_len,
+ int maxout, const unsigned char *in, int inlen)
+{
+ z_stream *context = void_context;
+
+ if (!inlen) {
+ *out_len = 0;
+ return SECSuccess;
+ }
+
+ context->next_in = (unsigned char*) in;
+ context->avail_in = inlen;
+ context->next_out = out;
+ context->avail_out = maxout;
+ if (inflate(context, Z_SYNC_FLUSH) != Z_OK) {
+ PORT_SetError(SSL_ERROR_DECOMPRESSION_FAILURE);
+ return SECFailure;
+ }
+
+ *out_len = maxout - context->avail_out;
+ return SECSuccess;
+}
+
+static SECStatus
+ssl3_DestroyCompressContext(void *void_context, PRBool unused)
+{
+ deflateEnd(void_context);
+ PORT_Free(void_context);
+ return SECSuccess;
+}
+
+static SECStatus
+ssl3_DestroyDecompressContext(void *void_context, PRBool unused)
+{
+ inflateEnd(void_context);
+ PORT_Free(void_context);
+ return SECSuccess;
+}
+
+#endif /* NSS_ENABLE_ZLIB */
+
+/* Initialize the compression functions and contexts for the given
+ * CipherSpec. */
+static SECStatus
+ssl3_InitCompressionContext(ssl3CipherSpec *pwSpec)
+{
+ /* Setup the compression functions */
+ switch (pwSpec->compression_method) {
+ case ssl_compression_null:
+ pwSpec->compressor = NULL;
+ pwSpec->decompressor = NULL;
+ pwSpec->compressContext = NULL;
+ pwSpec->decompressContext = NULL;
+ pwSpec->destroyCompressContext = NULL;
+ pwSpec->destroyDecompressContext = NULL;
+ break;
+#ifdef NSS_ENABLE_ZLIB
+ case ssl_compression_deflate:
+ pwSpec->compressor = ssl3_DeflateCompress;
+ pwSpec->decompressor = ssl3_DeflateDecompress;
+ pwSpec->compressContext = PORT_Alloc(SSL3_DEFLATE_CONTEXT_SIZE);
+ pwSpec->decompressContext = PORT_Alloc(SSL3_DEFLATE_CONTEXT_SIZE);
+ pwSpec->destroyCompressContext = ssl3_DestroyCompressContext;
+ pwSpec->destroyDecompressContext = ssl3_DestroyDecompressContext;
+ ssl3_DeflateInit(pwSpec->compressContext);
+ ssl3_InflateInit(pwSpec->decompressContext);
+ break;
+#endif /* NSS_ENABLE_ZLIB */
+ default:
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+#ifndef NO_PKCS11_BYPASS
+/* Initialize encryption contexts for pending spec.
+ * MAC contexts are set up when computing the mac, not here.
+ * Master Secret already is derived in spec->msItem
+ * Caller holds Spec write lock.
+ */
+static SECStatus
+ssl3_InitPendingContextsBypass(sslSocket *ss)
+{
+ ssl3CipherSpec * pwSpec;
+ const ssl3BulkCipherDef *cipher_def;
+ void * serverContext = NULL;
+ void * clientContext = NULL;
+ BLapiInitContextFunc initFn = (BLapiInitContextFunc)NULL;
+ int mode = 0;
+ unsigned int optArg1 = 0;
+ unsigned int optArg2 = 0;
+ PRBool server_encrypts = ss->sec.isServer;
+ SSLCipherAlgorithm calg;
+ SECStatus rv;
+
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
+ PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
+
+ pwSpec = ss->ssl3.pwSpec;
+ cipher_def = pwSpec->cipher_def;
+
+ calg = cipher_def->calg;
+
+ if (calg == calg_aes_gcm) {
+ pwSpec->encode = NULL;
+ pwSpec->decode = NULL;
+ pwSpec->destroy = NULL;
+ pwSpec->encodeContext = NULL;
+ pwSpec->decodeContext = NULL;
+ pwSpec->aead = ssl3_AESGCMBypass;
+ ssl3_InitCompressionContext(pwSpec);
+ return SECSuccess;
+ }
+
+ serverContext = pwSpec->server.cipher_context;
+ clientContext = pwSpec->client.cipher_context;
+
+ switch (calg) {
+ case ssl_calg_null:
+ pwSpec->encode = Null_Cipher;
+ pwSpec->decode = Null_Cipher;
+ pwSpec->destroy = NULL;
+ goto success;
+
+ case ssl_calg_rc4:
+ initFn = (BLapiInitContextFunc)RC4_InitContext;
+ pwSpec->encode = (SSLCipher) RC4_Encrypt;
+ pwSpec->decode = (SSLCipher) RC4_Decrypt;
+ pwSpec->destroy = (SSLDestroy) RC4_DestroyContext;
+ break;
+ case ssl_calg_rc2:
+ initFn = (BLapiInitContextFunc)RC2_InitContext;
+ mode = NSS_RC2_CBC;
+ optArg1 = cipher_def->key_size;
+ pwSpec->encode = (SSLCipher) RC2_Encrypt;
+ pwSpec->decode = (SSLCipher) RC2_Decrypt;
+ pwSpec->destroy = (SSLDestroy) RC2_DestroyContext;
+ break;
+ case ssl_calg_des:
+ initFn = (BLapiInitContextFunc)DES_InitContext;
+ mode = NSS_DES_CBC;
+ optArg1 = server_encrypts;
+ pwSpec->encode = (SSLCipher) DES_Encrypt;
+ pwSpec->decode = (SSLCipher) DES_Decrypt;
+ pwSpec->destroy = (SSLDestroy) DES_DestroyContext;
+ break;
+ case ssl_calg_3des:
+ initFn = (BLapiInitContextFunc)DES_InitContext;
+ mode = NSS_DES_EDE3_CBC;
+ optArg1 = server_encrypts;
+ pwSpec->encode = (SSLCipher) DES_Encrypt;
+ pwSpec->decode = (SSLCipher) DES_Decrypt;
+ pwSpec->destroy = (SSLDestroy) DES_DestroyContext;
+ break;
+ case ssl_calg_aes:
+ initFn = (BLapiInitContextFunc)AES_InitContext;
+ mode = NSS_AES_CBC;
+ optArg1 = server_encrypts;
+ optArg2 = AES_BLOCK_SIZE;
+ pwSpec->encode = (SSLCipher) AES_Encrypt;
+ pwSpec->decode = (SSLCipher) AES_Decrypt;
+ pwSpec->destroy = (SSLDestroy) AES_DestroyContext;
+ break;
+
+ case ssl_calg_camellia:
+ initFn = (BLapiInitContextFunc)Camellia_InitContext;
+ mode = NSS_CAMELLIA_CBC;
+ optArg1 = server_encrypts;
+ optArg2 = CAMELLIA_BLOCK_SIZE;
+ pwSpec->encode = (SSLCipher) Camellia_Encrypt;
+ pwSpec->decode = (SSLCipher) Camellia_Decrypt;
+ pwSpec->destroy = (SSLDestroy) Camellia_DestroyContext;
+ break;
+
+ case ssl_calg_seed:
+ initFn = (BLapiInitContextFunc)SEED_InitContext;
+ mode = NSS_SEED_CBC;
+ optArg1 = server_encrypts;
+ optArg2 = SEED_BLOCK_SIZE;
+ pwSpec->encode = (SSLCipher) SEED_Encrypt;
+ pwSpec->decode = (SSLCipher) SEED_Decrypt;
+ pwSpec->destroy = (SSLDestroy) SEED_DestroyContext;
+ break;
+
+ case ssl_calg_idea:
+ case ssl_calg_fortezza :
+ default:
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ goto bail_out;
+ }
+ rv = (*initFn)(serverContext,
+ pwSpec->server.write_key_item.data,
+ pwSpec->server.write_key_item.len,
+ pwSpec->server.write_iv_item.data,
+ mode, optArg1, optArg2);
+ if (rv != SECSuccess) {
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ goto bail_out;
+ }
+
+ switch (calg) {
+ case ssl_calg_des:
+ case ssl_calg_3des:
+ case ssl_calg_aes:
+ case ssl_calg_camellia:
+ case ssl_calg_seed:
+ /* For block ciphers, if the server is encrypting, then the client
+ * is decrypting, and vice versa.
+ */
+ optArg1 = !optArg1;
+ break;
+ /* kill warnings. */
+ case ssl_calg_null:
+ case ssl_calg_rc4:
+ case ssl_calg_rc2:
+ case ssl_calg_idea:
+ case ssl_calg_fortezza:
+ break;
+ }
+
+ rv = (*initFn)(clientContext,
+ pwSpec->client.write_key_item.data,
+ pwSpec->client.write_key_item.len,
+ pwSpec->client.write_iv_item.data,
+ mode, optArg1, optArg2);
+ if (rv != SECSuccess) {
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ goto bail_out;
+ }
+
+ pwSpec->encodeContext = (ss->sec.isServer) ? serverContext : clientContext;
+ pwSpec->decodeContext = (ss->sec.isServer) ? clientContext : serverContext;
+
+ ssl3_InitCompressionContext(pwSpec);
+
+success:
+ return SECSuccess;
+
+bail_out:
+ return SECFailure;
+}
+#endif
+
+/* This function should probably be moved to pk11wrap and be named
+ * PK11_ParamFromIVAndEffectiveKeyBits
+ */
+static SECItem *
+ssl3_ParamFromIV(CK_MECHANISM_TYPE mtype, SECItem *iv, CK_ULONG ulEffectiveBits)
+{
+ SECItem * param = PK11_ParamFromIV(mtype, iv);
+ if (param && param->data && param->len >= sizeof(CK_RC2_PARAMS)) {
+ switch (mtype) {
+ case CKM_RC2_KEY_GEN:
+ case CKM_RC2_ECB:
+ case CKM_RC2_CBC:
+ case CKM_RC2_MAC:
+ case CKM_RC2_MAC_GENERAL:
+ case CKM_RC2_CBC_PAD:
+ *(CK_RC2_PARAMS *)param->data = ulEffectiveBits;
+ default: break;
+ }
+ }
+ return param;
+}
+
+/* ssl3_BuildRecordPseudoHeader writes the TLS pseudo-header (the data which
+ * is included in the MAC) to |out| and returns its length. */
+static unsigned int
+ssl3_BuildRecordPseudoHeader(unsigned char *out,
+ SSL3SequenceNumber seq_num,
+ SSL3ContentType type,
+ PRBool includesVersion,
+ SSL3ProtocolVersion version,
+ PRBool isDTLS,
+ int length)
+{
+ out[0] = (unsigned char)(seq_num.high >> 24);
+ out[1] = (unsigned char)(seq_num.high >> 16);
+ out[2] = (unsigned char)(seq_num.high >> 8);
+ out[3] = (unsigned char)(seq_num.high >> 0);
+ out[4] = (unsigned char)(seq_num.low >> 24);
+ out[5] = (unsigned char)(seq_num.low >> 16);
+ out[6] = (unsigned char)(seq_num.low >> 8);
+ out[7] = (unsigned char)(seq_num.low >> 0);
+ out[8] = type;
+
+ /* SSL3 MAC doesn't include the record's version field. */
+ if (!includesVersion) {
+ out[9] = MSB(length);
+ out[10] = LSB(length);
+ return 11;
+ }
+
+ /* TLS MAC and AEAD additional data include version. */
+ if (isDTLS) {
+ SSL3ProtocolVersion dtls_version;
+
+ dtls_version = dtls_TLSVersionToDTLSVersion(version);
+ out[9] = MSB(dtls_version);
+ out[10] = LSB(dtls_version);
+ } else {
+ out[9] = MSB(version);
+ out[10] = LSB(version);
+ }
+ out[11] = MSB(length);
+ out[12] = LSB(length);
+ return 13;
+}
+
+typedef SECStatus (*PK11CryptFcn)(
+ PK11SymKey *symKey, CK_MECHANISM_TYPE mechanism, SECItem *param,
+ unsigned char *out, unsigned int *outLen, unsigned int maxLen,
+ const unsigned char *in, unsigned int inLen);
+
+static PK11CryptFcn pk11_encrypt = NULL;
+static PK11CryptFcn pk11_decrypt = NULL;
+
+static PRCallOnceType resolvePK11CryptOnce;
+
+static PRStatus
+ssl3_ResolvePK11CryptFunctions(void)
+{
+#ifdef LINUX
+ /* On Linux we use the system NSS libraries. Look up the PK11_Encrypt and
+ * PK11_Decrypt functions at run time. */
+ void *handle = dlopen(NULL, RTLD_LAZY);
+ if (!handle) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return PR_FAILURE;
+ }
+ pk11_encrypt = (PK11CryptFcn)dlsym(handle, "PK11_Encrypt");
+ pk11_decrypt = (PK11CryptFcn)dlsym(handle, "PK11_Decrypt");
+ dlclose(handle);
+ return PR_SUCCESS;
+#else
+ /* On other platforms we use our own copy of NSS. PK11_Encrypt and
+ * PK11_Decrypt are known to be available. */
+ pk11_encrypt = PK11_Encrypt;
+ pk11_decrypt = PK11_Decrypt;
+ return PR_SUCCESS;
+#endif
+}
+
+/*
+ * In NSS 3.15, PK11_Encrypt and PK11_Decrypt were added to provide access
+ * to the AES GCM implementation in the NSS softoken. So the presence of
+ * these two functions implies the NSS version supports AES GCM.
+ */
+static PRBool
+ssl3_HasGCMSupport(void)
+{
+ (void)PR_CallOnce(&resolvePK11CryptOnce, ssl3_ResolvePK11CryptFunctions);
+ return pk11_encrypt != NULL;
+}
+
+/* On this socket, disable the GCM cipher suites */
+SECStatus
+ssl3_DisableGCMSuites(sslSocket * ss)
+{
+ unsigned int i;
+
+ for (i = 0; i < PR_ARRAY_SIZE(cipher_suite_defs); i++) {
+ const ssl3CipherSuiteDef *cipher_def = &cipher_suite_defs[i];
+ if (cipher_def->bulk_cipher_alg == cipher_aes_128_gcm) {
+ SECStatus rv = ssl3_CipherPrefSet(ss, cipher_def->cipher_suite,
+ PR_FALSE);
+ PORT_Assert(rv == SECSuccess); /* else is coding error */
+ }
+ }
+ return SECSuccess;
+}
+
+static SECStatus
+ssl3_AESGCM(ssl3KeyMaterial *keys,
+ PRBool doDecrypt,
+ unsigned char *out,
+ int *outlen,
+ int maxout,
+ const unsigned char *in,
+ int inlen,
+ SSL3ContentType type,
+ SSL3ProtocolVersion version,
+ SSL3SequenceNumber seq_num)
+{
+ SECItem param;
+ SECStatus rv = SECFailure;
+ unsigned char nonce[12];
+ unsigned char additionalData[13];
+ unsigned int additionalDataLen;
+ unsigned int uOutLen;
+ CK_GCM_PARAMS gcmParams;
+
+ static const int tagSize = 16;
+ static const int explicitNonceLen = 8;
+
+ /* See https://tools.ietf.org/html/rfc5246#section-6.2.3.3 for the
+ * definition of the AEAD additional data. */
+ additionalDataLen = ssl3_BuildRecordPseudoHeader(
+ additionalData, seq_num, type, PR_TRUE /* includes version */,
+ version, PR_FALSE /* not DTLS */,
+ inlen - (doDecrypt ? explicitNonceLen + tagSize : 0));
+ PORT_Assert(additionalDataLen <= sizeof(additionalData));
+
+ /* See https://tools.ietf.org/html/rfc5288#section-3 for details of how the
+ * nonce is formed. */
+ memcpy(nonce, keys->write_iv, 4);
+ if (doDecrypt) {
+ memcpy(nonce + 4, in, explicitNonceLen);
+ in += explicitNonceLen;
+ inlen -= explicitNonceLen;
+ *outlen = 0;
+ } else {
+ if (maxout < explicitNonceLen) {
+ PORT_SetError(SEC_ERROR_INPUT_LEN);
+ return SECFailure;
+ }
+ /* Use the 64-bit sequence number as the explicit nonce. */
+ memcpy(nonce + 4, additionalData, explicitNonceLen);
+ memcpy(out, additionalData, explicitNonceLen);
+ out += explicitNonceLen;
+ maxout -= explicitNonceLen;
+ *outlen = explicitNonceLen;
+ }
+
+ param.type = siBuffer;
+ param.data = (unsigned char *) &gcmParams;
+ param.len = sizeof(gcmParams);
+ gcmParams.pIv = nonce;
+ gcmParams.ulIvLen = sizeof(nonce);
+ gcmParams.pAAD = additionalData;
+ gcmParams.ulAADLen = additionalDataLen;
+ gcmParams.ulTagBits = tagSize * 8;
+
+ if (doDecrypt) {
+ rv = pk11_decrypt(keys->write_key, CKM_AES_GCM, &param, out, &uOutLen,
+ maxout, in, inlen);
+ } else {
+ rv = pk11_encrypt(keys->write_key, CKM_AES_GCM, &param, out, &uOutLen,
+ maxout, in, inlen);
+ }
+ *outlen += (int) uOutLen;
+
+ return rv;
+}
+
+#ifndef NO_PKCS11_BYPASS
+static SECStatus
+ssl3_AESGCMBypass(ssl3KeyMaterial *keys,
+ PRBool doDecrypt,
+ unsigned char *out,
+ int *outlen,
+ int maxout,
+ const unsigned char *in,
+ int inlen,
+ SSL3ContentType type,
+ SSL3ProtocolVersion version,
+ SSL3SequenceNumber seq_num)
+{
+ SECStatus rv = SECFailure;
+ unsigned char nonce[12];
+ unsigned char additionalData[13];
+ unsigned int additionalDataLen;
+ unsigned int uOutLen;
+ AESContext *cx;
+ CK_GCM_PARAMS gcmParams;
+
+ static const int tagSize = 16;
+ static const int explicitNonceLen = 8;
+
+ /* See https://tools.ietf.org/html/rfc5246#section-6.2.3.3 for the
+ * definition of the AEAD additional data. */
+ additionalDataLen = ssl3_BuildRecordPseudoHeader(
+ additionalData, seq_num, type, PR_TRUE /* includes version */,
+ version, PR_FALSE /* not DTLS */,
+ inlen - (doDecrypt ? explicitNonceLen + tagSize : 0));
+ PORT_Assert(additionalDataLen <= sizeof(additionalData));
+
+ /* See https://tools.ietf.org/html/rfc5288#section-3 for details of how the
+ * nonce is formed. */
+ PORT_Assert(keys->write_iv_item.len == 4);
+ if (keys->write_iv_item.len != 4) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ memcpy(nonce, keys->write_iv_item.data, 4);
+ if (doDecrypt) {
+ memcpy(nonce + 4, in, explicitNonceLen);
+ in += explicitNonceLen;
+ inlen -= explicitNonceLen;
+ *outlen = 0;
+ } else {
+ if (maxout < explicitNonceLen) {
+ PORT_SetError(SEC_ERROR_INPUT_LEN);
+ return SECFailure;
+ }
+ /* Use the 64-bit sequence number as the explicit nonce. */
+ memcpy(nonce + 4, additionalData, explicitNonceLen);
+ memcpy(out, additionalData, explicitNonceLen);
+ out += explicitNonceLen;
+ maxout -= explicitNonceLen;
+ *outlen = explicitNonceLen;
+ }
+
+ gcmParams.pIv = nonce;
+ gcmParams.ulIvLen = sizeof(nonce);
+ gcmParams.pAAD = additionalData;
+ gcmParams.ulAADLen = additionalDataLen;
+ gcmParams.ulTagBits = tagSize * 8;
+
+ cx = (AESContext *)keys->cipher_context;
+ rv = AES_InitContext(cx, keys->write_key_item.data,
+ keys->write_key_item.len,
+ (unsigned char *)&gcmParams, NSS_AES_GCM, !doDecrypt,
+ AES_BLOCK_SIZE);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ if (doDecrypt) {
+ rv = AES_Decrypt(cx, out, &uOutLen, maxout, in, inlen);
+ } else {
+ rv = AES_Encrypt(cx, out, &uOutLen, maxout, in, inlen);
+ }
+ AES_DestroyContext(cx, PR_FALSE);
+ *outlen += (int) uOutLen;
+
+ return rv;
+}
+#endif
+
+/* Initialize encryption and MAC contexts for pending spec.
+ * Master Secret already is derived.
+ * Caller holds Spec write lock.
+ */
+static SECStatus
+ssl3_InitPendingContextsPKCS11(sslSocket *ss)
+{
+ ssl3CipherSpec * pwSpec;
+ const ssl3BulkCipherDef *cipher_def;
+ PK11Context * serverContext = NULL;
+ PK11Context * clientContext = NULL;
+ SECItem * param;
+ CK_MECHANISM_TYPE mechanism;
+ CK_MECHANISM_TYPE mac_mech;
+ CK_ULONG macLength;
+ CK_ULONG effKeyBits;
+ SECItem iv;
+ SECItem mac_param;
+ SSLCipherAlgorithm calg;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
+ PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
+
+ pwSpec = ss->ssl3.pwSpec;
+ cipher_def = pwSpec->cipher_def;
+ macLength = pwSpec->mac_size;
+ calg = cipher_def->calg;
+ PORT_Assert(alg2Mech[calg].calg == calg);
+
+ pwSpec->client.write_mac_context = NULL;
+ pwSpec->server.write_mac_context = NULL;
+
+ if (calg == calg_aes_gcm) {
+ pwSpec->encode = NULL;
+ pwSpec->decode = NULL;
+ pwSpec->destroy = NULL;
+ pwSpec->encodeContext = NULL;
+ pwSpec->decodeContext = NULL;
+ pwSpec->aead = ssl3_AESGCM;
+ return SECSuccess;
+ }
+
+ /*
+ ** Now setup the MAC contexts,
+ ** crypto contexts are setup below.
+ */
+
+ mac_mech = pwSpec->mac_def->mmech;
+ mac_param.data = (unsigned char *)&macLength;
+ mac_param.len = sizeof(macLength);
+ mac_param.type = 0;
+
+ pwSpec->client.write_mac_context = PK11_CreateContextBySymKey(
+ mac_mech, CKA_SIGN, pwSpec->client.write_mac_key, &mac_param);
+ if (pwSpec->client.write_mac_context == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
+ goto fail;
+ }
+ pwSpec->server.write_mac_context = PK11_CreateContextBySymKey(
+ mac_mech, CKA_SIGN, pwSpec->server.write_mac_key, &mac_param);
+ if (pwSpec->server.write_mac_context == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
+ goto fail;
+ }
+
+ /*
+ ** Now setup the crypto contexts.
+ */
+
+ if (calg == calg_null) {
+ pwSpec->encode = Null_Cipher;
+ pwSpec->decode = Null_Cipher;
+ pwSpec->destroy = NULL;
+ return SECSuccess;
+ }
+ mechanism = alg2Mech[calg].cmech;
+ effKeyBits = cipher_def->key_size * BPB;
+
+ /*
+ * build the server context
+ */
+ iv.data = pwSpec->server.write_iv;
+ iv.len = cipher_def->iv_size;
+ param = ssl3_ParamFromIV(mechanism, &iv, effKeyBits);
+ if (param == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_IV_PARAM_FAILURE);
+ goto fail;
+ }
+ serverContext = PK11_CreateContextBySymKey(mechanism,
+ (ss->sec.isServer ? CKA_ENCRYPT : CKA_DECRYPT),
+ pwSpec->server.write_key, param);
+ iv.data = PK11_IVFromParam(mechanism, param, (int *)&iv.len);
+ if (iv.data)
+ PORT_Memcpy(pwSpec->server.write_iv, iv.data, iv.len);
+ SECITEM_FreeItem(param, PR_TRUE);
+ if (serverContext == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
+ goto fail;
+ }
+
+ /*
+ * build the client context
+ */
+ iv.data = pwSpec->client.write_iv;
+ iv.len = cipher_def->iv_size;
+
+ param = ssl3_ParamFromIV(mechanism, &iv, effKeyBits);
+ if (param == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_IV_PARAM_FAILURE);
+ goto fail;
+ }
+ clientContext = PK11_CreateContextBySymKey(mechanism,
+ (ss->sec.isServer ? CKA_DECRYPT : CKA_ENCRYPT),
+ pwSpec->client.write_key, param);
+ iv.data = PK11_IVFromParam(mechanism, param, (int *)&iv.len);
+ if (iv.data)
+ PORT_Memcpy(pwSpec->client.write_iv, iv.data, iv.len);
+ SECITEM_FreeItem(param,PR_TRUE);
+ if (clientContext == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
+ goto fail;
+ }
+ pwSpec->encode = (SSLCipher) PK11_CipherOp;
+ pwSpec->decode = (SSLCipher) PK11_CipherOp;
+ pwSpec->destroy = (SSLDestroy) PK11_DestroyContext;
+
+ pwSpec->encodeContext = (ss->sec.isServer) ? serverContext : clientContext;
+ pwSpec->decodeContext = (ss->sec.isServer) ? clientContext : serverContext;
+
+ serverContext = NULL;
+ clientContext = NULL;
+
+ ssl3_InitCompressionContext(pwSpec);
+
+ return SECSuccess;
+
+fail:
+ if (serverContext != NULL) PK11_DestroyContext(serverContext, PR_TRUE);
+ if (clientContext != NULL) PK11_DestroyContext(clientContext, PR_TRUE);
+ if (pwSpec->client.write_mac_context != NULL) {
+ PK11_DestroyContext(pwSpec->client.write_mac_context,PR_TRUE);
+ pwSpec->client.write_mac_context = NULL;
+ }
+ if (pwSpec->server.write_mac_context != NULL) {
+ PK11_DestroyContext(pwSpec->server.write_mac_context,PR_TRUE);
+ pwSpec->server.write_mac_context = NULL;
+ }
+
+ return SECFailure;
+}
+
+/* Complete the initialization of all keys, ciphers, MACs and their contexts
+ * for the pending Cipher Spec.
+ * Called from: ssl3_SendClientKeyExchange (for Full handshake)
+ * ssl3_HandleRSAClientKeyExchange (for Full handshake)
+ * ssl3_HandleServerHello (for session restart)
+ * ssl3_HandleClientHello (for session restart)
+ * Sets error code, but caller probably should override to disambiguate.
+ * NULL pms means re-use old master_secret.
+ *
+ * This code is common to the bypass and PKCS11 execution paths.
+ * For the bypass case, pms is NULL.
+ */
+SECStatus
+ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms)
+{
+ ssl3CipherSpec * pwSpec;
+ ssl3CipherSpec * cwSpec;
+ SECStatus rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ ssl_GetSpecWriteLock(ss); /**************************************/
+
+ PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
+
+ pwSpec = ss->ssl3.pwSpec;
+ cwSpec = ss->ssl3.cwSpec;
+
+ if (pms || (!pwSpec->msItem.len && !pwSpec->master_secret)) {
+ rv = ssl3_DeriveMasterSecret(ss, pms);
+ if (rv != SECSuccess) {
+ goto done; /* err code set by ssl3_DeriveMasterSecret */
+ }
+ }
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11 && pwSpec->msItem.len && pwSpec->msItem.data) {
+ /* Double Bypass succeeded in extracting the master_secret */
+ const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def;
+ PRBool isTLS = (PRBool)(kea_def->tls_keygen ||
+ (pwSpec->version > SSL_LIBRARY_VERSION_3_0));
+ pwSpec->bypassCiphers = PR_TRUE;
+ rv = ssl3_KeyAndMacDeriveBypass( pwSpec,
+ (const unsigned char *)&ss->ssl3.hs.client_random,
+ (const unsigned char *)&ss->ssl3.hs.server_random,
+ isTLS,
+ (PRBool)(kea_def->is_limited));
+ if (rv == SECSuccess) {
+ rv = ssl3_InitPendingContextsBypass(ss);
+ }
+ } else
+#endif
+ if (pwSpec->master_secret) {
+ rv = ssl3_DeriveConnectionKeysPKCS11(ss);
+ if (rv == SECSuccess) {
+ rv = ssl3_InitPendingContextsPKCS11(ss);
+ }
+ } else {
+ PORT_Assert(pwSpec->master_secret);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ rv = SECFailure;
+ }
+ if (rv != SECSuccess) {
+ goto done;
+ }
+
+ /* Generic behaviors -- common to all crypto methods */
+ if (!IS_DTLS(ss)) {
+ pwSpec->read_seq_num.high = pwSpec->write_seq_num.high = 0;
+ } else {
+ if (cwSpec->epoch == PR_UINT16_MAX) {
+ /* The problem here is that we have rehandshaked too many
+ * times (you are not allowed to wrap the epoch). The
+ * spec says you should be discarding the connection
+ * and start over, so not much we can do here. */
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ rv = SECFailure;
+ goto done;
+ }
+ /* The sequence number has the high 16 bits as the epoch. */
+ pwSpec->epoch = cwSpec->epoch + 1;
+ pwSpec->read_seq_num.high = pwSpec->write_seq_num.high =
+ pwSpec->epoch << 16;
+
+ dtls_InitRecvdRecords(&pwSpec->recvdRecords);
+ }
+ pwSpec->read_seq_num.low = pwSpec->write_seq_num.low = 0;
+
+done:
+ ssl_ReleaseSpecWriteLock(ss); /******************************/
+ if (rv != SECSuccess)
+ ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
+ return rv;
+}
+
+/*
+ * 60 bytes is 3 times the maximum length MAC size that is supported.
+ */
+static const unsigned char mac_pad_1 [60] = {
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36
+};
+static const unsigned char mac_pad_2 [60] = {
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c
+};
+
+/* Called from: ssl3_SendRecord()
+** Caller must already hold the SpecReadLock. (wish we could assert that!)
+*/
+static SECStatus
+ssl3_ComputeRecordMAC(
+ ssl3CipherSpec * spec,
+ PRBool useServerMacKey,
+ PRBool isDTLS,
+ SSL3ContentType type,
+ SSL3ProtocolVersion version,
+ SSL3SequenceNumber seq_num,
+ const SSL3Opaque * input,
+ int inputLength,
+ unsigned char * outbuf,
+ unsigned int * outLength)
+{
+ const ssl3MACDef * mac_def;
+ SECStatus rv;
+ PRBool isTLS;
+ unsigned int tempLen;
+ unsigned char temp[MAX_MAC_LENGTH];
+
+ /* TLS MAC includes the record's version field, SSL's doesn't.
+ ** We decide which MAC defintiion to use based on the version of
+ ** the protocol that was negotiated when the spec became current,
+ ** NOT based on the version value in the record itself.
+ ** But, we use the record's version value in the computation.
+ */
+ isTLS = spec->version > SSL_LIBRARY_VERSION_3_0;
+ tempLen = ssl3_BuildRecordPseudoHeader(temp, seq_num, type, isTLS,
+ version, isDTLS, inputLength);
+ PORT_Assert(tempLen <= sizeof(temp));
+
+ PRINT_BUF(95, (NULL, "frag hash1: temp", temp, tempLen));
+ PRINT_BUF(95, (NULL, "frag hash1: input", input, inputLength));
+
+ mac_def = spec->mac_def;
+ if (mac_def->mac == mac_null) {
+ *outLength = 0;
+ return SECSuccess;
+ }
+#ifndef NO_PKCS11_BYPASS
+ if (spec->bypassCiphers) {
+ /* bypass version */
+ const SECHashObject *hashObj = NULL;
+ unsigned int pad_bytes = 0;
+ PRUint64 write_mac_context[MAX_MAC_CONTEXT_LLONGS];
+
+ switch (mac_def->mac) {
+ case ssl_mac_null:
+ *outLength = 0;
+ return SECSuccess;
+ case ssl_mac_md5:
+ pad_bytes = 48;
+ hashObj = HASH_GetRawHashObject(HASH_AlgMD5);
+ break;
+ case ssl_mac_sha:
+ pad_bytes = 40;
+ hashObj = HASH_GetRawHashObject(HASH_AlgSHA1);
+ break;
+ case ssl_hmac_md5: /* used with TLS */
+ hashObj = HASH_GetRawHashObject(HASH_AlgMD5);
+ break;
+ case ssl_hmac_sha: /* used with TLS */
+ hashObj = HASH_GetRawHashObject(HASH_AlgSHA1);
+ break;
+ case ssl_hmac_sha256: /* used with TLS */
+ hashObj = HASH_GetRawHashObject(HASH_AlgSHA256);
+ break;
+ default:
+ break;
+ }
+ if (!hashObj) {
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ if (!isTLS) {
+ /* compute "inner" part of SSL3 MAC */
+ hashObj->begin(write_mac_context);
+ if (useServerMacKey)
+ hashObj->update(write_mac_context,
+ spec->server.write_mac_key_item.data,
+ spec->server.write_mac_key_item.len);
+ else
+ hashObj->update(write_mac_context,
+ spec->client.write_mac_key_item.data,
+ spec->client.write_mac_key_item.len);
+ hashObj->update(write_mac_context, mac_pad_1, pad_bytes);
+ hashObj->update(write_mac_context, temp, tempLen);
+ hashObj->update(write_mac_context, input, inputLength);
+ hashObj->end(write_mac_context, temp, &tempLen, sizeof temp);
+
+ /* compute "outer" part of SSL3 MAC */
+ hashObj->begin(write_mac_context);
+ if (useServerMacKey)
+ hashObj->update(write_mac_context,
+ spec->server.write_mac_key_item.data,
+ spec->server.write_mac_key_item.len);
+ else
+ hashObj->update(write_mac_context,
+ spec->client.write_mac_key_item.data,
+ spec->client.write_mac_key_item.len);
+ hashObj->update(write_mac_context, mac_pad_2, pad_bytes);
+ hashObj->update(write_mac_context, temp, tempLen);
+ hashObj->end(write_mac_context, outbuf, outLength, spec->mac_size);
+ rv = SECSuccess;
+ } else { /* is TLS */
+#define cx ((HMACContext *)write_mac_context)
+ if (useServerMacKey) {
+ rv = HMAC_Init(cx, hashObj,
+ spec->server.write_mac_key_item.data,
+ spec->server.write_mac_key_item.len, PR_FALSE);
+ } else {
+ rv = HMAC_Init(cx, hashObj,
+ spec->client.write_mac_key_item.data,
+ spec->client.write_mac_key_item.len, PR_FALSE);
+ }
+ if (rv == SECSuccess) {
+ HMAC_Begin(cx);
+ HMAC_Update(cx, temp, tempLen);
+ HMAC_Update(cx, input, inputLength);
+ rv = HMAC_Finish(cx, outbuf, outLength, spec->mac_size);
+ HMAC_Destroy(cx, PR_FALSE);
+ }
+#undef cx
+ }
+ } else
+#endif
+ {
+ PK11Context *mac_context =
+ (useServerMacKey ? spec->server.write_mac_context
+ : spec->client.write_mac_context);
+ rv = PK11_DigestBegin(mac_context);
+ rv |= PK11_DigestOp(mac_context, temp, tempLen);
+ rv |= PK11_DigestOp(mac_context, input, inputLength);
+ rv |= PK11_DigestFinal(mac_context, outbuf, outLength, spec->mac_size);
+ }
+
+ PORT_Assert(rv != SECSuccess || *outLength == (unsigned)spec->mac_size);
+
+ PRINT_BUF(95, (NULL, "frag hash2: result", outbuf, *outLength));
+
+ if (rv != SECSuccess) {
+ rv = SECFailure;
+ ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
+ }
+ return rv;
+}
+
+/* This is a bodge to allow this code to be compiled against older NSS headers
+ * that don't contain the CBC constant-time changes. */
+#ifndef CKM_NSS_HMAC_CONSTANT_TIME
+#define CKM_NSS_HMAC_CONSTANT_TIME (CKM_NSS + 19)
+#define CKM_NSS_SSL3_MAC_CONSTANT_TIME (CKM_NSS + 20)
+
+typedef struct CK_NSS_MAC_CONSTANT_TIME_PARAMS {
+ CK_MECHANISM_TYPE macAlg; /* in */
+ CK_ULONG ulBodyTotalLen; /* in */
+ CK_BYTE * pHeader; /* in */
+ CK_ULONG ulHeaderLen; /* in */
+} CK_NSS_MAC_CONSTANT_TIME_PARAMS;
+#endif
+
+/* Called from: ssl3_HandleRecord()
+ * Caller must already hold the SpecReadLock. (wish we could assert that!)
+ *
+ * On entry:
+ * originalLen >= inputLen >= MAC size
+*/
+static SECStatus
+ssl3_ComputeRecordMACConstantTime(
+ ssl3CipherSpec * spec,
+ PRBool useServerMacKey,
+ PRBool isDTLS,
+ SSL3ContentType type,
+ SSL3ProtocolVersion version,
+ SSL3SequenceNumber seq_num,
+ const SSL3Opaque * input,
+ int inputLen,
+ int originalLen,
+ unsigned char * outbuf,
+ unsigned int * outLen)
+{
+ CK_MECHANISM_TYPE macType;
+ CK_NSS_MAC_CONSTANT_TIME_PARAMS params;
+ PK11Context * mac_context;
+ SECItem param;
+ SECStatus rv;
+ unsigned char header[13];
+ PK11SymKey * key;
+ int recordLength;
+
+ PORT_Assert(inputLen >= spec->mac_size);
+ PORT_Assert(originalLen >= inputLen);
+
+ if (spec->bypassCiphers) {
+ /* This function doesn't support PKCS#11 bypass. We fallback on the
+ * non-constant time version. */
+ goto fallback;
+ }
+
+ if (spec->mac_def->mac == mac_null) {
+ *outLen = 0;
+ return SECSuccess;
+ }
+
+ header[0] = (unsigned char)(seq_num.high >> 24);
+ header[1] = (unsigned char)(seq_num.high >> 16);
+ header[2] = (unsigned char)(seq_num.high >> 8);
+ header[3] = (unsigned char)(seq_num.high >> 0);
+ header[4] = (unsigned char)(seq_num.low >> 24);
+ header[5] = (unsigned char)(seq_num.low >> 16);
+ header[6] = (unsigned char)(seq_num.low >> 8);
+ header[7] = (unsigned char)(seq_num.low >> 0);
+ header[8] = type;
+
+ macType = CKM_NSS_HMAC_CONSTANT_TIME;
+ recordLength = inputLen - spec->mac_size;
+ if (spec->version <= SSL_LIBRARY_VERSION_3_0) {
+ macType = CKM_NSS_SSL3_MAC_CONSTANT_TIME;
+ header[9] = recordLength >> 8;
+ header[10] = recordLength;
+ params.ulHeaderLen = 11;
+ } else {
+ if (isDTLS) {
+ SSL3ProtocolVersion dtls_version;
+
+ dtls_version = dtls_TLSVersionToDTLSVersion(version);
+ header[9] = dtls_version >> 8;
+ header[10] = dtls_version;
+ } else {
+ header[9] = version >> 8;
+ header[10] = version;
+ }
+ header[11] = recordLength >> 8;
+ header[12] = recordLength;
+ params.ulHeaderLen = 13;
+ }
+
+ params.macAlg = spec->mac_def->mmech;
+ params.ulBodyTotalLen = originalLen;
+ params.pHeader = header;
+
+ param.data = (unsigned char*) &params;
+ param.len = sizeof(params);
+ param.type = 0;
+
+ key = spec->server.write_mac_key;
+ if (!useServerMacKey) {
+ key = spec->client.write_mac_key;
+ }
+ mac_context = PK11_CreateContextBySymKey(macType, CKA_SIGN, key, &param);
+ if (mac_context == NULL) {
+ /* Older versions of NSS may not support constant-time MAC. */
+ goto fallback;
+ }
+
+ rv = PK11_DigestBegin(mac_context);
+ rv |= PK11_DigestOp(mac_context, input, inputLen);
+ rv |= PK11_DigestFinal(mac_context, outbuf, outLen, spec->mac_size);
+ PK11_DestroyContext(mac_context, PR_TRUE);
+
+ PORT_Assert(rv != SECSuccess || *outLen == (unsigned)spec->mac_size);
+
+ if (rv != SECSuccess) {
+ rv = SECFailure;
+ ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
+ }
+ return rv;
+
+fallback:
+ /* ssl3_ComputeRecordMAC expects the MAC to have been removed from the
+ * length already. */
+ inputLen -= spec->mac_size;
+ return ssl3_ComputeRecordMAC(spec, useServerMacKey, isDTLS, type,
+ version, seq_num, input, inputLen,
+ outbuf, outLen);
+}
+
+static PRBool
+ssl3_ClientAuthTokenPresent(sslSessionID *sid) {
+ PK11SlotInfo *slot = NULL;
+ PRBool isPresent = PR_TRUE;
+
+ /* we only care if we are doing client auth */
+ /* If NSS_PLATFORM_CLIENT_AUTH is defined and a platformClientKey is being
+ * used, u.ssl3.clAuthValid will be false and this function will always
+ * return PR_TRUE. */
+ if (!sid || !sid->u.ssl3.clAuthValid) {
+ return PR_TRUE;
+ }
+
+ /* get the slot */
+ slot = SECMOD_LookupSlot(sid->u.ssl3.clAuthModuleID,
+ sid->u.ssl3.clAuthSlotID);
+ if (slot == NULL ||
+ !PK11_IsPresent(slot) ||
+ sid->u.ssl3.clAuthSeries != PK11_GetSlotSeries(slot) ||
+ sid->u.ssl3.clAuthSlotID != PK11_GetSlotID(slot) ||
+ sid->u.ssl3.clAuthModuleID != PK11_GetModuleID(slot) ||
+ (PK11_NeedLogin(slot) && !PK11_IsLoggedIn(slot, NULL))) {
+ isPresent = PR_FALSE;
+ }
+ if (slot) {
+ PK11_FreeSlot(slot);
+ }
+ return isPresent;
+}
+
+/* Caller must hold the spec read lock. */
+SECStatus
+ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec,
+ PRBool isServer,
+ PRBool isDTLS,
+ PRBool capRecordVersion,
+ SSL3ContentType type,
+ const SSL3Opaque * pIn,
+ PRUint32 contentLen,
+ sslBuffer * wrBuf)
+{
+ const ssl3BulkCipherDef * cipher_def;
+ SECStatus rv;
+ PRUint32 macLen = 0;
+ PRUint32 fragLen;
+ PRUint32 p1Len, p2Len, oddLen = 0;
+ PRUint16 headerLen;
+ int ivLen = 0;
+ int cipherBytes = 0;
+
+ cipher_def = cwSpec->cipher_def;
+ headerLen = isDTLS ? DTLS_RECORD_HEADER_LENGTH : SSL3_RECORD_HEADER_LENGTH;
+
+ if (cipher_def->type == type_block &&
+ cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
+ /* Prepend the per-record explicit IV using technique 2b from
+ * RFC 4346 section 6.2.3.2: The IV is a cryptographically
+ * strong random number XORed with the CBC residue from the previous
+ * record.
+ */
+ ivLen = cipher_def->iv_size;
+ if (ivLen > wrBuf->space - headerLen) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ rv = PK11_GenerateRandom(wrBuf->buf + headerLen, ivLen);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE);
+ return rv;
+ }
+ rv = cwSpec->encode( cwSpec->encodeContext,
+ wrBuf->buf + headerLen,
+ &cipherBytes, /* output and actual outLen */
+ ivLen, /* max outlen */
+ wrBuf->buf + headerLen,
+ ivLen); /* input and inputLen*/
+ if (rv != SECSuccess || cipherBytes != ivLen) {
+ PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
+ return SECFailure;
+ }
+ }
+
+ if (cwSpec->compressor) {
+ int outlen;
+ rv = cwSpec->compressor(
+ cwSpec->compressContext,
+ wrBuf->buf + headerLen + ivLen, &outlen,
+ wrBuf->space - headerLen - ivLen, pIn, contentLen);
+ if (rv != SECSuccess)
+ return rv;
+ pIn = wrBuf->buf + headerLen + ivLen;
+ contentLen = outlen;
+ }
+
+ if (cipher_def->type == type_aead) {
+ const int nonceLen = cipher_def->explicit_nonce_size;
+ const int tagLen = cipher_def->tag_size;
+
+ if (headerLen + nonceLen + contentLen + tagLen > wrBuf->space) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ cipherBytes = contentLen;
+ rv = cwSpec->aead(
+ isServer ? &cwSpec->server : &cwSpec->client,
+ PR_FALSE, /* do encrypt */
+ wrBuf->buf + headerLen, /* output */
+ &cipherBytes, /* out len */
+ wrBuf->space - headerLen, /* max out */
+ pIn, contentLen, /* input */
+ type, cwSpec->version, cwSpec->write_seq_num);
+ if (rv != SECSuccess) {
+ PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
+ return SECFailure;
+ }
+ } else {
+ /*
+ * Add the MAC
+ */
+ rv = ssl3_ComputeRecordMAC( cwSpec, isServer, isDTLS,
+ type, cwSpec->version, cwSpec->write_seq_num, pIn, contentLen,
+ wrBuf->buf + headerLen + ivLen + contentLen, &macLen);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
+ return SECFailure;
+ }
+ p1Len = contentLen;
+ p2Len = macLen;
+ fragLen = contentLen + macLen; /* needs to be encrypted */
+ PORT_Assert(fragLen <= MAX_FRAGMENT_LENGTH + 1024);
+
+ /*
+ * Pad the text (if we're doing a block cipher)
+ * then Encrypt it
+ */
+ if (cipher_def->type == type_block) {
+ unsigned char * pBuf;
+ int padding_length;
+ int i;
+
+ oddLen = contentLen % cipher_def->block_size;
+ /* Assume blockSize is a power of two */
+ padding_length = cipher_def->block_size - 1 -
+ ((fragLen) & (cipher_def->block_size - 1));
+ fragLen += padding_length + 1;
+ PORT_Assert((fragLen % cipher_def->block_size) == 0);
+
+ /* Pad according to TLS rules (also acceptable to SSL3). */
+ pBuf = &wrBuf->buf[headerLen + ivLen + fragLen - 1];
+ for (i = padding_length + 1; i > 0; --i) {
+ *pBuf-- = padding_length;
+ }
+ /* now, if contentLen is not a multiple of block size, fix it */
+ p2Len = fragLen - p1Len;
+ }
+ if (p1Len < 256) {
+ oddLen = p1Len;
+ p1Len = 0;
+ } else {
+ p1Len -= oddLen;
+ }
+ if (oddLen) {
+ p2Len += oddLen;
+ PORT_Assert( (cipher_def->block_size < 2) || \
+ (p2Len % cipher_def->block_size) == 0);
+ memmove(wrBuf->buf + headerLen + ivLen + p1Len, pIn + p1Len,
+ oddLen);
+ }
+ if (p1Len > 0) {
+ int cipherBytesPart1 = -1;
+ rv = cwSpec->encode( cwSpec->encodeContext,
+ wrBuf->buf + headerLen + ivLen, /* output */
+ &cipherBytesPart1, /* actual outlen */
+ p1Len, /* max outlen */
+ pIn, p1Len); /* input, and inputlen */
+ PORT_Assert(rv == SECSuccess && cipherBytesPart1 == (int) p1Len);
+ if (rv != SECSuccess || cipherBytesPart1 != (int) p1Len) {
+ PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
+ return SECFailure;
+ }
+ cipherBytes += cipherBytesPart1;
+ }
+ if (p2Len > 0) {
+ int cipherBytesPart2 = -1;
+ rv = cwSpec->encode( cwSpec->encodeContext,
+ wrBuf->buf + headerLen + ivLen + p1Len,
+ &cipherBytesPart2, /* output and actual outLen */
+ p2Len, /* max outlen */
+ wrBuf->buf + headerLen + ivLen + p1Len,
+ p2Len); /* input and inputLen*/
+ PORT_Assert(rv == SECSuccess && cipherBytesPart2 == (int) p2Len);
+ if (rv != SECSuccess || cipherBytesPart2 != (int) p2Len) {
+ PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
+ return SECFailure;
+ }
+ cipherBytes += cipherBytesPart2;
+ }
+ }
+
+ PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024);
+
+ wrBuf->len = cipherBytes + headerLen;
+ wrBuf->buf[0] = type;
+ if (isDTLS) {
+ SSL3ProtocolVersion version;
+
+ version = dtls_TLSVersionToDTLSVersion(cwSpec->version);
+ wrBuf->buf[1] = MSB(version);
+ wrBuf->buf[2] = LSB(version);
+ wrBuf->buf[3] = (unsigned char)(cwSpec->write_seq_num.high >> 24);
+ wrBuf->buf[4] = (unsigned char)(cwSpec->write_seq_num.high >> 16);
+ wrBuf->buf[5] = (unsigned char)(cwSpec->write_seq_num.high >> 8);
+ wrBuf->buf[6] = (unsigned char)(cwSpec->write_seq_num.high >> 0);
+ wrBuf->buf[7] = (unsigned char)(cwSpec->write_seq_num.low >> 24);
+ wrBuf->buf[8] = (unsigned char)(cwSpec->write_seq_num.low >> 16);
+ wrBuf->buf[9] = (unsigned char)(cwSpec->write_seq_num.low >> 8);
+ wrBuf->buf[10] = (unsigned char)(cwSpec->write_seq_num.low >> 0);
+ wrBuf->buf[11] = MSB(cipherBytes);
+ wrBuf->buf[12] = LSB(cipherBytes);
+ } else {
+ SSL3ProtocolVersion version = cwSpec->version;
+
+ if (capRecordVersion) {
+ version = PR_MIN(SSL_LIBRARY_VERSION_TLS_1_0, version);
+ }
+ wrBuf->buf[1] = MSB(version);
+ wrBuf->buf[2] = LSB(version);
+ wrBuf->buf[3] = MSB(cipherBytes);
+ wrBuf->buf[4] = LSB(cipherBytes);
+ }
+
+ ssl3_BumpSequenceNumber(&cwSpec->write_seq_num);
+
+ return SECSuccess;
+}
+
+/* Process the plain text before sending it.
+ * Returns the number of bytes of plaintext that were successfully sent
+ * plus the number of bytes of plaintext that were copied into the
+ * output (write) buffer.
+ * Returns SECFailure on a hard IO error, memory error, or crypto error.
+ * Does NOT return SECWouldBlock.
+ *
+ * Notes on the use of the private ssl flags:
+ * (no private SSL flags)
+ * Attempt to make and send SSL records for all plaintext
+ * If non-blocking and a send gets WOULD_BLOCK,
+ * or if the pending (ciphertext) buffer is not empty,
+ * then buffer remaining bytes of ciphertext into pending buf,
+ * and continue to do that for all succssive records until all
+ * bytes are used.
+ * ssl_SEND_FLAG_FORCE_INTO_BUFFER
+ * As above, except this suppresses all write attempts, and forces
+ * all ciphertext into the pending ciphertext buffer.
+ * ssl_SEND_FLAG_USE_EPOCH (for DTLS)
+ * Forces the use of the provided epoch
+ * ssl_SEND_FLAG_CAP_RECORD_VERSION
+ * Caps the record layer version number of TLS ClientHello to { 3, 1 }
+ * (TLS 1.0). Some TLS 1.0 servers (which seem to use F5 BIG-IP) ignore
+ * ClientHello.client_version and use the record layer version number
+ * (TLSPlaintext.version) instead when negotiating protocol versions. In
+ * addition, if the record layer version number of ClientHello is { 3, 2 }
+ * (TLS 1.1) or higher, these servers reset the TCP connections. Set this
+ * flag to work around such servers.
+ */
+PRInt32
+ssl3_SendRecord( sslSocket * ss,
+ DTLSEpoch epoch, /* DTLS only */
+ SSL3ContentType type,
+ const SSL3Opaque * pIn, /* input buffer */
+ PRInt32 nIn, /* bytes of input */
+ PRInt32 flags)
+{
+ sslBuffer * wrBuf = &ss->sec.writeBuf;
+ SECStatus rv;
+ PRInt32 totalSent = 0;
+ PRBool capRecordVersion;
+
+ SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d",
+ SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type),
+ nIn));
+ PRINT_BUF(3, (ss, "Send record (plain text)", pIn, nIn));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
+
+ capRecordVersion = ((flags & ssl_SEND_FLAG_CAP_RECORD_VERSION) != 0);
+
+ if (capRecordVersion) {
+ /* ssl_SEND_FLAG_CAP_RECORD_VERSION can only be used with the
+ * TLS initial ClientHello. */
+ PORT_Assert(!IS_DTLS(ss));
+ PORT_Assert(!ss->firstHsDone);
+ PORT_Assert(type == content_handshake);
+ PORT_Assert(ss->ssl3.hs.ws == wait_server_hello);
+ }
+
+ if (ss->ssl3.initialized == PR_FALSE) {
+ /* This can happen on a server if the very first incoming record
+ ** looks like a defective ssl3 record (e.g. too long), and we're
+ ** trying to send an alert.
+ */
+ PR_ASSERT(type == content_alert);
+ rv = ssl3_InitState(ss);
+ if (rv != SECSuccess) {
+ return SECFailure; /* ssl3_InitState has set the error code. */
+ }
+ }
+
+ /* check for Token Presence */
+ if (!ssl3_ClientAuthTokenPresent(ss->sec.ci.sid)) {
+ PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL);
+ return SECFailure;
+ }
+
+ while (nIn > 0) {
+ PRUint32 contentLen = PR_MIN(nIn, MAX_FRAGMENT_LENGTH);
+ unsigned int spaceNeeded;
+ unsigned int numRecords;
+
+ ssl_GetSpecReadLock(ss); /********************************/
+
+ if (nIn > 1 && ss->opt.cbcRandomIV &&
+ ss->ssl3.cwSpec->version < SSL_LIBRARY_VERSION_TLS_1_1 &&
+ type == content_application_data &&
+ ss->ssl3.cwSpec->cipher_def->type == type_block /* CBC mode */) {
+ /* We will split the first byte of the record into its own record,
+ * as explained in the documentation for SSL_CBC_RANDOM_IV in ssl.h
+ */
+ numRecords = 2;
+ } else {
+ numRecords = 1;
+ }
+
+ spaceNeeded = contentLen + (numRecords * SSL3_BUFFER_FUDGE);
+ if (ss->ssl3.cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1 &&
+ ss->ssl3.cwSpec->cipher_def->type == type_block) {
+ spaceNeeded += ss->ssl3.cwSpec->cipher_def->iv_size;
+ }
+ if (spaceNeeded > wrBuf->space) {
+ rv = sslBuffer_Grow(wrBuf, spaceNeeded);
+ if (rv != SECSuccess) {
+ SSL_DBG(("%d: SSL3[%d]: SendRecord, tried to get %d bytes",
+ SSL_GETPID(), ss->fd, spaceNeeded));
+ goto spec_locked_loser; /* sslBuffer_Grow set error code. */
+ }
+ }
+
+ if (numRecords == 2) {
+ sslBuffer secondRecord;
+
+ rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
+ ss->sec.isServer, IS_DTLS(ss),
+ capRecordVersion, type, pIn,
+ 1, wrBuf);
+ if (rv != SECSuccess)
+ goto spec_locked_loser;
+
+ PRINT_BUF(50, (ss, "send (encrypted) record data [1/2]:",
+ wrBuf->buf, wrBuf->len));
+
+ secondRecord.buf = wrBuf->buf + wrBuf->len;
+ secondRecord.len = 0;
+ secondRecord.space = wrBuf->space - wrBuf->len;
+
+ rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
+ ss->sec.isServer, IS_DTLS(ss),
+ capRecordVersion, type,
+ pIn + 1, contentLen - 1,
+ &secondRecord);
+ if (rv == SECSuccess) {
+ PRINT_BUF(50, (ss, "send (encrypted) record data [2/2]:",
+ secondRecord.buf, secondRecord.len));
+ wrBuf->len += secondRecord.len;
+ }
+ } else {
+ if (!IS_DTLS(ss)) {
+ rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
+ ss->sec.isServer,
+ IS_DTLS(ss),
+ capRecordVersion,
+ type, pIn,
+ contentLen, wrBuf);
+ } else {
+ rv = dtls_CompressMACEncryptRecord(ss, epoch,
+ !!(flags & ssl_SEND_FLAG_USE_EPOCH),
+ type, pIn,
+ contentLen, wrBuf);
+ }
+
+ if (rv == SECSuccess) {
+ PRINT_BUF(50, (ss, "send (encrypted) record data:",
+ wrBuf->buf, wrBuf->len));
+ }
+ }
+
+spec_locked_loser:
+ ssl_ReleaseSpecReadLock(ss); /************************************/
+
+ if (rv != SECSuccess)
+ return SECFailure;
+
+ pIn += contentLen;
+ nIn -= contentLen;
+ PORT_Assert( nIn >= 0 );
+
+ /* If there's still some previously saved ciphertext,
+ * or the caller doesn't want us to send the data yet,
+ * then add all our new ciphertext to the amount previously saved.
+ */
+ if ((ss->pendingBuf.len > 0) ||
+ (flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) {
+
+ rv = ssl_SaveWriteData(ss, wrBuf->buf, wrBuf->len);
+ if (rv != SECSuccess) {
+ /* presumably a memory error, SEC_ERROR_NO_MEMORY */
+ return SECFailure;
+ }
+ wrBuf->len = 0; /* All cipher text is saved away. */
+
+ if (!(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) {
+ PRInt32 sent;
+ ss->handshakeBegun = 1;
+ sent = ssl_SendSavedWriteData(ss);
+ if (sent < 0 && PR_GetError() != PR_WOULD_BLOCK_ERROR) {
+ ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE);
+ return SECFailure;
+ }
+ if (ss->pendingBuf.len) {
+ flags |= ssl_SEND_FLAG_FORCE_INTO_BUFFER;
+ }
+ }
+ } else if (wrBuf->len > 0) {
+ PRInt32 sent;
+ ss->handshakeBegun = 1;
+ sent = ssl_DefSend(ss, wrBuf->buf, wrBuf->len,
+ flags & ~ssl_SEND_FLAG_MASK);
+ if (sent < 0) {
+ if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
+ ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE);
+ return SECFailure;
+ }
+ /* we got PR_WOULD_BLOCK_ERROR, which means none was sent. */
+ sent = 0;
+ }
+ wrBuf->len -= sent;
+ if (wrBuf->len) {
+ if (IS_DTLS(ss)) {
+ /* DTLS just says no in this case. No buffering */
+ PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
+ return SECFailure;
+ }
+ /* now take all the remaining unsent new ciphertext and
+ * append it to the buffer of previously unsent ciphertext.
+ */
+ rv = ssl_SaveWriteData(ss, wrBuf->buf + sent, wrBuf->len);
+ if (rv != SECSuccess) {
+ /* presumably a memory error, SEC_ERROR_NO_MEMORY */
+ return SECFailure;
+ }
+ }
+ }
+ totalSent += contentLen;
+ }
+ return totalSent;
+}
+
+#define SSL3_PENDING_HIGH_WATER 1024
+
+/* Attempt to send the content of "in" in an SSL application_data record.
+ * Returns "len" or SECFailure, never SECWouldBlock, nor SECSuccess.
+ */
+int
+ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
+ PRInt32 len, PRInt32 flags)
+{
+ PRInt32 totalSent = 0;
+ PRInt32 discarded = 0;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
+ /* These flags for internal use only */
+ PORT_Assert(!(flags & (ssl_SEND_FLAG_USE_EPOCH |
+ ssl_SEND_FLAG_NO_RETRANSMIT)));
+ if (len < 0 || !in) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+
+ if (ss->pendingBuf.len > SSL3_PENDING_HIGH_WATER &&
+ !ssl_SocketIsBlocking(ss)) {
+ PORT_Assert(!ssl_SocketIsBlocking(ss));
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ return SECFailure;
+ }
+
+ if (ss->appDataBuffered && len) {
+ PORT_Assert (in[0] == (unsigned char)(ss->appDataBuffered));
+ if (in[0] != (unsigned char)(ss->appDataBuffered)) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ in++;
+ len--;
+ discarded = 1;
+ }
+ while (len > totalSent) {
+ PRInt32 sent, toSend;
+
+ if (totalSent > 0) {
+ /*
+ * The thread yield is intended to give the reader thread a
+ * chance to get some cycles while the writer thread is in
+ * the middle of a large application data write. (See
+ * Bugzilla bug 127740, comment #1.)
+ */
+ ssl_ReleaseXmitBufLock(ss);
+ PR_Sleep(PR_INTERVAL_NO_WAIT); /* PR_Yield(); */
+ ssl_GetXmitBufLock(ss);
+ }
+ toSend = PR_MIN(len - totalSent, MAX_FRAGMENT_LENGTH);
+ /*
+ * Note that the 0 epoch is OK because flags will never require
+ * its use, as guaranteed by the PORT_Assert above.
+ */
+ sent = ssl3_SendRecord(ss, 0, content_application_data,
+ in + totalSent, toSend, flags);
+ if (sent < 0) {
+ if (totalSent > 0 && PR_GetError() == PR_WOULD_BLOCK_ERROR) {
+ PORT_Assert(ss->lastWriteBlocked);
+ break;
+ }
+ return SECFailure; /* error code set by ssl3_SendRecord */
+ }
+ totalSent += sent;
+ if (ss->pendingBuf.len) {
+ /* must be a non-blocking socket */
+ PORT_Assert(!ssl_SocketIsBlocking(ss));
+ PORT_Assert(ss->lastWriteBlocked);
+ break;
+ }
+ }
+ if (ss->pendingBuf.len) {
+ /* Must be non-blocking. */
+ PORT_Assert(!ssl_SocketIsBlocking(ss));
+ if (totalSent > 0) {
+ ss->appDataBuffered = 0x100 | in[totalSent - 1];
+ }
+
+ totalSent = totalSent + discarded - 1;
+ if (totalSent <= 0) {
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ totalSent = SECFailure;
+ }
+ return totalSent;
+ }
+ ss->appDataBuffered = 0;
+ return totalSent + discarded;
+}
+
+/* Attempt to send buffered handshake messages.
+ * This function returns SECSuccess or SECFailure, never SECWouldBlock.
+ * Always set sendBuf.len to 0, even when returning SECFailure.
+ *
+ * Depending on whether we are doing DTLS or not, this either calls
+ *
+ * - ssl3_FlushHandshakeMessages if non-DTLS
+ * - dtls_FlushHandshakeMessages if DTLS
+ *
+ * Called from SSL3_SendAlert(), ssl3_SendChangeCipherSpecs(),
+ * ssl3_AppendHandshake(), ssl3_SendClientHello(),
+ * ssl3_SendHelloRequest(), ssl3_SendServerHelloDone(),
+ * ssl3_SendFinished(),
+ */
+static SECStatus
+ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags)
+{
+ if (IS_DTLS(ss)) {
+ return dtls_FlushHandshakeMessages(ss, flags);
+ } else {
+ return ssl3_FlushHandshakeMessages(ss, flags);
+ }
+}
+
+/* Attempt to send the content of sendBuf buffer in an SSL handshake record.
+ * This function returns SECSuccess or SECFailure, never SECWouldBlock.
+ * Always set sendBuf.len to 0, even when returning SECFailure.
+ *
+ * Called from ssl3_FlushHandshake
+ */
+static SECStatus
+ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags)
+{
+ static const PRInt32 allowedFlags = ssl_SEND_FLAG_FORCE_INTO_BUFFER |
+ ssl_SEND_FLAG_CAP_RECORD_VERSION;
+ PRInt32 rv = SECSuccess;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
+
+ if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len)
+ return rv;
+
+ /* only these flags are allowed */
+ PORT_Assert(!(flags & ~allowedFlags));
+ if ((flags & ~allowedFlags) != 0) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ } else {
+ rv = ssl3_SendRecord(ss, 0, content_handshake, ss->sec.ci.sendBuf.buf,
+ ss->sec.ci.sendBuf.len, flags);
+ }
+ if (rv < 0) {
+ int err = PORT_GetError();
+ PORT_Assert(err != PR_WOULD_BLOCK_ERROR);
+ if (err == PR_WOULD_BLOCK_ERROR) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ }
+ } else if (rv < ss->sec.ci.sendBuf.len) {
+ /* short write should never happen */
+ PORT_Assert(rv >= ss->sec.ci.sendBuf.len);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ rv = SECFailure;
+ } else {
+ rv = SECSuccess;
+ }
+
+ /* Whether we succeeded or failed, toss the old handshake data. */
+ ss->sec.ci.sendBuf.len = 0;
+ return rv;
+}
+
+/*
+ * Called from ssl3_HandleAlert and from ssl3_HandleCertificate when
+ * the remote client sends a negative response to our certificate request.
+ * Returns SECFailure if the application has required client auth.
+ * SECSuccess otherwise.
+ */
+static SECStatus
+ssl3_HandleNoCertificate(sslSocket *ss)
+{
+ if (ss->sec.peerCert != NULL) {
+ if (ss->sec.peerKey != NULL) {
+ SECKEY_DestroyPublicKey(ss->sec.peerKey);
+ ss->sec.peerKey = NULL;
+ }
+ CERT_DestroyCertificate(ss->sec.peerCert);
+ ss->sec.peerCert = NULL;
+ }
+ ssl3_CleanupPeerCerts(ss);
+
+ /* If the server has required client-auth blindly but doesn't
+ * actually look at the certificate it won't know that no
+ * certificate was presented so we shutdown the socket to ensure
+ * an error. We only do this if we haven't already completed the
+ * first handshake because if we're redoing the handshake we
+ * know the server is paying attention to the certificate.
+ */
+ if ((ss->opt.requireCertificate == SSL_REQUIRE_ALWAYS) ||
+ (!ss->firstHsDone &&
+ (ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE))) {
+ PRFileDesc * lower;
+
+ if (ss->sec.uncache)
+ ss->sec.uncache(ss->sec.ci.sid);
+ SSL3_SendAlert(ss, alert_fatal, bad_certificate);
+
+ lower = ss->fd->lower;
+#ifdef _WIN32
+ lower->methods->shutdown(lower, PR_SHUTDOWN_SEND);
+#else
+ lower->methods->shutdown(lower, PR_SHUTDOWN_BOTH);
+#endif
+ PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+/************************************************************************
+ * Alerts
+ */
+
+/*
+** Acquires both handshake and XmitBuf locks.
+** Called from: ssl3_IllegalParameter <-
+** ssl3_HandshakeFailure <-
+** ssl3_HandleAlert <- ssl3_HandleRecord.
+** ssl3_HandleChangeCipherSpecs <- ssl3_HandleRecord
+** ssl3_ConsumeHandshakeVariable <-
+** ssl3_HandleHelloRequest <-
+** ssl3_HandleServerHello <-
+** ssl3_HandleServerKeyExchange <-
+** ssl3_HandleCertificateRequest <-
+** ssl3_HandleServerHelloDone <-
+** ssl3_HandleClientHello <-
+** ssl3_HandleV2ClientHello <-
+** ssl3_HandleCertificateVerify <-
+** ssl3_HandleClientKeyExchange <-
+** ssl3_HandleCertificate <-
+** ssl3_HandleFinished <-
+** ssl3_HandleHandshakeMessage <-
+** ssl3_HandleRecord <-
+**
+*/
+SECStatus
+SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc)
+{
+ PRUint8 bytes[2];
+ SECStatus rv;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: send alert record, level=%d desc=%d",
+ SSL_GETPID(), ss->fd, level, desc));
+
+ bytes[0] = level;
+ bytes[1] = desc;
+
+ ssl_GetSSL3HandshakeLock(ss);
+ if (level == alert_fatal) {
+ if (!ss->opt.noCache && ss->sec.ci.sid && ss->sec.uncache) {
+ ss->sec.uncache(ss->sec.ci.sid);
+ }
+ }
+ ssl_GetXmitBufLock(ss);
+ rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
+ if (rv == SECSuccess) {
+ PRInt32 sent;
+ sent = ssl3_SendRecord(ss, 0, content_alert, bytes, 2,
+ desc == no_certificate
+ ? ssl_SEND_FLAG_FORCE_INTO_BUFFER : 0);
+ rv = (sent >= 0) ? SECSuccess : (SECStatus)sent;
+ }
+ ssl_ReleaseXmitBufLock(ss);
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ return rv; /* error set by ssl3_FlushHandshake or ssl3_SendRecord */
+}
+
+/*
+ * Send illegal_parameter alert. Set generic error number.
+ */
+static SECStatus
+ssl3_IllegalParameter(sslSocket *ss)
+{
+ (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+ PORT_SetError(ss->sec.isServer ? SSL_ERROR_BAD_CLIENT
+ : SSL_ERROR_BAD_SERVER );
+ return SECFailure;
+}
+
+/*
+ * Send handshake_Failure alert. Set generic error number.
+ */
+static SECStatus
+ssl3_HandshakeFailure(sslSocket *ss)
+{
+ (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
+ PORT_SetError( ss->sec.isServer ? SSL_ERROR_BAD_CLIENT
+ : SSL_ERROR_BAD_SERVER );
+ return SECFailure;
+}
+
+static void
+ssl3_SendAlertForCertError(sslSocket * ss, PRErrorCode errCode)
+{
+ SSL3AlertDescription desc = bad_certificate;
+ PRBool isTLS = ss->version >= SSL_LIBRARY_VERSION_3_1_TLS;
+
+ switch (errCode) {
+ case SEC_ERROR_LIBRARY_FAILURE: desc = unsupported_certificate; break;
+ case SEC_ERROR_EXPIRED_CERTIFICATE: desc = certificate_expired; break;
+ case SEC_ERROR_REVOKED_CERTIFICATE: desc = certificate_revoked; break;
+ case SEC_ERROR_INADEQUATE_KEY_USAGE:
+ case SEC_ERROR_INADEQUATE_CERT_TYPE:
+ desc = certificate_unknown; break;
+ case SEC_ERROR_UNTRUSTED_CERT:
+ desc = isTLS ? access_denied : certificate_unknown; break;
+ case SEC_ERROR_UNKNOWN_ISSUER:
+ case SEC_ERROR_UNTRUSTED_ISSUER:
+ desc = isTLS ? unknown_ca : certificate_unknown; break;
+ case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
+ desc = isTLS ? unknown_ca : certificate_expired; break;
+
+ case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:
+ case SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID:
+ case SEC_ERROR_CA_CERT_INVALID:
+ case SEC_ERROR_BAD_SIGNATURE:
+ default: desc = bad_certificate; break;
+ }
+ SSL_DBG(("%d: SSL3[%d]: peer certificate is no good: error=%d",
+ SSL_GETPID(), ss->fd, errCode));
+
+ (void) SSL3_SendAlert(ss, alert_fatal, desc);
+}
+
+
+/*
+ * Send decode_error alert. Set generic error number.
+ */
+SECStatus
+ssl3_DecodeError(sslSocket *ss)
+{
+ (void)SSL3_SendAlert(ss, alert_fatal,
+ ss->version > SSL_LIBRARY_VERSION_3_0 ? decode_error
+ : illegal_parameter);
+ PORT_SetError( ss->sec.isServer ? SSL_ERROR_BAD_CLIENT
+ : SSL_ERROR_BAD_SERVER );
+ return SECFailure;
+}
+
+/* Called from ssl3_HandleRecord.
+** Caller must hold both RecvBuf and Handshake locks.
+*/
+static SECStatus
+ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf)
+{
+ SSL3AlertLevel level;
+ SSL3AlertDescription desc;
+ int error;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ SSL_TRC(3, ("%d: SSL3[%d]: handle alert record", SSL_GETPID(), ss->fd));
+
+ if (buf->len != 2) {
+ (void)ssl3_DecodeError(ss);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_ALERT);
+ return SECFailure;
+ }
+ level = (SSL3AlertLevel)buf->buf[0];
+ desc = (SSL3AlertDescription)buf->buf[1];
+ buf->len = 0;
+ SSL_TRC(5, ("%d: SSL3[%d] received alert, level = %d, description = %d",
+ SSL_GETPID(), ss->fd, level, desc));
+
+ switch (desc) {
+ case close_notify: ss->recvdCloseNotify = 1;
+ error = SSL_ERROR_CLOSE_NOTIFY_ALERT; break;
+ case unexpected_message: error = SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT;
+ break;
+ case bad_record_mac: error = SSL_ERROR_BAD_MAC_ALERT; break;
+ case decryption_failed_RESERVED:
+ error = SSL_ERROR_DECRYPTION_FAILED_ALERT;
+ break;
+ case record_overflow: error = SSL_ERROR_RECORD_OVERFLOW_ALERT; break;
+ case decompression_failure: error = SSL_ERROR_DECOMPRESSION_FAILURE_ALERT;
+ break;
+ case handshake_failure: error = SSL_ERROR_HANDSHAKE_FAILURE_ALERT;
+ break;
+ case no_certificate: error = SSL_ERROR_NO_CERTIFICATE; break;
+ case bad_certificate: error = SSL_ERROR_BAD_CERT_ALERT; break;
+ case unsupported_certificate:error = SSL_ERROR_UNSUPPORTED_CERT_ALERT;break;
+ case certificate_revoked: error = SSL_ERROR_REVOKED_CERT_ALERT; break;
+ case certificate_expired: error = SSL_ERROR_EXPIRED_CERT_ALERT; break;
+ case certificate_unknown: error = SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT;
+ break;
+ case illegal_parameter: error = SSL_ERROR_ILLEGAL_PARAMETER_ALERT;break;
+
+ /* All alerts below are TLS only. */
+ case unknown_ca: error = SSL_ERROR_UNKNOWN_CA_ALERT; break;
+ case access_denied: error = SSL_ERROR_ACCESS_DENIED_ALERT; break;
+ case decode_error: error = SSL_ERROR_DECODE_ERROR_ALERT; break;
+ case decrypt_error: error = SSL_ERROR_DECRYPT_ERROR_ALERT; break;
+ case export_restriction: error = SSL_ERROR_EXPORT_RESTRICTION_ALERT;
+ break;
+ case protocol_version: error = SSL_ERROR_PROTOCOL_VERSION_ALERT; break;
+ case insufficient_security: error = SSL_ERROR_INSUFFICIENT_SECURITY_ALERT;
+ break;
+ case internal_error: error = SSL_ERROR_INTERNAL_ERROR_ALERT; break;
+ case user_canceled: error = SSL_ERROR_USER_CANCELED_ALERT; break;
+ case no_renegotiation: error = SSL_ERROR_NO_RENEGOTIATION_ALERT; break;
+
+ /* Alerts for TLS client hello extensions */
+ case unsupported_extension:
+ error = SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT; break;
+ case certificate_unobtainable:
+ error = SSL_ERROR_CERTIFICATE_UNOBTAINABLE_ALERT; break;
+ case unrecognized_name:
+ error = SSL_ERROR_UNRECOGNIZED_NAME_ALERT; break;
+ case bad_certificate_status_response:
+ error = SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT; break;
+ case bad_certificate_hash_value:
+ error = SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT; break;
+ default: error = SSL_ERROR_RX_UNKNOWN_ALERT; break;
+ }
+ if (level == alert_fatal) {
+ if (!ss->opt.noCache) {
+ if (ss->sec.uncache)
+ ss->sec.uncache(ss->sec.ci.sid);
+ }
+ if ((ss->ssl3.hs.ws == wait_server_hello) &&
+ (desc == handshake_failure)) {
+ /* XXX This is a hack. We're assuming that any handshake failure
+ * XXX on the client hello is a failure to match ciphers.
+ */
+ error = SSL_ERROR_NO_CYPHER_OVERLAP;
+ }
+ PORT_SetError(error);
+ return SECFailure;
+ }
+ if ((desc == no_certificate) && (ss->ssl3.hs.ws == wait_client_cert)) {
+ /* I'm a server. I've requested a client cert. He hasn't got one. */
+ SECStatus rv;
+
+ PORT_Assert(ss->sec.isServer);
+ ss->ssl3.hs.ws = wait_client_key;
+ rv = ssl3_HandleNoCertificate(ss);
+ return rv;
+ }
+ return SECSuccess;
+}
+
+/*
+ * Change Cipher Specs
+ * Called from ssl3_HandleServerHelloDone,
+ * ssl3_HandleClientHello,
+ * and ssl3_HandleFinished
+ *
+ * Acquires and releases spec write lock, to protect switching the current
+ * and pending write spec pointers.
+ */
+
+static SECStatus
+ssl3_SendChangeCipherSpecs(sslSocket *ss)
+{
+ PRUint8 change = change_cipher_spec_choice;
+ ssl3CipherSpec * pwSpec;
+ SECStatus rv;
+ PRInt32 sent;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: send change_cipher_spec record",
+ SSL_GETPID(), ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
+ if (rv != SECSuccess) {
+ return rv; /* error code set by ssl3_FlushHandshake */
+ }
+ if (!IS_DTLS(ss)) {
+ sent = ssl3_SendRecord(ss, 0, content_change_cipher_spec, &change, 1,
+ ssl_SEND_FLAG_FORCE_INTO_BUFFER);
+ if (sent < 0) {
+ return (SECStatus)sent; /* error code set by ssl3_SendRecord */
+ }
+ } else {
+ rv = dtls_QueueMessage(ss, content_change_cipher_spec, &change, 1);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ }
+
+ /* swap the pending and current write specs. */
+ ssl_GetSpecWriteLock(ss); /**************************************/
+ pwSpec = ss->ssl3.pwSpec;
+
+ ss->ssl3.pwSpec = ss->ssl3.cwSpec;
+ ss->ssl3.cwSpec = pwSpec;
+
+ SSL_TRC(3, ("%d: SSL3[%d] Set Current Write Cipher Suite to Pending",
+ SSL_GETPID(), ss->fd ));
+
+ /* We need to free up the contexts, keys and certs ! */
+ /* If we are really through with the old cipher spec
+ * (Both the read and write sides have changed) destroy it.
+ */
+ if (ss->ssl3.prSpec == ss->ssl3.pwSpec) {
+ if (!IS_DTLS(ss)) {
+ ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE/*freeSrvName*/);
+ } else {
+ /* With DTLS, we need to set a holddown timer in case the final
+ * message got lost */
+ ss->ssl3.hs.rtTimeoutMs = DTLS_FINISHED_TIMER_MS;
+ dtls_StartTimer(ss, dtls_FinishedTimerCb);
+ }
+ }
+ ssl_ReleaseSpecWriteLock(ss); /**************************************/
+
+ return SECSuccess;
+}
+
+/* Called from ssl3_HandleRecord.
+** Caller must hold both RecvBuf and Handshake locks.
+ *
+ * Acquires and releases spec write lock, to protect switching the current
+ * and pending write spec pointers.
+*/
+static SECStatus
+ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf)
+{
+ ssl3CipherSpec * prSpec;
+ SSL3WaitState ws = ss->ssl3.hs.ws;
+ SSL3ChangeCipherSpecChoice change;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ SSL_TRC(3, ("%d: SSL3[%d]: handle change_cipher_spec record",
+ SSL_GETPID(), ss->fd));
+
+ if (ws != wait_change_cipher) {
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER);
+ return SECFailure;
+ }
+
+ if(buf->len != 1) {
+ (void)ssl3_DecodeError(ss);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER);
+ return SECFailure;
+ }
+ change = (SSL3ChangeCipherSpecChoice)buf->buf[0];
+ if (change != change_cipher_spec_choice) {
+ /* illegal_parameter is correct here for both SSL3 and TLS. */
+ (void)ssl3_IllegalParameter(ss);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER);
+ return SECFailure;
+ }
+ buf->len = 0;
+
+ /* Swap the pending and current read specs. */
+ ssl_GetSpecWriteLock(ss); /*************************************/
+ prSpec = ss->ssl3.prSpec;
+
+ ss->ssl3.prSpec = ss->ssl3.crSpec;
+ ss->ssl3.crSpec = prSpec;
+ ss->ssl3.hs.ws = wait_finished;
+
+ SSL_TRC(3, ("%d: SSL3[%d] Set Current Read Cipher Suite to Pending",
+ SSL_GETPID(), ss->fd ));
+
+ /* If we are really through with the old cipher prSpec
+ * (Both the read and write sides have changed) destroy it.
+ */
+ if (ss->ssl3.prSpec == ss->ssl3.pwSpec) {
+ ssl3_DestroyCipherSpec(ss->ssl3.prSpec, PR_FALSE/*freeSrvName*/);
+ }
+ ssl_ReleaseSpecWriteLock(ss); /*************************************/
+ return SECSuccess;
+}
+
+/* This method uses PKCS11 to derive the MS from the PMS, where PMS
+** is a PKCS11 symkey. This is used in all cases except the
+** "triple bypass" with RSA key exchange.
+** Called from ssl3_InitPendingCipherSpec. prSpec is pwSpec.
+*/
+static SECStatus
+ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
+{
+ ssl3CipherSpec * pwSpec = ss->ssl3.pwSpec;
+ const ssl3KEADef *kea_def= ss->ssl3.hs.kea_def;
+ unsigned char * cr = (unsigned char *)&ss->ssl3.hs.client_random;
+ unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random;
+ PRBool isTLS = (PRBool)(kea_def->tls_keygen ||
+ (pwSpec->version > SSL_LIBRARY_VERSION_3_0));
+ PRBool isTLS12=
+ (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
+ /*
+ * Whenever isDH is true, we need to use CKM_TLS_MASTER_KEY_DERIVE_DH
+ * which, unlike CKM_TLS_MASTER_KEY_DERIVE, converts arbitrary size
+ * data into a 48-byte value.
+ */
+ PRBool isDH = (PRBool) ((ss->ssl3.hs.kea_def->exchKeyType == kt_dh) ||
+ (ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh));
+ SECStatus rv = SECFailure;
+ CK_MECHANISM_TYPE master_derive;
+ CK_MECHANISM_TYPE key_derive;
+ SECItem params;
+ CK_FLAGS keyFlags;
+ CK_VERSION pms_version;
+ CK_SSL3_MASTER_KEY_DERIVE_PARAMS master_params;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
+ PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
+ if (isTLS12) {
+ if(isDH) master_derive = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256;
+ else master_derive = CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256;
+ key_derive = CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256;
+ keyFlags = CKF_SIGN | CKF_VERIFY;
+ } else if (isTLS) {
+ if(isDH) master_derive = CKM_TLS_MASTER_KEY_DERIVE_DH;
+ else master_derive = CKM_TLS_MASTER_KEY_DERIVE;
+ key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
+ keyFlags = CKF_SIGN | CKF_VERIFY;
+ } else {
+ if (isDH) master_derive = CKM_SSL3_MASTER_KEY_DERIVE_DH;
+ else master_derive = CKM_SSL3_MASTER_KEY_DERIVE;
+ key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE;
+ keyFlags = 0;
+ }
+
+ if (pms || !pwSpec->master_secret) {
+ if (isDH) {
+ master_params.pVersion = NULL;
+ } else {
+ master_params.pVersion = &pms_version;
+ }
+ master_params.RandomInfo.pClientRandom = cr;
+ master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
+ master_params.RandomInfo.pServerRandom = sr;
+ master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
+
+ params.data = (unsigned char *) &master_params;
+ params.len = sizeof master_params;
+ }
+
+ if (pms != NULL) {
+#if defined(TRACE)
+ if (ssl_trace >= 100) {
+ SECStatus extractRV = PK11_ExtractKeyValue(pms);
+ if (extractRV == SECSuccess) {
+ SECItem * keyData = PK11_GetKeyData(pms);
+ if (keyData && keyData->data && keyData->len) {
+ ssl_PrintBuf(ss, "Pre-Master Secret",
+ keyData->data, keyData->len);
+ }
+ }
+ }
+#endif
+ pwSpec->master_secret = PK11_DeriveWithFlags(pms, master_derive,
+ &params, key_derive, CKA_DERIVE, 0, keyFlags);
+ if (!isDH && pwSpec->master_secret && ss->opt.detectRollBack) {
+ SSL3ProtocolVersion client_version;
+ client_version = pms_version.major << 8 | pms_version.minor;
+
+ if (IS_DTLS(ss)) {
+ client_version = dtls_DTLSVersionToTLSVersion(client_version);
+ }
+
+ if (client_version != ss->clientHelloVersion) {
+ /* Destroy it. Version roll-back detected. */
+ PK11_FreeSymKey(pwSpec->master_secret);
+ pwSpec->master_secret = NULL;
+ }
+ }
+ if (pwSpec->master_secret == NULL) {
+ /* Generate a faux master secret in the same slot as the old one. */
+ PK11SlotInfo * slot = PK11_GetSlotFromKey((PK11SymKey *)pms);
+ PK11SymKey * fpms = ssl3_GenerateRSAPMS(ss, pwSpec, slot);
+
+ PK11_FreeSlot(slot);
+ if (fpms != NULL) {
+ pwSpec->master_secret = PK11_DeriveWithFlags(fpms,
+ master_derive, &params, key_derive,
+ CKA_DERIVE, 0, keyFlags);
+ PK11_FreeSymKey(fpms);
+ }
+ }
+ }
+ if (pwSpec->master_secret == NULL) {
+ /* Generate a faux master secret from the internal slot. */
+ PK11SlotInfo * slot = PK11_GetInternalSlot();
+ PK11SymKey * fpms = ssl3_GenerateRSAPMS(ss, pwSpec, slot);
+
+ PK11_FreeSlot(slot);
+ if (fpms != NULL) {
+ pwSpec->master_secret = PK11_DeriveWithFlags(fpms,
+ master_derive, &params, key_derive,
+ CKA_DERIVE, 0, keyFlags);
+ if (pwSpec->master_secret == NULL) {
+ pwSpec->master_secret = fpms; /* use the fpms as the master. */
+ fpms = NULL;
+ }
+ }
+ if (fpms) {
+ PK11_FreeSymKey(fpms);
+ }
+ }
+ if (pwSpec->master_secret == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
+ return rv;
+ }
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11) {
+ SECItem * keydata;
+ /* In hope of doing a "double bypass",
+ * need to extract the master secret's value from the key object
+ * and store it raw in the sslSocket struct.
+ */
+ rv = PK11_ExtractKeyValue(pwSpec->master_secret);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ /* This returns the address of the secItem inside the key struct,
+ * not a copy or a reference. So, there's no need to free it.
+ */
+ keydata = PK11_GetKeyData(pwSpec->master_secret);
+ if (keydata && keydata->len <= sizeof pwSpec->raw_master_secret) {
+ memcpy(pwSpec->raw_master_secret, keydata->data, keydata->len);
+ pwSpec->msItem.data = pwSpec->raw_master_secret;
+ pwSpec->msItem.len = keydata->len;
+ } else {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ }
+#endif
+ return SECSuccess;
+}
+
+
+/*
+ * Derive encryption and MAC Keys (and IVs) from master secret
+ * Sets a useful error code when returning SECFailure.
+ *
+ * Called only from ssl3_InitPendingCipherSpec(),
+ * which in turn is called from
+ * sendRSAClientKeyExchange (for Full handshake)
+ * sendDHClientKeyExchange (for Full handshake)
+ * ssl3_HandleClientKeyExchange (for Full handshake)
+ * ssl3_HandleServerHello (for session restart)
+ * ssl3_HandleClientHello (for session restart)
+ * Caller MUST hold the specWriteLock, and SSL3HandshakeLock.
+ * ssl3_InitPendingCipherSpec does that.
+ *
+ */
+static SECStatus
+ssl3_DeriveConnectionKeysPKCS11(sslSocket *ss)
+{
+ ssl3CipherSpec * pwSpec = ss->ssl3.pwSpec;
+ const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def;
+ unsigned char * cr = (unsigned char *)&ss->ssl3.hs.client_random;
+ unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random;
+ PRBool isTLS = (PRBool)(kea_def->tls_keygen ||
+ (pwSpec->version > SSL_LIBRARY_VERSION_3_0));
+ PRBool isTLS12=
+ (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
+ /* following variables used in PKCS11 path */
+ const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def;
+ PK11SlotInfo * slot = NULL;
+ PK11SymKey * symKey = NULL;
+ void * pwArg = ss->pkcs11PinArg;
+ int keySize;
+ CK_SSL3_KEY_MAT_PARAMS key_material_params;
+ CK_SSL3_KEY_MAT_OUT returnedKeys;
+ CK_MECHANISM_TYPE key_derive;
+ CK_MECHANISM_TYPE bulk_mechanism;
+ SSLCipherAlgorithm calg;
+ SECItem params;
+ PRBool skipKeysAndIVs = (PRBool)(cipher_def->calg == calg_null);
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
+ PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
+
+ if (!pwSpec->master_secret) {
+ PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
+ return SECFailure;
+ }
+ /*
+ * generate the key material
+ */
+ key_material_params.ulMacSizeInBits = pwSpec->mac_size * BPB;
+ key_material_params.ulKeySizeInBits = cipher_def->secret_key_size* BPB;
+ key_material_params.ulIVSizeInBits = cipher_def->iv_size * BPB;
+ if (cipher_def->type == type_block &&
+ pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
+ /* Block ciphers in >= TLS 1.1 use a per-record, explicit IV. */
+ key_material_params.ulIVSizeInBits = 0;
+ memset(pwSpec->client.write_iv, 0, cipher_def->iv_size);
+ memset(pwSpec->server.write_iv, 0, cipher_def->iv_size);
+ }
+
+ key_material_params.bIsExport = (CK_BBOOL)(kea_def->is_limited);
+
+ key_material_params.RandomInfo.pClientRandom = cr;
+ key_material_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
+ key_material_params.RandomInfo.pServerRandom = sr;
+ key_material_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
+ key_material_params.pReturnedKeyMaterial = &returnedKeys;
+
+ returnedKeys.pIVClient = pwSpec->client.write_iv;
+ returnedKeys.pIVServer = pwSpec->server.write_iv;
+ keySize = cipher_def->key_size;
+
+ if (skipKeysAndIVs) {
+ keySize = 0;
+ key_material_params.ulKeySizeInBits = 0;
+ key_material_params.ulIVSizeInBits = 0;
+ returnedKeys.pIVClient = NULL;
+ returnedKeys.pIVServer = NULL;
+ }
+
+ calg = cipher_def->calg;
+ PORT_Assert( alg2Mech[calg].calg == calg);
+ bulk_mechanism = alg2Mech[calg].cmech;
+
+ params.data = (unsigned char *)&key_material_params;
+ params.len = sizeof(key_material_params);
+
+ if (isTLS12) {
+ key_derive = CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256;
+ } else if (isTLS) {
+ key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
+ } else {
+ key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE;
+ }
+
+ /* CKM_SSL3_KEY_AND_MAC_DERIVE is defined to set ENCRYPT, DECRYPT, and
+ * DERIVE by DEFAULT */
+ symKey = PK11_Derive(pwSpec->master_secret, key_derive, &params,
+ bulk_mechanism, CKA_ENCRYPT, keySize);
+ if (!symKey) {
+ ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
+ return SECFailure;
+ }
+ /* we really should use the actual mac'ing mechanism here, but we
+ * don't because these types are used to map keytype anyway and both
+ * mac's map to the same keytype.
+ */
+ slot = PK11_GetSlotFromKey(symKey);
+
+ PK11_FreeSlot(slot); /* slot is held until the key is freed */
+ pwSpec->client.write_mac_key =
+ PK11_SymKeyFromHandle(slot, symKey, PK11_OriginDerive,
+ CKM_SSL3_SHA1_MAC, returnedKeys.hClientMacSecret, PR_TRUE, pwArg);
+ if (pwSpec->client.write_mac_key == NULL ) {
+ goto loser; /* loser sets err */
+ }
+ pwSpec->server.write_mac_key =
+ PK11_SymKeyFromHandle(slot, symKey, PK11_OriginDerive,
+ CKM_SSL3_SHA1_MAC, returnedKeys.hServerMacSecret, PR_TRUE, pwArg);
+ if (pwSpec->server.write_mac_key == NULL ) {
+ goto loser; /* loser sets err */
+ }
+ if (!skipKeysAndIVs) {
+ pwSpec->client.write_key =
+ PK11_SymKeyFromHandle(slot, symKey, PK11_OriginDerive,
+ bulk_mechanism, returnedKeys.hClientKey, PR_TRUE, pwArg);
+ if (pwSpec->client.write_key == NULL ) {
+ goto loser; /* loser sets err */
+ }
+ pwSpec->server.write_key =
+ PK11_SymKeyFromHandle(slot, symKey, PK11_OriginDerive,
+ bulk_mechanism, returnedKeys.hServerKey, PR_TRUE, pwArg);
+ if (pwSpec->server.write_key == NULL ) {
+ goto loser; /* loser sets err */
+ }
+ }
+ PK11_FreeSymKey(symKey);
+ return SECSuccess;
+
+
+loser:
+ if (symKey) PK11_FreeSymKey(symKey);
+ ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
+ return SECFailure;
+}
+
+/* ssl3_InitHandshakeHashes creates handshake hash contexts and hashes in
+ * buffered messages in ss->ssl3.hs.messages. */
+static SECStatus
+ssl3_InitHandshakeHashes(sslSocket *ss)
+{
+ SSL_TRC(30,("%d: SSL3[%d]: start handshake hashes", SSL_GETPID(), ss->fd));
+
+ PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_unknown);
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11) {
+ PORT_Assert(!ss->ssl3.hs.sha_obj && !ss->ssl3.hs.sha_clone);
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+ /* If we ever support ciphersuites where the PRF hash isn't SHA-256
+ * then this will need to be updated. */
+ ss->ssl3.hs.sha_obj = HASH_GetRawHashObject(HASH_AlgSHA256);
+ if (!ss->ssl3.hs.sha_obj) {
+ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+ return SECFailure;
+ }
+ ss->ssl3.hs.sha_clone = (void (*)(void *, void *))SHA256_Clone;
+ ss->ssl3.hs.hashType = handshake_hash_single;
+ ss->ssl3.hs.sha_obj->begin(ss->ssl3.hs.sha_cx);
+ } else {
+ ss->ssl3.hs.hashType = handshake_hash_combo;
+ MD5_Begin((MD5Context *)ss->ssl3.hs.md5_cx);
+ SHA1_Begin((SHA1Context *)ss->ssl3.hs.sha_cx);
+ }
+ } else
+#endif
+ {
+ PORT_Assert(!ss->ssl3.hs.md5 && !ss->ssl3.hs.sha);
+ /*
+ * note: We should probably lookup an SSL3 slot for these
+ * handshake hashes in hopes that we wind up with the same slots
+ * that the master secret will wind up in ...
+ */
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+ /* If we ever support ciphersuites where the PRF hash isn't SHA-256
+ * then this will need to be updated. */
+ ss->ssl3.hs.sha = PK11_CreateDigestContext(SEC_OID_SHA256);
+ if (ss->ssl3.hs.sha == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ return SECFailure;
+ }
+ ss->ssl3.hs.hashType = handshake_hash_single;
+
+ if (PK11_DigestBegin(ss->ssl3.hs.sha) != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+ return SECFailure;
+ }
+ } else {
+ /* Both ss->ssl3.hs.md5 and ss->ssl3.hs.sha should be NULL or
+ * created successfully. */
+ ss->ssl3.hs.md5 = PK11_CreateDigestContext(SEC_OID_MD5);
+ if (ss->ssl3.hs.md5 == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
+ return SECFailure;
+ }
+ ss->ssl3.hs.sha = PK11_CreateDigestContext(SEC_OID_SHA1);
+ if (ss->ssl3.hs.sha == NULL) {
+ PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE);
+ ss->ssl3.hs.md5 = NULL;
+ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ return SECFailure;
+ }
+ ss->ssl3.hs.hashType = handshake_hash_combo;
+
+ if (PK11_DigestBegin(ss->ssl3.hs.md5) != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
+ return SECFailure;
+ }
+ if (PK11_DigestBegin(ss->ssl3.hs.sha) != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ return SECFailure;
+ }
+ }
+ }
+
+ if (ss->ssl3.hs.messages.len > 0) {
+ if (ssl3_UpdateHandshakeHashes(ss, ss->ssl3.hs.messages.buf,
+ ss->ssl3.hs.messages.len) !=
+ SECSuccess) {
+ return SECFailure;
+ }
+ PORT_Free(ss->ssl3.hs.messages.buf);
+ ss->ssl3.hs.messages.buf = NULL;
+ ss->ssl3.hs.messages.len = 0;
+ ss->ssl3.hs.messages.space = 0;
+ }
+
+ return SECSuccess;
+}
+
+static SECStatus
+ssl3_RestartHandshakeHashes(sslSocket *ss)
+{
+ SECStatus rv = SECSuccess;
+
+ SSL_TRC(30,("%d: SSL3[%d]: reset handshake hashes",
+ SSL_GETPID(), ss->fd ));
+ ss->ssl3.hs.hashType = handshake_hash_unknown;
+ ss->ssl3.hs.messages.len = 0;
+#ifndef NO_PKCS11_BYPASS
+ ss->ssl3.hs.sha_obj = NULL;
+ ss->ssl3.hs.sha_clone = NULL;
+#endif
+ if (ss->ssl3.hs.md5) {
+ PK11_DestroyContext(ss->ssl3.hs.md5,PR_TRUE);
+ ss->ssl3.hs.md5 = NULL;
+ }
+ if (ss->ssl3.hs.sha) {
+ PK11_DestroyContext(ss->ssl3.hs.sha,PR_TRUE);
+ ss->ssl3.hs.sha = NULL;
+ }
+ return rv;
+}
+
+/*
+ * Handshake messages
+ */
+/* Called from ssl3_InitHandshakeHashes()
+** ssl3_AppendHandshake()
+** ssl3_StartHandshakeHash()
+** ssl3_HandleV2ClientHello()
+** ssl3_HandleHandshakeMessage()
+** Caller must hold the ssl3Handshake lock.
+*/
+static SECStatus
+ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b,
+ unsigned int l)
+{
+ SECStatus rv = SECSuccess;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ /* We need to buffer the handshake messages until we have established
+ * which handshake hash function to use. */
+ if (ss->ssl3.hs.hashType == handshake_hash_unknown) {
+ return sslBuffer_Append(&ss->ssl3.hs.messages, b, l);
+ }
+
+ PRINT_BUF(90, (NULL, "handshake hash input:", b, l));
+
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11) {
+ if (ss->ssl3.hs.hashType == handshake_hash_single) {
+ ss->ssl3.hs.sha_obj->update(ss->ssl3.hs.sha_cx, b, l);
+ } else {
+ MD5_Update((MD5Context *)ss->ssl3.hs.md5_cx, b, l);
+ SHA1_Update((SHA1Context *)ss->ssl3.hs.sha_cx, b, l);
+ }
+ return rv;
+ }
+#endif
+ if (ss->ssl3.hs.hashType == handshake_hash_single) {
+ rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+ return rv;
+ }
+ } else {
+ rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
+ return rv;
+ }
+ rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ return rv;
+ }
+ }
+ return rv;
+}
+
+/**************************************************************************
+ * Append Handshake functions.
+ * All these functions set appropriate error codes.
+ * Most rely on ssl3_AppendHandshake to set the error code.
+ **************************************************************************/
+SECStatus
+ssl3_AppendHandshake(sslSocket *ss, const void *void_src, PRInt32 bytes)
+{
+ unsigned char * src = (unsigned char *)void_src;
+ int room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len;
+ SECStatus rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); /* protects sendBuf. */
+
+ if (!bytes)
+ return SECSuccess;
+ if (ss->sec.ci.sendBuf.space < MAX_SEND_BUF_LENGTH && room < bytes) {
+ rv = sslBuffer_Grow(&ss->sec.ci.sendBuf, PR_MAX(MIN_SEND_BUF_LENGTH,
+ PR_MIN(MAX_SEND_BUF_LENGTH, ss->sec.ci.sendBuf.len + bytes)));
+ if (rv != SECSuccess)
+ return rv; /* sslBuffer_Grow has set a memory error code. */
+ room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len;
+ }
+
+ PRINT_BUF(60, (ss, "Append to Handshake", (unsigned char*)void_src, bytes));
+ rv = ssl3_UpdateHandshakeHashes(ss, src, bytes);
+ if (rv != SECSuccess)
+ return rv; /* error code set by ssl3_UpdateHandshakeHashes */
+
+ while (bytes > room) {
+ if (room > 0)
+ PORT_Memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, src,
+ room);
+ ss->sec.ci.sendBuf.len += room;
+ rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
+ if (rv != SECSuccess) {
+ return rv; /* error code set by ssl3_FlushHandshake */
+ }
+ bytes -= room;
+ src += room;
+ room = ss->sec.ci.sendBuf.space;
+ PORT_Assert(ss->sec.ci.sendBuf.len == 0);
+ }
+ PORT_Memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, src, bytes);
+ ss->sec.ci.sendBuf.len += bytes;
+ return SECSuccess;
+}
+
+SECStatus
+ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num, PRInt32 lenSize)
+{
+ SECStatus rv;
+ PRUint8 b[4];
+ PRUint8 * p = b;
+
+ switch (lenSize) {
+ case 4:
+ *p++ = (num >> 24) & 0xff;
+ case 3:
+ *p++ = (num >> 16) & 0xff;
+ case 2:
+ *p++ = (num >> 8) & 0xff;
+ case 1:
+ *p = num & 0xff;
+ }
+ SSL_TRC(60, ("%d: number:", SSL_GETPID()));
+ rv = ssl3_AppendHandshake(ss, &b[0], lenSize);
+ return rv; /* error code set by AppendHandshake, if applicable. */
+}
+
+SECStatus
+ssl3_AppendHandshakeVariable(
+ sslSocket *ss, const SSL3Opaque *src, PRInt32 bytes, PRInt32 lenSize)
+{
+ SECStatus rv;
+
+ PORT_Assert((bytes < (1<<8) && lenSize == 1) ||
+ (bytes < (1L<<16) && lenSize == 2) ||
+ (bytes < (1L<<24) && lenSize == 3));
+
+ SSL_TRC(60,("%d: append variable:", SSL_GETPID()));
+ rv = ssl3_AppendHandshakeNumber(ss, bytes, lenSize);
+ if (rv != SECSuccess) {
+ return rv; /* error code set by AppendHandshake, if applicable. */
+ }
+ SSL_TRC(60, ("data:"));
+ rv = ssl3_AppendHandshake(ss, src, bytes);
+ return rv; /* error code set by AppendHandshake, if applicable. */
+}
+
+SECStatus
+ssl3_AppendHandshakeHeader(sslSocket *ss, SSL3HandshakeType t, PRUint32 length)
+{
+ SECStatus rv;
+
+ /* If we already have a message in place, we need to enqueue it.
+ * This empties the buffer. This is a convenient place to call
+ * dtls_StageHandshakeMessage to mark the message boundary.
+ */
+ if (IS_DTLS(ss)) {
+ rv = dtls_StageHandshakeMessage(ss);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ }
+
+ SSL_TRC(30,("%d: SSL3[%d]: append handshake header: type %s",
+ SSL_GETPID(), ss->fd, ssl3_DecodeHandshakeType(t)));
+
+ rv = ssl3_AppendHandshakeNumber(ss, t, 1);
+ if (rv != SECSuccess) {
+ return rv; /* error code set by AppendHandshake, if applicable. */
+ }
+ rv = ssl3_AppendHandshakeNumber(ss, length, 3);
+ if (rv != SECSuccess) {
+ return rv; /* error code set by AppendHandshake, if applicable. */
+ }
+
+ if (IS_DTLS(ss)) {
+ /* Note that we make an unfragmented message here. We fragment in the
+ * transmission code, if necessary */
+ rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.sendMessageSeq, 2);
+ if (rv != SECSuccess) {
+ return rv; /* error code set by AppendHandshake, if applicable. */
+ }
+ ss->ssl3.hs.sendMessageSeq++;
+
+ /* 0 is the fragment offset, because it's not fragmented yet */
+ rv = ssl3_AppendHandshakeNumber(ss, 0, 3);
+ if (rv != SECSuccess) {
+ return rv; /* error code set by AppendHandshake, if applicable. */
+ }
+
+ /* Fragment length -- set to the packet length because not fragmented */
+ rv = ssl3_AppendHandshakeNumber(ss, length, 3);
+ if (rv != SECSuccess) {
+ return rv; /* error code set by AppendHandshake, if applicable. */
+ }
+ }
+
+ return rv; /* error code set by AppendHandshake, if applicable. */
+}
+
+/* ssl3_AppendSignatureAndHashAlgorithm appends the serialisation of
+ * |sigAndHash| to the current handshake message. */
+SECStatus
+ssl3_AppendSignatureAndHashAlgorithm(
+ sslSocket *ss, const SSL3SignatureAndHashAlgorithm* sigAndHash)
+{
+ unsigned char serialized[2];
+
+ serialized[0] = ssl3_OIDToTLSHashAlgorithm(sigAndHash->hashAlg);
+ if (serialized[0] == 0) {
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
+ return SECFailure;
+ }
+
+ serialized[1] = sigAndHash->sigAlg;
+
+ return ssl3_AppendHandshake(ss, serialized, sizeof(serialized));
+}
+
+/**************************************************************************
+ * Consume Handshake functions.
+ *
+ * All data used in these functions is protected by two locks,
+ * the RecvBufLock and the SSL3HandshakeLock
+ **************************************************************************/
+
+/* Read up the next "bytes" number of bytes from the (decrypted) input
+ * stream "b" (which is *length bytes long). Copy them into buffer "v".
+ * Reduces *length by bytes. Advances *b by bytes.
+ *
+ * If this function returns SECFailure, it has already sent an alert,
+ * and has set a generic error code. The caller should probably
+ * override the generic error code by setting another.
+ */
+SECStatus
+ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, SSL3Opaque **b,
+ PRUint32 *length)
+{
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ if ((PRUint32)bytes > *length) {
+ return ssl3_DecodeError(ss);
+ }
+ PORT_Memcpy(v, *b, bytes);
+ PRINT_BUF(60, (ss, "consume bytes:", *b, bytes));
+ *b += bytes;
+ *length -= bytes;
+ return SECSuccess;
+}
+
+/* Read up the next "bytes" number of bytes from the (decrypted) input
+ * stream "b" (which is *length bytes long), and interpret them as an
+ * integer in network byte order. Returns the received value.
+ * Reduces *length by bytes. Advances *b by bytes.
+ *
+ * Returns SECFailure (-1) on failure.
+ * This value is indistinguishable from the equivalent received value.
+ * Only positive numbers are to be received this way.
+ * Thus, the largest value that may be sent this way is 0x7fffffff.
+ * On error, an alert has been sent, and a generic error code has been set.
+ */
+PRInt32
+ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, SSL3Opaque **b,
+ PRUint32 *length)
+{
+ PRUint8 *buf = *b;
+ int i;
+ PRInt32 num = 0;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ PORT_Assert( bytes <= sizeof num);
+
+ if ((PRUint32)bytes > *length) {
+ return ssl3_DecodeError(ss);
+ }
+ PRINT_BUF(60, (ss, "consume bytes:", *b, bytes));
+
+ for (i = 0; i < bytes; i++)
+ num = (num << 8) + buf[i];
+ *b += bytes;
+ *length -= bytes;
+ return num;
+}
+
+/* Read in two values from the incoming decrypted byte stream "b", which is
+ * *length bytes long. The first value is a number whose size is "bytes"
+ * bytes long. The second value is a byte-string whose size is the value
+ * of the first number received. The latter byte-string, and its length,
+ * is returned in the SECItem i.
+ *
+ * Returns SECFailure (-1) on failure.
+ * On error, an alert has been sent, and a generic error code has been set.
+ *
+ * RADICAL CHANGE for NSS 3.11. All callers of this function make copies
+ * of the data returned in the SECItem *i, so making a copy of it here
+ * is simply wasteful. So, This function now just sets SECItem *i to
+ * point to the values in the buffer **b.
+ */
+SECStatus
+ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRInt32 bytes,
+ SSL3Opaque **b, PRUint32 *length)
+{
+ PRInt32 count;
+
+ PORT_Assert(bytes <= 3);
+ i->len = 0;
+ i->data = NULL;
+ count = ssl3_ConsumeHandshakeNumber(ss, bytes, b, length);
+ if (count < 0) { /* Can't test for SECSuccess here. */
+ return SECFailure;
+ }
+ if (count > 0) {
+ if ((PRUint32)count > *length) {
+ return ssl3_DecodeError(ss);
+ }
+ i->data = *b;
+ i->len = count;
+ *b += count;
+ *length -= count;
+ }
+ return SECSuccess;
+}
+
+/* tlsHashOIDMap contains the mapping between TLS hash identifiers and the
+ * SECOidTag used internally by NSS. */
+static const struct {
+ int tlsHash;
+ SECOidTag oid;
+} tlsHashOIDMap[] = {
+ { tls_hash_md5, SEC_OID_MD5 },
+ { tls_hash_sha1, SEC_OID_SHA1 },
+ { tls_hash_sha224, SEC_OID_SHA224 },
+ { tls_hash_sha256, SEC_OID_SHA256 },
+ { tls_hash_sha384, SEC_OID_SHA384 },
+ { tls_hash_sha512, SEC_OID_SHA512 }
+};
+
+/* ssl3_TLSHashAlgorithmToOID converts a TLS hash identifier into an OID value.
+ * If the hash is not recognised, SEC_OID_UNKNOWN is returned.
+ *
+ * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
+SECOidTag
+ssl3_TLSHashAlgorithmToOID(int hashFunc)
+{
+ unsigned int i;
+
+ for (i = 0; i < PR_ARRAY_SIZE(tlsHashOIDMap); i++) {
+ if (hashFunc == tlsHashOIDMap[i].tlsHash) {
+ return tlsHashOIDMap[i].oid;
+ }
+ }
+ return SEC_OID_UNKNOWN;
+}
+
+/* ssl3_OIDToTLSHashAlgorithm converts an OID to a TLS hash algorithm
+ * identifier. If the hash is not recognised, zero is returned.
+ *
+ * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
+static int
+ssl3_OIDToTLSHashAlgorithm(SECOidTag oid)
+{
+ unsigned int i;
+
+ for (i = 0; i < PR_ARRAY_SIZE(tlsHashOIDMap); i++) {
+ if (oid == tlsHashOIDMap[i].oid) {
+ return tlsHashOIDMap[i].tlsHash;
+ }
+ }
+ return 0;
+}
+
+/* ssl3_TLSSignatureAlgorithmForKeyType returns the TLS 1.2 signature algorithm
+ * identifier for a given KeyType. */
+static SECStatus
+ssl3_TLSSignatureAlgorithmForKeyType(KeyType keyType,
+ TLSSignatureAlgorithm *out)
+{
+ switch (keyType) {
+ case rsaKey:
+ *out = tls_sig_rsa;
+ return SECSuccess;
+ case dsaKey:
+ *out = tls_sig_dsa;
+ return SECSuccess;
+ case ecKey:
+ *out = tls_sig_ecdsa;
+ return SECSuccess;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ return SECFailure;
+ }
+}
+
+/* ssl3_TLSSignatureAlgorithmForCertificate returns the TLS 1.2 signature
+ * algorithm identifier for the given certificate. */
+static SECStatus
+ssl3_TLSSignatureAlgorithmForCertificate(CERTCertificate *cert,
+ TLSSignatureAlgorithm *out)
+{
+ SECKEYPublicKey *key;
+ KeyType keyType;
+
+ key = CERT_ExtractPublicKey(cert);
+ if (key == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
+ return SECFailure;
+ }
+
+ keyType = key->keyType;
+ SECKEY_DestroyPublicKey(key);
+ return ssl3_TLSSignatureAlgorithmForKeyType(keyType, out);
+}
+
+/* ssl3_CheckSignatureAndHashAlgorithmConsistency checks that the signature
+ * algorithm identifier in |sigAndHash| is consistent with the public key in
+ * |cert|. If so, SECSuccess is returned. Otherwise, PORT_SetError is called
+ * and SECFailure is returned. */
+SECStatus
+ssl3_CheckSignatureAndHashAlgorithmConsistency(
+ const SSL3SignatureAndHashAlgorithm *sigAndHash, CERTCertificate* cert)
+{
+ SECStatus rv;
+ TLSSignatureAlgorithm sigAlg;
+
+ rv = ssl3_TLSSignatureAlgorithmForCertificate(cert, &sigAlg);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ if (sigAlg != sigAndHash->sigAlg) {
+ PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+/* ssl3_ConsumeSignatureAndHashAlgorithm reads a SignatureAndHashAlgorithm
+ * structure from |b| and puts the resulting value into |out|. |b| and |length|
+ * are updated accordingly.
+ *
+ * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
+SECStatus
+ssl3_ConsumeSignatureAndHashAlgorithm(sslSocket *ss,
+ SSL3Opaque **b,
+ PRUint32 *length,
+ SSL3SignatureAndHashAlgorithm *out)
+{
+ unsigned char bytes[2];
+ SECStatus rv;
+
+ rv = ssl3_ConsumeHandshake(ss, bytes, sizeof(bytes), b, length);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ out->hashAlg = ssl3_TLSHashAlgorithmToOID(bytes[0]);
+ if (out->hashAlg == SEC_OID_UNKNOWN) {
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
+ return SECFailure;
+ }
+
+ out->sigAlg = bytes[1];
+ return SECSuccess;
+}
+
+/**************************************************************************
+ * end of Consume Handshake functions.
+ **************************************************************************/
+
+/* Extract the hashes of handshake messages to this point.
+ * Called from ssl3_SendCertificateVerify
+ * ssl3_SendFinished
+ * ssl3_HandleHandshakeMessage
+ *
+ * Caller must hold the SSL3HandshakeLock.
+ * Caller must hold a read or write lock on the Spec R/W lock.
+ * (There is presently no way to assert on a Read lock.)
+ */
+static SECStatus
+ssl3_ComputeHandshakeHashes(sslSocket * ss,
+ ssl3CipherSpec *spec, /* uses ->master_secret */
+ SSL3Hashes * hashes, /* output goes here. */
+ PRUint32 sender)
+{
+ SECStatus rv = SECSuccess;
+ PRBool isTLS = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0);
+ unsigned int outLength;
+ SSL3Opaque md5_inner[MAX_MAC_LENGTH];
+ SSL3Opaque sha_inner[MAX_MAC_LENGTH];
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ hashes->hashAlg = SEC_OID_UNKNOWN;
+
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11 &&
+ ss->ssl3.hs.hashType == handshake_hash_single) {
+ /* compute them without PKCS11 */
+ PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS];
+
+ if (!spec->msItem.data) {
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
+ return SECFailure;
+ }
+
+ ss->ssl3.hs.sha_clone(sha_cx, ss->ssl3.hs.sha_cx);
+ ss->ssl3.hs.sha_obj->end(sha_cx, hashes->u.raw, &hashes->len,
+ sizeof(hashes->u.raw));
+
+ PRINT_BUF(60, (NULL, "SHA-256: result", hashes->u.raw, hashes->len));
+
+ /* If we ever support ciphersuites where the PRF hash isn't SHA-256
+ * then this will need to be updated. */
+ hashes->hashAlg = SEC_OID_SHA256;
+ rv = SECSuccess;
+ } else if (ss->opt.bypassPKCS11) {
+ /* compute them without PKCS11 */
+ PRUint64 md5_cx[MAX_MAC_CONTEXT_LLONGS];
+ PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS];
+
+#define md5cx ((MD5Context *)md5_cx)
+#define shacx ((SHA1Context *)sha_cx)
+
+ if (!spec->msItem.data) {
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
+ return SECFailure;
+ }
+
+ MD5_Clone (md5cx, (MD5Context *)ss->ssl3.hs.md5_cx);
+ SHA1_Clone(shacx, (SHA1Context *)ss->ssl3.hs.sha_cx);
+
+ if (!isTLS) {
+ /* compute hashes for SSL3. */
+ unsigned char s[4];
+
+ s[0] = (unsigned char)(sender >> 24);
+ s[1] = (unsigned char)(sender >> 16);
+ s[2] = (unsigned char)(sender >> 8);
+ s[3] = (unsigned char)sender;
+
+ if (sender != 0) {
+ MD5_Update(md5cx, s, 4);
+ PRINT_BUF(95, (NULL, "MD5 inner: sender", s, 4));
+ }
+
+ PRINT_BUF(95, (NULL, "MD5 inner: MAC Pad 1", mac_pad_1,
+ mac_defs[mac_md5].pad_size));
+
+ MD5_Update(md5cx, spec->msItem.data, spec->msItem.len);
+ MD5_Update(md5cx, mac_pad_1, mac_defs[mac_md5].pad_size);
+ MD5_End(md5cx, md5_inner, &outLength, MD5_LENGTH);
+
+ PRINT_BUF(95, (NULL, "MD5 inner: result", md5_inner, outLength));
+
+ if (sender != 0) {
+ SHA1_Update(shacx, s, 4);
+ PRINT_BUF(95, (NULL, "SHA inner: sender", s, 4));
+ }
+
+ PRINT_BUF(95, (NULL, "SHA inner: MAC Pad 1", mac_pad_1,
+ mac_defs[mac_sha].pad_size));
+
+ SHA1_Update(shacx, spec->msItem.data, spec->msItem.len);
+ SHA1_Update(shacx, mac_pad_1, mac_defs[mac_sha].pad_size);
+ SHA1_End(shacx, sha_inner, &outLength, SHA1_LENGTH);
+
+ PRINT_BUF(95, (NULL, "SHA inner: result", sha_inner, outLength));
+ PRINT_BUF(95, (NULL, "MD5 outer: MAC Pad 2", mac_pad_2,
+ mac_defs[mac_md5].pad_size));
+ PRINT_BUF(95, (NULL, "MD5 outer: MD5 inner", md5_inner, MD5_LENGTH));
+
+ MD5_Begin(md5cx);
+ MD5_Update(md5cx, spec->msItem.data, spec->msItem.len);
+ MD5_Update(md5cx, mac_pad_2, mac_defs[mac_md5].pad_size);
+ MD5_Update(md5cx, md5_inner, MD5_LENGTH);
+ }
+ MD5_End(md5cx, hashes->u.s.md5, &outLength, MD5_LENGTH);
+
+ PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->u.s.md5, MD5_LENGTH));
+
+ if (!isTLS) {
+ PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2,
+ mac_defs[mac_sha].pad_size));
+ PRINT_BUF(95, (NULL, "SHA outer: SHA inner", sha_inner, SHA1_LENGTH));
+
+ SHA1_Begin(shacx);
+ SHA1_Update(shacx, spec->msItem.data, spec->msItem.len);
+ SHA1_Update(shacx, mac_pad_2, mac_defs[mac_sha].pad_size);
+ SHA1_Update(shacx, sha_inner, SHA1_LENGTH);
+ }
+ SHA1_End(shacx, hashes->u.s.sha, &outLength, SHA1_LENGTH);
+
+ PRINT_BUF(60, (NULL, "SHA outer: result", hashes->u.s.sha, SHA1_LENGTH));
+
+ hashes->len = MD5_LENGTH + SHA1_LENGTH;
+ rv = SECSuccess;
+#undef md5cx
+#undef shacx
+ } else
+#endif
+ if (ss->ssl3.hs.hashType == handshake_hash_single) {
+ /* compute hashes with PKCS11 */
+ PK11Context *h;
+ unsigned int stateLen;
+ unsigned char stackBuf[1024];
+ unsigned char *stateBuf = NULL;
+
+ if (!spec->master_secret) {
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
+ return SECFailure;
+ }
+
+ h = ss->ssl3.hs.sha;
+ stateBuf = PK11_SaveContextAlloc(h, stackBuf,
+ sizeof(stackBuf), &stateLen);
+ if (stateBuf == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+ goto tls12_loser;
+ }
+ rv |= PK11_DigestFinal(h, hashes->u.raw, &hashes->len,
+ sizeof(hashes->u.raw));
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+ rv = SECFailure;
+ goto tls12_loser;
+ }
+ /* If we ever support ciphersuites where the PRF hash isn't SHA-256
+ * then this will need to be updated. */
+ hashes->hashAlg = SEC_OID_SHA256;
+ rv = SECSuccess;
+
+tls12_loser:
+ if (stateBuf) {
+ if (PK11_RestoreContext(h, stateBuf, stateLen) != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+ rv = SECFailure;
+ }
+ if (stateBuf != stackBuf) {
+ PORT_ZFree(stateBuf, stateLen);
+ }
+ }
+ } else {
+ /* compute hashes with PKCS11 */
+ PK11Context * md5;
+ PK11Context * sha = NULL;
+ unsigned char *md5StateBuf = NULL;
+ unsigned char *shaStateBuf = NULL;
+ unsigned int md5StateLen, shaStateLen;
+ unsigned char md5StackBuf[256];
+ unsigned char shaStackBuf[512];
+
+ if (!spec->master_secret) {
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
+ return SECFailure;
+ }
+
+ md5StateBuf = PK11_SaveContextAlloc(ss->ssl3.hs.md5, md5StackBuf,
+ sizeof md5StackBuf, &md5StateLen);
+ if (md5StateBuf == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
+ goto loser;
+ }
+ md5 = ss->ssl3.hs.md5;
+
+ shaStateBuf = PK11_SaveContextAlloc(ss->ssl3.hs.sha, shaStackBuf,
+ sizeof shaStackBuf, &shaStateLen);
+ if (shaStateBuf == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ goto loser;
+ }
+ sha = ss->ssl3.hs.sha;
+
+ if (!isTLS) {
+ /* compute hashes for SSL3. */
+ unsigned char s[4];
+
+ s[0] = (unsigned char)(sender >> 24);
+ s[1] = (unsigned char)(sender >> 16);
+ s[2] = (unsigned char)(sender >> 8);
+ s[3] = (unsigned char)sender;
+
+ if (sender != 0) {
+ rv |= PK11_DigestOp(md5, s, 4);
+ PRINT_BUF(95, (NULL, "MD5 inner: sender", s, 4));
+ }
+
+ PRINT_BUF(95, (NULL, "MD5 inner: MAC Pad 1", mac_pad_1,
+ mac_defs[mac_md5].pad_size));
+
+ rv |= PK11_DigestKey(md5,spec->master_secret);
+ rv |= PK11_DigestOp(md5, mac_pad_1, mac_defs[mac_md5].pad_size);
+ rv |= PK11_DigestFinal(md5, md5_inner, &outLength, MD5_LENGTH);
+ PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
+ rv = SECFailure;
+ goto loser;
+ }
+
+ PRINT_BUF(95, (NULL, "MD5 inner: result", md5_inner, outLength));
+
+ if (sender != 0) {
+ rv |= PK11_DigestOp(sha, s, 4);
+ PRINT_BUF(95, (NULL, "SHA inner: sender", s, 4));
+ }
+
+ PRINT_BUF(95, (NULL, "SHA inner: MAC Pad 1", mac_pad_1,
+ mac_defs[mac_sha].pad_size));
+
+ rv |= PK11_DigestKey(sha, spec->master_secret);
+ rv |= PK11_DigestOp(sha, mac_pad_1, mac_defs[mac_sha].pad_size);
+ rv |= PK11_DigestFinal(sha, sha_inner, &outLength, SHA1_LENGTH);
+ PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ rv = SECFailure;
+ goto loser;
+ }
+
+ PRINT_BUF(95, (NULL, "SHA inner: result", sha_inner, outLength));
+
+ PRINT_BUF(95, (NULL, "MD5 outer: MAC Pad 2", mac_pad_2,
+ mac_defs[mac_md5].pad_size));
+ PRINT_BUF(95, (NULL, "MD5 outer: MD5 inner", md5_inner, MD5_LENGTH));
+
+ rv |= PK11_DigestBegin(md5);
+ rv |= PK11_DigestKey(md5, spec->master_secret);
+ rv |= PK11_DigestOp(md5, mac_pad_2, mac_defs[mac_md5].pad_size);
+ rv |= PK11_DigestOp(md5, md5_inner, MD5_LENGTH);
+ }
+ rv |= PK11_DigestFinal(md5, hashes->u.s.md5, &outLength, MD5_LENGTH);
+ PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
+ rv = SECFailure;
+ goto loser;
+ }
+
+ PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->u.s.md5, MD5_LENGTH));
+
+ if (!isTLS) {
+ PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2,
+ mac_defs[mac_sha].pad_size));
+ PRINT_BUF(95, (NULL, "SHA outer: SHA inner", sha_inner, SHA1_LENGTH));
+
+ rv |= PK11_DigestBegin(sha);
+ rv |= PK11_DigestKey(sha,spec->master_secret);
+ rv |= PK11_DigestOp(sha, mac_pad_2, mac_defs[mac_sha].pad_size);
+ rv |= PK11_DigestOp(sha, sha_inner, SHA1_LENGTH);
+ }
+ rv |= PK11_DigestFinal(sha, hashes->u.s.sha, &outLength, SHA1_LENGTH);
+ PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ rv = SECFailure;
+ goto loser;
+ }
+
+ PRINT_BUF(60, (NULL, "SHA outer: result", hashes->u.s.sha, SHA1_LENGTH));
+
+ hashes->len = MD5_LENGTH + SHA1_LENGTH;
+ rv = SECSuccess;
+
+ loser:
+ if (md5StateBuf) {
+ if (PK11_RestoreContext(ss->ssl3.hs.md5, md5StateBuf, md5StateLen)
+ != SECSuccess)
+ {
+ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
+ rv = SECFailure;
+ }
+ if (md5StateBuf != md5StackBuf) {
+ PORT_ZFree(md5StateBuf, md5StateLen);
+ }
+ }
+ if (shaStateBuf) {
+ if (PK11_RestoreContext(ss->ssl3.hs.sha, shaStateBuf, shaStateLen)
+ != SECSuccess)
+ {
+ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ rv = SECFailure;
+ }
+ if (shaStateBuf != shaStackBuf) {
+ PORT_ZFree(shaStateBuf, shaStateLen);
+ }
+ }
+ }
+ return rv;
+}
+
+/*
+ * SSL 2 based implementations pass in the initial outbound buffer
+ * so that the handshake hash can contain the included information.
+ *
+ * Called from ssl2_BeginClientHandshake() in sslcon.c
+ */
+SECStatus
+ssl3_StartHandshakeHash(sslSocket *ss, unsigned char * buf, int length)
+{
+ SECStatus rv;
+
+ ssl_GetSSL3HandshakeLock(ss); /**************************************/
+
+ rv = ssl3_InitState(ss);
+ if (rv != SECSuccess) {
+ goto done; /* ssl3_InitState has set the error code. */
+ }
+ rv = ssl3_RestartHandshakeHashes(ss);
+ if (rv != SECSuccess) {
+ goto done;
+ }
+
+ PORT_Memset(&ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH);
+ PORT_Memcpy(
+ &ss->ssl3.hs.client_random.rand[SSL3_RANDOM_LENGTH - SSL_CHALLENGE_BYTES],
+ &ss->sec.ci.clientChallenge,
+ SSL_CHALLENGE_BYTES);
+
+ rv = ssl3_UpdateHandshakeHashes(ss, buf, length);
+ /* if it failed, ssl3_UpdateHandshakeHashes has set the error code. */
+
+done:
+ ssl_ReleaseSSL3HandshakeLock(ss); /**************************************/
+ return rv;
+}
+
+/**************************************************************************
+ * end of Handshake Hash functions.
+ * Begin Send and Handle functions for handshakes.
+ **************************************************************************/
+
+/* Called from ssl3_HandleHelloRequest(),
+ * ssl3_RedoHandshake()
+ * ssl2_BeginClientHandshake (when resuming ssl3 session)
+ * dtls_HandleHelloVerifyRequest(with resending=PR_TRUE)
+ */
+SECStatus
+ssl3_SendClientHello(sslSocket *ss, PRBool resending)
+{
+ sslSessionID * sid;
+ ssl3CipherSpec * cwSpec;
+ SECStatus rv;
+ int i;
+ int length;
+ int num_suites;
+ int actual_count = 0;
+ PRBool isTLS = PR_FALSE;
+ PRBool requestingResume = PR_FALSE;
+ PRInt32 total_exten_len = 0;
+ unsigned numCompressionMethods;
+ PRInt32 flags;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: send client_hello handshake", SSL_GETPID(),
+ ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
+
+ rv = ssl3_InitState(ss);
+ if (rv != SECSuccess) {
+ return rv; /* ssl3_InitState has set the error code. */
+ }
+ ss->ssl3.hs.sendingSCSV = PR_FALSE; /* Must be reset every handshake */
+ PORT_Assert(IS_DTLS(ss) || !resending);
+
+ /* We might be starting a session renegotiation in which case we should
+ * clear previous state.
+ */
+ PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData));
+
+ rv = ssl3_RestartHandshakeHashes(ss);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ /*
+ * During a renegotiation, ss->clientHelloVersion will be used again to
+ * work around a Windows SChannel bug. Ensure that it is still enabled.
+ */
+ if (ss->firstHsDone) {
+ if (SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
+ PORT_SetError(SSL_ERROR_SSL_DISABLED);
+ return SECFailure;
+ }
+
+ if (ss->clientHelloVersion < ss->vrange.min ||
+ ss->clientHelloVersion > ss->vrange.max) {
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+ return SECFailure;
+ }
+ }
+
+ /* We ignore ss->sec.ci.sid here, and use ssl_Lookup because Lookup
+ * handles expired entries and other details.
+ * XXX If we've been called from ssl2_BeginClientHandshake, then
+ * this lookup is duplicative and wasteful.
+ */
+ sid = (ss->opt.noCache) ? NULL
+ : ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID, ss->url);
+
+ /* We can't resume based on a different token. If the sid exists,
+ * make sure the token that holds the master secret still exists ...
+ * If we previously did client-auth, make sure that the token that holds
+ * the private key still exists, is logged in, hasn't been removed, etc.
+ */
+ if (sid) {
+ PRBool sidOK = PR_TRUE;
+ if (sid->u.ssl3.keys.msIsWrapped) {
+ /* Session key was wrapped, which means it was using PKCS11, */
+ PK11SlotInfo *slot = NULL;
+ if (sid->u.ssl3.masterValid && !ss->opt.bypassPKCS11) {
+ slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID,
+ sid->u.ssl3.masterSlotID);
+ }
+ if (slot == NULL) {
+ sidOK = PR_FALSE;
+ } else {
+ PK11SymKey *wrapKey = NULL;
+ if (!PK11_IsPresent(slot) ||
+ ((wrapKey = PK11_GetWrapKey(slot,
+ sid->u.ssl3.masterWrapIndex,
+ sid->u.ssl3.masterWrapMech,
+ sid->u.ssl3.masterWrapSeries,
+ ss->pkcs11PinArg)) == NULL) ) {
+ sidOK = PR_FALSE;
+ }
+ if (wrapKey) PK11_FreeSymKey(wrapKey);
+ PK11_FreeSlot(slot);
+ slot = NULL;
+ }
+ }
+ /* If we previously did client-auth, make sure that the token that
+ ** holds the private key still exists, is logged in, hasn't been
+ ** removed, etc.
+ */
+ if (sidOK && !ssl3_ClientAuthTokenPresent(sid)) {
+ sidOK = PR_FALSE;
+ }
+
+ /* TLS 1.0 (RFC 2246) Appendix E says:
+ * Whenever a client already knows the highest protocol known to
+ * a server (for example, when resuming a session), it should
+ * initiate the connection in that native protocol.
+ * So we pass sid->version to ssl3_NegotiateVersion() here, except
+ * when renegotiating.
+ *
+ * Windows SChannel compares the client_version inside the RSA
+ * EncryptedPreMasterSecret of a renegotiation with the
+ * client_version of the initial ClientHello rather than the
+ * ClientHello in the renegotiation. To work around this bug, we
+ * continue to use the client_version used in the initial
+ * ClientHello when renegotiating.
+ */
+ if (sidOK) {
+ if (ss->firstHsDone) {
+ /*
+ * The client_version of the initial ClientHello is still
+ * available in ss->clientHelloVersion. Ensure that
+ * sid->version is bounded within
+ * [ss->vrange.min, ss->clientHelloVersion], otherwise we
+ * can't use sid.
+ */
+ if (sid->version >= ss->vrange.min &&
+ sid->version <= ss->clientHelloVersion) {
+ ss->version = ss->clientHelloVersion;
+ } else {
+ sidOK = PR_FALSE;
+ }
+ } else {
+ if (ssl3_NegotiateVersion(ss, sid->version,
+ PR_FALSE) != SECSuccess) {
+ sidOK = PR_FALSE;
+ }
+ }
+ }
+
+ if (!sidOK) {
+ SSL_AtomicIncrementLong(& ssl3stats.sch_sid_cache_not_ok );
+ if (ss->sec.uncache)
+ (*ss->sec.uncache)(sid);
+ ssl_FreeSID(sid);
+ sid = NULL;
+ }
+ }
+
+ if (sid) {
+ requestingResume = PR_TRUE;
+ SSL_AtomicIncrementLong(& ssl3stats.sch_sid_cache_hits );
+
+ /* Are we attempting a stateless session resume? */
+ if (sid->version > SSL_LIBRARY_VERSION_3_0 &&
+ sid->u.ssl3.sessionTicket.ticket.data)
+ SSL_AtomicIncrementLong(& ssl3stats.sch_sid_stateless_resumes );
+
+ PRINT_BUF(4, (ss, "client, found session-id:", sid->u.ssl3.sessionID,
+ sid->u.ssl3.sessionIDLength));
+
+ ss->ssl3.policy = sid->u.ssl3.policy;
+ } else {
+ SSL_AtomicIncrementLong(& ssl3stats.sch_sid_cache_misses );
+
+ /*
+ * Windows SChannel compares the client_version inside the RSA
+ * EncryptedPreMasterSecret of a renegotiation with the
+ * client_version of the initial ClientHello rather than the
+ * ClientHello in the renegotiation. To work around this bug, we
+ * continue to use the client_version used in the initial
+ * ClientHello when renegotiating.
+ */
+ if (ss->firstHsDone) {
+ ss->version = ss->clientHelloVersion;
+ } else {
+ rv = ssl3_NegotiateVersion(ss, SSL_LIBRARY_VERSION_MAX_SUPPORTED,
+ PR_TRUE);
+ if (rv != SECSuccess)
+ return rv; /* error code was set */
+ }
+
+ sid = ssl3_NewSessionID(ss, PR_FALSE);
+ if (!sid) {
+ return SECFailure; /* memory error is set */
+ }
+ }
+
+ isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0);
+ ssl_GetSpecWriteLock(ss);
+ cwSpec = ss->ssl3.cwSpec;
+ if (cwSpec->mac_def->mac == mac_null) {
+ /* SSL records are not being MACed. */
+ cwSpec->version = ss->version;
+ }
+ ssl_ReleaseSpecWriteLock(ss);
+
+ if (ss->sec.ci.sid != NULL) {
+ ssl_FreeSID(ss->sec.ci.sid); /* decrement ref count, free if zero */
+ }
+ ss->sec.ci.sid = sid;
+
+ ss->sec.send = ssl3_SendApplicationData;
+
+ /* shouldn't get here if SSL3 is disabled, but ... */
+ if (SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
+ PR_NOT_REACHED("No versions of SSL 3.0 or later are enabled");
+ PORT_SetError(SSL_ERROR_SSL_DISABLED);
+ return SECFailure;
+ }
+
+ /* how many suites does our PKCS11 support (regardless of policy)? */
+ num_suites = ssl3_config_match_init(ss);
+ if (!num_suites)
+ return SECFailure; /* ssl3_config_match_init has set error code. */
+
+ /* HACK for SCSV in SSL 3.0. On initial handshake, prepend SCSV,
+ * only if TLS is disabled.
+ */
+ if (!ss->firstHsDone && !isTLS) {
+ /* Must set this before calling Hello Extension Senders,
+ * to suppress sending of empty RI extension.
+ */
+ ss->ssl3.hs.sendingSCSV = PR_TRUE;
+ }
+
+ if (isTLS || (ss->firstHsDone && ss->peerRequestedProtection)) {
+ PRUint32 maxBytes = 65535; /* 2^16 - 1 */
+ PRInt32 extLen;
+
+ extLen = ssl3_CallHelloExtensionSenders(ss, PR_FALSE, maxBytes, NULL);
+ if (extLen < 0) {
+ return SECFailure;
+ }
+ maxBytes -= extLen;
+ total_exten_len += extLen;
+
+ if (total_exten_len > 0)
+ total_exten_len += 2;
+ }
+
+#if defined(NSS_ENABLE_ECC)
+ if (!total_exten_len || !isTLS) {
+ /* not sending the elliptic_curves and ec_point_formats extensions */
+ ssl3_DisableECCSuites(ss, NULL); /* disable all ECC suites */
+ }
+#endif
+
+ if (IS_DTLS(ss)) {
+ ssl3_DisableNonDTLSSuites(ss);
+ }
+
+ if (!ssl3_HasGCMSupport()) {
+ ssl3_DisableGCMSuites(ss);
+ }
+
+ /* how many suites are permitted by policy and user preference? */
+ num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE);
+ if (!num_suites)
+ return SECFailure; /* count_cipher_suites has set error code. */
+ if (ss->ssl3.hs.sendingSCSV) {
+ ++num_suites; /* make room for SCSV */
+ }
+
+ /* count compression methods */
+ numCompressionMethods = 0;
+ for (i = 0; i < compressionMethodsCount; i++) {
+ if (compressionEnabled(ss, compressions[i]))
+ numCompressionMethods++;
+ }
+
+ length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH +
+ 1 + ((sid == NULL) ? 0 : sid->u.ssl3.sessionIDLength) +
+ 2 + num_suites*sizeof(ssl3CipherSuite) +
+ 1 + numCompressionMethods + total_exten_len;
+ if (IS_DTLS(ss)) {
+ length += 1 + ss->ssl3.hs.cookieLen;
+ }
+
+ rv = ssl3_AppendHandshakeHeader(ss, client_hello, length);
+ if (rv != SECSuccess) {
+ return rv; /* err set by ssl3_AppendHandshake* */
+ }
+
+ if (ss->firstHsDone) {
+ /* The client hello version must stay unchanged to work around
+ * the Windows SChannel bug described above. */
+ PORT_Assert(ss->version == ss->clientHelloVersion);
+ }
+ ss->clientHelloVersion = ss->version;
+ if (IS_DTLS(ss)) {
+ PRUint16 version;
+
+ version = dtls_TLSVersionToDTLSVersion(ss->clientHelloVersion);
+ rv = ssl3_AppendHandshakeNumber(ss, version, 2);
+ } else {
+ rv = ssl3_AppendHandshakeNumber(ss, ss->clientHelloVersion, 2);
+ }
+ if (rv != SECSuccess) {
+ return rv; /* err set by ssl3_AppendHandshake* */
+ }
+
+ if (!resending) { /* Don't re-generate if we are in DTLS re-sending mode */
+ rv = ssl3_GetNewRandom(&ss->ssl3.hs.client_random);
+ if (rv != SECSuccess) {
+ return rv; /* err set by GetNewRandom. */
+ }
+ }
+ rv = ssl3_AppendHandshake(ss, &ss->ssl3.hs.client_random,
+ SSL3_RANDOM_LENGTH);
+ if (rv != SECSuccess) {
+ return rv; /* err set by ssl3_AppendHandshake* */
+ }
+
+ if (sid)
+ rv = ssl3_AppendHandshakeVariable(
+ ss, sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength, 1);
+ else
+ rv = ssl3_AppendHandshakeVariable(ss, NULL, 0, 1);
+ if (rv != SECSuccess) {
+ return rv; /* err set by ssl3_AppendHandshake* */
+ }
+
+ if (IS_DTLS(ss)) {
+ rv = ssl3_AppendHandshakeVariable(
+ ss, ss->ssl3.hs.cookie, ss->ssl3.hs.cookieLen, 1);
+ if (rv != SECSuccess) {
+ return rv; /* err set by ssl3_AppendHandshake* */
+ }
+ }
+
+ rv = ssl3_AppendHandshakeNumber(ss, num_suites*sizeof(ssl3CipherSuite), 2);
+ if (rv != SECSuccess) {
+ return rv; /* err set by ssl3_AppendHandshake* */
+ }
+
+ if (ss->ssl3.hs.sendingSCSV) {
+ /* Add the actual SCSV */
+ rv = ssl3_AppendHandshakeNumber(ss, TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
+ sizeof(ssl3CipherSuite));
+ if (rv != SECSuccess) {
+ return rv; /* err set by ssl3_AppendHandshake* */
+ }
+ actual_count++;
+ }
+ for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
+ ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
+ if (config_match(suite, ss->ssl3.policy, PR_TRUE)) {
+ actual_count++;
+ if (actual_count > num_suites) {
+ /* set error card removal/insertion error */
+ PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL);
+ return SECFailure;
+ }
+ rv = ssl3_AppendHandshakeNumber(ss, suite->cipher_suite,
+ sizeof(ssl3CipherSuite));
+ if (rv != SECSuccess) {
+ return rv; /* err set by ssl3_AppendHandshake* */
+ }
+ }
+ }
+
+ /* if cards were removed or inserted between count_cipher_suites and
+ * generating our list, detect the error here rather than send it off to
+ * the server.. */
+ if (actual_count != num_suites) {
+ /* Card removal/insertion error */
+ PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL);
+ return SECFailure;
+ }
+
+ rv = ssl3_AppendHandshakeNumber(ss, numCompressionMethods, 1);
+ if (rv != SECSuccess) {
+ return rv; /* err set by ssl3_AppendHandshake* */
+ }
+ for (i = 0; i < compressionMethodsCount; i++) {
+ if (!compressionEnabled(ss, compressions[i]))
+ continue;
+ rv = ssl3_AppendHandshakeNumber(ss, compressions[i], 1);
+ if (rv != SECSuccess) {
+ return rv; /* err set by ssl3_AppendHandshake* */
+ }
+ }
+
+ if (total_exten_len) {
+ PRUint32 maxBytes = total_exten_len - 2;
+ PRInt32 extLen;
+
+ rv = ssl3_AppendHandshakeNumber(ss, maxBytes, 2);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+
+ extLen = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, maxBytes, NULL);
+ if (extLen < 0) {
+ return SECFailure;
+ }
+ maxBytes -= extLen;
+ PORT_Assert(!maxBytes);
+ }
+ if (ss->ssl3.hs.sendingSCSV) {
+ /* Since we sent the SCSV, pretend we sent empty RI extension. */
+ TLSExtensionData *xtnData = &ss->xtnData;
+ xtnData->advertised[xtnData->numAdvertised++] =
+ ssl_renegotiation_info_xtn;
+ }
+
+ flags = 0;
+ if (!ss->firstHsDone && !requestingResume && !IS_DTLS(ss)) {
+ flags |= ssl_SEND_FLAG_CAP_RECORD_VERSION;
+ }
+ rv = ssl3_FlushHandshake(ss, flags);
+ if (rv != SECSuccess) {
+ return rv; /* error code set by ssl3_FlushHandshake */
+ }
+
+ ss->ssl3.hs.ws = wait_server_hello;
+ return rv;
+}
+
+
+/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
+ * ssl3 Hello Request.
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+static SECStatus
+ssl3_HandleHelloRequest(sslSocket *ss)
+{
+ sslSessionID *sid = ss->sec.ci.sid;
+ SECStatus rv;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: handle hello_request handshake",
+ SSL_GETPID(), ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ if (ss->ssl3.hs.ws == wait_server_hello)
+ return SECSuccess;
+ if (ss->ssl3.hs.ws != idle_handshake || ss->sec.isServer) {
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST);
+ return SECFailure;
+ }
+ if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
+ ssl_GetXmitBufLock(ss);
+ rv = SSL3_SendAlert(ss, alert_warning, no_renegotiation);
+ ssl_ReleaseXmitBufLock(ss);
+ PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED);
+ return SECFailure;
+ }
+
+ if (sid) {
+ if (ss->sec.uncache)
+ ss->sec.uncache(sid);
+ ssl_FreeSID(sid);
+ ss->sec.ci.sid = NULL;
+ }
+
+ if (IS_DTLS(ss)) {
+ dtls_RehandshakeCleanup(ss);
+ }
+
+ ssl_GetXmitBufLock(ss);
+ rv = ssl3_SendClientHello(ss, PR_FALSE);
+ ssl_ReleaseXmitBufLock(ss);
+
+ return rv;
+}
+
+#define UNKNOWN_WRAP_MECHANISM 0x7fffffff
+
+static const CK_MECHANISM_TYPE wrapMechanismList[SSL_NUM_WRAP_MECHS] = {
+ CKM_DES3_ECB,
+ CKM_CAST5_ECB,
+ CKM_DES_ECB,
+ CKM_KEY_WRAP_LYNKS,
+ CKM_IDEA_ECB,
+ CKM_CAST3_ECB,
+ CKM_CAST_ECB,
+ CKM_RC5_ECB,
+ CKM_RC2_ECB,
+ CKM_CDMF_ECB,
+ CKM_SKIPJACK_WRAP,
+ CKM_SKIPJACK_CBC64,
+ CKM_AES_ECB,
+ CKM_CAMELLIA_ECB,
+ CKM_SEED_ECB,
+ UNKNOWN_WRAP_MECHANISM
+};
+
+static int
+ssl_FindIndexByWrapMechanism(CK_MECHANISM_TYPE mech)
+{
+ const CK_MECHANISM_TYPE *pMech = wrapMechanismList;
+
+ while (mech != *pMech && *pMech != UNKNOWN_WRAP_MECHANISM) {
+ ++pMech;
+ }
+ return (*pMech == UNKNOWN_WRAP_MECHANISM) ? -1
+ : (pMech - wrapMechanismList);
+}
+
+static PK11SymKey *
+ssl_UnwrapSymWrappingKey(
+ SSLWrappedSymWrappingKey *pWswk,
+ SECKEYPrivateKey * svrPrivKey,
+ SSL3KEAType exchKeyType,
+ CK_MECHANISM_TYPE masterWrapMech,
+ void * pwArg)
+{
+ PK11SymKey * unwrappedWrappingKey = NULL;
+ SECItem wrappedKey;
+#ifdef NSS_ENABLE_ECC
+ PK11SymKey * Ks;
+ SECKEYPublicKey pubWrapKey;
+ ECCWrappedKeyInfo *ecWrapped;
+#endif /* NSS_ENABLE_ECC */
+
+ /* found the wrapping key on disk. */
+ PORT_Assert(pWswk->symWrapMechanism == masterWrapMech);
+ PORT_Assert(pWswk->exchKeyType == exchKeyType);
+ if (pWswk->symWrapMechanism != masterWrapMech ||
+ pWswk->exchKeyType != exchKeyType) {
+ goto loser;
+ }
+ wrappedKey.type = siBuffer;
+ wrappedKey.data = pWswk->wrappedSymmetricWrappingkey;
+ wrappedKey.len = pWswk->wrappedSymKeyLen;
+ PORT_Assert(wrappedKey.len <= sizeof pWswk->wrappedSymmetricWrappingkey);
+
+ switch (exchKeyType) {
+
+ case kt_rsa:
+ unwrappedWrappingKey =
+ PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
+ masterWrapMech, CKA_UNWRAP, 0);
+ break;
+
+#ifdef NSS_ENABLE_ECC
+ case kt_ecdh:
+ /*
+ * For kt_ecdh, we first create an EC public key based on
+ * data stored with the wrappedSymmetricWrappingkey. Next,
+ * we do an ECDH computation involving this public key and
+ * the SSL server's (long-term) EC private key. The resulting
+ * shared secret is treated the same way as Fortezza's Ks, i.e.,
+ * it is used to recover the symmetric wrapping key.
+ *
+ * The data in wrappedSymmetricWrappingkey is laid out as defined
+ * in the ECCWrappedKeyInfo structure.
+ */
+ ecWrapped = (ECCWrappedKeyInfo *) pWswk->wrappedSymmetricWrappingkey;
+
+ PORT_Assert(ecWrapped->encodedParamLen + ecWrapped->pubValueLen +
+ ecWrapped->wrappedKeyLen <= MAX_EC_WRAPPED_KEY_BUFLEN);
+
+ if (ecWrapped->encodedParamLen + ecWrapped->pubValueLen +
+ ecWrapped->wrappedKeyLen > MAX_EC_WRAPPED_KEY_BUFLEN) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ goto loser;
+ }
+
+ pubWrapKey.keyType = ecKey;
+ pubWrapKey.u.ec.size = ecWrapped->size;
+ pubWrapKey.u.ec.DEREncodedParams.len = ecWrapped->encodedParamLen;
+ pubWrapKey.u.ec.DEREncodedParams.data = ecWrapped->var;
+ pubWrapKey.u.ec.publicValue.len = ecWrapped->pubValueLen;
+ pubWrapKey.u.ec.publicValue.data = ecWrapped->var +
+ ecWrapped->encodedParamLen;
+
+ wrappedKey.len = ecWrapped->wrappedKeyLen;
+ wrappedKey.data = ecWrapped->var + ecWrapped->encodedParamLen +
+ ecWrapped->pubValueLen;
+
+ /* Derive Ks using ECDH */
+ Ks = PK11_PubDeriveWithKDF(svrPrivKey, &pubWrapKey, PR_FALSE, NULL,
+ NULL, CKM_ECDH1_DERIVE, masterWrapMech,
+ CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
+ if (Ks == NULL) {
+ goto loser;
+ }
+
+ /* Use Ks to unwrap the wrapping key */
+ unwrappedWrappingKey = PK11_UnwrapSymKey(Ks, masterWrapMech, NULL,
+ &wrappedKey, masterWrapMech,
+ CKA_UNWRAP, 0);
+ PK11_FreeSymKey(Ks);
+
+ break;
+#endif
+
+ default:
+ /* Assert? */
+ SET_ERROR_CODE
+ goto loser;
+ }
+loser:
+ return unwrappedWrappingKey;
+}
+
+/* Each process sharing the server session ID cache has its own array of
+ * SymKey pointers for the symmetric wrapping keys that are used to wrap
+ * the master secrets. There is one key for each KEA type. These Symkeys
+ * correspond to the wrapped SymKeys kept in the server session cache.
+ */
+
+typedef struct {
+ PK11SymKey * symWrapKey[kt_kea_size];
+} ssl3SymWrapKey;
+
+static PZLock * symWrapKeysLock = NULL;
+static ssl3SymWrapKey symWrapKeys[SSL_NUM_WRAP_MECHS];
+
+SECStatus ssl_FreeSymWrapKeysLock(void)
+{
+ if (symWrapKeysLock) {
+ PZ_DestroyLock(symWrapKeysLock);
+ symWrapKeysLock = NULL;
+ return SECSuccess;
+ }
+ PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+ return SECFailure;
+}
+
+SECStatus
+SSL3_ShutdownServerCache(void)
+{
+ int i, j;
+
+ if (!symWrapKeysLock)
+ return SECSuccess; /* lock was never initialized */
+ PZ_Lock(symWrapKeysLock);
+ /* get rid of all symWrapKeys */
+ for (i = 0; i < SSL_NUM_WRAP_MECHS; ++i) {
+ for (j = 0; j < kt_kea_size; ++j) {
+ PK11SymKey ** pSymWrapKey;
+ pSymWrapKey = &symWrapKeys[i].symWrapKey[j];
+ if (*pSymWrapKey) {
+ PK11_FreeSymKey(*pSymWrapKey);
+ *pSymWrapKey = NULL;
+ }
+ }
+ }
+
+ PZ_Unlock(symWrapKeysLock);
+ ssl_FreeSessionCacheLocks();
+ return SECSuccess;
+}
+
+SECStatus ssl_InitSymWrapKeysLock(void)
+{
+ symWrapKeysLock = PZ_NewLock(nssILockOther);
+ return symWrapKeysLock ? SECSuccess : SECFailure;
+}
+
+/* Try to get wrapping key for mechanism from in-memory array.
+ * If that fails, look for one on disk.
+ * If that fails, generate a new one, put the new one on disk,
+ * Put the new key in the in-memory array.
+ */
+static PK11SymKey *
+getWrappingKey( sslSocket * ss,
+ PK11SlotInfo * masterSecretSlot,
+ SSL3KEAType exchKeyType,
+ CK_MECHANISM_TYPE masterWrapMech,
+ void * pwArg)
+{
+ SECKEYPrivateKey * svrPrivKey;
+ SECKEYPublicKey * svrPubKey = NULL;
+ PK11SymKey * unwrappedWrappingKey = NULL;
+ PK11SymKey ** pSymWrapKey;
+ CK_MECHANISM_TYPE asymWrapMechanism = CKM_INVALID_MECHANISM;
+ int length;
+ int symWrapMechIndex;
+ SECStatus rv;
+ SECItem wrappedKey;
+ SSLWrappedSymWrappingKey wswk;
+#ifdef NSS_ENABLE_ECC
+ PK11SymKey * Ks = NULL;
+ SECKEYPublicKey *pubWrapKey = NULL;
+ SECKEYPrivateKey *privWrapKey = NULL;
+ ECCWrappedKeyInfo *ecWrapped;
+#endif /* NSS_ENABLE_ECC */
+
+ svrPrivKey = ss->serverCerts[exchKeyType].SERVERKEY;
+ PORT_Assert(svrPrivKey != NULL);
+ if (!svrPrivKey) {
+ return NULL; /* why are we here?!? */
+ }
+
+ symWrapMechIndex = ssl_FindIndexByWrapMechanism(masterWrapMech);
+ PORT_Assert(symWrapMechIndex >= 0);
+ if (symWrapMechIndex < 0)
+ return NULL; /* invalid masterWrapMech. */
+
+ pSymWrapKey = &symWrapKeys[symWrapMechIndex].symWrapKey[exchKeyType];
+
+ ssl_InitSessionCacheLocks(PR_TRUE);
+
+ PZ_Lock(symWrapKeysLock);
+
+ unwrappedWrappingKey = *pSymWrapKey;
+ if (unwrappedWrappingKey != NULL) {
+ if (PK11_VerifyKeyOK(unwrappedWrappingKey)) {
+ unwrappedWrappingKey = PK11_ReferenceSymKey(unwrappedWrappingKey);
+ goto done;
+ }
+ /* slot series has changed, so this key is no good any more. */
+ PK11_FreeSymKey(unwrappedWrappingKey);
+ *pSymWrapKey = unwrappedWrappingKey = NULL;
+ }
+
+ /* Try to get wrapped SymWrapping key out of the (disk) cache. */
+ /* Following call fills in wswk on success. */
+ if (ssl_GetWrappingKey(symWrapMechIndex, exchKeyType, &wswk)) {
+ /* found the wrapped sym wrapping key on disk. */
+ unwrappedWrappingKey =
+ ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, exchKeyType,
+ masterWrapMech, pwArg);
+ if (unwrappedWrappingKey) {
+ goto install;
+ }
+ }
+
+ if (!masterSecretSlot) /* caller doesn't want to create a new one. */
+ goto loser;
+
+ length = PK11_GetBestKeyLength(masterSecretSlot, masterWrapMech);
+ /* Zero length means fixed key length algorithm, or error.
+ * It's ambiguous.
+ */
+ unwrappedWrappingKey = PK11_KeyGen(masterSecretSlot, masterWrapMech, NULL,
+ length, pwArg);
+ if (!unwrappedWrappingKey) {
+ goto loser;
+ }
+
+ /* Prepare the buffer to receive the wrappedWrappingKey,
+ * the symmetric wrapping key wrapped using the server's pub key.
+ */
+ PORT_Memset(&wswk, 0, sizeof wswk); /* eliminate UMRs. */
+
+ if (ss->serverCerts[exchKeyType].serverKeyPair) {
+ svrPubKey = ss->serverCerts[exchKeyType].serverKeyPair->pubKey;
+ }
+ if (svrPubKey == NULL) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ goto loser;
+ }
+ wrappedKey.type = siBuffer;
+ wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey);
+ wrappedKey.data = wswk.wrappedSymmetricWrappingkey;
+
+ PORT_Assert(wrappedKey.len <= sizeof wswk.wrappedSymmetricWrappingkey);
+ if (wrappedKey.len > sizeof wswk.wrappedSymmetricWrappingkey)
+ goto loser;
+
+ /* wrap symmetric wrapping key in server's public key. */
+ switch (exchKeyType) {
+ case kt_rsa:
+ asymWrapMechanism = CKM_RSA_PKCS;
+ rv = PK11_PubWrapSymKey(asymWrapMechanism, svrPubKey,
+ unwrappedWrappingKey, &wrappedKey);
+ break;
+
+#ifdef NSS_ENABLE_ECC
+ case kt_ecdh:
+ /*
+ * We generate an ephemeral EC key pair. Perform an ECDH
+ * computation involving this ephemeral EC public key and
+ * the SSL server's (long-term) EC private key. The resulting
+ * shared secret is treated in the same way as Fortezza's Ks,
+ * i.e., it is used to wrap the wrapping key. To facilitate
+ * unwrapping in ssl_UnwrapWrappingKey, we also store all
+ * relevant info about the ephemeral EC public key in
+ * wswk.wrappedSymmetricWrappingkey and lay it out as
+ * described in the ECCWrappedKeyInfo structure.
+ */
+ PORT_Assert(svrPubKey->keyType == ecKey);
+ if (svrPubKey->keyType != ecKey) {
+ /* something is wrong in sslsecur.c if this isn't an ecKey */
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ rv = SECFailure;
+ goto ec_cleanup;
+ }
+
+ privWrapKey = SECKEY_CreateECPrivateKey(
+ &svrPubKey->u.ec.DEREncodedParams, &pubWrapKey, NULL);
+ if ((privWrapKey == NULL) || (pubWrapKey == NULL)) {
+ rv = SECFailure;
+ goto ec_cleanup;
+ }
+
+ /* Set the key size in bits */
+ if (pubWrapKey->u.ec.size == 0) {
+ pubWrapKey->u.ec.size = SECKEY_PublicKeyStrengthInBits(svrPubKey);
+ }
+
+ PORT_Assert(pubWrapKey->u.ec.DEREncodedParams.len +
+ pubWrapKey->u.ec.publicValue.len < MAX_EC_WRAPPED_KEY_BUFLEN);
+ if (pubWrapKey->u.ec.DEREncodedParams.len +
+ pubWrapKey->u.ec.publicValue.len >= MAX_EC_WRAPPED_KEY_BUFLEN) {
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ rv = SECFailure;
+ goto ec_cleanup;
+ }
+
+ /* Derive Ks using ECDH */
+ Ks = PK11_PubDeriveWithKDF(svrPrivKey, pubWrapKey, PR_FALSE, NULL,
+ NULL, CKM_ECDH1_DERIVE, masterWrapMech,
+ CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
+ if (Ks == NULL) {
+ rv = SECFailure;
+ goto ec_cleanup;
+ }
+
+ ecWrapped = (ECCWrappedKeyInfo *) (wswk.wrappedSymmetricWrappingkey);
+ ecWrapped->size = pubWrapKey->u.ec.size;
+ ecWrapped->encodedParamLen = pubWrapKey->u.ec.DEREncodedParams.len;
+ PORT_Memcpy(ecWrapped->var, pubWrapKey->u.ec.DEREncodedParams.data,
+ pubWrapKey->u.ec.DEREncodedParams.len);
+
+ ecWrapped->pubValueLen = pubWrapKey->u.ec.publicValue.len;
+ PORT_Memcpy(ecWrapped->var + ecWrapped->encodedParamLen,
+ pubWrapKey->u.ec.publicValue.data,
+ pubWrapKey->u.ec.publicValue.len);
+
+ wrappedKey.len = MAX_EC_WRAPPED_KEY_BUFLEN -
+ (ecWrapped->encodedParamLen + ecWrapped->pubValueLen);
+ wrappedKey.data = ecWrapped->var + ecWrapped->encodedParamLen +
+ ecWrapped->pubValueLen;
+
+ /* wrap symmetricWrapping key with the local Ks */
+ rv = PK11_WrapSymKey(masterWrapMech, NULL, Ks,
+ unwrappedWrappingKey, &wrappedKey);
+
+ if (rv != SECSuccess) {
+ goto ec_cleanup;
+ }
+
+ /* Write down the length of wrapped key in the buffer
+ * wswk.wrappedSymmetricWrappingkey at the appropriate offset
+ */
+ ecWrapped->wrappedKeyLen = wrappedKey.len;
+
+ec_cleanup:
+ if (privWrapKey) SECKEY_DestroyPrivateKey(privWrapKey);
+ if (pubWrapKey) SECKEY_DestroyPublicKey(pubWrapKey);
+ if (Ks) PK11_FreeSymKey(Ks);
+ asymWrapMechanism = masterWrapMech;
+ break;
+#endif /* NSS_ENABLE_ECC */
+
+ default:
+ rv = SECFailure;
+ break;
+ }
+
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
+ PORT_Assert(asymWrapMechanism != CKM_INVALID_MECHANISM);
+
+ wswk.symWrapMechanism = masterWrapMech;
+ wswk.symWrapMechIndex = symWrapMechIndex;
+ wswk.asymWrapMechanism = asymWrapMechanism;
+ wswk.exchKeyType = exchKeyType;
+ wswk.wrappedSymKeyLen = wrappedKey.len;
+
+ /* put it on disk. */
+ /* If the wrapping key for this KEA type has already been set,
+ * then abandon the value we just computed and
+ * use the one we got from the disk.
+ */
+ if (ssl_SetWrappingKey(&wswk)) {
+ /* somebody beat us to it. The original contents of our wswk
+ * has been replaced with the content on disk. Now, discard
+ * the key we just created and unwrap this new one.
+ */
+ PK11_FreeSymKey(unwrappedWrappingKey);
+
+ unwrappedWrappingKey =
+ ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, exchKeyType,
+ masterWrapMech, pwArg);
+ }
+
+install:
+ if (unwrappedWrappingKey) {
+ *pSymWrapKey = PK11_ReferenceSymKey(unwrappedWrappingKey);
+ }
+
+loser:
+done:
+ PZ_Unlock(symWrapKeysLock);
+ return unwrappedWrappingKey;
+}
+
+/* hexEncode hex encodes |length| bytes from |in| and writes it as |length*2|
+ * bytes to |out|. */
+static void
+hexEncode(char *out, const unsigned char *in, unsigned int length)
+{
+ static const char hextable[] = "0123456789abcdef";
+ unsigned int i;
+
+ for (i = 0; i < length; i++) {
+ *(out++) = hextable[in[i] >> 4];
+ *(out++) = hextable[in[i] & 15];
+ }
+}
+
+/* Called from ssl3_SendClientKeyExchange(). */
+/* Presently, this always uses PKCS11. There is no bypass for this. */
+static SECStatus
+sendRSAClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
+{
+ PK11SymKey * pms = NULL;
+ SECStatus rv = SECFailure;
+ SECItem enc_pms = {siBuffer, NULL, 0};
+ PRBool isTLS;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+
+ /* Generate the pre-master secret ... */
+ ssl_GetSpecWriteLock(ss);
+ isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
+
+ pms = ssl3_GenerateRSAPMS(ss, ss->ssl3.pwSpec, NULL);
+ ssl_ReleaseSpecWriteLock(ss);
+ if (pms == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
+ /* Get the wrapped (encrypted) pre-master secret, enc_pms */
+ enc_pms.len = SECKEY_PublicKeyStrength(svrPubKey);
+ enc_pms.data = (unsigned char*)PORT_Alloc(enc_pms.len);
+ if (enc_pms.data == NULL) {
+ goto loser; /* err set by PORT_Alloc */
+ }
+
+ /* wrap pre-master secret in server's public key. */
+ rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, pms, &enc_pms);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
+ if (ssl_keylog_iob) {
+ SECStatus extractRV = PK11_ExtractKeyValue(pms);
+ if (extractRV == SECSuccess) {
+ SECItem * keyData = PK11_GetKeyData(pms);
+ if (keyData && keyData->data && keyData->len) {
+#ifdef TRACE
+ if (ssl_trace >= 100) {
+ ssl_PrintBuf(ss, "Pre-Master Secret",
+ keyData->data, keyData->len);
+ }
+#endif
+ if (ssl_keylog_iob && enc_pms.len >= 8 && keyData->len == 48) {
+ /* https://developer.mozilla.org/en/NSS_Key_Log_Format */
+
+ /* There could be multiple, concurrent writers to the
+ * keylog, so we have to do everything in a single call to
+ * fwrite. */
+ char buf[4 + 8*2 + 1 + 48*2 + 1];
+
+ strcpy(buf, "RSA ");
+ hexEncode(buf + 4, enc_pms.data, 8);
+ buf[20] = ' ';
+ hexEncode(buf + 21, keyData->data, 48);
+ buf[sizeof(buf) - 1] = '\n';
+
+ fwrite(buf, sizeof(buf), 1, ssl_keylog_iob);
+ fflush(ssl_keylog_iob);
+ }
+ }
+ }
+ }
+
+ rv = ssl3_InitPendingCipherSpec(ss, pms);
+ PK11_FreeSymKey(pms); pms = NULL;
+
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
+ rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
+ isTLS ? enc_pms.len + 2 : enc_pms.len);
+ if (rv != SECSuccess) {
+ goto loser; /* err set by ssl3_AppendHandshake* */
+ }
+ if (isTLS) {
+ rv = ssl3_AppendHandshakeVariable(ss, enc_pms.data, enc_pms.len, 2);
+ } else {
+ rv = ssl3_AppendHandshake(ss, enc_pms.data, enc_pms.len);
+ }
+ if (rv != SECSuccess) {
+ goto loser; /* err set by ssl3_AppendHandshake* */
+ }
+
+ rv = SECSuccess;
+
+loser:
+ if (enc_pms.data != NULL) {
+ PORT_Free(enc_pms.data);
+ }
+ if (pms != NULL) {
+ PK11_FreeSymKey(pms);
+ }
+ return rv;
+}
+
+/* Called from ssl3_SendClientKeyExchange(). */
+/* Presently, this always uses PKCS11. There is no bypass for this. */
+static SECStatus
+sendDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
+{
+ PK11SymKey * pms = NULL;
+ SECStatus rv = SECFailure;
+ PRBool isTLS;
+ CK_MECHANISM_TYPE target;
+
+ SECKEYDHParams dhParam; /* DH parameters */
+ SECKEYPublicKey *pubKey = NULL; /* Ephemeral DH key */
+ SECKEYPrivateKey *privKey = NULL; /* Ephemeral DH key */
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+
+ isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
+
+ /* Copy DH parameters from server key */
+
+ if (svrPubKey->keyType != dhKey) {
+ PORT_SetError(SEC_ERROR_BAD_KEY);
+ goto loser;
+ }
+ dhParam.prime.data = svrPubKey->u.dh.prime.data;
+ dhParam.prime.len = svrPubKey->u.dh.prime.len;
+ dhParam.base.data = svrPubKey->u.dh.base.data;
+ dhParam.base.len = svrPubKey->u.dh.base.len;
+
+ /* Generate ephemeral DH keypair */
+ privKey = SECKEY_CreateDHPrivateKey(&dhParam, &pubKey, NULL);
+ if (!privKey || !pubKey) {
+ ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
+ rv = SECFailure;
+ goto loser;
+ }
+ PRINT_BUF(50, (ss, "DH public value:",
+ pubKey->u.dh.publicValue.data,
+ pubKey->u.dh.publicValue.len));
+
+ if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH;
+ else target = CKM_SSL3_MASTER_KEY_DERIVE_DH;
+
+ /* Determine the PMS */
+
+ pms = PK11_PubDerive(privKey, svrPubKey, PR_FALSE, NULL, NULL,
+ CKM_DH_PKCS_DERIVE, target, CKA_DERIVE, 0, NULL);
+
+ if (pms == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
+ SECKEY_DestroyPrivateKey(privKey);
+ privKey = NULL;
+
+ rv = ssl3_InitPendingCipherSpec(ss, pms);
+ PK11_FreeSymKey(pms); pms = NULL;
+
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
+ rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
+ pubKey->u.dh.publicValue.len + 2);
+ if (rv != SECSuccess) {
+ goto loser; /* err set by ssl3_AppendHandshake* */
+ }
+ rv = ssl3_AppendHandshakeVariable(ss,
+ pubKey->u.dh.publicValue.data,
+ pubKey->u.dh.publicValue.len, 2);
+ SECKEY_DestroyPublicKey(pubKey);
+ pubKey = NULL;
+
+ if (rv != SECSuccess) {
+ goto loser; /* err set by ssl3_AppendHandshake* */
+ }
+
+ rv = SECSuccess;
+
+
+loser:
+
+ if(pms) PK11_FreeSymKey(pms);
+ if(privKey) SECKEY_DestroyPrivateKey(privKey);
+ if(pubKey) SECKEY_DestroyPublicKey(pubKey);
+ return rv;
+}
+
+
+
+
+
+/* Called from ssl3_HandleServerHelloDone(). */
+static SECStatus
+ssl3_SendClientKeyExchange(sslSocket *ss)
+{
+ SECKEYPublicKey * serverKey = NULL;
+ SECStatus rv = SECFailure;
+ PRBool isTLS;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: send client_key_exchange handshake",
+ SSL_GETPID(), ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ if (ss->sec.peerKey == NULL) {
+ serverKey = CERT_ExtractPublicKey(ss->sec.peerCert);
+ if (serverKey == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
+ return SECFailure;
+ }
+ } else {
+ serverKey = ss->sec.peerKey;
+ ss->sec.peerKey = NULL; /* we're done with it now */
+ }
+
+ isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
+ /* enforce limits on kea key sizes. */
+ if (ss->ssl3.hs.kea_def->is_limited) {
+ int keyLen = SECKEY_PublicKeyStrength(serverKey); /* bytes */
+
+ if (keyLen * BPB > ss->ssl3.hs.kea_def->key_size_limit) {
+ if (isTLS)
+ (void)SSL3_SendAlert(ss, alert_fatal, export_restriction);
+ else
+ (void)ssl3_HandshakeFailure(ss);
+ PORT_SetError(SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED);
+ goto loser;
+ }
+ }
+
+ ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType;
+ ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(serverKey);
+
+ switch (ss->ssl3.hs.kea_def->exchKeyType) {
+ case kt_rsa:
+ rv = sendRSAClientKeyExchange(ss, serverKey);
+ break;
+
+ case kt_dh:
+ rv = sendDHClientKeyExchange(ss, serverKey);
+ break;
+
+#ifdef NSS_ENABLE_ECC
+ case kt_ecdh:
+ rv = ssl3_SendECDHClientKeyExchange(ss, serverKey);
+ break;
+#endif /* NSS_ENABLE_ECC */
+
+ default:
+ /* got an unknown or unsupported Key Exchange Algorithm. */
+ SEND_ALERT
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+ break;
+ }
+
+ SSL_TRC(3, ("%d: SSL3[%d]: DONE sending client_key_exchange",
+ SSL_GETPID(), ss->fd));
+
+loser:
+ if (serverKey)
+ SECKEY_DestroyPublicKey(serverKey);
+ return rv; /* err code already set. */
+}
+
+/* Called from ssl3_HandleServerHelloDone(). */
+static SECStatus
+ssl3_SendCertificateVerify(sslSocket *ss)
+{
+ SECStatus rv = SECFailure;
+ PRBool isTLS;
+ PRBool isTLS12;
+ SECItem buf = {siBuffer, NULL, 0};
+ SSL3Hashes hashes;
+ KeyType keyType;
+ unsigned int len;
+ SSL3SignatureAndHashAlgorithm sigAndHash;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ SSL_TRC(3, ("%d: SSL3[%d]: send certificate_verify handshake",
+ SSL_GETPID(), ss->fd));
+
+ ssl_GetSpecReadLock(ss);
+ rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0);
+ ssl_ReleaseSpecReadLock(ss);
+ if (rv != SECSuccess) {
+ goto done; /* err code was set by ssl3_ComputeHandshakeHashes */
+ }
+
+ isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
+ isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
+ if (ss->ssl3.platformClientKey) {
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ keyType = CERT_GetCertKeyType(
+ &ss->ssl3.clientCertificate->subjectPublicKeyInfo);
+ rv = ssl3_PlatformSignHashes(
+ &hashes, ss->ssl3.platformClientKey, &buf, isTLS, keyType);
+ ssl_FreePlatformKey(ss->ssl3.platformClientKey);
+ ss->ssl3.platformClientKey = (PlatformKey)NULL;
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
+ } else {
+ keyType = ss->ssl3.clientPrivateKey->keyType;
+ rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS);
+ if (rv == SECSuccess) {
+ PK11SlotInfo * slot;
+ sslSessionID * sid = ss->sec.ci.sid;
+
+ /* Remember the info about the slot that did the signing.
+ ** Later, when doing an SSL restart handshake, verify this.
+ ** These calls are mere accessors, and can't fail.
+ */
+ slot = PK11_GetSlotFromPrivateKey(ss->ssl3.clientPrivateKey);
+ sid->u.ssl3.clAuthSeries = PK11_GetSlotSeries(slot);
+ sid->u.ssl3.clAuthSlotID = PK11_GetSlotID(slot);
+ sid->u.ssl3.clAuthModuleID = PK11_GetModuleID(slot);
+ sid->u.ssl3.clAuthValid = PR_TRUE;
+ PK11_FreeSlot(slot);
+ }
+ SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
+ ss->ssl3.clientPrivateKey = NULL;
+ }
+ if (rv != SECSuccess) {
+ goto done; /* err code was set by ssl3_SignHashes */
+ }
+
+ len = buf.len + 2 + (isTLS12 ? 2 : 0);
+
+ rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, len);
+ if (rv != SECSuccess) {
+ goto done; /* error code set by AppendHandshake */
+ }
+ if (isTLS12) {
+ rv = ssl3_TLSSignatureAlgorithmForKeyType(keyType,
+ &sigAndHash.sigAlg);
+ if (rv != SECSuccess) {
+ goto done;
+ }
+ /* We always sign using the handshake hash function. It's possible that
+ * a server could support SHA-256 as the handshake hash but not as a
+ * signature hash. In that case we wouldn't be able to do client
+ * certificates with it. The alternative is to buffer all handshake
+ * messages. */
+ sigAndHash.hashAlg = hashes.hashAlg;
+
+ rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash);
+ if (rv != SECSuccess) {
+ goto done; /* err set by AppendHandshake. */
+ }
+ }
+ rv = ssl3_AppendHandshakeVariable(ss, buf.data, buf.len, 2);
+ if (rv != SECSuccess) {
+ goto done; /* error code set by AppendHandshake */
+ }
+
+done:
+ if (buf.data)
+ PORT_Free(buf.data);
+ return rv;
+}
+
+/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
+ * ssl3 ServerHello message.
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+static SECStatus
+ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+ sslSessionID *sid = ss->sec.ci.sid;
+ PRInt32 temp; /* allow for consume number failure */
+ PRBool suite_found = PR_FALSE;
+ int i;
+ int errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
+ SECStatus rv;
+ SECItem sidBytes = {siBuffer, NULL, 0};
+ PRBool sid_match;
+ PRBool isTLS = PR_FALSE;
+ SSL3AlertDescription desc = illegal_parameter;
+ SSL3ProtocolVersion version;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello handshake",
+ SSL_GETPID(), ss->fd));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ PORT_Assert( ss->ssl3.initialized );
+
+ if (ss->ssl3.hs.ws != wait_server_hello) {
+ errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO;
+ desc = unexpected_message;
+ goto alert_loser;
+ }
+
+ /* clean up anything left from previous handshake. */
+ if (ss->ssl3.clientCertChain != NULL) {
+ CERT_DestroyCertificateList(ss->ssl3.clientCertChain);
+ ss->ssl3.clientCertChain = NULL;
+ }
+ if (ss->ssl3.clientCertificate != NULL) {
+ CERT_DestroyCertificate(ss->ssl3.clientCertificate);
+ ss->ssl3.clientCertificate = NULL;
+ }
+ if (ss->ssl3.clientPrivateKey != NULL) {
+ SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
+ ss->ssl3.clientPrivateKey = NULL;
+ }
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ if (ss->ssl3.platformClientKey) {
+ ssl_FreePlatformKey(ss->ssl3.platformClientKey);
+ ss->ssl3.platformClientKey = (PlatformKey)NULL;
+ }
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
+
+ if (ss->ssl3.channelID != NULL) {
+ SECKEY_DestroyPrivateKey(ss->ssl3.channelID);
+ ss->ssl3.channelID = NULL;
+ }
+ if (ss->ssl3.channelIDPub != NULL) {
+ SECKEY_DestroyPublicKey(ss->ssl3.channelIDPub);
+ ss->ssl3.channelIDPub = NULL;
+ }
+
+ temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
+ if (temp < 0) {
+ goto loser; /* alert has been sent */
+ }
+ version = (SSL3ProtocolVersion)temp;
+
+ if (IS_DTLS(ss)) {
+ /* RFC 4347 required that you verify that the server versions
+ * match (Section 4.2.1) in the HelloVerifyRequest and the
+ * ServerHello.
+ *
+ * RFC 6347 suggests (SHOULD) that servers always use 1.0
+ * in HelloVerifyRequest and allows the versions not to match,
+ * especially when 1.2 is being negotiated.
+ *
+ * Therefore we do not check for matching here.
+ */
+ version = dtls_DTLSVersionToTLSVersion(version);
+ if (version == 0) { /* Insane version number */
+ goto alert_loser;
+ }
+ }
+
+ rv = ssl3_NegotiateVersion(ss, version, PR_FALSE);
+ if (rv != SECSuccess) {
+ desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version
+ : handshake_failure;
+ errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
+ goto alert_loser;
+ }
+ isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0);
+
+ rv = ssl3_InitHandshakeHashes(ss);
+ if (rv != SECSuccess) {
+ desc = internal_error;
+ errCode = PORT_GetError();
+ goto alert_loser;
+ }
+
+ rv = ssl3_ConsumeHandshake(
+ ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* alert has been sent */
+ }
+
+ rv = ssl3_ConsumeHandshakeVariable(ss, &sidBytes, 1, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* alert has been sent */
+ }
+ if (sidBytes.len > SSL3_SESSIONID_BYTES) {
+ if (isTLS)
+ desc = decode_error;
+ goto alert_loser; /* malformed. */
+ }
+
+ /* find selected cipher suite in our list. */
+ temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
+ if (temp < 0) {
+ goto loser; /* alert has been sent */
+ }
+ ssl3_config_match_init(ss);
+ for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
+ ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
+ if (temp == suite->cipher_suite) {
+ if (!config_match(suite, ss->ssl3.policy, PR_TRUE)) {
+ break; /* failure */
+ }
+ if (!ssl3_CipherSuiteAllowedForVersion(suite->cipher_suite,
+ ss->version)) {
+ desc = handshake_failure;
+ errCode = SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION;
+ goto alert_loser;
+ }
+
+ suite_found = PR_TRUE;
+ break; /* success */
+ }
+ }
+ if (!suite_found) {
+ desc = handshake_failure;
+ errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
+ goto alert_loser;
+ }
+ ss->ssl3.hs.cipher_suite = (ssl3CipherSuite)temp;
+ ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef((ssl3CipherSuite)temp);
+ PORT_Assert(ss->ssl3.hs.suite_def);
+ if (!ss->ssl3.hs.suite_def) {
+ PORT_SetError(errCode = SEC_ERROR_LIBRARY_FAILURE);
+ goto loser; /* we don't send alerts for our screw-ups. */
+ }
+
+ /* find selected compression method in our list. */
+ temp = ssl3_ConsumeHandshakeNumber(ss, 1, &b, &length);
+ if (temp < 0) {
+ goto loser; /* alert has been sent */
+ }
+ suite_found = PR_FALSE;
+ for (i = 0; i < compressionMethodsCount; i++) {
+ if (temp == compressions[i]) {
+ if (!compressionEnabled(ss, compressions[i])) {
+ break; /* failure */
+ }
+ suite_found = PR_TRUE;
+ break; /* success */
+ }
+ }
+ if (!suite_found) {
+ desc = handshake_failure;
+ errCode = SSL_ERROR_NO_COMPRESSION_OVERLAP;
+ goto alert_loser;
+ }
+ ss->ssl3.hs.compression = (SSLCompressionMethod)temp;
+
+ /* Note that if !isTLS and the extra stuff is not extensions, we
+ * do NOT goto alert_loser.
+ * There are some old SSL 3.0 implementations that do send stuff
+ * after the end of the server hello, and we deliberately ignore
+ * such stuff in the interest of maximal interoperability (being
+ * "generous in what you accept").
+ * Update: Starting in NSS 3.12.6, we handle the renegotiation_info
+ * extension in SSL 3.0.
+ */
+ if (length != 0) {
+ SECItem extensions;
+ rv = ssl3_ConsumeHandshakeVariable(ss, &extensions, 2, &b, &length);
+ if (rv != SECSuccess || length != 0) {
+ if (isTLS)
+ goto alert_loser;
+ } else {
+ rv = ssl3_HandleHelloExtensions(ss, &extensions.data,
+ &extensions.len);
+ if (rv != SECSuccess)
+ goto alert_loser;
+ }
+ }
+ if ((ss->opt.requireSafeNegotiation ||
+ (ss->firstHsDone && (ss->peerRequestedProtection ||
+ ss->opt.enableRenegotiation == SSL_RENEGOTIATE_REQUIRES_XTN))) &&
+ !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) {
+ desc = handshake_failure;
+ errCode = ss->firstHsDone ? SSL_ERROR_RENEGOTIATION_NOT_ALLOWED
+ : SSL_ERROR_UNSAFE_NEGOTIATION;
+ goto alert_loser;
+ }
+
+ /* Any errors after this point are not "malformed" errors. */
+ desc = handshake_failure;
+
+ /* we need to call ssl3_SetupPendingCipherSpec here so we can check the
+ * key exchange algorithm. */
+ rv = ssl3_SetupPendingCipherSpec(ss);
+ if (rv != SECSuccess) {
+ goto alert_loser; /* error code is set. */
+ }
+
+ /* We may or may not have sent a session id, we may get one back or
+ * not and if so it may match the one we sent.
+ * Attempt to restore the master secret to see if this is so...
+ * Don't consider failure to find a matching SID an error.
+ */
+ sid_match = (PRBool)(sidBytes.len > 0 &&
+ sidBytes.len == sid->u.ssl3.sessionIDLength &&
+ !PORT_Memcmp(sid->u.ssl3.sessionID, sidBytes.data, sidBytes.len));
+
+ if (sid_match &&
+ sid->version == ss->version &&
+ sid->u.ssl3.cipherSuite == ss->ssl3.hs.cipher_suite) do {
+ ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
+
+ SECItem wrappedMS; /* wrapped master secret. */
+
+ ss->sec.authAlgorithm = sid->authAlgorithm;
+ ss->sec.authKeyBits = sid->authKeyBits;
+ ss->sec.keaType = sid->keaType;
+ ss->sec.keaKeyBits = sid->keaKeyBits;
+
+ /* 3 cases here:
+ * a) key is wrapped (implies using PKCS11)
+ * b) key is unwrapped, but we're still using PKCS11
+ * c) key is unwrapped, and we're bypassing PKCS11.
+ */
+ if (sid->u.ssl3.keys.msIsWrapped) {
+ PK11SlotInfo *slot;
+ PK11SymKey * wrapKey; /* wrapping key */
+ CK_FLAGS keyFlags = 0;
+
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11) {
+ /* we cannot restart a non-bypass session in a
+ ** bypass socket.
+ */
+ break;
+ }
+#endif
+ /* unwrap master secret with PKCS11 */
+ slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID,
+ sid->u.ssl3.masterSlotID);
+ if (slot == NULL) {
+ break; /* not considered an error. */
+ }
+ if (!PK11_IsPresent(slot)) {
+ PK11_FreeSlot(slot);
+ break; /* not considered an error. */
+ }
+ wrapKey = PK11_GetWrapKey(slot, sid->u.ssl3.masterWrapIndex,
+ sid->u.ssl3.masterWrapMech,
+ sid->u.ssl3.masterWrapSeries,
+ ss->pkcs11PinArg);
+ PK11_FreeSlot(slot);
+ if (wrapKey == NULL) {
+ break; /* not considered an error. */
+ }
+
+ if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */
+ keyFlags = CKF_SIGN | CKF_VERIFY;
+ }
+
+ wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
+ wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
+ pwSpec->master_secret =
+ PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech,
+ NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE,
+ CKA_DERIVE, sizeof(SSL3MasterSecret), keyFlags);
+ errCode = PORT_GetError();
+ PK11_FreeSymKey(wrapKey);
+ if (pwSpec->master_secret == NULL) {
+ break; /* errorCode set just after call to UnwrapSymKey. */
+ }
+#ifndef NO_PKCS11_BYPASS
+ } else if (ss->opt.bypassPKCS11) {
+ /* MS is not wrapped */
+ wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
+ wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
+ memcpy(pwSpec->raw_master_secret, wrappedMS.data, wrappedMS.len);
+ pwSpec->msItem.data = pwSpec->raw_master_secret;
+ pwSpec->msItem.len = wrappedMS.len;
+#endif
+ } else {
+ /* We CAN restart a bypass session in a non-bypass socket. */
+ /* need to import the raw master secret to session object */
+ PK11SlotInfo *slot = PK11_GetInternalSlot();
+ wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
+ wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
+ pwSpec->master_secret =
+ PK11_ImportSymKey(slot, CKM_SSL3_MASTER_KEY_DERIVE,
+ PK11_OriginUnwrap, CKA_ENCRYPT,
+ &wrappedMS, NULL);
+ PK11_FreeSlot(slot);
+ if (pwSpec->master_secret == NULL) {
+ break;
+ }
+ }
+
+ /* Got a Match */
+ SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_cache_hits );
+
+ /* If we sent a session ticket, then this is a stateless resume. */
+ if (sid->version > SSL_LIBRARY_VERSION_3_0 &&
+ sid->u.ssl3.sessionTicket.ticket.data != NULL)
+ SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_stateless_resumes );
+
+ if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn))
+ ss->ssl3.hs.ws = wait_new_session_ticket;
+ else
+ ss->ssl3.hs.ws = wait_change_cipher;
+
+ ss->ssl3.hs.isResuming = PR_TRUE;
+
+ /* copy the peer cert from the SID */
+ if (sid->peerCert != NULL) {
+ ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
+ ssl3_CopyPeerCertsFromSID(ss, sid);
+ }
+
+ /* NULL value for PMS signifies re-use of the old MS */
+ rv = ssl3_InitPendingCipherSpec(ss, NULL);
+ if (rv != SECSuccess) {
+ goto alert_loser; /* err code was set */
+ }
+ goto winner;
+ } while (0);
+
+ if (sid_match)
+ SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_cache_not_ok );
+ else
+ SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_cache_misses );
+
+ /* throw the old one away */
+ sid->u.ssl3.keys.resumable = PR_FALSE;
+ if (ss->sec.uncache)
+ (*ss->sec.uncache)(sid);
+ ssl_FreeSID(sid);
+
+ /* get a new sid */
+ ss->sec.ci.sid = sid = ssl3_NewSessionID(ss, PR_FALSE);
+ if (sid == NULL) {
+ goto alert_loser; /* memory error is set. */
+ }
+
+ sid->version = ss->version;
+ sid->u.ssl3.sessionIDLength = sidBytes.len;
+ PORT_Memcpy(sid->u.ssl3.sessionID, sidBytes.data, sidBytes.len);
+
+ ss->ssl3.hs.isResuming = PR_FALSE;
+ ss->ssl3.hs.ws = wait_server_cert;
+
+winner:
+ /* If we will need a ChannelID key then we make the callback now. This
+ * allows the handshake to be restarted cleanly if the callback returns
+ * SECWouldBlock. */
+ if (ssl3_ExtensionNegotiated(ss, ssl_channel_id_xtn)) {
+ rv = ss->getChannelID(ss->getChannelIDArg, ss->fd,
+ &ss->ssl3.channelIDPub, &ss->ssl3.channelID);
+ if (rv == SECWouldBlock) {
+ ssl3_SetAlwaysBlock(ss);
+ return rv;
+ }
+ if (rv != SECSuccess ||
+ ss->ssl3.channelIDPub == NULL ||
+ ss->ssl3.channelID == NULL) {
+ PORT_SetError(SSL_ERROR_GET_CHANNEL_ID_FAILED);
+ desc = internal_error;
+ goto alert_loser;
+ }
+ }
+
+ return SECSuccess;
+
+alert_loser:
+ (void)SSL3_SendAlert(ss, alert_fatal, desc);
+
+loser:
+ errCode = ssl_MapLowLevelError(errCode);
+ return SECFailure;
+}
+
+/* ssl3_BigIntGreaterThanOne returns true iff |mpint|, taken as an unsigned,
+ * big-endian integer is > 1 */
+static PRBool
+ssl3_BigIntGreaterThanOne(const SECItem* mpint) {
+ unsigned char firstNonZeroByte = 0;
+ unsigned int i;
+
+ for (i = 0; i < mpint->len; i++) {
+ if (mpint->data[i]) {
+ firstNonZeroByte = mpint->data[i];
+ break;
+ }
+ }
+
+ if (firstNonZeroByte == 0)
+ return PR_FALSE;
+ if (firstNonZeroByte > 1)
+ return PR_TRUE;
+
+ /* firstNonZeroByte == 1, therefore mpint > 1 iff the first non-zero byte
+ * is followed by another byte. */
+ return (i < mpint->len - 1);
+}
+
+/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
+ * ssl3 ServerKeyExchange message.
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+static SECStatus
+ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+ PLArenaPool * arena = NULL;
+ SECKEYPublicKey *peerKey = NULL;
+ PRBool isTLS, isTLS12;
+ SECStatus rv;
+ int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH;
+ SSL3AlertDescription desc = illegal_parameter;
+ SSL3Hashes hashes;
+ SECItem signature = {siBuffer, NULL, 0};
+ SSL3SignatureAndHashAlgorithm sigAndHash;
+
+ sigAndHash.hashAlg = SEC_OID_UNKNOWN;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: handle server_key_exchange handshake",
+ SSL_GETPID(), ss->fd));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ if (ss->ssl3.hs.ws != wait_server_key &&
+ ss->ssl3.hs.ws != wait_server_cert) {
+ errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH;
+ desc = unexpected_message;
+ goto alert_loser;
+ }
+ if (ss->sec.peerCert == NULL) {
+ errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH;
+ desc = unexpected_message;
+ goto alert_loser;
+ }
+
+ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
+ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
+
+ switch (ss->ssl3.hs.kea_def->exchKeyType) {
+
+ case kt_rsa: {
+ SECItem modulus = {siBuffer, NULL, 0};
+ SECItem exponent = {siBuffer, NULL, 0};
+
+ rv = ssl3_ConsumeHandshakeVariable(ss, &modulus, 2, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed. */
+ }
+ rv = ssl3_ConsumeHandshakeVariable(ss, &exponent, 2, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed. */
+ }
+ if (isTLS12) {
+ rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
+ &sigAndHash);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed or unsupported. */
+ }
+ rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
+ &sigAndHash, ss->sec.peerCert);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed. */
+ }
+ if (length != 0) {
+ if (isTLS)
+ desc = decode_error;
+ goto alert_loser; /* malformed. */
+ }
+
+ /* failures after this point are not malformed handshakes. */
+ /* TLS: send decrypt_error if signature failed. */
+ desc = isTLS ? decrypt_error : handshake_failure;
+
+ /*
+ * check to make sure the hash is signed by right guy
+ */
+ rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg, modulus, exponent,
+ &ss->ssl3.hs.client_random,
+ &ss->ssl3.hs.server_random,
+ &hashes, ss->opt.bypassPKCS11);
+ if (rv != SECSuccess) {
+ errCode =
+ ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+ goto alert_loser;
+ }
+ rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature,
+ isTLS, ss->pkcs11PinArg);
+ if (rv != SECSuccess) {
+ errCode =
+ ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+ goto alert_loser;
+ }
+
+ /*
+ * we really need to build a new key here because we can no longer
+ * ignore calling SECKEY_DestroyPublicKey. Using the key may allocate
+ * pkcs11 slots and ID's.
+ */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ goto no_memory;
+ }
+
+ peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
+ if (peerKey == NULL) {
+ PORT_FreeArena(arena, PR_FALSE);
+ goto no_memory;
+ }
+
+ peerKey->arena = arena;
+ peerKey->keyType = rsaKey;
+ peerKey->pkcs11Slot = NULL;
+ peerKey->pkcs11ID = CK_INVALID_HANDLE;
+ if (SECITEM_CopyItem(arena, &peerKey->u.rsa.modulus, &modulus) ||
+ SECITEM_CopyItem(arena, &peerKey->u.rsa.publicExponent, &exponent))
+ {
+ PORT_FreeArena(arena, PR_FALSE);
+ goto no_memory;
+ }
+ ss->sec.peerKey = peerKey;
+ ss->ssl3.hs.ws = wait_cert_request;
+ return SECSuccess;
+ }
+
+ case kt_dh: {
+ SECItem dh_p = {siBuffer, NULL, 0};
+ SECItem dh_g = {siBuffer, NULL, 0};
+ SECItem dh_Ys = {siBuffer, NULL, 0};
+
+ rv = ssl3_ConsumeHandshakeVariable(ss, &dh_p, 2, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed. */
+ }
+ if (dh_p.len < 512/8) {
+ errCode = SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY;
+ goto alert_loser;
+ }
+ rv = ssl3_ConsumeHandshakeVariable(ss, &dh_g, 2, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed. */
+ }
+ if (dh_g.len > dh_p.len || !ssl3_BigIntGreaterThanOne(&dh_g))
+ goto alert_loser;
+ rv = ssl3_ConsumeHandshakeVariable(ss, &dh_Ys, 2, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed. */
+ }
+ if (dh_Ys.len > dh_p.len || !ssl3_BigIntGreaterThanOne(&dh_Ys))
+ goto alert_loser;
+ if (isTLS12) {
+ rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
+ &sigAndHash);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed or unsupported. */
+ }
+ rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
+ &sigAndHash, ss->sec.peerCert);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed. */
+ }
+ if (length != 0) {
+ if (isTLS)
+ desc = decode_error;
+ goto alert_loser; /* malformed. */
+ }
+
+ PRINT_BUF(60, (NULL, "Server DH p", dh_p.data, dh_p.len));
+ PRINT_BUF(60, (NULL, "Server DH g", dh_g.data, dh_g.len));
+ PRINT_BUF(60, (NULL, "Server DH Ys", dh_Ys.data, dh_Ys.len));
+
+ /* failures after this point are not malformed handshakes. */
+ /* TLS: send decrypt_error if signature failed. */
+ desc = isTLS ? decrypt_error : handshake_failure;
+
+ /*
+ * check to make sure the hash is signed by right guy
+ */
+ rv = ssl3_ComputeDHKeyHash(sigAndHash.hashAlg, dh_p, dh_g, dh_Ys,
+ &ss->ssl3.hs.client_random,
+ &ss->ssl3.hs.server_random,
+ &hashes, ss->opt.bypassPKCS11);
+ if (rv != SECSuccess) {
+ errCode =
+ ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+ goto alert_loser;
+ }
+ rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature,
+ isTLS, ss->pkcs11PinArg);
+ if (rv != SECSuccess) {
+ errCode =
+ ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+ goto alert_loser;
+ }
+
+ /*
+ * we really need to build a new key here because we can no longer
+ * ignore calling SECKEY_DestroyPublicKey. Using the key may allocate
+ * pkcs11 slots and ID's.
+ */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ goto no_memory;
+ }
+
+ ss->sec.peerKey = peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
+ if (peerKey == NULL) {
+ goto no_memory;
+ }
+
+ peerKey->arena = arena;
+ peerKey->keyType = dhKey;
+ peerKey->pkcs11Slot = NULL;
+ peerKey->pkcs11ID = CK_INVALID_HANDLE;
+
+ if (SECITEM_CopyItem(arena, &peerKey->u.dh.prime, &dh_p) ||
+ SECITEM_CopyItem(arena, &peerKey->u.dh.base, &dh_g) ||
+ SECITEM_CopyItem(arena, &peerKey->u.dh.publicValue, &dh_Ys))
+ {
+ PORT_FreeArena(arena, PR_FALSE);
+ goto no_memory;
+ }
+ ss->sec.peerKey = peerKey;
+ ss->ssl3.hs.ws = wait_cert_request;
+ return SECSuccess;
+ }
+
+#ifdef NSS_ENABLE_ECC
+ case kt_ecdh:
+ rv = ssl3_HandleECDHServerKeyExchange(ss, b, length);
+ return rv;
+#endif /* NSS_ENABLE_ECC */
+
+ default:
+ desc = handshake_failure;
+ errCode = SEC_ERROR_UNSUPPORTED_KEYALG;
+ break; /* goto alert_loser; */
+ }
+
+alert_loser:
+ (void)SSL3_SendAlert(ss, alert_fatal, desc);
+loser:
+ PORT_SetError( errCode );
+ return SECFailure;
+
+no_memory: /* no-memory error has already been set. */
+ ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+ return SECFailure;
+}
+
+
+typedef struct dnameNode {
+ struct dnameNode *next;
+ SECItem name;
+} dnameNode;
+
+/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
+ * ssl3 Certificate Request message.
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+static SECStatus
+ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+ PLArenaPool * arena = NULL;
+ dnameNode * node;
+ PRInt32 remaining;
+ PRBool isTLS = PR_FALSE;
+ PRBool isTLS12 = PR_FALSE;
+ int i;
+ int errCode = SSL_ERROR_RX_MALFORMED_CERT_REQUEST;
+ int nnames = 0;
+ SECStatus rv;
+ SSL3AlertDescription desc = illegal_parameter;
+ SECItem cert_types = {siBuffer, NULL, 0};
+ SECItem algorithms = {siBuffer, NULL, 0};
+ CERTDistNames ca_list;
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ CERTCertList * platform_cert_list = NULL;
+ CERTCertListNode * certNode = NULL;
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
+
+ SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_request handshake",
+ SSL_GETPID(), ss->fd));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ if (ss->ssl3.hs.ws != wait_cert_request &&
+ ss->ssl3.hs.ws != wait_server_key) {
+ desc = unexpected_message;
+ errCode = SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST;
+ goto alert_loser;
+ }
+
+ PORT_Assert(ss->ssl3.clientCertChain == NULL);
+ PORT_Assert(ss->ssl3.clientCertificate == NULL);
+ PORT_Assert(ss->ssl3.clientPrivateKey == NULL);
+ PORT_Assert(ss->ssl3.platformClientKey == (PlatformKey)NULL);
+
+ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
+ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
+ rv = ssl3_ConsumeHandshakeVariable(ss, &cert_types, 1, &b, &length);
+ if (rv != SECSuccess)
+ goto loser; /* malformed, alert has been sent */
+
+ PORT_Assert(!ss->requestedCertTypes);
+ ss->requestedCertTypes = &cert_types;
+
+ if (isTLS12) {
+ rv = ssl3_ConsumeHandshakeVariable(ss, &algorithms, 2, &b, &length);
+ if (rv != SECSuccess)
+ goto loser; /* malformed, alert has been sent */
+ /* An empty or odd-length value is invalid.
+ * SignatureAndHashAlgorithm
+ * supported_signature_algorithms<2..2^16-2>;
+ */
+ if (algorithms.len == 0 || (algorithms.len & 1) != 0)
+ goto alert_loser;
+ }
+
+ arena = ca_list.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL)
+ goto no_mem;
+
+ remaining = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
+ if (remaining < 0)
+ goto loser; /* malformed, alert has been sent */
+
+ if ((PRUint32)remaining > length)
+ goto alert_loser;
+
+ ca_list.head = node = PORT_ArenaZNew(arena, dnameNode);
+ if (node == NULL)
+ goto no_mem;
+
+ while (remaining > 0) {
+ PRInt32 len;
+
+ if (remaining < 2)
+ goto alert_loser; /* malformed */
+
+ node->name.len = len = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
+ if (len <= 0)
+ goto loser; /* malformed, alert has been sent */
+
+ remaining -= 2;
+ if (remaining < len)
+ goto alert_loser; /* malformed */
+
+ node->name.data = b;
+ b += len;
+ length -= len;
+ remaining -= len;
+ nnames++;
+ if (remaining <= 0)
+ break; /* success */
+
+ node->next = PORT_ArenaZNew(arena, dnameNode);
+ node = node->next;
+ if (node == NULL)
+ goto no_mem;
+ }
+
+ ca_list.nnames = nnames;
+ ca_list.names = PORT_ArenaNewArray(arena, SECItem, nnames);
+ if (nnames > 0 && ca_list.names == NULL)
+ goto no_mem;
+
+ for(i = 0, node = (dnameNode*)ca_list.head;
+ i < nnames;
+ i++, node = node->next) {
+ ca_list.names[i] = node->name;
+ }
+
+ if (length != 0)
+ goto alert_loser; /* malformed */
+
+ desc = no_certificate;
+ ss->ssl3.hs.ws = wait_hello_done;
+
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ if (ss->getPlatformClientAuthData != NULL) {
+ /* XXX Should pass cert_types and algorithms in this call!! */
+ rv = (SECStatus)(*ss->getPlatformClientAuthData)(
+ ss->getPlatformClientAuthDataArg,
+ ss->fd, &ca_list,
+ &platform_cert_list,
+ (void**)&ss->ssl3.platformClientKey,
+ &ss->ssl3.clientCertificate,
+ &ss->ssl3.clientPrivateKey);
+ } else
+#endif
+ if (ss->getClientAuthData != NULL) {
+ /* XXX Should pass cert_types and algorithms in this call!! */
+ rv = (SECStatus)(*ss->getClientAuthData)(ss->getClientAuthDataArg,
+ ss->fd, &ca_list,
+ &ss->ssl3.clientCertificate,
+ &ss->ssl3.clientPrivateKey);
+ } else {
+ rv = SECFailure; /* force it to send a no_certificate alert */
+ }
+
+ switch (rv) {
+ case SECWouldBlock: /* getClientAuthData has put up a dialog box. */
+ ssl3_SetAlwaysBlock(ss);
+ break; /* not an error */
+
+ case SECSuccess:
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ if (!platform_cert_list || CERT_LIST_EMPTY(platform_cert_list) ||
+ !ss->ssl3.platformClientKey) {
+ if (platform_cert_list) {
+ CERT_DestroyCertList(platform_cert_list);
+ platform_cert_list = NULL;
+ }
+ if (ss->ssl3.platformClientKey) {
+ ssl_FreePlatformKey(ss->ssl3.platformClientKey);
+ ss->ssl3.platformClientKey = (PlatformKey)NULL;
+ }
+ /* Fall through to NSS client auth check */
+ } else {
+ certNode = CERT_LIST_HEAD(platform_cert_list);
+ ss->ssl3.clientCertificate = CERT_DupCertificate(certNode->cert);
+
+ /* Setting ssl3.clientCertChain non-NULL will cause
+ * ssl3_HandleServerHelloDone to call SendCertificate.
+ * Note: clientCertChain should include the EE cert as
+ * clientCertificate is ignored during the actual sending
+ */
+ ss->ssl3.clientCertChain =
+ hack_NewCertificateListFromCertList(platform_cert_list);
+ CERT_DestroyCertList(platform_cert_list);
+ platform_cert_list = NULL;
+ if (ss->ssl3.clientCertChain == NULL) {
+ if (ss->ssl3.clientCertificate != NULL) {
+ CERT_DestroyCertificate(ss->ssl3.clientCertificate);
+ ss->ssl3.clientCertificate = NULL;
+ }
+ if (ss->ssl3.platformClientKey) {
+ ssl_FreePlatformKey(ss->ssl3.platformClientKey);
+ ss->ssl3.platformClientKey = (PlatformKey)NULL;
+ }
+ goto send_no_certificate;
+ }
+ break; /* not an error */
+ }
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
+ /* check what the callback function returned */
+ if ((!ss->ssl3.clientCertificate) || (!ss->ssl3.clientPrivateKey)) {
+ /* we are missing either the key or cert */
+ if (ss->ssl3.clientCertificate) {
+ /* got a cert, but no key - free it */
+ CERT_DestroyCertificate(ss->ssl3.clientCertificate);
+ ss->ssl3.clientCertificate = NULL;
+ }
+ if (ss->ssl3.clientPrivateKey) {
+ /* got a key, but no cert - free it */
+ SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
+ ss->ssl3.clientPrivateKey = NULL;
+ }
+ goto send_no_certificate;
+ }
+ /* Setting ssl3.clientCertChain non-NULL will cause
+ * ssl3_HandleServerHelloDone to call SendCertificate.
+ */
+ ss->ssl3.clientCertChain = CERT_CertChainFromCert(
+ ss->ssl3.clientCertificate,
+ certUsageSSLClient, PR_FALSE);
+ if (ss->ssl3.clientCertChain == NULL) {
+ if (ss->ssl3.clientCertificate != NULL) {
+ CERT_DestroyCertificate(ss->ssl3.clientCertificate);
+ ss->ssl3.clientCertificate = NULL;
+ }
+ if (ss->ssl3.clientPrivateKey != NULL) {
+ SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
+ ss->ssl3.clientPrivateKey = NULL;
+ }
+ goto send_no_certificate;
+ }
+ break; /* not an error */
+
+ case SECFailure:
+ default:
+send_no_certificate:
+ if (isTLS) {
+ ss->ssl3.sendEmptyCert = PR_TRUE;
+ } else {
+ (void)SSL3_SendAlert(ss, alert_warning, no_certificate);
+ }
+ rv = SECSuccess;
+ break;
+ }
+ goto done;
+
+no_mem:
+ rv = SECFailure;
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ goto done;
+
+alert_loser:
+ if (isTLS && desc == illegal_parameter)
+ desc = decode_error;
+ (void)SSL3_SendAlert(ss, alert_fatal, desc);
+loser:
+ PORT_SetError(errCode);
+ rv = SECFailure;
+done:
+ ss->requestedCertTypes = NULL;
+ if (arena != NULL)
+ PORT_FreeArena(arena, PR_FALSE);
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ if (platform_cert_list)
+ CERT_DestroyCertList(platform_cert_list);
+#endif
+ return rv;
+}
+
+/*
+ * attempt to restart the handshake after asynchronously handling
+ * a request for the client's certificate.
+ *
+ * inputs:
+ * cert Client cert chosen by application.
+ * Note: ssl takes this reference, and does not bump the
+ * reference count. The caller should drop its reference
+ * without calling CERT_DestroyCert after calling this function.
+ *
+ * key Private key associated with cert. This function takes
+ * ownership of the private key, so the caller should drop its
+ * reference without destroying the private key after this
+ * function returns.
+ *
+ * certChain DER-encoded certs, client cert and its signers.
+ * Note: ssl takes this reference, and does not copy the chain.
+ * The caller should drop its reference without destroying the
+ * chain. SSL will free the chain when it is done with it.
+ *
+ * Return value: XXX
+ *
+ * XXX This code only works on the initial handshake on a connection, XXX
+ * It does not work on a subsequent handshake (redo).
+ *
+ * Caller holds 1stHandshakeLock.
+ */
+SECStatus
+ssl3_RestartHandshakeAfterCertReq(sslSocket * ss,
+ CERTCertificate * cert,
+ SECKEYPrivateKey * key,
+ CERTCertificateList *certChain)
+{
+ SECStatus rv = SECSuccess;
+
+ /* XXX This code only works on the initial handshake on a connection,
+ ** XXX It does not work on a subsequent handshake (redo).
+ */
+ if (ss->handshake != 0) {
+ ss->handshake = ssl_GatherRecord1stHandshake;
+ ss->ssl3.clientCertificate = cert;
+ ss->ssl3.clientPrivateKey = key;
+ ss->ssl3.clientCertChain = certChain;
+ if (!cert || !key || !certChain) {
+ /* we are missing the key, cert, or cert chain */
+ if (ss->ssl3.clientCertificate) {
+ CERT_DestroyCertificate(ss->ssl3.clientCertificate);
+ ss->ssl3.clientCertificate = NULL;
+ }
+ if (ss->ssl3.clientPrivateKey) {
+ SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
+ ss->ssl3.clientPrivateKey = NULL;
+ }
+ if (ss->ssl3.clientCertChain != NULL) {
+ CERT_DestroyCertificateList(ss->ssl3.clientCertChain);
+ ss->ssl3.clientCertChain = NULL;
+ }
+ if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) {
+ ss->ssl3.sendEmptyCert = PR_TRUE;
+ } else {
+ (void)SSL3_SendAlert(ss, alert_warning, no_certificate);
+ }
+ }
+ } else {
+ if (cert) {
+ CERT_DestroyCertificate(cert);
+ }
+ if (key) {
+ SECKEY_DestroyPrivateKey(key);
+ }
+ if (certChain) {
+ CERT_DestroyCertificateList(certChain);
+ }
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ rv = SECFailure;
+ }
+ return rv;
+}
+
+PRBool
+ssl3_CanFalseStart(sslSocket *ss) {
+ PRBool rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ /* XXX: does not take into account whether we are waiting for
+ * SSL_AuthCertificateComplete or SSL_RestartHandshakeAfterCertReq. If/when
+ * that is done, this function could return different results each time it
+ * would be called.
+ */
+
+ ssl_GetSpecReadLock(ss);
+ rv = ss->opt.enableFalseStart &&
+ !ss->sec.isServer &&
+ !ss->ssl3.hs.isResuming &&
+ ss->ssl3.cwSpec &&
+
+ /* An attacker can control the selected ciphersuite so we only wish to
+ * do False Start in the case that the selected ciphersuite is
+ * sufficiently strong that the attack can gain no advantage.
+ * Therefore we require an 80-bit cipher and a forward-secret key
+ * exchange. */
+ ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10 &&
+ (ss->ssl3.hs.kea_def->kea == kea_dhe_dss ||
+ ss->ssl3.hs.kea_def->kea == kea_dhe_rsa ||
+ ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa ||
+ ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa);
+ ssl_ReleaseSpecReadLock(ss);
+ return rv;
+}
+
+static SECStatus ssl3_SendClientSecondRound(sslSocket *ss);
+
+/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
+ * ssl3 Server Hello Done message.
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+static SECStatus
+ssl3_HandleServerHelloDone(sslSocket *ss)
+{
+ SECStatus rv;
+ SSL3WaitState ws = ss->ssl3.hs.ws;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello_done handshake",
+ SSL_GETPID(), ss->fd));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ if (ws != wait_hello_done &&
+ ws != wait_server_cert &&
+ ws != wait_server_key &&
+ ws != wait_cert_request) {
+ SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
+ return SECFailure;
+ }
+
+ rv = ssl3_SendClientSecondRound(ss);
+
+ return rv;
+}
+
+/* Called from ssl3_HandleServerHelloDone and ssl3_AuthCertificateComplete.
+ *
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+static SECStatus
+ssl3_SendClientSecondRound(sslSocket *ss)
+{
+ SECStatus rv;
+ PRBool sendClientCert;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ sendClientCert = !ss->ssl3.sendEmptyCert &&
+ ss->ssl3.clientCertChain != NULL &&
+ (ss->ssl3.platformClientKey ||
+ ss->ssl3.clientPrivateKey != NULL);
+
+ /* We must wait for the server's certificate to be authenticated before
+ * sending the client certificate in order to disclosing the client
+ * certificate to an attacker that does not have a valid cert for the
+ * domain we are connecting to.
+ *
+ * XXX: We should do the same for the NPN extension, but for that we
+ * need an option to give the application the ability to leak the NPN
+ * information to get better performance.
+ *
+ * During the initial handshake on a connection, we never send/receive
+ * application data until we have authenticated the server's certificate;
+ * i.e. we have fully authenticated the handshake before using the cipher
+ * specs agreed upon for that handshake. During a renegotiation, we may
+ * continue sending and receiving application data during the handshake
+ * interleaved with the handshake records. If we were to send the client's
+ * second round for a renegotiation before the server's certificate was
+ * authenticated, then the application data sent/received after this point
+ * would be using cipher spec that hadn't been authenticated. By waiting
+ * until the server's certificate has been authenticated during
+ * renegotiations, we ensure that renegotiations have the same property
+ * as initial handshakes; i.e. we have fully authenticated the handshake
+ * before using the cipher specs agreed upon for that handshake for
+ * application data.
+ */
+ if (ss->ssl3.hs.restartTarget) {
+ PR_NOT_REACHED("unexpected ss->ssl3.hs.restartTarget");
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ if (ss->ssl3.hs.authCertificatePending &&
+ (sendClientCert || ss->ssl3.sendEmptyCert || ss->firstHsDone)) {
+ ss->ssl3.hs.restartTarget = ssl3_SendClientSecondRound;
+ return SECWouldBlock;
+ }
+
+ ssl_GetXmitBufLock(ss); /*******************************/
+
+ if (ss->ssl3.sendEmptyCert) {
+ ss->ssl3.sendEmptyCert = PR_FALSE;
+ rv = ssl3_SendEmptyCertificate(ss);
+ /* Don't send verify */
+ if (rv != SECSuccess) {
+ goto loser; /* error code is set. */
+ }
+ } else if (sendClientCert) {
+ rv = ssl3_SendCertificate(ss);
+ if (rv != SECSuccess) {
+ goto loser; /* error code is set. */
+ }
+ }
+
+ rv = ssl3_SendClientKeyExchange(ss);
+ if (rv != SECSuccess) {
+ goto loser; /* err is set. */
+ }
+
+ if (sendClientCert) {
+ rv = ssl3_SendCertificateVerify(ss);
+ if (rv != SECSuccess) {
+ goto loser; /* err is set. */
+ }
+ }
+
+ rv = ssl3_SendChangeCipherSpecs(ss);
+ if (rv != SECSuccess) {
+ goto loser; /* err code was set. */
+ }
+
+ /* XXX: If the server's certificate hasn't been authenticated by this
+ * point, then we may be leaking this NPN message to an attacker.
+ */
+ if (!ss->firstHsDone) {
+ rv = ssl3_SendNextProto(ss);
+ if (rv != SECSuccess) {
+ goto loser; /* err code was set. */
+ }
+ }
+ rv = ssl3_SendEncryptedExtensions(ss);
+ if (rv != SECSuccess) {
+ goto loser; /* err code was set. */
+ }
+
+ rv = ssl3_SendFinished(ss, 0);
+ if (rv != SECSuccess) {
+ goto loser; /* err code was set. */
+ }
+
+ ssl_ReleaseXmitBufLock(ss); /*******************************/
+
+ if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn))
+ ss->ssl3.hs.ws = wait_new_session_ticket;
+ else
+ ss->ssl3.hs.ws = wait_change_cipher;
+
+ /* Do the handshake callback for sslv3 here, if we can false start. */
+ if (ss->handshakeCallback != NULL && ssl3_CanFalseStart(ss)) {
+ (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
+ }
+
+ return SECSuccess;
+
+loser:
+ ssl_ReleaseXmitBufLock(ss);
+ return rv;
+}
+
+/*
+ * Routines used by servers
+ */
+static SECStatus
+ssl3_SendHelloRequest(sslSocket *ss)
+{
+ SECStatus rv;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: send hello_request handshake", SSL_GETPID(),
+ ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
+
+ rv = ssl3_AppendHandshakeHeader(ss, hello_request, 0);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake */
+ }
+ rv = ssl3_FlushHandshake(ss, 0);
+ if (rv != SECSuccess) {
+ return rv; /* error code set by ssl3_FlushHandshake */
+ }
+ ss->ssl3.hs.ws = wait_client_hello;
+ return SECSuccess;
+}
+
+/*
+ * Called from:
+ * ssl3_HandleClientHello()
+ */
+static SECComparison
+ssl3_ServerNameCompare(const SECItem *name1, const SECItem *name2)
+{
+ if (!name1 != !name2) {
+ return SECLessThan;
+ }
+ if (!name1) {
+ return SECEqual;
+ }
+ if (name1->type != name2->type) {
+ return SECLessThan;
+ }
+ return SECITEM_CompareItem(name1, name2);
+}
+
+/* Sets memory error when returning NULL.
+ * Called from:
+ * ssl3_SendClientHello()
+ * ssl3_HandleServerHello()
+ * ssl3_HandleClientHello()
+ * ssl3_HandleV2ClientHello()
+ */
+sslSessionID *
+ssl3_NewSessionID(sslSocket *ss, PRBool is_server)
+{
+ sslSessionID *sid;
+
+ sid = PORT_ZNew(sslSessionID);
+ if (sid == NULL)
+ return sid;
+
+ if (is_server) {
+ const SECItem * srvName;
+ SECStatus rv = SECSuccess;
+
+ ssl_GetSpecReadLock(ss); /********************************/
+ srvName = &ss->ssl3.prSpec->srvVirtName;
+ if (srvName->len && srvName->data) {
+ rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.srvName, srvName);
+ }
+ ssl_ReleaseSpecReadLock(ss); /************************************/
+ if (rv != SECSuccess) {
+ PORT_Free(sid);
+ return NULL;
+ }
+ }
+ sid->peerID = (ss->peerID == NULL) ? NULL : PORT_Strdup(ss->peerID);
+ sid->urlSvrName = (ss->url == NULL) ? NULL : PORT_Strdup(ss->url);
+ sid->addr = ss->sec.ci.peer;
+ sid->port = ss->sec.ci.port;
+ sid->references = 1;
+ sid->cached = never_cached;
+ sid->version = ss->version;
+
+ sid->u.ssl3.keys.resumable = PR_TRUE;
+ sid->u.ssl3.policy = SSL_ALLOWED;
+ sid->u.ssl3.clientWriteKey = NULL;
+ sid->u.ssl3.serverWriteKey = NULL;
+
+ if (is_server) {
+ SECStatus rv;
+ int pid = SSL_GETPID();
+
+ sid->u.ssl3.sessionIDLength = SSL3_SESSIONID_BYTES;
+ sid->u.ssl3.sessionID[0] = (pid >> 8) & 0xff;
+ sid->u.ssl3.sessionID[1] = pid & 0xff;
+ rv = PK11_GenerateRandom(sid->u.ssl3.sessionID + 2,
+ SSL3_SESSIONID_BYTES -2);
+ if (rv != SECSuccess) {
+ ssl_FreeSID(sid);
+ ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE);
+ return NULL;
+ }
+ }
+ return sid;
+}
+
+/* Called from: ssl3_HandleClientHello, ssl3_HandleV2ClientHello */
+static SECStatus
+ssl3_SendServerHelloSequence(sslSocket *ss)
+{
+ const ssl3KEADef *kea_def;
+ SECStatus rv;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: begin send server_hello sequence",
+ SSL_GETPID(), ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
+
+ rv = ssl3_SendServerHello(ss);
+ if (rv != SECSuccess) {
+ return rv; /* err code is set. */
+ }
+ rv = ssl3_SendCertificate(ss);
+ if (rv != SECSuccess) {
+ return rv; /* error code is set. */
+ }
+ rv = ssl3_SendCertificateStatus(ss);
+ if (rv != SECSuccess) {
+ return rv; /* error code is set. */
+ }
+ /* We have to do this after the call to ssl3_SendServerHello,
+ * because kea_def is set up by ssl3_SendServerHello().
+ */
+ kea_def = ss->ssl3.hs.kea_def;
+ ss->ssl3.hs.usedStepDownKey = PR_FALSE;
+
+ if (kea_def->is_limited && kea_def->exchKeyType == kt_rsa) {
+ /* see if we can legally use the key in the cert. */
+ int keyLen; /* bytes */
+
+ keyLen = PK11_GetPrivateModulusLen(
+ ss->serverCerts[kea_def->exchKeyType].SERVERKEY);
+
+ if (keyLen > 0 &&
+ keyLen * BPB <= kea_def->key_size_limit ) {
+ /* XXX AND cert is not signing only!! */
+ /* just fall through and use it. */
+ } else if (ss->stepDownKeyPair != NULL) {
+ ss->ssl3.hs.usedStepDownKey = PR_TRUE;
+ rv = ssl3_SendServerKeyExchange(ss);
+ if (rv != SECSuccess) {
+ return rv; /* err code was set. */
+ }
+ } else {
+#ifndef HACKED_EXPORT_SERVER
+ PORT_SetError(SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED);
+ return rv;
+#endif
+ }
+#ifdef NSS_ENABLE_ECC
+ } else if ((kea_def->kea == kea_ecdhe_rsa) ||
+ (kea_def->kea == kea_ecdhe_ecdsa)) {
+ rv = ssl3_SendServerKeyExchange(ss);
+ if (rv != SECSuccess) {
+ return rv; /* err code was set. */
+ }
+#endif /* NSS_ENABLE_ECC */
+ }
+
+ if (ss->opt.requestCertificate) {
+ rv = ssl3_SendCertificateRequest(ss);
+ if (rv != SECSuccess) {
+ return rv; /* err code is set. */
+ }
+ }
+ rv = ssl3_SendServerHelloDone(ss);
+ if (rv != SECSuccess) {
+ return rv; /* err code is set. */
+ }
+
+ ss->ssl3.hs.ws = (ss->opt.requestCertificate) ? wait_client_cert
+ : wait_client_key;
+ return SECSuccess;
+}
+
+/* An empty TLS Renegotiation Info (RI) extension */
+static const PRUint8 emptyRIext[5] = {0xff, 0x01, 0x00, 0x01, 0x00};
+
+/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
+ * ssl3 Client Hello message.
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+static SECStatus
+ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+ sslSessionID * sid = NULL;
+ PRInt32 tmp;
+ unsigned int i;
+ int j;
+ SECStatus rv;
+ int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO;
+ SSL3AlertDescription desc = illegal_parameter;
+ SSL3AlertLevel level = alert_fatal;
+ SSL3ProtocolVersion version;
+ SECItem sidBytes = {siBuffer, NULL, 0};
+ SECItem cookieBytes = {siBuffer, NULL, 0};
+ SECItem suites = {siBuffer, NULL, 0};
+ SECItem comps = {siBuffer, NULL, 0};
+ PRBool haveSpecWriteLock = PR_FALSE;
+ PRBool haveXmitBufLock = PR_FALSE;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: handle client_hello handshake",
+ SSL_GETPID(), ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert( ss->ssl3.initialized );
+
+ /* Get peer name of client */
+ rv = ssl_GetPeerInfo(ss);
+ if (rv != SECSuccess) {
+ return rv; /* error code is set. */
+ }
+
+ /* Clearing the handshake pointers so that ssl_Do1stHandshake won't
+ * call ssl2_HandleMessage.
+ *
+ * The issue here is that TLS ordinarily starts out in
+ * ssl2_HandleV3HandshakeRecord() because of the backward-compatibility
+ * code paths. That function zeroes these next pointers. But with DTLS,
+ * we don't even try to do the v2 ClientHello so we skip that function
+ * and need to reset these values here.
+ */
+ if (IS_DTLS(ss)) {
+ ss->nextHandshake = 0;
+ ss->securityHandshake = 0;
+ }
+
+ /* We might be starting session renegotiation in which case we should
+ * clear previous state.
+ */
+ PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData));
+ ss->statelessResume = PR_FALSE;
+
+ if ((ss->ssl3.hs.ws != wait_client_hello) &&
+ (ss->ssl3.hs.ws != idle_handshake)) {
+ desc = unexpected_message;
+ errCode = SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO;
+ goto alert_loser;
+ }
+ if (ss->ssl3.hs.ws == idle_handshake &&
+ ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
+ desc = no_renegotiation;
+ level = alert_warning;
+ errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
+ goto alert_loser;
+ }
+
+ if (IS_DTLS(ss)) {
+ dtls_RehandshakeCleanup(ss);
+ }
+
+ tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
+ if (tmp < 0)
+ goto loser; /* malformed, alert already sent */
+
+ /* Translate the version */
+ if (IS_DTLS(ss)) {
+ ss->clientHelloVersion = version =
+ dtls_DTLSVersionToTLSVersion((SSL3ProtocolVersion)tmp);
+ } else {
+ ss->clientHelloVersion = version = (SSL3ProtocolVersion)tmp;
+ }
+
+ rv = ssl3_NegotiateVersion(ss, version, PR_TRUE);
+ if (rv != SECSuccess) {
+ desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version
+ : handshake_failure;
+ errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
+ goto alert_loser;
+ }
+
+ rv = ssl3_InitHandshakeHashes(ss);
+ if (rv != SECSuccess) {
+ desc = internal_error;
+ errCode = PORT_GetError();
+ goto alert_loser;
+ }
+
+ /* grab the client random data. */
+ rv = ssl3_ConsumeHandshake(
+ ss, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed */
+ }
+
+ /* grab the client's SID, if present. */
+ rv = ssl3_ConsumeHandshakeVariable(ss, &sidBytes, 1, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed */
+ }
+
+ /* grab the client's cookie, if present. */
+ if (IS_DTLS(ss)) {
+ rv = ssl3_ConsumeHandshakeVariable(ss, &cookieBytes, 1, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed */
+ }
+ }
+
+ /* grab the list of cipher suites. */
+ rv = ssl3_ConsumeHandshakeVariable(ss, &suites, 2, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed */
+ }
+
+ /* grab the list of compression methods. */
+ rv = ssl3_ConsumeHandshakeVariable(ss, &comps, 1, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed */
+ }
+
+ desc = handshake_failure;
+
+ /* Handle TLS hello extensions for SSL3 & TLS. We do not know if
+ * we are restarting a previous session until extensions have been
+ * parsed, since we might have received a SessionTicket extension.
+ * Note: we allow extensions even when negotiating SSL3 for the sake
+ * of interoperability (and backwards compatibility).
+ */
+
+ if (length) {
+ /* Get length of hello extensions */
+ PRInt32 extension_length;
+ extension_length = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
+ if (extension_length < 0) {
+ goto loser; /* alert already sent */
+ }
+ if (extension_length != length) {
+ ssl3_DecodeError(ss); /* send alert */
+ goto loser;
+ }
+ rv = ssl3_HandleHelloExtensions(ss, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed */
+ }
+ }
+ if (!ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) {
+ /* If we didn't receive an RI extension, look for the SCSV,
+ * and if found, treat it just like an empty RI extension
+ * by processing a local copy of an empty RI extension.
+ */
+ for (i = 0; i + 1 < suites.len; i += 2) {
+ PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1];
+ if (suite_i == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) {
+ SSL3Opaque * b2 = (SSL3Opaque *)emptyRIext;
+ PRUint32 L2 = sizeof emptyRIext;
+ (void)ssl3_HandleHelloExtensions(ss, &b2, &L2);
+ break;
+ }
+ }
+ }
+ if (ss->firstHsDone &&
+ (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_REQUIRES_XTN ||
+ ss->opt.enableRenegotiation == SSL_RENEGOTIATE_TRANSITIONAL) &&
+ !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) {
+ desc = no_renegotiation;
+ level = alert_warning;
+ errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
+ goto alert_loser;
+ }
+ if ((ss->opt.requireSafeNegotiation ||
+ (ss->firstHsDone && ss->peerRequestedProtection)) &&
+ !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) {
+ desc = handshake_failure;
+ errCode = SSL_ERROR_UNSAFE_NEGOTIATION;
+ goto alert_loser;
+ }
+
+ /* We do stateful resumes only if either of the following
+ * conditions are satisfied: (1) the client does not support the
+ * session ticket extension, or (2) the client support the session
+ * ticket extension, but sent an empty ticket.
+ */
+ if (!ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) ||
+ ss->xtnData.emptySessionTicket) {
+ if (sidBytes.len > 0 && !ss->opt.noCache) {
+ SSL_TRC(7, ("%d: SSL3[%d]: server, lookup client session-id for 0x%08x%08x%08x%08x",
+ SSL_GETPID(), ss->fd, ss->sec.ci.peer.pr_s6_addr32[0],
+ ss->sec.ci.peer.pr_s6_addr32[1],
+ ss->sec.ci.peer.pr_s6_addr32[2],
+ ss->sec.ci.peer.pr_s6_addr32[3]));
+ if (ssl_sid_lookup) {
+ sid = (*ssl_sid_lookup)(&ss->sec.ci.peer, sidBytes.data,
+ sidBytes.len, ss->dbHandle);
+ } else {
+ errCode = SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED;
+ goto loser;
+ }
+ }
+ } else if (ss->statelessResume) {
+ /* Fill in the client's session ID if doing a stateless resume.
+ * (When doing stateless resumes, server echos client's SessionID.)
+ */
+ sid = ss->sec.ci.sid;
+ PORT_Assert(sid != NULL); /* Should have already been filled in.*/
+
+ if (sidBytes.len > 0 && sidBytes.len <= SSL3_SESSIONID_BYTES) {
+ sid->u.ssl3.sessionIDLength = sidBytes.len;
+ PORT_Memcpy(sid->u.ssl3.sessionID, sidBytes.data,
+ sidBytes.len);
+ sid->u.ssl3.sessionIDLength = sidBytes.len;
+ } else {
+ sid->u.ssl3.sessionIDLength = 0;
+ }
+ ss->sec.ci.sid = NULL;
+ }
+
+ /* We only send a session ticket extension if the client supports
+ * the extension and we are unable to do either a stateful or
+ * stateless resume.
+ *
+ * TODO: send a session ticket if performing a stateful
+ * resumption. (As per RFC4507, a server may issue a session
+ * ticket while doing a (stateless or stateful) session resume,
+ * but OpenSSL-0.9.8g does not accept session tickets while
+ * resuming.)
+ */
+ if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) && sid == NULL) {
+ ssl3_RegisterServerHelloExtensionSender(ss,
+ ssl_session_ticket_xtn, ssl3_SendSessionTicketXtn);
+ }
+
+ if (sid != NULL) {
+ /* We've found a session cache entry for this client.
+ * Now, if we're going to require a client-auth cert,
+ * and we don't already have this client's cert in the session cache,
+ * and this is the first handshake on this connection (not a redo),
+ * then drop this old cache entry and start a new session.
+ */
+ if ((sid->peerCert == NULL) && ss->opt.requestCertificate &&
+ ((ss->opt.requireCertificate == SSL_REQUIRE_ALWAYS) ||
+ (ss->opt.requireCertificate == SSL_REQUIRE_NO_ERROR) ||
+ ((ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE)
+ && !ss->firstHsDone))) {
+
+ SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_not_ok );
+ if (ss->sec.uncache)
+ ss->sec.uncache(sid);
+ ssl_FreeSID(sid);
+ sid = NULL;
+ }
+ }
+
+#ifdef NSS_ENABLE_ECC
+ /* Disable any ECC cipher suites for which we have no cert. */
+ ssl3_FilterECCipherSuitesByServerCerts(ss);
+#endif
+
+ if (IS_DTLS(ss)) {
+ ssl3_DisableNonDTLSSuites(ss);
+ }
+
+ if (!ssl3_HasGCMSupport()) {
+ ssl3_DisableGCMSuites(ss);
+ }
+
+#ifdef PARANOID
+ /* Look for a matching cipher suite. */
+ j = ssl3_config_match_init(ss);
+ if (j <= 0) { /* no ciphers are working/supported by PK11 */
+ errCode = PORT_GetError(); /* error code is already set. */
+ goto alert_loser;
+ }
+#endif
+
+ /* If we already have a session for this client, be sure to pick the
+ ** same cipher suite and compression method we picked before.
+ ** This is not a loop, despite appearances.
+ */
+ if (sid) do {
+ ssl3CipherSuiteCfg *suite;
+
+ /* Check that the cached compression method is still enabled. */
+ if (!compressionEnabled(ss, sid->u.ssl3.compression))
+ break;
+
+ /* Check that the cached compression method is in the client's list */
+ for (i = 0; i < comps.len; i++) {
+ if (comps.data[i] == sid->u.ssl3.compression)
+ break;
+ }
+ if (i == comps.len)
+ break;
+
+ suite = ss->cipherSuites;
+ /* Find the entry for the cipher suite used in the cached session. */
+ for (j = ssl_V3_SUITES_IMPLEMENTED; j > 0; --j, ++suite) {
+ if (suite->cipher_suite == sid->u.ssl3.cipherSuite)
+ break;
+ }
+ PORT_Assert(j > 0);
+ if (j <= 0)
+ break;
+#ifdef PARANOID
+ /* Double check that the cached cipher suite is still enabled,
+ * implemented, and allowed by policy. Might have been disabled.
+ * The product policy won't change during the process lifetime.
+ * Implemented ("isPresent") shouldn't change for servers.
+ */
+ if (!config_match(suite, ss->ssl3.policy, PR_TRUE))
+ break;
+#else
+ if (!suite->enabled)
+ break;
+#endif
+ /* Double check that the cached cipher suite is in the client's list */
+ for (i = 0; i + 1 < suites.len; i += 2) {
+ PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1];
+ if (suite_i == suite->cipher_suite) {
+ ss->ssl3.hs.cipher_suite = suite->cipher_suite;
+ ss->ssl3.hs.suite_def =
+ ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite);
+
+ /* Use the cached compression method. */
+ ss->ssl3.hs.compression = sid->u.ssl3.compression;
+ goto compression_found;
+ }
+ }
+ } while (0);
+
+ /* START A NEW SESSION */
+
+#ifndef PARANOID
+ /* Look for a matching cipher suite. */
+ j = ssl3_config_match_init(ss);
+ if (j <= 0) { /* no ciphers are working/supported by PK11 */
+ errCode = PORT_GetError(); /* error code is already set. */
+ goto alert_loser;
+ }
+#endif
+
+ /* Select a cipher suite.
+ **
+ ** NOTE: This suite selection algorithm should be the same as the one in
+ ** ssl3_HandleV2ClientHello().
+ **
+ ** If TLS 1.0 is enabled, we could handle the case where the client
+ ** offered TLS 1.1 but offered only export cipher suites by choosing TLS
+ ** 1.0 and selecting one of those export cipher suites. However, a secure
+ ** TLS 1.1 client should not have export cipher suites enabled at all,
+ ** and a TLS 1.1 client should definitely not be offering *only* export
+ ** cipher suites. Therefore, we refuse to negotiate export cipher suites
+ ** with any client that indicates support for TLS 1.1 or higher when we
+ ** (the server) have TLS 1.1 support enabled.
+ */
+ for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) {
+ ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];
+ if (!config_match(suite, ss->ssl3.policy, PR_TRUE) ||
+ !ssl3_CipherSuiteAllowedForVersion(suite->cipher_suite,
+ ss->version)) {
+ continue;
+ }
+ for (i = 0; i + 1 < suites.len; i += 2) {
+ PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1];
+ if (suite_i == suite->cipher_suite) {
+ ss->ssl3.hs.cipher_suite = suite->cipher_suite;
+ ss->ssl3.hs.suite_def =
+ ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite);
+ goto suite_found;
+ }
+ }
+ }
+ errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
+ goto alert_loser;
+
+suite_found:
+ /* Look for a matching compression algorithm. */
+ for (i = 0; i < comps.len; i++) {
+ if (!compressionEnabled(ss, comps.data[i]))
+ continue;
+ for (j = 0; j < compressionMethodsCount; j++) {
+ if (comps.data[i] == compressions[j]) {
+ ss->ssl3.hs.compression =
+ (SSLCompressionMethod)compressions[j];
+ goto compression_found;
+ }
+ }
+ }
+ errCode = SSL_ERROR_NO_COMPRESSION_OVERLAP;
+ /* null compression must be supported */
+ goto alert_loser;
+
+compression_found:
+ suites.data = NULL;
+ comps.data = NULL;
+
+ ss->sec.send = ssl3_SendApplicationData;
+
+ /* If there are any failures while processing the old sid,
+ * we don't consider them to be errors. Instead, We just behave
+ * as if the client had sent us no sid to begin with, and make a new one.
+ */
+ if (sid != NULL) do {
+ ssl3CipherSpec *pwSpec;
+ SECItem wrappedMS; /* wrapped key */
+
+ if (sid->version != ss->version ||
+ sid->u.ssl3.cipherSuite != ss->ssl3.hs.cipher_suite ||
+ sid->u.ssl3.compression != ss->ssl3.hs.compression) {
+ break; /* not an error */
+ }
+
+ if (ss->sec.ci.sid) {
+ if (ss->sec.uncache)
+ ss->sec.uncache(ss->sec.ci.sid);
+ PORT_Assert(ss->sec.ci.sid != sid); /* should be impossible, but ... */
+ if (ss->sec.ci.sid != sid) {
+ ssl_FreeSID(ss->sec.ci.sid);
+ }
+ ss->sec.ci.sid = NULL;
+ }
+ /* we need to resurrect the master secret.... */
+
+ ssl_GetSpecWriteLock(ss); haveSpecWriteLock = PR_TRUE;
+ pwSpec = ss->ssl3.pwSpec;
+ if (sid->u.ssl3.keys.msIsWrapped) {
+ PK11SymKey * wrapKey; /* wrapping key */
+ CK_FLAGS keyFlags = 0;
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11) {
+ /* we cannot restart a non-bypass session in a
+ ** bypass socket.
+ */
+ break;
+ }
+#endif
+
+ wrapKey = getWrappingKey(ss, NULL, sid->u.ssl3.exchKeyType,
+ sid->u.ssl3.masterWrapMech,
+ ss->pkcs11PinArg);
+ if (!wrapKey) {
+ /* we have a SID cache entry, but no wrapping key for it??? */
+ break;
+ }
+
+ if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */
+ keyFlags = CKF_SIGN | CKF_VERIFY;
+ }
+
+ wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
+ wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
+
+ /* unwrap the master secret. */
+ pwSpec->master_secret =
+ PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech,
+ NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE,
+ CKA_DERIVE, sizeof(SSL3MasterSecret), keyFlags);
+ PK11_FreeSymKey(wrapKey);
+ if (pwSpec->master_secret == NULL) {
+ break; /* not an error */
+ }
+#ifndef NO_PKCS11_BYPASS
+ } else if (ss->opt.bypassPKCS11) {
+ wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
+ wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
+ memcpy(pwSpec->raw_master_secret, wrappedMS.data, wrappedMS.len);
+ pwSpec->msItem.data = pwSpec->raw_master_secret;
+ pwSpec->msItem.len = wrappedMS.len;
+#endif
+ } else {
+ /* We CAN restart a bypass session in a non-bypass socket. */
+ /* need to import the raw master secret to session object */
+ PK11SlotInfo * slot;
+ wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
+ wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
+ slot = PK11_GetInternalSlot();
+ pwSpec->master_secret =
+ PK11_ImportSymKey(slot, CKM_SSL3_MASTER_KEY_DERIVE,
+ PK11_OriginUnwrap, CKA_ENCRYPT, &wrappedMS,
+ NULL);
+ PK11_FreeSlot(slot);
+ if (pwSpec->master_secret == NULL) {
+ break; /* not an error */
+ }
+ }
+ ss->sec.ci.sid = sid;
+ if (sid->peerCert != NULL) {
+ ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
+ ssl3_CopyPeerCertsFromSID(ss, sid);
+ }
+
+ /*
+ * Old SID passed all tests, so resume this old session.
+ *
+ * XXX make sure compression still matches
+ */
+ SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_hits );
+ if (ss->statelessResume)
+ SSL_AtomicIncrementLong(& ssl3stats.hch_sid_stateless_resumes );
+ ss->ssl3.hs.isResuming = PR_TRUE;
+
+ ss->sec.authAlgorithm = sid->authAlgorithm;
+ ss->sec.authKeyBits = sid->authKeyBits;
+ ss->sec.keaType = sid->keaType;
+ ss->sec.keaKeyBits = sid->keaKeyBits;
+
+ /* server sids don't remember the server cert we previously sent,
+ ** but they do remember the kea type we originally used, so we
+ ** can locate it again, provided that the current ssl socket
+ ** has had its server certs configured the same as the previous one.
+ */
+ ss->sec.localCert =
+ CERT_DupCertificate(ss->serverCerts[sid->keaType].serverCert);
+
+ /* Copy cached name in to pending spec */
+ if (sid != NULL &&
+ sid->version > SSL_LIBRARY_VERSION_3_0 &&
+ sid->u.ssl3.srvName.len && sid->u.ssl3.srvName.data) {
+ /* Set server name from sid */
+ SECItem *sidName = &sid->u.ssl3.srvName;
+ SECItem *pwsName = &ss->ssl3.pwSpec->srvVirtName;
+ if (pwsName->data) {
+ SECITEM_FreeItem(pwsName, PR_FALSE);
+ }
+ rv = SECITEM_CopyItem(NULL, pwsName, sidName);
+ if (rv != SECSuccess) {
+ errCode = PORT_GetError();
+ desc = internal_error;
+ goto alert_loser;
+ }
+ }
+
+ /* Clean up sni name array */
+ if (ssl3_ExtensionNegotiated(ss, ssl_server_name_xtn) &&
+ ss->xtnData.sniNameArr) {
+ PORT_Free(ss->xtnData.sniNameArr);
+ ss->xtnData.sniNameArr = NULL;
+ ss->xtnData.sniNameArrSize = 0;
+ }
+
+ ssl_GetXmitBufLock(ss); haveXmitBufLock = PR_TRUE;
+
+ rv = ssl3_SendServerHello(ss);
+ if (rv != SECSuccess) {
+ errCode = PORT_GetError();
+ goto loser;
+ }
+
+ if (haveSpecWriteLock) {
+ ssl_ReleaseSpecWriteLock(ss);
+ haveSpecWriteLock = PR_FALSE;
+ }
+
+ /* NULL value for PMS signifies re-use of the old MS */
+ rv = ssl3_InitPendingCipherSpec(ss, NULL);
+ if (rv != SECSuccess) {
+ errCode = PORT_GetError();
+ goto loser;
+ }
+
+ rv = ssl3_SendChangeCipherSpecs(ss);
+ if (rv != SECSuccess) {
+ errCode = PORT_GetError();
+ goto loser;
+ }
+ rv = ssl3_SendFinished(ss, 0);
+ ss->ssl3.hs.ws = wait_change_cipher;
+ if (rv != SECSuccess) {
+ errCode = PORT_GetError();
+ goto loser;
+ }
+
+ if (haveXmitBufLock) {
+ ssl_ReleaseXmitBufLock(ss);
+ haveXmitBufLock = PR_FALSE;
+ }
+
+ return SECSuccess;
+ } while (0);
+
+ if (haveSpecWriteLock) {
+ ssl_ReleaseSpecWriteLock(ss);
+ haveSpecWriteLock = PR_FALSE;
+ }
+
+ if (sid) { /* we had a sid, but it's no longer valid, free it */
+ SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_not_ok );
+ if (ss->sec.uncache)
+ ss->sec.uncache(sid);
+ ssl_FreeSID(sid);
+ sid = NULL;
+ }
+ SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_misses );
+
+ if (ssl3_ExtensionNegotiated(ss, ssl_server_name_xtn)) {
+ int ret = 0;
+ if (ss->sniSocketConfig) do { /* not a loop */
+ ret = SSL_SNI_SEND_ALERT;
+ /* If extension is negotiated, the len of names should > 0. */
+ if (ss->xtnData.sniNameArrSize) {
+ /* Calling client callback to reconfigure the socket. */
+ ret = (SECStatus)(*ss->sniSocketConfig)(ss->fd,
+ ss->xtnData.sniNameArr,
+ ss->xtnData.sniNameArrSize,
+ ss->sniSocketConfigArg);
+ }
+ if (ret <= SSL_SNI_SEND_ALERT) {
+ /* Application does not know the name or was not able to
+ * properly reconfigure the socket. */
+ errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
+ desc = unrecognized_name;
+ break;
+ } else if (ret == SSL_SNI_CURRENT_CONFIG_IS_USED) {
+ SECStatus rv = SECSuccess;
+ SECItem * cwsName, *pwsName;
+
+ ssl_GetSpecWriteLock(ss); /*******************************/
+ pwsName = &ss->ssl3.pwSpec->srvVirtName;
+ cwsName = &ss->ssl3.cwSpec->srvVirtName;
+#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS
+ /* not allow name change on the 2d HS */
+ if (ss->firstHsDone) {
+ if (ssl3_ServerNameCompare(pwsName, cwsName)) {
+ ssl_ReleaseSpecWriteLock(ss); /******************/
+ errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
+ desc = handshake_failure;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ }
+#endif
+ if (pwsName->data) {
+ SECITEM_FreeItem(pwsName, PR_FALSE);
+ }
+ if (cwsName->data) {
+ rv = SECITEM_CopyItem(NULL, pwsName, cwsName);
+ }
+ ssl_ReleaseSpecWriteLock(ss); /**************************/
+ if (rv != SECSuccess) {
+ errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
+ desc = internal_error;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ } else if (ret < ss->xtnData.sniNameArrSize) {
+ /* Application has configured new socket info. Lets check it
+ * and save the name. */
+ SECStatus rv;
+ SECItem * name = &ss->xtnData.sniNameArr[ret];
+ int configedCiphers;
+ SECItem * pwsName;
+
+ /* get rid of the old name and save the newly picked. */
+ /* This code is protected by ssl3HandshakeLock. */
+ ssl_GetSpecWriteLock(ss); /*******************************/
+#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS
+ /* not allow name change on the 2d HS */
+ if (ss->firstHsDone) {
+ SECItem *cwsName = &ss->ssl3.cwSpec->srvVirtName;
+ if (ssl3_ServerNameCompare(name, cwsName)) {
+ ssl_ReleaseSpecWriteLock(ss); /******************/
+ errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
+ desc = handshake_failure;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ }
+#endif
+ pwsName = &ss->ssl3.pwSpec->srvVirtName;
+ if (pwsName->data) {
+ SECITEM_FreeItem(pwsName, PR_FALSE);
+ }
+ rv = SECITEM_CopyItem(NULL, pwsName, name);
+ ssl_ReleaseSpecWriteLock(ss); /***************************/
+ if (rv != SECSuccess) {
+ errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
+ desc = internal_error;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ configedCiphers = ssl3_config_match_init(ss);
+ if (configedCiphers <= 0) {
+ /* no ciphers are working/supported */
+ errCode = PORT_GetError();
+ desc = handshake_failure;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ /* Need to tell the client that application has picked
+ * the name from the offered list and reconfigured the socket.
+ */
+ ssl3_RegisterServerHelloExtensionSender(ss, ssl_server_name_xtn,
+ ssl3_SendServerNameXtn);
+ } else {
+ /* Callback returned index outside of the boundary. */
+ PORT_Assert(ret < ss->xtnData.sniNameArrSize);
+ errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
+ desc = internal_error;
+ ret = SSL_SNI_SEND_ALERT;
+ break;
+ }
+ } while (0);
+ /* Free sniNameArr. The data that each SECItem in the array
+ * points into is the data from the input buffer "b". It will
+ * not be available outside the scope of this or it's child
+ * functions.*/
+ if (ss->xtnData.sniNameArr) {
+ PORT_Free(ss->xtnData.sniNameArr);
+ ss->xtnData.sniNameArr = NULL;
+ ss->xtnData.sniNameArrSize = 0;
+ }
+ if (ret <= SSL_SNI_SEND_ALERT) {
+ /* desc and errCode should be set. */
+ goto alert_loser;
+ }
+ }
+#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS
+ else if (ss->firstHsDone) {
+ /* Check that we don't have the name is current spec
+ * if this extension was not negotiated on the 2d hs. */
+ PRBool passed = PR_TRUE;
+ ssl_GetSpecReadLock(ss); /*******************************/
+ if (ss->ssl3.cwSpec->srvVirtName.data) {
+ passed = PR_FALSE;
+ }
+ ssl_ReleaseSpecReadLock(ss); /***************************/
+ if (!passed) {
+ errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
+ desc = handshake_failure;
+ goto alert_loser;
+ }
+ }
+#endif
+
+ sid = ssl3_NewSessionID(ss, PR_TRUE);
+ if (sid == NULL) {
+ errCode = PORT_GetError();
+ goto loser; /* memory error is set. */
+ }
+ ss->sec.ci.sid = sid;
+
+ ss->ssl3.hs.isResuming = PR_FALSE;
+ ssl_GetXmitBufLock(ss);
+ rv = ssl3_SendServerHelloSequence(ss);
+ ssl_ReleaseXmitBufLock(ss);
+ if (rv != SECSuccess) {
+ errCode = PORT_GetError();
+ goto loser;
+ }
+
+ if (haveXmitBufLock) {
+ ssl_ReleaseXmitBufLock(ss);
+ haveXmitBufLock = PR_FALSE;
+ }
+
+ return SECSuccess;
+
+alert_loser:
+ if (haveSpecWriteLock) {
+ ssl_ReleaseSpecWriteLock(ss);
+ haveSpecWriteLock = PR_FALSE;
+ }
+ (void)SSL3_SendAlert(ss, level, desc);
+ /* FALLTHRU */
+loser:
+ if (haveSpecWriteLock) {
+ ssl_ReleaseSpecWriteLock(ss);
+ haveSpecWriteLock = PR_FALSE;
+ }
+
+ if (haveXmitBufLock) {
+ ssl_ReleaseXmitBufLock(ss);
+ haveXmitBufLock = PR_FALSE;
+ }
+
+ PORT_SetError(errCode);
+ return SECFailure;
+}
+
+/*
+ * ssl3_HandleV2ClientHello is used when a V2 formatted hello comes
+ * in asking to use the V3 handshake.
+ * Called from ssl2_HandleClientHelloMessage() in sslcon.c
+ */
+SECStatus
+ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length)
+{
+ sslSessionID * sid = NULL;
+ unsigned char * suites;
+ unsigned char * random;
+ SSL3ProtocolVersion version;
+ SECStatus rv;
+ int i;
+ int j;
+ int sid_length;
+ int suite_length;
+ int rand_length;
+ int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO;
+ SSL3AlertDescription desc = handshake_failure;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: handle v2 client_hello", SSL_GETPID(), ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+
+ ssl_GetSSL3HandshakeLock(ss);
+
+ PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData));
+
+ rv = ssl3_InitState(ss);
+ if (rv != SECSuccess) {
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ return rv; /* ssl3_InitState has set the error code. */
+ }
+ rv = ssl3_RestartHandshakeHashes(ss);
+ if (rv != SECSuccess) {
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ return rv;
+ }
+
+ if (ss->ssl3.hs.ws != wait_client_hello) {
+ desc = unexpected_message;
+ errCode = SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO;
+ goto loser; /* alert_loser */
+ }
+
+ version = (buffer[1] << 8) | buffer[2];
+ suite_length = (buffer[3] << 8) | buffer[4];
+ sid_length = (buffer[5] << 8) | buffer[6];
+ rand_length = (buffer[7] << 8) | buffer[8];
+ ss->clientHelloVersion = version;
+
+ rv = ssl3_NegotiateVersion(ss, version, PR_TRUE);
+ if (rv != SECSuccess) {
+ /* send back which ever alert client will understand. */
+ desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version : handshake_failure;
+ errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
+ goto alert_loser;
+ }
+
+ rv = ssl3_InitHandshakeHashes(ss);
+ if (rv != SECSuccess) {
+ desc = internal_error;
+ errCode = PORT_GetError();
+ goto alert_loser;
+ }
+
+ /* if we get a non-zero SID, just ignore it. */
+ if (length !=
+ SSL_HL_CLIENT_HELLO_HBYTES + suite_length + sid_length + rand_length) {
+ SSL_DBG(("%d: SSL3[%d]: bad v2 client hello message, len=%d should=%d",
+ SSL_GETPID(), ss->fd, length,
+ SSL_HL_CLIENT_HELLO_HBYTES + suite_length + sid_length +
+ rand_length));
+ goto loser; /* malformed */ /* alert_loser */
+ }
+
+ suites = buffer + SSL_HL_CLIENT_HELLO_HBYTES;
+ random = suites + suite_length + sid_length;
+
+ if (rand_length < SSL_MIN_CHALLENGE_BYTES ||
+ rand_length > SSL_MAX_CHALLENGE_BYTES) {
+ goto loser; /* malformed */ /* alert_loser */
+ }
+
+ PORT_Assert(SSL_MAX_CHALLENGE_BYTES == SSL3_RANDOM_LENGTH);
+
+ PORT_Memset(&ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH);
+ PORT_Memcpy(
+ &ss->ssl3.hs.client_random.rand[SSL3_RANDOM_LENGTH - rand_length],
+ random, rand_length);
+
+ PRINT_BUF(60, (ss, "client random:", &ss->ssl3.hs.client_random.rand[0],
+ SSL3_RANDOM_LENGTH));
+#ifdef NSS_ENABLE_ECC
+ /* Disable any ECC cipher suites for which we have no cert. */
+ ssl3_FilterECCipherSuitesByServerCerts(ss);
+#endif
+ i = ssl3_config_match_init(ss);
+ if (i <= 0) {
+ errCode = PORT_GetError(); /* error code is already set. */
+ goto alert_loser;
+ }
+
+ /* Select a cipher suite.
+ **
+ ** NOTE: This suite selection algorithm should be the same as the one in
+ ** ssl3_HandleClientHello().
+ **
+ ** See the comments about export cipher suites in ssl3_HandleClientHello().
+ */
+ for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) {
+ ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];
+ if (!config_match(suite, ss->ssl3.policy, PR_TRUE) ||
+ !ssl3_CipherSuiteAllowedForVersion(suite->cipher_suite,
+ ss->version)) {
+ continue;
+ }
+ for (i = 0; i+2 < suite_length; i += 3) {
+ PRUint32 suite_i = (suites[i] << 16)|(suites[i+1] << 8)|suites[i+2];
+ if (suite_i == suite->cipher_suite) {
+ ss->ssl3.hs.cipher_suite = suite->cipher_suite;
+ ss->ssl3.hs.suite_def =
+ ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite);
+ goto suite_found;
+ }
+ }
+ }
+ errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
+ goto alert_loser;
+
+suite_found:
+
+ /* Look for the SCSV, and if found, treat it just like an empty RI
+ * extension by processing a local copy of an empty RI extension.
+ */
+ for (i = 0; i+2 < suite_length; i += 3) {
+ PRUint32 suite_i = (suites[i] << 16) | (suites[i+1] << 8) | suites[i+2];
+ if (suite_i == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) {
+ SSL3Opaque * b2 = (SSL3Opaque *)emptyRIext;
+ PRUint32 L2 = sizeof emptyRIext;
+ (void)ssl3_HandleHelloExtensions(ss, &b2, &L2);
+ break;
+ }
+ }
+
+ if (ss->opt.requireSafeNegotiation &&
+ !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) {
+ desc = handshake_failure;
+ errCode = SSL_ERROR_UNSAFE_NEGOTIATION;
+ goto alert_loser;
+ }
+
+ ss->ssl3.hs.compression = ssl_compression_null;
+ ss->sec.send = ssl3_SendApplicationData;
+
+ /* we don't even search for a cache hit here. It's just a miss. */
+ SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_misses );
+ sid = ssl3_NewSessionID(ss, PR_TRUE);
+ if (sid == NULL) {
+ errCode = PORT_GetError();
+ goto loser; /* memory error is set. */
+ }
+ ss->sec.ci.sid = sid;
+ /* do not worry about memory leak of sid since it now belongs to ci */
+
+ /* We have to update the handshake hashes before we can send stuff */
+ rv = ssl3_UpdateHandshakeHashes(ss, buffer, length);
+ if (rv != SECSuccess) {
+ errCode = PORT_GetError();
+ goto loser;
+ }
+
+ ssl_GetXmitBufLock(ss);
+ rv = ssl3_SendServerHelloSequence(ss);
+ ssl_ReleaseXmitBufLock(ss);
+ if (rv != SECSuccess) {
+ errCode = PORT_GetError();
+ goto loser;
+ }
+
+ /* XXX_1 The call stack to here is:
+ * ssl_Do1stHandshake -> ssl2_HandleClientHelloMessage -> here.
+ * ssl2_HandleClientHelloMessage returns whatever we return here.
+ * ssl_Do1stHandshake will continue looping if it gets back either
+ * SECSuccess or SECWouldBlock.
+ * SECSuccess is preferable here. See XXX_1 in sslgathr.c.
+ */
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ return SECSuccess;
+
+alert_loser:
+ SSL3_SendAlert(ss, alert_fatal, desc);
+loser:
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ PORT_SetError(errCode);
+ return SECFailure;
+}
+
+/* The negotiated version number has been already placed in ss->version.
+**
+** Called from: ssl3_HandleClientHello (resuming session),
+** ssl3_SendServerHelloSequence <- ssl3_HandleClientHello (new session),
+** ssl3_SendServerHelloSequence <- ssl3_HandleV2ClientHello (new session)
+*/
+static SECStatus
+ssl3_SendServerHello(sslSocket *ss)
+{
+ sslSessionID *sid;
+ SECStatus rv;
+ PRUint32 maxBytes = 65535;
+ PRUint32 length;
+ PRInt32 extensions_len = 0;
+ SSL3ProtocolVersion version;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: send server_hello handshake", SSL_GETPID(),
+ ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ if (!IS_DTLS(ss)) {
+ PORT_Assert(MSB(ss->version) == MSB(SSL_LIBRARY_VERSION_3_0));
+
+ if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_3_0)) {
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+ return SECFailure;
+ }
+ } else {
+ PORT_Assert(MSB(ss->version) == MSB(SSL_LIBRARY_VERSION_DTLS_1_0));
+
+ if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_DTLS_1_0)) {
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+ return SECFailure;
+ }
+ }
+
+ sid = ss->sec.ci.sid;
+
+ extensions_len = ssl3_CallHelloExtensionSenders(ss, PR_FALSE, maxBytes,
+ &ss->xtnData.serverSenders[0]);
+ if (extensions_len > 0)
+ extensions_len += 2; /* Add sizeof total extension length */
+
+ length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH + 1 +
+ ((sid == NULL) ? 0: sid->u.ssl3.sessionIDLength) +
+ sizeof(ssl3CipherSuite) + 1 + extensions_len;
+ rv = ssl3_AppendHandshakeHeader(ss, server_hello, length);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+
+ if (IS_DTLS(ss)) {
+ version = dtls_TLSVersionToDTLSVersion(ss->version);
+ } else {
+ version = ss->version;
+ }
+
+ rv = ssl3_AppendHandshakeNumber(ss, version, 2);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+ rv = ssl3_GetNewRandom(&ss->ssl3.hs.server_random);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE);
+ return rv;
+ }
+ rv = ssl3_AppendHandshake(
+ ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+
+ if (sid)
+ rv = ssl3_AppendHandshakeVariable(
+ ss, sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength, 1);
+ else
+ rv = ssl3_AppendHandshakeVariable(ss, NULL, 0, 1);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+
+ rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.cipher_suite, 2);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+ rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.compression, 1);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+ if (extensions_len) {
+ PRInt32 sent_len;
+
+ extensions_len -= 2;
+ rv = ssl3_AppendHandshakeNumber(ss, extensions_len, 2);
+ if (rv != SECSuccess)
+ return rv; /* err set by ssl3_SetupPendingCipherSpec */
+ sent_len = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, extensions_len,
+ &ss->xtnData.serverSenders[0]);
+ PORT_Assert(sent_len == extensions_len);
+ if (sent_len != extensions_len) {
+ if (sent_len >= 0)
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ }
+ rv = ssl3_SetupPendingCipherSpec(ss);
+ if (rv != SECSuccess) {
+ return rv; /* err set by ssl3_SetupPendingCipherSpec */
+ }
+
+ return SECSuccess;
+}
+
+/* ssl3_PickSignatureHashAlgorithm selects a hash algorithm to use when signing
+ * elements of the handshake. (The negotiated cipher suite determines the
+ * signature algorithm.) Prior to TLS 1.2, the MD5/SHA1 combination is always
+ * used. With TLS 1.2, a client may advertise its support for signature and
+ * hash combinations. */
+static SECStatus
+ssl3_PickSignatureHashAlgorithm(sslSocket *ss,
+ SSL3SignatureAndHashAlgorithm* out)
+{
+ TLSSignatureAlgorithm sigAlg;
+ unsigned int i, j;
+ /* hashPreference expresses our preferences for hash algorithms, most
+ * preferable first. */
+ static const PRUint8 hashPreference[] = {
+ tls_hash_sha256,
+ tls_hash_sha384,
+ tls_hash_sha512,
+ tls_hash_sha1,
+ };
+
+ switch (ss->ssl3.hs.kea_def->kea) {
+ case kea_rsa:
+ case kea_rsa_export:
+ case kea_rsa_export_1024:
+ case kea_dh_rsa:
+ case kea_dh_rsa_export:
+ case kea_dhe_rsa:
+ case kea_dhe_rsa_export:
+ case kea_rsa_fips:
+ case kea_ecdh_rsa:
+ case kea_ecdhe_rsa:
+ sigAlg = tls_sig_rsa;
+ break;
+ case kea_dh_dss:
+ case kea_dh_dss_export:
+ case kea_dhe_dss:
+ case kea_dhe_dss_export:
+ sigAlg = tls_sig_dsa;
+ break;
+ case kea_ecdh_ecdsa:
+ case kea_ecdhe_ecdsa:
+ sigAlg = tls_sig_ecdsa;
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+ return SECFailure;
+ }
+ out->sigAlg = sigAlg;
+
+ if (ss->version <= SSL_LIBRARY_VERSION_TLS_1_1) {
+ /* SEC_OID_UNKNOWN means the MD5/SHA1 combo hash used in TLS 1.1 and
+ * prior. */
+ out->hashAlg = SEC_OID_UNKNOWN;
+ return SECSuccess;
+ }
+
+ if (ss->ssl3.hs.numClientSigAndHash == 0) {
+ /* If the client didn't provide any signature_algorithms extension then
+ * we can assume that they support SHA-1:
+ * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
+ out->hashAlg = SEC_OID_SHA1;
+ return SECSuccess;
+ }
+
+ for (i = 0; i < PR_ARRAY_SIZE(hashPreference); i++) {
+ for (j = 0; j < ss->ssl3.hs.numClientSigAndHash; j++) {
+ const SSL3SignatureAndHashAlgorithm* sh =
+ &ss->ssl3.hs.clientSigAndHash[j];
+ if (sh->sigAlg == sigAlg && sh->hashAlg == hashPreference[i]) {
+ out->hashAlg = sh->hashAlg;
+ return SECSuccess;
+ }
+ }
+ }
+
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
+ return SECFailure;
+}
+
+
+static SECStatus
+ssl3_SendServerKeyExchange(sslSocket *ss)
+{
+ const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def;
+ SECStatus rv = SECFailure;
+ int length;
+ PRBool isTLS;
+ SECItem signed_hash = {siBuffer, NULL, 0};
+ SSL3Hashes hashes;
+ SECKEYPublicKey * sdPub; /* public key for step-down */
+ SSL3SignatureAndHashAlgorithm sigAndHash;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: send server_key_exchange handshake",
+ SSL_GETPID(), ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ if (ssl3_PickSignatureHashAlgorithm(ss, &sigAndHash) != SECSuccess) {
+ return SECFailure;
+ }
+
+ switch (kea_def->exchKeyType) {
+ case kt_rsa:
+ /* Perform SSL Step-Down here. */
+ sdPub = ss->stepDownKeyPair->pubKey;
+ PORT_Assert(sdPub != NULL);
+ if (!sdPub) {
+ PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+ return SECFailure;
+ }
+ rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg,
+ sdPub->u.rsa.modulus,
+ sdPub->u.rsa.publicExponent,
+ &ss->ssl3.hs.client_random,
+ &ss->ssl3.hs.server_random,
+ &hashes, ss->opt.bypassPKCS11);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+ return rv;
+ }
+
+ isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
+ rv = ssl3_SignHashes(&hashes, ss->serverCerts[kt_rsa].SERVERKEY,
+ &signed_hash, isTLS);
+ if (rv != SECSuccess) {
+ goto loser; /* ssl3_SignHashes has set err. */
+ }
+ if (signed_hash.data == NULL) {
+ /* how can this happen and rv == SECSuccess ?? */
+ PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+ length = 2 + sdPub->u.rsa.modulus.len +
+ 2 + sdPub->u.rsa.publicExponent.len +
+ 2 + signed_hash.len;
+
+ rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length);
+ if (rv != SECSuccess) {
+ goto loser; /* err set by AppendHandshake. */
+ }
+
+ rv = ssl3_AppendHandshakeVariable(ss, sdPub->u.rsa.modulus.data,
+ sdPub->u.rsa.modulus.len, 2);
+ if (rv != SECSuccess) {
+ goto loser; /* err set by AppendHandshake. */
+ }
+
+ rv = ssl3_AppendHandshakeVariable(
+ ss, sdPub->u.rsa.publicExponent.data,
+ sdPub->u.rsa.publicExponent.len, 2);
+ if (rv != SECSuccess) {
+ goto loser; /* err set by AppendHandshake. */
+ }
+
+ if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+ rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash);
+ if (rv != SECSuccess) {
+ goto loser; /* err set by AppendHandshake. */
+ }
+ }
+
+ rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data,
+ signed_hash.len, 2);
+ if (rv != SECSuccess) {
+ goto loser; /* err set by AppendHandshake. */
+ }
+ PORT_Free(signed_hash.data);
+ return SECSuccess;
+
+#ifdef NSS_ENABLE_ECC
+ case kt_ecdh: {
+ rv = ssl3_SendECDHServerKeyExchange(ss, &sigAndHash);
+ return rv;
+ }
+#endif /* NSS_ENABLE_ECC */
+
+ case kt_dh:
+ case kt_null:
+ default:
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+ break;
+ }
+loser:
+ if (signed_hash.data != NULL)
+ PORT_Free(signed_hash.data);
+ return SECFailure;
+}
+
+
+static SECStatus
+ssl3_SendCertificateRequest(sslSocket *ss)
+{
+ PRBool isTLS12;
+ SECItem * name;
+ CERTDistNames *ca_list;
+ const PRUint8 *certTypes;
+ const PRUint8 *sigAlgs;
+ SECItem * names = NULL;
+ SECStatus rv;
+ int length;
+ int i;
+ int calen = 0;
+ int nnames = 0;
+ int certTypesLength;
+ int sigAlgsLength;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: send certificate_request handshake",
+ SSL_GETPID(), ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
+
+ /* ssl3.ca_list is initialized to NULL, and never changed. */
+ ca_list = ss->ssl3.ca_list;
+ if (!ca_list) {
+ ca_list = ssl3_server_ca_list;
+ }
+
+ if (ca_list != NULL) {
+ names = ca_list->names;
+ nnames = ca_list->nnames;
+ }
+
+ for (i = 0, name = names; i < nnames; i++, name++) {
+ calen += 2 + name->len;
+ }
+
+ certTypes = certificate_types;
+ certTypesLength = sizeof certificate_types;
+ sigAlgs = supported_signature_algorithms;
+ sigAlgsLength = sizeof supported_signature_algorithms;
+
+ length = 1 + certTypesLength + 2 + calen;
+ if (isTLS12) {
+ length += 2 + sigAlgsLength;
+ }
+
+ rv = ssl3_AppendHandshakeHeader(ss, certificate_request, length);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+ rv = ssl3_AppendHandshakeVariable(ss, certTypes, certTypesLength, 1);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+ if (isTLS12) {
+ rv = ssl3_AppendHandshakeVariable(ss, sigAlgs, sigAlgsLength, 2);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+ }
+ rv = ssl3_AppendHandshakeNumber(ss, calen, 2);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+ for (i = 0, name = names; i < nnames; i++, name++) {
+ rv = ssl3_AppendHandshakeVariable(ss, name->data, name->len, 2);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+ }
+
+ return SECSuccess;
+}
+
+static SECStatus
+ssl3_SendServerHelloDone(sslSocket *ss)
+{
+ SECStatus rv;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: send server_hello_done handshake",
+ SSL_GETPID(), ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ rv = ssl3_AppendHandshakeHeader(ss, server_hello_done, 0);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+ rv = ssl3_FlushHandshake(ss, 0);
+ if (rv != SECSuccess) {
+ return rv; /* error code set by ssl3_FlushHandshake */
+ }
+ return SECSuccess;
+}
+
+/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
+ * ssl3 Certificate Verify message
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+static SECStatus
+ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
+ SSL3Hashes *hashes)
+{
+ SECItem signed_hash = {siBuffer, NULL, 0};
+ SECStatus rv;
+ int errCode = SSL_ERROR_RX_MALFORMED_CERT_VERIFY;
+ SSL3AlertDescription desc = handshake_failure;
+ PRBool isTLS, isTLS12;
+ SSL3SignatureAndHashAlgorithm sigAndHash;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_verify handshake",
+ SSL_GETPID(), ss->fd));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
+ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
+
+ if (ss->ssl3.hs.ws != wait_cert_verify || ss->sec.peerCert == NULL) {
+ desc = unexpected_message;
+ errCode = SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY;
+ goto alert_loser;
+ }
+
+ if (isTLS12) {
+ rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
+ &sigAndHash);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed or unsupported. */
+ }
+ rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
+ &sigAndHash, ss->sec.peerCert);
+ if (rv != SECSuccess) {
+ errCode = PORT_GetError();
+ desc = decrypt_error;
+ goto alert_loser;
+ }
+
+ /* We only support CertificateVerify messages that use the handshake
+ * hash. */
+ if (sigAndHash.hashAlg != hashes->hashAlg) {
+ errCode = SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM;
+ desc = decrypt_error;
+ goto alert_loser;
+ }
+ }
+
+ rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed. */
+ }
+
+ /* XXX verify that the key & kea match */
+ rv = ssl3_VerifySignedHashes(hashes, ss->sec.peerCert, &signed_hash,
+ isTLS, ss->pkcs11PinArg);
+ if (rv != SECSuccess) {
+ errCode = PORT_GetError();
+ desc = isTLS ? decrypt_error : handshake_failure;
+ goto alert_loser;
+ }
+
+ signed_hash.data = NULL;
+
+ if (length != 0) {
+ desc = isTLS ? decode_error : illegal_parameter;
+ goto alert_loser; /* malformed */
+ }
+ ss->ssl3.hs.ws = wait_change_cipher;
+ return SECSuccess;
+
+alert_loser:
+ SSL3_SendAlert(ss, alert_fatal, desc);
+loser:
+ PORT_SetError(errCode);
+ return SECFailure;
+}
+
+
+/* find a slot that is able to generate a PMS and wrap it with RSA.
+ * Then generate and return the PMS.
+ * If the serverKeySlot parameter is non-null, this function will use
+ * that slot to do the job, otherwise it will find a slot.
+ *
+ * Called from ssl3_DeriveConnectionKeysPKCS11() (above)
+ * sendRSAClientKeyExchange() (above)
+ * ssl3_HandleRSAClientKeyExchange() (below)
+ * Caller must hold the SpecWriteLock, the SSL3HandshakeLock
+ */
+static PK11SymKey *
+ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec,
+ PK11SlotInfo * serverKeySlot)
+{
+ PK11SymKey * pms = NULL;
+ PK11SlotInfo * slot = serverKeySlot;
+ void * pwArg = ss->pkcs11PinArg;
+ SECItem param;
+ CK_VERSION version;
+ CK_MECHANISM_TYPE mechanism_array[3];
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ if (slot == NULL) {
+ SSLCipherAlgorithm calg;
+ /* The specReadLock would suffice here, but we cannot assert on
+ ** read locks. Also, all the callers who call with a non-null
+ ** slot already hold the SpecWriteLock.
+ */
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
+ PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
+
+ calg = spec->cipher_def->calg;
+ PORT_Assert(alg2Mech[calg].calg == calg);
+
+ /* First get an appropriate slot. */
+ mechanism_array[0] = CKM_SSL3_PRE_MASTER_KEY_GEN;
+ mechanism_array[1] = CKM_RSA_PKCS;
+ mechanism_array[2] = alg2Mech[calg].cmech;
+
+ slot = PK11_GetBestSlotMultiple(mechanism_array, 3, pwArg);
+ if (slot == NULL) {
+ /* can't find a slot with all three, find a slot with the minimum */
+ slot = PK11_GetBestSlotMultiple(mechanism_array, 2, pwArg);
+ if (slot == NULL) {
+ PORT_SetError(SSL_ERROR_TOKEN_SLOT_NOT_FOUND);
+ return pms; /* which is NULL */
+ }
+ }
+ }
+
+ /* Generate the pre-master secret ... */
+ if (IS_DTLS(ss)) {
+ SSL3ProtocolVersion temp;
+
+ temp = dtls_TLSVersionToDTLSVersion(ss->clientHelloVersion);
+ version.major = MSB(temp);
+ version.minor = LSB(temp);
+ } else {
+ version.major = MSB(ss->clientHelloVersion);
+ version.minor = LSB(ss->clientHelloVersion);
+ }
+
+ param.data = (unsigned char *)&version;
+ param.len = sizeof version;
+
+ pms = PK11_KeyGen(slot, CKM_SSL3_PRE_MASTER_KEY_GEN, &param, 0, pwArg);
+ if (!serverKeySlot)
+ PK11_FreeSlot(slot);
+ if (pms == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ }
+ return pms;
+}
+
+/* Note: The Bleichenbacher attack on PKCS#1 necessitates that we NEVER
+ * return any indication of failure of the Client Key Exchange message,
+ * where that failure is caused by the content of the client's message.
+ * This function must not return SECFailure for any reason that is directly
+ * or indirectly caused by the content of the client's encrypted PMS.
+ * We must not send an alert and also not drop the connection.
+ * Instead, we generate a random PMS. This will cause a failure
+ * in the processing the finished message, which is exactly where
+ * the failure must occur.
+ *
+ * Called from ssl3_HandleClientKeyExchange
+ */
+static SECStatus
+ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
+ SSL3Opaque *b,
+ PRUint32 length,
+ SECKEYPrivateKey *serverKey)
+{
+ PK11SymKey * pms;
+#ifndef NO_PKCS11_BYPASS
+ unsigned char * cr = (unsigned char *)&ss->ssl3.hs.client_random;
+ unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random;
+ ssl3CipherSpec * pwSpec = ss->ssl3.pwSpec;
+ unsigned int outLen = 0;
+#endif
+ PRBool isTLS = PR_FALSE;
+ SECStatus rv;
+ SECItem enc_pms;
+ unsigned char rsaPmsBuf[SSL3_RSA_PMS_LENGTH];
+ SECItem pmsItem = {siBuffer, NULL, 0};
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ PORT_Assert( ss->ssl3.prSpec == ss->ssl3.pwSpec );
+
+ enc_pms.data = b;
+ enc_pms.len = length;
+ pmsItem.data = rsaPmsBuf;
+ pmsItem.len = sizeof rsaPmsBuf;
+
+ if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */
+ PRInt32 kLen;
+ kLen = ssl3_ConsumeHandshakeNumber(ss, 2, &enc_pms.data, &enc_pms.len);
+ if (kLen < 0) {
+ PORT_SetError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ return SECFailure;
+ }
+ if ((unsigned)kLen < enc_pms.len) {
+ enc_pms.len = kLen;
+ }
+ isTLS = PR_TRUE;
+ } else {
+ isTLS = (PRBool)(ss->ssl3.hs.kea_def->tls_keygen != 0);
+ }
+
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11) {
+ /* TRIPLE BYPASS, get PMS directly from RSA decryption.
+ * Use PK11_PrivDecryptPKCS1 to decrypt the PMS to a buffer,
+ * then, check for version rollback attack, then
+ * do the equivalent of ssl3_DeriveMasterSecret, placing the MS in
+ * pwSpec->msItem. Finally call ssl3_InitPendingCipherSpec with
+ * ss and NULL, so that it will use the MS we've already derived here.
+ */
+
+ rv = PK11_PrivDecryptPKCS1(serverKey, rsaPmsBuf, &outLen,
+ sizeof rsaPmsBuf, enc_pms.data, enc_pms.len);
+ if (rv != SECSuccess) {
+ /* triple bypass failed. Let's try for a double bypass. */
+ goto double_bypass;
+ } else if (ss->opt.detectRollBack) {
+ SSL3ProtocolVersion client_version =
+ (rsaPmsBuf[0] << 8) | rsaPmsBuf[1];
+
+ if (IS_DTLS(ss)) {
+ client_version = dtls_DTLSVersionToTLSVersion(client_version);
+ }
+
+ if (client_version != ss->clientHelloVersion) {
+ /* Version roll-back detected. ensure failure. */
+ rv = PK11_GenerateRandom(rsaPmsBuf, sizeof rsaPmsBuf);
+ }
+ }
+ /* have PMS, build MS without PKCS11 */
+ rv = ssl3_MasterKeyDeriveBypass(pwSpec, cr, sr, &pmsItem, isTLS,
+ PR_TRUE);
+ if (rv != SECSuccess) {
+ pwSpec->msItem.data = pwSpec->raw_master_secret;
+ pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH;
+ PK11_GenerateRandom(pwSpec->msItem.data, pwSpec->msItem.len);
+ }
+ rv = ssl3_InitPendingCipherSpec(ss, NULL);
+ } else
+#endif
+ {
+#ifndef NO_PKCS11_BYPASS
+double_bypass:
+#endif
+ /*
+ * unwrap pms out of the incoming buffer
+ * Note: CKM_SSL3_MASTER_KEY_DERIVE is NOT the mechanism used to do
+ * the unwrap. Rather, it is the mechanism with which the
+ * unwrapped pms will be used.
+ */
+ pms = PK11_PubUnwrapSymKey(serverKey, &enc_pms,
+ CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0);
+ if (pms != NULL) {
+ PRINT_BUF(60, (ss, "decrypted premaster secret:",
+ PK11_GetKeyData(pms)->data,
+ PK11_GetKeyData(pms)->len));
+ } else {
+ /* unwrap failed. Generate a bogus PMS and carry on. */
+ PK11SlotInfo * slot = PK11_GetSlotFromPrivateKey(serverKey);
+
+ ssl_GetSpecWriteLock(ss);
+ pms = ssl3_GenerateRSAPMS(ss, ss->ssl3.prSpec, slot);
+ ssl_ReleaseSpecWriteLock(ss);
+ PK11_FreeSlot(slot);
+ }
+
+ if (pms == NULL) {
+ /* last gasp. */
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ return SECFailure;
+ }
+
+ /* This step will derive the MS from the PMS, among other things. */
+ rv = ssl3_InitPendingCipherSpec(ss, pms);
+ PK11_FreeSymKey(pms);
+ }
+
+ if (rv != SECSuccess) {
+ SEND_ALERT
+ return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */
+ }
+ return SECSuccess;
+}
+
+
+/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
+ * ssl3 ClientKeyExchange message from the remote client
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+static SECStatus
+ssl3_HandleClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+ SECKEYPrivateKey *serverKey = NULL;
+ SECStatus rv;
+ const ssl3KEADef *kea_def;
+ ssl3KeyPair *serverKeyPair = NULL;
+#ifdef NSS_ENABLE_ECC
+ SECKEYPublicKey *serverPubKey = NULL;
+#endif /* NSS_ENABLE_ECC */
+
+ SSL_TRC(3, ("%d: SSL3[%d]: handle client_key_exchange handshake",
+ SSL_GETPID(), ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ if (ss->ssl3.hs.ws != wait_client_key) {
+ SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH);
+ return SECFailure;
+ }
+
+ kea_def = ss->ssl3.hs.kea_def;
+
+ if (ss->ssl3.hs.usedStepDownKey) {
+ PORT_Assert(kea_def->is_limited /* XXX OR cert is signing only */
+ && kea_def->exchKeyType == kt_rsa
+ && ss->stepDownKeyPair != NULL);
+ if (!kea_def->is_limited ||
+ kea_def->exchKeyType != kt_rsa ||
+ ss->stepDownKeyPair == NULL) {
+ /* shouldn't happen, don't use step down if it does */
+ goto skip;
+ }
+ serverKeyPair = ss->stepDownKeyPair;
+ ss->sec.keaKeyBits = EXPORT_RSA_KEY_LENGTH * BPB;
+ } else
+skip:
+#ifdef NSS_ENABLE_ECC
+ /* XXX Using SSLKEAType to index server certifiates
+ * does not work for (EC)DHE ciphers. Until we have
+ * an indexing mechanism general enough for all key
+ * exchange algorithms, we'll need to deal with each
+ * one seprately.
+ */
+ if ((kea_def->kea == kea_ecdhe_rsa) ||
+ (kea_def->kea == kea_ecdhe_ecdsa)) {
+ if (ss->ephemeralECDHKeyPair != NULL) {
+ serverKeyPair = ss->ephemeralECDHKeyPair;
+ if (serverKeyPair->pubKey) {
+ ss->sec.keaKeyBits =
+ SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey);
+ }
+ }
+ } else
+#endif
+ {
+ sslServerCerts * sc = ss->serverCerts + kea_def->exchKeyType;
+ serverKeyPair = sc->serverKeyPair;
+ ss->sec.keaKeyBits = sc->serverKeyBits;
+ }
+
+ if (serverKeyPair) {
+ serverKey = serverKeyPair->privKey;
+ }
+
+ if (serverKey == NULL) {
+ SEND_ALERT
+ PORT_SetError(SSL_ERROR_NO_SERVER_KEY_FOR_ALG);
+ return SECFailure;
+ }
+
+ ss->sec.keaType = kea_def->exchKeyType;
+
+ switch (kea_def->exchKeyType) {
+ case kt_rsa:
+ rv = ssl3_HandleRSAClientKeyExchange(ss, b, length, serverKey);
+ if (rv != SECSuccess) {
+ SEND_ALERT
+ return SECFailure; /* error code set */
+ }
+ break;
+
+
+#ifdef NSS_ENABLE_ECC
+ case kt_ecdh:
+ /* XXX We really ought to be able to store multiple
+ * EC certs (a requirement if we wish to support both
+ * ECDH-RSA and ECDH-ECDSA key exchanges concurrently).
+ * When we make that change, we'll need an index other
+ * than kt_ecdh to pick the right EC certificate.
+ */
+ if (serverKeyPair) {
+ serverPubKey = serverKeyPair->pubKey;
+ }
+ if (serverPubKey == NULL) {
+ /* XXX Is this the right error code? */
+ PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
+ return SECFailure;
+ }
+ rv = ssl3_HandleECDHClientKeyExchange(ss, b, length,
+ serverPubKey, serverKey);
+ if (rv != SECSuccess) {
+ return SECFailure; /* error code set */
+ }
+ break;
+#endif /* NSS_ENABLE_ECC */
+
+ default:
+ (void) ssl3_HandshakeFailure(ss);
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+ return SECFailure;
+ }
+ ss->ssl3.hs.ws = ss->sec.peerCert ? wait_cert_verify : wait_change_cipher;
+ return SECSuccess;
+
+}
+
+/* This is TLS's equivalent of sending a no_certificate alert. */
+static SECStatus
+ssl3_SendEmptyCertificate(sslSocket *ss)
+{
+ SECStatus rv;
+
+ rv = ssl3_AppendHandshakeHeader(ss, certificate, 3);
+ if (rv == SECSuccess) {
+ rv = ssl3_AppendHandshakeNumber(ss, 0, 3);
+ }
+ return rv; /* error, if any, set by functions called above. */
+}
+
+SECStatus
+ssl3_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+ SECStatus rv;
+ NewSessionTicket session_ticket;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: handle session_ticket handshake",
+ SSL_GETPID(), ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ if (ss->ssl3.hs.ws != wait_new_session_ticket) {
+ SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET);
+ return SECFailure;
+ }
+
+ session_ticket.received_timestamp = ssl_Time();
+ if (length < 4) {
+ (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET);
+ return SECFailure;
+ }
+ session_ticket.ticket_lifetime_hint =
+ (PRUint32)ssl3_ConsumeHandshakeNumber(ss, 4, &b, &length);
+
+ rv = ssl3_ConsumeHandshakeVariable(ss, &session_ticket.ticket, 2,
+ &b, &length);
+ if (length != 0 || rv != SECSuccess) {
+ (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET);
+ return SECFailure; /* malformed */
+ }
+
+ rv = ssl3_SetSIDSessionTicket(ss->sec.ci.sid, &session_ticket);
+ if (rv != SECSuccess) {
+ (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
+ PORT_SetError(SSL_ERROR_INTERNAL_ERROR_ALERT);
+ return SECFailure;
+ }
+ ss->ssl3.hs.ws = wait_change_cipher;
+ return SECSuccess;
+}
+
+#ifdef NISCC_TEST
+static PRInt32 connNum = 0;
+
+static SECStatus
+get_fake_cert(SECItem *pCertItem, int *pIndex)
+{
+ PRFileDesc *cf;
+ char * testdir;
+ char * startat;
+ char * stopat;
+ const char *extension;
+ int fileNum;
+ PRInt32 numBytes = 0;
+ PRStatus prStatus;
+ PRFileInfo info;
+ char cfn[100];
+
+ pCertItem->data = 0;
+ if ((testdir = PR_GetEnv("NISCC_TEST")) == NULL) {
+ return SECSuccess;
+ }
+ *pIndex = (NULL != strstr(testdir, "root"));
+ extension = (strstr(testdir, "simple") ? "" : ".der");
+ fileNum = PR_ATOMIC_INCREMENT(&connNum) - 1;
+ if ((startat = PR_GetEnv("START_AT")) != NULL) {
+ fileNum += atoi(startat);
+ }
+ if ((stopat = PR_GetEnv("STOP_AT")) != NULL &&
+ fileNum >= atoi(stopat)) {
+ *pIndex = -1;
+ return SECSuccess;
+ }
+ sprintf(cfn, "%s/%08d%s", testdir, fileNum, extension);
+ cf = PR_Open(cfn, PR_RDONLY, 0);
+ if (!cf) {
+ goto loser;
+ }
+ prStatus = PR_GetOpenFileInfo(cf, &info);
+ if (prStatus != PR_SUCCESS) {
+ PR_Close(cf);
+ goto loser;
+ }
+ pCertItem = SECITEM_AllocItem(NULL, pCertItem, info.size);
+ if (pCertItem) {
+ numBytes = PR_Read(cf, pCertItem->data, info.size);
+ }
+ PR_Close(cf);
+ if (numBytes != info.size) {
+ SECITEM_FreeItem(pCertItem, PR_FALSE);
+ PORT_SetError(SEC_ERROR_IO);
+ goto loser;
+ }
+ fprintf(stderr, "using %s\n", cfn);
+ return SECSuccess;
+
+loser:
+ fprintf(stderr, "failed to use %s\n", cfn);
+ *pIndex = -1;
+ return SECFailure;
+}
+#endif
+
+/*
+ * Used by both client and server.
+ * Called from HandleServerHelloDone and from SendServerHelloSequence.
+ */
+static SECStatus
+ssl3_SendCertificate(sslSocket *ss)
+{
+ SECStatus rv;
+ CERTCertificateList *certChain;
+ int len = 0;
+ int i;
+ SSL3KEAType certIndex;
+#ifdef NISCC_TEST
+ SECItem fakeCert;
+ int ndex = -1;
+#endif
+
+ SSL_TRC(3, ("%d: SSL3[%d]: send certificate handshake",
+ SSL_GETPID(), ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ if (ss->sec.localCert)
+ CERT_DestroyCertificate(ss->sec.localCert);
+ if (ss->sec.isServer) {
+ sslServerCerts * sc = NULL;
+
+ /* XXX SSLKEAType isn't really a good choice for
+ * indexing certificates (it breaks when we deal
+ * with (EC)DHE-* cipher suites. This hack ensures
+ * the RSA cert is picked for (EC)DHE-RSA.
+ * Revisit this when we add server side support
+ * for ECDHE-ECDSA or client-side authentication
+ * using EC certificates.
+ */
+ if ((ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) ||
+ (ss->ssl3.hs.kea_def->kea == kea_dhe_rsa)) {
+ certIndex = kt_rsa;
+ } else {
+ certIndex = ss->ssl3.hs.kea_def->exchKeyType;
+ }
+ sc = ss->serverCerts + certIndex;
+ certChain = sc->serverCertChain;
+ ss->sec.authKeyBits = sc->serverKeyBits;
+ ss->sec.authAlgorithm = ss->ssl3.hs.kea_def->signKeyType;
+ ss->sec.localCert = CERT_DupCertificate(sc->serverCert);
+ } else {
+ certChain = ss->ssl3.clientCertChain;
+ ss->sec.localCert = CERT_DupCertificate(ss->ssl3.clientCertificate);
+ }
+
+#ifdef NISCC_TEST
+ rv = get_fake_cert(&fakeCert, &ndex);
+#endif
+
+ if (certChain) {
+ for (i = 0; i < certChain->len; i++) {
+#ifdef NISCC_TEST
+ if (fakeCert.len > 0 && i == ndex) {
+ len += fakeCert.len + 3;
+ } else {
+ len += certChain->certs[i].len + 3;
+ }
+#else
+ len += certChain->certs[i].len + 3;
+#endif
+ }
+ }
+
+ rv = ssl3_AppendHandshakeHeader(ss, certificate, len + 3);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+ rv = ssl3_AppendHandshakeNumber(ss, len, 3);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+ if (certChain) {
+ for (i = 0; i < certChain->len; i++) {
+#ifdef NISCC_TEST
+ if (fakeCert.len > 0 && i == ndex) {
+ rv = ssl3_AppendHandshakeVariable(ss, fakeCert.data,
+ fakeCert.len, 3);
+ SECITEM_FreeItem(&fakeCert, PR_FALSE);
+ } else {
+ rv = ssl3_AppendHandshakeVariable(ss, certChain->certs[i].data,
+ certChain->certs[i].len, 3);
+ }
+#else
+ rv = ssl3_AppendHandshakeVariable(ss, certChain->certs[i].data,
+ certChain->certs[i].len, 3);
+#endif
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+ }
+ }
+
+ return SECSuccess;
+}
+
+/*
+ * Used by server only.
+ * single-stapling, send only a single cert status
+ */
+static SECStatus
+ssl3_SendCertificateStatus(sslSocket *ss)
+{
+ SECStatus rv;
+ int len = 0;
+ SECItemArray *statusToSend = NULL;
+ SSL3KEAType certIndex;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: send certificate status handshake",
+ SSL_GETPID(), ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert( ss->sec.isServer);
+
+ if (!ssl3_ExtensionNegotiated(ss, ssl_cert_status_xtn))
+ return SECSuccess;
+
+ /* Use certStatus based on the cert being used. */
+ if ((ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) ||
+ (ss->ssl3.hs.kea_def->kea == kea_dhe_rsa)) {
+ certIndex = kt_rsa;
+ } else {
+ certIndex = ss->ssl3.hs.kea_def->exchKeyType;
+ }
+ if (ss->certStatusArray[certIndex] && ss->certStatusArray[certIndex]->len) {
+ statusToSend = ss->certStatusArray[certIndex];
+ }
+ if (!statusToSend)
+ return SECSuccess;
+
+ /* Use the array's first item only (single stapling) */
+ len = 1 + statusToSend->items[0].len + 3;
+
+ rv = ssl3_AppendHandshakeHeader(ss, certificate_status, len);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
+ rv = ssl3_AppendHandshakeNumber(ss, 1 /*ocsp*/, 1);
+ if (rv != SECSuccess)
+ return rv; /* err set by AppendHandshake. */
+
+ rv = ssl3_AppendHandshakeVariable(ss,
+ statusToSend->items[0].data,
+ statusToSend->items[0].len,
+ 3);
+ if (rv != SECSuccess)
+ return rv; /* err set by AppendHandshake. */
+
+ return SECSuccess;
+}
+
+/* This is used to delete the CA certificates in the peer certificate chain
+ * from the cert database after they've been validated.
+ */
+static void
+ssl3_CleanupPeerCerts(sslSocket *ss)
+{
+ PLArenaPool * arena = ss->ssl3.peerCertArena;
+ ssl3CertNode *certs = (ssl3CertNode *)ss->ssl3.peerCertChain;
+
+ for (; certs; certs = certs->next) {
+ CERT_DestroyCertificate(certs->cert);
+ }
+ if (arena) PORT_FreeArena(arena, PR_FALSE);
+ ss->ssl3.peerCertArena = NULL;
+ ss->ssl3.peerCertChain = NULL;
+}
+
+static void
+ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid)
+{
+ PLArenaPool *arena;
+ ssl3CertNode *lastCert = NULL;
+ ssl3CertNode *certs = NULL;
+ int i;
+
+ if (!sid->peerCertChain[0])
+ return;
+ PORT_Assert(!ss->ssl3.peerCertArena);
+ PORT_Assert(!ss->ssl3.peerCertChain);
+ ss->ssl3.peerCertArena = arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ for (i = 0; i < MAX_PEER_CERT_CHAIN_SIZE && sid->peerCertChain[i]; i++) {
+ ssl3CertNode *c = PORT_ArenaNew(arena, ssl3CertNode);
+ c->cert = CERT_DupCertificate(sid->peerCertChain[i]);
+ c->next = NULL;
+ if (lastCert) {
+ lastCert->next = c;
+ } else {
+ certs = c;
+ }
+ lastCert = c;
+ }
+ ss->ssl3.peerCertChain = certs;
+}
+
+static void
+ssl3_CopyPeerCertsToSID(ssl3CertNode *certs, sslSessionID *sid)
+{
+ int i = 0;
+ ssl3CertNode *c = certs;
+ for (; i < MAX_PEER_CERT_CHAIN_SIZE && c; i++, c = c->next) {
+ PORT_Assert(!sid->peerCertChain[i]);
+ sid->peerCertChain[i] = CERT_DupCertificate(c->cert);
+ }
+}
+
+/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
+ * ssl3 CertificateStatus message.
+ * Caller must hold Handshake and RecvBuf locks.
+ * This is always called before ssl3_HandleCertificate, even if the Certificate
+ * message is sent first.
+ */
+static SECStatus
+ssl3_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+ PRInt32 status, len;
+
+ if (ss->ssl3.hs.ws != wait_certificate_status) {
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_STATUS);
+ return SECFailure;
+ }
+
+ PORT_Assert(!ss->sec.isServer);
+
+ /* Consume the CertificateStatusType enum */
+ status = ssl3_ConsumeHandshakeNumber(ss, 1, &b, &length);
+ if (status != 1 /* ocsp */) {
+ goto format_loser;
+ }
+
+ len = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
+ if (len != length) {
+ goto format_loser;
+ }
+
+#define MAX_CERTSTATUS_LEN 0x1ffff /* 128k - 1 */
+ if (length > MAX_CERTSTATUS_LEN)
+ goto format_loser;
+#undef MAX_CERTSTATUS_LEN
+
+ /* Array size 1, because we currently implement single-stapling only */
+ SECITEM_AllocArray(NULL, &ss->sec.ci.sid->peerCertStatus, 1);
+ if (!ss->sec.ci.sid->peerCertStatus.items)
+ return SECFailure;
+
+ ss->sec.ci.sid->peerCertStatus.items[0].data = PORT_Alloc(length);
+
+ if (!ss->sec.ci.sid->peerCertStatus.items[0].data) {
+ SECITEM_FreeArray(&ss->sec.ci.sid->peerCertStatus, PR_FALSE);
+ return SECFailure;
+ }
+
+ PORT_Memcpy(ss->sec.ci.sid->peerCertStatus.items[0].data, b, length);
+ ss->sec.ci.sid->peerCertStatus.items[0].len = length;
+ ss->sec.ci.sid->peerCertStatus.items[0].type = siBuffer;
+
+ return ssl3_AuthCertificate(ss);
+
+format_loser:
+ return ssl3_DecodeError(ss);
+}
+
+/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
+ * ssl3 Certificate message.
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+static SECStatus
+ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+ ssl3CertNode * c;
+ ssl3CertNode * lastCert = NULL;
+ PRInt32 remaining = 0;
+ PRInt32 size;
+ SECStatus rv;
+ PRBool isServer = (PRBool)(!!ss->sec.isServer);
+ PRBool isTLS;
+ SSL3AlertDescription desc;
+ int errCode = SSL_ERROR_RX_MALFORMED_CERTIFICATE;
+ SECItem certItem;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: handle certificate handshake",
+ SSL_GETPID(), ss->fd));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ if ((ss->ssl3.hs.ws != wait_server_cert) &&
+ (ss->ssl3.hs.ws != wait_client_cert)) {
+ desc = unexpected_message;
+ errCode = SSL_ERROR_RX_UNEXPECTED_CERTIFICATE;
+ goto alert_loser;
+ }
+
+ if (ss->sec.peerCert != NULL) {
+ if (ss->sec.peerKey) {
+ SECKEY_DestroyPublicKey(ss->sec.peerKey);
+ ss->sec.peerKey = NULL;
+ }
+ CERT_DestroyCertificate(ss->sec.peerCert);
+ ss->sec.peerCert = NULL;
+ }
+
+ ssl3_CleanupPeerCerts(ss);
+ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
+
+ /* It is reported that some TLS client sends a Certificate message
+ ** with a zero-length message body. We'll treat that case like a
+ ** normal no_certificates message to maximize interoperability.
+ */
+ if (length) {
+ remaining = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
+ if (remaining < 0)
+ goto loser; /* fatal alert already sent by ConsumeHandshake. */
+ if ((PRUint32)remaining > length)
+ goto decode_loser;
+ }
+
+ if (!remaining) {
+ if (!(isTLS && isServer)) {
+ desc = bad_certificate;
+ goto alert_loser;
+ }
+ /* This is TLS's version of a no_certificate alert. */
+ /* I'm a server. I've requested a client cert. He hasn't got one. */
+ rv = ssl3_HandleNoCertificate(ss);
+ if (rv != SECSuccess) {
+ errCode = PORT_GetError();
+ goto loser;
+ }
+ ss->ssl3.hs.ws = wait_client_key;
+ return SECSuccess;
+ }
+
+ ss->ssl3.peerCertArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (ss->ssl3.peerCertArena == NULL) {
+ goto loser; /* don't send alerts on memory errors */
+ }
+
+ /* First get the peer cert. */
+ remaining -= 3;
+ if (remaining < 0)
+ goto decode_loser;
+
+ size = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
+ if (size <= 0)
+ goto loser; /* fatal alert already sent by ConsumeHandshake. */
+
+ if (remaining < size)
+ goto decode_loser;
+
+ certItem.data = b;
+ certItem.len = size;
+ b += size;
+ length -= size;
+ remaining -= size;
+
+ ss->sec.peerCert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL,
+ PR_FALSE, PR_TRUE);
+ if (ss->sec.peerCert == NULL) {
+ /* We should report an alert if the cert was bad, but not if the
+ * problem was just some local problem, like memory error.
+ */
+ goto ambiguous_err;
+ }
+
+ /* Now get all of the CA certs. */
+ while (remaining > 0) {
+ remaining -= 3;
+ if (remaining < 0)
+ goto decode_loser;
+
+ size = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
+ if (size <= 0)
+ goto loser; /* fatal alert already sent by ConsumeHandshake. */
+
+ if (remaining < size)
+ goto decode_loser;
+
+ certItem.data = b;
+ certItem.len = size;
+ b += size;
+ length -= size;
+ remaining -= size;
+
+ c = PORT_ArenaNew(ss->ssl3.peerCertArena, ssl3CertNode);
+ if (c == NULL) {
+ goto loser; /* don't send alerts on memory errors */
+ }
+
+ c->cert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL,
+ PR_FALSE, PR_TRUE);
+ if (c->cert == NULL) {
+ goto ambiguous_err;
+ }
+
+ c->next = NULL;
+ if (lastCert) {
+ lastCert->next = c;
+ } else {
+ ss->ssl3.peerCertChain = c;
+ }
+ lastCert = c;
+ }
+
+ if (remaining != 0)
+ goto decode_loser;
+
+ SECKEY_UpdateCertPQG(ss->sec.peerCert);
+
+ if (!isServer && ssl3_ExtensionNegotiated(ss, ssl_cert_status_xtn)) {
+ ss->ssl3.hs.ws = wait_certificate_status;
+ rv = SECSuccess;
+ } else {
+ rv = ssl3_AuthCertificate(ss); /* sets ss->ssl3.hs.ws */
+ }
+
+ return rv;
+
+ambiguous_err:
+ errCode = PORT_GetError();
+ switch (errCode) {
+ case PR_OUT_OF_MEMORY_ERROR:
+ case SEC_ERROR_BAD_DATABASE:
+ case SEC_ERROR_NO_MEMORY:
+ if (isTLS) {
+ desc = internal_error;
+ goto alert_loser;
+ }
+ goto loser;
+ }
+ ssl3_SendAlertForCertError(ss, errCode);
+ goto loser;
+
+decode_loser:
+ desc = isTLS ? decode_error : bad_certificate;
+
+alert_loser:
+ (void)SSL3_SendAlert(ss, alert_fatal, desc);
+
+loser:
+ (void)ssl_MapLowLevelError(errCode);
+ return SECFailure;
+}
+
+static SECStatus
+ssl3_AuthCertificate(sslSocket *ss)
+{
+ SECStatus rv;
+ PRBool isServer = (PRBool)(!!ss->sec.isServer);
+ int errCode;
+
+ ss->ssl3.hs.authCertificatePending = PR_FALSE;
+
+ /*
+ * Ask caller-supplied callback function to validate cert chain.
+ */
+ rv = (SECStatus)(*ss->authCertificate)(ss->authCertificateArg, ss->fd,
+ PR_TRUE, isServer);
+ if (rv) {
+ errCode = PORT_GetError();
+ if (rv != SECWouldBlock) {
+ if (ss->handleBadCert) {
+ rv = (*ss->handleBadCert)(ss->badCertArg, ss->fd);
+ }
+ }
+
+ if (rv == SECWouldBlock) {
+ if (ss->sec.isServer) {
+ errCode = SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS;
+ rv = SECFailure;
+ goto loser;
+ }
+
+ ss->ssl3.hs.authCertificatePending = PR_TRUE;
+ rv = SECSuccess;
+
+ /* XXX: Async cert validation and False Start don't work together
+ * safely yet; if we leave False Start enabled, we may end up false
+ * starting (sending application data) before we
+ * SSL_AuthCertificateComplete has been called.
+ */
+ ss->opt.enableFalseStart = PR_FALSE;
+ }
+
+ if (rv != SECSuccess) {
+ ssl3_SendAlertForCertError(ss, errCode);
+ goto loser;
+ }
+ }
+
+ ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);
+ ssl3_CopyPeerCertsToSID(ss->ssl3.peerCertChain, ss->sec.ci.sid);
+
+ if (!ss->sec.isServer) {
+ CERTCertificate *cert = ss->sec.peerCert;
+
+ /* set the server authentication and key exchange types and sizes
+ ** from the value in the cert. If the key exchange key is different,
+ ** it will get fixed when we handle the server key exchange message.
+ */
+ SECKEYPublicKey * pubKey = CERT_ExtractPublicKey(cert);
+ ss->sec.authAlgorithm = ss->ssl3.hs.kea_def->signKeyType;
+ ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType;
+ if (pubKey) {
+ ss->sec.keaKeyBits = ss->sec.authKeyBits =
+ SECKEY_PublicKeyStrengthInBits(pubKey);
+#ifdef NSS_ENABLE_ECC
+ if (ss->sec.keaType == kt_ecdh) {
+ /* Get authKeyBits from signing key.
+ * XXX The code below uses a quick approximation of
+ * key size based on cert->signatureWrap.signature.data
+ * (which contains the DER encoded signature). The field
+ * cert->signatureWrap.signature.len contains the
+ * length of the encoded signature in bits.
+ */
+ if (ss->ssl3.hs.kea_def->kea == kea_ecdh_ecdsa) {
+ ss->sec.authKeyBits =
+ cert->signatureWrap.signature.data[3]*8;
+ if (cert->signatureWrap.signature.data[4] == 0x00)
+ ss->sec.authKeyBits -= 8;
+ /*
+ * XXX: if cert is not signed by ecdsa we should
+ * destroy pubKey and goto bad_cert
+ */
+ } else if (ss->ssl3.hs.kea_def->kea == kea_ecdh_rsa) {
+ ss->sec.authKeyBits = cert->signatureWrap.signature.len;
+ /*
+ * XXX: if cert is not signed by rsa we should
+ * destroy pubKey and goto bad_cert
+ */
+ }
+ }
+#endif /* NSS_ENABLE_ECC */
+ SECKEY_DestroyPublicKey(pubKey);
+ pubKey = NULL;
+ }
+
+ ss->ssl3.hs.ws = wait_cert_request; /* disallow server_key_exchange */
+ if (ss->ssl3.hs.kea_def->is_limited ||
+ /* XXX OR server cert is signing only. */
+#ifdef NSS_ENABLE_ECC
+ ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa ||
+ ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa ||
+#endif /* NSS_ENABLE_ECC */
+ ss->ssl3.hs.kea_def->exchKeyType == kt_dh) {
+ ss->ssl3.hs.ws = wait_server_key; /* allow server_key_exchange */
+ }
+ } else {
+ ss->ssl3.hs.ws = wait_client_key;
+ }
+
+ PORT_Assert(rv == SECSuccess);
+ if (rv != SECSuccess) {
+ errCode = SEC_ERROR_LIBRARY_FAILURE;
+ rv = SECFailure;
+ goto loser;
+ }
+
+ return rv;
+
+loser:
+ (void)ssl_MapLowLevelError(errCode);
+ return SECFailure;
+}
+
+static SECStatus ssl3_FinishHandshake(sslSocket *ss);
+
+static SECStatus
+ssl3_AlwaysFail(sslSocket * ss)
+{
+ PORT_SetError(PR_INVALID_STATE_ERROR);
+ return SECFailure;
+}
+
+/* Caller must hold 1stHandshakeLock.
+*/
+SECStatus
+ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error)
+{
+ SECStatus rv;
+
+ PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss));
+
+ if (ss->sec.isServer) {
+ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS);
+ return SECFailure;
+ }
+
+ ssl_GetRecvBufLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ if (!ss->ssl3.hs.authCertificatePending) {
+ PORT_SetError(PR_INVALID_STATE_ERROR);
+ rv = SECFailure;
+ goto done;
+ }
+
+ ss->ssl3.hs.authCertificatePending = PR_FALSE;
+
+ if (error != 0) {
+ ss->ssl3.hs.restartTarget = ssl3_AlwaysFail;
+ ssl3_SendAlertForCertError(ss, error);
+ rv = SECSuccess;
+ } else if (ss->ssl3.hs.restartTarget != NULL) {
+ sslRestartTarget target = ss->ssl3.hs.restartTarget;
+ ss->ssl3.hs.restartTarget = NULL;
+ rv = target(ss);
+ /* Even if we blocked here, we have accomplished enough to claim
+ * success. Any remaining work will be taken care of by subsequent
+ * calls to SSL_ForceHandshake/PR_Send/PR_Read/etc.
+ */
+ if (rv == SECWouldBlock) {
+ rv = SECSuccess;
+ }
+ } else {
+ rv = SECSuccess;
+ }
+
+done:
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_ReleaseRecvBufLock(ss);
+
+ return rv;
+}
+
+static SECStatus
+ssl3_ComputeTLSFinished(ssl3CipherSpec *spec,
+ PRBool isServer,
+ const SSL3Hashes * hashes,
+ TLSFinished * tlsFinished)
+{
+ const char * label;
+ unsigned int len;
+ SECStatus rv;
+
+ label = isServer ? "server finished" : "client finished";
+ len = 15;
+
+ rv = ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->u.raw,
+ hashes->len, tlsFinished->verify_data,
+ sizeof tlsFinished->verify_data);
+
+ return rv;
+}
+
+/* The calling function must acquire and release the appropriate
+ * lock (e.g., ssl_GetSpecReadLock / ssl_ReleaseSpecReadLock for
+ * ss->ssl3.crSpec).
+ */
+SECStatus
+ssl3_TLSPRFWithMasterSecret(ssl3CipherSpec *spec, const char *label,
+ unsigned int labelLen, const unsigned char *val, unsigned int valLen,
+ unsigned char *out, unsigned int outLen)
+{
+ SECStatus rv = SECSuccess;
+
+ if (spec->master_secret && !spec->bypassCiphers) {
+ SECItem param = {siBuffer, NULL, 0};
+ CK_MECHANISM_TYPE mech = CKM_TLS_PRF_GENERAL;
+ PK11Context *prf_context;
+ unsigned int retLen;
+
+ if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+ mech = CKM_NSS_TLS_PRF_GENERAL_SHA256;
+ }
+ prf_context = PK11_CreateContextBySymKey(mech, CKA_SIGN,
+ spec->master_secret, &param);
+ if (!prf_context)
+ return SECFailure;
+
+ rv = PK11_DigestBegin(prf_context);
+ rv |= PK11_DigestOp(prf_context, (unsigned char *) label, labelLen);
+ rv |= PK11_DigestOp(prf_context, val, valLen);
+ rv |= PK11_DigestFinal(prf_context, out, &retLen, outLen);
+ PORT_Assert(rv != SECSuccess || retLen == outLen);
+
+ PK11_DestroyContext(prf_context, PR_TRUE);
+ } else {
+ /* bypass PKCS11 */
+#ifdef NO_PKCS11_BYPASS
+ PORT_Assert(spec->master_secret);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ rv = SECFailure;
+#else
+ SECItem inData = { siBuffer, };
+ SECItem outData = { siBuffer, };
+ PRBool isFIPS = PR_FALSE;
+
+ inData.data = (unsigned char *) val;
+ inData.len = valLen;
+ outData.data = out;
+ outData.len = outLen;
+ if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+ rv = TLS_P_hash(HASH_AlgSHA256, &spec->msItem, label, &inData,
+ &outData, isFIPS);
+ } else {
+ rv = TLS_PRF(&spec->msItem, label, &inData, &outData, isFIPS);
+ }
+ PORT_Assert(rv != SECSuccess || outData.len == outLen);
+#endif
+ }
+ return rv;
+}
+
+/* called from ssl3_HandleServerHelloDone
+ */
+static SECStatus
+ssl3_SendNextProto(sslSocket *ss)
+{
+ SECStatus rv;
+ int padding_len;
+ static const unsigned char padding[32] = {0};
+
+ if (ss->ssl3.nextProto.len == 0 ||
+ ss->ssl3.nextProtoState == SSL_NEXT_PROTO_SELECTED) {
+ return SECSuccess;
+ }
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ padding_len = 32 - ((ss->ssl3.nextProto.len + 2) % 32);
+
+ rv = ssl3_AppendHandshakeHeader(ss, next_proto, ss->ssl3.nextProto.len +
+ 2 + padding_len);
+ if (rv != SECSuccess) {
+ return rv; /* error code set by AppendHandshakeHeader */
+ }
+ rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.nextProto.data,
+ ss->ssl3.nextProto.len, 1);
+ if (rv != SECSuccess) {
+ return rv; /* error code set by AppendHandshake */
+ }
+ rv = ssl3_AppendHandshakeVariable(ss, padding, padding_len, 1);
+ if (rv != SECSuccess) {
+ return rv; /* error code set by AppendHandshake */
+ }
+ return rv;
+}
+
+/* called from ssl3_SendFinished
+ *
+ * This function is simply a debugging aid and therefore does not return a
+ * SECStatus. */
+static void
+ssl3_RecordKeyLog(sslSocket *ss)
+{
+ SECStatus rv;
+ SECItem *keyData;
+ char buf[14 /* "CLIENT_RANDOM " */ +
+ SSL3_RANDOM_LENGTH*2 /* client_random */ +
+ 1 /* " " */ +
+ 48*2 /* master secret */ +
+ 1 /* new line */];
+ unsigned int j;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ if (!ssl_keylog_iob)
+ return;
+
+ rv = PK11_ExtractKeyValue(ss->ssl3.cwSpec->master_secret);
+ if (rv != SECSuccess)
+ return;
+
+ ssl_GetSpecReadLock(ss);
+
+ /* keyData does not need to be freed. */
+ keyData = PK11_GetKeyData(ss->ssl3.cwSpec->master_secret);
+ if (!keyData || !keyData->data || keyData->len != 48) {
+ ssl_ReleaseSpecReadLock(ss);
+ return;
+ }
+
+ /* https://developer.mozilla.org/en/NSS_Key_Log_Format */
+
+ /* There could be multiple, concurrent writers to the
+ * keylog, so we have to do everything in a single call to
+ * fwrite. */
+
+ memcpy(buf, "CLIENT_RANDOM ", 14);
+ j = 14;
+ hexEncode(buf + j, ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH);
+ j += SSL3_RANDOM_LENGTH*2;
+ buf[j++] = ' ';
+ hexEncode(buf + j, keyData->data, 48);
+ j += 48*2;
+ buf[j++] = '\n';
+
+ PORT_Assert(j == sizeof(buf));
+
+ ssl_ReleaseSpecReadLock(ss);
+
+ if (fwrite(buf, sizeof(buf), 1, ssl_keylog_iob) != 1)
+ return;
+ fflush(ssl_keylog_iob);
+ return;
+}
+
+/* called from ssl3_SendClientSecondRound
+ * ssl3_HandleFinished
+ */
+static SECStatus
+ssl3_SendEncryptedExtensions(sslSocket *ss)
+{
+ static const char CHANNEL_ID_MAGIC[] = "TLS Channel ID signature";
+ /* This is the ASN.1 prefix for a P-256 public key. Specifically it's:
+ * SEQUENCE
+ * SEQUENCE
+ * OID id-ecPublicKey
+ * OID prime256v1
+ * BIT STRING, length 66, 0 trailing bits: 0x04
+ *
+ * The 0x04 in the BIT STRING is the prefix for an uncompressed, X9.62
+ * public key. Following that are the two field elements as 32-byte,
+ * big-endian numbers, as required by the Channel ID. */
+ static const unsigned char P256_SPKI_PREFIX[] = {
+ 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
+ 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
+ 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
+ 0x42, 0x00, 0x04
+ };
+ /* ChannelIDs are always 128 bytes long: 64 bytes of P-256 public key and 64
+ * bytes of ECDSA signature. */
+ static const int CHANNEL_ID_PUBLIC_KEY_LENGTH = 64;
+ static const int CHANNEL_ID_LENGTH = 128;
+
+ SECStatus rv = SECFailure;
+ SECItem *spki = NULL;
+ SSL3Hashes hashes;
+ const unsigned char *pub_bytes;
+ unsigned char signed_data[sizeof(CHANNEL_ID_MAGIC) + sizeof(SSL3Hashes)];
+ unsigned char digest[SHA256_LENGTH];
+ SECItem digest_item;
+ unsigned char signature[64];
+ SECItem signature_item;
+
+ PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ if (ss->ssl3.channelID == NULL)
+ return SECSuccess;
+
+ PORT_Assert(ssl3_ExtensionNegotiated(ss, ssl_channel_id_xtn));
+
+ if (SECKEY_GetPrivateKeyType(ss->ssl3.channelID) != ecKey ||
+ PK11_SignatureLen(ss->ssl3.channelID) != sizeof(signature)) {
+ PORT_SetError(SSL_ERROR_INVALID_CHANNEL_ID_KEY);
+ rv = SECFailure;
+ goto loser;
+ }
+
+ ssl_GetSpecReadLock(ss);
+ rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.cwSpec, &hashes, 0);
+ ssl_ReleaseSpecReadLock(ss);
+
+ if (rv != SECSuccess)
+ goto loser;
+
+ rv = ssl3_AppendHandshakeHeader(ss, encrypted_extensions,
+ 2 + 2 + CHANNEL_ID_LENGTH);
+ if (rv != SECSuccess)
+ goto loser; /* error code set by AppendHandshakeHeader */
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_channel_id_xtn, 2);
+ if (rv != SECSuccess)
+ goto loser; /* error code set by AppendHandshake */
+ rv = ssl3_AppendHandshakeNumber(ss, CHANNEL_ID_LENGTH, 2);
+ if (rv != SECSuccess)
+ goto loser; /* error code set by AppendHandshake */
+
+ spki = SECKEY_EncodeDERSubjectPublicKeyInfo(ss->ssl3.channelIDPub);
+
+ if (spki->len != sizeof(P256_SPKI_PREFIX) + CHANNEL_ID_PUBLIC_KEY_LENGTH ||
+ memcmp(spki->data, P256_SPKI_PREFIX, sizeof(P256_SPKI_PREFIX) != 0)) {
+ PORT_SetError(SSL_ERROR_INVALID_CHANNEL_ID_KEY);
+ rv = SECFailure;
+ goto loser;
+ }
+
+ pub_bytes = spki->data + sizeof(P256_SPKI_PREFIX);
+
+ memcpy(signed_data, CHANNEL_ID_MAGIC, sizeof(CHANNEL_ID_MAGIC));
+ memcpy(signed_data + sizeof(CHANNEL_ID_MAGIC), hashes.u.raw, hashes.len);
+
+ rv = PK11_HashBuf(SEC_OID_SHA256, digest, signed_data,
+ sizeof(CHANNEL_ID_MAGIC) + hashes.len);
+ if (rv != SECSuccess)
+ goto loser;
+
+ digest_item.data = digest;
+ digest_item.len = sizeof(digest);
+
+ signature_item.data = signature;
+ signature_item.len = sizeof(signature);
+
+ rv = PK11_Sign(ss->ssl3.channelID, &signature_item, &digest_item);
+ if (rv != SECSuccess)
+ goto loser;
+
+ rv = ssl3_AppendHandshake(ss, pub_bytes, CHANNEL_ID_PUBLIC_KEY_LENGTH);
+ if (rv != SECSuccess)
+ goto loser;
+ rv = ssl3_AppendHandshake(ss, signature, sizeof(signature));
+
+loser:
+ if (spki)
+ SECITEM_FreeItem(spki, PR_TRUE);
+ if (ss->ssl3.channelID) {
+ SECKEY_DestroyPrivateKey(ss->ssl3.channelID);
+ ss->ssl3.channelID = NULL;
+ }
+ if (ss->ssl3.channelIDPub) {
+ SECKEY_DestroyPublicKey(ss->ssl3.channelIDPub);
+ ss->ssl3.channelIDPub = NULL;
+ }
+
+ return rv;
+}
+
+/* ssl3_RestartHandshakeAfterChannelIDReq is called to restart a handshake
+ * after a ChannelID callback returned SECWouldBlock. At this point we have
+ * processed the server's ServerHello but not yet any further messages. We will
+ * always get a message from the server after a ServerHello so either they are
+ * waiting in the buffer or we'll get network I/O. */
+SECStatus
+ssl3_RestartHandshakeAfterChannelIDReq(sslSocket *ss,
+ SECKEYPublicKey *channelIDPub,
+ SECKEYPrivateKey *channelID)
+{
+ if (ss->handshake == 0) {
+ SECKEY_DestroyPublicKey(channelIDPub);
+ SECKEY_DestroyPrivateKey(channelID);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ if (channelIDPub == NULL ||
+ channelID == NULL) {
+ if (channelIDPub)
+ SECKEY_DestroyPublicKey(channelIDPub);
+ if (channelID)
+ SECKEY_DestroyPrivateKey(channelID);
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+
+ if (ss->ssl3.channelID)
+ SECKEY_DestroyPrivateKey(ss->ssl3.channelID);
+ if (ss->ssl3.channelIDPub)
+ SECKEY_DestroyPublicKey(ss->ssl3.channelIDPub);
+
+ ss->handshake = ssl_GatherRecord1stHandshake;
+ ss->ssl3.channelID = channelID;
+ ss->ssl3.channelIDPub = channelIDPub;
+
+ return SECSuccess;
+}
+
+/* called from ssl3_HandleServerHelloDone
+ * ssl3_HandleClientHello
+ * ssl3_HandleFinished
+ */
+static SECStatus
+ssl3_SendFinished(sslSocket *ss, PRInt32 flags)
+{
+ ssl3CipherSpec *cwSpec;
+ PRBool isTLS;
+ PRBool isServer = ss->sec.isServer;
+ SECStatus rv;
+ SSL3Sender sender = isServer ? sender_server : sender_client;
+ SSL3Hashes hashes;
+ TLSFinished tlsFinished;
+
+ SSL_TRC(3, ("%d: SSL3[%d]: send finished handshake", SSL_GETPID(), ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ ssl_GetSpecReadLock(ss);
+ cwSpec = ss->ssl3.cwSpec;
+ isTLS = (PRBool)(cwSpec->version > SSL_LIBRARY_VERSION_3_0);
+ rv = ssl3_ComputeHandshakeHashes(ss, cwSpec, &hashes, sender);
+ if (isTLS && rv == SECSuccess) {
+ rv = ssl3_ComputeTLSFinished(cwSpec, isServer, &hashes, &tlsFinished);
+ }
+ ssl_ReleaseSpecReadLock(ss);
+ if (rv != SECSuccess) {
+ goto fail; /* err code was set by ssl3_ComputeHandshakeHashes */
+ }
+
+ if (isTLS) {
+ if (isServer)
+ ss->ssl3.hs.finishedMsgs.tFinished[1] = tlsFinished;
+ else
+ ss->ssl3.hs.finishedMsgs.tFinished[0] = tlsFinished;
+ ss->ssl3.hs.finishedBytes = sizeof tlsFinished;
+ rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof tlsFinished);
+ if (rv != SECSuccess)
+ goto fail; /* err set by AppendHandshake. */
+ rv = ssl3_AppendHandshake(ss, &tlsFinished, sizeof tlsFinished);
+ if (rv != SECSuccess)
+ goto fail; /* err set by AppendHandshake. */
+ } else {
+ if (isServer)
+ ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes.u.s;
+ else
+ ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes.u.s;
+ PORT_Assert(hashes.len == sizeof hashes.u.s);
+ ss->ssl3.hs.finishedBytes = sizeof hashes.u.s;
+ rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof hashes.u.s);
+ if (rv != SECSuccess)
+ goto fail; /* err set by AppendHandshake. */
+ rv = ssl3_AppendHandshake(ss, &hashes.u.s, sizeof hashes.u.s);
+ if (rv != SECSuccess)
+ goto fail; /* err set by AppendHandshake. */
+ }
+ rv = ssl3_FlushHandshake(ss, flags);
+ if (rv != SECSuccess) {
+ goto fail; /* error code set by ssl3_FlushHandshake */
+ }
+
+ ssl3_RecordKeyLog(ss);
+
+ return SECSuccess;
+
+fail:
+ return rv;
+}
+
+/* wrap the master secret, and put it into the SID.
+ * Caller holds the Spec read lock.
+ */
+SECStatus
+ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid,
+ ssl3CipherSpec *spec, SSL3KEAType effectiveExchKeyType)
+{
+ PK11SymKey * wrappingKey = NULL;
+ PK11SlotInfo * symKeySlot;
+ void * pwArg = ss->pkcs11PinArg;
+ SECStatus rv = SECFailure;
+ PRBool isServer = ss->sec.isServer;
+ CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
+ symKeySlot = PK11_GetSlotFromKey(spec->master_secret);
+ if (!isServer) {
+ int wrapKeyIndex;
+ int incarnation;
+
+ /* these next few functions are mere accessors and don't fail. */
+ sid->u.ssl3.masterWrapIndex = wrapKeyIndex =
+ PK11_GetCurrentWrapIndex(symKeySlot);
+ PORT_Assert(wrapKeyIndex == 0); /* array has only one entry! */
+
+ sid->u.ssl3.masterWrapSeries = incarnation =
+ PK11_GetSlotSeries(symKeySlot);
+ sid->u.ssl3.masterSlotID = PK11_GetSlotID(symKeySlot);
+ sid->u.ssl3.masterModuleID = PK11_GetModuleID(symKeySlot);
+ sid->u.ssl3.masterValid = PR_TRUE;
+ /* Get the default wrapping key, for wrapping the master secret before
+ * placing it in the SID cache entry. */
+ wrappingKey = PK11_GetWrapKey(symKeySlot, wrapKeyIndex,
+ CKM_INVALID_MECHANISM, incarnation,
+ pwArg);
+ if (wrappingKey) {
+ mechanism = PK11_GetMechanism(wrappingKey); /* can't fail. */
+ } else {
+ int keyLength;
+ /* if the wrappingKey doesn't exist, attempt to create it.
+ * Note: we intentionally ignore errors here. If we cannot
+ * generate a wrapping key, it is not fatal to this SSL connection,
+ * but we will not be able to restart this session.
+ */
+ mechanism = PK11_GetBestWrapMechanism(symKeySlot);
+ keyLength = PK11_GetBestKeyLength(symKeySlot, mechanism);
+ /* Zero length means fixed key length algorithm, or error.
+ * It's ambiguous.
+ */
+ wrappingKey = PK11_KeyGen(symKeySlot, mechanism, NULL,
+ keyLength, pwArg);
+ if (wrappingKey) {
+ PK11_SetWrapKey(symKeySlot, wrapKeyIndex, wrappingKey);
+ }
+ }
+ } else {
+ /* server socket using session cache. */
+ mechanism = PK11_GetBestWrapMechanism(symKeySlot);
+ if (mechanism != CKM_INVALID_MECHANISM) {
+ wrappingKey =
+ getWrappingKey(ss, symKeySlot, effectiveExchKeyType,
+ mechanism, pwArg);
+ if (wrappingKey) {
+ mechanism = PK11_GetMechanism(wrappingKey); /* can't fail. */
+ }
+ }
+ }
+
+ sid->u.ssl3.masterWrapMech = mechanism;
+ PK11_FreeSlot(symKeySlot);
+
+ if (wrappingKey) {
+ SECItem wmsItem;
+
+ wmsItem.data = sid->u.ssl3.keys.wrapped_master_secret;
+ wmsItem.len = sizeof sid->u.ssl3.keys.wrapped_master_secret;
+ rv = PK11_WrapSymKey(mechanism, NULL, wrappingKey,
+ spec->master_secret, &wmsItem);
+ /* rv is examined below. */
+ sid->u.ssl3.keys.wrapped_master_secret_len = wmsItem.len;
+ PK11_FreeSymKey(wrappingKey);
+ }
+ return rv;
+}
+
+/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
+ * ssl3 Finished message from the peer.
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+static SECStatus
+ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
+ const SSL3Hashes *hashes)
+{
+ sslSessionID * sid = ss->sec.ci.sid;
+ SECStatus rv = SECSuccess;
+ PRBool isServer = ss->sec.isServer;
+ PRBool isTLS;
+ SSL3KEAType effectiveExchKeyType;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ SSL_TRC(3, ("%d: SSL3[%d]: handle finished handshake",
+ SSL_GETPID(), ss->fd));
+
+ if (ss->ssl3.hs.ws != wait_finished) {
+ SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_FINISHED);
+ return SECFailure;
+ }
+
+ isTLS = (PRBool)(ss->ssl3.crSpec->version > SSL_LIBRARY_VERSION_3_0);
+ if (isTLS) {
+ TLSFinished tlsFinished;
+
+ if (length != sizeof tlsFinished) {
+ (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_FINISHED);
+ return SECFailure;
+ }
+ rv = ssl3_ComputeTLSFinished(ss->ssl3.crSpec, !isServer,
+ hashes, &tlsFinished);
+ if (!isServer)
+ ss->ssl3.hs.finishedMsgs.tFinished[1] = tlsFinished;
+ else
+ ss->ssl3.hs.finishedMsgs.tFinished[0] = tlsFinished;
+ ss->ssl3.hs.finishedBytes = sizeof tlsFinished;
+ if (rv != SECSuccess ||
+ 0 != NSS_SecureMemcmp(&tlsFinished, b, length)) {
+ (void)SSL3_SendAlert(ss, alert_fatal, decrypt_error);
+ PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+ return SECFailure;
+ }
+ } else {
+ if (length != sizeof(SSL3Finished)) {
+ (void)ssl3_IllegalParameter(ss);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_FINISHED);
+ return SECFailure;
+ }
+
+ if (!isServer)
+ ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes->u.s;
+ else
+ ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes->u.s;
+ PORT_Assert(hashes->len == sizeof hashes->u.s);
+ ss->ssl3.hs.finishedBytes = sizeof hashes->u.s;
+ if (0 != NSS_SecureMemcmp(&hashes->u.s, b, length)) {
+ (void)ssl3_HandshakeFailure(ss);
+ PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+ return SECFailure;
+ }
+ }
+
+ ssl_GetXmitBufLock(ss); /*************************************/
+
+ if ((isServer && !ss->ssl3.hs.isResuming) ||
+ (!isServer && ss->ssl3.hs.isResuming)) {
+ PRInt32 flags = 0;
+
+ /* Send a NewSessionTicket message if the client sent us
+ * either an empty session ticket, or one that did not verify.
+ * (Note that if either of these conditions was met, then the
+ * server has sent a SessionTicket extension in the
+ * ServerHello message.)
+ */
+ if (isServer && !ss->ssl3.hs.isResuming &&
+ ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn)) {
+ rv = ssl3_SendNewSessionTicket(ss);
+ if (rv != SECSuccess) {
+ goto xmit_loser;
+ }
+ }
+
+ rv = ssl3_SendChangeCipherSpecs(ss);
+ if (rv != SECSuccess) {
+ goto xmit_loser; /* err is set. */
+ }
+ /* If this thread is in SSL_SecureSend (trying to write some data)
+ ** then set the ssl_SEND_FLAG_FORCE_INTO_BUFFER flag, so that the
+ ** last two handshake messages (change cipher spec and finished)
+ ** will be sent in the same send/write call as the application data.
+ */
+ if (ss->writerThread == PR_GetCurrentThread()) {
+ flags = ssl_SEND_FLAG_FORCE_INTO_BUFFER;
+ }
+
+ if (!isServer) {
+ if (!ss->firstHsDone) {
+ rv = ssl3_SendNextProto(ss);
+ if (rv != SECSuccess) {
+ goto xmit_loser; /* err code was set. */
+ }
+ }
+ rv = ssl3_SendEncryptedExtensions(ss);
+ if (rv != SECSuccess)
+ goto xmit_loser; /* err code was set. */
+ }
+
+ if (IS_DTLS(ss)) {
+ flags |= ssl_SEND_FLAG_NO_RETRANSMIT;
+ }
+
+ rv = ssl3_SendFinished(ss, flags);
+ if (rv != SECSuccess) {
+ goto xmit_loser; /* err is set. */
+ }
+ }
+
+xmit_loser:
+ ssl_ReleaseXmitBufLock(ss); /*************************************/
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ ss->gs.writeOffset = 0;
+ ss->gs.readOffset = 0;
+
+ if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) {
+ effectiveExchKeyType = kt_rsa;
+ } else {
+ effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType;
+ }
+
+ if (sid->cached == never_cached && !ss->opt.noCache && ss->sec.cache) {
+ /* fill in the sid */
+ sid->u.ssl3.cipherSuite = ss->ssl3.hs.cipher_suite;
+ sid->u.ssl3.compression = ss->ssl3.hs.compression;
+ sid->u.ssl3.policy = ss->ssl3.policy;
+#ifdef NSS_ENABLE_ECC
+ sid->u.ssl3.negotiatedECCurves = ss->ssl3.hs.negotiatedECCurves;
+#endif
+ sid->u.ssl3.exchKeyType = effectiveExchKeyType;
+ sid->version = ss->version;
+ sid->authAlgorithm = ss->sec.authAlgorithm;
+ sid->authKeyBits = ss->sec.authKeyBits;
+ sid->keaType = ss->sec.keaType;
+ sid->keaKeyBits = ss->sec.keaKeyBits;
+ sid->lastAccessTime = sid->creationTime = ssl_Time();
+ sid->expirationTime = sid->creationTime + ssl3_sid_timeout;
+ sid->localCert = CERT_DupCertificate(ss->sec.localCert);
+
+ ssl_GetSpecReadLock(ss); /*************************************/
+
+ /* Copy the master secret (wrapped or unwrapped) into the sid */
+ if (ss->ssl3.crSpec->msItem.len && ss->ssl3.crSpec->msItem.data) {
+ sid->u.ssl3.keys.wrapped_master_secret_len =
+ ss->ssl3.crSpec->msItem.len;
+ memcpy(sid->u.ssl3.keys.wrapped_master_secret,
+ ss->ssl3.crSpec->msItem.data, ss->ssl3.crSpec->msItem.len);
+ sid->u.ssl3.masterValid = PR_TRUE;
+ sid->u.ssl3.keys.msIsWrapped = PR_FALSE;
+ rv = SECSuccess;
+ } else {
+ rv = ssl3_CacheWrappedMasterSecret(ss, ss->sec.ci.sid,
+ ss->ssl3.crSpec,
+ effectiveExchKeyType);
+ sid->u.ssl3.keys.msIsWrapped = PR_TRUE;
+ }
+ ssl_ReleaseSpecReadLock(ss); /*************************************/
+
+ /* If the wrap failed, we don't cache the sid.
+ * The connection continues normally however.
+ */
+ ss->ssl3.hs.cacheSID = rv == SECSuccess;
+ }
+
+ if (ss->ssl3.hs.authCertificatePending) {
+ if (ss->ssl3.hs.restartTarget) {
+ PR_NOT_REACHED("ssl3_HandleFinished: unexpected restartTarget");
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ ss->ssl3.hs.restartTarget = ssl3_FinishHandshake;
+ return SECWouldBlock;
+ }
+
+ rv = ssl3_FinishHandshake(ss);
+ return rv;
+}
+
+SECStatus
+ssl3_FinishHandshake(sslSocket * ss)
+{
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ PORT_Assert( ss->ssl3.hs.restartTarget == NULL );
+
+ /* The first handshake is now completed. */
+ ss->handshake = NULL;
+ ss->firstHsDone = PR_TRUE;
+
+ if (ss->ssl3.hs.cacheSID) {
+ (*ss->sec.cache)(ss->sec.ci.sid);
+ ss->ssl3.hs.cacheSID = PR_FALSE;
+ }
+
+ ss->ssl3.hs.ws = idle_handshake;
+
+ /* Do the handshake callback for sslv3 here, if we cannot false start. */
+ if (ss->handshakeCallback != NULL && !ssl3_CanFalseStart(ss)) {
+ (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
+ }
+
+ return SECSuccess;
+}
+
+/* Called from ssl3_HandleHandshake() when it has gathered a complete ssl3
+ * hanshake message.
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+SECStatus
+ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+ SECStatus rv = SECSuccess;
+ SSL3HandshakeType type = ss->ssl3.hs.msg_type;
+ SSL3Hashes hashes; /* computed hashes are put here. */
+ PRUint8 hdr[4];
+ PRUint8 dtlsData[8];
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ /*
+ * We have to compute the hashes before we update them with the
+ * current message.
+ */
+ ssl_GetSpecReadLock(ss); /************************************/
+ if((type == finished) || (type == certificate_verify)) {
+ SSL3Sender sender = (SSL3Sender)0;
+ ssl3CipherSpec *rSpec = ss->ssl3.prSpec;
+
+ if (type == finished) {
+ sender = ss->sec.isServer ? sender_client : sender_server;
+ rSpec = ss->ssl3.crSpec;
+ }
+ rv = ssl3_ComputeHandshakeHashes(ss, rSpec, &hashes, sender);
+ }
+ ssl_ReleaseSpecReadLock(ss); /************************************/
+ if (rv != SECSuccess) {
+ return rv; /* error code was set by ssl3_ComputeHandshakeHashes*/
+ }
+ SSL_TRC(30,("%d: SSL3[%d]: handle handshake message: %s", SSL_GETPID(),
+ ss->fd, ssl3_DecodeHandshakeType(ss->ssl3.hs.msg_type)));
+
+ hdr[0] = (PRUint8)ss->ssl3.hs.msg_type;
+ hdr[1] = (PRUint8)(length >> 16);
+ hdr[2] = (PRUint8)(length >> 8);
+ hdr[3] = (PRUint8)(length );
+
+ /* Start new handshake hashes when we start a new handshake */
+ if (ss->ssl3.hs.msg_type == client_hello) {
+ rv = ssl3_RestartHandshakeHashes(ss);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ }
+ /* We should not include hello_request and hello_verify_request messages
+ * in the handshake hashes */
+ if ((ss->ssl3.hs.msg_type != hello_request) &&
+ (ss->ssl3.hs.msg_type != hello_verify_request)) {
+ rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char*) hdr, 4);
+ if (rv != SECSuccess) return rv; /* err code already set. */
+
+ /* Extra data to simulate a complete DTLS handshake fragment */
+ if (IS_DTLS(ss)) {
+ /* Sequence number */
+ dtlsData[0] = MSB(ss->ssl3.hs.recvMessageSeq);
+ dtlsData[1] = LSB(ss->ssl3.hs.recvMessageSeq);
+
+ /* Fragment offset */
+ dtlsData[2] = 0;
+ dtlsData[3] = 0;
+ dtlsData[4] = 0;
+
+ /* Fragment length */
+ dtlsData[5] = (PRUint8)(length >> 16);
+ dtlsData[6] = (PRUint8)(length >> 8);
+ dtlsData[7] = (PRUint8)(length );
+
+ rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char*) dtlsData,
+ sizeof(dtlsData));
+ if (rv != SECSuccess) return rv; /* err code already set. */
+ }
+
+ /* The message body */
+ rv = ssl3_UpdateHandshakeHashes(ss, b, length);
+ if (rv != SECSuccess) return rv; /* err code already set. */
+ }
+
+ PORT_SetError(0); /* each message starts with no error. */
+
+ if (ss->ssl3.hs.ws == wait_certificate_status &&
+ ss->ssl3.hs.msg_type != certificate_status) {
+ /* If we negotiated the certificate_status extension then we deferred
+ * certificate validation until we get the CertificateStatus messsage.
+ * But the CertificateStatus message is optional. If the server did
+ * not send it then we need to validate the certificate now. If the
+ * server does send the CertificateStatus message then we will
+ * authenticate the certificate in ssl3_HandleCertificateStatus.
+ */
+ rv = ssl3_AuthCertificate(ss); /* sets ss->ssl3.hs.ws */
+ PORT_Assert(rv != SECWouldBlock);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ }
+
+ switch (ss->ssl3.hs.msg_type) {
+ case hello_request:
+ if (length != 0) {
+ (void)ssl3_DecodeError(ss);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST);
+ return SECFailure;
+ }
+ if (ss->sec.isServer) {
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST);
+ return SECFailure;
+ }
+ rv = ssl3_HandleHelloRequest(ss);
+ break;
+ case client_hello:
+ if (!ss->sec.isServer) {
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO);
+ return SECFailure;
+ }
+ rv = ssl3_HandleClientHello(ss, b, length);
+ break;
+ case server_hello:
+ if (ss->sec.isServer) {
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO);
+ return SECFailure;
+ }
+ rv = ssl3_HandleServerHello(ss, b, length);
+ break;
+ case hello_verify_request:
+ if (!IS_DTLS(ss) || ss->sec.isServer) {
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST);
+ return SECFailure;
+ }
+ rv = dtls_HandleHelloVerifyRequest(ss, b, length);
+ break;
+ case certificate:
+ rv = ssl3_HandleCertificate(ss, b, length);
+ break;
+ case certificate_status:
+ rv = ssl3_HandleCertificateStatus(ss, b, length);
+ break;
+ case server_key_exchange:
+ if (ss->sec.isServer) {
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH);
+ return SECFailure;
+ }
+ rv = ssl3_HandleServerKeyExchange(ss, b, length);
+ break;
+ case certificate_request:
+ if (ss->sec.isServer) {
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST);
+ return SECFailure;
+ }
+ rv = ssl3_HandleCertificateRequest(ss, b, length);
+ break;
+ case server_hello_done:
+ if (length != 0) {
+ (void)ssl3_DecodeError(ss);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_DONE);
+ return SECFailure;
+ }
+ if (ss->sec.isServer) {
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
+ return SECFailure;
+ }
+ rv = ssl3_HandleServerHelloDone(ss);
+ break;
+ case certificate_verify:
+ if (!ss->sec.isServer) {
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY);
+ return SECFailure;
+ }
+ rv = ssl3_HandleCertificateVerify(ss, b, length, &hashes);
+ break;
+ case client_key_exchange:
+ if (!ss->sec.isServer) {
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH);
+ return SECFailure;
+ }
+ rv = ssl3_HandleClientKeyExchange(ss, b, length);
+ break;
+ case new_session_ticket:
+ if (ss->sec.isServer) {
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET);
+ return SECFailure;
+ }
+ rv = ssl3_HandleNewSessionTicket(ss, b, length);
+ break;
+ case finished:
+ rv = ssl3_HandleFinished(ss, b, length, &hashes);
+ break;
+ default:
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNKNOWN_HANDSHAKE);
+ rv = SECFailure;
+ }
+
+ if (IS_DTLS(ss) && (rv != SECFailure)) {
+ /* Increment the expected sequence number */
+ ss->ssl3.hs.recvMessageSeq++;
+ }
+
+ return rv;
+}
+
+/* Called only from ssl3_HandleRecord, for each (deciphered) ssl3 record.
+ * origBuf is the decrypted ssl record content.
+ * Caller must hold the handshake and RecvBuf locks.
+ */
+static SECStatus
+ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
+{
+ /*
+ * There may be a partial handshake message already in the handshake
+ * state. The incoming buffer may contain another portion, or a
+ * complete message or several messages followed by another portion.
+ *
+ * Each message is made contiguous before being passed to the actual
+ * message parser.
+ */
+ sslBuffer *buf = &ss->ssl3.hs.msgState; /* do not lose the original buffer pointer */
+ SECStatus rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ if (buf->buf == NULL) {
+ *buf = *origBuf;
+ }
+ while (buf->len > 0) {
+ if (ss->ssl3.hs.header_bytes < 4) {
+ PRUint8 t;
+ t = *(buf->buf++);
+ buf->len--;
+ if (ss->ssl3.hs.header_bytes++ == 0)
+ ss->ssl3.hs.msg_type = (SSL3HandshakeType)t;
+ else
+ ss->ssl3.hs.msg_len = (ss->ssl3.hs.msg_len << 8) + t;
+ if (ss->ssl3.hs.header_bytes < 4)
+ continue;
+
+#define MAX_HANDSHAKE_MSG_LEN 0x1ffff /* 128k - 1 */
+ if (ss->ssl3.hs.msg_len > MAX_HANDSHAKE_MSG_LEN) {
+ (void)ssl3_DecodeError(ss);
+ PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
+ return SECFailure;
+ }
+#undef MAX_HANDSHAKE_MSG_LEN
+
+ /* If msg_len is zero, be sure we fall through,
+ ** even if buf->len is zero.
+ */
+ if (ss->ssl3.hs.msg_len > 0)
+ continue;
+ }
+
+ /*
+ * Header has been gathered and there is at least one byte of new
+ * data available for this message. If it can be done right out
+ * of the original buffer, then use it from there.
+ */
+ if (ss->ssl3.hs.msg_body.len == 0 && buf->len >= ss->ssl3.hs.msg_len) {
+ /* handle it from input buffer */
+ rv = ssl3_HandleHandshakeMessage(ss, buf->buf, ss->ssl3.hs.msg_len);
+ if (rv == SECFailure) {
+ /* This test wants to fall through on either
+ * SECSuccess or SECWouldBlock.
+ * ssl3_HandleHandshakeMessage MUST set the error code.
+ */
+ return rv;
+ }
+ buf->buf += ss->ssl3.hs.msg_len;
+ buf->len -= ss->ssl3.hs.msg_len;
+ ss->ssl3.hs.msg_len = 0;
+ ss->ssl3.hs.header_bytes = 0;
+ if (rv != SECSuccess) { /* return if SECWouldBlock. */
+ return rv;
+ }
+ } else {
+ /* must be copied to msg_body and dealt with from there */
+ unsigned int bytes;
+
+ PORT_Assert(ss->ssl3.hs.msg_body.len < ss->ssl3.hs.msg_len);
+ bytes = PR_MIN(buf->len, ss->ssl3.hs.msg_len - ss->ssl3.hs.msg_body.len);
+
+ /* Grow the buffer if needed */
+ rv = sslBuffer_Grow(&ss->ssl3.hs.msg_body, ss->ssl3.hs.msg_len);
+ if (rv != SECSuccess) {
+ /* sslBuffer_Grow has set a memory error code. */
+ return SECFailure;
+ }
+
+ PORT_Memcpy(ss->ssl3.hs.msg_body.buf + ss->ssl3.hs.msg_body.len,
+ buf->buf, bytes);
+ ss->ssl3.hs.msg_body.len += bytes;
+ buf->buf += bytes;
+ buf->len -= bytes;
+
+ PORT_Assert(ss->ssl3.hs.msg_body.len <= ss->ssl3.hs.msg_len);
+
+ /* if we have a whole message, do it */
+ if (ss->ssl3.hs.msg_body.len == ss->ssl3.hs.msg_len) {
+ rv = ssl3_HandleHandshakeMessage(
+ ss, ss->ssl3.hs.msg_body.buf, ss->ssl3.hs.msg_len);
+ if (rv == SECFailure) {
+ /* This test wants to fall through on either
+ * SECSuccess or SECWouldBlock.
+ * ssl3_HandleHandshakeMessage MUST set error code.
+ */
+ return rv;
+ }
+ ss->ssl3.hs.msg_body.len = 0;
+ ss->ssl3.hs.msg_len = 0;
+ ss->ssl3.hs.header_bytes = 0;
+ if (rv != SECSuccess) { /* return if SECWouldBlock. */
+ return rv;
+ }
+ } else {
+ PORT_Assert(buf->len == 0);
+ break;
+ }
+ }
+ } /* end loop */
+
+ origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */
+ buf->buf = NULL; /* not a leak. */
+ return SECSuccess;
+}
+
+/* These macros return the given value with the MSB copied to all the other
+ * bits. They use the fact that arithmetic shift shifts-in the sign bit.
+ * However, this is not ensured by the C standard so you may need to replace
+ * them with something else for odd compilers. */
+#define DUPLICATE_MSB_TO_ALL(x) ( (unsigned)( (int)(x) >> (sizeof(int)*8-1) ) )
+#define DUPLICATE_MSB_TO_ALL_8(x) ((unsigned char)(DUPLICATE_MSB_TO_ALL(x)))
+
+/* SECStatusToMask returns, in constant time, a mask value of all ones if
+ * rv == SECSuccess. Otherwise it returns zero. */
+static unsigned int
+SECStatusToMask(SECStatus rv)
+{
+ unsigned int good;
+ /* rv ^ SECSuccess is zero iff rv == SECSuccess. Subtracting one results
+ * in the MSB being set to one iff it was zero before. */
+ good = rv ^ SECSuccess;
+ good--;
+ return DUPLICATE_MSB_TO_ALL(good);
+}
+
+/* ssl_ConstantTimeGE returns 0xff if a>=b and 0x00 otherwise. */
+static unsigned char
+ssl_ConstantTimeGE(unsigned int a, unsigned int b)
+{
+ a -= b;
+ return DUPLICATE_MSB_TO_ALL(~a);
+}
+
+/* ssl_ConstantTimeEQ8 returns 0xff if a==b and 0x00 otherwise. */
+static unsigned char
+ssl_ConstantTimeEQ8(unsigned char a, unsigned char b)
+{
+ unsigned int c = a ^ b;
+ c--;
+ return DUPLICATE_MSB_TO_ALL_8(c);
+}
+
+static SECStatus
+ssl_RemoveSSLv3CBCPadding(sslBuffer *plaintext,
+ unsigned int blockSize,
+ unsigned int macSize)
+{
+ unsigned int paddingLength, good, t;
+ const unsigned int overhead = 1 /* padding length byte */ + macSize;
+
+ /* These lengths are all public so we can test them in non-constant
+ * time. */
+ if (overhead > plaintext->len) {
+ return SECFailure;
+ }
+
+ paddingLength = plaintext->buf[plaintext->len-1];
+ /* SSLv3 padding bytes are random and cannot be checked. */
+ t = plaintext->len;
+ t -= paddingLength+overhead;
+ /* If len >= paddingLength+overhead then the MSB of t is zero. */
+ good = DUPLICATE_MSB_TO_ALL(~t);
+ /* SSLv3 requires that the padding is minimal. */
+ t = blockSize - (paddingLength+1);
+ good &= DUPLICATE_MSB_TO_ALL(~t);
+ plaintext->len -= good & (paddingLength+1);
+ return (good & SECSuccess) | (~good & SECFailure);
+}
+
+static SECStatus
+ssl_RemoveTLSCBCPadding(sslBuffer *plaintext, unsigned int macSize)
+{
+ unsigned int paddingLength, good, t, toCheck, i;
+ const unsigned int overhead = 1 /* padding length byte */ + macSize;
+
+ /* These lengths are all public so we can test them in non-constant
+ * time. */
+ if (overhead > plaintext->len) {
+ return SECFailure;
+ }
+
+ paddingLength = plaintext->buf[plaintext->len-1];
+ t = plaintext->len;
+ t -= paddingLength+overhead;
+ /* If len >= paddingLength+overhead then the MSB of t is zero. */
+ good = DUPLICATE_MSB_TO_ALL(~t);
+
+ /* The padding consists of a length byte at the end of the record and then
+ * that many bytes of padding, all with the same value as the length byte.
+ * Thus, with the length byte included, there are paddingLength+1 bytes of
+ * padding.
+ *
+ * We can't check just |paddingLength+1| bytes because that leaks
+ * decrypted information. Therefore we always have to check the maximum
+ * amount of padding possible. (Again, the length of the record is
+ * public information so we can use it.) */
+ toCheck = 255; /* maximum amount of padding. */
+ if (toCheck > plaintext->len-1) {
+ toCheck = plaintext->len-1;
+ }
+
+ for (i = 0; i < toCheck; i++) {
+ unsigned int t = paddingLength - i;
+ /* If i <= paddingLength then the MSB of t is zero and mask is
+ * 0xff. Otherwise, mask is 0. */
+ unsigned char mask = DUPLICATE_MSB_TO_ALL(~t);
+ unsigned char b = plaintext->buf[plaintext->len-1-i];
+ /* The final |paddingLength+1| bytes should all have the value
+ * |paddingLength|. Therefore the XOR should be zero. */
+ good &= ~(mask&(paddingLength ^ b));
+ }
+
+ /* If any of the final |paddingLength+1| bytes had the wrong value,
+ * one or more of the lower eight bits of |good| will be cleared. We
+ * AND the bottom 8 bits together and duplicate the result to all the
+ * bits. */
+ good &= good >> 4;
+ good &= good >> 2;
+ good &= good >> 1;
+ good <<= sizeof(good)*8-1;
+ good = DUPLICATE_MSB_TO_ALL(good);
+
+ plaintext->len -= good & (paddingLength+1);
+ return (good & SECSuccess) | (~good & SECFailure);
+}
+
+/* On entry:
+ * originalLength >= macSize
+ * macSize <= MAX_MAC_LENGTH
+ * plaintext->len >= macSize
+ */
+static void
+ssl_CBCExtractMAC(sslBuffer *plaintext,
+ unsigned int originalLength,
+ SSL3Opaque* out,
+ unsigned int macSize)
+{
+ unsigned char rotatedMac[MAX_MAC_LENGTH];
+ /* macEnd is the index of |plaintext->buf| just after the end of the
+ * MAC. */
+ unsigned macEnd = plaintext->len;
+ unsigned macStart = macEnd - macSize;
+ /* scanStart contains the number of bytes that we can ignore because
+ * the MAC's position can only vary by 255 bytes. */
+ unsigned scanStart = 0;
+ unsigned i, j, divSpoiler;
+ unsigned char rotateOffset;
+
+ if (originalLength > macSize + 255 + 1)
+ scanStart = originalLength - (macSize + 255 + 1);
+
+ /* divSpoiler contains a multiple of macSize that is used to cause the
+ * modulo operation to be constant time. Without this, the time varies
+ * based on the amount of padding when running on Intel chips at least.
+ *
+ * The aim of right-shifting macSize is so that the compiler doesn't
+ * figure out that it can remove divSpoiler as that would require it
+ * to prove that macSize is always even, which I hope is beyond it. */
+ divSpoiler = macSize >> 1;
+ divSpoiler <<= (sizeof(divSpoiler)-1)*8;
+ rotateOffset = (divSpoiler + macStart - scanStart) % macSize;
+
+ memset(rotatedMac, 0, macSize);
+ for (i = scanStart; i < originalLength;) {
+ for (j = 0; j < macSize && i < originalLength; i++, j++) {
+ unsigned char macStarted = ssl_ConstantTimeGE(i, macStart);
+ unsigned char macEnded = ssl_ConstantTimeGE(i, macEnd);
+ unsigned char b = 0;
+ b = plaintext->buf[i];
+ rotatedMac[j] |= b & macStarted & ~macEnded;
+ }
+ }
+
+ /* Now rotate the MAC. If we knew that the MAC fit into a CPU cache line
+ * we could line-align |rotatedMac| and rotate in place. */
+ memset(out, 0, macSize);
+ for (i = 0; i < macSize; i++) {
+ unsigned char offset =
+ (divSpoiler + macSize - rotateOffset + i) % macSize;
+ for (j = 0; j < macSize; j++) {
+ out[j] |= rotatedMac[i] & ssl_ConstantTimeEQ8(j, offset);
+ }
+ }
+}
+
+/* if cText is non-null, then decipher, check MAC, and decompress the
+ * SSL record from cText->buf (typically gs->inbuf)
+ * into databuf (typically gs->buf), and any previous contents of databuf
+ * is lost. Then handle databuf according to its SSL record type,
+ * unless it's an application record.
+ *
+ * If cText is NULL, then the ciphertext has previously been deciphered and
+ * checked, and is already sitting in databuf. It is processed as an SSL
+ * Handshake message.
+ *
+ * DOES NOT process the decrypted/decompressed application data.
+ * On return, databuf contains the decrypted/decompressed record.
+ *
+ * Called from ssl3_GatherCompleteHandshake
+ * ssl3_RestartHandshakeAfterCertReq
+ *
+ * Caller must hold the RecvBufLock.
+ *
+ * This function aquires and releases the SSL3Handshake Lock, holding the
+ * lock around any calls to functions that handle records other than
+ * Application Data records.
+ */
+SECStatus
+ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
+{
+ const ssl3BulkCipherDef *cipher_def;
+ ssl3CipherSpec * crSpec;
+ SECStatus rv;
+ unsigned int hashBytes = MAX_MAC_LENGTH + 1;
+ PRBool isTLS;
+ SSL3ContentType rType;
+ SSL3Opaque hash[MAX_MAC_LENGTH];
+ SSL3Opaque givenHashBuf[MAX_MAC_LENGTH];
+ SSL3Opaque *givenHash;
+ sslBuffer *plaintext;
+ sslBuffer temp_buf;
+ PRUint64 dtls_seq_num;
+ unsigned int ivLen = 0;
+ unsigned int originalLen = 0;
+ unsigned int good;
+ unsigned int minLength;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+
+ if (!ss->ssl3.initialized) {
+ ssl_GetSSL3HandshakeLock(ss);
+ rv = ssl3_InitState(ss);
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ if (rv != SECSuccess) {
+ return rv; /* ssl3_InitState has set the error code. */
+ }
+ }
+
+ /* check for Token Presence */
+ if (!ssl3_ClientAuthTokenPresent(ss->sec.ci.sid)) {
+ PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL);
+ return SECFailure;
+ }
+
+ /* cText is NULL when we're called from ssl3_RestartHandshakeAfterXXX().
+ * This implies that databuf holds a previously deciphered SSL Handshake
+ * message.
+ */
+ if (cText == NULL) {
+ SSL_DBG(("%d: SSL3[%d]: HandleRecord, resuming handshake",
+ SSL_GETPID(), ss->fd));
+ rType = content_handshake;
+ goto process_it;
+ }
+
+ ssl_GetSpecReadLock(ss); /******************************************/
+
+ crSpec = ss->ssl3.crSpec;
+ cipher_def = crSpec->cipher_def;
+
+ /*
+ * DTLS relevance checks:
+ * Note that this code currently ignores all out-of-epoch packets,
+ * which means we lose some in the case of rehandshake +
+ * loss/reordering. Since DTLS is explicitly unreliable, this
+ * seems like a good tradeoff for implementation effort and is
+ * consistent with the guidance of RFC 6347 Sections 4.1 and 4.2.4.1
+ */
+ if (IS_DTLS(ss)) {
+ DTLSEpoch epoch = (cText->seq_num.high >> 16) & 0xffff;
+
+ if (crSpec->epoch != epoch) {
+ ssl_ReleaseSpecReadLock(ss);
+ SSL_DBG(("%d: SSL3[%d]: HandleRecord, received packet "
+ "from irrelevant epoch %d", SSL_GETPID(), ss->fd, epoch));
+ /* Silently drop the packet */
+ databuf->len = 0; /* Needed to ensure data not left around */
+ return SECSuccess;
+ }
+
+ dtls_seq_num = (((PRUint64)(cText->seq_num.high & 0xffff)) << 32) |
+ ((PRUint64)cText->seq_num.low);
+
+ if (dtls_RecordGetRecvd(&crSpec->recvdRecords, dtls_seq_num) != 0) {
+ ssl_ReleaseSpecReadLock(ss);
+ SSL_DBG(("%d: SSL3[%d]: HandleRecord, rejecting "
+ "potentially replayed packet", SSL_GETPID(), ss->fd));
+ /* Silently drop the packet */
+ databuf->len = 0; /* Needed to ensure data not left around */
+ return SECSuccess;
+ }
+ }
+
+ good = ~0U;
+ minLength = crSpec->mac_size;
+ if (cipher_def->type == type_block) {
+ /* CBC records have a padding length byte at the end. */
+ minLength++;
+ if (crSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
+ /* With >= TLS 1.1, CBC records have an explicit IV. */
+ minLength += cipher_def->iv_size;
+ }
+ } else if (cipher_def->type == type_aead) {
+ minLength = cipher_def->explicit_nonce_size + cipher_def->tag_size;
+ }
+
+ /* We can perform this test in variable time because the record's total
+ * length and the ciphersuite are both public knowledge. */
+ if (cText->buf->len < minLength) {
+ goto decrypt_loser;
+ }
+
+ if (cipher_def->type == type_block &&
+ crSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
+ /* Consume the per-record explicit IV. RFC 4346 Section 6.2.3.2 states
+ * "The receiver decrypts the entire GenericBlockCipher structure and
+ * then discards the first cipher block corresponding to the IV
+ * component." Instead, we decrypt the first cipher block and then
+ * discard it before decrypting the rest.
+ */
+ SSL3Opaque iv[MAX_IV_LENGTH];
+ int decoded;
+
+ ivLen = cipher_def->iv_size;
+ if (ivLen < 8 || ivLen > sizeof(iv)) {
+ ssl_ReleaseSpecReadLock(ss);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ PRINT_BUF(80, (ss, "IV (ciphertext):", cText->buf->buf, ivLen));
+
+ /* The decryption result is garbage, but since we just throw away
+ * the block it doesn't matter. The decryption of the next block
+ * depends only on the ciphertext of the IV block.
+ */
+ rv = crSpec->decode(crSpec->decodeContext, iv, &decoded,
+ sizeof(iv), cText->buf->buf, ivLen);
+
+ good &= SECStatusToMask(rv);
+ }
+
+ /* If we will be decompressing the buffer we need to decrypt somewhere
+ * other than into databuf */
+ if (crSpec->decompressor) {
+ temp_buf.buf = NULL;
+ temp_buf.space = 0;
+ plaintext = &temp_buf;
+ } else {
+ plaintext = databuf;
+ }
+
+ plaintext->len = 0; /* filled in by decode call below. */
+ if (plaintext->space < MAX_FRAGMENT_LENGTH) {
+ rv = sslBuffer_Grow(plaintext, MAX_FRAGMENT_LENGTH + 2048);
+ if (rv != SECSuccess) {
+ ssl_ReleaseSpecReadLock(ss);
+ SSL_DBG(("%d: SSL3[%d]: HandleRecord, tried to get %d bytes",
+ SSL_GETPID(), ss->fd, MAX_FRAGMENT_LENGTH + 2048));
+ /* sslBuffer_Grow has set a memory error code. */
+ /* Perhaps we should send an alert. (but we have no memory!) */
+ return SECFailure;
+ }
+ }
+
+ PRINT_BUF(80, (ss, "ciphertext:", cText->buf->buf + ivLen,
+ cText->buf->len - ivLen));
+
+ isTLS = (PRBool)(crSpec->version > SSL_LIBRARY_VERSION_3_0);
+
+ if (isTLS && cText->buf->len - ivLen > (MAX_FRAGMENT_LENGTH + 2048)) {
+ ssl_ReleaseSpecReadLock(ss);
+ SSL3_SendAlert(ss, alert_fatal, record_overflow);
+ PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
+ return SECFailure;
+ }
+
+ rType = cText->type;
+ if (cipher_def->type == type_aead) {
+ rv = crSpec->aead(
+ ss->sec.isServer ? &crSpec->client : &crSpec->server,
+ PR_TRUE, /* do decrypt */
+ plaintext->buf, /* out */
+ (int*) &plaintext->len, /* outlen */
+ plaintext->space, /* maxout */
+ cText->buf->buf, /* in */
+ cText->buf->len, /* inlen */
+ rType, /* record type */
+ cText->version,
+ IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num);
+ if (rv != SECSuccess) {
+ good = 0;
+ }
+ } else {
+ if (cipher_def->type == type_block &&
+ ((cText->buf->len - ivLen) % cipher_def->block_size) != 0) {
+ goto decrypt_loser;
+ }
+
+ /* decrypt from cText buf to plaintext. */
+ rv = crSpec->decode(
+ crSpec->decodeContext, plaintext->buf, (int *)&plaintext->len,
+ plaintext->space, cText->buf->buf + ivLen, cText->buf->len - ivLen);
+ if (rv != SECSuccess) {
+ goto decrypt_loser;
+ }
+
+ PRINT_BUF(80, (ss, "cleartext:", plaintext->buf, plaintext->len));
+
+ originalLen = plaintext->len;
+
+ /* If it's a block cipher, check and strip the padding. */
+ if (cipher_def->type == type_block) {
+ const unsigned int blockSize = cipher_def->block_size;
+ const unsigned int macSize = crSpec->mac_size;
+
+ if (crSpec->version <= SSL_LIBRARY_VERSION_3_0) {
+ good &= SECStatusToMask(ssl_RemoveSSLv3CBCPadding(
+ plaintext, blockSize, macSize));
+ } else {
+ good &= SECStatusToMask(ssl_RemoveTLSCBCPadding(
+ plaintext, macSize));
+ }
+ }
+
+ /* compute the MAC */
+ if (cipher_def->type == type_block) {
+ rv = ssl3_ComputeRecordMACConstantTime(
+ crSpec, (PRBool)(!ss->sec.isServer),
+ IS_DTLS(ss), rType, cText->version,
+ IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
+ plaintext->buf, plaintext->len, originalLen,
+ hash, &hashBytes);
+
+ ssl_CBCExtractMAC(plaintext, originalLen, givenHashBuf,
+ crSpec->mac_size);
+ givenHash = givenHashBuf;
+
+ /* plaintext->len will always have enough space to remove the MAC
+ * because in ssl_Remove{SSLv3|TLS}CBCPadding we only adjust
+ * plaintext->len if the result has enough space for the MAC and we
+ * tested the unadjusted size against minLength, above. */
+ plaintext->len -= crSpec->mac_size;
+ } else {
+ /* This is safe because we checked the minLength above. */
+ plaintext->len -= crSpec->mac_size;
+
+ rv = ssl3_ComputeRecordMAC(
+ crSpec, (PRBool)(!ss->sec.isServer),
+ IS_DTLS(ss), rType, cText->version,
+ IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
+ plaintext->buf, plaintext->len,
+ hash, &hashBytes);
+
+ /* We can read the MAC directly from the record because its location
+ * is public when a stream cipher is used. */
+ givenHash = plaintext->buf + plaintext->len;
+ }
+
+ good &= SECStatusToMask(rv);
+
+ if (hashBytes != (unsigned)crSpec->mac_size ||
+ NSS_SecureMemcmp(givenHash, hash, crSpec->mac_size) != 0) {
+ /* We're allowed to leak whether or not the MAC check was correct */
+ good = 0;
+ }
+ }
+
+ if (good == 0) {
+decrypt_loser:
+ /* must not hold spec lock when calling SSL3_SendAlert. */
+ ssl_ReleaseSpecReadLock(ss);
+
+ SSL_DBG(("%d: SSL3[%d]: decryption failed", SSL_GETPID(), ss->fd));
+
+ if (!IS_DTLS(ss)) {
+ SSL3_SendAlert(ss, alert_fatal, bad_record_mac);
+ /* always log mac error, in case attacker can read server logs. */
+ PORT_SetError(SSL_ERROR_BAD_MAC_READ);
+ return SECFailure;
+ } else {
+ /* Silently drop the packet */
+ databuf->len = 0; /* Needed to ensure data not left around */
+ return SECSuccess;
+ }
+ }
+
+ if (!IS_DTLS(ss)) {
+ ssl3_BumpSequenceNumber(&crSpec->read_seq_num);
+ } else {
+ dtls_RecordSetRecvd(&crSpec->recvdRecords, dtls_seq_num);
+ }
+
+ ssl_ReleaseSpecReadLock(ss); /*****************************************/
+
+ /*
+ * The decrypted data is now in plaintext.
+ */
+
+ /* possibly decompress the record. If we aren't using compression then
+ * plaintext == databuf and so the uncompressed data is already in
+ * databuf. */
+ if (crSpec->decompressor) {
+ if (databuf->space < plaintext->len + SSL3_COMPRESSION_MAX_EXPANSION) {
+ rv = sslBuffer_Grow(
+ databuf, plaintext->len + SSL3_COMPRESSION_MAX_EXPANSION);
+ if (rv != SECSuccess) {
+ SSL_DBG(("%d: SSL3[%d]: HandleRecord, tried to get %d bytes",
+ SSL_GETPID(), ss->fd,
+ plaintext->len + SSL3_COMPRESSION_MAX_EXPANSION));
+ /* sslBuffer_Grow has set a memory error code. */
+ /* Perhaps we should send an alert. (but we have no memory!) */
+ PORT_Free(plaintext->buf);
+ return SECFailure;
+ }
+ }
+
+ rv = crSpec->decompressor(crSpec->decompressContext,
+ databuf->buf,
+ (int*) &databuf->len,
+ databuf->space,
+ plaintext->buf,
+ plaintext->len);
+
+ if (rv != SECSuccess) {
+ int err = ssl_MapLowLevelError(SSL_ERROR_DECOMPRESSION_FAILURE);
+ SSL3_SendAlert(ss, alert_fatal,
+ isTLS ? decompression_failure : bad_record_mac);
+
+ /* There appears to be a bug with (at least) Apache + OpenSSL where
+ * resumed SSLv3 connections don't actually use compression. See
+ * comments 93-95 of
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=275744
+ *
+ * So, if we get a decompression error, and the record appears to
+ * be already uncompressed, then we return a more specific error
+ * code to hopefully save somebody some debugging time in the
+ * future.
+ */
+ if (plaintext->len >= 4) {
+ unsigned int len = ((unsigned int) plaintext->buf[1] << 16) |
+ ((unsigned int) plaintext->buf[2] << 8) |
+ (unsigned int) plaintext->buf[3];
+ if (len == plaintext->len - 4) {
+ /* This appears to be uncompressed already */
+ err = SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD;
+ }
+ }
+
+ PORT_Free(plaintext->buf);
+ PORT_SetError(err);
+ return SECFailure;
+ }
+
+ PORT_Free(plaintext->buf);
+ }
+
+ /*
+ ** Having completed the decompression, check the length again.
+ */
+ if (isTLS && databuf->len > (MAX_FRAGMENT_LENGTH + 1024)) {
+ SSL3_SendAlert(ss, alert_fatal, record_overflow);
+ PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
+ return SECFailure;
+ }
+
+ /* Application data records are processed by the caller of this
+ ** function, not by this function.
+ */
+ if (rType == content_application_data) {
+ if (ss->firstHsDone)
+ return SECSuccess;
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA);
+ return SECFailure;
+ }
+
+ /* It's a record that must be handled by ssl itself, not the application.
+ */
+process_it:
+ /* XXX Get the xmit lock here. Odds are very high that we'll be xmiting
+ * data ang getting the xmit lock here prevents deadlocks.
+ */
+ ssl_GetSSL3HandshakeLock(ss);
+
+ /* All the functions called in this switch MUST set error code if
+ ** they return SECFailure or SECWouldBlock.
+ */
+ switch (rType) {
+ case content_change_cipher_spec:
+ rv = ssl3_HandleChangeCipherSpecs(ss, databuf);
+ break;
+ case content_alert:
+ rv = ssl3_HandleAlert(ss, databuf);
+ break;
+ case content_handshake:
+ if (!IS_DTLS(ss)) {
+ rv = ssl3_HandleHandshake(ss, databuf);
+ } else {
+ rv = dtls_HandleHandshake(ss, databuf);
+ }
+ break;
+ /*
+ case content_application_data is handled before this switch
+ */
+ default:
+ SSL_DBG(("%d: SSL3[%d]: bogus content type=%d",
+ SSL_GETPID(), ss->fd, cText->type));
+ /* XXX Send an alert ??? */
+ PORT_SetError(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE);
+ rv = SECFailure;
+ break;
+ }
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ return rv;
+
+}
+
+/*
+ * Initialization functions
+ */
+
+/* Called from ssl3_InitState, immediately below. */
+/* Caller must hold the SpecWriteLock. */
+static void
+ssl3_InitCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
+{
+ spec->cipher_def = &bulk_cipher_defs[cipher_null];
+ PORT_Assert(spec->cipher_def->cipher == cipher_null);
+ spec->mac_def = &mac_defs[mac_null];
+ PORT_Assert(spec->mac_def->mac == mac_null);
+ spec->encode = Null_Cipher;
+ spec->decode = Null_Cipher;
+ spec->destroy = NULL;
+ spec->compressor = NULL;
+ spec->decompressor = NULL;
+ spec->destroyCompressContext = NULL;
+ spec->destroyDecompressContext = NULL;
+ spec->mac_size = 0;
+ spec->master_secret = NULL;
+ spec->bypassCiphers = PR_FALSE;
+
+ spec->msItem.data = NULL;
+ spec->msItem.len = 0;
+
+ spec->client.write_key = NULL;
+ spec->client.write_mac_key = NULL;
+ spec->client.write_mac_context = NULL;
+
+ spec->server.write_key = NULL;
+ spec->server.write_mac_key = NULL;
+ spec->server.write_mac_context = NULL;
+
+ spec->write_seq_num.high = 0;
+ spec->write_seq_num.low = 0;
+
+ spec->read_seq_num.high = 0;
+ spec->read_seq_num.low = 0;
+
+ spec->epoch = 0;
+ dtls_InitRecvdRecords(&spec->recvdRecords);
+
+ spec->version = ss->vrange.max;
+}
+
+/* Called from: ssl3_SendRecord
+** ssl3_StartHandshakeHash() <- ssl2_BeginClientHandshake()
+** ssl3_SendClientHello()
+** ssl3_HandleV2ClientHello()
+** ssl3_HandleRecord()
+**
+** This function should perhaps acquire and release the SpecWriteLock.
+**
+**
+*/
+static SECStatus
+ssl3_InitState(sslSocket *ss)
+{
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ if (ss->ssl3.initialized)
+ return SECSuccess; /* Function should be idempotent */
+
+ ss->ssl3.policy = SSL_ALLOWED;
+
+ ssl_GetSpecWriteLock(ss);
+ ss->ssl3.crSpec = ss->ssl3.cwSpec = &ss->ssl3.specs[0];
+ ss->ssl3.prSpec = ss->ssl3.pwSpec = &ss->ssl3.specs[1];
+ ss->ssl3.hs.sendingSCSV = PR_FALSE;
+ ssl3_InitCipherSpec(ss, ss->ssl3.crSpec);
+ ssl3_InitCipherSpec(ss, ss->ssl3.prSpec);
+
+ ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello;
+#ifdef NSS_ENABLE_ECC
+ ss->ssl3.hs.negotiatedECCurves = ssl3_GetSupportedECCurveMask(ss);
+#endif
+ ssl_ReleaseSpecWriteLock(ss);
+
+ PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData));
+
+ if (IS_DTLS(ss)) {
+ ss->ssl3.hs.sendMessageSeq = 0;
+ ss->ssl3.hs.recvMessageSeq = 0;
+ ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS;
+ ss->ssl3.hs.rtRetries = 0;
+ ss->ssl3.hs.recvdHighWater = -1;
+ PR_INIT_CLIST(&ss->ssl3.hs.lastMessageFlight);
+ dtls_SetMTU(ss, 0); /* Set the MTU to the highest plateau */
+ }
+
+ PORT_Assert(!ss->ssl3.hs.messages.buf && !ss->ssl3.hs.messages.space);
+ ss->ssl3.hs.messages.buf = NULL;
+ ss->ssl3.hs.messages.space = 0;
+
+ ss->ssl3.initialized = PR_TRUE;
+ return SECSuccess;
+}
+
+/* Returns a reference counted object that contains a key pair.
+ * Or NULL on failure. Initial ref count is 1.
+ * Uses the keys in the pair as input.
+ */
+ssl3KeyPair *
+ssl3_NewKeyPair( SECKEYPrivateKey * privKey, SECKEYPublicKey * pubKey)
+{
+ ssl3KeyPair * pair;
+
+ if (!privKey || !pubKey) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return NULL;
+ }
+ pair = PORT_ZNew(ssl3KeyPair);
+ if (!pair)
+ return NULL; /* error code is set. */
+ pair->refCount = 1;
+ pair->privKey = privKey;
+ pair->pubKey = pubKey;
+ return pair; /* success */
+}
+
+ssl3KeyPair *
+ssl3_GetKeyPairRef(ssl3KeyPair * keyPair)
+{
+ PR_ATOMIC_INCREMENT(&keyPair->refCount);
+ return keyPair;
+}
+
+void
+ssl3_FreeKeyPair(ssl3KeyPair * keyPair)
+{
+ PRInt32 newCount = PR_ATOMIC_DECREMENT(&keyPair->refCount);
+ if (!newCount) {
+ if (keyPair->privKey)
+ SECKEY_DestroyPrivateKey(keyPair->privKey);
+ if (keyPair->pubKey)
+ SECKEY_DestroyPublicKey( keyPair->pubKey);
+ PORT_Free(keyPair);
+ }
+}
+
+
+
+/*
+ * Creates the public and private RSA keys for SSL Step down.
+ * Called from SSL_ConfigSecureServer in sslsecur.c
+ */
+SECStatus
+ssl3_CreateRSAStepDownKeys(sslSocket *ss)
+{
+ SECStatus rv = SECSuccess;
+ SECKEYPrivateKey * privKey; /* RSA step down key */
+ SECKEYPublicKey * pubKey; /* RSA step down key */
+
+ if (ss->stepDownKeyPair)
+ ssl3_FreeKeyPair(ss->stepDownKeyPair);
+ ss->stepDownKeyPair = NULL;
+#ifndef HACKED_EXPORT_SERVER
+ /* Sigh, should have a get key strength call for private keys */
+ if (PK11_GetPrivateModulusLen(ss->serverCerts[kt_rsa].SERVERKEY) >
+ EXPORT_RSA_KEY_LENGTH) {
+ /* need to ask for the key size in bits */
+ privKey = SECKEY_CreateRSAPrivateKey(EXPORT_RSA_KEY_LENGTH * BPB,
+ &pubKey, NULL);
+ if (!privKey || !pubKey ||
+ !(ss->stepDownKeyPair = ssl3_NewKeyPair(privKey, pubKey))) {
+ ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
+ rv = SECFailure;
+ }
+ }
+#endif
+ return rv;
+}
+
+
+/* record the export policy for this cipher suite */
+SECStatus
+ssl3_SetPolicy(ssl3CipherSuite which, int policy)
+{
+ ssl3CipherSuiteCfg *suite;
+
+ suite = ssl_LookupCipherSuiteCfg(which, cipherSuites);
+ if (suite == NULL) {
+ return SECFailure; /* err code was set by ssl_LookupCipherSuiteCfg */
+ }
+ suite->policy = policy;
+
+ return SECSuccess;
+}
+
+SECStatus
+ssl3_GetPolicy(ssl3CipherSuite which, PRInt32 *oPolicy)
+{
+ ssl3CipherSuiteCfg *suite;
+ PRInt32 policy;
+ SECStatus rv;
+
+ suite = ssl_LookupCipherSuiteCfg(which, cipherSuites);
+ if (suite) {
+ policy = suite->policy;
+ rv = SECSuccess;
+ } else {
+ policy = SSL_NOT_ALLOWED;
+ rv = SECFailure; /* err code was set by Lookup. */
+ }
+ *oPolicy = policy;
+ return rv;
+}
+
+/* record the user preference for this suite */
+SECStatus
+ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool enabled)
+{
+ ssl3CipherSuiteCfg *suite;
+
+ suite = ssl_LookupCipherSuiteCfg(which, cipherSuites);
+ if (suite == NULL) {
+ return SECFailure; /* err code was set by ssl_LookupCipherSuiteCfg */
+ }
+ suite->enabled = enabled;
+ return SECSuccess;
+}
+
+/* return the user preference for this suite */
+SECStatus
+ssl3_CipherPrefGetDefault(ssl3CipherSuite which, PRBool *enabled)
+{
+ ssl3CipherSuiteCfg *suite;
+ PRBool pref;
+ SECStatus rv;
+
+ suite = ssl_LookupCipherSuiteCfg(which, cipherSuites);
+ if (suite) {
+ pref = suite->enabled;
+ rv = SECSuccess;
+ } else {
+ pref = SSL_NOT_ALLOWED;
+ rv = SECFailure; /* err code was set by Lookup. */
+ }
+ *enabled = pref;
+ return rv;
+}
+
+SECStatus
+ssl3_CipherPrefSet(sslSocket *ss, ssl3CipherSuite which, PRBool enabled)
+{
+ ssl3CipherSuiteCfg *suite;
+
+ suite = ssl_LookupCipherSuiteCfg(which, ss->cipherSuites);
+ if (suite == NULL) {
+ return SECFailure; /* err code was set by ssl_LookupCipherSuiteCfg */
+ }
+ suite->enabled = enabled;
+ return SECSuccess;
+}
+
+SECStatus
+ssl3_CipherPrefGet(sslSocket *ss, ssl3CipherSuite which, PRBool *enabled)
+{
+ ssl3CipherSuiteCfg *suite;
+ PRBool pref;
+ SECStatus rv;
+
+ suite = ssl_LookupCipherSuiteCfg(which, ss->cipherSuites);
+ if (suite) {
+ pref = suite->enabled;
+ rv = SECSuccess;
+ } else {
+ pref = SSL_NOT_ALLOWED;
+ rv = SECFailure; /* err code was set by Lookup. */
+ }
+ *enabled = pref;
+ return rv;
+}
+
+/* copy global default policy into socket. */
+void
+ssl3_InitSocketPolicy(sslSocket *ss)
+{
+ PORT_Memcpy(ss->cipherSuites, cipherSuites, sizeof cipherSuites);
+}
+
+SECStatus
+ssl3_GetTLSUniqueChannelBinding(sslSocket *ss,
+ unsigned char *out,
+ unsigned int *outLen,
+ unsigned int outLenMax) {
+ PRBool isTLS;
+ int index = 0;
+ unsigned int len;
+ SECStatus rv = SECFailure;
+
+ *outLen = 0;
+
+ ssl_GetSSL3HandshakeLock(ss);
+
+ ssl_GetSpecReadLock(ss);
+ isTLS = (PRBool)(ss->ssl3.cwSpec->version > SSL_LIBRARY_VERSION_3_0);
+ ssl_ReleaseSpecReadLock(ss);
+
+ /* The tls-unique channel binding is the first Finished structure in the
+ * handshake. In the case of a resumption, that's the server's Finished.
+ * Otherwise, it's the client's Finished. */
+ len = ss->ssl3.hs.finishedBytes;
+
+ /* Sending or receiving a Finished message will set finishedBytes to a
+ * non-zero value. */
+ if (len == 0) {
+ PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED);
+ goto loser;
+ }
+
+ /* If we are in the middle of a renegotiation then the channel binding
+ * value is poorly defined and depends on the direction that it will be
+ * used on. Therefore we simply return an error in this case. */
+ if (ss->firstHsDone && ss->ssl3.hs.ws != idle_handshake) {
+ PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED);
+ goto loser;
+ }
+
+ /* If resuming, then we want the second Finished value in the array, which
+ * is the server's */
+ if (ss->ssl3.hs.isResuming)
+ index = 1;
+
+ *outLen = len;
+ if (outLenMax < len) {
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ goto loser;
+ }
+
+ if (isTLS) {
+ memcpy(out, &ss->ssl3.hs.finishedMsgs.tFinished[index], len);
+ } else {
+ memcpy(out, &ss->ssl3.hs.finishedMsgs.sFinished[index], len);
+ }
+
+ rv = SECSuccess;
+
+loser:
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ return rv;
+}
+
+/* ssl3_config_match_init must have already been called by
+ * the caller of this function.
+ */
+SECStatus
+ssl3_ConstructV2CipherSpecsHack(sslSocket *ss, unsigned char *cs, int *size)
+{
+ int i, count = 0;
+
+ PORT_Assert(ss != 0);
+ if (!ss) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ if (SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
+ *size = 0;
+ return SECSuccess;
+ }
+ if (cs == NULL) {
+ *size = count_cipher_suites(ss, SSL_ALLOWED, PR_TRUE);
+ return SECSuccess;
+ }
+
+ /* ssl3_config_match_init was called by the caller of this function. */
+ for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
+ ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
+ if (config_match(suite, SSL_ALLOWED, PR_TRUE)) {
+ if (cs != NULL) {
+ *cs++ = 0x00;
+ *cs++ = (suite->cipher_suite >> 8) & 0xFF;
+ *cs++ = suite->cipher_suite & 0xFF;
+ }
+ count++;
+ }
+ }
+ *size = count;
+ return SECSuccess;
+}
+
+/*
+** If ssl3 socket has completed the first handshake, and is in idle state,
+** then start a new handshake.
+** If flushCache is true, the SID cache will be flushed first, forcing a
+** "Full" handshake (not a session restart handshake), to be done.
+**
+** called from SSL_RedoHandshake(), which already holds the handshake locks.
+*/
+SECStatus
+ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache)
+{
+ sslSessionID * sid = ss->sec.ci.sid;
+ SECStatus rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ if (!ss->firstHsDone ||
+ ((ss->version >= SSL_LIBRARY_VERSION_3_0) &&
+ ss->ssl3.initialized &&
+ (ss->ssl3.hs.ws != idle_handshake))) {
+ PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED);
+ return SECFailure;
+ }
+
+ if (IS_DTLS(ss)) {
+ dtls_RehandshakeCleanup(ss);
+ }
+
+ if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
+ PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED);
+ return SECFailure;
+ }
+ if (sid && flushCache) {
+ if (ss->sec.uncache)
+ ss->sec.uncache(sid); /* remove it from whichever cache it's in. */
+ ssl_FreeSID(sid); /* dec ref count and free if zero. */
+ ss->sec.ci.sid = NULL;
+ }
+
+ ssl_GetXmitBufLock(ss); /**************************************/
+
+ /* start off a new handshake. */
+ rv = (ss->sec.isServer) ? ssl3_SendHelloRequest(ss)
+ : ssl3_SendClientHello(ss, PR_FALSE);
+
+ ssl_ReleaseXmitBufLock(ss); /**************************************/
+ return rv;
+}
+
+/* Called from ssl_DestroySocketContents() in sslsock.c */
+void
+ssl3_DestroySSL3Info(sslSocket *ss)
+{
+
+ if (ss->ssl3.clientCertificate != NULL)
+ CERT_DestroyCertificate(ss->ssl3.clientCertificate);
+
+ if (ss->ssl3.clientPrivateKey != NULL)
+ SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ if (ss->ssl3.platformClientKey)
+ ssl_FreePlatformKey(ss->ssl3.platformClientKey);
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
+
+ if (ss->ssl3.channelID)
+ SECKEY_DestroyPrivateKey(ss->ssl3.channelID);
+ if (ss->ssl3.channelIDPub)
+ SECKEY_DestroyPublicKey(ss->ssl3.channelIDPub);
+
+ if (ss->ssl3.peerCertArena != NULL)
+ ssl3_CleanupPeerCerts(ss);
+
+ if (ss->ssl3.clientCertChain != NULL) {
+ CERT_DestroyCertificateList(ss->ssl3.clientCertChain);
+ ss->ssl3.clientCertChain = NULL;
+ }
+
+ /* clean up handshake */
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11) {
+ if (ss->ssl3.hs.hashType == handshake_hash_combo) {
+ SHA1_DestroyContext((SHA1Context *)ss->ssl3.hs.sha_cx, PR_FALSE);
+ MD5_DestroyContext((MD5Context *)ss->ssl3.hs.md5_cx, PR_FALSE);
+ } else if (ss->ssl3.hs.hashType == handshake_hash_single) {
+ ss->ssl3.hs.sha_obj->destroy(ss->ssl3.hs.sha_cx, PR_FALSE);
+ }
+ }
+#endif
+ if (ss->ssl3.hs.md5) {
+ PK11_DestroyContext(ss->ssl3.hs.md5,PR_TRUE);
+ }
+ if (ss->ssl3.hs.sha) {
+ PK11_DestroyContext(ss->ssl3.hs.sha,PR_TRUE);
+ }
+ if (ss->ssl3.hs.clientSigAndHash) {
+ PORT_Free(ss->ssl3.hs.clientSigAndHash);
+ }
+ if (ss->ssl3.hs.messages.buf) {
+ PORT_Free(ss->ssl3.hs.messages.buf);
+ ss->ssl3.hs.messages.buf = NULL;
+ ss->ssl3.hs.messages.len = 0;
+ ss->ssl3.hs.messages.space = 0;
+ }
+
+ /* free the SSL3Buffer (msg_body) */
+ PORT_Free(ss->ssl3.hs.msg_body.buf);
+
+ /* free up the CipherSpecs */
+ ssl3_DestroyCipherSpec(&ss->ssl3.specs[0], PR_TRUE/*freeSrvName*/);
+ ssl3_DestroyCipherSpec(&ss->ssl3.specs[1], PR_TRUE/*freeSrvName*/);
+
+ /* Destroy the DTLS data */
+ if (IS_DTLS(ss)) {
+ dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight);
+ if (ss->ssl3.hs.recvdFragments.buf) {
+ PORT_Free(ss->ssl3.hs.recvdFragments.buf);
+ }
+ }
+
+ ss->ssl3.initialized = PR_FALSE;
+
+ SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
+}
+
+/* End of ssl3con.c */
diff --git a/chromium/net/third_party/nss/ssl/ssl3ecc.c b/chromium/net/third_party/nss/ssl/ssl3ecc.c
new file mode 100644
index 00000000000..a3638e75f1c
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/ssl3ecc.c
@@ -0,0 +1,1280 @@
+/*
+ * SSL3 Protocol
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* ECC code moved here from ssl3con.c */
+
+#include "nss.h"
+#include "cert.h"
+#include "ssl.h"
+#include "cryptohi.h" /* for DSAU_ stuff */
+#include "keyhi.h"
+#include "secder.h"
+#include "secitem.h"
+
+#include "sslimpl.h"
+#include "sslproto.h"
+#include "sslerr.h"
+#include "prtime.h"
+#include "prinrval.h"
+#include "prerror.h"
+#include "pratom.h"
+#include "prthread.h"
+#include "prinit.h"
+
+#include "pk11func.h"
+#include "secmod.h"
+
+#include <stdio.h>
+
+/* This is a bodge to allow this code to be compiled against older NSS headers
+ * that don't contain the TLS 1.2 changes. */
+#ifndef CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256
+#define CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 (CKM_NSS + 24)
+#endif
+
+#ifdef NSS_ENABLE_ECC
+
+/*
+ * In NSS 3.13.2 the definition of the EC_POINT_FORM_UNCOMPRESSED macro
+ * was moved from the internal header ec.h to the public header blapit.h.
+ * Define the macro here when compiling against older system NSS headers.
+ */
+#ifndef EC_POINT_FORM_UNCOMPRESSED
+#define EC_POINT_FORM_UNCOMPRESSED 0x04
+#endif
+
+#ifndef PK11_SETATTRS
+#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
+ (x)->pValue=(v); (x)->ulValueLen = (l);
+#endif
+
+#define SSL_GET_SERVER_PUBLIC_KEY(sock, type) \
+ (ss->serverCerts[type].serverKeyPair ? \
+ ss->serverCerts[type].serverKeyPair->pubKey : NULL)
+
+#define SSL_IS_CURVE_NEGOTIATED(curvemsk, curveName) \
+ ((curveName > ec_noName) && \
+ (curveName < ec_pastLastName) && \
+ ((1UL << curveName) & curvemsk) != 0)
+
+
+
+static SECStatus ssl3_CreateECDHEphemeralKeys(sslSocket *ss, ECName ec_curve);
+
+#define supportedCurve(x) (((x) > ec_noName) && ((x) < ec_pastLastName))
+
+/* Table containing OID tags for elliptic curves named in the
+ * ECC-TLS IETF draft.
+ */
+static const SECOidTag ecName2OIDTag[] = {
+ 0,
+ SEC_OID_SECG_EC_SECT163K1, /* 1 */
+ SEC_OID_SECG_EC_SECT163R1, /* 2 */
+ SEC_OID_SECG_EC_SECT163R2, /* 3 */
+ SEC_OID_SECG_EC_SECT193R1, /* 4 */
+ SEC_OID_SECG_EC_SECT193R2, /* 5 */
+ SEC_OID_SECG_EC_SECT233K1, /* 6 */
+ SEC_OID_SECG_EC_SECT233R1, /* 7 */
+ SEC_OID_SECG_EC_SECT239K1, /* 8 */
+ SEC_OID_SECG_EC_SECT283K1, /* 9 */
+ SEC_OID_SECG_EC_SECT283R1, /* 10 */
+ SEC_OID_SECG_EC_SECT409K1, /* 11 */
+ SEC_OID_SECG_EC_SECT409R1, /* 12 */
+ SEC_OID_SECG_EC_SECT571K1, /* 13 */
+ SEC_OID_SECG_EC_SECT571R1, /* 14 */
+ SEC_OID_SECG_EC_SECP160K1, /* 15 */
+ SEC_OID_SECG_EC_SECP160R1, /* 16 */
+ SEC_OID_SECG_EC_SECP160R2, /* 17 */
+ SEC_OID_SECG_EC_SECP192K1, /* 18 */
+ SEC_OID_SECG_EC_SECP192R1, /* 19 */
+ SEC_OID_SECG_EC_SECP224K1, /* 20 */
+ SEC_OID_SECG_EC_SECP224R1, /* 21 */
+ SEC_OID_SECG_EC_SECP256K1, /* 22 */
+ SEC_OID_SECG_EC_SECP256R1, /* 23 */
+ SEC_OID_SECG_EC_SECP384R1, /* 24 */
+ SEC_OID_SECG_EC_SECP521R1, /* 25 */
+};
+
+static const PRUint16 curve2bits[] = {
+ 0, /* ec_noName = 0, */
+ 163, /* ec_sect163k1 = 1, */
+ 163, /* ec_sect163r1 = 2, */
+ 163, /* ec_sect163r2 = 3, */
+ 193, /* ec_sect193r1 = 4, */
+ 193, /* ec_sect193r2 = 5, */
+ 233, /* ec_sect233k1 = 6, */
+ 233, /* ec_sect233r1 = 7, */
+ 239, /* ec_sect239k1 = 8, */
+ 283, /* ec_sect283k1 = 9, */
+ 283, /* ec_sect283r1 = 10, */
+ 409, /* ec_sect409k1 = 11, */
+ 409, /* ec_sect409r1 = 12, */
+ 571, /* ec_sect571k1 = 13, */
+ 571, /* ec_sect571r1 = 14, */
+ 160, /* ec_secp160k1 = 15, */
+ 160, /* ec_secp160r1 = 16, */
+ 160, /* ec_secp160r2 = 17, */
+ 192, /* ec_secp192k1 = 18, */
+ 192, /* ec_secp192r1 = 19, */
+ 224, /* ec_secp224k1 = 20, */
+ 224, /* ec_secp224r1 = 21, */
+ 256, /* ec_secp256k1 = 22, */
+ 256, /* ec_secp256r1 = 23, */
+ 384, /* ec_secp384r1 = 24, */
+ 521, /* ec_secp521r1 = 25, */
+ 65535 /* ec_pastLastName */
+};
+
+typedef struct Bits2CurveStr {
+ PRUint16 bits;
+ ECName curve;
+} Bits2Curve;
+
+static const Bits2Curve bits2curve [] = {
+ { 192, ec_secp192r1 /* = 19, fast */ },
+ { 160, ec_secp160r2 /* = 17, fast */ },
+ { 160, ec_secp160k1 /* = 15, */ },
+ { 160, ec_secp160r1 /* = 16, */ },
+ { 163, ec_sect163k1 /* = 1, */ },
+ { 163, ec_sect163r1 /* = 2, */ },
+ { 163, ec_sect163r2 /* = 3, */ },
+ { 192, ec_secp192k1 /* = 18, */ },
+ { 193, ec_sect193r1 /* = 4, */ },
+ { 193, ec_sect193r2 /* = 5, */ },
+ { 224, ec_secp224r1 /* = 21, fast */ },
+ { 224, ec_secp224k1 /* = 20, */ },
+ { 233, ec_sect233k1 /* = 6, */ },
+ { 233, ec_sect233r1 /* = 7, */ },
+ { 239, ec_sect239k1 /* = 8, */ },
+ { 256, ec_secp256r1 /* = 23, fast */ },
+ { 256, ec_secp256k1 /* = 22, */ },
+ { 283, ec_sect283k1 /* = 9, */ },
+ { 283, ec_sect283r1 /* = 10, */ },
+ { 384, ec_secp384r1 /* = 24, fast */ },
+ { 409, ec_sect409k1 /* = 11, */ },
+ { 409, ec_sect409r1 /* = 12, */ },
+ { 521, ec_secp521r1 /* = 25, fast */ },
+ { 571, ec_sect571k1 /* = 13, */ },
+ { 571, ec_sect571r1 /* = 14, */ },
+ { 65535, ec_noName }
+};
+
+typedef struct ECDHEKeyPairStr {
+ ssl3KeyPair * pair;
+ int error; /* error code of the call-once function */
+ PRCallOnceType once;
+} ECDHEKeyPair;
+
+/* arrays of ECDHE KeyPairs */
+static ECDHEKeyPair gECDHEKeyPairs[ec_pastLastName];
+
+SECStatus
+ssl3_ECName2Params(PLArenaPool * arena, ECName curve, SECKEYECParams * params)
+{
+ SECOidData *oidData = NULL;
+
+ if ((curve <= ec_noName) || (curve >= ec_pastLastName) ||
+ ((oidData = SECOID_FindOIDByTag(ecName2OIDTag[curve])) == NULL)) {
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+ return SECFailure;
+ }
+
+ SECITEM_AllocItem(arena, params, (2 + oidData->oid.len));
+ /*
+ * params->data needs to contain the ASN encoding of an object ID (OID)
+ * representing the named curve. The actual OID is in
+ * oidData->oid.data so we simply prepend 0x06 and OID length
+ */
+ params->data[0] = SEC_ASN1_OBJECT_ID;
+ params->data[1] = oidData->oid.len;
+ memcpy(params->data + 2, oidData->oid.data, oidData->oid.len);
+
+ return SECSuccess;
+}
+
+static ECName
+params2ecName(SECKEYECParams * params)
+{
+ SECItem oid = { siBuffer, NULL, 0};
+ SECOidData *oidData = NULL;
+ ECName i;
+
+ /*
+ * params->data needs to contain the ASN encoding of an object ID (OID)
+ * representing a named curve. Here, we strip away everything
+ * before the actual OID and use the OID to look up a named curve.
+ */
+ if (params->data[0] != SEC_ASN1_OBJECT_ID) return ec_noName;
+ oid.len = params->len - 2;
+ oid.data = params->data + 2;
+ if ((oidData = SECOID_FindOID(&oid)) == NULL) return ec_noName;
+ for (i = ec_noName + 1; i < ec_pastLastName; i++) {
+ if (ecName2OIDTag[i] == oidData->offset)
+ return i;
+ }
+
+ return ec_noName;
+}
+
+/* Caller must set hiLevel error code. */
+static SECStatus
+ssl3_ComputeECDHKeyHash(SECOidTag hashAlg,
+ SECItem ec_params, SECItem server_ecpoint,
+ SSL3Random *client_rand, SSL3Random *server_rand,
+ SSL3Hashes *hashes, PRBool bypassPKCS11)
+{
+ PRUint8 * hashBuf;
+ PRUint8 * pBuf;
+ SECStatus rv = SECSuccess;
+ unsigned int bufLen;
+ /*
+ * XXX For now, we only support named curves (the appropriate
+ * checks are made before this method is called) so ec_params
+ * takes up only two bytes. ECPoint needs to fit in 256 bytes
+ * (because the spec says the length must fit in one byte)
+ */
+ PRUint8 buf[2*SSL3_RANDOM_LENGTH + 2 + 1 + 256];
+
+ bufLen = 2*SSL3_RANDOM_LENGTH + ec_params.len + 1 + server_ecpoint.len;
+ if (bufLen <= sizeof buf) {
+ hashBuf = buf;
+ } else {
+ hashBuf = PORT_Alloc(bufLen);
+ if (!hashBuf) {
+ return SECFailure;
+ }
+ }
+
+ memcpy(hashBuf, client_rand, SSL3_RANDOM_LENGTH);
+ pBuf = hashBuf + SSL3_RANDOM_LENGTH;
+ memcpy(pBuf, server_rand, SSL3_RANDOM_LENGTH);
+ pBuf += SSL3_RANDOM_LENGTH;
+ memcpy(pBuf, ec_params.data, ec_params.len);
+ pBuf += ec_params.len;
+ pBuf[0] = (PRUint8)(server_ecpoint.len);
+ pBuf += 1;
+ memcpy(pBuf, server_ecpoint.data, server_ecpoint.len);
+ pBuf += server_ecpoint.len;
+ PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen);
+
+ rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes,
+ bypassPKCS11);
+
+ PRINT_BUF(95, (NULL, "ECDHkey hash: ", hashBuf, bufLen));
+ PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result",
+ hashes->u.s.md5, MD5_LENGTH));
+ PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result",
+ hashes->u.s.sha, SHA1_LENGTH));
+
+ if (hashBuf != buf)
+ PORT_Free(hashBuf);
+ return rv;
+}
+
+
+/* Called from ssl3_SendClientKeyExchange(). */
+SECStatus
+ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
+{
+ PK11SymKey * pms = NULL;
+ SECStatus rv = SECFailure;
+ PRBool isTLS, isTLS12;
+ CK_MECHANISM_TYPE target;
+ SECKEYPublicKey *pubKey = NULL; /* Ephemeral ECDH key */
+ SECKEYPrivateKey *privKey = NULL; /* Ephemeral ECDH key */
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+
+ isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
+ isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
+
+ /* Generate ephemeral EC keypair */
+ if (svrPubKey->keyType != ecKey) {
+ PORT_SetError(SEC_ERROR_BAD_KEY);
+ goto loser;
+ }
+ /* XXX SHOULD CALL ssl3_CreateECDHEphemeralKeys here, instead! */
+ privKey = SECKEY_CreateECPrivateKey(&svrPubKey->u.ec.DEREncodedParams,
+ &pubKey, ss->pkcs11PinArg);
+ if (!privKey || !pubKey) {
+ ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
+ rv = SECFailure;
+ goto loser;
+ }
+ PRINT_BUF(50, (ss, "ECDH public value:",
+ pubKey->u.ec.publicValue.data,
+ pubKey->u.ec.publicValue.len));
+
+ if (isTLS12) {
+ target = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256;
+ } else if (isTLS) {
+ target = CKM_TLS_MASTER_KEY_DERIVE_DH;
+ } else {
+ target = CKM_SSL3_MASTER_KEY_DERIVE_DH;
+ }
+
+ /* Determine the PMS */
+ pms = PK11_PubDeriveWithKDF(privKey, svrPubKey, PR_FALSE, NULL, NULL,
+ CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0,
+ CKD_NULL, NULL, NULL);
+
+ if (pms == NULL) {
+ SSL3AlertDescription desc = illegal_parameter;
+ (void)SSL3_SendAlert(ss, alert_fatal, desc);
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
+ SECKEY_DestroyPrivateKey(privKey);
+ privKey = NULL;
+
+ rv = ssl3_InitPendingCipherSpec(ss, pms);
+ PK11_FreeSymKey(pms); pms = NULL;
+
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
+ rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
+ pubKey->u.ec.publicValue.len + 1);
+ if (rv != SECSuccess) {
+ goto loser; /* err set by ssl3_AppendHandshake* */
+ }
+
+ rv = ssl3_AppendHandshakeVariable(ss,
+ pubKey->u.ec.publicValue.data,
+ pubKey->u.ec.publicValue.len, 1);
+ SECKEY_DestroyPublicKey(pubKey);
+ pubKey = NULL;
+
+ if (rv != SECSuccess) {
+ goto loser; /* err set by ssl3_AppendHandshake* */
+ }
+
+ rv = SECSuccess;
+
+loser:
+ if(pms) PK11_FreeSymKey(pms);
+ if(privKey) SECKEY_DestroyPrivateKey(privKey);
+ if(pubKey) SECKEY_DestroyPublicKey(pubKey);
+ return rv;
+}
+
+
+/*
+** Called from ssl3_HandleClientKeyExchange()
+*/
+SECStatus
+ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b,
+ PRUint32 length,
+ SECKEYPublicKey *srvrPubKey,
+ SECKEYPrivateKey *srvrPrivKey)
+{
+ PK11SymKey * pms;
+ SECStatus rv;
+ SECKEYPublicKey clntPubKey;
+ CK_MECHANISM_TYPE target;
+ PRBool isTLS, isTLS12;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+
+ clntPubKey.keyType = ecKey;
+ clntPubKey.u.ec.DEREncodedParams.len =
+ srvrPubKey->u.ec.DEREncodedParams.len;
+ clntPubKey.u.ec.DEREncodedParams.data =
+ srvrPubKey->u.ec.DEREncodedParams.data;
+
+ rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.ec.publicValue,
+ 1, &b, &length);
+ if (rv != SECSuccess) {
+ SEND_ALERT
+ return SECFailure; /* XXX Who sets the error code?? */
+ }
+
+ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
+ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
+
+ if (isTLS12) {
+ target = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256;
+ } else if (isTLS) {
+ target = CKM_TLS_MASTER_KEY_DERIVE_DH;
+ } else {
+ target = CKM_SSL3_MASTER_KEY_DERIVE_DH;
+ }
+
+ /* Determine the PMS */
+ pms = PK11_PubDeriveWithKDF(srvrPrivKey, &clntPubKey, PR_FALSE, NULL, NULL,
+ CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0,
+ CKD_NULL, NULL, NULL);
+
+ if (pms == NULL) {
+ /* last gasp. */
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ return SECFailure;
+ }
+
+ rv = ssl3_InitPendingCipherSpec(ss, pms);
+ PK11_FreeSymKey(pms);
+ if (rv != SECSuccess) {
+ SEND_ALERT
+ return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */
+ }
+ return SECSuccess;
+}
+
+ECName
+ssl3_GetCurveWithECKeyStrength(PRUint32 curvemsk, int requiredECCbits)
+{
+ int i;
+
+ for ( i = 0; bits2curve[i].curve != ec_noName; i++) {
+ if (bits2curve[i].bits < requiredECCbits)
+ continue;
+ if (SSL_IS_CURVE_NEGOTIATED(curvemsk, bits2curve[i].curve)) {
+ return bits2curve[i].curve;
+ }
+ }
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+ return ec_noName;
+}
+
+/* find the "weakest link". Get strength of signature key and of sym key.
+ * choose curve for the weakest of those two.
+ */
+ECName
+ssl3_GetCurveNameForServerSocket(sslSocket *ss)
+{
+ SECKEYPublicKey * svrPublicKey = NULL;
+ ECName ec_curve = ec_noName;
+ int signatureKeyStrength = 521;
+ int requiredECCbits = ss->sec.secretKeyBits * 2;
+
+ if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa) {
+ svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_ecdh);
+ if (svrPublicKey)
+ ec_curve = params2ecName(&svrPublicKey->u.ec.DEREncodedParams);
+ if (!SSL_IS_CURVE_NEGOTIATED(ss->ssl3.hs.negotiatedECCurves, ec_curve)) {
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+ return ec_noName;
+ }
+ signatureKeyStrength = curve2bits[ ec_curve ];
+ } else {
+ /* RSA is our signing cert */
+ int serverKeyStrengthInBits;
+
+ svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_rsa);
+ if (!svrPublicKey) {
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+ return ec_noName;
+ }
+
+ /* currently strength in bytes */
+ serverKeyStrengthInBits = svrPublicKey->u.rsa.modulus.len;
+ if (svrPublicKey->u.rsa.modulus.data[0] == 0) {
+ serverKeyStrengthInBits--;
+ }
+ /* convert to strength in bits */
+ serverKeyStrengthInBits *= BPB;
+
+ signatureKeyStrength =
+ SSL_RSASTRENGTH_TO_ECSTRENGTH(serverKeyStrengthInBits);
+ }
+ if ( requiredECCbits > signatureKeyStrength )
+ requiredECCbits = signatureKeyStrength;
+
+ return ssl3_GetCurveWithECKeyStrength(ss->ssl3.hs.negotiatedECCurves,
+ requiredECCbits);
+}
+
+/* function to clear out the lists */
+static SECStatus
+ssl3_ShutdownECDHECurves(void *appData, void *nssData)
+{
+ int i;
+ ECDHEKeyPair *keyPair = &gECDHEKeyPairs[0];
+
+ for (i=0; i < ec_pastLastName; i++, keyPair++) {
+ if (keyPair->pair) {
+ ssl3_FreeKeyPair(keyPair->pair);
+ }
+ }
+ memset(gECDHEKeyPairs, 0, sizeof gECDHEKeyPairs);
+ return SECSuccess;
+}
+
+static PRStatus
+ssl3_ECRegister(void)
+{
+ SECStatus rv;
+ rv = NSS_RegisterShutdown(ssl3_ShutdownECDHECurves, gECDHEKeyPairs);
+ if (rv != SECSuccess) {
+ gECDHEKeyPairs[ec_noName].error = PORT_GetError();
+ }
+ return (PRStatus)rv;
+}
+
+/* CallOnce function, called once for each named curve. */
+static PRStatus
+ssl3_CreateECDHEphemeralKeyPair(void * arg)
+{
+ SECKEYPrivateKey * privKey = NULL;
+ SECKEYPublicKey * pubKey = NULL;
+ ssl3KeyPair * keyPair = NULL;
+ ECName ec_curve = (ECName)arg;
+ SECKEYECParams ecParams = { siBuffer, NULL, 0 };
+
+ PORT_Assert(gECDHEKeyPairs[ec_curve].pair == NULL);
+
+ /* ok, no one has generated a global key for this curve yet, do so */
+ if (ssl3_ECName2Params(NULL, ec_curve, &ecParams) != SECSuccess) {
+ gECDHEKeyPairs[ec_curve].error = PORT_GetError();
+ return PR_FAILURE;
+ }
+
+ privKey = SECKEY_CreateECPrivateKey(&ecParams, &pubKey, NULL);
+ SECITEM_FreeItem(&ecParams, PR_FALSE);
+
+ if (!privKey || !pubKey || !(keyPair = ssl3_NewKeyPair(privKey, pubKey))) {
+ if (privKey) {
+ SECKEY_DestroyPrivateKey(privKey);
+ }
+ if (pubKey) {
+ SECKEY_DestroyPublicKey(pubKey);
+ }
+ ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
+ gECDHEKeyPairs[ec_curve].error = PORT_GetError();
+ return PR_FAILURE;
+ }
+
+ gECDHEKeyPairs[ec_curve].pair = keyPair;
+ return PR_SUCCESS;
+}
+
+/*
+ * Creates the ephemeral public and private ECDH keys used by
+ * server in ECDHE_RSA and ECDHE_ECDSA handshakes.
+ * For now, the elliptic curve is chosen to be the same
+ * strength as the signing certificate (ECC or RSA).
+ * We need an API to specify the curve. This won't be a real
+ * issue until we further develop server-side support for ECC
+ * cipher suites.
+ */
+static SECStatus
+ssl3_CreateECDHEphemeralKeys(sslSocket *ss, ECName ec_curve)
+{
+ ssl3KeyPair * keyPair = NULL;
+
+ /* if there's no global key for this curve, make one. */
+ if (gECDHEKeyPairs[ec_curve].pair == NULL) {
+ PRStatus status;
+
+ status = PR_CallOnce(&gECDHEKeyPairs[ec_noName].once, ssl3_ECRegister);
+ if (status != PR_SUCCESS) {
+ PORT_SetError(gECDHEKeyPairs[ec_noName].error);
+ return SECFailure;
+ }
+ status = PR_CallOnceWithArg(&gECDHEKeyPairs[ec_curve].once,
+ ssl3_CreateECDHEphemeralKeyPair,
+ (void *)ec_curve);
+ if (status != PR_SUCCESS) {
+ PORT_SetError(gECDHEKeyPairs[ec_curve].error);
+ return SECFailure;
+ }
+ }
+
+ keyPair = gECDHEKeyPairs[ec_curve].pair;
+ PORT_Assert(keyPair != NULL);
+ if (!keyPair)
+ return SECFailure;
+ ss->ephemeralECDHKeyPair = ssl3_GetKeyPairRef(keyPair);
+
+ return SECSuccess;
+}
+
+SECStatus
+ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+ PLArenaPool * arena = NULL;
+ SECKEYPublicKey *peerKey = NULL;
+ PRBool isTLS, isTLS12;
+ SECStatus rv;
+ int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH;
+ SSL3AlertDescription desc = illegal_parameter;
+ SSL3Hashes hashes;
+ SECItem signature = {siBuffer, NULL, 0};
+
+ SECItem ec_params = {siBuffer, NULL, 0};
+ SECItem ec_point = {siBuffer, NULL, 0};
+ unsigned char paramBuf[3]; /* only for curve_type == named_curve */
+ SSL3SignatureAndHashAlgorithm sigAndHash;
+
+ sigAndHash.hashAlg = SEC_OID_UNKNOWN;
+
+ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
+ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
+
+ /* XXX This works only for named curves, revisit this when
+ * we support generic curves.
+ */
+ ec_params.len = sizeof paramBuf;
+ ec_params.data = paramBuf;
+ rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed. */
+ }
+
+ /* Fail if the curve is not a named curve */
+ if ((ec_params.data[0] != ec_type_named) ||
+ (ec_params.data[1] != 0) ||
+ !supportedCurve(ec_params.data[2])) {
+ errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
+ desc = handshake_failure;
+ goto alert_loser;
+ }
+
+ rv = ssl3_ConsumeHandshakeVariable(ss, &ec_point, 1, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed. */
+ }
+ /* Fail if the ec point uses compressed representation */
+ if (ec_point.data[0] != EC_POINT_FORM_UNCOMPRESSED) {
+ errCode = SEC_ERROR_UNSUPPORTED_EC_POINT_FORM;
+ desc = handshake_failure;
+ goto alert_loser;
+ }
+
+ if (isTLS12) {
+ rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
+ &sigAndHash);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed or unsupported. */
+ }
+ rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
+ &sigAndHash, ss->sec.peerCert);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+
+ rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length);
+ if (rv != SECSuccess) {
+ goto loser; /* malformed. */
+ }
+
+ if (length != 0) {
+ if (isTLS)
+ desc = decode_error;
+ goto alert_loser; /* malformed. */
+ }
+
+ PRINT_BUF(60, (NULL, "Server EC params", ec_params.data,
+ ec_params.len));
+ PRINT_BUF(60, (NULL, "Server EC point", ec_point.data, ec_point.len));
+
+ /* failures after this point are not malformed handshakes. */
+ /* TLS: send decrypt_error if signature failed. */
+ desc = isTLS ? decrypt_error : handshake_failure;
+
+ /*
+ * check to make sure the hash is signed by right guy
+ */
+ rv = ssl3_ComputeECDHKeyHash(sigAndHash.hashAlg, ec_params, ec_point,
+ &ss->ssl3.hs.client_random,
+ &ss->ssl3.hs.server_random,
+ &hashes, ss->opt.bypassPKCS11);
+
+ if (rv != SECSuccess) {
+ errCode =
+ ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+ goto alert_loser;
+ }
+ rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature,
+ isTLS, ss->pkcs11PinArg);
+ if (rv != SECSuccess) {
+ errCode =
+ ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+ goto alert_loser;
+ }
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ goto no_memory;
+ }
+
+ ss->sec.peerKey = peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
+ if (peerKey == NULL) {
+ goto no_memory;
+ }
+
+ peerKey->arena = arena;
+ peerKey->keyType = ecKey;
+
+ /* set up EC parameters in peerKey */
+ if (ssl3_ECName2Params(arena, ec_params.data[2],
+ &peerKey->u.ec.DEREncodedParams) != SECSuccess) {
+ /* we should never get here since we already
+ * checked that we are dealing with a supported curve
+ */
+ errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
+ goto alert_loser;
+ }
+
+ /* copy publicValue in peerKey */
+ if (SECITEM_CopyItem(arena, &peerKey->u.ec.publicValue, &ec_point))
+ {
+ PORT_FreeArena(arena, PR_FALSE);
+ goto no_memory;
+ }
+ peerKey->pkcs11Slot = NULL;
+ peerKey->pkcs11ID = CK_INVALID_HANDLE;
+
+ ss->sec.peerKey = peerKey;
+ ss->ssl3.hs.ws = wait_cert_request;
+
+ return SECSuccess;
+
+alert_loser:
+ (void)SSL3_SendAlert(ss, alert_fatal, desc);
+loser:
+ PORT_SetError( errCode );
+ return SECFailure;
+
+no_memory: /* no-memory error has already been set. */
+ ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+ return SECFailure;
+}
+
+SECStatus
+ssl3_SendECDHServerKeyExchange(
+ sslSocket *ss,
+ const SSL3SignatureAndHashAlgorithm *sigAndHash)
+{
+ const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def;
+ SECStatus rv = SECFailure;
+ int length;
+ PRBool isTLS, isTLS12;
+ SECItem signed_hash = {siBuffer, NULL, 0};
+ SSL3Hashes hashes;
+
+ SECKEYPublicKey * ecdhePub;
+ SECItem ec_params = {siBuffer, NULL, 0};
+ unsigned char paramBuf[3];
+ ECName curve;
+ SSL3KEAType certIndex;
+
+ /* Generate ephemeral ECDH key pair and send the public key */
+ curve = ssl3_GetCurveNameForServerSocket(ss);
+ if (curve == ec_noName) {
+ goto loser;
+ }
+ rv = ssl3_CreateECDHEphemeralKeys(ss, curve);
+ if (rv != SECSuccess) {
+ goto loser; /* err set by AppendHandshake. */
+ }
+ ecdhePub = ss->ephemeralECDHKeyPair->pubKey;
+ PORT_Assert(ecdhePub != NULL);
+ if (!ecdhePub) {
+ PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+ return SECFailure;
+ }
+
+ ec_params.len = sizeof paramBuf;
+ ec_params.data = paramBuf;
+ curve = params2ecName(&ecdhePub->u.ec.DEREncodedParams);
+ if (curve != ec_noName) {
+ ec_params.data[0] = ec_type_named;
+ ec_params.data[1] = 0x00;
+ ec_params.data[2] = curve;
+ } else {
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+ goto loser;
+ }
+
+ rv = ssl3_ComputeECDHKeyHash(sigAndHash->hashAlg,
+ ec_params,
+ ecdhePub->u.ec.publicValue,
+ &ss->ssl3.hs.client_random,
+ &ss->ssl3.hs.server_random,
+ &hashes, ss->opt.bypassPKCS11);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
+ isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
+ isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
+
+ /* XXX SSLKEAType isn't really a good choice for
+ * indexing certificates but that's all we have
+ * for now.
+ */
+ if (kea_def->kea == kea_ecdhe_rsa)
+ certIndex = kt_rsa;
+ else /* kea_def->kea == kea_ecdhe_ecdsa */
+ certIndex = kt_ecdh;
+
+ rv = ssl3_SignHashes(&hashes, ss->serverCerts[certIndex].SERVERKEY,
+ &signed_hash, isTLS);
+ if (rv != SECSuccess) {
+ goto loser; /* ssl3_SignHashes has set err. */
+ }
+ if (signed_hash.data == NULL) {
+ /* how can this happen and rv == SECSuccess ?? */
+ PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
+
+ length = ec_params.len +
+ 1 + ecdhePub->u.ec.publicValue.len +
+ (isTLS12 ? 2 : 0) + 2 + signed_hash.len;
+
+ rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length);
+ if (rv != SECSuccess) {
+ goto loser; /* err set by AppendHandshake. */
+ }
+
+ rv = ssl3_AppendHandshake(ss, ec_params.data, ec_params.len);
+ if (rv != SECSuccess) {
+ goto loser; /* err set by AppendHandshake. */
+ }
+
+ rv = ssl3_AppendHandshakeVariable(ss, ecdhePub->u.ec.publicValue.data,
+ ecdhePub->u.ec.publicValue.len, 1);
+ if (rv != SECSuccess) {
+ goto loser; /* err set by AppendHandshake. */
+ }
+
+ if (isTLS12) {
+ rv = ssl3_AppendSignatureAndHashAlgorithm(ss, sigAndHash);
+ if (rv != SECSuccess) {
+ goto loser; /* err set by AppendHandshake. */
+ }
+ }
+
+ rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data,
+ signed_hash.len, 2);
+ if (rv != SECSuccess) {
+ goto loser; /* err set by AppendHandshake. */
+ }
+
+ PORT_Free(signed_hash.data);
+ return SECSuccess;
+
+loser:
+ if (signed_hash.data != NULL)
+ PORT_Free(signed_hash.data);
+ return SECFailure;
+}
+
+/* Lists of ECC cipher suites for searching and disabling. */
+
+static const ssl3CipherSuite ecdh_suites[] = {
+ TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDH_ECDSA_WITH_NULL_SHA,
+ TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDH_RSA_WITH_NULL_SHA,
+ TLS_ECDH_RSA_WITH_RC4_128_SHA,
+ 0 /* end of list marker */
+};
+
+static const ssl3CipherSuite ecdh_ecdsa_suites[] = {
+ TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDH_ECDSA_WITH_NULL_SHA,
+ TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ 0 /* end of list marker */
+};
+
+static const ssl3CipherSuite ecdh_rsa_suites[] = {
+ TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDH_RSA_WITH_NULL_SHA,
+ TLS_ECDH_RSA_WITH_RC4_128_SHA,
+ 0 /* end of list marker */
+};
+
+static const ssl3CipherSuite ecdhe_ecdsa_suites[] = {
+ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_NULL_SHA,
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ 0 /* end of list marker */
+};
+
+static const ssl3CipherSuite ecdhe_rsa_suites[] = {
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_NULL_SHA,
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ 0 /* end of list marker */
+};
+
+/* List of all ECC cipher suites */
+static const ssl3CipherSuite ecSuites[] = {
+ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_NULL_SHA,
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_NULL_SHA,
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDH_ECDSA_WITH_NULL_SHA,
+ TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDH_RSA_WITH_NULL_SHA,
+ TLS_ECDH_RSA_WITH_RC4_128_SHA,
+ 0 /* end of list marker */
+};
+
+/* On this socket, Disable the ECC cipher suites in the argument's list */
+SECStatus
+ssl3_DisableECCSuites(sslSocket * ss, const ssl3CipherSuite * suite)
+{
+ if (!suite)
+ suite = ecSuites;
+ for (; *suite; ++suite) {
+ SECStatus rv = ssl3_CipherPrefSet(ss, *suite, PR_FALSE);
+
+ PORT_Assert(rv == SECSuccess); /* else is coding error */
+ }
+ return SECSuccess;
+}
+
+/* Look at the server certs configured on this socket, and disable any
+ * ECC cipher suites that are not supported by those certs.
+ */
+void
+ssl3_FilterECCipherSuitesByServerCerts(sslSocket * ss)
+{
+ CERTCertificate * svrCert;
+
+ svrCert = ss->serverCerts[kt_rsa].serverCert;
+ if (!svrCert) {
+ ssl3_DisableECCSuites(ss, ecdhe_rsa_suites);
+ }
+
+ svrCert = ss->serverCerts[kt_ecdh].serverCert;
+ if (!svrCert) {
+ ssl3_DisableECCSuites(ss, ecdh_suites);
+ ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites);
+ } else {
+ SECOidTag sigTag = SECOID_GetAlgorithmTag(&svrCert->signature);
+
+ switch (sigTag) {
+ case SEC_OID_PKCS1_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
+ ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites);
+ break;
+ case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
+ case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE:
+ case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
+ case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
+ case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
+ case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
+ case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
+ ssl3_DisableECCSuites(ss, ecdh_rsa_suites);
+ break;
+ default:
+ ssl3_DisableECCSuites(ss, ecdh_suites);
+ break;
+ }
+ }
+}
+
+/* Ask: is ANY ECC cipher suite enabled on this socket? */
+/* Order(N^2). Yuk. Also, this ignores export policy. */
+PRBool
+ssl3_IsECCEnabled(sslSocket * ss)
+{
+ const ssl3CipherSuite * suite;
+ PK11SlotInfo *slot;
+
+ /* make sure we can do ECC */
+ slot = PK11_GetBestSlot(CKM_ECDH1_DERIVE, ss->pkcs11PinArg);
+ if (!slot) {
+ return PR_FALSE;
+ }
+ PK11_FreeSlot(slot);
+
+ /* make sure an ECC cipher is enabled */
+ for (suite = ecSuites; *suite; ++suite) {
+ PRBool enabled = PR_FALSE;
+ SECStatus rv = ssl3_CipherPrefGet(ss, *suite, &enabled);
+
+ PORT_Assert(rv == SECSuccess); /* else is coding error */
+ if (rv == SECSuccess && enabled)
+ return PR_TRUE;
+ }
+ return PR_FALSE;
+}
+
+#define BE(n) 0, n
+
+/* Prefabricated TLS client hello extension, Elliptic Curves List,
+ * offers only 3 curves, the Suite B curves, 23-25
+ */
+static const PRUint8 suiteBECList[12] = {
+ BE(10), /* Extension type */
+ BE( 8), /* octets that follow ( 3 pairs + 1 length pair) */
+ BE( 6), /* octets that follow ( 3 pairs) */
+ BE(23), BE(24), BE(25)
+};
+
+/* Prefabricated TLS client hello extension, Elliptic Curves List,
+ * offers curves 1-25.
+ */
+static const PRUint8 tlsECList[56] = {
+ BE(10), /* Extension type */
+ BE(52), /* octets that follow (25 pairs + 1 length pair) */
+ BE(50), /* octets that follow (25 pairs) */
+ BE( 1), BE( 2), BE( 3), BE( 4), BE( 5), BE( 6), BE( 7),
+ BE( 8), BE( 9), BE(10), BE(11), BE(12), BE(13), BE(14), BE(15),
+ BE(16), BE(17), BE(18), BE(19), BE(20), BE(21), BE(22), BE(23),
+ BE(24), BE(25)
+};
+
+static const PRUint8 ecPtFmt[6] = {
+ BE(11), /* Extension type */
+ BE( 2), /* octets that follow */
+ 1, /* octets that follow */
+ 0 /* uncompressed type only */
+};
+
+/* This function already presumes we can do ECC, ssl3_IsECCEnabled must be
+ * called before this function. It looks to see if we have a token which
+ * is capable of doing smaller than SuiteB curves. If the token can, we
+ * presume the token can do the whole SSL suite of curves. If it can't we
+ * presume the token that allowed ECC to be enabled can only do suite B
+ * curves. */
+static PRBool
+ssl3_SuiteBOnly(sslSocket *ss)
+{
+#if 0
+ /* See if we can support small curves (like 163). If not, assume we can
+ * only support Suite-B curves (P-256, P-384, P-521). */
+ PK11SlotInfo *slot =
+ PK11_GetBestSlotWithAttributes(CKM_ECDH1_DERIVE, 0, 163,
+ ss ? ss->pkcs11PinArg : NULL);
+
+ if (!slot) {
+ /* nope, presume we can only do suite B */
+ return PR_TRUE;
+ }
+ /* we can, presume we can do all curves */
+ PK11_FreeSlot(slot);
+ return PR_FALSE;
+#else
+ return PR_TRUE;
+#endif
+}
+
+/* Send our "canned" (precompiled) Supported Elliptic Curves extension,
+ * which says that we support all TLS-defined named curves.
+ */
+PRInt32
+ssl3_SendSupportedCurvesXtn(
+ sslSocket * ss,
+ PRBool append,
+ PRUint32 maxBytes)
+{
+ PRInt32 ecListSize = 0;
+ const PRUint8 *ecList = NULL;
+
+ if (!ss || !ssl3_IsECCEnabled(ss))
+ return 0;
+
+ if (ssl3_SuiteBOnly(ss)) {
+ ecListSize = sizeof suiteBECList;
+ ecList = suiteBECList;
+ } else {
+ ecListSize = sizeof tlsECList;
+ ecList = tlsECList;
+ }
+
+ if (append && maxBytes >= ecListSize) {
+ SECStatus rv = ssl3_AppendHandshake(ss, ecList, ecListSize);
+ if (rv != SECSuccess)
+ return -1;
+ if (!ss->sec.isServer) {
+ TLSExtensionData *xtnData = &ss->xtnData;
+ xtnData->advertised[xtnData->numAdvertised++] =
+ ssl_elliptic_curves_xtn;
+ }
+ }
+ return ecListSize;
+}
+
+PRUint32
+ssl3_GetSupportedECCurveMask(sslSocket *ss)
+{
+ if (ssl3_SuiteBOnly(ss)) {
+ return SSL3_SUITE_B_SUPPORTED_CURVES_MASK;
+ }
+ return SSL3_ALL_SUPPORTED_CURVES_MASK;
+}
+
+/* Send our "canned" (precompiled) Supported Point Formats extension,
+ * which says that we only support uncompressed points.
+ */
+PRInt32
+ssl3_SendSupportedPointFormatsXtn(
+ sslSocket * ss,
+ PRBool append,
+ PRUint32 maxBytes)
+{
+ if (!ss || !ssl3_IsECCEnabled(ss))
+ return 0;
+ if (append && maxBytes >= (sizeof ecPtFmt)) {
+ SECStatus rv = ssl3_AppendHandshake(ss, ecPtFmt, (sizeof ecPtFmt));
+ if (rv != SECSuccess)
+ return -1;
+ if (!ss->sec.isServer) {
+ TLSExtensionData *xtnData = &ss->xtnData;
+ xtnData->advertised[xtnData->numAdvertised++] =
+ ssl_ec_point_formats_xtn;
+ }
+ }
+ return (sizeof ecPtFmt);
+}
+
+/* Just make sure that the remote client supports uncompressed points,
+ * Since that is all we support. Disable ECC cipher suites if it doesn't.
+ */
+SECStatus
+ssl3_HandleSupportedPointFormatsXtn(sslSocket *ss, PRUint16 ex_type,
+ SECItem *data)
+{
+ int i;
+
+ if (data->len < 2 || data->len > 255 || !data->data ||
+ data->len != (unsigned int)data->data[0] + 1) {
+ /* malformed */
+ goto loser;
+ }
+ for (i = data->len; --i > 0; ) {
+ if (data->data[i] == 0) {
+ /* indicate that we should send a reply */
+ SECStatus rv;
+ rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type,
+ &ssl3_SendSupportedPointFormatsXtn);
+ return rv;
+ }
+ }
+loser:
+ /* evil client doesn't support uncompressed */
+ ssl3_DisableECCSuites(ss, ecSuites);
+ return SECFailure;
+}
+
+
+#define SSL3_GET_SERVER_PUBLICKEY(sock, type) \
+ (ss->serverCerts[type].serverKeyPair ? \
+ ss->serverCerts[type].serverKeyPair->pubKey : NULL)
+
+/* Extract the TLS curve name for the public key in our EC server cert. */
+ECName ssl3_GetSvrCertCurveName(sslSocket *ss)
+{
+ SECKEYPublicKey *srvPublicKey;
+ ECName ec_curve = ec_noName;
+
+ srvPublicKey = SSL3_GET_SERVER_PUBLICKEY(ss, kt_ecdh);
+ if (srvPublicKey) {
+ ec_curve = params2ecName(&srvPublicKey->u.ec.DEREncodedParams);
+ }
+ return ec_curve;
+}
+
+/* Ensure that the curve in our server cert is one of the ones suppored
+ * by the remote client, and disable all ECC cipher suites if not.
+ */
+SECStatus
+ssl3_HandleSupportedCurvesXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+{
+ PRInt32 list_len;
+ PRUint32 peerCurves = 0;
+ PRUint32 mutualCurves = 0;
+ PRUint16 svrCertCurveName;
+
+ if (!data->data || data->len < 4 || data->len > 65535)
+ goto loser;
+ /* get the length of elliptic_curve_list */
+ list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+ if (list_len < 0 || data->len != list_len || (data->len % 2) != 0) {
+ /* malformed */
+ goto loser;
+ }
+ /* build bit vector of peer's supported curve names */
+ while (data->len) {
+ PRInt32 curve_name =
+ ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+ if (curve_name > ec_noName && curve_name < ec_pastLastName) {
+ peerCurves |= (1U << curve_name);
+ }
+ }
+ /* What curves do we support in common? */
+ mutualCurves = ss->ssl3.hs.negotiatedECCurves &= peerCurves;
+ if (!mutualCurves) { /* no mutually supported EC Curves */
+ goto loser;
+ }
+
+ /* if our ECC cert doesn't use one of these supported curves,
+ * disable ECC cipher suites that require an ECC cert.
+ */
+ svrCertCurveName = ssl3_GetSvrCertCurveName(ss);
+ if (svrCertCurveName != ec_noName &&
+ (mutualCurves & (1U << svrCertCurveName)) != 0) {
+ return SECSuccess;
+ }
+ /* Our EC cert doesn't contain a mutually supported curve.
+ * Disable all ECC cipher suites that require an EC cert
+ */
+ ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites);
+ ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites);
+ return SECFailure;
+
+loser:
+ /* no common curve supported */
+ ssl3_DisableECCSuites(ss, ecSuites);
+ return SECFailure;
+}
+
+#endif /* NSS_ENABLE_ECC */
diff --git a/chromium/net/third_party/nss/ssl/ssl3ext.c b/chromium/net/third_party/nss/ssl/ssl3ext.c
new file mode 100644
index 00000000000..04157701e90
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/ssl3ext.c
@@ -0,0 +1,2299 @@
+/*
+ * SSL3 Protocol
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* TLS extension code moved here from ssl3ecc.c */
+
+#include "nssrenam.h"
+#include "nss.h"
+#include "ssl.h"
+#include "sslimpl.h"
+#include "sslproto.h"
+#include "pk11pub.h"
+#ifdef NO_PKCS11_BYPASS
+#include "blapit.h"
+#else
+#include "blapi.h"
+#endif
+#include "prinit.h"
+
+static unsigned char key_name[SESS_TICKET_KEY_NAME_LEN];
+static PK11SymKey *session_ticket_enc_key_pkcs11 = NULL;
+static PK11SymKey *session_ticket_mac_key_pkcs11 = NULL;
+
+#ifndef NO_PKCS11_BYPASS
+static unsigned char session_ticket_enc_key[AES_256_KEY_LENGTH];
+static unsigned char session_ticket_mac_key[SHA256_LENGTH];
+
+static PRBool session_ticket_keys_initialized = PR_FALSE;
+#endif
+static PRCallOnceType generate_session_keys_once;
+
+/* forward static function declarations */
+static SECStatus ssl3_ParseEncryptedSessionTicket(sslSocket *ss,
+ SECItem *data, EncryptedSessionTicket *enc_session_ticket);
+static SECStatus ssl3_AppendToItem(SECItem *item, const unsigned char *buf,
+ PRUint32 bytes);
+static SECStatus ssl3_AppendNumberToItem(SECItem *item, PRUint32 num,
+ PRInt32 lenSize);
+static SECStatus ssl3_GetSessionTicketKeysPKCS11(sslSocket *ss,
+ PK11SymKey **aes_key, PK11SymKey **mac_key);
+#ifndef NO_PKCS11_BYPASS
+static SECStatus ssl3_GetSessionTicketKeys(const unsigned char **aes_key,
+ PRUint32 *aes_key_length, const unsigned char **mac_key,
+ PRUint32 *mac_key_length);
+#endif
+static PRInt32 ssl3_SendRenegotiationInfoXtn(sslSocket * ss,
+ PRBool append, PRUint32 maxBytes);
+static SECStatus ssl3_HandleRenegotiationInfoXtn(sslSocket *ss,
+ PRUint16 ex_type, SECItem *data);
+static SECStatus ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss,
+ PRUint16 ex_type, SECItem *data);
+static SECStatus ssl3_ClientHandleAppProtoXtn(sslSocket *ss,
+ PRUint16 ex_type, SECItem *data);
+static SECStatus ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss,
+ PRUint16 ex_type, SECItem *data);
+static PRInt32 ssl3_ClientSendAppProtoXtn(sslSocket *ss, PRBool append,
+ PRUint32 maxBytes);
+static PRInt32 ssl3_ClientSendNextProtoNegoXtn(sslSocket *ss, PRBool append,
+ PRUint32 maxBytes);
+static PRInt32 ssl3_SendUseSRTPXtn(sslSocket *ss, PRBool append,
+ PRUint32 maxBytes);
+static SECStatus ssl3_HandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type,
+ SECItem *data);
+static SECStatus ssl3_ClientHandleChannelIDXtn(sslSocket *ss,
+ PRUint16 ex_type, SECItem *data);
+static PRInt32 ssl3_ClientSendChannelIDXtn(sslSocket *ss, PRBool append,
+ PRUint32 maxBytes);
+static SECStatus ssl3_ServerSendStatusRequestXtn(sslSocket * ss,
+ PRBool append, PRUint32 maxBytes);
+static SECStatus ssl3_ServerHandleStatusRequestXtn(sslSocket *ss,
+ PRUint16 ex_type, SECItem *data);
+static SECStatus ssl3_ClientHandleStatusRequestXtn(sslSocket *ss,
+ PRUint16 ex_type,
+ SECItem *data);
+static PRInt32 ssl3_ClientSendStatusRequestXtn(sslSocket * ss, PRBool append,
+ PRUint32 maxBytes);
+static PRInt32 ssl3_ClientSendSigAlgsXtn(sslSocket *ss, PRBool append,
+ PRUint32 maxBytes);
+static SECStatus ssl3_ServerHandleSigAlgsXtn(sslSocket *ss, PRUint16 ex_type,
+ SECItem *data);
+
+/*
+ * Write bytes. Using this function means the SECItem structure
+ * cannot be freed. The caller is expected to call this function
+ * on a shallow copy of the structure.
+ */
+static SECStatus
+ssl3_AppendToItem(SECItem *item, const unsigned char *buf, PRUint32 bytes)
+{
+ if (bytes > item->len)
+ return SECFailure;
+
+ PORT_Memcpy(item->data, buf, bytes);
+ item->data += bytes;
+ item->len -= bytes;
+ return SECSuccess;
+}
+
+/*
+ * Write a number in network byte order. Using this function means the
+ * SECItem structure cannot be freed. The caller is expected to call
+ * this function on a shallow copy of the structure.
+ */
+static SECStatus
+ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, PRInt32 lenSize)
+{
+ SECStatus rv;
+ PRUint8 b[4];
+ PRUint8 * p = b;
+
+ switch (lenSize) {
+ case 4:
+ *p++ = (PRUint8) (num >> 24);
+ case 3:
+ *p++ = (PRUint8) (num >> 16);
+ case 2:
+ *p++ = (PRUint8) (num >> 8);
+ case 1:
+ *p = (PRUint8) num;
+ }
+ rv = ssl3_AppendToItem(item, &b[0], lenSize);
+ return rv;
+}
+
+static SECStatus ssl3_SessionTicketShutdown(void* appData, void* nssData)
+{
+ if (session_ticket_enc_key_pkcs11) {
+ PK11_FreeSymKey(session_ticket_enc_key_pkcs11);
+ session_ticket_enc_key_pkcs11 = NULL;
+ }
+ if (session_ticket_mac_key_pkcs11) {
+ PK11_FreeSymKey(session_ticket_mac_key_pkcs11);
+ session_ticket_mac_key_pkcs11 = NULL;
+ }
+ PORT_Memset(&generate_session_keys_once, 0,
+ sizeof(generate_session_keys_once));
+ return SECSuccess;
+}
+
+
+static PRStatus
+ssl3_GenerateSessionTicketKeysPKCS11(void *data)
+{
+ SECStatus rv;
+ sslSocket *ss = (sslSocket *)data;
+ SECKEYPrivateKey *svrPrivKey = ss->serverCerts[kt_rsa].SERVERKEY;
+ SECKEYPublicKey *svrPubKey = ss->serverCerts[kt_rsa].serverKeyPair->pubKey;
+
+ if (svrPrivKey == NULL || svrPubKey == NULL) {
+ SSL_DBG(("%d: SSL[%d]: Pub or priv key(s) is NULL.",
+ SSL_GETPID(), ss->fd));
+ goto loser;
+ }
+
+ /* Get a copy of the session keys from shared memory. */
+ PORT_Memcpy(key_name, SESS_TICKET_KEY_NAME_PREFIX,
+ sizeof(SESS_TICKET_KEY_NAME_PREFIX));
+ if (!ssl_GetSessionTicketKeysPKCS11(svrPrivKey, svrPubKey,
+ ss->pkcs11PinArg, &key_name[SESS_TICKET_KEY_NAME_PREFIX_LEN],
+ &session_ticket_enc_key_pkcs11, &session_ticket_mac_key_pkcs11))
+ return PR_FAILURE;
+
+ rv = NSS_RegisterShutdown(ssl3_SessionTicketShutdown, NULL);
+ if (rv != SECSuccess)
+ goto loser;
+
+ return PR_SUCCESS;
+
+loser:
+ ssl3_SessionTicketShutdown(NULL, NULL);
+ return PR_FAILURE;
+}
+
+static SECStatus
+ssl3_GetSessionTicketKeysPKCS11(sslSocket *ss, PK11SymKey **aes_key,
+ PK11SymKey **mac_key)
+{
+ if (PR_CallOnceWithArg(&generate_session_keys_once,
+ ssl3_GenerateSessionTicketKeysPKCS11, ss) != PR_SUCCESS)
+ return SECFailure;
+
+ if (session_ticket_enc_key_pkcs11 == NULL ||
+ session_ticket_mac_key_pkcs11 == NULL)
+ return SECFailure;
+
+ *aes_key = session_ticket_enc_key_pkcs11;
+ *mac_key = session_ticket_mac_key_pkcs11;
+ return SECSuccess;
+}
+
+#ifndef NO_PKCS11_BYPASS
+static PRStatus
+ssl3_GenerateSessionTicketKeys(void)
+{
+ PORT_Memcpy(key_name, SESS_TICKET_KEY_NAME_PREFIX,
+ sizeof(SESS_TICKET_KEY_NAME_PREFIX));
+
+ if (!ssl_GetSessionTicketKeys(&key_name[SESS_TICKET_KEY_NAME_PREFIX_LEN],
+ session_ticket_enc_key, session_ticket_mac_key))
+ return PR_FAILURE;
+
+ session_ticket_keys_initialized = PR_TRUE;
+ return PR_SUCCESS;
+}
+
+static SECStatus
+ssl3_GetSessionTicketKeys(const unsigned char **aes_key,
+ PRUint32 *aes_key_length, const unsigned char **mac_key,
+ PRUint32 *mac_key_length)
+{
+ if (PR_CallOnce(&generate_session_keys_once,
+ ssl3_GenerateSessionTicketKeys) != PR_SUCCESS)
+ return SECFailure;
+
+ if (!session_ticket_keys_initialized)
+ return SECFailure;
+
+ *aes_key = session_ticket_enc_key;
+ *aes_key_length = sizeof(session_ticket_enc_key);
+ *mac_key = session_ticket_mac_key;
+ *mac_key_length = sizeof(session_ticket_mac_key);
+
+ return SECSuccess;
+}
+#endif
+
+/* Table of handlers for received TLS hello extensions, one per extension.
+ * In the second generation, this table will be dynamic, and functions
+ * will be registered here.
+ */
+/* This table is used by the server, to handle client hello extensions. */
+static const ssl3HelloExtensionHandler clientHelloHandlers[] = {
+ { ssl_server_name_xtn, &ssl3_HandleServerNameXtn },
+#ifdef NSS_ENABLE_ECC
+ { ssl_elliptic_curves_xtn, &ssl3_HandleSupportedCurvesXtn },
+ { ssl_ec_point_formats_xtn, &ssl3_HandleSupportedPointFormatsXtn },
+#endif
+ { ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn },
+ { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
+ { ssl_next_proto_nego_xtn, &ssl3_ServerHandleNextProtoNegoXtn },
+ { ssl_use_srtp_xtn, &ssl3_HandleUseSRTPXtn },
+ { ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn },
+ { ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn },
+ { -1, NULL }
+};
+
+/* These two tables are used by the client, to handle server hello
+ * extensions. */
+static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = {
+ { ssl_server_name_xtn, &ssl3_HandleServerNameXtn },
+ /* TODO: add a handler for ssl_ec_point_formats_xtn */
+ { ssl_session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn },
+ { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
+ { ssl_next_proto_nego_xtn, &ssl3_ClientHandleNextProtoNegoXtn },
+ { ssl_app_layer_protocol_xtn, &ssl3_ClientHandleAppProtoXtn },
+ { ssl_use_srtp_xtn, &ssl3_HandleUseSRTPXtn },
+ { ssl_channel_id_xtn, &ssl3_ClientHandleChannelIDXtn },
+ { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
+ { -1, NULL }
+};
+
+static const ssl3HelloExtensionHandler serverHelloHandlersSSL3[] = {
+ { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
+ { -1, NULL }
+};
+
+/* Tables of functions to format TLS hello extensions, one function per
+ * extension.
+ * These static tables are for the formatting of client hello extensions.
+ * The server's table of hello senders is dynamic, in the socket struct,
+ * and sender functions are registered there.
+ */
+static const
+ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = {
+ { ssl_server_name_xtn, &ssl3_SendServerNameXtn },
+ { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
+#ifdef NSS_ENABLE_ECC
+ { ssl_elliptic_curves_xtn, &ssl3_SendSupportedCurvesXtn },
+ { ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn },
+#endif
+ { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn },
+ { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn },
+ { ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn },
+ { ssl_use_srtp_xtn, &ssl3_SendUseSRTPXtn },
+ { ssl_channel_id_xtn, &ssl3_ClientSendChannelIDXtn },
+ { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn },
+ { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn }
+ /* any extra entries will appear as { 0, NULL } */
+};
+
+static const
+ssl3HelloExtensionSender clientHelloSendersSSL3[SSL_MAX_EXTENSIONS] = {
+ { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn }
+ /* any extra entries will appear as { 0, NULL } */
+};
+
+static PRBool
+arrayContainsExtension(const PRUint16 *array, PRUint32 len, PRUint16 ex_type)
+{
+ int i;
+ for (i = 0; i < len; i++) {
+ if (ex_type == array[i])
+ return PR_TRUE;
+ }
+ return PR_FALSE;
+}
+
+PRBool
+ssl3_ExtensionNegotiated(sslSocket *ss, PRUint16 ex_type) {
+ TLSExtensionData *xtnData = &ss->xtnData;
+ return arrayContainsExtension(xtnData->negotiated,
+ xtnData->numNegotiated, ex_type);
+}
+
+static PRBool
+ssl3_ClientExtensionAdvertised(sslSocket *ss, PRUint16 ex_type) {
+ TLSExtensionData *xtnData = &ss->xtnData;
+ return arrayContainsExtension(xtnData->advertised,
+ xtnData->numAdvertised, ex_type);
+}
+
+/* Format an SNI extension, using the name from the socket's URL,
+ * unless that name is a dotted decimal string.
+ * Used by client and server.
+ */
+PRInt32
+ssl3_SendServerNameXtn(sslSocket * ss, PRBool append,
+ PRUint32 maxBytes)
+{
+ SECStatus rv;
+ if (!ss)
+ return 0;
+ if (!ss->sec.isServer) {
+ PRUint32 len;
+ PRNetAddr netAddr;
+
+ /* must have a hostname */
+ if (!ss->url || !ss->url[0])
+ return 0;
+ /* must not be an IPv4 or IPv6 address */
+ if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) {
+ /* is an IP address (v4 or v6) */
+ return 0;
+ }
+ len = PORT_Strlen(ss->url);
+ if (append && maxBytes >= len + 9) {
+ /* extension_type */
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_server_name_xtn, 2);
+ if (rv != SECSuccess) return -1;
+ /* length of extension_data */
+ rv = ssl3_AppendHandshakeNumber(ss, len + 5, 2);
+ if (rv != SECSuccess) return -1;
+ /* length of server_name_list */
+ rv = ssl3_AppendHandshakeNumber(ss, len + 3, 2);
+ if (rv != SECSuccess) return -1;
+ /* Name Type (sni_host_name) */
+ rv = ssl3_AppendHandshake(ss, "\0", 1);
+ if (rv != SECSuccess) return -1;
+ /* HostName (length and value) */
+ rv = ssl3_AppendHandshakeVariable(ss, (PRUint8 *)ss->url, len, 2);
+ if (rv != SECSuccess) return -1;
+ if (!ss->sec.isServer) {
+ TLSExtensionData *xtnData = &ss->xtnData;
+ xtnData->advertised[xtnData->numAdvertised++] =
+ ssl_server_name_xtn;
+ }
+ }
+ return len + 9;
+ }
+ /* Server side */
+ if (append && maxBytes >= 4) {
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_server_name_xtn, 2);
+ if (rv != SECSuccess) return -1;
+ /* length of extension_data */
+ rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+ if (rv != SECSuccess) return -1;
+ }
+ return 4;
+}
+
+/* handle an incoming SNI extension, by ignoring it. */
+SECStatus
+ssl3_HandleServerNameXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
+{
+ SECItem *names = NULL;
+ PRUint32 listCount = 0, namesPos = 0, i;
+ TLSExtensionData *xtnData = &ss->xtnData;
+ SECItem ldata;
+ PRInt32 listLenBytes = 0;
+
+ if (!ss->sec.isServer) {
+ /* Verify extension_data is empty. */
+ if (data->data || data->len ||
+ !ssl3_ExtensionNegotiated(ss, ssl_server_name_xtn)) {
+ /* malformed or was not initiated by the client.*/
+ return SECFailure;
+ }
+ return SECSuccess;
+ }
+
+ /* Server side - consume client data and register server sender. */
+ /* do not parse the data if don't have user extension handling function. */
+ if (!ss->sniSocketConfig) {
+ return SECSuccess;
+ }
+ /* length of server_name_list */
+ listLenBytes = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+ if (listLenBytes == 0 || listLenBytes != data->len) {
+ return SECFailure;
+ }
+ ldata = *data;
+ /* Calculate the size of the array.*/
+ while (listLenBytes > 0) {
+ SECItem litem;
+ SECStatus rv;
+ PRInt32 type;
+ /* Name Type (sni_host_name) */
+ type = ssl3_ConsumeHandshakeNumber(ss, 1, &ldata.data, &ldata.len);
+ if (!ldata.len) {
+ return SECFailure;
+ }
+ rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 2, &ldata.data, &ldata.len);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ /* Adjust total length for cunsumed item, item len and type.*/
+ listLenBytes -= litem.len + 3;
+ if (listLenBytes > 0 && !ldata.len) {
+ return SECFailure;
+ }
+ listCount += 1;
+ }
+ if (!listCount) {
+ return SECFailure;
+ }
+ names = PORT_ZNewArray(SECItem, listCount);
+ if (!names) {
+ return SECFailure;
+ }
+ for (i = 0;i < listCount;i++) {
+ int j;
+ PRInt32 type;
+ SECStatus rv;
+ PRBool nametypePresent = PR_FALSE;
+ /* Name Type (sni_host_name) */
+ type = ssl3_ConsumeHandshakeNumber(ss, 1, &data->data, &data->len);
+ /* Check if we have such type in the list */
+ for (j = 0;j < listCount && names[j].data;j++) {
+ if (names[j].type == type) {
+ nametypePresent = PR_TRUE;
+ break;
+ }
+ }
+ /* HostName (length and value) */
+ rv = ssl3_ConsumeHandshakeVariable(ss, &names[namesPos], 2,
+ &data->data, &data->len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (nametypePresent == PR_FALSE) {
+ namesPos += 1;
+ }
+ }
+ /* Free old and set the new data. */
+ if (xtnData->sniNameArr) {
+ PORT_Free(ss->xtnData.sniNameArr);
+ }
+ xtnData->sniNameArr = names;
+ xtnData->sniNameArrSize = namesPos;
+ xtnData->negotiated[xtnData->numNegotiated++] = ssl_server_name_xtn;
+
+ return SECSuccess;
+
+loser:
+ PORT_Free(names);
+ return SECFailure;
+}
+
+/* Called by both clients and servers.
+ * Clients sends a filled in session ticket if one is available, and otherwise
+ * sends an empty ticket. Servers always send empty tickets.
+ */
+PRInt32
+ssl3_SendSessionTicketXtn(
+ sslSocket * ss,
+ PRBool append,
+ PRUint32 maxBytes)
+{
+ PRInt32 extension_length;
+ NewSessionTicket *session_ticket = NULL;
+
+ /* Ignore the SessionTicket extension if processing is disabled. */
+ if (!ss->opt.enableSessionTickets)
+ return 0;
+
+ /* Empty extension length = extension_type (2-bytes) +
+ * length(extension_data) (2-bytes)
+ */
+ extension_length = 4;
+
+ /* If we are a client then send a session ticket if one is availble.
+ * Servers that support the extension and are willing to negotiate the
+ * the extension always respond with an empty extension.
+ */
+ if (!ss->sec.isServer) {
+ sslSessionID *sid = ss->sec.ci.sid;
+ session_ticket = &sid->u.ssl3.sessionTicket;
+ if (session_ticket->ticket.data) {
+ if (ss->xtnData.ticketTimestampVerified) {
+ extension_length += session_ticket->ticket.len;
+ } else if (!append &&
+ (session_ticket->ticket_lifetime_hint == 0 ||
+ (session_ticket->ticket_lifetime_hint +
+ session_ticket->received_timestamp > ssl_Time()))) {
+ extension_length += session_ticket->ticket.len;
+ ss->xtnData.ticketTimestampVerified = PR_TRUE;
+ }
+ }
+ }
+
+ if (append && maxBytes >= extension_length) {
+ SECStatus rv;
+ /* extension_type */
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_session_ticket_xtn, 2);
+ if (rv != SECSuccess)
+ goto loser;
+ if (session_ticket && session_ticket->ticket.data &&
+ ss->xtnData.ticketTimestampVerified) {
+ rv = ssl3_AppendHandshakeVariable(ss, session_ticket->ticket.data,
+ session_ticket->ticket.len, 2);
+ ss->xtnData.ticketTimestampVerified = PR_FALSE;
+ } else {
+ rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+ }
+ if (rv != SECSuccess)
+ goto loser;
+
+ if (!ss->sec.isServer) {
+ TLSExtensionData *xtnData = &ss->xtnData;
+ xtnData->advertised[xtnData->numAdvertised++] =
+ ssl_session_ticket_xtn;
+ }
+ } else if (maxBytes < extension_length) {
+ PORT_Assert(0);
+ return 0;
+ }
+ return extension_length;
+
+ loser:
+ ss->xtnData.ticketTimestampVerified = PR_FALSE;
+ return -1;
+}
+
+/* handle an incoming Next Protocol Negotiation extension. */
+static SECStatus
+ssl3_ServerHandleNextProtoNegoXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
+{
+ if (ss->firstHsDone || data->len != 0) {
+ /* Clients MUST send an empty NPN extension, if any. */
+ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
+ return SECFailure;
+ }
+
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+
+ /* TODO: server side NPN support would require calling
+ * ssl3_RegisterServerHelloExtensionSender here in order to echo the
+ * extension back to the client. */
+
+ return SECSuccess;
+}
+
+/* ssl3_ValidateNextProtoNego checks that the given block of data is valid: none
+ * of the lengths may be 0 and the sum of the lengths must equal the length of
+ * the block. */
+SECStatus
+ssl3_ValidateNextProtoNego(const unsigned char* data, unsigned int length)
+{
+ unsigned int offset = 0;
+
+ while (offset < length) {
+ unsigned int newOffset = offset + 1 + (unsigned int) data[offset];
+ /* Reject embedded nulls to protect against buggy applications that
+ * store protocol identifiers in null-terminated strings.
+ */
+ if (newOffset > length || data[offset] == 0) {
+ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
+ return SECFailure;
+ }
+ offset = newOffset;
+ }
+
+ if (offset > length) {
+ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+static SECStatus
+ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type,
+ SECItem *data)
+{
+ SECStatus rv;
+ unsigned char resultBuffer[255];
+ SECItem result = { siBuffer, resultBuffer, 0 };
+
+ PORT_Assert(!ss->firstHsDone);
+
+ if (ssl3_ExtensionNegotiated(ss, ssl_app_layer_protocol_xtn)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ rv = ssl3_ValidateNextProtoNego(data->data, data->len);
+ if (rv != SECSuccess)
+ return rv;
+
+ /* ss->nextProtoCallback cannot normally be NULL if we negotiated the
+ * extension. However, It is possible that an application erroneously
+ * cleared the callback between the time we sent the ClientHello and now.
+ */
+ PORT_Assert(ss->nextProtoCallback != NULL);
+ if (!ss->nextProtoCallback) {
+ /* XXX Use a better error code. This is an application error, not an
+ * NSS bug. */
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ rv = ss->nextProtoCallback(ss->nextProtoArg, ss->fd, data->data, data->len,
+ result.data, &result.len, sizeof resultBuffer);
+ if (rv != SECSuccess)
+ return rv;
+ /* If the callback wrote more than allowed to |result| it has corrupted our
+ * stack. */
+ if (result.len > sizeof resultBuffer) {
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ return SECFailure;
+ }
+
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+
+ SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
+ return SECITEM_CopyItem(NULL, &ss->ssl3.nextProto, &result);
+}
+
+static SECStatus
+ssl3_ClientHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+{
+ const unsigned char* d = data->data;
+ PRUint16 name_list_len;
+ SECItem protocol_name;
+
+ if (ssl3_ExtensionNegotiated(ss, ssl_next_proto_nego_xtn)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ /* The extension data from the server has the following format:
+ * uint16 name_list_len;
+ * uint8 len;
+ * uint8 protocol_name[len]; */
+ if (data->len < 4 || data->len > 2 + 1 + 255) {
+ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
+ return SECFailure;
+ }
+
+ name_list_len = ((PRUint16) d[0]) << 8 |
+ ((PRUint16) d[1]);
+ if (name_list_len != data->len - 2 ||
+ d[2] != data->len - 3) {
+ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
+ return SECFailure;
+ }
+
+ protocol_name.data = data->data + 3;
+ protocol_name.len = data->len - 3;
+
+ SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
+ ss->ssl3.nextProtoState = SSL_NEXT_PROTO_SELECTED;
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+ return SECITEM_CopyItem(NULL, &ss->ssl3.nextProto, &protocol_name);
+}
+
+static PRInt32
+ssl3_ClientSendNextProtoNegoXtn(sslSocket * ss, PRBool append,
+ PRUint32 maxBytes)
+{
+ PRInt32 extension_length;
+
+ /* Renegotiations do not send this extension. */
+ if (!ss->nextProtoCallback || ss->firstHsDone) {
+ return 0;
+ }
+
+ extension_length = 4;
+
+ if (append && maxBytes >= extension_length) {
+ SECStatus rv;
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_next_proto_nego_xtn, 2);
+ if (rv != SECSuccess)
+ goto loser;
+ rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+ if (rv != SECSuccess)
+ goto loser;
+ ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+ ssl_next_proto_nego_xtn;
+ } else if (maxBytes < extension_length) {
+ return 0;
+ }
+
+ return extension_length;
+
+loser:
+ return -1;
+}
+
+static PRInt32
+ssl3_ClientSendAppProtoXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes)
+{
+ PRInt32 extension_length;
+ unsigned char *alpn_protos = NULL;
+
+ /* Renegotiations do not send this extension. */
+ if (!ss->opt.nextProtoNego.data || ss->firstHsDone) {
+ return 0;
+ }
+
+ extension_length = 2 /* extension type */ + 2 /* extension length */ +
+ 2 /* protocol name list length */ +
+ ss->opt.nextProtoNego.len;
+
+ if (append && maxBytes >= extension_length) {
+ /* NPN requires that the client's fallback protocol is first in the
+ * list. However, ALPN sends protocols in preference order. So we
+ * allocate a buffer and move the first protocol to the end of the
+ * list. */
+ SECStatus rv;
+ const unsigned int len = ss->opt.nextProtoNego.len;
+
+ alpn_protos = PORT_Alloc(len);
+ if (alpn_protos == NULL) {
+ return SECFailure;
+ }
+ if (len > 0) {
+ /* Each protocol string is prefixed with a single byte length. */
+ unsigned int i = ss->opt.nextProtoNego.data[0] + 1;
+ if (i <= len) {
+ memcpy(alpn_protos, &ss->opt.nextProtoNego.data[i], len - i);
+ memcpy(alpn_protos + len - i, ss->opt.nextProtoNego.data, i);
+ } else {
+ /* This seems to be invalid data so we'll send as-is. */
+ memcpy(alpn_protos, ss->opt.nextProtoNego.data, len);
+ }
+ }
+
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2);
+ if (rv != SECSuccess)
+ goto loser;
+ rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
+ if (rv != SECSuccess)
+ goto loser;
+ rv = ssl3_AppendHandshakeVariable(ss, alpn_protos, len, 2);
+ PORT_Free(alpn_protos);
+ alpn_protos = NULL;
+ if (rv != SECSuccess)
+ goto loser;
+ ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+ ssl_app_layer_protocol_xtn;
+ } else if (maxBytes < extension_length) {
+ return 0;
+ }
+
+ return extension_length;
+
+loser:
+ if (alpn_protos)
+ PORT_Free(alpn_protos);
+ return -1;
+}
+
+static SECStatus
+ssl3_ClientHandleChannelIDXtn(sslSocket *ss, PRUint16 ex_type,
+ SECItem *data)
+{
+ PORT_Assert(ss->getChannelID != NULL);
+
+ if (data->len) {
+ PORT_SetError(SSL_ERROR_BAD_CHANNEL_ID_DATA);
+ return SECFailure;
+ }
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+ return SECSuccess;
+}
+
+static PRInt32
+ssl3_ClientSendChannelIDXtn(sslSocket * ss, PRBool append,
+ PRUint32 maxBytes)
+{
+ PRInt32 extension_length = 4;
+
+ if (!ss->getChannelID)
+ return 0;
+
+ if (maxBytes < extension_length) {
+ PORT_Assert(0);
+ return 0;
+ }
+
+ if (append) {
+ SECStatus rv;
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_channel_id_xtn, 2);
+ if (rv != SECSuccess)
+ goto loser;
+ rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+ if (rv != SECSuccess)
+ goto loser;
+ ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+ ssl_channel_id_xtn;
+ }
+
+ return extension_length;
+
+loser:
+ return -1;
+}
+
+static SECStatus
+ssl3_ClientHandleStatusRequestXtn(sslSocket *ss, PRUint16 ex_type,
+ SECItem *data)
+{
+ /* The echoed extension must be empty. */
+ if (data->len != 0)
+ return SECFailure;
+
+ /* Keep track of negotiated extensions. */
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+
+ return SECSuccess;
+}
+
+static PRInt32
+ssl3_ServerSendStatusRequestXtn(
+ sslSocket * ss,
+ PRBool append,
+ PRUint32 maxBytes)
+{
+ PRInt32 extension_length;
+ SECStatus rv;
+ int i;
+ PRBool haveStatus = PR_FALSE;
+
+ for (i = kt_null; i < kt_kea_size; i++) {
+ /* TODO: This is a temporary workaround.
+ * The correct code needs to see if we have an OCSP response for
+ * the server certificate being used, rather than if we have any
+ * OCSP response. See also ssl3_SendCertificateStatus.
+ */
+ if (ss->certStatusArray[i] && ss->certStatusArray[i]->len) {
+ haveStatus = PR_TRUE;
+ break;
+ }
+ }
+ if (!haveStatus)
+ return 0;
+
+ extension_length = 2 + 2;
+ if (append && maxBytes >= extension_length) {
+ /* extension_type */
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_cert_status_xtn, 2);
+ if (rv != SECSuccess)
+ return -1;
+ /* length of extension_data */
+ rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+ if (rv != SECSuccess)
+ return -1;
+ }
+
+ return extension_length;
+}
+
+/* ssl3_ClientSendStatusRequestXtn builds the status_request extension on the
+ * client side. See RFC 4366 section 3.6. */
+static PRInt32
+ssl3_ClientSendStatusRequestXtn(sslSocket * ss, PRBool append,
+ PRUint32 maxBytes)
+{
+ PRInt32 extension_length;
+
+ if (!ss->opt.enableOCSPStapling)
+ return 0;
+
+ /* extension_type (2-bytes) +
+ * length(extension_data) (2-bytes) +
+ * status_type (1) +
+ * responder_id_list length (2) +
+ * request_extensions length (2)
+ */
+ extension_length = 9;
+
+ if (append && maxBytes >= extension_length) {
+ SECStatus rv;
+ TLSExtensionData *xtnData;
+
+ /* extension_type */
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_cert_status_xtn, 2);
+ if (rv != SECSuccess)
+ return -1;
+ rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
+ if (rv != SECSuccess)
+ return -1;
+ rv = ssl3_AppendHandshakeNumber(ss, 1 /* status_type ocsp */, 1);
+ if (rv != SECSuccess)
+ return -1;
+ /* A zero length responder_id_list means that the responders are
+ * implicitly known to the server. */
+ rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+ if (rv != SECSuccess)
+ return -1;
+ /* A zero length request_extensions means that there are no extensions.
+ * Specifically, we don't set the id-pkix-ocsp-nonce extension. This
+ * means that the server can replay a cached OCSP response to us. */
+ rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+ if (rv != SECSuccess)
+ return -1;
+
+ xtnData = &ss->xtnData;
+ xtnData->advertised[xtnData->numAdvertised++] = ssl_cert_status_xtn;
+ } else if (maxBytes < extension_length) {
+ PORT_Assert(0);
+ return 0;
+ }
+ return extension_length;
+}
+
+/*
+ * NewSessionTicket
+ * Called from ssl3_HandleFinished
+ */
+SECStatus
+ssl3_SendNewSessionTicket(sslSocket *ss)
+{
+ int i;
+ SECStatus rv;
+ NewSessionTicket ticket;
+ SECItem plaintext;
+ SECItem plaintext_item = {0, NULL, 0};
+ SECItem ciphertext = {0, NULL, 0};
+ PRUint32 ciphertext_length;
+ PRBool ms_is_wrapped;
+ unsigned char wrapped_ms[SSL3_MASTER_SECRET_LENGTH];
+ SECItem ms_item = {0, NULL, 0};
+ SSL3KEAType effectiveExchKeyType = ssl_kea_null;
+ PRUint32 padding_length;
+ PRUint32 message_length;
+ PRUint32 cert_length;
+ PRUint8 length_buf[4];
+ PRUint32 now;
+ PK11SymKey *aes_key_pkcs11;
+ PK11SymKey *mac_key_pkcs11;
+#ifndef NO_PKCS11_BYPASS
+ const unsigned char *aes_key;
+ const unsigned char *mac_key;
+ PRUint32 aes_key_length;
+ PRUint32 mac_key_length;
+ PRUint64 aes_ctx_buf[MAX_CIPHER_CONTEXT_LLONGS];
+ AESContext *aes_ctx;
+ const SECHashObject *hashObj = NULL;
+ PRUint64 hmac_ctx_buf[MAX_MAC_CONTEXT_LLONGS];
+ HMACContext *hmac_ctx;
+#endif
+ CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC;
+ PK11Context *aes_ctx_pkcs11;
+ CK_MECHANISM_TYPE macMech = CKM_SHA256_HMAC;
+ PK11Context *hmac_ctx_pkcs11;
+ unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH];
+ unsigned int computed_mac_length;
+ unsigned char iv[AES_BLOCK_SIZE];
+ SECItem ivItem;
+ SECItem *srvName = NULL;
+ PRUint32 srvNameLen = 0;
+ CK_MECHANISM_TYPE msWrapMech = 0; /* dummy default value,
+ * must be >= 0 */
+
+ SSL_TRC(3, ("%d: SSL3[%d]: send session_ticket handshake",
+ SSL_GETPID(), ss->fd));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ ticket.ticket_lifetime_hint = TLS_EX_SESS_TICKET_LIFETIME_HINT;
+ cert_length = (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) ?
+ 3 + ss->sec.ci.sid->peerCert->derCert.len : 0;
+
+ /* Get IV and encryption keys */
+ ivItem.data = iv;
+ ivItem.len = sizeof(iv);
+ rv = PK11_GenerateRandom(iv, sizeof(iv));
+ if (rv != SECSuccess) goto loser;
+
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11) {
+ rv = ssl3_GetSessionTicketKeys(&aes_key, &aes_key_length,
+ &mac_key, &mac_key_length);
+ } else
+#endif
+ {
+ rv = ssl3_GetSessionTicketKeysPKCS11(ss, &aes_key_pkcs11,
+ &mac_key_pkcs11);
+ }
+ if (rv != SECSuccess) goto loser;
+
+ if (ss->ssl3.pwSpec->msItem.len && ss->ssl3.pwSpec->msItem.data) {
+ /* The master secret is available unwrapped. */
+ ms_item.data = ss->ssl3.pwSpec->msItem.data;
+ ms_item.len = ss->ssl3.pwSpec->msItem.len;
+ ms_is_wrapped = PR_FALSE;
+ } else {
+ /* Extract the master secret wrapped. */
+ sslSessionID sid;
+ PORT_Memset(&sid, 0, sizeof(sslSessionID));
+
+ if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) {
+ effectiveExchKeyType = kt_rsa;
+ } else {
+ effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType;
+ }
+
+ rv = ssl3_CacheWrappedMasterSecret(ss, &sid, ss->ssl3.pwSpec,
+ effectiveExchKeyType);
+ if (rv == SECSuccess) {
+ if (sid.u.ssl3.keys.wrapped_master_secret_len > sizeof(wrapped_ms))
+ goto loser;
+ memcpy(wrapped_ms, sid.u.ssl3.keys.wrapped_master_secret,
+ sid.u.ssl3.keys.wrapped_master_secret_len);
+ ms_item.data = wrapped_ms;
+ ms_item.len = sid.u.ssl3.keys.wrapped_master_secret_len;
+ msWrapMech = sid.u.ssl3.masterWrapMech;
+ } else {
+ /* TODO: else send an empty ticket. */
+ goto loser;
+ }
+ ms_is_wrapped = PR_TRUE;
+ }
+ /* Prep to send negotiated name */
+ srvName = &ss->ssl3.pwSpec->srvVirtName;
+ if (srvName->data && srvName->len) {
+ srvNameLen = 2 + srvName->len; /* len bytes + name len */
+ }
+
+ ciphertext_length =
+ sizeof(PRUint16) /* ticket_version */
+ + sizeof(SSL3ProtocolVersion) /* ssl_version */
+ + sizeof(ssl3CipherSuite) /* ciphersuite */
+ + 1 /* compression */
+ + 10 /* cipher spec parameters */
+ + 1 /* SessionTicket.ms_is_wrapped */
+ + 1 /* effectiveExchKeyType */
+ + 4 /* msWrapMech */
+ + 2 /* master_secret.length */
+ + ms_item.len /* master_secret */
+ + 1 /* client_auth_type */
+ + cert_length /* cert */
+ + 1 /* server name type */
+ + srvNameLen /* name len + length field */
+ + sizeof(ticket.ticket_lifetime_hint);
+ padding_length = AES_BLOCK_SIZE -
+ (ciphertext_length % AES_BLOCK_SIZE);
+ ciphertext_length += padding_length;
+
+ message_length =
+ sizeof(ticket.ticket_lifetime_hint) /* ticket_lifetime_hint */
+ + 2 /* length field for NewSessionTicket.ticket */
+ + SESS_TICKET_KEY_NAME_LEN /* key_name */
+ + AES_BLOCK_SIZE /* iv */
+ + 2 /* length field for NewSessionTicket.ticket.encrypted_state */
+ + ciphertext_length /* encrypted_state */
+ + TLS_EX_SESS_TICKET_MAC_LENGTH; /* mac */
+
+ if (SECITEM_AllocItem(NULL, &plaintext_item, ciphertext_length) == NULL)
+ goto loser;
+
+ plaintext = plaintext_item;
+
+ /* ticket_version */
+ rv = ssl3_AppendNumberToItem(&plaintext, TLS_EX_SESS_TICKET_VERSION,
+ sizeof(PRUint16));
+ if (rv != SECSuccess) goto loser;
+
+ /* ssl_version */
+ rv = ssl3_AppendNumberToItem(&plaintext, ss->version,
+ sizeof(SSL3ProtocolVersion));
+ if (rv != SECSuccess) goto loser;
+
+ /* ciphersuite */
+ rv = ssl3_AppendNumberToItem(&plaintext, ss->ssl3.hs.cipher_suite,
+ sizeof(ssl3CipherSuite));
+ if (rv != SECSuccess) goto loser;
+
+ /* compression */
+ rv = ssl3_AppendNumberToItem(&plaintext, ss->ssl3.hs.compression, 1);
+ if (rv != SECSuccess) goto loser;
+
+ /* cipher spec parameters */
+ rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authAlgorithm, 1);
+ if (rv != SECSuccess) goto loser;
+ rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authKeyBits, 4);
+ if (rv != SECSuccess) goto loser;
+ rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaType, 1);
+ if (rv != SECSuccess) goto loser;
+ rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaKeyBits, 4);
+ if (rv != SECSuccess) goto loser;
+
+ /* master_secret */
+ rv = ssl3_AppendNumberToItem(&plaintext, ms_is_wrapped, 1);
+ if (rv != SECSuccess) goto loser;
+ rv = ssl3_AppendNumberToItem(&plaintext, effectiveExchKeyType, 1);
+ if (rv != SECSuccess) goto loser;
+ rv = ssl3_AppendNumberToItem(&plaintext, msWrapMech, 4);
+ if (rv != SECSuccess) goto loser;
+ rv = ssl3_AppendNumberToItem(&plaintext, ms_item.len, 2);
+ if (rv != SECSuccess) goto loser;
+ rv = ssl3_AppendToItem(&plaintext, ms_item.data, ms_item.len);
+ if (rv != SECSuccess) goto loser;
+
+ /* client_identity */
+ if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) {
+ rv = ssl3_AppendNumberToItem(&plaintext, CLIENT_AUTH_CERTIFICATE, 1);
+ if (rv != SECSuccess) goto loser;
+ rv = ssl3_AppendNumberToItem(&plaintext,
+ ss->sec.ci.sid->peerCert->derCert.len, 3);
+ if (rv != SECSuccess) goto loser;
+ rv = ssl3_AppendToItem(&plaintext,
+ ss->sec.ci.sid->peerCert->derCert.data,
+ ss->sec.ci.sid->peerCert->derCert.len);
+ if (rv != SECSuccess) goto loser;
+ } else {
+ rv = ssl3_AppendNumberToItem(&plaintext, 0, 1);
+ if (rv != SECSuccess) goto loser;
+ }
+
+ /* timestamp */
+ now = ssl_Time();
+ rv = ssl3_AppendNumberToItem(&plaintext, now,
+ sizeof(ticket.ticket_lifetime_hint));
+ if (rv != SECSuccess) goto loser;
+
+ if (srvNameLen) {
+ /* Name Type (sni_host_name) */
+ rv = ssl3_AppendNumberToItem(&plaintext, srvName->type, 1);
+ if (rv != SECSuccess) goto loser;
+ /* HostName (length and value) */
+ rv = ssl3_AppendNumberToItem(&plaintext, srvName->len, 2);
+ if (rv != SECSuccess) goto loser;
+ rv = ssl3_AppendToItem(&plaintext, srvName->data, srvName->len);
+ if (rv != SECSuccess) goto loser;
+ } else {
+ /* No Name */
+ rv = ssl3_AppendNumberToItem(&plaintext, (char)TLS_STE_NO_SERVER_NAME,
+ 1);
+ if (rv != SECSuccess) goto loser;
+ }
+
+ PORT_Assert(plaintext.len == padding_length);
+ for (i = 0; i < padding_length; i++)
+ plaintext.data[i] = (unsigned char)padding_length;
+
+ if (SECITEM_AllocItem(NULL, &ciphertext, ciphertext_length) == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+
+ /* Generate encrypted portion of ticket. */
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11) {
+ aes_ctx = (AESContext *)aes_ctx_buf;
+ rv = AES_InitContext(aes_ctx, aes_key, aes_key_length, iv,
+ NSS_AES_CBC, 1, AES_BLOCK_SIZE);
+ if (rv != SECSuccess) goto loser;
+
+ rv = AES_Encrypt(aes_ctx, ciphertext.data, &ciphertext.len,
+ ciphertext.len, plaintext_item.data,
+ plaintext_item.len);
+ if (rv != SECSuccess) goto loser;
+ } else
+#endif
+ {
+ aes_ctx_pkcs11 = PK11_CreateContextBySymKey(cipherMech,
+ CKA_ENCRYPT, aes_key_pkcs11, &ivItem);
+ if (!aes_ctx_pkcs11)
+ goto loser;
+
+ rv = PK11_CipherOp(aes_ctx_pkcs11, ciphertext.data,
+ (int *)&ciphertext.len, ciphertext.len,
+ plaintext_item.data, plaintext_item.len);
+ PK11_Finalize(aes_ctx_pkcs11);
+ PK11_DestroyContext(aes_ctx_pkcs11, PR_TRUE);
+ if (rv != SECSuccess) goto loser;
+ }
+
+ /* Convert ciphertext length to network order. */
+ length_buf[0] = (ciphertext.len >> 8) & 0xff;
+ length_buf[1] = (ciphertext.len ) & 0xff;
+
+ /* Compute MAC. */
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11) {
+ hmac_ctx = (HMACContext *)hmac_ctx_buf;
+ hashObj = HASH_GetRawHashObject(HASH_AlgSHA256);
+ if (HMAC_Init(hmac_ctx, hashObj, mac_key,
+ mac_key_length, PR_FALSE) != SECSuccess)
+ goto loser;
+
+ HMAC_Begin(hmac_ctx);
+ HMAC_Update(hmac_ctx, key_name, SESS_TICKET_KEY_NAME_LEN);
+ HMAC_Update(hmac_ctx, iv, sizeof(iv));
+ HMAC_Update(hmac_ctx, (unsigned char *)length_buf, 2);
+ HMAC_Update(hmac_ctx, ciphertext.data, ciphertext.len);
+ HMAC_Finish(hmac_ctx, computed_mac, &computed_mac_length,
+ sizeof(computed_mac));
+ } else
+#endif
+ {
+ SECItem macParam;
+ macParam.data = NULL;
+ macParam.len = 0;
+ hmac_ctx_pkcs11 = PK11_CreateContextBySymKey(macMech,
+ CKA_SIGN, mac_key_pkcs11, &macParam);
+ if (!hmac_ctx_pkcs11)
+ goto loser;
+
+ rv = PK11_DigestBegin(hmac_ctx_pkcs11);
+ rv = PK11_DigestOp(hmac_ctx_pkcs11, key_name,
+ SESS_TICKET_KEY_NAME_LEN);
+ rv = PK11_DigestOp(hmac_ctx_pkcs11, iv, sizeof(iv));
+ rv = PK11_DigestOp(hmac_ctx_pkcs11, (unsigned char *)length_buf, 2);
+ rv = PK11_DigestOp(hmac_ctx_pkcs11, ciphertext.data, ciphertext.len);
+ rv = PK11_DigestFinal(hmac_ctx_pkcs11, computed_mac,
+ &computed_mac_length, sizeof(computed_mac));
+ PK11_DestroyContext(hmac_ctx_pkcs11, PR_TRUE);
+ if (rv != SECSuccess) goto loser;
+ }
+
+ /* Serialize the handshake message. */
+ rv = ssl3_AppendHandshakeHeader(ss, new_session_ticket, message_length);
+ if (rv != SECSuccess) goto loser;
+
+ rv = ssl3_AppendHandshakeNumber(ss, ticket.ticket_lifetime_hint,
+ sizeof(ticket.ticket_lifetime_hint));
+ if (rv != SECSuccess) goto loser;
+
+ rv = ssl3_AppendHandshakeNumber(ss,
+ message_length - sizeof(ticket.ticket_lifetime_hint) - 2, 2);
+ if (rv != SECSuccess) goto loser;
+
+ rv = ssl3_AppendHandshake(ss, key_name, SESS_TICKET_KEY_NAME_LEN);
+ if (rv != SECSuccess) goto loser;
+
+ rv = ssl3_AppendHandshake(ss, iv, sizeof(iv));
+ if (rv != SECSuccess) goto loser;
+
+ rv = ssl3_AppendHandshakeVariable(ss, ciphertext.data, ciphertext.len, 2);
+ if (rv != SECSuccess) goto loser;
+
+ rv = ssl3_AppendHandshake(ss, computed_mac, computed_mac_length);
+ if (rv != SECSuccess) goto loser;
+
+loser:
+ if (plaintext_item.data)
+ SECITEM_FreeItem(&plaintext_item, PR_FALSE);
+ if (ciphertext.data)
+ SECITEM_FreeItem(&ciphertext, PR_FALSE);
+
+ return rv;
+}
+
+/* When a client receives a SessionTicket extension a NewSessionTicket
+ * message is expected during the handshake.
+ */
+SECStatus
+ssl3_ClientHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type,
+ SECItem *data)
+{
+ if (data->len != 0)
+ return SECFailure;
+
+ /* Keep track of negotiated extensions. */
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+ return SECSuccess;
+}
+
+SECStatus
+ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type,
+ SECItem *data)
+{
+ SECStatus rv;
+ SECItem *decrypted_state = NULL;
+ SessionTicket *parsed_session_ticket = NULL;
+ sslSessionID *sid = NULL;
+ SSL3Statistics *ssl3stats;
+
+ /* Ignore the SessionTicket extension if processing is disabled. */
+ if (!ss->opt.enableSessionTickets)
+ return SECSuccess;
+
+ /* Keep track of negotiated extensions. */
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+
+ /* Parse the received ticket sent in by the client. We are
+ * lenient about some parse errors, falling back to a fullshake
+ * instead of terminating the current connection.
+ */
+ if (data->len == 0) {
+ ss->xtnData.emptySessionTicket = PR_TRUE;
+ } else {
+ int i;
+ SECItem extension_data;
+ EncryptedSessionTicket enc_session_ticket;
+ unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH];
+ unsigned int computed_mac_length;
+#ifndef NO_PKCS11_BYPASS
+ const SECHashObject *hashObj;
+ const unsigned char *aes_key;
+ const unsigned char *mac_key;
+ PRUint32 aes_key_length;
+ PRUint32 mac_key_length;
+ PRUint64 hmac_ctx_buf[MAX_MAC_CONTEXT_LLONGS];
+ HMACContext *hmac_ctx;
+ PRUint64 aes_ctx_buf[MAX_CIPHER_CONTEXT_LLONGS];
+ AESContext *aes_ctx;
+#endif
+ PK11SymKey *aes_key_pkcs11;
+ PK11SymKey *mac_key_pkcs11;
+ PK11Context *hmac_ctx_pkcs11;
+ CK_MECHANISM_TYPE macMech = CKM_SHA256_HMAC;
+ PK11Context *aes_ctx_pkcs11;
+ CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC;
+ unsigned char * padding;
+ PRUint32 padding_length;
+ unsigned char *buffer;
+ unsigned int buffer_len;
+ PRInt32 temp;
+ SECItem cert_item;
+ PRInt8 nameType = TLS_STE_NO_SERVER_NAME;
+
+ /* Turn off stateless session resumption if the client sends a
+ * SessionTicket extension, even if the extension turns out to be
+ * malformed (ss->sec.ci.sid is non-NULL when doing session
+ * renegotiation.)
+ */
+ if (ss->sec.ci.sid != NULL) {
+ if (ss->sec.uncache)
+ ss->sec.uncache(ss->sec.ci.sid);
+ ssl_FreeSID(ss->sec.ci.sid);
+ ss->sec.ci.sid = NULL;
+ }
+
+ extension_data.data = data->data; /* Keep a copy for future use. */
+ extension_data.len = data->len;
+
+ if (ssl3_ParseEncryptedSessionTicket(ss, data, &enc_session_ticket)
+ != SECSuccess)
+ return SECFailure;
+
+ /* Get session ticket keys. */
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11) {
+ rv = ssl3_GetSessionTicketKeys(&aes_key, &aes_key_length,
+ &mac_key, &mac_key_length);
+ } else
+#endif
+ {
+ rv = ssl3_GetSessionTicketKeysPKCS11(ss, &aes_key_pkcs11,
+ &mac_key_pkcs11);
+ }
+ if (rv != SECSuccess) {
+ SSL_DBG(("%d: SSL[%d]: Unable to get/generate session ticket keys.",
+ SSL_GETPID(), ss->fd));
+ goto loser;
+ }
+
+ /* If the ticket sent by the client was generated under a key different
+ * from the one we have, bypass ticket processing.
+ */
+ if (PORT_Memcmp(enc_session_ticket.key_name, key_name,
+ SESS_TICKET_KEY_NAME_LEN) != 0) {
+ SSL_DBG(("%d: SSL[%d]: Session ticket key_name sent mismatch.",
+ SSL_GETPID(), ss->fd));
+ goto no_ticket;
+ }
+
+ /* Verify the MAC on the ticket. MAC verification may also
+ * fail if the MAC key has been recently refreshed.
+ */
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11) {
+ hmac_ctx = (HMACContext *)hmac_ctx_buf;
+ hashObj = HASH_GetRawHashObject(HASH_AlgSHA256);
+ if (HMAC_Init(hmac_ctx, hashObj, mac_key,
+ sizeof(session_ticket_mac_key), PR_FALSE) != SECSuccess)
+ goto no_ticket;
+ HMAC_Begin(hmac_ctx);
+ HMAC_Update(hmac_ctx, extension_data.data,
+ extension_data.len - TLS_EX_SESS_TICKET_MAC_LENGTH);
+ if (HMAC_Finish(hmac_ctx, computed_mac, &computed_mac_length,
+ sizeof(computed_mac)) != SECSuccess)
+ goto no_ticket;
+ } else
+#endif
+ {
+ SECItem macParam;
+ macParam.data = NULL;
+ macParam.len = 0;
+ hmac_ctx_pkcs11 = PK11_CreateContextBySymKey(macMech,
+ CKA_SIGN, mac_key_pkcs11, &macParam);
+ if (!hmac_ctx_pkcs11) {
+ SSL_DBG(("%d: SSL[%d]: Unable to create HMAC context: %d.",
+ SSL_GETPID(), ss->fd, PORT_GetError()));
+ goto no_ticket;
+ } else {
+ SSL_DBG(("%d: SSL[%d]: Successfully created HMAC context.",
+ SSL_GETPID(), ss->fd));
+ }
+ rv = PK11_DigestBegin(hmac_ctx_pkcs11);
+ rv = PK11_DigestOp(hmac_ctx_pkcs11, extension_data.data,
+ extension_data.len - TLS_EX_SESS_TICKET_MAC_LENGTH);
+ if (rv != SECSuccess) {
+ PK11_DestroyContext(hmac_ctx_pkcs11, PR_TRUE);
+ goto no_ticket;
+ }
+ rv = PK11_DigestFinal(hmac_ctx_pkcs11, computed_mac,
+ &computed_mac_length, sizeof(computed_mac));
+ PK11_DestroyContext(hmac_ctx_pkcs11, PR_TRUE);
+ if (rv != SECSuccess)
+ goto no_ticket;
+ }
+ if (NSS_SecureMemcmp(computed_mac, enc_session_ticket.mac,
+ computed_mac_length) != 0) {
+ SSL_DBG(("%d: SSL[%d]: Session ticket MAC mismatch.",
+ SSL_GETPID(), ss->fd));
+ goto no_ticket;
+ }
+
+ /* We ignore key_name for now.
+ * This is ok as MAC verification succeeded.
+ */
+
+ /* Decrypt the ticket. */
+
+ /* Plaintext is shorter than the ciphertext due to padding. */
+ decrypted_state = SECITEM_AllocItem(NULL, NULL,
+ enc_session_ticket.encrypted_state.len);
+
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11) {
+ aes_ctx = (AESContext *)aes_ctx_buf;
+ rv = AES_InitContext(aes_ctx, aes_key,
+ sizeof(session_ticket_enc_key), enc_session_ticket.iv,
+ NSS_AES_CBC, 0,AES_BLOCK_SIZE);
+ if (rv != SECSuccess) {
+ SSL_DBG(("%d: SSL[%d]: Unable to create AES context.",
+ SSL_GETPID(), ss->fd));
+ goto no_ticket;
+ }
+
+ rv = AES_Decrypt(aes_ctx, decrypted_state->data,
+ &decrypted_state->len, decrypted_state->len,
+ enc_session_ticket.encrypted_state.data,
+ enc_session_ticket.encrypted_state.len);
+ if (rv != SECSuccess)
+ goto no_ticket;
+ } else
+#endif
+ {
+ SECItem ivItem;
+ ivItem.data = enc_session_ticket.iv;
+ ivItem.len = AES_BLOCK_SIZE;
+ aes_ctx_pkcs11 = PK11_CreateContextBySymKey(cipherMech,
+ CKA_DECRYPT, aes_key_pkcs11, &ivItem);
+ if (!aes_ctx_pkcs11) {
+ SSL_DBG(("%d: SSL[%d]: Unable to create AES context.",
+ SSL_GETPID(), ss->fd));
+ goto no_ticket;
+ }
+
+ rv = PK11_CipherOp(aes_ctx_pkcs11, decrypted_state->data,
+ (int *)&decrypted_state->len, decrypted_state->len,
+ enc_session_ticket.encrypted_state.data,
+ enc_session_ticket.encrypted_state.len);
+ PK11_Finalize(aes_ctx_pkcs11);
+ PK11_DestroyContext(aes_ctx_pkcs11, PR_TRUE);
+ if (rv != SECSuccess)
+ goto no_ticket;
+ }
+
+ /* Check padding. */
+ padding_length =
+ (PRUint32)decrypted_state->data[decrypted_state->len - 1];
+ if (padding_length == 0 || padding_length > AES_BLOCK_SIZE)
+ goto no_ticket;
+
+ padding = &decrypted_state->data[decrypted_state->len - padding_length];
+ for (i = 0; i < padding_length; i++, padding++) {
+ if (padding_length != (PRUint32)*padding)
+ goto no_ticket;
+ }
+
+ /* Deserialize session state. */
+ buffer = decrypted_state->data;
+ buffer_len = decrypted_state->len;
+
+ parsed_session_ticket = PORT_ZAlloc(sizeof(SessionTicket));
+ if (parsed_session_ticket == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+
+ /* Read ticket_version (which is ignored for now.) */
+ temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
+ if (temp < 0) goto no_ticket;
+ parsed_session_ticket->ticket_version = (SSL3ProtocolVersion)temp;
+
+ /* Read SSLVersion. */
+ temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
+ if (temp < 0) goto no_ticket;
+ parsed_session_ticket->ssl_version = (SSL3ProtocolVersion)temp;
+
+ /* Read cipher_suite. */
+ temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
+ if (temp < 0) goto no_ticket;
+ parsed_session_ticket->cipher_suite = (ssl3CipherSuite)temp;
+
+ /* Read compression_method. */
+ temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+ if (temp < 0) goto no_ticket;
+ parsed_session_ticket->compression_method = (SSLCompressionMethod)temp;
+
+ /* Read cipher spec parameters. */
+ temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+ if (temp < 0) goto no_ticket;
+ parsed_session_ticket->authAlgorithm = (SSLSignType)temp;
+ temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
+ if (temp < 0) goto no_ticket;
+ parsed_session_ticket->authKeyBits = (PRUint32)temp;
+ temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+ if (temp < 0) goto no_ticket;
+ parsed_session_ticket->keaType = (SSLKEAType)temp;
+ temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
+ if (temp < 0) goto no_ticket;
+ parsed_session_ticket->keaKeyBits = (PRUint32)temp;
+
+ /* Read wrapped master_secret. */
+ temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+ if (temp < 0) goto no_ticket;
+ parsed_session_ticket->ms_is_wrapped = (PRBool)temp;
+
+ temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+ if (temp < 0) goto no_ticket;
+ parsed_session_ticket->exchKeyType = (SSL3KEAType)temp;
+
+ temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
+ if (temp < 0) goto no_ticket;
+ parsed_session_ticket->msWrapMech = (CK_MECHANISM_TYPE)temp;
+
+ temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
+ if (temp < 0) goto no_ticket;
+ parsed_session_ticket->ms_length = (PRUint16)temp;
+ if (parsed_session_ticket->ms_length == 0 || /* sanity check MS. */
+ parsed_session_ticket->ms_length >
+ sizeof(parsed_session_ticket->master_secret))
+ goto no_ticket;
+
+ /* Allow for the wrapped master secret to be longer. */
+ if (buffer_len < sizeof(SSL3_MASTER_SECRET_LENGTH))
+ goto no_ticket;
+ PORT_Memcpy(parsed_session_ticket->master_secret, buffer,
+ parsed_session_ticket->ms_length);
+ buffer += parsed_session_ticket->ms_length;
+ buffer_len -= parsed_session_ticket->ms_length;
+
+ /* Read client_identity */
+ temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+ if (temp < 0)
+ goto no_ticket;
+ parsed_session_ticket->client_identity.client_auth_type =
+ (ClientAuthenticationType)temp;
+ switch(parsed_session_ticket->client_identity.client_auth_type) {
+ case CLIENT_AUTH_ANONYMOUS:
+ break;
+ case CLIENT_AUTH_CERTIFICATE:
+ rv = ssl3_ConsumeHandshakeVariable(ss, &cert_item, 3,
+ &buffer, &buffer_len);
+ if (rv != SECSuccess) goto no_ticket;
+ rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->peer_cert,
+ &cert_item);
+ if (rv != SECSuccess) goto no_ticket;
+ break;
+ default:
+ goto no_ticket;
+ }
+ /* Read timestamp. */
+ temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
+ if (temp < 0)
+ goto no_ticket;
+ parsed_session_ticket->timestamp = (PRUint32)temp;
+
+ /* Read server name */
+ nameType =
+ ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+ if (nameType != TLS_STE_NO_SERVER_NAME) {
+ SECItem name_item;
+ rv = ssl3_ConsumeHandshakeVariable(ss, &name_item, 2, &buffer,
+ &buffer_len);
+ if (rv != SECSuccess) goto no_ticket;
+ rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->srvName,
+ &name_item);
+ if (rv != SECSuccess) goto no_ticket;
+ parsed_session_ticket->srvName.type = nameType;
+ }
+
+ /* Done parsing. Check that all bytes have been consumed. */
+ if (buffer_len != padding_length)
+ goto no_ticket;
+
+ /* Use the ticket if it has not expired, otherwise free the allocated
+ * memory since the ticket is of no use.
+ */
+ if (parsed_session_ticket->timestamp != 0 &&
+ parsed_session_ticket->timestamp +
+ TLS_EX_SESS_TICKET_LIFETIME_HINT > ssl_Time()) {
+
+ sid = ssl3_NewSessionID(ss, PR_TRUE);
+ if (sid == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+
+ /* Copy over parameters. */
+ sid->version = parsed_session_ticket->ssl_version;
+ sid->u.ssl3.cipherSuite = parsed_session_ticket->cipher_suite;
+ sid->u.ssl3.compression = parsed_session_ticket->compression_method;
+ sid->authAlgorithm = parsed_session_ticket->authAlgorithm;
+ sid->authKeyBits = parsed_session_ticket->authKeyBits;
+ sid->keaType = parsed_session_ticket->keaType;
+ sid->keaKeyBits = parsed_session_ticket->keaKeyBits;
+
+ /* Copy master secret. */
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11 &&
+ parsed_session_ticket->ms_is_wrapped)
+ goto no_ticket;
+#endif
+ if (parsed_session_ticket->ms_length >
+ sizeof(sid->u.ssl3.keys.wrapped_master_secret))
+ goto no_ticket;
+ PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret,
+ parsed_session_ticket->master_secret,
+ parsed_session_ticket->ms_length);
+ sid->u.ssl3.keys.wrapped_master_secret_len =
+ parsed_session_ticket->ms_length;
+ sid->u.ssl3.exchKeyType = parsed_session_ticket->exchKeyType;
+ sid->u.ssl3.masterWrapMech = parsed_session_ticket->msWrapMech;
+ sid->u.ssl3.keys.msIsWrapped =
+ parsed_session_ticket->ms_is_wrapped;
+ sid->u.ssl3.masterValid = PR_TRUE;
+ sid->u.ssl3.keys.resumable = PR_TRUE;
+
+ /* Copy over client cert from session ticket if there is one. */
+ if (parsed_session_ticket->peer_cert.data != NULL) {
+ if (sid->peerCert != NULL)
+ CERT_DestroyCertificate(sid->peerCert);
+ sid->peerCert = CERT_NewTempCertificate(ss->dbHandle,
+ &parsed_session_ticket->peer_cert, NULL, PR_FALSE, PR_TRUE);
+ if (sid->peerCert == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+ }
+ if (parsed_session_ticket->srvName.data != NULL) {
+ sid->u.ssl3.srvName = parsed_session_ticket->srvName;
+ }
+ ss->statelessResume = PR_TRUE;
+ ss->sec.ci.sid = sid;
+ }
+ }
+
+ if (0) {
+no_ticket:
+ SSL_DBG(("%d: SSL[%d]: Session ticket parsing failed.",
+ SSL_GETPID(), ss->fd));
+ ssl3stats = SSL_GetStatistics();
+ SSL_AtomicIncrementLong(& ssl3stats->hch_sid_ticket_parse_failures );
+ }
+ rv = SECSuccess;
+
+loser:
+ /* ss->sec.ci.sid == sid if it did NOT come here via goto statement
+ * in that case do not free sid
+ */
+ if (sid && (ss->sec.ci.sid != sid)) {
+ ssl_FreeSID(sid);
+ sid = NULL;
+ }
+ if (decrypted_state != NULL) {
+ SECITEM_FreeItem(decrypted_state, PR_TRUE);
+ decrypted_state = NULL;
+ }
+
+ if (parsed_session_ticket != NULL) {
+ if (parsed_session_ticket->peer_cert.data) {
+ SECITEM_FreeItem(&parsed_session_ticket->peer_cert, PR_FALSE);
+ }
+ PORT_ZFree(parsed_session_ticket, sizeof(SessionTicket));
+ }
+
+ return rv;
+}
+
+/*
+ * Read bytes. Using this function means the SECItem structure
+ * cannot be freed. The caller is expected to call this function
+ * on a shallow copy of the structure.
+ */
+static SECStatus
+ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes)
+{
+ if (bytes > item->len)
+ return SECFailure;
+
+ *buf = item->data;
+ item->data += bytes;
+ item->len -= bytes;
+ return SECSuccess;
+}
+
+static SECStatus
+ssl3_ParseEncryptedSessionTicket(sslSocket *ss, SECItem *data,
+ EncryptedSessionTicket *enc_session_ticket)
+{
+ if (ssl3_ConsumeFromItem(data, &enc_session_ticket->key_name,
+ SESS_TICKET_KEY_NAME_LEN) != SECSuccess)
+ return SECFailure;
+ if (ssl3_ConsumeFromItem(data, &enc_session_ticket->iv,
+ AES_BLOCK_SIZE) != SECSuccess)
+ return SECFailure;
+ if (ssl3_ConsumeHandshakeVariable(ss, &enc_session_ticket->encrypted_state,
+ 2, &data->data, &data->len) != SECSuccess)
+ return SECFailure;
+ if (ssl3_ConsumeFromItem(data, &enc_session_ticket->mac,
+ TLS_EX_SESS_TICKET_MAC_LENGTH) != SECSuccess)
+ return SECFailure;
+ if (data->len != 0) /* Make sure that we have consumed all bytes. */
+ return SECFailure;
+
+ return SECSuccess;
+}
+
+/* go through hello extensions in buffer "b".
+ * For each one, find the extension handler in the table, and
+ * if present, invoke that handler.
+ * Servers ignore any extensions with unknown extension types.
+ * Clients reject any extensions with unadvertised extension types.
+ */
+SECStatus
+ssl3_HandleHelloExtensions(sslSocket *ss, SSL3Opaque **b, PRUint32 *length)
+{
+ const ssl3HelloExtensionHandler * handlers;
+
+ if (ss->sec.isServer) {
+ handlers = clientHelloHandlers;
+ } else if (ss->version > SSL_LIBRARY_VERSION_3_0) {
+ handlers = serverHelloHandlersTLS;
+ } else {
+ handlers = serverHelloHandlersSSL3;
+ }
+
+ while (*length) {
+ const ssl3HelloExtensionHandler * handler;
+ SECStatus rv;
+ PRInt32 extension_type;
+ SECItem extension_data;
+
+ /* Get the extension's type field */
+ extension_type = ssl3_ConsumeHandshakeNumber(ss, 2, b, length);
+ if (extension_type < 0) /* failure to decode extension_type */
+ return SECFailure; /* alert already sent */
+
+ /* get the data for this extension, so we can pass it or skip it. */
+ rv = ssl3_ConsumeHandshakeVariable(ss, &extension_data, 2, b, length);
+ if (rv != SECSuccess)
+ return rv;
+
+ /* Check whether the server sent an extension which was not advertised
+ * in the ClientHello.
+ */
+ if (!ss->sec.isServer &&
+ !ssl3_ClientExtensionAdvertised(ss, extension_type))
+ return SECFailure; /* TODO: send unsupported_extension alert */
+
+ /* Check whether an extension has been sent multiple times. */
+ if (ssl3_ExtensionNegotiated(ss, extension_type))
+ return SECFailure;
+
+ /* find extension_type in table of Hello Extension Handlers */
+ for (handler = handlers; handler->ex_type >= 0; handler++) {
+ /* if found, call this handler */
+ if (handler->ex_type == extension_type) {
+ rv = (*handler->ex_handler)(ss, (PRUint16)extension_type,
+ &extension_data);
+ /* Ignore this result */
+ /* Treat all bad extensions as unrecognized types. */
+ break;
+ }
+ }
+ }
+ return SECSuccess;
+}
+
+/* Add a callback function to the table of senders of server hello extensions.
+ */
+SECStatus
+ssl3_RegisterServerHelloExtensionSender(sslSocket *ss, PRUint16 ex_type,
+ ssl3HelloExtensionSenderFunc cb)
+{
+ int i;
+ ssl3HelloExtensionSender *sender = &ss->xtnData.serverSenders[0];
+
+ for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) {
+ if (!sender->ex_sender) {
+ sender->ex_type = ex_type;
+ sender->ex_sender = cb;
+ return SECSuccess;
+ }
+ /* detect duplicate senders */
+ PORT_Assert(sender->ex_type != ex_type);
+ if (sender->ex_type == ex_type) {
+ /* duplicate */
+ break;
+ }
+ }
+ PORT_Assert(i < SSL_MAX_EXTENSIONS); /* table needs to grow */
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+}
+
+/* call each of the extension senders and return the accumulated length */
+PRInt32
+ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes,
+ const ssl3HelloExtensionSender *sender)
+{
+ PRInt32 total_exten_len = 0;
+ int i;
+
+ if (!sender) {
+ sender = ss->version > SSL_LIBRARY_VERSION_3_0 ?
+ &clientHelloSendersTLS[0] : &clientHelloSendersSSL3[0];
+ }
+
+ for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) {
+ if (sender->ex_sender) {
+ PRInt32 extLen = (*sender->ex_sender)(ss, append, maxBytes);
+ if (extLen < 0)
+ return -1;
+ maxBytes -= extLen;
+ total_exten_len += extLen;
+ }
+ }
+ return total_exten_len;
+}
+
+
+/* Extension format:
+ * Extension number: 2 bytes
+ * Extension length: 2 bytes
+ * Verify Data Length: 1 byte
+ * Verify Data (TLS): 12 bytes (client) or 24 bytes (server)
+ * Verify Data (SSL): 36 bytes (client) or 72 bytes (server)
+ */
+static PRInt32
+ssl3_SendRenegotiationInfoXtn(
+ sslSocket * ss,
+ PRBool append,
+ PRUint32 maxBytes)
+{
+ PRInt32 len, needed;
+
+ /* In draft-ietf-tls-renegotiation-03, it is NOT RECOMMENDED to send
+ * both the SCSV and the empty RI, so when we send SCSV in
+ * the initial handshake, we don't also send RI.
+ */
+ if (!ss || ss->ssl3.hs.sendingSCSV)
+ return 0;
+ len = !ss->firstHsDone ? 0 :
+ (ss->sec.isServer ? ss->ssl3.hs.finishedBytes * 2
+ : ss->ssl3.hs.finishedBytes);
+ needed = 5 + len;
+ if (append && maxBytes >= needed) {
+ SECStatus rv;
+ /* extension_type */
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_renegotiation_info_xtn, 2);
+ if (rv != SECSuccess) return -1;
+ /* length of extension_data */
+ rv = ssl3_AppendHandshakeNumber(ss, len + 1, 2);
+ if (rv != SECSuccess) return -1;
+ /* verify_Data from previous Finished message(s) */
+ rv = ssl3_AppendHandshakeVariable(ss,
+ ss->ssl3.hs.finishedMsgs.data, len, 1);
+ if (rv != SECSuccess) return -1;
+ if (!ss->sec.isServer) {
+ TLSExtensionData *xtnData = &ss->xtnData;
+ xtnData->advertised[xtnData->numAdvertised++] =
+ ssl_renegotiation_info_xtn;
+ }
+ }
+ return needed;
+}
+
+static SECStatus
+ssl3_ServerHandleStatusRequestXtn(sslSocket *ss, PRUint16 ex_type,
+ SECItem *data)
+{
+ SECStatus rv = SECSuccess;
+
+ /* remember that we got this extension. */
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+ PORT_Assert(ss->sec.isServer);
+ /* prepare to send back the appropriate response */
+ rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type,
+ ssl3_ServerSendStatusRequestXtn);
+ return rv;
+}
+
+/* This function runs in both the client and server. */
+static SECStatus
+ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+{
+ SECStatus rv = SECSuccess;
+ PRUint32 len = 0;
+
+ if (ss->firstHsDone) {
+ len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes
+ : ss->ssl3.hs.finishedBytes * 2;
+ }
+ if (data->len != 1 + len ||
+ data->data[0] != len || (len &&
+ NSS_SecureMemcmp(ss->ssl3.hs.finishedMsgs.data,
+ data->data + 1, len))) {
+ /* Can we do this here? Or, must we arrange for the caller to do it? */
+ (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
+ PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+ return SECFailure;
+ }
+ /* remember that we got this extension and it was correct. */
+ ss->peerRequestedProtection = 1;
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+ if (ss->sec.isServer) {
+ /* prepare to send back the appropriate response */
+ rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type,
+ ssl3_SendRenegotiationInfoXtn);
+ }
+ return rv;
+}
+
+static PRInt32
+ssl3_SendUseSRTPXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
+{
+ PRUint32 ext_data_len;
+ PRInt16 i;
+ SECStatus rv;
+
+ if (!ss)
+ return 0;
+
+ if (!ss->sec.isServer) {
+ /* Client side */
+
+ if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount)
+ return 0; /* Not relevant */
+
+ ext_data_len = 2 + 2 * ss->ssl3.dtlsSRTPCipherCount + 1;
+
+ if (append && maxBytes >= 4 + ext_data_len) {
+ /* Extension type */
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2);
+ if (rv != SECSuccess) return -1;
+ /* Length of extension data */
+ rv = ssl3_AppendHandshakeNumber(ss, ext_data_len, 2);
+ if (rv != SECSuccess) return -1;
+ /* Length of the SRTP cipher list */
+ rv = ssl3_AppendHandshakeNumber(ss,
+ 2 * ss->ssl3.dtlsSRTPCipherCount,
+ 2);
+ if (rv != SECSuccess) return -1;
+ /* The SRTP ciphers */
+ for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) {
+ rv = ssl3_AppendHandshakeNumber(ss,
+ ss->ssl3.dtlsSRTPCiphers[i],
+ 2);
+ }
+ /* Empty MKI value */
+ ssl3_AppendHandshakeVariable(ss, NULL, 0, 1);
+
+ ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+ ssl_use_srtp_xtn;
+ }
+
+ return 4 + ext_data_len;
+ }
+
+ /* Server side */
+ if (append && maxBytes >= 9) {
+ /* Extension type */
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2);
+ if (rv != SECSuccess) return -1;
+ /* Length of extension data */
+ rv = ssl3_AppendHandshakeNumber(ss, 5, 2);
+ if (rv != SECSuccess) return -1;
+ /* Length of the SRTP cipher list */
+ rv = ssl3_AppendHandshakeNumber(ss, 2, 2);
+ if (rv != SECSuccess) return -1;
+ /* The selected cipher */
+ rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.dtlsSRTPCipherSuite, 2);
+ if (rv != SECSuccess) return -1;
+ /* Empty MKI value */
+ ssl3_AppendHandshakeVariable(ss, NULL, 0, 1);
+ }
+
+ return 9;
+}
+
+static SECStatus
+ssl3_HandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
+{
+ SECStatus rv;
+ SECItem ciphers = {siBuffer, NULL, 0};
+ PRUint16 i;
+ unsigned int j;
+ PRUint16 cipher = 0;
+ PRBool found = PR_FALSE;
+ SECItem litem;
+
+ if (!ss->sec.isServer) {
+ /* Client side */
+ if (!data->data || !data->len) {
+ /* malformed */
+ return SECFailure;
+ }
+
+ /* Get the cipher list */
+ rv = ssl3_ConsumeHandshakeVariable(ss, &ciphers, 2,
+ &data->data, &data->len);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ /* Now check that the number of ciphers listed is 1 (len = 2) */
+ if (ciphers.len != 2) {
+ return SECFailure;
+ }
+
+ /* Get the selected cipher */
+ cipher = (ciphers.data[0] << 8) | ciphers.data[1];
+
+ /* Now check that this is one of the ciphers we offered */
+ for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) {
+ if (cipher == ss->ssl3.dtlsSRTPCiphers[i]) {
+ found = PR_TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ return SECFailure;
+ }
+
+ /* Get the srtp_mki value */
+ rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 1,
+ &data->data, &data->len);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ /* We didn't offer an MKI, so this must be 0 length */
+ /* XXX RFC 5764 Section 4.1.3 says:
+ * If the client detects a nonzero-length MKI in the server's
+ * response that is different than the one the client offered,
+ * then the client MUST abort the handshake and SHOULD send an
+ * invalid_parameter alert.
+ *
+ * Due to a limitation of the ssl3_HandleHelloExtensions function,
+ * returning SECFailure here won't abort the handshake. It will
+ * merely cause the use_srtp extension to be not negotiated. We
+ * should fix this. See NSS bug 753136.
+ */
+ if (litem.len != 0) {
+ return SECFailure;
+ }
+
+ if (data->len != 0) {
+ /* malformed */
+ return SECFailure;
+ }
+
+ /* OK, this looks fine. */
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ssl_use_srtp_xtn;
+ ss->ssl3.dtlsSRTPCipherSuite = cipher;
+ return SECSuccess;
+ }
+
+ /* Server side */
+ if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount) {
+ /* Ignore the extension if we aren't doing DTLS or no DTLS-SRTP
+ * preferences have been set. */
+ return SECSuccess;
+ }
+
+ if (!data->data || data->len < 5) {
+ /* malformed */
+ return SECFailure;
+ }
+
+ /* Get the cipher list */
+ rv = ssl3_ConsumeHandshakeVariable(ss, &ciphers, 2,
+ &data->data, &data->len);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ /* Check that the list is even length */
+ if (ciphers.len % 2) {
+ return SECFailure;
+ }
+
+ /* Walk through the offered list and pick the most preferred of our
+ * ciphers, if any */
+ for (i = 0; !found && i < ss->ssl3.dtlsSRTPCipherCount; i++) {
+ for (j = 0; j + 1 < ciphers.len; j += 2) {
+ cipher = (ciphers.data[j] << 8) | ciphers.data[j + 1];
+ if (cipher == ss->ssl3.dtlsSRTPCiphers[i]) {
+ found = PR_TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Get the srtp_mki value */
+ rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 1, &data->data, &data->len);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (data->len != 0) {
+ return SECFailure; /* Malformed */
+ }
+
+ /* Now figure out what to do */
+ if (!found) {
+ /* No matching ciphers */
+ return SECSuccess;
+ }
+
+ /* OK, we have a valid cipher and we've selected it */
+ ss->ssl3.dtlsSRTPCipherSuite = cipher;
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ssl_use_srtp_xtn;
+
+ return ssl3_RegisterServerHelloExtensionSender(ss, ssl_use_srtp_xtn,
+ ssl3_SendUseSRTPXtn);
+}
+
+/* ssl3_ServerHandleSigAlgsXtn handles the signature_algorithms extension
+ * from a client.
+ * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
+static SECStatus
+ssl3_ServerHandleSigAlgsXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
+{
+ SECStatus rv;
+ SECItem algorithms;
+ const unsigned char *b;
+ unsigned int numAlgorithms, i;
+
+ /* Ignore this extension if we aren't doing TLS 1.2 or greater. */
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) {
+ return SECSuccess;
+ }
+
+ /* Keep track of negotiated extensions. */
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+
+ rv = ssl3_ConsumeHandshakeVariable(ss, &algorithms, 2, &data->data,
+ &data->len);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ /* Trailing data, empty value, or odd-length value is invalid. */
+ if (data->len != 0 || algorithms.len == 0 || (algorithms.len & 1) != 0) {
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+ return SECFailure;
+ }
+
+ numAlgorithms = algorithms.len/2;
+
+ /* We don't care to process excessive numbers of algorithms. */
+ if (numAlgorithms > 512) {
+ numAlgorithms = 512;
+ }
+
+ ss->ssl3.hs.clientSigAndHash =
+ PORT_NewArray(SSL3SignatureAndHashAlgorithm, numAlgorithms);
+ if (!ss->ssl3.hs.clientSigAndHash) {
+ return SECFailure;
+ }
+ ss->ssl3.hs.numClientSigAndHash = 0;
+
+ b = algorithms.data;
+ for (i = 0; i < numAlgorithms; i++) {
+ unsigned char tls_hash = *(b++);
+ unsigned char tls_sig = *(b++);
+ SECOidTag hash = ssl3_TLSHashAlgorithmToOID(tls_hash);
+
+ if (hash == SEC_OID_UNKNOWN) {
+ /* We ignore formats that we don't understand. */
+ continue;
+ }
+ /* tls_sig support will be checked later in
+ * ssl3_PickSignatureHashAlgorithm. */
+ ss->ssl3.hs.clientSigAndHash[i].hashAlg = hash;
+ ss->ssl3.hs.clientSigAndHash[i].sigAlg = tls_sig;
+ ss->ssl3.hs.numClientSigAndHash++;
+ }
+
+ if (!ss->ssl3.hs.numClientSigAndHash) {
+ /* We didn't understand any of the client's requested signature
+ * formats. We'll use the defaults. */
+ PORT_Free(ss->ssl3.hs.clientSigAndHash);
+ ss->ssl3.hs.clientSigAndHash = NULL;
+ }
+
+ return SECSuccess;
+}
+
+/* ssl3_ClientSendSigAlgsXtn sends the signature_algorithm extension for TLS
+ * 1.2 ClientHellos. */
+static PRInt32
+ssl3_ClientSendSigAlgsXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes)
+{
+ static const unsigned char signatureAlgorithms[] = {
+ /* This block is the contents of our signature_algorithms extension, in
+ * wire format. See
+ * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
+ tls_hash_sha256, tls_sig_rsa,
+ tls_hash_sha384, tls_sig_rsa,
+ tls_hash_sha1, tls_sig_rsa,
+#ifdef NSS_ENABLE_ECC
+ tls_hash_sha256, tls_sig_ecdsa,
+ tls_hash_sha384, tls_sig_ecdsa,
+ tls_hash_sha1, tls_sig_ecdsa,
+#endif
+ tls_hash_sha256, tls_sig_dsa,
+ tls_hash_sha1, tls_sig_dsa,
+ };
+ PRInt32 extension_length;
+
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) {
+ return 0;
+ }
+
+ extension_length =
+ 2 /* extension type */ +
+ 2 /* extension length */ +
+ 2 /* supported_signature_algorithms length */ +
+ sizeof(signatureAlgorithms);
+
+ if (append && maxBytes >= extension_length) {
+ SECStatus rv;
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_signature_algorithms_xtn, 2);
+ if (rv != SECSuccess)
+ goto loser;
+ rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
+ if (rv != SECSuccess)
+ goto loser;
+ rv = ssl3_AppendHandshakeVariable(ss, signatureAlgorithms,
+ sizeof(signatureAlgorithms), 2);
+ if (rv != SECSuccess)
+ goto loser;
+ ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+ ssl_signature_algorithms_xtn;
+ } else if (maxBytes < extension_length) {
+ PORT_Assert(0);
+ return 0;
+ }
+
+ return extension_length;
+
+loser:
+ return -1;
+}
diff --git a/chromium/net/third_party/nss/ssl/ssl3gthr.c b/chromium/net/third_party/nss/ssl/ssl3gthr.c
new file mode 100644
index 00000000000..6d625152662
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/ssl3gthr.c
@@ -0,0 +1,413 @@
+/*
+ * Gather (Read) entire SSL3 records from socket into buffer.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cert.h"
+#include "ssl.h"
+#include "sslimpl.h"
+#include "ssl3prot.h"
+
+/*
+ * Attempt to read in an entire SSL3 record.
+ * Blocks here for blocking sockets, otherwise returns -1 with
+ * PR_WOULD_BLOCK_ERROR when socket would block.
+ *
+ * returns 1 if received a complete SSL3 record.
+ * returns 0 if recv returns EOF
+ * returns -1 if recv returns < 0
+ * (The error value may have already been set to PR_WOULD_BLOCK_ERROR)
+ *
+ * Caller must hold the recv buf lock.
+ *
+ * The Gather state machine has 3 states: GS_INIT, GS_HEADER, GS_DATA.
+ * GS_HEADER: waiting for the 5-byte SSL3 record header to come in.
+ * GS_DATA: waiting for the body of the SSL3 record to come in.
+ *
+ * This loop returns when either
+ * (a) an error or EOF occurs,
+ * (b) PR_WOULD_BLOCK_ERROR,
+ * (c) data (entire SSL3 record) has been received.
+ */
+static int
+ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags)
+{
+ unsigned char *bp;
+ unsigned char *lbp;
+ int nb;
+ int err;
+ int rv = 1;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ if (gs->state == GS_INIT) {
+ gs->state = GS_HEADER;
+ gs->remainder = 5;
+ gs->offset = 0;
+ gs->writeOffset = 0;
+ gs->readOffset = 0;
+ gs->inbuf.len = 0;
+ }
+
+ lbp = gs->inbuf.buf;
+ for(;;) {
+ SSL_TRC(30, ("%d: SSL3[%d]: gather state %d (need %d more)",
+ SSL_GETPID(), ss->fd, gs->state, gs->remainder));
+ bp = ((gs->state != GS_HEADER) ? lbp : gs->hdr) + gs->offset;
+ nb = ssl_DefRecv(ss, bp, gs->remainder, flags);
+
+ if (nb > 0) {
+ PRINT_BUF(60, (ss, "raw gather data:", bp, nb));
+ } else if (nb == 0) {
+ /* EOF */
+ SSL_TRC(30, ("%d: SSL3[%d]: EOF", SSL_GETPID(), ss->fd));
+ rv = 0;
+ break;
+ } else /* if (nb < 0) */ {
+ SSL_DBG(("%d: SSL3[%d]: recv error %d", SSL_GETPID(), ss->fd,
+ PR_GetError()));
+ rv = SECFailure;
+ break;
+ }
+
+ PORT_Assert( nb <= gs->remainder );
+ if (nb > gs->remainder) {
+ /* ssl_DefRecv is misbehaving! this error is fatal to SSL. */
+ gs->state = GS_INIT; /* so we don't crash next time */
+ rv = SECFailure;
+ break;
+ }
+
+ gs->offset += nb;
+ gs->remainder -= nb;
+ if (gs->state == GS_DATA)
+ gs->inbuf.len += nb;
+
+ /* if there's more to go, read some more. */
+ if (gs->remainder > 0) {
+ continue;
+ }
+
+ /* have received entire record header, or entire record. */
+ switch (gs->state) {
+ case GS_HEADER:
+ /*
+ ** Have received SSL3 record header in gs->hdr.
+ ** Now extract the length of the following encrypted data,
+ ** and then read in the rest of the SSL3 record into gs->inbuf.
+ */
+ gs->remainder = (gs->hdr[3] << 8) | gs->hdr[4];
+
+ /* This is the max fragment length for an encrypted fragment
+ ** plus the size of the record header.
+ */
+ if(gs->remainder > (MAX_FRAGMENT_LENGTH + 2048 + 5)) {
+ SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ gs->state = GS_INIT;
+ PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
+ return SECFailure;
+ }
+
+ gs->state = GS_DATA;
+ gs->offset = 0;
+ gs->inbuf.len = 0;
+
+ if (gs->remainder > gs->inbuf.space) {
+ err = sslBuffer_Grow(&gs->inbuf, gs->remainder);
+ if (err) { /* realloc has set error code to no mem. */
+ return err;
+ }
+ lbp = gs->inbuf.buf;
+ }
+ break; /* End this case. Continue around the loop. */
+
+
+ case GS_DATA:
+ /*
+ ** SSL3 record has been completely received.
+ */
+ gs->state = GS_INIT;
+ return 1;
+ }
+ }
+
+ return rv;
+}
+
+/*
+ * Read in an entire DTLS record.
+ *
+ * Blocks here for blocking sockets, otherwise returns -1 with
+ * PR_WOULD_BLOCK_ERROR when socket would block.
+ *
+ * This is simpler than SSL because we are reading on a datagram socket
+ * and datagrams must contain >=1 complete records.
+ *
+ * returns 1 if received a complete DTLS record.
+ * returns 0 if recv returns EOF
+ * returns -1 if recv returns < 0
+ * (The error value may have already been set to PR_WOULD_BLOCK_ERROR)
+ *
+ * Caller must hold the recv buf lock.
+ *
+ * This loop returns when either
+ * (a) an error or EOF occurs,
+ * (b) PR_WOULD_BLOCK_ERROR,
+ * (c) data (entire DTLS record) has been received.
+ */
+static int
+dtls_GatherData(sslSocket *ss, sslGather *gs, int flags)
+{
+ int nb;
+ int err;
+ int rv = 1;
+
+ SSL_TRC(30, ("dtls_GatherData"));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+
+ gs->state = GS_HEADER;
+ gs->offset = 0;
+
+ if (gs->dtlsPacketOffset == gs->dtlsPacket.len) { /* No data left */
+ gs->dtlsPacketOffset = 0;
+ gs->dtlsPacket.len = 0;
+
+ /* Resize to the maximum possible size so we can fit a full datagram */
+ /* This is the max fragment length for an encrypted fragment
+ ** plus the size of the record header.
+ ** This magic constant is copied from ssl3_GatherData, with 5 changed
+ ** to 13 (the size of the record header).
+ */
+ if (gs->dtlsPacket.space < MAX_FRAGMENT_LENGTH + 2048 + 13) {
+ err = sslBuffer_Grow(&gs->dtlsPacket,
+ MAX_FRAGMENT_LENGTH + 2048 + 13);
+ if (err) { /* realloc has set error code to no mem. */
+ return err;
+ }
+ }
+
+ /* recv() needs to read a full datagram at a time */
+ nb = ssl_DefRecv(ss, gs->dtlsPacket.buf, gs->dtlsPacket.space, flags);
+
+ if (nb > 0) {
+ PRINT_BUF(60, (ss, "raw gather data:", gs->dtlsPacket.buf, nb));
+ } else if (nb == 0) {
+ /* EOF */
+ SSL_TRC(30, ("%d: SSL3[%d]: EOF", SSL_GETPID(), ss->fd));
+ rv = 0;
+ return rv;
+ } else /* if (nb < 0) */ {
+ SSL_DBG(("%d: SSL3[%d]: recv error %d", SSL_GETPID(), ss->fd,
+ PR_GetError()));
+ rv = SECFailure;
+ return rv;
+ }
+
+ gs->dtlsPacket.len = nb;
+ }
+
+ /* At this point we should have >=1 complete records lined up in
+ * dtlsPacket. Read off the header.
+ */
+ if ((gs->dtlsPacket.len - gs->dtlsPacketOffset) < 13) {
+ SSL_DBG(("%d: SSL3[%d]: rest of DTLS packet "
+ "too short to contain header", SSL_GETPID(), ss->fd));
+ PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
+ gs->dtlsPacketOffset = 0;
+ gs->dtlsPacket.len = 0;
+ rv = SECFailure;
+ return rv;
+ }
+ memcpy(gs->hdr, gs->dtlsPacket.buf + gs->dtlsPacketOffset, 13);
+ gs->dtlsPacketOffset += 13;
+
+ /* Have received SSL3 record header in gs->hdr. */
+ gs->remainder = (gs->hdr[11] << 8) | gs->hdr[12];
+
+ if ((gs->dtlsPacket.len - gs->dtlsPacketOffset) < gs->remainder) {
+ SSL_DBG(("%d: SSL3[%d]: rest of DTLS packet too short "
+ "to contain rest of body", SSL_GETPID(), ss->fd));
+ PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
+ gs->dtlsPacketOffset = 0;
+ gs->dtlsPacket.len = 0;
+ rv = SECFailure;
+ return rv;
+ }
+
+ /* OK, we have at least one complete packet, copy into inbuf */
+ if (gs->remainder > gs->inbuf.space) {
+ err = sslBuffer_Grow(&gs->inbuf, gs->remainder);
+ if (err) { /* realloc has set error code to no mem. */
+ return err;
+ }
+ }
+
+ memcpy(gs->inbuf.buf, gs->dtlsPacket.buf + gs->dtlsPacketOffset,
+ gs->remainder);
+ gs->inbuf.len = gs->remainder;
+ gs->offset = gs->remainder;
+ gs->dtlsPacketOffset += gs->remainder;
+ gs->state = GS_INIT;
+
+ return 1;
+}
+
+/* Gather in a record and when complete, Handle that record.
+ * Repeat this until the handshake is complete,
+ * or until application data is available.
+ *
+ * Returns 1 when the handshake is completed without error, or
+ * application data is available.
+ * Returns 0 if ssl3_GatherData hits EOF.
+ * Returns -1 on read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error.
+ * Returns -2 on SECWouldBlock return from ssl3_HandleRecord.
+ *
+ * Called from ssl_GatherRecord1stHandshake in sslcon.c,
+ * and from SSL_ForceHandshake in sslsecur.c
+ * and from ssl3_GatherAppDataRecord below (<- DoRecv in sslsecur.c).
+ *
+ * Caller must hold the recv buf lock.
+ */
+int
+ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
+{
+ SSL3Ciphertext cText;
+ int rv;
+ PRBool canFalseStart = PR_FALSE;
+
+ SSL_TRC(30, ("ssl3_GatherCompleteHandshake"));
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ do {
+ PRBool handleRecordNow = PR_FALSE;
+
+ ssl_GetSSL3HandshakeLock(ss);
+
+ /* Without this, we may end up wrongly reporting
+ * SSL_ERROR_RX_UNEXPECTED_* errors if we receive any records from the
+ * peer while we are waiting to be restarted.
+ */
+ if (ss->ssl3.hs.restartTarget) {
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ return (int) SECFailure;
+ }
+
+ /* Treat an empty msgState like a NULL msgState. (Most of the time
+ * when ssl3_HandleHandshake returns SECWouldBlock, it leaves
+ * behind a non-NULL but zero-length msgState).
+ * Test: async_cert_restart_server_sends_hello_request_first_in_separate_record
+ */
+ if (ss->ssl3.hs.msgState.buf) {
+ if (ss->ssl3.hs.msgState.len == 0) {
+ ss->ssl3.hs.msgState.buf = NULL;
+ } else {
+ handleRecordNow = PR_TRUE;
+ }
+ }
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+
+ if (handleRecordNow) {
+ /* ssl3_HandleHandshake previously returned SECWouldBlock and the
+ * as-yet-unprocessed plaintext of that previous handshake record.
+ * We need to process it now before we overwrite it with the next
+ * handshake record.
+ */
+ rv = ssl3_HandleRecord(ss, NULL, &ss->gs.buf);
+ } else {
+ /* bring in the next sslv3 record. */
+ if (!IS_DTLS(ss)) {
+ rv = ssl3_GatherData(ss, &ss->gs, flags);
+ } else {
+ rv = dtls_GatherData(ss, &ss->gs, flags);
+
+ /* If we got a would block error, that means that no data was
+ * available, so we check the timer to see if it's time to
+ * retransmit */
+ if (rv == SECFailure &&
+ (PORT_GetError() == PR_WOULD_BLOCK_ERROR)) {
+ ssl_GetSSL3HandshakeLock(ss);
+ dtls_CheckTimer(ss);
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ /* Restore the error in case something succeeded */
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ }
+ }
+
+ if (rv <= 0) {
+ return rv;
+ }
+
+ /* decipher it, and handle it if it's a handshake.
+ * If it's application data, ss->gs.buf will not be empty upon return.
+ * If it's a change cipher spec, alert, or handshake message,
+ * ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess.
+ */
+ cText.type = (SSL3ContentType)ss->gs.hdr[0];
+ cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2];
+
+ if (IS_DTLS(ss)) {
+ int i;
+
+ cText.version = dtls_DTLSVersionToTLSVersion(cText.version);
+ /* DTLS sequence number */
+ cText.seq_num.high = 0; cText.seq_num.low = 0;
+ for (i = 0; i < 4; i++) {
+ cText.seq_num.high <<= 8; cText.seq_num.low <<= 8;
+ cText.seq_num.high |= ss->gs.hdr[3 + i];
+ cText.seq_num.low |= ss->gs.hdr[7 + i];
+ }
+ }
+
+ cText.buf = &ss->gs.inbuf;
+ rv = ssl3_HandleRecord(ss, &cText, &ss->gs.buf);
+ }
+ if (rv < 0) {
+ return ss->recvdCloseNotify ? 0 : rv;
+ }
+
+ /* If we kicked off a false start in ssl3_HandleServerHelloDone, break
+ * out of this loop early without finishing the handshake.
+ */
+ if (ss->opt.enableFalseStart) {
+ ssl_GetSSL3HandshakeLock(ss);
+ canFalseStart = (ss->ssl3.hs.ws == wait_change_cipher ||
+ ss->ssl3.hs.ws == wait_new_session_ticket) &&
+ ssl3_CanFalseStart(ss);
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ }
+ } while (ss->ssl3.hs.ws != idle_handshake &&
+ !canFalseStart &&
+ ss->gs.buf.len == 0);
+
+ ss->gs.readOffset = 0;
+ ss->gs.writeOffset = ss->gs.buf.len;
+ return 1;
+}
+
+/* Repeatedly gather in a record and when complete, Handle that record.
+ * Repeat this until some application data is received.
+ *
+ * Returns 1 when application data is available.
+ * Returns 0 if ssl3_GatherData hits EOF.
+ * Returns -1 on read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error.
+ * Returns -2 on SECWouldBlock return from ssl3_HandleRecord.
+ *
+ * Called from DoRecv in sslsecur.c
+ * Caller must hold the recv buf lock.
+ */
+int
+ssl3_GatherAppDataRecord(sslSocket *ss, int flags)
+{
+ int rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ do {
+ rv = ssl3_GatherCompleteHandshake(ss, flags);
+ } while (rv > 0 && ss->gs.buf.len == 0);
+
+ return rv;
+}
diff --git a/chromium/net/third_party/nss/ssl/ssl3prot.h b/chromium/net/third_party/nss/ssl/ssl3prot.h
new file mode 100644
index 00000000000..0eab970bc6a
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/ssl3prot.h
@@ -0,0 +1,363 @@
+/* Private header file of libSSL.
+ * Various and sundry protocol constants. DON'T CHANGE THESE. These
+ * values are defined by the SSL 3.0 protocol specification.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __ssl3proto_h_
+#define __ssl3proto_h_
+
+typedef PRUint8 SSL3Opaque;
+
+typedef PRUint16 SSL3ProtocolVersion;
+/* version numbers are defined in sslproto.h */
+
+typedef PRUint16 ssl3CipherSuite;
+/* The cipher suites are defined in sslproto.h */
+
+#define MAX_CERT_TYPES 10
+#define MAX_COMPRESSION_METHODS 10
+#define MAX_MAC_LENGTH 64
+#define MAX_PADDING_LENGTH 64
+#define MAX_KEY_LENGTH 64
+#define EXPORT_KEY_LENGTH 5
+#define SSL3_RANDOM_LENGTH 32
+
+#define SSL3_RECORD_HEADER_LENGTH 5
+
+/* SSL3_RECORD_HEADER_LENGTH + epoch/sequence_number */
+#define DTLS_RECORD_HEADER_LENGTH 13
+
+#define MAX_FRAGMENT_LENGTH 16384
+
+typedef enum {
+ content_change_cipher_spec = 20,
+ content_alert = 21,
+ content_handshake = 22,
+ content_application_data = 23
+} SSL3ContentType;
+
+typedef struct {
+ SSL3ContentType type;
+ SSL3ProtocolVersion version;
+ PRUint16 length;
+ SECItem fragment;
+} SSL3Plaintext;
+
+typedef struct {
+ SSL3ContentType type;
+ SSL3ProtocolVersion version;
+ PRUint16 length;
+ SECItem fragment;
+} SSL3Compressed;
+
+typedef struct {
+ SECItem content;
+ SSL3Opaque MAC[MAX_MAC_LENGTH];
+} SSL3GenericStreamCipher;
+
+typedef struct {
+ SECItem content;
+ SSL3Opaque MAC[MAX_MAC_LENGTH];
+ PRUint8 padding[MAX_PADDING_LENGTH];
+ PRUint8 padding_length;
+} SSL3GenericBlockCipher;
+
+typedef enum { change_cipher_spec_choice = 1 } SSL3ChangeCipherSpecChoice;
+
+typedef struct {
+ SSL3ChangeCipherSpecChoice choice;
+} SSL3ChangeCipherSpec;
+
+typedef enum { alert_warning = 1, alert_fatal = 2 } SSL3AlertLevel;
+
+typedef enum {
+ close_notify = 0,
+ unexpected_message = 10,
+ bad_record_mac = 20,
+ decryption_failed_RESERVED = 21, /* do not send; see RFC 5246 */
+ record_overflow = 22, /* TLS only */
+ decompression_failure = 30,
+ handshake_failure = 40,
+ no_certificate = 41, /* SSL3 only, NOT TLS */
+ bad_certificate = 42,
+ unsupported_certificate = 43,
+ certificate_revoked = 44,
+ certificate_expired = 45,
+ certificate_unknown = 46,
+ illegal_parameter = 47,
+
+/* All alerts below are TLS only. */
+ unknown_ca = 48,
+ access_denied = 49,
+ decode_error = 50,
+ decrypt_error = 51,
+ export_restriction = 60,
+ protocol_version = 70,
+ insufficient_security = 71,
+ internal_error = 80,
+ user_canceled = 90,
+ no_renegotiation = 100,
+
+/* Alerts for client hello extensions */
+ unsupported_extension = 110,
+ certificate_unobtainable = 111,
+ unrecognized_name = 112,
+ bad_certificate_status_response = 113,
+ bad_certificate_hash_value = 114
+
+} SSL3AlertDescription;
+
+typedef struct {
+ SSL3AlertLevel level;
+ SSL3AlertDescription description;
+} SSL3Alert;
+
+typedef enum {
+ hello_request = 0,
+ client_hello = 1,
+ server_hello = 2,
+ hello_verify_request = 3,
+ new_session_ticket = 4,
+ certificate = 11,
+ server_key_exchange = 12,
+ certificate_request = 13,
+ server_hello_done = 14,
+ certificate_verify = 15,
+ client_key_exchange = 16,
+ finished = 20,
+ certificate_status = 22,
+ next_proto = 67,
+ encrypted_extensions= 203
+} SSL3HandshakeType;
+
+typedef struct {
+ PRUint8 empty;
+} SSL3HelloRequest;
+
+typedef struct {
+ SSL3Opaque rand[SSL3_RANDOM_LENGTH];
+} SSL3Random;
+
+typedef struct {
+ SSL3Opaque id[32];
+ PRUint8 length;
+} SSL3SessionID;
+
+typedef struct {
+ SSL3ProtocolVersion client_version;
+ SSL3Random random;
+ SSL3SessionID session_id;
+ SECItem cipher_suites;
+ PRUint8 cm_count;
+ SSLCompressionMethod compression_methods[MAX_COMPRESSION_METHODS];
+} SSL3ClientHello;
+
+typedef struct {
+ SSL3ProtocolVersion server_version;
+ SSL3Random random;
+ SSL3SessionID session_id;
+ ssl3CipherSuite cipher_suite;
+ SSLCompressionMethod compression_method;
+} SSL3ServerHello;
+
+typedef struct {
+ SECItem list;
+} SSL3Certificate;
+
+/* SSL3SignType moved to ssl.h */
+
+/* The SSL key exchange method used */
+typedef enum {
+ kea_null,
+ kea_rsa,
+ kea_rsa_export,
+ kea_rsa_export_1024,
+ kea_dh_dss,
+ kea_dh_dss_export,
+ kea_dh_rsa,
+ kea_dh_rsa_export,
+ kea_dhe_dss,
+ kea_dhe_dss_export,
+ kea_dhe_rsa,
+ kea_dhe_rsa_export,
+ kea_dh_anon,
+ kea_dh_anon_export,
+ kea_rsa_fips,
+ kea_ecdh_ecdsa,
+ kea_ecdhe_ecdsa,
+ kea_ecdh_rsa,
+ kea_ecdhe_rsa,
+ kea_ecdh_anon
+} SSL3KeyExchangeAlgorithm;
+
+typedef struct {
+ SECItem modulus;
+ SECItem exponent;
+} SSL3ServerRSAParams;
+
+typedef struct {
+ SECItem p;
+ SECItem g;
+ SECItem Ys;
+} SSL3ServerDHParams;
+
+typedef struct {
+ union {
+ SSL3ServerDHParams dh;
+ SSL3ServerRSAParams rsa;
+ } u;
+} SSL3ServerParams;
+
+/* This enum reflects HashAlgorithm enum from
+ * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+ *
+ * When updating, be sure to also update ssl3_TLSHashAlgorithmToOID. */
+enum {
+ tls_hash_md5 = 1,
+ tls_hash_sha1 = 2,
+ tls_hash_sha224 = 3,
+ tls_hash_sha256 = 4,
+ tls_hash_sha384 = 5,
+ tls_hash_sha512 = 6
+};
+
+/* This enum reflects SignatureAlgorithm enum from
+ * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
+typedef enum {
+ tls_sig_rsa = 1,
+ tls_sig_dsa = 2,
+ tls_sig_ecdsa = 3
+} TLSSignatureAlgorithm;
+
+typedef struct {
+ SECOidTag hashAlg;
+ TLSSignatureAlgorithm sigAlg;
+} SSL3SignatureAndHashAlgorithm;
+
+/* SSL3HashesIndividually contains a combination MD5/SHA1 hash, as used in TLS
+ * prior to 1.2. */
+typedef struct {
+ PRUint8 md5[16];
+ PRUint8 sha[20];
+} SSL3HashesIndividually;
+
+/* SSL3Hashes contains an SSL hash value. The digest is contained in |u.raw|
+ * which, if |hashAlg==SEC_OID_UNKNOWN| is also a SSL3HashesIndividually
+ * struct. */
+typedef struct {
+ unsigned int len;
+ SECOidTag hashAlg;
+ union {
+ PRUint8 raw[64];
+ SSL3HashesIndividually s;
+ } u;
+} SSL3Hashes;
+
+typedef struct {
+ union {
+ SSL3Opaque anonymous;
+ SSL3Hashes certified;
+ } u;
+} SSL3ServerKeyExchange;
+
+typedef enum {
+ ct_RSA_sign = 1,
+ ct_DSS_sign = 2,
+ ct_RSA_fixed_DH = 3,
+ ct_DSS_fixed_DH = 4,
+ ct_RSA_ephemeral_DH = 5,
+ ct_DSS_ephemeral_DH = 6,
+ ct_ECDSA_sign = 64,
+ ct_RSA_fixed_ECDH = 65,
+ ct_ECDSA_fixed_ECDH = 66
+
+} SSL3ClientCertificateType;
+
+typedef SECItem *SSL3DistinquishedName;
+
+typedef struct {
+ SSL3Opaque client_version[2];
+ SSL3Opaque random[46];
+} SSL3RSAPreMasterSecret;
+
+typedef SECItem SSL3EncryptedPreMasterSecret;
+
+
+typedef SSL3Opaque SSL3MasterSecret[48];
+
+typedef enum { implicit, explicit } SSL3PublicValueEncoding;
+
+typedef struct {
+ union {
+ SSL3Opaque implicit;
+ SECItem explicit;
+ } dh_public;
+} SSL3ClientDiffieHellmanPublic;
+
+typedef struct {
+ union {
+ SSL3EncryptedPreMasterSecret rsa;
+ SSL3ClientDiffieHellmanPublic diffie_helman;
+ } exchange_keys;
+} SSL3ClientKeyExchange;
+
+typedef SSL3Hashes SSL3PreSignedCertificateVerify;
+
+typedef SECItem SSL3CertificateVerify;
+
+typedef enum {
+ sender_client = 0x434c4e54,
+ sender_server = 0x53525652
+} SSL3Sender;
+
+typedef SSL3HashesIndividually SSL3Finished;
+
+typedef struct {
+ SSL3Opaque verify_data[12];
+} TLSFinished;
+
+/*
+ * TLS extension related data structures and constants.
+ */
+
+/* SessionTicket extension related data structures. */
+
+/* NewSessionTicket handshake message. */
+typedef struct {
+ PRUint32 received_timestamp;
+ PRUint32 ticket_lifetime_hint;
+ SECItem ticket;
+} NewSessionTicket;
+
+typedef enum {
+ CLIENT_AUTH_ANONYMOUS = 0,
+ CLIENT_AUTH_CERTIFICATE = 1
+} ClientAuthenticationType;
+
+typedef struct {
+ ClientAuthenticationType client_auth_type;
+ union {
+ SSL3Opaque *certificate_list;
+ } identity;
+} ClientIdentity;
+
+#define SESS_TICKET_KEY_NAME_LEN 16
+#define SESS_TICKET_KEY_NAME_PREFIX "NSS!"
+#define SESS_TICKET_KEY_NAME_PREFIX_LEN 4
+#define SESS_TICKET_KEY_VAR_NAME_LEN 12
+
+typedef struct {
+ unsigned char *key_name;
+ unsigned char *iv;
+ SECItem encrypted_state;
+ unsigned char *mac;
+} EncryptedSessionTicket;
+
+#define TLS_EX_SESS_TICKET_MAC_LENGTH 32
+
+#define TLS_STE_NO_SERVER_NAME -1
+
+#endif /* __ssl3proto_h_ */
diff --git a/chromium/net/third_party/nss/ssl/sslauth.c b/chromium/net/third_party/nss/ssl/sslauth.c
new file mode 100644
index 00000000000..8e818decd85
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslauth.c
@@ -0,0 +1,332 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "cert.h"
+#include "secitem.h"
+#include "ssl.h"
+#include "sslimpl.h"
+#include "sslproto.h"
+#include "pk11func.h"
+#include "ocsp.h"
+
+/* NEED LOCKS IN HERE. */
+CERTCertificate *
+SSL_PeerCertificate(PRFileDesc *fd)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate",
+ SSL_GETPID(), fd));
+ return 0;
+ }
+ if (ss->opt.useSecurity && ss->sec.peerCert) {
+ return CERT_DupCertificate(ss->sec.peerCert);
+ }
+ return 0;
+}
+
+/* NEED LOCKS IN HERE. */
+SECStatus
+SSL_PeerCertificateChain(PRFileDesc *fd, CERTCertificate **certs,
+ unsigned int *numCerts, unsigned int maxNumCerts)
+{
+ sslSocket *ss;
+ ssl3CertNode* cur;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificateChain",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+ if (!ss->opt.useSecurity)
+ return SECFailure;
+
+ if (ss->sec.peerCert == NULL) {
+ *numCerts = 0;
+ return SECSuccess;
+ }
+
+ *numCerts = 1; /* for the leaf certificate */
+ if (maxNumCerts > 0)
+ certs[0] = CERT_DupCertificate(ss->sec.peerCert);
+
+ for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) {
+ if (*numCerts < maxNumCerts)
+ certs[*numCerts] = CERT_DupCertificate(cur->cert);
+ (*numCerts)++;
+ }
+
+ return SECSuccess;
+}
+
+/* NEED LOCKS IN HERE. */
+CERTCertificate *
+SSL_LocalCertificate(PRFileDesc *fd)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate",
+ SSL_GETPID(), fd));
+ return NULL;
+ }
+ if (ss->opt.useSecurity) {
+ if (ss->sec.localCert) {
+ return CERT_DupCertificate(ss->sec.localCert);
+ }
+ if (ss->sec.ci.sid && ss->sec.ci.sid->localCert) {
+ return CERT_DupCertificate(ss->sec.ci.sid->localCert);
+ }
+ }
+ return NULL;
+}
+
+
+
+/* NEED LOCKS IN HERE. */
+SECStatus
+SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
+ char **ip, char **sp)
+{
+ sslSocket *ss;
+ const char *cipherName;
+ PRBool isDes = PR_FALSE;
+ PRBool enoughFirstHsDone = PR_FALSE;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SecurityStatus",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ if (cp) *cp = 0;
+ if (kp0) *kp0 = 0;
+ if (kp1) *kp1 = 0;
+ if (ip) *ip = 0;
+ if (sp) *sp = 0;
+ if (op) {
+ *op = SSL_SECURITY_STATUS_OFF;
+ }
+
+ if (ss->firstHsDone) {
+ enoughFirstHsDone = PR_TRUE;
+ } else if (ss->version >= SSL_LIBRARY_VERSION_3_0 &&
+ ssl3_CanFalseStart(ss)) {
+ enoughFirstHsDone = PR_TRUE;
+ }
+
+ if (ss->opt.useSecurity && enoughFirstHsDone) {
+ if (ss->version < SSL_LIBRARY_VERSION_3_0) {
+ cipherName = ssl_cipherName[ss->sec.cipherType];
+ } else {
+ cipherName = ssl3_cipherName[ss->sec.cipherType];
+ }
+ PORT_Assert(cipherName);
+ if (cipherName) {
+ if (PORT_Strstr(cipherName, "DES")) isDes = PR_TRUE;
+
+ if (cp) {
+ *cp = PORT_Strdup(cipherName);
+ }
+ }
+
+ if (kp0) {
+ *kp0 = ss->sec.keyBits;
+ if (isDes) *kp0 = (*kp0 * 7) / 8;
+ }
+ if (kp1) {
+ *kp1 = ss->sec.secretKeyBits;
+ if (isDes) *kp1 = (*kp1 * 7) / 8;
+ }
+ if (op) {
+ if (ss->sec.keyBits == 0) {
+ *op = SSL_SECURITY_STATUS_OFF;
+ } else if (ss->sec.secretKeyBits < 90) {
+ *op = SSL_SECURITY_STATUS_ON_LOW;
+
+ } else {
+ *op = SSL_SECURITY_STATUS_ON_HIGH;
+ }
+ }
+
+ if (ip || sp) {
+ CERTCertificate *cert;
+
+ cert = ss->sec.peerCert;
+ if (cert) {
+ if (ip) {
+ *ip = CERT_NameToAscii(&cert->issuer);
+ }
+ if (sp) {
+ *sp = CERT_NameToAscii(&cert->subject);
+ }
+ } else {
+ if (ip) {
+ *ip = PORT_Strdup("no certificate");
+ }
+ if (sp) {
+ *sp = PORT_Strdup("no certificate");
+ }
+ }
+ }
+ }
+
+ return SECSuccess;
+}
+
+/************************************************************************/
+
+/* NEED LOCKS IN HERE. */
+SECStatus
+SSL_AuthCertificateHook(PRFileDesc *s, SSLAuthCertificate func, void *arg)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(s);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in AuthCertificateHook",
+ SSL_GETPID(), s));
+ return SECFailure;
+ }
+
+ ss->authCertificate = func;
+ ss->authCertificateArg = arg;
+
+ return SECSuccess;
+}
+
+/* NEED LOCKS IN HERE. */
+SECStatus
+SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func,
+ void *arg)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(s);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook",
+ SSL_GETPID(), s));
+ return SECFailure;
+ }
+
+ ss->getClientAuthData = func;
+ ss->getClientAuthDataArg = arg;
+ return SECSuccess;
+}
+
+SECStatus
+SSL_SetClientChannelIDCallback(PRFileDesc *fd,
+ SSLClientChannelIDCallback callback,
+ void *arg) {
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetClientChannelIDCallback",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ ss->getChannelID = callback;
+ ss->getChannelIDArg = arg;
+
+ return SECSuccess;
+}
+
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+/* NEED LOCKS IN HERE. */
+SECStatus
+SSL_GetPlatformClientAuthDataHook(PRFileDesc *s,
+ SSLGetPlatformClientAuthData func,
+ void *arg)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(s);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in GetPlatformClientAuthDataHook",
+ SSL_GETPID(), s));
+ return SECFailure;
+ }
+
+ ss->getPlatformClientAuthData = func;
+ ss->getPlatformClientAuthDataArg = arg;
+ return SECSuccess;
+}
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
+
+/* NEED LOCKS IN HERE. */
+SECStatus
+SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(s);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook",
+ SSL_GETPID(), s));
+ return SECFailure;
+ }
+
+ ss->pkcs11PinArg = arg;
+ return SECSuccess;
+}
+
+
+/* This is the "default" authCert callback function. It is called when a
+ * certificate message is received from the peer and the local application
+ * has not registered an authCert callback function.
+ */
+SECStatus
+SSL_AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
+{
+ SECStatus rv;
+ CERTCertDBHandle * handle;
+ sslSocket * ss;
+ SECCertUsage certUsage;
+ const char * hostname = NULL;
+ PRTime now = PR_Now();
+ SECItemArray * certStatusArray;
+
+ ss = ssl_FindSocket(fd);
+ PORT_Assert(ss != NULL);
+ if (!ss) {
+ return SECFailure;
+ }
+
+ handle = (CERTCertDBHandle *)arg;
+ certStatusArray = &ss->sec.ci.sid->peerCertStatus;
+
+ if (certStatusArray->len) {
+ CERT_CacheOCSPResponseFromSideChannel(handle, ss->sec.peerCert,
+ now, &certStatusArray->items[0],
+ ss->pkcs11PinArg);
+ }
+
+ /* this may seem backwards, but isn't. */
+ certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
+
+ rv = CERT_VerifyCert(handle, ss->sec.peerCert, checkSig, certUsage,
+ now, ss->pkcs11PinArg, NULL);
+
+ if ( rv != SECSuccess || isServer )
+ return rv;
+
+ /* cert is OK. This is the client side of an SSL connection.
+ * Now check the name field in the cert against the desired hostname.
+ * NB: This is our only defense against Man-In-The-Middle (MITM) attacks!
+ */
+ hostname = ss->url;
+ if (hostname && hostname[0])
+ rv = CERT_VerifyCertName(ss->sec.peerCert, hostname);
+ else
+ rv = SECFailure;
+ if (rv != SECSuccess)
+ PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
+
+ return rv;
+}
diff --git a/chromium/net/third_party/nss/ssl/sslcon.c b/chromium/net/third_party/nss/ssl/sslcon.c
new file mode 100644
index 00000000000..2fc6602a2b6
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslcon.c
@@ -0,0 +1,3696 @@
+/*
+ * SSL v2 handshake functions, and functions common to SSL2 and SSL3.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nssrenam.h"
+#include "cert.h"
+#include "secitem.h"
+#include "sechash.h"
+#include "cryptohi.h" /* for SGN_ funcs */
+#include "keyhi.h" /* for SECKEY_ high level functions. */
+#include "ssl.h"
+#include "sslimpl.h"
+#include "sslproto.h"
+#include "ssl3prot.h"
+#include "sslerr.h"
+#include "pk11func.h"
+#include "prinit.h"
+#include "prtime.h" /* for PR_Now() */
+
+#define XXX
+static PRBool policyWasSet;
+
+/* This ordered list is indexed by (SSL_CK_xx * 3) */
+/* Second and third bytes are MSB and LSB of master key length. */
+static const PRUint8 allCipherSuites[] = {
+ 0, 0, 0,
+ SSL_CK_RC4_128_WITH_MD5, 0x00, 0x80,
+ SSL_CK_RC4_128_EXPORT40_WITH_MD5, 0x00, 0x80,
+ SSL_CK_RC2_128_CBC_WITH_MD5, 0x00, 0x80,
+ SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, 0x00, 0x80,
+ SSL_CK_IDEA_128_CBC_WITH_MD5, 0x00, 0x80,
+ SSL_CK_DES_64_CBC_WITH_MD5, 0x00, 0x40,
+ SSL_CK_DES_192_EDE3_CBC_WITH_MD5, 0x00, 0xC0,
+ 0, 0, 0
+};
+
+#define ssl2_NUM_SUITES_IMPLEMENTED 6
+
+/* This list is sent back to the client when the client-hello message
+ * contains no overlapping ciphers, so the client can report what ciphers
+ * are supported by the server. Unlike allCipherSuites (above), this list
+ * is sorted by descending preference, not by cipherSuite number.
+ */
+static const PRUint8 implementedCipherSuites[ssl2_NUM_SUITES_IMPLEMENTED * 3] = {
+ SSL_CK_RC4_128_WITH_MD5, 0x00, 0x80,
+ SSL_CK_RC2_128_CBC_WITH_MD5, 0x00, 0x80,
+ SSL_CK_DES_192_EDE3_CBC_WITH_MD5, 0x00, 0xC0,
+ SSL_CK_DES_64_CBC_WITH_MD5, 0x00, 0x40,
+ SSL_CK_RC4_128_EXPORT40_WITH_MD5, 0x00, 0x80,
+ SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, 0x00, 0x80
+};
+
+typedef struct ssl2SpecsStr {
+ PRUint8 nkm; /* do this many hashes to generate key material. */
+ PRUint8 nkd; /* size of readKey and writeKey in bytes. */
+ PRUint8 blockSize;
+ PRUint8 blockShift;
+ CK_MECHANISM_TYPE mechanism;
+ PRUint8 keyLen; /* cipher symkey size in bytes. */
+ PRUint8 pubLen; /* publicly reveal this many bytes of key. */
+ PRUint8 ivLen; /* length of IV data at *ca. */
+} ssl2Specs;
+
+static const ssl2Specs ssl_Specs[] = {
+/* NONE */
+ { 0, 0, 0, 0, },
+/* SSL_CK_RC4_128_WITH_MD5 */
+ { 2, 16, 1, 0, CKM_RC4, 16, 0, 0, },
+/* SSL_CK_RC4_128_EXPORT40_WITH_MD5 */
+ { 2, 16, 1, 0, CKM_RC4, 16, 11, 0, },
+/* SSL_CK_RC2_128_CBC_WITH_MD5 */
+ { 2, 16, 8, 3, CKM_RC2_CBC, 16, 0, 8, },
+/* SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5 */
+ { 2, 16, 8, 3, CKM_RC2_CBC, 16, 11, 8, },
+/* SSL_CK_IDEA_128_CBC_WITH_MD5 */
+ { 0, 0, 0, 0, },
+/* SSL_CK_DES_64_CBC_WITH_MD5 */
+ { 1, 8, 8, 3, CKM_DES_CBC, 8, 0, 8, },
+/* SSL_CK_DES_192_EDE3_CBC_WITH_MD5 */
+ { 3, 24, 8, 3, CKM_DES3_CBC, 24, 0, 8, },
+};
+
+#define SET_ERROR_CODE /* reminder */
+#define TEST_FOR_FAILURE /* reminder */
+
+/*
+** Put a string tag in the library so that we can examine an executable
+** and see what kind of security it supports.
+*/
+const char *ssl_version = "SECURITY_VERSION:"
+ " +us"
+ " +export"
+#ifdef TRACE
+ " +trace"
+#endif
+#ifdef DEBUG
+ " +debug"
+#endif
+ ;
+
+const char * const ssl_cipherName[] = {
+ "unknown",
+ "RC4",
+ "RC4-Export",
+ "RC2-CBC",
+ "RC2-CBC-Export",
+ "IDEA-CBC",
+ "DES-CBC",
+ "DES-EDE3-CBC",
+ "unknown",
+ "unknown", /* was fortezza, NO LONGER USED */
+};
+
+
+/* bit-masks, showing which SSLv2 suites are allowed.
+ * lsb corresponds to first cipher suite in allCipherSuites[].
+ */
+static PRUint16 allowedByPolicy; /* all off by default */
+static PRUint16 maybeAllowedByPolicy; /* all off by default */
+static PRUint16 chosenPreference = 0xff; /* all on by default */
+
+/* bit values for the above two bit masks */
+#define SSL_CB_RC4_128_WITH_MD5 (1 << SSL_CK_RC4_128_WITH_MD5)
+#define SSL_CB_RC4_128_EXPORT40_WITH_MD5 (1 << SSL_CK_RC4_128_EXPORT40_WITH_MD5)
+#define SSL_CB_RC2_128_CBC_WITH_MD5 (1 << SSL_CK_RC2_128_CBC_WITH_MD5)
+#define SSL_CB_RC2_128_CBC_EXPORT40_WITH_MD5 (1 << SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5)
+#define SSL_CB_IDEA_128_CBC_WITH_MD5 (1 << SSL_CK_IDEA_128_CBC_WITH_MD5)
+#define SSL_CB_DES_64_CBC_WITH_MD5 (1 << SSL_CK_DES_64_CBC_WITH_MD5)
+#define SSL_CB_DES_192_EDE3_CBC_WITH_MD5 (1 << SSL_CK_DES_192_EDE3_CBC_WITH_MD5)
+#define SSL_CB_IMPLEMENTED \
+ (SSL_CB_RC4_128_WITH_MD5 | \
+ SSL_CB_RC4_128_EXPORT40_WITH_MD5 | \
+ SSL_CB_RC2_128_CBC_WITH_MD5 | \
+ SSL_CB_RC2_128_CBC_EXPORT40_WITH_MD5 | \
+ SSL_CB_DES_64_CBC_WITH_MD5 | \
+ SSL_CB_DES_192_EDE3_CBC_WITH_MD5)
+
+
+/* Construct a socket's list of cipher specs from the global default values.
+ */
+static SECStatus
+ssl2_ConstructCipherSpecs(sslSocket *ss)
+{
+ PRUint8 * cs = NULL;
+ unsigned int allowed;
+ unsigned int count;
+ int ssl3_count = 0;
+ int final_count;
+ int i;
+ SECStatus rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ count = 0;
+ PORT_Assert(ss != 0);
+ allowed = !ss->opt.enableSSL2 ? 0 :
+ (ss->allowedByPolicy & ss->chosenPreference & SSL_CB_IMPLEMENTED);
+ while (allowed) {
+ if (allowed & 1)
+ ++count;
+ allowed >>= 1;
+ }
+
+ /* Call ssl3_config_match_init() once here,
+ * instead of inside ssl3_ConstructV2CipherSpecsHack(),
+ * because the latter gets called twice below,
+ * and then again in ssl2_BeginClientHandshake().
+ */
+ ssl3_config_match_init(ss);
+
+ /* ask SSL3 how many cipher suites it has. */
+ rv = ssl3_ConstructV2CipherSpecsHack(ss, NULL, &ssl3_count);
+ if (rv < 0)
+ return rv;
+ count += ssl3_count;
+
+ /* Allocate memory to hold cipher specs */
+ if (count > 0)
+ cs = (PRUint8*) PORT_Alloc(count * 3);
+ else
+ PORT_SetError(SSL_ERROR_SSL_DISABLED);
+ if (cs == NULL)
+ return SECFailure;
+
+ if (ss->cipherSpecs != NULL) {
+ PORT_Free(ss->cipherSpecs);
+ }
+ ss->cipherSpecs = cs;
+ ss->sizeCipherSpecs = count * 3;
+
+ /* fill in cipher specs for SSL2 cipher suites */
+ allowed = !ss->opt.enableSSL2 ? 0 :
+ (ss->allowedByPolicy & ss->chosenPreference & SSL_CB_IMPLEMENTED);
+ for (i = 0; i < ssl2_NUM_SUITES_IMPLEMENTED * 3; i += 3) {
+ const PRUint8 * hs = implementedCipherSuites + i;
+ int ok = allowed & (1U << hs[0]);
+ if (ok) {
+ cs[0] = hs[0];
+ cs[1] = hs[1];
+ cs[2] = hs[2];
+ cs += 3;
+ }
+ }
+
+ /* now have SSL3 add its suites onto the end */
+ rv = ssl3_ConstructV2CipherSpecsHack(ss, cs, &final_count);
+
+ /* adjust for any difference between first pass and second pass */
+ ss->sizeCipherSpecs -= (ssl3_count - final_count) * 3;
+
+ return rv;
+}
+
+/* This function is called immediately after ssl2_ConstructCipherSpecs()
+** at the beginning of a handshake. It detects cases where a protocol
+** (e.g. SSL2 or SSL3) is logically enabled, but all its cipher suites
+** for that protocol have been disabled. If such cases, it clears the
+** enable bit for the protocol. If no protocols remain enabled, or
+** if no cipher suites are found, it sets the error code and returns
+** SECFailure, otherwise it returns SECSuccess.
+*/
+static SECStatus
+ssl2_CheckConfigSanity(sslSocket *ss)
+{
+ unsigned int allowed;
+ int ssl3CipherCount = 0;
+ SECStatus rv;
+
+ /* count the SSL2 and SSL3 enabled ciphers.
+ * if either is zero, clear the socket's enable for that protocol.
+ */
+ if (!ss->cipherSpecs)
+ goto disabled;
+
+ allowed = ss->allowedByPolicy & ss->chosenPreference;
+ if (! allowed)
+ ss->opt.enableSSL2 = PR_FALSE; /* not really enabled if no ciphers */
+
+ /* ssl3_config_match_init was called in ssl2_ConstructCipherSpecs(). */
+ /* Ask how many ssl3 CipherSuites were enabled. */
+ rv = ssl3_ConstructV2CipherSpecsHack(ss, NULL, &ssl3CipherCount);
+ if (rv != SECSuccess || ssl3CipherCount <= 0) {
+ /* SSL3/TLS not really enabled if no ciphers */
+ ss->vrange.min = SSL_LIBRARY_VERSION_NONE;
+ ss->vrange.max = SSL_LIBRARY_VERSION_NONE;
+ }
+
+ if (!ss->opt.enableSSL2 && SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
+ SSL_DBG(("%d: SSL[%d]: Can't handshake! all versions disabled.",
+ SSL_GETPID(), ss->fd));
+disabled:
+ PORT_SetError(SSL_ERROR_SSL_DISABLED);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+/*
+ * Since this is a global (not per-socket) setting, we cannot use the
+ * HandshakeLock to protect this. Probably want a global lock.
+ */
+SECStatus
+ssl2_SetPolicy(PRInt32 which, PRInt32 policy)
+{
+ PRUint32 bitMask;
+ SECStatus rv = SECSuccess;
+
+ which &= 0x000f;
+ bitMask = 1 << which;
+
+ if (!(bitMask & SSL_CB_IMPLEMENTED)) {
+ PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
+ return SECFailure;
+ }
+
+ if (policy == SSL_ALLOWED) {
+ allowedByPolicy |= bitMask;
+ maybeAllowedByPolicy |= bitMask;
+ } else if (policy == SSL_RESTRICTED) {
+ allowedByPolicy &= ~bitMask;
+ maybeAllowedByPolicy |= bitMask;
+ } else {
+ allowedByPolicy &= ~bitMask;
+ maybeAllowedByPolicy &= ~bitMask;
+ }
+ allowedByPolicy &= SSL_CB_IMPLEMENTED;
+ maybeAllowedByPolicy &= SSL_CB_IMPLEMENTED;
+
+ policyWasSet = PR_TRUE;
+ return rv;
+}
+
+SECStatus
+ssl2_GetPolicy(PRInt32 which, PRInt32 *oPolicy)
+{
+ PRUint32 bitMask;
+ PRInt32 policy;
+
+ which &= 0x000f;
+ bitMask = 1 << which;
+
+ /* Caller assures oPolicy is not null. */
+ if (!(bitMask & SSL_CB_IMPLEMENTED)) {
+ PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
+ *oPolicy = SSL_NOT_ALLOWED;
+ return SECFailure;
+ }
+
+ if (maybeAllowedByPolicy & bitMask) {
+ policy = (allowedByPolicy & bitMask) ? SSL_ALLOWED : SSL_RESTRICTED;
+ } else {
+ policy = SSL_NOT_ALLOWED;
+ }
+
+ *oPolicy = policy;
+ return SECSuccess;
+}
+
+/*
+ * Since this is a global (not per-socket) setting, we cannot use the
+ * HandshakeLock to protect this. Probably want a global lock.
+ * Called from SSL_CipherPrefSetDefault in sslsock.c
+ * These changes have no effect on any sslSockets already created.
+ */
+SECStatus
+ssl2_CipherPrefSetDefault(PRInt32 which, PRBool enabled)
+{
+ PRUint32 bitMask;
+
+ which &= 0x000f;
+ bitMask = 1 << which;
+
+ if (!(bitMask & SSL_CB_IMPLEMENTED)) {
+ PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
+ return SECFailure;
+ }
+
+ if (enabled)
+ chosenPreference |= bitMask;
+ else
+ chosenPreference &= ~bitMask;
+ chosenPreference &= SSL_CB_IMPLEMENTED;
+
+ return SECSuccess;
+}
+
+SECStatus
+ssl2_CipherPrefGetDefault(PRInt32 which, PRBool *enabled)
+{
+ PRBool rv = PR_FALSE;
+ PRUint32 bitMask;
+
+ which &= 0x000f;
+ bitMask = 1 << which;
+
+ if (!(bitMask & SSL_CB_IMPLEMENTED)) {
+ PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
+ *enabled = PR_FALSE;
+ return SECFailure;
+ }
+
+ rv = (PRBool)((chosenPreference & bitMask) != 0);
+ *enabled = rv;
+ return SECSuccess;
+}
+
+SECStatus
+ssl2_CipherPrefSet(sslSocket *ss, PRInt32 which, PRBool enabled)
+{
+ PRUint32 bitMask;
+
+ which &= 0x000f;
+ bitMask = 1 << which;
+
+ if (!(bitMask & SSL_CB_IMPLEMENTED)) {
+ PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
+ return SECFailure;
+ }
+
+ if (enabled)
+ ss->chosenPreference |= bitMask;
+ else
+ ss->chosenPreference &= ~bitMask;
+ ss->chosenPreference &= SSL_CB_IMPLEMENTED;
+
+ return SECSuccess;
+}
+
+SECStatus
+ssl2_CipherPrefGet(sslSocket *ss, PRInt32 which, PRBool *enabled)
+{
+ PRBool rv = PR_FALSE;
+ PRUint32 bitMask;
+
+ which &= 0x000f;
+ bitMask = 1 << which;
+
+ if (!(bitMask & SSL_CB_IMPLEMENTED)) {
+ PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
+ *enabled = PR_FALSE;
+ return SECFailure;
+ }
+
+ rv = (PRBool)((ss->chosenPreference & bitMask) != 0);
+ *enabled = rv;
+ return SECSuccess;
+}
+
+
+/* copy global default policy into socket. */
+void
+ssl2_InitSocketPolicy(sslSocket *ss)
+{
+ ss->allowedByPolicy = allowedByPolicy;
+ ss->maybeAllowedByPolicy = maybeAllowedByPolicy;
+ ss->chosenPreference = chosenPreference;
+}
+
+
+/************************************************************************/
+
+/* Called from ssl2_CreateSessionCypher(), which already holds handshake lock.
+ */
+static SECStatus
+ssl2_CreateMAC(sslSecurityInfo *sec, SECItem *readKey, SECItem *writeKey,
+ int cipherChoice)
+{
+ switch (cipherChoice) {
+
+ case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:
+ case SSL_CK_RC2_128_CBC_WITH_MD5:
+ case SSL_CK_RC4_128_EXPORT40_WITH_MD5:
+ case SSL_CK_RC4_128_WITH_MD5:
+ case SSL_CK_DES_64_CBC_WITH_MD5:
+ case SSL_CK_DES_192_EDE3_CBC_WITH_MD5:
+ sec->hash = HASH_GetHashObject(HASH_AlgMD5);
+ SECITEM_CopyItem(0, &sec->sendSecret, writeKey);
+ SECITEM_CopyItem(0, &sec->rcvSecret, readKey);
+ break;
+
+ default:
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+ return SECFailure;
+ }
+ sec->hashcx = (*sec->hash->create)();
+ if (sec->hashcx == NULL)
+ return SECFailure;
+ return SECSuccess;
+}
+
+/************************************************************************
+ * All the Send functions below must acquire and release the socket's
+ * xmitBufLock.
+ */
+
+/* Called from all the Send* functions below. */
+static SECStatus
+ssl2_GetSendBuffer(sslSocket *ss, unsigned int len)
+{
+ SECStatus rv = SECSuccess;
+
+ PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
+
+ if (len < 128) {
+ len = 128;
+ }
+ if (len > ss->sec.ci.sendBuf.space) {
+ rv = sslBuffer_Grow(&ss->sec.ci.sendBuf, len);
+ if (rv != SECSuccess) {
+ SSL_DBG(("%d: SSL[%d]: ssl2_GetSendBuffer failed, tried to get %d bytes",
+ SSL_GETPID(), ss->fd, len));
+ rv = SECFailure;
+ }
+ }
+ return rv;
+}
+
+/* Called from:
+ * ssl2_ClientSetupSessionCypher() <- ssl2_HandleServerHelloMessage()
+ * ssl2_HandleRequestCertificate() <- ssl2_HandleMessage() <-
+ ssl_Do1stHandshake()
+ * ssl2_HandleMessage() <- ssl_Do1stHandshake()
+ * ssl2_HandleServerHelloMessage() <- ssl_Do1stHandshake()
+ after ssl2_BeginClientHandshake()
+ * ssl2_HandleClientHelloMessage() <- ssl_Do1stHandshake()
+ after ssl2_BeginServerHandshake()
+ *
+ * Acquires and releases the socket's xmitBufLock.
+ */
+int
+ssl2_SendErrorMessage(sslSocket *ss, int error)
+{
+ int rv;
+ PRUint8 msg[SSL_HL_ERROR_HBYTES];
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ msg[0] = SSL_MT_ERROR;
+ msg[1] = MSB(error);
+ msg[2] = LSB(error);
+
+ ssl_GetXmitBufLock(ss); /***************************************/
+
+ SSL_TRC(3, ("%d: SSL[%d]: sending error %d", SSL_GETPID(), ss->fd, error));
+
+ ss->handshakeBegun = 1;
+ rv = (*ss->sec.send)(ss, msg, sizeof(msg), 0);
+ if (rv >= 0) {
+ rv = SECSuccess;
+ }
+ ssl_ReleaseXmitBufLock(ss); /***************************************/
+ return rv;
+}
+
+/* Called from ssl2_TryToFinish().
+ * Acquires and releases the socket's xmitBufLock.
+ */
+static SECStatus
+ssl2_SendClientFinishedMessage(sslSocket *ss)
+{
+ SECStatus rv = SECSuccess;
+ int sent;
+ PRUint8 msg[1 + SSL_CONNECTIONID_BYTES];
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ ssl_GetXmitBufLock(ss); /***************************************/
+
+ if (ss->sec.ci.sentFinished == 0) {
+ ss->sec.ci.sentFinished = 1;
+
+ SSL_TRC(3, ("%d: SSL[%d]: sending client-finished",
+ SSL_GETPID(), ss->fd));
+
+ msg[0] = SSL_MT_CLIENT_FINISHED;
+ PORT_Memcpy(msg+1, ss->sec.ci.connectionID,
+ sizeof(ss->sec.ci.connectionID));
+
+ DUMP_MSG(29, (ss, msg, 1 + sizeof(ss->sec.ci.connectionID)));
+ sent = (*ss->sec.send)(ss, msg, 1 + sizeof(ss->sec.ci.connectionID), 0);
+ rv = (sent >= 0) ? SECSuccess : (SECStatus)sent;
+ }
+ ssl_ReleaseXmitBufLock(ss); /***************************************/
+ return rv;
+}
+
+/* Called from
+ * ssl2_HandleClientSessionKeyMessage() <- ssl2_HandleClientHelloMessage()
+ * ssl2_HandleClientHelloMessage() <- ssl_Do1stHandshake()
+ after ssl2_BeginServerHandshake()
+ * Acquires and releases the socket's xmitBufLock.
+ */
+static SECStatus
+ssl2_SendServerVerifyMessage(sslSocket *ss)
+{
+ PRUint8 * msg;
+ int sendLen;
+ int sent;
+ SECStatus rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ ssl_GetXmitBufLock(ss); /***************************************/
+
+ sendLen = 1 + SSL_CHALLENGE_BYTES;
+ rv = ssl2_GetSendBuffer(ss, sendLen);
+ if (rv != SECSuccess) {
+ goto done;
+ }
+
+ msg = ss->sec.ci.sendBuf.buf;
+ msg[0] = SSL_MT_SERVER_VERIFY;
+ PORT_Memcpy(msg+1, ss->sec.ci.clientChallenge, SSL_CHALLENGE_BYTES);
+
+ DUMP_MSG(29, (ss, msg, sendLen));
+ sent = (*ss->sec.send)(ss, msg, sendLen, 0);
+
+ rv = (sent >= 0) ? SECSuccess : (SECStatus)sent;
+
+done:
+ ssl_ReleaseXmitBufLock(ss); /***************************************/
+ return rv;
+}
+
+/* Called from ssl2_TryToFinish().
+ * Acquires and releases the socket's xmitBufLock.
+ */
+static SECStatus
+ssl2_SendServerFinishedMessage(sslSocket *ss)
+{
+ sslSessionID * sid;
+ PRUint8 * msg;
+ int sendLen, sent;
+ SECStatus rv = SECSuccess;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ ssl_GetXmitBufLock(ss); /***************************************/
+
+ if (ss->sec.ci.sentFinished == 0) {
+ ss->sec.ci.sentFinished = 1;
+ PORT_Assert(ss->sec.ci.sid != 0);
+ sid = ss->sec.ci.sid;
+
+ SSL_TRC(3, ("%d: SSL[%d]: sending server-finished",
+ SSL_GETPID(), ss->fd));
+
+ sendLen = 1 + sizeof(sid->u.ssl2.sessionID);
+ rv = ssl2_GetSendBuffer(ss, sendLen);
+ if (rv != SECSuccess) {
+ goto done;
+ }
+
+ msg = ss->sec.ci.sendBuf.buf;
+ msg[0] = SSL_MT_SERVER_FINISHED;
+ PORT_Memcpy(msg+1, sid->u.ssl2.sessionID,
+ sizeof(sid->u.ssl2.sessionID));
+
+ DUMP_MSG(29, (ss, msg, sendLen));
+ sent = (*ss->sec.send)(ss, msg, sendLen, 0);
+
+ if (sent < 0) {
+ /* If send failed, it is now a bogus session-id */
+ if (ss->sec.uncache)
+ (*ss->sec.uncache)(sid);
+ rv = (SECStatus)sent;
+ } else if (!ss->opt.noCache) {
+ /* Put the sid in session-id cache, (may already be there) */
+ (*ss->sec.cache)(sid);
+ rv = SECSuccess;
+ }
+ ssl_FreeSID(sid);
+ ss->sec.ci.sid = 0;
+ }
+done:
+ ssl_ReleaseXmitBufLock(ss); /***************************************/
+ return rv;
+}
+
+/* Called from ssl2_ClientSetupSessionCypher() <-
+ * ssl2_HandleServerHelloMessage()
+ * after ssl2_BeginClientHandshake()
+ * Acquires and releases the socket's xmitBufLock.
+ */
+static SECStatus
+ssl2_SendSessionKeyMessage(sslSocket *ss, int cipher, int keySize,
+ PRUint8 *ca, int caLen,
+ PRUint8 *ck, int ckLen,
+ PRUint8 *ek, int ekLen)
+{
+ PRUint8 * msg;
+ int sendLen;
+ int sent;
+ SECStatus rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ ssl_GetXmitBufLock(ss); /***************************************/
+
+ sendLen = SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen + ekLen + caLen;
+ rv = ssl2_GetSendBuffer(ss, sendLen);
+ if (rv != SECSuccess)
+ goto done;
+
+ SSL_TRC(3, ("%d: SSL[%d]: sending client-session-key",
+ SSL_GETPID(), ss->fd));
+
+ msg = ss->sec.ci.sendBuf.buf;
+ msg[0] = SSL_MT_CLIENT_MASTER_KEY;
+ msg[1] = cipher;
+ msg[2] = MSB(keySize);
+ msg[3] = LSB(keySize);
+ msg[4] = MSB(ckLen);
+ msg[5] = LSB(ckLen);
+ msg[6] = MSB(ekLen);
+ msg[7] = LSB(ekLen);
+ msg[8] = MSB(caLen);
+ msg[9] = LSB(caLen);
+ PORT_Memcpy(msg+SSL_HL_CLIENT_MASTER_KEY_HBYTES, ck, ckLen);
+ PORT_Memcpy(msg+SSL_HL_CLIENT_MASTER_KEY_HBYTES+ckLen, ek, ekLen);
+ PORT_Memcpy(msg+SSL_HL_CLIENT_MASTER_KEY_HBYTES+ckLen+ekLen, ca, caLen);
+
+ DUMP_MSG(29, (ss, msg, sendLen));
+ sent = (*ss->sec.send)(ss, msg, sendLen, 0);
+ rv = (sent >= 0) ? SECSuccess : (SECStatus)sent;
+done:
+ ssl_ReleaseXmitBufLock(ss); /***************************************/
+ return rv;
+}
+
+/* Called from ssl2_TriggerNextMessage() <- ssl2_HandleMessage()
+ * Acquires and releases the socket's xmitBufLock.
+ */
+static SECStatus
+ssl2_SendCertificateRequestMessage(sslSocket *ss)
+{
+ PRUint8 * msg;
+ int sent;
+ int sendLen;
+ SECStatus rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ ssl_GetXmitBufLock(ss); /***************************************/
+
+ sendLen = SSL_HL_REQUEST_CERTIFICATE_HBYTES + SSL_CHALLENGE_BYTES;
+ rv = ssl2_GetSendBuffer(ss, sendLen);
+ if (rv != SECSuccess)
+ goto done;
+
+ SSL_TRC(3, ("%d: SSL[%d]: sending certificate request",
+ SSL_GETPID(), ss->fd));
+
+ /* Generate random challenge for client to encrypt */
+ PK11_GenerateRandom(ss->sec.ci.serverChallenge, SSL_CHALLENGE_BYTES);
+
+ msg = ss->sec.ci.sendBuf.buf;
+ msg[0] = SSL_MT_REQUEST_CERTIFICATE;
+ msg[1] = SSL_AT_MD5_WITH_RSA_ENCRYPTION;
+ PORT_Memcpy(msg + SSL_HL_REQUEST_CERTIFICATE_HBYTES,
+ ss->sec.ci.serverChallenge, SSL_CHALLENGE_BYTES);
+
+ DUMP_MSG(29, (ss, msg, sendLen));
+ sent = (*ss->sec.send)(ss, msg, sendLen, 0);
+ rv = (sent >= 0) ? SECSuccess : (SECStatus)sent;
+done:
+ ssl_ReleaseXmitBufLock(ss); /***************************************/
+ return rv;
+}
+
+/* Called from ssl2_HandleRequestCertificate() <- ssl2_HandleMessage()
+ * Acquires and releases the socket's xmitBufLock.
+ */
+static int
+ssl2_SendCertificateResponseMessage(sslSocket *ss, SECItem *cert,
+ SECItem *encCode)
+{
+ PRUint8 *msg;
+ int rv, sendLen;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ ssl_GetXmitBufLock(ss); /***************************************/
+
+ sendLen = SSL_HL_CLIENT_CERTIFICATE_HBYTES + encCode->len + cert->len;
+ rv = ssl2_GetSendBuffer(ss, sendLen);
+ if (rv)
+ goto done;
+
+ SSL_TRC(3, ("%d: SSL[%d]: sending certificate response",
+ SSL_GETPID(), ss->fd));
+
+ msg = ss->sec.ci.sendBuf.buf;
+ msg[0] = SSL_MT_CLIENT_CERTIFICATE;
+ msg[1] = SSL_CT_X509_CERTIFICATE;
+ msg[2] = MSB(cert->len);
+ msg[3] = LSB(cert->len);
+ msg[4] = MSB(encCode->len);
+ msg[5] = LSB(encCode->len);
+ PORT_Memcpy(msg + SSL_HL_CLIENT_CERTIFICATE_HBYTES, cert->data, cert->len);
+ PORT_Memcpy(msg + SSL_HL_CLIENT_CERTIFICATE_HBYTES + cert->len,
+ encCode->data, encCode->len);
+
+ DUMP_MSG(29, (ss, msg, sendLen));
+ rv = (*ss->sec.send)(ss, msg, sendLen, 0);
+ if (rv >= 0) {
+ rv = SECSuccess;
+ }
+done:
+ ssl_ReleaseXmitBufLock(ss); /***************************************/
+ return rv;
+}
+
+/********************************************************************
+** Send functions above this line must aquire & release the socket's
+** xmitBufLock.
+** All the ssl2_Send functions below this line are called vis ss->sec.send
+** and require that the caller hold the xmitBufLock.
+*/
+
+/*
+** Called from ssl2_SendStream, ssl2_SendBlock, but not from ssl2_SendClear.
+*/
+static SECStatus
+ssl2_CalcMAC(PRUint8 * result,
+ sslSecurityInfo * sec,
+ const PRUint8 * data,
+ unsigned int dataLen,
+ unsigned int paddingLen)
+{
+ const PRUint8 * secret = sec->sendSecret.data;
+ unsigned int secretLen = sec->sendSecret.len;
+ unsigned long sequenceNumber = sec->sendSequence;
+ unsigned int nout;
+ PRUint8 seq[4];
+ PRUint8 padding[32];/* XXX max blocksize? */
+
+ if (!sec->hash || !sec->hash->length)
+ return SECSuccess;
+ if (!sec->hashcx)
+ return SECFailure;
+
+ /* Reset hash function */
+ (*sec->hash->begin)(sec->hashcx);
+
+ /* Feed hash the data */
+ (*sec->hash->update)(sec->hashcx, secret, secretLen);
+ (*sec->hash->update)(sec->hashcx, data, dataLen);
+ PORT_Memset(padding, paddingLen, paddingLen);
+ (*sec->hash->update)(sec->hashcx, padding, paddingLen);
+
+ seq[0] = (PRUint8) (sequenceNumber >> 24);
+ seq[1] = (PRUint8) (sequenceNumber >> 16);
+ seq[2] = (PRUint8) (sequenceNumber >> 8);
+ seq[3] = (PRUint8) (sequenceNumber);
+
+ PRINT_BUF(60, (0, "calc-mac secret:", secret, secretLen));
+ PRINT_BUF(60, (0, "calc-mac data:", data, dataLen));
+ PRINT_BUF(60, (0, "calc-mac padding:", padding, paddingLen));
+ PRINT_BUF(60, (0, "calc-mac seq:", seq, 4));
+
+ (*sec->hash->update)(sec->hashcx, seq, 4);
+
+ /* Get result */
+ (*sec->hash->end)(sec->hashcx, result, &nout, sec->hash->length);
+
+ return SECSuccess;
+}
+
+/*
+** Maximum transmission amounts. These are tiny bit smaller than they
+** need to be (they account for the MAC length plus some padding),
+** assuming the MAC is 16 bytes long and the padding is a max of 7 bytes
+** long. This gives an additional 9 bytes of slop to work within.
+*/
+#define MAX_STREAM_CYPHER_LEN 0x7fe0
+#define MAX_BLOCK_CYPHER_LEN 0x3fe0
+
+/*
+** Send some data in the clear.
+** Package up data with the length header and send it.
+**
+** Return count of bytes successfully written, or negative number (failure).
+*/
+static PRInt32
+ssl2_SendClear(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags)
+{
+ PRUint8 * out;
+ int rv;
+ int amount;
+ int count = 0;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
+
+ SSL_TRC(10, ("%d: SSL[%d]: sending %d bytes in the clear",
+ SSL_GETPID(), ss->fd, len));
+ PRINT_BUF(50, (ss, "clear data:", (PRUint8*) in, len));
+
+ while (len) {
+ amount = PR_MIN( len, MAX_STREAM_CYPHER_LEN );
+ if (amount + 2 > ss->sec.writeBuf.space) {
+ rv = sslBuffer_Grow(&ss->sec.writeBuf, amount + 2);
+ if (rv != SECSuccess) {
+ count = rv;
+ break;
+ }
+ }
+ out = ss->sec.writeBuf.buf;
+
+ /*
+ ** Construct message.
+ */
+ out[0] = 0x80 | MSB(amount);
+ out[1] = LSB(amount);
+ PORT_Memcpy(&out[2], in, amount);
+
+ /* Now send the data */
+ rv = ssl_DefSend(ss, out, amount + 2, flags & ~ssl_SEND_FLAG_MASK);
+ if (rv < 0) {
+ if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) {
+ rv = 0;
+ } else {
+ /* Return short write if some data already went out... */
+ if (count == 0)
+ count = rv;
+ break;
+ }
+ }
+
+ if ((unsigned)rv < (amount + 2)) {
+ /* Short write. Save the data and return. */
+ if (ssl_SaveWriteData(ss, out + rv, amount + 2 - rv)
+ == SECFailure) {
+ count = SECFailure;
+ } else {
+ count += amount;
+ ss->sec.sendSequence++;
+ }
+ break;
+ }
+
+ ss->sec.sendSequence++;
+ in += amount;
+ count += amount;
+ len -= amount;
+ }
+
+ return count;
+}
+
+/*
+** Send some data, when using a stream cipher. Stream ciphers have a
+** block size of 1. Package up the data with the length header
+** and send it.
+*/
+static PRInt32
+ssl2_SendStream(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags)
+{
+ PRUint8 * out;
+ int rv;
+ int count = 0;
+
+ int amount;
+ PRUint8 macLen;
+ int nout;
+ int buflen;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
+
+ SSL_TRC(10, ("%d: SSL[%d]: sending %d bytes using stream cipher",
+ SSL_GETPID(), ss->fd, len));
+ PRINT_BUF(50, (ss, "clear data:", (PRUint8*) in, len));
+
+ while (len) {
+ ssl_GetSpecReadLock(ss); /*************************************/
+
+ macLen = ss->sec.hash->length;
+ amount = PR_MIN( len, MAX_STREAM_CYPHER_LEN );
+ buflen = amount + 2 + macLen;
+ if (buflen > ss->sec.writeBuf.space) {
+ rv = sslBuffer_Grow(&ss->sec.writeBuf, buflen);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ out = ss->sec.writeBuf.buf;
+ nout = amount + macLen;
+ out[0] = 0x80 | MSB(nout);
+ out[1] = LSB(nout);
+
+ /* Calculate MAC */
+ rv = ssl2_CalcMAC(out+2, /* put MAC here */
+ &ss->sec,
+ in, amount, /* input addr & length */
+ 0); /* no padding */
+ if (rv != SECSuccess)
+ goto loser;
+
+ /* Encrypt MAC */
+ rv = (*ss->sec.enc)(ss->sec.writecx, out+2, &nout, macLen, out+2, macLen);
+ if (rv) goto loser;
+
+ /* Encrypt data from caller */
+ rv = (*ss->sec.enc)(ss->sec.writecx, out+2+macLen, &nout, amount, in, amount);
+ if (rv) goto loser;
+
+ ssl_ReleaseSpecReadLock(ss); /*************************************/
+
+ PRINT_BUF(50, (ss, "encrypted data:", out, buflen));
+
+ rv = ssl_DefSend(ss, out, buflen, flags & ~ssl_SEND_FLAG_MASK);
+ if (rv < 0) {
+ if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) {
+ SSL_TRC(50, ("%d: SSL[%d]: send stream would block, "
+ "saving data", SSL_GETPID(), ss->fd));
+ rv = 0;
+ } else {
+ SSL_TRC(10, ("%d: SSL[%d]: send stream error %d",
+ SSL_GETPID(), ss->fd, PORT_GetError()));
+ /* Return short write if some data already went out... */
+ if (count == 0)
+ count = rv;
+ goto done;
+ }
+ }
+
+ if ((unsigned)rv < buflen) {
+ /* Short write. Save the data and return. */
+ if (ssl_SaveWriteData(ss, out + rv, buflen - rv) == SECFailure) {
+ count = SECFailure;
+ } else {
+ count += amount;
+ ss->sec.sendSequence++;
+ }
+ goto done;
+ }
+
+ ss->sec.sendSequence++;
+ in += amount;
+ count += amount;
+ len -= amount;
+ }
+
+done:
+ return count;
+
+loser:
+ ssl_ReleaseSpecReadLock(ss);
+ return SECFailure;
+}
+
+/*
+** Send some data, when using a block cipher. Package up the data with
+** the length header and send it.
+*/
+/* XXX assumes blocksize is > 7 */
+static PRInt32
+ssl2_SendBlock(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags)
+{
+ PRUint8 * out; /* begining of output buffer. */
+ PRUint8 * op; /* next output byte goes here. */
+ int rv; /* value from funcs we called. */
+ int count = 0; /* this function's return value. */
+
+ unsigned int hlen; /* output record hdr len, 2 or 3 */
+ unsigned int macLen; /* MAC is this many bytes long. */
+ int amount; /* of plaintext to go in record. */
+ unsigned int padding; /* add this many padding byte. */
+ int nout; /* ciphertext size after header. */
+ int buflen; /* size of generated record. */
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
+
+ SSL_TRC(10, ("%d: SSL[%d]: sending %d bytes using block cipher",
+ SSL_GETPID(), ss->fd, len));
+ PRINT_BUF(50, (ss, "clear data:", in, len));
+
+ while (len) {
+ ssl_GetSpecReadLock(ss); /*************************************/
+
+ macLen = ss->sec.hash->length;
+ /* Figure out how much to send, including mac and padding */
+ amount = PR_MIN( len, MAX_BLOCK_CYPHER_LEN );
+ nout = amount + macLen;
+ padding = nout & (ss->sec.blockSize - 1);
+ if (padding) {
+ hlen = 3;
+ padding = ss->sec.blockSize - padding;
+ nout += padding;
+ } else {
+ hlen = 2;
+ }
+ buflen = hlen + nout;
+ if (buflen > ss->sec.writeBuf.space) {
+ rv = sslBuffer_Grow(&ss->sec.writeBuf, buflen);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ out = ss->sec.writeBuf.buf;
+
+ /* Construct header */
+ op = out;
+ if (padding) {
+ *op++ = MSB(nout);
+ *op++ = LSB(nout);
+ *op++ = padding;
+ } else {
+ *op++ = 0x80 | MSB(nout);
+ *op++ = LSB(nout);
+ }
+
+ /* Calculate MAC */
+ rv = ssl2_CalcMAC(op, /* MAC goes here. */
+ &ss->sec,
+ in, amount, /* intput addr, len */
+ padding);
+ if (rv != SECSuccess)
+ goto loser;
+ op += macLen;
+
+ /* Copy in the input data */
+ /* XXX could eliminate the copy by folding it into the encryption */
+ PORT_Memcpy(op, in, amount);
+ op += amount;
+ if (padding) {
+ PORT_Memset(op, padding, padding);
+ op += padding;
+ }
+
+ /* Encrypt result */
+ rv = (*ss->sec.enc)(ss->sec.writecx, out+hlen, &nout, buflen-hlen,
+ out+hlen, op - (out + hlen));
+ if (rv)
+ goto loser;
+
+ ssl_ReleaseSpecReadLock(ss); /*************************************/
+
+ PRINT_BUF(50, (ss, "final xmit data:", out, op - out));
+
+ rv = ssl_DefSend(ss, out, op - out, flags & ~ssl_SEND_FLAG_MASK);
+ if (rv < 0) {
+ if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) {
+ rv = 0;
+ } else {
+ SSL_TRC(10, ("%d: SSL[%d]: send block error %d",
+ SSL_GETPID(), ss->fd, PORT_GetError()));
+ /* Return short write if some data already went out... */
+ if (count == 0)
+ count = rv;
+ goto done;
+ }
+ }
+
+ if (rv < (op - out)) {
+ /* Short write. Save the data and return. */
+ if (ssl_SaveWriteData(ss, out + rv, op - out - rv) == SECFailure) {
+ count = SECFailure;
+ } else {
+ count += amount;
+ ss->sec.sendSequence++;
+ }
+ goto done;
+ }
+
+ ss->sec.sendSequence++;
+ in += amount;
+ count += amount;
+ len -= amount;
+ }
+
+done:
+ return count;
+
+loser:
+ ssl_ReleaseSpecReadLock(ss);
+ return SECFailure;
+}
+
+/*
+** Called from: ssl2_HandleServerHelloMessage,
+** ssl2_HandleClientSessionKeyMessage,
+** ssl2_HandleClientHelloMessage,
+**
+*/
+static void
+ssl2_UseEncryptedSendFunc(sslSocket *ss)
+{
+ ssl_GetXmitBufLock(ss);
+ PORT_Assert(ss->sec.hashcx != 0);
+
+ ss->gs.encrypted = 1;
+ ss->sec.send = (ss->sec.blockSize > 1) ? ssl2_SendBlock : ssl2_SendStream;
+ ssl_ReleaseXmitBufLock(ss);
+}
+
+/* Called while initializing socket in ssl_CreateSecurityInfo().
+** This function allows us to keep the name of ssl2_SendClear static.
+*/
+void
+ssl2_UseClearSendFunc(sslSocket *ss)
+{
+ ss->sec.send = ssl2_SendClear;
+}
+
+/************************************************************************
+** END of Send functions. *
+*************************************************************************/
+
+/***********************************************************************
+ * For SSL3, this gathers in and handles records/messages until either
+ * the handshake is complete or application data is available.
+ *
+ * For SSL2, this gathers in only the next SSLV2 record.
+ *
+ * Called from ssl_Do1stHandshake() via function pointer ss->handshake.
+ * Caller must hold handshake lock.
+ * This function acquires and releases the RecvBufLock.
+ *
+ * returns SECSuccess for success.
+ * returns SECWouldBlock when that value is returned by ssl2_GatherRecord() or
+ * ssl3_GatherCompleteHandshake().
+ * returns SECFailure on all other errors.
+ *
+ * The gather functions called by ssl_GatherRecord1stHandshake are expected
+ * to return values interpreted as follows:
+ * 1 : the function completed without error.
+ * 0 : the function read EOF.
+ * -1 : read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error.
+ * -2 : the function wants ssl_GatherRecord1stHandshake to be called again
+ * immediately, by ssl_Do1stHandshake.
+ *
+ * This code is similar to, and easily confused with, DoRecv() in sslsecur.c
+ *
+ * This function is called from ssl_Do1stHandshake().
+ * The following functions put ssl_GatherRecord1stHandshake into ss->handshake:
+ * ssl2_HandleMessage
+ * ssl2_HandleVerifyMessage
+ * ssl2_HandleServerHelloMessage
+ * ssl2_BeginClientHandshake
+ * ssl2_HandleClientSessionKeyMessage
+ * ssl3_RestartHandshakeAfterCertReq
+ * ssl3_RestartHandshakeAfterServerCert
+ * ssl2_HandleClientHelloMessage
+ * ssl2_BeginServerHandshake
+ */
+SECStatus
+ssl_GatherRecord1stHandshake(sslSocket *ss)
+{
+ int rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ ssl_GetRecvBufLock(ss);
+
+ /* The special case DTLS logic is needed here because the SSL/TLS
+ * version wants to auto-detect SSL2 vs. SSL3 on the initial handshake
+ * (ss->version == 0) but with DTLS it gets confused, so we force the
+ * SSL3 version.
+ */
+ if ((ss->version >= SSL_LIBRARY_VERSION_3_0) || IS_DTLS(ss)) {
+ /* Wait for handshake to complete, or application data to arrive. */
+ rv = ssl3_GatherCompleteHandshake(ss, 0);
+ } else {
+ /* See if we have a complete record */
+ rv = ssl2_GatherRecord(ss, 0);
+ }
+ SSL_TRC(10, ("%d: SSL[%d]: handshake gathering, rv=%d",
+ SSL_GETPID(), ss->fd, rv));
+
+ ssl_ReleaseRecvBufLock(ss);
+
+ if (rv <= 0) {
+ if (rv == SECWouldBlock) {
+ /* Progress is blocked waiting for callback completion. */
+ SSL_TRC(10, ("%d: SSL[%d]: handshake blocked (need %d)",
+ SSL_GETPID(), ss->fd, ss->gs.remainder));
+ return SECWouldBlock;
+ }
+ if (rv == 0) {
+ /* EOF. Loser */
+ PORT_SetError(PR_END_OF_FILE_ERROR);
+ }
+ return SECFailure; /* rv is < 0 here. */
+ }
+
+ SSL_TRC(10, ("%d: SSL[%d]: got handshake record of %d bytes",
+ SSL_GETPID(), ss->fd, ss->gs.recordLen));
+
+ ss->handshake = 0; /* makes ssl_Do1stHandshake call ss->nextHandshake.*/
+ return SECSuccess;
+}
+
+/************************************************************************/
+
+/* Called from ssl2_ServerSetupSessionCypher()
+ * ssl2_ClientSetupSessionCypher()
+ */
+static SECStatus
+ssl2_FillInSID(sslSessionID * sid,
+ int cipher,
+ PRUint8 *keyData,
+ int keyLen,
+ PRUint8 *ca,
+ int caLen,
+ int keyBits,
+ int secretKeyBits,
+ SSLSignType authAlgorithm,
+ PRUint32 authKeyBits,
+ SSLKEAType keaType,
+ PRUint32 keaKeyBits)
+{
+ PORT_Assert(sid->references == 1);
+ PORT_Assert(sid->cached == never_cached);
+ PORT_Assert(sid->u.ssl2.masterKey.data == 0);
+ PORT_Assert(sid->u.ssl2.cipherArg.data == 0);
+
+ sid->version = SSL_LIBRARY_VERSION_2;
+
+ sid->u.ssl2.cipherType = cipher;
+ sid->u.ssl2.masterKey.data = (PRUint8*) PORT_Alloc(keyLen);
+ if (!sid->u.ssl2.masterKey.data) {
+ return SECFailure;
+ }
+ PORT_Memcpy(sid->u.ssl2.masterKey.data, keyData, keyLen);
+ sid->u.ssl2.masterKey.len = keyLen;
+ sid->u.ssl2.keyBits = keyBits;
+ sid->u.ssl2.secretKeyBits = secretKeyBits;
+ sid->authAlgorithm = authAlgorithm;
+ sid->authKeyBits = authKeyBits;
+ sid->keaType = keaType;
+ sid->keaKeyBits = keaKeyBits;
+ sid->lastAccessTime = sid->creationTime = ssl_Time();
+ sid->expirationTime = sid->creationTime + ssl_sid_timeout;
+
+ if (caLen) {
+ sid->u.ssl2.cipherArg.data = (PRUint8*) PORT_Alloc(caLen);
+ if (!sid->u.ssl2.cipherArg.data) {
+ return SECFailure;
+ }
+ sid->u.ssl2.cipherArg.len = caLen;
+ PORT_Memcpy(sid->u.ssl2.cipherArg.data, ca, caLen);
+ }
+ return SECSuccess;
+}
+
+/*
+** Construct session keys given the masterKey (tied to the session-id),
+** the client's challenge and the server's nonce.
+**
+** Called from ssl2_CreateSessionCypher() <-
+*/
+static SECStatus
+ssl2_ProduceKeys(sslSocket * ss,
+ SECItem * readKey,
+ SECItem * writeKey,
+ SECItem * masterKey,
+ PRUint8 * challenge,
+ PRUint8 * nonce,
+ int cipherType)
+{
+ PK11Context * cx = 0;
+ unsigned nkm = 0; /* number of hashes to generate key mat. */
+ unsigned nkd = 0; /* size of readKey and writeKey. */
+ unsigned part;
+ unsigned i;
+ unsigned off;
+ SECStatus rv;
+ PRUint8 countChar;
+ PRUint8 km[3*16]; /* buffer for key material. */
+
+ readKey->data = 0;
+ writeKey->data = 0;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ rv = SECSuccess;
+ cx = PK11_CreateDigestContext(SEC_OID_MD5);
+ if (cx == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
+ return SECFailure;
+ }
+
+ nkm = ssl_Specs[cipherType].nkm;
+ nkd = ssl_Specs[cipherType].nkd;
+
+ readKey->data = (PRUint8*) PORT_Alloc(nkd);
+ if (!readKey->data)
+ goto loser;
+ readKey->len = nkd;
+
+ writeKey->data = (PRUint8*) PORT_Alloc(nkd);
+ if (!writeKey->data)
+ goto loser;
+ writeKey->len = nkd;
+
+ /* Produce key material */
+ countChar = '0';
+ for (i = 0, off = 0; i < nkm; i++, off += 16) {
+ rv = PK11_DigestBegin(cx);
+ rv |= PK11_DigestOp(cx, masterKey->data, masterKey->len);
+ rv |= PK11_DigestOp(cx, &countChar, 1);
+ rv |= PK11_DigestOp(cx, challenge, SSL_CHALLENGE_BYTES);
+ rv |= PK11_DigestOp(cx, nonce, SSL_CONNECTIONID_BYTES);
+ rv |= PK11_DigestFinal(cx, km+off, &part, MD5_LENGTH);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
+ rv = SECFailure;
+ goto loser;
+ }
+ countChar++;
+ }
+
+ /* Produce keys */
+ PORT_Memcpy(readKey->data, km, nkd);
+ PORT_Memcpy(writeKey->data, km + nkd, nkd);
+
+loser:
+ PK11_DestroyContext(cx, PR_TRUE);
+ return rv;
+}
+
+/* Called from ssl2_ServerSetupSessionCypher()
+** <- ssl2_HandleClientSessionKeyMessage()
+** <- ssl2_HandleClientHelloMessage()
+** and from ssl2_ClientSetupSessionCypher()
+** <- ssl2_HandleServerHelloMessage()
+*/
+static SECStatus
+ssl2_CreateSessionCypher(sslSocket *ss, sslSessionID *sid, PRBool isClient)
+{
+ SECItem * rk = NULL;
+ SECItem * wk = NULL;
+ SECItem * param;
+ SECStatus rv;
+ int cipherType = sid->u.ssl2.cipherType;
+ PK11SlotInfo * slot = NULL;
+ CK_MECHANISM_TYPE mechanism;
+ SECItem readKey;
+ SECItem writeKey;
+
+ void *readcx = 0;
+ void *writecx = 0;
+ readKey.data = 0;
+ writeKey.data = 0;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+ if (ss->sec.ci.sid == 0)
+ goto sec_loser; /* don't crash if asserts are off */
+
+ /* Trying to cut down on all these switch statements that should be tables.
+ * So, test cipherType once, here, and then use tables below.
+ */
+ switch (cipherType) {
+ case SSL_CK_RC4_128_EXPORT40_WITH_MD5:
+ case SSL_CK_RC4_128_WITH_MD5:
+ case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:
+ case SSL_CK_RC2_128_CBC_WITH_MD5:
+ case SSL_CK_DES_64_CBC_WITH_MD5:
+ case SSL_CK_DES_192_EDE3_CBC_WITH_MD5:
+ break;
+
+ default:
+ SSL_DBG(("%d: SSL[%d]: ssl2_CreateSessionCypher: unknown cipher=%d",
+ SSL_GETPID(), ss->fd, cipherType));
+ PORT_SetError(isClient ? SSL_ERROR_BAD_SERVER : SSL_ERROR_BAD_CLIENT);
+ goto sec_loser;
+ }
+
+ rk = isClient ? &readKey : &writeKey;
+ wk = isClient ? &writeKey : &readKey;
+
+ /* Produce the keys for this session */
+ rv = ssl2_ProduceKeys(ss, &readKey, &writeKey, &sid->u.ssl2.masterKey,
+ ss->sec.ci.clientChallenge, ss->sec.ci.connectionID,
+ cipherType);
+ if (rv != SECSuccess)
+ goto loser;
+ PRINT_BUF(7, (ss, "Session read-key: ", rk->data, rk->len));
+ PRINT_BUF(7, (ss, "Session write-key: ", wk->data, wk->len));
+
+ PORT_Memcpy(ss->sec.ci.readKey, readKey.data, readKey.len);
+ PORT_Memcpy(ss->sec.ci.writeKey, writeKey.data, writeKey.len);
+ ss->sec.ci.keySize = readKey.len;
+
+ /* Setup the MAC */
+ rv = ssl2_CreateMAC(&ss->sec, rk, wk, cipherType);
+ if (rv != SECSuccess)
+ goto loser;
+
+ /* First create the session key object */
+ SSL_TRC(3, ("%d: SSL[%d]: using %s", SSL_GETPID(), ss->fd,
+ ssl_cipherName[cipherType]));
+
+
+ mechanism = ssl_Specs[cipherType].mechanism;
+
+ /* set destructer before we call loser... */
+ ss->sec.destroy = (void (*)(void*, PRBool)) PK11_DestroyContext;
+ slot = PK11_GetBestSlot(mechanism, ss->pkcs11PinArg);
+ if (slot == NULL)
+ goto loser;
+
+ param = PK11_ParamFromIV(mechanism, &sid->u.ssl2.cipherArg);
+ if (param == NULL)
+ goto loser;
+ readcx = PK11_CreateContextByRawKey(slot, mechanism, PK11_OriginUnwrap,
+ CKA_DECRYPT, rk, param,
+ ss->pkcs11PinArg);
+ SECITEM_FreeItem(param, PR_TRUE);
+ if (readcx == NULL)
+ goto loser;
+
+ /* build the client context */
+ param = PK11_ParamFromIV(mechanism, &sid->u.ssl2.cipherArg);
+ if (param == NULL)
+ goto loser;
+ writecx = PK11_CreateContextByRawKey(slot, mechanism, PK11_OriginUnwrap,
+ CKA_ENCRYPT, wk, param,
+ ss->pkcs11PinArg);
+ SECITEM_FreeItem(param,PR_TRUE);
+ if (writecx == NULL)
+ goto loser;
+ PK11_FreeSlot(slot);
+
+ rv = SECSuccess;
+ ss->sec.enc = (SSLCipher) PK11_CipherOp;
+ ss->sec.dec = (SSLCipher) PK11_CipherOp;
+ ss->sec.readcx = (void *) readcx;
+ ss->sec.writecx = (void *) writecx;
+ ss->sec.blockSize = ssl_Specs[cipherType].blockSize;
+ ss->sec.blockShift = ssl_Specs[cipherType].blockShift;
+ ss->sec.cipherType = sid->u.ssl2.cipherType;
+ ss->sec.keyBits = sid->u.ssl2.keyBits;
+ ss->sec.secretKeyBits = sid->u.ssl2.secretKeyBits;
+ goto done;
+
+ loser:
+ if (ss->sec.destroy) {
+ if (readcx) (*ss->sec.destroy)(readcx, PR_TRUE);
+ if (writecx) (*ss->sec.destroy)(writecx, PR_TRUE);
+ }
+ ss->sec.destroy = NULL;
+ if (slot) PK11_FreeSlot(slot);
+
+ sec_loser:
+ rv = SECFailure;
+
+ done:
+ if (rk) {
+ SECITEM_ZfreeItem(rk, PR_FALSE);
+ }
+ if (wk) {
+ SECITEM_ZfreeItem(wk, PR_FALSE);
+ }
+ return rv;
+}
+
+/*
+** Setup the server ciphers given information from a CLIENT-MASTER-KEY
+** message.
+** "ss" pointer to the ssl-socket object
+** "cipher" the cipher type to use
+** "keyBits" the size of the final cipher key
+** "ck" the clear-key data
+** "ckLen" the number of bytes of clear-key data
+** "ek" the encrypted-key data
+** "ekLen" the number of bytes of encrypted-key data
+** "ca" the cipher-arg data
+** "caLen" the number of bytes of cipher-arg data
+**
+** The MASTER-KEY is constructed by first decrypting the encrypted-key
+** data. This produces the SECRET-KEY-DATA. The MASTER-KEY is composed by
+** concatenating the clear-key data with the SECRET-KEY-DATA. This code
+** checks to make sure that the client didn't send us an improper amount
+** of SECRET-KEY-DATA (it restricts the length of that data to match the
+** spec).
+**
+** Called from ssl2_HandleClientSessionKeyMessage().
+*/
+static SECStatus
+ssl2_ServerSetupSessionCypher(sslSocket *ss, int cipher, unsigned int keyBits,
+ PRUint8 *ck, unsigned int ckLen,
+ PRUint8 *ek, unsigned int ekLen,
+ PRUint8 *ca, unsigned int caLen)
+{
+ PRUint8 * dk = NULL; /* decrypted master key */
+ sslSessionID * sid;
+ sslServerCerts * sc = ss->serverCerts + kt_rsa;
+ PRUint8 * kbuf = 0; /* buffer for RSA decrypted data. */
+ unsigned int ddLen; /* length of RSA decrypted data in kbuf */
+ unsigned int keySize;
+ unsigned int dkLen; /* decrypted key length in bytes */
+ int modulusLen;
+ SECStatus rv;
+ PRUint16 allowed; /* cipher kinds enabled and allowed by policy */
+ PRUint8 mkbuf[SSL_MAX_MASTER_KEY_BYTES];
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert((sc->SERVERKEY != 0));
+ PORT_Assert((ss->sec.ci.sid != 0));
+ sid = ss->sec.ci.sid;
+
+ /* Trying to cut down on all these switch statements that should be tables.
+ * So, test cipherType once, here, and then use tables below.
+ */
+ switch (cipher) {
+ case SSL_CK_RC4_128_EXPORT40_WITH_MD5:
+ case SSL_CK_RC4_128_WITH_MD5:
+ case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:
+ case SSL_CK_RC2_128_CBC_WITH_MD5:
+ case SSL_CK_DES_64_CBC_WITH_MD5:
+ case SSL_CK_DES_192_EDE3_CBC_WITH_MD5:
+ break;
+
+ default:
+ SSL_DBG(("%d: SSL[%d]: ssl2_ServerSetupSessionCypher: unknown cipher=%d",
+ SSL_GETPID(), ss->fd, cipher));
+ PORT_SetError(SSL_ERROR_BAD_CLIENT);
+ goto loser;
+ }
+
+ allowed = ss->allowedByPolicy & ss->chosenPreference & SSL_CB_IMPLEMENTED;
+ if (!(allowed & (1 << cipher))) {
+ /* client chose a kind we don't allow! */
+ SSL_DBG(("%d: SSL[%d]: disallowed cipher=%d",
+ SSL_GETPID(), ss->fd, cipher));
+ PORT_SetError(SSL_ERROR_BAD_CLIENT);
+ goto loser;
+ }
+
+ keySize = ssl_Specs[cipher].keyLen;
+ if (keyBits != keySize * BPB) {
+ SSL_DBG(("%d: SSL[%d]: invalid master secret key length=%d (bits)!",
+ SSL_GETPID(), ss->fd, keyBits));
+ PORT_SetError(SSL_ERROR_BAD_CLIENT);
+ goto loser;
+ }
+
+ if (ckLen != ssl_Specs[cipher].pubLen) {
+ SSL_DBG(("%d: SSL[%d]: invalid clear key length, ckLen=%d (bytes)!",
+ SSL_GETPID(), ss->fd, ckLen));
+ PORT_SetError(SSL_ERROR_BAD_CLIENT);
+ goto loser;
+ }
+
+ if (caLen != ssl_Specs[cipher].ivLen) {
+ SSL_DBG(("%d: SSL[%d]: invalid key args length, caLen=%d (bytes)!",
+ SSL_GETPID(), ss->fd, caLen));
+ PORT_SetError(SSL_ERROR_BAD_CLIENT);
+ goto loser;
+ }
+
+ modulusLen = PK11_GetPrivateModulusLen(sc->SERVERKEY);
+ if (modulusLen == -1) {
+ /* XXX If the key is bad, then PK11_PubDecryptRaw will fail below. */
+ modulusLen = ekLen;
+ }
+ if (ekLen > modulusLen || ekLen + ckLen < keySize) {
+ SSL_DBG(("%d: SSL[%d]: invalid encrypted key length, ekLen=%d (bytes)!",
+ SSL_GETPID(), ss->fd, ekLen));
+ PORT_SetError(SSL_ERROR_BAD_CLIENT);
+ goto loser;
+ }
+
+ /* allocate the buffer to hold the decrypted portion of the key. */
+ kbuf = (PRUint8*)PORT_Alloc(modulusLen);
+ if (!kbuf) {
+ goto loser;
+ }
+ dkLen = keySize - ckLen;
+ dk = kbuf + modulusLen - dkLen;
+
+ /* Decrypt encrypted half of the key.
+ ** NOTE: PK11_PubDecryptRaw will barf on a non-RSA key. This is
+ ** desired behavior here.
+ */
+ rv = PK11_PubDecryptRaw(sc->SERVERKEY, kbuf, &ddLen, modulusLen, ek, ekLen);
+ if (rv != SECSuccess)
+ goto hide_loser;
+
+ /* Is the length of the decrypted data (ddLen) the expected value? */
+ if (modulusLen != ddLen)
+ goto hide_loser;
+
+ /* Cheaply verify that PKCS#1 was used to format the encryption block */
+ if ((kbuf[0] != 0x00) || (kbuf[1] != 0x02) || (dk[-1] != 0x00)) {
+ SSL_DBG(("%d: SSL[%d]: strange encryption block",
+ SSL_GETPID(), ss->fd));
+ PORT_SetError(SSL_ERROR_BAD_CLIENT);
+ goto hide_loser;
+ }
+
+ /* Make sure we're not subject to a version rollback attack. */
+ if (!SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
+ static const PRUint8 threes[8] = { 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03 };
+
+ if (PORT_Memcmp(dk - 8 - 1, threes, 8) == 0) {
+ PORT_SetError(SSL_ERROR_BAD_CLIENT);
+ goto hide_loser;
+ }
+ }
+ if (0) {
+hide_loser:
+ /* Defense against the Bleichenbacher attack.
+ * Provide the client with NO CLUES that the decrypted master key
+ * was erroneous. Don't send any error messages.
+ * Instead, Generate a completely bogus master key .
+ */
+ PK11_GenerateRandom(dk, dkLen);
+ }
+
+ /*
+ ** Construct master key out of the pieces.
+ */
+ if (ckLen) {
+ PORT_Memcpy(mkbuf, ck, ckLen);
+ }
+ PORT_Memcpy(mkbuf + ckLen, dk, dkLen);
+
+ /* Fill in session-id */
+ rv = ssl2_FillInSID(sid, cipher, mkbuf, keySize, ca, caLen,
+ keyBits, keyBits - (ckLen<<3),
+ ss->sec.authAlgorithm, ss->sec.authKeyBits,
+ ss->sec.keaType, ss->sec.keaKeyBits);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Create session ciphers */
+ rv = ssl2_CreateSessionCypher(ss, sid, PR_FALSE);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ SSL_TRC(1, ("%d: SSL[%d]: server, using %s cipher, clear=%d total=%d",
+ SSL_GETPID(), ss->fd, ssl_cipherName[cipher],
+ ckLen<<3, keySize<<3));
+ rv = SECSuccess;
+ goto done;
+
+ loser:
+ rv = SECFailure;
+
+ done:
+ PORT_Free(kbuf);
+ return rv;
+}
+
+/************************************************************************/
+
+/*
+** Rewrite the incoming cipher specs, comparing to list of specs we support,
+** (ss->cipherSpecs) and eliminating anything we don't support
+**
+* Note: Our list may contain SSL v3 ciphers.
+* We MUST NOT match on any of those.
+* Fortunately, this is easy to detect because SSLv3 ciphers have zero
+* in the first byte, and none of the SSLv2 ciphers do.
+*
+* Called from ssl2_HandleClientHelloMessage().
+* Returns the number of bytes of "qualified cipher specs",
+* which is typically a multiple of 3, but will be zero if there are none.
+*/
+static int
+ssl2_QualifyCypherSpecs(sslSocket *ss,
+ PRUint8 * cs, /* cipher specs in client hello msg. */
+ int csLen)
+{
+ PRUint8 * ms;
+ PRUint8 * hs;
+ PRUint8 * qs;
+ int mc;
+ int hc;
+ PRUint8 qualifiedSpecs[ssl2_NUM_SUITES_IMPLEMENTED * 3];
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+
+ if (!ss->cipherSpecs) {
+ SECStatus rv = ssl2_ConstructCipherSpecs(ss);
+ if (rv != SECSuccess || !ss->cipherSpecs)
+ return 0;
+ }
+
+ PRINT_BUF(10, (ss, "specs from client:", cs, csLen));
+ qs = qualifiedSpecs;
+ ms = ss->cipherSpecs;
+ for (mc = ss->sizeCipherSpecs; mc > 0; mc -= 3, ms += 3) {
+ if (ms[0] == 0)
+ continue;
+ for (hs = cs, hc = csLen; hc > 0; hs += 3, hc -= 3) {
+ if ((hs[0] == ms[0]) &&
+ (hs[1] == ms[1]) &&
+ (hs[2] == ms[2])) {
+ /* Copy this cipher spec into the "keep" section */
+ qs[0] = hs[0];
+ qs[1] = hs[1];
+ qs[2] = hs[2];
+ qs += 3;
+ break;
+ }
+ }
+ }
+ hc = qs - qualifiedSpecs;
+ PRINT_BUF(10, (ss, "qualified specs from client:", qualifiedSpecs, hc));
+ PORT_Memcpy(cs, qualifiedSpecs, hc);
+ return hc;
+}
+
+/*
+** Pick the best cipher we can find, given the array of server cipher
+** specs. Returns cipher number (e.g. SSL_CK_*), or -1 for no overlap.
+** If successful, stores the master key size (bytes) in *pKeyLen.
+**
+** This is correct only for the client side, but presently
+** this function is only called from
+** ssl2_ClientSetupSessionCypher() <- ssl2_HandleServerHelloMessage()
+**
+** Note that most servers only return a single cipher suite in their
+** ServerHello messages. So, the code below for finding the "best" cipher
+** suite usually has only one choice. The client and server should send
+** their cipher suite lists sorted in descending order by preference.
+*/
+static int
+ssl2_ChooseSessionCypher(sslSocket *ss,
+ int hc, /* number of cs's in hs. */
+ PRUint8 * hs, /* server hello's cipher suites. */
+ int * pKeyLen) /* out: sym key size in bytes. */
+{
+ PRUint8 * ms;
+ unsigned int i;
+ int bestKeySize;
+ int bestRealKeySize;
+ int bestCypher;
+ int keySize;
+ int realKeySize;
+ PRUint8 * ohs = hs;
+ const PRUint8 * preferred;
+ static const PRUint8 noneSuch[3] = { 0, 0, 0 };
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+
+ if (!ss->cipherSpecs) {
+ SECStatus rv = ssl2_ConstructCipherSpecs(ss);
+ if (rv != SECSuccess || !ss->cipherSpecs)
+ goto loser;
+ }
+
+ if (!ss->preferredCipher) {
+ unsigned int allowed = ss->allowedByPolicy & ss->chosenPreference &
+ SSL_CB_IMPLEMENTED;
+ if (allowed) {
+ preferred = implementedCipherSuites;
+ for (i = ssl2_NUM_SUITES_IMPLEMENTED; i > 0; --i) {
+ if (0 != (allowed & (1U << preferred[0]))) {
+ ss->preferredCipher = preferred;
+ break;
+ }
+ preferred += 3;
+ }
+ }
+ }
+ preferred = ss->preferredCipher ? ss->preferredCipher : noneSuch;
+ /*
+ ** Scan list of ciphers received from peer and look for a match in
+ ** our list.
+ * Note: Our list may contain SSL v3 ciphers.
+ * We MUST NOT match on any of those.
+ * Fortunately, this is easy to detect because SSLv3 ciphers have zero
+ * in the first byte, and none of the SSLv2 ciphers do.
+ */
+ bestKeySize = bestRealKeySize = 0;
+ bestCypher = -1;
+ while (--hc >= 0) {
+ for (i = 0, ms = ss->cipherSpecs; i < ss->sizeCipherSpecs; i += 3, ms += 3) {
+ if ((hs[0] == preferred[0]) &&
+ (hs[1] == preferred[1]) &&
+ (hs[2] == preferred[2]) &&
+ hs[0] != 0) {
+ /* Pick this cipher immediately! */
+ *pKeyLen = (((hs[1] << 8) | hs[2]) + 7) >> 3;
+ return hs[0];
+ }
+ if ((hs[0] == ms[0]) && (hs[1] == ms[1]) && (hs[2] == ms[2]) &&
+ hs[0] != 0) {
+ /* Found a match */
+
+ /* Use secret keySize to determine which cipher is best */
+ realKeySize = (hs[1] << 8) | hs[2];
+ switch (hs[0]) {
+ case SSL_CK_RC4_128_EXPORT40_WITH_MD5:
+ case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:
+ keySize = 40;
+ break;
+ default:
+ keySize = realKeySize;
+ break;
+ }
+ if (keySize > bestKeySize) {
+ bestCypher = hs[0];
+ bestKeySize = keySize;
+ bestRealKeySize = realKeySize;
+ }
+ }
+ }
+ hs += 3;
+ }
+ if (bestCypher < 0) {
+ /*
+ ** No overlap between server and client. Re-examine server list
+ ** to see what kind of ciphers it does support so that we can set
+ ** the error code appropriately.
+ */
+ if ((ohs[0] == SSL_CK_RC4_128_WITH_MD5) ||
+ (ohs[0] == SSL_CK_RC2_128_CBC_WITH_MD5)) {
+ PORT_SetError(SSL_ERROR_US_ONLY_SERVER);
+ } else if ((ohs[0] == SSL_CK_RC4_128_EXPORT40_WITH_MD5) ||
+ (ohs[0] == SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5)) {
+ PORT_SetError(SSL_ERROR_EXPORT_ONLY_SERVER);
+ } else {
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+ }
+ SSL_DBG(("%d: SSL[%d]: no cipher overlap", SSL_GETPID(), ss->fd));
+ goto loser;
+ }
+ *pKeyLen = (bestRealKeySize + 7) >> 3;
+ return bestCypher;
+
+ loser:
+ return -1;
+}
+
+static SECStatus
+ssl2_ClientHandleServerCert(sslSocket *ss, PRUint8 *certData, int certLen)
+{
+ CERTCertificate *cert = NULL;
+ SECItem certItem;
+
+ certItem.data = certData;
+ certItem.len = certLen;
+
+ /* decode the certificate */
+ cert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL,
+ PR_FALSE, PR_TRUE);
+
+ if (cert == NULL) {
+ SSL_DBG(("%d: SSL[%d]: decode of server certificate fails",
+ SSL_GETPID(), ss->fd));
+ PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
+ return SECFailure;
+ }
+
+#ifdef TRACE
+ {
+ if (ssl_trace >= 1) {
+ char *issuer;
+ char *subject;
+ issuer = CERT_NameToAscii(&cert->issuer);
+ subject = CERT_NameToAscii(&cert->subject);
+ SSL_TRC(1,("%d: server certificate issuer: '%s'",
+ SSL_GETPID(), issuer ? issuer : "OOPS"));
+ SSL_TRC(1,("%d: server name: '%s'",
+ SSL_GETPID(), subject ? subject : "OOPS"));
+ PORT_Free(issuer);
+ PORT_Free(subject);
+ }
+ }
+#endif
+
+ ss->sec.peerCert = cert;
+ return SECSuccess;
+}
+
+
+/*
+ * Format one block of data for public/private key encryption using
+ * the rules defined in PKCS #1. SSL2 does this itself to handle the
+ * rollback detection.
+ */
+#define RSA_BLOCK_MIN_PAD_LEN 8
+#define RSA_BLOCK_FIRST_OCTET 0x00
+#define RSA_BLOCK_AFTER_PAD_OCTET 0x00
+#define RSA_BLOCK_PUBLIC_OCTET 0x02
+unsigned char *
+ssl_FormatSSL2Block(unsigned modulusLen, SECItem *data)
+{
+ unsigned char *block;
+ unsigned char *bp;
+ int padLen;
+ SECStatus rv;
+ int i;
+
+ if (modulusLen < data->len + (3 + RSA_BLOCK_MIN_PAD_LEN)) {
+ PORT_SetError(SEC_ERROR_BAD_KEY);
+ return NULL;
+ }
+ block = (unsigned char *) PORT_Alloc(modulusLen);
+ if (block == NULL)
+ return NULL;
+
+ bp = block;
+
+ /*
+ * All RSA blocks start with two octets:
+ * 0x00 || BlockType
+ */
+ *bp++ = RSA_BLOCK_FIRST_OCTET;
+ *bp++ = RSA_BLOCK_PUBLIC_OCTET;
+
+ /*
+ * 0x00 || BT || Pad || 0x00 || ActualData
+ * 1 1 padLen 1 data->len
+ * Pad is all non-zero random bytes.
+ */
+ padLen = modulusLen - data->len - 3;
+ PORT_Assert (padLen >= RSA_BLOCK_MIN_PAD_LEN);
+ rv = PK11_GenerateRandom(bp, padLen);
+ if (rv == SECFailure) goto loser;
+ /* replace all the 'zero' bytes */
+ for (i = 0; i < padLen; i++) {
+ while (bp[i] == RSA_BLOCK_AFTER_PAD_OCTET) {
+ rv = PK11_GenerateRandom(bp+i, 1);
+ if (rv == SECFailure) goto loser;
+ }
+ }
+ bp += padLen;
+ *bp++ = RSA_BLOCK_AFTER_PAD_OCTET;
+ PORT_Memcpy (bp, data->data, data->len);
+
+ return block;
+loser:
+ if (block) PORT_Free(block);
+ return NULL;
+}
+
+/*
+** Given the server's public key and cipher specs, generate a session key
+** that is ready to use for encrypting/decrypting the byte stream. At
+** the same time, generate the SSL_MT_CLIENT_MASTER_KEY message and
+** send it to the server.
+**
+** Called from ssl2_HandleServerHelloMessage()
+*/
+static SECStatus
+ssl2_ClientSetupSessionCypher(sslSocket *ss, PRUint8 *cs, int csLen)
+{
+ sslSessionID * sid;
+ PRUint8 * ca; /* points to iv data, or NULL if none. */
+ PRUint8 * ekbuf = 0;
+ CERTCertificate * cert = 0;
+ SECKEYPublicKey * serverKey = 0;
+ unsigned modulusLen = 0;
+ SECStatus rv;
+ int cipher;
+ int keyLen; /* cipher symkey size in bytes. */
+ int ckLen; /* publicly reveal this many bytes of key. */
+ int caLen; /* length of IV data at *ca. */
+ int nc;
+
+ unsigned char *eblock; /* holds unencrypted PKCS#1 formatted key. */
+ SECItem rek; /* holds portion of symkey to be encrypted. */
+
+ PRUint8 keyData[SSL_MAX_MASTER_KEY_BYTES];
+ PRUint8 iv [8];
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ eblock = NULL;
+
+ sid = ss->sec.ci.sid;
+ PORT_Assert(sid != 0);
+
+ cert = ss->sec.peerCert;
+
+ serverKey = CERT_ExtractPublicKey(cert);
+ if (!serverKey) {
+ SSL_DBG(("%d: SSL[%d]: extract public key failed: error=%d",
+ SSL_GETPID(), ss->fd, PORT_GetError()));
+ PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
+ rv = SECFailure;
+ goto loser2;
+ }
+
+ ss->sec.authAlgorithm = ssl_sign_rsa;
+ ss->sec.keaType = ssl_kea_rsa;
+ ss->sec.keaKeyBits = \
+ ss->sec.authKeyBits = SECKEY_PublicKeyStrengthInBits(serverKey);
+
+ /* Choose a compatible cipher with the server */
+ nc = csLen / 3;
+ cipher = ssl2_ChooseSessionCypher(ss, nc, cs, &keyLen);
+ if (cipher < 0) {
+ /* ssl2_ChooseSessionCypher has set error code. */
+ ssl2_SendErrorMessage(ss, SSL_PE_NO_CYPHERS);
+ goto loser;
+ }
+
+ /* Generate the random keys */
+ PK11_GenerateRandom(keyData, sizeof(keyData));
+
+ /*
+ ** Next, carve up the keys into clear and encrypted portions. The
+ ** clear data is taken from the start of keyData and the encrypted
+ ** portion from the remainder. Note that each of these portions is
+ ** carved in half, one half for the read-key and one for the
+ ** write-key.
+ */
+ ca = 0;
+
+ /* We know that cipher is a legit value here, because
+ * ssl2_ChooseSessionCypher doesn't return bogus values.
+ */
+ ckLen = ssl_Specs[cipher].pubLen; /* cleartext key length. */
+ caLen = ssl_Specs[cipher].ivLen; /* IV length. */
+ if (caLen) {
+ PORT_Assert(sizeof iv >= caLen);
+ PK11_GenerateRandom(iv, caLen);
+ ca = iv;
+ }
+
+ /* Fill in session-id */
+ rv = ssl2_FillInSID(sid, cipher, keyData, keyLen,
+ ca, caLen, keyLen << 3, (keyLen - ckLen) << 3,
+ ss->sec.authAlgorithm, ss->sec.authKeyBits,
+ ss->sec.keaType, ss->sec.keaKeyBits);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ SSL_TRC(1, ("%d: SSL[%d]: client, using %s cipher, clear=%d total=%d",
+ SSL_GETPID(), ss->fd, ssl_cipherName[cipher],
+ ckLen<<3, keyLen<<3));
+
+ /* Now setup read and write ciphers */
+ rv = ssl2_CreateSessionCypher(ss, sid, PR_TRUE);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /*
+ ** Fill in the encryption buffer with some random bytes. Then
+ ** copy in the portion of the session key we are encrypting.
+ */
+ modulusLen = SECKEY_PublicKeyStrength(serverKey);
+ rek.data = keyData + ckLen;
+ rek.len = keyLen - ckLen;
+ eblock = ssl_FormatSSL2Block(modulusLen, &rek);
+ if (eblock == NULL)
+ goto loser;
+
+ /* Set up the padding for version 2 rollback detection. */
+ /* XXX We should really use defines here */
+ if (!SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
+ PORT_Assert((modulusLen - rek.len) > 12);
+ PORT_Memset(eblock + modulusLen - rek.len - 8 - 1, 0x03, 8);
+ }
+ ekbuf = (PRUint8*) PORT_Alloc(modulusLen);
+ if (!ekbuf)
+ goto loser;
+ PRINT_BUF(10, (ss, "master key encryption block:",
+ eblock, modulusLen));
+
+ /* Encrypt ekitem */
+ rv = PK11_PubEncryptRaw(serverKey, ekbuf, eblock, modulusLen,
+ ss->pkcs11PinArg);
+ if (rv)
+ goto loser;
+
+ /* Now we have everything ready to send */
+ rv = ssl2_SendSessionKeyMessage(ss, cipher, keyLen << 3, ca, caLen,
+ keyData, ckLen, ekbuf, modulusLen);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SECSuccess;
+ goto done;
+
+ loser:
+ rv = SECFailure;
+
+ loser2:
+ done:
+ PORT_Memset(keyData, 0, sizeof(keyData));
+ PORT_ZFree(ekbuf, modulusLen);
+ PORT_ZFree(eblock, modulusLen);
+ SECKEY_DestroyPublicKey(serverKey);
+ return rv;
+}
+
+/************************************************************************/
+
+/*
+ * Called from ssl2_HandleMessage in response to SSL_MT_SERVER_FINISHED message.
+ * Caller holds recvBufLock and handshakeLock
+ */
+static void
+ssl2_ClientRegSessionID(sslSocket *ss, PRUint8 *s)
+{
+ sslSessionID *sid = ss->sec.ci.sid;
+
+ /* Record entry in nonce cache */
+ if (sid->peerCert == NULL) {
+ PORT_Memcpy(sid->u.ssl2.sessionID, s, sizeof(sid->u.ssl2.sessionID));
+ sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);
+
+ }
+ if (!ss->opt.noCache)
+ (*ss->sec.cache)(sid);
+}
+
+/* Called from ssl2_HandleMessage() */
+static SECStatus
+ssl2_TriggerNextMessage(sslSocket *ss)
+{
+ SECStatus rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ if ((ss->sec.ci.requiredElements & CIS_HAVE_CERTIFICATE) &&
+ !(ss->sec.ci.sentElements & CIS_HAVE_CERTIFICATE)) {
+ ss->sec.ci.sentElements |= CIS_HAVE_CERTIFICATE;
+ rv = ssl2_SendCertificateRequestMessage(ss);
+ return rv;
+ }
+ return SECSuccess;
+}
+
+/* See if it's time to send our finished message, or if the handshakes are
+** complete. Send finished message if appropriate.
+** Returns SECSuccess unless anything goes wrong.
+**
+** Called from ssl2_HandleMessage,
+** ssl2_HandleVerifyMessage
+** ssl2_HandleServerHelloMessage
+** ssl2_HandleClientSessionKeyMessage
+*/
+static SECStatus
+ssl2_TryToFinish(sslSocket *ss)
+{
+ SECStatus rv;
+ char e, ef;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ e = ss->sec.ci.elements;
+ ef = e | CIS_HAVE_FINISHED;
+ if ((ef & ss->sec.ci.requiredElements) == ss->sec.ci.requiredElements) {
+ if (ss->sec.isServer) {
+ /* Send server finished message if we already didn't */
+ rv = ssl2_SendServerFinishedMessage(ss);
+ } else {
+ /* Send client finished message if we already didn't */
+ rv = ssl2_SendClientFinishedMessage(ss);
+ }
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ if ((e & ss->sec.ci.requiredElements) == ss->sec.ci.requiredElements) {
+ /* Totally finished */
+ ss->handshake = 0;
+ return SECSuccess;
+ }
+ }
+ return SECSuccess;
+}
+
+/*
+** Called from ssl2_HandleRequestCertificate
+*/
+static SECStatus
+ssl2_SignResponse(sslSocket *ss,
+ SECKEYPrivateKey *key,
+ SECItem *response)
+{
+ SGNContext * sgn = NULL;
+ PRUint8 * challenge;
+ unsigned int len;
+ SECStatus rv = SECFailure;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ challenge = ss->sec.ci.serverChallenge;
+ len = ss->sec.ci.serverChallengeLen;
+
+ /* Sign the expected data... */
+ sgn = SGN_NewContext(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,key);
+ if (!sgn)
+ goto done;
+ rv = SGN_Begin(sgn);
+ if (rv != SECSuccess)
+ goto done;
+ rv = SGN_Update(sgn, ss->sec.ci.readKey, ss->sec.ci.keySize);
+ if (rv != SECSuccess)
+ goto done;
+ rv = SGN_Update(sgn, ss->sec.ci.writeKey, ss->sec.ci.keySize);
+ if (rv != SECSuccess)
+ goto done;
+ rv = SGN_Update(sgn, challenge, len);
+ if (rv != SECSuccess)
+ goto done;
+ rv = SGN_Update(sgn, ss->sec.peerCert->derCert.data,
+ ss->sec.peerCert->derCert.len);
+ if (rv != SECSuccess)
+ goto done;
+ rv = SGN_End(sgn, response);
+ if (rv != SECSuccess)
+ goto done;
+
+done:
+ SGN_DestroyContext(sgn, PR_TRUE);
+ return rv == SECSuccess ? SECSuccess : SECFailure;
+}
+
+/*
+** Try to handle a request-certificate message. Get client's certificate
+** and private key and sign a message for the server to see.
+** Caller must hold handshakeLock
+**
+** Called from ssl2_HandleMessage().
+*/
+static int
+ssl2_HandleRequestCertificate(sslSocket *ss)
+{
+ CERTCertificate * cert = NULL; /* app-selected client cert. */
+ SECKEYPrivateKey *key = NULL; /* priv key for cert. */
+ SECStatus rv;
+ SECItem response;
+ int ret = 0;
+ PRUint8 authType;
+
+
+ /*
+ * These things all need to be initialized before we can "goto loser".
+ */
+ response.data = NULL;
+
+ /* get challenge info from connectionInfo */
+ authType = ss->sec.ci.authType;
+
+ if (authType != SSL_AT_MD5_WITH_RSA_ENCRYPTION) {
+ SSL_TRC(7, ("%d: SSL[%d]: unsupported auth type 0x%x", SSL_GETPID(),
+ ss->fd, authType));
+ goto no_cert_error;
+ }
+
+ /* Get certificate and private-key from client */
+ if (!ss->getClientAuthData) {
+ SSL_TRC(7, ("%d: SSL[%d]: client doesn't support client-auth",
+ SSL_GETPID(), ss->fd));
+ goto no_cert_error;
+ }
+ ret = (*ss->getClientAuthData)(ss->getClientAuthDataArg, ss->fd,
+ NULL, &cert, &key);
+ if ( ret == SECWouldBlock ) {
+ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
+ ret = -1;
+ goto loser;
+ }
+
+ if (ret) {
+ goto no_cert_error;
+ }
+
+ /* check what the callback function returned */
+ if ((!cert) || (!key)) {
+ /* we are missing either the key or cert */
+ if (cert) {
+ /* got a cert, but no key - free it */
+ CERT_DestroyCertificate(cert);
+ cert = NULL;
+ }
+ if (key) {
+ /* got a key, but no cert - free it */
+ SECKEY_DestroyPrivateKey(key);
+ key = NULL;
+ }
+ goto no_cert_error;
+ }
+
+ rv = ssl2_SignResponse(ss, key, &response);
+ if ( rv != SECSuccess ) {
+ ret = -1;
+ goto loser;
+ }
+
+ /* Send response message */
+ ret = ssl2_SendCertificateResponseMessage(ss, &cert->derCert, &response);
+
+ /* Now, remember the cert we sent. But first, forget any previous one. */
+ if (ss->sec.localCert) {
+ CERT_DestroyCertificate(ss->sec.localCert);
+ }
+ ss->sec.localCert = CERT_DupCertificate(cert);
+ PORT_Assert(!ss->sec.ci.sid->localCert);
+ if (ss->sec.ci.sid->localCert) {
+ CERT_DestroyCertificate(ss->sec.ci.sid->localCert);
+ }
+ ss->sec.ci.sid->localCert = cert;
+ cert = NULL;
+
+ goto done;
+
+ no_cert_error:
+ SSL_TRC(7, ("%d: SSL[%d]: no certificate (ret=%d)", SSL_GETPID(),
+ ss->fd, ret));
+ ret = ssl2_SendErrorMessage(ss, SSL_PE_NO_CERTIFICATE);
+
+ loser:
+ done:
+ if ( cert ) {
+ CERT_DestroyCertificate(cert);
+ }
+ if ( key ) {
+ SECKEY_DestroyPrivateKey(key);
+ }
+ if ( response.data ) {
+ PORT_Free(response.data);
+ }
+
+ return ret;
+}
+
+/*
+** Called from ssl2_HandleMessage for SSL_MT_CLIENT_CERTIFICATE message.
+** Caller must hold HandshakeLock and RecvBufLock, since cd and response
+** are contained in the gathered input data.
+*/
+static SECStatus
+ssl2_HandleClientCertificate(sslSocket * ss,
+ PRUint8 certType, /* XXX unused */
+ PRUint8 * cd,
+ unsigned int cdLen,
+ PRUint8 * response,
+ unsigned int responseLen)
+{
+ CERTCertificate *cert = NULL;
+ SECKEYPublicKey *pubKey = NULL;
+ VFYContext * vfy = NULL;
+ SECItem * derCert;
+ SECStatus rv = SECFailure;
+ SECItem certItem;
+ SECItem rep;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+
+ /* Extract the certificate */
+ certItem.data = cd;
+ certItem.len = cdLen;
+
+ cert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL,
+ PR_FALSE, PR_TRUE);
+ if (cert == NULL) {
+ goto loser;
+ }
+
+ /* save the certificate, since the auth routine will need it */
+ ss->sec.peerCert = cert;
+
+ /* Extract the public key */
+ pubKey = CERT_ExtractPublicKey(cert);
+ if (!pubKey)
+ goto loser;
+
+ /* Verify the response data... */
+ rep.data = response;
+ rep.len = responseLen;
+ /* SSL 2.0 only supports RSA certs, so we don't have to worry about
+ * DSA here. */
+ vfy = VFY_CreateContext(pubKey, &rep, SEC_OID_PKCS1_RSA_ENCRYPTION,
+ ss->pkcs11PinArg);
+ if (!vfy)
+ goto loser;
+ rv = VFY_Begin(vfy);
+ if (rv)
+ goto loser;
+
+ rv = VFY_Update(vfy, ss->sec.ci.readKey, ss->sec.ci.keySize);
+ if (rv)
+ goto loser;
+ rv = VFY_Update(vfy, ss->sec.ci.writeKey, ss->sec.ci.keySize);
+ if (rv)
+ goto loser;
+ rv = VFY_Update(vfy, ss->sec.ci.serverChallenge, SSL_CHALLENGE_BYTES);
+ if (rv)
+ goto loser;
+
+ derCert = &ss->serverCerts[kt_rsa].serverCert->derCert;
+ rv = VFY_Update(vfy, derCert->data, derCert->len);
+ if (rv)
+ goto loser;
+ rv = VFY_End(vfy);
+ if (rv)
+ goto loser;
+
+ /* Now ask the server application if it likes the certificate... */
+ rv = (SECStatus) (*ss->authCertificate)(ss->authCertificateArg,
+ ss->fd, PR_TRUE, PR_TRUE);
+ /* Hey, it liked it. */
+ if (SECSuccess == rv)
+ goto done;
+
+loser:
+ ss->sec.peerCert = NULL;
+ CERT_DestroyCertificate(cert);
+
+done:
+ VFY_DestroyContext(vfy, PR_TRUE);
+ SECKEY_DestroyPublicKey(pubKey);
+ return rv;
+}
+
+/*
+** Handle remaining messages between client/server. Process finished
+** messages from either side and any authentication requests.
+** This should only be called for SSLv2 handshake messages,
+** not for application data records.
+** Caller must hold handshake lock.
+**
+** Called from ssl_Do1stHandshake().
+**
+*/
+static SECStatus
+ssl2_HandleMessage(sslSocket *ss)
+{
+ PRUint8 * data;
+ PRUint8 * cid;
+ unsigned len, certType, certLen, responseLen;
+ int rv;
+ int rv2;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ ssl_GetRecvBufLock(ss);
+
+ data = ss->gs.buf.buf + ss->gs.recordOffset;
+
+ if (ss->gs.recordLen < 1) {
+ goto bad_peer;
+ }
+ SSL_TRC(3, ("%d: SSL[%d]: received %d message",
+ SSL_GETPID(), ss->fd, data[0]));
+ DUMP_MSG(29, (ss, data, ss->gs.recordLen));
+
+ switch (data[0]) {
+ case SSL_MT_CLIENT_FINISHED:
+ if (ss->sec.ci.elements & CIS_HAVE_FINISHED) {
+ SSL_DBG(("%d: SSL[%d]: dup client-finished message",
+ SSL_GETPID(), ss->fd));
+ goto bad_peer;
+ }
+
+ /* See if nonce matches */
+ len = ss->gs.recordLen - 1;
+ cid = data + 1;
+ if ((len != sizeof(ss->sec.ci.connectionID)) ||
+ (PORT_Memcmp(ss->sec.ci.connectionID, cid, len) != 0)) {
+ SSL_DBG(("%d: SSL[%d]: bad connection-id", SSL_GETPID(), ss->fd));
+ PRINT_BUF(5, (ss, "sent connection-id",
+ ss->sec.ci.connectionID,
+ sizeof(ss->sec.ci.connectionID)));
+ PRINT_BUF(5, (ss, "rcvd connection-id", cid, len));
+ goto bad_peer;
+ }
+
+ SSL_TRC(5, ("%d: SSL[%d]: got client finished, waiting for 0x%d",
+ SSL_GETPID(), ss->fd,
+ ss->sec.ci.requiredElements ^ ss->sec.ci.elements));
+ ss->sec.ci.elements |= CIS_HAVE_FINISHED;
+ break;
+
+ case SSL_MT_SERVER_FINISHED:
+ if (ss->sec.ci.elements & CIS_HAVE_FINISHED) {
+ SSL_DBG(("%d: SSL[%d]: dup server-finished message",
+ SSL_GETPID(), ss->fd));
+ goto bad_peer;
+ }
+
+ if (ss->gs.recordLen - 1 != SSL2_SESSIONID_BYTES) {
+ SSL_DBG(("%d: SSL[%d]: bad server-finished message, len=%d",
+ SSL_GETPID(), ss->fd, ss->gs.recordLen));
+ goto bad_peer;
+ }
+ ssl2_ClientRegSessionID(ss, data+1);
+ SSL_TRC(5, ("%d: SSL[%d]: got server finished, waiting for 0x%d",
+ SSL_GETPID(), ss->fd,
+ ss->sec.ci.requiredElements ^ ss->sec.ci.elements));
+ ss->sec.ci.elements |= CIS_HAVE_FINISHED;
+ break;
+
+ case SSL_MT_REQUEST_CERTIFICATE:
+ len = ss->gs.recordLen - 2;
+ if ((len < SSL_MIN_CHALLENGE_BYTES) ||
+ (len > SSL_MAX_CHALLENGE_BYTES)) {
+ /* Bad challenge */
+ SSL_DBG(("%d: SSL[%d]: bad cert request message: code len=%d",
+ SSL_GETPID(), ss->fd, len));
+ goto bad_peer;
+ }
+
+ /* save auth request info */
+ ss->sec.ci.authType = data[1];
+ ss->sec.ci.serverChallengeLen = len;
+ PORT_Memcpy(ss->sec.ci.serverChallenge, data + 2, len);
+
+ rv = ssl2_HandleRequestCertificate(ss);
+ if (rv == SECWouldBlock) {
+ SSL_TRC(3, ("%d: SSL[%d]: async cert request",
+ SSL_GETPID(), ss->fd));
+ /* someone is handling this asynchronously */
+ ssl_ReleaseRecvBufLock(ss);
+ return SECWouldBlock;
+ }
+ if (rv) {
+ SET_ERROR_CODE
+ goto loser;
+ }
+ break;
+
+ case SSL_MT_CLIENT_CERTIFICATE:
+ if (!ss->authCertificate) {
+ /* Server asked for authentication and can't handle it */
+ PORT_SetError(SSL_ERROR_BAD_SERVER);
+ goto loser;
+ }
+ if (ss->gs.recordLen < SSL_HL_CLIENT_CERTIFICATE_HBYTES) {
+ SET_ERROR_CODE
+ goto loser;
+ }
+ certType = data[1];
+ certLen = (data[2] << 8) | data[3];
+ responseLen = (data[4] << 8) | data[5];
+ if (certType != SSL_CT_X509_CERTIFICATE) {
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
+ goto loser;
+ }
+ if (certLen + responseLen + SSL_HL_CLIENT_CERTIFICATE_HBYTES
+ > ss->gs.recordLen) {
+ /* prevent overflow crash. */
+ rv = SECFailure;
+ } else
+ rv = ssl2_HandleClientCertificate(ss, data[1],
+ data + SSL_HL_CLIENT_CERTIFICATE_HBYTES,
+ certLen,
+ data + SSL_HL_CLIENT_CERTIFICATE_HBYTES + certLen,
+ responseLen);
+ if (rv) {
+ rv2 = ssl2_SendErrorMessage(ss, SSL_PE_BAD_CERTIFICATE);
+ SET_ERROR_CODE
+ goto loser;
+ }
+ ss->sec.ci.elements |= CIS_HAVE_CERTIFICATE;
+ break;
+
+ case SSL_MT_ERROR:
+ rv = (data[1] << 8) | data[2];
+ SSL_TRC(2, ("%d: SSL[%d]: got error message, error=0x%x",
+ SSL_GETPID(), ss->fd, rv));
+
+ /* Convert protocol error number into API error number */
+ switch (rv) {
+ case SSL_PE_NO_CYPHERS:
+ rv = SSL_ERROR_NO_CYPHER_OVERLAP;
+ break;
+ case SSL_PE_NO_CERTIFICATE:
+ rv = SSL_ERROR_NO_CERTIFICATE;
+ break;
+ case SSL_PE_BAD_CERTIFICATE:
+ rv = SSL_ERROR_BAD_CERTIFICATE;
+ break;
+ case SSL_PE_UNSUPPORTED_CERTIFICATE_TYPE:
+ rv = SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE;
+ break;
+ default:
+ goto bad_peer;
+ }
+ /* XXX make certificate-request optionally fail... */
+ PORT_SetError(rv);
+ goto loser;
+
+ default:
+ SSL_DBG(("%d: SSL[%d]: unknown message %d",
+ SSL_GETPID(), ss->fd, data[0]));
+ goto loser;
+ }
+
+ SSL_TRC(3, ("%d: SSL[%d]: handled %d message, required=0x%x got=0x%x",
+ SSL_GETPID(), ss->fd, data[0],
+ ss->sec.ci.requiredElements, ss->sec.ci.elements));
+
+ rv = ssl2_TryToFinish(ss);
+ if (rv != SECSuccess)
+ goto loser;
+
+ ss->gs.recordLen = 0;
+ ssl_ReleaseRecvBufLock(ss);
+
+ if (ss->handshake == 0) {
+ return SECSuccess;
+ }
+
+ ss->handshake = ssl_GatherRecord1stHandshake;
+ ss->nextHandshake = ssl2_HandleMessage;
+ return ssl2_TriggerNextMessage(ss);
+
+ bad_peer:
+ PORT_SetError(ss->sec.isServer ? SSL_ERROR_BAD_CLIENT : SSL_ERROR_BAD_SERVER);
+ /* FALL THROUGH */
+
+ loser:
+ ssl_ReleaseRecvBufLock(ss);
+ return SECFailure;
+}
+
+/************************************************************************/
+
+/* Called from ssl_Do1stHandshake, after ssl2_HandleServerHelloMessage.
+*/
+static SECStatus
+ssl2_HandleVerifyMessage(sslSocket *ss)
+{
+ PRUint8 * data;
+ SECStatus rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+ ssl_GetRecvBufLock(ss);
+
+ data = ss->gs.buf.buf + ss->gs.recordOffset;
+ DUMP_MSG(29, (ss, data, ss->gs.recordLen));
+ if ((ss->gs.recordLen != 1 + SSL_CHALLENGE_BYTES) ||
+ (data[0] != SSL_MT_SERVER_VERIFY) ||
+ NSS_SecureMemcmp(data+1, ss->sec.ci.clientChallenge,
+ SSL_CHALLENGE_BYTES)) {
+ /* Bad server */
+ PORT_SetError(SSL_ERROR_BAD_SERVER);
+ goto loser;
+ }
+ ss->sec.ci.elements |= CIS_HAVE_VERIFY;
+
+ SSL_TRC(5, ("%d: SSL[%d]: got server-verify, required=0x%d got=0x%x",
+ SSL_GETPID(), ss->fd, ss->sec.ci.requiredElements,
+ ss->sec.ci.elements));
+
+ rv = ssl2_TryToFinish(ss);
+ if (rv)
+ goto loser;
+
+ ss->gs.recordLen = 0;
+ ssl_ReleaseRecvBufLock(ss);
+
+ if (ss->handshake == 0) {
+ return SECSuccess;
+ }
+ ss->handshake = ssl_GatherRecord1stHandshake;
+ ss->nextHandshake = ssl2_HandleMessage;
+ return SECSuccess;
+
+
+ loser:
+ ssl_ReleaseRecvBufLock(ss);
+ return SECFailure;
+}
+
+/* Not static because ssl2_GatherData() tests ss->nextHandshake for this value.
+ * ICK!
+ * Called from ssl_Do1stHandshake after ssl2_BeginClientHandshake()
+ */
+SECStatus
+ssl2_HandleServerHelloMessage(sslSocket *ss)
+{
+ sslSessionID * sid;
+ PRUint8 * cert;
+ PRUint8 * cs;
+ PRUint8 * data;
+ SECStatus rv;
+ int needed, sidHit, certLen, csLen, cidLen, certType, err;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ if (!ss->opt.enableSSL2) {
+ PORT_SetError(SSL_ERROR_SSL2_DISABLED);
+ return SECFailure;
+ }
+
+ ssl_GetRecvBufLock(ss);
+
+ PORT_Assert(ss->sec.ci.sid != 0);
+ sid = ss->sec.ci.sid;
+
+ data = ss->gs.buf.buf + ss->gs.recordOffset;
+ DUMP_MSG(29, (ss, data, ss->gs.recordLen));
+
+ /* Make sure first message has some data and is the server hello message */
+ if ((ss->gs.recordLen < SSL_HL_SERVER_HELLO_HBYTES)
+ || (data[0] != SSL_MT_SERVER_HELLO)) {
+ if ((data[0] == SSL_MT_ERROR) && (ss->gs.recordLen == 3)) {
+ err = (data[1] << 8) | data[2];
+ if (err == SSL_PE_NO_CYPHERS) {
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+ goto loser;
+ }
+ }
+ goto bad_server;
+ }
+
+ sidHit = data[1];
+ certType = data[2];
+ ss->version = (data[3] << 8) | data[4];
+ certLen = (data[5] << 8) | data[6];
+ csLen = (data[7] << 8) | data[8];
+ cidLen = (data[9] << 8) | data[10];
+ cert = data + SSL_HL_SERVER_HELLO_HBYTES;
+ cs = cert + certLen;
+
+ SSL_TRC(5,
+ ("%d: SSL[%d]: server-hello, hit=%d vers=%x certLen=%d csLen=%d cidLen=%d",
+ SSL_GETPID(), ss->fd, sidHit, ss->version, certLen,
+ csLen, cidLen));
+ if (ss->version != SSL_LIBRARY_VERSION_2) {
+ if (ss->version < SSL_LIBRARY_VERSION_2) {
+ SSL_TRC(3, ("%d: SSL[%d]: demoting self (%x) to server version (%x)",
+ SSL_GETPID(), ss->fd, SSL_LIBRARY_VERSION_2,
+ ss->version));
+ } else {
+ SSL_TRC(1, ("%d: SSL[%d]: server version is %x (we are %x)",
+ SSL_GETPID(), ss->fd, ss->version, SSL_LIBRARY_VERSION_2));
+ /* server claims to be newer but does not follow protocol */
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
+ goto loser;
+ }
+ }
+
+ if ((SSL_HL_SERVER_HELLO_HBYTES + certLen + csLen + cidLen
+ > ss->gs.recordLen)
+ || (csLen % 3) != 0
+ /* || cidLen < SSL_CONNECTIONID_BYTES || cidLen > 32 */
+ ) {
+ goto bad_server;
+ }
+
+ /* Save connection-id.
+ ** This code only saves the first 16 byte of the connectionID.
+ ** If the connectionID is shorter than 16 bytes, it is zero-padded.
+ */
+ if (cidLen < sizeof ss->sec.ci.connectionID)
+ memset(ss->sec.ci.connectionID, 0, sizeof ss->sec.ci.connectionID);
+ cidLen = PR_MIN(cidLen, sizeof ss->sec.ci.connectionID);
+ PORT_Memcpy(ss->sec.ci.connectionID, cs + csLen, cidLen);
+
+ /* See if session-id hit */
+ needed = CIS_HAVE_MASTER_KEY | CIS_HAVE_FINISHED | CIS_HAVE_VERIFY;
+ if (sidHit) {
+ if (certLen || csLen) {
+ /* Uh oh - bogus server */
+ SSL_DBG(("%d: SSL[%d]: client, huh? hit=%d certLen=%d csLen=%d",
+ SSL_GETPID(), ss->fd, sidHit, certLen, csLen));
+ goto bad_server;
+ }
+
+ /* Total winner. */
+ SSL_TRC(1, ("%d: SSL[%d]: client, using nonce for peer=0x%08x "
+ "port=0x%04x",
+ SSL_GETPID(), ss->fd, ss->sec.ci.peer, ss->sec.ci.port));
+ ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
+ ss->sec.authAlgorithm = sid->authAlgorithm;
+ ss->sec.authKeyBits = sid->authKeyBits;
+ ss->sec.keaType = sid->keaType;
+ ss->sec.keaKeyBits = sid->keaKeyBits;
+ rv = ssl2_CreateSessionCypher(ss, sid, PR_TRUE);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ } else {
+ if (certType != SSL_CT_X509_CERTIFICATE) {
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
+ goto loser;
+ }
+ if (csLen == 0) {
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+ SSL_DBG(("%d: SSL[%d]: no cipher overlap",
+ SSL_GETPID(), ss->fd));
+ goto loser;
+ }
+ if (certLen == 0) {
+ SSL_DBG(("%d: SSL[%d]: client, huh? certLen=%d csLen=%d",
+ SSL_GETPID(), ss->fd, certLen, csLen));
+ goto bad_server;
+ }
+
+ if (sid->cached != never_cached) {
+ /* Forget our session-id - server didn't like it */
+ SSL_TRC(7, ("%d: SSL[%d]: server forgot me, uncaching session-id",
+ SSL_GETPID(), ss->fd));
+ if (ss->sec.uncache)
+ (*ss->sec.uncache)(sid);
+ ssl_FreeSID(sid);
+ ss->sec.ci.sid = sid = PORT_ZNew(sslSessionID);
+ if (!sid) {
+ goto loser;
+ }
+ sid->references = 1;
+ sid->addr = ss->sec.ci.peer;
+ sid->port = ss->sec.ci.port;
+ }
+
+ /* decode the server's certificate */
+ rv = ssl2_ClientHandleServerCert(ss, cert, certLen);
+ if (rv != SECSuccess) {
+ if (PORT_GetError() == SSL_ERROR_BAD_CERTIFICATE) {
+ (void) ssl2_SendErrorMessage(ss, SSL_PE_BAD_CERTIFICATE);
+ }
+ goto loser;
+ }
+
+ /* Setup new session cipher */
+ rv = ssl2_ClientSetupSessionCypher(ss, cs, csLen);
+ if (rv != SECSuccess) {
+ if (PORT_GetError() == SSL_ERROR_BAD_CERTIFICATE) {
+ (void) ssl2_SendErrorMessage(ss, SSL_PE_BAD_CERTIFICATE);
+ }
+ goto loser;
+ }
+ }
+
+ /* Build up final list of required elements */
+ ss->sec.ci.elements = CIS_HAVE_MASTER_KEY;
+ ss->sec.ci.requiredElements = needed;
+
+ if (!sidHit) {
+ /* verify the server's certificate. if sidHit, don't check signatures */
+ rv = (* ss->authCertificate)(ss->authCertificateArg, ss->fd,
+ (PRBool)(!sidHit), PR_FALSE);
+ if (rv) {
+ if (ss->handleBadCert) {
+ rv = (*ss->handleBadCert)(ss->badCertArg, ss->fd);
+ if ( rv ) {
+ if ( rv == SECWouldBlock ) {
+ SSL_DBG(("%d: SSL[%d]: SSL2 bad cert handler returned "
+ "SECWouldBlock", SSL_GETPID(), ss->fd));
+ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
+ rv = SECFailure;
+ } else {
+ /* cert is bad */
+ SSL_DBG(("%d: SSL[%d]: server certificate is no good: error=%d",
+ SSL_GETPID(), ss->fd, PORT_GetError()));
+ }
+ goto loser;
+ }
+ /* cert is good */
+ } else {
+ SSL_DBG(("%d: SSL[%d]: server certificate is no good: error=%d",
+ SSL_GETPID(), ss->fd, PORT_GetError()));
+ goto loser;
+ }
+ }
+ }
+ /*
+ ** At this point we have a completed session key and our session
+ ** cipher is setup and ready to go. Switch to encrypted write routine
+ ** as all future message data is to be encrypted.
+ */
+ ssl2_UseEncryptedSendFunc(ss);
+
+ rv = ssl2_TryToFinish(ss);
+ if (rv != SECSuccess)
+ goto loser;
+
+ ss->gs.recordLen = 0;
+
+ ssl_ReleaseRecvBufLock(ss);
+
+ if (ss->handshake == 0) {
+ return SECSuccess;
+ }
+
+ SSL_TRC(5, ("%d: SSL[%d]: got server-hello, required=0x%d got=0x%x",
+ SSL_GETPID(), ss->fd, ss->sec.ci.requiredElements,
+ ss->sec.ci.elements));
+ ss->handshake = ssl_GatherRecord1stHandshake;
+ ss->nextHandshake = ssl2_HandleVerifyMessage;
+ return SECSuccess;
+
+ bad_server:
+ PORT_SetError(SSL_ERROR_BAD_SERVER);
+ /* FALL THROUGH */
+
+ loser:
+ ssl_ReleaseRecvBufLock(ss);
+ return SECFailure;
+}
+
+/* Sends out the initial client Hello message on the connection.
+ * Acquires and releases the socket's xmitBufLock.
+ */
+SECStatus
+ssl2_BeginClientHandshake(sslSocket *ss)
+{
+ sslSessionID *sid;
+ PRUint8 *msg;
+ PRUint8 *cp;
+ PRUint8 *localCipherSpecs = NULL;
+ unsigned int localCipherSize;
+ unsigned int i;
+ int sendLen, sidLen = 0;
+ SECStatus rv;
+ TLSExtensionData *xtnData;
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ ss->sec.isServer = 0;
+ ss->sec.sendSequence = 0;
+ ss->sec.rcvSequence = 0;
+ ssl_ChooseSessionIDProcs(&ss->sec);
+
+ if (!ss->cipherSpecs) {
+ rv = ssl2_ConstructCipherSpecs(ss);
+ if (rv != SECSuccess)
+ goto loser;
+ }
+
+ /* count the SSL2 and SSL3 enabled ciphers.
+ * if either is zero, clear the socket's enable for that protocol.
+ */
+ rv = ssl2_CheckConfigSanity(ss);
+ if (rv != SECSuccess)
+ goto loser;
+
+ /* Get peer name of server */
+ rv = ssl_GetPeerInfo(ss);
+ if (rv < 0) {
+#ifdef HPUX11
+ /*
+ * On some HP-UX B.11.00 systems, getpeername() occasionally
+ * fails with ENOTCONN after a successful completion of
+ * non-blocking connect. I found that if we do a write()
+ * and then retry getpeername(), it will work.
+ */
+ if (PR_GetError() == PR_NOT_CONNECTED_ERROR) {
+ char dummy;
+ (void) PR_Write(ss->fd->lower, &dummy, 0);
+ rv = ssl_GetPeerInfo(ss);
+ if (rv < 0) {
+ goto loser;
+ }
+ }
+#else
+ goto loser;
+#endif
+ }
+
+ SSL_TRC(3, ("%d: SSL[%d]: sending client-hello", SSL_GETPID(), ss->fd));
+
+ /* Try to find server in our session-id cache */
+ if (ss->opt.noCache) {
+ sid = NULL;
+ } else {
+ sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID,
+ ss->url);
+ }
+ while (sid) { /* this isn't really a loop */
+ PRBool sidVersionEnabled =
+ (!SSL3_ALL_VERSIONS_DISABLED(&ss->vrange) &&
+ sid->version >= ss->vrange.min &&
+ sid->version <= ss->vrange.max) ||
+ (sid->version < SSL_LIBRARY_VERSION_3_0 && ss->opt.enableSSL2);
+
+ /* if we're not doing this SID's protocol any more, drop it. */
+ if (!sidVersionEnabled) {
+ if (ss->sec.uncache)
+ ss->sec.uncache(sid);
+ ssl_FreeSID(sid);
+ sid = NULL;
+ break;
+ }
+ if (sid->version < SSL_LIBRARY_VERSION_3_0) {
+ /* If the cipher in this sid is not enabled, drop it. */
+ for (i = 0; i < ss->sizeCipherSpecs; i += 3) {
+ if (ss->cipherSpecs[i] == sid->u.ssl2.cipherType)
+ break;
+ }
+ if (i >= ss->sizeCipherSpecs) {
+ if (ss->sec.uncache)
+ ss->sec.uncache(sid);
+ ssl_FreeSID(sid);
+ sid = NULL;
+ break;
+ }
+ }
+ sidLen = sizeof(sid->u.ssl2.sessionID);
+ PRINT_BUF(4, (ss, "client, found session-id:", sid->u.ssl2.sessionID,
+ sidLen));
+ ss->version = sid->version;
+ PORT_Assert(!ss->sec.localCert);
+ if (ss->sec.localCert) {
+ CERT_DestroyCertificate(ss->sec.localCert);
+ }
+ ss->sec.localCert = CERT_DupCertificate(sid->localCert);
+ break; /* this isn't really a loop */
+ }
+ if (!sid) {
+ sidLen = 0;
+ sid = PORT_ZNew(sslSessionID);
+ if (!sid) {
+ goto loser;
+ }
+ sid->references = 1;
+ sid->cached = never_cached;
+ sid->addr = ss->sec.ci.peer;
+ sid->port = ss->sec.ci.port;
+ if (ss->peerID != NULL) {
+ sid->peerID = PORT_Strdup(ss->peerID);
+ }
+ if (ss->url != NULL) {
+ sid->urlSvrName = PORT_Strdup(ss->url);
+ }
+ }
+ ss->sec.ci.sid = sid;
+
+ PORT_Assert(sid != NULL);
+
+ if ((sid->version >= SSL_LIBRARY_VERSION_3_0 || !ss->opt.v2CompatibleHello) &&
+ !SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
+ ss->gs.state = GS_INIT;
+ ss->handshake = ssl_GatherRecord1stHandshake;
+
+ /* ssl3_SendClientHello will override this if it succeeds. */
+ ss->version = SSL_LIBRARY_VERSION_3_0;
+
+ ssl_GetSSL3HandshakeLock(ss);
+ ssl_GetXmitBufLock(ss);
+ rv = ssl3_SendClientHello(ss, PR_FALSE);
+ ssl_ReleaseXmitBufLock(ss);
+ ssl_ReleaseSSL3HandshakeLock(ss);
+
+ return rv;
+ }
+#if defined(NSS_ENABLE_ECC)
+ /* ensure we don't neogtiate ECC cipher suites with SSL2 hello */
+ ssl3_DisableECCSuites(ss, NULL); /* disable all ECC suites */
+ if (ss->cipherSpecs != NULL) {
+ PORT_Free(ss->cipherSpecs);
+ ss->cipherSpecs = NULL;
+ ss->sizeCipherSpecs = 0;
+ }
+#endif
+
+ if (!ss->cipherSpecs) {
+ rv = ssl2_ConstructCipherSpecs(ss);
+ if (rv < 0) {
+ return rv;
+ }
+ }
+ localCipherSpecs = ss->cipherSpecs;
+ localCipherSize = ss->sizeCipherSpecs;
+
+ /* Add 3 for SCSV */
+ sendLen = SSL_HL_CLIENT_HELLO_HBYTES + localCipherSize + 3 + sidLen +
+ SSL_CHALLENGE_BYTES;
+
+ /* Generate challenge bytes for server */
+ PK11_GenerateRandom(ss->sec.ci.clientChallenge, SSL_CHALLENGE_BYTES);
+
+ ssl_GetXmitBufLock(ss); /***************************************/
+
+ rv = ssl2_GetSendBuffer(ss, sendLen);
+ if (rv)
+ goto unlock_loser;
+
+ /* Construct client-hello message */
+ cp = msg = ss->sec.ci.sendBuf.buf;
+ msg[0] = SSL_MT_CLIENT_HELLO;
+ ss->clientHelloVersion = SSL3_ALL_VERSIONS_DISABLED(&ss->vrange) ?
+ SSL_LIBRARY_VERSION_2 : ss->vrange.max;
+
+ msg[1] = MSB(ss->clientHelloVersion);
+ msg[2] = LSB(ss->clientHelloVersion);
+ /* Add 3 for SCSV */
+ msg[3] = MSB(localCipherSize + 3);
+ msg[4] = LSB(localCipherSize + 3);
+ msg[5] = MSB(sidLen);
+ msg[6] = LSB(sidLen);
+ msg[7] = MSB(SSL_CHALLENGE_BYTES);
+ msg[8] = LSB(SSL_CHALLENGE_BYTES);
+ cp += SSL_HL_CLIENT_HELLO_HBYTES;
+ PORT_Memcpy(cp, localCipherSpecs, localCipherSize);
+ cp += localCipherSize;
+ /*
+ * Add SCSV. SSL 2.0 cipher suites are listed before SSL 3.0 cipher
+ * suites in localCipherSpecs for compatibility with SSL 2.0 servers.
+ * Since SCSV looks like an SSL 3.0 cipher suite, we can't add it at
+ * the beginning.
+ */
+ cp[0] = 0x00;
+ cp[1] = 0x00;
+ cp[2] = 0xff;
+ cp += 3;
+ if (sidLen) {
+ PORT_Memcpy(cp, sid->u.ssl2.sessionID, sidLen);
+ cp += sidLen;
+ }
+ PORT_Memcpy(cp, ss->sec.ci.clientChallenge, SSL_CHALLENGE_BYTES);
+
+ /* Send it to the server */
+ DUMP_MSG(29, (ss, msg, sendLen));
+ ss->handshakeBegun = 1;
+ rv = (*ss->sec.send)(ss, msg, sendLen, 0);
+
+ ssl_ReleaseXmitBufLock(ss); /***************************************/
+
+ if (rv < 0) {
+ goto loser;
+ }
+
+ rv = ssl3_StartHandshakeHash(ss, msg, sendLen);
+ if (rv < 0) {
+ goto loser;
+ }
+
+ /*
+ * Since we sent the SCSV, pretend we sent empty RI extension. We need
+ * to record the extension has been advertised after ssl3_InitState has
+ * been called, which ssl3_StartHandshakeHash took care for us above.
+ */
+ xtnData = &ss->xtnData;
+ xtnData->advertised[xtnData->numAdvertised++] = ssl_renegotiation_info_xtn;
+
+ /* Setup to receive servers hello message */
+ ssl_GetRecvBufLock(ss);
+ ss->gs.recordLen = 0;
+ ssl_ReleaseRecvBufLock(ss);
+
+ ss->handshake = ssl_GatherRecord1stHandshake;
+ ss->nextHandshake = ssl2_HandleServerHelloMessage;
+ return SECSuccess;
+
+unlock_loser:
+ ssl_ReleaseXmitBufLock(ss);
+loser:
+ return SECFailure;
+}
+
+/************************************************************************/
+
+/* Handle the CLIENT-MASTER-KEY message.
+** Acquires and releases RecvBufLock.
+** Called from ssl2_HandleClientHelloMessage().
+*/
+static SECStatus
+ssl2_HandleClientSessionKeyMessage(sslSocket *ss)
+{
+ PRUint8 * data;
+ unsigned int caLen;
+ unsigned int ckLen;
+ unsigned int ekLen;
+ unsigned int keyBits;
+ int cipher;
+ SECStatus rv;
+
+
+ ssl_GetRecvBufLock(ss);
+
+ data = ss->gs.buf.buf + ss->gs.recordOffset;
+ DUMP_MSG(29, (ss, data, ss->gs.recordLen));
+
+ if ((ss->gs.recordLen < SSL_HL_CLIENT_MASTER_KEY_HBYTES)
+ || (data[0] != SSL_MT_CLIENT_MASTER_KEY)) {
+ goto bad_client;
+ }
+ cipher = data[1];
+ keyBits = (data[2] << 8) | data[3];
+ ckLen = (data[4] << 8) | data[5];
+ ekLen = (data[6] << 8) | data[7];
+ caLen = (data[8] << 8) | data[9];
+
+ SSL_TRC(5, ("%d: SSL[%d]: session-key, cipher=%d keyBits=%d ckLen=%d ekLen=%d caLen=%d",
+ SSL_GETPID(), ss->fd, cipher, keyBits, ckLen, ekLen, caLen));
+
+ if (ss->gs.recordLen <
+ SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen + ekLen + caLen) {
+ SSL_DBG(("%d: SSL[%d]: protocol size mismatch dataLen=%d",
+ SSL_GETPID(), ss->fd, ss->gs.recordLen));
+ goto bad_client;
+ }
+
+ /* Use info from client to setup session key */
+ rv = ssl2_ServerSetupSessionCypher(ss, cipher, keyBits,
+ data + SSL_HL_CLIENT_MASTER_KEY_HBYTES, ckLen,
+ data + SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen, ekLen,
+ data + SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen + ekLen, caLen);
+ ss->gs.recordLen = 0; /* we're done with this record. */
+
+ ssl_ReleaseRecvBufLock(ss);
+
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ ss->sec.ci.elements |= CIS_HAVE_MASTER_KEY;
+ ssl2_UseEncryptedSendFunc(ss);
+
+ /* Send server verify message now that keys are established */
+ rv = ssl2_SendServerVerifyMessage(ss);
+ if (rv != SECSuccess)
+ goto loser;
+
+ rv = ssl2_TryToFinish(ss);
+ if (rv != SECSuccess)
+ goto loser;
+ if (ss->handshake == 0) {
+ return SECSuccess;
+ }
+
+ SSL_TRC(5, ("%d: SSL[%d]: server: waiting for elements=0x%d",
+ SSL_GETPID(), ss->fd,
+ ss->sec.ci.requiredElements ^ ss->sec.ci.elements));
+ ss->handshake = ssl_GatherRecord1stHandshake;
+ ss->nextHandshake = ssl2_HandleMessage;
+
+ return ssl2_TriggerNextMessage(ss);
+
+bad_client:
+ ssl_ReleaseRecvBufLock(ss);
+ PORT_SetError(SSL_ERROR_BAD_CLIENT);
+ /* FALLTHROUGH */
+
+loser:
+ return SECFailure;
+}
+
+/*
+** Handle the initial hello message from the client
+**
+** not static because ssl2_GatherData() tests ss->nextHandshake for this value.
+*/
+SECStatus
+ssl2_HandleClientHelloMessage(sslSocket *ss)
+{
+ sslSessionID *sid;
+ sslServerCerts * sc;
+ CERTCertificate *serverCert;
+ PRUint8 *msg;
+ PRUint8 *data;
+ PRUint8 *cs;
+ PRUint8 *sd;
+ PRUint8 *cert = NULL;
+ PRUint8 *challenge;
+ unsigned int challengeLen;
+ SECStatus rv;
+ int csLen;
+ int sendLen;
+ int sdLen;
+ int certLen;
+ int pid;
+ int sent;
+ int gotXmitBufLock = 0;
+#if defined(SOLARIS) && defined(i386)
+ volatile PRUint8 hit;
+#else
+ int hit;
+#endif
+ PRUint8 csImpl[sizeof implementedCipherSuites];
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ sc = ss->serverCerts + kt_rsa;
+ serverCert = sc->serverCert;
+
+ ssl_GetRecvBufLock(ss);
+
+
+ data = ss->gs.buf.buf + ss->gs.recordOffset;
+ DUMP_MSG(29, (ss, data, ss->gs.recordLen));
+
+ /* Make sure first message has some data and is the client hello message */
+ if ((ss->gs.recordLen < SSL_HL_CLIENT_HELLO_HBYTES)
+ || (data[0] != SSL_MT_CLIENT_HELLO)) {
+ goto bad_client;
+ }
+
+ /* Get peer name of client */
+ rv = ssl_GetPeerInfo(ss);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Examine version information */
+ /*
+ * See if this might be a V2 client hello asking to use the V3 protocol
+ */
+ if ((data[0] == SSL_MT_CLIENT_HELLO) &&
+ (data[1] >= MSB(SSL_LIBRARY_VERSION_3_0)) &&
+ !SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
+ rv = ssl3_HandleV2ClientHello(ss, data, ss->gs.recordLen);
+ if (rv != SECFailure) { /* Success */
+ ss->handshake = NULL;
+ ss->nextHandshake = ssl_GatherRecord1stHandshake;
+ ss->securityHandshake = NULL;
+ ss->gs.state = GS_INIT;
+
+ /* ssl3_HandleV3ClientHello has set ss->version,
+ ** and has gotten us a brand new sid.
+ */
+ ss->sec.ci.sid->version = ss->version;
+ }
+ ssl_ReleaseRecvBufLock(ss);
+ return rv;
+ }
+ /* Previously, there was a test here to see if SSL2 was enabled.
+ ** If not, an error code was set, and SECFailure was returned,
+ ** without sending any error code to the other end of the connection.
+ ** That test has been removed. If SSL2 has been disabled, there
+ ** should be no SSL2 ciphers enabled, and consequently, the code
+ ** below should send the ssl2 error message SSL_PE_NO_CYPHERS.
+ ** We now believe this is the correct thing to do, even when SSL2
+ ** has been explicitly disabled by the application.
+ */
+
+ /* Extract info from message */
+ ss->version = (data[1] << 8) | data[2];
+
+ /* If some client thinks ssl v2 is 2.0 instead of 0.2, we'll allow it. */
+ if (ss->version >= SSL_LIBRARY_VERSION_3_0) {
+ ss->version = SSL_LIBRARY_VERSION_2;
+ }
+
+ csLen = (data[3] << 8) | data[4];
+ sdLen = (data[5] << 8) | data[6];
+ challengeLen = (data[7] << 8) | data[8];
+ cs = data + SSL_HL_CLIENT_HELLO_HBYTES;
+ sd = cs + csLen;
+ challenge = sd + sdLen;
+ PRINT_BUF(7, (ss, "server, client session-id value:", sd, sdLen));
+
+ if (!csLen || (csLen % 3) != 0 ||
+ (sdLen != 0 && sdLen != SSL2_SESSIONID_BYTES) ||
+ challengeLen < SSL_MIN_CHALLENGE_BYTES ||
+ challengeLen > SSL_MAX_CHALLENGE_BYTES ||
+ (unsigned)ss->gs.recordLen !=
+ SSL_HL_CLIENT_HELLO_HBYTES + csLen + sdLen + challengeLen) {
+ SSL_DBG(("%d: SSL[%d]: bad client hello message, len=%d should=%d",
+ SSL_GETPID(), ss->fd, ss->gs.recordLen,
+ SSL_HL_CLIENT_HELLO_HBYTES+csLen+sdLen+challengeLen));
+ goto bad_client;
+ }
+
+ SSL_TRC(3, ("%d: SSL[%d]: client version is %x",
+ SSL_GETPID(), ss->fd, ss->version));
+ if (ss->version != SSL_LIBRARY_VERSION_2) {
+ if (ss->version > SSL_LIBRARY_VERSION_2) {
+ /*
+ ** Newer client than us. Things are ok because new clients
+ ** are required to be backwards compatible with old servers.
+ ** Change version number to our version number so that client
+ ** knows whats up.
+ */
+ ss->version = SSL_LIBRARY_VERSION_2;
+ } else {
+ SSL_TRC(1, ("%d: SSL[%d]: client version is %x (we are %x)",
+ SSL_GETPID(), ss->fd, ss->version, SSL_LIBRARY_VERSION_2));
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
+ goto loser;
+ }
+ }
+
+ /* Qualify cipher specs before returning them to client */
+ csLen = ssl2_QualifyCypherSpecs(ss, cs, csLen);
+ if (csLen == 0) {
+ /* no overlap, send client our list of supported SSL v2 ciphers. */
+ cs = csImpl;
+ csLen = sizeof implementedCipherSuites;
+ PORT_Memcpy(cs, implementedCipherSuites, csLen);
+ csLen = ssl2_QualifyCypherSpecs(ss, cs, csLen);
+ if (csLen == 0) {
+ /* We don't support any SSL v2 ciphers! */
+ ssl2_SendErrorMessage(ss, SSL_PE_NO_CYPHERS);
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+ goto loser;
+ }
+ /* Since this handhsake is going to fail, don't cache it. */
+ ss->opt.noCache = 1;
+ }
+
+ /* Squirrel away the challenge for later */
+ PORT_Memcpy(ss->sec.ci.clientChallenge, challenge, challengeLen);
+
+ /* Examine message and see if session-id is good */
+ ss->sec.ci.elements = 0;
+ if (sdLen > 0 && !ss->opt.noCache) {
+ SSL_TRC(7, ("%d: SSL[%d]: server, lookup client session-id for 0x%08x%08x%08x%08x",
+ SSL_GETPID(), ss->fd, ss->sec.ci.peer.pr_s6_addr32[0],
+ ss->sec.ci.peer.pr_s6_addr32[1],
+ ss->sec.ci.peer.pr_s6_addr32[2],
+ ss->sec.ci.peer.pr_s6_addr32[3]));
+ sid = (*ssl_sid_lookup)(&ss->sec.ci.peer, sd, sdLen, ss->dbHandle);
+ } else {
+ sid = NULL;
+ }
+ if (sid) {
+ /* Got a good session-id. Short cut! */
+ SSL_TRC(1, ("%d: SSL[%d]: server, using session-id for 0x%08x (age=%d)",
+ SSL_GETPID(), ss->fd, ss->sec.ci.peer,
+ ssl_Time() - sid->creationTime));
+ PRINT_BUF(1, (ss, "session-id value:", sd, sdLen));
+ ss->sec.ci.sid = sid;
+ ss->sec.ci.elements = CIS_HAVE_MASTER_KEY;
+ hit = 1;
+ certLen = 0;
+ csLen = 0;
+
+ ss->sec.authAlgorithm = sid->authAlgorithm;
+ ss->sec.authKeyBits = sid->authKeyBits;
+ ss->sec.keaType = sid->keaType;
+ ss->sec.keaKeyBits = sid->keaKeyBits;
+
+ rv = ssl2_CreateSessionCypher(ss, sid, PR_FALSE);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ } else {
+ SECItem * derCert = &serverCert->derCert;
+
+ SSL_TRC(7, ("%d: SSL[%d]: server, lookup nonce missed",
+ SSL_GETPID(), ss->fd));
+ if (!serverCert) {
+ SET_ERROR_CODE
+ goto loser;
+ }
+ hit = 0;
+ sid = PORT_ZNew(sslSessionID);
+ if (!sid) {
+ goto loser;
+ }
+ sid->references = 1;
+ sid->addr = ss->sec.ci.peer;
+ sid->port = ss->sec.ci.port;
+
+ /* Invent a session-id */
+ ss->sec.ci.sid = sid;
+ PK11_GenerateRandom(sid->u.ssl2.sessionID+2, SSL2_SESSIONID_BYTES-2);
+
+ pid = SSL_GETPID();
+ sid->u.ssl2.sessionID[0] = MSB(pid);
+ sid->u.ssl2.sessionID[1] = LSB(pid);
+ cert = derCert->data;
+ certLen = derCert->len;
+
+ /* pretend that server sids remember the local cert. */
+ PORT_Assert(!sid->localCert);
+ if (sid->localCert) {
+ CERT_DestroyCertificate(sid->localCert);
+ }
+ sid->localCert = CERT_DupCertificate(serverCert);
+
+ ss->sec.authAlgorithm = ssl_sign_rsa;
+ ss->sec.keaType = ssl_kea_rsa;
+ ss->sec.keaKeyBits = \
+ ss->sec.authKeyBits = ss->serverCerts[kt_rsa].serverKeyBits;
+ }
+
+ /* server sids don't remember the local cert, so whether we found
+ ** a sid or not, just "remember" we used the rsa server cert.
+ */
+ if (ss->sec.localCert) {
+ CERT_DestroyCertificate(ss->sec.localCert);
+ }
+ ss->sec.localCert = CERT_DupCertificate(serverCert);
+
+ /* Build up final list of required elements */
+ ss->sec.ci.requiredElements = CIS_HAVE_MASTER_KEY | CIS_HAVE_FINISHED;
+ if (ss->opt.requestCertificate) {
+ ss->sec.ci.requiredElements |= CIS_HAVE_CERTIFICATE;
+ }
+ ss->sec.ci.sentElements = 0;
+
+ /* Send hello message back to client */
+ sendLen = SSL_HL_SERVER_HELLO_HBYTES + certLen + csLen
+ + SSL_CONNECTIONID_BYTES;
+
+ ssl_GetXmitBufLock(ss); gotXmitBufLock = 1;
+ rv = ssl2_GetSendBuffer(ss, sendLen);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ SSL_TRC(3, ("%d: SSL[%d]: sending server-hello (%d)",
+ SSL_GETPID(), ss->fd, sendLen));
+
+ msg = ss->sec.ci.sendBuf.buf;
+ msg[0] = SSL_MT_SERVER_HELLO;
+ msg[1] = hit;
+ msg[2] = SSL_CT_X509_CERTIFICATE;
+ msg[3] = MSB(ss->version);
+ msg[4] = LSB(ss->version);
+ msg[5] = MSB(certLen);
+ msg[6] = LSB(certLen);
+ msg[7] = MSB(csLen);
+ msg[8] = LSB(csLen);
+ msg[9] = MSB(SSL_CONNECTIONID_BYTES);
+ msg[10] = LSB(SSL_CONNECTIONID_BYTES);
+ if (certLen) {
+ PORT_Memcpy(msg+SSL_HL_SERVER_HELLO_HBYTES, cert, certLen);
+ }
+ if (csLen) {
+ PORT_Memcpy(msg+SSL_HL_SERVER_HELLO_HBYTES+certLen, cs, csLen);
+ }
+ PORT_Memcpy(msg+SSL_HL_SERVER_HELLO_HBYTES+certLen+csLen,
+ ss->sec.ci.connectionID, SSL_CONNECTIONID_BYTES);
+
+ DUMP_MSG(29, (ss, msg, sendLen));
+
+ ss->handshakeBegun = 1;
+ sent = (*ss->sec.send)(ss, msg, sendLen, 0);
+ if (sent < 0) {
+ goto loser;
+ }
+ ssl_ReleaseXmitBufLock(ss); gotXmitBufLock = 0;
+
+ ss->gs.recordLen = 0;
+ ss->handshake = ssl_GatherRecord1stHandshake;
+ if (hit) {
+ /* Old SID Session key is good. Go encrypted */
+ ssl2_UseEncryptedSendFunc(ss);
+
+ /* Send server verify message now that keys are established */
+ rv = ssl2_SendServerVerifyMessage(ss);
+ if (rv != SECSuccess)
+ goto loser;
+
+ ss->nextHandshake = ssl2_HandleMessage;
+ ssl_ReleaseRecvBufLock(ss);
+ rv = ssl2_TriggerNextMessage(ss);
+ return rv;
+ }
+ ss->nextHandshake = ssl2_HandleClientSessionKeyMessage;
+ ssl_ReleaseRecvBufLock(ss);
+ return SECSuccess;
+
+ bad_client:
+ PORT_SetError(SSL_ERROR_BAD_CLIENT);
+ /* FALLTHROUGH */
+
+ loser:
+ if (gotXmitBufLock) {
+ ssl_ReleaseXmitBufLock(ss); gotXmitBufLock = 0;
+ }
+ SSL_TRC(10, ("%d: SSL[%d]: server, wait for client-hello lossage",
+ SSL_GETPID(), ss->fd));
+ ssl_ReleaseRecvBufLock(ss);
+ return SECFailure;
+}
+
+SECStatus
+ssl2_BeginServerHandshake(sslSocket *ss)
+{
+ SECStatus rv;
+ sslServerCerts * rsaAuth = ss->serverCerts + kt_rsa;
+
+ ss->sec.isServer = 1;
+ ssl_ChooseSessionIDProcs(&ss->sec);
+ ss->sec.sendSequence = 0;
+ ss->sec.rcvSequence = 0;
+
+ /* don't turn on SSL2 if we don't have an RSA key and cert */
+ if (!rsaAuth->serverKeyPair || !rsaAuth->SERVERKEY ||
+ !rsaAuth->serverCert) {
+ ss->opt.enableSSL2 = PR_FALSE;
+ }
+
+ if (!ss->cipherSpecs) {
+ rv = ssl2_ConstructCipherSpecs(ss);
+ if (rv != SECSuccess)
+ goto loser;
+ }
+
+ /* count the SSL2 and SSL3 enabled ciphers.
+ * if either is zero, clear the socket's enable for that protocol.
+ */
+ rv = ssl2_CheckConfigSanity(ss);
+ if (rv != SECSuccess)
+ goto loser;
+
+ /*
+ ** Generate connection-id. Always do this, even if things fail
+ ** immediately. This way the random number generator is always
+ ** rolling around, every time we get a connection.
+ */
+ PK11_GenerateRandom(ss->sec.ci.connectionID,
+ sizeof(ss->sec.ci.connectionID));
+
+ ss->gs.recordLen = 0;
+ ss->handshake = ssl_GatherRecord1stHandshake;
+ ss->nextHandshake = ssl2_HandleClientHelloMessage;
+ return SECSuccess;
+
+loser:
+ return SECFailure;
+}
+
+/* This function doesn't really belong in this file.
+** It's here to keep AIX compilers from optimizing it away,
+** and not including it in the DSO.
+*/
+
+#include "nss.h"
+extern const char __nss_ssl_rcsid[];
+extern const char __nss_ssl_sccsid[];
+
+PRBool
+NSSSSL_VersionCheck(const char *importedVersion)
+{
+ /*
+ * This is the secret handshake algorithm.
+ *
+ * This release has a simple version compatibility
+ * check algorithm. This release is not backward
+ * compatible with previous major releases. It is
+ * not compatible with future major, minor, or
+ * patch releases.
+ */
+ volatile char c; /* force a reference that won't get optimized away */
+
+ c = __nss_ssl_rcsid[0] + __nss_ssl_sccsid[0];
+ return NSS_VersionCheck(importedVersion);
+}
+
+const char *
+NSSSSL_GetVersion(void)
+{
+ return NSS_VERSION;
+}
diff --git a/chromium/net/third_party/nss/ssl/ssldef.c b/chromium/net/third_party/nss/ssl/ssldef.c
new file mode 100644
index 00000000000..cc3ecc8bf14
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/ssldef.c
@@ -0,0 +1,210 @@
+/*
+ * "Default" SSLSocket methods, used by sockets that do neither SSL nor socks.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cert.h"
+#include "ssl.h"
+#include "sslimpl.h"
+
+#if defined(WIN32)
+#define MAP_ERROR(from,to) if (err == from) { PORT_SetError(to); }
+#define DEFINE_ERROR PRErrorCode err = PR_GetError();
+#else
+#define MAP_ERROR(from,to)
+#define DEFINE_ERROR
+#endif
+
+int ssl_DefConnect(sslSocket *ss, const PRNetAddr *sa)
+{
+ PRFileDesc *lower = ss->fd->lower;
+ int rv;
+
+ rv = lower->methods->connect(lower, sa, ss->cTimeout);
+ return rv;
+}
+
+int ssl_DefBind(sslSocket *ss, const PRNetAddr *addr)
+{
+ PRFileDesc *lower = ss->fd->lower;
+ int rv;
+
+ rv = lower->methods->bind(lower, addr);
+ return rv;
+}
+
+int ssl_DefListen(sslSocket *ss, int backlog)
+{
+ PRFileDesc *lower = ss->fd->lower;
+ int rv;
+
+ rv = lower->methods->listen(lower, backlog);
+ return rv;
+}
+
+int ssl_DefShutdown(sslSocket *ss, int how)
+{
+ PRFileDesc *lower = ss->fd->lower;
+ int rv;
+
+ rv = lower->methods->shutdown(lower, how);
+ return rv;
+}
+
+int ssl_DefRecv(sslSocket *ss, unsigned char *buf, int len, int flags)
+{
+ PRFileDesc *lower = ss->fd->lower;
+ int rv;
+
+ rv = lower->methods->recv(lower, (void *)buf, len, flags, ss->rTimeout);
+ if (rv < 0) {
+ DEFINE_ERROR
+ MAP_ERROR(PR_SOCKET_SHUTDOWN_ERROR, PR_CONNECT_RESET_ERROR)
+ } else if (rv > len) {
+ PORT_Assert(rv <= len);
+ PORT_SetError(PR_BUFFER_OVERFLOW_ERROR);
+ rv = SECFailure;
+ }
+ return rv;
+}
+
+/* Default (unencrypted) send.
+ * For blocking sockets, always returns len or SECFailure, no short writes.
+ * For non-blocking sockets:
+ * Returns positive count if any data was written, else returns SECFailure.
+ * Short writes may occur. Does not return SECWouldBlock.
+ */
+int ssl_DefSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
+{
+ PRFileDesc *lower = ss->fd->lower;
+ int sent = 0;
+
+#if NSS_DISABLE_NAGLE_DELAYS
+ /* Although this is overkill, we disable Nagle delays completely for
+ ** SSL sockets.
+ */
+ if (ss->opt.useSecurity && !ss->delayDisabled) {
+ ssl_EnableNagleDelay(ss, PR_FALSE); /* ignore error */
+ ss->delayDisabled = 1;
+ }
+#endif
+ do {
+ int rv = lower->methods->send(lower, (const void *)(buf + sent),
+ len - sent, flags, ss->wTimeout);
+ if (rv < 0) {
+ PRErrorCode err = PR_GetError();
+ if (err == PR_WOULD_BLOCK_ERROR) {
+ ss->lastWriteBlocked = 1;
+ return sent ? sent : SECFailure;
+ }
+ ss->lastWriteBlocked = 0;
+ MAP_ERROR(PR_CONNECT_ABORTED_ERROR, PR_CONNECT_RESET_ERROR)
+ /* Loser */
+ return rv;
+ }
+ sent += rv;
+
+ if (IS_DTLS(ss) && (len > sent)) {
+ /* We got a partial write so just return it */
+ return sent;
+ }
+ } while (len > sent);
+ ss->lastWriteBlocked = 0;
+ return sent;
+}
+
+int ssl_DefRead(sslSocket *ss, unsigned char *buf, int len)
+{
+ PRFileDesc *lower = ss->fd->lower;
+ int rv;
+
+ rv = lower->methods->read(lower, (void *)buf, len);
+ if (rv < 0) {
+ DEFINE_ERROR
+ MAP_ERROR(PR_SOCKET_SHUTDOWN_ERROR, PR_CONNECT_RESET_ERROR)
+ }
+ return rv;
+}
+
+int ssl_DefWrite(sslSocket *ss, const unsigned char *buf, int len)
+{
+ PRFileDesc *lower = ss->fd->lower;
+ int sent = 0;
+
+ do {
+ int rv = lower->methods->write(lower, (const void *)(buf + sent),
+ len - sent);
+ if (rv < 0) {
+ PRErrorCode err = PR_GetError();
+ if (err == PR_WOULD_BLOCK_ERROR) {
+ ss->lastWriteBlocked = 1;
+ return sent ? sent : SECFailure;
+ }
+ ss->lastWriteBlocked = 0;
+ MAP_ERROR(PR_CONNECT_ABORTED_ERROR, PR_CONNECT_RESET_ERROR)
+ /* Loser */
+ return rv;
+ }
+ sent += rv;
+ } while (len > sent);
+ ss->lastWriteBlocked = 0;
+ return sent;
+}
+
+int ssl_DefGetpeername(sslSocket *ss, PRNetAddr *name)
+{
+ PRFileDesc *lower = ss->fd->lower;
+ int rv;
+
+ rv = lower->methods->getpeername(lower, name);
+ return rv;
+}
+
+int ssl_DefGetsockname(sslSocket *ss, PRNetAddr *name)
+{
+ PRFileDesc *lower = ss->fd->lower;
+ int rv;
+
+ rv = lower->methods->getsockname(lower, name);
+ return rv;
+}
+
+int ssl_DefClose(sslSocket *ss)
+{
+ PRFileDesc *fd;
+ PRFileDesc *popped;
+ int rv;
+
+ fd = ss->fd;
+
+ /* First, remove the SSL layer PRFileDesc from the socket's stack,
+ ** then invoke the SSL layer's PRFileDesc destructor.
+ ** This must happen before the next layer down is closed.
+ */
+ PORT_Assert(fd->higher == NULL);
+ if (fd->higher) {
+ PORT_SetError(PR_BAD_DESCRIPTOR_ERROR);
+ return SECFailure;
+ }
+ ss->fd = NULL;
+
+ /* PR_PopIOLayer will swap the contents of the top two PRFileDescs on
+ ** the stack, and then remove the second one. This way, the address
+ ** of the PRFileDesc on the top of the stack doesn't change.
+ */
+ popped = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
+ popped->dtor(popped);
+
+ /* fd is now the PRFileDesc for the next layer down.
+ ** Now close the underlying socket.
+ */
+ rv = fd->methods->close(fd);
+
+ ssl_FreeSocket(ss);
+
+ SSL_TRC(5, ("%d: SSL[%d]: closing, rv=%d errno=%d",
+ SSL_GETPID(), fd, rv, PORT_GetError()));
+ return rv;
+}
diff --git a/chromium/net/third_party/nss/ssl/sslenum.c b/chromium/net/third_party/nss/ssl/sslenum.c
new file mode 100644
index 00000000000..597ec072399
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslenum.c
@@ -0,0 +1,150 @@
+/*
+ * Table enumerating all implemented cipher suites
+ * Part of public API.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ssl.h"
+#include "sslproto.h"
+
+/*
+ * The ciphers are listed in the following order:
+ * - stronger ciphers before weaker ciphers
+ * - national ciphers before international ciphers
+ * - faster ciphers before slower ciphers
+ *
+ * National ciphers such as Camellia are listed before international ciphers
+ * such as AES and RC4 to allow servers that prefer Camellia to negotiate
+ * Camellia without having to disable AES and RC4, which are needed for
+ * interoperability with clients that don't yet implement Camellia.
+ *
+ * The ordering of cipher suites in this table must match the ordering in
+ * the cipherSuites table in ssl3con.c.
+ *
+ * If new ECC cipher suites are added, also update the ssl3CipherSuite arrays
+ * in ssl3ecc.c.
+ *
+ * Finally, update the ssl_V3_SUITES_IMPLEMENTED macro in sslimpl.h.
+ */
+const PRUint16 SSL_ImplementedCiphers[] = {
+ /* AES-GCM */
+#ifdef NSS_ENABLE_ECC
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+#endif /* NSS_ENABLE_ECC */
+ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+
+ /* 256-bit */
+#ifdef NSS_ENABLE_ECC
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+#endif /* NSS_ENABLE_ECC */
+ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
+ TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+ TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+#ifdef NSS_ENABLE_ECC
+ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+#endif /* NSS_ENABLE_ECC */
+ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA256,
+
+ /* 128-bit */
+#ifdef NSS_ENABLE_ECC
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+#endif /* NSS_ENABLE_ECC */
+ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
+ TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
+ TLS_DHE_DSS_WITH_RC4_128_SHA,
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+#ifdef NSS_ENABLE_ECC
+ TLS_ECDH_RSA_WITH_RC4_128_SHA,
+ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+#endif /* NSS_ENABLE_ECC */
+ TLS_RSA_WITH_SEED_CBC_SHA,
+ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
+ SSL_RSA_WITH_RC4_128_SHA,
+ SSL_RSA_WITH_RC4_128_MD5,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA256,
+
+ /* 112-bit 3DES */
+#ifdef NSS_ENABLE_ECC
+ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+#endif /* NSS_ENABLE_ECC */
+ SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+#ifdef NSS_ENABLE_ECC
+ TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+#endif /* NSS_ENABLE_ECC */
+ SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,
+ SSL_RSA_WITH_3DES_EDE_CBC_SHA,
+
+ /* 56-bit DES "domestic" cipher suites */
+ SSL_DHE_RSA_WITH_DES_CBC_SHA,
+ SSL_DHE_DSS_WITH_DES_CBC_SHA,
+ SSL_RSA_FIPS_WITH_DES_CBC_SHA,
+ SSL_RSA_WITH_DES_CBC_SHA,
+
+ /* export ciphersuites with 1024-bit public key exchange keys */
+ TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,
+ TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,
+
+ /* export ciphersuites with 512-bit public key exchange keys */
+ SSL_RSA_EXPORT_WITH_RC4_40_MD5,
+ SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
+
+ /* ciphersuites with no encryption */
+#ifdef NSS_ENABLE_ECC
+ TLS_ECDHE_ECDSA_WITH_NULL_SHA,
+ TLS_ECDHE_RSA_WITH_NULL_SHA,
+ TLS_ECDH_RSA_WITH_NULL_SHA,
+ TLS_ECDH_ECDSA_WITH_NULL_SHA,
+#endif /* NSS_ENABLE_ECC */
+ SSL_RSA_WITH_NULL_SHA,
+ TLS_RSA_WITH_NULL_SHA256,
+ SSL_RSA_WITH_NULL_MD5,
+
+ /* SSL2 cipher suites. */
+ SSL_EN_RC4_128_WITH_MD5,
+ SSL_EN_RC2_128_CBC_WITH_MD5,
+ SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* actually 112, not 192 */
+ SSL_EN_DES_64_CBC_WITH_MD5,
+ SSL_EN_RC4_128_EXPORT40_WITH_MD5,
+ SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5,
+
+ 0
+
+};
+
+const PRUint16 SSL_NumImplementedCiphers =
+ (sizeof SSL_ImplementedCiphers) / (sizeof SSL_ImplementedCiphers[0]) - 1;
+
+const PRUint16 *
+SSL_GetImplementedCiphers(void)
+{
+ return SSL_ImplementedCiphers;
+}
+
+PRUint16
+SSL_GetNumImplementedCiphers(void)
+{
+ return SSL_NumImplementedCiphers;
+}
diff --git a/chromium/net/third_party/nss/ssl/sslerr.c b/chromium/net/third_party/nss/ssl/sslerr.c
new file mode 100644
index 00000000000..f827221aee2
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslerr.c
@@ -0,0 +1,41 @@
+/*
+ * Function to set error code only when meaningful error has not already
+ * been set.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prerror.h"
+#include "secerr.h"
+#include "sslerr.h"
+#include "seccomon.h"
+
+/* look at the current value of PR_GetError, and evaluate it to see
+ * if it is meaningful or meaningless (out of context).
+ * If it is meaningless, replace it with the hiLevelError.
+ * Returns the chosen error value.
+ */
+int
+ssl_MapLowLevelError(int hiLevelError)
+{
+ int oldErr = PORT_GetError();
+
+ switch (oldErr) {
+
+ case 0:
+ case PR_IO_ERROR:
+ case SEC_ERROR_IO:
+ case SEC_ERROR_BAD_DATA:
+ case SEC_ERROR_LIBRARY_FAILURE:
+ case SEC_ERROR_EXTENSION_NOT_FOUND:
+ case SSL_ERROR_BAD_CLIENT:
+ case SSL_ERROR_BAD_SERVER:
+ case SSL_ERROR_SESSION_NOT_FOUND:
+ PORT_SetError(hiLevelError);
+ return hiLevelError;
+
+ default: /* leave the majority of error codes alone. */
+ return oldErr;
+ }
+}
diff --git a/chromium/net/third_party/nss/ssl/sslerr.h b/chromium/net/third_party/nss/ssl/sslerr.h
new file mode 100644
index 00000000000..5a949c9a248
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslerr.h
@@ -0,0 +1,204 @@
+/*
+ * Enumeration of all SSL-specific error codes.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef __SSL_ERR_H_
+#define __SSL_ERR_H_
+
+
+#define SSL_ERROR_BASE (-0x3000)
+#define SSL_ERROR_LIMIT (SSL_ERROR_BASE + 1000)
+
+#define IS_SSL_ERROR(code) \
+ (((code) >= SSL_ERROR_BASE) && ((code) < SSL_ERROR_LIMIT))
+
+#ifndef NO_SECURITY_ERROR_ENUM
+typedef enum {
+SSL_ERROR_EXPORT_ONLY_SERVER = (SSL_ERROR_BASE + 0),
+SSL_ERROR_US_ONLY_SERVER = (SSL_ERROR_BASE + 1),
+SSL_ERROR_NO_CYPHER_OVERLAP = (SSL_ERROR_BASE + 2),
+/*
+ * Received an alert reporting what we did wrong. (more alerts below)
+ */
+SSL_ERROR_NO_CERTIFICATE /*_ALERT */ = (SSL_ERROR_BASE + 3),
+SSL_ERROR_BAD_CERTIFICATE = (SSL_ERROR_BASE + 4),
+SSL_ERROR_UNUSED_5 = (SSL_ERROR_BASE + 5),
+ /* error 5 is obsolete */
+SSL_ERROR_BAD_CLIENT = (SSL_ERROR_BASE + 6),
+SSL_ERROR_BAD_SERVER = (SSL_ERROR_BASE + 7),
+SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE = (SSL_ERROR_BASE + 8),
+SSL_ERROR_UNSUPPORTED_VERSION = (SSL_ERROR_BASE + 9),
+SSL_ERROR_UNUSED_10 = (SSL_ERROR_BASE + 10),
+ /* error 10 is obsolete */
+SSL_ERROR_WRONG_CERTIFICATE = (SSL_ERROR_BASE + 11),
+SSL_ERROR_BAD_CERT_DOMAIN = (SSL_ERROR_BASE + 12),
+SSL_ERROR_POST_WARNING = (SSL_ERROR_BASE + 13),
+SSL_ERROR_SSL2_DISABLED = (SSL_ERROR_BASE + 14),
+SSL_ERROR_BAD_MAC_READ = (SSL_ERROR_BASE + 15),
+/*
+ * Received an alert reporting what we did wrong.
+ * (two more alerts above, and many more below)
+ */
+SSL_ERROR_BAD_MAC_ALERT = (SSL_ERROR_BASE + 16),
+SSL_ERROR_BAD_CERT_ALERT = (SSL_ERROR_BASE + 17),
+SSL_ERROR_REVOKED_CERT_ALERT = (SSL_ERROR_BASE + 18),
+SSL_ERROR_EXPIRED_CERT_ALERT = (SSL_ERROR_BASE + 19),
+
+SSL_ERROR_SSL_DISABLED = (SSL_ERROR_BASE + 20),
+SSL_ERROR_FORTEZZA_PQG = (SSL_ERROR_BASE + 21),
+SSL_ERROR_UNKNOWN_CIPHER_SUITE = (SSL_ERROR_BASE + 22),
+SSL_ERROR_NO_CIPHERS_SUPPORTED = (SSL_ERROR_BASE + 23),
+SSL_ERROR_BAD_BLOCK_PADDING = (SSL_ERROR_BASE + 24),
+SSL_ERROR_RX_RECORD_TOO_LONG = (SSL_ERROR_BASE + 25),
+SSL_ERROR_TX_RECORD_TOO_LONG = (SSL_ERROR_BASE + 26),
+/*
+ * Received a malformed (too long or short) SSL handshake.
+ */
+SSL_ERROR_RX_MALFORMED_HELLO_REQUEST = (SSL_ERROR_BASE + 27),
+SSL_ERROR_RX_MALFORMED_CLIENT_HELLO = (SSL_ERROR_BASE + 28),
+SSL_ERROR_RX_MALFORMED_SERVER_HELLO = (SSL_ERROR_BASE + 29),
+SSL_ERROR_RX_MALFORMED_CERTIFICATE = (SSL_ERROR_BASE + 30),
+SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH = (SSL_ERROR_BASE + 31),
+SSL_ERROR_RX_MALFORMED_CERT_REQUEST = (SSL_ERROR_BASE + 32),
+SSL_ERROR_RX_MALFORMED_HELLO_DONE = (SSL_ERROR_BASE + 33),
+SSL_ERROR_RX_MALFORMED_CERT_VERIFY = (SSL_ERROR_BASE + 34),
+SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH = (SSL_ERROR_BASE + 35),
+SSL_ERROR_RX_MALFORMED_FINISHED = (SSL_ERROR_BASE + 36),
+/*
+ * Received a malformed (too long or short) SSL record.
+ */
+SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER = (SSL_ERROR_BASE + 37),
+SSL_ERROR_RX_MALFORMED_ALERT = (SSL_ERROR_BASE + 38),
+SSL_ERROR_RX_MALFORMED_HANDSHAKE = (SSL_ERROR_BASE + 39),
+SSL_ERROR_RX_MALFORMED_APPLICATION_DATA = (SSL_ERROR_BASE + 40),
+/*
+ * Received an SSL handshake that was inappropriate for the state we're in.
+ * E.g. Server received message from server, or wrong state in state machine.
+ */
+SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST = (SSL_ERROR_BASE + 41),
+SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO = (SSL_ERROR_BASE + 42),
+SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO = (SSL_ERROR_BASE + 43),
+SSL_ERROR_RX_UNEXPECTED_CERTIFICATE = (SSL_ERROR_BASE + 44),
+SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH = (SSL_ERROR_BASE + 45),
+SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST = (SSL_ERROR_BASE + 46),
+SSL_ERROR_RX_UNEXPECTED_HELLO_DONE = (SSL_ERROR_BASE + 47),
+SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY = (SSL_ERROR_BASE + 48),
+SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH = (SSL_ERROR_BASE + 49),
+SSL_ERROR_RX_UNEXPECTED_FINISHED = (SSL_ERROR_BASE + 50),
+/*
+ * Received an SSL record that was inappropriate for the state we're in.
+ */
+SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER = (SSL_ERROR_BASE + 51),
+SSL_ERROR_RX_UNEXPECTED_ALERT = (SSL_ERROR_BASE + 52),
+SSL_ERROR_RX_UNEXPECTED_HANDSHAKE = (SSL_ERROR_BASE + 53),
+SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA= (SSL_ERROR_BASE + 54),
+/*
+ * Received record/message with unknown discriminant.
+ */
+SSL_ERROR_RX_UNKNOWN_RECORD_TYPE = (SSL_ERROR_BASE + 55),
+SSL_ERROR_RX_UNKNOWN_HANDSHAKE = (SSL_ERROR_BASE + 56),
+SSL_ERROR_RX_UNKNOWN_ALERT = (SSL_ERROR_BASE + 57),
+/*
+ * Received an alert reporting what we did wrong. (more alerts above)
+ */
+SSL_ERROR_CLOSE_NOTIFY_ALERT = (SSL_ERROR_BASE + 58),
+SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT = (SSL_ERROR_BASE + 59),
+SSL_ERROR_DECOMPRESSION_FAILURE_ALERT = (SSL_ERROR_BASE + 60),
+SSL_ERROR_HANDSHAKE_FAILURE_ALERT = (SSL_ERROR_BASE + 61),
+SSL_ERROR_ILLEGAL_PARAMETER_ALERT = (SSL_ERROR_BASE + 62),
+SSL_ERROR_UNSUPPORTED_CERT_ALERT = (SSL_ERROR_BASE + 63),
+SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT = (SSL_ERROR_BASE + 64),
+
+SSL_ERROR_GENERATE_RANDOM_FAILURE = (SSL_ERROR_BASE + 65),
+SSL_ERROR_SIGN_HASHES_FAILURE = (SSL_ERROR_BASE + 66),
+SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE = (SSL_ERROR_BASE + 67),
+SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE = (SSL_ERROR_BASE + 68),
+SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE = (SSL_ERROR_BASE + 69),
+
+SSL_ERROR_ENCRYPTION_FAILURE = (SSL_ERROR_BASE + 70),
+SSL_ERROR_DECRYPTION_FAILURE = (SSL_ERROR_BASE + 71), /* don't use */
+SSL_ERROR_SOCKET_WRITE_FAILURE = (SSL_ERROR_BASE + 72),
+
+SSL_ERROR_MD5_DIGEST_FAILURE = (SSL_ERROR_BASE + 73),
+SSL_ERROR_SHA_DIGEST_FAILURE = (SSL_ERROR_BASE + 74),
+SSL_ERROR_MAC_COMPUTATION_FAILURE = (SSL_ERROR_BASE + 75),
+SSL_ERROR_SYM_KEY_CONTEXT_FAILURE = (SSL_ERROR_BASE + 76),
+SSL_ERROR_SYM_KEY_UNWRAP_FAILURE = (SSL_ERROR_BASE + 77),
+SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED = (SSL_ERROR_BASE + 78),
+SSL_ERROR_IV_PARAM_FAILURE = (SSL_ERROR_BASE + 79),
+SSL_ERROR_INIT_CIPHER_SUITE_FAILURE = (SSL_ERROR_BASE + 80),
+SSL_ERROR_SESSION_KEY_GEN_FAILURE = (SSL_ERROR_BASE + 81),
+SSL_ERROR_NO_SERVER_KEY_FOR_ALG = (SSL_ERROR_BASE + 82),
+SSL_ERROR_TOKEN_INSERTION_REMOVAL = (SSL_ERROR_BASE + 83),
+SSL_ERROR_TOKEN_SLOT_NOT_FOUND = (SSL_ERROR_BASE + 84),
+SSL_ERROR_NO_COMPRESSION_OVERLAP = (SSL_ERROR_BASE + 85),
+SSL_ERROR_HANDSHAKE_NOT_COMPLETED = (SSL_ERROR_BASE + 86),
+SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE = (SSL_ERROR_BASE + 87),
+SSL_ERROR_CERT_KEA_MISMATCH = (SSL_ERROR_BASE + 88),
+/* SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA became obsolete in NSS 3.14. */
+SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA = (SSL_ERROR_BASE + 89),
+SSL_ERROR_SESSION_NOT_FOUND = (SSL_ERROR_BASE + 90),
+
+SSL_ERROR_DECRYPTION_FAILED_ALERT = (SSL_ERROR_BASE + 91),
+SSL_ERROR_RECORD_OVERFLOW_ALERT = (SSL_ERROR_BASE + 92),
+SSL_ERROR_UNKNOWN_CA_ALERT = (SSL_ERROR_BASE + 93),
+SSL_ERROR_ACCESS_DENIED_ALERT = (SSL_ERROR_BASE + 94),
+SSL_ERROR_DECODE_ERROR_ALERT = (SSL_ERROR_BASE + 95),
+SSL_ERROR_DECRYPT_ERROR_ALERT = (SSL_ERROR_BASE + 96),
+SSL_ERROR_EXPORT_RESTRICTION_ALERT = (SSL_ERROR_BASE + 97),
+SSL_ERROR_PROTOCOL_VERSION_ALERT = (SSL_ERROR_BASE + 98),
+SSL_ERROR_INSUFFICIENT_SECURITY_ALERT = (SSL_ERROR_BASE + 99),
+SSL_ERROR_INTERNAL_ERROR_ALERT = (SSL_ERROR_BASE + 100),
+SSL_ERROR_USER_CANCELED_ALERT = (SSL_ERROR_BASE + 101),
+SSL_ERROR_NO_RENEGOTIATION_ALERT = (SSL_ERROR_BASE + 102),
+
+SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED = (SSL_ERROR_BASE + 103),
+
+SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT = (SSL_ERROR_BASE + 104),
+SSL_ERROR_CERTIFICATE_UNOBTAINABLE_ALERT = (SSL_ERROR_BASE + 105),
+SSL_ERROR_UNRECOGNIZED_NAME_ALERT = (SSL_ERROR_BASE + 106),
+SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT = (SSL_ERROR_BASE + 107),
+SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT = (SSL_ERROR_BASE + 108),
+
+SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET = (SSL_ERROR_BASE + 109),
+SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET = (SSL_ERROR_BASE + 110),
+
+SSL_ERROR_DECOMPRESSION_FAILURE = (SSL_ERROR_BASE + 111),
+SSL_ERROR_RENEGOTIATION_NOT_ALLOWED = (SSL_ERROR_BASE + 112),
+SSL_ERROR_UNSAFE_NEGOTIATION = (SSL_ERROR_BASE + 113),
+
+SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD = (SSL_ERROR_BASE + 114),
+
+SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY = (SSL_ERROR_BASE + 115),
+
+SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID = (SSL_ERROR_BASE + 116),
+
+SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2 = (SSL_ERROR_BASE + 117),
+SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS = (SSL_ERROR_BASE + 118),
+SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_CLIENTS = (SSL_ERROR_BASE + 119),
+
+SSL_ERROR_INVALID_VERSION_RANGE = (SSL_ERROR_BASE + 120),
+SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION = (SSL_ERROR_BASE + 121),
+
+SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST = (SSL_ERROR_BASE + 122),
+SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST = (SSL_ERROR_BASE + 123),
+
+SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION = (SSL_ERROR_BASE + 124),
+
+SSL_ERROR_RX_UNEXPECTED_CERT_STATUS = (SSL_ERROR_BASE + 125),
+
+SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM = (SSL_ERROR_BASE + 126),
+SSL_ERROR_DIGEST_FAILURE = (SSL_ERROR_BASE + 127),
+SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 128),
+
+SSL_ERROR_BAD_CHANNEL_ID_DATA = (SSL_ERROR_BASE + 129),
+SSL_ERROR_INVALID_CHANNEL_ID_KEY = (SSL_ERROR_BASE + 130),
+SSL_ERROR_GET_CHANNEL_ID_FAILED = (SSL_ERROR_BASE + 131),
+
+SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
+} SSLErrorCodes;
+#endif /* NO_SECURITY_ERROR_ENUM */
+
+#endif /* __SSL_ERR_H_ */
diff --git a/chromium/net/third_party/nss/ssl/sslerrstrs.c b/chromium/net/third_party/nss/ssl/sslerrstrs.c
new file mode 100644
index 00000000000..34f4ea9b9d8
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslerrstrs.c
@@ -0,0 +1,34 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "prerror.h"
+#include "sslerr.h"
+#include "prinit.h"
+#include "nssutil.h"
+#include "ssl.h"
+
+#define ER3(name, value, str) {#name, str},
+
+static const struct PRErrorMessage ssltext[] = {
+#include "SSLerrs.h"
+ {0,0}
+};
+
+static const struct PRErrorTable ssl_et = {
+ ssltext, "sslerr", SSL_ERROR_BASE,
+ (sizeof ssltext)/(sizeof ssltext[0])
+};
+
+static PRStatus
+ssl_InitializePRErrorTableOnce(void) {
+ return PR_ErrorInstallTable(&ssl_et);
+}
+
+static PRCallOnceType once;
+
+SECStatus
+ssl_InitializePRErrorTable(void)
+{
+ return (PR_SUCCESS == PR_CallOnce(&once, ssl_InitializePRErrorTableOnce))
+ ? SECSuccess : SECFailure;
+}
diff --git a/chromium/net/third_party/nss/ssl/sslgathr.c b/chromium/net/third_party/nss/ssl/sslgathr.c
new file mode 100644
index 00000000000..6c17eb00fae
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslgathr.c
@@ -0,0 +1,453 @@
+/*
+ * Gather (Read) entire SSL2 records from socket into buffer.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "cert.h"
+#include "ssl.h"
+#include "sslimpl.h"
+#include "sslproto.h"
+
+/* Forward static declarations */
+static SECStatus ssl2_HandleV3HandshakeRecord(sslSocket *ss);
+
+/*
+** Gather a single record of data from the receiving stream. This code
+** first gathers the header (2 or 3 bytes long depending on the value of
+** the most significant bit in the first byte) then gathers up the data
+** for the record into gs->buf. This code handles non-blocking I/O
+** and is to be called multiple times until ss->sec.recordLen != 0.
+** This function decrypts the gathered record in place, in gs_buf.
+ *
+ * Caller must hold RecvBufLock.
+ *
+ * Returns +1 when it has gathered a complete SSLV2 record.
+ * Returns 0 if it hits EOF.
+ * Returns -1 (SECFailure) on any error
+ * Returns -2 (SECWouldBlock) when it gathers an SSL v3 client hello header.
+**
+** The SSL2 Gather State machine has 4 states:
+** GS_INIT - Done reading in previous record. Haven't begun to read in
+** next record. When ssl2_GatherData is called with the machine
+** in this state, the machine will attempt to read the first 3
+** bytes of the SSL2 record header, and will advance the state
+** to GS_HEADER.
+**
+** GS_HEADER - The machine is in this state while waiting for the completion
+** of the first 3 bytes of the SSL2 record. When complete, the
+** machine will compute the remaining unread length of this record
+** and will initiate a read of that many bytes. The machine will
+** advance to one of two states, depending on whether the record
+** is encrypted (GS_MAC), or unencrypted (GS_DATA).
+**
+** GS_MAC - The machine is in this state while waiting for the remainder
+** of the SSL2 record to be read in. When the read is completed,
+** the machine checks the record for valid length, decrypts it,
+** and checks and discards the MAC, then advances to GS_INIT.
+**
+** GS_DATA - The machine is in this state while waiting for the remainder
+** of the unencrypted SSL2 record to be read in. Upon completion,
+** the machine advances to the GS_INIT state and returns the data.
+*/
+int
+ssl2_GatherData(sslSocket *ss, sslGather *gs, int flags)
+{
+ unsigned char * bp;
+ unsigned char * pBuf;
+ int nb, err, rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+
+ if (gs->state == GS_INIT) {
+ /* Initialize gathering engine */
+ gs->state = GS_HEADER;
+ gs->remainder = 3;
+ gs->count = 3;
+ gs->offset = 0;
+ gs->recordLen = 0;
+ gs->recordPadding = 0;
+ gs->hdr[2] = 0;
+
+ gs->writeOffset = 0;
+ gs->readOffset = 0;
+ }
+ if (gs->encrypted) {
+ PORT_Assert(ss->sec.hash != 0);
+ }
+
+ pBuf = gs->buf.buf;
+ for (;;) {
+ SSL_TRC(30, ("%d: SSL[%d]: gather state %d (need %d more)",
+ SSL_GETPID(), ss->fd, gs->state, gs->remainder));
+ bp = ((gs->state != GS_HEADER) ? pBuf : gs->hdr) + gs->offset;
+ nb = ssl_DefRecv(ss, bp, gs->remainder, flags);
+ if (nb > 0) {
+ PRINT_BUF(60, (ss, "raw gather data:", bp, nb));
+ }
+ if (nb == 0) {
+ /* EOF */
+ SSL_TRC(30, ("%d: SSL[%d]: EOF", SSL_GETPID(), ss->fd));
+ rv = 0;
+ break;
+ }
+ if (nb < 0) {
+ SSL_DBG(("%d: SSL[%d]: recv error %d", SSL_GETPID(), ss->fd,
+ PR_GetError()));
+ rv = SECFailure;
+ break;
+ }
+
+ gs->offset += nb;
+ gs->remainder -= nb;
+
+ if (gs->remainder > 0) {
+ continue;
+ }
+
+ /* Probably finished this piece */
+ switch (gs->state) {
+ case GS_HEADER:
+ if (!SSL3_ALL_VERSIONS_DISABLED(&ss->vrange) && !ss->firstHsDone) {
+
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ /* If this looks like an SSL3 handshake record,
+ ** and we're expecting an SSL2 Hello message from our peer,
+ ** handle it here.
+ */
+ if (gs->hdr[0] == content_handshake) {
+ if ((ss->nextHandshake == ssl2_HandleClientHelloMessage) ||
+ (ss->nextHandshake == ssl2_HandleServerHelloMessage)) {
+ rv = ssl2_HandleV3HandshakeRecord(ss);
+ if (rv == SECFailure) {
+ return SECFailure;
+ }
+ }
+ /* XXX_1 The call stack to here is:
+ * ssl_Do1stHandshake -> ssl_GatherRecord1stHandshake ->
+ * ssl2_GatherRecord -> here.
+ * We want to return all the way out to ssl_Do1stHandshake,
+ * and have it call ssl_GatherRecord1stHandshake again.
+ * ssl_GatherRecord1stHandshake will call
+ * ssl3_GatherCompleteHandshake when it is called again.
+ *
+ * Returning SECWouldBlock here causes
+ * ssl_GatherRecord1stHandshake to return without clearing
+ * ss->handshake, ensuring that ssl_Do1stHandshake will
+ * call it again immediately.
+ *
+ * If we return 1 here, ssl_GatherRecord1stHandshake will
+ * clear ss->handshake before returning, and thus will not
+ * be called again by ssl_Do1stHandshake.
+ */
+ return SECWouldBlock;
+ } else if (gs->hdr[0] == content_alert) {
+ if (ss->nextHandshake == ssl2_HandleServerHelloMessage) {
+ /* XXX This is a hack. We're assuming that any failure
+ * XXX on the client hello is a failure to match
+ * XXX ciphers.
+ */
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+ return SECFailure;
+ }
+ }
+ }
+
+ /* we've got the first 3 bytes. The header may be two or three. */
+ if (gs->hdr[0] & 0x80) {
+ /* This record has a 2-byte header, and no padding */
+ gs->count = ((gs->hdr[0] & 0x7f) << 8) | gs->hdr[1];
+ gs->recordPadding = 0;
+ } else {
+ /* This record has a 3-byte header that is all read in now. */
+ gs->count = ((gs->hdr[0] & 0x3f) << 8) | gs->hdr[1];
+ /* is_escape = (gs->hdr[0] & 0x40) != 0; */
+ gs->recordPadding = gs->hdr[2];
+ }
+ if (!gs->count) {
+ PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
+ goto cleanup;
+ }
+
+ if (gs->count > gs->buf.space) {
+ err = sslBuffer_Grow(&gs->buf, gs->count);
+ if (err) {
+ return err;
+ }
+ pBuf = gs->buf.buf;
+ }
+
+
+ if (gs->hdr[0] & 0x80) {
+ /* we've already read in the first byte of the body.
+ ** Put it into the buffer.
+ */
+ pBuf[0] = gs->hdr[2];
+ gs->offset = 1;
+ gs->remainder = gs->count - 1;
+ } else {
+ gs->offset = 0;
+ gs->remainder = gs->count;
+ }
+
+ if (gs->encrypted) {
+ gs->state = GS_MAC;
+ gs->recordLen = gs->count - gs->recordPadding
+ - ss->sec.hash->length;
+ } else {
+ gs->state = GS_DATA;
+ gs->recordLen = gs->count;
+ }
+
+ break;
+
+
+ case GS_MAC:
+ /* Have read in entire rest of the ciphertext.
+ ** Check for valid length.
+ ** Decrypt it.
+ ** Check the MAC.
+ */
+ PORT_Assert(gs->encrypted);
+
+ {
+ unsigned int macLen;
+ int nout;
+ unsigned char mac[SSL_MAX_MAC_BYTES];
+
+ ssl_GetSpecReadLock(ss); /**********************************/
+
+ /* If this is a stream cipher, blockSize will be 1,
+ * and this test will always be false.
+ * If this is a block cipher, this will detect records
+ * that are not a multiple of the blocksize in length.
+ */
+ if (gs->count & (ss->sec.blockSize - 1)) {
+ /* This is an error. Sender is misbehaving */
+ SSL_DBG(("%d: SSL[%d]: sender, count=%d blockSize=%d",
+ SSL_GETPID(), ss->fd, gs->count,
+ ss->sec.blockSize));
+ PORT_SetError(SSL_ERROR_BAD_BLOCK_PADDING);
+ rv = SECFailure;
+ goto spec_locked_done;
+ }
+ PORT_Assert(gs->count == gs->offset);
+
+ if (gs->offset == 0) {
+ rv = 0; /* means EOF. */
+ goto spec_locked_done;
+ }
+
+ /* Decrypt the portion of data that we just received.
+ ** Decrypt it in place.
+ */
+ rv = (*ss->sec.dec)(ss->sec.readcx, pBuf, &nout, gs->offset,
+ pBuf, gs->offset);
+ if (rv != SECSuccess) {
+ goto spec_locked_done;
+ }
+
+
+ /* Have read in all the MAC portion of record
+ **
+ ** Prepare MAC by resetting it and feeding it the shared secret
+ */
+ macLen = ss->sec.hash->length;
+ if (gs->offset >= macLen) {
+ PRUint32 sequenceNumber = ss->sec.rcvSequence++;
+ unsigned char seq[4];
+
+ seq[0] = (unsigned char) (sequenceNumber >> 24);
+ seq[1] = (unsigned char) (sequenceNumber >> 16);
+ seq[2] = (unsigned char) (sequenceNumber >> 8);
+ seq[3] = (unsigned char) (sequenceNumber);
+
+ (*ss->sec.hash->begin)(ss->sec.hashcx);
+ (*ss->sec.hash->update)(ss->sec.hashcx, ss->sec.rcvSecret.data,
+ ss->sec.rcvSecret.len);
+ (*ss->sec.hash->update)(ss->sec.hashcx, pBuf + macLen,
+ gs->offset - macLen);
+ (*ss->sec.hash->update)(ss->sec.hashcx, seq, 4);
+ (*ss->sec.hash->end)(ss->sec.hashcx, mac, &macLen, macLen);
+
+ PORT_Assert(macLen == ss->sec.hash->length);
+
+ ssl_ReleaseSpecReadLock(ss); /******************************/
+
+ if (NSS_SecureMemcmp(mac, pBuf, macLen) != 0) {
+ /* MAC's didn't match... */
+ SSL_DBG(("%d: SSL[%d]: mac check failed, seq=%d",
+ SSL_GETPID(), ss->fd, ss->sec.rcvSequence));
+ PRINT_BUF(1, (ss, "computed mac:", mac, macLen));
+ PRINT_BUF(1, (ss, "received mac:", pBuf, macLen));
+ PORT_SetError(SSL_ERROR_BAD_MAC_READ);
+ rv = SECFailure;
+ goto cleanup;
+ }
+ } else {
+ ssl_ReleaseSpecReadLock(ss); /******************************/
+ }
+
+ if (gs->recordPadding + macLen <= gs->offset) {
+ gs->recordOffset = macLen;
+ gs->readOffset = macLen;
+ gs->writeOffset = gs->offset - gs->recordPadding;
+ rv = 1;
+ } else {
+ PORT_SetError(SSL_ERROR_BAD_BLOCK_PADDING);
+cleanup:
+ /* nothing in the buffer any more. */
+ gs->recordOffset = 0;
+ gs->readOffset = 0;
+ gs->writeOffset = 0;
+ rv = SECFailure;
+ }
+
+ gs->recordLen = gs->writeOffset - gs->readOffset;
+ gs->recordPadding = 0; /* forget we did any padding. */
+ gs->state = GS_INIT;
+
+
+ if (rv > 0) {
+ PRINT_BUF(50, (ss, "recv clear record:",
+ pBuf + gs->recordOffset, gs->recordLen));
+ }
+ return rv;
+
+spec_locked_done:
+ ssl_ReleaseSpecReadLock(ss);
+ return rv;
+ }
+
+ case GS_DATA:
+ /* Have read in all the DATA portion of record */
+
+ gs->recordOffset = 0;
+ gs->readOffset = 0;
+ gs->writeOffset = gs->offset;
+ PORT_Assert(gs->recordLen == gs->writeOffset - gs->readOffset);
+ gs->recordLen = gs->offset;
+ gs->recordPadding = 0;
+ gs->state = GS_INIT;
+
+ ++ss->sec.rcvSequence;
+
+ PRINT_BUF(50, (ss, "recv clear record:",
+ pBuf + gs->recordOffset, gs->recordLen));
+ return 1;
+
+ } /* end switch gs->state */
+ } /* end gather loop. */
+ return rv;
+}
+
+/*
+** Gather a single record of data from the receiving stream. This code
+** first gathers the header (2 or 3 bytes long depending on the value of
+** the most significant bit in the first byte) then gathers up the data
+** for the record into the readBuf. This code handles non-blocking I/O
+** and is to be called multiple times until ss->sec.recordLen != 0.
+ *
+ * Returns +1 when it has gathered a complete SSLV2 record.
+ * Returns 0 if it hits EOF.
+ * Returns -1 (SECFailure) on any error
+ * Returns -2 (SECWouldBlock)
+ *
+ * Called by ssl_GatherRecord1stHandshake in sslcon.c,
+ * and by DoRecv in sslsecur.c
+ * Caller must hold RecvBufLock.
+ */
+int
+ssl2_GatherRecord(sslSocket *ss, int flags)
+{
+ return ssl2_GatherData(ss, &ss->gs, flags);
+}
+
+/*
+ * Returns +1 when it has gathered a complete SSLV2 record.
+ * Returns 0 if it hits EOF.
+ * Returns -1 (SECFailure) on any error
+ * Returns -2 (SECWouldBlock)
+ *
+ * Called from SocksStartGather in sslsocks.c
+ * Caller must hold RecvBufLock.
+ */
+int
+ssl2_StartGatherBytes(sslSocket *ss, sslGather *gs, unsigned int count)
+{
+ int rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ gs->state = GS_DATA;
+ gs->remainder = count;
+ gs->count = count;
+ gs->offset = 0;
+ if (count > gs->buf.space) {
+ rv = sslBuffer_Grow(&gs->buf, count);
+ if (rv) {
+ return rv;
+ }
+ }
+ return ssl2_GatherData(ss, gs, 0);
+}
+
+/* Caller should hold RecvBufLock. */
+SECStatus
+ssl_InitGather(sslGather *gs)
+{
+ SECStatus status;
+
+ gs->state = GS_INIT;
+ gs->writeOffset = 0;
+ gs->readOffset = 0;
+ gs->dtlsPacketOffset = 0;
+ gs->dtlsPacket.len = 0;
+ status = sslBuffer_Grow(&gs->buf, 4096);
+ return status;
+}
+
+/* Caller must hold RecvBufLock. */
+void
+ssl_DestroyGather(sslGather *gs)
+{
+ if (gs) { /* the PORT_*Free functions check for NULL pointers. */
+ PORT_ZFree(gs->buf.buf, gs->buf.space);
+ PORT_Free(gs->inbuf.buf);
+ PORT_Free(gs->dtlsPacket.buf);
+ }
+}
+
+/* Caller must hold RecvBufLock. */
+static SECStatus
+ssl2_HandleV3HandshakeRecord(sslSocket *ss)
+{
+ SECStatus rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+
+ /* We've read in 3 bytes, there are 2 more to go in an ssl3 header. */
+ ss->gs.remainder = 2;
+ ss->gs.count = 0;
+
+ /* Clearing these handshake pointers ensures that
+ * ssl_Do1stHandshake won't call ssl2_HandleMessage when we return.
+ */
+ ss->nextHandshake = 0;
+ ss->securityHandshake = 0;
+
+ /* Setting ss->version to an SSL 3.x value will cause
+ ** ssl_GatherRecord1stHandshake to invoke ssl3_GatherCompleteHandshake()
+ ** the next time it is called.
+ **/
+ rv = ssl3_NegotiateVersion(ss, SSL_LIBRARY_VERSION_MAX_SUPPORTED,
+ PR_TRUE);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ ss->sec.send = ssl3_SendApplicationData;
+
+ return SECSuccess;
+}
diff --git a/chromium/net/third_party/nss/ssl/sslimpl.h b/chromium/net/third_party/nss/ssl/sslimpl.h
new file mode 100644
index 00000000000..da302abe57d
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslimpl.h
@@ -0,0 +1,1941 @@
+/*
+ * This file is PRIVATE to SSL and should be the first thing included by
+ * any SSL implementation file.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __sslimpl_h_
+#define __sslimpl_h_
+
+#ifdef DEBUG
+#undef NDEBUG
+#else
+#undef NDEBUG
+#define NDEBUG
+#endif
+#include "secport.h"
+#include "secerr.h"
+#include "sslerr.h"
+#include "ssl3prot.h"
+#include "hasht.h"
+#include "keythi.h"
+#include "nssilock.h"
+#include "pkcs11t.h"
+#if defined(XP_UNIX) || defined(XP_BEOS)
+#include "unistd.h"
+#endif
+#include "nssrwlk.h"
+#include "prthread.h"
+#include "prclist.h"
+
+#include "sslt.h" /* for some formerly private types, now public */
+
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+#if defined(XP_WIN32)
+#include <windows.h>
+#include <wincrypt.h>
+#elif defined(XP_MACOSX)
+#include <Security/Security.h>
+#endif
+#endif
+
+/* to make some of these old enums public without namespace pollution,
+** it was necessary to prepend ssl_ to the names.
+** These #defines preserve compatibility with the old code here in libssl.
+*/
+typedef SSLKEAType SSL3KEAType;
+typedef SSLMACAlgorithm SSL3MACAlgorithm;
+typedef SSLSignType SSL3SignType;
+
+#define sign_null ssl_sign_null
+#define sign_rsa ssl_sign_rsa
+#define sign_dsa ssl_sign_dsa
+#define sign_ecdsa ssl_sign_ecdsa
+
+#define calg_null ssl_calg_null
+#define calg_rc4 ssl_calg_rc4
+#define calg_rc2 ssl_calg_rc2
+#define calg_des ssl_calg_des
+#define calg_3des ssl_calg_3des
+#define calg_idea ssl_calg_idea
+#define calg_fortezza ssl_calg_fortezza /* deprecated, must preserve */
+#define calg_aes ssl_calg_aes
+#define calg_camellia ssl_calg_camellia
+#define calg_seed ssl_calg_seed
+#define calg_aes_gcm ssl_calg_aes_gcm
+
+#define mac_null ssl_mac_null
+#define mac_md5 ssl_mac_md5
+#define mac_sha ssl_mac_sha
+#define hmac_md5 ssl_hmac_md5
+#define hmac_sha ssl_hmac_sha
+#define hmac_sha256 ssl_hmac_sha256
+
+#define SET_ERROR_CODE /* reminder */
+#define SEND_ALERT /* reminder */
+#define TEST_FOR_FAILURE /* reminder */
+#define DEAL_WITH_FAILURE /* reminder */
+
+#if defined(DEBUG) || defined(TRACE)
+#ifdef __cplusplus
+#define Debug 1
+#else
+extern int Debug;
+#endif
+#else
+#undef Debug
+#endif
+
+#if defined(DEBUG) && !defined(TRACE) && !defined(NISCC_TEST)
+#define TRACE
+#endif
+
+#ifdef TRACE
+#define SSL_TRC(a,b) if (ssl_trace >= (a)) ssl_Trace b
+#define PRINT_BUF(a,b) if (ssl_trace >= (a)) ssl_PrintBuf b
+#define DUMP_MSG(a,b) if (ssl_trace >= (a)) ssl_DumpMsg b
+#else
+#define SSL_TRC(a,b)
+#define PRINT_BUF(a,b)
+#define DUMP_MSG(a,b)
+#endif
+
+#ifdef DEBUG
+#define SSL_DBG(b) if (ssl_debug) ssl_Trace b
+#else
+#define SSL_DBG(b)
+#endif
+
+#include "private/pprthred.h" /* for PR_InMonitor() */
+#define ssl_InMonitor(m) PZ_InMonitor(m)
+
+#define LSB(x) ((unsigned char) ((x) & 0xff))
+#define MSB(x) ((unsigned char) (((unsigned)(x)) >> 8))
+
+/************************************************************************/
+
+typedef enum { SSLAppOpRead = 0,
+ SSLAppOpWrite,
+ SSLAppOpRDWR,
+ SSLAppOpPost,
+ SSLAppOpHeader
+} SSLAppOperation;
+
+#define SSL_MIN_MASTER_KEY_BYTES 5
+#define SSL_MAX_MASTER_KEY_BYTES 64
+
+#define SSL2_SESSIONID_BYTES 16
+#define SSL3_SESSIONID_BYTES 32
+
+#define SSL_MIN_CHALLENGE_BYTES 16
+#define SSL_MAX_CHALLENGE_BYTES 32
+#define SSL_CHALLENGE_BYTES 16
+
+#define SSL_CONNECTIONID_BYTES 16
+
+#define SSL_MIN_CYPHER_ARG_BYTES 0
+#define SSL_MAX_CYPHER_ARG_BYTES 32
+
+#define SSL_MAX_MAC_BYTES 16
+
+#define SSL3_RSA_PMS_LENGTH 48
+#define SSL3_MASTER_SECRET_LENGTH 48
+
+/* number of wrap mechanisms potentially used to wrap master secrets. */
+#define SSL_NUM_WRAP_MECHS 16
+
+/* This makes the cert cache entry exactly 4k. */
+#define SSL_MAX_CACHED_CERT_LEN 4060
+
+#define NUM_MIXERS 9
+
+/* Mask of the 25 named curves we support. */
+#define SSL3_ALL_SUPPORTED_CURVES_MASK 0x3fffffe
+/* Mask of only 3 curves, suite B */
+#define SSL3_SUITE_B_SUPPORTED_CURVES_MASK 0x3800000
+
+#ifndef BPB
+#define BPB 8 /* Bits Per Byte */
+#endif
+
+#define EXPORT_RSA_KEY_LENGTH 64 /* bytes */
+
+#define INITIAL_DTLS_TIMEOUT_MS 1000 /* Default value from RFC 4347 = 1s*/
+#define MAX_DTLS_TIMEOUT_MS 60000 /* 1 minute */
+#define DTLS_FINISHED_TIMER_MS 120000 /* Time to wait in FINISHED state */
+
+typedef struct sslBufferStr sslBuffer;
+typedef struct sslConnectInfoStr sslConnectInfo;
+typedef struct sslGatherStr sslGather;
+typedef struct sslSecurityInfoStr sslSecurityInfo;
+typedef struct sslSessionIDStr sslSessionID;
+typedef struct sslSocketStr sslSocket;
+typedef struct sslSocketOpsStr sslSocketOps;
+
+typedef struct ssl3StateStr ssl3State;
+typedef struct ssl3CertNodeStr ssl3CertNode;
+typedef struct ssl3BulkCipherDefStr ssl3BulkCipherDef;
+typedef struct ssl3MACDefStr ssl3MACDef;
+typedef struct ssl3KeyPairStr ssl3KeyPair;
+
+struct ssl3CertNodeStr {
+ struct ssl3CertNodeStr *next;
+ CERTCertificate * cert;
+};
+
+typedef SECStatus (*sslHandshakeFunc)(sslSocket *ss);
+
+/* This type points to the low layer send func,
+** e.g. ssl2_SendStream or ssl3_SendPlainText.
+** These functions return the same values as PR_Send,
+** i.e. >= 0 means number of bytes sent, < 0 means error.
+*/
+typedef PRInt32 (*sslSendFunc)(sslSocket *ss, const unsigned char *buf,
+ PRInt32 n, PRInt32 flags);
+
+typedef void (*sslSessionIDCacheFunc) (sslSessionID *sid);
+typedef void (*sslSessionIDUncacheFunc)(sslSessionID *sid);
+typedef sslSessionID *(*sslSessionIDLookupFunc)(const PRIPv6Addr *addr,
+ unsigned char* sid,
+ unsigned int sidLen,
+ CERTCertDBHandle * dbHandle);
+
+/* registerable callback function that either appends extension to buffer
+ * or returns length of data that it would have appended.
+ */
+typedef PRInt32 (*ssl3HelloExtensionSenderFunc)(sslSocket *ss, PRBool append,
+ PRUint32 maxBytes);
+
+/* registerable callback function that handles a received extension,
+ * of the given type.
+ */
+typedef SECStatus (* ssl3HelloExtensionHandlerFunc)(sslSocket *ss,
+ PRUint16 ex_type,
+ SECItem * data);
+
+/* row in a table of hello extension senders */
+typedef struct {
+ PRInt32 ex_type;
+ ssl3HelloExtensionSenderFunc ex_sender;
+} ssl3HelloExtensionSender;
+
+/* row in a table of hello extension handlers */
+typedef struct {
+ PRInt32 ex_type;
+ ssl3HelloExtensionHandlerFunc ex_handler;
+} ssl3HelloExtensionHandler;
+
+extern SECStatus
+ssl3_RegisterServerHelloExtensionSender(sslSocket *ss, PRUint16 ex_type,
+ ssl3HelloExtensionSenderFunc cb);
+
+extern PRInt32
+ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes,
+ const ssl3HelloExtensionSender *sender);
+
+/* Socket ops */
+struct sslSocketOpsStr {
+ int (*connect) (sslSocket *, const PRNetAddr *);
+ PRFileDesc *(*accept) (sslSocket *, PRNetAddr *);
+ int (*bind) (sslSocket *, const PRNetAddr *);
+ int (*listen) (sslSocket *, int);
+ int (*shutdown)(sslSocket *, int);
+ int (*close) (sslSocket *);
+
+ int (*recv) (sslSocket *, unsigned char *, int, int);
+
+ /* points to the higher-layer send func, e.g. ssl_SecureSend. */
+ int (*send) (sslSocket *, const unsigned char *, int, int);
+ int (*read) (sslSocket *, unsigned char *, int);
+ int (*write) (sslSocket *, const unsigned char *, int);
+
+ int (*getpeername)(sslSocket *, PRNetAddr *);
+ int (*getsockname)(sslSocket *, PRNetAddr *);
+};
+
+/* Flags interpreted by ssl send functions. */
+#define ssl_SEND_FLAG_FORCE_INTO_BUFFER 0x40000000
+#define ssl_SEND_FLAG_NO_BUFFER 0x20000000
+#define ssl_SEND_FLAG_USE_EPOCH 0x10000000 /* DTLS only */
+#define ssl_SEND_FLAG_NO_RETRANSMIT 0x08000000 /* DTLS only */
+#define ssl_SEND_FLAG_CAP_RECORD_VERSION \
+ 0x04000000 /* TLS only */
+#define ssl_SEND_FLAG_MASK 0x7f000000
+
+/*
+** A buffer object.
+*/
+struct sslBufferStr {
+ unsigned char * buf;
+ unsigned int len;
+ unsigned int space;
+};
+
+/*
+** SSL3 cipher suite policy and preference struct.
+*/
+typedef struct {
+#if !defined(_WIN32)
+ unsigned int cipher_suite : 16;
+ unsigned int policy : 8;
+ unsigned int enabled : 1;
+ unsigned int isPresent : 1;
+#else
+ ssl3CipherSuite cipher_suite;
+ PRUint8 policy;
+ unsigned char enabled : 1;
+ unsigned char isPresent : 1;
+#endif
+} ssl3CipherSuiteCfg;
+
+#ifdef NSS_ENABLE_ECC
+#define ssl_V3_SUITES_IMPLEMENTED 61
+#else
+#define ssl_V3_SUITES_IMPLEMENTED 37
+#endif /* NSS_ENABLE_ECC */
+
+#define MAX_DTLS_SRTP_CIPHER_SUITES 4
+
+typedef struct sslOptionsStr {
+ /* If SSL_SetNextProtoNego has been called, then this contains the
+ * list of supported protocols. */
+ SECItem nextProtoNego;
+
+ unsigned int useSecurity : 1; /* 1 */
+ unsigned int useSocks : 1; /* 2 */
+ unsigned int requestCertificate : 1; /* 3 */
+ unsigned int requireCertificate : 2; /* 4-5 */
+ unsigned int handshakeAsClient : 1; /* 6 */
+ unsigned int handshakeAsServer : 1; /* 7 */
+ unsigned int enableSSL2 : 1; /* 8 */
+ unsigned int unusedBit9 : 1; /* 9 */
+ unsigned int unusedBit10 : 1; /* 10 */
+ unsigned int noCache : 1; /* 11 */
+ unsigned int fdx : 1; /* 12 */
+ unsigned int v2CompatibleHello : 1; /* 13 */
+ unsigned int detectRollBack : 1; /* 14 */
+ unsigned int noStepDown : 1; /* 15 */
+ unsigned int bypassPKCS11 : 1; /* 16 */
+ unsigned int noLocks : 1; /* 17 */
+ unsigned int enableSessionTickets : 1; /* 18 */
+ unsigned int enableDeflate : 1; /* 19 */
+ unsigned int enableRenegotiation : 2; /* 20-21 */
+ unsigned int requireSafeNegotiation : 1; /* 22 */
+ unsigned int enableFalseStart : 1; /* 23 */
+ unsigned int cbcRandomIV : 1; /* 24 */
+ unsigned int enableOCSPStapling : 1; /* 25 */
+} sslOptions;
+
+typedef enum { sslHandshakingUndetermined = 0,
+ sslHandshakingAsClient,
+ sslHandshakingAsServer
+} sslHandshakingType;
+
+typedef struct sslServerCertsStr {
+ /* Configuration state for server sockets */
+ CERTCertificate * serverCert;
+ CERTCertificateList * serverCertChain;
+ ssl3KeyPair * serverKeyPair;
+ unsigned int serverKeyBits;
+} sslServerCerts;
+
+#define SERVERKEY serverKeyPair->privKey
+
+#define SSL_LOCK_RANK_SPEC 255
+#define SSL_LOCK_RANK_GLOBAL NSS_RWLOCK_RANK_NONE
+
+/* These are the valid values for shutdownHow.
+** These values are each 1 greater than the NSPR values, and the code
+** depends on that relation to efficiently convert PR_SHUTDOWN values
+** into ssl_SHUTDOWN values. These values use one bit for read, and
+** another bit for write, and can be used as bitmasks.
+*/
+#define ssl_SHUTDOWN_NONE 0 /* NOT shutdown at all */
+#define ssl_SHUTDOWN_RCV 1 /* PR_SHUTDOWN_RCV +1 */
+#define ssl_SHUTDOWN_SEND 2 /* PR_SHUTDOWN_SEND +1 */
+#define ssl_SHUTDOWN_BOTH 3 /* PR_SHUTDOWN_BOTH +1 */
+
+/*
+** A gather object. Used to read some data until a count has been
+** satisfied. Primarily for support of async sockets.
+** Everything in here is protected by the recvBufLock.
+*/
+struct sslGatherStr {
+ int state; /* see GS_ values below. */ /* ssl 2 & 3 */
+
+ /* "buf" holds received plaintext SSL records, after decrypt and MAC check.
+ * SSL2: recv'd ciphertext records are put here, then decrypted in place.
+ * SSL3: recv'd ciphertext records are put in inbuf (see below), then
+ * decrypted into buf.
+ */
+ sslBuffer buf; /*recvBufLock*/ /* ssl 2 & 3 */
+
+ /* number of bytes previously read into hdr or buf(ssl2) or inbuf (ssl3).
+ ** (offset - writeOffset) is the number of ciphertext bytes read in but
+ ** not yet deciphered.
+ */
+ unsigned int offset; /* ssl 2 & 3 */
+
+ /* number of bytes to read in next call to ssl_DefRecv (recv) */
+ unsigned int remainder; /* ssl 2 & 3 */
+
+ /* Number of ciphertext bytes to read in after 2-byte SSL record header. */
+ unsigned int count; /* ssl2 only */
+
+ /* size of the final plaintext record.
+ ** == count - (recordPadding + MAC size)
+ */
+ unsigned int recordLen; /* ssl2 only */
+
+ /* number of bytes of padding to be removed after decrypting. */
+ /* This value is taken from the record's hdr[2], which means a too large
+ * value could crash us.
+ */
+ unsigned int recordPadding; /* ssl2 only */
+
+ /* plaintext DATA begins this many bytes into "buf". */
+ unsigned int recordOffset; /* ssl2 only */
+
+ int encrypted; /* SSL2 session is now encrypted. ssl2 only */
+
+ /* These next two values are used by SSL2 and SSL3.
+ ** DoRecv uses them to extract application data.
+ ** The difference between writeOffset and readOffset is the amount of
+ ** data available to the application. Note that the actual offset of
+ ** the data in "buf" is recordOffset (above), not readOffset.
+ ** In the current implementation, this is made available before the
+ ** MAC is checked!!
+ */
+ unsigned int readOffset; /* Spot where DATA reader (e.g. application
+ ** or handshake code) will read next.
+ ** Always zero for SSl3 application data.
+ */
+ /* offset in buf/inbuf/hdr into which new data will be read from socket. */
+ unsigned int writeOffset;
+
+ /* Buffer for ssl3 to read (encrypted) data from the socket */
+ sslBuffer inbuf; /*recvBufLock*/ /* ssl3 only */
+
+ /* The ssl[23]_GatherData functions read data into this buffer, rather
+ ** than into buf or inbuf, while in the GS_HEADER state.
+ ** The portion of the SSL record header put here always comes off the wire
+ ** as plaintext, never ciphertext.
+ ** For SSL2, the plaintext portion is two bytes long. For SSl3 it is 5.
+ ** For DTLS it is 13.
+ */
+ unsigned char hdr[13]; /* ssl 2 & 3 or dtls */
+
+ /* Buffer for DTLS data read off the wire as a single datagram */
+ sslBuffer dtlsPacket;
+
+ /* the start of the buffered DTLS record in dtlsPacket */
+ unsigned int dtlsPacketOffset;
+};
+
+/* sslGather.state */
+#define GS_INIT 0
+#define GS_HEADER 1
+#define GS_MAC 2
+#define GS_DATA 3
+#define GS_PAD 4
+
+#if defined(NSS_PLATFORM_CLIENT_AUTH) && defined(XP_WIN32)
+typedef PCERT_KEY_CONTEXT PlatformKey;
+#elif defined(NSS_PLATFORM_CLIENT_AUTH) && defined(XP_MACOSX)
+typedef SecKeyRef PlatformKey;
+#else
+typedef void *PlatformKey;
+#endif
+
+
+
+/*
+** ssl3State and CipherSpec structs
+*/
+
+/* The SSL bulk cipher definition */
+typedef enum {
+ cipher_null,
+ cipher_rc4,
+ cipher_rc4_40,
+ cipher_rc4_56,
+ cipher_rc2,
+ cipher_rc2_40,
+ cipher_des,
+ cipher_3des,
+ cipher_des40,
+ cipher_idea,
+ cipher_aes_128,
+ cipher_aes_256,
+ cipher_camellia_128,
+ cipher_camellia_256,
+ cipher_seed,
+ cipher_aes_128_gcm,
+ cipher_missing /* reserved for no such supported cipher */
+ /* This enum must match ssl3_cipherName[] in ssl3con.c. */
+} SSL3BulkCipher;
+
+typedef enum { type_stream, type_block, type_aead } CipherType;
+
+#define MAX_IV_LENGTH 24
+
+/*
+ * Do not depend upon 64 bit arithmetic in the underlying machine.
+ */
+typedef struct {
+ PRUint32 high;
+ PRUint32 low;
+} SSL3SequenceNumber;
+
+typedef PRUint16 DTLSEpoch;
+
+typedef void (*DTLSTimerCb)(sslSocket *);
+
+#define MAX_MAC_CONTEXT_BYTES 400 /* 400 is large enough for MD5, SHA-1, and
+ * SHA-256. For SHA-384 support, increase
+ * it to 712. */
+#define MAX_MAC_CONTEXT_LLONGS (MAX_MAC_CONTEXT_BYTES / 8)
+
+#define MAX_CIPHER_CONTEXT_BYTES 2080
+#define MAX_CIPHER_CONTEXT_LLONGS (MAX_CIPHER_CONTEXT_BYTES / 8)
+
+typedef struct {
+ SSL3Opaque wrapped_master_secret[48];
+ PRUint16 wrapped_master_secret_len;
+ PRUint8 msIsWrapped;
+ PRUint8 resumable;
+} ssl3SidKeys; /* 52 bytes */
+
+typedef struct {
+ PK11SymKey *write_key;
+ PK11SymKey *write_mac_key;
+ PK11Context *write_mac_context;
+ SECItem write_key_item;
+ SECItem write_iv_item;
+ SECItem write_mac_key_item;
+ SSL3Opaque write_iv[MAX_IV_LENGTH];
+ PRUint64 cipher_context[MAX_CIPHER_CONTEXT_LLONGS];
+} ssl3KeyMaterial;
+
+typedef SECStatus (*SSLCipher)(void * context,
+ unsigned char * out,
+ int * outlen,
+ int maxout,
+ const unsigned char *in,
+ int inlen);
+typedef SECStatus (*SSLAEADCipher)(
+ ssl3KeyMaterial * keys,
+ PRBool doDecrypt,
+ unsigned char * out,
+ int * outlen,
+ int maxout,
+ const unsigned char *in,
+ int inlen,
+ SSL3ContentType type,
+ SSL3ProtocolVersion version,
+ SSL3SequenceNumber seqnum);
+typedef SECStatus (*SSLCompressor)(void * context,
+ unsigned char * out,
+ int * outlen,
+ int maxout,
+ const unsigned char *in,
+ int inlen);
+typedef SECStatus (*SSLDestroy)(void *context, PRBool freeit);
+
+/* The DTLS anti-replay window. Defined here because we need it in
+ * the cipher spec. Note that this is a ring buffer but left and
+ * right represent the true window, with modular arithmetic used to
+ * map them onto the buffer.
+ */
+#define DTLS_RECVD_RECORDS_WINDOW 1024 /* Packets; approximate
+ * Must be divisible by 8
+ */
+typedef struct DTLSRecvdRecordsStr {
+ unsigned char data[DTLS_RECVD_RECORDS_WINDOW/8];
+ PRUint64 left;
+ PRUint64 right;
+} DTLSRecvdRecords;
+
+/*
+** These are the "specs" in the "ssl3" struct.
+** Access to the pointers to these specs, and all the specs' contents
+** (direct and indirect) is protected by the reader/writer lock ss->specLock.
+*/
+typedef struct {
+ const ssl3BulkCipherDef *cipher_def;
+ const ssl3MACDef * mac_def;
+ SSLCompressionMethod compression_method;
+ int mac_size;
+ SSLCipher encode;
+ SSLCipher decode;
+ SSLAEADCipher aead;
+ SSLDestroy destroy;
+ void * encodeContext;
+ void * decodeContext;
+ SSLCompressor compressor; /* Don't name these fields compress */
+ SSLCompressor decompressor; /* and uncompress because zconf.h */
+ /* may define them as macros. */
+ SSLDestroy destroyCompressContext;
+ void * compressContext;
+ SSLDestroy destroyDecompressContext;
+ void * decompressContext;
+ PRBool bypassCiphers; /* did double bypass (at least) */
+ PK11SymKey * master_secret;
+ SSL3SequenceNumber write_seq_num;
+ SSL3SequenceNumber read_seq_num;
+ SSL3ProtocolVersion version;
+ ssl3KeyMaterial client;
+ ssl3KeyMaterial server;
+ SECItem msItem;
+ unsigned char key_block[NUM_MIXERS * MD5_LENGTH];
+ unsigned char raw_master_secret[56];
+ SECItem srvVirtName; /* for server: name that was negotiated
+ * with a client. For client - is
+ * always set to NULL.*/
+ DTLSEpoch epoch;
+ DTLSRecvdRecords recvdRecords;
+} ssl3CipherSpec;
+
+typedef enum { never_cached,
+ in_client_cache,
+ in_server_cache,
+ invalid_cache /* no longer in any cache. */
+} Cached;
+
+#define MAX_PEER_CERT_CHAIN_SIZE 8
+
+struct sslSessionIDStr {
+ sslSessionID * next; /* chain used for client sockets, only */
+
+ CERTCertificate * peerCert;
+ CERTCertificate * peerCertChain[MAX_PEER_CERT_CHAIN_SIZE];
+ SECItemArray peerCertStatus; /* client only */
+ const char * peerID; /* client only */
+ const char * urlSvrName; /* client only */
+ CERTCertificate * localCert;
+
+ PRIPv6Addr addr;
+ PRUint16 port;
+
+ SSL3ProtocolVersion version;
+
+ PRUint32 creationTime; /* seconds since Jan 1, 1970 */
+ PRUint32 lastAccessTime; /* seconds since Jan 1, 1970 */
+ PRUint32 expirationTime; /* seconds since Jan 1, 1970 */
+ Cached cached;
+ int references;
+
+ SSLSignType authAlgorithm;
+ PRUint32 authKeyBits;
+ SSLKEAType keaType;
+ PRUint32 keaKeyBits;
+
+ union {
+ struct {
+ /* the V2 code depends upon the size of sessionID. */
+ unsigned char sessionID[SSL2_SESSIONID_BYTES];
+
+ /* Stuff used to recreate key and read/write cipher objects */
+ SECItem masterKey; /* never wrapped */
+ int cipherType;
+ SECItem cipherArg;
+ int keyBits;
+ int secretKeyBits;
+ } ssl2;
+ struct {
+ /* values that are copied into the server's on-disk SID cache. */
+ PRUint8 sessionIDLength;
+ SSL3Opaque sessionID[SSL3_SESSIONID_BYTES];
+
+ ssl3CipherSuite cipherSuite;
+ SSLCompressionMethod compression;
+ int policy;
+ ssl3SidKeys keys;
+ CK_MECHANISM_TYPE masterWrapMech;
+ /* mechanism used to wrap master secret */
+ SSL3KEAType exchKeyType;
+ /* key type used in exchange algorithm,
+ * and to wrap the sym wrapping key. */
+#ifdef NSS_ENABLE_ECC
+ PRUint32 negotiatedECCurves;
+#endif /* NSS_ENABLE_ECC */
+
+ /* The following values are NOT restored from the server's on-disk
+ * session cache, but are restored from the client's cache.
+ */
+ PK11SymKey * clientWriteKey;
+ PK11SymKey * serverWriteKey;
+
+ /* The following values pertain to the slot that wrapped the
+ ** master secret. (used only in client)
+ */
+ SECMODModuleID masterModuleID;
+ /* what module wrapped the master secret */
+ CK_SLOT_ID masterSlotID;
+ PRUint16 masterWrapIndex;
+ /* what's the key index for the wrapping key */
+ PRUint16 masterWrapSeries;
+ /* keep track of the slot series, so we don't
+ * accidently try to use new keys after the
+ * card gets removed and replaced.*/
+
+ /* The following values pertain to the slot that did the signature
+ ** for client auth. (used only in client)
+ */
+ SECMODModuleID clAuthModuleID;
+ CK_SLOT_ID clAuthSlotID;
+ PRUint16 clAuthSeries;
+
+ char masterValid;
+ char clAuthValid;
+
+ /* Session ticket if we have one, is sent as an extension in the
+ * ClientHello message. This field is used by clients.
+ */
+ NewSessionTicket sessionTicket;
+ SECItem srvName;
+ } ssl3;
+ } u;
+};
+
+
+typedef struct ssl3CipherSuiteDefStr {
+ ssl3CipherSuite cipher_suite;
+ SSL3BulkCipher bulk_cipher_alg;
+ SSL3MACAlgorithm mac_alg;
+ SSL3KeyExchangeAlgorithm key_exchange_alg;
+} ssl3CipherSuiteDef;
+
+/*
+** There are tables of these, all const.
+*/
+typedef struct {
+ SSL3KeyExchangeAlgorithm kea;
+ SSL3KEAType exchKeyType;
+ SSL3SignType signKeyType;
+ PRBool is_limited;
+ int key_size_limit;
+ PRBool tls_keygen;
+} ssl3KEADef;
+
+/*
+** There are tables of these, all const.
+*/
+struct ssl3BulkCipherDefStr {
+ SSL3BulkCipher cipher;
+ SSLCipherAlgorithm calg;
+ int key_size;
+ int secret_key_size;
+ CipherType type;
+ int iv_size;
+ int block_size;
+ int tag_size; /* authentication tag size for AEAD ciphers. */
+ int explicit_nonce_size; /* for AEAD ciphers. */
+};
+
+/*
+** There are tables of these, all const.
+*/
+struct ssl3MACDefStr {
+ SSL3MACAlgorithm mac;
+ CK_MECHANISM_TYPE mmech;
+ int pad_size;
+ int mac_size;
+};
+
+typedef enum {
+ wait_client_hello,
+ wait_client_cert,
+ wait_client_key,
+ wait_cert_verify,
+ wait_change_cipher,
+ wait_finished,
+ wait_server_hello,
+ wait_certificate_status,
+ wait_server_cert,
+ wait_server_key,
+ wait_cert_request,
+ wait_hello_done,
+ wait_new_session_ticket,
+ idle_handshake
+} SSL3WaitState;
+
+/*
+ * TLS extension related constants and data structures.
+ */
+typedef struct TLSExtensionDataStr TLSExtensionData;
+typedef struct SessionTicketDataStr SessionTicketData;
+
+struct TLSExtensionDataStr {
+ /* registered callbacks that send server hello extensions */
+ ssl3HelloExtensionSender serverSenders[SSL_MAX_EXTENSIONS];
+ /* Keep track of the extensions that are negotiated. */
+ PRUint16 numAdvertised;
+ PRUint16 numNegotiated;
+ PRUint16 advertised[SSL_MAX_EXTENSIONS];
+ PRUint16 negotiated[SSL_MAX_EXTENSIONS];
+
+ /* SessionTicket Extension related data. */
+ PRBool ticketTimestampVerified;
+ PRBool emptySessionTicket;
+
+ /* SNI Extension related data
+ * Names data is not coppied from the input buffer. It can not be
+ * used outside the scope where input buffer is defined and that
+ * is beyond ssl3_HandleClientHello function. */
+ SECItem *sniNameArr;
+ PRUint32 sniNameArrSize;
+};
+
+typedef SECStatus (*sslRestartTarget)(sslSocket *);
+
+/*
+** A DTLS queued message (potentially to be retransmitted)
+*/
+typedef struct DTLSQueuedMessageStr {
+ PRCList link; /* The linked list link */
+ DTLSEpoch epoch; /* The epoch to use */
+ SSL3ContentType type; /* The message type */
+ unsigned char *data; /* The data */
+ PRUint16 len; /* The data length */
+} DTLSQueuedMessage;
+
+typedef enum {
+ handshake_hash_unknown = 0,
+ handshake_hash_combo = 1, /* The MD5/SHA-1 combination */
+ handshake_hash_single = 2 /* A single hash */
+} SSL3HandshakeHashType;
+
+/*
+** This is the "hs" member of the "ssl3" struct.
+** This entire struct is protected by ssl3HandshakeLock
+*/
+typedef struct SSL3HandshakeStateStr {
+ SSL3Random server_random;
+ SSL3Random client_random;
+ SSL3WaitState ws;
+
+ /* This group of members is used for handshake running hashes. */
+ SSL3HandshakeHashType hashType;
+ sslBuffer messages; /* Accumulated handshake messages */
+#ifndef NO_PKCS11_BYPASS
+ /* Bypass mode:
+ * SSL 3.0 - TLS 1.1 use both |md5_cx| and |sha_cx|. |md5_cx| is used for
+ * MD5 and |sha_cx| for SHA-1.
+ * TLS 1.2 and later use only |sha_cx|, for SHA-256. NOTE: When we support
+ * SHA-384, increase MAX_MAC_CONTEXT_BYTES to 712. */
+ PRUint64 md5_cx[MAX_MAC_CONTEXT_LLONGS];
+ PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS];
+ const SECHashObject * sha_obj;
+ /* The function prototype of sha_obj->clone() does not match the prototype
+ * of the freebl <HASH>_Clone functions, so we need a dedicated function
+ * pointer for the <HASH>_Clone function. */
+ void (*sha_clone)(void *dest, void *src);
+#endif
+ /* PKCS #11 mode:
+ * SSL 3.0 - TLS 1.1 use both |md5| and |sha|. |md5| is used for MD5 and
+ * |sha| for SHA-1.
+ * TLS 1.2 and later use only |sha|, for SHA-256. */
+ PK11Context * md5;
+ PK11Context * sha;
+
+const ssl3KEADef * kea_def;
+ ssl3CipherSuite cipher_suite;
+const ssl3CipherSuiteDef *suite_def;
+ SSLCompressionMethod compression;
+ sslBuffer msg_body; /* protected by recvBufLock */
+ /* partial handshake message from record layer */
+ unsigned int header_bytes;
+ /* number of bytes consumed from handshake */
+ /* message for message type and header length */
+ SSL3HandshakeType msg_type;
+ unsigned long msg_len;
+ SECItem ca_list; /* used only by client */
+ PRBool isResuming; /* are we resuming a session */
+ PRBool usedStepDownKey; /* we did a server key exchange. */
+ PRBool sendingSCSV; /* instead of empty RI */
+ sslBuffer msgState; /* current state for handshake messages*/
+ /* protected by recvBufLock */
+ PRUint16 finishedBytes; /* size of single finished below */
+ union {
+ TLSFinished tFinished[2]; /* client, then server */
+ SSL3Finished sFinished[2];
+ SSL3Opaque data[72];
+ } finishedMsgs;
+#ifdef NSS_ENABLE_ECC
+ PRUint32 negotiatedECCurves; /* bit mask */
+#endif /* NSS_ENABLE_ECC */
+
+ PRBool authCertificatePending;
+ /* Which function should SSL_RestartHandshake* call if we're blocked?
+ * One of NULL, ssl3_SendClientSecondRound, ssl3_FinishHandshake,
+ * or ssl3_AlwaysFail */
+ sslRestartTarget restartTarget;
+ /* Shared state between ssl3_HandleFinished and ssl3_FinishHandshake */
+ PRBool cacheSID;
+
+ /* clientSigAndHash contains the contents of the signature_algorithms
+ * extension (if any) from the client. This is only valid for TLS 1.2
+ * or later. */
+ SSL3SignatureAndHashAlgorithm *clientSigAndHash;
+ unsigned int numClientSigAndHash;
+
+ /* This group of values is used for DTLS */
+ PRUint16 sendMessageSeq; /* The sending message sequence
+ * number */
+ PRCList lastMessageFlight; /* The last message flight we
+ * sent */
+ PRUint16 maxMessageSent; /* The largest message we sent */
+ PRUint16 recvMessageSeq; /* The receiving message sequence
+ * number */
+ sslBuffer recvdFragments; /* The fragments we have received in
+ * a bitmask */
+ PRInt32 recvdHighWater; /* The high water mark for fragments
+ * received. -1 means no reassembly
+ * in progress. */
+ unsigned char cookie[32]; /* The cookie */
+ unsigned char cookieLen; /* The length of the cookie */
+ PRIntervalTime rtTimerStarted; /* When the timer was started */
+ DTLSTimerCb rtTimerCb; /* The function to call on expiry */
+ PRUint32 rtTimeoutMs; /* The length of the current timeout
+ * used for backoff (in ms) */
+ PRUint32 rtRetries; /* The retry counter */
+} SSL3HandshakeState;
+
+
+
+/*
+** This is the "ssl3" struct, as in "ss->ssl3".
+** note:
+** usually, crSpec == cwSpec and prSpec == pwSpec.
+** Sometimes, crSpec == pwSpec and prSpec == cwSpec.
+** But there are never more than 2 actual specs.
+** No spec must ever be modified if either "current" pointer points to it.
+*/
+struct ssl3StateStr {
+
+ /*
+ ** The following Specs and Spec pointers must be protected using the
+ ** Spec Lock.
+ */
+ ssl3CipherSpec * crSpec; /* current read spec. */
+ ssl3CipherSpec * prSpec; /* pending read spec. */
+ ssl3CipherSpec * cwSpec; /* current write spec. */
+ ssl3CipherSpec * pwSpec; /* pending write spec. */
+
+ CERTCertificate * clientCertificate; /* used by client */
+ SECKEYPrivateKey * clientPrivateKey; /* used by client */
+ /* platformClientKey is present even when NSS_PLATFORM_CLIENT_AUTH is not
+ * defined in order to allow cleaner conditional code.
+ * At most one of clientPrivateKey and platformClientKey may be set. */
+ PlatformKey platformClientKey; /* used by client */
+ CERTCertificateList *clientCertChain; /* used by client */
+ PRBool sendEmptyCert; /* used by client */
+
+ SECKEYPrivateKey *channelID; /* used by client */
+ SECKEYPublicKey *channelIDPub; /* used by client */
+
+ int policy;
+ /* This says what cipher suites we can do, and should
+ * be either SSL_ALLOWED or SSL_RESTRICTED
+ */
+ PLArenaPool * peerCertArena;
+ /* These are used to keep track of the peer CA */
+ void * peerCertChain;
+ /* chain while we are trying to validate it. */
+ CERTDistNames * ca_list;
+ /* used by server. trusted CAs for this socket. */
+ PRBool initialized;
+ SSL3HandshakeState hs;
+ ssl3CipherSpec specs[2]; /* one is current, one is pending. */
+
+ /* In a client: if the server supports Next Protocol Negotiation, then
+ * this is the protocol that was negotiated.
+ */
+ SECItem nextProto;
+ SSLNextProtoState nextProtoState;
+
+ PRUint16 mtu; /* Our estimate of the MTU */
+
+ /* DTLS-SRTP cipher suite preferences (if any) */
+ PRUint16 dtlsSRTPCiphers[MAX_DTLS_SRTP_CIPHER_SUITES];
+ PRUint16 dtlsSRTPCipherCount;
+ PRUint16 dtlsSRTPCipherSuite; /* 0 if not selected */
+};
+
+#define DTLS_MAX_MTU 1500 /* Ethernet MTU but without subtracting the
+ * headers, so slightly larger than expected */
+#define IS_DTLS(ss) (ss->protocolVariant == ssl_variant_datagram)
+
+typedef struct {
+ SSL3ContentType type;
+ SSL3ProtocolVersion version;
+ SSL3SequenceNumber seq_num; /* DTLS only */
+ sslBuffer * buf;
+} SSL3Ciphertext;
+
+struct ssl3KeyPairStr {
+ SECKEYPrivateKey * privKey;
+ SECKEYPublicKey * pubKey;
+ PRInt32 refCount; /* use PR_Atomic calls for this. */
+};
+
+typedef struct SSLWrappedSymWrappingKeyStr {
+ SSL3Opaque wrappedSymmetricWrappingkey[512];
+ CK_MECHANISM_TYPE symWrapMechanism;
+ /* unwrapped symmetric wrapping key uses this mechanism */
+ CK_MECHANISM_TYPE asymWrapMechanism;
+ /* mechanism used to wrap the SymmetricWrappingKey using
+ * server's public and/or private keys. */
+ SSL3KEAType exchKeyType; /* type of keys used to wrap SymWrapKey*/
+ PRInt32 symWrapMechIndex;
+ PRUint16 wrappedSymKeyLen;
+} SSLWrappedSymWrappingKey;
+
+typedef struct SessionTicketStr {
+ PRUint16 ticket_version;
+ SSL3ProtocolVersion ssl_version;
+ ssl3CipherSuite cipher_suite;
+ SSLCompressionMethod compression_method;
+ SSLSignType authAlgorithm;
+ PRUint32 authKeyBits;
+ SSLKEAType keaType;
+ PRUint32 keaKeyBits;
+ /*
+ * exchKeyType and msWrapMech contain meaningful values only if
+ * ms_is_wrapped is true.
+ */
+ PRUint8 ms_is_wrapped;
+ SSLKEAType exchKeyType; /* XXX(wtc): same as keaType above? */
+ CK_MECHANISM_TYPE msWrapMech;
+ PRUint16 ms_length;
+ SSL3Opaque master_secret[48];
+ ClientIdentity client_identity;
+ SECItem peer_cert;
+ PRUint32 timestamp;
+ SECItem srvName; /* negotiated server name */
+} SessionTicket;
+
+/*
+ * SSL2 buffers used in SSL3.
+ * writeBuf in the SecurityInfo maintained by sslsecur.c is used
+ * to hold the data just about to be passed to the kernel
+ * sendBuf in the ConnectInfo maintained by sslcon.c is used
+ * to hold handshake messages as they are accumulated
+ */
+
+/*
+** This is "ci", as in "ss->sec.ci".
+**
+** Protection: All the variables in here are protected by
+** firstHandshakeLock AND (in ssl3) ssl3HandshakeLock
+*/
+struct sslConnectInfoStr {
+ /* outgoing handshakes appended to this. */
+ sslBuffer sendBuf; /*xmitBufLock*/ /* ssl 2 & 3 */
+
+ PRIPv6Addr peer; /* ssl 2 & 3 */
+ unsigned short port; /* ssl 2 & 3 */
+
+ sslSessionID *sid; /* ssl 2 & 3 */
+
+ /* see CIS_HAVE defines below for the bit values in *elements. */
+ char elements; /* ssl2 only */
+ char requiredElements; /* ssl2 only */
+ char sentElements; /* ssl2 only */
+
+ char sentFinished; /* ssl2 only */
+
+ /* Length of server challenge. Used by client when saving challenge */
+ int serverChallengeLen; /* ssl2 only */
+ /* type of authentication requested by server */
+ unsigned char authType; /* ssl2 only */
+
+ /* Challenge sent by client to server in client-hello message */
+ /* SSL3 gets a copy of this. See ssl3_StartHandshakeHash(). */
+ unsigned char clientChallenge[SSL_MAX_CHALLENGE_BYTES]; /* ssl 2 & 3 */
+
+ /* Connection-id sent by server to client in server-hello message */
+ unsigned char connectionID[SSL_CONNECTIONID_BYTES]; /* ssl2 only */
+
+ /* Challenge sent by server to client in request-certificate message */
+ unsigned char serverChallenge[SSL_MAX_CHALLENGE_BYTES]; /* ssl2 only */
+
+ /* Information kept to handle a request-certificate message */
+ unsigned char readKey[SSL_MAX_MASTER_KEY_BYTES]; /* ssl2 only */
+ unsigned char writeKey[SSL_MAX_MASTER_KEY_BYTES]; /* ssl2 only */
+ unsigned keySize; /* ssl2 only */
+};
+
+/* bit values for ci->elements, ci->requiredElements, sentElements. */
+#define CIS_HAVE_MASTER_KEY 0x01
+#define CIS_HAVE_CERTIFICATE 0x02
+#define CIS_HAVE_FINISHED 0x04
+#define CIS_HAVE_VERIFY 0x08
+
+/* Note: The entire content of this struct and whatever it points to gets
+ * blown away by SSL_ResetHandshake(). This is "sec" as in "ss->sec".
+ *
+ * Unless otherwise specified below, the contents of this struct are
+ * protected by firstHandshakeLock AND (in ssl3) ssl3HandshakeLock.
+ */
+struct sslSecurityInfoStr {
+ sslSendFunc send; /*xmitBufLock*/ /* ssl 2 & 3 */
+ int isServer; /* Spec Lock?*/ /* ssl 2 & 3 */
+ sslBuffer writeBuf; /*xmitBufLock*/ /* ssl 2 & 3 */
+
+ int cipherType; /* ssl 2 & 3 */
+ int keyBits; /* ssl 2 & 3 */
+ int secretKeyBits; /* ssl 2 & 3 */
+ CERTCertificate *localCert; /* ssl 2 & 3 */
+ CERTCertificate *peerCert; /* ssl 2 & 3 */
+ SECKEYPublicKey *peerKey; /* ssl3 only */
+
+ SSLSignType authAlgorithm;
+ PRUint32 authKeyBits;
+ SSLKEAType keaType;
+ PRUint32 keaKeyBits;
+
+ /*
+ ** Procs used for SID cache (nonce) management.
+ ** Different implementations exist for clients/servers
+ ** The lookup proc is only used for servers. Baloney!
+ */
+ sslSessionIDCacheFunc cache; /* ssl 2 & 3 */
+ sslSessionIDUncacheFunc uncache; /* ssl 2 & 3 */
+
+ /*
+ ** everything below here is for ssl2 only.
+ ** This stuff is equivalent to SSL3's "spec", and is protected by the
+ ** same "Spec Lock" as used for SSL3's specs.
+ */
+ PRUint32 sendSequence; /*xmitBufLock*/ /* ssl2 only */
+ PRUint32 rcvSequence; /*recvBufLock*/ /* ssl2 only */
+
+ /* Hash information; used for one-way-hash functions (MD2, MD5, etc.) */
+ const SECHashObject *hash; /* Spec Lock */ /* ssl2 only */
+ void *hashcx; /* Spec Lock */ /* ssl2 only */
+
+ SECItem sendSecret; /* Spec Lock */ /* ssl2 only */
+ SECItem rcvSecret; /* Spec Lock */ /* ssl2 only */
+
+ /* Session cypher contexts; one for each direction */
+ void *readcx; /* Spec Lock */ /* ssl2 only */
+ void *writecx; /* Spec Lock */ /* ssl2 only */
+ SSLCipher enc; /* Spec Lock */ /* ssl2 only */
+ SSLCipher dec; /* Spec Lock */ /* ssl2 only */
+ void (*destroy)(void *, PRBool); /* Spec Lock */ /* ssl2 only */
+
+ /* Blocking information for the session cypher */
+ int blockShift; /* Spec Lock */ /* ssl2 only */
+ int blockSize; /* Spec Lock */ /* ssl2 only */
+
+ /* These are used during a connection handshake */
+ sslConnectInfo ci; /* ssl 2 & 3 */
+
+};
+
+/*
+** SSL Socket struct
+**
+** Protection: XXX
+*/
+struct sslSocketStr {
+ PRFileDesc * fd;
+
+ /* Pointer to operations vector for this socket */
+ const sslSocketOps * ops;
+
+ /* SSL socket options */
+ sslOptions opt;
+ /* Enabled version range */
+ SSLVersionRange vrange;
+
+ /* State flags */
+ unsigned long clientAuthRequested;
+ unsigned long delayDisabled; /* Nagle delay disabled */
+ unsigned long firstHsDone; /* first handshake is complete. */
+ unsigned long handshakeBegun;
+ unsigned long lastWriteBlocked;
+ unsigned long recvdCloseNotify; /* received SSL EOF. */
+ unsigned long TCPconnected;
+ unsigned long appDataBuffered;
+ unsigned long peerRequestedProtection; /* from old renegotiation */
+
+ /* version of the protocol to use */
+ SSL3ProtocolVersion version;
+ SSL3ProtocolVersion clientHelloVersion; /* version sent in client hello. */
+
+ sslSecurityInfo sec; /* not a pointer any more */
+
+ /* protected by firstHandshakeLock AND (in ssl3) ssl3HandshakeLock. */
+ const char *url; /* ssl 2 & 3 */
+
+ sslHandshakeFunc handshake; /*firstHandshakeLock*/
+ sslHandshakeFunc nextHandshake; /*firstHandshakeLock*/
+ sslHandshakeFunc securityHandshake; /*firstHandshakeLock*/
+
+ /* the following variable is only used with socks or other proxies. */
+ char * peerID; /* String uniquely identifies target server. */
+
+ unsigned char * cipherSpecs;
+ unsigned int sizeCipherSpecs;
+const unsigned char * preferredCipher;
+
+ /* TLS ClientCertificateTypes requested during HandleCertificateRequest. */
+ /* Will be NULL at all other times. */
+ const SECItem *requestedCertTypes;
+
+ ssl3KeyPair * stepDownKeyPair; /* RSA step down keys */
+
+ /* Callbacks */
+ SSLAuthCertificate authCertificate;
+ void *authCertificateArg;
+ SSLGetClientAuthData getClientAuthData;
+ void *getClientAuthDataArg;
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ SSLGetPlatformClientAuthData getPlatformClientAuthData;
+ void *getPlatformClientAuthDataArg;
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
+ SSLSNISocketConfig sniSocketConfig;
+ void *sniSocketConfigArg;
+ SSLBadCertHandler handleBadCert;
+ void *badCertArg;
+ SSLHandshakeCallback handshakeCallback;
+ void *handshakeCallbackData;
+ void *pkcs11PinArg;
+ SSLNextProtoCallback nextProtoCallback;
+ void *nextProtoArg;
+ SSLClientChannelIDCallback getChannelID;
+ void *getChannelIDArg;
+
+ PRIntervalTime rTimeout; /* timeout for NSPR I/O */
+ PRIntervalTime wTimeout; /* timeout for NSPR I/O */
+ PRIntervalTime cTimeout; /* timeout for NSPR I/O */
+
+ PZLock * recvLock; /* lock against multiple reader threads. */
+ PZLock * sendLock; /* lock against multiple sender threads. */
+
+ PZMonitor * recvBufLock; /* locks low level recv buffers. */
+ PZMonitor * xmitBufLock; /* locks low level xmit buffers. */
+
+ /* Only one thread may operate on the socket until the initial handshake
+ ** is complete. This Monitor ensures that. Since SSL2 handshake is
+ ** only done once, this is also effectively the SSL2 handshake lock.
+ */
+ PZMonitor * firstHandshakeLock;
+
+ /* This monitor protects the ssl3 handshake state machine data.
+ ** Only one thread (reader or writer) may be in the ssl3 handshake state
+ ** machine at any time. */
+ PZMonitor * ssl3HandshakeLock;
+
+ /* reader/writer lock, protects the secret data needed to encrypt and MAC
+ ** outgoing records, and to decrypt and MAC check incoming ciphertext
+ ** records. */
+ NSSRWLock * specLock;
+
+ /* handle to perm cert db (and implicitly to the temp cert db) used
+ ** with this socket.
+ */
+ CERTCertDBHandle * dbHandle;
+
+ PRThread * writerThread; /* thread holds SSL_LOCK_WRITER lock */
+
+ PRUint16 shutdownHow; /* See ssl_SHUTDOWN defines below. */
+
+ PRUint16 allowedByPolicy; /* copy of global policy bits. */
+ PRUint16 maybeAllowedByPolicy; /* copy of global policy bits. */
+ PRUint16 chosenPreference; /* SSL2 cipher preferences. */
+
+ sslHandshakingType handshaking;
+
+ /* Gather object used for gathering data */
+ sslGather gs; /*recvBufLock*/
+
+ sslBuffer saveBuf; /*xmitBufLock*/
+ sslBuffer pendingBuf; /*xmitBufLock*/
+
+ /* Configuration state for server sockets */
+ /* server cert and key for each KEA type */
+ sslServerCerts serverCerts[kt_kea_size];
+ /* each cert needs its own status */
+ SECItemArray * certStatusArray[kt_kea_size];
+
+ ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED];
+ ssl3KeyPair * ephemeralECDHKeyPair; /* for ECDHE-* handshake */
+
+ /* SSL3 state info. Formerly was a pointer */
+ ssl3State ssl3;
+
+ /*
+ * TLS extension related data.
+ */
+ /* True when the current session is a stateless resume. */
+ PRBool statelessResume;
+ TLSExtensionData xtnData;
+
+ /* Whether we are doing stream or datagram mode */
+ SSLProtocolVariant protocolVariant;
+};
+
+
+
+/* All the global data items declared here should be protected using the
+** ssl_global_data_lock, which is a reader/writer lock.
+*/
+extern NSSRWLock * ssl_global_data_lock;
+extern char ssl_debug;
+extern char ssl_trace;
+extern FILE * ssl_trace_iob;
+extern FILE * ssl_keylog_iob;
+extern CERTDistNames * ssl3_server_ca_list;
+extern PRUint32 ssl_sid_timeout;
+extern PRUint32 ssl3_sid_timeout;
+
+extern const char * const ssl_cipherName[];
+extern const char * const ssl3_cipherName[];
+
+extern sslSessionIDLookupFunc ssl_sid_lookup;
+extern sslSessionIDCacheFunc ssl_sid_cache;
+extern sslSessionIDUncacheFunc ssl_sid_uncache;
+
+/************************************************************************/
+
+SEC_BEGIN_PROTOS
+
+/* Functions for handling SECItemArrays, added in NSS 3.15 */
+extern SECItemArray *SECITEM_AllocArray(PLArenaPool *arena,
+ SECItemArray *array,
+ unsigned int len);
+extern SECItemArray *SECITEM_DupArray(PLArenaPool *arena,
+ const SECItemArray *from);
+extern void SECITEM_FreeArray(SECItemArray *array, PRBool freeit);
+extern void SECITEM_ZfreeArray(SECItemArray *array, PRBool freeit);
+
+/* Internal initialization and installation of the SSL error tables */
+extern SECStatus ssl_Init(void);
+extern SECStatus ssl_InitializePRErrorTable(void);
+
+/* Implementation of ops for default (non socks, non secure) case */
+extern int ssl_DefConnect(sslSocket *ss, const PRNetAddr *addr);
+extern PRFileDesc *ssl_DefAccept(sslSocket *ss, PRNetAddr *addr);
+extern int ssl_DefBind(sslSocket *ss, const PRNetAddr *addr);
+extern int ssl_DefListen(sslSocket *ss, int backlog);
+extern int ssl_DefShutdown(sslSocket *ss, int how);
+extern int ssl_DefClose(sslSocket *ss);
+extern int ssl_DefRecv(sslSocket *ss, unsigned char *buf, int len, int flags);
+extern int ssl_DefSend(sslSocket *ss, const unsigned char *buf,
+ int len, int flags);
+extern int ssl_DefRead(sslSocket *ss, unsigned char *buf, int len);
+extern int ssl_DefWrite(sslSocket *ss, const unsigned char *buf, int len);
+extern int ssl_DefGetpeername(sslSocket *ss, PRNetAddr *name);
+extern int ssl_DefGetsockname(sslSocket *ss, PRNetAddr *name);
+extern int ssl_DefGetsockopt(sslSocket *ss, PRSockOption optname,
+ void *optval, PRInt32 *optlen);
+extern int ssl_DefSetsockopt(sslSocket *ss, PRSockOption optname,
+ const void *optval, PRInt32 optlen);
+
+/* Implementation of ops for socks only case */
+extern int ssl_SocksConnect(sslSocket *ss, const PRNetAddr *addr);
+extern PRFileDesc *ssl_SocksAccept(sslSocket *ss, PRNetAddr *addr);
+extern int ssl_SocksBind(sslSocket *ss, const PRNetAddr *addr);
+extern int ssl_SocksListen(sslSocket *ss, int backlog);
+extern int ssl_SocksGetsockname(sslSocket *ss, PRNetAddr *name);
+extern int ssl_SocksRecv(sslSocket *ss, unsigned char *buf, int len, int flags);
+extern int ssl_SocksSend(sslSocket *ss, const unsigned char *buf,
+ int len, int flags);
+extern int ssl_SocksRead(sslSocket *ss, unsigned char *buf, int len);
+extern int ssl_SocksWrite(sslSocket *ss, const unsigned char *buf, int len);
+
+/* Implementation of ops for secure only case */
+extern int ssl_SecureConnect(sslSocket *ss, const PRNetAddr *addr);
+extern PRFileDesc *ssl_SecureAccept(sslSocket *ss, PRNetAddr *addr);
+extern int ssl_SecureRecv(sslSocket *ss, unsigned char *buf,
+ int len, int flags);
+extern int ssl_SecureSend(sslSocket *ss, const unsigned char *buf,
+ int len, int flags);
+extern int ssl_SecureRead(sslSocket *ss, unsigned char *buf, int len);
+extern int ssl_SecureWrite(sslSocket *ss, const unsigned char *buf, int len);
+extern int ssl_SecureShutdown(sslSocket *ss, int how);
+extern int ssl_SecureClose(sslSocket *ss);
+
+/* Implementation of ops for secure socks case */
+extern int ssl_SecureSocksConnect(sslSocket *ss, const PRNetAddr *addr);
+extern PRFileDesc *ssl_SecureSocksAccept(sslSocket *ss, PRNetAddr *addr);
+extern PRFileDesc *ssl_FindTop(sslSocket *ss);
+
+/* Gather funcs. */
+extern sslGather * ssl_NewGather(void);
+extern SECStatus ssl_InitGather(sslGather *gs);
+extern void ssl_DestroyGather(sslGather *gs);
+extern int ssl2_GatherData(sslSocket *ss, sslGather *gs, int flags);
+extern int ssl2_GatherRecord(sslSocket *ss, int flags);
+extern SECStatus ssl_GatherRecord1stHandshake(sslSocket *ss);
+
+extern SECStatus ssl2_HandleClientHelloMessage(sslSocket *ss);
+extern SECStatus ssl2_HandleServerHelloMessage(sslSocket *ss);
+extern int ssl2_StartGatherBytes(sslSocket *ss, sslGather *gs,
+ unsigned int count);
+
+extern SECStatus ssl_CreateSecurityInfo(sslSocket *ss);
+extern SECStatus ssl_CopySecurityInfo(sslSocket *ss, sslSocket *os);
+extern void ssl_ResetSecurityInfo(sslSecurityInfo *sec, PRBool doMemset);
+extern void ssl_DestroySecurityInfo(sslSecurityInfo *sec);
+
+extern void ssl_PrintBuf(sslSocket *ss, const char *msg, const void *cp, int len);
+extern void ssl_DumpMsg(sslSocket *ss, unsigned char *bp, unsigned len);
+
+extern int ssl_SendSavedWriteData(sslSocket *ss);
+extern SECStatus ssl_SaveWriteData(sslSocket *ss,
+ const void* p, unsigned int l);
+extern SECStatus ssl2_BeginClientHandshake(sslSocket *ss);
+extern SECStatus ssl2_BeginServerHandshake(sslSocket *ss);
+extern int ssl_Do1stHandshake(sslSocket *ss);
+
+extern SECStatus sslBuffer_Grow(sslBuffer *b, unsigned int newLen);
+extern SECStatus sslBuffer_Append(sslBuffer *b, const void * data,
+ unsigned int len);
+
+extern void ssl2_UseClearSendFunc(sslSocket *ss);
+extern void ssl_ChooseSessionIDProcs(sslSecurityInfo *sec);
+
+extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server);
+extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port,
+ const char *peerID, const char *urlSvrName);
+extern void ssl_FreeSID(sslSessionID *sid);
+
+extern int ssl3_SendApplicationData(sslSocket *ss, const PRUint8 *in,
+ int len, int flags);
+
+extern PRBool ssl_FdIsBlocking(PRFileDesc *fd);
+
+extern PRBool ssl_SocketIsBlocking(sslSocket *ss);
+
+extern void ssl3_SetAlwaysBlock(sslSocket *ss);
+
+extern SECStatus ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled);
+
+extern PRBool ssl3_CanFalseStart(sslSocket *ss);
+extern SECStatus
+ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec,
+ PRBool isServer,
+ PRBool isDTLS,
+ PRBool capRecordVersion,
+ SSL3ContentType type,
+ const SSL3Opaque * pIn,
+ PRUint32 contentLen,
+ sslBuffer * wrBuf);
+extern PRInt32 ssl3_SendRecord(sslSocket *ss, DTLSEpoch epoch,
+ SSL3ContentType type,
+ const SSL3Opaque* pIn, PRInt32 nIn,
+ PRInt32 flags);
+
+#ifdef NSS_ENABLE_ZLIB
+/*
+ * The DEFLATE algorithm can result in an expansion of 0.1% + 12 bytes. For a
+ * maximum TLS record payload of 2**14 bytes, that's 29 bytes.
+ */
+#define SSL3_COMPRESSION_MAX_EXPANSION 29
+#else /* !NSS_ENABLE_ZLIB */
+#define SSL3_COMPRESSION_MAX_EXPANSION 0
+#endif
+
+/*
+ * make sure there is room in the write buffer for padding and
+ * other compression and cryptographic expansions.
+ */
+#define SSL3_BUFFER_FUDGE 100 + SSL3_COMPRESSION_MAX_EXPANSION
+
+#define SSL_LOCK_READER(ss) if (ss->recvLock) PZ_Lock(ss->recvLock)
+#define SSL_UNLOCK_READER(ss) if (ss->recvLock) PZ_Unlock(ss->recvLock)
+#define SSL_LOCK_WRITER(ss) if (ss->sendLock) PZ_Lock(ss->sendLock)
+#define SSL_UNLOCK_WRITER(ss) if (ss->sendLock) PZ_Unlock(ss->sendLock)
+
+/* firstHandshakeLock -> recvBufLock */
+#define ssl_Get1stHandshakeLock(ss) \
+ { if (!ss->opt.noLocks) { \
+ PORT_Assert(PZ_InMonitor((ss)->firstHandshakeLock) || \
+ !ssl_HaveRecvBufLock(ss)); \
+ PZ_EnterMonitor((ss)->firstHandshakeLock); \
+ } }
+#define ssl_Release1stHandshakeLock(ss) \
+ { if (!ss->opt.noLocks) PZ_ExitMonitor((ss)->firstHandshakeLock); }
+#define ssl_Have1stHandshakeLock(ss) \
+ (PZ_InMonitor((ss)->firstHandshakeLock))
+
+/* ssl3HandshakeLock -> xmitBufLock */
+#define ssl_GetSSL3HandshakeLock(ss) \
+ { if (!ss->opt.noLocks) { \
+ PORT_Assert(!ssl_HaveXmitBufLock(ss)); \
+ PZ_EnterMonitor((ss)->ssl3HandshakeLock); \
+ } }
+#define ssl_ReleaseSSL3HandshakeLock(ss) \
+ { if (!ss->opt.noLocks) PZ_ExitMonitor((ss)->ssl3HandshakeLock); }
+#define ssl_HaveSSL3HandshakeLock(ss) \
+ (PZ_InMonitor((ss)->ssl3HandshakeLock))
+
+#define ssl_GetSpecReadLock(ss) \
+ { if (!ss->opt.noLocks) NSSRWLock_LockRead((ss)->specLock); }
+#define ssl_ReleaseSpecReadLock(ss) \
+ { if (!ss->opt.noLocks) NSSRWLock_UnlockRead((ss)->specLock); }
+/* NSSRWLock_HaveReadLock is not exported so there's no
+ * ssl_HaveSpecReadLock macro. */
+
+#define ssl_GetSpecWriteLock(ss) \
+ { if (!ss->opt.noLocks) NSSRWLock_LockWrite((ss)->specLock); }
+#define ssl_ReleaseSpecWriteLock(ss) \
+ { if (!ss->opt.noLocks) NSSRWLock_UnlockWrite((ss)->specLock); }
+#define ssl_HaveSpecWriteLock(ss) \
+ (NSSRWLock_HaveWriteLock((ss)->specLock))
+
+/* recvBufLock -> ssl3HandshakeLock -> xmitBufLock */
+#define ssl_GetRecvBufLock(ss) \
+ { if (!ss->opt.noLocks) { \
+ PORT_Assert(!ssl_HaveSSL3HandshakeLock(ss)); \
+ PORT_Assert(!ssl_HaveXmitBufLock(ss)); \
+ PZ_EnterMonitor((ss)->recvBufLock); \
+ } }
+#define ssl_ReleaseRecvBufLock(ss) \
+ { if (!ss->opt.noLocks) PZ_ExitMonitor( (ss)->recvBufLock); }
+#define ssl_HaveRecvBufLock(ss) \
+ (PZ_InMonitor((ss)->recvBufLock))
+
+/* xmitBufLock -> specLock */
+#define ssl_GetXmitBufLock(ss) \
+ { if (!ss->opt.noLocks) PZ_EnterMonitor((ss)->xmitBufLock); }
+#define ssl_ReleaseXmitBufLock(ss) \
+ { if (!ss->opt.noLocks) PZ_ExitMonitor( (ss)->xmitBufLock); }
+#define ssl_HaveXmitBufLock(ss) \
+ (PZ_InMonitor((ss)->xmitBufLock))
+
+/* Placeholder value used in version ranges when SSL 3.0 and all
+ * versions of TLS are disabled.
+ */
+#define SSL_LIBRARY_VERSION_NONE 0
+
+/* SSL_LIBRARY_VERSION_MAX_SUPPORTED is the maximum version that this version
+ * of libssl supports. Applications should use SSL_VersionRangeGetSupported at
+ * runtime to determine which versions are supported by the version of libssl
+ * in use.
+ */
+#define SSL_LIBRARY_VERSION_MAX_SUPPORTED SSL_LIBRARY_VERSION_TLS_1_2
+
+/* Rename this macro SSL_ALL_VERSIONS_DISABLED when SSL 2.0 is removed. */
+#define SSL3_ALL_VERSIONS_DISABLED(vrange) \
+ ((vrange)->min == SSL_LIBRARY_VERSION_NONE)
+
+extern PRBool ssl3_VersionIsSupported(SSLProtocolVariant protocolVariant,
+ SSL3ProtocolVersion version);
+
+extern SECStatus ssl3_KeyAndMacDeriveBypass(ssl3CipherSpec * pwSpec,
+ const unsigned char * cr, const unsigned char * sr,
+ PRBool isTLS, PRBool isExport);
+extern SECStatus ssl3_MasterKeyDeriveBypass( ssl3CipherSpec * pwSpec,
+ const unsigned char * cr, const unsigned char * sr,
+ const SECItem * pms, PRBool isTLS, PRBool isRSA);
+
+/* These functions are called from secnav, even though they're "private". */
+
+extern int ssl2_SendErrorMessage(struct sslSocketStr *ss, int error);
+extern sslSocket *ssl_FindSocket(PRFileDesc *fd);
+extern void ssl_FreeSocket(struct sslSocketStr *ssl);
+extern SECStatus SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level,
+ SSL3AlertDescription desc);
+extern SECStatus ssl3_DecodeError(sslSocket *ss);
+
+extern SECStatus ssl3_RestartHandshakeAfterCertReq(sslSocket * ss,
+ CERTCertificate * cert,
+ SECKEYPrivateKey * key,
+ CERTCertificateList *certChain);
+
+extern SECStatus ssl3_RestartHandshakeAfterChannelIDReq(
+ sslSocket *ss,
+ SECKEYPublicKey *channelIDPub,
+ SECKEYPrivateKey *channelID);
+
+extern SECStatus ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error);
+
+/*
+ * for dealing with SSL 3.0 clients sending SSL 2.0 format hellos
+ */
+extern SECStatus ssl3_HandleV2ClientHello(
+ sslSocket *ss, unsigned char *buffer, int length);
+extern SECStatus ssl3_StartHandshakeHash(
+ sslSocket *ss, unsigned char *buf, int length);
+
+/*
+ * SSL3 specific routines
+ */
+SECStatus ssl3_SendClientHello(sslSocket *ss, PRBool resending);
+
+/*
+ * input into the SSL3 machinery from the actualy network reading code
+ */
+SECStatus ssl3_HandleRecord(
+ sslSocket *ss, SSL3Ciphertext *cipher, sslBuffer *out);
+
+int ssl3_GatherAppDataRecord(sslSocket *ss, int flags);
+int ssl3_GatherCompleteHandshake(sslSocket *ss, int flags);
+/*
+ * When talking to export clients or using export cipher suites, servers
+ * with public RSA keys larger than 512 bits need to use a 512-bit public
+ * key, signed by the larger key. The smaller key is a "step down" key.
+ * Generate that key pair and keep it around.
+ */
+extern SECStatus ssl3_CreateRSAStepDownKeys(sslSocket *ss);
+
+#ifdef NSS_ENABLE_ECC
+extern void ssl3_FilterECCipherSuitesByServerCerts(sslSocket *ss);
+extern PRBool ssl3_IsECCEnabled(sslSocket *ss);
+extern SECStatus ssl3_DisableECCSuites(sslSocket * ss,
+ const ssl3CipherSuite * suite);
+extern PRUint32 ssl3_GetSupportedECCurveMask(sslSocket *ss);
+
+
+/* Macro for finding a curve equivalent in strength to RSA key's */
+#define SSL_RSASTRENGTH_TO_ECSTRENGTH(s) \
+ ((s <= 1024) ? 160 \
+ : ((s <= 2048) ? 224 \
+ : ((s <= 3072) ? 256 \
+ : ((s <= 7168) ? 384 : 521 ) ) ) )
+
+/* Types and names of elliptic curves used in TLS */
+typedef enum { ec_type_explicitPrime = 1,
+ ec_type_explicitChar2Curve = 2,
+ ec_type_named
+} ECType;
+
+typedef enum { ec_noName = 0,
+ ec_sect163k1 = 1,
+ ec_sect163r1 = 2,
+ ec_sect163r2 = 3,
+ ec_sect193r1 = 4,
+ ec_sect193r2 = 5,
+ ec_sect233k1 = 6,
+ ec_sect233r1 = 7,
+ ec_sect239k1 = 8,
+ ec_sect283k1 = 9,
+ ec_sect283r1 = 10,
+ ec_sect409k1 = 11,
+ ec_sect409r1 = 12,
+ ec_sect571k1 = 13,
+ ec_sect571r1 = 14,
+ ec_secp160k1 = 15,
+ ec_secp160r1 = 16,
+ ec_secp160r2 = 17,
+ ec_secp192k1 = 18,
+ ec_secp192r1 = 19,
+ ec_secp224k1 = 20,
+ ec_secp224r1 = 21,
+ ec_secp256k1 = 22,
+ ec_secp256r1 = 23,
+ ec_secp384r1 = 24,
+ ec_secp521r1 = 25,
+ ec_pastLastName
+} ECName;
+
+extern SECStatus ssl3_ECName2Params(PLArenaPool *arena, ECName curve,
+ SECKEYECParams *params);
+ECName ssl3_GetCurveWithECKeyStrength(PRUint32 curvemsk, int requiredECCbits);
+
+
+#endif /* NSS_ENABLE_ECC */
+
+extern SECStatus ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool on);
+extern SECStatus ssl3_CipherPrefGetDefault(ssl3CipherSuite which, PRBool *on);
+extern SECStatus ssl2_CipherPrefSetDefault(PRInt32 which, PRBool enabled);
+extern SECStatus ssl2_CipherPrefGetDefault(PRInt32 which, PRBool *enabled);
+
+extern SECStatus ssl3_CipherPrefSet(sslSocket *ss, ssl3CipherSuite which, PRBool on);
+extern SECStatus ssl3_CipherPrefGet(sslSocket *ss, ssl3CipherSuite which, PRBool *on);
+extern SECStatus ssl2_CipherPrefSet(sslSocket *ss, PRInt32 which, PRBool enabled);
+extern SECStatus ssl2_CipherPrefGet(sslSocket *ss, PRInt32 which, PRBool *enabled);
+
+extern SECStatus ssl3_SetPolicy(ssl3CipherSuite which, PRInt32 policy);
+extern SECStatus ssl3_GetPolicy(ssl3CipherSuite which, PRInt32 *policy);
+extern SECStatus ssl2_SetPolicy(PRInt32 which, PRInt32 policy);
+extern SECStatus ssl2_GetPolicy(PRInt32 which, PRInt32 *policy);
+
+extern void ssl2_InitSocketPolicy(sslSocket *ss);
+extern void ssl3_InitSocketPolicy(sslSocket *ss);
+
+extern SECStatus ssl3_ConstructV2CipherSpecsHack(sslSocket *ss,
+ unsigned char *cs, int *size);
+
+extern SECStatus ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache);
+extern SECStatus ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b,
+ PRUint32 length);
+
+extern void ssl3_DestroySSL3Info(sslSocket *ss);
+
+extern SECStatus ssl3_NegotiateVersion(sslSocket *ss,
+ SSL3ProtocolVersion peerVersion,
+ PRBool allowLargerPeerVersion);
+
+extern SECStatus ssl_GetPeerInfo(sslSocket *ss);
+
+#ifdef NSS_ENABLE_ECC
+/* ECDH functions */
+extern SECStatus ssl3_SendECDHClientKeyExchange(sslSocket * ss,
+ SECKEYPublicKey * svrPubKey);
+extern SECStatus ssl3_HandleECDHServerKeyExchange(sslSocket *ss,
+ SSL3Opaque *b, PRUint32 length);
+extern SECStatus ssl3_HandleECDHClientKeyExchange(sslSocket *ss,
+ SSL3Opaque *b, PRUint32 length,
+ SECKEYPublicKey *srvrPubKey,
+ SECKEYPrivateKey *srvrPrivKey);
+extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss,
+ const SSL3SignatureAndHashAlgorithm *sigAndHash);
+#endif
+
+extern SECStatus ssl3_ComputeCommonKeyHash(SECOidTag hashAlg,
+ PRUint8 * hashBuf,
+ unsigned int bufLen, SSL3Hashes *hashes,
+ PRBool bypassPKCS11);
+extern void ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName);
+extern SECStatus ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms);
+extern SECStatus ssl3_AppendHandshake(sslSocket *ss, const void *void_src,
+ PRInt32 bytes);
+extern SECStatus ssl3_AppendHandshakeHeader(sslSocket *ss,
+ SSL3HandshakeType t, PRUint32 length);
+extern SECStatus ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num,
+ PRInt32 lenSize);
+extern SECStatus ssl3_AppendHandshakeVariable( sslSocket *ss,
+ const SSL3Opaque *src, PRInt32 bytes, PRInt32 lenSize);
+extern SECStatus ssl3_AppendSignatureAndHashAlgorithm(sslSocket *ss,
+ const SSL3SignatureAndHashAlgorithm* sigAndHash);
+extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes,
+ SSL3Opaque **b, PRUint32 *length);
+extern PRInt32 ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes,
+ SSL3Opaque **b, PRUint32 *length);
+extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i,
+ PRInt32 bytes, SSL3Opaque **b, PRUint32 *length);
+extern SECOidTag ssl3_TLSHashAlgorithmToOID(int hashFunc);
+extern SECStatus ssl3_CheckSignatureAndHashAlgorithmConsistency(
+ const SSL3SignatureAndHashAlgorithm *sigAndHash,
+ CERTCertificate* cert);
+extern SECStatus ssl3_ConsumeSignatureAndHashAlgorithm(sslSocket *ss,
+ SSL3Opaque **b, PRUint32 *length,
+ SSL3SignatureAndHashAlgorithm *out);
+extern SECStatus ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key,
+ SECItem *buf, PRBool isTLS);
+extern SECStatus ssl3_VerifySignedHashes(SSL3Hashes *hash,
+ CERTCertificate *cert, SECItem *buf, PRBool isTLS,
+ void *pwArg);
+extern SECStatus ssl3_CacheWrappedMasterSecret(sslSocket *ss,
+ sslSessionID *sid, ssl3CipherSpec *spec,
+ SSL3KEAType effectiveExchKeyType);
+
+/* Functions that handle ClientHello and ServerHello extensions. */
+extern SECStatus ssl3_HandleServerNameXtn(sslSocket * ss,
+ PRUint16 ex_type, SECItem *data);
+extern SECStatus ssl3_HandleSupportedCurvesXtn(sslSocket * ss,
+ PRUint16 ex_type, SECItem *data);
+extern SECStatus ssl3_HandleSupportedPointFormatsXtn(sslSocket * ss,
+ PRUint16 ex_type, SECItem *data);
+extern SECStatus ssl3_ClientHandleSessionTicketXtn(sslSocket *ss,
+ PRUint16 ex_type, SECItem *data);
+extern SECStatus ssl3_ServerHandleSessionTicketXtn(sslSocket *ss,
+ PRUint16 ex_type, SECItem *data);
+
+/* ClientHello and ServerHello extension senders.
+ * Note that not all extension senders are exposed here; only those that
+ * that need exposure.
+ */
+extern PRInt32 ssl3_SendSessionTicketXtn(sslSocket *ss, PRBool append,
+ PRUint32 maxBytes);
+
+/* ClientHello and ServerHello extension senders.
+ * The code is in ssl3ext.c.
+ */
+extern PRInt32 ssl3_SendServerNameXtn(sslSocket *ss, PRBool append,
+ PRUint32 maxBytes);
+
+/* Assigns new cert, cert chain and keys to ss->serverCerts
+ * struct. If certChain is NULL, tries to find one. Aborts if
+ * fails to do so. If cert and keyPair are NULL - unconfigures
+ * sslSocket of kea type.*/
+extern SECStatus ssl_ConfigSecureServer(sslSocket *ss, CERTCertificate *cert,
+ const CERTCertificateList *certChain,
+ ssl3KeyPair *keyPair, SSLKEAType kea);
+
+#ifdef NSS_ENABLE_ECC
+extern PRInt32 ssl3_SendSupportedCurvesXtn(sslSocket *ss,
+ PRBool append, PRUint32 maxBytes);
+extern PRInt32 ssl3_SendSupportedPointFormatsXtn(sslSocket *ss,
+ PRBool append, PRUint32 maxBytes);
+#endif
+
+/* call the registered extension handlers. */
+extern SECStatus ssl3_HandleHelloExtensions(sslSocket *ss,
+ SSL3Opaque **b, PRUint32 *length);
+
+/* Hello Extension related routines. */
+extern PRBool ssl3_ExtensionNegotiated(sslSocket *ss, PRUint16 ex_type);
+extern SECStatus ssl3_SetSIDSessionTicket(sslSessionID *sid,
+ NewSessionTicket *session_ticket);
+extern SECStatus ssl3_SendNewSessionTicket(sslSocket *ss);
+extern PRBool ssl_GetSessionTicketKeys(unsigned char *keyName,
+ unsigned char *encKey, unsigned char *macKey);
+extern PRBool ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey,
+ SECKEYPublicKey *svrPubKey, void *pwArg,
+ unsigned char *keyName, PK11SymKey **aesKey,
+ PK11SymKey **macKey);
+
+/* Tell clients to consider tickets valid for this long. */
+#define TLS_EX_SESS_TICKET_LIFETIME_HINT (2 * 24 * 60 * 60) /* 2 days */
+#define TLS_EX_SESS_TICKET_VERSION (0x0100)
+
+extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char* data,
+ unsigned int length);
+
+extern SECStatus ssl3_GetTLSUniqueChannelBinding(sslSocket *ss,
+ unsigned char *out,
+ unsigned int *outLen,
+ unsigned int outLenMax);
+
+/* Construct a new NSPR socket for the app to use */
+extern PRFileDesc *ssl_NewPRSocket(sslSocket *ss, PRFileDesc *fd);
+extern void ssl_FreePRSocket(PRFileDesc *fd);
+
+/* Internal config function so SSL2 can initialize the present state of
+ * various ciphers */
+extern int ssl3_config_match_init(sslSocket *);
+
+/* Create a new ref counted key pair object from two keys. */
+extern ssl3KeyPair * ssl3_NewKeyPair( SECKEYPrivateKey * privKey,
+ SECKEYPublicKey * pubKey);
+
+/* get a new reference (bump ref count) to an ssl3KeyPair. */
+extern ssl3KeyPair * ssl3_GetKeyPairRef(ssl3KeyPair * keyPair);
+
+/* Decrement keypair's ref count and free if zero. */
+extern void ssl3_FreeKeyPair(ssl3KeyPair * keyPair);
+
+/* calls for accessing wrapping keys across processes. */
+extern PRBool
+ssl_GetWrappingKey( PRInt32 symWrapMechIndex,
+ SSL3KEAType exchKeyType,
+ SSLWrappedSymWrappingKey *wswk);
+
+/* The caller passes in the new value it wants
+ * to set. This code tests the wrapped sym key entry in the file on disk.
+ * If it is uninitialized, this function writes the caller's value into
+ * the disk entry, and returns false.
+ * Otherwise, it overwrites the caller's wswk with the value obtained from
+ * the disk, and returns PR_TRUE.
+ * This is all done while holding the locks/semaphores necessary to make
+ * the operation atomic.
+ */
+extern PRBool
+ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk);
+
+/* get rid of the symmetric wrapping key references. */
+extern SECStatus SSL3_ShutdownServerCache(void);
+
+extern SECStatus ssl_InitSymWrapKeysLock(void);
+
+extern SECStatus ssl_FreeSymWrapKeysLock(void);
+
+extern SECStatus ssl_InitSessionCacheLocks(PRBool lazyInit);
+
+extern SECStatus ssl_FreeSessionCacheLocks(void);
+
+/***************** platform client auth ****************/
+
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+// Releases the platform key.
+extern void ssl_FreePlatformKey(PlatformKey key);
+
+// Implement the client CertificateVerify message for SSL3/TLS1.0
+extern SECStatus ssl3_PlatformSignHashes(SSL3Hashes *hash,
+ PlatformKey key, SECItem *buf,
+ PRBool isTLS, KeyType keyType);
+
+// Converts a CERTCertList* (A collection of CERTCertificates) into a
+// CERTCertificateList* (A collection of SECItems), or returns NULL if
+// it cannot be converted.
+// This is to allow the platform-supplied chain to be created with purely
+// public API functions, using the preferred CERTCertList mutators, rather
+// pushing this hack to clients.
+extern CERTCertificateList* hack_NewCertificateListFromCertList(
+ CERTCertList* list);
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
+
+/**************** DTLS-specific functions **************/
+extern void dtls_FreeQueuedMessage(DTLSQueuedMessage *msg);
+extern void dtls_FreeQueuedMessages(PRCList *lst);
+extern void dtls_FreeHandshakeMessages(PRCList *lst);
+
+extern SECStatus dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf);
+extern SECStatus dtls_HandleHelloVerifyRequest(sslSocket *ss,
+ SSL3Opaque *b, PRUint32 length);
+extern SECStatus dtls_StageHandshakeMessage(sslSocket *ss);
+extern SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type,
+ const SSL3Opaque *pIn, PRInt32 nIn);
+extern SECStatus dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
+extern SECStatus dtls_CompressMACEncryptRecord(sslSocket *ss,
+ DTLSEpoch epoch,
+ PRBool use_epoch,
+ SSL3ContentType type,
+ const SSL3Opaque *pIn,
+ PRUint32 contentLen,
+ sslBuffer *wrBuf);
+SECStatus ssl3_DisableNonDTLSSuites(sslSocket * ss);
+extern SECStatus dtls_StartTimer(sslSocket *ss, DTLSTimerCb cb);
+extern SECStatus dtls_RestartTimer(sslSocket *ss, PRBool backoff,
+ DTLSTimerCb cb);
+extern void dtls_CheckTimer(sslSocket *ss);
+extern void dtls_CancelTimer(sslSocket *ss);
+extern void dtls_FinishedTimerCb(sslSocket *ss);
+extern void dtls_SetMTU(sslSocket *ss, PRUint16 advertised);
+extern void dtls_InitRecvdRecords(DTLSRecvdRecords *records);
+extern int dtls_RecordGetRecvd(DTLSRecvdRecords *records, PRUint64 seq);
+extern void dtls_RecordSetRecvd(DTLSRecvdRecords *records, PRUint64 seq);
+extern void dtls_RehandshakeCleanup(sslSocket *ss);
+extern SSL3ProtocolVersion
+dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv);
+extern SSL3ProtocolVersion
+dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv);
+
+/********************** misc calls *********************/
+
+extern int ssl_MapLowLevelError(int hiLevelError);
+
+extern PRUint32 ssl_Time(void);
+
+extern void SSL_AtomicIncrementLong(long * x);
+
+SECStatus SSL_DisableDefaultExportCipherSuites(void);
+SECStatus SSL_DisableExportCipherSuites(PRFileDesc * fd);
+PRBool SSL_IsExportCipherSuite(PRUint16 cipherSuite);
+
+extern SECStatus
+ssl3_TLSPRFWithMasterSecret(ssl3CipherSpec *spec,
+ const char *label, unsigned int labelLen,
+ const unsigned char *val, unsigned int valLen,
+ unsigned char *out, unsigned int outLen);
+
+#ifdef TRACE
+#define SSL_TRACE(msg) ssl_Trace msg
+#else
+#define SSL_TRACE(msg)
+#endif
+
+void ssl_Trace(const char *format, ...);
+
+SEC_END_PROTOS
+
+#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
+#define SSL_GETPID getpid
+#elif defined(WIN32)
+extern int __cdecl _getpid(void);
+#define SSL_GETPID _getpid
+#else
+#define SSL_GETPID() 0
+#endif
+
+#endif /* __sslimpl_h_ */
diff --git a/chromium/net/third_party/nss/ssl/sslinfo.c b/chromium/net/third_party/nss/ssl/sslinfo.c
new file mode 100644
index 00000000000..215731e4b02
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslinfo.c
@@ -0,0 +1,413 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "ssl.h"
+#include "sslimpl.h"
+#include "sslproto.h"
+
+static const char *
+ssl_GetCompressionMethodName(SSLCompressionMethod compression)
+{
+ switch (compression) {
+ case ssl_compression_null:
+ return "NULL";
+#ifdef NSS_ENABLE_ZLIB
+ case ssl_compression_deflate:
+ return "DEFLATE";
+#endif
+ default:
+ return "???";
+ }
+}
+
+SECStatus
+SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
+{
+ sslSocket * ss;
+ SSLChannelInfo inf;
+ sslSessionID * sid;
+ PRBool enoughFirstHsDone = PR_FALSE;
+
+ if (!info || len < sizeof inf.length) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetChannelInfo",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ memset(&inf, 0, sizeof inf);
+ inf.length = PR_MIN(sizeof inf, len);
+
+ if (ss->firstHsDone) {
+ enoughFirstHsDone = PR_TRUE;
+ } else if (ss->version >= SSL_LIBRARY_VERSION_3_0 &&
+ ssl3_CanFalseStart(ss)) {
+ enoughFirstHsDone = PR_TRUE;
+ }
+
+ if (ss->opt.useSecurity && enoughFirstHsDone) {
+ sid = ss->sec.ci.sid;
+ inf.protocolVersion = ss->version;
+ inf.authKeyBits = ss->sec.authKeyBits;
+ inf.keaKeyBits = ss->sec.keaKeyBits;
+ if (ss->version < SSL_LIBRARY_VERSION_3_0) { /* SSL2 */
+ inf.cipherSuite = ss->sec.cipherType | 0xff00;
+ inf.compressionMethod = ssl_compression_null;
+ inf.compressionMethodName = "N/A";
+ } else if (ss->ssl3.initialized) { /* SSL3 and TLS */
+ ssl_GetSpecReadLock(ss);
+ /* XXX The cipher suite should be in the specs and this
+ * function should get it from cwSpec rather than from the "hs".
+ * See bug 275744 comment 69 and bug 766137.
+ */
+ inf.cipherSuite = ss->ssl3.hs.cipher_suite;
+ inf.compressionMethod = ss->ssl3.cwSpec->compression_method;
+ ssl_ReleaseSpecReadLock(ss);
+ inf.compressionMethodName =
+ ssl_GetCompressionMethodName(inf.compressionMethod);
+ }
+ if (sid) {
+ inf.creationTime = sid->creationTime;
+ inf.lastAccessTime = sid->lastAccessTime;
+ inf.expirationTime = sid->expirationTime;
+ if (ss->version < SSL_LIBRARY_VERSION_3_0) { /* SSL2 */
+ inf.sessionIDLength = SSL2_SESSIONID_BYTES;
+ memcpy(inf.sessionID, sid->u.ssl2.sessionID,
+ SSL2_SESSIONID_BYTES);
+ } else {
+ unsigned int sidLen = sid->u.ssl3.sessionIDLength;
+ sidLen = PR_MIN(sidLen, sizeof inf.sessionID);
+ inf.sessionIDLength = sidLen;
+ memcpy(inf.sessionID, sid->u.ssl3.sessionID, sidLen);
+ }
+ }
+ }
+
+ memcpy(info, &inf, inf.length);
+
+ return SECSuccess;
+}
+
+
+#define CS(x) x, #x
+#define CK(x) x | 0xff00, #x
+
+#define S_DSA "DSA", ssl_auth_dsa
+#define S_RSA "RSA", ssl_auth_rsa
+#define S_KEA "KEA", ssl_auth_kea
+#define S_ECDSA "ECDSA", ssl_auth_ecdsa
+
+#define K_DHE "DHE", kt_dh
+#define K_RSA "RSA", kt_rsa
+#define K_KEA "KEA", kt_kea
+#define K_ECDH "ECDH", kt_ecdh
+#define K_ECDHE "ECDHE", kt_ecdh
+
+#define C_SEED "SEED", calg_seed
+#define C_CAMELLIA "CAMELLIA", calg_camellia
+#define C_AES "AES", calg_aes
+#define C_RC4 "RC4", calg_rc4
+#define C_RC2 "RC2", calg_rc2
+#define C_DES "DES", calg_des
+#define C_3DES "3DES", calg_3des
+#define C_NULL "NULL", calg_null
+#define C_SJ "SKIPJACK", calg_sj
+#define C_AESGCM "AES-GCM", calg_aes_gcm
+
+#define B_256 256, 256, 256
+#define B_128 128, 128, 128
+#define B_3DES 192, 156, 112
+#define B_SJ 96, 80, 80
+#define B_DES 64, 56, 56
+#define B_56 128, 56, 56
+#define B_40 128, 40, 40
+#define B_0 0, 0, 0
+
+#define M_SHA256 "SHA256", ssl_hmac_sha256, 256
+#define M_SHA "SHA1", ssl_mac_sha, 160
+#define M_MD5 "MD5", ssl_mac_md5, 128
+#define M_NULL "NULL", ssl_mac_null, 0
+
+static const SSLCipherSuiteInfo suiteInfo[] = {
+/* <------ Cipher suite --------------------> <auth> <KEA> <bulk cipher> <MAC> <FIPS> */
+{0,CS(TLS_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_RSA, C_AESGCM, B_128, M_NULL, 1, 0, 0, },
+
+{0,CS(TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_256, M_SHA, 0, 0, 0, },
+{0,CS(TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_256, M_SHA, 0, 0, 0, },
+{0,CS(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256), S_RSA, K_DHE, C_AES, B_256, M_SHA256, 1, 0, 0, },
+{0,CS(TLS_DHE_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_DHE, C_AES, B_256, M_SHA, 1, 0, 0, },
+{0,CS(TLS_DHE_DSS_WITH_AES_256_CBC_SHA), S_DSA, K_DHE, C_AES, B_256, M_SHA, 1, 0, 0, },
+{0,CS(TLS_RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_RSA, C_CAMELLIA, B_256, M_SHA, 0, 0, 0, },
+{0,CS(TLS_RSA_WITH_AES_256_CBC_SHA256), S_RSA, K_RSA, C_AES, B_256, M_SHA256, 1, 0, 0, },
+{0,CS(TLS_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_RSA, C_AES, B_256, M_SHA, 1, 0, 0, },
+
+{0,CS(TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_128, M_SHA, 0, 0, 0, },
+{0,CS(TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_128, M_SHA, 0, 0, 0, },
+{0,CS(TLS_DHE_DSS_WITH_RC4_128_SHA), S_DSA, K_DHE, C_RC4, B_128, M_SHA, 0, 0, 0, },
+{0,CS(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_DHE, C_AES, B_128, M_SHA256, 1, 0, 0, },
+{0,CS(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_DHE, C_AESGCM, B_128, M_NULL, 1, 0, 0, },
+{0,CS(TLS_DHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_DHE, C_AES, B_128, M_SHA, 1, 0, 0, },
+{0,CS(TLS_DHE_DSS_WITH_AES_128_CBC_SHA), S_DSA, K_DHE, C_AES, B_128, M_SHA, 1, 0, 0, },
+{0,CS(TLS_RSA_WITH_SEED_CBC_SHA), S_RSA, K_RSA, C_SEED,B_128, M_SHA, 1, 0, 0, },
+{0,CS(TLS_RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_RSA, C_CAMELLIA, B_128, M_SHA, 0, 0, 0, },
+{0,CS(SSL_RSA_WITH_RC4_128_SHA), S_RSA, K_RSA, C_RC4, B_128, M_SHA, 0, 0, 0, },
+{0,CS(SSL_RSA_WITH_RC4_128_MD5), S_RSA, K_RSA, C_RC4, B_128, M_MD5, 0, 0, 0, },
+{0,CS(TLS_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_RSA, C_AES, B_128, M_SHA256, 1, 0, 0, },
+{0,CS(TLS_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_RSA, C_AES, B_128, M_SHA, 1, 0, 0, },
+
+{0,CS(SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_DHE, C_3DES,B_3DES,M_SHA, 1, 0, 0, },
+{0,CS(SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA), S_DSA, K_DHE, C_3DES,B_3DES,M_SHA, 1, 0, 0, },
+{0,CS(SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA), S_RSA, K_RSA, C_3DES,B_3DES,M_SHA, 1, 0, 1, },
+{0,CS(SSL_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_RSA, C_3DES,B_3DES,M_SHA, 1, 0, 0, },
+
+{0,CS(SSL_DHE_RSA_WITH_DES_CBC_SHA), S_RSA, K_DHE, C_DES, B_DES, M_SHA, 0, 0, 0, },
+{0,CS(SSL_DHE_DSS_WITH_DES_CBC_SHA), S_DSA, K_DHE, C_DES, B_DES, M_SHA, 0, 0, 0, },
+{0,CS(SSL_RSA_FIPS_WITH_DES_CBC_SHA), S_RSA, K_RSA, C_DES, B_DES, M_SHA, 0, 0, 1, },
+{0,CS(SSL_RSA_WITH_DES_CBC_SHA), S_RSA, K_RSA, C_DES, B_DES, M_SHA, 0, 0, 0, },
+
+{0,CS(TLS_RSA_EXPORT1024_WITH_RC4_56_SHA), S_RSA, K_RSA, C_RC4, B_56, M_SHA, 0, 1, 0, },
+{0,CS(TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA), S_RSA, K_RSA, C_DES, B_DES, M_SHA, 0, 1, 0, },
+{0,CS(SSL_RSA_EXPORT_WITH_RC4_40_MD5), S_RSA, K_RSA, C_RC4, B_40, M_MD5, 0, 1, 0, },
+{0,CS(SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5), S_RSA, K_RSA, C_RC2, B_40, M_MD5, 0, 1, 0, },
+{0,CS(TLS_RSA_WITH_NULL_SHA256), S_RSA, K_RSA, C_NULL,B_0, M_SHA256, 0, 1, 0, },
+{0,CS(SSL_RSA_WITH_NULL_SHA), S_RSA, K_RSA, C_NULL,B_0, M_SHA, 0, 1, 0, },
+{0,CS(SSL_RSA_WITH_NULL_MD5), S_RSA, K_RSA, C_NULL,B_0, M_MD5, 0, 1, 0, },
+
+#ifdef NSS_ENABLE_ECC
+/* ECC cipher suites */
+{0,CS(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_ECDHE, C_AESGCM, B_128, M_NULL, 1, 0, 0, },
+{0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), S_ECDSA, K_ECDHE, C_AESGCM, B_128, M_NULL, 1, 0, 0, },
+
+{0,CS(TLS_ECDH_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDH, C_NULL, B_0, M_SHA, 0, 0, 0, },
+{0,CS(TLS_ECDH_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDH, C_RC4, B_128, M_SHA, 0, 0, 0, },
+{0,CS(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDH, C_3DES, B_3DES, M_SHA, 1, 0, 0, },
+{0,CS(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_128, M_SHA, 1, 0, 0, },
+{0,CS(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_256, M_SHA, 1, 0, 0, },
+
+{0,CS(TLS_ECDHE_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDHE, C_NULL, B_0, M_SHA, 0, 0, 0, },
+{0,CS(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDHE, C_RC4, B_128, M_SHA, 0, 0, 0, },
+{0,CS(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDHE, C_3DES, B_3DES, M_SHA, 1, 0, 0, },
+{0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA, 1, 0, 0, },
+{0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA256, 1, 0, 0, },
+{0,CS(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA, 1, 0, 0, },
+
+{0,CS(TLS_ECDH_RSA_WITH_NULL_SHA), S_RSA, K_ECDH, C_NULL, B_0, M_SHA, 0, 0, 0, },
+{0,CS(TLS_ECDH_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDH, C_RC4, B_128, M_SHA, 0, 0, 0, },
+{0,CS(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDH, C_3DES, B_3DES, M_SHA, 1, 0, 0, },
+{0,CS(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDH, C_AES, B_128, M_SHA, 1, 0, 0, },
+{0,CS(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDH, C_AES, B_256, M_SHA, 1, 0, 0, },
+
+{0,CS(TLS_ECDHE_RSA_WITH_NULL_SHA), S_RSA, K_ECDHE, C_NULL, B_0, M_SHA, 0, 0, 0, },
+{0,CS(TLS_ECDHE_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDHE, C_RC4, B_128, M_SHA, 0, 0, 0, },
+{0,CS(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDHE, C_3DES, B_3DES, M_SHA, 1, 0, 0, },
+{0,CS(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_128, M_SHA, 1, 0, 0, },
+{0,CS(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_ECDHE, C_AES, B_128, M_SHA256, 1, 0, 0, },
+{0,CS(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_256, M_SHA, 1, 0, 0, },
+#endif /* NSS_ENABLE_ECC */
+
+/* SSL 2 table */
+{0,CK(SSL_CK_RC4_128_WITH_MD5), S_RSA, K_RSA, C_RC4, B_128, M_MD5, 0, 0, 0, },
+{0,CK(SSL_CK_RC2_128_CBC_WITH_MD5), S_RSA, K_RSA, C_RC2, B_128, M_MD5, 0, 0, 0, },
+{0,CK(SSL_CK_DES_192_EDE3_CBC_WITH_MD5), S_RSA, K_RSA, C_3DES,B_3DES,M_MD5, 0, 0, 0, },
+{0,CK(SSL_CK_DES_64_CBC_WITH_MD5), S_RSA, K_RSA, C_DES, B_DES, M_MD5, 0, 0, 0, },
+{0,CK(SSL_CK_RC4_128_EXPORT40_WITH_MD5), S_RSA, K_RSA, C_RC4, B_40, M_MD5, 0, 1, 0, },
+{0,CK(SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5), S_RSA, K_RSA, C_RC2, B_40, M_MD5, 0, 1, 0, }
+};
+
+#define NUM_SUITEINFOS ((sizeof suiteInfo) / (sizeof suiteInfo[0]))
+
+
+SECStatus SSL_GetCipherSuiteInfo(PRUint16 cipherSuite,
+ SSLCipherSuiteInfo *info, PRUintn len)
+{
+ unsigned int i;
+
+ len = PR_MIN(len, sizeof suiteInfo[0]);
+ if (!info || len < sizeof suiteInfo[0].length) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ for (i = 0; i < NUM_SUITEINFOS; i++) {
+ if (suiteInfo[i].cipherSuite == cipherSuite) {
+ memcpy(info, &suiteInfo[i], len);
+ info->length = len;
+ return SECSuccess;
+ }
+ }
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+}
+
+/* This function might be a candidate to be public.
+ * Disables all export ciphers in the default set of enabled ciphers.
+ */
+SECStatus
+SSL_DisableDefaultExportCipherSuites(void)
+{
+ const SSLCipherSuiteInfo * pInfo = suiteInfo;
+ unsigned int i;
+ SECStatus rv;
+
+ for (i = 0; i < NUM_SUITEINFOS; ++i, ++pInfo) {
+ if (pInfo->isExportable) {
+ rv = SSL_CipherPrefSetDefault(pInfo->cipherSuite, PR_FALSE);
+ PORT_Assert(rv == SECSuccess);
+ }
+ }
+ return SECSuccess;
+}
+
+/* This function might be a candidate to be public,
+ * except that it takes an sslSocket pointer as an argument.
+ * A Public version would take a PRFileDesc pointer.
+ * Disables all export ciphers in the default set of enabled ciphers.
+ */
+SECStatus
+SSL_DisableExportCipherSuites(PRFileDesc * fd)
+{
+ const SSLCipherSuiteInfo * pInfo = suiteInfo;
+ unsigned int i;
+ SECStatus rv;
+
+ for (i = 0; i < NUM_SUITEINFOS; ++i, ++pInfo) {
+ if (pInfo->isExportable) {
+ rv = SSL_CipherPrefSet(fd, pInfo->cipherSuite, PR_FALSE);
+ PORT_Assert(rv == SECSuccess);
+ }
+ }
+ return SECSuccess;
+}
+
+/* Tells us if the named suite is exportable
+ * returns false for unknown suites.
+ */
+PRBool
+SSL_IsExportCipherSuite(PRUint16 cipherSuite)
+{
+ unsigned int i;
+ for (i = 0; i < NUM_SUITEINFOS; i++) {
+ if (suiteInfo[i].cipherSuite == cipherSuite) {
+ return (PRBool)(suiteInfo[i].isExportable);
+ }
+ }
+ return PR_FALSE;
+}
+
+SECItem*
+SSL_GetNegotiatedHostInfo(PRFileDesc *fd)
+{
+ SECItem *sniName = NULL;
+ sslSocket *ss;
+ char *name = NULL;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetNegotiatedHostInfo",
+ SSL_GETPID(), fd));
+ return NULL;
+ }
+
+ if (ss->sec.isServer) {
+ if (ss->version > SSL_LIBRARY_VERSION_3_0 &&
+ ss->ssl3.initialized) { /* TLS */
+ SECItem *crsName;
+ ssl_GetSpecReadLock(ss); /*********************************/
+ crsName = &ss->ssl3.cwSpec->srvVirtName;
+ if (crsName->data) {
+ sniName = SECITEM_DupItem(crsName);
+ }
+ ssl_ReleaseSpecReadLock(ss); /*----------------------------*/
+ }
+ return sniName;
+ }
+ name = SSL_RevealURL(fd);
+ if (name) {
+ sniName = PORT_ZNew(SECItem);
+ if (!sniName) {
+ PORT_Free(name);
+ return NULL;
+ }
+ sniName->data = (void*)name;
+ sniName->len = PORT_Strlen(name);
+ }
+ return sniName;
+}
+
+SECStatus
+SSL_ExportKeyingMaterial(PRFileDesc *fd,
+ const char *label, unsigned int labelLen,
+ PRBool hasContext,
+ const unsigned char *context, unsigned int contextLen,
+ unsigned char *out, unsigned int outLen)
+{
+ sslSocket *ss;
+ unsigned char *val = NULL;
+ unsigned int valLen, i;
+ SECStatus rv = SECFailure;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in ExportKeyingMaterial",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ ssl_GetRecvBufLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ if (ss->version < SSL_LIBRARY_VERSION_3_1_TLS) {
+ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION);
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_ReleaseRecvBufLock(ss);
+ return SECFailure;
+ }
+
+ /* construct PRF arguments */
+ valLen = SSL3_RANDOM_LENGTH * 2;
+ if (hasContext) {
+ valLen += 2 /* PRUint16 length */ + contextLen;
+ }
+ val = PORT_Alloc(valLen);
+ if (!val) {
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_ReleaseRecvBufLock(ss);
+ return SECFailure;
+ }
+ i = 0;
+
+ PORT_Memcpy(val + i, &ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH);
+ i += SSL3_RANDOM_LENGTH;
+ PORT_Memcpy(val + i, &ss->ssl3.hs.server_random.rand, SSL3_RANDOM_LENGTH);
+ i += SSL3_RANDOM_LENGTH;
+
+ if (hasContext) {
+ val[i++] = contextLen >> 8;
+ val[i++] = contextLen;
+ PORT_Memcpy(val + i, context, contextLen);
+ i += contextLen;
+ }
+ PORT_Assert(i == valLen);
+
+ /* Allow TLS keying material to be exported sooner, when the master
+ * secret is available and we have sent ChangeCipherSpec.
+ */
+ ssl_GetSpecReadLock(ss);
+ if (!ss->ssl3.cwSpec->master_secret && !ss->ssl3.cwSpec->msItem.len) {
+ PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED);
+ rv = SECFailure;
+ } else {
+ rv = ssl3_TLSPRFWithMasterSecret(ss->ssl3.cwSpec, label, labelLen, val,
+ valLen, out, outLen);
+ }
+ ssl_ReleaseSpecReadLock(ss);
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_ReleaseRecvBufLock(ss);
+
+ PORT_ZFree(val, valLen);
+ return rv;
+}
diff --git a/chromium/net/third_party/nss/ssl/sslinit.c b/chromium/net/third_party/nss/ssl/sslinit.c
new file mode 100644
index 00000000000..047cc8d1d94
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslinit.c
@@ -0,0 +1,28 @@
+/*
+ * NSS utility functions
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prtypes.h"
+#include "prinit.h"
+#include "seccomon.h"
+#include "secerr.h"
+#include "ssl.h"
+#include "sslimpl.h"
+
+static int ssl_inited = 0;
+
+SECStatus
+ssl_Init(void)
+{
+ if (!ssl_inited) {
+ if (ssl_InitializePRErrorTable() != SECSuccess) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return (SECFailure);
+ }
+ ssl_inited = 1;
+ }
+ return SECSuccess;
+}
diff --git a/chromium/net/third_party/nss/ssl/sslmutex.c b/chromium/net/third_party/nss/ssl/sslmutex.c
new file mode 100644
index 00000000000..ff6368069df
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslmutex.c
@@ -0,0 +1,640 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "seccomon.h"
+/* This ifdef should match the one in sslsnce.c */
+#if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)
+
+#include "sslmutex.h"
+#include "prerr.h"
+
+static SECStatus single_process_sslMutex_Init(sslMutex* pMutex)
+{
+ PR_ASSERT(pMutex != 0 && pMutex->u.sslLock == 0 );
+
+ pMutex->u.sslLock = PR_NewLock();
+ if (!pMutex->u.sslLock) {
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+static SECStatus single_process_sslMutex_Destroy(sslMutex* pMutex)
+{
+ PR_ASSERT(pMutex != 0);
+ PR_ASSERT(pMutex->u.sslLock!= 0);
+ if (!pMutex->u.sslLock) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ PR_DestroyLock(pMutex->u.sslLock);
+ return SECSuccess;
+}
+
+static SECStatus single_process_sslMutex_Unlock(sslMutex* pMutex)
+{
+ PR_ASSERT(pMutex != 0 );
+ PR_ASSERT(pMutex->u.sslLock !=0);
+ if (!pMutex->u.sslLock) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ PR_Unlock(pMutex->u.sslLock);
+ return SECSuccess;
+}
+
+static SECStatus single_process_sslMutex_Lock(sslMutex* pMutex)
+{
+ PR_ASSERT(pMutex != 0);
+ PR_ASSERT(pMutex->u.sslLock != 0 );
+ if (!pMutex->u.sslLock) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ PR_Lock(pMutex->u.sslLock);
+ return SECSuccess;
+}
+
+#if defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD)
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include "unix_err.h"
+#include "pratom.h"
+
+#define SSL_MUTEX_MAGIC 0xfeedfd
+#define NONBLOCKING_POSTS 1 /* maybe this is faster */
+
+#if NONBLOCKING_POSTS
+
+#ifndef FNONBLOCK
+#define FNONBLOCK O_NONBLOCK
+#endif
+
+static int
+setNonBlocking(int fd, int nonBlocking)
+{
+ int flags;
+ int err;
+
+ flags = fcntl(fd, F_GETFL, 0);
+ if (0 > flags)
+ return flags;
+ if (nonBlocking)
+ flags |= FNONBLOCK;
+ else
+ flags &= ~FNONBLOCK;
+ err = fcntl(fd, F_SETFL, flags);
+ return err;
+}
+#endif
+
+SECStatus
+sslMutex_Init(sslMutex *pMutex, int shared)
+{
+ int err;
+ PR_ASSERT(pMutex);
+ pMutex->isMultiProcess = (PRBool)(shared != 0);
+ if (!shared) {
+ return single_process_sslMutex_Init(pMutex);
+ }
+ pMutex->u.pipeStr.mPipes[0] = -1;
+ pMutex->u.pipeStr.mPipes[1] = -1;
+ pMutex->u.pipeStr.mPipes[2] = -1;
+ pMutex->u.pipeStr.nWaiters = 0;
+
+ err = pipe(pMutex->u.pipeStr.mPipes);
+ if (err) {
+ nss_MD_unix_map_default_error(errno);
+ return err;
+ }
+#if NONBLOCKING_POSTS
+ err = setNonBlocking(pMutex->u.pipeStr.mPipes[1], 1);
+ if (err)
+ goto loser;
+#endif
+
+ pMutex->u.pipeStr.mPipes[2] = SSL_MUTEX_MAGIC;
+
+#if defined(LINUX) && defined(i386)
+ /* Pipe starts out empty */
+ return SECSuccess;
+#else
+ /* Pipe starts with one byte. */
+ return sslMutex_Unlock(pMutex);
+#endif
+
+loser:
+ nss_MD_unix_map_default_error(errno);
+ close(pMutex->u.pipeStr.mPipes[0]);
+ close(pMutex->u.pipeStr.mPipes[1]);
+ return SECFailure;
+}
+
+SECStatus
+sslMutex_Destroy(sslMutex *pMutex, PRBool processLocal)
+{
+ if (PR_FALSE == pMutex->isMultiProcess) {
+ return single_process_sslMutex_Destroy(pMutex);
+ }
+ if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ close(pMutex->u.pipeStr.mPipes[0]);
+ close(pMutex->u.pipeStr.mPipes[1]);
+
+ if (processLocal) {
+ return SECSuccess;
+ }
+
+ pMutex->u.pipeStr.mPipes[0] = -1;
+ pMutex->u.pipeStr.mPipes[1] = -1;
+ pMutex->u.pipeStr.mPipes[2] = -1;
+ pMutex->u.pipeStr.nWaiters = 0;
+
+ return SECSuccess;
+}
+
+#if defined(LINUX) && defined(i386)
+/* No memory barrier needed for this platform */
+
+/* nWaiters includes the holder of the lock (if any) and the number
+** threads waiting for it. After incrementing nWaiters, if the count
+** is exactly 1, then you have the lock and may proceed. If the
+** count is greater than 1, then you must wait on the pipe.
+*/
+
+
+SECStatus
+sslMutex_Unlock(sslMutex *pMutex)
+{
+ PRInt32 newValue;
+ if (PR_FALSE == pMutex->isMultiProcess) {
+ return single_process_sslMutex_Unlock(pMutex);
+ }
+
+ if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ /* Do Memory Barrier here. */
+ newValue = PR_ATOMIC_DECREMENT(&pMutex->u.pipeStr.nWaiters);
+ if (newValue > 0) {
+ int cc;
+ char c = 1;
+ do {
+ cc = write(pMutex->u.pipeStr.mPipes[1], &c, 1);
+ } while (cc < 0 && (errno == EINTR || errno == EAGAIN));
+ if (cc != 1) {
+ if (cc < 0)
+ nss_MD_unix_map_default_error(errno);
+ else
+ PORT_SetError(PR_UNKNOWN_ERROR);
+ return SECFailure;
+ }
+ }
+ return SECSuccess;
+}
+
+SECStatus
+sslMutex_Lock(sslMutex *pMutex)
+{
+ PRInt32 newValue;
+ if (PR_FALSE == pMutex->isMultiProcess) {
+ return single_process_sslMutex_Lock(pMutex);
+ }
+
+ if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ newValue = PR_ATOMIC_INCREMENT(&pMutex->u.pipeStr.nWaiters);
+ /* Do Memory Barrier here. */
+ if (newValue > 1) {
+ int cc;
+ char c;
+ do {
+ cc = read(pMutex->u.pipeStr.mPipes[0], &c, 1);
+ } while (cc < 0 && errno == EINTR);
+ if (cc != 1) {
+ if (cc < 0)
+ nss_MD_unix_map_default_error(errno);
+ else
+ PORT_SetError(PR_UNKNOWN_ERROR);
+ return SECFailure;
+ }
+ }
+ return SECSuccess;
+}
+
+#else
+
+/* Using Atomic operations requires the use of a memory barrier instruction
+** on PowerPC, Sparc, and Alpha. NSPR's PR_Atomic functions do not perform
+** them, and NSPR does not provide a function that does them (e.g. PR_Barrier).
+** So, we don't use them on those platforms.
+*/
+
+SECStatus
+sslMutex_Unlock(sslMutex *pMutex)
+{
+ int cc;
+ char c = 1;
+
+ if (PR_FALSE == pMutex->isMultiProcess) {
+ return single_process_sslMutex_Unlock(pMutex);
+ }
+
+ if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ do {
+ cc = write(pMutex->u.pipeStr.mPipes[1], &c, 1);
+ } while (cc < 0 && (errno == EINTR || errno == EAGAIN));
+ if (cc != 1) {
+ if (cc < 0)
+ nss_MD_unix_map_default_error(errno);
+ else
+ PORT_SetError(PR_UNKNOWN_ERROR);
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+SECStatus
+sslMutex_Lock(sslMutex *pMutex)
+{
+ int cc;
+ char c;
+
+ if (PR_FALSE == pMutex->isMultiProcess) {
+ return single_process_sslMutex_Lock(pMutex);
+ }
+
+ if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+
+ do {
+ cc = read(pMutex->u.pipeStr.mPipes[0], &c, 1);
+ } while (cc < 0 && errno == EINTR);
+ if (cc != 1) {
+ if (cc < 0)
+ nss_MD_unix_map_default_error(errno);
+ else
+ PORT_SetError(PR_UNKNOWN_ERROR);
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+#endif
+
+#elif defined(WIN32)
+
+#include "win32err.h"
+
+/* on Windows, we need to find the optimal type of locking mechanism to use
+ for the sslMutex.
+
+ There are 3 cases :
+ 1) single-process, use a PRLock, as for all other platforms
+ 2) Win95 multi-process, use a Win32 mutex
+ 3) on WINNT multi-process, use a PRLock + a Win32 mutex
+
+*/
+
+#ifdef WINNT
+
+SECStatus sslMutex_2LevelInit(sslMutex *sem)
+{
+ /* the following adds a PRLock to sslMutex . This is done in each
+ process of a multi-process server and is only needed on WINNT, if
+ using fibers. We can't tell if native threads or fibers are used, so
+ we always do it on WINNT
+ */
+ PR_ASSERT(sem);
+ if (sem) {
+ /* we need to reset the sslLock in the children or the single_process init
+ function below will assert */
+ sem->u.sslLock = NULL;
+ }
+ return single_process_sslMutex_Init(sem);
+}
+
+static SECStatus sslMutex_2LevelDestroy(sslMutex *sem)
+{
+ return single_process_sslMutex_Destroy(sem);
+}
+
+#endif
+
+SECStatus
+sslMutex_Init(sslMutex *pMutex, int shared)
+{
+#ifdef WINNT
+ SECStatus retvalue;
+#endif
+ HANDLE hMutex;
+ SECURITY_ATTRIBUTES attributes =
+ { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
+
+ PR_ASSERT(pMutex != 0 && (pMutex->u.sslMutx == 0 ||
+ pMutex->u.sslMutx == INVALID_HANDLE_VALUE) );
+
+ pMutex->isMultiProcess = (PRBool)(shared != 0);
+
+ if (PR_FALSE == pMutex->isMultiProcess) {
+ return single_process_sslMutex_Init(pMutex);
+ }
+
+#ifdef WINNT
+ /* we need a lock on WINNT for fibers in the parent process */
+ retvalue = sslMutex_2LevelInit(pMutex);
+ if (SECSuccess != retvalue)
+ return SECFailure;
+#endif
+
+ if (!pMutex || ((hMutex = pMutex->u.sslMutx) != 0 &&
+ hMutex != INVALID_HANDLE_VALUE)) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ attributes.bInheritHandle = (shared ? TRUE : FALSE);
+ hMutex = CreateMutex(&attributes, FALSE, NULL);
+ if (hMutex == NULL) {
+ hMutex = INVALID_HANDLE_VALUE;
+ nss_MD_win32_map_default_error(GetLastError());
+ return SECFailure;
+ }
+ pMutex->u.sslMutx = hMutex;
+ return SECSuccess;
+}
+
+SECStatus
+sslMutex_Destroy(sslMutex *pMutex, PRBool processLocal)
+{
+ HANDLE hMutex;
+ int rv;
+ int retvalue = SECSuccess;
+
+ PR_ASSERT(pMutex != 0);
+ if (PR_FALSE == pMutex->isMultiProcess) {
+ return single_process_sslMutex_Destroy(pMutex);
+ }
+
+ /* multi-process mode */
+#ifdef WINNT
+ /* on NT, get rid of the PRLock used for fibers within a process */
+ retvalue = sslMutex_2LevelDestroy(pMutex);
+#endif
+
+ PR_ASSERT( pMutex->u.sslMutx != 0 &&
+ pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
+ if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0
+ || hMutex == INVALID_HANDLE_VALUE) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+
+ rv = CloseHandle(hMutex); /* ignore error */
+ if (!processLocal && rv) {
+ pMutex->u.sslMutx = hMutex = INVALID_HANDLE_VALUE;
+ }
+ if (!rv) {
+ nss_MD_win32_map_default_error(GetLastError());
+ retvalue = SECFailure;
+ }
+ return retvalue;
+}
+
+int
+sslMutex_Unlock(sslMutex *pMutex)
+{
+ BOOL success = FALSE;
+ HANDLE hMutex;
+
+ PR_ASSERT(pMutex != 0 );
+ if (PR_FALSE == pMutex->isMultiProcess) {
+ return single_process_sslMutex_Unlock(pMutex);
+ }
+
+ PR_ASSERT(pMutex->u.sslMutx != 0 &&
+ pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
+ if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 ||
+ hMutex == INVALID_HANDLE_VALUE) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ success = ReleaseMutex(hMutex);
+ if (!success) {
+ nss_MD_win32_map_default_error(GetLastError());
+ return SECFailure;
+ }
+#ifdef WINNT
+ return single_process_sslMutex_Unlock(pMutex);
+ /* release PRLock for other fibers in the process */
+#else
+ return SECSuccess;
+#endif
+}
+
+int
+sslMutex_Lock(sslMutex *pMutex)
+{
+ HANDLE hMutex;
+ DWORD event;
+ DWORD lastError;
+ SECStatus rv;
+ SECStatus retvalue = SECSuccess;
+ PR_ASSERT(pMutex != 0);
+
+ if (PR_FALSE == pMutex->isMultiProcess) {
+ return single_process_sslMutex_Lock(pMutex);
+ }
+#ifdef WINNT
+ /* lock first to preserve from other threads/fibers
+ in the same process */
+ retvalue = single_process_sslMutex_Lock(pMutex);
+#endif
+ PR_ASSERT(pMutex->u.sslMutx != 0 &&
+ pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
+ if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 ||
+ hMutex == INVALID_HANDLE_VALUE) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure; /* what else ? */
+ }
+ /* acquire the mutex to be the only owner accross all other processes */
+ event = WaitForSingleObject(hMutex, INFINITE);
+ switch (event) {
+ case WAIT_OBJECT_0:
+ case WAIT_ABANDONED:
+ rv = SECSuccess;
+ break;
+
+ case WAIT_TIMEOUT:
+#if defined(WAIT_IO_COMPLETION)
+ case WAIT_IO_COMPLETION:
+#endif
+ default: /* should never happen. nothing we can do. */
+ PR_ASSERT(!("WaitForSingleObject returned invalid value."));
+ PORT_SetError(PR_UNKNOWN_ERROR);
+ rv = SECFailure;
+ break;
+
+ case WAIT_FAILED: /* failure returns this */
+ rv = SECFailure;
+ lastError = GetLastError(); /* for debugging */
+ nss_MD_win32_map_default_error(lastError);
+ break;
+ }
+
+ if (! (SECSuccess == retvalue && SECSuccess == rv)) {
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+#elif defined(XP_UNIX)
+
+#include <errno.h>
+#include "unix_err.h"
+
+SECStatus
+sslMutex_Init(sslMutex *pMutex, int shared)
+{
+ int rv;
+ PR_ASSERT(pMutex);
+ pMutex->isMultiProcess = (PRBool)(shared != 0);
+ if (!shared) {
+ return single_process_sslMutex_Init(pMutex);
+ }
+ do {
+ rv = sem_init(&pMutex->u.sem, shared, 1);
+ } while (rv < 0 && errno == EINTR);
+ if (rv < 0) {
+ nss_MD_unix_map_default_error(errno);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+sslMutex_Destroy(sslMutex *pMutex, PRBool processLocal)
+{
+ int rv;
+ if (PR_FALSE == pMutex->isMultiProcess) {
+ return single_process_sslMutex_Destroy(pMutex);
+ }
+
+ /* semaphores are global resources. See SEM_DESTROY(3) man page */
+ if (processLocal) {
+ return SECSuccess;
+ }
+ do {
+ rv = sem_destroy(&pMutex->u.sem);
+ } while (rv < 0 && errno == EINTR);
+ if (rv < 0) {
+ nss_MD_unix_map_default_error(errno);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+sslMutex_Unlock(sslMutex *pMutex)
+{
+ int rv;
+ if (PR_FALSE == pMutex->isMultiProcess) {
+ return single_process_sslMutex_Unlock(pMutex);
+ }
+ do {
+ rv = sem_post(&pMutex->u.sem);
+ } while (rv < 0 && errno == EINTR);
+ if (rv < 0) {
+ nss_MD_unix_map_default_error(errno);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+sslMutex_Lock(sslMutex *pMutex)
+{
+ int rv;
+ if (PR_FALSE == pMutex->isMultiProcess) {
+ return single_process_sslMutex_Lock(pMutex);
+ }
+ do {
+ rv = sem_wait(&pMutex->u.sem);
+ } while (rv < 0 && errno == EINTR);
+ if (rv < 0) {
+ nss_MD_unix_map_default_error(errno);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+#else
+
+SECStatus
+sslMutex_Init(sslMutex *pMutex, int shared)
+{
+ PR_ASSERT(pMutex);
+ pMutex->isMultiProcess = (PRBool)(shared != 0);
+ if (!shared) {
+ return single_process_sslMutex_Init(pMutex);
+ }
+ PORT_Assert(!("sslMutex_Init not implemented for multi-process applications !"));
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return SECFailure;
+}
+
+SECStatus
+sslMutex_Destroy(sslMutex *pMutex, PRBool processLocal)
+{
+ PR_ASSERT(pMutex);
+ if (PR_FALSE == pMutex->isMultiProcess) {
+ return single_process_sslMutex_Destroy(pMutex);
+ }
+ PORT_Assert(!("sslMutex_Destroy not implemented for multi-process applications !"));
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return SECFailure;
+}
+
+SECStatus
+sslMutex_Unlock(sslMutex *pMutex)
+{
+ PR_ASSERT(pMutex);
+ if (PR_FALSE == pMutex->isMultiProcess) {
+ return single_process_sslMutex_Unlock(pMutex);
+ }
+ PORT_Assert(!("sslMutex_Unlock not implemented for multi-process applications !"));
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return SECFailure;
+}
+
+SECStatus
+sslMutex_Lock(sslMutex *pMutex)
+{
+ PR_ASSERT(pMutex);
+ if (PR_FALSE == pMutex->isMultiProcess) {
+ return single_process_sslMutex_Lock(pMutex);
+ }
+ PORT_Assert(!("sslMutex_Lock not implemented for multi-process applications !"));
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return SECFailure;
+}
+
+#endif
+
+#endif
diff --git a/chromium/net/third_party/nss/ssl/sslmutex.h b/chromium/net/third_party/nss/ssl/sslmutex.h
new file mode 100644
index 00000000000..b784baf665b
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslmutex.h
@@ -0,0 +1,125 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef __SSLMUTEX_H_
+#define __SSLMUTEX_H_ 1
+
+/* What SSL really wants is portable process-shared unnamed mutexes in
+ * shared memory, that have the property that if the process that holds
+ * them dies, they are released automatically, and that (unlike fcntl
+ * record locking) lock to the thread, not to the process.
+ * NSPR doesn't provide that.
+ * Windows has mutexes that meet that description, but they're not portable.
+ * POSIX mutexes are not automatically released when the holder dies,
+ * and other processes/threads cannot release the mutex on behalf of the
+ * dead holder.
+ * POSIX semaphores can be used to accomplish this on systems that implement
+ * process-shared unnamed POSIX semaphores, because a watchdog thread can
+ * discover and release semaphores that were held by a dead process.
+ * On systems that do not support process-shared POSIX unnamed semaphores,
+ * they can be emulated using pipes.
+ * The performance cost of doing that is not yet measured.
+ *
+ * So, this API looks a lot like POSIX pthread mutexes.
+ */
+
+#include "prtypes.h"
+#include "prlock.h"
+
+#if defined(NETBSD)
+#include <sys/param.h> /* for __NetBSD_Version__ */
+#endif
+
+#if defined(WIN32)
+
+#include <wtypes.h>
+
+typedef struct
+{
+ PRBool isMultiProcess;
+#ifdef WINNT
+ /* on WINNT we need both the PRLock and the Win32 mutex for fibers */
+ struct {
+#else
+ union {
+#endif
+ PRLock* sslLock;
+ HANDLE sslMutx;
+ } u;
+} sslMutex;
+
+typedef int sslPID;
+
+#elif defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD)
+
+#include <sys/types.h>
+#include "prtypes.h"
+
+typedef struct {
+ PRBool isMultiProcess;
+ union {
+ PRLock* sslLock;
+ struct {
+ int mPipes[3];
+ PRInt32 nWaiters;
+ } pipeStr;
+ } u;
+} sslMutex;
+typedef pid_t sslPID;
+
+#elif defined(XP_UNIX) /* other types of Unix */
+
+#include <sys/types.h> /* for pid_t */
+#include <semaphore.h> /* for sem_t, and sem_* functions */
+
+typedef struct
+{
+ PRBool isMultiProcess;
+ union {
+ PRLock* sslLock;
+ sem_t sem;
+ } u;
+} sslMutex;
+
+typedef pid_t sslPID;
+
+#else
+
+/* what platform is this ?? */
+
+typedef struct {
+ PRBool isMultiProcess;
+ union {
+ PRLock* sslLock;
+ /* include cross-process locking mechanism here */
+ } u;
+} sslMutex;
+
+typedef int sslPID;
+
+#endif
+
+#include "seccomon.h"
+
+SEC_BEGIN_PROTOS
+
+extern SECStatus sslMutex_Init(sslMutex *sem, int shared);
+
+/* If processLocal is set to true, then just free resources which are *only* associated
+ * with the current process. Leave any shared resources (including the state of
+ * shared memory) intact. */
+extern SECStatus sslMutex_Destroy(sslMutex *sem, PRBool processLocal);
+
+extern SECStatus sslMutex_Unlock(sslMutex *sem);
+
+extern SECStatus sslMutex_Lock(sslMutex *sem);
+
+#ifdef WINNT
+
+extern SECStatus sslMutex_2LevelInit(sslMutex *sem);
+
+#endif
+
+SEC_END_PROTOS
+
+#endif
diff --git a/chromium/net/third_party/nss/ssl/sslnonce.c b/chromium/net/third_party/nss/ssl/sslnonce.c
new file mode 100644
index 00000000000..5d8a95407aa
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslnonce.c
@@ -0,0 +1,508 @@
+/*
+ * This file implements the CLIENT Session ID cache.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cert.h"
+#include "pk11pub.h"
+#include "secitem.h"
+#include "ssl.h"
+#include "nss.h"
+
+#include "sslimpl.h"
+#include "sslproto.h"
+#include "nssilock.h"
+#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)
+#include <time.h>
+#endif
+
+PRUint32 ssl_sid_timeout = 100;
+PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
+
+static sslSessionID *cache = NULL;
+static PZLock * cacheLock = NULL;
+
+/* sids can be in one of 4 states:
+ *
+ * never_cached, created, but not yet put into cache.
+ * in_client_cache, in the client cache's linked list.
+ * in_server_cache, entry came from the server's cache file.
+ * invalid_cache has been removed from the cache.
+ */
+
+#define LOCK_CACHE lock_cache()
+#define UNLOCK_CACHE PZ_Unlock(cacheLock)
+
+static SECStatus
+ssl_InitClientSessionCacheLock(void)
+{
+ cacheLock = PZ_NewLock(nssILockCache);
+ return cacheLock ? SECSuccess : SECFailure;
+}
+
+static SECStatus
+ssl_FreeClientSessionCacheLock(void)
+{
+ if (cacheLock) {
+ PZ_DestroyLock(cacheLock);
+ cacheLock = NULL;
+ return SECSuccess;
+ }
+ PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+ return SECFailure;
+}
+
+static PRBool LocksInitializedEarly = PR_FALSE;
+
+static SECStatus
+FreeSessionCacheLocks()
+{
+ SECStatus rv1, rv2;
+ rv1 = ssl_FreeSymWrapKeysLock();
+ rv2 = ssl_FreeClientSessionCacheLock();
+ if ( (SECSuccess == rv1) && (SECSuccess == rv2) ) {
+ return SECSuccess;
+ }
+ return SECFailure;
+}
+
+static SECStatus
+InitSessionCacheLocks(void)
+{
+ SECStatus rv1, rv2;
+ PRErrorCode rc;
+ rv1 = ssl_InitSymWrapKeysLock();
+ rv2 = ssl_InitClientSessionCacheLock();
+ if ( (SECSuccess == rv1) && (SECSuccess == rv2) ) {
+ return SECSuccess;
+ }
+ rc = PORT_GetError();
+ FreeSessionCacheLocks();
+ PORT_SetError(rc);
+ return SECFailure;
+}
+
+/* free the session cache locks if they were initialized early */
+SECStatus
+ssl_FreeSessionCacheLocks()
+{
+ PORT_Assert(PR_TRUE == LocksInitializedEarly);
+ if (!LocksInitializedEarly) {
+ PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+ return SECFailure;
+ }
+ FreeSessionCacheLocks();
+ LocksInitializedEarly = PR_FALSE;
+ return SECSuccess;
+}
+
+static PRCallOnceType lockOnce;
+
+/* free the session cache locks if they were initialized lazily */
+static SECStatus ssl_ShutdownLocks(void* appData, void* nssData)
+{
+ PORT_Assert(PR_FALSE == LocksInitializedEarly);
+ if (LocksInitializedEarly) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ FreeSessionCacheLocks();
+ memset(&lockOnce, 0, sizeof(lockOnce));
+ return SECSuccess;
+}
+
+static PRStatus initSessionCacheLocksLazily(void)
+{
+ SECStatus rv = InitSessionCacheLocks();
+ if (SECSuccess != rv) {
+ return PR_FAILURE;
+ }
+ rv = NSS_RegisterShutdown(ssl_ShutdownLocks, NULL);
+ PORT_Assert(SECSuccess == rv);
+ if (SECSuccess != rv) {
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+/* lazyInit means that the call is not happening during a 1-time
+ * initialization function, but rather during dynamic, lazy initialization
+ */
+SECStatus
+ssl_InitSessionCacheLocks(PRBool lazyInit)
+{
+ if (LocksInitializedEarly) {
+ return SECSuccess;
+ }
+
+ if (lazyInit) {
+ return (PR_SUCCESS ==
+ PR_CallOnce(&lockOnce, initSessionCacheLocksLazily)) ?
+ SECSuccess : SECFailure;
+ }
+
+ if (SECSuccess == InitSessionCacheLocks()) {
+ LocksInitializedEarly = PR_TRUE;
+ return SECSuccess;
+ }
+
+ return SECFailure;
+}
+
+static void
+lock_cache(void)
+{
+ ssl_InitSessionCacheLocks(PR_TRUE);
+ PZ_Lock(cacheLock);
+}
+
+/* BEWARE: This function gets called for both client and server SIDs !!
+ * If the unreferenced sid is not in the cache, Free sid and its contents.
+ */
+static void
+ssl_DestroySID(sslSessionID *sid)
+{
+ int i;
+ SSL_TRC(8, ("SSL: destroy sid: sid=0x%x cached=%d", sid, sid->cached));
+ PORT_Assert((sid->references == 0));
+
+ if (sid->cached == in_client_cache)
+ return; /* it will get taken care of next time cache is traversed. */
+
+ if (sid->version < SSL_LIBRARY_VERSION_3_0) {
+ SECITEM_ZfreeItem(&sid->u.ssl2.masterKey, PR_FALSE);
+ SECITEM_ZfreeItem(&sid->u.ssl2.cipherArg, PR_FALSE);
+ }
+ if (sid->peerID != NULL)
+ PORT_Free((void *)sid->peerID); /* CONST */
+
+ if (sid->urlSvrName != NULL)
+ PORT_Free((void *)sid->urlSvrName); /* CONST */
+
+ if ( sid->peerCert ) {
+ CERT_DestroyCertificate(sid->peerCert);
+ }
+ for (i = 0; i < MAX_PEER_CERT_CHAIN_SIZE && sid->peerCertChain[i]; i++) {
+ CERT_DestroyCertificate(sid->peerCertChain[i]);
+ }
+ if (sid->peerCertStatus.items) {
+ SECITEM_FreeArray(&sid->peerCertStatus, PR_FALSE);
+ }
+
+ if ( sid->localCert ) {
+ CERT_DestroyCertificate(sid->localCert);
+ }
+ if (sid->u.ssl3.sessionTicket.ticket.data) {
+ SECITEM_FreeItem(&sid->u.ssl3.sessionTicket.ticket, PR_FALSE);
+ }
+ if (sid->u.ssl3.srvName.data) {
+ SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE);
+ }
+
+ PORT_ZFree(sid, sizeof(sslSessionID));
+}
+
+/* BEWARE: This function gets called for both client and server SIDs !!
+ * Decrement reference count, and
+ * free sid if ref count is zero, and sid is not in the cache.
+ * Does NOT remove from the cache first.
+ * If the sid is still in the cache, it is left there until next time
+ * the cache list is traversed.
+ */
+static void
+ssl_FreeLockedSID(sslSessionID *sid)
+{
+ PORT_Assert(sid->references >= 1);
+ if (--sid->references == 0) {
+ ssl_DestroySID(sid);
+ }
+}
+
+/* BEWARE: This function gets called for both client and server SIDs !!
+ * Decrement reference count, and
+ * free sid if ref count is zero, and sid is not in the cache.
+ * Does NOT remove from the cache first.
+ * These locks are necessary because the sid _might_ be in the cache list.
+ */
+void
+ssl_FreeSID(sslSessionID *sid)
+{
+ LOCK_CACHE;
+ ssl_FreeLockedSID(sid);
+ UNLOCK_CACHE;
+}
+
+/************************************************************************/
+
+/*
+** Lookup sid entry in cache by Address, port, and peerID string.
+** If found, Increment reference count, and return pointer to caller.
+** If it has timed out or ref count is zero, remove from list and free it.
+*/
+
+sslSessionID *
+ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
+ const char * urlSvrName)
+{
+ sslSessionID **sidp;
+ sslSessionID * sid;
+ PRUint32 now;
+
+ if (!urlSvrName)
+ return NULL;
+ now = ssl_Time();
+ LOCK_CACHE;
+ sidp = &cache;
+ while ((sid = *sidp) != 0) {
+ PORT_Assert(sid->cached == in_client_cache);
+ PORT_Assert(sid->references >= 1);
+
+ SSL_TRC(8, ("SSL: Lookup1: sid=0x%x", sid));
+
+ if (sid->expirationTime < now || !sid->references) {
+ /*
+ ** This session-id timed out, or was orphaned.
+ ** Don't even care who it belongs to, blow it out of our cache.
+ */
+ SSL_TRC(7, ("SSL: lookup1, throwing sid out, age=%d refs=%d",
+ now - sid->creationTime, sid->references));
+
+ *sidp = sid->next; /* delink it from the list. */
+ sid->cached = invalid_cache; /* mark not on list. */
+ if (!sid->references)
+ ssl_DestroySID(sid);
+ else
+ ssl_FreeLockedSID(sid); /* drop ref count, free. */
+
+ } else if (!memcmp(&sid->addr, addr, sizeof(PRIPv6Addr)) && /* server IP addr matches */
+ (sid->port == port) && /* server port matches */
+ /* proxy (peerID) matches */
+ (((peerID == NULL) && (sid->peerID == NULL)) ||
+ ((peerID != NULL) && (sid->peerID != NULL) &&
+ PORT_Strcmp(sid->peerID, peerID) == 0)) &&
+ /* is cacheable */
+ (sid->version < SSL_LIBRARY_VERSION_3_0 ||
+ sid->u.ssl3.keys.resumable) &&
+ /* server hostname matches. */
+ (sid->urlSvrName != NULL) &&
+ ((0 == PORT_Strcmp(urlSvrName, sid->urlSvrName)) ||
+ ((sid->peerCert != NULL) && (SECSuccess ==
+ CERT_VerifyCertName(sid->peerCert, urlSvrName))) )
+ ) {
+ /* Hit */
+ sid->lastAccessTime = now;
+ sid->references++;
+ break;
+ } else {
+ sidp = &sid->next;
+ }
+ }
+ UNLOCK_CACHE;
+ return sid;
+}
+
+/*
+** Add an sid to the cache or return a previously cached entry to the cache.
+** Although this is static, it is called via ss->sec.cache().
+*/
+static void
+CacheSID(sslSessionID *sid)
+{
+ PRUint32 expirationPeriod;
+ SSL_TRC(8, ("SSL: Cache: sid=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
+ "time=%x cached=%d",
+ sid, sid->cached, sid->addr.pr_s6_addr32[0],
+ sid->addr.pr_s6_addr32[1], sid->addr.pr_s6_addr32[2],
+ sid->addr.pr_s6_addr32[3], sid->port, sid->creationTime,
+ sid->cached));
+
+ if (sid->cached == in_client_cache)
+ return;
+
+ if (!sid->urlSvrName) {
+ /* don't cache this SID because it can never be matched */
+ return;
+ }
+
+ /* XXX should be different trace for version 2 vs. version 3 */
+ if (sid->version < SSL_LIBRARY_VERSION_3_0) {
+ expirationPeriod = ssl_sid_timeout;
+ PRINT_BUF(8, (0, "sessionID:",
+ sid->u.ssl2.sessionID, sizeof(sid->u.ssl2.sessionID)));
+ PRINT_BUF(8, (0, "masterKey:",
+ sid->u.ssl2.masterKey.data, sid->u.ssl2.masterKey.len));
+ PRINT_BUF(8, (0, "cipherArg:",
+ sid->u.ssl2.cipherArg.data, sid->u.ssl2.cipherArg.len));
+ } else {
+ if (sid->u.ssl3.sessionIDLength == 0 &&
+ sid->u.ssl3.sessionTicket.ticket.data == NULL)
+ return;
+ /* Client generates the SessionID if this was a stateless resume. */
+ if (sid->u.ssl3.sessionIDLength == 0) {
+ SECStatus rv;
+ rv = PK11_GenerateRandom(sid->u.ssl3.sessionID,
+ SSL3_SESSIONID_BYTES);
+ if (rv != SECSuccess)
+ return;
+ sid->u.ssl3.sessionIDLength = SSL3_SESSIONID_BYTES;
+ }
+ expirationPeriod = ssl3_sid_timeout;
+ PRINT_BUF(8, (0, "sessionID:",
+ sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength));
+ }
+ PORT_Assert(sid->creationTime != 0 && sid->expirationTime != 0);
+ if (!sid->creationTime)
+ sid->lastAccessTime = sid->creationTime = ssl_Time();
+ if (!sid->expirationTime)
+ sid->expirationTime = sid->creationTime + expirationPeriod;
+
+ /*
+ * Put sid into the cache. Bump reference count to indicate that
+ * cache is holding a reference. Uncache will reduce the cache
+ * reference.
+ */
+ LOCK_CACHE;
+ sid->references++;
+ sid->cached = in_client_cache;
+ sid->next = cache;
+ cache = sid;
+ UNLOCK_CACHE;
+}
+
+/*
+ * If sid "zap" is in the cache,
+ * removes sid from cache, and decrements reference count.
+ * Caller must hold cache lock.
+ */
+static void
+UncacheSID(sslSessionID *zap)
+{
+ sslSessionID **sidp = &cache;
+ sslSessionID *sid;
+
+ if (zap->cached != in_client_cache) {
+ return;
+ }
+
+ SSL_TRC(8,("SSL: Uncache: zap=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
+ "time=%x cipher=%d",
+ zap, zap->cached, zap->addr.pr_s6_addr32[0],
+ zap->addr.pr_s6_addr32[1], zap->addr.pr_s6_addr32[2],
+ zap->addr.pr_s6_addr32[3], zap->port, zap->creationTime,
+ zap->u.ssl2.cipherType));
+ if (zap->version < SSL_LIBRARY_VERSION_3_0) {
+ PRINT_BUF(8, (0, "sessionID:",
+ zap->u.ssl2.sessionID, sizeof(zap->u.ssl2.sessionID)));
+ PRINT_BUF(8, (0, "masterKey:",
+ zap->u.ssl2.masterKey.data, zap->u.ssl2.masterKey.len));
+ PRINT_BUF(8, (0, "cipherArg:",
+ zap->u.ssl2.cipherArg.data, zap->u.ssl2.cipherArg.len));
+ }
+
+ /* See if it's in the cache, if so nuke it */
+ while ((sid = *sidp) != 0) {
+ if (sid == zap) {
+ /*
+ ** Bingo. Reduce reference count by one so that when
+ ** everyone is done with the sid we can free it up.
+ */
+ *sidp = zap->next;
+ zap->cached = invalid_cache;
+ ssl_FreeLockedSID(zap);
+ return;
+ }
+ sidp = &sid->next;
+ }
+}
+
+/* If sid "zap" is in the cache,
+ * removes sid from cache, and decrements reference count.
+ * Although this function is static, it is called externally via
+ * ss->sec.uncache().
+ */
+static void
+LockAndUncacheSID(sslSessionID *zap)
+{
+ LOCK_CACHE;
+ UncacheSID(zap);
+ UNLOCK_CACHE;
+
+}
+
+/* choose client or server cache functions for this sslsocket. */
+void
+ssl_ChooseSessionIDProcs(sslSecurityInfo *sec)
+{
+ if (sec->isServer) {
+ sec->cache = ssl_sid_cache;
+ sec->uncache = ssl_sid_uncache;
+ } else {
+ sec->cache = CacheSID;
+ sec->uncache = LockAndUncacheSID;
+ }
+}
+
+/* wipe out the entire client session cache. */
+void
+SSL_ClearSessionCache(void)
+{
+ LOCK_CACHE;
+ while(cache != NULL)
+ UncacheSID(cache);
+ UNLOCK_CACHE;
+}
+
+/* returns an unsigned int containing the number of seconds in PR_Now() */
+PRUint32
+ssl_Time(void)
+{
+ PRUint32 myTime;
+#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)
+ myTime = time(NULL); /* accurate until the year 2038. */
+#else
+ /* portable, but possibly slower */
+ PRTime now;
+ PRInt64 ll;
+
+ now = PR_Now();
+ LL_I2L(ll, 1000000L);
+ LL_DIV(now, now, ll);
+ LL_L2UI(myTime, now);
+#endif
+ return myTime;
+}
+
+SECStatus
+ssl3_SetSIDSessionTicket(sslSessionID *sid, NewSessionTicket *session_ticket)
+{
+ SECStatus rv;
+
+ /* We need to lock the cache, as this sid might already be in the cache. */
+ LOCK_CACHE;
+
+ /* A server might have sent us an empty ticket, which has the
+ * effect of clearing the previously known ticket.
+ */
+ if (sid->u.ssl3.sessionTicket.ticket.data)
+ SECITEM_FreeItem(&sid->u.ssl3.sessionTicket.ticket, PR_FALSE);
+ if (session_ticket->ticket.len > 0) {
+ rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.sessionTicket.ticket,
+ &session_ticket->ticket);
+ if (rv != SECSuccess) {
+ UNLOCK_CACHE;
+ return rv;
+ }
+ } else {
+ sid->u.ssl3.sessionTicket.ticket.data = NULL;
+ sid->u.ssl3.sessionTicket.ticket.len = 0;
+ }
+ sid->u.ssl3.sessionTicket.received_timestamp =
+ session_ticket->received_timestamp;
+ sid->u.ssl3.sessionTicket.ticket_lifetime_hint =
+ session_ticket->ticket_lifetime_hint;
+
+ UNLOCK_CACHE;
+ return SECSuccess;
+}
diff --git a/chromium/net/third_party/nss/ssl/sslplatf.c b/chromium/net/third_party/nss/ssl/sslplatf.c
new file mode 100644
index 00000000000..fee702191a7
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslplatf.c
@@ -0,0 +1,732 @@
+/*
+ * Platform specific crypto wrappers
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Ryan Sleevi <ryan.sleevi@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/* $Id$ */
+#include "certt.h"
+#include "cryptohi.h"
+#include "keythi.h"
+#include "nss.h"
+#include "secitem.h"
+#include "ssl.h"
+#include "sslimpl.h"
+#include "prerror.h"
+#include "prinit.h"
+
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+#ifdef XP_WIN32
+#include <NCrypt.h>
+#endif
+#endif
+
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+CERTCertificateList*
+hack_NewCertificateListFromCertList(CERTCertList* list)
+{
+ CERTCertificateList * chain = NULL;
+ PLArenaPool * arena = NULL;
+ CERTCertListNode * node;
+ int len;
+
+ if (CERT_LIST_EMPTY(list))
+ goto loser;
+
+ arena = PORT_NewArena(4096);
+ if (arena == NULL)
+ goto loser;
+
+ for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
+ len++, node = CERT_LIST_NEXT(node)) {
+ }
+
+ chain = PORT_ArenaNew(arena, CERTCertificateList);
+ if (chain == NULL)
+ goto loser;
+
+ chain->certs = PORT_ArenaNewArray(arena, SECItem, len);
+ if (!chain->certs)
+ goto loser;
+ chain->len = len;
+
+ for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
+ len++, node = CERT_LIST_NEXT(node)) {
+ // Check to see if the last cert to be sent is a self-signed cert,
+ // and if so, omit it from the list of certificates. However, if
+ // there is only one cert (len == 0), include the cert, as it means
+ // the EE cert is self-signed.
+ if (len > 0 && (len == chain->len - 1) && node->cert->isRoot) {
+ chain->len = len;
+ break;
+ }
+ SECITEM_CopyItem(arena, &chain->certs[len], &node->cert->derCert);
+ }
+
+ chain->arena = arena;
+ return chain;
+
+loser:
+ if (arena) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ return NULL;
+}
+
+#if defined(XP_WIN32)
+typedef SECURITY_STATUS (WINAPI *NCryptFreeObjectFunc)(NCRYPT_HANDLE);
+typedef SECURITY_STATUS (WINAPI *NCryptSignHashFunc)(
+ NCRYPT_KEY_HANDLE /* hKey */,
+ VOID* /* pPaddingInfo */,
+ PBYTE /* pbHashValue */,
+ DWORD /* cbHashValue */,
+ PBYTE /* pbSignature */,
+ DWORD /* cbSignature */,
+ DWORD* /* pcbResult */,
+ DWORD /* dwFlags */);
+
+static PRCallOnceType cngFunctionsInitOnce;
+static const PRCallOnceType pristineCallOnce;
+
+static PRLibrary *ncrypt_library = NULL;
+static NCryptFreeObjectFunc pNCryptFreeObject = NULL;
+static NCryptSignHashFunc pNCryptSignHash = NULL;
+
+static SECStatus
+ssl_ShutdownCngFunctions(void *appData, void *nssData)
+{
+ pNCryptSignHash = NULL;
+ pNCryptFreeObject = NULL;
+ if (ncrypt_library) {
+ PR_UnloadLibrary(ncrypt_library);
+ ncrypt_library = NULL;
+ }
+
+ cngFunctionsInitOnce = pristineCallOnce;
+
+ return SECSuccess;
+}
+
+static PRStatus
+ssl_InitCngFunctions(void)
+{
+ SECStatus rv;
+
+ ncrypt_library = PR_LoadLibrary("ncrypt.dll");
+ if (ncrypt_library == NULL)
+ goto loser;
+
+ pNCryptFreeObject = (NCryptFreeObjectFunc)PR_FindFunctionSymbol(
+ ncrypt_library, "NCryptFreeObject");
+ if (pNCryptFreeObject == NULL)
+ goto loser;
+
+ pNCryptSignHash = (NCryptSignHashFunc)PR_FindFunctionSymbol(
+ ncrypt_library, "NCryptSignHash");
+ if (pNCryptSignHash == NULL)
+ goto loser;
+
+ rv = NSS_RegisterShutdown(ssl_ShutdownCngFunctions, NULL);
+ if (rv != SECSuccess)
+ goto loser;
+
+ return PR_SUCCESS;
+
+loser:
+ pNCryptSignHash = NULL;
+ pNCryptFreeObject = NULL;
+ if (ncrypt_library) {
+ PR_UnloadLibrary(ncrypt_library);
+ ncrypt_library = NULL;
+ }
+
+ return PR_FAILURE;
+}
+
+static SECStatus
+ssl_InitCng(void)
+{
+ if (PR_CallOnce(&cngFunctionsInitOnce, ssl_InitCngFunctions) != PR_SUCCESS)
+ return SECFailure;
+ return SECSuccess;
+}
+
+void
+ssl_FreePlatformKey(PlatformKey key)
+{
+ if (!key)
+ return;
+
+ if (key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) {
+ if (ssl_InitCng() == SECSuccess) {
+ (*pNCryptFreeObject)(key->hNCryptKey);
+ }
+ } else {
+ CryptReleaseContext(key->hCryptProv, 0);
+ }
+ PORT_Free(key);
+}
+
+static SECStatus
+ssl3_CngPlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
+ PRBool isTLS, KeyType keyType)
+{
+ SECStatus rv = SECFailure;
+ SECURITY_STATUS ncrypt_status;
+ PRBool doDerEncode = PR_FALSE;
+ SECItem hashItem;
+ DWORD signatureLen = 0;
+ DWORD dwFlags = 0;
+ VOID *pPaddingInfo = NULL;
+
+ /* Always encode using PKCS#1 block type. */
+ BCRYPT_PKCS1_PADDING_INFO rsaPaddingInfo;
+
+ if (key->dwKeySpec != CERT_NCRYPT_KEY_SPEC) {
+ PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
+ return SECFailure;
+ }
+ if (ssl_InitCng() != SECSuccess) {
+ PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
+ return SECFailure;
+ }
+
+ switch (keyType) {
+ case rsaKey:
+ switch (hash->hashAlg) {
+ case SEC_OID_UNKNOWN:
+ /* No OID/encoded DigestInfo. */
+ rsaPaddingInfo.pszAlgId = NULL;
+ break;
+ case SEC_OID_SHA1:
+ rsaPaddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM;
+ break;
+ case SEC_OID_SHA256:
+ rsaPaddingInfo.pszAlgId = BCRYPT_SHA256_ALGORITHM;
+ break;
+ case SEC_OID_SHA384:
+ rsaPaddingInfo.pszAlgId = BCRYPT_SHA384_ALGORITHM;
+ break;
+ case SEC_OID_SHA512:
+ rsaPaddingInfo.pszAlgId = BCRYPT_SHA512_ALGORITHM;
+ break;
+ default:
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
+ return SECFailure;
+ }
+ hashItem.data = hash->u.raw;
+ hashItem.len = hash->len;
+ dwFlags = BCRYPT_PAD_PKCS1;
+ pPaddingInfo = &rsaPaddingInfo;
+ break;
+ case dsaKey:
+ case ecKey:
+ if (keyType == ecKey) {
+ doDerEncode = PR_TRUE;
+ } else {
+ doDerEncode = isTLS;
+ }
+ if (hash->hashAlg == SEC_OID_UNKNOWN) {
+ hashItem.data = hash->u.s.sha;
+ hashItem.len = sizeof(hash->u.s.sha);
+ } else {
+ hashItem.data = hash->u.raw;
+ hashItem.len = hash->len;
+ }
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ goto done;
+ }
+ PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len));
+
+ ncrypt_status = (*pNCryptSignHash)(key->hNCryptKey, pPaddingInfo,
+ (PBYTE)hashItem.data, hashItem.len,
+ NULL, 0, &signatureLen, dwFlags);
+ if (FAILED(ncrypt_status) || signatureLen == 0) {
+ PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, ncrypt_status);
+ goto done;
+ }
+
+ buf->data = (unsigned char *)PORT_Alloc(signatureLen);
+ if (!buf->data) {
+ goto done; /* error code was set. */
+ }
+
+ ncrypt_status = (*pNCryptSignHash)(key->hNCryptKey, pPaddingInfo,
+ (PBYTE)hashItem.data, hashItem.len,
+ (PBYTE)buf->data, signatureLen,
+ &signatureLen, dwFlags);
+ if (FAILED(ncrypt_status) || signatureLen == 0) {
+ PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, ncrypt_status);
+ goto done;
+ }
+
+ buf->len = signatureLen;
+
+ if (doDerEncode) {
+ SECItem derSig = {siBuffer, NULL, 0};
+
+ /* This also works for an ECDSA signature */
+ rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len);
+ if (rv == SECSuccess) {
+ PORT_Free(buf->data); /* discard unencoded signature. */
+ *buf = derSig; /* give caller encoded signature. */
+ } else if (derSig.data) {
+ PORT_Free(derSig.data);
+ }
+ } else {
+ rv = SECSuccess;
+ }
+
+ PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len));
+
+done:
+ if (rv != SECSuccess && buf->data) {
+ PORT_Free(buf->data);
+ buf->data = NULL;
+ buf->len = 0;
+ }
+
+ return rv;
+}
+
+static SECStatus
+ssl3_CAPIPlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
+ PRBool isTLS, KeyType keyType)
+{
+ SECStatus rv = SECFailure;
+ PRBool doDerEncode = PR_FALSE;
+ SECItem hashItem;
+ DWORD argLen = 0;
+ DWORD signatureLen = 0;
+ ALG_ID hashAlg = 0;
+ HCRYPTHASH hHash = 0;
+ DWORD hashLen = 0;
+ unsigned int i = 0;
+
+ buf->data = NULL;
+
+ switch (hash->hashAlg) {
+ case SEC_OID_UNKNOWN:
+ hashAlg = 0;
+ break;
+ case SEC_OID_SHA1:
+ hashAlg = CALG_SHA1;
+ break;
+ case SEC_OID_SHA256:
+ hashAlg = CALG_SHA_256;
+ break;
+ case SEC_OID_SHA384:
+ hashAlg = CALG_SHA_384;
+ break;
+ case SEC_OID_SHA512:
+ hashAlg = CALG_SHA_512;
+ break;
+ default:
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
+ return SECFailure;
+ }
+
+ switch (keyType) {
+ case rsaKey:
+ if (hashAlg == 0) {
+ hashAlg = CALG_SSL3_SHAMD5;
+ }
+ hashItem.data = hash->u.raw;
+ hashItem.len = hash->len;
+ break;
+ case dsaKey:
+ case ecKey:
+ if (keyType == ecKey) {
+ doDerEncode = PR_TRUE;
+ } else {
+ doDerEncode = isTLS;
+ }
+ if (hashAlg == 0) {
+ hashAlg = CALG_SHA1;
+ hashItem.data = hash->u.s.sha;
+ hashItem.len = sizeof(hash->u.s.sha);
+ } else {
+ hashItem.data = hash->u.raw;
+ hashItem.len = hash->len;
+ }
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ goto done;
+ }
+ PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len));
+
+ if (!CryptCreateHash(key->hCryptProv, hashAlg, 0, 0, &hHash)) {
+ PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError());
+ goto done;
+ }
+ argLen = sizeof(hashLen);
+ if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hashLen, &argLen, 0)) {
+ PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError());
+ goto done;
+ }
+ if (hashLen != hashItem.len) {
+ PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, 0);
+ goto done;
+ }
+ if (!CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*)hashItem.data, 0)) {
+ PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError());
+ goto done;
+ }
+ if (!CryptSignHash(hHash, key->dwKeySpec, NULL, 0,
+ NULL, &signatureLen) || signatureLen == 0) {
+ PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError());
+ goto done;
+ }
+ buf->data = (unsigned char *)PORT_Alloc(signatureLen);
+ if (!buf->data)
+ goto done; /* error code was set. */
+
+ if (!CryptSignHash(hHash, key->dwKeySpec, NULL, 0,
+ (BYTE*)buf->data, &signatureLen)) {
+ PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError());
+ goto done;
+ }
+ buf->len = signatureLen;
+
+ /* CryptoAPI signs in little-endian, so reverse */
+ for (i = 0; i < buf->len / 2; ++i) {
+ unsigned char tmp = buf->data[i];
+ buf->data[i] = buf->data[buf->len - 1 - i];
+ buf->data[buf->len - 1 - i] = tmp;
+ }
+ if (doDerEncode) {
+ SECItem derSig = {siBuffer, NULL, 0};
+
+ /* This also works for an ECDSA signature */
+ rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len);
+ if (rv == SECSuccess) {
+ PORT_Free(buf->data); /* discard unencoded signature. */
+ *buf = derSig; /* give caller encoded signature. */
+ } else if (derSig.data) {
+ PORT_Free(derSig.data);
+ }
+ } else {
+ rv = SECSuccess;
+ }
+
+ PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len));
+done:
+ if (hHash)
+ CryptDestroyHash(hHash);
+ if (rv != SECSuccess && buf->data) {
+ PORT_Free(buf->data);
+ buf->data = NULL;
+ }
+ return rv;
+}
+
+SECStatus
+ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
+ PRBool isTLS, KeyType keyType)
+{
+ if (key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) {
+ return ssl3_CngPlatformSignHashes(hash, key, buf, isTLS, keyType);
+ }
+ return ssl3_CAPIPlatformSignHashes(hash, key, buf, isTLS, keyType);
+}
+
+#elif defined(XP_MACOSX)
+#include <Security/cssm.h>
+
+void
+ssl_FreePlatformKey(PlatformKey key)
+{
+ CFRelease(key);
+}
+
+#define SSL_MAX_DIGEST_INFO_PREFIX 20
+
+/* ssl3_GetDigestInfoPrefix sets |out| and |out_len| to point to a buffer that
+ * contains ASN.1 data that should be prepended to a hash of the given type in
+ * order to create a DigestInfo structure that is valid for use in a PKCS #1
+ * v1.5 RSA signature. |out_len| will not be set to a value greater than
+ * SSL_MAX_DIGEST_INFO_PREFIX. */
+static SECStatus
+ssl3_GetDigestInfoPrefix(SECOidTag hashAlg,
+ const SSL3Opaque** out, unsigned int *out_len)
+{
+ /* These are the DER encoding of ASN.1 DigestInfo structures:
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm AlgorithmIdentifier,
+ * digest OCTET STRING
+ * }
+ * See PKCS #1 v2.2 Section 9.2, Note 1.
+ */
+ static const unsigned char kSHA1[] = {
+ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
+ 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14
+ };
+ static const unsigned char kSHA224[] = {
+ 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05,
+ 0x00, 0x04, 0x1c
+ };
+ static const unsigned char kSHA256[] = {
+ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x04, 0x20
+ };
+ static const unsigned char kSHA384[] = {
+ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
+ 0x00, 0x04, 0x30
+ };
+ static const unsigned char kSHA512[] = {
+ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+ 0x00, 0x04, 0x40
+ };
+
+ switch (hashAlg) {
+ case SEC_OID_UNKNOWN:
+ *out_len = 0;
+ break;
+ case SEC_OID_SHA1:
+ *out = kSHA1;
+ *out_len = sizeof(kSHA1);
+ break;
+ case SEC_OID_SHA224:
+ *out = kSHA224;
+ *out_len = sizeof(kSHA224);
+ break;
+ case SEC_OID_SHA256:
+ *out = kSHA256;
+ *out_len = sizeof(kSHA256);
+ break;
+ case SEC_OID_SHA384:
+ *out = kSHA384;
+ *out_len = sizeof(kSHA384);
+ break;
+ case SEC_OID_SHA512:
+ *out = kSHA512;
+ *out_len = sizeof(kSHA512);
+ break;
+ default:
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+SECStatus
+ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
+ PRBool isTLS, KeyType keyType)
+{
+ SECStatus rv = SECFailure;
+ PRBool doDerEncode = PR_FALSE;
+ unsigned int signatureLen;
+ OSStatus status = noErr;
+ CSSM_CSP_HANDLE cspHandle = 0;
+ const CSSM_KEY *cssmKey = NULL;
+ CSSM_ALGORITHMS sigAlg;
+ CSSM_ALGORITHMS digestAlg;
+ const CSSM_ACCESS_CREDENTIALS * cssmCreds = NULL;
+ CSSM_RETURN cssmRv;
+ CSSM_DATA hashData;
+ CSSM_DATA signatureData;
+ CSSM_CC_HANDLE cssmSignature = 0;
+ const SSL3Opaque* prefix;
+ unsigned int prefixLen;
+ SSL3Opaque prefixAndHash[SSL_MAX_DIGEST_INFO_PREFIX + HASH_LENGTH_MAX];
+
+ buf->data = NULL;
+
+ status = SecKeyGetCSPHandle(key, &cspHandle);
+ if (status != noErr) {
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ goto done;
+ }
+
+ status = SecKeyGetCSSMKey(key, &cssmKey);
+ if (status != noErr || !cssmKey) {
+ PORT_SetError(SEC_ERROR_NO_KEY);
+ goto done;
+ }
+
+ /* SecKeyGetBlockSize wasn't addeded until OS X 10.6 - but the
+ * needed information is readily available on the key itself.
+ */
+ signatureLen = (cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8;
+
+ if (signatureLen == 0) {
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ goto done;
+ }
+
+ buf->data = (unsigned char *)PORT_Alloc(signatureLen);
+ if (!buf->data)
+ goto done; /* error code was set. */
+
+ sigAlg = cssmKey->KeyHeader.AlgorithmId;
+ digestAlg = CSSM_ALGID_NONE;
+
+ switch (keyType) {
+ case rsaKey:
+ PORT_Assert(sigAlg == CSSM_ALGID_RSA);
+ if (ssl3_GetDigestInfoPrefix(hash->hashAlg, &prefix, &prefixLen) !=
+ SECSuccess) {
+ goto done;
+ }
+ if (prefixLen + hash->len > sizeof(prefixAndHash)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ goto done;
+ }
+ memcpy(prefixAndHash, prefix, prefixLen);
+ memcpy(prefixAndHash + prefixLen, hash->u.raw, hash->len);
+ hashData.Data = prefixAndHash;
+ hashData.Length = prefixLen + hash->len;
+ break;
+ case dsaKey:
+ case ecKey:
+ if (keyType == ecKey) {
+ PORT_Assert(sigAlg == CSSM_ALGID_ECDSA);
+ doDerEncode = PR_TRUE;
+ } else {
+ PORT_Assert(sigAlg == CSSM_ALGID_DSA);
+ doDerEncode = isTLS;
+ }
+ if (hash->hashAlg == SEC_OID_UNKNOWN) {
+ hashData.Data = hash->u.s.sha;
+ hashData.Length = sizeof(hash->u.s.sha);
+ } else {
+ hashData.Data = hash->u.raw;
+ hashData.Length = hash->len;
+ }
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ goto done;
+ }
+ PRINT_BUF(60, (NULL, "hash(es) to be signed", hashData.Data, hashData.Length));
+
+ /* TODO(rsleevi): Should it be kSecCredentialTypeNoUI? In Win32, at least,
+ * you can prevent the UI by setting the provider handle on the
+ * certificate to be opened with CRYPT_SILENT, but is there an equivalent?
+ */
+ status = SecKeyGetCredentials(key, CSSM_ACL_AUTHORIZATION_SIGN,
+ kSecCredentialTypeDefault, &cssmCreds);
+ if (status != noErr) {
+ PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, status);
+ goto done;
+ }
+
+ signatureData.Length = signatureLen;
+ signatureData.Data = (uint8*)buf->data;
+
+ cssmRv = CSSM_CSP_CreateSignatureContext(cspHandle, sigAlg, cssmCreds,
+ cssmKey, &cssmSignature);
+ if (cssmRv) {
+ PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv);
+ goto done;
+ }
+
+ /* See "Apple Cryptographic Service Provider Functional Specification" */
+ if (cssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) {
+ /* To set RSA blinding for RSA keys */
+ CSSM_CONTEXT_ATTRIBUTE blindingAttr;
+ blindingAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING;
+ blindingAttr.AttributeLength = sizeof(uint32);
+ blindingAttr.Attribute.Uint32 = 1;
+ cssmRv = CSSM_UpdateContextAttributes(cssmSignature, 1, &blindingAttr);
+ if (cssmRv) {
+ PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv);
+ goto done;
+ }
+ }
+
+ cssmRv = CSSM_SignData(cssmSignature, &hashData, 1, digestAlg,
+ &signatureData);
+ if (cssmRv) {
+ PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv);
+ goto done;
+ }
+ buf->len = signatureData.Length;
+
+ if (doDerEncode) {
+ SECItem derSig = {siBuffer, NULL, 0};
+
+ /* This also works for an ECDSA signature */
+ rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len);
+ if (rv == SECSuccess) {
+ PORT_Free(buf->data); /* discard unencoded signature. */
+ *buf = derSig; /* give caller encoded signature. */
+ } else if (derSig.data) {
+ PORT_Free(derSig.data);
+ }
+ } else {
+ rv = SECSuccess;
+ }
+
+ PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len));
+done:
+ /* cspHandle, cssmKey, and cssmCreds are owned by the SecKeyRef and
+ * should not be freed. When the PlatformKey is freed, they will be
+ * released.
+ */
+ if (cssmSignature)
+ CSSM_DeleteContext(cssmSignature);
+
+ if (rv != SECSuccess && buf->data) {
+ PORT_Free(buf->data);
+ buf->data = NULL;
+ }
+ return rv;
+}
+#else
+void
+ssl_FreePlatformKey(PlatformKey key)
+{
+}
+
+SECStatus
+ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
+ PRBool isTLS, KeyType keyType)
+{
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return SECFailure;
+}
+#endif
+
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
diff --git a/chromium/net/third_party/nss/ssl/sslproto.h b/chromium/net/third_party/nss/ssl/sslproto.h
new file mode 100644
index 00000000000..53bba011bb9
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslproto.h
@@ -0,0 +1,231 @@
+/*
+ * Various and sundry protocol constants. DON'T CHANGE THESE. These values
+ * are mostly defined by the SSL2, SSL3, or TLS protocol specifications.
+ * Cipher kinds and ciphersuites are part of the public API.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __sslproto_h_
+#define __sslproto_h_
+
+/* All versions less than 3_0 are treated as SSL version 2 */
+#define SSL_LIBRARY_VERSION_2 0x0002
+#define SSL_LIBRARY_VERSION_3_0 0x0300
+#define SSL_LIBRARY_VERSION_TLS_1_0 0x0301
+#define SSL_LIBRARY_VERSION_TLS_1_1 0x0302
+#define SSL_LIBRARY_VERSION_TLS_1_2 0x0303
+/* Note: this is the internal format, not the wire format */
+#define SSL_LIBRARY_VERSION_DTLS_1_0 0x0302
+
+/* deprecated old name */
+#define SSL_LIBRARY_VERSION_3_1_TLS SSL_LIBRARY_VERSION_TLS_1_0
+
+/* The DTLS version used in the spec */
+#define SSL_LIBRARY_VERSION_DTLS_1_0_WIRE ((~0x0100) & 0xffff)
+
+/* Header lengths of some of the messages */
+#define SSL_HL_ERROR_HBYTES 3
+#define SSL_HL_CLIENT_HELLO_HBYTES 9
+#define SSL_HL_CLIENT_MASTER_KEY_HBYTES 10
+#define SSL_HL_CLIENT_FINISHED_HBYTES 1
+#define SSL_HL_SERVER_HELLO_HBYTES 11
+#define SSL_HL_SERVER_VERIFY_HBYTES 1
+#define SSL_HL_SERVER_FINISHED_HBYTES 1
+#define SSL_HL_REQUEST_CERTIFICATE_HBYTES 2
+#define SSL_HL_CLIENT_CERTIFICATE_HBYTES 6
+
+/* Security handshake protocol codes */
+#define SSL_MT_ERROR 0
+#define SSL_MT_CLIENT_HELLO 1
+#define SSL_MT_CLIENT_MASTER_KEY 2
+#define SSL_MT_CLIENT_FINISHED 3
+#define SSL_MT_SERVER_HELLO 4
+#define SSL_MT_SERVER_VERIFY 5
+#define SSL_MT_SERVER_FINISHED 6
+#define SSL_MT_REQUEST_CERTIFICATE 7
+#define SSL_MT_CLIENT_CERTIFICATE 8
+
+/* Certificate types */
+#define SSL_CT_X509_CERTIFICATE 0x01
+#if 0 /* XXX Not implemented yet */
+#define SSL_PKCS6_CERTIFICATE 0x02
+#endif
+#define SSL_AT_MD5_WITH_RSA_ENCRYPTION 0x01
+
+/* Error codes */
+#define SSL_PE_NO_CYPHERS 0x0001
+#define SSL_PE_NO_CERTIFICATE 0x0002
+#define SSL_PE_BAD_CERTIFICATE 0x0004
+#define SSL_PE_UNSUPPORTED_CERTIFICATE_TYPE 0x0006
+
+/* Cypher kinds (not the spec version!) */
+#define SSL_CK_RC4_128_WITH_MD5 0x01
+#define SSL_CK_RC4_128_EXPORT40_WITH_MD5 0x02
+#define SSL_CK_RC2_128_CBC_WITH_MD5 0x03
+#define SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5 0x04
+#define SSL_CK_IDEA_128_CBC_WITH_MD5 0x05
+#define SSL_CK_DES_64_CBC_WITH_MD5 0x06
+#define SSL_CK_DES_192_EDE3_CBC_WITH_MD5 0x07
+
+/* Cipher enables. These are used only for SSL_EnableCipher
+ * These values define the SSL2 suites, and do not colide with the
+ * SSL3 Cipher suites defined below.
+ */
+#define SSL_EN_RC4_128_WITH_MD5 0xFF01
+#define SSL_EN_RC4_128_EXPORT40_WITH_MD5 0xFF02
+#define SSL_EN_RC2_128_CBC_WITH_MD5 0xFF03
+#define SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5 0xFF04
+#define SSL_EN_IDEA_128_CBC_WITH_MD5 0xFF05
+#define SSL_EN_DES_64_CBC_WITH_MD5 0xFF06
+#define SSL_EN_DES_192_EDE3_CBC_WITH_MD5 0xFF07
+
+/* SSL v3 Cipher Suites */
+#define SSL_NULL_WITH_NULL_NULL 0x0000
+
+#define SSL_RSA_WITH_NULL_MD5 0x0001
+#define SSL_RSA_WITH_NULL_SHA 0x0002
+#define SSL_RSA_EXPORT_WITH_RC4_40_MD5 0x0003
+#define SSL_RSA_WITH_RC4_128_MD5 0x0004
+#define SSL_RSA_WITH_RC4_128_SHA 0x0005
+#define SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 0x0006
+#define SSL_RSA_WITH_IDEA_CBC_SHA 0x0007
+#define SSL_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0008
+#define SSL_RSA_WITH_DES_CBC_SHA 0x0009
+#define SSL_RSA_WITH_3DES_EDE_CBC_SHA 0x000a
+
+#define SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA 0x000b
+#define SSL_DH_DSS_WITH_DES_CBC_SHA 0x000c
+#define SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA 0x000d
+#define SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA 0x000e
+#define SSL_DH_RSA_WITH_DES_CBC_SHA 0x000f
+#define SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA 0x0010
+
+#define SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA 0x0011
+#define SSL_DHE_DSS_WITH_DES_CBC_SHA 0x0012
+#define SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA 0x0013
+#define SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0014
+#define SSL_DHE_RSA_WITH_DES_CBC_SHA 0x0015
+#define SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x0016
+
+#define SSL_DH_ANON_EXPORT_WITH_RC4_40_MD5 0x0017
+#define SSL_DH_ANON_WITH_RC4_128_MD5 0x0018
+#define SSL_DH_ANON_EXPORT_WITH_DES40_CBC_SHA 0x0019
+#define SSL_DH_ANON_WITH_DES_CBC_SHA 0x001a
+#define SSL_DH_ANON_WITH_3DES_EDE_CBC_SHA 0x001b
+
+#define SSL_FORTEZZA_DMS_WITH_NULL_SHA 0x001c /* deprecated */
+#define SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA 0x001d /* deprecated */
+#define SSL_FORTEZZA_DMS_WITH_RC4_128_SHA 0x001e /* deprecated */
+
+/* New TLS cipher suites */
+#define TLS_RSA_WITH_AES_128_CBC_SHA 0x002F
+#define TLS_DH_DSS_WITH_AES_128_CBC_SHA 0x0030
+#define TLS_DH_RSA_WITH_AES_128_CBC_SHA 0x0031
+#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA 0x0032
+#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033
+#define TLS_DH_ANON_WITH_AES_128_CBC_SHA 0x0034
+
+#define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035
+#define TLS_DH_DSS_WITH_AES_256_CBC_SHA 0x0036
+#define TLS_DH_RSA_WITH_AES_256_CBC_SHA 0x0037
+#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA 0x0038
+#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039
+#define TLS_DH_ANON_WITH_AES_256_CBC_SHA 0x003A
+#define TLS_RSA_WITH_NULL_SHA256 0x003B
+#define TLS_RSA_WITH_AES_128_CBC_SHA256 0x003C
+#define TLS_RSA_WITH_AES_256_CBC_SHA256 0x003D
+
+#define TLS_RSA_WITH_CAMELLIA_128_CBC_SHA 0x0041
+#define TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA 0x0042
+#define TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA 0x0043
+#define TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA 0x0044
+#define TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA 0x0045
+#define TLS_DH_ANON_WITH_CAMELLIA_128_CBC_SHA 0x0046
+
+#define TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA 0x0062
+#define TLS_RSA_EXPORT1024_WITH_RC4_56_SHA 0x0064
+
+#define TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA 0x0063
+#define TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA 0x0065
+#define TLS_DHE_DSS_WITH_RC4_128_SHA 0x0066
+#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x0067
+#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x006B
+
+#define TLS_RSA_WITH_CAMELLIA_256_CBC_SHA 0x0084
+#define TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA 0x0085
+#define TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA 0x0086
+#define TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA 0x0087
+#define TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA 0x0088
+#define TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA 0x0089
+
+#define TLS_RSA_WITH_SEED_CBC_SHA 0x0096
+
+#define TLS_RSA_WITH_AES_128_GCM_SHA256 0x009C
+#define TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x009E
+#define TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 0x00A2
+
+/* TLS "Signaling Cipher Suite Value" (SCSV). May be requested by client.
+ * Must NEVER be chosen by server. SSL 3.0 server acknowledges by sending
+ * back an empty Renegotiation Info (RI) server hello extension.
+ */
+#define TLS_EMPTY_RENEGOTIATION_INFO_SCSV 0x00FF
+
+/* Cipher Suite Values starting with 0xC000 are defined in informational
+ * RFCs.
+ */
+#define TLS_ECDH_ECDSA_WITH_NULL_SHA 0xC001
+#define TLS_ECDH_ECDSA_WITH_RC4_128_SHA 0xC002
+#define TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC003
+#define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0xC004
+#define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0xC005
+
+#define TLS_ECDHE_ECDSA_WITH_NULL_SHA 0xC006
+#define TLS_ECDHE_ECDSA_WITH_RC4_128_SHA 0xC007
+#define TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC008
+#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0xC009
+#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0xC00A
+
+#define TLS_ECDH_RSA_WITH_NULL_SHA 0xC00B
+#define TLS_ECDH_RSA_WITH_RC4_128_SHA 0xC00C
+#define TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA 0xC00D
+#define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 0xC00E
+#define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 0xC00F
+
+#define TLS_ECDHE_RSA_WITH_NULL_SHA 0xC010
+#define TLS_ECDHE_RSA_WITH_RC4_128_SHA 0xC011
+#define TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 0xC012
+#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xC013
+#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xC014
+
+#define TLS_ECDH_anon_WITH_NULL_SHA 0xC015
+#define TLS_ECDH_anon_WITH_RC4_128_SHA 0xC016
+#define TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA 0xC017
+#define TLS_ECDH_anon_WITH_AES_128_CBC_SHA 0xC018
+#define TLS_ECDH_anon_WITH_AES_256_CBC_SHA 0xC019
+
+#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023
+#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xC027
+
+#define TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B
+#define TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0xC02D
+#define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xC02F
+#define TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 0xC031
+
+/* Netscape "experimental" cipher suites. */
+#define SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA 0xffe0
+#define SSL_RSA_OLDFIPS_WITH_DES_CBC_SHA 0xffe1
+
+/* New non-experimental openly spec'ed versions of those cipher suites. */
+#define SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA 0xfeff
+#define SSL_RSA_FIPS_WITH_DES_CBC_SHA 0xfefe
+
+/* DTLS-SRTP cipher suites from RFC 5764 */
+/* If you modify this, also modify MAX_DTLS_SRTP_CIPHER_SUITES in sslimpl.h */
+#define SRTP_AES128_CM_HMAC_SHA1_80 0x0001
+#define SRTP_AES128_CM_HMAC_SHA1_32 0x0002
+#define SRTP_NULL_HMAC_SHA1_80 0x0005
+#define SRTP_NULL_HMAC_SHA1_32 0x0006
+
+#endif /* __sslproto_h_ */
diff --git a/chromium/net/third_party/nss/ssl/sslreveal.c b/chromium/net/third_party/nss/ssl/sslreveal.c
new file mode 100644
index 00000000000..d97299885d9
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslreveal.c
@@ -0,0 +1,112 @@
+/*
+ * Accessor functions for SSLSocket private members.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cert.h"
+#include "ssl.h"
+#include "certt.h"
+#include "sslimpl.h"
+
+/* given PRFileDesc, returns a copy of certificate associated with the socket
+ * the caller should delete the cert when done with SSL_DestroyCertificate
+ */
+CERTCertificate *
+SSL_RevealCert(PRFileDesc * fd)
+{
+ CERTCertificate * cert = NULL;
+ sslSocket * sslsocket = NULL;
+
+ sslsocket = ssl_FindSocket(fd);
+
+ /* CERT_DupCertificate increases reference count and returns pointer to
+ * the same cert
+ */
+ if (sslsocket && sslsocket->sec.peerCert)
+ cert = CERT_DupCertificate(sslsocket->sec.peerCert);
+
+ return cert;
+}
+
+/* given PRFileDesc, returns a pointer to PinArg associated with the socket
+ */
+void *
+SSL_RevealPinArg(PRFileDesc * fd)
+{
+ sslSocket * sslsocket = NULL;
+ void * PinArg = NULL;
+
+ sslsocket = ssl_FindSocket(fd);
+
+ /* is pkcs11PinArg part of the sslSocket or sslSecurityInfo ? */
+ if (sslsocket)
+ PinArg = sslsocket->pkcs11PinArg;
+
+ return PinArg;
+}
+
+
+/* given PRFileDesc, returns a pointer to the URL associated with the socket
+ * the caller should free url when done
+ */
+char *
+SSL_RevealURL(PRFileDesc * fd)
+{
+ sslSocket * sslsocket = NULL;
+ char * url = NULL;
+
+ sslsocket = ssl_FindSocket(fd);
+
+ if (sslsocket && sslsocket->url)
+ url = PL_strdup(sslsocket->url);
+
+ return url;
+}
+
+
+/* given PRFileDesc, returns status information related to extensions
+ * negotiated with peer during the handshake.
+ */
+
+SECStatus
+SSL_HandshakeNegotiatedExtension(PRFileDesc * socket,
+ SSLExtensionType extId,
+ PRBool *pYes)
+{
+ /* some decisions derived from SSL_GetChannelInfo */
+ sslSocket * sslsocket = NULL;
+
+ if (!pYes) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ sslsocket = ssl_FindSocket(socket);
+ if (!sslsocket) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in HandshakeNegotiatedExtension",
+ SSL_GETPID(), socket));
+ return SECFailure;
+ }
+
+ *pYes = PR_FALSE;
+
+ /* according to public API SSL_GetChannelInfo, this doesn't need a lock */
+ if (sslsocket->opt.useSecurity) {
+ if (sslsocket->ssl3.initialized) { /* SSL3 and TLS */
+ /* now we know this socket went through ssl3_InitState() and
+ * ss->xtnData got initialized, which is the only member accessed by
+ * ssl3_ExtensionNegotiated();
+ * Member xtnData appears to get accessed in functions that handle
+ * the handshake (hello messages and extension sending),
+ * therefore the handshake lock should be sufficient.
+ */
+ ssl_GetSSL3HandshakeLock(sslsocket);
+ *pYes = ssl3_ExtensionNegotiated(sslsocket, extId);
+ ssl_ReleaseSSL3HandshakeLock(sslsocket);
+ }
+ }
+
+ return SECSuccess;
+}
diff --git a/chromium/net/third_party/nss/ssl/sslsecur.c b/chromium/net/third_party/nss/ssl/sslsecur.c
new file mode 100644
index 00000000000..0714a0b75bb
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslsecur.c
@@ -0,0 +1,1598 @@
+/*
+ * Various SSL functions.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "cert.h"
+#include "secitem.h"
+#include "keyhi.h"
+#include "ssl.h"
+#include "sslimpl.h"
+#include "sslproto.h"
+#include "secoid.h" /* for SECOID_GetALgorithmTag */
+#include "pk11func.h" /* for PK11_GenerateRandom */
+#include "nss.h" /* for NSS_RegisterShutdown */
+#include "prinit.h" /* for PR_CallOnceWithArg */
+
+#define MAX_BLOCK_CYPHER_SIZE 32
+
+#define TEST_FOR_FAILURE /* reminder */
+#define SET_ERROR_CODE /* reminder */
+
+/* Returns a SECStatus: SECSuccess or SECFailure, NOT SECWouldBlock.
+ *
+ * Currently, the list of functions called through ss->handshake is:
+ *
+ * In sslsocks.c:
+ * SocksGatherRecord
+ * SocksHandleReply
+ * SocksStartGather
+ *
+ * In sslcon.c:
+ * ssl_GatherRecord1stHandshake
+ * ssl2_HandleClientSessionKeyMessage
+ * ssl2_HandleMessage
+ * ssl2_HandleVerifyMessage
+ * ssl2_BeginClientHandshake
+ * ssl2_BeginServerHandshake
+ * ssl2_HandleClientHelloMessage
+ * ssl2_HandleServerHelloMessage
+ *
+ * The ss->handshake function returns SECWouldBlock under these conditions:
+ * 1. ssl_GatherRecord1stHandshake called ssl2_GatherData which read in
+ * the beginning of an SSL v3 hello message and returned SECWouldBlock
+ * to switch to SSL v3 handshake processing.
+ *
+ * 2. ssl2_HandleClientHelloMessage discovered version 3.0 in the incoming
+ * v2 client hello msg, and called ssl3_HandleV2ClientHello which
+ * returned SECWouldBlock.
+ *
+ * 3. SECWouldBlock was returned by one of the callback functions, via
+ * one of these paths:
+ * - ssl2_HandleMessage() -> ssl2_HandleRequestCertificate() ->
+ * ss->getClientAuthData()
+ *
+ * - ssl2_HandleServerHelloMessage() -> ss->handleBadCert()
+ *
+ * - ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() ->
+ * ssl3_HandleRecord() -> ssl3_HandleHandshake() ->
+ * ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificate() ->
+ * ss->handleBadCert()
+ *
+ * - ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() ->
+ * ssl3_HandleRecord() -> ssl3_HandleHandshake() ->
+ * ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificateRequest() ->
+ * ss->getClientAuthData()
+ *
+ * Called from: SSL_ForceHandshake (below),
+ * ssl_SecureRecv (below) and
+ * ssl_SecureSend (below)
+ * from: WaitForResponse in sslsocks.c
+ * ssl_SocksRecv in sslsocks.c
+ * ssl_SocksSend in sslsocks.c
+ *
+ * Caller must hold the (write) handshakeLock.
+ */
+int
+ssl_Do1stHandshake(sslSocket *ss)
+{
+ int rv = SECSuccess;
+ int loopCount = 0;
+
+ do {
+ PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+ PORT_Assert(ss->opt.noLocks || !ssl_HaveRecvBufLock(ss));
+ PORT_Assert(ss->opt.noLocks || !ssl_HaveXmitBufLock(ss));
+ PORT_Assert(ss->opt.noLocks || !ssl_HaveSSL3HandshakeLock(ss));
+
+ if (ss->handshake == 0) {
+ /* Previous handshake finished. Switch to next one */
+ ss->handshake = ss->nextHandshake;
+ ss->nextHandshake = 0;
+ }
+ if (ss->handshake == 0) {
+ /* Previous handshake finished. Switch to security handshake */
+ ss->handshake = ss->securityHandshake;
+ ss->securityHandshake = 0;
+ }
+ if (ss->handshake == 0) {
+ ssl_GetRecvBufLock(ss);
+ ss->gs.recordLen = 0;
+ ssl_ReleaseRecvBufLock(ss);
+
+ SSL_TRC(3, ("%d: SSL[%d]: handshake is completed",
+ SSL_GETPID(), ss->fd));
+ /* call handshake callback for ssl v2 */
+ /* for v3 this is done in ssl3_HandleFinished() */
+ if ((ss->handshakeCallback != NULL) && /* has callback */
+ (!ss->firstHsDone) && /* only first time */
+ (ss->version < SSL_LIBRARY_VERSION_3_0)) { /* not ssl3 */
+ ss->firstHsDone = PR_TRUE;
+ (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
+ }
+ ss->firstHsDone = PR_TRUE;
+ ss->gs.writeOffset = 0;
+ ss->gs.readOffset = 0;
+ break;
+ }
+ rv = (*ss->handshake)(ss);
+ ++loopCount;
+ /* This code must continue to loop on SECWouldBlock,
+ * or any positive value. See XXX_1 comments.
+ */
+ } while (rv != SECFailure); /* was (rv >= 0); XXX_1 */
+
+ PORT_Assert(ss->opt.noLocks || !ssl_HaveRecvBufLock(ss));
+ PORT_Assert(ss->opt.noLocks || !ssl_HaveXmitBufLock(ss));
+ PORT_Assert(ss->opt.noLocks || !ssl_HaveSSL3HandshakeLock(ss));
+
+ if (rv == SECWouldBlock) {
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ rv = SECFailure;
+ }
+ return rv;
+}
+
+/*
+ * Handshake function that blocks. Used to force a
+ * retry on a connection on the next read/write.
+ */
+static SECStatus
+ssl3_AlwaysBlock(sslSocket *ss)
+{
+ PORT_SetError(PR_WOULD_BLOCK_ERROR); /* perhaps redundant. */
+ return SECWouldBlock;
+}
+
+/*
+ * set the initial handshake state machine to block
+ */
+void
+ssl3_SetAlwaysBlock(sslSocket *ss)
+{
+ if (!ss->firstHsDone) {
+ ss->handshake = ssl3_AlwaysBlock;
+ ss->nextHandshake = 0;
+ }
+}
+
+static SECStatus
+ssl_SetTimeout(PRFileDesc *fd, PRIntervalTime timeout)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SetTimeout", SSL_GETPID(), fd));
+ return SECFailure;
+ }
+ SSL_LOCK_READER(ss);
+ ss->rTimeout = timeout;
+ if (ss->opt.fdx) {
+ SSL_LOCK_WRITER(ss);
+ }
+ ss->wTimeout = timeout;
+ if (ss->opt.fdx) {
+ SSL_UNLOCK_WRITER(ss);
+ }
+ SSL_UNLOCK_READER(ss);
+ return SECSuccess;
+}
+
+/* Acquires and releases HandshakeLock.
+*/
+SECStatus
+SSL_ResetHandshake(PRFileDesc *s, PRBool asServer)
+{
+ sslSocket *ss;
+ SECStatus status;
+ PRNetAddr addr;
+
+ ss = ssl_FindSocket(s);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in ResetHandshake", SSL_GETPID(), s));
+ return SECFailure;
+ }
+
+ /* Don't waste my time */
+ if (!ss->opt.useSecurity)
+ return SECSuccess;
+
+ SSL_LOCK_READER(ss);
+ SSL_LOCK_WRITER(ss);
+
+ /* Reset handshake state */
+ ssl_Get1stHandshakeLock(ss);
+
+ ss->firstHsDone = PR_FALSE;
+ if ( asServer ) {
+ ss->handshake = ssl2_BeginServerHandshake;
+ ss->handshaking = sslHandshakingAsServer;
+ } else {
+ ss->handshake = ssl2_BeginClientHandshake;
+ ss->handshaking = sslHandshakingAsClient;
+ }
+ ss->nextHandshake = 0;
+ ss->securityHandshake = 0;
+
+ ssl_GetRecvBufLock(ss);
+ status = ssl_InitGather(&ss->gs);
+ ssl_ReleaseRecvBufLock(ss);
+
+ ssl_GetSSL3HandshakeLock(ss);
+
+ /*
+ ** Blow away old security state and get a fresh setup.
+ */
+ ssl_GetXmitBufLock(ss);
+ ssl_ResetSecurityInfo(&ss->sec, PR_TRUE);
+ status = ssl_CreateSecurityInfo(ss);
+ ssl_ReleaseXmitBufLock(ss);
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ if (!ss->TCPconnected)
+ ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr));
+
+ SSL_UNLOCK_WRITER(ss);
+ SSL_UNLOCK_READER(ss);
+
+ return status;
+}
+
+/* For SSLv2, does nothing but return an error.
+** For SSLv3, flushes SID cache entry (if requested),
+** and then starts new client hello or hello request.
+** Acquires and releases HandshakeLock.
+*/
+SECStatus
+SSL_ReHandshake(PRFileDesc *fd, PRBool flushCache)
+{
+ sslSocket *ss;
+ SECStatus rv;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in RedoHandshake", SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ if (!ss->opt.useSecurity)
+ return SECSuccess;
+
+ ssl_Get1stHandshakeLock(ss);
+
+ /* SSL v2 protocol does not support subsequent handshakes. */
+ if (ss->version < SSL_LIBRARY_VERSION_3_0) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ } else {
+ ssl_GetSSL3HandshakeLock(ss);
+ rv = ssl3_RedoHandshake(ss, flushCache); /* force full handshake. */
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ }
+
+ ssl_Release1stHandshakeLock(ss);
+
+ return rv;
+}
+
+/*
+** Same as above, but with an I/O timeout.
+ */
+SSL_IMPORT SECStatus SSL_ReHandshakeWithTimeout(PRFileDesc *fd,
+ PRBool flushCache,
+ PRIntervalTime timeout)
+{
+ if (SECSuccess != ssl_SetTimeout(fd, timeout)) {
+ return SECFailure;
+ }
+ return SSL_ReHandshake(fd, flushCache);
+}
+
+SECStatus
+SSL_RedoHandshake(PRFileDesc *fd)
+{
+ return SSL_ReHandshake(fd, PR_TRUE);
+}
+
+/* Register an application callback to be called when SSL handshake completes.
+** Acquires and releases HandshakeLock.
+*/
+SECStatus
+SSL_HandshakeCallback(PRFileDesc *fd, SSLHandshakeCallback cb,
+ void *client_data)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in HandshakeCallback",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ if (!ss->opt.useSecurity) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ ss->handshakeCallback = cb;
+ ss->handshakeCallbackData = client_data;
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ return SECSuccess;
+}
+
+/* Try to make progress on an SSL handshake by attempting to read the
+** next handshake from the peer, and sending any responses.
+** For non-blocking sockets, returns PR_ERROR_WOULD_BLOCK if it cannot
+** read the next handshake from the underlying socket.
+** For SSLv2, returns when handshake is complete or fatal error occurs.
+** For SSLv3, returns when handshake is complete, or application data has
+** arrived that must be taken by application before handshake can continue,
+** or a fatal error occurs.
+** Application should use handshake completion callback to tell which.
+*/
+SECStatus
+SSL_ForceHandshake(PRFileDesc *fd)
+{
+ sslSocket *ss;
+ SECStatus rv = SECFailure;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in ForceHandshake",
+ SSL_GETPID(), fd));
+ return rv;
+ }
+
+ /* Don't waste my time */
+ if (!ss->opt.useSecurity)
+ return SECSuccess;
+
+ if (!ssl_SocketIsBlocking(ss)) {
+ ssl_GetXmitBufLock(ss);
+ if (ss->pendingBuf.len != 0) {
+ int sent = ssl_SendSavedWriteData(ss);
+ if ((sent < 0) && (PORT_GetError() != PR_WOULD_BLOCK_ERROR)) {
+ ssl_ReleaseXmitBufLock(ss);
+ return SECFailure;
+ }
+ }
+ ssl_ReleaseXmitBufLock(ss);
+ }
+
+ ssl_Get1stHandshakeLock(ss);
+
+ if (ss->version >= SSL_LIBRARY_VERSION_3_0) {
+ int gatherResult;
+
+ ssl_GetRecvBufLock(ss);
+ gatherResult = ssl3_GatherCompleteHandshake(ss, 0);
+ ssl_ReleaseRecvBufLock(ss);
+ if (gatherResult > 0) {
+ rv = SECSuccess;
+ } else if (gatherResult == 0) {
+ PORT_SetError(PR_END_OF_FILE_ERROR);
+ } else if (gatherResult == SECWouldBlock) {
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ }
+ } else if (!ss->firstHsDone) {
+ rv = ssl_Do1stHandshake(ss);
+ } else {
+ /* tried to force handshake on an SSL 2 socket that has
+ ** already completed the handshake. */
+ rv = SECSuccess; /* just pretend we did it. */
+ }
+
+ ssl_Release1stHandshakeLock(ss);
+
+ return rv;
+}
+
+/*
+ ** Same as above, but with an I/O timeout.
+ */
+SSL_IMPORT SECStatus SSL_ForceHandshakeWithTimeout(PRFileDesc *fd,
+ PRIntervalTime timeout)
+{
+ if (SECSuccess != ssl_SetTimeout(fd, timeout)) {
+ return SECFailure;
+ }
+ return SSL_ForceHandshake(fd);
+}
+
+
+/************************************************************************/
+
+/*
+** Grow a buffer to hold newLen bytes of data.
+** Called for both recv buffers and xmit buffers.
+** Caller must hold xmitBufLock or recvBufLock, as appropriate.
+*/
+SECStatus
+sslBuffer_Grow(sslBuffer *b, unsigned int newLen)
+{
+ newLen = PR_MAX(newLen, MAX_FRAGMENT_LENGTH + 2048);
+ if (newLen > b->space) {
+ unsigned char *newBuf;
+ if (b->buf) {
+ newBuf = (unsigned char *) PORT_Realloc(b->buf, newLen);
+ } else {
+ newBuf = (unsigned char *) PORT_Alloc(newLen);
+ }
+ if (!newBuf) {
+ return SECFailure;
+ }
+ SSL_TRC(10, ("%d: SSL: grow buffer from %d to %d",
+ SSL_GETPID(), b->space, newLen));
+ b->buf = newBuf;
+ b->space = newLen;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+sslBuffer_Append(sslBuffer *b, const void * data, unsigned int len)
+{
+ unsigned int newLen = b->len + len;
+ SECStatus rv;
+
+ rv = sslBuffer_Grow(b, newLen);
+ if (rv != SECSuccess)
+ return rv;
+ PORT_Memcpy(b->buf + b->len, data, len);
+ b->len += len;
+ return SECSuccess;
+}
+
+/*
+** Save away write data that is trying to be written before the security
+** handshake has been completed. When the handshake is completed, we will
+** flush this data out.
+** Caller must hold xmitBufLock
+*/
+SECStatus
+ssl_SaveWriteData(sslSocket *ss, const void *data, unsigned int len)
+{
+ SECStatus rv;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
+ rv = sslBuffer_Append(&ss->pendingBuf, data, len);
+ SSL_TRC(5, ("%d: SSL[%d]: saving %u bytes of data (%u total saved so far)",
+ SSL_GETPID(), ss->fd, len, ss->pendingBuf.len));
+ return rv;
+}
+
+/*
+** Send saved write data. This will flush out data sent prior to a
+** complete security handshake. Hopefully there won't be too much of it.
+** Returns count of the bytes sent, NOT a SECStatus.
+** Caller must hold xmitBufLock
+*/
+int
+ssl_SendSavedWriteData(sslSocket *ss)
+{
+ int rv = 0;
+
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
+ if (ss->pendingBuf.len != 0) {
+ SSL_TRC(5, ("%d: SSL[%d]: sending %d bytes of saved data",
+ SSL_GETPID(), ss->fd, ss->pendingBuf.len));
+ rv = ssl_DefSend(ss, ss->pendingBuf.buf, ss->pendingBuf.len, 0);
+ if (rv < 0) {
+ return rv;
+ }
+ ss->pendingBuf.len -= rv;
+ if (ss->pendingBuf.len > 0 && rv > 0) {
+ /* UGH !! This shifts the whole buffer down by copying it */
+ PORT_Memmove(ss->pendingBuf.buf, ss->pendingBuf.buf + rv,
+ ss->pendingBuf.len);
+ }
+ }
+ return rv;
+}
+
+/************************************************************************/
+
+/*
+** Receive some application data on a socket. Reads SSL records from the input
+** stream, decrypts them and then copies them to the output buffer.
+** Called from ssl_SecureRecv() below.
+**
+** Caller does NOT hold 1stHandshakeLock because that handshake is over.
+** Caller doesn't call this until initial handshake is complete.
+** For SSLv2, there is no subsequent handshake.
+** For SSLv3, the call to ssl3_GatherAppDataRecord may encounter handshake
+** messages from a subsequent handshake.
+**
+** This code is similar to, and easily confused with,
+** ssl_GatherRecord1stHandshake() in sslcon.c
+*/
+static int
+DoRecv(sslSocket *ss, unsigned char *out, int len, int flags)
+{
+ int rv;
+ int amount;
+ int available;
+
+ ssl_GetRecvBufLock(ss);
+
+ available = ss->gs.writeOffset - ss->gs.readOffset;
+ if (available == 0) {
+ /* Get some more data */
+ if (ss->version >= SSL_LIBRARY_VERSION_3_0) {
+ /* Wait for application data to arrive. */
+ rv = ssl3_GatherAppDataRecord(ss, 0);
+ } else {
+ /* See if we have a complete record */
+ rv = ssl2_GatherRecord(ss, 0);
+ }
+ if (rv <= 0) {
+ if (rv == 0) {
+ /* EOF */
+ SSL_TRC(10, ("%d: SSL[%d]: ssl_recv EOF",
+ SSL_GETPID(), ss->fd));
+ goto done;
+ }
+ if ((rv != SECWouldBlock) &&
+ (PR_GetError() != PR_WOULD_BLOCK_ERROR)) {
+ /* Some random error */
+ goto done;
+ }
+
+ /*
+ ** Gather record is blocked waiting for more record data to
+ ** arrive. Try to process what we have already received
+ */
+ } else {
+ /* Gather record has finished getting a complete record */
+ }
+
+ /* See if any clear data is now available */
+ available = ss->gs.writeOffset - ss->gs.readOffset;
+ if (available == 0) {
+ /*
+ ** No partial data is available. Force error code to
+ ** EWOULDBLOCK so that caller will try again later. Note
+ ** that the error code is probably EWOULDBLOCK already,
+ ** but if it isn't (for example, if we received a zero
+ ** length record) then this will force it to be correct.
+ */
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ rv = SECFailure;
+ goto done;
+ }
+ SSL_TRC(30, ("%d: SSL[%d]: partial data ready, available=%d",
+ SSL_GETPID(), ss->fd, available));
+ }
+
+ /* Dole out clear data to reader */
+ amount = PR_MIN(len, available);
+ PORT_Memcpy(out, ss->gs.buf.buf + ss->gs.readOffset, amount);
+ if (!(flags & PR_MSG_PEEK)) {
+ ss->gs.readOffset += amount;
+ }
+ PORT_Assert(ss->gs.readOffset <= ss->gs.writeOffset);
+ rv = amount;
+
+ SSL_TRC(30, ("%d: SSL[%d]: amount=%d available=%d",
+ SSL_GETPID(), ss->fd, amount, available));
+ PRINT_BUF(4, (ss, "DoRecv receiving plaintext:", out, amount));
+
+done:
+ ssl_ReleaseRecvBufLock(ss);
+ return rv;
+}
+
+/************************************************************************/
+
+/*
+** Return SSLKEAType derived from cert's Public Key algorithm info.
+*/
+SSLKEAType
+NSS_FindCertKEAType(CERTCertificate * cert)
+{
+ SSLKEAType keaType = kt_null;
+ int tag;
+
+ if (!cert) goto loser;
+
+ tag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
+
+ switch (tag) {
+ case SEC_OID_X500_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_RSA_ENCRYPTION:
+ keaType = kt_rsa;
+ break;
+ case SEC_OID_X942_DIFFIE_HELMAN_KEY:
+ keaType = kt_dh;
+ break;
+#ifdef NSS_ENABLE_ECC
+ case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
+ keaType = kt_ecdh;
+ break;
+#endif /* NSS_ENABLE_ECC */
+ default:
+ keaType = kt_null;
+ }
+
+ loser:
+
+ return keaType;
+}
+
+static const PRCallOnceType pristineCallOnce;
+static PRCallOnceType setupServerCAListOnce;
+
+static SECStatus serverCAListShutdown(void* appData, void* nssData)
+{
+ PORT_Assert(ssl3_server_ca_list);
+ if (ssl3_server_ca_list) {
+ CERT_FreeDistNames(ssl3_server_ca_list);
+ ssl3_server_ca_list = NULL;
+ }
+ setupServerCAListOnce = pristineCallOnce;
+ return SECSuccess;
+}
+
+static PRStatus serverCAListSetup(void *arg)
+{
+ CERTCertDBHandle *dbHandle = (CERTCertDBHandle *)arg;
+ SECStatus rv = NSS_RegisterShutdown(serverCAListShutdown, NULL);
+ PORT_Assert(SECSuccess == rv);
+ if (SECSuccess == rv) {
+ ssl3_server_ca_list = CERT_GetSSLCACerts(dbHandle);
+ return PR_SUCCESS;
+ }
+ return PR_FAILURE;
+}
+
+SECStatus
+ssl_ConfigSecureServer(sslSocket *ss, CERTCertificate *cert,
+ const CERTCertificateList *certChain,
+ ssl3KeyPair *keyPair, SSLKEAType kea)
+{
+ CERTCertificateList *localCertChain = NULL;
+ sslServerCerts *sc = ss->serverCerts + kea;
+
+ /* load the server certificate */
+ if (sc->serverCert != NULL) {
+ CERT_DestroyCertificate(sc->serverCert);
+ sc->serverCert = NULL;
+ sc->serverKeyBits = 0;
+ }
+ /* load the server cert chain */
+ if (sc->serverCertChain != NULL) {
+ CERT_DestroyCertificateList(sc->serverCertChain);
+ sc->serverCertChain = NULL;
+ }
+ if (cert) {
+ sc->serverCert = CERT_DupCertificate(cert);
+ /* get the size of the cert's public key, and remember it */
+ sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->pubKey);
+ if (!certChain) {
+ localCertChain =
+ CERT_CertChainFromCert(sc->serverCert, certUsageSSLServer,
+ PR_TRUE);
+ if (!localCertChain)
+ goto loser;
+ }
+ sc->serverCertChain = (certChain) ? CERT_DupCertList(certChain) :
+ localCertChain;
+ if (!sc->serverCertChain) {
+ goto loser;
+ }
+ localCertChain = NULL; /* consumed */
+ }
+
+ /* get keyPair */
+ if (sc->serverKeyPair != NULL) {
+ ssl3_FreeKeyPair(sc->serverKeyPair);
+ sc->serverKeyPair = NULL;
+ }
+ if (keyPair) {
+ SECKEY_CacheStaticFlags(keyPair->privKey);
+ sc->serverKeyPair = ssl3_GetKeyPairRef(keyPair);
+ }
+ if (kea == kt_rsa && cert && sc->serverKeyBits > 512 &&
+ !ss->opt.noStepDown && !ss->stepDownKeyPair) {
+ if (ssl3_CreateRSAStepDownKeys(ss) != SECSuccess) {
+ goto loser;
+ }
+ }
+ return SECSuccess;
+
+loser:
+ if (localCertChain) {
+ CERT_DestroyCertificateList(localCertChain);
+ }
+ if (sc->serverCert != NULL) {
+ CERT_DestroyCertificate(sc->serverCert);
+ sc->serverCert = NULL;
+ }
+ if (sc->serverCertChain != NULL) {
+ CERT_DestroyCertificateList(sc->serverCertChain);
+ sc->serverCertChain = NULL;
+ }
+ if (sc->serverKeyPair != NULL) {
+ ssl3_FreeKeyPair(sc->serverKeyPair);
+ sc->serverKeyPair = NULL;
+ }
+ return SECFailure;
+}
+
+/* XXX need to protect the data that gets changed here.!! */
+
+SECStatus
+SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert,
+ SECKEYPrivateKey *key, SSL3KEAType kea)
+{
+
+ return SSL_ConfigSecureServerWithCertChain(fd, cert, NULL, key, kea);
+}
+
+SECStatus
+SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert,
+ const CERTCertificateList *certChainOpt,
+ SECKEYPrivateKey *key, SSL3KEAType kea)
+{
+ sslSocket *ss;
+ SECKEYPublicKey *pubKey = NULL;
+ ssl3KeyPair *keyPair = NULL;
+ SECStatus rv = SECFailure;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure;
+ }
+
+ /* Both key and cert must have a value or be NULL */
+ /* Passing a value of NULL will turn off key exchange algorithms that were
+ * previously turned on */
+ if (!cert != !key) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* make sure the key exchange is recognized */
+ if ((kea >= kt_kea_size) || (kea < kt_null)) {
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+ return SECFailure;
+ }
+
+ if (kea != NSS_FindCertKEAType(cert)) {
+ PORT_SetError(SSL_ERROR_CERT_KEA_MISMATCH);
+ return SECFailure;
+ }
+
+ if (cert) {
+ /* get the size of the cert's public key, and remember it */
+ pubKey = CERT_ExtractPublicKey(cert);
+ if (!pubKey)
+ return SECFailure;
+ }
+
+ if (key) {
+ SECKEYPrivateKey * keyCopy = NULL;
+ CK_MECHANISM_TYPE keyMech = CKM_INVALID_MECHANISM;
+
+ if (key->pkcs11Slot) {
+ PK11SlotInfo * bestSlot;
+ bestSlot = PK11_ReferenceSlot(key->pkcs11Slot);
+ if (bestSlot) {
+ keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key);
+ PK11_FreeSlot(bestSlot);
+ }
+ }
+ if (keyCopy == NULL)
+ keyMech = PK11_MapSignKeyType(key->keyType);
+ if (keyMech != CKM_INVALID_MECHANISM) {
+ PK11SlotInfo * bestSlot;
+ /* XXX Maybe should be bestSlotMultiple? */
+ bestSlot = PK11_GetBestSlot(keyMech, NULL /* wincx */);
+ if (bestSlot) {
+ keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key);
+ PK11_FreeSlot(bestSlot);
+ }
+ }
+ if (keyCopy == NULL)
+ keyCopy = SECKEY_CopyPrivateKey(key);
+ if (keyCopy == NULL)
+ goto loser;
+ keyPair = ssl3_NewKeyPair(keyCopy, pubKey);
+ if (keyPair == NULL) {
+ SECKEY_DestroyPrivateKey(keyCopy);
+ goto loser;
+ }
+ pubKey = NULL; /* adopted by serverKeyPair */
+ }
+ if (ssl_ConfigSecureServer(ss, cert, certChainOpt,
+ keyPair, kea) == SECFailure) {
+ goto loser;
+ }
+
+ /* Only do this once because it's global. */
+ if (PR_SUCCESS == PR_CallOnceWithArg(&setupServerCAListOnce,
+ &serverCAListSetup,
+ (void *)(ss->dbHandle))) {
+ rv = SECSuccess;
+ }
+
+loser:
+ if (keyPair) {
+ ssl3_FreeKeyPair(keyPair);
+ }
+ if (pubKey) {
+ SECKEY_DestroyPublicKey(pubKey);
+ pubKey = NULL;
+ }
+ return rv;
+}
+
+/************************************************************************/
+
+SECStatus
+ssl_CreateSecurityInfo(sslSocket *ss)
+{
+ SECStatus status;
+
+ /* initialize sslv2 socket to send data in the clear. */
+ ssl2_UseClearSendFunc(ss);
+
+ ss->sec.blockSize = 1;
+ ss->sec.blockShift = 0;
+
+ ssl_GetXmitBufLock(ss);
+ status = sslBuffer_Grow(&ss->sec.writeBuf, 4096);
+ ssl_ReleaseXmitBufLock(ss);
+
+ return status;
+}
+
+SECStatus
+ssl_CopySecurityInfo(sslSocket *ss, sslSocket *os)
+{
+ ss->sec.send = os->sec.send;
+ ss->sec.isServer = os->sec.isServer;
+ ss->sec.keyBits = os->sec.keyBits;
+ ss->sec.secretKeyBits = os->sec.secretKeyBits;
+
+ ss->sec.peerCert = CERT_DupCertificate(os->sec.peerCert);
+ if (os->sec.peerCert && !ss->sec.peerCert)
+ goto loser;
+
+ ss->sec.cache = os->sec.cache;
+ ss->sec.uncache = os->sec.uncache;
+
+ /* we don't dup the connection info. */
+
+ ss->sec.sendSequence = os->sec.sendSequence;
+ ss->sec.rcvSequence = os->sec.rcvSequence;
+
+ if (os->sec.hash && os->sec.hashcx) {
+ ss->sec.hash = os->sec.hash;
+ ss->sec.hashcx = os->sec.hash->clone(os->sec.hashcx);
+ if (os->sec.hashcx && !ss->sec.hashcx)
+ goto loser;
+ } else {
+ ss->sec.hash = NULL;
+ ss->sec.hashcx = NULL;
+ }
+
+ SECITEM_CopyItem(0, &ss->sec.sendSecret, &os->sec.sendSecret);
+ if (os->sec.sendSecret.data && !ss->sec.sendSecret.data)
+ goto loser;
+ SECITEM_CopyItem(0, &ss->sec.rcvSecret, &os->sec.rcvSecret);
+ if (os->sec.rcvSecret.data && !ss->sec.rcvSecret.data)
+ goto loser;
+
+ /* XXX following code is wrong if either cx != 0 */
+ PORT_Assert(os->sec.readcx == 0);
+ PORT_Assert(os->sec.writecx == 0);
+ ss->sec.readcx = os->sec.readcx;
+ ss->sec.writecx = os->sec.writecx;
+ ss->sec.destroy = 0;
+
+ ss->sec.enc = os->sec.enc;
+ ss->sec.dec = os->sec.dec;
+
+ ss->sec.blockShift = os->sec.blockShift;
+ ss->sec.blockSize = os->sec.blockSize;
+
+ return SECSuccess;
+
+loser:
+ return SECFailure;
+}
+
+/* Reset sec back to its initial state.
+** Caller holds any relevant locks.
+*/
+void
+ssl_ResetSecurityInfo(sslSecurityInfo *sec, PRBool doMemset)
+{
+ /* Destroy MAC */
+ if (sec->hash && sec->hashcx) {
+ (*sec->hash->destroy)(sec->hashcx, PR_TRUE);
+ sec->hashcx = NULL;
+ sec->hash = NULL;
+ }
+ SECITEM_ZfreeItem(&sec->sendSecret, PR_FALSE);
+ SECITEM_ZfreeItem(&sec->rcvSecret, PR_FALSE);
+
+ /* Destroy ciphers */
+ if (sec->destroy) {
+ (*sec->destroy)(sec->readcx, PR_TRUE);
+ (*sec->destroy)(sec->writecx, PR_TRUE);
+ sec->readcx = NULL;
+ sec->writecx = NULL;
+ } else {
+ PORT_Assert(sec->readcx == 0);
+ PORT_Assert(sec->writecx == 0);
+ }
+ sec->readcx = 0;
+ sec->writecx = 0;
+
+ if (sec->localCert) {
+ CERT_DestroyCertificate(sec->localCert);
+ sec->localCert = NULL;
+ }
+ if (sec->peerCert) {
+ CERT_DestroyCertificate(sec->peerCert);
+ sec->peerCert = NULL;
+ }
+ if (sec->peerKey) {
+ SECKEY_DestroyPublicKey(sec->peerKey);
+ sec->peerKey = NULL;
+ }
+
+ /* cleanup the ci */
+ if (sec->ci.sid != NULL) {
+ ssl_FreeSID(sec->ci.sid);
+ }
+ PORT_ZFree(sec->ci.sendBuf.buf, sec->ci.sendBuf.space);
+ if (doMemset) {
+ memset(&sec->ci, 0, sizeof sec->ci);
+ }
+
+}
+
+/*
+** Called from SSL_ResetHandshake (above), and
+** from ssl_FreeSocket in sslsock.c
+** Caller should hold relevant locks (e.g. XmitBufLock)
+*/
+void
+ssl_DestroySecurityInfo(sslSecurityInfo *sec)
+{
+ ssl_ResetSecurityInfo(sec, PR_FALSE);
+
+ PORT_ZFree(sec->writeBuf.buf, sec->writeBuf.space);
+ sec->writeBuf.buf = 0;
+
+ memset(sec, 0, sizeof *sec);
+}
+
+/************************************************************************/
+
+int
+ssl_SecureConnect(sslSocket *ss, const PRNetAddr *sa)
+{
+ PRFileDesc *osfd = ss->fd->lower;
+ int rv;
+
+ if ( ss->opt.handshakeAsServer ) {
+ ss->securityHandshake = ssl2_BeginServerHandshake;
+ ss->handshaking = sslHandshakingAsServer;
+ } else {
+ ss->securityHandshake = ssl2_BeginClientHandshake;
+ ss->handshaking = sslHandshakingAsClient;
+ }
+
+ /* connect to server */
+ rv = osfd->methods->connect(osfd, sa, ss->cTimeout);
+ if (rv == PR_SUCCESS) {
+ ss->TCPconnected = 1;
+ } else {
+ int err = PR_GetError();
+ SSL_DBG(("%d: SSL[%d]: connect failed, errno=%d",
+ SSL_GETPID(), ss->fd, err));
+ if (err == PR_IS_CONNECTED_ERROR) {
+ ss->TCPconnected = 1;
+ }
+ }
+
+ SSL_TRC(5, ("%d: SSL[%d]: secure connect completed, rv == %d",
+ SSL_GETPID(), ss->fd, rv));
+ return rv;
+}
+
+/*
+ * The TLS 1.2 RFC 5246, Section 7.2.1 says:
+ *
+ * Unless some other fatal alert has been transmitted, each party is
+ * required to send a close_notify alert before closing the write side
+ * of the connection. The other party MUST respond with a close_notify
+ * alert of its own and close down the connection immediately,
+ * discarding any pending writes. It is not required for the initiator
+ * of the close to wait for the responding close_notify alert before
+ * closing the read side of the connection.
+ *
+ * The second sentence requires that we send a close_notify alert when we
+ * have received a close_notify alert. In practice, all SSL implementations
+ * close the socket immediately after sending a close_notify alert (which is
+ * allowed by the third sentence), so responding with a close_notify alert
+ * would result in a write failure with the ECONNRESET error. This is why
+ * we don't respond with a close_notify alert.
+ *
+ * Also, in the unlikely event that the TCP pipe is full and the peer stops
+ * reading, the SSL3_SendAlert call in ssl_SecureClose and ssl_SecureShutdown
+ * may block indefinitely in blocking mode, and may fail (without retrying)
+ * in non-blocking mode.
+ */
+
+int
+ssl_SecureClose(sslSocket *ss)
+{
+ int rv;
+
+ if (ss->version >= SSL_LIBRARY_VERSION_3_0 &&
+ !(ss->shutdownHow & ssl_SHUTDOWN_SEND) &&
+ ss->firstHsDone &&
+ !ss->recvdCloseNotify &&
+ ss->ssl3.initialized) {
+
+ /* We don't want the final alert to be Nagle delayed. */
+ if (!ss->delayDisabled) {
+ ssl_EnableNagleDelay(ss, PR_FALSE);
+ ss->delayDisabled = 1;
+ }
+
+ (void) SSL3_SendAlert(ss, alert_warning, close_notify);
+ }
+ rv = ssl_DefClose(ss);
+ return rv;
+}
+
+/* Caller handles all locking */
+int
+ssl_SecureShutdown(sslSocket *ss, int nsprHow)
+{
+ PRFileDesc *osfd = ss->fd->lower;
+ int rv;
+ PRIntn sslHow = nsprHow + 1;
+
+ if ((unsigned)nsprHow > PR_SHUTDOWN_BOTH) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return PR_FAILURE;
+ }
+
+ if ((sslHow & ssl_SHUTDOWN_SEND) != 0 &&
+ ss->version >= SSL_LIBRARY_VERSION_3_0 &&
+ !(ss->shutdownHow & ssl_SHUTDOWN_SEND) &&
+ ss->firstHsDone &&
+ !ss->recvdCloseNotify &&
+ ss->ssl3.initialized) {
+
+ (void) SSL3_SendAlert(ss, alert_warning, close_notify);
+ }
+
+ rv = osfd->methods->shutdown(osfd, nsprHow);
+
+ ss->shutdownHow |= sslHow;
+
+ return rv;
+}
+
+/************************************************************************/
+
+
+int
+ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags)
+{
+ sslSecurityInfo *sec;
+ int rv = 0;
+
+ sec = &ss->sec;
+
+ if (ss->shutdownHow & ssl_SHUTDOWN_RCV) {
+ PORT_SetError(PR_SOCKET_SHUTDOWN_ERROR);
+ return PR_FAILURE;
+ }
+ if (flags & ~PR_MSG_PEEK) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return PR_FAILURE;
+ }
+
+ if (!ssl_SocketIsBlocking(ss) && !ss->opt.fdx) {
+ ssl_GetXmitBufLock(ss);
+ if (ss->pendingBuf.len != 0) {
+ rv = ssl_SendSavedWriteData(ss);
+ if ((rv < 0) && (PORT_GetError() != PR_WOULD_BLOCK_ERROR)) {
+ ssl_ReleaseXmitBufLock(ss);
+ return SECFailure;
+ }
+ }
+ ssl_ReleaseXmitBufLock(ss);
+ }
+
+ rv = 0;
+ /* If any of these is non-zero, the initial handshake is not done. */
+ if (!ss->firstHsDone) {
+ ssl_Get1stHandshakeLock(ss);
+ if (ss->handshake || ss->nextHandshake || ss->securityHandshake) {
+ rv = ssl_Do1stHandshake(ss);
+ }
+ ssl_Release1stHandshakeLock(ss);
+ }
+ if (rv < 0) {
+ return rv;
+ }
+
+ if (len == 0) return 0;
+
+ rv = DoRecv(ss, (unsigned char*) buf, len, flags);
+ SSL_TRC(2, ("%d: SSL[%d]: recving %d bytes securely (errno=%d)",
+ SSL_GETPID(), ss->fd, rv, PORT_GetError()));
+ return rv;
+}
+
+int
+ssl_SecureRead(sslSocket *ss, unsigned char *buf, int len)
+{
+ return ssl_SecureRecv(ss, buf, len, 0);
+}
+
+/* Caller holds the SSL Socket's write lock. SSL_LOCK_WRITER(ss) */
+int
+ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
+{
+ int rv = 0;
+
+ SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes",
+ SSL_GETPID(), ss->fd, len));
+
+ if (ss->shutdownHow & ssl_SHUTDOWN_SEND) {
+ PORT_SetError(PR_SOCKET_SHUTDOWN_ERROR);
+ rv = PR_FAILURE;
+ goto done;
+ }
+ if (flags) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ rv = PR_FAILURE;
+ goto done;
+ }
+
+ ssl_GetXmitBufLock(ss);
+ if (ss->pendingBuf.len != 0) {
+ PORT_Assert(ss->pendingBuf.len > 0);
+ rv = ssl_SendSavedWriteData(ss);
+ if (rv >= 0 && ss->pendingBuf.len != 0) {
+ PORT_Assert(ss->pendingBuf.len > 0);
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ rv = SECFailure;
+ }
+ }
+ ssl_ReleaseXmitBufLock(ss);
+ if (rv < 0) {
+ goto done;
+ }
+
+ if (len > 0)
+ ss->writerThread = PR_GetCurrentThread();
+ /* If any of these is non-zero, the initial handshake is not done. */
+ if (!ss->firstHsDone) {
+ PRBool canFalseStart = PR_FALSE;
+ ssl_Get1stHandshakeLock(ss);
+ if (ss->version >= SSL_LIBRARY_VERSION_3_0) {
+ ssl_GetSSL3HandshakeLock(ss);
+ if ((ss->ssl3.hs.ws == wait_change_cipher ||
+ ss->ssl3.hs.ws == wait_finished ||
+ ss->ssl3.hs.ws == wait_new_session_ticket) &&
+ ssl3_CanFalseStart(ss)) {
+ canFalseStart = PR_TRUE;
+ }
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ }
+ if (!canFalseStart &&
+ (ss->handshake || ss->nextHandshake || ss->securityHandshake)) {
+ rv = ssl_Do1stHandshake(ss);
+ }
+ ssl_Release1stHandshakeLock(ss);
+ }
+ if (rv < 0) {
+ ss->writerThread = NULL;
+ goto done;
+ }
+
+ /* Check for zero length writes after we do housekeeping so we make forward
+ * progress.
+ */
+ if (len == 0) {
+ rv = 0;
+ goto done;
+ }
+ PORT_Assert(buf != NULL);
+ if (!buf) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ rv = PR_FAILURE;
+ goto done;
+ }
+
+ /* Send out the data using one of these functions:
+ * ssl2_SendClear, ssl2_SendStream, ssl2_SendBlock,
+ * ssl3_SendApplicationData
+ */
+ ssl_GetXmitBufLock(ss);
+ rv = (*ss->sec.send)(ss, buf, len, flags);
+ ssl_ReleaseXmitBufLock(ss);
+ ss->writerThread = NULL;
+done:
+ if (rv < 0) {
+ SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count, error %d",
+ SSL_GETPID(), ss->fd, rv, PORT_GetError()));
+ } else {
+ SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count",
+ SSL_GETPID(), ss->fd, rv));
+ }
+ return rv;
+}
+
+int
+ssl_SecureWrite(sslSocket *ss, const unsigned char *buf, int len)
+{
+ return ssl_SecureSend(ss, buf, len, 0);
+}
+
+SECStatus
+SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f, void *arg)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSLBadCertHook",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ ss->handleBadCert = f;
+ ss->badCertArg = arg;
+
+ return SECSuccess;
+}
+
+/*
+ * Allow the application to pass the url or hostname into the SSL library
+ * so that we can do some checking on it. It will be used for the value in
+ * SNI extension of client hello message.
+ */
+SECStatus
+SSL_SetURL(PRFileDesc *fd, const char *url)
+{
+ sslSocket * ss = ssl_FindSocket(fd);
+ SECStatus rv = SECSuccess;
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSLSetURL",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ if ( ss->url ) {
+ PORT_Free((void *)ss->url); /* CONST */
+ }
+
+ ss->url = (const char *)PORT_Strdup(url);
+ if ( ss->url == NULL ) {
+ rv = SECFailure;
+ }
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ return rv;
+}
+
+/*
+ * Allow the application to pass the set of trust anchors
+ */
+SECStatus
+SSL_SetTrustAnchors(PRFileDesc *fd, CERTCertList *certList)
+{
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ PR_NOT_REACHED("not implemented");
+ return SECFailure;
+#if 0
+ sslSocket * ss = ssl_FindSocket(fd);
+ CERTDistNames *names = NULL;
+
+ if (!certList) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetTrustAnchors",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ names = CERT_DistNamesFromCertList(certList);
+ if (names == NULL) {
+ return SECFailure;
+ }
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+ if (ss->ssl3.ca_list) {
+ CERT_FreeDistNames(ss->ssl3.ca_list);
+ }
+ ss->ssl3.ca_list = names;
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ return SECSuccess;
+#endif
+}
+
+/*
+** Returns Negative number on error, zero or greater on success.
+** Returns the amount of data immediately available to be read.
+*/
+int
+SSL_DataPending(PRFileDesc *fd)
+{
+ sslSocket *ss;
+ int rv = 0;
+
+ ss = ssl_FindSocket(fd);
+
+ if (ss && ss->opt.useSecurity) {
+ ssl_GetRecvBufLock(ss);
+ rv = ss->gs.writeOffset - ss->gs.readOffset;
+ ssl_ReleaseRecvBufLock(ss);
+ }
+
+ return rv;
+}
+
+SECStatus
+SSL_InvalidateSession(PRFileDesc *fd)
+{
+ sslSocket * ss = ssl_FindSocket(fd);
+ SECStatus rv = SECFailure;
+
+ if (ss) {
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ if (ss->sec.ci.sid && ss->sec.uncache) {
+ ss->sec.uncache(ss->sec.ci.sid);
+ rv = SECSuccess;
+ }
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+ }
+ return rv;
+}
+
+SECItem *
+SSL_GetSessionID(PRFileDesc *fd)
+{
+ sslSocket * ss;
+ SECItem * item = NULL;
+
+ ss = ssl_FindSocket(fd);
+ if (ss) {
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ if (ss->opt.useSecurity && ss->firstHsDone && ss->sec.ci.sid) {
+ item = (SECItem *)PORT_Alloc(sizeof(SECItem));
+ if (item) {
+ sslSessionID * sid = ss->sec.ci.sid;
+ if (sid->version < SSL_LIBRARY_VERSION_3_0) {
+ item->len = SSL2_SESSIONID_BYTES;
+ item->data = (unsigned char*)PORT_Alloc(item->len);
+ PORT_Memcpy(item->data, sid->u.ssl2.sessionID, item->len);
+ } else {
+ item->len = sid->u.ssl3.sessionIDLength;
+ item->data = (unsigned char*)PORT_Alloc(item->len);
+ PORT_Memcpy(item->data, sid->u.ssl3.sessionID, item->len);
+ }
+ }
+ }
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+ }
+ return item;
+}
+
+SECStatus
+SSL_CertDBHandleSet(PRFileDesc *fd, CERTCertDBHandle *dbHandle)
+{
+ sslSocket * ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss)
+ return SECFailure;
+ if (!dbHandle) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ ss->dbHandle = dbHandle;
+ return SECSuccess;
+}
+
+/*
+ * attempt to restart the handshake after asynchronously handling
+ * a request for the client's certificate.
+ *
+ * inputs:
+ * cert Client cert chosen by application.
+ * Note: ssl takes this reference, and does not bump the
+ * reference count. The caller should drop its reference
+ * without calling CERT_DestroyCertificate after calling this
+ * function.
+ *
+ * key Private key associated with cert. This function takes
+ * ownership of the private key, so the caller should drop its
+ * reference without destroying the private key after this
+ * function returns.
+ *
+ * certChain Chain of signers for cert.
+ * Note: ssl takes this reference, and does not copy the chain.
+ * The caller should drop its reference without destroying the
+ * chain. SSL will free the chain when it is done with it.
+ *
+ * Return value: XXX
+ *
+ * XXX This code only works on the initial handshake on a connection, XXX
+ * It does not work on a subsequent handshake (redo).
+ */
+SECStatus
+SSL_RestartHandshakeAfterCertReq(PRFileDesc * fd,
+ CERTCertificate * cert,
+ SECKEYPrivateKey * key,
+ CERTCertificateList *certChain)
+{
+ sslSocket * ss = ssl_FindSocket(fd);
+ SECStatus ret;
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RestartHandshakeAfterCertReq",
+ SSL_GETPID(), fd));
+ if (cert) {
+ CERT_DestroyCertificate(cert);
+ }
+ if (key) {
+ SECKEY_DestroyPrivateKey(key);
+ }
+ if (certChain) {
+ CERT_DestroyCertificateList(certChain);
+ }
+ return SECFailure;
+ }
+
+ ssl_Get1stHandshakeLock(ss); /************************************/
+
+ if (ss->version >= SSL_LIBRARY_VERSION_3_0) {
+ ret = ssl3_RestartHandshakeAfterCertReq(ss, cert, key, certChain);
+ } else {
+ if (certChain != NULL) {
+ CERT_DestroyCertificateList(certChain);
+ }
+ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
+ ret = SECFailure;
+ }
+
+ ssl_Release1stHandshakeLock(ss); /************************************/
+ return ret;
+}
+
+SECStatus
+SSL_RestartHandshakeAfterChannelIDReq(PRFileDesc * fd,
+ SECKEYPublicKey * channelIDPub,
+ SECKEYPrivateKey *channelID)
+{
+ sslSocket * ss = ssl_FindSocket(fd);
+ SECStatus ret;
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in"
+ " SSL_RestartHandshakeAfterChannelIDReq",
+ SSL_GETPID(), fd));
+ goto loser;
+ }
+
+
+ ssl_Get1stHandshakeLock(ss);
+
+ if (ss->version < SSL_LIBRARY_VERSION_3_0) {
+ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
+ ssl_Release1stHandshakeLock(ss);
+ goto loser;
+ }
+
+ ret = ssl3_RestartHandshakeAfterChannelIDReq(ss, channelIDPub,
+ channelID);
+ ssl_Release1stHandshakeLock(ss);
+
+ return ret;
+
+loser:
+ SECKEY_DestroyPublicKey(channelIDPub);
+ SECKEY_DestroyPrivateKey(channelID);
+ return SECFailure;
+}
+
+/* DO NOT USE. This function was exported in ssl.def with the wrong signature;
+ * this implementation exists to maintain link-time compatibility.
+ */
+int
+SSL_RestartHandshakeAfterServerCert(sslSocket * ss)
+{
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return -1;
+}
+
+/* See documentation in ssl.h */
+SECStatus
+SSL_AuthCertificateComplete(PRFileDesc *fd, PRErrorCode error)
+{
+ SECStatus rv;
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_AuthCertificateComplete",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ ssl_Get1stHandshakeLock(ss);
+
+ if (!ss->ssl3.initialized) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ } else if (ss->version < SSL_LIBRARY_VERSION_3_0) {
+ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
+ rv = SECFailure;
+ } else {
+ rv = ssl3_AuthCertificateComplete(ss, error);
+ }
+
+ ssl_Release1stHandshakeLock(ss);
+
+ return rv;
+}
+
+/* For more info see ssl.h */
+SECStatus
+SSL_SNISocketConfigHook(PRFileDesc *fd, SSLSNISocketConfig func,
+ void *arg)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SNISocketConfigHook",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ ss->sniSocketConfig = func;
+ ss->sniSocketConfigArg = arg;
+ return SECSuccess;
+}
diff --git a/chromium/net/third_party/nss/ssl/sslsnce.c b/chromium/net/third_party/nss/ssl/sslsnce.c
new file mode 100644
index 00000000000..b0446adc17f
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslsnce.c
@@ -0,0 +1,2213 @@
+/* This file implements the SERVER Session ID cache.
+ * NOTE: The contents of this file are NOT used by the client.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server
+ * cache sids!
+ *
+ * About record locking among different server processes:
+ *
+ * All processes that are part of the same conceptual server (serving on
+ * the same address and port) MUST share a common SSL session cache.
+ * This code makes the content of the shared cache accessible to all
+ * processes on the same "server". This code works on Unix and Win32 only.
+ *
+ * We use NSPR anonymous shared memory and move data to & from shared memory.
+ * We must do explicit locking of the records for all reads and writes.
+ * The set of Cache entries are divided up into "sets" of 128 entries.
+ * Each set is protected by a lock. There may be one or more sets protected
+ * by each lock. That is, locks to sets are 1:N.
+ * There is one lock for the entire cert cache.
+ * There is one lock for the set of wrapped sym wrap keys.
+ *
+ * The anonymous shared memory is laid out as if it were declared like this:
+ *
+ * struct {
+ * cacheDescriptor desc;
+ * sidCacheLock sidCacheLocks[ numSIDCacheLocks];
+ * sidCacheLock keyCacheLock;
+ * sidCacheLock certCacheLock;
+ * sidCacheSet sidCacheSets[ numSIDCacheSets ];
+ * sidCacheEntry sidCacheData[ numSIDCacheEntries];
+ * certCacheEntry certCacheData[numCertCacheEntries];
+ * SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS];
+ * PRUint8 keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN]
+ * encKeyCacheEntry ticketEncKey; // Wrapped in non-bypass mode
+ * encKeyCacheEntry ticketMacKey; // Wrapped in non-bypass mode
+ * PRBool ticketKeysValid;
+ * sidCacheLock srvNameCacheLock;
+ * srvNameCacheEntry srvNameData[ numSrvNameCacheEntries ];
+ * } cacheMemCacheData;
+ */
+#include "seccomon.h"
+
+#if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)
+
+#include "cert.h"
+#include "ssl.h"
+#include "sslimpl.h"
+#include "sslproto.h"
+#include "pk11func.h"
+#include "base64.h"
+#include "keyhi.h"
+#ifdef NO_PKCS11_BYPASS
+#include "blapit.h"
+#include "sechash.h"
+#else
+#include "blapi.h"
+#endif
+
+#include <stdio.h>
+
+#if defined(XP_UNIX) || defined(XP_BEOS)
+
+#include <syslog.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include "unix_err.h"
+
+#else
+
+#ifdef XP_WIN32
+#include <wtypes.h>
+#include "win32err.h"
+#endif
+
+#endif
+#include <sys/types.h>
+
+#define SET_ERROR_CODE /* reminder */
+
+#include "nspr.h"
+#include "sslmutex.h"
+
+/*
+** Format of a cache entry in the shared memory.
+*/
+struct sidCacheEntryStr {
+/* 16 */ PRIPv6Addr addr; /* client's IP address */
+/* 4 */ PRUint32 creationTime;
+/* 4 */ PRUint32 lastAccessTime;
+/* 4 */ PRUint32 expirationTime;
+/* 2 */ PRUint16 version;
+/* 1 */ PRUint8 valid;
+/* 1 */ PRUint8 sessionIDLength;
+/* 32 */ PRUint8 sessionID[SSL3_SESSIONID_BYTES];
+/* 2 */ PRUint16 authAlgorithm;
+/* 2 */ PRUint16 authKeyBits;
+/* 2 */ PRUint16 keaType;
+/* 2 */ PRUint16 keaKeyBits;
+/* 72 - common header total */
+
+ union {
+ struct {
+/* 64 */ PRUint8 masterKey[SSL_MAX_MASTER_KEY_BYTES];
+/* 32 */ PRUint8 cipherArg[SSL_MAX_CYPHER_ARG_BYTES];
+
+/* 1 */ PRUint8 cipherType;
+/* 1 */ PRUint8 masterKeyLen;
+/* 1 */ PRUint8 keyBits;
+/* 1 */ PRUint8 secretKeyBits;
+/* 1 */ PRUint8 cipherArgLen;
+/*101 */} ssl2;
+
+ struct {
+/* 2 */ ssl3CipherSuite cipherSuite;
+/* 2 */ PRUint16 compression; /* SSLCompressionMethod */
+
+/* 52 */ ssl3SidKeys keys; /* keys, wrapped as needed. */
+
+/* 4 */ PRUint32 masterWrapMech;
+/* 4 */ SSL3KEAType exchKeyType;
+/* 4 */ PRInt32 certIndex;
+/* 4 */ PRInt32 srvNameIndex;
+/* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */
+/*104 */} ssl3;
+/* force sizeof(sidCacheEntry) to be a multiple of cache line size */
+ struct {
+/*120 */ PRUint8 filler[120]; /* 72+120==192, a multiple of 16 */
+ } forceSize;
+ } u;
+};
+typedef struct sidCacheEntryStr sidCacheEntry;
+
+/* The length of this struct is supposed to be a power of 2, e.g. 4KB */
+struct certCacheEntryStr {
+ PRUint16 certLength; /* 2 */
+ PRUint16 sessionIDLength; /* 2 */
+ PRUint8 sessionID[SSL3_SESSIONID_BYTES]; /* 32 */
+ PRUint8 cert[SSL_MAX_CACHED_CERT_LEN]; /* 4060 */
+}; /* total 4096 */
+typedef struct certCacheEntryStr certCacheEntry;
+
+struct sidCacheLockStr {
+ PRUint32 timeStamp;
+ sslMutex mutex;
+ sslPID pid;
+};
+typedef struct sidCacheLockStr sidCacheLock;
+
+struct sidCacheSetStr {
+ PRIntn next;
+};
+typedef struct sidCacheSetStr sidCacheSet;
+
+struct encKeyCacheEntryStr {
+ PRUint8 bytes[512];
+ PRInt32 length;
+};
+typedef struct encKeyCacheEntryStr encKeyCacheEntry;
+
+#define SSL_MAX_DNS_HOST_NAME 1024
+
+struct srvNameCacheEntryStr {
+ PRUint16 type; /* 2 */
+ PRUint16 nameLen; /* 2 */
+ PRUint8 name[SSL_MAX_DNS_HOST_NAME + 12]; /* 1034 */
+ PRUint8 nameHash[SHA256_LENGTH]; /* 32 */
+ /* 1072 */
+};
+typedef struct srvNameCacheEntryStr srvNameCacheEntry;
+
+
+struct cacheDescStr {
+
+ PRUint32 cacheMemSize;
+
+ PRUint32 numSIDCacheLocks;
+ PRUint32 numSIDCacheSets;
+ PRUint32 numSIDCacheSetsPerLock;
+
+ PRUint32 numSIDCacheEntries;
+ PRUint32 sidCacheSize;
+
+ PRUint32 numCertCacheEntries;
+ PRUint32 certCacheSize;
+
+ PRUint32 numKeyCacheEntries;
+ PRUint32 keyCacheSize;
+
+ PRUint32 numSrvNameCacheEntries;
+ PRUint32 srvNameCacheSize;
+
+ PRUint32 ssl2Timeout;
+ PRUint32 ssl3Timeout;
+
+ PRUint32 numSIDCacheLocksInitialized;
+
+ /* These values are volatile, and are accessed through sharedCache-> */
+ PRUint32 nextCertCacheEntry; /* certCacheLock protects */
+ PRBool stopPolling;
+ PRBool everInherited;
+
+ /* The private copies of these values are pointers into shared mem */
+ /* The copies of these values in shared memory are merely offsets */
+ sidCacheLock * sidCacheLocks;
+ sidCacheLock * keyCacheLock;
+ sidCacheLock * certCacheLock;
+ sidCacheLock * srvNameCacheLock;
+ sidCacheSet * sidCacheSets;
+ sidCacheEntry * sidCacheData;
+ certCacheEntry * certCacheData;
+ SSLWrappedSymWrappingKey * keyCacheData;
+ PRUint8 * ticketKeyNameSuffix;
+ encKeyCacheEntry * ticketEncKey;
+ encKeyCacheEntry * ticketMacKey;
+ PRUint32 * ticketKeysValid;
+ srvNameCacheEntry * srvNameCacheData;
+
+ /* Only the private copies of these pointers are valid */
+ char * cacheMem;
+ struct cacheDescStr * sharedCache; /* shared copy of this struct */
+ PRFileMap * cacheMemMap;
+ PRThread * poller;
+ PRUint32 mutexTimeout;
+ PRBool shared;
+};
+typedef struct cacheDescStr cacheDesc;
+
+static cacheDesc globalCache;
+
+static const char envVarName[] = { SSL_ENV_VAR_NAME };
+
+static PRBool isMultiProcess = PR_FALSE;
+
+
+#define DEF_SID_CACHE_ENTRIES 10000
+#define DEF_CERT_CACHE_ENTRIES 250
+#define MIN_CERT_CACHE_ENTRIES 125 /* the effective size in old releases. */
+#define DEF_KEY_CACHE_ENTRIES 250
+#define DEF_NAME_CACHE_ENTRIES 1000
+
+#define SID_CACHE_ENTRIES_PER_SET 128
+#define SID_ALIGNMENT 16
+
+#define DEF_SSL2_TIMEOUT 100 /* seconds */
+#define MAX_SSL2_TIMEOUT 100 /* seconds */
+#define MIN_SSL2_TIMEOUT 5 /* seconds */
+
+#define DEF_SSL3_TIMEOUT 86400L /* 24 hours */
+#define MAX_SSL3_TIMEOUT 86400L /* 24 hours */
+#define MIN_SSL3_TIMEOUT 5 /* seconds */
+
+#if defined(AIX) || defined(LINUX) || defined(NETBSD) || defined(OPENBSD)
+#define MAX_SID_CACHE_LOCKS 8 /* two FDs per lock */
+#elif defined(OSF1)
+#define MAX_SID_CACHE_LOCKS 16 /* one FD per lock */
+#else
+#define MAX_SID_CACHE_LOCKS 256
+#endif
+
+#define SID_HOWMANY(val, size) (((val) + ((size) - 1)) / (size))
+#define SID_ROUNDUP(val, size) ((size) * SID_HOWMANY((val), (size)))
+
+
+static sslPID myPid;
+static PRUint32 ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS;
+
+/* forward static function declarations */
+static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s,
+ unsigned nl);
+static SECStatus LaunchLockPoller(cacheDesc *cache);
+static SECStatus StopLockPoller(cacheDesc *cache);
+
+
+struct inheritanceStr {
+ PRUint32 cacheMemSize;
+ PRUint32 fmStrLen;
+};
+
+typedef struct inheritanceStr inheritance;
+
+#if defined(_WIN32) || defined(XP_OS2)
+
+#define DEFAULT_CACHE_DIRECTORY "\\temp"
+
+#endif /* _win32 */
+
+#if defined(XP_UNIX) || defined(XP_BEOS)
+
+#define DEFAULT_CACHE_DIRECTORY "/tmp"
+
+#endif /* XP_UNIX || XP_BEOS */
+
+
+/************************************************************************/
+
+static PRUint32
+LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
+{
+ SECStatus rv = sslMutex_Lock(&lock->mutex);
+ if (rv != SECSuccess)
+ return 0;
+ if (!now)
+ now = ssl_Time();
+ lock->timeStamp = now;
+ lock->pid = myPid;
+ return now;
+}
+
+static SECStatus
+UnlockSidCacheLock(sidCacheLock *lock)
+{
+ SECStatus rv;
+
+ lock->pid = 0;
+ rv = sslMutex_Unlock(&lock->mutex);
+ return rv;
+}
+
+/* returns the value of ssl_Time on success, zero on failure. */
+static PRUint32
+LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
+{
+ PRUint32 lockNum = set % cache->numSIDCacheLocks;
+ sidCacheLock * lock = cache->sidCacheLocks + lockNum;
+
+ return LockSidCacheLock(lock, now);
+}
+
+static SECStatus
+UnlockSet(cacheDesc *cache, PRUint32 set)
+{
+ PRUint32 lockNum = set % cache->numSIDCacheLocks;
+ sidCacheLock * lock = cache->sidCacheLocks + lockNum;
+
+ return UnlockSidCacheLock(lock);
+}
+
+/************************************************************************/
+
+
+/* Put a certificate in the cache. Update the cert index in the sce.
+*/
+static PRUint32
+CacheCert(cacheDesc * cache, CERTCertificate *cert, sidCacheEntry *sce)
+{
+ PRUint32 now;
+ certCacheEntry cce;
+
+ if ((cert->derCert.len > SSL_MAX_CACHED_CERT_LEN) ||
+ (cert->derCert.len <= 0) ||
+ (cert->derCert.data == NULL)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return 0;
+ }
+
+ cce.sessionIDLength = sce->sessionIDLength;
+ PORT_Memcpy(cce.sessionID, sce->sessionID, cce.sessionIDLength);
+
+ cce.certLength = cert->derCert.len;
+ PORT_Memcpy(cce.cert, cert->derCert.data, cce.certLength);
+
+ /* get lock on cert cache */
+ now = LockSidCacheLock(cache->certCacheLock, 0);
+ if (now) {
+
+ /* Find where to place the next cert cache entry. */
+ cacheDesc * sharedCache = cache->sharedCache;
+ PRUint32 ndx = sharedCache->nextCertCacheEntry;
+
+ /* write the entry */
+ cache->certCacheData[ndx] = cce;
+
+ /* remember where we put it. */
+ sce->u.ssl3.certIndex = ndx;
+
+ /* update the "next" cache entry index */
+ sharedCache->nextCertCacheEntry =
+ (ndx + 1) % cache->numCertCacheEntries;
+
+ UnlockSidCacheLock(cache->certCacheLock);
+ }
+ return now;
+
+}
+
+/* Server configuration hash tables need to account the SECITEM.type
+ * field as well. These functions accomplish that. */
+static PLHashNumber
+Get32BitNameHash(const SECItem *name)
+{
+ PLHashNumber rv = SECITEM_Hash(name);
+
+ PRUint8 *rvc = (PRUint8 *)&rv;
+ rvc[ name->len % sizeof(rv) ] ^= name->type;
+
+ return rv;
+}
+
+/* Put a name in the cache. Update the cert index in the sce.
+*/
+static PRUint32
+CacheSrvName(cacheDesc * cache, SECItem *name, sidCacheEntry *sce)
+{
+ PRUint32 now;
+ PRUint32 ndx;
+ srvNameCacheEntry snce;
+
+ if (!name || name->len <= 0 ||
+ name->len > SSL_MAX_DNS_HOST_NAME) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return 0;
+ }
+
+ snce.type = name->type;
+ snce.nameLen = name->len;
+ PORT_Memcpy(snce.name, name->data, snce.nameLen);
+#ifdef NO_PKCS11_BYPASS
+ HASH_HashBuf(HASH_AlgSHA256, snce.nameHash, name->data, name->len);
+#else
+ SHA256_HashBuf(snce.nameHash, (unsigned char*)name->data,
+ name->len);
+#endif
+ /* get index of the next name */
+ ndx = Get32BitNameHash(name);
+ /* get lock on cert cache */
+ now = LockSidCacheLock(cache->srvNameCacheLock, 0);
+ if (now) {
+ if (cache->numSrvNameCacheEntries > 0) {
+ /* Fit the index into array */
+ ndx %= cache->numSrvNameCacheEntries;
+ /* write the entry */
+ cache->srvNameCacheData[ndx] = snce;
+ /* remember where we put it. */
+ sce->u.ssl3.srvNameIndex = ndx;
+ /* Copy hash into sid hash */
+ PORT_Memcpy(sce->u.ssl3.srvNameHash, snce.nameHash, SHA256_LENGTH);
+ }
+ UnlockSidCacheLock(cache->srvNameCacheLock);
+ }
+ return now;
+}
+
+/*
+** Convert local SID to shared memory one
+*/
+static void
+ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
+{
+ to->valid = 1;
+ to->version = from->version;
+ to->addr = from->addr;
+ to->creationTime = from->creationTime;
+ to->lastAccessTime = from->lastAccessTime;
+ to->expirationTime = from->expirationTime;
+ to->authAlgorithm = from->authAlgorithm;
+ to->authKeyBits = from->authKeyBits;
+ to->keaType = from->keaType;
+ to->keaKeyBits = from->keaKeyBits;
+
+ if (from->version < SSL_LIBRARY_VERSION_3_0) {
+ if ((from->u.ssl2.masterKey.len > SSL_MAX_MASTER_KEY_BYTES) ||
+ (from->u.ssl2.cipherArg.len > SSL_MAX_CYPHER_ARG_BYTES)) {
+ SSL_DBG(("%d: SSL: masterKeyLen=%d cipherArgLen=%d",
+ myPid, from->u.ssl2.masterKey.len,
+ from->u.ssl2.cipherArg.len));
+ to->valid = 0;
+ return;
+ }
+
+ to->u.ssl2.cipherType = from->u.ssl2.cipherType;
+ to->u.ssl2.masterKeyLen = from->u.ssl2.masterKey.len;
+ to->u.ssl2.cipherArgLen = from->u.ssl2.cipherArg.len;
+ to->u.ssl2.keyBits = from->u.ssl2.keyBits;
+ to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
+ to->sessionIDLength = SSL2_SESSIONID_BYTES;
+ PORT_Memcpy(to->sessionID, from->u.ssl2.sessionID, SSL2_SESSIONID_BYTES);
+ PORT_Memcpy(to->u.ssl2.masterKey, from->u.ssl2.masterKey.data,
+ from->u.ssl2.masterKey.len);
+ PORT_Memcpy(to->u.ssl2.cipherArg, from->u.ssl2.cipherArg.data,
+ from->u.ssl2.cipherArg.len);
+#ifdef DEBUG
+ PORT_Memset(to->u.ssl2.masterKey+from->u.ssl2.masterKey.len, 0,
+ sizeof(to->u.ssl2.masterKey) - from->u.ssl2.masterKey.len);
+ PORT_Memset(to->u.ssl2.cipherArg+from->u.ssl2.cipherArg.len, 0,
+ sizeof(to->u.ssl2.cipherArg) - from->u.ssl2.cipherArg.len);
+#endif
+ SSL_TRC(8, ("%d: SSL: ConvertSID: masterKeyLen=%d cipherArgLen=%d "
+ "time=%d addr=0x%08x%08x%08x%08x cipherType=%d", myPid,
+ to->u.ssl2.masterKeyLen, to->u.ssl2.cipherArgLen,
+ to->creationTime, to->addr.pr_s6_addr32[0],
+ to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
+ to->addr.pr_s6_addr32[3], to->u.ssl2.cipherType));
+ } else {
+ /* This is an SSL v3 session */
+
+ to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite;
+ to->u.ssl3.compression = (PRUint16)from->u.ssl3.compression;
+ to->u.ssl3.keys = from->u.ssl3.keys;
+ to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech;
+ to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType;
+ to->sessionIDLength = from->u.ssl3.sessionIDLength;
+ to->u.ssl3.certIndex = -1;
+ to->u.ssl3.srvNameIndex = -1;
+
+ PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID,
+ to->sessionIDLength);
+
+ SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x "
+ "cipherSuite=%d",
+ myPid, to->creationTime, to->addr.pr_s6_addr32[0],
+ to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
+ to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite));
+ }
+}
+
+/*
+** Convert shared memory cache-entry to local memory based one
+** This is only called from ServerSessionIDLookup().
+** Caller must hold cache lock when calling this.
+*/
+static sslSessionID *
+ConvertToSID(sidCacheEntry * from,
+ certCacheEntry * pcce,
+ srvNameCacheEntry *psnce,
+ CERTCertDBHandle * dbHandle)
+{
+ sslSessionID *to;
+ PRUint16 version = from->version;
+
+ to = PORT_ZNew(sslSessionID);
+ if (!to) {
+ return 0;
+ }
+
+ if (version < SSL_LIBRARY_VERSION_3_0) {
+ /* This is an SSL v2 session */
+ to->u.ssl2.masterKey.data =
+ (unsigned char*) PORT_Alloc(from->u.ssl2.masterKeyLen);
+ if (!to->u.ssl2.masterKey.data) {
+ goto loser;
+ }
+ if (from->u.ssl2.cipherArgLen) {
+ to->u.ssl2.cipherArg.data =
+ (unsigned char*)PORT_Alloc(from->u.ssl2.cipherArgLen);
+ if (!to->u.ssl2.cipherArg.data) {
+ goto loser;
+ }
+ PORT_Memcpy(to->u.ssl2.cipherArg.data, from->u.ssl2.cipherArg,
+ from->u.ssl2.cipherArgLen);
+ }
+
+ to->u.ssl2.cipherType = from->u.ssl2.cipherType;
+ to->u.ssl2.masterKey.len = from->u.ssl2.masterKeyLen;
+ to->u.ssl2.cipherArg.len = from->u.ssl2.cipherArgLen;
+ to->u.ssl2.keyBits = from->u.ssl2.keyBits;
+ to->u.ssl2.secretKeyBits = from->u.ssl2.secretKeyBits;
+/* to->sessionIDLength = SSL2_SESSIONID_BYTES; */
+ PORT_Memcpy(to->u.ssl2.sessionID, from->sessionID, SSL2_SESSIONID_BYTES);
+ PORT_Memcpy(to->u.ssl2.masterKey.data, from->u.ssl2.masterKey,
+ from->u.ssl2.masterKeyLen);
+
+ SSL_TRC(8, ("%d: SSL: ConvertToSID: masterKeyLen=%d cipherArgLen=%d "
+ "time=%d addr=0x%08x%08x%08x%08x cipherType=%d",
+ myPid, to->u.ssl2.masterKey.len,
+ to->u.ssl2.cipherArg.len, to->creationTime,
+ to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1],
+ to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3],
+ to->u.ssl2.cipherType));
+ } else {
+ /* This is an SSL v3 session */
+
+ to->u.ssl3.sessionIDLength = from->sessionIDLength;
+ to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite;
+ to->u.ssl3.compression = (SSLCompressionMethod)from->u.ssl3.compression;
+ to->u.ssl3.keys = from->u.ssl3.keys;
+ to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech;
+ to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType;
+ if (from->u.ssl3.srvNameIndex != -1 && psnce) {
+ SECItem name;
+ SECStatus rv;
+ name.type = psnce->type;
+ name.len = psnce->nameLen;
+ name.data = psnce->name;
+ rv = SECITEM_CopyItem(NULL, &to->u.ssl3.srvName, &name);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+
+ PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
+
+ /* the portions of the SID that are only restored on the client
+ * are set to invalid values on the server.
+ */
+ to->u.ssl3.clientWriteKey = NULL;
+ to->u.ssl3.serverWriteKey = NULL;
+
+ to->urlSvrName = NULL;
+
+ to->u.ssl3.masterModuleID = (SECMODModuleID)-1; /* invalid value */
+ to->u.ssl3.masterSlotID = (CK_SLOT_ID)-1; /* invalid value */
+ to->u.ssl3.masterWrapIndex = 0;
+ to->u.ssl3.masterWrapSeries = 0;
+ to->u.ssl3.masterValid = PR_FALSE;
+
+ to->u.ssl3.clAuthModuleID = (SECMODModuleID)-1; /* invalid value */
+ to->u.ssl3.clAuthSlotID = (CK_SLOT_ID)-1; /* invalid value */
+ to->u.ssl3.clAuthSeries = 0;
+ to->u.ssl3.clAuthValid = PR_FALSE;
+
+ if (from->u.ssl3.certIndex != -1 && pcce) {
+ SECItem derCert;
+
+ derCert.len = pcce->certLength;
+ derCert.data = pcce->cert;
+
+ to->peerCert = CERT_NewTempCertificate(dbHandle, &derCert, NULL,
+ PR_FALSE, PR_TRUE);
+ if (to->peerCert == NULL)
+ goto loser;
+ }
+ }
+
+ to->version = from->version;
+ to->creationTime = from->creationTime;
+ to->lastAccessTime = from->lastAccessTime;
+ to->expirationTime = from->expirationTime;
+ to->cached = in_server_cache;
+ to->addr = from->addr;
+ to->references = 1;
+ to->authAlgorithm = from->authAlgorithm;
+ to->authKeyBits = from->authKeyBits;
+ to->keaType = from->keaType;
+ to->keaKeyBits = from->keaKeyBits;
+
+ return to;
+
+ loser:
+ if (to) {
+ if (version < SSL_LIBRARY_VERSION_3_0) {
+ if (to->u.ssl2.masterKey.data)
+ PORT_Free(to->u.ssl2.masterKey.data);
+ if (to->u.ssl2.cipherArg.data)
+ PORT_Free(to->u.ssl2.cipherArg.data);
+ } else {
+ SECITEM_FreeItem(&to->u.ssl3.srvName, PR_FALSE);
+ }
+ PORT_Free(to);
+ }
+ return NULL;
+}
+
+
+
+/*
+** Perform some mumbo jumbo on the ip-address and the session-id value to
+** compute a hash value.
+*/
+static PRUint32
+SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl)
+{
+ PRUint32 rv;
+ PRUint32 x[8];
+
+ memset(x, 0, sizeof x);
+ if (nl > sizeof x)
+ nl = sizeof x;
+ memcpy(x, s, nl);
+
+ rv = (addr->pr_s6_addr32[0] ^ addr->pr_s6_addr32[1] ^
+ addr->pr_s6_addr32[2] ^ addr->pr_s6_addr32[3] ^
+ x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7])
+ % cache->numSIDCacheSets;
+ return rv;
+}
+
+
+
+/*
+** Look something up in the cache. This will invalidate old entries
+** in the process. Caller has locked the cache set!
+** Returns PR_TRUE if found a valid match. PR_FALSE otherwise.
+*/
+static sidCacheEntry *
+FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now,
+ const PRIPv6Addr *addr, unsigned char *sessionID,
+ unsigned sessionIDLength)
+{
+ PRUint32 ndx = cache->sidCacheSets[setNum].next;
+ int i;
+
+ sidCacheEntry * set = cache->sidCacheData +
+ (setNum * SID_CACHE_ENTRIES_PER_SET);
+
+ for (i = SID_CACHE_ENTRIES_PER_SET; i > 0; --i) {
+ sidCacheEntry * sce;
+
+ ndx = (ndx - 1) % SID_CACHE_ENTRIES_PER_SET;
+ sce = set + ndx;
+
+ if (!sce->valid)
+ continue;
+
+ if (now > sce->expirationTime) {
+ /* SessionID has timed out. Invalidate the entry. */
+ SSL_TRC(7, ("%d: timed out sid entry addr=%08x%08x%08x%08x now=%x "
+ "time+=%x",
+ myPid, sce->addr.pr_s6_addr32[0],
+ sce->addr.pr_s6_addr32[1], sce->addr.pr_s6_addr32[2],
+ sce->addr.pr_s6_addr32[3], now,
+ sce->expirationTime ));
+ sce->valid = 0;
+ continue;
+ }
+
+ /*
+ ** Next, examine specific session-id/addr data to see if the cache
+ ** entry matches our addr+session-id value
+ */
+ if (sessionIDLength == sce->sessionIDLength &&
+ !memcmp(&sce->addr, addr, sizeof(PRIPv6Addr)) &&
+ !memcmp(sce->sessionID, sessionID, sessionIDLength)) {
+ /* Found it */
+ return sce;
+ }
+ }
+
+ PORT_SetError(SSL_ERROR_SESSION_NOT_FOUND);
+ return NULL;
+}
+
+/************************************************************************/
+
+/* This is the primary function for finding entries in the server's sid cache.
+ * Although it is static, this function is called via the global function
+ * pointer ssl_sid_lookup.
+ */
+static sslSessionID *
+ServerSessionIDLookup(const PRIPv6Addr *addr,
+ unsigned char *sessionID,
+ unsigned int sessionIDLength,
+ CERTCertDBHandle * dbHandle)
+{
+ sslSessionID * sid = 0;
+ sidCacheEntry * psce;
+ certCacheEntry *pcce = 0;
+ srvNameCacheEntry *psnce = 0;
+ cacheDesc * cache = &globalCache;
+ PRUint32 now;
+ PRUint32 set;
+ PRInt32 cndx;
+ sidCacheEntry sce;
+ certCacheEntry cce;
+ srvNameCacheEntry snce;
+
+ set = SIDindex(cache, addr, sessionID, sessionIDLength);
+ now = LockSet(cache, set, 0);
+ if (!now)
+ return NULL;
+
+ psce = FindSID(cache, set, now, addr, sessionID, sessionIDLength);
+ if (psce) {
+ if (psce->version >= SSL_LIBRARY_VERSION_3_0) {
+ if ((cndx = psce->u.ssl3.certIndex) != -1) {
+
+ PRUint32 gotLock = LockSidCacheLock(cache->certCacheLock, now);
+ if (gotLock) {
+ pcce = &cache->certCacheData[cndx];
+
+ /* See if the cert's session ID matches the sce cache. */
+ if ((pcce->sessionIDLength == psce->sessionIDLength) &&
+ !PORT_Memcmp(pcce->sessionID, psce->sessionID,
+ pcce->sessionIDLength)) {
+ cce = *pcce;
+ } else {
+ /* The cert doesen't match the SID cache entry,
+ ** so invalidate the SID cache entry.
+ */
+ psce->valid = 0;
+ psce = 0;
+ pcce = 0;
+ }
+ UnlockSidCacheLock(cache->certCacheLock);
+ } else {
+ /* what the ??. Didn't get the cert cache lock.
+ ** Don't invalidate the SID cache entry, but don't find it.
+ */
+ PORT_Assert(!("Didn't get cert Cache Lock!"));
+ psce = 0;
+ pcce = 0;
+ }
+ }
+ if (psce && ((cndx = psce->u.ssl3.srvNameIndex) != -1)) {
+ PRUint32 gotLock = LockSidCacheLock(cache->srvNameCacheLock,
+ now);
+ if (gotLock) {
+ psnce = &cache->srvNameCacheData[cndx];
+
+ if (!PORT_Memcmp(psnce->nameHash, psce->u.ssl3.srvNameHash,
+ SHA256_LENGTH)) {
+ snce = *psnce;
+ } else {
+ /* The name doesen't match the SID cache entry,
+ ** so invalidate the SID cache entry.
+ */
+ psce->valid = 0;
+ psce = 0;
+ psnce = 0;
+ }
+ UnlockSidCacheLock(cache->srvNameCacheLock);
+ } else {
+ /* what the ??. Didn't get the cert cache lock.
+ ** Don't invalidate the SID cache entry, but don't find it.
+ */
+ PORT_Assert(!("Didn't get name Cache Lock!"));
+ psce = 0;
+ psnce = 0;
+ }
+
+ }
+ }
+ if (psce) {
+ psce->lastAccessTime = now;
+ sce = *psce; /* grab a copy while holding the lock */
+ }
+ }
+ UnlockSet(cache, set);
+ if (psce) {
+ /* sce conains a copy of the cache entry.
+ ** Convert shared memory format to local format
+ */
+ sid = ConvertToSID(&sce, pcce ? &cce : 0, psnce ? &snce : 0, dbHandle);
+ }
+ return sid;
+}
+
+/*
+** Place a sid into the cache, if it isn't already there.
+*/
+static void
+ServerSessionIDCache(sslSessionID *sid)
+{
+ sidCacheEntry sce;
+ PRUint32 now = 0;
+ PRUint16 version = sid->version;
+ cacheDesc * cache = &globalCache;
+
+ if ((version >= SSL_LIBRARY_VERSION_3_0) &&
+ (sid->u.ssl3.sessionIDLength == 0)) {
+ return;
+ }
+
+ if (sid->cached == never_cached || sid->cached == invalid_cache) {
+ PRUint32 set;
+
+ PORT_Assert(sid->creationTime != 0);
+ if (!sid->creationTime)
+ sid->lastAccessTime = sid->creationTime = ssl_Time();
+ if (version < SSL_LIBRARY_VERSION_3_0) {
+ /* override caller's expiration time, which uses client timeout
+ * duration, not server timeout duration.
+ */
+ sid->expirationTime = sid->creationTime + cache->ssl2Timeout;
+ SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
+ "cipher=%d", myPid, sid->cached,
+ sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
+ sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
+ sid->creationTime, sid->u.ssl2.cipherType));
+ PRINT_BUF(8, (0, "sessionID:", sid->u.ssl2.sessionID,
+ SSL2_SESSIONID_BYTES));
+ PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
+ sid->u.ssl2.masterKey.len));
+ PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
+ sid->u.ssl2.cipherArg.len));
+
+ } else {
+ /* override caller's expiration time, which uses client timeout
+ * duration, not server timeout duration.
+ */
+ sid->expirationTime = sid->creationTime + cache->ssl3Timeout;
+ SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
+ "cipherSuite=%d", myPid, sid->cached,
+ sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
+ sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
+ sid->creationTime, sid->u.ssl3.cipherSuite));
+ PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
+ sid->u.ssl3.sessionIDLength));
+ }
+
+ ConvertFromSID(&sce, sid);
+
+ if (version >= SSL_LIBRARY_VERSION_3_0) {
+ SECItem *name = &sid->u.ssl3.srvName;
+ if (name->len && name->data) {
+ now = CacheSrvName(cache, name, &sce);
+ }
+ if (sid->peerCert != NULL) {
+ now = CacheCert(cache, sid->peerCert, &sce);
+ }
+ }
+
+ set = SIDindex(cache, &sce.addr, sce.sessionID, sce.sessionIDLength);
+ now = LockSet(cache, set, now);
+ if (now) {
+ PRUint32 next = cache->sidCacheSets[set].next;
+ PRUint32 ndx = set * SID_CACHE_ENTRIES_PER_SET + next;
+
+ /* Write out new cache entry */
+ cache->sidCacheData[ndx] = sce;
+
+ cache->sidCacheSets[set].next =
+ (next + 1) % SID_CACHE_ENTRIES_PER_SET;
+
+ UnlockSet(cache, set);
+ sid->cached = in_server_cache;
+ }
+ }
+}
+
+/*
+** Although this is static, it is called from ssl via global function pointer
+** ssl_sid_uncache. This invalidates the referenced cache entry.
+*/
+static void
+ServerSessionIDUncache(sslSessionID *sid)
+{
+ cacheDesc * cache = &globalCache;
+ PRUint8 * sessionID;
+ unsigned int sessionIDLength;
+ PRErrorCode err;
+ PRUint32 set;
+ PRUint32 now;
+ sidCacheEntry *psce;
+
+ if (sid == NULL)
+ return;
+
+ /* Uncaching a SID should never change the error code.
+ ** So save it here and restore it before exiting.
+ */
+ err = PR_GetError();
+
+ if (sid->version < SSL_LIBRARY_VERSION_3_0) {
+ sessionID = sid->u.ssl2.sessionID;
+ sessionIDLength = SSL2_SESSIONID_BYTES;
+ SSL_TRC(8, ("%d: SSL: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
+ "cipher=%d", myPid, sid->cached,
+ sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
+ sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
+ sid->creationTime, sid->u.ssl2.cipherType));
+ PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
+ PRINT_BUF(8, (0, "masterKey:", sid->u.ssl2.masterKey.data,
+ sid->u.ssl2.masterKey.len));
+ PRINT_BUF(8, (0, "cipherArg:", sid->u.ssl2.cipherArg.data,
+ sid->u.ssl2.cipherArg.len));
+ } else {
+ sessionID = sid->u.ssl3.sessionID;
+ sessionIDLength = sid->u.ssl3.sessionIDLength;
+ SSL_TRC(8, ("%d: SSL3: UncacheMT: valid=%d addr=0x%08x%08x%08x%08x time=%x "
+ "cipherSuite=%d", myPid, sid->cached,
+ sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
+ sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
+ sid->creationTime, sid->u.ssl3.cipherSuite));
+ PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
+ }
+ set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength);
+ now = LockSet(cache, set, 0);
+ if (now) {
+ psce = FindSID(cache, set, now, &sid->addr, sessionID, sessionIDLength);
+ if (psce) {
+ psce->valid = 0;
+ }
+ UnlockSet(cache, set);
+ }
+ sid->cached = invalid_cache;
+ PORT_SetError(err);
+}
+
+#ifdef XP_OS2
+
+#define INCL_DOSPROCESS
+#include <os2.h>
+
+long gettid(void)
+{
+ PTIB ptib;
+ PPIB ppib;
+ DosGetInfoBlocks(&ptib, &ppib);
+ return ((long)ptib->tib_ordinal); /* thread id */
+}
+#endif
+
+static void
+CloseCache(cacheDesc *cache)
+{
+ int locks_initialized = cache->numSIDCacheLocksInitialized;
+
+ if (cache->cacheMem) {
+ if (cache->sharedCache) {
+ sidCacheLock *pLock = cache->sidCacheLocks;
+ for (; locks_initialized > 0; --locks_initialized, ++pLock ) {
+ /* If everInherited is true, this shared cache was (and may
+ ** still be) in use by multiple processes. We do not wish to
+ ** destroy the mutexes while they are still in use, but we do
+ ** want to free mutex resources associated with this process.
+ */
+ sslMutex_Destroy(&pLock->mutex,
+ cache->sharedCache->everInherited);
+ }
+ }
+ if (cache->shared) {
+ PR_MemUnmap(cache->cacheMem, cache->cacheMemSize);
+ } else {
+ PORT_Free(cache->cacheMem);
+ }
+ cache->cacheMem = NULL;
+ }
+ if (cache->cacheMemMap) {
+ PR_CloseFileMap(cache->cacheMemMap);
+ cache->cacheMemMap = NULL;
+ }
+ memset(cache, 0, sizeof *cache);
+}
+
+static SECStatus
+InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
+ int maxSrvNameCacheEntries, PRUint32 ssl2_timeout,
+ PRUint32 ssl3_timeout, const char *directory, PRBool shared)
+{
+ ptrdiff_t ptr;
+ sidCacheLock *pLock;
+ char * cacheMem;
+ PRFileMap * cacheMemMap;
+ char * cfn = NULL; /* cache file name */
+ int locks_initialized = 0;
+ int locks_to_initialize = 0;
+ PRUint32 init_time;
+
+ if ( (!cache) || (maxCacheEntries < 0) || (!directory) ) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (cache->cacheMem) {
+ /* Already done */
+ return SECSuccess;
+ }
+
+ /* make sure loser can clean up properly */
+ cache->shared = shared;
+ cache->cacheMem = cacheMem = NULL;
+ cache->cacheMemMap = cacheMemMap = NULL;
+ cache->sharedCache = (cacheDesc *)0;
+
+ cache->numSIDCacheLocksInitialized = 0;
+ cache->nextCertCacheEntry = 0;
+ cache->stopPolling = PR_FALSE;
+ cache->everInherited = PR_FALSE;
+ cache->poller = NULL;
+ cache->mutexTimeout = 0;
+
+ cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries
+ : DEF_SID_CACHE_ENTRIES;
+ cache->numSIDCacheSets =
+ SID_HOWMANY(cache->numSIDCacheEntries, SID_CACHE_ENTRIES_PER_SET);
+
+ cache->numSIDCacheEntries =
+ cache->numSIDCacheSets * SID_CACHE_ENTRIES_PER_SET;
+
+ cache->numSIDCacheLocks =
+ PR_MIN(cache->numSIDCacheSets, ssl_max_sid_cache_locks);
+
+ cache->numSIDCacheSetsPerLock =
+ SID_HOWMANY(cache->numSIDCacheSets, cache->numSIDCacheLocks);
+
+ cache->numCertCacheEntries = (maxCertCacheEntries > 0) ?
+ maxCertCacheEntries : 0;
+ cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries >= 0) ?
+ maxSrvNameCacheEntries : DEF_NAME_CACHE_ENTRIES;
+
+ /* compute size of shared memory, and offsets of all pointers */
+ ptr = 0;
+ cache->cacheMem = (char *)ptr;
+ ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT);
+
+ cache->sidCacheLocks = (sidCacheLock *)ptr;
+ cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks;
+ cache->certCacheLock = cache->keyCacheLock + 1;
+ cache->srvNameCacheLock = cache->certCacheLock + 1;
+ ptr = (ptrdiff_t)(cache->srvNameCacheLock + 1);
+ ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
+
+ cache->sidCacheSets = (sidCacheSet *)ptr;
+ ptr = (ptrdiff_t)(cache->sidCacheSets + cache->numSIDCacheSets);
+ ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
+
+ cache->sidCacheData = (sidCacheEntry *)ptr;
+ ptr = (ptrdiff_t)(cache->sidCacheData + cache->numSIDCacheEntries);
+ ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
+
+ cache->certCacheData = (certCacheEntry *)ptr;
+ cache->sidCacheSize =
+ (char *)cache->certCacheData - (char *)cache->sidCacheData;
+
+ if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES) {
+ /* This is really a poor way to computer this! */
+ cache->numCertCacheEntries = cache->sidCacheSize / sizeof(certCacheEntry);
+ if (cache->numCertCacheEntries < MIN_CERT_CACHE_ENTRIES)
+ cache->numCertCacheEntries = MIN_CERT_CACHE_ENTRIES;
+ }
+ ptr = (ptrdiff_t)(cache->certCacheData + cache->numCertCacheEntries);
+ ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
+
+ cache->keyCacheData = (SSLWrappedSymWrappingKey *)ptr;
+ cache->certCacheSize =
+ (char *)cache->keyCacheData - (char *)cache->certCacheData;
+
+ cache->numKeyCacheEntries = kt_kea_size * SSL_NUM_WRAP_MECHS;
+ ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries);
+ ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
+
+ cache->keyCacheSize = (char *)ptr - (char *)cache->keyCacheData;
+
+ cache->ticketKeyNameSuffix = (PRUint8 *)ptr;
+ ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix +
+ SESS_TICKET_KEY_VAR_NAME_LEN);
+ ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
+
+ cache->ticketEncKey = (encKeyCacheEntry *)ptr;
+ ptr = (ptrdiff_t)(cache->ticketEncKey + 1);
+ ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
+
+ cache->ticketMacKey = (encKeyCacheEntry *)ptr;
+ ptr = (ptrdiff_t)(cache->ticketMacKey + 1);
+ ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
+
+ cache->ticketKeysValid = (PRUint32 *)ptr;
+ ptr = (ptrdiff_t)(cache->ticketKeysValid + 1);
+ ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
+
+ cache->srvNameCacheData = (srvNameCacheEntry *)ptr;
+ cache->srvNameCacheSize =
+ cache->numSrvNameCacheEntries * sizeof(srvNameCacheEntry);
+ ptr = (ptrdiff_t)(cache->srvNameCacheData + cache->numSrvNameCacheEntries);
+ ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
+
+ cache->cacheMemSize = ptr;
+
+ if (ssl2_timeout) {
+ if (ssl2_timeout > MAX_SSL2_TIMEOUT) {
+ ssl2_timeout = MAX_SSL2_TIMEOUT;
+ }
+ if (ssl2_timeout < MIN_SSL2_TIMEOUT) {
+ ssl2_timeout = MIN_SSL2_TIMEOUT;
+ }
+ cache->ssl2Timeout = ssl2_timeout;
+ } else {
+ cache->ssl2Timeout = DEF_SSL2_TIMEOUT;
+ }
+
+ if (ssl3_timeout) {
+ if (ssl3_timeout > MAX_SSL3_TIMEOUT) {
+ ssl3_timeout = MAX_SSL3_TIMEOUT;
+ }
+ if (ssl3_timeout < MIN_SSL3_TIMEOUT) {
+ ssl3_timeout = MIN_SSL3_TIMEOUT;
+ }
+ cache->ssl3Timeout = ssl3_timeout;
+ } else {
+ cache->ssl3Timeout = DEF_SSL3_TIMEOUT;
+ }
+
+ if (shared) {
+ /* Create file names */
+#if defined(XP_UNIX) || defined(XP_BEOS)
+ /* there's some confusion here about whether PR_OpenAnonFileMap wants
+ ** a directory name or a file name for its first argument.
+ cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid);
+ */
+ cfn = PR_smprintf("%s", directory);
+#elif defined(XP_WIN32)
+ cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
+ GetCurrentThreadId());
+#elif defined(XP_OS2)
+ cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
+ gettid());
+#else
+#error "Don't know how to create file name for this platform!"
+#endif
+ if (!cfn) {
+ goto loser;
+ }
+
+ /* Create cache */
+ cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize,
+ PR_PROT_READWRITE);
+
+ PR_smprintf_free(cfn);
+ if(!cacheMemMap) {
+ goto loser;
+ }
+
+ cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize);
+ } else {
+ cacheMem = PORT_Alloc(cache->cacheMemSize);
+ }
+
+ if (! cacheMem) {
+ goto loser;
+ }
+
+ /* Initialize shared memory. This may not be necessary on all platforms */
+ memset(cacheMem, 0, cache->cacheMemSize);
+
+ /* Copy cache descriptor header into shared memory */
+ memcpy(cacheMem, cache, sizeof *cache);
+
+ /* save private copies of these values */
+ cache->cacheMemMap = cacheMemMap;
+ cache->cacheMem = cacheMem;
+ cache->sharedCache = (cacheDesc *)cacheMem;
+
+ /* Fix pointers in our private copy of cache descriptor to point to
+ ** spaces in shared memory
+ */
+ ptr = (ptrdiff_t)cache->cacheMem;
+ *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
+ *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
+ *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
+ *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
+ *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
+ *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
+ *(ptrdiff_t *)(&cache->certCacheData) += ptr;
+ *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
+ *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr;
+ *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
+ *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
+ *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
+ *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
+
+ /* initialize the locks */
+ init_time = ssl_Time();
+ pLock = cache->sidCacheLocks;
+ for (locks_to_initialize = cache->numSIDCacheLocks + 3;
+ locks_initialized < locks_to_initialize;
+ ++locks_initialized, ++pLock ) {
+
+ SECStatus err = sslMutex_Init(&pLock->mutex, shared);
+ if (err) {
+ cache->numSIDCacheLocksInitialized = locks_initialized;
+ goto loser;
+ }
+ pLock->timeStamp = init_time;
+ pLock->pid = 0;
+ }
+ cache->numSIDCacheLocksInitialized = locks_initialized;
+
+ return SECSuccess;
+
+loser:
+ CloseCache(cache);
+ return SECFailure;
+}
+
+PRUint32
+SSL_GetMaxServerCacheLocks(void)
+{
+ return ssl_max_sid_cache_locks + 2;
+ /* The extra two are the cert cache lock and the key cache lock. */
+}
+
+SECStatus
+SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
+{
+ /* Minimum is 1 sid cache lock, 1 cert cache lock and 1 key cache lock.
+ ** We'd like to test for a maximum value, but not all platforms' header
+ ** files provide a symbol or function or other means of determining
+ ** the maximum, other than trial and error.
+ */
+ if (maxLocks < 3) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ ssl_max_sid_cache_locks = maxLocks - 2;
+ /* The extra two are the cert cache lock and the key cache lock. */
+ return SECSuccess;
+}
+
+static SECStatus
+ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
+ PRUint32 ssl2_timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory,
+ PRBool shared,
+ int maxCacheEntries,
+ int maxCertCacheEntries,
+ int maxSrvNameCacheEntries)
+{
+ SECStatus rv;
+
+ PORT_Assert(sizeof(sidCacheEntry) == 192);
+ PORT_Assert(sizeof(certCacheEntry) == 4096);
+ PORT_Assert(sizeof(srvNameCacheEntry) == 1072);
+
+ rv = ssl_Init();
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ myPid = SSL_GETPID();
+ if (!directory) {
+ directory = DEFAULT_CACHE_DIRECTORY;
+ }
+ rv = InitCache(cache, maxCacheEntries, maxCertCacheEntries,
+ maxSrvNameCacheEntries, ssl2_timeout, ssl3_timeout,
+ directory, shared);
+ if (rv) {
+ SET_ERROR_CODE
+ return SECFailure;
+ }
+
+ ssl_sid_lookup = ServerSessionIDLookup;
+ ssl_sid_cache = ServerSessionIDCache;
+ ssl_sid_uncache = ServerSessionIDUncache;
+ return SECSuccess;
+}
+
+SECStatus
+SSL_ConfigServerSessionIDCacheInstance( cacheDesc *cache,
+ int maxCacheEntries,
+ PRUint32 ssl2_timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory, PRBool shared)
+{
+ return ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
+ ssl2_timeout,
+ ssl3_timeout,
+ directory,
+ shared,
+ maxCacheEntries,
+ -1, -1);
+}
+
+SECStatus
+SSL_ConfigServerSessionIDCache( int maxCacheEntries,
+ PRUint32 ssl2_timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory)
+{
+ ssl_InitSessionCacheLocks(PR_FALSE);
+ return SSL_ConfigServerSessionIDCacheInstance(&globalCache,
+ maxCacheEntries, ssl2_timeout, ssl3_timeout, directory, PR_FALSE);
+}
+
+SECStatus
+SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache)
+{
+ CloseCache(cache);
+ return SECSuccess;
+}
+
+SECStatus
+SSL_ShutdownServerSessionIDCache(void)
+{
+#if defined(XP_UNIX) || defined(XP_BEOS)
+ /* Stop the thread that polls cache for expired locks on Unix */
+ StopLockPoller(&globalCache);
+#endif
+ SSL3_ShutdownServerCache();
+ return SSL_ShutdownServerSessionIDCacheInstance(&globalCache);
+}
+
+/* Use this function, instead of SSL_ConfigServerSessionIDCache,
+ * if the cache will be shared by multiple processes.
+ */
+static SECStatus
+ssl_ConfigMPServerSIDCacheWithOpt( PRUint32 ssl2_timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory,
+ int maxCacheEntries,
+ int maxCertCacheEntries,
+ int maxSrvNameCacheEntries)
+{
+ char * envValue;
+ char * inhValue;
+ cacheDesc * cache = &globalCache;
+ PRUint32 fmStrLen;
+ SECStatus result;
+ PRStatus prStatus;
+ SECStatus putEnvFailed;
+ inheritance inherit;
+ char fmString[PR_FILEMAP_STRING_BUFSIZE];
+
+ isMultiProcess = PR_TRUE;
+ result = ssl_ConfigServerSessionIDCacheInstanceWithOpt(cache,
+ ssl2_timeout, ssl3_timeout, directory, PR_TRUE,
+ maxCacheEntries, maxCacheEntries, maxSrvNameCacheEntries);
+ if (result != SECSuccess)
+ return result;
+
+ prStatus = PR_ExportFileMapAsString(cache->cacheMemMap,
+ sizeof fmString, fmString);
+ if ((prStatus != PR_SUCCESS) || !(fmStrLen = strlen(fmString))) {
+ SET_ERROR_CODE
+ return SECFailure;
+ }
+
+ inherit.cacheMemSize = cache->cacheMemSize;
+ inherit.fmStrLen = fmStrLen;
+
+ inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit);
+ if (!inhValue || !strlen(inhValue)) {
+ SET_ERROR_CODE
+ return SECFailure;
+ }
+ envValue = PR_smprintf("%s,%s", inhValue, fmString);
+ if (!envValue || !strlen(envValue)) {
+ SET_ERROR_CODE
+ return SECFailure;
+ }
+ PORT_Free(inhValue);
+
+ putEnvFailed = (SECStatus)NSS_PutEnv(envVarName, envValue);
+ PR_smprintf_free(envValue);
+ if (putEnvFailed) {
+ SET_ERROR_CODE
+ result = SECFailure;
+ }
+
+#if defined(XP_UNIX) || defined(XP_BEOS)
+ /* Launch thread to poll cache for expired locks on Unix */
+ LaunchLockPoller(cache);
+#endif
+ return result;
+}
+
+/* Use this function, instead of SSL_ConfigServerSessionIDCache,
+ * if the cache will be shared by multiple processes.
+ */
+SECStatus
+SSL_ConfigMPServerSIDCache( int maxCacheEntries,
+ PRUint32 ssl2_timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory)
+{
+ return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout,
+ ssl3_timeout,
+ directory,
+ maxCacheEntries,
+ -1, -1);
+}
+
+SECStatus
+SSL_ConfigServerSessionIDCacheWithOpt(
+ PRUint32 ssl2_timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory,
+ int maxCacheEntries,
+ int maxCertCacheEntries,
+ int maxSrvNameCacheEntries,
+ PRBool enableMPCache)
+{
+ if (!enableMPCache) {
+ ssl_InitSessionCacheLocks(PR_FALSE);
+ return ssl_ConfigServerSessionIDCacheInstanceWithOpt(&globalCache,
+ ssl2_timeout, ssl3_timeout, directory, PR_FALSE,
+ maxCacheEntries, maxCertCacheEntries, maxSrvNameCacheEntries);
+ } else {
+ return ssl_ConfigMPServerSIDCacheWithOpt(ssl2_timeout, ssl3_timeout,
+ directory, maxCacheEntries, maxCertCacheEntries,
+ maxSrvNameCacheEntries);
+ }
+}
+
+SECStatus
+SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
+{
+ unsigned char * decoString = NULL;
+ char * fmString = NULL;
+ char * myEnvString = NULL;
+ unsigned int decoLen;
+ ptrdiff_t ptr;
+ inheritance inherit;
+ cacheDesc my;
+#ifdef WINNT
+ sidCacheLock* newLocks;
+ int locks_initialized = 0;
+ int locks_to_initialize = 0;
+#endif
+ SECStatus status = ssl_Init();
+
+ if (status != SECSuccess) {
+ return status;
+ }
+
+ myPid = SSL_GETPID();
+
+ /* If this child was created by fork(), and not by exec() on unix,
+ ** then isMultiProcess will already be set.
+ ** If not, we'll set it below.
+ */
+ if (isMultiProcess) {
+ if (cache && cache->sharedCache) {
+ cache->sharedCache->everInherited = PR_TRUE;
+ }
+ return SECSuccess; /* already done. */
+ }
+
+ ssl_InitSessionCacheLocks(PR_FALSE);
+
+ ssl_sid_lookup = ServerSessionIDLookup;
+ ssl_sid_cache = ServerSessionIDCache;
+ ssl_sid_uncache = ServerSessionIDUncache;
+
+ if (!envString) {
+ envString = getenv(envVarName);
+ if (!envString) {
+ SET_ERROR_CODE
+ return SECFailure;
+ }
+ }
+ myEnvString = PORT_Strdup(envString);
+ if (!myEnvString)
+ return SECFailure;
+ fmString = strchr(myEnvString, ',');
+ if (!fmString)
+ goto loser;
+ *fmString++ = 0;
+
+ decoString = ATOB_AsciiToData(myEnvString, &decoLen);
+ if (!decoString) {
+ SET_ERROR_CODE
+ goto loser;
+ }
+ if (decoLen != sizeof inherit) {
+ SET_ERROR_CODE
+ goto loser;
+ }
+
+ PORT_Memcpy(&inherit, decoString, sizeof inherit);
+
+ if (strlen(fmString) != inherit.fmStrLen ) {
+ goto loser;
+ }
+
+ memset(cache, 0, sizeof *cache);
+ cache->cacheMemSize = inherit.cacheMemSize;
+
+ /* Create cache */
+ cache->cacheMemMap = PR_ImportFileMapFromString(fmString);
+ if(! cache->cacheMemMap) {
+ goto loser;
+ }
+ cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize);
+ if (! cache->cacheMem) {
+ goto loser;
+ }
+ cache->sharedCache = (cacheDesc *)cache->cacheMem;
+
+ if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) {
+ SET_ERROR_CODE
+ goto loser;
+ }
+
+ /* We're now going to overwrite the local cache instance with the
+ ** shared copy of the cache struct, then update several values in
+ ** the local cache using the values for cache->cacheMemMap and
+ ** cache->cacheMem computed just above. So, we copy cache into
+ ** the automatic variable "my", to preserve the variables while
+ ** cache is overwritten.
+ */
+ my = *cache; /* save values computed above. */
+ memcpy(cache, cache->sharedCache, sizeof *cache); /* overwrite */
+
+ /* Fix pointers in our private copy of cache descriptor to point to
+ ** spaces in shared memory, whose address is now in "my".
+ */
+ ptr = (ptrdiff_t)my.cacheMem;
+ *(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
+ *(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
+ *(ptrdiff_t *)(&cache->certCacheLock) += ptr;
+ *(ptrdiff_t *)(&cache->srvNameCacheLock) += ptr;
+ *(ptrdiff_t *)(&cache->sidCacheSets ) += ptr;
+ *(ptrdiff_t *)(&cache->sidCacheData ) += ptr;
+ *(ptrdiff_t *)(&cache->certCacheData) += ptr;
+ *(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
+ *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr;
+ *(ptrdiff_t *)(&cache->ticketEncKey ) += ptr;
+ *(ptrdiff_t *)(&cache->ticketMacKey ) += ptr;
+ *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr;
+ *(ptrdiff_t *)(&cache->srvNameCacheData) += ptr;
+
+ cache->cacheMemMap = my.cacheMemMap;
+ cache->cacheMem = my.cacheMem;
+ cache->sharedCache = (cacheDesc *)cache->cacheMem;
+
+#ifdef WINNT
+ /* On Windows NT we need to "fix" the sidCacheLocks here to support fibers
+ ** When NT fibers are used in a multi-process server, a second level of
+ ** locking is needed to prevent a deadlock, in case a fiber acquires the
+ ** cross-process mutex, yields, and another fiber is later scheduled on
+ ** the same native thread and tries to acquire the cross-process mutex.
+ ** We do this by using a PRLock in the sslMutex. However, it is stored in
+ ** shared memory as part of sidCacheLocks, and we don't want to overwrite
+ ** the PRLock of the parent process. So we need to make new, private
+ ** copies of sidCacheLocks before modifying the sslMutex with our own
+ ** PRLock
+ */
+
+ /* note from jpierre : this should be free'd in child processes when
+ ** a function is added to delete the SSL session cache in the future.
+ */
+ locks_to_initialize = cache->numSIDCacheLocks + 3;
+ newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize);
+ if (!newLocks)
+ goto loser;
+ /* copy the old locks */
+ memcpy(newLocks, cache->sidCacheLocks,
+ locks_to_initialize * sizeof(sidCacheLock));
+ cache->sidCacheLocks = newLocks;
+ /* fix the locks */
+ for (; locks_initialized < locks_to_initialize; ++locks_initialized) {
+ /* now, make a local PRLock in this sslMutex for this child process */
+ SECStatus err;
+ err = sslMutex_2LevelInit(&newLocks[locks_initialized].mutex);
+ if (err != SECSuccess) {
+ cache->numSIDCacheLocksInitialized = locks_initialized;
+ goto loser;
+ }
+ }
+ cache->numSIDCacheLocksInitialized = locks_initialized;
+
+ /* also fix the key and cert cache which use the last 2 lock entries */
+ cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks;
+ cache->certCacheLock = cache->keyCacheLock + 1;
+ cache->srvNameCacheLock = cache->certCacheLock + 1;
+#endif
+
+ PORT_Free(myEnvString);
+ PORT_Free(decoString);
+
+ /* mark that we have inherited this. */
+ cache->sharedCache->everInherited = PR_TRUE;
+ isMultiProcess = PR_TRUE;
+
+ return SECSuccess;
+
+loser:
+ PORT_Free(myEnvString);
+ if (decoString)
+ PORT_Free(decoString);
+ CloseCache(cache);
+ return SECFailure;
+}
+
+SECStatus
+SSL_InheritMPServerSIDCache(const char * envString)
+{
+ return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString);
+}
+
+#if defined(XP_UNIX) || defined(XP_BEOS)
+
+#define SID_LOCK_EXPIRATION_TIMEOUT 30 /* seconds */
+
+static void
+LockPoller(void * arg)
+{
+ cacheDesc * cache = (cacheDesc *)arg;
+ cacheDesc * sharedCache = cache->sharedCache;
+ sidCacheLock * pLock;
+ PRIntervalTime timeout;
+ PRUint32 now;
+ PRUint32 then;
+ int locks_polled = 0;
+ int locks_to_poll = cache->numSIDCacheLocks + 2;
+ PRUint32 expiration = cache->mutexTimeout;
+
+ timeout = PR_SecondsToInterval(expiration);
+ while(!sharedCache->stopPolling) {
+ PR_Sleep(timeout);
+ if (sharedCache->stopPolling)
+ break;
+
+ now = ssl_Time();
+ then = now - expiration;
+ for (pLock = cache->sidCacheLocks, locks_polled = 0;
+ locks_to_poll > locks_polled && !sharedCache->stopPolling;
+ ++locks_polled, ++pLock ) {
+ pid_t pid;
+
+ if (pLock->timeStamp < then &&
+ pLock->timeStamp != 0 &&
+ (pid = pLock->pid) != 0) {
+
+ /* maybe we should try the lock? */
+ int result = kill(pid, 0);
+ if (result < 0 && errno == ESRCH) {
+ SECStatus rv;
+ /* No process exists by that pid any more.
+ ** Treat this mutex as abandoned.
+ */
+ pLock->timeStamp = now;
+ pLock->pid = 0;
+ rv = sslMutex_Unlock(&pLock->mutex);
+ if (rv != SECSuccess) {
+ /* Now what? */
+ }
+ }
+ }
+ } /* end of loop over locks */
+ } /* end of entire polling loop */
+}
+
+/* Launch thread to poll cache for expired locks */
+static SECStatus
+LaunchLockPoller(cacheDesc *cache)
+{
+ const char * timeoutString;
+ PRThread * pollerThread;
+
+ cache->mutexTimeout = SID_LOCK_EXPIRATION_TIMEOUT;
+ timeoutString = getenv("NSS_SSL_SERVER_CACHE_MUTEX_TIMEOUT");
+ if (timeoutString) {
+ long newTime = strtol(timeoutString, 0, 0);
+ if (newTime == 0)
+ return SECSuccess; /* application doesn't want poller thread */
+ if (newTime > 0)
+ cache->mutexTimeout = (PRUint32)newTime;
+ /* if error (newTime < 0) ignore it and use default */
+ }
+
+ pollerThread =
+ PR_CreateThread(PR_USER_THREAD, LockPoller, cache, PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (!pollerThread) {
+ return SECFailure;
+ }
+ cache->poller = pollerThread;
+ return SECSuccess;
+}
+
+/* Stop the thread that polls cache for expired locks */
+static SECStatus
+StopLockPoller(cacheDesc *cache)
+{
+ if (!cache->poller) {
+ return SECSuccess;
+ }
+ cache->sharedCache->stopPolling = PR_TRUE;
+ if (PR_Interrupt(cache->poller) != PR_SUCCESS) {
+ return SECFailure;
+ }
+ if (PR_JoinThread(cache->poller) != PR_SUCCESS) {
+ return SECFailure;
+ }
+ cache->poller = NULL;
+ return SECSuccess;
+}
+#endif
+
+/************************************************************************
+ * Code dealing with shared wrapped symmetric wrapping keys below *
+ ************************************************************************/
+
+/* If now is zero, it implies that the lock is not held, and must be
+** aquired here.
+*/
+static PRBool
+getSvrWrappingKey(PRInt32 symWrapMechIndex,
+ SSL3KEAType exchKeyType,
+ SSLWrappedSymWrappingKey *wswk,
+ cacheDesc * cache,
+ PRUint32 lockTime)
+{
+ PRUint32 ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
+ SSLWrappedSymWrappingKey * pwswk = cache->keyCacheData + ndx;
+ PRUint32 now = 0;
+ PRBool rv = PR_FALSE;
+
+ if (!cache->cacheMem) { /* cache is uninitialized */
+ PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
+ return rv;
+ }
+ if (!lockTime) {
+ lockTime = now = LockSidCacheLock(cache->keyCacheLock, now);
+ if (!lockTime) {
+ return rv;
+ }
+ }
+ if (pwswk->exchKeyType == exchKeyType &&
+ pwswk->symWrapMechIndex == symWrapMechIndex &&
+ pwswk->wrappedSymKeyLen != 0) {
+ *wswk = *pwswk;
+ rv = PR_TRUE;
+ }
+ if (now) {
+ UnlockSidCacheLock(cache->keyCacheLock);
+ }
+ return rv;
+}
+
+PRBool
+ssl_GetWrappingKey( PRInt32 symWrapMechIndex,
+ SSL3KEAType exchKeyType,
+ SSLWrappedSymWrappingKey *wswk)
+{
+ PRBool rv;
+
+ PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
+ PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
+ if ((unsigned)exchKeyType < kt_kea_size &&
+ (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) {
+ rv = getSvrWrappingKey(symWrapMechIndex, exchKeyType, wswk,
+ &globalCache, 0);
+ } else {
+ rv = PR_FALSE;
+ }
+
+ return rv;
+}
+
+/* Wrap and cache a session ticket key. */
+static PRBool
+WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey,
+ const char *keyName, encKeyCacheEntry* cacheEntry)
+{
+ SECItem wrappedKey = {siBuffer, NULL, 0};
+
+ wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey);
+ PORT_Assert(wrappedKey.len <= sizeof(cacheEntry->bytes));
+ if (wrappedKey.len > sizeof(cacheEntry->bytes))
+ return PR_FALSE;
+ wrappedKey.data = cacheEntry->bytes;
+
+ if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, symKey, &wrappedKey)
+ != SECSuccess) {
+ SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket %s.",
+ SSL_GETPID(), "unknown", keyName));
+ return PR_FALSE;
+ }
+ cacheEntry->length = wrappedKey.len;
+ return PR_TRUE;
+}
+
+static PRBool
+GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey,
+ PK11SymKey **macKey)
+{
+ PK11SlotInfo *slot;
+ CK_MECHANISM_TYPE mechanismArray[2];
+ PK11SymKey *aesKeyTmp = NULL;
+ PK11SymKey *macKeyTmp = NULL;
+ cacheDesc *cache = &globalCache;
+ PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN];
+ PRUint8 *ticketKeyNameSuffix;
+
+ if (!cache->cacheMem) {
+ /* cache is not initalized. Use stack buffer */
+ ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
+ } else {
+ ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
+ }
+
+ if (PK11_GenerateRandom(ticketKeyNameSuffix,
+ SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess) {
+ SSL_DBG(("%d: SSL[%s]: Unable to generate random key name bytes.",
+ SSL_GETPID(), "unknown"));
+ goto loser;
+ }
+
+ mechanismArray[0] = CKM_AES_CBC;
+ mechanismArray[1] = CKM_SHA256_HMAC;
+
+ slot = PK11_GetBestSlotMultiple(mechanismArray, 2, pwArg);
+ if (slot) {
+ aesKeyTmp = PK11_KeyGen(slot, mechanismArray[0], NULL,
+ AES_256_KEY_LENGTH, pwArg);
+ macKeyTmp = PK11_KeyGen(slot, mechanismArray[1], NULL,
+ SHA256_LENGTH, pwArg);
+ PK11_FreeSlot(slot);
+ }
+
+ if (aesKeyTmp == NULL || macKeyTmp == NULL) {
+ SSL_DBG(("%d: SSL[%s]: Unable to generate session ticket keys.",
+ SSL_GETPID(), "unknown"));
+ goto loser;
+ }
+ PORT_Memcpy(keyName, ticketKeyNameSuffix, SESS_TICKET_KEY_VAR_NAME_LEN);
+ *aesKey = aesKeyTmp;
+ *macKey = macKeyTmp;
+ return PR_TRUE;
+
+loser:
+ if (aesKeyTmp)
+ PK11_FreeSymKey(aesKeyTmp);
+ if (macKeyTmp)
+ PK11_FreeSymKey(macKeyTmp);
+ return PR_FALSE;
+}
+
+static PRBool
+GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg,
+ unsigned char *keyName, PK11SymKey **aesKey,
+ PK11SymKey **macKey)
+{
+ PK11SymKey *aesKeyTmp = NULL;
+ PK11SymKey *macKeyTmp = NULL;
+ cacheDesc *cache = &globalCache;
+
+ if (!GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp)) {
+ goto loser;
+ }
+
+ if (cache->cacheMem) {
+ /* Export the keys to the shared cache in wrapped form. */
+ if (!WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey))
+ goto loser;
+ if (!WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey))
+ goto loser;
+ }
+ *aesKey = aesKeyTmp;
+ *macKey = macKeyTmp;
+ return PR_TRUE;
+
+loser:
+ if (aesKeyTmp)
+ PK11_FreeSymKey(aesKeyTmp);
+ if (macKeyTmp)
+ PK11_FreeSymKey(macKeyTmp);
+ return PR_FALSE;
+}
+
+static PRBool
+UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName,
+ PK11SymKey **aesKey, PK11SymKey **macKey)
+{
+ SECItem wrappedKey = {siBuffer, NULL, 0};
+ PK11SymKey *aesKeyTmp = NULL;
+ PK11SymKey *macKeyTmp = NULL;
+ cacheDesc *cache = &globalCache;
+
+ wrappedKey.data = cache->ticketEncKey->bytes;
+ wrappedKey.len = cache->ticketEncKey->length;
+ PORT_Assert(wrappedKey.len <= sizeof(cache->ticketEncKey->bytes));
+ aesKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
+ CKM_AES_CBC, CKA_DECRYPT, 0);
+
+ wrappedKey.data = cache->ticketMacKey->bytes;
+ wrappedKey.len = cache->ticketMacKey->length;
+ PORT_Assert(wrappedKey.len <= sizeof(cache->ticketMacKey->bytes));
+ macKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
+ CKM_SHA256_HMAC, CKA_SIGN, 0);
+
+ if (aesKeyTmp == NULL || macKeyTmp == NULL) {
+ SSL_DBG(("%d: SSL[%s]: Unable to unwrap session ticket keys.",
+ SSL_GETPID(), "unknown"));
+ goto loser;
+ }
+ SSL_DBG(("%d: SSL[%s]: Successfully unwrapped session ticket keys.",
+ SSL_GETPID(), "unknown"));
+
+ PORT_Memcpy(keyName, cache->ticketKeyNameSuffix,
+ SESS_TICKET_KEY_VAR_NAME_LEN);
+ *aesKey = aesKeyTmp;
+ *macKey = macKeyTmp;
+ return PR_TRUE;
+
+loser:
+ if (aesKeyTmp)
+ PK11_FreeSymKey(aesKeyTmp);
+ if (macKeyTmp)
+ PK11_FreeSymKey(macKeyTmp);
+ return PR_FALSE;
+}
+
+PRBool
+ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey,
+ SECKEYPublicKey *svrPubKey, void *pwArg,
+ unsigned char *keyName, PK11SymKey **aesKey,
+ PK11SymKey **macKey)
+{
+ PRUint32 now = 0;
+ PRBool rv = PR_FALSE;
+ PRBool keysGenerated = PR_FALSE;
+ cacheDesc *cache = &globalCache;
+
+ if (!cache->cacheMem) {
+ /* cache is uninitialized. Generate keys and return them
+ * without caching. */
+ return GenerateTicketKeys(pwArg, keyName, aesKey, macKey);
+ }
+
+ now = LockSidCacheLock(cache->keyCacheLock, now);
+ if (!now)
+ return rv;
+
+ if (!*(cache->ticketKeysValid)) {
+ /* Keys do not exist, create them. */
+ if (!GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName,
+ aesKey, macKey))
+ goto loser;
+ keysGenerated = PR_TRUE;
+ *(cache->ticketKeysValid) = 1;
+ }
+
+ rv = PR_TRUE;
+
+ loser:
+ UnlockSidCacheLock(cache->keyCacheLock);
+ if (rv && !keysGenerated)
+ rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, aesKey, macKey);
+ return rv;
+}
+
+PRBool
+ssl_GetSessionTicketKeys(unsigned char *keyName, unsigned char *encKey,
+ unsigned char *macKey)
+{
+ PRBool rv = PR_FALSE;
+ PRUint32 now = 0;
+ cacheDesc *cache = &globalCache;
+ PRUint8 ticketMacKey[SHA256_LENGTH], ticketEncKey[AES_256_KEY_LENGTH];
+ PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN];
+ PRUint8 *ticketMacKeyPtr, *ticketEncKeyPtr, *ticketKeyNameSuffix;
+ PRBool cacheIsEnabled = PR_TRUE;
+
+ if (!cache->cacheMem) { /* cache is uninitialized */
+ cacheIsEnabled = PR_FALSE;
+ ticketKeyNameSuffix = ticketKeyNameSuffixLocal;
+ ticketEncKeyPtr = ticketEncKey;
+ ticketMacKeyPtr = ticketMacKey;
+ } else {
+ /* these values have constant memory locations in the cache.
+ * Ok to reference them without holding the lock. */
+ ticketKeyNameSuffix = cache->ticketKeyNameSuffix;
+ ticketEncKeyPtr = cache->ticketEncKey->bytes;
+ ticketMacKeyPtr = cache->ticketMacKey->bytes;
+ }
+
+ if (cacheIsEnabled) {
+ /* Grab lock if initialized. */
+ now = LockSidCacheLock(cache->keyCacheLock, now);
+ if (!now)
+ return rv;
+ }
+ /* Going to regenerate keys on every call if cache was not
+ * initialized. */
+ if (!cacheIsEnabled || !*(cache->ticketKeysValid)) {
+ if (PK11_GenerateRandom(ticketKeyNameSuffix,
+ SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess)
+ goto loser;
+ if (PK11_GenerateRandom(ticketEncKeyPtr,
+ AES_256_KEY_LENGTH) != SECSuccess)
+ goto loser;
+ if (PK11_GenerateRandom(ticketMacKeyPtr,
+ SHA256_LENGTH) != SECSuccess)
+ goto loser;
+ if (cacheIsEnabled) {
+ *(cache->ticketKeysValid) = 1;
+ }
+ }
+
+ rv = PR_TRUE;
+
+ loser:
+ if (cacheIsEnabled) {
+ UnlockSidCacheLock(cache->keyCacheLock);
+ }
+ if (rv) {
+ PORT_Memcpy(keyName, ticketKeyNameSuffix,
+ SESS_TICKET_KEY_VAR_NAME_LEN);
+ PORT_Memcpy(encKey, ticketEncKeyPtr, AES_256_KEY_LENGTH);
+ PORT_Memcpy(macKey, ticketMacKeyPtr, SHA256_LENGTH);
+ }
+ return rv;
+}
+
+/* The caller passes in the new value it wants
+ * to set. This code tests the wrapped sym key entry in the shared memory.
+ * If it is uninitialized, this function writes the caller's value into
+ * the disk entry, and returns false.
+ * Otherwise, it overwrites the caller's wswk with the value obtained from
+ * the disk, and returns PR_TRUE.
+ * This is all done while holding the locks/mutexes necessary to make
+ * the operation atomic.
+ */
+PRBool
+ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
+{
+ cacheDesc * cache = &globalCache;
+ PRBool rv = PR_FALSE;
+ SSL3KEAType exchKeyType = wswk->exchKeyType;
+ /* type of keys used to wrap SymWrapKey*/
+ PRInt32 symWrapMechIndex = wswk->symWrapMechIndex;
+ PRUint32 ndx;
+ PRUint32 now = 0;
+ SSLWrappedSymWrappingKey myWswk;
+
+ if (!cache->cacheMem) { /* cache is uninitialized */
+ PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED);
+ return 0;
+ }
+
+ PORT_Assert( (unsigned)exchKeyType < kt_kea_size);
+ if ((unsigned)exchKeyType >= kt_kea_size)
+ return 0;
+
+ PORT_Assert( (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS);
+ if ((unsigned)symWrapMechIndex >= SSL_NUM_WRAP_MECHS)
+ return 0;
+
+ ndx = (exchKeyType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex;
+ PORT_Memset(&myWswk, 0, sizeof myWswk); /* eliminate UMRs. */
+
+ now = LockSidCacheLock(cache->keyCacheLock, now);
+ if (now) {
+ rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->exchKeyType,
+ &myWswk, cache, now);
+ if (rv) {
+ /* we found it on disk, copy it out to the caller. */
+ PORT_Memcpy(wswk, &myWswk, sizeof *wswk);
+ } else {
+ /* Wasn't on disk, and we're still holding the lock, so write it. */
+ cache->keyCacheData[ndx] = *wswk;
+ }
+ UnlockSidCacheLock(cache->keyCacheLock);
+ }
+ return rv;
+}
+
+#else /* MAC version or other platform */
+
+#include "seccomon.h"
+#include "cert.h"
+#include "ssl.h"
+#include "sslimpl.h"
+
+SECStatus
+SSL_ConfigServerSessionIDCache( int maxCacheEntries,
+ PRUint32 ssl2_timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory)
+{
+ PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigServerSessionIDCache)");
+ return SECFailure;
+}
+
+SECStatus
+SSL_ConfigMPServerSIDCache( int maxCacheEntries,
+ PRUint32 ssl2_timeout,
+ PRUint32 ssl3_timeout,
+ const char * directory)
+{
+ PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_ConfigMPServerSIDCache)");
+ return SECFailure;
+}
+
+SECStatus
+SSL_InheritMPServerSIDCache(const char * envString)
+{
+ PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_InheritMPServerSIDCache)");
+ return SECFailure;
+}
+
+PRBool
+ssl_GetWrappingKey( PRInt32 symWrapMechIndex,
+ SSL3KEAType exchKeyType,
+ SSLWrappedSymWrappingKey *wswk)
+{
+ PRBool rv = PR_FALSE;
+ PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)");
+ return rv;
+}
+
+/* This is a kind of test-and-set. The caller passes in the new value it wants
+ * to set. This code tests the wrapped sym key entry in the shared memory.
+ * If it is uninitialized, this function writes the caller's value into
+ * the disk entry, and returns false.
+ * Otherwise, it overwrites the caller's wswk with the value obtained from
+ * the disk, and returns PR_TRUE.
+ * This is all done while holding the locks/mutexes necessary to make
+ * the operation atomic.
+ */
+PRBool
+ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk)
+{
+ PRBool rv = PR_FALSE;
+ PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)");
+ return rv;
+}
+
+PRUint32
+SSL_GetMaxServerCacheLocks(void)
+{
+ PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_GetMaxServerCacheLocks)");
+ return -1;
+}
+
+SECStatus
+SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
+{
+ PR_ASSERT(!"SSL servers are not supported on this platform. (SSL_SetMaxServerCacheLocks)");
+ return SECFailure;
+}
+
+#endif /* XP_UNIX || XP_WIN32 */
diff --git a/chromium/net/third_party/nss/ssl/sslsock.c b/chromium/net/third_party/nss/ssl/sslsock.c
new file mode 100644
index 00000000000..c17c7a3ad03
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslsock.c
@@ -0,0 +1,3128 @@
+/*
+ * vtables (and methods that call through them) for the 4 types of
+ * SSLSockets supported. Only one type is still supported.
+ * Various other functions.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "seccomon.h"
+#include "cert.h"
+#include "keyhi.h"
+#include "ssl.h"
+#include "sslimpl.h"
+#include "sslproto.h"
+#include "nspr.h"
+#include "private/pprio.h"
+#ifndef NO_PKCS11_BYPASS
+#include "blapi.h"
+#endif
+#include "pk11pub.h"
+#include "nss.h"
+
+/* This is a bodge to allow this code to be compiled against older NSS headers
+ * that don't contain the TLS 1.2 changes. */
+#ifndef CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256
+#define CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 (CKM_NSS + 24)
+#endif
+
+#define SET_ERROR_CODE /* reminder */
+
+struct cipherPolicyStr {
+ int cipher;
+ unsigned char export; /* policy value for export policy */
+ unsigned char france; /* policy value for france policy */
+};
+
+typedef struct cipherPolicyStr cipherPolicy;
+
+/* This table contains two preconfigured policies: Export and France.
+** It is used only by the functions NSS_SetDomesticPolicy,
+** NSS_SetExportPolicy, and NSS_SetFrancePolicy.
+** Order of entries is not important.
+*/
+static cipherPolicy ssl_ciphers[] = { /* Export France */
+ { SSL_EN_RC4_128_WITH_MD5, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { SSL_EN_RC4_128_EXPORT40_WITH_MD5, SSL_ALLOWED, SSL_ALLOWED },
+ { SSL_EN_RC2_128_CBC_WITH_MD5, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, SSL_ALLOWED, SSL_ALLOWED },
+ { SSL_EN_DES_64_CBC_WITH_MD5, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { SSL_EN_DES_192_EDE3_CBC_WITH_MD5, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { SSL_RSA_WITH_RC4_128_MD5, SSL_RESTRICTED, SSL_NOT_ALLOWED },
+ { SSL_RSA_WITH_RC4_128_SHA, SSL_RESTRICTED, SSL_NOT_ALLOWED },
+ { SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RESTRICTED, SSL_NOT_ALLOWED },
+ { SSL_RSA_FIPS_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { SSL_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_ALLOWED, SSL_ALLOWED },
+ { SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL_ALLOWED, SSL_ALLOWED },
+ { SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_DHE_DSS_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { SSL_RSA_WITH_NULL_MD5, SSL_ALLOWED, SSL_ALLOWED },
+ { SSL_RSA_WITH_NULL_SHA, SSL_ALLOWED, SSL_ALLOWED },
+ { TLS_RSA_WITH_NULL_SHA256, SSL_ALLOWED, SSL_ALLOWED },
+ { TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_DHE_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_RSA_WITH_AES_128_CBC_SHA256, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_RSA_WITH_AES_128_GCM_SHA256, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_DHE_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_RSA_WITH_AES_256_CBC_SHA256, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_RSA_WITH_SEED_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, SSL_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, SSL_ALLOWED, SSL_NOT_ALLOWED },
+#ifdef NSS_ENABLE_ECC
+ { TLS_ECDH_ECDSA_WITH_NULL_SHA, SSL_ALLOWED, SSL_ALLOWED },
+ { TLS_ECDH_ECDSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDHE_ECDSA_WITH_NULL_SHA, SSL_ALLOWED, SSL_ALLOWED },
+ { TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDH_RSA_WITH_NULL_SHA, SSL_ALLOWED, SSL_ALLOWED },
+ { TLS_ECDH_RSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDHE_RSA_WITH_NULL_SHA, SSL_ALLOWED, SSL_ALLOWED },
+ { TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+#endif /* NSS_ENABLE_ECC */
+ { 0, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }
+};
+
+static const sslSocketOps ssl_default_ops = { /* No SSL. */
+ ssl_DefConnect,
+ NULL,
+ ssl_DefBind,
+ ssl_DefListen,
+ ssl_DefShutdown,
+ ssl_DefClose,
+ ssl_DefRecv,
+ ssl_DefSend,
+ ssl_DefRead,
+ ssl_DefWrite,
+ ssl_DefGetpeername,
+ ssl_DefGetsockname
+};
+
+static const sslSocketOps ssl_secure_ops = { /* SSL. */
+ ssl_SecureConnect,
+ NULL,
+ ssl_DefBind,
+ ssl_DefListen,
+ ssl_SecureShutdown,
+ ssl_SecureClose,
+ ssl_SecureRecv,
+ ssl_SecureSend,
+ ssl_SecureRead,
+ ssl_SecureWrite,
+ ssl_DefGetpeername,
+ ssl_DefGetsockname
+};
+
+/*
+** default settings for socket enables
+*/
+static sslOptions ssl_defaults = {
+ { siBuffer, NULL, 0 }, /* nextProtoNego */
+ PR_TRUE, /* useSecurity */
+ PR_FALSE, /* useSocks */
+ PR_FALSE, /* requestCertificate */
+ 2, /* requireCertificate */
+ PR_FALSE, /* handshakeAsClient */
+ PR_FALSE, /* handshakeAsServer */
+ PR_FALSE, /* enableSSL2 */ /* now defaults to off in NSS 3.13 */
+ PR_FALSE, /* unusedBit9 */
+ PR_FALSE, /* unusedBit10 */
+ PR_FALSE, /* noCache */
+ PR_FALSE, /* fdx */
+ PR_FALSE, /* v2CompatibleHello */ /* now defaults to off in NSS 3.13 */
+ PR_TRUE, /* detectRollBack */
+ PR_FALSE, /* noStepDown */
+ PR_FALSE, /* bypassPKCS11 */
+ PR_FALSE, /* noLocks */
+ PR_FALSE, /* enableSessionTickets */
+ PR_FALSE, /* enableDeflate */
+ 2, /* enableRenegotiation (default: requires extension) */
+ PR_FALSE, /* requireSafeNegotiation */
+ PR_FALSE, /* enableFalseStart */
+ PR_TRUE, /* cbcRandomIV */
+ PR_FALSE /* enableOCSPStapling */
+};
+
+/*
+ * default range of enabled SSL/TLS protocols
+ */
+static SSLVersionRange versions_defaults_stream = {
+ SSL_LIBRARY_VERSION_3_0,
+ SSL_LIBRARY_VERSION_TLS_1_0
+};
+
+static SSLVersionRange versions_defaults_datagram = {
+ SSL_LIBRARY_VERSION_TLS_1_1,
+ SSL_LIBRARY_VERSION_TLS_1_1
+};
+
+#define VERSIONS_DEFAULTS(variant) \
+ (variant == ssl_variant_stream ? &versions_defaults_stream : \
+ &versions_defaults_datagram)
+
+sslSessionIDLookupFunc ssl_sid_lookup;
+sslSessionIDCacheFunc ssl_sid_cache;
+sslSessionIDUncacheFunc ssl_sid_uncache;
+
+static PRBool ssl_inited = PR_FALSE;
+static PRDescIdentity ssl_layer_id;
+
+PRBool locksEverDisabled; /* implicitly PR_FALSE */
+PRBool ssl_force_locks; /* implicitly PR_FALSE */
+int ssl_lock_readers = 1; /* default true. */
+char ssl_debug;
+char ssl_trace;
+FILE * ssl_trace_iob;
+FILE * ssl_keylog_iob;
+char lockStatus[] = "Locks are ENABLED. ";
+#define LOCKSTATUS_OFFSET 10 /* offset of ENABLED */
+
+/* SRTP_NULL_HMAC_SHA1_80 and SRTP_NULL_HMAC_SHA1_32 are not implemented. */
+static const PRUint16 srtpCiphers[] = {
+ SRTP_AES128_CM_HMAC_SHA1_80,
+ SRTP_AES128_CM_HMAC_SHA1_32,
+ 0
+};
+
+/* forward declarations. */
+static sslSocket *ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant variant);
+static SECStatus ssl_MakeLocks(sslSocket *ss);
+static void ssl_SetDefaultsFromEnvironment(void);
+static PRStatus ssl_PushIOLayer(sslSocket *ns, PRFileDesc *stack,
+ PRDescIdentity id);
+
+/************************************************************************/
+
+/*
+** Lookup a socket structure from a file descriptor.
+** Only functions called through the PRIOMethods table should use this.
+** Other app-callable functions should use ssl_FindSocket.
+*/
+static sslSocket *
+ssl_GetPrivate(PRFileDesc *fd)
+{
+ sslSocket *ss;
+
+ PORT_Assert(fd != NULL);
+ PORT_Assert(fd->methods->file_type == PR_DESC_LAYERED);
+ PORT_Assert(fd->identity == ssl_layer_id);
+
+ if (fd->methods->file_type != PR_DESC_LAYERED ||
+ fd->identity != ssl_layer_id) {
+ PORT_SetError(PR_BAD_DESCRIPTOR_ERROR);
+ return NULL;
+ }
+
+ ss = (sslSocket *)fd->secret;
+ ss->fd = fd;
+ return ss;
+}
+
+/* This function tries to find the SSL layer in the stack.
+ * It searches for the first SSL layer at or below the argument fd,
+ * and failing that, it searches for the nearest SSL layer above the
+ * argument fd. It returns the private sslSocket from the found layer.
+ */
+sslSocket *
+ssl_FindSocket(PRFileDesc *fd)
+{
+ PRFileDesc *layer;
+ sslSocket *ss;
+
+ PORT_Assert(fd != NULL);
+ PORT_Assert(ssl_layer_id != 0);
+
+ layer = PR_GetIdentitiesLayer(fd, ssl_layer_id);
+ if (layer == NULL) {
+ PORT_SetError(PR_BAD_DESCRIPTOR_ERROR);
+ return NULL;
+ }
+
+ ss = (sslSocket *)layer->secret;
+ ss->fd = layer;
+ return ss;
+}
+
+static sslSocket *
+ssl_DupSocket(sslSocket *os)
+{
+ sslSocket *ss;
+ SECStatus rv;
+
+ ss = ssl_NewSocket((PRBool)(!os->opt.noLocks), os->protocolVariant);
+ if (ss) {
+ ss->opt = os->opt;
+ ss->opt.useSocks = PR_FALSE;
+ ss->vrange = os->vrange;
+
+ ss->peerID = !os->peerID ? NULL : PORT_Strdup(os->peerID);
+ ss->url = !os->url ? NULL : PORT_Strdup(os->url);
+
+ ss->ops = os->ops;
+ ss->rTimeout = os->rTimeout;
+ ss->wTimeout = os->wTimeout;
+ ss->cTimeout = os->cTimeout;
+ ss->dbHandle = os->dbHandle;
+
+ /* copy ssl2&3 policy & prefs, even if it's not selected (yet) */
+ ss->allowedByPolicy = os->allowedByPolicy;
+ ss->maybeAllowedByPolicy= os->maybeAllowedByPolicy;
+ ss->chosenPreference = os->chosenPreference;
+ PORT_Memcpy(ss->cipherSuites, os->cipherSuites, sizeof os->cipherSuites);
+ PORT_Memcpy(ss->ssl3.dtlsSRTPCiphers, os->ssl3.dtlsSRTPCiphers,
+ sizeof(PRUint16) * os->ssl3.dtlsSRTPCipherCount);
+ ss->ssl3.dtlsSRTPCipherCount = os->ssl3.dtlsSRTPCipherCount;
+
+ if (os->cipherSpecs) {
+ ss->cipherSpecs = (unsigned char*)PORT_Alloc(os->sizeCipherSpecs);
+ if (ss->cipherSpecs)
+ PORT_Memcpy(ss->cipherSpecs, os->cipherSpecs,
+ os->sizeCipherSpecs);
+ ss->sizeCipherSpecs = os->sizeCipherSpecs;
+ ss->preferredCipher = os->preferredCipher;
+ } else {
+ ss->cipherSpecs = NULL; /* produced lazily */
+ ss->sizeCipherSpecs = 0;
+ ss->preferredCipher = NULL;
+ }
+ if (ss->opt.useSecurity) {
+ /* This int should be SSLKEAType, but CC on Irix complains,
+ * during the for loop.
+ */
+ int i;
+ sslServerCerts * oc = os->serverCerts;
+ sslServerCerts * sc = ss->serverCerts;
+
+ for (i=kt_null; i < kt_kea_size; i++, oc++, sc++) {
+ if (oc->serverCert && oc->serverCertChain) {
+ sc->serverCert = CERT_DupCertificate(oc->serverCert);
+ sc->serverCertChain = CERT_DupCertList(oc->serverCertChain);
+ if (!sc->serverCertChain)
+ goto loser;
+ } else {
+ sc->serverCert = NULL;
+ sc->serverCertChain = NULL;
+ }
+ sc->serverKeyPair = oc->serverKeyPair ?
+ ssl3_GetKeyPairRef(oc->serverKeyPair) : NULL;
+ if (oc->serverKeyPair && !sc->serverKeyPair)
+ goto loser;
+ sc->serverKeyBits = oc->serverKeyBits;
+ ss->certStatusArray[i] = !os->certStatusArray[i] ? NULL :
+ SECITEM_DupArray(NULL, os->certStatusArray[i]);
+ }
+ ss->stepDownKeyPair = !os->stepDownKeyPair ? NULL :
+ ssl3_GetKeyPairRef(os->stepDownKeyPair);
+ ss->ephemeralECDHKeyPair = !os->ephemeralECDHKeyPair ? NULL :
+ ssl3_GetKeyPairRef(os->ephemeralECDHKeyPair);
+/*
+ * XXX the preceding CERT_ and SECKEY_ functions can fail and return NULL.
+ * XXX We should detect this, and not just march on with NULL pointers.
+ */
+ ss->authCertificate = os->authCertificate;
+ ss->authCertificateArg = os->authCertificateArg;
+ ss->getClientAuthData = os->getClientAuthData;
+ ss->getClientAuthDataArg = os->getClientAuthDataArg;
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ ss->getPlatformClientAuthData = os->getPlatformClientAuthData;
+ ss->getPlatformClientAuthDataArg = os->getPlatformClientAuthDataArg;
+#endif
+ ss->sniSocketConfig = os->sniSocketConfig;
+ ss->sniSocketConfigArg = os->sniSocketConfigArg;
+ ss->handleBadCert = os->handleBadCert;
+ ss->badCertArg = os->badCertArg;
+ ss->handshakeCallback = os->handshakeCallback;
+ ss->handshakeCallbackData = os->handshakeCallbackData;
+ ss->pkcs11PinArg = os->pkcs11PinArg;
+ ss->getChannelID = os->getChannelID;
+ ss->getChannelIDArg = os->getChannelIDArg;
+
+ /* Create security data */
+ rv = ssl_CopySecurityInfo(ss, os);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+ }
+ return ss;
+
+loser:
+ ssl_FreeSocket(ss);
+ return NULL;
+}
+
+static void
+ssl_DestroyLocks(sslSocket *ss)
+{
+ /* Destroy locks. */
+ if (ss->firstHandshakeLock) {
+ PZ_DestroyMonitor(ss->firstHandshakeLock);
+ ss->firstHandshakeLock = NULL;
+ }
+ if (ss->ssl3HandshakeLock) {
+ PZ_DestroyMonitor(ss->ssl3HandshakeLock);
+ ss->ssl3HandshakeLock = NULL;
+ }
+ if (ss->specLock) {
+ NSSRWLock_Destroy(ss->specLock);
+ ss->specLock = NULL;
+ }
+
+ if (ss->recvLock) {
+ PZ_DestroyLock(ss->recvLock);
+ ss->recvLock = NULL;
+ }
+ if (ss->sendLock) {
+ PZ_DestroyLock(ss->sendLock);
+ ss->sendLock = NULL;
+ }
+ if (ss->xmitBufLock) {
+ PZ_DestroyMonitor(ss->xmitBufLock);
+ ss->xmitBufLock = NULL;
+ }
+ if (ss->recvBufLock) {
+ PZ_DestroyMonitor(ss->recvBufLock);
+ ss->recvBufLock = NULL;
+ }
+}
+
+/* Caller holds any relevant locks */
+static void
+ssl_DestroySocketContents(sslSocket *ss)
+{
+ /* "i" should be of type SSLKEAType, but CC on IRIX complains during
+ * the for loop.
+ */
+ int i;
+
+ /* Free up socket */
+ ssl_DestroySecurityInfo(&ss->sec);
+
+ ssl3_DestroySSL3Info(ss);
+
+ PORT_Free(ss->saveBuf.buf);
+ PORT_Free(ss->pendingBuf.buf);
+ ssl_DestroyGather(&ss->gs);
+
+ if (ss->peerID != NULL)
+ PORT_Free(ss->peerID);
+ if (ss->url != NULL)
+ PORT_Free((void *)ss->url); /* CONST */
+ if (ss->cipherSpecs) {
+ PORT_Free(ss->cipherSpecs);
+ ss->cipherSpecs = NULL;
+ ss->sizeCipherSpecs = 0;
+ }
+
+ /* Clean up server configuration */
+ for (i=kt_null; i < kt_kea_size; i++) {
+ sslServerCerts * sc = ss->serverCerts + i;
+ if (sc->serverCert != NULL)
+ CERT_DestroyCertificate(sc->serverCert);
+ if (sc->serverCertChain != NULL)
+ CERT_DestroyCertificateList(sc->serverCertChain);
+ if (sc->serverKeyPair != NULL)
+ ssl3_FreeKeyPair(sc->serverKeyPair);
+ if (ss->certStatusArray[i] != NULL) {
+ SECITEM_FreeArray(ss->certStatusArray[i], PR_TRUE);
+ ss->certStatusArray[i] = NULL;
+ }
+ }
+ if (ss->stepDownKeyPair) {
+ ssl3_FreeKeyPair(ss->stepDownKeyPair);
+ ss->stepDownKeyPair = NULL;
+ }
+ if (ss->ephemeralECDHKeyPair) {
+ ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair);
+ ss->ephemeralECDHKeyPair = NULL;
+ }
+ SECITEM_FreeItem(&ss->opt.nextProtoNego, PR_FALSE);
+ PORT_Assert(!ss->xtnData.sniNameArr);
+ if (ss->xtnData.sniNameArr) {
+ PORT_Free(ss->xtnData.sniNameArr);
+ ss->xtnData.sniNameArr = NULL;
+ }
+}
+
+/*
+ * free an sslSocket struct, and all the stuff that hangs off of it
+ */
+void
+ssl_FreeSocket(sslSocket *ss)
+{
+/* Get every lock you can imagine!
+** Caller already holds these:
+** SSL_LOCK_READER(ss);
+** SSL_LOCK_WRITER(ss);
+*/
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetRecvBufLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+ ssl_GetXmitBufLock(ss);
+ ssl_GetSpecWriteLock(ss);
+
+ ssl_DestroySocketContents(ss);
+
+ /* Release all the locks acquired above. */
+ SSL_UNLOCK_READER(ss);
+ SSL_UNLOCK_WRITER(ss);
+ ssl_Release1stHandshakeLock(ss);
+ ssl_ReleaseRecvBufLock(ss);
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_ReleaseXmitBufLock(ss);
+ ssl_ReleaseSpecWriteLock(ss);
+
+ ssl_DestroyLocks(ss);
+
+#ifdef DEBUG
+ PORT_Memset(ss, 0x1f, sizeof *ss);
+#endif
+ PORT_Free(ss);
+ return;
+}
+
+/************************************************************************/
+SECStatus
+ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled)
+{
+ PRFileDesc * osfd = ss->fd->lower;
+ SECStatus rv = SECFailure;
+ PRSocketOptionData opt;
+
+ opt.option = PR_SockOpt_NoDelay;
+ opt.value.no_delay = (PRBool)!enabled;
+
+ if (osfd->methods->setsocketoption) {
+ rv = (SECStatus) osfd->methods->setsocketoption(osfd, &opt);
+ } else {
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ }
+
+ return rv;
+}
+
+static void
+ssl_ChooseOps(sslSocket *ss)
+{
+ ss->ops = ss->opt.useSecurity ? &ssl_secure_ops : &ssl_default_ops;
+}
+
+/* Called from SSL_Enable (immediately below) */
+static SECStatus
+PrepareSocket(sslSocket *ss)
+{
+ SECStatus rv = SECSuccess;
+
+ ssl_ChooseOps(ss);
+ return rv;
+}
+
+SECStatus
+SSL_Enable(PRFileDesc *fd, int which, PRBool on)
+{
+ return SSL_OptionSet(fd, which, on);
+}
+
+#ifndef NO_PKCS11_BYPASS
+static const PRCallOnceType pristineCallOnce;
+static PRCallOnceType setupBypassOnce;
+
+static SECStatus SSL_BypassShutdown(void* appData, void* nssData)
+{
+ /* unload freeBL shared library from memory */
+ BL_Unload();
+ setupBypassOnce = pristineCallOnce;
+ return SECSuccess;
+}
+
+static PRStatus SSL_BypassRegisterShutdown(void)
+{
+ SECStatus rv = NSS_RegisterShutdown(SSL_BypassShutdown, NULL);
+ PORT_Assert(SECSuccess == rv);
+ return SECSuccess == rv ? PR_SUCCESS : PR_FAILURE;
+}
+#endif
+
+static PRStatus SSL_BypassSetup(void)
+{
+#ifdef NO_PKCS11_BYPASS
+ /* Guarantee binary compatibility */
+ return PR_SUCCESS;
+#else
+ return PR_CallOnce(&setupBypassOnce, &SSL_BypassRegisterShutdown);
+#endif
+}
+
+/* Implements the semantics for SSL_OptionSet(SSL_ENABLE_TLS, on) described in
+ * ssl.h in the section "SSL version range setting API".
+ */
+static void
+ssl_EnableTLS(SSLVersionRange *vrange, PRBool on)
+{
+ if (SSL3_ALL_VERSIONS_DISABLED(vrange)) {
+ if (on) {
+ vrange->min = SSL_LIBRARY_VERSION_TLS_1_0;
+ vrange->max = SSL_LIBRARY_VERSION_TLS_1_0;
+ } /* else don't change anything */
+ return;
+ }
+
+ if (on) {
+ /* Expand the range of enabled version to include TLS 1.0 */
+ vrange->min = PR_MIN(vrange->min, SSL_LIBRARY_VERSION_TLS_1_0);
+ vrange->max = PR_MAX(vrange->max, SSL_LIBRARY_VERSION_TLS_1_0);
+ } else {
+ /* Disable all TLS versions, leaving only SSL 3.0 if it was enabled */
+ if (vrange->min == SSL_LIBRARY_VERSION_3_0) {
+ vrange->max = SSL_LIBRARY_VERSION_3_0;
+ } else {
+ /* Only TLS was enabled, so now no versions are. */
+ vrange->min = SSL_LIBRARY_VERSION_NONE;
+ vrange->max = SSL_LIBRARY_VERSION_NONE;
+ }
+ }
+}
+
+/* Implements the semantics for SSL_OptionSet(SSL_ENABLE_SSL3, on) described in
+ * ssl.h in the section "SSL version range setting API".
+ */
+static void
+ssl_EnableSSL3(SSLVersionRange *vrange, PRBool on)
+{
+ if (SSL3_ALL_VERSIONS_DISABLED(vrange)) {
+ if (on) {
+ vrange->min = SSL_LIBRARY_VERSION_3_0;
+ vrange->max = SSL_LIBRARY_VERSION_3_0;
+ } /* else don't change anything */
+ return;
+ }
+
+ if (on) {
+ /* Expand the range of enabled versions to include SSL 3.0. We know
+ * SSL 3.0 or some version of TLS is already enabled at this point, so
+ * we don't need to change vrange->max.
+ */
+ vrange->min = SSL_LIBRARY_VERSION_3_0;
+ } else {
+ /* Disable SSL 3.0, leaving TLS unaffected. */
+ if (vrange->max > SSL_LIBRARY_VERSION_3_0) {
+ vrange->min = PR_MAX(vrange->min, SSL_LIBRARY_VERSION_TLS_1_0);
+ } else {
+ /* Only SSL 3.0 was enabled, so now no versions are. */
+ vrange->min = SSL_LIBRARY_VERSION_NONE;
+ vrange->max = SSL_LIBRARY_VERSION_NONE;
+ }
+ }
+}
+
+SECStatus
+SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+ SECStatus rv = SECSuccess;
+ PRBool holdingLocks;
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in Enable", SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ holdingLocks = (!ss->opt.noLocks);
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ switch (which) {
+ case SSL_SOCKS:
+ ss->opt.useSocks = PR_FALSE;
+ rv = PrepareSocket(ss);
+ if (on) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ }
+ break;
+
+ case SSL_SECURITY:
+ ss->opt.useSecurity = on;
+ rv = PrepareSocket(ss);
+ break;
+
+ case SSL_REQUEST_CERTIFICATE:
+ ss->opt.requestCertificate = on;
+ break;
+
+ case SSL_REQUIRE_CERTIFICATE:
+ ss->opt.requireCertificate = on;
+ break;
+
+ case SSL_HANDSHAKE_AS_CLIENT:
+ if ( ss->opt.handshakeAsServer && on ) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ break;
+ }
+ ss->opt.handshakeAsClient = on;
+ break;
+
+ case SSL_HANDSHAKE_AS_SERVER:
+ if ( ss->opt.handshakeAsClient && on ) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ break;
+ }
+ ss->opt.handshakeAsServer = on;
+ break;
+
+ case SSL_ENABLE_TLS:
+ if (IS_DTLS(ss)) {
+ if (on) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure; /* not allowed */
+ }
+ break;
+ }
+ ssl_EnableTLS(&ss->vrange, on);
+ ss->preferredCipher = NULL;
+ if (ss->cipherSpecs) {
+ PORT_Free(ss->cipherSpecs);
+ ss->cipherSpecs = NULL;
+ ss->sizeCipherSpecs = 0;
+ }
+ break;
+
+ case SSL_ENABLE_SSL3:
+ if (IS_DTLS(ss)) {
+ if (on) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure; /* not allowed */
+ }
+ break;
+ }
+ ssl_EnableSSL3(&ss->vrange, on);
+ ss->preferredCipher = NULL;
+ if (ss->cipherSpecs) {
+ PORT_Free(ss->cipherSpecs);
+ ss->cipherSpecs = NULL;
+ ss->sizeCipherSpecs = 0;
+ }
+ break;
+
+ case SSL_ENABLE_SSL2:
+ if (IS_DTLS(ss)) {
+ if (on) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure; /* not allowed */
+ }
+ break;
+ }
+ ss->opt.enableSSL2 = on;
+ if (on) {
+ ss->opt.v2CompatibleHello = on;
+ }
+ ss->preferredCipher = NULL;
+ if (ss->cipherSpecs) {
+ PORT_Free(ss->cipherSpecs);
+ ss->cipherSpecs = NULL;
+ ss->sizeCipherSpecs = 0;
+ }
+ break;
+
+ case SSL_NO_CACHE:
+ ss->opt.noCache = on;
+ break;
+
+ case SSL_ENABLE_FDX:
+ if (on && ss->opt.noLocks) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ }
+ ss->opt.fdx = on;
+ break;
+
+ case SSL_V2_COMPATIBLE_HELLO:
+ if (IS_DTLS(ss)) {
+ if (on) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure; /* not allowed */
+ }
+ break;
+ }
+ ss->opt.v2CompatibleHello = on;
+ if (!on) {
+ ss->opt.enableSSL2 = on;
+ }
+ break;
+
+ case SSL_ROLLBACK_DETECTION:
+ ss->opt.detectRollBack = on;
+ break;
+
+ case SSL_NO_STEP_DOWN:
+ ss->opt.noStepDown = on;
+ if (on)
+ SSL_DisableExportCipherSuites(fd);
+ break;
+
+ case SSL_BYPASS_PKCS11:
+ if (ss->handshakeBegun) {
+ PORT_SetError(PR_INVALID_STATE_ERROR);
+ rv = SECFailure;
+ } else {
+ if (PR_FALSE != on) {
+ if (PR_SUCCESS == SSL_BypassSetup() ) {
+#ifdef NO_PKCS11_BYPASS
+ ss->opt.bypassPKCS11 = PR_FALSE;
+#else
+ ss->opt.bypassPKCS11 = on;
+#endif
+ } else {
+ rv = SECFailure;
+ }
+ } else {
+ ss->opt.bypassPKCS11 = PR_FALSE;
+ }
+ }
+ break;
+
+ case SSL_NO_LOCKS:
+ if (on && ss->opt.fdx) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ }
+ if (on && ssl_force_locks)
+ on = PR_FALSE; /* silent override */
+ ss->opt.noLocks = on;
+ if (on) {
+ locksEverDisabled = PR_TRUE;
+ strcpy(lockStatus + LOCKSTATUS_OFFSET, "DISABLED.");
+ } else if (!holdingLocks) {
+ rv = ssl_MakeLocks(ss);
+ if (rv != SECSuccess) {
+ ss->opt.noLocks = PR_TRUE;
+ }
+ }
+ break;
+
+ case SSL_ENABLE_SESSION_TICKETS:
+ ss->opt.enableSessionTickets = on;
+ break;
+
+ case SSL_ENABLE_DEFLATE:
+ ss->opt.enableDeflate = on;
+ break;
+
+ case SSL_ENABLE_RENEGOTIATION:
+ ss->opt.enableRenegotiation = on;
+ break;
+
+ case SSL_REQUIRE_SAFE_NEGOTIATION:
+ ss->opt.requireSafeNegotiation = on;
+ break;
+
+ case SSL_ENABLE_FALSE_START:
+ ss->opt.enableFalseStart = on;
+ break;
+
+ case SSL_CBC_RANDOM_IV:
+ ss->opt.cbcRandomIV = on;
+ break;
+
+ case SSL_ENABLE_OCSP_STAPLING:
+ ss->opt.enableOCSPStapling = on;
+ break;
+
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ }
+
+ /* We can't use the macros for releasing the locks here,
+ * because ss->opt.noLocks might have changed just above.
+ * We must release these locks (monitors) here, if we aquired them above,
+ * regardless of the current value of ss->opt.noLocks.
+ */
+ if (holdingLocks) {
+ PZ_ExitMonitor((ss)->ssl3HandshakeLock);
+ PZ_ExitMonitor((ss)->firstHandshakeLock);
+ }
+
+ return rv;
+}
+
+SECStatus
+SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+ SECStatus rv = SECSuccess;
+ PRBool on = PR_FALSE;
+
+ if (!pOn) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in Enable", SSL_GETPID(), fd));
+ *pOn = PR_FALSE;
+ return SECFailure;
+ }
+
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ switch (which) {
+ case SSL_SOCKS: on = PR_FALSE; break;
+ case SSL_SECURITY: on = ss->opt.useSecurity; break;
+ case SSL_REQUEST_CERTIFICATE: on = ss->opt.requestCertificate; break;
+ case SSL_REQUIRE_CERTIFICATE: on = ss->opt.requireCertificate; break;
+ case SSL_HANDSHAKE_AS_CLIENT: on = ss->opt.handshakeAsClient; break;
+ case SSL_HANDSHAKE_AS_SERVER: on = ss->opt.handshakeAsServer; break;
+ case SSL_ENABLE_TLS:
+ on = ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_0;
+ break;
+ case SSL_ENABLE_SSL3:
+ on = ss->vrange.min == SSL_LIBRARY_VERSION_3_0;
+ break;
+ case SSL_ENABLE_SSL2: on = ss->opt.enableSSL2; break;
+ case SSL_NO_CACHE: on = ss->opt.noCache; break;
+ case SSL_ENABLE_FDX: on = ss->opt.fdx; break;
+ case SSL_V2_COMPATIBLE_HELLO: on = ss->opt.v2CompatibleHello; break;
+ case SSL_ROLLBACK_DETECTION: on = ss->opt.detectRollBack; break;
+ case SSL_NO_STEP_DOWN: on = ss->opt.noStepDown; break;
+ case SSL_BYPASS_PKCS11: on = ss->opt.bypassPKCS11; break;
+ case SSL_NO_LOCKS: on = ss->opt.noLocks; break;
+ case SSL_ENABLE_SESSION_TICKETS:
+ on = ss->opt.enableSessionTickets;
+ break;
+ case SSL_ENABLE_DEFLATE: on = ss->opt.enableDeflate; break;
+ case SSL_ENABLE_RENEGOTIATION:
+ on = ss->opt.enableRenegotiation; break;
+ case SSL_REQUIRE_SAFE_NEGOTIATION:
+ on = ss->opt.requireSafeNegotiation; break;
+ case SSL_ENABLE_FALSE_START: on = ss->opt.enableFalseStart; break;
+ case SSL_CBC_RANDOM_IV: on = ss->opt.cbcRandomIV; break;
+ case SSL_ENABLE_OCSP_STAPLING: on = ss->opt.enableOCSPStapling; break;
+
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ }
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ *pOn = on;
+ return rv;
+}
+
+SECStatus
+SSL_OptionGetDefault(PRInt32 which, PRBool *pOn)
+{
+ SECStatus rv = SECSuccess;
+ PRBool on = PR_FALSE;
+
+ if (!pOn) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ ssl_SetDefaultsFromEnvironment();
+
+ switch (which) {
+ case SSL_SOCKS: on = PR_FALSE; break;
+ case SSL_SECURITY: on = ssl_defaults.useSecurity; break;
+ case SSL_REQUEST_CERTIFICATE: on = ssl_defaults.requestCertificate; break;
+ case SSL_REQUIRE_CERTIFICATE: on = ssl_defaults.requireCertificate; break;
+ case SSL_HANDSHAKE_AS_CLIENT: on = ssl_defaults.handshakeAsClient; break;
+ case SSL_HANDSHAKE_AS_SERVER: on = ssl_defaults.handshakeAsServer; break;
+ case SSL_ENABLE_TLS:
+ on = versions_defaults_stream.max >= SSL_LIBRARY_VERSION_TLS_1_0;
+ break;
+ case SSL_ENABLE_SSL3:
+ on = versions_defaults_stream.min == SSL_LIBRARY_VERSION_3_0;
+ break;
+ case SSL_ENABLE_SSL2: on = ssl_defaults.enableSSL2; break;
+ case SSL_NO_CACHE: on = ssl_defaults.noCache; break;
+ case SSL_ENABLE_FDX: on = ssl_defaults.fdx; break;
+ case SSL_V2_COMPATIBLE_HELLO: on = ssl_defaults.v2CompatibleHello; break;
+ case SSL_ROLLBACK_DETECTION: on = ssl_defaults.detectRollBack; break;
+ case SSL_NO_STEP_DOWN: on = ssl_defaults.noStepDown; break;
+ case SSL_BYPASS_PKCS11: on = ssl_defaults.bypassPKCS11; break;
+ case SSL_NO_LOCKS: on = ssl_defaults.noLocks; break;
+ case SSL_ENABLE_SESSION_TICKETS:
+ on = ssl_defaults.enableSessionTickets;
+ break;
+ case SSL_ENABLE_DEFLATE: on = ssl_defaults.enableDeflate; break;
+ case SSL_ENABLE_RENEGOTIATION:
+ on = ssl_defaults.enableRenegotiation; break;
+ case SSL_REQUIRE_SAFE_NEGOTIATION:
+ on = ssl_defaults.requireSafeNegotiation;
+ break;
+ case SSL_ENABLE_FALSE_START: on = ssl_defaults.enableFalseStart; break;
+ case SSL_CBC_RANDOM_IV: on = ssl_defaults.cbcRandomIV; break;
+ case SSL_ENABLE_OCSP_STAPLING:
+ on = ssl_defaults.enableOCSPStapling;
+ break;
+
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ }
+
+ *pOn = on;
+ return rv;
+}
+
+/* XXX Use Global Lock to protect this stuff. */
+SECStatus
+SSL_EnableDefault(int which, PRBool on)
+{
+ return SSL_OptionSetDefault(which, on);
+}
+
+SECStatus
+SSL_OptionSetDefault(PRInt32 which, PRBool on)
+{
+ SECStatus status = ssl_Init();
+
+ if (status != SECSuccess) {
+ return status;
+ }
+
+ ssl_SetDefaultsFromEnvironment();
+
+ switch (which) {
+ case SSL_SOCKS:
+ ssl_defaults.useSocks = PR_FALSE;
+ if (on) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ break;
+
+ case SSL_SECURITY:
+ ssl_defaults.useSecurity = on;
+ break;
+
+ case SSL_REQUEST_CERTIFICATE:
+ ssl_defaults.requestCertificate = on;
+ break;
+
+ case SSL_REQUIRE_CERTIFICATE:
+ ssl_defaults.requireCertificate = on;
+ break;
+
+ case SSL_HANDSHAKE_AS_CLIENT:
+ if ( ssl_defaults.handshakeAsServer && on ) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ ssl_defaults.handshakeAsClient = on;
+ break;
+
+ case SSL_HANDSHAKE_AS_SERVER:
+ if ( ssl_defaults.handshakeAsClient && on ) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ ssl_defaults.handshakeAsServer = on;
+ break;
+
+ case SSL_ENABLE_TLS:
+ ssl_EnableTLS(&versions_defaults_stream, on);
+ break;
+
+ case SSL_ENABLE_SSL3:
+ ssl_EnableSSL3(&versions_defaults_stream, on);
+ break;
+
+ case SSL_ENABLE_SSL2:
+ ssl_defaults.enableSSL2 = on;
+ if (on) {
+ ssl_defaults.v2CompatibleHello = on;
+ }
+ break;
+
+ case SSL_NO_CACHE:
+ ssl_defaults.noCache = on;
+ break;
+
+ case SSL_ENABLE_FDX:
+ if (on && ssl_defaults.noLocks) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ ssl_defaults.fdx = on;
+ break;
+
+ case SSL_V2_COMPATIBLE_HELLO:
+ ssl_defaults.v2CompatibleHello = on;
+ if (!on) {
+ ssl_defaults.enableSSL2 = on;
+ }
+ break;
+
+ case SSL_ROLLBACK_DETECTION:
+ ssl_defaults.detectRollBack = on;
+ break;
+
+ case SSL_NO_STEP_DOWN:
+ ssl_defaults.noStepDown = on;
+ if (on)
+ SSL_DisableDefaultExportCipherSuites();
+ break;
+
+ case SSL_BYPASS_PKCS11:
+ if (PR_FALSE != on) {
+ if (PR_SUCCESS == SSL_BypassSetup()) {
+#ifdef NO_PKCS11_BYPASS
+ ssl_defaults.bypassPKCS11 = PR_FALSE;
+#else
+ ssl_defaults.bypassPKCS11 = on;
+#endif
+ } else {
+ return SECFailure;
+ }
+ } else {
+ ssl_defaults.bypassPKCS11 = PR_FALSE;
+ }
+ break;
+
+ case SSL_NO_LOCKS:
+ if (on && ssl_defaults.fdx) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (on && ssl_force_locks)
+ on = PR_FALSE; /* silent override */
+ ssl_defaults.noLocks = on;
+ if (on) {
+ locksEverDisabled = PR_TRUE;
+ strcpy(lockStatus + LOCKSTATUS_OFFSET, "DISABLED.");
+ }
+ break;
+
+ case SSL_ENABLE_SESSION_TICKETS:
+ ssl_defaults.enableSessionTickets = on;
+ break;
+
+ case SSL_ENABLE_DEFLATE:
+ ssl_defaults.enableDeflate = on;
+ break;
+
+ case SSL_ENABLE_RENEGOTIATION:
+ ssl_defaults.enableRenegotiation = on;
+ break;
+
+ case SSL_REQUIRE_SAFE_NEGOTIATION:
+ ssl_defaults.requireSafeNegotiation = on;
+ break;
+
+ case SSL_ENABLE_FALSE_START:
+ ssl_defaults.enableFalseStart = on;
+ break;
+
+ case SSL_CBC_RANDOM_IV:
+ ssl_defaults.cbcRandomIV = on;
+ break;
+
+ case SSL_ENABLE_OCSP_STAPLING:
+ ssl_defaults.enableOCSPStapling = on;
+ break;
+
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+/* function tells us if the cipher suite is one that we no longer support. */
+static PRBool
+ssl_IsRemovedCipherSuite(PRInt32 suite)
+{
+ switch (suite) {
+ case SSL_FORTEZZA_DMS_WITH_NULL_SHA:
+ case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA:
+ case SSL_FORTEZZA_DMS_WITH_RC4_128_SHA:
+ return PR_TRUE;
+ default:
+ return PR_FALSE;
+ }
+}
+
+/* Part of the public NSS API.
+ * Since this is a global (not per-socket) setting, we cannot use the
+ * HandshakeLock to protect this. Probably want a global lock.
+ */
+SECStatus
+SSL_SetPolicy(long which, int policy)
+{
+ if ((which & 0xfffe) == SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA) {
+ /* one of the two old FIPS ciphers */
+ if (which == SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA)
+ which = SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA;
+ else if (which == SSL_RSA_OLDFIPS_WITH_DES_CBC_SHA)
+ which = SSL_RSA_FIPS_WITH_DES_CBC_SHA;
+ }
+ if (ssl_IsRemovedCipherSuite(which))
+ return SECSuccess;
+ return SSL_CipherPolicySet(which, policy);
+}
+
+SECStatus
+SSL_CipherPolicySet(PRInt32 which, PRInt32 policy)
+{
+ SECStatus rv = ssl_Init();
+
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ if (ssl_IsRemovedCipherSuite(which)) {
+ rv = SECSuccess;
+ } else if (SSL_IS_SSL2_CIPHER(which)) {
+ rv = ssl2_SetPolicy(which, policy);
+ } else {
+ rv = ssl3_SetPolicy((ssl3CipherSuite)which, policy);
+ }
+ return rv;
+}
+
+SECStatus
+SSL_CipherPolicyGet(PRInt32 which, PRInt32 *oPolicy)
+{
+ SECStatus rv;
+
+ if (!oPolicy) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (ssl_IsRemovedCipherSuite(which)) {
+ *oPolicy = SSL_NOT_ALLOWED;
+ rv = SECSuccess;
+ } else if (SSL_IS_SSL2_CIPHER(which)) {
+ rv = ssl2_GetPolicy(which, oPolicy);
+ } else {
+ rv = ssl3_GetPolicy((ssl3CipherSuite)which, oPolicy);
+ }
+ return rv;
+}
+
+/* Part of the public NSS API.
+ * Since this is a global (not per-socket) setting, we cannot use the
+ * HandshakeLock to protect this. Probably want a global lock.
+ * These changes have no effect on any sslSockets already created.
+ */
+SECStatus
+SSL_EnableCipher(long which, PRBool enabled)
+{
+ if ((which & 0xfffe) == SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA) {
+ /* one of the two old FIPS ciphers */
+ if (which == SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA)
+ which = SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA;
+ else if (which == SSL_RSA_OLDFIPS_WITH_DES_CBC_SHA)
+ which = SSL_RSA_FIPS_WITH_DES_CBC_SHA;
+ }
+ if (ssl_IsRemovedCipherSuite(which))
+ return SECSuccess;
+ return SSL_CipherPrefSetDefault(which, enabled);
+}
+
+SECStatus
+SSL_CipherPrefSetDefault(PRInt32 which, PRBool enabled)
+{
+ SECStatus rv = ssl_Init();
+
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ if (ssl_IsRemovedCipherSuite(which))
+ return SECSuccess;
+ if (enabled && ssl_defaults.noStepDown && SSL_IsExportCipherSuite(which)) {
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ return SECFailure;
+ }
+ if (SSL_IS_SSL2_CIPHER(which)) {
+ rv = ssl2_CipherPrefSetDefault(which, enabled);
+ } else {
+ rv = ssl3_CipherPrefSetDefault((ssl3CipherSuite)which, enabled);
+ }
+ return rv;
+}
+
+SECStatus
+SSL_CipherPrefGetDefault(PRInt32 which, PRBool *enabled)
+{
+ SECStatus rv;
+
+ if (!enabled) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (ssl_IsRemovedCipherSuite(which)) {
+ *enabled = PR_FALSE;
+ rv = SECSuccess;
+ } else if (SSL_IS_SSL2_CIPHER(which)) {
+ rv = ssl2_CipherPrefGetDefault(which, enabled);
+ } else {
+ rv = ssl3_CipherPrefGetDefault((ssl3CipherSuite)which, enabled);
+ }
+ return rv;
+}
+
+SECStatus
+SSL_CipherPrefSet(PRFileDesc *fd, PRInt32 which, PRBool enabled)
+{
+ SECStatus rv;
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in CipherPrefSet", SSL_GETPID(), fd));
+ return SECFailure;
+ }
+ if (ssl_IsRemovedCipherSuite(which))
+ return SECSuccess;
+ if (enabled && ss->opt.noStepDown && SSL_IsExportCipherSuite(which)) {
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ return SECFailure;
+ }
+ if (SSL_IS_SSL2_CIPHER(which)) {
+ rv = ssl2_CipherPrefSet(ss, which, enabled);
+ } else {
+ rv = ssl3_CipherPrefSet(ss, (ssl3CipherSuite)which, enabled);
+ }
+ return rv;
+}
+
+SECStatus
+SSL_CipherPrefGet(PRFileDesc *fd, PRInt32 which, PRBool *enabled)
+{
+ SECStatus rv;
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!enabled) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in CipherPrefGet", SSL_GETPID(), fd));
+ *enabled = PR_FALSE;
+ return SECFailure;
+ }
+ if (ssl_IsRemovedCipherSuite(which)) {
+ *enabled = PR_FALSE;
+ rv = SECSuccess;
+ } else if (SSL_IS_SSL2_CIPHER(which)) {
+ rv = ssl2_CipherPrefGet(ss, which, enabled);
+ } else {
+ rv = ssl3_CipherPrefGet(ss, (ssl3CipherSuite)which, enabled);
+ }
+ return rv;
+}
+
+SECStatus
+NSS_SetDomesticPolicy(void)
+{
+ SECStatus status = SECSuccess;
+ cipherPolicy * policy;
+
+ for (policy = ssl_ciphers; policy->cipher != 0; ++policy) {
+ status = SSL_SetPolicy(policy->cipher, SSL_ALLOWED);
+ if (status != SECSuccess)
+ break;
+ }
+ return status;
+}
+
+SECStatus
+NSS_SetExportPolicy(void)
+{
+ return NSS_SetDomesticPolicy();
+}
+
+SECStatus
+NSS_SetFrancePolicy(void)
+{
+ return NSS_SetDomesticPolicy();
+}
+
+SECStatus
+SSL_GetChannelBinding(PRFileDesc *fd,
+ SSLChannelBindingType binding_type,
+ unsigned char *out,
+ unsigned int *outLen,
+ unsigned int outLenMax) {
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetChannelBinding",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ if (binding_type != SSL_CHANNEL_BINDING_TLS_UNIQUE) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+
+ return ssl3_GetTLSUniqueChannelBinding(ss, out, outLen, outLenMax);
+}
+
+
+/* LOCKS ??? XXX */
+static PRFileDesc *
+ssl_ImportFD(PRFileDesc *model, PRFileDesc *fd, SSLProtocolVariant variant)
+{
+ sslSocket * ns = NULL;
+ PRStatus rv;
+ PRNetAddr addr;
+ SECStatus status = ssl_Init();
+
+ if (status != SECSuccess) {
+ return NULL;
+ }
+
+ if (model == NULL) {
+ /* Just create a default socket if we're given NULL for the model */
+ ns = ssl_NewSocket((PRBool)(!ssl_defaults.noLocks), variant);
+ } else {
+ sslSocket * ss = ssl_FindSocket(model);
+ if (ss == NULL || ss->protocolVariant != variant) {
+ SSL_DBG(("%d: SSL[%d]: bad model socket in ssl_ImportFD",
+ SSL_GETPID(), model));
+ return NULL;
+ }
+ ns = ssl_DupSocket(ss);
+ }
+ if (ns == NULL)
+ return NULL;
+
+ rv = ssl_PushIOLayer(ns, fd, PR_TOP_IO_LAYER);
+ if (rv != PR_SUCCESS) {
+ ssl_FreeSocket(ns);
+ SET_ERROR_CODE
+ return NULL;
+ }
+ ns = ssl_FindSocket(fd);
+ PORT_Assert(ns);
+ if (ns)
+ ns->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ns, &addr));
+ return fd;
+}
+
+PRFileDesc *
+SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd)
+{
+ return ssl_ImportFD(model, fd, ssl_variant_stream);
+}
+
+PRFileDesc *
+DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd)
+{
+ return ssl_ImportFD(model, fd, ssl_variant_datagram);
+}
+
+SECStatus
+SSL_SetNextProtoCallback(PRFileDesc *fd, SSLNextProtoCallback callback,
+ void *arg)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetNextProtoCallback", SSL_GETPID(),
+ fd));
+ return SECFailure;
+ }
+
+ ssl_GetSSL3HandshakeLock(ss);
+ ss->nextProtoCallback = callback;
+ ss->nextProtoArg = arg;
+ ssl_ReleaseSSL3HandshakeLock(ss);
+
+ return SECSuccess;
+}
+
+/* ssl_NextProtoNegoCallback is set as an NPN callback for the case when
+ * SSL_SetNextProtoNego is used.
+ */
+static SECStatus
+ssl_NextProtoNegoCallback(void *arg, PRFileDesc *fd,
+ const unsigned char *protos, unsigned int protos_len,
+ unsigned char *protoOut, unsigned int *protoOutLen,
+ unsigned int protoMaxLen)
+{
+ unsigned int i, j;
+ const unsigned char *result;
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in ssl_NextProtoNegoCallback",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ if (protos_len == 0) {
+ /* The server supports the extension, but doesn't have any protocols
+ * configured. In this case we request our favoured protocol. */
+ goto pick_first;
+ }
+
+ /* For each protocol in server preference, see if we support it. */
+ for (i = 0; i < protos_len; ) {
+ for (j = 0; j < ss->opt.nextProtoNego.len; ) {
+ if (protos[i] == ss->opt.nextProtoNego.data[j] &&
+ PORT_Memcmp(&protos[i+1], &ss->opt.nextProtoNego.data[j+1],
+ protos[i]) == 0) {
+ /* We found a match. */
+ ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NEGOTIATED;
+ result = &protos[i];
+ goto found;
+ }
+ j += 1 + (unsigned int)ss->opt.nextProtoNego.data[j];
+ }
+ i += 1 + (unsigned int)protos[i];
+ }
+
+pick_first:
+ ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NO_OVERLAP;
+ result = ss->opt.nextProtoNego.data;
+
+found:
+ if (protoMaxLen < result[0]) {
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ return SECFailure;
+ }
+ memcpy(protoOut, result + 1, result[0]);
+ *protoOutLen = result[0];
+ return SECSuccess;
+}
+
+SECStatus
+SSL_SetNextProtoNego(PRFileDesc *fd, const unsigned char *data,
+ unsigned int length)
+{
+ sslSocket *ss;
+ SECStatus rv;
+ SECItem dataItem = { siBuffer, (unsigned char *) data, length };
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetNextProtoNego",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ if (ssl3_ValidateNextProtoNego(data, length) != SECSuccess)
+ return SECFailure;
+
+ ssl_GetSSL3HandshakeLock(ss);
+ SECITEM_FreeItem(&ss->opt.nextProtoNego, PR_FALSE);
+ rv = SECITEM_CopyItem(NULL, &ss->opt.nextProtoNego, &dataItem);
+ ssl_ReleaseSSL3HandshakeLock(ss);
+
+ if (rv != SECSuccess)
+ return rv;
+
+ return SSL_SetNextProtoCallback(fd, ssl_NextProtoNegoCallback, NULL);
+}
+
+SECStatus
+SSL_GetNextProto(PRFileDesc *fd, SSLNextProtoState *state, unsigned char *buf,
+ unsigned int *bufLen, unsigned int bufLenMax)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetNextProto", SSL_GETPID(),
+ fd));
+ return SECFailure;
+ }
+
+ if (!state || !buf || !bufLen) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ *state = ss->ssl3.nextProtoState;
+
+ if (ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
+ ss->ssl3.nextProto.data) {
+ if (ss->ssl3.nextProto.len > bufLenMax) {
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ return SECFailure;
+ }
+ PORT_Memcpy(buf, ss->ssl3.nextProto.data, ss->ssl3.nextProto.len);
+ *bufLen = ss->ssl3.nextProto.len;
+ } else {
+ *bufLen = 0;
+ }
+
+ return SECSuccess;
+}
+
+SECStatus SSL_SetSRTPCiphers(PRFileDesc *fd,
+ const PRUint16 *ciphers,
+ unsigned int numCiphers)
+{
+ sslSocket *ss;
+ unsigned int i;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss || !IS_DTLS(ss)) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetSRTPCiphers",
+ SSL_GETPID(), fd));
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (numCiphers > MAX_DTLS_SRTP_CIPHER_SUITES) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ ss->ssl3.dtlsSRTPCipherCount = 0;
+ for (i = 0; i < numCiphers; i++) {
+ const PRUint16 *srtpCipher = srtpCiphers;
+
+ while (*srtpCipher) {
+ if (ciphers[i] == *srtpCipher)
+ break;
+ srtpCipher++;
+ }
+ if (*srtpCipher) {
+ ss->ssl3.dtlsSRTPCiphers[ss->ssl3.dtlsSRTPCipherCount++] =
+ ciphers[i];
+ } else {
+ SSL_DBG(("%d: SSL[%d]: invalid or unimplemented SRTP cipher "
+ "suite specified: 0x%04hx", SSL_GETPID(), fd,
+ ciphers[i]));
+ }
+ }
+
+ if (ss->ssl3.dtlsSRTPCipherCount == 0) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+SECStatus
+SSL_GetSRTPCipher(PRFileDesc *fd, PRUint16 *cipher)
+{
+ sslSocket * ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetSRTPCipher",
+ SSL_GETPID(), fd));
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (!ss->ssl3.dtlsSRTPCipherSuite) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ *cipher = ss->ssl3.dtlsSRTPCipherSuite;
+ return SECSuccess;
+}
+
+PRFileDesc *
+SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
+{
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ PR_NOT_REACHED("not implemented");
+ return NULL;
+
+#if 0
+ sslSocket * sm = NULL, *ss = NULL;
+ int i;
+ sslServerCerts * mc = NULL;
+ sslServerCerts * sc = NULL;
+
+ if (model == NULL) {
+ PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
+ return NULL;
+ }
+ sm = ssl_FindSocket(model);
+ if (sm == NULL) {
+ SSL_DBG(("%d: SSL[%d]: bad model socket in ssl_ReconfigFD",
+ SSL_GETPID(), model));
+ return NULL;
+ }
+ ss = ssl_FindSocket(fd);
+ PORT_Assert(ss);
+ if (ss == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ ss->opt = sm->opt;
+ ss->vrange = sm->vrange;
+ PORT_Memcpy(ss->cipherSuites, sm->cipherSuites, sizeof sm->cipherSuites);
+ PORT_Memcpy(ss->ssl3.dtlsSRTPCiphers, sm->ssl3.dtlsSRTPCiphers,
+ sizeof(PRUint16) * sm->ssl3.dtlsSRTPCipherCount);
+ ss->ssl3.dtlsSRTPCipherCount = sm->ssl3.dtlsSRTPCipherCount;
+
+ if (!ss->opt.useSecurity) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+ /* This int should be SSLKEAType, but CC on Irix complains,
+ * during the for loop.
+ */
+ for (i=kt_null; i < kt_kea_size; i++) {
+ mc = &(sm->serverCerts[i]);
+ sc = &(ss->serverCerts[i]);
+ if (mc->serverCert && mc->serverCertChain) {
+ if (sc->serverCert) {
+ CERT_DestroyCertificate(sc->serverCert);
+ }
+ sc->serverCert = CERT_DupCertificate(mc->serverCert);
+ if (sc->serverCertChain) {
+ CERT_DestroyCertificateList(sc->serverCertChain);
+ }
+ sc->serverCertChain = CERT_DupCertList(mc->serverCertChain);
+ if (!sc->serverCertChain)
+ goto loser;
+ if (sm->certStatusArray[i]) {
+ if (ss->certStatusArray[i]) {
+ SECITEM_FreeArray(ss->certStatusArray[i], PR_TRUE);
+ ss->certStatusArray[i] = NULL;
+ }
+ ss->certStatusArray[i] = SECITEM_DupArray(NULL, sm->certStatusArray[i]);
+ if (!ss->certStatusArray[i])
+ goto loser;
+ }
+ }
+ if (mc->serverKeyPair) {
+ if (sc->serverKeyPair) {
+ ssl3_FreeKeyPair(sc->serverKeyPair);
+ }
+ sc->serverKeyPair = ssl3_GetKeyPairRef(mc->serverKeyPair);
+ sc->serverKeyBits = mc->serverKeyBits;
+ }
+ }
+ if (sm->stepDownKeyPair) {
+ if (ss->stepDownKeyPair) {
+ ssl3_FreeKeyPair(ss->stepDownKeyPair);
+ }
+ ss->stepDownKeyPair = ssl3_GetKeyPairRef(sm->stepDownKeyPair);
+ }
+ if (sm->ephemeralECDHKeyPair) {
+ if (ss->ephemeralECDHKeyPair) {
+ ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair);
+ }
+ ss->ephemeralECDHKeyPair =
+ ssl3_GetKeyPairRef(sm->ephemeralECDHKeyPair);
+ }
+ /* copy trust anchor names */
+ if (sm->ssl3.ca_list) {
+ if (ss->ssl3.ca_list) {
+ CERT_FreeDistNames(ss->ssl3.ca_list);
+ }
+ ss->ssl3.ca_list = CERT_DupDistNames(sm->ssl3.ca_list);
+ if (!ss->ssl3.ca_list) {
+ goto loser;
+ }
+ }
+
+ if (sm->authCertificate)
+ ss->authCertificate = sm->authCertificate;
+ if (sm->authCertificateArg)
+ ss->authCertificateArg = sm->authCertificateArg;
+ if (sm->getClientAuthData)
+ ss->getClientAuthData = sm->getClientAuthData;
+ if (sm->getClientAuthDataArg)
+ ss->getClientAuthDataArg = sm->getClientAuthDataArg;
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ if (sm->getPlatformClientAuthData)
+ ss->getPlatformClientAuthData = sm->getPlatformClientAuthData;
+ if (sm->getPlatformClientAuthDataArg)
+ ss->getPlatformClientAuthDataArg = sm->getPlatformClientAuthDataArg;
+#endif
+ if (sm->sniSocketConfig)
+ ss->sniSocketConfig = sm->sniSocketConfig;
+ if (sm->sniSocketConfigArg)
+ ss->sniSocketConfigArg = sm->sniSocketConfigArg;
+ if (sm->handleBadCert)
+ ss->handleBadCert = sm->handleBadCert;
+ if (sm->badCertArg)
+ ss->badCertArg = sm->badCertArg;
+ if (sm->handshakeCallback)
+ ss->handshakeCallback = sm->handshakeCallback;
+ if (sm->handshakeCallbackData)
+ ss->handshakeCallbackData = sm->handshakeCallbackData;
+ if (sm->pkcs11PinArg)
+ ss->pkcs11PinArg = sm->pkcs11PinArg;
+ if (sm->getChannelID)
+ ss->getChannelID = sm->getChannelID;
+ if (sm->getChannelIDArg)
+ ss->getChannelIDArg = sm->getChannelIDArg;
+ return fd;
+loser:
+ return NULL;
+#endif
+}
+
+PRBool
+ssl3_VersionIsSupported(SSLProtocolVariant protocolVariant,
+ SSL3ProtocolVersion version)
+{
+ switch (protocolVariant) {
+ case ssl_variant_stream:
+ return (version >= SSL_LIBRARY_VERSION_3_0 &&
+ version <= SSL_LIBRARY_VERSION_MAX_SUPPORTED);
+ case ssl_variant_datagram:
+ return (version >= SSL_LIBRARY_VERSION_TLS_1_1 &&
+ version <= SSL_LIBRARY_VERSION_MAX_SUPPORTED);
+ default:
+ /* Can't get here */
+ PORT_Assert(PR_FALSE);
+ return PR_FALSE;
+ }
+}
+
+/* Returns PR_TRUE if the given version range is valid and
+** fully supported; otherwise, returns PR_FALSE.
+*/
+static PRBool
+ssl3_VersionRangeIsValid(SSLProtocolVariant protocolVariant,
+ const SSLVersionRange *vrange)
+{
+ return vrange &&
+ vrange->min <= vrange->max &&
+ ssl3_VersionIsSupported(protocolVariant, vrange->min) &&
+ ssl3_VersionIsSupported(protocolVariant, vrange->max);
+}
+
+SECStatus
+SSL_VersionRangeGetSupported(SSLProtocolVariant protocolVariant,
+ SSLVersionRange *vrange)
+{
+ if (!vrange) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ switch (protocolVariant) {
+ case ssl_variant_stream:
+ vrange->min = SSL_LIBRARY_VERSION_3_0;
+ vrange->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED;
+ break;
+ case ssl_variant_datagram:
+ vrange->min = SSL_LIBRARY_VERSION_TLS_1_1;
+ vrange->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED;
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+SECStatus
+SSL_VersionRangeGetDefault(SSLProtocolVariant protocolVariant,
+ SSLVersionRange *vrange)
+{
+ if ((protocolVariant != ssl_variant_stream &&
+ protocolVariant != ssl_variant_datagram) || !vrange) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ *vrange = *VERSIONS_DEFAULTS(protocolVariant);
+
+ return SECSuccess;
+}
+
+SECStatus
+SSL_VersionRangeSetDefault(SSLProtocolVariant protocolVariant,
+ const SSLVersionRange *vrange)
+{
+ if (!ssl3_VersionRangeIsValid(protocolVariant, vrange)) {
+ PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE);
+ return SECFailure;
+ }
+
+ *VERSIONS_DEFAULTS(protocolVariant) = *vrange;
+
+ return SECSuccess;
+}
+
+SECStatus
+SSL_VersionRangeGet(PRFileDesc *fd, SSLVersionRange *vrange)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL3_VersionRangeGet",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ if (!vrange) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ *vrange = ss->vrange;
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ return SECSuccess;
+}
+
+static PRCallOnceType checkTLS12TokenOnce;
+static PRBool tls12TokenExists;
+
+static PRStatus
+ssl_CheckTLS12Token(void)
+{
+ tls12TokenExists =
+ PK11_TokenExists(CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256);
+ return PR_SUCCESS;
+}
+
+static PRBool
+ssl_TLS12TokenExists(void)
+{
+ (void) PR_CallOnce(&checkTLS12TokenOnce, ssl_CheckTLS12Token);
+ return tls12TokenExists;
+}
+
+SECStatus
+SSL_VersionRangeSet(PRFileDesc *fd, const SSLVersionRange *vrange)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL3_VersionRangeSet",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ if (!ssl3_VersionRangeIsValid(ss->protocolVariant, vrange)) {
+ PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE);
+ return SECFailure;
+ }
+
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ ss->vrange = *vrange;
+ /* If we don't have a sufficiently up-to-date softoken then we cannot do
+ * TLS 1.2. */
+ if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_2 &&
+ !ssl_TLS12TokenExists()) {
+ /* If the user requested a minimum version of 1.2, then we don't
+ * silently downgrade. */
+ if (ss->vrange.min >= SSL_LIBRARY_VERSION_TLS_1_2) {
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+ PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE);
+ return SECFailure;
+ }
+ ss->vrange.max = SSL_LIBRARY_VERSION_TLS_1_1;
+ }
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ return SECSuccess;
+}
+
+const SECItemArray *
+SSL_PeerStapledOCSPResponses(PRFileDesc *fd)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_PeerStapledOCSPResponses",
+ SSL_GETPID(), fd));
+ return NULL;
+ }
+
+ if (!ss->sec.ci.sid) {
+ PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+ return NULL;
+ }
+
+ return &ss->sec.ci.sid->peerCertStatus;
+}
+
+SECStatus
+SSL_HandshakeResumedSession(PRFileDesc *fd, PRBool *handshake_resumed) {
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_HandshakeResumedSession",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ *handshake_resumed = ss->ssl3.hs.isResuming;
+ return SECSuccess;
+}
+
+const SECItem *
+SSL_GetRequestedClientCertificateTypes(PRFileDesc *fd)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in "
+ "SSL_GetRequestedClientCertificateTypes", SSL_GETPID(), fd));
+ return NULL;
+ }
+
+ return ss->requestedCertTypes;
+}
+
+/************************************************************************/
+/* The following functions are the TOP LEVEL SSL functions.
+** They all get called through the NSPRIOMethods table below.
+*/
+
+static PRFileDesc * PR_CALLBACK
+ssl_Accept(PRFileDesc *fd, PRNetAddr *sockaddr, PRIntervalTime timeout)
+{
+ sslSocket *ss;
+ sslSocket *ns = NULL;
+ PRFileDesc *newfd = NULL;
+ PRFileDesc *osfd;
+ PRStatus status;
+
+ ss = ssl_GetPrivate(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in accept", SSL_GETPID(), fd));
+ return NULL;
+ }
+
+ /* IF this is a listen socket, there shouldn't be any I/O going on */
+ SSL_LOCK_READER(ss);
+ SSL_LOCK_WRITER(ss);
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ ss->cTimeout = timeout;
+
+ osfd = ss->fd->lower;
+
+ /* First accept connection */
+ newfd = osfd->methods->accept(osfd, sockaddr, timeout);
+ if (newfd == NULL) {
+ SSL_DBG(("%d: SSL[%d]: accept failed, errno=%d",
+ SSL_GETPID(), ss->fd, PORT_GetError()));
+ } else {
+ /* Create ssl module */
+ ns = ssl_DupSocket(ss);
+ }
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+ SSL_UNLOCK_WRITER(ss);
+ SSL_UNLOCK_READER(ss); /* ss isn't used below here. */
+
+ if (ns == NULL)
+ goto loser;
+
+ /* push ssl module onto the new socket */
+ status = ssl_PushIOLayer(ns, newfd, PR_TOP_IO_LAYER);
+ if (status != PR_SUCCESS)
+ goto loser;
+
+ /* Now start server connection handshake with client.
+ ** Don't need locks here because nobody else has a reference to ns yet.
+ */
+ if ( ns->opt.useSecurity ) {
+ if ( ns->opt.handshakeAsClient ) {
+ ns->handshake = ssl2_BeginClientHandshake;
+ ss->handshaking = sslHandshakingAsClient;
+ } else {
+ ns->handshake = ssl2_BeginServerHandshake;
+ ss->handshaking = sslHandshakingAsServer;
+ }
+ }
+ ns->TCPconnected = 1;
+ return newfd;
+
+loser:
+ if (ns != NULL)
+ ssl_FreeSocket(ns);
+ if (newfd != NULL)
+ PR_Close(newfd);
+ return NULL;
+}
+
+static PRStatus PR_CALLBACK
+ssl_Connect(PRFileDesc *fd, const PRNetAddr *sockaddr, PRIntervalTime timeout)
+{
+ sslSocket *ss;
+ PRStatus rv;
+
+ ss = ssl_GetPrivate(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in connect", SSL_GETPID(), fd));
+ return PR_FAILURE;
+ }
+
+ /* IF this is a listen socket, there shouldn't be any I/O going on */
+ SSL_LOCK_READER(ss);
+ SSL_LOCK_WRITER(ss);
+
+ ss->cTimeout = timeout;
+ rv = (PRStatus)(*ss->ops->connect)(ss, sockaddr);
+
+ SSL_UNLOCK_WRITER(ss);
+ SSL_UNLOCK_READER(ss);
+
+ return rv;
+}
+
+static PRStatus PR_CALLBACK
+ssl_Bind(PRFileDesc *fd, const PRNetAddr *addr)
+{
+ sslSocket * ss = ssl_GetPrivate(fd);
+ PRStatus rv;
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in bind", SSL_GETPID(), fd));
+ return PR_FAILURE;
+ }
+ SSL_LOCK_READER(ss);
+ SSL_LOCK_WRITER(ss);
+
+ rv = (PRStatus)(*ss->ops->bind)(ss, addr);
+
+ SSL_UNLOCK_WRITER(ss);
+ SSL_UNLOCK_READER(ss);
+ return rv;
+}
+
+static PRStatus PR_CALLBACK
+ssl_Listen(PRFileDesc *fd, PRIntn backlog)
+{
+ sslSocket * ss = ssl_GetPrivate(fd);
+ PRStatus rv;
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in listen", SSL_GETPID(), fd));
+ return PR_FAILURE;
+ }
+ SSL_LOCK_READER(ss);
+ SSL_LOCK_WRITER(ss);
+
+ rv = (PRStatus)(*ss->ops->listen)(ss, backlog);
+
+ SSL_UNLOCK_WRITER(ss);
+ SSL_UNLOCK_READER(ss);
+ return rv;
+}
+
+static PRStatus PR_CALLBACK
+ssl_Shutdown(PRFileDesc *fd, PRIntn how)
+{
+ sslSocket * ss = ssl_GetPrivate(fd);
+ PRStatus rv;
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in shutdown", SSL_GETPID(), fd));
+ return PR_FAILURE;
+ }
+ if (how == PR_SHUTDOWN_RCV || how == PR_SHUTDOWN_BOTH) {
+ SSL_LOCK_READER(ss);
+ }
+ if (how == PR_SHUTDOWN_SEND || how == PR_SHUTDOWN_BOTH) {
+ SSL_LOCK_WRITER(ss);
+ }
+
+ rv = (PRStatus)(*ss->ops->shutdown)(ss, how);
+
+ if (how == PR_SHUTDOWN_SEND || how == PR_SHUTDOWN_BOTH) {
+ SSL_UNLOCK_WRITER(ss);
+ }
+ if (how == PR_SHUTDOWN_RCV || how == PR_SHUTDOWN_BOTH) {
+ SSL_UNLOCK_READER(ss);
+ }
+ return rv;
+}
+
+static PRStatus PR_CALLBACK
+ssl_Close(PRFileDesc *fd)
+{
+ sslSocket *ss;
+ PRStatus rv;
+
+ ss = ssl_GetPrivate(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in close", SSL_GETPID(), fd));
+ return PR_FAILURE;
+ }
+
+ /* There must not be any I/O going on */
+ SSL_LOCK_READER(ss);
+ SSL_LOCK_WRITER(ss);
+
+ /* By the time this function returns,
+ ** ss is an invalid pointer, and the locks to which it points have
+ ** been unlocked and freed. So, this is the ONE PLACE in all of SSL
+ ** where the LOCK calls and the corresponding UNLOCK calls are not in
+ ** the same function scope. The unlock calls are in ssl_FreeSocket().
+ */
+ rv = (PRStatus)(*ss->ops->close)(ss);
+
+ return rv;
+}
+
+static int PR_CALLBACK
+ssl_Recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags,
+ PRIntervalTime timeout)
+{
+ sslSocket *ss;
+ int rv;
+
+ ss = ssl_GetPrivate(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in recv", SSL_GETPID(), fd));
+ return SECFailure;
+ }
+ SSL_LOCK_READER(ss);
+ ss->rTimeout = timeout;
+ if (!ss->opt.fdx)
+ ss->wTimeout = timeout;
+ rv = (*ss->ops->recv)(ss, (unsigned char*)buf, len, flags);
+ SSL_UNLOCK_READER(ss);
+ return rv;
+}
+
+static int PR_CALLBACK
+ssl_Send(PRFileDesc *fd, const void *buf, PRInt32 len, PRIntn flags,
+ PRIntervalTime timeout)
+{
+ sslSocket *ss;
+ int rv;
+
+ ss = ssl_GetPrivate(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in send", SSL_GETPID(), fd));
+ return SECFailure;
+ }
+ SSL_LOCK_WRITER(ss);
+ ss->wTimeout = timeout;
+ if (!ss->opt.fdx)
+ ss->rTimeout = timeout;
+ rv = (*ss->ops->send)(ss, (const unsigned char*)buf, len, flags);
+ SSL_UNLOCK_WRITER(ss);
+ return rv;
+}
+
+static int PR_CALLBACK
+ssl_Read(PRFileDesc *fd, void *buf, PRInt32 len)
+{
+ sslSocket *ss;
+ int rv;
+
+ ss = ssl_GetPrivate(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in read", SSL_GETPID(), fd));
+ return SECFailure;
+ }
+ SSL_LOCK_READER(ss);
+ ss->rTimeout = PR_INTERVAL_NO_TIMEOUT;
+ if (!ss->opt.fdx)
+ ss->wTimeout = PR_INTERVAL_NO_TIMEOUT;
+ rv = (*ss->ops->read)(ss, (unsigned char*)buf, len);
+ SSL_UNLOCK_READER(ss);
+ return rv;
+}
+
+static int PR_CALLBACK
+ssl_Write(PRFileDesc *fd, const void *buf, PRInt32 len)
+{
+ sslSocket *ss;
+ int rv;
+
+ ss = ssl_GetPrivate(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in write", SSL_GETPID(), fd));
+ return SECFailure;
+ }
+ SSL_LOCK_WRITER(ss);
+ ss->wTimeout = PR_INTERVAL_NO_TIMEOUT;
+ if (!ss->opt.fdx)
+ ss->rTimeout = PR_INTERVAL_NO_TIMEOUT;
+ rv = (*ss->ops->write)(ss, (const unsigned char*)buf, len);
+ SSL_UNLOCK_WRITER(ss);
+ return rv;
+}
+
+static PRStatus PR_CALLBACK
+ssl_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
+{
+ sslSocket *ss;
+
+ ss = ssl_GetPrivate(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in getpeername", SSL_GETPID(), fd));
+ return PR_FAILURE;
+ }
+ return (PRStatus)(*ss->ops->getpeername)(ss, addr);
+}
+
+/*
+*/
+SECStatus
+ssl_GetPeerInfo(sslSocket *ss)
+{
+ PRFileDesc * osfd;
+ int rv;
+ PRNetAddr sin;
+
+ osfd = ss->fd->lower;
+
+ PORT_Memset(&sin, 0, sizeof(sin));
+ rv = osfd->methods->getpeername(osfd, &sin);
+ if (rv < 0) {
+ return SECFailure;
+ }
+ ss->TCPconnected = 1;
+ if (sin.inet.family == PR_AF_INET) {
+ PR_ConvertIPv4AddrToIPv6(sin.inet.ip, &ss->sec.ci.peer);
+ ss->sec.ci.port = sin.inet.port;
+ } else if (sin.ipv6.family == PR_AF_INET6) {
+ ss->sec.ci.peer = sin.ipv6.ip;
+ ss->sec.ci.port = sin.ipv6.port;
+ } else {
+ PORT_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+static PRStatus PR_CALLBACK
+ssl_GetSockName(PRFileDesc *fd, PRNetAddr *name)
+{
+ sslSocket *ss;
+
+ ss = ssl_GetPrivate(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in getsockname", SSL_GETPID(), fd));
+ return PR_FAILURE;
+ }
+ return (PRStatus)(*ss->ops->getsockname)(ss, name);
+}
+
+SECStatus
+SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses,
+ SSLKEAType kea)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetStapledOCSPResponses",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ if ( kea <= 0 || kea >= kt_kea_size) {
+ SSL_DBG(("%d: SSL[%d]: invalid key in SSL_SetStapledOCSPResponses",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ if (ss->certStatusArray[kea]) {
+ SECITEM_FreeArray(ss->certStatusArray[kea], PR_TRUE);
+ ss->certStatusArray[kea] = NULL;
+ }
+ if (responses) {
+ ss->certStatusArray[kea] = SECITEM_DupArray(NULL, responses);
+ }
+ return (ss->certStatusArray[kea] || !responses) ? SECSuccess : SECFailure;
+}
+
+SECStatus
+SSL_SetSockPeerID(PRFileDesc *fd, const char *peerID)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetSockPeerID",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ if (ss->peerID) {
+ PORT_Free(ss->peerID);
+ ss->peerID = NULL;
+ }
+ if (peerID)
+ ss->peerID = PORT_Strdup(peerID);
+ return (ss->peerID || !peerID) ? SECSuccess : SECFailure;
+}
+
+#define PR_POLL_RW (PR_POLL_WRITE | PR_POLL_READ)
+
+static PRInt16 PR_CALLBACK
+ssl_Poll(PRFileDesc *fd, PRInt16 how_flags, PRInt16 *p_out_flags)
+{
+ sslSocket *ss;
+ PRInt16 new_flags = how_flags; /* should select on these flags. */
+ PRNetAddr addr;
+
+ *p_out_flags = 0;
+ ss = ssl_GetPrivate(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_Poll",
+ SSL_GETPID(), fd));
+ return 0; /* don't poll on this socket */
+ }
+
+ if (ss->opt.useSecurity &&
+ ss->handshaking != sslHandshakingUndetermined &&
+ !ss->firstHsDone &&
+ (how_flags & PR_POLL_RW)) {
+ if (!ss->TCPconnected) {
+ ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr));
+ }
+ /* If it's not connected, then presumably the application is polling
+ ** on read or write appropriately, so don't change it.
+ */
+ if (ss->TCPconnected) {
+ if (!ss->handshakeBegun) {
+ /* If the handshake has not begun, poll on read or write
+ ** based on the local application's role in the handshake,
+ ** not based on what the application requested.
+ */
+ new_flags &= ~PR_POLL_RW;
+ if (ss->handshaking == sslHandshakingAsClient) {
+ new_flags |= PR_POLL_WRITE;
+ } else { /* handshaking as server */
+ new_flags |= PR_POLL_READ;
+ }
+ } else
+ /* First handshake is in progress */
+ if (ss->lastWriteBlocked) {
+ if (new_flags & PR_POLL_READ) {
+ /* The caller is waiting for data to be received,
+ ** but the initial handshake is blocked on write, or the
+ ** client's first handshake record has not been written.
+ ** The code should select on write, not read.
+ */
+ new_flags ^= PR_POLL_READ; /* don't select on read. */
+ new_flags |= PR_POLL_WRITE; /* do select on write. */
+ }
+ } else if (new_flags & PR_POLL_WRITE) {
+ /* The caller is trying to write, but the handshake is
+ ** blocked waiting for data to read, and the first
+ ** handshake has been sent. so do NOT to poll on write.
+ */
+ new_flags ^= PR_POLL_WRITE; /* don't select on write. */
+ new_flags |= PR_POLL_READ; /* do select on read. */
+ }
+ }
+ } else if ((new_flags & PR_POLL_READ) && (SSL_DataPending(fd) > 0)) {
+ *p_out_flags = PR_POLL_READ; /* it's ready already. */
+ return new_flags;
+ } else if ((ss->lastWriteBlocked) && (how_flags & PR_POLL_READ) &&
+ (ss->pendingBuf.len != 0)) { /* write data waiting to be sent */
+ new_flags |= PR_POLL_WRITE; /* also select on write. */
+ }
+
+ if (ss->version >= SSL_LIBRARY_VERSION_3_0 &&
+ ss->ssl3.hs.restartTarget != NULL) {
+ /* Read and write will block until the asynchronous callback completes
+ * (e.g. until SSL_AuthCertificateComplete is called), so don't tell
+ * the caller to poll the socket unless there is pending write data.
+ */
+ if (ss->lastWriteBlocked && ss->pendingBuf.len != 0) {
+ /* Ignore any newly-received data on the socket, but do wait for
+ * the socket to become writable again. Here, it is OK for an error
+ * to be detected, because our logic for sending pending write data
+ * will allow us to report the error to the caller without the risk
+ * of the application spinning.
+ */
+ new_flags &= (PR_POLL_WRITE | PR_POLL_EXCEPT);
+ } else {
+ /* Unfortunately, clearing new_flags will make it impossible for
+ * the application to detect errors that it would otherwise be
+ * able to detect with PR_POLL_EXCEPT, until the asynchronous
+ * callback completes. However, we must clear all the flags to
+ * prevent the application from spinning (alternating between
+ * calling PR_Poll that would return PR_POLL_EXCEPT, and send/recv
+ * which won't actually report the I/O error while we are waiting
+ * for the asynchronous callback to complete).
+ */
+ new_flags = 0;
+ }
+ }
+
+ if (new_flags && (fd->lower->methods->poll != NULL)) {
+ PRInt16 lower_out_flags = 0;
+ PRInt16 lower_new_flags;
+ lower_new_flags = fd->lower->methods->poll(fd->lower, new_flags,
+ &lower_out_flags);
+ if ((lower_new_flags & lower_out_flags) && (how_flags != new_flags)) {
+ PRInt16 out_flags = lower_out_flags & ~PR_POLL_RW;
+ if (lower_out_flags & PR_POLL_READ)
+ out_flags |= PR_POLL_WRITE;
+ if (lower_out_flags & PR_POLL_WRITE)
+ out_flags |= PR_POLL_READ;
+ *p_out_flags = out_flags;
+ new_flags = how_flags;
+ } else {
+ *p_out_flags = lower_out_flags;
+ new_flags = lower_new_flags;
+ }
+ }
+
+ return new_flags;
+}
+
+static PRInt32 PR_CALLBACK
+ssl_TransmitFile(PRFileDesc *sd, PRFileDesc *fd,
+ const void *headers, PRInt32 hlen,
+ PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+ PRSendFileData sfd;
+
+ sfd.fd = fd;
+ sfd.file_offset = 0;
+ sfd.file_nbytes = 0;
+ sfd.header = headers;
+ sfd.hlen = hlen;
+ sfd.trailer = NULL;
+ sfd.tlen = 0;
+
+ return sd->methods->sendfile(sd, &sfd, flags, timeout);
+}
+
+
+PRBool
+ssl_FdIsBlocking(PRFileDesc *fd)
+{
+ PRSocketOptionData opt;
+ PRStatus status;
+
+ opt.option = PR_SockOpt_Nonblocking;
+ opt.value.non_blocking = PR_FALSE;
+ status = PR_GetSocketOption(fd, &opt);
+ if (status != PR_SUCCESS)
+ return PR_FALSE;
+ return (PRBool)!opt.value.non_blocking;
+}
+
+PRBool
+ssl_SocketIsBlocking(sslSocket *ss)
+{
+ return ssl_FdIsBlocking(ss->fd);
+}
+
+PRInt32 sslFirstBufSize = 8 * 1024;
+PRInt32 sslCopyLimit = 1024;
+
+static PRInt32 PR_CALLBACK
+ssl_WriteV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 vectors,
+ PRIntervalTime timeout)
+{
+ PRInt32 bufLen;
+ PRInt32 left;
+ PRInt32 rv;
+ PRInt32 sent = 0;
+ const PRInt32 first_len = sslFirstBufSize;
+ const PRInt32 limit = sslCopyLimit;
+ PRBool blocking;
+ PRIOVec myIov = { 0, 0 };
+ char buf[MAX_FRAGMENT_LENGTH];
+
+ if (vectors > PR_MAX_IOVECTOR_SIZE) {
+ PORT_SetError(PR_BUFFER_OVERFLOW_ERROR);
+ return -1;
+ }
+ blocking = ssl_FdIsBlocking(fd);
+
+#define K16 sizeof(buf)
+#define KILL_VECTORS while (vectors && !iov->iov_len) { ++iov; --vectors; }
+#define GET_VECTOR do { myIov = *iov++; --vectors; KILL_VECTORS } while (0)
+#define HANDLE_ERR(rv, len) \
+ if (rv != len) { \
+ if (rv < 0) { \
+ if (!blocking \
+ && (PR_GetError() == PR_WOULD_BLOCK_ERROR) \
+ && (sent > 0)) { \
+ return sent; \
+ } else { \
+ return -1; \
+ } \
+ } \
+ /* Only a nonblocking socket can have partial sends */ \
+ PR_ASSERT(!blocking); \
+ return sent + rv; \
+ }
+#define SEND(bfr, len) \
+ do { \
+ rv = ssl_Send(fd, bfr, len, 0, timeout); \
+ HANDLE_ERR(rv, len) \
+ sent += len; \
+ } while (0)
+
+ /* Make sure the first write is at least 8 KB, if possible. */
+ KILL_VECTORS
+ if (!vectors)
+ return ssl_Send(fd, 0, 0, 0, timeout);
+ GET_VECTOR;
+ if (!vectors) {
+ return ssl_Send(fd, myIov.iov_base, myIov.iov_len, 0, timeout);
+ }
+ if (myIov.iov_len < first_len) {
+ PORT_Memcpy(buf, myIov.iov_base, myIov.iov_len);
+ bufLen = myIov.iov_len;
+ left = first_len - bufLen;
+ while (vectors && left) {
+ int toCopy;
+ GET_VECTOR;
+ toCopy = PR_MIN(left, myIov.iov_len);
+ PORT_Memcpy(buf + bufLen, myIov.iov_base, toCopy);
+ bufLen += toCopy;
+ left -= toCopy;
+ myIov.iov_base += toCopy;
+ myIov.iov_len -= toCopy;
+ }
+ SEND( buf, bufLen );
+ }
+
+ while (vectors || myIov.iov_len) {
+ PRInt32 addLen;
+ if (!myIov.iov_len) {
+ GET_VECTOR;
+ }
+ while (myIov.iov_len >= K16) {
+ SEND(myIov.iov_base, K16);
+ myIov.iov_base += K16;
+ myIov.iov_len -= K16;
+ }
+ if (!myIov.iov_len)
+ continue;
+
+ if (!vectors || myIov.iov_len > limit) {
+ addLen = 0;
+ } else if ((addLen = iov->iov_len % K16) + myIov.iov_len <= limit) {
+ /* Addlen is already computed. */;
+ } else if (vectors > 1 &&
+ iov[1].iov_len % K16 + addLen + myIov.iov_len <= 2 * limit) {
+ addLen = limit - myIov.iov_len;
+ } else
+ addLen = 0;
+
+ if (!addLen) {
+ SEND( myIov.iov_base, myIov.iov_len );
+ myIov.iov_len = 0;
+ continue;
+ }
+ PORT_Memcpy(buf, myIov.iov_base, myIov.iov_len);
+ bufLen = myIov.iov_len;
+ do {
+ GET_VECTOR;
+ PORT_Memcpy(buf + bufLen, myIov.iov_base, addLen);
+ myIov.iov_base += addLen;
+ myIov.iov_len -= addLen;
+ bufLen += addLen;
+
+ left = PR_MIN( limit, K16 - bufLen);
+ if (!vectors /* no more left */
+ || myIov.iov_len > 0 /* we didn't use that one all up */
+ || bufLen >= K16 /* it's full. */
+ ) {
+ addLen = 0;
+ } else if ((addLen = iov->iov_len % K16) <= left) {
+ /* Addlen is already computed. */;
+ } else if (vectors > 1 &&
+ iov[1].iov_len % K16 + addLen <= left + limit) {
+ addLen = left;
+ } else
+ addLen = 0;
+
+ } while (addLen);
+ SEND( buf, bufLen );
+ }
+ return sent;
+}
+
+/*
+ * These functions aren't implemented.
+ */
+
+static PRInt32 PR_CALLBACK
+ssl_Available(PRFileDesc *fd)
+{
+ PORT_Assert(0);
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return SECFailure;
+}
+
+static PRInt64 PR_CALLBACK
+ssl_Available64(PRFileDesc *fd)
+{
+ PRInt64 res;
+
+ PORT_Assert(0);
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ LL_I2L(res, -1L);
+ return res;
+}
+
+static PRStatus PR_CALLBACK
+ssl_FSync(PRFileDesc *fd)
+{
+ PORT_Assert(0);
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+static PRInt32 PR_CALLBACK
+ssl_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence how) {
+ PORT_Assert(0);
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return SECFailure;
+}
+
+static PRInt64 PR_CALLBACK
+ssl_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence how) {
+ PRInt64 res;
+
+ PORT_Assert(0);
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ LL_I2L(res, -1L);
+ return res;
+}
+
+static PRStatus PR_CALLBACK
+ssl_FileInfo(PRFileDesc *fd, PRFileInfo *info)
+{
+ PORT_Assert(0);
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+static PRStatus PR_CALLBACK
+ssl_FileInfo64(PRFileDesc *fd, PRFileInfo64 *info)
+{
+ PORT_Assert(0);
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+static PRInt32 PR_CALLBACK
+ssl_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
+ PRNetAddr *addr, PRIntervalTime timeout)
+{
+ PORT_Assert(0);
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return SECFailure;
+}
+
+static PRInt32 PR_CALLBACK
+ssl_SendTo(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
+ const PRNetAddr *addr, PRIntervalTime timeout)
+{
+ PORT_Assert(0);
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return SECFailure;
+}
+
+static const PRIOMethods ssl_methods = {
+ PR_DESC_LAYERED,
+ ssl_Close, /* close */
+ ssl_Read, /* read */
+ ssl_Write, /* write */
+ ssl_Available, /* available */
+ ssl_Available64, /* available64 */
+ ssl_FSync, /* fsync */
+ ssl_Seek, /* seek */
+ ssl_Seek64, /* seek64 */
+ ssl_FileInfo, /* fileInfo */
+ ssl_FileInfo64, /* fileInfo64 */
+ ssl_WriteV, /* writev */
+ ssl_Connect, /* connect */
+ ssl_Accept, /* accept */
+ ssl_Bind, /* bind */
+ ssl_Listen, /* listen */
+ ssl_Shutdown, /* shutdown */
+ ssl_Recv, /* recv */
+ ssl_Send, /* send */
+ ssl_RecvFrom, /* recvfrom */
+ ssl_SendTo, /* sendto */
+ ssl_Poll, /* poll */
+ PR_EmulateAcceptRead, /* acceptread */
+ ssl_TransmitFile, /* transmitfile */
+ ssl_GetSockName, /* getsockname */
+ ssl_GetPeerName, /* getpeername */
+ NULL, /* getsockopt OBSOLETE */
+ NULL, /* setsockopt OBSOLETE */
+ NULL, /* getsocketoption */
+ NULL, /* setsocketoption */
+ PR_EmulateSendFile, /* Send a (partial) file with header/trailer*/
+ NULL, /* reserved for future use */
+ NULL, /* reserved for future use */
+ NULL, /* reserved for future use */
+ NULL, /* reserved for future use */
+ NULL /* reserved for future use */
+};
+
+
+static PRIOMethods combined_methods;
+
+static void
+ssl_SetupIOMethods(void)
+{
+ PRIOMethods *new_methods = &combined_methods;
+ const PRIOMethods *nspr_methods = PR_GetDefaultIOMethods();
+ const PRIOMethods *my_methods = &ssl_methods;
+
+ *new_methods = *nspr_methods;
+
+ new_methods->file_type = my_methods->file_type;
+ new_methods->close = my_methods->close;
+ new_methods->read = my_methods->read;
+ new_methods->write = my_methods->write;
+ new_methods->available = my_methods->available;
+ new_methods->available64 = my_methods->available64;
+ new_methods->fsync = my_methods->fsync;
+ new_methods->seek = my_methods->seek;
+ new_methods->seek64 = my_methods->seek64;
+ new_methods->fileInfo = my_methods->fileInfo;
+ new_methods->fileInfo64 = my_methods->fileInfo64;
+ new_methods->writev = my_methods->writev;
+ new_methods->connect = my_methods->connect;
+ new_methods->accept = my_methods->accept;
+ new_methods->bind = my_methods->bind;
+ new_methods->listen = my_methods->listen;
+ new_methods->shutdown = my_methods->shutdown;
+ new_methods->recv = my_methods->recv;
+ new_methods->send = my_methods->send;
+ new_methods->recvfrom = my_methods->recvfrom;
+ new_methods->sendto = my_methods->sendto;
+ new_methods->poll = my_methods->poll;
+ new_methods->acceptread = my_methods->acceptread;
+ new_methods->transmitfile = my_methods->transmitfile;
+ new_methods->getsockname = my_methods->getsockname;
+ new_methods->getpeername = my_methods->getpeername;
+/* new_methods->getsocketoption = my_methods->getsocketoption; */
+/* new_methods->setsocketoption = my_methods->setsocketoption; */
+ new_methods->sendfile = my_methods->sendfile;
+
+}
+
+static PRCallOnceType initIoLayerOnce;
+
+static PRStatus
+ssl_InitIOLayer(void)
+{
+ ssl_layer_id = PR_GetUniqueIdentity("SSL");
+ ssl_SetupIOMethods();
+ ssl_inited = PR_TRUE;
+ return PR_SUCCESS;
+}
+
+static PRStatus
+ssl_PushIOLayer(sslSocket *ns, PRFileDesc *stack, PRDescIdentity id)
+{
+ PRFileDesc *layer = NULL;
+ PRStatus status;
+
+ if (!ssl_inited) {
+ status = PR_CallOnce(&initIoLayerOnce, &ssl_InitIOLayer);
+ if (status != PR_SUCCESS)
+ goto loser;
+ }
+
+ if (ns == NULL)
+ goto loser;
+
+ layer = PR_CreateIOLayerStub(ssl_layer_id, &combined_methods);
+ if (layer == NULL)
+ goto loser;
+ layer->secret = (PRFilePrivate *)ns;
+
+ /* Here, "stack" points to the PRFileDesc on the top of the stack.
+ ** "layer" points to a new FD that is to be inserted into the stack.
+ ** If layer is being pushed onto the top of the stack, then
+ ** PR_PushIOLayer switches the contents of stack and layer, and then
+ ** puts stack on top of layer, so that after it is done, the top of
+ ** stack is the same "stack" as it was before, and layer is now the
+ ** FD for the former top of stack.
+ ** After this call, stack always points to the top PRFD on the stack.
+ ** If this function fails, the contents of stack and layer are as
+ ** they were before the call.
+ */
+ status = PR_PushIOLayer(stack, id, layer);
+ if (status != PR_SUCCESS)
+ goto loser;
+
+ ns->fd = (id == PR_TOP_IO_LAYER) ? stack : layer;
+ return PR_SUCCESS;
+
+loser:
+ if (layer) {
+ layer->dtor(layer); /* free layer */
+ }
+ return PR_FAILURE;
+}
+
+/* if this fails, caller must destroy socket. */
+static SECStatus
+ssl_MakeLocks(sslSocket *ss)
+{
+ ss->firstHandshakeLock = PZ_NewMonitor(nssILockSSL);
+ if (!ss->firstHandshakeLock)
+ goto loser;
+ ss->ssl3HandshakeLock = PZ_NewMonitor(nssILockSSL);
+ if (!ss->ssl3HandshakeLock)
+ goto loser;
+ ss->specLock = NSSRWLock_New(SSL_LOCK_RANK_SPEC, NULL);
+ if (!ss->specLock)
+ goto loser;
+ ss->recvBufLock = PZ_NewMonitor(nssILockSSL);
+ if (!ss->recvBufLock)
+ goto loser;
+ ss->xmitBufLock = PZ_NewMonitor(nssILockSSL);
+ if (!ss->xmitBufLock)
+ goto loser;
+ ss->writerThread = NULL;
+ if (ssl_lock_readers) {
+ ss->recvLock = PZ_NewLock(nssILockSSL);
+ if (!ss->recvLock)
+ goto loser;
+ ss->sendLock = PZ_NewLock(nssILockSSL);
+ if (!ss->sendLock)
+ goto loser;
+ }
+ return SECSuccess;
+loser:
+ ssl_DestroyLocks(ss);
+ return SECFailure;
+}
+
+#if defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_BEOS)
+#define NSS_HAVE_GETENV 1
+#endif
+
+#define LOWER(x) (x | 0x20) /* cheap ToLower function ignores LOCALE */
+
+static void
+ssl_SetDefaultsFromEnvironment(void)
+{
+#if defined( NSS_HAVE_GETENV )
+ static int firsttime = 1;
+
+ if (firsttime) {
+ char * ev;
+ firsttime = 0;
+#ifdef DEBUG
+ ev = getenv("SSLDEBUGFILE");
+ if (ev && ev[0]) {
+ ssl_trace_iob = fopen(ev, "w");
+ }
+ if (!ssl_trace_iob) {
+ ssl_trace_iob = stderr;
+ }
+#ifdef TRACE
+ ev = getenv("SSLTRACE");
+ if (ev && ev[0]) {
+ ssl_trace = atoi(ev);
+ SSL_TRACE(("SSL: tracing set to %d", ssl_trace));
+ }
+#endif /* TRACE */
+ ev = getenv("SSLDEBUG");
+ if (ev && ev[0]) {
+ ssl_debug = atoi(ev);
+ SSL_TRACE(("SSL: debugging set to %d", ssl_debug));
+ }
+#endif /* DEBUG */
+ ev = getenv("SSLKEYLOGFILE");
+ if (ev && ev[0]) {
+ ssl_keylog_iob = fopen(ev, "a");
+ if (!ssl_keylog_iob) {
+ SSL_TRACE(("SSL: failed to open key log file"));
+ } else {
+ if (ftell(ssl_keylog_iob) == 0) {
+ fputs("# SSL/TLS secrets log file, generated by NSS\n",
+ ssl_keylog_iob);
+ }
+ SSL_TRACE(("SSL: logging SSL/TLS secrets to %s", ev));
+ }
+ }
+#ifndef NO_PKCS11_BYPASS
+ ev = getenv("SSLBYPASS");
+ if (ev && ev[0]) {
+ ssl_defaults.bypassPKCS11 = (ev[0] == '1');
+ SSL_TRACE(("SSL: bypass default set to %d", \
+ ssl_defaults.bypassPKCS11));
+ }
+#endif /* NO_PKCS11_BYPASS */
+ ev = getenv("SSLFORCELOCKS");
+ if (ev && ev[0] == '1') {
+ ssl_force_locks = PR_TRUE;
+ ssl_defaults.noLocks = 0;
+ strcpy(lockStatus + LOCKSTATUS_OFFSET, "FORCED. ");
+ SSL_TRACE(("SSL: force_locks set to %d", ssl_force_locks));
+ }
+ ev = getenv("NSS_SSL_ENABLE_RENEGOTIATION");
+ if (ev) {
+ if (ev[0] == '1' || LOWER(ev[0]) == 'u')
+ ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_UNRESTRICTED;
+ else if (ev[0] == '0' || LOWER(ev[0]) == 'n')
+ ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_NEVER;
+ else if (ev[0] == '2' || LOWER(ev[0]) == 'r')
+ ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_REQUIRES_XTN;
+ else if (ev[0] == '3' || LOWER(ev[0]) == 't')
+ ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_TRANSITIONAL;
+ SSL_TRACE(("SSL: enableRenegotiation set to %d",
+ ssl_defaults.enableRenegotiation));
+ }
+ ev = getenv("NSS_SSL_REQUIRE_SAFE_NEGOTIATION");
+ if (ev && ev[0] == '1') {
+ ssl_defaults.requireSafeNegotiation = PR_TRUE;
+ SSL_TRACE(("SSL: requireSafeNegotiation set to %d",
+ PR_TRUE));
+ }
+ ev = getenv("NSS_SSL_CBC_RANDOM_IV");
+ if (ev && ev[0] == '0') {
+ ssl_defaults.cbcRandomIV = PR_FALSE;
+ SSL_TRACE(("SSL: cbcRandomIV set to 0"));
+ }
+ }
+#endif /* NSS_HAVE_GETENV */
+}
+
+/*
+** Create a newsocket structure for a file descriptor.
+*/
+static sslSocket *
+ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant)
+{
+ sslSocket *ss;
+
+ ssl_SetDefaultsFromEnvironment();
+
+ if (ssl_force_locks)
+ makeLocks = PR_TRUE;
+
+ /* Make a new socket and get it ready */
+ ss = (sslSocket*) PORT_ZAlloc(sizeof(sslSocket));
+ if (ss) {
+ /* This should be of type SSLKEAType, but CC on IRIX
+ * complains during the for loop.
+ */
+ int i;
+ SECStatus status;
+
+ ss->opt = ssl_defaults;
+ ss->opt.useSocks = PR_FALSE;
+ ss->opt.noLocks = !makeLocks;
+ ss->vrange = *VERSIONS_DEFAULTS(protocolVariant);
+ ss->protocolVariant = protocolVariant;
+
+ ss->peerID = NULL;
+ ss->rTimeout = PR_INTERVAL_NO_TIMEOUT;
+ ss->wTimeout = PR_INTERVAL_NO_TIMEOUT;
+ ss->cTimeout = PR_INTERVAL_NO_TIMEOUT;
+ ss->cipherSpecs = NULL;
+ ss->sizeCipherSpecs = 0; /* produced lazily */
+ ss->preferredCipher = NULL;
+ ss->url = NULL;
+
+ for (i=kt_null; i < kt_kea_size; i++) {
+ sslServerCerts * sc = ss->serverCerts + i;
+ sc->serverCert = NULL;
+ sc->serverCertChain = NULL;
+ sc->serverKeyPair = NULL;
+ sc->serverKeyBits = 0;
+ ss->certStatusArray[i] = NULL;
+ }
+ ss->requestedCertTypes = NULL;
+ ss->stepDownKeyPair = NULL;
+ ss->dbHandle = CERT_GetDefaultCertDB();
+
+ /* Provide default implementation of hooks */
+ ss->authCertificate = SSL_AuthCertificate;
+ ss->authCertificateArg = (void *)ss->dbHandle;
+ ss->sniSocketConfig = NULL;
+ ss->sniSocketConfigArg = NULL;
+ ss->getClientAuthData = NULL;
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ ss->getPlatformClientAuthData = NULL;
+ ss->getPlatformClientAuthDataArg = NULL;
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
+ ss->handleBadCert = NULL;
+ ss->badCertArg = NULL;
+ ss->pkcs11PinArg = NULL;
+ ss->ephemeralECDHKeyPair = NULL;
+ ss->getChannelID = NULL;
+ ss->getChannelIDArg = NULL;
+
+ ssl_ChooseOps(ss);
+ ssl2_InitSocketPolicy(ss);
+ ssl3_InitSocketPolicy(ss);
+ PR_INIT_CLIST(&ss->ssl3.hs.lastMessageFlight);
+
+ if (makeLocks) {
+ status = ssl_MakeLocks(ss);
+ if (status != SECSuccess)
+ goto loser;
+ }
+ status = ssl_CreateSecurityInfo(ss);
+ if (status != SECSuccess)
+ goto loser;
+ status = ssl_InitGather(&ss->gs);
+ if (status != SECSuccess) {
+loser:
+ ssl_DestroySocketContents(ss);
+ ssl_DestroyLocks(ss);
+ PORT_Free(ss);
+ ss = NULL;
+ }
+ }
+ return ss;
+}
+
diff --git a/chromium/net/third_party/nss/ssl/sslt.h b/chromium/net/third_party/nss/ssl/sslt.h
new file mode 100644
index 00000000000..f4be1743303
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslt.h
@@ -0,0 +1,208 @@
+/*
+ * This file contains prototypes for the public SSL functions.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __sslt_h_
+#define __sslt_h_
+
+#include "prtypes.h"
+
+/* SECItemArray is added in NSS 3.15. Define the type if compiling
+** against an older version of NSS.
+*/
+#include "nssutil.h"
+#if NSSUTIL_VMAJOR == 3 && NSSUTIL_VMINOR < 15
+typedef struct SECItemArrayStr SECItemArray;
+
+struct SECItemArrayStr {
+ SECItem *items;
+ unsigned int len;
+};
+#endif /* NSSUTIL_VMAJOR == 3 && NSSUTIL_VMINOR < 15 */
+
+typedef struct SSL3StatisticsStr {
+ /* statistics from ssl3_SendClientHello (sch) */
+ long sch_sid_cache_hits;
+ long sch_sid_cache_misses;
+ long sch_sid_cache_not_ok;
+
+ /* statistics from ssl3_HandleServerHello (hsh) */
+ long hsh_sid_cache_hits;
+ long hsh_sid_cache_misses;
+ long hsh_sid_cache_not_ok;
+
+ /* statistics from ssl3_HandleClientHello (hch) */
+ long hch_sid_cache_hits;
+ long hch_sid_cache_misses;
+ long hch_sid_cache_not_ok;
+
+ /* statistics related to stateless resume */
+ long sch_sid_stateless_resumes;
+ long hsh_sid_stateless_resumes;
+ long hch_sid_stateless_resumes;
+ long hch_sid_ticket_parse_failures;
+} SSL3Statistics;
+
+/* Key Exchange algorithm values */
+typedef enum {
+ ssl_kea_null = 0,
+ ssl_kea_rsa = 1,
+ ssl_kea_dh = 2,
+ ssl_kea_fortezza = 3, /* deprecated, now unused */
+ ssl_kea_ecdh = 4,
+ ssl_kea_size /* number of ssl_kea_ algorithms */
+} SSLKEAType;
+
+/* The following defines are for backwards compatibility.
+** They will be removed in a forthcoming release to reduce namespace pollution.
+** programs that use the kt_ symbols should convert to the ssl_kt_ symbols
+** soon.
+*/
+#define kt_null ssl_kea_null
+#define kt_rsa ssl_kea_rsa
+#define kt_dh ssl_kea_dh
+#define kt_fortezza ssl_kea_fortezza /* deprecated, now unused */
+#define kt_ecdh ssl_kea_ecdh
+#define kt_kea_size ssl_kea_size
+
+typedef enum {
+ ssl_sign_null = 0,
+ ssl_sign_rsa = 1,
+ ssl_sign_dsa = 2,
+ ssl_sign_ecdsa = 3
+} SSLSignType;
+
+typedef enum {
+ ssl_auth_null = 0,
+ ssl_auth_rsa = 1,
+ ssl_auth_dsa = 2,
+ ssl_auth_kea = 3,
+ ssl_auth_ecdsa = 4
+} SSLAuthType;
+
+typedef enum {
+ ssl_calg_null = 0,
+ ssl_calg_rc4 = 1,
+ ssl_calg_rc2 = 2,
+ ssl_calg_des = 3,
+ ssl_calg_3des = 4,
+ ssl_calg_idea = 5,
+ ssl_calg_fortezza = 6, /* deprecated, now unused */
+ ssl_calg_aes = 7,
+ ssl_calg_camellia = 8,
+ ssl_calg_seed = 9,
+ ssl_calg_aes_gcm = 10
+} SSLCipherAlgorithm;
+
+typedef enum {
+ ssl_mac_null = 0,
+ ssl_mac_md5 = 1,
+ ssl_mac_sha = 2,
+ ssl_hmac_md5 = 3, /* TLS HMAC version of mac_md5 */
+ ssl_hmac_sha = 4, /* TLS HMAC version of mac_sha */
+ ssl_hmac_sha256 = 5
+} SSLMACAlgorithm;
+
+typedef enum {
+ ssl_compression_null = 0,
+ ssl_compression_deflate = 1 /* RFC 3749 */
+} SSLCompressionMethod;
+
+typedef struct SSLChannelInfoStr {
+ PRUint32 length;
+ PRUint16 protocolVersion;
+ PRUint16 cipherSuite;
+
+ /* server authentication info */
+ PRUint32 authKeyBits;
+
+ /* key exchange algorithm info */
+ PRUint32 keaKeyBits;
+
+ /* session info */
+ PRUint32 creationTime; /* seconds since Jan 1, 1970 */
+ PRUint32 lastAccessTime; /* seconds since Jan 1, 1970 */
+ PRUint32 expirationTime; /* seconds since Jan 1, 1970 */
+ PRUint32 sessionIDLength; /* up to 32 */
+ PRUint8 sessionID [32];
+
+ /* The following fields are added in NSS 3.12.5. */
+
+ /* compression method info */
+ const char * compressionMethodName;
+ SSLCompressionMethod compressionMethod;
+} SSLChannelInfo;
+
+typedef struct SSLCipherSuiteInfoStr {
+ PRUint16 length;
+ PRUint16 cipherSuite;
+
+ /* Cipher Suite Name */
+ const char * cipherSuiteName;
+
+ /* server authentication info */
+ const char * authAlgorithmName;
+ SSLAuthType authAlgorithm;
+
+ /* key exchange algorithm info */
+ const char * keaTypeName;
+ SSLKEAType keaType;
+
+ /* symmetric encryption info */
+ const char * symCipherName;
+ SSLCipherAlgorithm symCipher;
+ PRUint16 symKeyBits;
+ PRUint16 symKeySpace;
+ PRUint16 effectiveKeyBits;
+
+ /* MAC info */
+ const char * macAlgorithmName;
+ SSLMACAlgorithm macAlgorithm;
+ PRUint16 macBits;
+
+ PRUintn isFIPS : 1;
+ PRUintn isExportable : 1;
+ PRUintn nonStandard : 1;
+ PRUintn reservedBits :29;
+
+} SSLCipherSuiteInfo;
+
+typedef enum {
+ ssl_variant_stream = 0,
+ ssl_variant_datagram = 1
+} SSLProtocolVariant;
+
+typedef struct SSLVersionRangeStr {
+ PRUint16 min;
+ PRUint16 max;
+} SSLVersionRange;
+
+typedef enum {
+ SSL_sni_host_name = 0,
+ SSL_sni_type_total
+} SSLSniNameType;
+
+/* Supported extensions. */
+/* Update SSL_MAX_EXTENSIONS whenever a new extension type is added. */
+typedef enum {
+ ssl_server_name_xtn = 0,
+ ssl_cert_status_xtn = 5,
+#ifdef NSS_ENABLE_ECC
+ ssl_elliptic_curves_xtn = 10,
+ ssl_ec_point_formats_xtn = 11,
+#endif
+ ssl_signature_algorithms_xtn = 13,
+ ssl_use_srtp_xtn = 14,
+ ssl_app_layer_protocol_xtn = 16,
+ ssl_session_ticket_xtn = 35,
+ ssl_next_proto_nego_xtn = 13172,
+ ssl_channel_id_xtn = 30031,
+ ssl_renegotiation_info_xtn = 0xff01 /* experimental number */
+} SSLExtensionType;
+
+#define SSL_MAX_EXTENSIONS 11
+
+#endif /* __sslt_h_ */
diff --git a/chromium/net/third_party/nss/ssl/ssltrace.c b/chromium/net/third_party/nss/ssl/ssltrace.c
new file mode 100644
index 00000000000..ee540d58751
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/ssltrace.c
@@ -0,0 +1,243 @@
+/*
+ * Functions to trace SSL protocol behavior in DEBUG builds.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include <stdarg.h>
+#include "cert.h"
+#include "ssl.h"
+#include "sslimpl.h"
+#include "sslproto.h"
+#include "prprf.h"
+
+#if defined(DEBUG) || defined(TRACE)
+static const char *hex = "0123456789abcdef";
+
+static const char printable[257] = {
+ "................" /* 0x */
+ "................" /* 1x */
+ " !\"#$%&'()*+,-./" /* 2x */
+ "0123456789:;<=>?" /* 3x */
+ "@ABCDEFGHIJKLMNO" /* 4x */
+ "PQRSTUVWXYZ[\\]^_" /* 5x */
+ "`abcdefghijklmno" /* 6x */
+ "pqrstuvwxyz{|}~." /* 7x */
+ "................" /* 8x */
+ "................" /* 9x */
+ "................" /* ax */
+ "................" /* bx */
+ "................" /* cx */
+ "................" /* dx */
+ "................" /* ex */
+ "................" /* fx */
+};
+
+void ssl_PrintBuf(sslSocket *ss, const char *msg, const void *vp, int len)
+{
+ const unsigned char *cp = (const unsigned char *)vp;
+ char buf[80];
+ char *bp;
+ char *ap;
+
+ if (ss) {
+ SSL_TRACE(("%d: SSL[%d]: %s [Len: %d]", SSL_GETPID(), ss->fd,
+ msg, len));
+ } else {
+ SSL_TRACE(("%d: SSL: %s [Len: %d]", SSL_GETPID(), msg, len));
+ }
+ memset(buf, ' ', sizeof buf);
+ bp = buf;
+ ap = buf + 50;
+ while (--len >= 0) {
+ unsigned char ch = *cp++;
+ *bp++ = hex[(ch >> 4) & 0xf];
+ *bp++ = hex[ch & 0xf];
+ *bp++ = ' ';
+ *ap++ = printable[ch];
+ if (ap - buf >= 66) {
+ *ap = 0;
+ SSL_TRACE((" %s", buf));
+ memset(buf, ' ', sizeof buf);
+ bp = buf;
+ ap = buf + 50;
+ }
+ }
+ if (bp > buf) {
+ *ap = 0;
+ SSL_TRACE((" %s", buf));
+ }
+}
+
+#define LEN(cp) (((cp)[0] << 8) | ((cp)[1]))
+
+static void PrintType(sslSocket *ss, char *msg)
+{
+ if (ss) {
+ SSL_TRACE(("%d: SSL[%d]: dump-msg: %s", SSL_GETPID(), ss->fd,
+ msg));
+ } else {
+ SSL_TRACE(("%d: SSL: dump-msg: %s", SSL_GETPID(), msg));
+ }
+}
+
+static void PrintInt(sslSocket *ss, char *msg, unsigned v)
+{
+ if (ss) {
+ SSL_TRACE(("%d: SSL[%d]: %s=%u", SSL_GETPID(), ss->fd,
+ msg, v));
+ } else {
+ SSL_TRACE(("%d: SSL: %s=%u", SSL_GETPID(), msg, v));
+ }
+}
+
+/* PrintBuf is just like ssl_PrintBuf above, except that:
+ * a) It prefixes each line of the buffer with "XX: SSL[xxx] "
+ * b) It dumps only hex, not ASCII.
+ */
+static void PrintBuf(sslSocket *ss, char *msg, unsigned char *cp, int len)
+{
+ char buf[80];
+ char *bp;
+
+ if (ss) {
+ SSL_TRACE(("%d: SSL[%d]: %s [Len: %d]",
+ SSL_GETPID(), ss->fd, msg, len));
+ } else {
+ SSL_TRACE(("%d: SSL: %s [Len: %d]",
+ SSL_GETPID(), msg, len));
+ }
+ bp = buf;
+ while (--len >= 0) {
+ unsigned char ch = *cp++;
+ *bp++ = hex[(ch >> 4) & 0xf];
+ *bp++ = hex[ch & 0xf];
+ *bp++ = ' ';
+ if (bp + 4 > buf + 50) {
+ *bp = 0;
+ if (ss) {
+ SSL_TRACE(("%d: SSL[%d]: %s",
+ SSL_GETPID(), ss->fd, buf));
+ } else {
+ SSL_TRACE(("%d: SSL: %s", SSL_GETPID(), buf));
+ }
+ bp = buf;
+ }
+ }
+ if (bp > buf) {
+ *bp = 0;
+ if (ss) {
+ SSL_TRACE(("%d: SSL[%d]: %s",
+ SSL_GETPID(), ss->fd, buf));
+ } else {
+ SSL_TRACE(("%d: SSL: %s", SSL_GETPID(), buf));
+ }
+ }
+}
+
+void ssl_DumpMsg(sslSocket *ss, unsigned char *bp, unsigned len)
+{
+ switch (bp[0]) {
+ case SSL_MT_ERROR:
+ PrintType(ss, "Error");
+ PrintInt(ss, "error", LEN(bp+1));
+ break;
+
+ case SSL_MT_CLIENT_HELLO:
+ {
+ unsigned lcs = LEN(bp+3);
+ unsigned ls = LEN(bp+5);
+ unsigned lc = LEN(bp+7);
+
+ PrintType(ss, "Client-Hello");
+
+ PrintInt(ss, "version (Major)", bp[1]);
+ PrintInt(ss, "version (minor)", bp[2]);
+
+ PrintBuf(ss, "cipher-specs", bp+9, lcs);
+ PrintBuf(ss, "session-id", bp+9+lcs, ls);
+ PrintBuf(ss, "challenge", bp+9+lcs+ls, lc);
+ }
+ break;
+ case SSL_MT_CLIENT_MASTER_KEY:
+ {
+ unsigned lck = LEN(bp+4);
+ unsigned lek = LEN(bp+6);
+ unsigned lka = LEN(bp+8);
+
+ PrintType(ss, "Client-Master-Key");
+
+ PrintInt(ss, "cipher-choice", bp[1]);
+ PrintInt(ss, "key-length", LEN(bp+2));
+
+ PrintBuf(ss, "clear-key", bp+10, lck);
+ PrintBuf(ss, "encrypted-key", bp+10+lck, lek);
+ PrintBuf(ss, "key-arg", bp+10+lck+lek, lka);
+ }
+ break;
+ case SSL_MT_CLIENT_FINISHED:
+ PrintType(ss, "Client-Finished");
+ PrintBuf(ss, "connection-id", bp+1, len-1);
+ break;
+ case SSL_MT_SERVER_HELLO:
+ {
+ unsigned lc = LEN(bp+5);
+ unsigned lcs = LEN(bp+7);
+ unsigned lci = LEN(bp+9);
+
+ PrintType(ss, "Server-Hello");
+
+ PrintInt(ss, "session-id-hit", bp[1]);
+ PrintInt(ss, "certificate-type", bp[2]);
+ PrintInt(ss, "version (Major)", bp[3]);
+ PrintInt(ss, "version (minor)", bp[3]);
+ PrintBuf(ss, "certificate", bp+11, lc);
+ PrintBuf(ss, "cipher-specs", bp+11+lc, lcs);
+ PrintBuf(ss, "connection-id", bp+11+lc+lcs, lci);
+ }
+ break;
+ case SSL_MT_SERVER_VERIFY:
+ PrintType(ss, "Server-Verify");
+ PrintBuf(ss, "challenge", bp+1, len-1);
+ break;
+ case SSL_MT_SERVER_FINISHED:
+ PrintType(ss, "Server-Finished");
+ PrintBuf(ss, "session-id", bp+1, len-1);
+ break;
+ case SSL_MT_REQUEST_CERTIFICATE:
+ PrintType(ss, "Request-Certificate");
+ PrintInt(ss, "authentication-type", bp[1]);
+ PrintBuf(ss, "certificate-challenge", bp+2, len-2);
+ break;
+ case SSL_MT_CLIENT_CERTIFICATE:
+ {
+ unsigned lc = LEN(bp+2);
+ unsigned lr = LEN(bp+4);
+ PrintType(ss, "Client-Certificate");
+ PrintInt(ss, "certificate-type", bp[1]);
+ PrintBuf(ss, "certificate", bp+6, lc);
+ PrintBuf(ss, "response", bp+6+lc, lr);
+ }
+ break;
+ default:
+ ssl_PrintBuf(ss, "sending *unknown* message type", bp, len);
+ return;
+ }
+}
+
+void
+ssl_Trace(const char *format, ... )
+{
+ char buf[2000];
+ va_list args;
+
+ if (ssl_trace_iob) {
+ va_start(args, format);
+ PR_vsnprintf(buf, sizeof(buf), format, args);
+ va_end(args);
+
+ fputs(buf, ssl_trace_iob);
+ fputs("\n", ssl_trace_iob);
+ }
+}
+#endif
diff --git a/chromium/net/third_party/nss/ssl/sslver.c b/chromium/net/third_party/nss/ssl/sslver.c
new file mode 100644
index 00000000000..35e0317eac2
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/sslver.c
@@ -0,0 +1,24 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Library identity and versioning */
+
+#include "nss.h"
+
+#if defined(DEBUG)
+#define _DEBUG_STRING " (debug)"
+#else
+#define _DEBUG_STRING ""
+#endif
+
+/*
+ * Version information for the 'ident' and 'what commands
+ *
+ * NOTE: the first component of the concatenated rcsid string
+ * must not end in a '$' to prevent rcs keyword substitution.
+ */
+const char __nss_ssl_rcsid[] = "$Header: NSS " NSS_VERSION _DEBUG_STRING
+ " " __DATE__ " " __TIME__ " $";
+const char __nss_ssl_sccsid[] = "@(#)NSS " NSS_VERSION _DEBUG_STRING
+ " " __DATE__ " " __TIME__;
diff --git a/chromium/net/third_party/nss/ssl/unix_err.c b/chromium/net/third_party/nss/ssl/unix_err.c
new file mode 100644
index 00000000000..1857cfefc70
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/unix_err.c
@@ -0,0 +1,517 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * This file essentially replicates NSPR's source for the functions that
+ * map system-specific error codes to NSPR error codes. We would use
+ * NSPR's functions, instead of duplicating them, but they're private.
+ * As long as SSL's server session cache code must do platform native I/O
+ * to accomplish its job, and NSPR's error mapping functions remain private,
+ * this code will continue to need to be replicated.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#if 0
+#include "primpl.h"
+#else
+#define _PR_POLL_AVAILABLE 1
+#include "prerror.h"
+#endif
+
+#if defined (__bsdi__) || defined(NTO) || defined(DARWIN) || defined(BEOS)
+#undef _PR_POLL_AVAILABLE
+#endif
+
+#if defined(_PR_POLL_AVAILABLE)
+#include <poll.h>
+#endif
+#include <errno.h>
+
+/* forward declarations. */
+void nss_MD_unix_map_default_error(int err);
+
+void nss_MD_unix_map_opendir_error(int err)
+{
+ nss_MD_unix_map_default_error(err);
+}
+
+void nss_MD_unix_map_closedir_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case EINVAL: prError = PR_BAD_DESCRIPTOR_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_readdir_error(int err)
+{
+ PRErrorCode prError;
+
+ switch (err) {
+ case ENOENT: prError = PR_NO_MORE_FILES_ERROR; break;
+#ifdef EOVERFLOW
+ case EOVERFLOW: prError = PR_IO_ERROR; break;
+#endif
+ case EINVAL: prError = PR_IO_ERROR; break;
+ case ENXIO: prError = PR_IO_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_unlink_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case EPERM: prError = PR_IS_DIRECTORY_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_stat_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case ETIMEDOUT: prError = PR_REMOTE_FILE_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_fstat_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case ETIMEDOUT: prError = PR_REMOTE_FILE_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_rename_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case EEXIST: prError = PR_DIRECTORY_NOT_EMPTY_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_access_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case ETIMEDOUT: prError = PR_REMOTE_FILE_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_mkdir_error(int err)
+{
+ nss_MD_unix_map_default_error(err);
+}
+
+void nss_MD_unix_map_rmdir_error(int err)
+{
+ PRErrorCode prError;
+
+ switch (err) {
+ case EEXIST: prError = PR_DIRECTORY_NOT_EMPTY_ERROR; break;
+ case EINVAL: prError = PR_DIRECTORY_NOT_EMPTY_ERROR; break;
+ case ETIMEDOUT: prError = PR_REMOTE_FILE_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_read_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case EINVAL: prError = PR_INVALID_METHOD_ERROR; break;
+ case ENXIO: prError = PR_INVALID_ARGUMENT_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_write_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case EINVAL: prError = PR_INVALID_METHOD_ERROR; break;
+ case ENXIO: prError = PR_INVALID_METHOD_ERROR; break;
+ case ETIMEDOUT: prError = PR_REMOTE_FILE_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_lseek_error(int err)
+{
+ nss_MD_unix_map_default_error(err);
+}
+
+void nss_MD_unix_map_fsync_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case ETIMEDOUT: prError = PR_REMOTE_FILE_ERROR; break;
+ case EINVAL: prError = PR_INVALID_METHOD_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_close_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case ETIMEDOUT: prError = PR_REMOTE_FILE_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_socket_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case ENOMEM: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_socketavailable_error(int err)
+{
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+}
+
+void nss_MD_unix_map_recv_error(int err)
+{
+ nss_MD_unix_map_default_error(err);
+}
+
+void nss_MD_unix_map_recvfrom_error(int err)
+{
+ nss_MD_unix_map_default_error(err);
+}
+
+void nss_MD_unix_map_send_error(int err)
+{
+ nss_MD_unix_map_default_error(err);
+}
+
+void nss_MD_unix_map_sendto_error(int err)
+{
+ nss_MD_unix_map_default_error(err);
+}
+
+void nss_MD_unix_map_writev_error(int err)
+{
+ nss_MD_unix_map_default_error(err);
+}
+
+void nss_MD_unix_map_accept_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case ENODEV: prError = PR_NOT_TCP_SOCKET_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_connect_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case EACCES: prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; break;
+#if defined(UNIXWARE) || defined(SNI) || defined(NEC)
+ /*
+ * On some platforms, if we connect to a port on the local host
+ * (the loopback address) that no process is listening on, we get
+ * EIO instead of ECONNREFUSED.
+ */
+ case EIO: prError = PR_CONNECT_REFUSED_ERROR; break;
+#endif
+ case ELOOP: prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; break;
+ case ENOENT: prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; break;
+ case ENXIO: prError = PR_IO_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_bind_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case EINVAL: prError = PR_SOCKET_ADDRESS_IS_BOUND_ERROR; break;
+ /*
+ * UNIX domain sockets are not supported in NSPR
+ */
+ case EIO: prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; break;
+ case EISDIR: prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; break;
+ case ELOOP: prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; break;
+ case ENOENT: prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; break;
+ case ENOTDIR: prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; break;
+ case EROFS: prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_listen_error(int err)
+{
+ nss_MD_unix_map_default_error(err);
+}
+
+void nss_MD_unix_map_shutdown_error(int err)
+{
+ nss_MD_unix_map_default_error(err);
+}
+
+void nss_MD_unix_map_socketpair_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case ENOMEM: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_getsockname_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case ENOMEM: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_getpeername_error(int err)
+{
+ PRErrorCode prError;
+
+ switch (err) {
+ case ENOMEM: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_getsockopt_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case EINVAL: prError = PR_BUFFER_OVERFLOW_ERROR; break;
+ case ENOMEM: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_setsockopt_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case EINVAL: prError = PR_BUFFER_OVERFLOW_ERROR; break;
+ case ENOMEM: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_open_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case EAGAIN: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ case EBUSY: prError = PR_IO_ERROR; break;
+ case ENODEV: prError = PR_FILE_NOT_FOUND_ERROR; break;
+ case ENOMEM: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ case ETIMEDOUT: prError = PR_REMOTE_FILE_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_mmap_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case EAGAIN: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ case EMFILE: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ case ENODEV: prError = PR_OPERATION_NOT_SUPPORTED_ERROR; break;
+ case ENXIO: prError = PR_INVALID_ARGUMENT_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_gethostname_error(int err)
+{
+ nss_MD_unix_map_default_error(err);
+}
+
+void nss_MD_unix_map_select_error(int err)
+{
+ nss_MD_unix_map_default_error(err);
+}
+
+#ifdef _PR_POLL_AVAILABLE
+void nss_MD_unix_map_poll_error(int err)
+{
+ PRErrorCode prError;
+
+ switch (err) {
+ case EAGAIN: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_poll_revents_error(int err)
+{
+ if (err & POLLNVAL)
+ PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF);
+ else if (err & POLLHUP)
+ PR_SetError(PR_CONNECT_RESET_ERROR, EPIPE);
+ else if (err & POLLERR)
+ PR_SetError(PR_IO_ERROR, EIO);
+ else
+ PR_SetError(PR_UNKNOWN_ERROR, err);
+}
+#endif /* _PR_POLL_AVAILABLE */
+
+
+void nss_MD_unix_map_flock_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case EINVAL: prError = PR_BAD_DESCRIPTOR_ERROR; break;
+ case EWOULDBLOCK: prError = PR_FILE_IS_LOCKED_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_unix_map_lockf_error(int err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case EACCES: prError = PR_FILE_IS_LOCKED_ERROR; break;
+ case EDEADLK: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ default: nss_MD_unix_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+#ifdef HPUX11
+void nss_MD_hpux_map_sendfile_error(int err)
+{
+ nss_MD_unix_map_default_error(err);
+}
+#endif /* HPUX11 */
+
+
+void nss_MD_unix_map_default_error(int err)
+{
+ PRErrorCode prError;
+ switch (err ) {
+ case EACCES: prError = PR_NO_ACCESS_RIGHTS_ERROR; break;
+ case EADDRINUSE: prError = PR_ADDRESS_IN_USE_ERROR; break;
+ case EADDRNOTAVAIL: prError = PR_ADDRESS_NOT_AVAILABLE_ERROR; break;
+ case EAFNOSUPPORT: prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; break;
+ case EAGAIN: prError = PR_WOULD_BLOCK_ERROR; break;
+ /*
+ * On QNX and Neutrino, EALREADY is defined as EBUSY.
+ */
+#if EALREADY != EBUSY
+ case EALREADY: prError = PR_ALREADY_INITIATED_ERROR; break;
+#endif
+ case EBADF: prError = PR_BAD_DESCRIPTOR_ERROR; break;
+#ifdef EBADMSG
+ case EBADMSG: prError = PR_IO_ERROR; break;
+#endif
+ case EBUSY: prError = PR_FILESYSTEM_MOUNTED_ERROR; break;
+ case ECONNREFUSED: prError = PR_CONNECT_REFUSED_ERROR; break;
+ case ECONNRESET: prError = PR_CONNECT_RESET_ERROR; break;
+ case EDEADLK: prError = PR_DEADLOCK_ERROR; break;
+#ifdef EDIRCORRUPTED
+ case EDIRCORRUPTED: prError = PR_DIRECTORY_CORRUPTED_ERROR; break;
+#endif
+#ifdef EDQUOT
+ case EDQUOT: prError = PR_NO_DEVICE_SPACE_ERROR; break;
+#endif
+ case EEXIST: prError = PR_FILE_EXISTS_ERROR; break;
+ case EFAULT: prError = PR_ACCESS_FAULT_ERROR; break;
+ case EFBIG: prError = PR_FILE_TOO_BIG_ERROR; break;
+ case EINPROGRESS: prError = PR_IN_PROGRESS_ERROR; break;
+ case EINTR: prError = PR_PENDING_INTERRUPT_ERROR; break;
+ case EINVAL: prError = PR_INVALID_ARGUMENT_ERROR; break;
+ case EIO: prError = PR_IO_ERROR; break;
+ case EISCONN: prError = PR_IS_CONNECTED_ERROR; break;
+ case EISDIR: prError = PR_IS_DIRECTORY_ERROR; break;
+ case ELOOP: prError = PR_LOOP_ERROR; break;
+ case EMFILE: prError = PR_PROC_DESC_TABLE_FULL_ERROR; break;
+ case EMLINK: prError = PR_MAX_DIRECTORY_ENTRIES_ERROR; break;
+ case EMSGSIZE: prError = PR_INVALID_ARGUMENT_ERROR; break;
+#ifdef EMULTIHOP
+ case EMULTIHOP: prError = PR_REMOTE_FILE_ERROR; break;
+#endif
+ case ENAMETOOLONG: prError = PR_NAME_TOO_LONG_ERROR; break;
+ case ENETUNREACH: prError = PR_NETWORK_UNREACHABLE_ERROR; break;
+ case ENFILE: prError = PR_SYS_DESC_TABLE_FULL_ERROR; break;
+#if !defined(SCO)
+ case ENOBUFS: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+#endif
+ case ENODEV: prError = PR_FILE_NOT_FOUND_ERROR; break;
+ case ENOENT: prError = PR_FILE_NOT_FOUND_ERROR; break;
+ case ENOLCK: prError = PR_FILE_IS_LOCKED_ERROR; break;
+#ifdef ENOLINK
+ case ENOLINK: prError = PR_REMOTE_FILE_ERROR; break;
+#endif
+ case ENOMEM: prError = PR_OUT_OF_MEMORY_ERROR; break;
+ case ENOPROTOOPT: prError = PR_INVALID_ARGUMENT_ERROR; break;
+ case ENOSPC: prError = PR_NO_DEVICE_SPACE_ERROR; break;
+#ifdef ENOSR
+ case ENOSR: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+#endif
+ case ENOTCONN: prError = PR_NOT_CONNECTED_ERROR; break;
+ case ENOTDIR: prError = PR_NOT_DIRECTORY_ERROR; break;
+ case ENOTSOCK: prError = PR_NOT_SOCKET_ERROR; break;
+ case ENXIO: prError = PR_FILE_NOT_FOUND_ERROR; break;
+ case EOPNOTSUPP: prError = PR_NOT_TCP_SOCKET_ERROR; break;
+#ifdef EOVERFLOW
+ case EOVERFLOW: prError = PR_BUFFER_OVERFLOW_ERROR; break;
+#endif
+ case EPERM: prError = PR_NO_ACCESS_RIGHTS_ERROR; break;
+ case EPIPE: prError = PR_CONNECT_RESET_ERROR; break;
+#ifdef EPROTO
+ case EPROTO: prError = PR_IO_ERROR; break;
+#endif
+ case EPROTONOSUPPORT: prError = PR_PROTOCOL_NOT_SUPPORTED_ERROR; break;
+ case EPROTOTYPE: prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; break;
+ case ERANGE: prError = PR_INVALID_METHOD_ERROR; break;
+ case EROFS: prError = PR_READ_ONLY_FILESYSTEM_ERROR; break;
+ case ESPIPE: prError = PR_INVALID_METHOD_ERROR; break;
+ case ETIMEDOUT: prError = PR_IO_TIMEOUT_ERROR; break;
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK: prError = PR_WOULD_BLOCK_ERROR; break;
+#endif
+ case EXDEV: prError = PR_NOT_SAME_DEVICE_ERROR; break;
+
+ default: prError = PR_UNKNOWN_ERROR; break;
+ }
+ PR_SetError(prError, err);
+}
diff --git a/chromium/net/third_party/nss/ssl/unix_err.h b/chromium/net/third_party/nss/ssl/unix_err.h
new file mode 100644
index 00000000000..be7fe292178
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/unix_err.h
@@ -0,0 +1,57 @@
+/*
+ * This file essentially replicates NSPR's source for the functions that
+ * map system-specific error codes to NSPR error codes. We would use
+ * NSPR's functions, instead of duplicating them, but they're private.
+ * As long as SSL's server session cache code must do platform native I/O
+ * to accomplish its job, and NSPR's error mapping functions remain private,
+ * this code will continue to need to be replicated.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* NSPR doesn't make these functions public, so we have to duplicate
+** them in NSS.
+*/
+extern void nss_MD_hpux_map_sendfile_error(int err);
+extern void nss_MD_unix_map_accept_error(int err);
+extern void nss_MD_unix_map_access_error(int err);
+extern void nss_MD_unix_map_bind_error(int err);
+extern void nss_MD_unix_map_close_error(int err);
+extern void nss_MD_unix_map_closedir_error(int err);
+extern void nss_MD_unix_map_connect_error(int err);
+extern void nss_MD_unix_map_default_error(int err);
+extern void nss_MD_unix_map_flock_error(int err);
+extern void nss_MD_unix_map_fstat_error(int err);
+extern void nss_MD_unix_map_fsync_error(int err);
+extern void nss_MD_unix_map_gethostname_error(int err);
+extern void nss_MD_unix_map_getpeername_error(int err);
+extern void nss_MD_unix_map_getsockname_error(int err);
+extern void nss_MD_unix_map_getsockopt_error(int err);
+extern void nss_MD_unix_map_listen_error(int err);
+extern void nss_MD_unix_map_lockf_error(int err);
+extern void nss_MD_unix_map_lseek_error(int err);
+extern void nss_MD_unix_map_mkdir_error(int err);
+extern void nss_MD_unix_map_mmap_error(int err);
+extern void nss_MD_unix_map_open_error(int err);
+extern void nss_MD_unix_map_opendir_error(int err);
+extern void nss_MD_unix_map_poll_error(int err);
+extern void nss_MD_unix_map_poll_revents_error(int err);
+extern void nss_MD_unix_map_read_error(int err);
+extern void nss_MD_unix_map_readdir_error(int err);
+extern void nss_MD_unix_map_recv_error(int err);
+extern void nss_MD_unix_map_recvfrom_error(int err);
+extern void nss_MD_unix_map_rename_error(int err);
+extern void nss_MD_unix_map_rmdir_error(int err);
+extern void nss_MD_unix_map_select_error(int err);
+extern void nss_MD_unix_map_send_error(int err);
+extern void nss_MD_unix_map_sendto_error(int err);
+extern void nss_MD_unix_map_setsockopt_error(int err);
+extern void nss_MD_unix_map_shutdown_error(int err);
+extern void nss_MD_unix_map_socket_error(int err);
+extern void nss_MD_unix_map_socketavailable_error(int err);
+extern void nss_MD_unix_map_socketpair_error(int err);
+extern void nss_MD_unix_map_stat_error(int err);
+extern void nss_MD_unix_map_unlink_error(int err);
+extern void nss_MD_unix_map_write_error(int err);
+extern void nss_MD_unix_map_writev_error(int err);
diff --git a/chromium/net/third_party/nss/ssl/win32err.c b/chromium/net/third_party/nss/ssl/win32err.c
new file mode 100644
index 00000000000..a70010d370a
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/win32err.c
@@ -0,0 +1,343 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * This file essentially replicates NSPR's source for the functions that
+ * map system-specific error codes to NSPR error codes. We would use
+ * NSPR's functions, instead of duplicating them, but they're private.
+ * As long as SSL's server session cache code must do platform native I/O
+ * to accomplish its job, and NSPR's error mapping functions remain private,
+ * this code will continue to need to be replicated.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prerror.h"
+#include "prlog.h"
+#include <errno.h>
+#include <windows.h>
+
+/*
+ * On Win32, we map three kinds of error codes:
+ * - GetLastError(): for Win32 functions
+ * - WSAGetLastError(): for Winsock functions
+ * - errno: for standard C library functions
+ *
+ * We do not check for WSAEINPROGRESS and WSAEINTR because we do not
+ * use blocking Winsock 1.1 calls.
+ *
+ * Except for the 'socket' call, we do not check for WSAEINITIALISED.
+ * It is assumed that if Winsock is not initialized, that fact will
+ * be detected at the time we create new sockets.
+ */
+
+/* forward declaration. */
+void nss_MD_win32_map_default_error(PRInt32 err);
+
+void nss_MD_win32_map_opendir_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_closedir_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_readdir_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_delete_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+/* The error code for stat() is in errno. */
+void nss_MD_win32_map_stat_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_fstat_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_rename_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+/* The error code for access() is in errno. */
+void nss_MD_win32_map_access_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_mkdir_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_rmdir_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_read_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_transmitfile_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_write_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_lseek_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_fsync_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+/*
+ * For both CloseHandle() and closesocket().
+ */
+void nss_MD_win32_map_close_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_socket_error(PRInt32 err)
+{
+ PR_ASSERT(err != WSANOTINITIALISED);
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_recv_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_recvfrom_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_send_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case WSAEMSGSIZE: prError = PR_INVALID_ARGUMENT_ERROR; break;
+ default: nss_MD_win32_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_win32_map_sendto_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case WSAEMSGSIZE: prError = PR_INVALID_ARGUMENT_ERROR; break;
+ default: nss_MD_win32_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_win32_map_accept_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case WSAEOPNOTSUPP: prError = PR_NOT_TCP_SOCKET_ERROR; break;
+ case WSAEINVAL: prError = PR_INVALID_STATE_ERROR; break;
+ default: nss_MD_win32_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_win32_map_acceptex_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_connect_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case WSAEWOULDBLOCK: prError = PR_IN_PROGRESS_ERROR; break;
+ case WSAEINVAL: prError = PR_ALREADY_INITIATED_ERROR; break;
+ case WSAETIMEDOUT: prError = PR_IO_TIMEOUT_ERROR; break;
+ default: nss_MD_win32_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_win32_map_bind_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case WSAEINVAL: prError = PR_SOCKET_ADDRESS_IS_BOUND_ERROR; break;
+ default: nss_MD_win32_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_win32_map_listen_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case WSAEOPNOTSUPP: prError = PR_NOT_TCP_SOCKET_ERROR; break;
+ case WSAEINVAL: prError = PR_INVALID_STATE_ERROR; break;
+ default: nss_MD_win32_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_win32_map_shutdown_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_getsockname_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case WSAEINVAL: prError = PR_INVALID_STATE_ERROR; break;
+ default: nss_MD_win32_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_win32_map_getpeername_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_getsockopt_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_setsockopt_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_open_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+void nss_MD_win32_map_gethostname_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+/* Win32 select() only works on sockets. So in this
+** context, WSAENOTSOCK is equivalent to EBADF on Unix.
+*/
+void nss_MD_win32_map_select_error(PRInt32 err)
+{
+ PRErrorCode prError;
+ switch (err) {
+ case WSAENOTSOCK: prError = PR_BAD_DESCRIPTOR_ERROR; break;
+ default: nss_MD_win32_map_default_error(err); return;
+ }
+ PR_SetError(prError, err);
+}
+
+void nss_MD_win32_map_lockf_error(PRInt32 err)
+{
+ nss_MD_win32_map_default_error(err);
+}
+
+
+
+void nss_MD_win32_map_default_error(PRInt32 err)
+{
+ PRErrorCode prError;
+
+ switch (err) {
+ case EACCES: prError = PR_NO_ACCESS_RIGHTS_ERROR; break;
+ case ENOENT: prError = PR_FILE_NOT_FOUND_ERROR; break;
+ case ERROR_ACCESS_DENIED: prError = PR_NO_ACCESS_RIGHTS_ERROR; break;
+ case ERROR_ALREADY_EXISTS: prError = PR_FILE_EXISTS_ERROR; break;
+ case ERROR_DISK_CORRUPT: prError = PR_IO_ERROR; break;
+ case ERROR_DISK_FULL: prError = PR_NO_DEVICE_SPACE_ERROR; break;
+ case ERROR_DISK_OPERATION_FAILED: prError = PR_IO_ERROR; break;
+ case ERROR_DRIVE_LOCKED: prError = PR_FILE_IS_LOCKED_ERROR; break;
+ case ERROR_FILENAME_EXCED_RANGE: prError = PR_NAME_TOO_LONG_ERROR; break;
+ case ERROR_FILE_CORRUPT: prError = PR_IO_ERROR; break;
+ case ERROR_FILE_EXISTS: prError = PR_FILE_EXISTS_ERROR; break;
+ case ERROR_FILE_INVALID: prError = PR_BAD_DESCRIPTOR_ERROR; break;
+#if ERROR_FILE_NOT_FOUND != ENOENT
+ case ERROR_FILE_NOT_FOUND: prError = PR_FILE_NOT_FOUND_ERROR; break;
+#endif
+ case ERROR_HANDLE_DISK_FULL: prError = PR_NO_DEVICE_SPACE_ERROR; break;
+ case ERROR_INVALID_ADDRESS: prError = PR_ACCESS_FAULT_ERROR; break;
+ case ERROR_INVALID_HANDLE: prError = PR_BAD_DESCRIPTOR_ERROR; break;
+ case ERROR_INVALID_NAME: prError = PR_INVALID_ARGUMENT_ERROR; break;
+ case ERROR_INVALID_PARAMETER: prError = PR_INVALID_ARGUMENT_ERROR; break;
+ case ERROR_INVALID_USER_BUFFER: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ case ERROR_LOCKED: prError = PR_FILE_IS_LOCKED_ERROR; break;
+ case ERROR_NETNAME_DELETED: prError = PR_CONNECT_RESET_ERROR; break;
+ case ERROR_NOACCESS: prError = PR_ACCESS_FAULT_ERROR; break;
+ case ERROR_NOT_ENOUGH_MEMORY: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ case ERROR_NOT_ENOUGH_QUOTA: prError = PR_OUT_OF_MEMORY_ERROR; break;
+ case ERROR_NOT_READY: prError = PR_IO_ERROR; break;
+ case ERROR_NO_MORE_FILES: prError = PR_NO_MORE_FILES_ERROR; break;
+ case ERROR_OPEN_FAILED: prError = PR_IO_ERROR; break;
+ case ERROR_OPEN_FILES: prError = PR_IO_ERROR; break;
+ case ERROR_OUTOFMEMORY: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ case ERROR_PATH_BUSY: prError = PR_IO_ERROR; break;
+ case ERROR_PATH_NOT_FOUND: prError = PR_FILE_NOT_FOUND_ERROR; break;
+ case ERROR_SEEK_ON_DEVICE: prError = PR_IO_ERROR; break;
+ case ERROR_SHARING_VIOLATION: prError = PR_FILE_IS_BUSY_ERROR; break;
+ case ERROR_STACK_OVERFLOW: prError = PR_ACCESS_FAULT_ERROR; break;
+ case ERROR_TOO_MANY_OPEN_FILES: prError = PR_SYS_DESC_TABLE_FULL_ERROR; break;
+ case ERROR_WRITE_PROTECT: prError = PR_NO_ACCESS_RIGHTS_ERROR; break;
+ case WSAEACCES: prError = PR_NO_ACCESS_RIGHTS_ERROR; break;
+ case WSAEADDRINUSE: prError = PR_ADDRESS_IN_USE_ERROR; break;
+ case WSAEADDRNOTAVAIL: prError = PR_ADDRESS_NOT_AVAILABLE_ERROR; break;
+ case WSAEAFNOSUPPORT: prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; break;
+ case WSAEALREADY: prError = PR_ALREADY_INITIATED_ERROR; break;
+ case WSAEBADF: prError = PR_BAD_DESCRIPTOR_ERROR; break;
+ case WSAECONNABORTED: prError = PR_CONNECT_ABORTED_ERROR; break;
+ case WSAECONNREFUSED: prError = PR_CONNECT_REFUSED_ERROR; break;
+ case WSAECONNRESET: prError = PR_CONNECT_RESET_ERROR; break;
+ case WSAEDESTADDRREQ: prError = PR_INVALID_ARGUMENT_ERROR; break;
+ case WSAEFAULT: prError = PR_ACCESS_FAULT_ERROR; break;
+ case WSAEHOSTUNREACH: prError = PR_HOST_UNREACHABLE_ERROR; break;
+ case WSAEINVAL: prError = PR_INVALID_ARGUMENT_ERROR; break;
+ case WSAEISCONN: prError = PR_IS_CONNECTED_ERROR; break;
+ case WSAEMFILE: prError = PR_PROC_DESC_TABLE_FULL_ERROR; break;
+ case WSAEMSGSIZE: prError = PR_BUFFER_OVERFLOW_ERROR; break;
+ case WSAENETDOWN: prError = PR_NETWORK_DOWN_ERROR; break;
+ case WSAENETRESET: prError = PR_CONNECT_ABORTED_ERROR; break;
+ case WSAENETUNREACH: prError = PR_NETWORK_UNREACHABLE_ERROR; break;
+ case WSAENOBUFS: prError = PR_INSUFFICIENT_RESOURCES_ERROR; break;
+ case WSAENOPROTOOPT: prError = PR_INVALID_ARGUMENT_ERROR; break;
+ case WSAENOTCONN: prError = PR_NOT_CONNECTED_ERROR; break;
+ case WSAENOTSOCK: prError = PR_NOT_SOCKET_ERROR; break;
+ case WSAEOPNOTSUPP: prError = PR_OPERATION_NOT_SUPPORTED_ERROR; break;
+ case WSAEPROTONOSUPPORT: prError = PR_PROTOCOL_NOT_SUPPORTED_ERROR; break;
+ case WSAEPROTOTYPE: prError = PR_INVALID_ARGUMENT_ERROR; break;
+ case WSAESHUTDOWN: prError = PR_SOCKET_SHUTDOWN_ERROR; break;
+ case WSAESOCKTNOSUPPORT: prError = PR_INVALID_ARGUMENT_ERROR; break;
+ case WSAETIMEDOUT: prError = PR_CONNECT_ABORTED_ERROR; break;
+ case WSAEWOULDBLOCK: prError = PR_WOULD_BLOCK_ERROR; break;
+ default: prError = PR_UNKNOWN_ERROR; break;
+ }
+ PR_SetError(prError, err);
+}
+
diff --git a/chromium/net/third_party/nss/ssl/win32err.h b/chromium/net/third_party/nss/ssl/win32err.h
new file mode 100644
index 00000000000..8ce588ec5a1
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/win32err.h
@@ -0,0 +1,51 @@
+/*
+ * This file essentially replicates NSPR's source for the functions that
+ * map system-specific error codes to NSPR error codes. We would use
+ * NSPR's functions, instead of duplicating them, but they're private.
+ * As long as SSL's server session cache code must do platform native I/O
+ * to accomplish its job, and NSPR's error mapping functions remain private,
+ * This code will continue to need to be replicated.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* NSPR doesn't make these functions public, so we have to duplicate
+** them in NSS.
+*/
+extern void nss_MD_win32_map_accept_error(PRInt32 err);
+extern void nss_MD_win32_map_acceptex_error(PRInt32 err);
+extern void nss_MD_win32_map_access_error(PRInt32 err);
+extern void nss_MD_win32_map_bind_error(PRInt32 err);
+extern void nss_MD_win32_map_close_error(PRInt32 err);
+extern void nss_MD_win32_map_closedir_error(PRInt32 err);
+extern void nss_MD_win32_map_connect_error(PRInt32 err);
+extern void nss_MD_win32_map_default_error(PRInt32 err);
+extern void nss_MD_win32_map_delete_error(PRInt32 err);
+extern void nss_MD_win32_map_fstat_error(PRInt32 err);
+extern void nss_MD_win32_map_fsync_error(PRInt32 err);
+extern void nss_MD_win32_map_gethostname_error(PRInt32 err);
+extern void nss_MD_win32_map_getpeername_error(PRInt32 err);
+extern void nss_MD_win32_map_getsockname_error(PRInt32 err);
+extern void nss_MD_win32_map_getsockopt_error(PRInt32 err);
+extern void nss_MD_win32_map_listen_error(PRInt32 err);
+extern void nss_MD_win32_map_lockf_error(PRInt32 err);
+extern void nss_MD_win32_map_lseek_error(PRInt32 err);
+extern void nss_MD_win32_map_mkdir_error(PRInt32 err);
+extern void nss_MD_win32_map_open_error(PRInt32 err);
+extern void nss_MD_win32_map_opendir_error(PRInt32 err);
+extern void nss_MD_win32_map_read_error(PRInt32 err);
+extern void nss_MD_win32_map_readdir_error(PRInt32 err);
+extern void nss_MD_win32_map_recv_error(PRInt32 err);
+extern void nss_MD_win32_map_recvfrom_error(PRInt32 err);
+extern void nss_MD_win32_map_rename_error(PRInt32 err);
+extern void nss_MD_win32_map_rmdir_error(PRInt32 err);
+extern void nss_MD_win32_map_select_error(PRInt32 err);
+extern void nss_MD_win32_map_send_error(PRInt32 err);
+extern void nss_MD_win32_map_sendto_error(PRInt32 err);
+extern void nss_MD_win32_map_setsockopt_error(PRInt32 err);
+extern void nss_MD_win32_map_shutdown_error(PRInt32 err);
+extern void nss_MD_win32_map_socket_error(PRInt32 err);
+extern void nss_MD_win32_map_stat_error(PRInt32 err);
+extern void nss_MD_win32_map_transmitfile_error(PRInt32 err);
+extern void nss_MD_win32_map_write_error(PRInt32 err);