зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1386955 - land NSS a0a4e05dcdd5 UPGRADE_NSS_RELEASE, r=me
--HG-- extra : rebase_source : 913834daab6b8404dbeb0654e40e3e7f4ca24a9f
This commit is contained in:
Родитель
e707e0373c
Коммит
95280a653c
|
@ -1919,7 +1919,7 @@ MOZ_ARG_WITH_BOOL(system-nss,
|
|||
_USE_SYSTEM_NSS=1 )
|
||||
|
||||
if test -n "$_USE_SYSTEM_NSS"; then
|
||||
AM_PATH_NSS(3.32, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
|
||||
AM_PATH_NSS(3.33, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
|
||||
fi
|
||||
|
||||
if test -n "$MOZ_SYSTEM_NSS"; then
|
||||
|
|
|
@ -1 +1 @@
|
|||
NSS_3_32_RTM
|
||||
a0a4e05dcdd5
|
||||
|
|
|
@ -1 +1 @@
|
|||
NSS_3_31_BRANCH
|
||||
NSS_3_32_BRANCH
|
||||
|
|
|
@ -6,6 +6,8 @@ if [[ $(id -u) -eq 0 ]]; then
|
|||
exec su worker -c "$0 $*"
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
# Apply clang-format on the provided folder and verify that this doesn't change any file.
|
||||
# If any file differs after formatting, the script eventually exits with 1.
|
||||
# Any differences between formatted and unformatted files is printed to stdout to give a hint what's wrong.
|
||||
|
@ -21,17 +23,16 @@ blacklist=(
|
|||
"./lib/zlib" \
|
||||
"./lib/sqlite" \
|
||||
"./gtests/google_test" \
|
||||
"./.hg" \
|
||||
"./out" \
|
||||
)
|
||||
|
||||
top="$(dirname $0)/../.."
|
||||
cd "$top"
|
||||
top=$(cd "$(dirname $0)/../.."; pwd -P)
|
||||
|
||||
if [ $# -gt 0 ]; then
|
||||
dirs=("$@")
|
||||
else
|
||||
dirs=($(find . -maxdepth 2 -mindepth 1 -type d ! -path . \( ! -regex '.*/' \)))
|
||||
cd "$top"
|
||||
dirs=($(find . -maxdepth 2 -mindepth 1 -type d ! -path '*/.*' -print))
|
||||
fi
|
||||
|
||||
format_folder()
|
||||
|
@ -49,17 +50,17 @@ for dir in "${dirs[@]}"; do
|
|||
if format_folder "$dir"; then
|
||||
c="${dir//[^\/]}"
|
||||
echo "formatting $dir ..."
|
||||
depth=""
|
||||
depth=()
|
||||
if [ "${#c}" == "1" ]; then
|
||||
depth="-maxdepth 1"
|
||||
depth+=(-maxdepth 1)
|
||||
fi
|
||||
find "$dir" $depth -type f \( -name '*.[ch]' -o -name '*.cc' \) -exec clang-format -i {} \+
|
||||
find "$dir" "${depth[@]}" -type f \( -name '*.[ch]' -o -name '*.cc' \) -exec clang-format -i {} \+
|
||||
fi
|
||||
done
|
||||
|
||||
TMPFILE=$(mktemp /tmp/$(basename $0).XXXXXX)
|
||||
trap 'rm $TMPFILE' exit
|
||||
if (cd $(dirname $0); hg root >/dev/null 2>&1); then
|
||||
trap 'rm -f $TMPFILE' exit
|
||||
if [[ -d "$top/.hg" ]]; then
|
||||
hg diff --git "$top" | tee $TMPFILE
|
||||
else
|
||||
git -C "$top" diff | tee $TMPFILE
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
4.16
|
||||
4.15
|
||||
|
||||
# The first line of this file must contain the human readable NSPR
|
||||
# version number, which is the minimum required version of NSPR
|
||||
|
|
|
@ -991,7 +991,7 @@ secu_PrintUniversalString(FILE *out, const SECItem *i, const char *m, int level)
|
|||
for (s = my.data, d = tmp.data; len > 0; len--) {
|
||||
PRUint32 bmpChar = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||
s += 4;
|
||||
if (!isprint(bmpChar))
|
||||
if (!isprint(bmpChar & 0xFF))
|
||||
goto loser;
|
||||
*d++ = (unsigned char)bmpChar;
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ static char *errStrings[] = {
|
|||
"ERROR: Failed to change default.\n",
|
||||
"ERROR: Unable to read from standard input.\n",
|
||||
"ERROR: Unknown error occurred.\n",
|
||||
"ERROR: -nocertdb option can only be used with the -jar command.\n"
|
||||
"ERROR: -nocertdb option can only be used with the -jar command.\n",
|
||||
"ERROR: NSS_Initialize() failed.\n"
|
||||
};
|
||||
|
||||
|
|
|
@ -84,6 +84,8 @@ main(int argc, char **argv)
|
|||
if (!inFile) {
|
||||
fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
|
||||
progName, optstate->value);
|
||||
PORT_Free(typeTag);
|
||||
PL_DestroyOptState(optstate);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
@ -93,6 +95,8 @@ main(int argc, char **argv)
|
|||
if (!outFile) {
|
||||
fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
|
||||
progName, optstate->value);
|
||||
PORT_Free(typeTag);
|
||||
PL_DestroyOptState(optstate);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "ocsp.h"
|
||||
#include "ssl.h"
|
||||
#include "sslproto.h"
|
||||
#include "sslexp.h"
|
||||
#include "pk11func.h"
|
||||
#include "secmod.h"
|
||||
#include "plgetopt.h"
|
||||
|
@ -251,6 +252,7 @@ PrintParameterUsage(void)
|
|||
"%-20s The following values are valid:\n"
|
||||
"%-20s P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n",
|
||||
"-I", "", "");
|
||||
fprintf(stderr, "%-20s Enable alternate content type for TLS 1.3 ServerHello\n", "-X alt-server-hello");
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -914,6 +916,7 @@ char *requestString = NULL;
|
|||
PRInt32 requestStringLen = 0;
|
||||
PRBool requestSent = PR_FALSE;
|
||||
PRBool enableZeroRtt = PR_FALSE;
|
||||
PRBool enableAltServerHello = PR_FALSE;
|
||||
|
||||
static int
|
||||
writeBytesToServer(PRFileDesc *s, const char *buf, int nb)
|
||||
|
@ -1178,6 +1181,16 @@ run_client(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* Alternate ServerHello content type (TLS 1.3 only) */
|
||||
if (enableAltServerHello) {
|
||||
rv = SSL_UseAltServerHelloType(s, PR_TRUE);
|
||||
if (rv != SECSuccess) {
|
||||
SECU_PrintError(progName, "error enabling alternate ServerHello type");
|
||||
error = 1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* require the use of fixed finite-field DH groups */
|
||||
if (requireDHNamedGroups) {
|
||||
rv = SSL_OptionSet(s, SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE);
|
||||
|
@ -1512,7 +1525,7 @@ main(int argc, char **argv)
|
|||
/* XXX: 'B' was used in the past but removed in 3.28,
|
||||
* please leave some time before resuing it. */
|
||||
optstate = PL_CreateOptState(argc, argv,
|
||||
"46A:CDFGHI:KL:M:OR:STUV:W:YZa:bc:d:fgh:m:n:op:qr:st:uvw:z");
|
||||
"46A:CDFGHI:KL:M:OR:STUV:W:X:YZa:bc:d:fgh:m:n:op:qr:st:uvw:z");
|
||||
while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
|
||||
switch (optstate->option) {
|
||||
case '?':
|
||||
|
@ -1618,6 +1631,13 @@ main(int argc, char **argv)
|
|||
}
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
if (!strcmp(optstate->value, "alt-server-hello")) {
|
||||
enableAltServerHello = PR_TRUE;
|
||||
} else {
|
||||
Usage(progName);
|
||||
}
|
||||
break;
|
||||
case 'Y':
|
||||
PrintCipherUsage(progName);
|
||||
exit(0);
|
||||
|
|
|
@ -10,3 +10,4 @@
|
|||
*/
|
||||
|
||||
#error "Do not include this header file."
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ const uint8_t kTlsChangeCipherSpecType = 20;
|
|||
const uint8_t kTlsAlertType = 21;
|
||||
const uint8_t kTlsHandshakeType = 22;
|
||||
const uint8_t kTlsApplicationDataType = 23;
|
||||
const uint8_t kTlsAltHandshakeType = 24;
|
||||
|
||||
const uint8_t kTlsHandshakeClientHello = 1;
|
||||
const uint8_t kTlsHandshakeServerHello = 2;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
LIBFUZZER_REVISION=56bd1d43451cca4b6a11d3be316bb77ab159b09d
|
||||
LIBFUZZER_REVISION=6937e68f927b6aefe526fcb9db8953f497e6e74d
|
||||
|
||||
d=$(dirname $0)
|
||||
$d/git-copy.sh https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer $LIBFUZZER_REVISION $d/../libFuzzer
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "nss.h"
|
||||
#include "scoped_ptrs.h"
|
||||
#include "prprf.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
|
@ -89,4 +90,23 @@ INSTANTIATE_TEST_CASE_P(ParseAVAStrings, Alg1485ParseTest,
|
|||
::testing::ValuesIn(kAVATestStrings));
|
||||
INSTANTIATE_TEST_CASE_P(CompareAVAStrings, Alg1485CompareTest,
|
||||
::testing::ValuesIn(kAVACompareStrings));
|
||||
|
||||
TEST_F(Alg1485Test, ShortOIDTest) {
|
||||
// This is not a valid OID (too short). CERT_GetOidString should return 0.
|
||||
unsigned char data[] = {0x05};
|
||||
const SECItem oid = {siBuffer, data, sizeof(data)};
|
||||
char* result = CERT_GetOidString(&oid);
|
||||
EXPECT_EQ(result, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(Alg1485Test, BrokenOIDTest) {
|
||||
// This is not a valid OID (first bit of last byte is not set).
|
||||
// CERT_GetOidString should return 0.
|
||||
unsigned char data[] = {0x81, 0x82, 0x83, 0x84};
|
||||
const SECItem oid = {siBuffer, data, sizeof(data)};
|
||||
char* result = CERT_GetOidString(&oid);
|
||||
EXPECT_EQ(15U, strlen(result));
|
||||
EXPECT_EQ(0, strncmp("OID.UNSUPPORTED", result, 15));
|
||||
PR_smprintf_free(result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ NSS_SRCDIRS = \
|
|||
certdb_gtest \
|
||||
certhigh_gtest \
|
||||
pk11_gtest \
|
||||
softoken_gtest \
|
||||
ssl_gtest \
|
||||
nss_bogo_shim \
|
||||
$(NULL)
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
#! 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 ../common/gtest.mk
|
||||
|
||||
CFLAGS += -I$(CORE_DEPTH)/lib/util
|
||||
|
||||
#######################################################################
|
||||
# (5) Execute "global" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
include $(CORE_DEPTH)/coreconf/rules.mk
|
||||
|
||||
#######################################################################
|
||||
# (6) Execute "component" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
|
||||
#######################################################################
|
||||
# (7) Execute "local" rules. (OPTIONAL). #
|
||||
#######################################################################
|
|
@ -0,0 +1,25 @@
|
|||
# -*- makefile -*-
|
||||
# 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 = ../..
|
||||
DEPTH = ../..
|
||||
MODULE = nss
|
||||
|
||||
CPPSRCS = \
|
||||
softoken_gtest.cc \
|
||||
$(NULL)
|
||||
|
||||
INCLUDES += \
|
||||
-I$(CORE_DEPTH)/gtests/google_test/gtest/include \
|
||||
-I$(CORE_DEPTH)/cpputil \
|
||||
$(NULL)
|
||||
|
||||
REQUIRES = nspr gtest
|
||||
|
||||
PROGRAM = softoken_gtest
|
||||
|
||||
EXTRA_LIBS = \
|
||||
$(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) \
|
||||
$(DIST)/lib/$(LIB_PREFIX)gtestutil.$(LIB_SUFFIX) \
|
||||
$(NULL)
|
|
@ -0,0 +1,125 @@
|
|||
#include <cstdlib>
|
||||
|
||||
#include "nspr.h"
|
||||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
|
||||
#include "scoped_ptrs.h"
|
||||
|
||||
#define GTEST_HAS_RTTI 0
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
// Given a prefix, attempts to create a unique directory that the user can do
|
||||
// work in without impacting other tests. For example, if given the prefix
|
||||
// "scratch", a directory like "scratch05c17b25" will be created in the current
|
||||
// working directory (or the location specified by NSS_GTEST_WORKDIR, if
|
||||
// defined).
|
||||
// Upon destruction, the implementation will attempt to delete the directory.
|
||||
// However, no attempt is made to first remove files in the directory - the
|
||||
// user is responsible for this. If the directory is not empty, deleting it will
|
||||
// fail.
|
||||
// Statistically, it is technically possible to fail to create a unique
|
||||
// directory name, but this is extremely unlikely given the expected workload of
|
||||
// this implementation.
|
||||
class ScopedUniqueDirectory {
|
||||
public:
|
||||
explicit ScopedUniqueDirectory(const std::string& prefix);
|
||||
|
||||
// NB: the directory must be empty upon destruction
|
||||
~ScopedUniqueDirectory() { assert(rmdir(mPath.c_str()) == 0); }
|
||||
|
||||
const std::string& GetPath() { return mPath; }
|
||||
|
||||
private:
|
||||
static const int RETRY_LIMIT = 5;
|
||||
static void GenerateRandomName(/*in/out*/ std::string& prefix);
|
||||
static bool TryMakingDirectory(/*in/out*/ std::string& prefix);
|
||||
|
||||
std::string mPath;
|
||||
};
|
||||
|
||||
ScopedUniqueDirectory::ScopedUniqueDirectory(const std::string& prefix) {
|
||||
std::string path;
|
||||
const char* workingDirectory = PR_GetEnvSecure("NSS_GTEST_WORKDIR");
|
||||
if (workingDirectory) {
|
||||
path.assign(workingDirectory);
|
||||
}
|
||||
path.append(prefix);
|
||||
for (int i = 0; i < RETRY_LIMIT; i++) {
|
||||
std::string pathCopy(path);
|
||||
// TryMakingDirectory will modify its input. If it fails, we want to throw
|
||||
// away the modified result.
|
||||
if (TryMakingDirectory(pathCopy)) {
|
||||
mPath.assign(pathCopy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(mPath.length() > 0);
|
||||
}
|
||||
|
||||
void ScopedUniqueDirectory::GenerateRandomName(std::string& prefix) {
|
||||
std::stringstream ss;
|
||||
ss << prefix;
|
||||
// RAND_MAX is at least 32767.
|
||||
ss << std::setfill('0') << std::setw(4) << std::hex << rand() << rand();
|
||||
// This will overwrite the value of prefix. This is a little inefficient, but
|
||||
// at least it makes the code simple.
|
||||
ss >> prefix;
|
||||
}
|
||||
|
||||
bool ScopedUniqueDirectory::TryMakingDirectory(std::string& prefix) {
|
||||
GenerateRandomName(prefix);
|
||||
#if defined(_WIN32)
|
||||
return _mkdir(prefix.c_str()) == 0;
|
||||
#else
|
||||
return mkdir(prefix.c_str(), 0777) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
class SoftokenTest : public ::testing::Test {
|
||||
protected:
|
||||
SoftokenTest() : mNSSDBDir("SoftokenTest.d-") {}
|
||||
|
||||
virtual void SetUp() {
|
||||
std::string nssInitArg("sql:");
|
||||
nssInitArg.append(mNSSDBDir.GetPath());
|
||||
ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
|
||||
NSS_INIT_NOROOTINIT));
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
ASSERT_EQ(SECSuccess, NSS_Shutdown());
|
||||
const std::string& nssDBDirPath = mNSSDBDir.GetPath();
|
||||
ASSERT_EQ(0, unlink((nssDBDirPath + "/cert9.db").c_str()));
|
||||
ASSERT_EQ(0, unlink((nssDBDirPath + "/key4.db").c_str()));
|
||||
ASSERT_EQ(0, unlink((nssDBDirPath + "/pkcs11.txt").c_str()));
|
||||
}
|
||||
|
||||
ScopedUniqueDirectory mNSSDBDir;
|
||||
};
|
||||
|
||||
TEST_F(SoftokenTest, ResetSoftokenEmptyPassword) {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
ASSERT_TRUE(slot);
|
||||
EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
|
||||
EXPECT_EQ(SECSuccess, PK11_ResetToken(slot.get(), nullptr));
|
||||
EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
|
||||
}
|
||||
|
||||
TEST_F(SoftokenTest, ResetSoftokenNonEmptyPassword) {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
ASSERT_TRUE(slot);
|
||||
EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
|
||||
EXPECT_EQ(SECSuccess, PK11_ResetToken(slot.get(), nullptr));
|
||||
EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password2"));
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
# 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/.
|
||||
{
|
||||
'includes': [
|
||||
'../../coreconf/config.gypi',
|
||||
'../common/gtest.gypi',
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'softoken_gtest',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'softoken_gtest.cc',
|
||||
],
|
||||
'dependencies': [
|
||||
'<(DEPTH)/exports.gyp:nss_exports',
|
||||
'<(DEPTH)/lib/util/util.gyp:nssutil3',
|
||||
'<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
|
||||
],
|
||||
'conditions': [
|
||||
[ 'test_build==1', {
|
||||
'dependencies': [
|
||||
'<(DEPTH)/lib/nss/nss.gyp:nss_static',
|
||||
'<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap_static',
|
||||
'<(DEPTH)/lib/cryptohi/cryptohi.gyp:cryptohi',
|
||||
'<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
|
||||
'<(DEPTH)/lib/certdb/certdb.gyp:certdb',
|
||||
'<(DEPTH)/lib/base/base.gyp:nssb',
|
||||
'<(DEPTH)/lib/dev/dev.gyp:nssdev',
|
||||
'<(DEPTH)/lib/pki/pki.gyp:nsspki',
|
||||
'<(DEPTH)/lib/ssl/ssl.gyp:ssl',
|
||||
],
|
||||
}, {
|
||||
'dependencies': [
|
||||
'<(DEPTH)/lib/nss/nss.gyp:nss3',
|
||||
'<(DEPTH)/lib/ssl/ssl.gyp:ssl3',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}
|
||||
],
|
||||
'target_defaults': {
|
||||
'include_dirs': [
|
||||
'../../lib/util'
|
||||
]
|
||||
},
|
||||
'variables': {
|
||||
'module': 'nss'
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@ CPPSRCS = \
|
|||
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 \
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "secerr.h"
|
||||
#include "ssl.h"
|
||||
#include "sslerr.h"
|
||||
#include "sslexp.h"
|
||||
#include "sslproto.h"
|
||||
|
||||
extern "C" {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
'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',
|
||||
|
|
|
@ -6,10 +6,12 @@
|
|||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "secerr.h"
|
||||
#include "ssl.h"
|
||||
#include "sslerr.h"
|
||||
#include "sslproto.h"
|
||||
#include "ssl3prot.h"
|
||||
|
||||
extern "C" {
|
||||
// This is not something that should make you happy.
|
||||
|
@ -323,6 +325,42 @@ TEST_F(TlsConnectStreamTls13, NegotiateShortHeaders) {
|
|||
Connect();
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, ClientAltHandshakeType) {
|
||||
client_->SetAltHandshakeTypeEnabled();
|
||||
auto filter = std::make_shared<TlsHeaderRecorder>();
|
||||
server_->SetPacketFilter(filter);
|
||||
Connect();
|
||||
ASSERT_EQ(kTlsHandshakeType, filter->header(0)->content_type());
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, ServerAltHandshakeType) {
|
||||
server_->SetAltHandshakeTypeEnabled();
|
||||
auto filter = std::make_shared<TlsHeaderRecorder>();
|
||||
server_->SetPacketFilter(filter);
|
||||
Connect();
|
||||
ASSERT_EQ(kTlsHandshakeType, filter->header(0)->content_type());
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, BothAltHandshakeType) {
|
||||
client_->SetAltHandshakeTypeEnabled();
|
||||
server_->SetAltHandshakeTypeEnabled();
|
||||
auto header_filter = std::make_shared<TlsHeaderRecorder>();
|
||||
auto sh_filter = std::make_shared<TlsInspectorRecordHandshakeMessage>(
|
||||
kTlsHandshakeServerHello);
|
||||
std::vector<std::shared_ptr<PacketFilter>> filters = {header_filter,
|
||||
sh_filter};
|
||||
auto chained = std::make_shared<ChainedPacketFilter>(filters);
|
||||
server_->SetPacketFilter(chained);
|
||||
header_filter->SetAgent(server_.get());
|
||||
header_filter->EnableDecryption();
|
||||
Connect();
|
||||
ASSERT_EQ(kTlsAltHandshakeType, header_filter->header(0)->content_type());
|
||||
ASSERT_EQ(kTlsHandshakeType, header_filter->header(1)->content_type());
|
||||
uint32_t ver;
|
||||
ASSERT_TRUE(sh_filter->buffer().Read(0, 2, &ver));
|
||||
ASSERT_EQ((uint32_t)(0x7a00 | TLS_1_3_DRAFT_VERSION), ver);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
GenericStream, TlsConnectGeneric,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
|
|
|
@ -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
|
|
@ -10,6 +10,7 @@
|
|||
#include "pk11func.h"
|
||||
#include "ssl.h"
|
||||
#include "sslerr.h"
|
||||
#include "sslexp.h"
|
||||
#include "sslproto.h"
|
||||
#include "tls_parser.h"
|
||||
|
||||
|
@ -414,6 +415,13 @@ void TlsAgent::SetShortHeadersEnabled() {
|
|||
EXPECT_EQ(SECSuccess, rv);
|
||||
}
|
||||
|
||||
void TlsAgent::SetAltHandshakeTypeEnabled() {
|
||||
EXPECT_TRUE(EnsureTlsSetup());
|
||||
|
||||
SECStatus rv = SSL_UseAltServerHelloType(ssl_fd(), true);
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
}
|
||||
|
||||
void TlsAgent::SetVersionRange(uint16_t minver, uint16_t maxver) {
|
||||
vrange_.min = minver;
|
||||
vrange_.max = maxver;
|
||||
|
|
|
@ -127,6 +127,7 @@ class TlsAgent : public PollTarget {
|
|||
void Set0RttEnabled(bool en);
|
||||
void SetFallbackSCSVEnabled(bool en);
|
||||
void SetShortHeadersEnabled();
|
||||
void SetAltHandshakeTypeEnabled();
|
||||
void SetVersionRange(uint16_t minver, uint16_t maxver);
|
||||
void GetVersionRange(uint16_t* minver, uint16_t* maxver);
|
||||
void CheckPreliminaryInfo();
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "tls_connect.h"
|
||||
#include "sslexp.h"
|
||||
extern "C" {
|
||||
#include "libssl_internals.h"
|
||||
}
|
||||
|
|
|
@ -227,7 +227,8 @@ PacketFilter::Action TlsHandshakeFilter::FilterRecord(
|
|||
const TlsRecordHeader& record_header, const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
// Check that the first byte is as requested.
|
||||
if (record_header.content_type() != kTlsHandshakeType) {
|
||||
if ((record_header.content_type() != kTlsHandshakeType) &&
|
||||
(record_header.content_type() != kTlsAltHandshakeType)) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
|
@ -369,6 +370,20 @@ PacketFilter::Action TlsConversationRecorder::FilterRecord(
|
|||
return KEEP;
|
||||
}
|
||||
|
||||
PacketFilter::Action TlsHeaderRecorder::FilterRecord(
|
||||
const TlsRecordHeader& header, const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
headers_.push_back(header);
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
const TlsRecordHeader* TlsHeaderRecorder::header(size_t index) {
|
||||
if (index > headers_.size() + 1) {
|
||||
return nullptr;
|
||||
}
|
||||
return &headers_[index];
|
||||
}
|
||||
|
||||
PacketFilter::Action ChainedPacketFilter::Filter(const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
DataBuffer in(input);
|
||||
|
@ -378,6 +393,7 @@ PacketFilter::Action ChainedPacketFilter::Filter(const DataBuffer& input,
|
|||
if (action == DROP) {
|
||||
return DROP;
|
||||
}
|
||||
|
||||
if (action == CHANGE) {
|
||||
in = *output;
|
||||
changed = true;
|
||||
|
|
|
@ -133,6 +133,7 @@ inline std::ostream& operator<<(std::ostream& stream, TlsRecordHeader& hdr) {
|
|||
stream << "Alert";
|
||||
break;
|
||||
case kTlsHandshakeType:
|
||||
case kTlsAltHandshakeType:
|
||||
stream << "Handshake";
|
||||
break;
|
||||
case kTlsApplicationDataType:
|
||||
|
@ -230,7 +231,19 @@ class TlsConversationRecorder : public TlsRecordFilter {
|
|||
DataBuffer* output);
|
||||
|
||||
private:
|
||||
DataBuffer& buffer_;
|
||||
DataBuffer buffer_;
|
||||
};
|
||||
|
||||
// Make a copy of the records
|
||||
class TlsHeaderRecorder : public TlsRecordFilter {
|
||||
public:
|
||||
virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output);
|
||||
const TlsRecordHeader* header(size_t index);
|
||||
|
||||
private:
|
||||
std::vector<TlsRecordHeader> headers_;
|
||||
};
|
||||
|
||||
// Runs multiple packet filters in series.
|
||||
|
|
|
@ -703,6 +703,11 @@ CERT_GetOidString(const SECItem* oid)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* If the OID has length 1, we bail. */
|
||||
if (oid->len < 2) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* first will point to the next sequence of bytes to decode */
|
||||
first = (PRUint8*)oid->data;
|
||||
/* stop points to one past the legitimate data */
|
||||
|
@ -728,6 +733,10 @@ CERT_GetOidString(const SECItem* oid)
|
|||
break;
|
||||
}
|
||||
}
|
||||
/* There's no first bit set, so this isn't valid. Bail.*/
|
||||
if (last == stop) {
|
||||
goto unsupported;
|
||||
}
|
||||
bytesBeforeLast = (unsigned int)(last - first);
|
||||
if (bytesBeforeLast <= 3U) { /* 0-28 bit number */
|
||||
PRUint32 n = 0;
|
||||
|
@ -748,12 +757,12 @@ CERT_GetOidString(const SECItem* oid)
|
|||
CASE(2, 0x7f);
|
||||
CASE(1, 0x7f);
|
||||
case 0:
|
||||
n |=
|
||||
last[0] & 0x7f;
|
||||
n |= last[0] & 0x7f;
|
||||
break;
|
||||
}
|
||||
if (last[0] & 0x80)
|
||||
if (last[0] & 0x80) {
|
||||
goto unsupported;
|
||||
}
|
||||
|
||||
if (!rvString) {
|
||||
/* This is the first number.. decompose it */
|
||||
|
|
|
@ -90,7 +90,12 @@ EXTRA_SHARED_LIBS += \
|
|||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(OS_ARCH), Linux)
|
||||
CFLAGS += -std=gnu99
|
||||
endif
|
||||
|
||||
ifeq ($(OS_ARCH), Darwin)
|
||||
CFLAGS += -std=gnu99
|
||||
EXTRA_SHARED_LIBS += -dylib_file @executable_path/libplc4.dylib:$(DIST)/lib/libplc4.dylib -dylib_file @executable_path/libplds4.dylib:$(DIST)/lib/libplds4.dylib
|
||||
endif
|
||||
|
||||
|
|
|
@ -166,6 +166,7 @@
|
|||
'OTHER_CFLAGS': [
|
||||
'-mpclmul',
|
||||
'-maes',
|
||||
'-std=gnu99',
|
||||
],
|
||||
},
|
||||
}],
|
||||
|
@ -232,6 +233,9 @@
|
|||
'FREEBL_LOWHASH',
|
||||
'FREEBL_NO_DEPEND',
|
||||
],
|
||||
'cflags': [
|
||||
'-std=gnu99',
|
||||
],
|
||||
}],
|
||||
[ 'OS=="linux" or OS=="android"', {
|
||||
'conditions': [
|
||||
|
|
|
@ -22,12 +22,12 @@
|
|||
* The format of the version string should be
|
||||
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
|
||||
*/
|
||||
#define NSS_VERSION "3.32" _NSS_CUSTOMIZED
|
||||
#define NSS_VERSION "3.33" _NSS_CUSTOMIZED " Beta"
|
||||
#define NSS_VMAJOR 3
|
||||
#define NSS_VMINOR 32
|
||||
#define NSS_VMINOR 33
|
||||
#define NSS_VPATCH 0
|
||||
#define NSS_VBUILD 0
|
||||
#define NSS_BETA PR_FALSE
|
||||
#define NSS_BETA PR_TRUE
|
||||
|
||||
#ifndef RC_INVOKED
|
||||
|
||||
|
|
|
@ -180,16 +180,18 @@ STAN_RemoveModuleFromDefaultTrustDomain(
|
|||
NSSTrustDomain *td;
|
||||
int i;
|
||||
td = STAN_GetDefaultTrustDomain();
|
||||
NSSRWLock_LockWrite(td->tokensLock);
|
||||
for (i = 0; i < module->slotCount; i++) {
|
||||
token = PK11Slot_GetNSSToken(module->slots[i]);
|
||||
if (token) {
|
||||
nssToken_NotifyCertsNotVisible(token);
|
||||
NSSRWLock_LockWrite(td->tokensLock);
|
||||
nssList_Remove(td->tokenList, token);
|
||||
NSSRWLock_UnlockWrite(td->tokensLock);
|
||||
PK11Slot_SetNSSToken(module->slots[i], NULL);
|
||||
nssToken_Destroy(token);
|
||||
}
|
||||
}
|
||||
NSSRWLock_LockWrite(td->tokensLock);
|
||||
nssListIterator_Destroy(td->tokens);
|
||||
td->tokens = nssList_CreateIterator(td->tokenList);
|
||||
NSSRWLock_UnlockWrite(td->tokensLock);
|
||||
|
|
|
@ -3566,7 +3566,6 @@ NSC_InitToken(CK_SLOT_ID slotID, CK_CHAR_PTR pPin,
|
|||
{
|
||||
SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
|
||||
SFTKDBHandle *handle;
|
||||
SFTKDBHandle *certHandle;
|
||||
SECStatus rv;
|
||||
unsigned int i;
|
||||
SFTKObject *object;
|
||||
|
@ -3614,19 +3613,16 @@ NSC_InitToken(CK_SLOT_ID slotID, CK_CHAR_PTR pPin,
|
|||
}
|
||||
|
||||
rv = sftkdb_ResetKeyDB(handle);
|
||||
/* clear the password */
|
||||
sftkdb_ClearPassword(handle);
|
||||
/* update slot->needLogin (should be true now since no password is set) */
|
||||
sftk_checkNeedLogin(slot, handle);
|
||||
sftk_freeDB(handle);
|
||||
if (rv != SECSuccess) {
|
||||
return CKR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
/* finally mark all the user certs as non-user certs */
|
||||
certHandle = sftk_getCertDB(slot);
|
||||
if (certHandle == NULL)
|
||||
return CKR_OK;
|
||||
|
||||
sftk_freeDB(certHandle);
|
||||
|
||||
return CKR_OK; /*is this the right function for not implemented*/
|
||||
}
|
||||
|
||||
/* NSC_InitPIN initializes the normal user's PIN. */
|
||||
|
|
|
@ -1600,7 +1600,7 @@ loser:
|
|||
return error;
|
||||
}
|
||||
|
||||
static const char RESET_CMD[] = "DROP TABLE IF EXISTS %s;";
|
||||
static const char RESET_CMD[] = "DELETE FROM %s;";
|
||||
CK_RV
|
||||
sdb_Reset(SDB *sdb)
|
||||
{
|
||||
|
@ -1621,7 +1621,8 @@ sdb_Reset(SDB *sdb)
|
|||
goto loser;
|
||||
}
|
||||
|
||||
/* delete the key table */
|
||||
if (tableExists(sqlDB, sdb_p->table)) {
|
||||
/* delete the contents of the key table */
|
||||
newStr = sqlite3_mprintf(RESET_CMD, sdb_p->table);
|
||||
if (newStr == NULL) {
|
||||
error = CKR_HOST_MEMORY;
|
||||
|
@ -1632,6 +1633,7 @@ sdb_Reset(SDB *sdb)
|
|||
|
||||
if (sqlerr != SQLITE_OK)
|
||||
goto loser;
|
||||
}
|
||||
|
||||
/* delete the password entry table */
|
||||
sqlerr = sqlite3_exec(sqlDB, "DROP TABLE IF EXISTS metaData;",
|
||||
|
@ -1868,28 +1870,27 @@ sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate,
|
|||
/*
|
||||
* we decide whether or not to use the cache based on the following input.
|
||||
*
|
||||
* NSS_SDB_USE_CACHE environment variable is non-existant or set to
|
||||
* anything other than "no" or "yes" ("auto", for instance).
|
||||
* This is the normal case. NSS will measure the performance of access
|
||||
* to the temp database versus the access to the users passed in
|
||||
* database location. If the temp database location is "significantly"
|
||||
* faster we will use the cache.
|
||||
* NSS_SDB_USE_CACHE environment variable is set to anything other than
|
||||
* "yes" or "no" (for instance, "auto"): NSS will measure the performance
|
||||
* of access to the temp database versus the access to the user's
|
||||
* passed-in database location. If the temp database location is
|
||||
* "significantly" faster we will use the cache.
|
||||
*
|
||||
* NSS_SDB_USE_CACHE environment variable is set to "no": cache will not
|
||||
* be used.
|
||||
* NSS_SDB_USE_CACHE environment variable is nonexistent or set to "no":
|
||||
* cache will not be used.
|
||||
*
|
||||
* NSS_SDB_USE_CACHE environment variable is set to "yes": cache will
|
||||
* always be used.
|
||||
*
|
||||
* It is expected that most applications would use the "auto" selection,
|
||||
* the environment variable is primarily to simplify testing, and to
|
||||
* correct potential corner cases where */
|
||||
* It is expected that most applications will not need this feature, and
|
||||
* thus it is disabled by default.
|
||||
*/
|
||||
|
||||
env = PR_GetEnvSecure("NSS_SDB_USE_CACHE");
|
||||
|
||||
if (env && PORT_Strcasecmp(env, "no") == 0) {
|
||||
if (!env || PORT_Strcasecmp(env, "no") == 0) {
|
||||
enableCache = PR_FALSE;
|
||||
} else if (env && PORT_Strcasecmp(env, "yes") == 0) {
|
||||
} else if (PORT_Strcasecmp(env, "yes") == 0) {
|
||||
enableCache = PR_TRUE;
|
||||
} else {
|
||||
char *tempDir = NULL;
|
||||
|
@ -2035,10 +2036,11 @@ s_open(const char *directory, const char *certPrefix, const char *keyPrefix,
|
|||
{
|
||||
char *env;
|
||||
env = PR_GetEnvSecure("NSS_SDB_USE_CACHE");
|
||||
/* If the environment variable is set to yes or no, sdb_init() will
|
||||
* ignore the value of accessOps, and we can skip the measuring.*/
|
||||
if (!env || ((PORT_Strcasecmp(env, "no") != 0) &&
|
||||
(PORT_Strcasecmp(env, "yes") != 0))) {
|
||||
/* If the environment variable is undefined or set to yes or no,
|
||||
* sdb_init() will ignore the value of accessOps, and we can skip the
|
||||
* measuring.*/
|
||||
if (env && PORT_Strcasecmp(env, "no") != 0 &&
|
||||
PORT_Strcasecmp(env, "yes") != 0) {
|
||||
accessOps = sdb_measureAccess(directory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,11 +21,11 @@
|
|||
* The format of the version string should be
|
||||
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
|
||||
*/
|
||||
#define SOFTOKEN_VERSION "3.32" SOFTOKEN_ECC_STRING
|
||||
#define SOFTOKEN_VERSION "3.33" SOFTOKEN_ECC_STRING " Beta"
|
||||
#define SOFTOKEN_VMAJOR 3
|
||||
#define SOFTOKEN_VMINOR 32
|
||||
#define SOFTOKEN_VMINOR 33
|
||||
#define SOFTOKEN_VPATCH 0
|
||||
#define SOFTOKEN_VBUILD 0
|
||||
#define SOFTOKEN_BETA PR_FALSE
|
||||
#define SOFTOKEN_BETA PR_TRUE
|
||||
|
||||
#endif /* _SOFTKVER_H_ */
|
||||
|
|
|
@ -511,3 +511,12 @@ ER3(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA, (SSL_ERROR_BASE + 160),
|
|||
|
||||
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.")
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
'preenc.h',
|
||||
'ssl.h',
|
||||
'sslerr.h',
|
||||
'sslexp.h',
|
||||
'sslproto.h',
|
||||
'sslt.h'
|
||||
],
|
||||
|
|
|
@ -10,6 +10,7 @@ EXPORTS = \
|
|||
ssl.h \
|
||||
sslt.h \
|
||||
sslerr.h \
|
||||
sslexp.h \
|
||||
sslproto.h \
|
||||
preenc.h \
|
||||
$(NULL)
|
||||
|
|
|
@ -234,3 +234,9 @@ SSL_AlertSentCallback;
|
|||
;+ local:
|
||||
;+*;
|
||||
;+};
|
||||
;+NSS_3.33 { # NSS 3.33 release
|
||||
;+ global:
|
||||
SSL_GetExperimentalAPI;
|
||||
;+ local:
|
||||
;+*;
|
||||
;+};
|
||||
|
|
|
@ -1374,6 +1374,13 @@ extern const char *NSSSSL_GetVersion(void);
|
|||
*/
|
||||
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_ */
|
||||
|
|
|
@ -1090,7 +1090,8 @@ ssl_ClientReadVersion(sslSocket *ss, PRUint8 **b, unsigned int *len,
|
|||
PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
|
||||
return SECFailure;
|
||||
}
|
||||
if (temp == tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3)) {
|
||||
if (temp == tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3) || (ss->opt.enableAltHandshaketype &&
|
||||
(temp == tls13_EncodeAltDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3)))) {
|
||||
v = SSL_LIBRARY_VERSION_TLS_1_3;
|
||||
} else {
|
||||
v = (SSL3ProtocolVersion)temp;
|
||||
|
@ -2977,6 +2978,7 @@ ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags)
|
|||
ssl_SEND_FLAG_CAP_RECORD_VERSION;
|
||||
PRInt32 count = -1;
|
||||
SECStatus rv;
|
||||
SSL3ContentType ct = content_handshake;
|
||||
|
||||
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
||||
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
|
||||
|
@ -2990,7 +2992,12 @@ ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags)
|
|||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
count = ssl3_SendRecord(ss, NULL, content_handshake,
|
||||
/* Maybe send the first message with alt handshake type. */
|
||||
if (ss->ssl3.hs.altHandshakeType) {
|
||||
ct = content_alt_handshake;
|
||||
ss->ssl3.hs.altHandshakeType = PR_FALSE;
|
||||
}
|
||||
count = ssl3_SendRecord(ss, NULL, ct,
|
||||
ss->sec.ci.sendBuf.buf,
|
||||
ss->sec.ci.sendBuf.len, flags);
|
||||
if (count < 0) {
|
||||
|
@ -9321,7 +9328,7 @@ ssl3_SendServerHello(sslSocket *ss)
|
|||
if (IS_DTLS(ss) && ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
version = dtls_TLSVersionToDTLSVersion(ss->version);
|
||||
} else {
|
||||
version = tls13_EncodeDraftVersion(ss->version);
|
||||
version = ss->ssl3.hs.altHandshakeType ? tls13_EncodeAltDraftVersion(ss->version) : tls13_EncodeDraftVersion(ss->version);
|
||||
}
|
||||
|
||||
rv = ssl3_AppendHandshakeNumber(ss, version, 2);
|
||||
|
@ -9752,13 +9759,12 @@ ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length,
|
|||
|
||||
hashAlg = ssl_SignatureSchemeToHashType(sigScheme);
|
||||
|
||||
if (hashes->u.pointer_to_hash_input.data) {
|
||||
rv = ssl3_ComputeHandshakeHash(hashes->u.pointer_to_hash_input.data,
|
||||
hashes->u.pointer_to_hash_input.len,
|
||||
/* Read from the message buffer, but we need to use only up to the end
|
||||
* of the previous handshake message. The length of the transcript up to
|
||||
* that point is saved in |hashes->u.transcriptLen|. */
|
||||
rv = ssl3_ComputeHandshakeHash(ss->ssl3.hs.messages.buf,
|
||||
hashes->u.transcriptLen,
|
||||
hashAlg, &localHashes);
|
||||
} else {
|
||||
rv = SECFailure;
|
||||
}
|
||||
|
||||
if (rv == SECSuccess) {
|
||||
hashesForVerify = &localHashes;
|
||||
|
@ -11658,15 +11664,15 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length,
|
|||
* additional handshake messages will have been added to the
|
||||
* buffer, e.g. the certificate_verify message itself.)
|
||||
*
|
||||
* Therefore, we use SSL3Hashes.u.pointer_to_hash_input
|
||||
* to signal the current state of the buffer.
|
||||
* Therefore, we use SSL3Hashes.u.transcriptLen to save how much
|
||||
* data there is and read directly from ss->ssl3.hs.messages
|
||||
* when calculating the hashes.
|
||||
*
|
||||
* ssl3_HandleCertificateVerify will detect
|
||||
* hashType == handshake_hash_record
|
||||
* and use that information to calculate the hash.
|
||||
*/
|
||||
hashes.u.pointer_to_hash_input.data = ss->ssl3.hs.messages.buf;
|
||||
hashes.u.pointer_to_hash_input.len = ss->ssl3.hs.messages.len;
|
||||
hashes.u.transcriptLen = ss->ssl3.hs.messages.len;
|
||||
hashesPtr = &hashes;
|
||||
} else {
|
||||
computeHashes = PR_TRUE;
|
||||
|
@ -12729,6 +12735,14 @@ process_it:
|
|||
*/
|
||||
ssl_GetSSL3HandshakeLock(ss);
|
||||
|
||||
/* Special case: allow alt content type for TLS 1.3 ServerHello. */
|
||||
if ((rType == content_alt_handshake) &&
|
||||
(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) &&
|
||||
(ss->ssl3.hs.ws == wait_server_hello) &&
|
||||
(ss->opt.enableAltHandshaketype) &&
|
||||
(!IS_DTLS(ss))) {
|
||||
rType = content_handshake;
|
||||
}
|
||||
/* All the functions called in this switch MUST set error code if
|
||||
** they return SECFailure or SECWouldBlock.
|
||||
*/
|
||||
|
|
|
@ -41,7 +41,8 @@ typedef enum {
|
|||
content_change_cipher_spec = 20,
|
||||
content_alert = 21,
|
||||
content_handshake = 22,
|
||||
content_application_data = 23
|
||||
content_application_data = 23,
|
||||
content_alt_handshake = 24
|
||||
} SSL3ContentType;
|
||||
|
||||
typedef struct {
|
||||
|
@ -235,7 +236,7 @@ typedef struct {
|
|||
union {
|
||||
PRUint8 raw[64];
|
||||
SSL3HashesIndividually s;
|
||||
SECItem pointer_to_hash_input;
|
||||
unsigned int transcriptLen;
|
||||
} u;
|
||||
} SSL3Hashes;
|
||||
|
||||
|
|
|
@ -246,6 +246,11 @@ typedef enum {
|
|||
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 */
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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)
|
||||
|
||||
/* Allow the ServerHello to be record type 24. Experiment to test:
|
||||
* https://github.com/tlswg/tls13-spec/pull/1051
|
||||
* This will either become part of the standard or be disabled
|
||||
* after we have tested it.
|
||||
*/
|
||||
#define SSL_UseAltServerHelloType(fd, enable) \
|
||||
SSL_EXPERIMENTAL_API("SSL_UseAltServerHelloType", \
|
||||
(PRFileDesc * _fd, PRBool _enable), \
|
||||
(fd, enable))
|
||||
|
||||
SEC_END_PROTOS
|
||||
|
||||
#endif /* __sslexp_h_ */
|
|
@ -298,6 +298,7 @@ typedef struct sslOptionsStr {
|
|||
unsigned int requireDHENamedGroups : 1;
|
||||
unsigned int enable0RttData : 1;
|
||||
unsigned int enableShortHeaders : 1;
|
||||
unsigned int enableAltHandshaketype : 1;
|
||||
} sslOptions;
|
||||
|
||||
typedef enum { sslHandshakingUndetermined = 0,
|
||||
|
@ -883,6 +884,7 @@ typedef struct SSL3HandshakeStateStr {
|
|||
ssl3KEADef kea_def_mutable; /* Used to hold the writable kea_def
|
||||
* we use for TLS 1.3 */
|
||||
PRBool shortHeaders; /* Assigned if we are doing short headers. */
|
||||
PRBool altHandshakeType; /* Assigned if we are doing the wrapped handshake. */
|
||||
} SSL3HandshakeState;
|
||||
|
||||
/*
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "cert.h"
|
||||
#include "keyhi.h"
|
||||
#include "ssl.h"
|
||||
#include "sslexp.h"
|
||||
#include "sslimpl.h"
|
||||
#include "sslproto.h"
|
||||
#include "nspr.h"
|
||||
|
@ -80,10 +81,11 @@ static sslOptions ssl_defaults = {
|
|||
PR_FALSE, /* requireDHENamedGroups */
|
||||
PR_FALSE, /* enable0RttData */
|
||||
#ifdef NSS_ENABLE_TLS13_SHORT_HEADERS
|
||||
PR_TRUE /* enableShortHeaders */
|
||||
PR_TRUE, /* enableShortHeaders */
|
||||
#else
|
||||
PR_FALSE /* enableShortHeaders */
|
||||
PR_FALSE, /* enableShortHeaders */
|
||||
#endif
|
||||
PR_FALSE /* enableAltHandshaketype */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -3840,3 +3842,48 @@ SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey,
|
|||
*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
|
||||
EXP(UseAltServerHelloType),
|
||||
#endif
|
||||
{ "", NULL }
|
||||
};
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -4475,6 +4475,17 @@ tls13_EncodeDraftVersion(SSL3ProtocolVersion version)
|
|||
return (PRUint16)version;
|
||||
}
|
||||
|
||||
PRUint16
|
||||
tls13_EncodeAltDraftVersion(SSL3ProtocolVersion version)
|
||||
{
|
||||
#ifdef TLS_1_3_DRAFT_VERSION
|
||||
if (version == SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
return 0x7a00 | TLS_1_3_DRAFT_VERSION;
|
||||
}
|
||||
#endif
|
||||
return (PRUint16)version;
|
||||
}
|
||||
|
||||
/* Pick the highest version we support that is also advertised. */
|
||||
SECStatus
|
||||
tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions)
|
||||
|
@ -4496,6 +4507,7 @@ tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions)
|
|||
}
|
||||
for (version = ss->vrange.max; version >= ss->vrange.min; --version) {
|
||||
PRUint16 wire = tls13_EncodeDraftVersion(version);
|
||||
PRUint16 alt_wire = tls13_EncodeAltDraftVersion(version);
|
||||
unsigned long offset;
|
||||
|
||||
for (offset = 0; offset < versions.len; offset += 2) {
|
||||
|
@ -4505,9 +4517,33 @@ tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions)
|
|||
ss->version = version;
|
||||
return SECSuccess;
|
||||
}
|
||||
if (ss->opt.enableAltHandshaketype && !IS_DTLS(ss) &&
|
||||
supported == alt_wire) {
|
||||
ss->version = version;
|
||||
ss->ssl3.hs.altHandshakeType = PR_TRUE;
|
||||
return SECSuccess;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_VERSION, protocol_version);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SSLExp_UseAltServerHelloType(PRFileDesc *fd, PRBool enable)
|
||||
{
|
||||
sslSocket *ss;
|
||||
|
||||
ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
SSL_DBG(("%d: SSL[%d]: bad socket in SSLExp_UseAltServerHelloType",
|
||||
SSL_GETPID(), fd));
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ss->opt.enableAltHandshaketype = enable;
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
|
|
@ -81,9 +81,10 @@ SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss);
|
|||
SECStatus tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf);
|
||||
PRBool tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid);
|
||||
PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version);
|
||||
PRUint16 tls13_DecodeDraftVersion(PRUint16 version);
|
||||
PRUint16 tls13_EncodeAltDraftVersion(SSL3ProtocolVersion version);
|
||||
SECStatus tls13_NegotiateVersion(sslSocket *ss,
|
||||
const TLSExtension *supported_versions);
|
||||
SECStatus tls13_SendNewSessionTicket(sslSocket *ss);
|
||||
SECStatus SSLExp_UseAltServerHelloType(PRFileDesc *fd, PRBool enable);
|
||||
|
||||
#endif /* __tls13con_h_ */
|
||||
|
|
|
@ -896,6 +896,10 @@ tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD
|
|||
extensions_len = 2 + 2 + 1 +
|
||||
2 * (ss->vrange.max - ss->vrange.min + 1);
|
||||
|
||||
if (ss->opt.enableAltHandshaketype && !IS_DTLS(ss)) {
|
||||
extensions_len += 2;
|
||||
}
|
||||
|
||||
if (maxBytes < (PRUint32)extensions_len) {
|
||||
PORT_Assert(0);
|
||||
return 0;
|
||||
|
@ -914,6 +918,15 @@ tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD
|
|||
if (rv != SECSuccess)
|
||||
return -1;
|
||||
|
||||
if (ss->opt.enableAltHandshaketype && !IS_DTLS(ss)) {
|
||||
rv = ssl3_ExtAppendHandshakeNumber(
|
||||
ss, tls13_EncodeAltDraftVersion(
|
||||
SSL_LIBRARY_VERSION_TLS_1_3),
|
||||
2);
|
||||
if (rv != SECSuccess)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (version = ss->vrange.max; version >= ss->vrange.min; --version) {
|
||||
rv = ssl3_ExtAppendHandshakeNumber(
|
||||
ss, tls13_EncodeDraftVersion(version), 2);
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
* The format of the version string should be
|
||||
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
|
||||
*/
|
||||
#define NSSUTIL_VERSION "3.32"
|
||||
#define NSSUTIL_VERSION "3.33 Beta"
|
||||
#define NSSUTIL_VMAJOR 3
|
||||
#define NSSUTIL_VMINOR 32
|
||||
#define NSSUTIL_VMINOR 33
|
||||
#define NSSUTIL_VPATCH 0
|
||||
#define NSSUTIL_VBUILD 0
|
||||
#define NSSUTIL_BETA PR_FALSE
|
||||
#define NSSUTIL_BETA PR_TRUE
|
||||
|
||||
SEC_BEGIN_PROTOS
|
||||
|
||||
|
|
|
@ -1841,13 +1841,11 @@ secoid_FindDynamic(const SECItem *key)
|
|||
{
|
||||
SECOidData *ret = NULL;
|
||||
|
||||
if (dynOidHash) {
|
||||
NSSRWLock_LockRead(dynOidLock);
|
||||
if (dynOidHash) { /* must check it again with lock held. */
|
||||
if (dynOidHash) {
|
||||
ret = (SECOidData *)PL_HashTableLookup(dynOidHash, key);
|
||||
}
|
||||
NSSRWLock_UnlockRead(dynOidLock);
|
||||
}
|
||||
if (ret == NULL) {
|
||||
PORT_SetError(SEC_ERROR_UNRECOGNIZED_OID);
|
||||
}
|
||||
|
@ -1866,14 +1864,12 @@ secoid_FindDynamicByTag(SECOidTag tagnum)
|
|||
}
|
||||
tagNumDiff = tagnum - SEC_OID_TOTAL;
|
||||
|
||||
if (dynOidTable) {
|
||||
NSSRWLock_LockRead(dynOidLock);
|
||||
if (dynOidTable != NULL && /* must check it again with lock held. */
|
||||
if (dynOidTable != NULL &&
|
||||
tagNumDiff < dynOidEntriesUsed) {
|
||||
dxo = dynOidTable[tagNumDiff];
|
||||
}
|
||||
NSSRWLock_UnlockRead(dynOidLock);
|
||||
}
|
||||
if (dxo == NULL) {
|
||||
PORT_SetError(SEC_ERROR_UNRECOGNIZED_OID);
|
||||
}
|
||||
|
|
|
@ -20,12 +20,16 @@ cwd = os.path.dirname(os.path.abspath(__file__))
|
|||
|
||||
class cfAction(argparse.Action):
|
||||
docker_command = ["docker"]
|
||||
restorecon = None
|
||||
|
||||
def __call__(self, parser, args, values, option_string=None):
|
||||
if "noroot" not in values:
|
||||
self.setDockerCommand()
|
||||
else:
|
||||
values.remove("noroot")
|
||||
files = [os.path.join('/home/worker/nss',
|
||||
os.path.relpath(os.path.abspath(x), start=cwd))
|
||||
for x in values]
|
||||
|
||||
# First check if we can run docker.
|
||||
try:
|
||||
|
@ -55,10 +59,12 @@ class cfAction(argparse.Action):
|
|||
self.buildImage(docker_image, cf_docker_folder)
|
||||
|
||||
command = self.docker_command + [
|
||||
'run', '-v', cwd + ':/home/worker/nss', '--rm', '-ti', docker_image
|
||||
'run', '-v', cwd + ':/home/worker/nss:Z', '--rm', '-ti', docker_image
|
||||
]
|
||||
# The clang format script returns 1 if something's to do. We don't care.
|
||||
subprocess.call(command + values)
|
||||
subprocess.call(command + files)
|
||||
if self.restorecon is not None:
|
||||
subprocess.call([self.restorecon, '-R', cwd])
|
||||
|
||||
def filesChanged(self, path):
|
||||
hash = sha256()
|
||||
|
@ -87,6 +93,8 @@ class cfAction(argparse.Action):
|
|||
|
||||
def setDockerCommand(self):
|
||||
if platform.system() == "Linux":
|
||||
from distutils.spawn import find_executable
|
||||
self.restorecon = find_executable('restorecon')
|
||||
self.docker_command = ["sudo"] + self.docker_command
|
||||
|
||||
|
||||
|
@ -114,6 +122,13 @@ class testAction(argparse.Action):
|
|||
self.runTest(values)
|
||||
|
||||
|
||||
class commandsAction(argparse.Action):
|
||||
commands = []
|
||||
def __call__(self, parser, args, values, option_string=None):
|
||||
for c in commandsAction.commands:
|
||||
print(c)
|
||||
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='NSS helper script. ' +
|
||||
|
@ -143,6 +158,16 @@ def parse_arguments():
|
|||
]
|
||||
parser_test.add_argument(
|
||||
'test', choices=tests, help="Available tests", action=testAction)
|
||||
|
||||
parser_commands = subparsers.add_parser(
|
||||
'mach-commands',
|
||||
help="list commands")
|
||||
parser_commands.add_argument(
|
||||
'mach-commands',
|
||||
nargs='*',
|
||||
action=commandsAction)
|
||||
|
||||
commandsAction.commands = [c for c in subparsers.choices]
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
|
|
|
@ -168,6 +168,7 @@
|
|||
'gtests/certdb_gtest/certdb_gtest.gyp:certdb_gtest',
|
||||
'gtests/freebl_gtest/freebl_gtest.gyp:prng_gtest',
|
||||
'gtests/pk11_gtest/pk11_gtest.gyp:pk11_gtest',
|
||||
'gtests/softoken_gtest/softoken_gtest.gyp:softoken_gtest',
|
||||
'gtests/ssl_gtest/ssl_gtest.gyp:ssl_gtest',
|
||||
'gtests/util_gtest/util_gtest.gyp:util_gtest',
|
||||
'gtests/nss_bogo_shim/nss_bogo_shim.gyp:nss_bogo_shim',
|
||||
|
|
|
@ -83,7 +83,7 @@ gtest_cleanup()
|
|||
}
|
||||
|
||||
################## main #################################################
|
||||
GTESTS="prng_gtest certhigh_gtest certdb_gtest der_gtest pk11_gtest util_gtest freebl_gtest"
|
||||
GTESTS="prng_gtest certhigh_gtest certdb_gtest der_gtest pk11_gtest util_gtest freebl_gtest softoken_gtest"
|
||||
SOURCE_DIR="$PWD"/../..
|
||||
gtest_init $0
|
||||
gtest_start
|
||||
|
|
Загрузка…
Ссылка в новой задаче