Bug 1331280 - Generic telemetry probe for TLS handshake status. r=keeler
authorEKR <ekr@rtfm.com>
Tue, 14 Feb 2017 13:12:00 -0500
changeset 342920 064b9835eaec3dd129768a2ad7c6924196b0c7ed
parent 342919 266f172505701ffe81f84cc9138db3fc7426dc25
child 342921 d8e9eea586edd64641ddc2f22d3f204e61596abe
push id31366
push usercbook@mozilla.com
push dateWed, 15 Feb 2017 11:25:19 +0000
treeherdermozilla-central@c0807d6938c1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskeeler
bugs1331280
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1331280 - Generic telemetry probe for TLS handshake status. r=keeler
security/manager/ssl/nsNSSIOLayer.cpp
security/pkix/include/pkix/pkixnss.h
toolkit/components/telemetry/Histograms.json
toolkit/components/telemetry/histogram-whitelists.json
--- a/security/manager/ssl/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/nsNSSIOLayer.cpp
@@ -1142,16 +1142,50 @@ retryDueToTLSIntolerance(PRErrorCode err
     return false;
   }
 
   Telemetry::Accumulate(post, reason);
 
   return true;
 }
 
+// Ensure that we haven't added too many errors to fit.
+static_assert((SSL_ERROR_END_OF_LIST - SSL_ERROR_BASE) <= 256,
+              "too many SSL errors");
+static_assert((SEC_ERROR_END_OF_LIST - SEC_ERROR_BASE) <= 256,
+              "too many SEC errors");
+static_assert((PR_MAX_ERROR - PR_NSPR_ERROR_BASE) <= 128,
+              "too many NSPR errors");
+static_assert((mozilla::pkix::ERROR_BASE - mozilla::pkix::END_OF_LIST) < 31,
+              "too many moz::pkix errors");
+
+static void
+reportHandshakeResult(int32_t bytesTransferred, PRErrorCode err)
+{
+  uint32_t bucket;
+
+  if (bytesTransferred >= 0) {
+    bucket = 0;
+  } else if (IS_SSL_ERROR(err)) {
+    bucket = err - SSL_ERROR_BASE;
+    MOZ_ASSERT(bucket > 0);   // SSL_ERROR_EXPORT_ONLY_SERVER isn't used.
+  } else if (IS_SEC_ERROR(err)) {
+    bucket = (err - SEC_ERROR_BASE) + 256;
+  } else if ((err >= PR_NSPR_ERROR_BASE) && (err < PR_MAX_ERROR)) {
+    bucket = (err - PR_NSPR_ERROR_BASE) + 512;
+  } else if ((err >= mozilla::pkix::ERROR_BASE) &&
+             (err < mozilla::pkix::ERROR_LIMIT)) {
+    bucket = (err - mozilla::pkix::ERROR_BASE) + 640;
+  } else {
+    bucket = 671;
+  }
+
+  Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_RESULT, bucket);
+}
+
 int32_t
 checkHandshake(int32_t bytesTransfered, bool wasReading,
                PRFileDesc* ssl_layer_fd, nsNSSSocketInfo* socketInfo)
 {
   const PRErrorCode originalError = PR_GetError();
   PRErrorCode err = originalError;
 
   // This is where we work around all of those SSL servers that don't
@@ -1219,16 +1253,20 @@ checkHandshake(int32_t bytesTransfered, 
     if (wasReading)
       bytesTransfered = -1;
   }
 
   // TLS intolerant servers only cause the first transfer to fail, so let's
   // set the HandshakePending attribute to false so that we don't try the logic
   // above again in a subsequent transfer.
   if (handleHandshakeResultNow) {
+    // Report the result once for each handshake. Note that this does not
+    // get handshakes which are cancelled before any reads or writes
+    // happen.
+    reportHandshakeResult(bytesTransfered, originalError);
     socketInfo->SetHandshakeNotPending();
   }
 
   if (bytesTransfered < 0) {
     // Remember that we encountered an error so that getSocketInfoIfRunning
     // will correctly cause us to fail if another part of Gecko
     // (erroneously) calls an I/O function (PR_Send/PR_Recv/etc.) again on
     // this socket. Note that we use the original error because if we use
--- a/security/pkix/include/pkix/pkixnss.h
+++ b/security/pkix/include/pkix/pkixnss.h
@@ -82,16 +82,17 @@ enum ErrorCode
   MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE = ERROR_BASE + 5,
   MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE = ERROR_BASE + 6,
   MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH = ERROR_BASE + 7,
   MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING = ERROR_BASE + 8,
   MOZILLA_PKIX_ERROR_VALIDITY_TOO_LONG = ERROR_BASE + 9,
   MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING = ERROR_BASE + 10,
   MOZILLA_PKIX_ERROR_INVALID_INTEGER_ENCODING = ERROR_BASE + 11,
   MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME = ERROR_BASE + 12,
+  END_OF_LIST
 };
 
 void RegisterErrorTable();
 
 inline SECItem UnsafeMapInputToSECItem(Input input)
 {
   SECItem result = {
     siBuffer,
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -1924,16 +1924,24 @@
   "SSL_HANDSHAKE_VERSION": {
     "alert_emails": ["seceng-telemetry@mozilla.com"],
     "bug_numbers": [1250568],
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 16,
     "description": "SSL Version (1=tls1, 2=tls1.1, 3=tls1.2, 4=tls1.3)"
   },
+  "SSL_HANDSHAKE_RESULT": {
+    "alert_emails": ["seceng-telemetry@mozilla.com"],
+    "bug_numbers": [1331280],
+    "expires_in_version": "never",
+    "kind": "enumerated",
+    "n_values": 672,
+    "description": "SSL handshake result, 0=success, 1-255=NSS error offset, 256-511=SEC error offset + 256, 512-639=NSPR error offset + 512, 640-670=PKIX error, 671=unknown err"
+  },
   "SSL_TIME_UNTIL_READY": {
     "alert_emails": ["seceng-telemetry@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 60000,
     "n_buckets": 200,
     "description": "ms of SSL wait time including TCP and proxy tunneling"
   },
--- a/toolkit/components/telemetry/histogram-whitelists.json
+++ b/toolkit/components/telemetry/histogram-whitelists.json
@@ -1809,16 +1809,17 @@
     "DEVTOOLS_HEAP_SNAPSHOT_NODE_COUNT",
     "DEVTOOLS_HEAP_SNAPSHOT_EDGE_COUNT",
     "NETWORK_CACHE_HIT_RATE_PER_CACHE_SIZE",
     "NETWORK_CACHE_METADATA_FIRST_READ_SIZE",
     "NETWORK_CACHE_METADATA_SIZE",
     "NETWORK_CACHE_HASH_STATS",
     "SSL_CIPHER_SUITE_FULL",
     "SSL_CIPHER_SUITE_RESUMED",
+    "SSL_HANDSHAKE_RESULT",
     "SSL_REASONS_FOR_NOT_FALSE_STARTING",
     "SSL_CERT_VERIFICATION_ERRORS",
     "CERT_VALIDATION_SUCCESS_BY_CA",
     "CERT_PINNING_FAILURES_BY_CA",
     "CERT_PINNING_MOZ_RESULTS_BY_HOST",
     "CERT_PINNING_MOZ_TEST_RESULTS_BY_HOST",
     "GFX_CRASH",
     "GC_REASON_2",