diff options
Diffstat (limited to 'security/nss/gtests/nss_bogo_shim')
-rw-r--r-- | security/nss/gtests/nss_bogo_shim/config.h | 4 | ||||
-rw-r--r-- | security/nss/gtests/nss_bogo_shim/config.json | 21 | ||||
-rw-r--r-- | security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc | 254 | ||||
-rw-r--r-- | security/nss/gtests/nss_bogo_shim/nss_bogo_shim.gyp | 21 | ||||
-rw-r--r-- | security/nss/gtests/nss_bogo_shim/nsskeys.cc | 1 |
5 files changed, 219 insertions, 82 deletions
diff --git a/security/nss/gtests/nss_bogo_shim/config.h b/security/nss/gtests/nss_bogo_shim/config.h index 3764783bc..822df65b3 100644 --- a/security/nss/gtests/nss_bogo_shim/config.h +++ b/security/nss/gtests/nss_bogo_shim/config.h @@ -65,8 +65,8 @@ class Config { template <typename T> void AddEntry(const std::string& name, T init) { - entries_[name] = std::unique_ptr<ConfigEntryBase>( - new ConfigEntry<T>(name, init)); + entries_[name] = + std::unique_ptr<ConfigEntryBase>(new ConfigEntry<T>(name, init)); } Status ParseArgs(int argc, char** argv); diff --git a/security/nss/gtests/nss_bogo_shim/config.json b/security/nss/gtests/nss_bogo_shim/config.json index 0a6864f73..4109bd2ca 100644 --- a/security/nss/gtests/nss_bogo_shim/config.json +++ b/security/nss/gtests/nss_bogo_shim/config.json @@ -5,7 +5,6 @@ "#*HelloRetryRequest*":"(NSS=18, BoGo=16)", "#*KeyShare*":"(NSS=18, BoGo=16)", "#*EncryptedExtensions*":"(NSS=18, BoGo=16)", - "#*ServerHelloSignatureAlgorithms*":"(NSS=18, BoGo=16)", "#*SecondClientHello*":"(NSS=18, BoGo=16)", "#*IgnoreClientVersionOrder*":"(NSS=18, BoGo=16)", "Resume-Server-BinderWrongLength":"Alert disagreement (Bug 1317633)", @@ -13,27 +12,21 @@ "CheckRecordVersion-TLS*":"Bug 1317634", "GREASE-Server-TLS13":"BoringSSL GREASEs without a flag, but we ignore it", "TLS13-ExpectNoSessionTicketOnBadKEMode-Server":"Bug in NSS. Don't send ticket when not permitted by KE modes (Bug 1317635)", - "Resume-Server-InvalidPSKBinder":"(Bogo incorrectly expects 'illegal_parameter')", - "FallbackSCSV-VersionMatch":"Draft version mismatch (NSS=15, BoGo=14)", "*KeyUpdate*":"KeyUpdate Unimplemented", "ClientAuth-NoFallback-TLS13":"Disagreement about alerts. Bug 1294975", - "ClientAuth-SHA1-Fallback":"Disagreement about alerts. Bug 1294975", "SendWarningAlerts-TLS13":"NSS needs to trigger on warning alerts", "NoSupportedCurves":"This tests a non-spec behavior for TLS 1.2 and expects the wrong alert for TLS 1.3", "SendEmptyRecords":"Tests a non-spec behavior in BoGo where it chokes on too many empty records", "LargePlaintext":"NSS needs to check for over-long records. Bug 1294978", "TLS13-RC4-MD5-server":"This fails properly but returns an unexpected error. Not a bug but needs cleanup", - "*VersionTolerance":"BoGo expects us to negotiate 1.3 but we negotiate 1.2 because BoGo didn't send draft version", "*SSL3*":"NSS disables SSLv3", "*SSLv3*":"NSS disables SSLv3", "*AES256*":"Inconsistent support for AES256", "*AES128-SHA256*":"No support for Suite B ciphers", - "*CHACHA20-POLY1305-OLD*":"Old ChaCha/Poly", "DuplicateExtension*":"NSS sends unexpected_extension alert", "WeakDH":"NSS supports 768-bit DH", "SillyDH":"NSS supports 4097-bit DH", "SendWarningAlerts":"This appears to be Boring-specific", - "V2ClientHello-WarningAlertPrefix":"Bug 1292893", "TLS12-AES128-GCM-client":"Bug 1292895", "*TLS12-AES128-GCM-LargeRecord*":"Bug 1292895", "Renegotiate-Client-Forbidden-1":"Bug 1292898", @@ -51,11 +44,19 @@ "WrongMessageType-TLS13-ServerFinished":"nss updated/broken", "EncryptedExtensionsWithKeyShare":"nss updated/broken", "EmptyEncryptedExtensions":"nss updated/broken", - "ClientAuth-SHA1-Fallback-RSA":"We fail when the sig_algs_ext is empty", - "Downgrade-TLS12-*":"NSS implements downgrade detection", "TrailingMessageData-*": "Bug 1304575", "DuplicateKeyShares":"Bug 1304578", - "Resume-Server-TLS13-TLS13":"Bug 1314351" + "Resume-Server-TLS13-TLS13":"Bug 1314351", + "SkipEarlyData-Interleaved":"Bug 1336916", + "ECDSAKeyUsage-TLS1*":"Bug 1338194", + "PointFormat-Client-MissingUncompressed":"We ignore ec_point_formats extensions sent by servers.", + "SkipEarlyData-SecondClientHelloEarlyData":"Boring doesn't reject early_data in the 2nd CH but fails later with bad_record_mac.", + "SkipEarlyData-*TooMuchData":"Bug 1339373", + "UnsolicitedServerNameAck-TLS1*":"Boring wants us to fail with an unexpected_extension alert, we simply ignore ssl_server_name_xtn.", + "RequireAnyClientCertificate-TLS1*":"Bug 1339387", + "SendExtensionOnClientCertificate-TLS13":"Bug 1339392", + "ALPNClient-Mismatch-TLS13":"NSS sends alerts in response to errors in protected handshake messages in the clear", + "P224-Server":"NSS doesn't support P-224" }, "ErrorMap" : { ":HANDSHAKE_FAILURE_ON_CLIENT_HELLO:":"SSL_ERROR_NO_CYPHER_OVERLAP", diff --git a/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc b/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc index a128cbb05..e12714e8d 100644 --- a/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc +++ b/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc @@ -12,19 +12,16 @@ #include "nss.h" #include "prio.h" #include "prnetdb.h" +#include "secerr.h" #include "ssl.h" +#include "ssl3prot.h" #include "sslerr.h" #include "sslproto.h" #include "nsskeys.h" -static const char* kVersionDisableFlags[] = { - "no-ssl3", - "no-tls1", - "no-tls11", - "no-tls12", - "no-tls13" -}; +static const char* kVersionDisableFlags[] = {"no-ssl3", "no-tls1", "no-tls11", + "no-tls12", "no-tls13"}; bool exitCodeUnimplemented = false; @@ -119,16 +116,17 @@ class TestAgent { if (cfg_.get<std::string>("key-file") != "") { key_ = ReadPrivateKey(cfg_.get<std::string>("key-file")); - if (!key_) { - // Temporary to handle our inability to handle ECDSA. - exitCodeUnimplemented = true; - return false; - } + if (!key_) return false; } if (cfg_.get<std::string>("cert-file") != "") { cert_ = ReadCertificate(cfg_.get<std::string>("cert-file")); if (!cert_) return false; } + + // Needed because certs are not entirely valid. + rv = SSL_AuthCertificateHook(ssl_fd_, AuthCertificateHook, this); + if (rv != SECSuccess) return false; + if (cfg_.get<bool>("server")) { // Server rv = SSL_ConfigServerCert(ssl_fd_, cert_, key_, nullptr, 0); @@ -136,19 +134,54 @@ class TestAgent { std::cerr << "Couldn't configure server cert\n"; return false; } - } else { - // Client. - // Needed because server certs are not entirely valid. - rv = SSL_AuthCertificateHook(ssl_fd_, AuthCertificateHook, this); + } else if (key_ && cert_) { + // Client. + rv = SSL_GetClientAuthDataHook(ssl_fd_, GetClientAuthDataHook, this); if (rv != SECSuccess) return false; + } - if (key_ && cert_) { - rv = SSL_GetClientAuthDataHook(ssl_fd_, GetClientAuthDataHook, this); - if (rv != SECSuccess) return false; - } + return true; + } + + static bool ConvertFromWireVersion(SSLProtocolVariant variant, + int wire_version, uint16_t* lib_version) { + // These default values are used when {min,max}-version isn't given. + if (wire_version == 0 || wire_version == 0xffff) { + *lib_version = static_cast<uint16_t>(wire_version); + return true; + } + +#ifdef TLS_1_3_DRAFT_VERSION + if (wire_version == (0x7f00 | TLS_1_3_DRAFT_VERSION)) { + // N.B. SSL_LIBRARY_VERSION_DTLS_1_3_WIRE == SSL_LIBRARY_VERSION_TLS_1_3 + wire_version = SSL_LIBRARY_VERSION_TLS_1_3; } +#endif + if (variant == ssl_variant_datagram) { + switch (wire_version) { + case SSL_LIBRARY_VERSION_DTLS_1_0_WIRE: + *lib_version = SSL_LIBRARY_VERSION_DTLS_1_0; + break; + case SSL_LIBRARY_VERSION_DTLS_1_2_WIRE: + *lib_version = SSL_LIBRARY_VERSION_DTLS_1_2; + break; + case SSL_LIBRARY_VERSION_DTLS_1_3_WIRE: + *lib_version = SSL_LIBRARY_VERSION_DTLS_1_3; + break; + default: + std::cerr << "Unrecognized DTLS version " << wire_version << ".\n"; + return false; + } + } else { + if (wire_version < SSL_LIBRARY_VERSION_3_0 || + wire_version > SSL_LIBRARY_VERSION_TLS_1_3) { + std::cerr << "Unrecognized TLS version " << wire_version << ".\n"; + return false; + } + *lib_version = static_cast<uint16_t>(wire_version); + } return true; } @@ -158,27 +191,18 @@ class TestAgent { return false; } - auto max_allowed = static_cast<uint16_t>(cfg_.get<int>("max-version")); - if (variant == ssl_variant_datagram) { - // For DTLS this is the wire version; adjust if needed. - switch (max_allowed) { - case SSL_LIBRARY_VERSION_DTLS_1_0_WIRE: - max_allowed = SSL_LIBRARY_VERSION_DTLS_1_0; - break; - case SSL_LIBRARY_VERSION_DTLS_1_2_WIRE: - max_allowed = SSL_LIBRARY_VERSION_DTLS_1_2; - break; - case SSL_LIBRARY_VERSION_DTLS_1_3_WIRE: - max_allowed = SSL_LIBRARY_VERSION_DTLS_1_3; - break; - case 0xffff: // No maximum specified. - break; - default: - // Unrecognized DTLS version. - return false; - } + uint16_t min_allowed; + uint16_t max_allowed; + if (!ConvertFromWireVersion(variant, cfg_.get<int>("min-version"), + &min_allowed)) { + return false; + } + if (!ConvertFromWireVersion(variant, cfg_.get<int>("max-version"), + &max_allowed)) { + return false; } + min_allowed = std::max(min_allowed, supported.min); max_allowed = std::min(max_allowed, supported.max); bool found_min = false; @@ -186,7 +210,7 @@ class TestAgent { // Ignore -no-ssl3, because SSLv3 is never supported. for (size_t i = 1; i < PR_ARRAY_SIZE(kVersionDisableFlags); ++i) { auto version = - static_cast<uint16_t>(SSL_LIBRARY_VERSION_TLS_1_0 + (i - 1)); + static_cast<uint16_t>(SSL_LIBRARY_VERSION_TLS_1_0 + (i - 1)); if (variant == ssl_variant_datagram) { // In DTLS mode, the -no-tlsN flags refer to DTLS versions, // but NSS wants the corresponding TLS versions. @@ -199,7 +223,7 @@ class TestAgent { } } - if (version < supported.min) { + if (version < min_allowed) { continue; } if (version > max_allowed) { @@ -220,12 +244,14 @@ class TestAgent { } } if (found_max && allowed) { - // Discontiguous range. + std::cerr << "Discontiguous version range.\n"; return false; } } - // Iff found_min is still false, no usable version was found. + if (!found_min) { + std::cerr << "All versions disabled.\n"; + } return found_min; } @@ -239,9 +265,56 @@ class TestAgent { rv = SSL_VersionRangeSet(ssl_fd_, &vrange); if (rv != SECSuccess) return false; + SSLVersionRange verify_vrange; + rv = SSL_VersionRangeGet(ssl_fd_, &verify_vrange); + if (rv != SECSuccess) return false; + if (vrange.min != verify_vrange.min || vrange.max != verify_vrange.max) + return false; + rv = SSL_OptionSet(ssl_fd_, SSL_NO_CACHE, false); if (rv != SECSuccess) return false; + auto alpn = cfg_.get<std::string>("advertise-alpn"); + if (!alpn.empty()) { + assert(!cfg_.get<bool>("server")); + + rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_ALPN, PR_TRUE); + if (rv != SECSuccess) return false; + + rv = SSL_SetNextProtoNego( + ssl_fd_, reinterpret_cast<const unsigned char*>(alpn.c_str()), + alpn.size()); + if (rv != SECSuccess) return false; + } + + if (cfg_.get<bool>("fallback-scsv")) { + rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_FALLBACK_SCSV, PR_TRUE); + if (rv != SECSuccess) return false; + } + + if (cfg_.get<bool>("false-start")) { + rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_FALSE_START, PR_TRUE); + if (rv != SECSuccess) return false; + } + + if (cfg_.get<bool>("enable-ocsp-stapling")) { + rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_OCSP_STAPLING, PR_TRUE); + if (rv != SECSuccess) return false; + } + + bool requireClientCert = cfg_.get<bool>("require-any-client-certificate"); + if (requireClientCert || cfg_.get<bool>("verify-peer")) { + assert(cfg_.get<bool>("server")); + + rv = SSL_OptionSet(ssl_fd_, SSL_REQUEST_CERTIFICATE, PR_TRUE); + if (rv != SECSuccess) return false; + + rv = SSL_OptionSet( + ssl_fd_, SSL_REQUIRE_CERTIFICATE, + requireClientCert ? SSL_REQUIRE_ALWAYS : SSL_REQUIRE_NO_ERROR); + if (rv != SECSuccess) return false; + } + if (!cfg_.get<bool>("server")) { // Needed to make resumption work. rv = SSL_SetURL(ssl_fd_, "server"); @@ -312,12 +385,53 @@ class TestAgent { rv = PR_Write(ssl_fd_, block, len); if (rv != len) { std::cerr << "Write failure\n"; + PORT_SetError(SEC_ERROR_OUTPUT_LEN); return SECFailure; } } return SECSuccess; } + // Write bytes to the other side then read them back and check + // that they were correctly XORed as in ReadWrite. + SECStatus WriteRead() { + static const uint8_t ch = 'E'; + + // We do 600-byte blocks to provide mis-alignment of the + // reader and writer. + uint8_t block[600]; + memset(block, ch, sizeof(block)); + int32_t rv = PR_Write(ssl_fd_, block, sizeof(block)); + if (rv != sizeof(block)) { + std::cerr << "Write failure\n"; + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + return SECFailure; + } + + size_t left = sizeof(block); + while (left) { + int32_t rv = PR_Read(ssl_fd_, block, left); + if (rv < 0) { + std::cerr << "Failure reading\n"; + return SECFailure; + } + if (rv == 0) { + PORT_SetError(SEC_ERROR_INPUT_LEN); + return SECFailure; + } + + int32_t len = rv; + for (int32_t i = 0; i < len; ++i) { + if (block[i] != (ch ^ 0xff)) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + } + left -= len; + } + return SECSuccess; + } + SECStatus DoExchange() { SECStatus rv = Handshake(); if (rv != SECSuccess) { @@ -327,12 +441,44 @@ class TestAgent { return SECFailure; } - rv = ReadWrite(); - if (rv != SECSuccess) { - PRErrorCode err = PR_GetError(); - std::cerr << "ReadWrite failed with error=" << FormatError(err) - << std::endl; - return SECFailure; + if (cfg_.get<bool>("write-then-read")) { + rv = WriteRead(); + if (rv != SECSuccess) { + PRErrorCode err = PR_GetError(); + std::cerr << "WriteRead failed with error=" << FormatError(err) + << std::endl; + return SECFailure; + } + } else { + rv = ReadWrite(); + if (rv != SECSuccess) { + PRErrorCode err = PR_GetError(); + std::cerr << "ReadWrite failed with error=" << FormatError(err) + << std::endl; + return SECFailure; + } + } + + auto alpn = cfg_.get<std::string>("expect-alpn"); + if (!alpn.empty()) { + SSLNextProtoState state; + char chosen[256]; + unsigned int chosen_len; + rv = SSL_GetNextProto(ssl_fd_, &state, + reinterpret_cast<unsigned char*>(chosen), + &chosen_len, sizeof(chosen)); + if (rv != SECSuccess) { + PRErrorCode err = PR_GetError(); + std::cerr << "SSL_GetNextProto failed with error=" << FormatError(err) + << std::endl; + return SECFailure; + } + + assert(chosen_len <= sizeof(chosen)); + if (std::string(chosen, chosen_len) != alpn) { + std::cerr << "Unexpected ALPN selection" << std::endl; + return SECFailure; + } } return SECSuccess; @@ -354,10 +500,19 @@ std::unique_ptr<const Config> ReadConfig(int argc, char** argv) { cfg->AddEntry<int>("resume-count", 0); cfg->AddEntry<std::string>("key-file", ""); cfg->AddEntry<std::string>("cert-file", ""); + cfg->AddEntry<int>("min-version", 0); cfg->AddEntry<int>("max-version", 0xffff); for (auto flag : kVersionDisableFlags) { cfg->AddEntry<bool>(flag, false); } + cfg->AddEntry<bool>("fallback-scsv", false); + cfg->AddEntry<bool>("false-start", false); + cfg->AddEntry<bool>("enable-ocsp-stapling", false); + cfg->AddEntry<bool>("write-then-read", false); + cfg->AddEntry<bool>("require-any-client-certificate", false); + cfg->AddEntry<bool>("verify-peer", false); + cfg->AddEntry<std::string>("advertise-alpn", ""); + cfg->AddEntry<std::string>("expect-alpn", ""); auto rv = cfg->ParseArgs(argc, argv); switch (rv) { @@ -373,7 +528,6 @@ std::unique_ptr<const Config> ReadConfig(int argc, char** argv) { return std::move(cfg); } - bool RunCycle(std::unique_ptr<const Config>& cfg) { std::unique_ptr<TestAgent> agent(TestAgent::Create(*cfg)); return agent && agent->DoExchange() == SECSuccess; diff --git a/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.gyp b/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.gyp index f4f94e94b..b8f71f95f 100644 --- a/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.gyp +++ b/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.gyp @@ -35,10 +35,8 @@ '<(DEPTH)/lib/dev/dev.gyp:nssdev', '<(DEPTH)/lib/base/base.gyp:nssb', '<(DEPTH)/lib/freebl/freebl.gyp:freebl', - '<(DEPTH)/lib/nss/nss.gyp:nss_static', - '<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap', - '<(DEPTH)/lib/certhigh/certhigh.gyp:certhi', - '<(DEPTH)/lib/zlib/zlib.gyp:nss_zlib' + '<(DEPTH)/lib/zlib/zlib.gyp:nss_zlib', + '<(DEPTH)/lib/libpkix/libpkix.gyp:libpkix', ], 'conditions': [ [ 'disable_dbm==0', { @@ -46,21 +44,6 @@ '<(DEPTH)/lib/dbm/src/src.gyp:dbm', ], }], - [ 'disable_libpkix==0', { - 'dependencies': [ - '<(DEPTH)/lib/libpkix/pkix/certsel/certsel.gyp:pkixcertsel', - '<(DEPTH)/lib/libpkix/pkix/checker/checker.gyp:pkixchecker', - '<(DEPTH)/lib/libpkix/pkix/crlsel/crlsel.gyp:pkixcrlsel', - '<(DEPTH)/lib/libpkix/pkix/params/params.gyp:pkixparams', - '<(DEPTH)/lib/libpkix/pkix/results/results.gyp:pkixresults', - '<(DEPTH)/lib/libpkix/pkix/store/store.gyp:pkixstore', - '<(DEPTH)/lib/libpkix/pkix/top/top.gyp:pkixtop', - '<(DEPTH)/lib/libpkix/pkix/util/util.gyp:pkixutil', - '<(DEPTH)/lib/libpkix/pkix_pl_nss/system/system.gyp:pkixsystem', - '<(DEPTH)/lib/libpkix/pkix_pl_nss/module/module.gyp:pkixmodule', - '<(DEPTH)/lib/libpkix/pkix_pl_nss/pki/pki.gyp:pkixpki', - ], - }], ], } ], diff --git a/security/nss/gtests/nss_bogo_shim/nsskeys.cc b/security/nss/gtests/nss_bogo_shim/nsskeys.cc index 1b5e15bee..471dac362 100644 --- a/security/nss/gtests/nss_bogo_shim/nsskeys.cc +++ b/security/nss/gtests/nss_bogo_shim/nsskeys.cc @@ -63,7 +63,6 @@ SECKEYPrivateKey* ReadPrivateKey(const std::string& file) { PK11_FreeSlot(slot); SECITEM_FreeItem(&item, PR_FALSE); if (rv != SECSuccess) { - // This is probably due to this being an ECDSA key (Bug 1295121). std::cerr << "Couldn't import key " << PORT_ErrorToString(PORT_GetError()) << "\n"; return nullptr; |