Bug 1385146 - Experimental API, r=ekr
--- a/gtests/ssl_gtest/manifest.mn
+++ b/gtests/ssl_gtest/manifest.mn
@@ -25,16 +25,17 @@ CPPSRCS = \
ssl_exporter_unittest.cc \
ssl_extension_unittest.cc \
ssl_fragment_unittest.cc \
ssl_fuzz_unittest.cc \
ssl_gather_unittest.cc \
ssl_gtest.cc \
ssl_hrr_unittest.cc \
ssl_loopback_unittest.cc \
+ ssl_misc_unittest.cc \
ssl_record_unittest.cc \
ssl_resumption_unittest.cc \
ssl_skip_unittest.cc \
ssl_staticrsa_unittest.cc \
ssl_v2_client_hello_unittest.cc \
ssl_version_unittest.cc \
ssl_versionpolicy_unittest.cc \
selfencrypt_unittest.cc \
--- a/gtests/ssl_gtest/ssl_0rtt_unittest.cc
+++ b/gtests/ssl_gtest/ssl_0rtt_unittest.cc
@@ -2,16 +2,17 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* 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 "secerr.h"
#include "ssl.h"
#include "sslerr.h"
+#include "sslexp.h"
#include "sslproto.h"
extern "C" {
// This is not something that should make you happy.
#include "libssl_internals.h"
}
#include "gtest_utils.h"
--- a/gtests/ssl_gtest/ssl_gtest.gyp
+++ b/gtests/ssl_gtest/ssl_gtest.gyp
@@ -26,16 +26,17 @@
'ssl_exporter_unittest.cc',
'ssl_extension_unittest.cc',
'ssl_fuzz_unittest.cc',
'ssl_fragment_unittest.cc',
'ssl_gather_unittest.cc',
'ssl_gtest.cc',
'ssl_hrr_unittest.cc',
'ssl_loopback_unittest.cc',
+ 'ssl_misc_unittest.cc',
'ssl_record_unittest.cc',
'ssl_resumption_unittest.cc',
'ssl_skip_unittest.cc',
'ssl_staticrsa_unittest.cc',
'ssl_v2_client_hello_unittest.cc',
'ssl_version_unittest.cc',
'ssl_versionpolicy_unittest.cc',
'test_io.cc',
new file mode 100644
--- /dev/null
+++ b/gtests/ssl_gtest/ssl_misc_unittest.cc
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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 "sslexp.h"
+
+#include "gtest_utils.h"
+
+namespace nss_test {
+
+class MiscTest : public ::testing::Test {};
+
+TEST_F(MiscTest, NonExistentExperimentalAPI) {
+ EXPECT_EQ(nullptr, SSL_GetExperimentalAPI("blah"));
+ EXPECT_EQ(SSL_ERROR_UNSUPPORTED_EXPERIMENTAL_API, PORT_GetError());
+}
+
+} // namespace nss_test
--- a/gtests/ssl_gtest/tls_connect.cc
+++ b/gtests/ssl_gtest/tls_connect.cc
@@ -1,15 +1,16 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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 "tls_connect.h"
+#include "sslexp.h"
extern "C" {
#include "libssl_internals.h"
}
#include <iostream>
#include "databuffer.h"
#include "gtest_utils.h"
--- a/lib/ssl/SSLerrs.h
+++ b/lib/ssl/SSLerrs.h
@@ -506,8 +506,17 @@ ER3(SSL_ERROR_MALFORMED_PSK_KEY_EXCHANGE
ER3(SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES, (SSL_ERROR_BASE + 159),
"SSL expected a PSK key exchange modes extension.")
ER3(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA, (SSL_ERROR_BASE + 160),
"SSL got a pre-TLS 1.3 version even though we sent early data.")
ER3(SSL_ERROR_TOO_MUCH_EARLY_DATA, (SSL_ERROR_BASE + 161),
"SSL received more early data than permitted.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_END_OF_EARLY_DATA, (SSL_ERROR_BASE + 162),
+ "SSL received an unexpected End of Early Data message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_END_OF_EARLY_DATA, (SSL_ERROR_BASE + 163),
+ "SSL received a malformed End of Early Data message.")
+
+ER3(SSL_ERROR_UNSUPPORTED_EXPERIMENTAL_API, (SSL_ERROR_BASE + 164),
+ "An experimental API was called, but not supported.")
--- a/lib/ssl/exports.gyp
+++ b/lib/ssl/exports.gyp
@@ -10,16 +10,17 @@
'target_name': 'lib_ssl_exports',
'type': 'none',
'copies': [
{
'files': [
'preenc.h',
'ssl.h',
'sslerr.h',
+ 'sslexp.h',
'sslproto.h',
'sslt.h'
],
'destination': '<(nss_public_dist_dir)/<(module)'
}
]
}
],
--- a/lib/ssl/manifest.mn
+++ b/lib/ssl/manifest.mn
@@ -5,16 +5,17 @@
CORE_DEPTH = ../..
# DEFINES = -DTRACE
EXPORTS = \
ssl.h \
sslt.h \
sslerr.h \
+ sslexp.h \
sslproto.h \
preenc.h \
$(NULL)
MODULE = nss
MAPFILE = $(OBJDIR)/ssl.def
CSRCS = \
--- a/lib/ssl/ssl.def
+++ b/lib/ssl/ssl.def
@@ -229,8 +229,14 @@ SSL_SetSessionTicketKeyPair;
;+};
;+NSS_3.30.0.1 { # Additional symbols for NSS 3.30 release
;+ global:
SSL_AlertReceivedCallback;
SSL_AlertSentCallback;
;+ local:
;+*;
;+};
+;+NSS_3.33 { # NSS 3.33 release
+;+ global:
+SSL_GetExperimentalAPI;
+;+ local:
+;+*;
+;+};
--- a/lib/ssl/ssl.h
+++ b/lib/ssl/ssl.h
@@ -1369,11 +1369,18 @@ extern const char *NSSSSL_GetVersion(voi
* 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);
+
+/*
+ * This is used to access experimental APIs. Don't call this directly. This is
+ * used to enable the experimental APIs that are defined in "sslexp.h".
+ */
+SSL_IMPORT void *SSL_GetExperimentalAPI(const char *name);
+
SEC_END_PROTOS
#endif /* __ssl_h_ */
--- a/lib/ssl/sslerr.h
+++ b/lib/ssl/sslerr.h
@@ -241,15 +241,20 @@ typedef enum {
SSL_ERROR_RX_UNEXPECTED_HELLO_RETRY_REQUEST = (SSL_ERROR_BASE + 154),
SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST = (SSL_ERROR_BASE + 155),
SSL_ERROR_BAD_2ND_CLIENT_HELLO = (SSL_ERROR_BASE + 156),
SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION = (SSL_ERROR_BASE + 157),
SSL_ERROR_MALFORMED_PSK_KEY_EXCHANGE_MODES = (SSL_ERROR_BASE + 158),
SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES = (SSL_ERROR_BASE + 159),
SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA = (SSL_ERROR_BASE + 160),
SSL_ERROR_TOO_MUCH_EARLY_DATA = (SSL_ERROR_BASE + 161),
+ SSL_ERROR_RX_UNEXPECTED_END_OF_EARLY_DATA = (SSL_ERROR_BASE + 162),
+ SSL_ERROR_RX_MALFORMED_END_OF_EARLY_DATA = (SSL_ERROR_BASE + 163),
+
+ SSL_ERROR_UNSUPPORTED_EXPERIMENTAL_API = (SSL_ERROR_BASE + 164),
+
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */
/* clang-format on */
#endif /* __SSL_ERR_H_ */
new file mode 100644
--- /dev/null
+++ b/lib/ssl/sslexp.h
@@ -0,0 +1,27 @@
+/*
+ * This file contains prototypes for experimental 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 __sslexp_h_
+#define __sslexp_h_
+
+#include "ssl.h"
+#include "sslerr.h"
+
+SEC_BEGIN_PROTOS
+
+/* The functions in this header file are not guaranteed to remain available in
+ * future NSS versions. Code that uses these functions needs to safeguard
+ * against the function not being available. */
+
+#define SSL_EXPERIMENTAL_API(name, arglist, args) \
+ (SSL_GetExperimentalAPI(name) \
+ ? ((SECStatus(*) arglist)SSL_GetExperimentalAPI(name))args \
+ : SECFailure)
+
+SEC_END_PROTOS
+
+#endif /* __sslexp_h_ */
--- a/lib/ssl/sslsock.c
+++ b/lib/ssl/sslsock.c
@@ -6,16 +6,17 @@
*
* 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 "sslexp.h"
#include "sslimpl.h"
#include "sslproto.h"
#include "nspr.h"
#include "private/pprio.h"
#include "nss.h"
#include "pk11pqg.h"
static const sslSocketOps ssl_default_ops = { /* No SSL. */
@@ -3835,8 +3836,51 @@ SSL_CanBypass(CERTCertificate *cert, SEC
{
if (!pcanbypass) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
*pcanbypass = PR_FALSE;
return SECSuccess;
}
+
+/* Functions that are truly experimental use EXP, functions that are no longer
+ * experimental use PUB.
+ *
+ * When initially defining a new API, add that API here using the EXP() macro
+ * and name the function with a SSLExp_ prefix. Define the experimental API as
+ * a macro in sslexp.h using the SSL_EXPERIMENTAL_API() macro defined there.
+ *
+ * Once an API is stable and proven, move the macro definition in sslexp.h to a
+ * proper function declaration in ssl.h. Keeping the function in this list
+ * ensures that code built against the release that contained the experimental
+ * API will continue to work; use PUB() to reference the public function.
+ */
+#define EXP(n) \
+ { \
+ "SSL_" #n, SSLExp_##n \
+ }
+#define PUB(n) \
+ { \
+ "SSL_" #n, SSL_##n \
+ }
+struct {
+ const char *const name;
+ void *function;
+} ssl_experimental_functions[] = {
+#ifndef SSL_DISABLE_EXPERIMENTAL_API
+#endif
+};
+#undef EXP
+#undef PUB
+
+void *
+SSL_GetExperimentalAPI(const char *name)
+{
+ unsigned int i;
+ for (i = 0; i < PR_ARRAY_SIZE(ssl_experimental_functions); ++i) {
+ if (strcmp(name, ssl_experimental_functions[i].name) == 0) {
+ return ssl_experimental_functions[i].function;
+ }
+ }
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_EXPERIMENTAL_API);
+ return NULL;
+}