Bug 1460617, land NSS 30a4b03cd9d1 UPGRADE_NSS_RELEASE, r=me
authorKai Engert <kaie@kuix.de>
Mon, 11 Jun 2018 20:12:02 +0200
changeset 422315 2af879207a80
parent 422314 9fb5a7ee3f35
child 422316 fddd866cc32c
push id34126
push userccoroiu@mozilla.com
push dateTue, 12 Jun 2018 09:19:49 +0000
treeherdermozilla-central@87b46cd1c941 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs1460617
milestone62.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 1460617, land NSS 30a4b03cd9d1 UPGRADE_NSS_RELEASE, r=me
security/nss/TAG-INFO
security/nss/automation/taskcluster/docker-hacl/Dockerfile
security/nss/cmd/pk1sign/pk1sign.c
security/nss/coreconf/coreconf.dep
security/nss/gtests/ssl_gtest/manifest.mn
security/nss/gtests/ssl_gtest/ssl_custext_unittest.cc
security/nss/gtests/ssl_gtest/ssl_gtest.gyp
security/nss/gtests/ssl_gtest/ssl_record_unittest.cc
security/nss/gtests/ssl_gtest/ssl_recordsize_unittest.cc
security/nss/gtests/ssl_gtest/tls_agent.cc
security/nss/gtests/ssl_gtest/tls_filter.cc
security/nss/gtests/ssl_gtest/tls_filter.h
security/nss/lib/ckfw/Makefile
security/nss/lib/ckfw/nssmkey/Makefile
security/nss/lib/ckfw/nssmkey/README
security/nss/lib/ckfw/nssmkey/ckmk.h
security/nss/lib/ckfw/nssmkey/ckmkver.c
security/nss/lib/ckfw/nssmkey/config.mk
security/nss/lib/ckfw/nssmkey/manchor.c
security/nss/lib/ckfw/nssmkey/manifest.mn
security/nss/lib/ckfw/nssmkey/mconstants.c
security/nss/lib/ckfw/nssmkey/mfind.c
security/nss/lib/ckfw/nssmkey/minst.c
security/nss/lib/ckfw/nssmkey/mobject.c
security/nss/lib/ckfw/nssmkey/mrsa.c
security/nss/lib/ckfw/nssmkey/msession.c
security/nss/lib/ckfw/nssmkey/mslot.c
security/nss/lib/ckfw/nssmkey/mtoken.c
security/nss/lib/ckfw/nssmkey/nssmkey.def
security/nss/lib/ckfw/nssmkey/nssmkey.h
security/nss/lib/ckfw/nssmkey/staticobj.c
security/nss/lib/freebl/dsa.c
security/nss/lib/freebl/ec.c
security/nss/lib/pkcs12/p12e.c
security/nss/lib/softoken/legacydb/pcertdb.c
security/nss/lib/softoken/sftkpwd.c
security/nss/lib/ssl/dtlscon.c
security/nss/lib/ssl/ssl.h
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3ext.c
security/nss/lib/ssl/ssl3ext.h
security/nss/lib/ssl/ssl3exthandle.c
security/nss/lib/ssl/ssl3exthandle.h
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslsock.c
security/nss/lib/ssl/sslspec.c
security/nss/lib/ssl/sslspec.h
security/nss/lib/ssl/sslt.h
security/nss/lib/ssl/tls13con.c
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-8232a58332dd
+30a4b03cd9d1
--- a/security/nss/automation/taskcluster/docker-hacl/Dockerfile
+++ b/security/nss/automation/taskcluster/docker-hacl/Dockerfile
@@ -3,18 +3,18 @@ FROM ubuntu:xenial
 MAINTAINER Franziskus Kiefer <franziskuskiefer@gmail.com>
 # Based on the HACL* image from Benjamin Beurdouche and
 # the original F* formula with Daniel Fabian
 
 # Pinned versions of HACL* (F* and KreMLin are pinned as submodules)
 ENV haclrepo https://github.com/mitls/hacl-star.git
 
 # Define versions of dependencies
-ENV opamv 4.04.2
-ENV haclversion e13326efee1a9910004dccbb56f3d7be6639e0b8
+ENV opamv 4.05.0
+ENV haclversion 1da331f9ef30e13269e45ae73bbe4a4bca679ae6
 
 # Install required packages and set versions
 ADD setup.sh /tmp/setup.sh
 RUN bash /tmp/setup.sh
 
 # Create user, add scripts.
 RUN useradd -ms /bin/bash worker
 WORKDIR /home/worker
--- a/security/nss/cmd/pk1sign/pk1sign.c
+++ b/security/nss/cmd/pk1sign/pk1sign.c
@@ -173,17 +173,17 @@ SignFile(FILE *outFile, PRFileDesc *inFi
     fputs("\n", outFile);
     ExportPublicKey(outFile, cert);
 
 loser:
     if (privKey) {
         SECKEY_DestroyPrivateKey(privKey);
     }
     if (data) {
-        PORT_Free(data);
+        PR_Free(data);
     }
     PORT_FreeArena(arena, PR_FALSE);
 
     return returnValue;
 }
 
 int
 main(int argc, char **argv)
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/security/nss/gtests/ssl_gtest/manifest.mn
+++ b/security/nss/gtests/ssl_gtest/manifest.mn
@@ -31,16 +31,17 @@ CPPSRCS = \
       ssl_gather_unittest.cc \
       ssl_gtest.cc \
       ssl_hrr_unittest.cc \
       ssl_keylog_unittest.cc \
       ssl_keyupdate_unittest.cc \
       ssl_loopback_unittest.cc \
       ssl_misc_unittest.cc \
       ssl_record_unittest.cc \
+      ssl_recordsize_unittest.cc \
       ssl_resumption_unittest.cc \
       ssl_renegotiation_unittest.cc \
       ssl_skip_unittest.cc \
       ssl_staticrsa_unittest.cc \
       ssl_tls13compat_unittest.cc \
       ssl_v2_client_hello_unittest.cc \
       ssl_version_unittest.cc \
       ssl_versionpolicy_unittest.cc \
--- a/security/nss/gtests/ssl_gtest/ssl_custext_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_custext_unittest.cc
@@ -63,16 +63,17 @@ static const uint16_t kManyExtensions[] 
     ssl_tls13_supported_versions_xtn,
     ssl_tls13_cookie_xtn,
     ssl_tls13_psk_key_exchange_modes_xtn,
     ssl_tls13_ticket_early_data_info_xtn,
     ssl_tls13_certificate_authorities_xtn,
     ssl_next_proto_nego_xtn,
     ssl_renegotiation_info_xtn,
     ssl_tls13_short_header_xtn,
+    ssl_record_size_limit_xtn,
     1,
     0xffff};
 // The list here includes all extensions we expect to use (SSL_MAX_EXTENSIONS),
 // plus the deprecated values (see sslt.h), and two extra dummy values.
 PR_STATIC_ASSERT((SSL_MAX_EXTENSIONS + 5) == PR_ARRAY_SIZE(kManyExtensions));
 
 void InstallManyWriters(std::shared_ptr<TlsAgent> agent,
                         SSLExtensionWriter writer, size_t *installed = nullptr,
--- a/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
+++ b/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
@@ -32,16 +32,17 @@
         'ssl_gather_unittest.cc',
         'ssl_gtest.cc',
         'ssl_hrr_unittest.cc',
         'ssl_keylog_unittest.cc',
         'ssl_keyupdate_unittest.cc',
         'ssl_loopback_unittest.cc',
         'ssl_misc_unittest.cc',
         'ssl_record_unittest.cc',
+        'ssl_recordsize_unittest.cc',
         'ssl_resumption_unittest.cc',
         'ssl_renegotiation_unittest.cc',
         'ssl_skip_unittest.cc',
         'ssl_staticrsa_unittest.cc',
         'ssl_tls13compat_unittest.cc',
         'ssl_v2_client_hello_unittest.cc',
         'ssl_version_unittest.cc',
         'ssl_versionpolicy_unittest.cc',
--- a/security/nss/gtests/ssl_gtest/ssl_record_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_record_unittest.cc
@@ -99,43 +99,57 @@ TEST_P(TlsPaddingTest, LastByteOfPadWron
                      plaintext_.data()[plaintext_.len() - 1] + 1, 1);
     Unpad(false);
   }
 }
 
 class RecordReplacer : public TlsRecordFilter {
  public:
   RecordReplacer(const std::shared_ptr<TlsAgent>& a, size_t size)
-      : TlsRecordFilter(a), enabled_(false), size_(size) {}
+      : TlsRecordFilter(a), size_(size) {
+    Disable();
+  }
 
   PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
                                     const DataBuffer& data,
                                     DataBuffer* changed) override {
-    if (!enabled_) {
-      return KEEP;
-    }
-
     EXPECT_EQ(kTlsApplicationDataType, header.content_type());
     changed->Allocate(size_);
 
     for (size_t i = 0; i < size_; ++i) {
       changed->data()[i] = i & 0xff;
     }
 
-    enabled_ = false;
+    Disable();
     return CHANGE;
   }
 
-  void Enable() { enabled_ = true; }
-
  private:
-  bool enabled_;
   size_t size_;
 };
 
+TEST_P(TlsConnectStream, BadRecordMac) {
+  EnsureTlsSetup();
+  Connect();
+  client_->SetFilter(std::make_shared<TlsRecordLastByteDamager>(client_));
+  ExpectAlert(server_, kTlsAlertBadRecordMac);
+  client_->SendData(10);
+
+  // Read from the client, get error.
+  uint8_t buf[10];
+  PRInt32 rv = PR_Read(server_->ssl_fd(), buf, sizeof(buf));
+  EXPECT_GT(0, rv);
+  EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, PORT_GetError());
+
+  // Read the server alert.
+  rv = PR_Read(client_->ssl_fd(), buf, sizeof(buf));
+  EXPECT_GT(0, rv);
+  EXPECT_EQ(SSL_ERROR_BAD_MAC_ALERT, PORT_GetError());
+}
+
 TEST_F(TlsConnectStreamTls13, LargeRecord) {
   EnsureTlsSetup();
 
   const size_t record_limit = 16384;
   auto replacer = MakeTlsFilter<RecordReplacer>(client_, record_limit);
   replacer->EnableDecryption();
   Connect();
 
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/ssl_recordsize_unittest.cc
@@ -0,0 +1,431 @@
+/* -*- 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 "secerr.h"
+#include "ssl.h"
+#include "sslerr.h"
+#include "sslproto.h"
+
+#include "gtest_utils.h"
+#include "scoped_ptrs.h"
+#include "tls_connect.h"
+#include "tls_filter.h"
+#include "tls_parser.h"
+
+namespace nss_test {
+
+// This class tracks the maximum size of record that was sent, both cleartext
+// and plain.  It only tracks records that have an outer type of
+// application_data.  In TLS 1.3, this includes handshake messages.
+class TlsRecordMaximum : public TlsRecordFilter {
+ public:
+  TlsRecordMaximum(const std::shared_ptr<TlsAgent>& a)
+      : TlsRecordFilter(a), max_ciphertext_(0), max_plaintext_(0) {}
+
+  size_t max_ciphertext() const { return max_ciphertext_; }
+  size_t max_plaintext() const { return max_plaintext_; }
+
+ protected:
+  PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+                                    const DataBuffer& record, size_t* offset,
+                                    DataBuffer* output) override {
+    std::cerr << "max: " << record << std::endl;
+    // Ignore unprotected packets.
+    if (header.content_type() != kTlsApplicationDataType) {
+      return KEEP;
+    }
+
+    max_ciphertext_ = (std::max)(max_ciphertext_, record.len());
+    return TlsRecordFilter::FilterRecord(header, record, offset, output);
+  }
+
+  PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+                                    const DataBuffer& data,
+                                    DataBuffer* changed) override {
+    max_plaintext_ = (std::max)(max_plaintext_, data.len());
+    return KEEP;
+  }
+
+ private:
+  size_t max_ciphertext_;
+  size_t max_plaintext_;
+};
+
+void CheckRecordSizes(const std::shared_ptr<TlsAgent>& agent,
+                      const std::shared_ptr<TlsRecordMaximum>& record_max,
+                      size_t config) {
+  uint16_t cipher_suite;
+  ASSERT_TRUE(agent->cipher_suite(&cipher_suite));
+
+  size_t expansion;
+  size_t iv;
+  switch (cipher_suite) {
+    case TLS_AES_128_GCM_SHA256:
+    case TLS_AES_256_GCM_SHA384:
+    case TLS_CHACHA20_POLY1305_SHA256:
+      expansion = 16;
+      iv = 0;
+      break;
+
+    case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+      expansion = 16;
+      iv = 8;
+      break;
+
+    case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+      // Expansion is 20 for the MAC.  Maximum block padding is 16.  Maximum
+      // padding is added when the input plus the MAC is an exact multiple of
+      // the block size.
+      expansion = 20 + 16 - ((config + 20) % 16);
+      iv = 16;
+      break;
+
+    default:
+      ADD_FAILURE() << "No expansion set for ciphersuite "
+                    << agent->cipher_suite_name();
+      return;
+  }
+
+  switch (agent->version()) {
+    case SSL_LIBRARY_VERSION_TLS_1_3:
+      EXPECT_EQ(0U, iv) << "No IV for TLS 1.3";
+      // We only have decryption in TLS 1.3.
+      EXPECT_EQ(config - 1, record_max->max_plaintext())
+          << "bad plaintext length for " << agent->role_str();
+      break;
+
+    case SSL_LIBRARY_VERSION_TLS_1_2:
+    case SSL_LIBRARY_VERSION_TLS_1_1:
+      expansion += iv;
+      break;
+
+    case SSL_LIBRARY_VERSION_TLS_1_0:
+      break;
+
+    default:
+      ADD_FAILURE() << "Unexpected version " << agent->version();
+      return;
+  }
+
+  EXPECT_EQ(config + expansion, record_max->max_ciphertext())
+      << "bad ciphertext length for " << agent->role_str();
+}
+
+TEST_P(TlsConnectGeneric, RecordSizeMaximum) {
+  uint16_t max_record_size =
+      (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) ? 16385 : 16384;
+  size_t send_size = (version_ >= SSL_LIBRARY_VERSION_TLS_1_3)
+                         ? max_record_size
+                         : max_record_size + 1;
+
+  EnsureTlsSetup();
+  auto client_max = MakeTlsFilter<TlsRecordMaximum>(client_);
+  client_max->EnableDecryption();
+  auto server_max = MakeTlsFilter<TlsRecordMaximum>(server_);
+  server_max->EnableDecryption();
+
+  Connect();
+  client_->SendData(send_size, send_size);
+  server_->SendData(send_size, send_size);
+  server_->ReadBytes(send_size);
+  client_->ReadBytes(send_size);
+
+  CheckRecordSizes(client_, client_max, max_record_size);
+  CheckRecordSizes(server_, server_max, max_record_size);
+}
+
+TEST_P(TlsConnectGeneric, RecordSizeMinimumClient) {
+  EnsureTlsSetup();
+  auto server_max = MakeTlsFilter<TlsRecordMaximum>(server_);
+  server_max->EnableDecryption();
+
+  client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
+  Connect();
+  SendReceive(127);  // Big enough for one record, allowing for 1+N splitting.
+
+  CheckRecordSizes(server_, server_max, 64);
+}
+
+TEST_P(TlsConnectGeneric, RecordSizeMinimumServer) {
+  EnsureTlsSetup();
+  auto client_max = MakeTlsFilter<TlsRecordMaximum>(client_);
+  client_max->EnableDecryption();
+
+  server_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
+  Connect();
+  SendReceive(127);
+
+  CheckRecordSizes(client_, client_max, 64);
+}
+
+TEST_P(TlsConnectGeneric, RecordSizeAsymmetric) {
+  EnsureTlsSetup();
+  auto client_max = MakeTlsFilter<TlsRecordMaximum>(client_);
+  client_max->EnableDecryption();
+  auto server_max = MakeTlsFilter<TlsRecordMaximum>(server_);
+  server_max->EnableDecryption();
+
+  client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
+  server_->SetOption(SSL_RECORD_SIZE_LIMIT, 100);
+  Connect();
+  SendReceive(127);
+
+  CheckRecordSizes(client_, client_max, 100);
+  CheckRecordSizes(server_, server_max, 64);
+}
+
+// This just modifies the encrypted payload so to include a few extra zeros.
+class TlsRecordExpander : public TlsRecordFilter {
+ public:
+  TlsRecordExpander(const std::shared_ptr<TlsAgent>& a, size_t expansion)
+      : TlsRecordFilter(a), expansion_(expansion) {}
+
+ protected:
+  virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+                                            const DataBuffer& data,
+                                            DataBuffer* changed) {
+    if (header.content_type() != kTlsApplicationDataType) {
+      return KEEP;
+    }
+    changed->Allocate(data.len() + expansion_);
+    changed->Write(0, data.data(), data.len());
+    return CHANGE;
+  }
+
+ private:
+  size_t expansion_;
+};
+
+// Tweak the plaintext of server records so that they exceed the client's limit.
+TEST_P(TlsConnectTls13, RecordSizePlaintextExceed) {
+  EnsureTlsSetup();
+  auto server_expand = MakeTlsFilter<TlsRecordExpander>(server_, 1);
+  server_expand->EnableDecryption();
+
+  client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
+  Connect();
+
+  server_->SendData(100);
+
+  client_->ExpectReadWriteError();
+  ExpectAlert(client_, kTlsAlertRecordOverflow);
+  client_->ReadBytes(100);
+  EXPECT_EQ(SSL_ERROR_RX_RECORD_TOO_LONG, client_->error_code());
+
+  // Consume the alert at the server.
+  server_->Handshake();
+  server_->CheckErrorCode(SSL_ERROR_RECORD_OVERFLOW_ALERT);
+}
+
+// Tweak the ciphertext of server records so that they greatly exceed the limit.
+// This requires a much larger expansion than for plaintext to trigger the
+// guard, which runs before decryption (current allowance is 304 octets).
+TEST_P(TlsConnectTls13, RecordSizeCiphertextExceed) {
+  EnsureTlsSetup();
+
+  client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
+  Connect();
+
+  auto server_expand = MakeTlsFilter<TlsRecordExpander>(server_, 320);
+  server_->SendData(100);
+
+  client_->ExpectReadWriteError();
+  ExpectAlert(client_, kTlsAlertRecordOverflow);
+  client_->ReadBytes(100);
+  EXPECT_EQ(SSL_ERROR_RX_RECORD_TOO_LONG, client_->error_code());
+
+  // Consume the alert at the server.
+  server_->Handshake();
+  server_->CheckErrorCode(SSL_ERROR_RECORD_OVERFLOW_ALERT);
+}
+
+// This indiscriminately adds padding to application data records.
+class TlsRecordPadder : public TlsRecordFilter {
+ public:
+  TlsRecordPadder(const std::shared_ptr<TlsAgent>& a, size_t padding)
+      : TlsRecordFilter(a), padding_(padding) {}
+
+ protected:
+  PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+                                    const DataBuffer& record, size_t* offset,
+                                    DataBuffer* output) override {
+    if (header.content_type() != kTlsApplicationDataType) {
+      return KEEP;
+    }
+
+    uint8_t inner_content_type;
+    DataBuffer plaintext;
+    if (!Unprotect(header, record, &inner_content_type, &plaintext)) {
+      return KEEP;
+    }
+
+    if (inner_content_type != kTlsApplicationDataType) {
+      return KEEP;
+    }
+
+    DataBuffer ciphertext;
+    bool ok =
+        Protect(header, inner_content_type, plaintext, &ciphertext, padding_);
+    EXPECT_TRUE(ok);
+    if (!ok) {
+      return KEEP;
+    }
+    *offset = header.Write(output, *offset, ciphertext);
+    return CHANGE;
+  }
+
+ private:
+  size_t padding_;
+};
+
+TEST_P(TlsConnectTls13, RecordSizeExceedPad) {
+  EnsureTlsSetup();
+  auto server_max = std::make_shared<TlsRecordMaximum>(server_);
+  auto server_expand = std::make_shared<TlsRecordPadder>(server_, 1);
+  server_->SetFilter(std::make_shared<ChainedPacketFilter>(
+      ChainedPacketFilterInit({server_max, server_expand})));
+  server_expand->EnableDecryption();
+
+  client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
+  Connect();
+
+  server_->SendData(100);
+
+  client_->ExpectReadWriteError();
+  ExpectAlert(client_, kTlsAlertRecordOverflow);
+  client_->ReadBytes(100);
+  EXPECT_EQ(SSL_ERROR_RX_RECORD_TOO_LONG, client_->error_code());
+
+  // Consume the alert at the server.
+  server_->Handshake();
+  server_->CheckErrorCode(SSL_ERROR_RECORD_OVERFLOW_ALERT);
+}
+
+TEST_P(TlsConnectGeneric, RecordSizeBadValues) {
+  EnsureTlsSetup();
+  EXPECT_EQ(SECFailure,
+            SSL_OptionSet(client_->ssl_fd(), SSL_RECORD_SIZE_LIMIT, 63));
+  EXPECT_EQ(SECFailure,
+            SSL_OptionSet(client_->ssl_fd(), SSL_RECORD_SIZE_LIMIT, -1));
+  EXPECT_EQ(SECFailure,
+            SSL_OptionSet(server_->ssl_fd(), SSL_RECORD_SIZE_LIMIT, 16386));
+  Connect();
+}
+
+TEST_P(TlsConnectGeneric, RecordSizeGetValues) {
+  EnsureTlsSetup();
+  int v;
+  EXPECT_EQ(SECSuccess,
+            SSL_OptionGet(client_->ssl_fd(), SSL_RECORD_SIZE_LIMIT, &v));
+  EXPECT_EQ(16385, v);
+  client_->SetOption(SSL_RECORD_SIZE_LIMIT, 300);
+  EXPECT_EQ(SECSuccess,
+            SSL_OptionGet(client_->ssl_fd(), SSL_RECORD_SIZE_LIMIT, &v));
+  EXPECT_EQ(300, v);
+  Connect();
+}
+
+// The value of the extension is capped by the maximum version of the client.
+TEST_P(TlsConnectGeneric, RecordSizeCapExtensionClient) {
+  EnsureTlsSetup();
+  client_->SetOption(SSL_RECORD_SIZE_LIMIT, 16385);
+  auto capture =
+      MakeTlsFilter<TlsExtensionCapture>(client_, ssl_record_size_limit_xtn);
+  capture->EnableDecryption();
+  Connect();
+
+  uint64_t val = 0;
+  EXPECT_TRUE(capture->extension().Read(0, 2, &val));
+  if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) {
+    EXPECT_EQ(16384U, val) << "Extension should be capped";
+  } else {
+    EXPECT_EQ(16385U, val);
+  }
+}
+
+// The value of the extension is capped by the maximum version of the server.
+TEST_P(TlsConnectGeneric, RecordSizeCapExtensionServer) {
+  EnsureTlsSetup();
+  server_->SetOption(SSL_RECORD_SIZE_LIMIT, 16385);
+  auto capture =
+      MakeTlsFilter<TlsExtensionCapture>(server_, ssl_record_size_limit_xtn);
+  capture->EnableDecryption();
+  Connect();
+
+  uint64_t val = 0;
+  EXPECT_TRUE(capture->extension().Read(0, 2, &val));
+  if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) {
+    EXPECT_EQ(16384U, val) << "Extension should be capped";
+  } else {
+    EXPECT_EQ(16385U, val);
+  }
+}
+
+// Damage the client extension and the handshake fails, but the server
+// doesn't generate a validation error.
+TEST_P(TlsConnectGenericPre13, RecordSizeClientExtensionInvalid) {
+  EnsureTlsSetup();
+  client_->SetOption(SSL_RECORD_SIZE_LIMIT, 1000);
+  static const uint8_t v[] = {0xf4, 0x1f};
+  MakeTlsFilter<TlsExtensionReplacer>(client_, ssl_record_size_limit_xtn,
+                                      DataBuffer(v, sizeof(v)));
+  ConnectExpectAlert(server_, kTlsAlertDecryptError);
+}
+
+// Special handling for TLS 1.3, where the alert isn't read.
+TEST_F(TlsConnectStreamTls13, RecordSizeClientExtensionInvalid) {
+  EnsureTlsSetup();
+  client_->SetOption(SSL_RECORD_SIZE_LIMIT, 1000);
+  static const uint8_t v[] = {0xf4, 0x1f};
+  MakeTlsFilter<TlsExtensionReplacer>(client_, ssl_record_size_limit_xtn,
+                                      DataBuffer(v, sizeof(v)));
+  client_->ExpectSendAlert(kTlsAlertBadRecordMac);
+  server_->ExpectSendAlert(kTlsAlertBadRecordMac);
+  ConnectExpectFail();
+}
+
+TEST_P(TlsConnectGeneric, RecordSizeServerExtensionInvalid) {
+  EnsureTlsSetup();
+  server_->SetOption(SSL_RECORD_SIZE_LIMIT, 1000);
+  static const uint8_t v[] = {0xf4, 0x1f};
+  auto replace = MakeTlsFilter<TlsExtensionReplacer>(
+      server_, ssl_record_size_limit_xtn, DataBuffer(v, sizeof(v)));
+  replace->EnableDecryption();
+  ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+}
+
+class RecordSizeDefaultsTest : public ::testing::Test {
+ public:
+  void SetUp() {
+    EXPECT_EQ(SECSuccess,
+              SSL_OptionGetDefault(SSL_RECORD_SIZE_LIMIT, &default_));
+  }
+  void TearDown() {
+    // Make sure to restore the default value at the end.
+    EXPECT_EQ(SECSuccess,
+              SSL_OptionSetDefault(SSL_RECORD_SIZE_LIMIT, default_));
+  }
+
+ private:
+  PRIntn default_ = 0;
+};
+
+TEST_F(RecordSizeDefaultsTest, RecordSizeBadValues) {
+  EXPECT_EQ(SECFailure, SSL_OptionSetDefault(SSL_RECORD_SIZE_LIMIT, 63));
+  EXPECT_EQ(SECFailure, SSL_OptionSetDefault(SSL_RECORD_SIZE_LIMIT, -1));
+  EXPECT_EQ(SECFailure, SSL_OptionSetDefault(SSL_RECORD_SIZE_LIMIT, 16386));
+}
+
+TEST_F(RecordSizeDefaultsTest, RecordSizeGetValue) {
+  int v;
+  EXPECT_EQ(SECSuccess, SSL_OptionGetDefault(SSL_RECORD_SIZE_LIMIT, &v));
+  EXPECT_EQ(16385, v);
+  EXPECT_EQ(SECSuccess, SSL_OptionSetDefault(SSL_RECORD_SIZE_LIMIT, 3000));
+  EXPECT_EQ(SECSuccess, SSL_OptionGetDefault(SSL_RECORD_SIZE_LIMIT, &v));
+  EXPECT_EQ(3000, v);
+}
+
+}  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/tls_agent.cc
+++ b/security/nss/gtests/ssl_gtest/tls_agent.cc
@@ -934,19 +934,19 @@ void TlsAgent::SendRecordDirect(const Tl
   SendDirect(buf);
 }
 
 static bool ErrorIsNonFatal(PRErrorCode code) {
   return code == PR_WOULD_BLOCK_ERROR || code == SSL_ERROR_RX_SHORT_DTLS_READ;
 }
 
 void TlsAgent::SendData(size_t bytes, size_t blocksize) {
-  uint8_t block[4096];
+  uint8_t block[16385];  // One larger than the maximum record size.
 
-  ASSERT_LT(blocksize, sizeof(block));
+  ASSERT_LE(blocksize, sizeof(block));
 
   while (bytes) {
     size_t tosend = std::min(blocksize, bytes);
 
     for (size_t i = 0; i < tosend; ++i) {
       block[i] = 0xff & send_ctr_;
       ++send_ctr_;
     }
--- a/security/nss/gtests/ssl_gtest/tls_filter.cc
+++ b/security/nss/gtests/ssl_gtest/tls_filter.cc
@@ -405,26 +405,28 @@ bool TlsRecordFilter::Unprotect(const Tl
   }
 
   return true;
 }
 
 bool TlsRecordFilter::Protect(const TlsRecordHeader& header,
                               uint8_t inner_content_type,
                               const DataBuffer& plaintext,
-                              DataBuffer* ciphertext) {
+                              DataBuffer* ciphertext, size_t padding) {
   if (!cipher_spec_ || header.content_type() != kTlsApplicationDataType) {
     *ciphertext = plaintext;
     return true;
   }
   if (g_ssl_gtest_verbose) {
     std::cerr << "protect: " << header.sequence_number() << std::endl;
   }
-  DataBuffer padded = plaintext;
-  padded.Write(padded.len(), inner_content_type, 1);
+  DataBuffer padded;
+  padded.Allocate(plaintext.len() + 1 + padding);
+  size_t offset = padded.Write(0, plaintext.data(), plaintext.len());
+  padded.Write(offset, inner_content_type, 1);
   return cipher_spec_->Protect(header, padded, ciphertext);
 }
 
 bool IsHelloRetry(const DataBuffer& body) {
   static const uint8_t ssl_hello_retry_random[] = {
       0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, 0xBE, 0x1D, 0x8C,
       0x02, 0x1E, 0x65, 0xB8, 0x91, 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB,
       0x8C, 0x5E, 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C};
--- a/security/nss/gtests/ssl_gtest/tls_filter.h
+++ b/security/nss/gtests/ssl_gtest/tls_filter.h
@@ -115,17 +115,18 @@ class TlsRecordFilter : public PacketFil
 
   // Enable decryption. This only works properly for TLS 1.3 and above.
   // Enabling it for lower version tests will cause undefined
   // behavior.
   void EnableDecryption();
   bool Unprotect(const TlsRecordHeader& header, const DataBuffer& cipherText,
                  uint8_t* inner_content_type, DataBuffer* plaintext);
   bool Protect(const TlsRecordHeader& header, uint8_t inner_content_type,
-               const DataBuffer& plaintext, DataBuffer* ciphertext);
+               const DataBuffer& plaintext, DataBuffer* ciphertext,
+               size_t padding = 0);
 
  protected:
   // There are two filter functions which can be overriden. Both are
   // called with the header and the record but the outer one is called
   // with a raw pointer to let you write into the buffer and lets you
   // do anything with this section of the stream. The inner one
   // just lets you change the record contents. By default, the
   // outer one calls the inner one, so if you override the outer
@@ -501,16 +502,32 @@ class TlsClientHelloVersionChanger : pub
   virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
                                                const DataBuffer& input,
                                                DataBuffer* output);
 
  private:
   std::weak_ptr<TlsAgent> server_;
 };
 
+// Damage a record.
+class TlsRecordLastByteDamager : public TlsRecordFilter {
+ public:
+  TlsRecordLastByteDamager(const std::shared_ptr<TlsAgent>& a)
+      : TlsRecordFilter(a) {}
+
+ protected:
+  PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+                                    const DataBuffer& data,
+                                    DataBuffer* changed) override {
+    *changed = data;
+    changed->data()[changed->len() - 1]++;
+    return CHANGE;
+  }
+};
+
 // This class selectively drops complete writes.  This relies on the fact that
 // writes in libssl are on record boundaries.
 class SelectiveDropFilter : public PacketFilter {
  public:
   SelectiveDropFilter(uint32_t pattern) : pattern_(pattern), counter_(0) {}
 
  protected:
   virtual PacketFilter::Action Filter(const DataBuffer& input,
--- a/security/nss/lib/ckfw/Makefile
+++ b/security/nss/lib/ckfw/Makefile
@@ -28,12 +28,8 @@ endif
 export:: private_export
 
 # can't do this in manifest.mn because OS_TARGET isn't defined there.
 ifeq (,$(filter-out WINNT WIN95,$(OS_TARGET)))
 ifdef NSS_BUILD_CAPI
 DIRS += capi
 endif
 endif
-
-#ifeq ($(OS_ARCH), Darwin)
-#DIRS += nssmkey
-#endif
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/Makefile
+++ /dev/null
@@ -1,72 +0,0 @@
-# 
-# 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 manifest.mn
-include $(CORE_DEPTH)/coreconf/config.mk
-include config.mk
-
-EXTRA_LIBS = \
-	$(DIST)/lib/$(LIB_PREFIX)nssckfw.$(LIB_SUFFIX) \
-	$(DIST)/lib/$(LIB_PREFIX)secutil.$(LIB_SUFFIX) \
-	$(DIST)/lib/$(LIB_PREFIX)nssb.$(LIB_SUFFIX) \
-	$(NULL)
-
-# can't do this in manifest.mn because OS_TARGET isn't defined there.
-ifeq (,$(filter-out WIN%,$(OS_TARGET)))
-
-ifdef NS_USE_GCC
-EXTRA_LIBS += \
-	-L$(NSPR_LIB_DIR) \
-	-lplc4 \
-	-lplds4 \
-	-lnspr4 \
-	$(NULL)
-else 
-EXTRA_SHARED_LIBS += \
-        $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plc4.lib \
-        $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plds4.lib \
-        $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4.lib \
-        $(NULL)
-endif # NS_USE_GCC
-else
-
-EXTRA_LIBS += \
-	-L$(NSPR_LIB_DIR) \
-	-lplc4 \
-	-lplds4 \
-	-lnspr4 \
-	-framework Security \
-	-framework CoreServices \
-	$(NULL)
-endif
-
-
-include $(CORE_DEPTH)/coreconf/rules.mk
-
-# Generate certdata.c.
-generate:
-	perl certdata.perl < certdata.txt
-
-# This'll need some help from a build person.
-
-
-ifeq ($(OS_TARGET)$(OS_RELEASE), AIX4.1)
-DSO_LDOPTS              = -bM:SRE -bh:4 -bnoentry
-EXTRA_DSO_LDOPTS        = -lc
-MKSHLIB                 = xlC $(DSO_LDOPTS)
-
-$(SHARED_LIBRARY): $(OBJS)
-	@$(MAKE_OBJDIR)
-	rm -f $@
-	$(MKSHLIB) -o $@ $(OBJS) $(EXTRA_LIBS) $(EXTRA_DSO_LDOPTS)
-	chmod +x $@
-
-endif
-
-ifeq ($(OS_TARGET)$(OS_RELEASE), AIX4.2)
-LD      += -G
-endif 
-
-
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/README
+++ /dev/null
@@ -1,21 +0,0 @@
-This Cryptoki module provides acces to certs and keys stored in
-Macintosh key Ring.
-
-- It does not yet export PKCS #12 keys. To get this to work should be 
-  implemented using exporting the key object in PKCS #8 wrapped format.
-  PSM work needs to happen before this can be completed.
-- It does not import or export CA Root trust from the mac keychain.
-- It does not handle S/MIME objects (pkcs #7 in mac keychain terms?).
-- The AuthRoots don't show up on the default list.
-- Only RSA keys are supported currently.
-
-There are a number of things that have not been tested that other PKCS #11
-apps may need:
-- reading Modulus and Public Exponents from private keys and public keys.
-- storing public keys.
-- setting attributes other than CKA_ID and CKA_LABEL.
-
-Other TODOs:
-- Check for and plug memory leaks.
-- Need to map mac errors into something more intellegible than 
-  CKR_GENERAL_ERROR.
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/ckmk.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/* 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 CKMK_H
-#define CKMK_H 1
-
-#include <Security/SecKeychainSearch.h>
-#include <Security/SecKeychainItem.h>
-#include <Security/SecKeychain.h>
-#include <Security/cssmtype.h>
-#include <Security/cssmapi.h>
-#include <Security/SecKey.h>
-#include <Security/SecCertificate.h>
-
-#define NTO
-
-#include "nssckmdt.h"
-#include "nssckfw.h"
-/*
- * I'm including this for access to the arena functions.
- * Looks like we should publish that API.
- */
-#ifndef BASE_H
-#include "base.h"
-#endif /* BASE_H */
-/*
- * This is where the Netscape extensions live, at least for now.
- */
-#ifndef CKT_H
-#include "ckt.h"
-#endif /* CKT_H */
-
-/*
- * statically defined raw objects. Allows us to data description objects
- * to this PKCS #11 module.
- */
-struct ckmkRawObjectStr {
-    CK_ULONG n;
-    const CK_ATTRIBUTE_TYPE *types;
-    const NSSItem *items;
-};
-typedef struct ckmkRawObjectStr ckmkRawObject;
-
-/*
- * Key/Cert Items
- */
-struct ckmkItemObjectStr {
-    SecKeychainItemRef itemRef;
-    SecItemClass itemClass;
-    PRBool hasID;
-    NSSItem modify;
-    NSSItem private;
-    NSSItem encrypt;
-    NSSItem decrypt;
-    NSSItem derive;
-    NSSItem sign;
-    NSSItem signRecover;
-    NSSItem verify;
-    NSSItem verifyRecover;
-    NSSItem wrap;
-    NSSItem unwrap;
-    NSSItem label;
-    NSSItem subject;
-    NSSItem issuer;
-    NSSItem serial;
-    NSSItem derCert;
-    NSSItem id;
-    NSSItem modulus;
-    NSSItem exponent;
-    NSSItem privateExponent;
-    NSSItem prime1;
-    NSSItem prime2;
-    NSSItem exponent1;
-    NSSItem exponent2;
-    NSSItem coefficient;
-};
-typedef struct ckmkItemObjectStr ckmkItemObject;
-
-typedef enum {
-    ckmkRaw,
-    ckmkItem,
-} ckmkObjectType;
-
-/*
- * all the various types of objects are abstracted away in cobject and
- * cfind as ckmkInternalObjects.
- */
-struct ckmkInternalObjectStr {
-    ckmkObjectType type;
-    union {
-        ckmkRawObject raw;
-        ckmkItemObject item;
-    } u;
-    CK_OBJECT_CLASS objClass;
-    NSSItem hashKey;
-    unsigned char hashKeyData[128];
-    NSSCKMDObject mdObject;
-};
-typedef struct ckmkInternalObjectStr ckmkInternalObject;
-
-/* our raw object data array */
-NSS_EXTERN_DATA ckmkInternalObject nss_ckmk_data[];
-NSS_EXTERN_DATA const PRUint32 nss_ckmk_nObjects;
-
-NSS_EXTERN_DATA const CK_VERSION nss_ckmk_CryptokiVersion;
-NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_ManufacturerID;
-NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_LibraryDescription;
-NSS_EXTERN_DATA const CK_VERSION nss_ckmk_LibraryVersion;
-NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_SlotDescription;
-NSS_EXTERN_DATA const CK_VERSION nss_ckmk_HardwareVersion;
-NSS_EXTERN_DATA const CK_VERSION nss_ckmk_FirmwareVersion;
-NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_TokenLabel;
-NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_TokenModel;
-NSS_EXTERN_DATA const NSSUTF8 *nss_ckmk_TokenSerialNumber;
-
-NSS_EXTERN_DATA const NSSCKMDInstance nss_ckmk_mdInstance;
-NSS_EXTERN_DATA const NSSCKMDSlot nss_ckmk_mdSlot;
-NSS_EXTERN_DATA const NSSCKMDToken nss_ckmk_mdToken;
-NSS_EXTERN_DATA const NSSCKMDMechanism nss_ckmk_mdMechanismRSA;
-
-NSS_EXTERN NSSCKMDSession *
-nss_ckmk_CreateSession(
-    NSSCKFWSession *fwSession,
-    CK_RV *pError);
-
-NSS_EXTERN NSSCKMDFindObjects *
-nss_ckmk_FindObjectsInit(
-    NSSCKFWSession *fwSession,
-    CK_ATTRIBUTE_PTR pTemplate,
-    CK_ULONG ulAttributeCount,
-    CK_RV *pError);
-
-/*
- * Object Utilities
- */
-NSS_EXTERN NSSCKMDObject *
-nss_ckmk_CreateMDObject(
-    NSSArena *arena,
-    ckmkInternalObject *io,
-    CK_RV *pError);
-
-NSS_EXTERN NSSCKMDObject *
-nss_ckmk_CreateObject(
-    NSSCKFWSession *fwSession,
-    CK_ATTRIBUTE_PTR pTemplate,
-    CK_ULONG ulAttributeCount,
-    CK_RV *pError);
-
-NSS_EXTERN const NSSItem *
-nss_ckmk_FetchAttribute(
-    ckmkInternalObject *io,
-    CK_ATTRIBUTE_TYPE type,
-    CK_RV *pError);
-
-NSS_EXTERN void
-nss_ckmk_DestroyInternalObject(
-    ckmkInternalObject *io);
-
-unsigned char *
-nss_ckmk_DERUnwrap(
-    unsigned char *src,
-    int size,
-    int *outSize,
-    unsigned char **next);
-
-CK_ULONG
-nss_ckmk_GetULongAttribute(
-    CK_ATTRIBUTE_TYPE type,
-    CK_ATTRIBUTE *template,
-    CK_ULONG templateSize,
-    CK_RV *pError);
-
-#define NSS_CKMK_ARRAY_SIZE(x) ((sizeof(x)) / (sizeof((x)[0])))
-
-#ifdef DEBUG
-#define CKMK_MACERR(str, err) cssmPerror(str, err)
-#else
-#define CKMK_MACERR(str, err)
-#endif
-
-#endif
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/ckmkver.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/* 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 "nssmkey.h"
-
-#if defined(DEBUG)
-#define _DEBUG_STRING " (debug)"
-#else
-#define _DEBUG_STRING ""
-#endif
-
-/*
- * Version information
- */
-const char __nss_ckmk_version[] = "Version: NSS Access to the MAC OS X Key Ring " NSS_CKMK_LIBRARY_VERSION _DEBUG_STRING;
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/config.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# 
-# 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/.
-
-ifdef BUILD_IDG
-DEFINES += -DNSSDEBUG
-endif
-
-ifdef NS_USE_CKFW_TRACE
-DEFINES += -DTRACE
-endif
-
-#
-#  Override TARGETS variable so that only static libraries
-#  are specifed as dependencies within rules.mk.
-#
-
-TARGETS        = $(LIBRARY)
-SHARED_LIBRARY =
-IMPORT_LIBRARY =
-PROGRAM        =
-
-
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/manchor.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/* 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/. */
-
-/*
- * nssmkey/manchor.c
- *
- * This file "anchors" the actual cryptoki entry points in this module's
- * shared library, which is required for dynamic loading.  See the
- * comments in nssck.api for more information.
- */
-
-#include "ckmk.h"
-
-#define MODULE_NAME ckmk
-#define INSTANCE_NAME (NSSCKMDInstance *)&nss_ckmk_mdInstance
-#include "nssck.api"
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/manifest.mn
+++ /dev/null
@@ -1,33 +0,0 @@
-# 
-# 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 = ../../../..
-
-MODULE = nss
-MAPFILE = $(OBJDIR)/nssmkey.def
-
-EXPORTS =		\
-	nssmkey.h	\
-	$(NULL)
-
-CSRCS =			\
-	manchor.c	\
-	mconstants.c	\
-	mfind.c		\
-	minst.c 	\
-	mobject.c	\
-	mrsa.c		\
-	msession.c	\
-	mslot.c		\
-	mtoken.c	\
-	ckmkver.c	\
-	staticobj.c	\
-	$(NULL)
-
-REQUIRES = nspr
-
-LIBRARY_NAME = nssmkey
-
-#EXTRA_SHARED_LIBS = -L$(DIST)/lib -lnssckfw -lnssb -lplc4 -lplds4
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/mconstants.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/* 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/. */
-
-/*
- * nssmkey/constants.c
- *
- * Identification and other constants, all collected here in one place.
- */
-
-#ifndef NSSBASET_H
-#include "nssbaset.h"
-#endif /* NSSBASET_H */
-
-#ifndef NSSCKT_H
-#include "nssckt.h"
-#endif /* NSSCKT_H */
-
-#include "nssmkey.h"
-
-NSS_IMPLEMENT_DATA const CK_VERSION
-    nss_ckmk_CryptokiVersion = {
-        NSS_CKMK_CRYPTOKI_VERSION_MAJOR,
-        NSS_CKMK_CRYPTOKI_VERSION_MINOR
-    };
-
-NSS_IMPLEMENT_DATA const NSSUTF8 *
-    nss_ckmk_ManufacturerID = (NSSUTF8 *)"Mozilla Foundation";
-
-NSS_IMPLEMENT_DATA const NSSUTF8 *
-    nss_ckmk_LibraryDescription = (NSSUTF8 *)"NSS Access to Mac OS X Key Ring";
-
-NSS_IMPLEMENT_DATA const CK_VERSION
-    nss_ckmk_LibraryVersion = {
-        NSS_CKMK_LIBRARY_VERSION_MAJOR,
-        NSS_CKMK_LIBRARY_VERSION_MINOR
-    };
-
-NSS_IMPLEMENT_DATA const NSSUTF8 *
-    nss_ckmk_SlotDescription = (NSSUTF8 *)"Mac OS X Key Ring";
-
-NSS_IMPLEMENT_DATA const CK_VERSION
-    nss_ckmk_HardwareVersion = {
-        NSS_CKMK_HARDWARE_VERSION_MAJOR,
-        NSS_CKMK_HARDWARE_VERSION_MINOR
-    };
-
-NSS_IMPLEMENT_DATA const CK_VERSION
-    nss_ckmk_FirmwareVersion = {
-        NSS_CKMK_FIRMWARE_VERSION_MAJOR,
-        NSS_CKMK_FIRMWARE_VERSION_MINOR
-    };
-
-NSS_IMPLEMENT_DATA const NSSUTF8 *
-    nss_ckmk_TokenLabel = (NSSUTF8 *)"Mac OS X Key Ring";
-
-NSS_IMPLEMENT_DATA const NSSUTF8 *
-    nss_ckmk_TokenModel = (NSSUTF8 *)"1";
-
-NSS_IMPLEMENT_DATA const NSSUTF8 *
-    nss_ckmk_TokenSerialNumber = (NSSUTF8 *)"1";
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/mfind.c
+++ /dev/null
@@ -1,352 +0,0 @@
-/* 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 CKMK_H
-#include "ckmk.h"
-#endif /* CKMK_H */
-
-/*
- * nssmkey/mfind.c
- *
- * This file implements the NSSCKMDFindObjects object for the
- * "nssmkey" cryptoki module.
- */
-
-struct ckmkFOStr {
-    NSSArena *arena;
-    CK_ULONG n;
-    CK_ULONG i;
-    ckmkInternalObject **objs;
-};
-
-static void
-ckmk_mdFindObjects_Final(
-    NSSCKMDFindObjects *mdFindObjects,
-    NSSCKFWFindObjects *fwFindObjects,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance)
-{
-    struct ckmkFOStr *fo = (struct ckmkFOStr *)mdFindObjects->etc;
-    NSSArena *arena = fo->arena;
-    PRUint32 i;
-
-    /* walk down an free the unused 'objs' */
-    for (i = fo->i; i < fo->n; i++) {
-        nss_ckmk_DestroyInternalObject(fo->objs[i]);
-    }
-
-    nss_ZFreeIf(fo->objs);
-    nss_ZFreeIf(fo);
-    nss_ZFreeIf(mdFindObjects);
-    if ((NSSArena *)NULL != arena) {
-        NSSArena_Destroy(arena);
-    }
-
-    return;
-}
-
-static NSSCKMDObject *
-ckmk_mdFindObjects_Next(
-    NSSCKMDFindObjects *mdFindObjects,
-    NSSCKFWFindObjects *fwFindObjects,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    NSSArena *arena,
-    CK_RV *pError)
-{
-    struct ckmkFOStr *fo = (struct ckmkFOStr *)mdFindObjects->etc;
-    ckmkInternalObject *io;
-
-    if (fo->i == fo->n) {
-        *pError = CKR_OK;
-        return (NSSCKMDObject *)NULL;
-    }
-
-    io = fo->objs[fo->i];
-    fo->i++;
-
-    return nss_ckmk_CreateMDObject(arena, io, pError);
-}
-
-static CK_BBOOL
-ckmk_attrmatch(
-    CK_ATTRIBUTE_PTR a,
-    ckmkInternalObject *o)
-{
-    PRBool prb;
-    const NSSItem *b;
-    CK_RV error;
-
-    b = nss_ckmk_FetchAttribute(o, a->type, &error);
-    if (b == NULL) {
-        return CK_FALSE;
-    }
-
-    if (a->ulValueLen != b->size) {
-        /* match a decoded serial number */
-        if ((a->type == CKA_SERIAL_NUMBER) && (a->ulValueLen < b->size)) {
-            int len;
-            unsigned char *data;
-
-            data = nss_ckmk_DERUnwrap(b->data, b->size, &len, NULL);
-            if ((len == a->ulValueLen) &&
-                nsslibc_memequal(a->pValue, data, len, (PRStatus *)NULL)) {
-                return CK_TRUE;
-            }
-        }
-        return CK_FALSE;
-    }
-
-    prb = nsslibc_memequal(a->pValue, b->data, b->size, (PRStatus *)NULL);
-
-    if (PR_TRUE == prb) {
-        return CK_TRUE;
-    } else {
-        return CK_FALSE;
-    }
-}
-
-static CK_BBOOL
-ckmk_match(
-    CK_ATTRIBUTE_PTR pTemplate,
-    CK_ULONG ulAttributeCount,
-    ckmkInternalObject *o)
-{
-    CK_ULONG i;
-
-    for (i = 0; i < ulAttributeCount; i++) {
-        if (CK_FALSE == ckmk_attrmatch(&pTemplate[i], o)) {
-            return CK_FALSE;
-        }
-    }
-
-    /* Every attribute passed */
-    return CK_TRUE;
-}
-
-#define CKMK_ITEM_CHUNK 20
-
-#define PUT_OBJECT(obj, err, size, count, list)                             \
-    {                                                                       \
-        if (count >= size) {                                                \
-            (list) = (list) ? nss_ZREALLOCARRAY(list, ckmkInternalObject *, \
-                                                ((size) +                   \
-                                                 CKMK_ITEM_CHUNK))          \
-                            : nss_ZNEWARRAY(NULL, ckmkInternalObject *,     \
-                                            ((size) +                       \
-                                             CKMK_ITEM_CHUNK));             \
-            if ((ckmkInternalObject **)NULL == list) {                      \
-                err = CKR_HOST_MEMORY;                                      \
-                goto loser;                                                 \
-            }                                                               \
-            (size) += CKMK_ITEM_CHUNK;                                      \
-        }                                                                   \
-        (list)[count] = (obj);                                              \
-        count++;                                                            \
-    }
-
-/* find all the certs that represent the appropriate object (cert, priv key, or
- *  pub key) in the cert store.
- */
-static PRUint32
-collect_class(
-    CK_OBJECT_CLASS objClass,
-    SecItemClass itemClass,
-    CK_ATTRIBUTE_PTR pTemplate,
-    CK_ULONG ulAttributeCount,
-    ckmkInternalObject ***listp,
-    PRUint32 *sizep,
-    PRUint32 count,
-    CK_RV *pError)
-{
-    ckmkInternalObject *next = NULL;
-    SecKeychainSearchRef searchRef = 0;
-    SecKeychainItemRef itemRef = 0;
-    OSStatus error;
-
-    /* future, build the attribute list based on the template
-     * so we can refine the search */
-    error = SecKeychainSearchCreateFromAttributes(
-        NULL, itemClass, NULL, &searchRef);
-
-    while (noErr == SecKeychainSearchCopyNext(searchRef, &itemRef)) {
-        /* if we don't have an internal object structure, get one */
-        if ((ckmkInternalObject *)NULL == next) {
-            next = nss_ZNEW(NULL, ckmkInternalObject);
-            if ((ckmkInternalObject *)NULL == next) {
-                *pError = CKR_HOST_MEMORY;
-                goto loser;
-            }
-        }
-        /* fill in the relevant object data */
-        next->type = ckmkItem;
-        next->objClass = objClass;
-        next->u.item.itemRef = itemRef;
-        next->u.item.itemClass = itemClass;
-
-        /* see if this is one of the objects we are looking for */
-        if (CK_TRUE == ckmk_match(pTemplate, ulAttributeCount, next)) {
-            /* yes, put it on the list */
-            PUT_OBJECT(next, *pError, *sizep, count, *listp);
-            next = NULL; /* this one is on the list, need to allocate a new one now */
-        } else {
-            /* no , release the current item and clear out the structure for reuse */
-            CFRelease(itemRef);
-            /* don't cache the values we just loaded */
-            nsslibc_memset(next, 0, sizeof(*next));
-        }
-    }
-loser:
-    if (searchRef) {
-        CFRelease(searchRef);
-    }
-    nss_ZFreeIf(next);
-    return count;
-}
-
-static PRUint32
-collect_objects(
-    CK_ATTRIBUTE_PTR pTemplate,
-    CK_ULONG ulAttributeCount,
-    ckmkInternalObject ***listp,
-    CK_RV *pError)
-{
-    PRUint32 i;
-    PRUint32 count = 0;
-    PRUint32 size = 0;
-    CK_OBJECT_CLASS objClass;
-
-    /*
-     * first handle the static build in objects (if any)
-     */
-    for (i = 0; i < nss_ckmk_nObjects; i++) {
-        ckmkInternalObject *o = (ckmkInternalObject *)&nss_ckmk_data[i];
-
-        if (CK_TRUE == ckmk_match(pTemplate, ulAttributeCount, o)) {
-            PUT_OBJECT(o, *pError, size, count, *listp);
-        }
-    }
-
-    /*
-     * now handle the various object types
-     */
-    objClass = nss_ckmk_GetULongAttribute(CKA_CLASS,
-                                          pTemplate, ulAttributeCount, pError);
-    if (CKR_OK != *pError) {
-        objClass = CK_INVALID_HANDLE;
-    }
-    *pError = CKR_OK;
-    switch (objClass) {
-        case CKO_CERTIFICATE:
-            count = collect_class(objClass, kSecCertificateItemClass,
-                                  pTemplate, ulAttributeCount, listp,
-                                  &size, count, pError);
-            break;
-        case CKO_PUBLIC_KEY:
-            count = collect_class(objClass, CSSM_DL_DB_RECORD_PUBLIC_KEY,
-                                  pTemplate, ulAttributeCount, listp,
-                                  &size, count, pError);
-            break;
-        case CKO_PRIVATE_KEY:
-            count = collect_class(objClass, CSSM_DL_DB_RECORD_PRIVATE_KEY,
-                                  pTemplate, ulAttributeCount, listp,
-                                  &size, count, pError);
-            break;
-        /* all of them */
-        case CK_INVALID_HANDLE:
-            count = collect_class(CKO_CERTIFICATE, kSecCertificateItemClass,
-                                  pTemplate, ulAttributeCount, listp,
-                                  &size, count, pError);
-            count = collect_class(CKO_PUBLIC_KEY, CSSM_DL_DB_RECORD_PUBLIC_KEY,
-                                  pTemplate, ulAttributeCount, listp,
-                                  &size, count, pError);
-            count = collect_class(CKO_PUBLIC_KEY, CSSM_DL_DB_RECORD_PRIVATE_KEY,
-                                  pTemplate, ulAttributeCount, listp,
-                                  &size, count, pError);
-            break;
-        default:
-            break;
-    }
-    if (CKR_OK != *pError) {
-        goto loser;
-    }
-
-    return count;
-loser:
-    nss_ZFreeIf(*listp);
-    return 0;
-}
-
-NSS_IMPLEMENT NSSCKMDFindObjects *
-nss_ckmk_FindObjectsInit(
-    NSSCKFWSession *fwSession,
-    CK_ATTRIBUTE_PTR pTemplate,
-    CK_ULONG ulAttributeCount,
-    CK_RV *pError)
-{
-    /* This could be made more efficient.  I'm rather rushed. */
-    NSSArena *arena;
-    NSSCKMDFindObjects *rv = (NSSCKMDFindObjects *)NULL;
-    struct ckmkFOStr *fo = (struct ckmkFOStr *)NULL;
-    ckmkInternalObject **temp = (ckmkInternalObject **)NULL;
-
-    arena = NSSArena_Create();
-    if ((NSSArena *)NULL == arena) {
-        goto loser;
-    }
-
-    rv = nss_ZNEW(arena, NSSCKMDFindObjects);
-    if ((NSSCKMDFindObjects *)NULL == rv) {
-        *pError = CKR_HOST_MEMORY;
-        goto loser;
-    }
-
-    fo = nss_ZNEW(arena, struct ckmkFOStr);
-    if ((struct ckmkFOStr *)NULL == fo) {
-        *pError = CKR_HOST_MEMORY;
-        goto loser;
-    }
-
-    fo->arena = arena;
-    /* fo->n and fo->i are already zero */
-
-    rv->etc = (void *)fo;
-    rv->Final = ckmk_mdFindObjects_Final;
-    rv->Next = ckmk_mdFindObjects_Next;
-    rv->null = (void *)NULL;
-
-    fo->n = collect_objects(pTemplate, ulAttributeCount, &temp, pError);
-    if (*pError != CKR_OK) {
-        goto loser;
-    }
-
-    fo->objs = nss_ZNEWARRAY(arena, ckmkInternalObject *, fo->n);
-    if ((ckmkInternalObject **)NULL == fo->objs) {
-        *pError = CKR_HOST_MEMORY;
-        goto loser;
-    }
-
-    (void)nsslibc_memcpy(fo->objs, temp, sizeof(ckmkInternalObject *) * fo->n);
-    nss_ZFreeIf(temp);
-    temp = (ckmkInternalObject **)NULL;
-
-    return rv;
-
-loser:
-    nss_ZFreeIf(temp);
-    nss_ZFreeIf(fo);
-    nss_ZFreeIf(rv);
-    if ((NSSArena *)NULL != arena) {
-        NSSArena_Destroy(arena);
-    }
-    return (NSSCKMDFindObjects *)NULL;
-}
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/minst.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/* 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 "ckmk.h"
-
-/*
- * nssmkey/minstance.c
- *
- * This file implements the NSSCKMDInstance object for the
- * "nssmkey" cryptoki module.
- */
-
-/*
- * NSSCKMDInstance methods
- */
-
-static CK_ULONG
-ckmk_mdInstance_GetNSlots(
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_RV *pError)
-{
-    return (CK_ULONG)1;
-}
-
-static CK_VERSION
-ckmk_mdInstance_GetCryptokiVersion(
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance)
-{
-    return nss_ckmk_CryptokiVersion;
-}
-
-static NSSUTF8 *
-ckmk_mdInstance_GetManufacturerID(
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_RV *pError)
-{
-    return (NSSUTF8 *)nss_ckmk_ManufacturerID;
-}
-
-static NSSUTF8 *
-ckmk_mdInstance_GetLibraryDescription(
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_RV *pError)
-{
-    return (NSSUTF8 *)nss_ckmk_LibraryDescription;
-}
-
-static CK_VERSION
-ckmk_mdInstance_GetLibraryVersion(
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance)
-{
-    return nss_ckmk_LibraryVersion;
-}
-
-static CK_RV
-ckmk_mdInstance_GetSlots(
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    NSSCKMDSlot *slots[])
-{
-    slots[0] = (NSSCKMDSlot *)&nss_ckmk_mdSlot;
-    return CKR_OK;
-}
-
-static CK_BBOOL
-ckmk_mdInstance_ModuleHandlesSessionObjects(
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance)
-{
-    /* we don't want to allow any session object creation, at least
-     * until we can investigate whether or not we can use those objects
-     */
-    return CK_TRUE;
-}
-
-NSS_IMPLEMENT_DATA const NSSCKMDInstance
-    nss_ckmk_mdInstance = {
-        (void *)NULL, /* etc */
-        NULL,         /* Initialize */
-        NULL,         /* Finalize */
-        ckmk_mdInstance_GetNSlots,
-        ckmk_mdInstance_GetCryptokiVersion,
-        ckmk_mdInstance_GetManufacturerID,
-        ckmk_mdInstance_GetLibraryDescription,
-        ckmk_mdInstance_GetLibraryVersion,
-        ckmk_mdInstance_ModuleHandlesSessionObjects,
-        /*NULL, /* HandleSessionObjects */
-        ckmk_mdInstance_GetSlots,
-        NULL,        /* WaitForSlotEvent */
-        (void *)NULL /* null terminator */
-    };
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/mobject.c
+++ /dev/null
@@ -1,1861 +0,0 @@
-/* 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 "ckmk.h"
-#include "nssbase.h"
-
-#include "secdert.h" /* for DER_INTEGER */
-#include "string.h"
-
-/* asn1 encoder (to build pkcs#8 blobs) */
-#include <seccomon.h>
-#include <secitem.h>
-#include <blapit.h>
-#include <secoid.h>
-#include <secasn1.h>
-
-/* for importing the keys */
-#include <CoreFoundation/CoreFoundation.h>
-#include <security/SecImportExport.h>
-
-/*
- * nssmkey/mobject.c
- *
- * This file implements the NSSCKMDObject object for the
- * "nssmkey" cryptoki module.
- */
-
-const CK_ATTRIBUTE_TYPE certAttrs[] = {
-    CKA_CLASS,
-    CKA_TOKEN,
-    CKA_PRIVATE,
-    CKA_MODIFIABLE,
-    CKA_LABEL,
-    CKA_CERTIFICATE_TYPE,
-    CKA_SUBJECT,
-    CKA_ISSUER,
-    CKA_SERIAL_NUMBER,
-    CKA_VALUE
-};
-const PRUint32 certAttrsCount = NSS_CKMK_ARRAY_SIZE(certAttrs);
-
-/* private keys, for now only support RSA */
-const CK_ATTRIBUTE_TYPE privKeyAttrs[] = {
-    CKA_CLASS,
-    CKA_TOKEN,
-    CKA_PRIVATE,
-    CKA_MODIFIABLE,
-    CKA_LABEL,
-    CKA_KEY_TYPE,
-    CKA_DERIVE,
-    CKA_LOCAL,
-    CKA_SUBJECT,
-    CKA_SENSITIVE,
-    CKA_DECRYPT,
-    CKA_SIGN,
-    CKA_SIGN_RECOVER,
-    CKA_UNWRAP,
-    CKA_EXTRACTABLE,
-    CKA_ALWAYS_SENSITIVE,
-    CKA_NEVER_EXTRACTABLE,
-    CKA_MODULUS,
-    CKA_PUBLIC_EXPONENT,
-};
-const PRUint32 privKeyAttrsCount = NSS_CKMK_ARRAY_SIZE(privKeyAttrs);
-
-/* public keys, for now only support RSA */
-const CK_ATTRIBUTE_TYPE pubKeyAttrs[] = {
-    CKA_CLASS,
-    CKA_TOKEN,
-    CKA_PRIVATE,
-    CKA_MODIFIABLE,
-    CKA_LABEL,
-    CKA_KEY_TYPE,
-    CKA_DERIVE,
-    CKA_LOCAL,
-    CKA_SUBJECT,
-    CKA_ENCRYPT,
-    CKA_VERIFY,
-    CKA_VERIFY_RECOVER,
-    CKA_WRAP,
-    CKA_MODULUS,
-    CKA_PUBLIC_EXPONENT,
-};
-const PRUint32 pubKeyAttrsCount = NSS_CKMK_ARRAY_SIZE(pubKeyAttrs);
-static const CK_BBOOL ck_true = CK_TRUE;
-static const CK_BBOOL ck_false = CK_FALSE;
-static const CK_CERTIFICATE_TYPE ckc_x509 = CKC_X_509;
-static const CK_KEY_TYPE ckk_rsa = CKK_RSA;
-static const CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE;
-static const CK_OBJECT_CLASS cko_private_key = CKO_PRIVATE_KEY;
-static const CK_OBJECT_CLASS cko_public_key = CKO_PUBLIC_KEY;
-static const NSSItem ckmk_trueItem = {
-    (void *)&ck_true, (PRUint32)sizeof(CK_BBOOL)
-};
-static const NSSItem ckmk_falseItem = {
-    (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL)
-};
-static const NSSItem ckmk_x509Item = {
-    (void *)&ckc_x509, (PRUint32)sizeof(CK_CERTIFICATE_TYPE)
-};
-static const NSSItem ckmk_rsaItem = {
-    (void *)&ckk_rsa, (PRUint32)sizeof(CK_KEY_TYPE)
-};
-static const NSSItem ckmk_certClassItem = {
-    (void *)&cko_certificate, (PRUint32)sizeof(CK_OBJECT_CLASS)
-};
-static const NSSItem ckmk_privKeyClassItem = {
-    (void *)&cko_private_key, (PRUint32)sizeof(CK_OBJECT_CLASS)
-};
-static const NSSItem ckmk_pubKeyClassItem = {
-    (void *)&cko_public_key, (PRUint32)sizeof(CK_OBJECT_CLASS)
-};
-static const NSSItem ckmk_emptyItem = {
-    (void *)&ck_true, 0
-};
-
-/*
- * these are utilities. The chould be moved to a new utilities file.
- */
-#ifdef DEBUG
-static void
-itemdump(char *str, void *data, int size, CK_RV error)
-{
-    unsigned char *ptr = (unsigned char *)data;
-    int i;
-    fprintf(stderr, str);
-    for (i = 0; i < size; i++) {
-        fprintf(stderr, "%02x ", (unsigned int)ptr[i]);
-    }
-    fprintf(stderr, " (error = %d)\n", (int)error);
-}
-#endif
-
-/*
- * unwrap a single DER value
- * now that we have util linked in, we should probably use
- * the ANS1_Decoder for this work...
- */
-unsigned char *
-nss_ckmk_DERUnwrap(
-    unsigned char *src,
-    int size,
-    int *outSize,
-    unsigned char **next)
-{
-    unsigned char *start = src;
-    unsigned int len = 0;
-
-    /* initialize error condition return values */
-    *outSize = 0;
-    if (next) {
-        *next = src;
-    }
-
-    if (size < 2) {
-        return start;
-    }
-    src++; /* skip the tag -- should check it against an expected value! */
-    len = (unsigned)*src++;
-    if (len & 0x80) {
-        int count = len & 0x7f;
-        len = 0;
-
-        if (count + 2 > size) {
-            return start;
-        }
-        while (count-- > 0) {
-            len = (len << 8) | (unsigned)*src++;
-        }
-    }
-    if (len + (src - start) > (unsigned int)size) {
-        return start;
-    }
-    if (next) {
-        *next = src + len;
-    }
-    *outSize = len;
-
-    return src;
-}
-
-/*
- * get an attribute from a template. Value is returned in NSS item.
- * data for the item is owned by the template.
- */
-CK_RV
-nss_ckmk_GetAttribute(
-    CK_ATTRIBUTE_TYPE type,
-    CK_ATTRIBUTE *template,
-    CK_ULONG templateSize,
-    NSSItem *item)
-{
-    CK_ULONG i;
-
-    for (i = 0; i < templateSize; i++) {
-        if (template[i].type == type) {
-            item->data = template[i].pValue;
-            item->size = template[i].ulValueLen;
-            return CKR_OK;
-        }
-    }
-    return CKR_TEMPLATE_INCOMPLETE;
-}
-
-/*
- * get an attribute which is type CK_ULONG.
- */
-CK_ULONG
-nss_ckmk_GetULongAttribute(
-    CK_ATTRIBUTE_TYPE type,
-    CK_ATTRIBUTE *template,
-    CK_ULONG templateSize,
-    CK_RV *pError)
-{
-    NSSItem item;
-
-    *pError = nss_ckmk_GetAttribute(type, template, templateSize, &item);
-    if (CKR_OK != *pError) {
-        return (CK_ULONG)0;
-    }
-    if (item.size != sizeof(CK_ULONG)) {
-        *pError = CKR_ATTRIBUTE_VALUE_INVALID;
-        return (CK_ULONG)0;
-    }
-    return *(CK_ULONG *)item.data;
-}
-
-/*
- * get an attribute which is type CK_BBOOL.
- */
-CK_BBOOL
-nss_ckmk_GetBoolAttribute(
-    CK_ATTRIBUTE_TYPE type,
-    CK_ATTRIBUTE *template,
-    CK_ULONG templateSize,
-    CK_BBOOL defaultBool)
-{
-    NSSItem item;
-    CK_RV error;
-
-    error = nss_ckmk_GetAttribute(type, template, templateSize, &item);
-    if (CKR_OK != error) {
-        return defaultBool;
-    }
-    if (item.size != sizeof(CK_BBOOL)) {
-        return defaultBool;
-    }
-    return *(CK_BBOOL *)item.data;
-}
-
-/*
- * get an attribute as a NULL terminated string. Caller is responsible to
- * free the string.
- */
-char *
-nss_ckmk_GetStringAttribute(
-    CK_ATTRIBUTE_TYPE type,
-    CK_ATTRIBUTE *template,
-    CK_ULONG templateSize,
-    CK_RV *pError)
-{
-    NSSItem item;
-    char *str;
-
-    /* get the attribute */
-    *pError = nss_ckmk_GetAttribute(type, template, templateSize, &item);
-    if (CKR_OK != *pError) {
-        return (char *)NULL;
-    }
-    /* make sure it is null terminated */
-    str = nss_ZNEWARRAY(NULL, char, item.size + 1);
-    if ((char *)NULL == str) {
-        *pError = CKR_HOST_MEMORY;
-        return (char *)NULL;
-    }
-
-    nsslibc_memcpy(str, item.data, item.size);
-    str[item.size] = 0;
-
-    return str;
-}
-
-/*
- * Apple doesn't seem to have a public interface to the DER encoder,
- * wip out a quick one for integers only (anything more complicated,
- * we should use one of the 3 in lib/util). -- especially since we
- * now link with it.
- */
-static CK_RV
-ckmk_encodeInt(NSSItem *dest, void *src, int srcLen)
-{
-    int dataLen = srcLen;
-    int lenLen = 1;
-    int encLen;
-    int isSigned = 0;
-    int offset = 0;
-    unsigned char *data = NULL;
-    int i;
-
-    if (*(unsigned char *)src & 0x80) {
-        dataLen++;
-        isSigned = 1;
-    }
-
-    /* calculate the length of the length specifier */
-    /* (NOTE: destroys dataLen value) */
-    if (dataLen > 0x7f) {
-        do {
-            lenLen++;
-            dataLen >>= 8;
-        } while (dataLen);
-    }
-
-    /* calculate our total length */
-    dataLen = isSigned + srcLen;
-    encLen = 1 + lenLen + dataLen;
-    data = nss_ZNEWARRAY(NULL, unsigned char, encLen);
-    if ((unsigned char *)NULL == data) {
-        return CKR_HOST_MEMORY;
-    }
-    data[0] = DER_INTEGER;
-    if (1 == lenLen) {
-        data[1] = dataLen;
-    } else {
-        data[1] = 0x80 + lenLen;
-        for (i = 0; i < lenLen; i++) {
-            data[i + 1] = ((dataLen >> ((lenLen -
-                                         i - 1) *
-                                        8)) &
-                           0xff);
-        }
-    }
-    offset = lenLen + 1;
-
-    if (isSigned) {
-        data[offset++] = 0;
-    }
-    nsslibc_memcpy(&data[offset], src, srcLen);
-    dest->data = data;
-    dest->size = encLen;
-    return CKR_OK;
-}
-
-/*
- * Get a Keyring attribute. If content is set to true, then we get the
- * content, not the attribute.
- */
-static CK_RV
-ckmk_GetCommonAttribute(
-    ckmkInternalObject *io,
-    SecItemAttr itemAttr,
-    PRBool content,
-    NSSItem *item,
-    char *dbString)
-{
-    SecKeychainAttributeList *attrList = NULL;
-    SecKeychainAttributeInfo attrInfo;
-    PRUint32 len = 0;
-    PRUint32 dataLen = 0;
-    PRUint32 attrFormat = 0;
-    void *dataVal = 0;
-    void *out = NULL;
-    CK_RV error = CKR_OK;
-    OSStatus macErr;
-
-    attrInfo.count = 1;
-    attrInfo.tag = &itemAttr;
-    attrInfo.format = &attrFormat;
-
-    macErr = SecKeychainItemCopyAttributesAndData(io->u.item.itemRef,
-                                                  &attrInfo, NULL, &attrList, &len, &out);
-    if (noErr != macErr) {
-        CKMK_MACERR(dbString, macErr);
-        return CKR_ATTRIBUTE_TYPE_INVALID;
-    }
-    dataLen = content ? len : attrList->attr->length;
-    dataVal = content ? out : attrList->attr->data;
-
-    /* Apple's documentation says this value is DER Encoded, but it clearly isn't
-     * der encode it before we ship it back off to NSS
-     */
-    if (kSecSerialNumberItemAttr == itemAttr) {
-        error = ckmk_encodeInt(item, dataVal, dataLen);
-        goto loser; /* logically 'done' if error == CKR_OK */
-    }
-    item->data = nss_ZNEWARRAY(NULL, char, dataLen);
-    if (NULL == item->data) {
-        error = CKR_HOST_MEMORY;
-        goto loser;
-    }
-    nsslibc_memcpy(item->data, dataVal, dataLen);
-    item->size = dataLen;
-
-loser:
-    SecKeychainItemFreeAttributesAndData(attrList, out);
-    return error;
-}
-
-/*
- * change an attribute (does not operate on the content).
- */
-static CK_RV
-ckmk_updateAttribute(
-    SecKeychainItemRef itemRef,
-    SecItemAttr itemAttr,
-    void *data,
-    PRUint32 len,
-    char *dbString)
-{
-    SecKeychainAttributeList attrList;
-    SecKeychainAttribute attrAttr;
-    OSStatus macErr;
-    CK_RV error = CKR_OK;
-
-    attrList.count = 1;
-    attrList.attr = &attrAttr;
-    attrAttr.tag = itemAttr;
-    attrAttr.data = data;
-    attrAttr.length = len;
-    macErr = SecKeychainItemModifyAttributesAndData(itemRef, &attrList, 0, NULL);
-    if (noErr != macErr) {
-        CKMK_MACERR(dbString, macErr);
-        error = CKR_ATTRIBUTE_TYPE_INVALID;
-    }
-    return error;
-}
-
-/*
- * get an attribute (does not operate on the content)
- */
-static CK_RV
-ckmk_GetDataAttribute(
-    ckmkInternalObject *io,
-    SecItemAttr itemAttr,
-    NSSItem *item,
-    char *dbString)
-{
-    return ckmk_GetCommonAttribute(io, itemAttr, PR_FALSE, item, dbString);
-}
-
-/*
- * get an attribute we know is a BOOL.
- */
-static CK_RV
-ckmk_GetBoolAttribute(
-    ckmkInternalObject *io,
-    SecItemAttr itemAttr,
-    NSSItem *item,
-    char *dbString)
-{
-    SecKeychainAttribute attr;
-    SecKeychainAttributeList attrList;
-    CK_BBOOL *boolp = NULL;
-    PRUint32 len = 0;
-    ;
-    void *out = NULL;
-    CK_RV error = CKR_OK;
-    OSStatus macErr;
-
-    attr.tag = itemAttr;
-    attr.length = 0;
-    attr.data = NULL;
-    attrList.count = 1;
-    attrList.attr = &attr;
-
-    boolp = nss_ZNEW(NULL, CK_BBOOL);
-    if ((CK_BBOOL *)NULL == boolp) {
-        error = CKR_HOST_MEMORY;
-        goto loser;
-    }
-
-    macErr = SecKeychainItemCopyContent(io->u.item.itemRef, NULL,
-                                        &attrList, &len, &out);
-    if (noErr != macErr) {
-        CKMK_MACERR(dbString, macErr);
-        error = CKR_ATTRIBUTE_TYPE_INVALID;
-        goto loser;
-    }
-    if (sizeof(PRUint32) != attr.length) {
-        error = CKR_ATTRIBUTE_TYPE_INVALID;
-        goto loser;
-    }
-    *boolp = *(PRUint32 *)attr.data ? 1 : 0;
-    item->data = boolp;
-    boolp = NULL;
-    item->size = sizeof(CK_BBOOL);
-
-loser:
-    nss_ZFreeIf(boolp);
-    SecKeychainItemFreeContent(&attrList, out);
-    return error;
-}
-
-/*
- * macros for fetching attributes into a cache and returning the
- * appropriate value. These operate inside switch statements
- */
-#define CKMK_HANDLE_ITEM(func, io, type, loc, item, error, str) \
-    if (0 == (item)->loc.size) {                                \
-        error = func(io, type, &(item)->loc, str);              \
-    }                                                           \
-    return (CKR_OK == (error)) ? &(item)->loc : NULL;
-
-#define CKMK_HANDLE_OPT_ITEM(func, io, type, loc, item, error, str) \
-    if (0 == (item)->loc.size) {                                    \
-        (void)func(io, type, &(item)->loc, str);                    \
-    }                                                               \
-    return &(item)->loc;
-
-#define CKMK_HANDLE_BOOL_ITEM(io, type, loc, item, error, str) \
-    CKMK_HANDLE_ITEM(ckmk_GetBoolAttribute, io, type, loc, item, error, str)
-#define CKMK_HANDLE_DATA_ITEM(io, type, loc, item, error, str) \
-    CKMK_HANDLE_ITEM(ckmk_GetDataAttribute, io, type, loc, item, error, str)
-#define CKMK_HANDLE_OPT_DATA_ITEM(io, type, loc, item, error, str) \
-    CKMK_HANDLE_OPT_ITEM(ckmk_GetDataAttribute, io, type, loc, item, error, str)
-
-/*
- * fetch the unique identifier for each object type.
- */
-static void
-ckmk_FetchHashKey(
-    ckmkInternalObject *io)
-{
-    NSSItem *key = &io->hashKey;
-
-    if (io->objClass == CKO_CERTIFICATE) {
-        ckmk_GetCommonAttribute(io, kSecCertEncodingItemAttr,
-                                PR_TRUE, key, "Fetching HashKey (cert)");
-    } else {
-        ckmk_GetCommonAttribute(io, kSecKeyLabel,
-                                PR_FALSE, key, "Fetching HashKey (key)");
-    }
-}
-
-/*
- * Apple mucks with the actual subject and issuer, so go fetch
- * the real ones ourselves.
- */
-static void
-ckmk_fetchCert(
-    ckmkInternalObject *io)
-{
-    CK_RV error;
-    unsigned char *cert, *next;
-    int certSize, thisEntrySize;
-
-    error = ckmk_GetCommonAttribute(io, kSecCertEncodingItemAttr, PR_TRUE,
-                                    &io->u.item.derCert, "Fetching Value (cert)");
-    if (CKR_OK != error) {
-        return;
-    }
-    /* unwrap the cert bundle */
-    cert = nss_ckmk_DERUnwrap((unsigned char *)io->u.item.derCert.data,
-                              io->u.item.derCert.size,
-                              &certSize, NULL);
-    /* unwrap the cert itself */
-    /* cert == certdata */
-    cert = nss_ckmk_DERUnwrap(cert, certSize, &certSize, NULL);
-
-    /* skip the optional version */
-    if ((cert[0] & 0xa0) == 0xa0) {
-        nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next);
-        certSize -= next - cert;
-        cert = next;
-    }
-    /* skip the serial number */
-    nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next);
-    certSize -= next - cert;
-    cert = next;
-
-    /* skip the OID */
-    nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next);
-    certSize -= next - cert;
-    cert = next;
-
-    /* save the (wrapped) issuer */
-    io->u.item.issuer.data = cert;
-    nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next);
-    io->u.item.issuer.size = next - cert;
-    certSize -= io->u.item.issuer.size;
-    cert = next;
-
-    /* skip the OID */
-    nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next);
-    certSize -= next - cert;
-    cert = next;
-
-    /* save the (wrapped) subject */
-    io->u.item.subject.data = cert;
-    nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next);
-    io->u.item.subject.size = next - cert;
-    certSize -= io->u.item.subject.size;
-    cert = next;
-}
-
-static void
-ckmk_fetchModulus(
-    ckmkInternalObject *io)
-{
-    NSSItem item;
-    PRInt32 modLen;
-    CK_RV error;
-
-    /* we can't reliably get the modulus for private keys through CSSM (sigh).
-     * For NSS this is OK because we really only use this to get the modulus
-     * length (unless we are trying to get a public key from a private keys,
-     * something CSSM ALSO does not do!).
-     */
-    error = ckmk_GetDataAttribute(io, kSecKeyKeySizeInBits, &item,
-                                  "Key Fetch Modulus");
-    if (CKR_OK != error) {
-        return;
-    }
-
-    modLen = *(PRInt32 *)item.data;
-    modLen = modLen / 8; /* convert from bits to bytes */
-
-    nss_ZFreeIf(item.data);
-    io->u.item.modulus.data = nss_ZNEWARRAY(NULL, char, modLen);
-    if (NULL == io->u.item.modulus.data) {
-        return;
-    }
-    *(char *)io->u.item.modulus.data = 0x80; /* fake NSS out or it will
-                                              * drop the first byte */
-    io->u.item.modulus.size = modLen;
-    return;
-}
-
-const NSSItem *
-ckmk_FetchCertAttribute(
-    ckmkInternalObject *io,
-    CK_ATTRIBUTE_TYPE type,
-    CK_RV *pError)
-{
-    ckmkItemObject *item = &io->u.item;
-    *pError = CKR_OK;
-    switch (type) {
-        case CKA_CLASS:
-            return &ckmk_certClassItem;
-        case CKA_TOKEN:
-        case CKA_MODIFIABLE:
-            return &ckmk_trueItem;
-        case CKA_PRIVATE:
-            return &ckmk_falseItem;
-        case CKA_CERTIFICATE_TYPE:
-            return &ckmk_x509Item;
-        case CKA_LABEL:
-            CKMK_HANDLE_OPT_DATA_ITEM(io, kSecLabelItemAttr, label, item, *pError,
-                                      "Cert:Label attr")
-        case CKA_SUBJECT:
-            /* OK, well apple does provide an subject and issuer attribute, but they
-             * decided to cannonicalize that value. Probably a good move for them,
-             * but makes it useless for most users of PKCS #11.. Get the real subject
-             * from the certificate */
-            if (0 == item->derCert.size) {
-                ckmk_fetchCert(io);
-            }
-            return &item->subject;
-        case CKA_ISSUER:
-            if (0 == item->derCert.size) {
-                ckmk_fetchCert(io);
-            }
-            return &item->issuer;
-        case CKA_SERIAL_NUMBER:
-            CKMK_HANDLE_DATA_ITEM(io, kSecSerialNumberItemAttr, serial, item, *pError,
-                                  "Cert:Serial Number attr")
-        case CKA_VALUE:
-            if (0 == item->derCert.size) {
-                ckmk_fetchCert(io);
-            }
-            return &item->derCert;
-        case CKA_ID:
-            CKMK_HANDLE_OPT_DATA_ITEM(io, kSecPublicKeyHashItemAttr, id, item, *pError,
-                                      "Cert:ID attr")
-        default:
-            *pError = CKR_ATTRIBUTE_TYPE_INVALID;
-            break;
-    }
-    return NULL;
-}
-
-const NSSItem *
-ckmk_FetchPubKeyAttribute(
-    ckmkInternalObject *io,
-    CK_ATTRIBUTE_TYPE type,
-    CK_RV *pError)
-{
-    ckmkItemObject *item = &io->u.item;
-    *pError = CKR_OK;
-
-    switch (type) {
-        case CKA_CLASS:
-            return &ckmk_pubKeyClassItem;
-        case CKA_TOKEN:
-        case CKA_LOCAL:
-            return &ckmk_trueItem;
-        case CKA_KEY_TYPE:
-            return &ckmk_rsaItem;
-        case CKA_LABEL:
-            CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyPrintName, label, item, *pError,
-                                      "PubKey:Label attr")
-        case CKA_ENCRYPT:
-            CKMK_HANDLE_BOOL_ITEM(io, kSecKeyEncrypt, encrypt, item, *pError,
-                                  "PubKey:Encrypt attr")
-        case CKA_VERIFY:
-            CKMK_HANDLE_BOOL_ITEM(io, kSecKeyVerify, verify, item, *pError,
-                                  "PubKey:Verify attr")
-        case CKA_VERIFY_RECOVER:
-            CKMK_HANDLE_BOOL_ITEM(io, kSecKeyVerifyRecover, verifyRecover,
-                                  item, *pError, "PubKey:VerifyRecover attr")
-        case CKA_PRIVATE:
-            CKMK_HANDLE_BOOL_ITEM(io, kSecKeyPrivate, private, item, *pError,
-                                  "PubKey:Private attr")
-        case CKA_MODIFIABLE:
-            CKMK_HANDLE_BOOL_ITEM(io, kSecKeyModifiable, modify, item, *pError,
-                                  "PubKey:Modify attr")
-        case CKA_DERIVE:
-            CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDerive, derive, item, *pError,
-                                  "PubKey:Derive attr")
-        case CKA_WRAP:
-            CKMK_HANDLE_BOOL_ITEM(io, kSecKeyWrap, wrap, item, *pError,
-                                  "PubKey:Wrap attr")
-        case CKA_SUBJECT:
-            CKMK_HANDLE_OPT_DATA_ITEM(io, kSecSubjectItemAttr, subject, item, *pError,
-                                      "PubKey:Subect attr")
-        case CKA_MODULUS:
-            return &ckmk_emptyItem;
-        case CKA_PUBLIC_EXPONENT:
-            return &ckmk_emptyItem;
-        case CKA_ID:
-            CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyLabel, id, item, *pError,
-                                      "PubKey:ID attr")
-        default:
-            *pError = CKR_ATTRIBUTE_TYPE_INVALID;
-            break;
-    }
-    return NULL;
-}
-
-const NSSItem *
-ckmk_FetchPrivKeyAttribute(
-    ckmkInternalObject *io,
-    CK_ATTRIBUTE_TYPE type,
-    CK_RV *pError)
-{
-    ckmkItemObject *item = &io->u.item;
-    *pError = CKR_OK;
-
-    switch (type) {
-        case CKA_CLASS:
-            return &ckmk_privKeyClassItem;
-        case CKA_TOKEN:
-        case CKA_LOCAL:
-            return &ckmk_trueItem;
-        case CKA_SENSITIVE:
-        case CKA_EXTRACTABLE: /* will probably move in the future */
-        case CKA_ALWAYS_SENSITIVE:
-        case CKA_NEVER_EXTRACTABLE:
-            return &ckmk_falseItem;
-        case CKA_KEY_TYPE:
-            return &ckmk_rsaItem;
-        case CKA_LABEL:
-            CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyPrintName, label, item, *pError,
-                                      "PrivateKey:Label attr")
-        case CKA_DECRYPT:
-            CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDecrypt, decrypt, item, *pError,
-                                  "PrivateKey:Decrypt attr")
-        case CKA_SIGN:
-            CKMK_HANDLE_BOOL_ITEM(io, kSecKeySign, sign, item, *pError,
-                                  "PrivateKey:Sign attr")
-        case CKA_SIGN_RECOVER:
-            CKMK_HANDLE_BOOL_ITEM(io, kSecKeySignRecover, signRecover, item, *pError,
-                                  "PrivateKey:Sign Recover attr")
-        case CKA_PRIVATE:
-            CKMK_HANDLE_BOOL_ITEM(io, kSecKeyPrivate, private, item, *pError,
-                                  "PrivateKey:Private attr")
-        case CKA_MODIFIABLE:
-            CKMK_HANDLE_BOOL_ITEM(io, kSecKeyModifiable, modify, item, *pError,
-                                  "PrivateKey:Modify attr")
-        case CKA_DERIVE:
-            CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDerive, derive, item, *pError,
-                                  "PrivateKey:Derive attr")
-        case CKA_UNWRAP:
-            CKMK_HANDLE_BOOL_ITEM(io, kSecKeyUnwrap, unwrap, item, *pError,
-                                  "PrivateKey:Unwrap attr")
-        case CKA_SUBJECT:
-            CKMK_HANDLE_OPT_DATA_ITEM(io, kSecSubjectItemAttr, subject, item, *pError,
-                                      "PrivateKey:Subject attr")
-        case CKA_MODULUS:
-            if (0 == item->modulus.size) {
-                ckmk_fetchModulus(io);
-            }
-            return &item->modulus;
-        case CKA_PUBLIC_EXPONENT:
-            return &ckmk_emptyItem;
-#ifdef notdef
-        /* the following are sensitive attributes. We could implement them for
-         * sensitive keys using the key export function, but it's better to
-         * just support wrap through this token. That will more reliably allow us
-         * to export any private key that is truly exportable.
-         */
-        case CKA_PRIVATE_EXPONENT:
-            CKMK_HANDLE_DATA_ITEM(io, kSecPrivateExponentItemAttr, privateExponent,
-                                  item, *pError)
-        case CKA_PRIME_1:
-            CKMK_HANDLE_DATA_ITEM(io, kSecPrime1ItemAttr, prime1, item, *pError)
-        case CKA_PRIME_2:
-            CKMK_HANDLE_DATA_ITEM(io, kSecPrime2ItemAttr, prime2, item, *pError)
-        case CKA_EXPONENT_1:
-            CKMK_HANDLE_DATA_ITEM(io, kSecExponent1ItemAttr, exponent1, item, *pError)
-        case CKA_EXPONENT_2:
-            CKMK_HANDLE_DATA_ITEM(io, kSecExponent2ItemAttr, exponent2, item, *pError)
-        case CKA_COEFFICIENT:
-            CKMK_HANDLE_DATA_ITEM(io, kSecCoefficientItemAttr, coefficient,
-                                  item, *pError)
-#endif
-        case CKA_ID:
-            CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyLabel, id, item, *pError,
-                                      "PrivateKey:ID attr")
-        default:
-            *pError = CKR_ATTRIBUTE_TYPE_INVALID;
-            return NULL;
-    }
-}
-
-const NSSItem *
-nss_ckmk_FetchAttribute(
-    ckmkInternalObject *io,
-    CK_ATTRIBUTE_TYPE type,
-    CK_RV *pError)
-{
-    CK_ULONG i;
-    const NSSItem *value = NULL;
-
-    if (io->type == ckmkRaw) {
-        for (i = 0; i < io->u.raw.n; i++) {
-            if (type == io->u.raw.types[i]) {
-                return &io->u.raw.items[i];
-            }
-        }
-        *pError = CKR_ATTRIBUTE_TYPE_INVALID;
-        return NULL;
-    }
-    /* deal with the common attributes */
-    switch (io->objClass) {
-        case CKO_CERTIFICATE:
-            value = ckmk_FetchCertAttribute(io, type, pError);
-            break;
-        case CKO_PRIVATE_KEY:
-            value = ckmk_FetchPrivKeyAttribute(io, type, pError);
-            break;
-        case CKO_PUBLIC_KEY:
-            value = ckmk_FetchPubKeyAttribute(io, type, pError);
-            break;
-        default:
-            *pError = CKR_OBJECT_HANDLE_INVALID;
-            return NULL;
-    }
-
-#ifdef DEBUG
-    if (CKA_ID == type) {
-        itemdump("id: ", value->data, value->size, *pError);
-    }
-#endif
-    return value;
-}
-
-static void
-ckmk_removeObjectFromHash(
-    ckmkInternalObject *io);
-
-/*
- *
- * These are the MSObject functions we need to implement
- *
- * Finalize - unneeded (actually we should clean up the hashtables)
- * Destroy
- * IsTokenObject - CK_TRUE
- * GetAttributeCount
- * GetAttributeTypes
- * GetAttributeSize
- * GetAttribute
- * SetAttribute
- * GetObjectSize
- */
-
-static CK_RV
-ckmk_mdObject_Destroy(
-    NSSCKMDObject *mdObject,
-    NSSCKFWObject *fwObject,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance)
-{
-    ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc;
-    OSStatus macErr;
-
-    if (ckmkRaw == io->type) {
-        /* there is not 'object write protected' error, use the next best thing */
-        return CKR_TOKEN_WRITE_PROTECTED;
-    }
-
-    /* This API is done well. The following 4 lines are the complete apple
-     * specific part of this implementation */
-    macErr = SecKeychainItemDelete(io->u.item.itemRef);
-    if (noErr != macErr) {
-        CKMK_MACERR("Delete object", macErr);
-    }
-
-    /* remove it from the hash */
-    ckmk_removeObjectFromHash(io);
-
-    /* free the puppy.. */
-    nss_ckmk_DestroyInternalObject(io);
-
-    return CKR_OK;
-}
-
-static CK_BBOOL
-ckmk_mdObject_IsTokenObject(
-    NSSCKMDObject *mdObject,
-    NSSCKFWObject *fwObject,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance)
-{
-    return CK_TRUE;
-}
-
-static CK_ULONG
-ckmk_mdObject_GetAttributeCount(
-    NSSCKMDObject *mdObject,
-    NSSCKFWObject *fwObject,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_RV *pError)
-{
-    ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc;
-
-    if (ckmkRaw == io->type) {
-        return io->u.raw.n;
-    }
-    switch (io->objClass) {
-        case CKO_CERTIFICATE:
-            return certAttrsCount;
-        case CKO_PUBLIC_KEY:
-            return pubKeyAttrsCount;
-        case CKO_PRIVATE_KEY:
-            return privKeyAttrsCount;
-        default:
-            break;
-    }
-    return 0;
-}
-
-static CK_RV
-ckmk_mdObject_GetAttributeTypes(
-    NSSCKMDObject *mdObject,
-    NSSCKFWObject *fwObject,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_ATTRIBUTE_TYPE_PTR typeArray,
-    CK_ULONG ulCount)
-{
-    ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc;
-    CK_ULONG i;
-    CK_RV error = CKR_OK;
-    const CK_ATTRIBUTE_TYPE *attrs = NULL;
-    CK_ULONG size = ckmk_mdObject_GetAttributeCount(
-        mdObject, fwObject, mdSession, fwSession,
-        mdToken, fwToken, mdInstance, fwInstance, &error);
-
-    if (size != ulCount) {
-        return CKR_BUFFER_TOO_SMALL;
-    }
-    if (io->type == ckmkRaw) {
-        attrs = io->u.raw.types;
-    } else
-        switch (io->objClass) {
-            case CKO_CERTIFICATE:
-                attrs =
-                    certAttrs;
-                break;
-            case CKO_PUBLIC_KEY:
-                attrs =
-                    pubKeyAttrs;
-                break;
-            case CKO_PRIVATE_KEY:
-                attrs =
-                    privKeyAttrs;
-                break;
-            default:
-                return CKR_OK;
-        }
-
-    for (i = 0; i < size; i++) {
-        typeArray[i] = attrs[i];
-    }
-
-    return CKR_OK;
-}
-
-static CK_ULONG
-ckmk_mdObject_GetAttributeSize(
-    NSSCKMDObject *mdObject,
-    NSSCKFWObject *fwObject,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_ATTRIBUTE_TYPE attribute,
-    CK_RV *pError)
-{
-    ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc;
-
-    const NSSItem *b;
-
-    b = nss_ckmk_FetchAttribute(io, attribute, pError);
-
-    if ((const NSSItem *)NULL == b) {
-        return 0;
-    }
-    return b->size;
-}
-
-static CK_RV
-ckmk_mdObject_SetAttribute(
-    NSSCKMDObject *mdObject,
-    NSSCKFWObject *fwObject,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_ATTRIBUTE_TYPE attribute,
-    NSSItem *value)
-{
-    ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc;
-    SecKeychainItemRef itemRef;
-
-    if (io->type == ckmkRaw) {
-        return CKR_TOKEN_WRITE_PROTECTED;
-    }
-    itemRef = io->u.item.itemRef;
-
-    switch (io->objClass) {
-        case CKO_PRIVATE_KEY:
-        case CKO_PUBLIC_KEY:
-            switch (attribute) {
-                case CKA_ID:
-                    ckmk_updateAttribute(itemRef, kSecKeyLabel,
-                                         value->data, value->size, "Set Attr Key ID");
-#ifdef DEBUG
-                    itemdump("key id: ", value->data, value->size, CKR_OK);
-#endif
-                    break;
-                case CKA_LABEL:
-                    ckmk_updateAttribute(itemRef, kSecKeyPrintName, value->data,
-                                         value->size, "Set Attr Key Label");
-                    break;
-                default:
-                    break;
-            }
-            break;
-
-        case CKO_CERTIFICATE:
-            switch (attribute) {
-                case CKA_ID:
-                    ckmk_updateAttribute(itemRef, kSecPublicKeyHashItemAttr,
-                                         value->data, value->size, "Set Attr Cert ID");
-                    break;
-                case CKA_LABEL:
-                    ckmk_updateAttribute(itemRef, kSecLabelItemAttr, value->data,
-                                         value->size, "Set Attr Cert Label");
-                    break;
-                default:
-                    break;
-            }
-            break;
-
-        default:
-            break;
-    }
-    return CKR_OK;
-}
-
-static NSSCKFWItem
-ckmk_mdObject_GetAttribute(
-    NSSCKMDObject *mdObject,
-    NSSCKFWObject *fwObject,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_ATTRIBUTE_TYPE attribute,
-    CK_RV *pError)
-{
-    NSSCKFWItem mdItem;
-    ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc;
-
-    mdItem.needsFreeing = PR_FALSE;
-    mdItem.item = (NSSItem *)nss_ckmk_FetchAttribute(io, attribute, pError);
-
-    return mdItem;
-}
-
-static CK_ULONG
-ckmk_mdObject_GetObjectSize(
-    NSSCKMDObject *mdObject,
-    NSSCKFWObject *fwObject,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_RV *pError)
-{
-    CK_ULONG rv = 1;
-
-    /* size is irrelevant to this token */
-    return rv;
-}
-
-static const NSSCKMDObject
-    ckmk_prototype_mdObject = {
-        (void *)NULL, /* etc */
-        NULL,         /* Finalize */
-        ckmk_mdObject_Destroy,
-        ckmk_mdObject_IsTokenObject,
-        ckmk_mdObject_GetAttributeCount,
-        ckmk_mdObject_GetAttributeTypes,
-        ckmk_mdObject_GetAttributeSize,
-        ckmk_mdObject_GetAttribute,
-        NULL, /* FreeAttribute */
-        ckmk_mdObject_SetAttribute,
-        ckmk_mdObject_GetObjectSize,
-        (void *)NULL /* null terminator */
-    };
-
-static nssHash *ckmkInternalObjectHash = NULL;
-
-NSS_IMPLEMENT NSSCKMDObject *
-nss_ckmk_CreateMDObject(
-    NSSArena *arena,
-    ckmkInternalObject *io,
-    CK_RV *pError)
-{
-    if ((nssHash *)NULL == ckmkInternalObjectHash) {
-        ckmkInternalObjectHash = nssHash_CreateItem(NULL, 10);
-    }
-    if (ckmkItem == io->type) {
-        /* the hash key, not a cryptographic key */
-        NSSItem *key = &io->hashKey;
-        ckmkInternalObject *old_o = NULL;
-
-        if (key->size == 0) {
-            ckmk_FetchHashKey(io);
-        }
-        old_o = (ckmkInternalObject *)
-            nssHash_Lookup(ckmkInternalObjectHash, key);
-        if (!old_o) {
-            nssHash_Add(ckmkInternalObjectHash, key, io);
-        } else if (old_o != io) {
-            nss_ckmk_DestroyInternalObject(io);
-            io = old_o;
-        }
-    }
-
-    if ((void *)NULL == io->mdObject.etc) {
-        (void)nsslibc_memcpy(&io->mdObject, &ckmk_prototype_mdObject,
-                             sizeof(ckmk_prototype_mdObject));
-        io->mdObject.etc = (void *)io;
-    }
-    return &io->mdObject;
-}
-
-static void
-ckmk_removeObjectFromHash(
-    ckmkInternalObject *io)
-{
-    NSSItem *key = &io->hashKey;
-
-    if ((nssHash *)NULL == ckmkInternalObjectHash) {
-        return;
-    }
-    if (key->size == 0) {
-        ckmk_FetchHashKey(io);
-    }
-    nssHash_Remove(ckmkInternalObjectHash, key);
-    return;
-}
-
-void
-nss_ckmk_DestroyInternalObject(
-    ckmkInternalObject *io)
-{
-    switch (io->type) {
-        case ckmkRaw:
-            return;
-        case ckmkItem:
-            nss_ZFreeIf(io->u.item.modify.data);
-            nss_ZFreeIf(io->u.item.private.data);
-            nss_ZFreeIf(io->u.item.encrypt.data);
-            nss_ZFreeIf(io->u.item.decrypt.data);
-            nss_ZFreeIf(io->u.item.derive.data);
-            nss_ZFreeIf(io->u.item.sign.data);
-            nss_ZFreeIf(io->u.item.signRecover.data);
-            nss_ZFreeIf(io->u.item.verify.data);
-            nss_ZFreeIf(io->u.item.verifyRecover.data);
-            nss_ZFreeIf(io->u.item.wrap.data);
-            nss_ZFreeIf(io->u.item.unwrap.data);
-            nss_ZFreeIf(io->u.item.label.data);
-            /*nss_ZFreeIf(io->u.item.subject.data); */
-            /*nss_ZFreeIf(io->u.item.issuer.data); */
-            nss_ZFreeIf(io->u.item.serial.data);
-            nss_ZFreeIf(io->u.item.modulus.data);
-            nss_ZFreeIf(io->u.item.exponent.data);
-            nss_ZFreeIf(io->u.item.privateExponent.data);
-            nss_ZFreeIf(io->u.item.prime1.data);
-            nss_ZFreeIf(io->u.item.prime2.data);
-            nss_ZFreeIf(io->u.item.exponent1.data);
-            nss_ZFreeIf(io->u.item.exponent2.data);
-            nss_ZFreeIf(io->u.item.coefficient.data);
-            break;
-    }
-    nss_ZFreeIf(io);
-    return;
-}
-
-static ckmkInternalObject *
-nss_ckmk_NewInternalObject(
-    CK_OBJECT_CLASS objClass,
-    SecKeychainItemRef itemRef,
-    SecItemClass itemClass,
-    CK_RV *pError)
-{
-    ckmkInternalObject *io = nss_ZNEW(NULL, ckmkInternalObject);
-
-    if ((ckmkInternalObject *)NULL == io) {
-        *pError = CKR_HOST_MEMORY;
-        return io;
-    }
-    io->type = ckmkItem;
-    io->objClass = objClass;
-    io->u.item.itemRef = itemRef;
-    io->u.item.itemClass = itemClass;
-    return io;
-}
-
-/*
- * Apple doesn't alway have a default keyChain set by the OS, use the
- * SearchList to try to find one.
- */
-static CK_RV
-ckmk_GetSafeDefaultKeychain(
-    SecKeychainRef *keychainRef)
-{
-    OSStatus macErr;
-    CFArrayRef searchList = 0;
-    CK_RV error = CKR_OK;
-
-    macErr = SecKeychainCopyDefault(keychainRef);
-    if (noErr != macErr) {
-        int searchCount = 0;
-        if (errSecNoDefaultKeychain != macErr) {
-            CKMK_MACERR("Getting default key chain", macErr);
-            error = CKR_GENERAL_ERROR;
-            goto loser;
-        }
-        /* ok, we don't have a default key chain, find one */
-        macErr = SecKeychainCopySearchList(&searchList);
-        if (noErr != macErr) {
-            CKMK_MACERR("failed to find a keyring searchList", macErr);
-            error = CKR_DEVICE_REMOVED;
-            goto loser;
-        }
-        searchCount = CFArrayGetCount(searchList);
-        if (searchCount < 1) {
-            error = CKR_DEVICE_REMOVED;
-            goto loser;
-        }
-        *keychainRef =
-            (SecKeychainRef)CFRetain(CFArrayGetValueAtIndex(searchList, 0));
-        if (0 == *keychainRef) {
-            error = CKR_DEVICE_REMOVED;
-            goto loser;
-        }
-        /* should we set it as default? */
-    }
-loser:
-    if (0 != searchList) {
-        CFRelease(searchList);
-    }
-    return error;
-}
-static ckmkInternalObject *
-nss_ckmk_CreateCertificate(
-    NSSCKFWSession *fwSession,
-    CK_ATTRIBUTE_PTR pTemplate,
-    CK_ULONG ulAttributeCount,
-    CK_RV *pError)
-{
-    NSSItem value;
-    ckmkInternalObject *io = NULL;
-    OSStatus macErr;
-    SecCertificateRef certRef;
-    SecKeychainItemRef itemRef;
-    SecKeychainRef keychainRef;
-    CSSM_DATA certData;
-
-    *pError = nss_ckmk_GetAttribute(CKA_VALUE, pTemplate,
-                                    ulAttributeCount, &value);
-    if (CKR_OK != *pError) {
-        goto loser;
-    }
-
-    certData.Data = value.data;
-    certData.Length = value.size;
-    macErr = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3,
-                                          CSSM_CERT_ENCODING_BER, &certRef);
-    if (noErr != macErr) {
-        CKMK_MACERR("Create cert from data Failed", macErr);
-        *pError = CKR_GENERAL_ERROR; /* need to map macErr */
-        goto loser;
-    }
-
-    *pError = ckmk_GetSafeDefaultKeychain(&keychainRef);
-    if (CKR_OK != *pError) {
-        goto loser;
-    }
-
-    macErr = SecCertificateAddToKeychain(certRef, keychainRef);
-    itemRef = (SecKeychainItemRef)certRef;
-    if (errSecDuplicateItem != macErr) {
-        NSSItem keyID = { NULL, 0 };
-        char *nickname = NULL;
-        CK_RV dummy;
-
-        if (noErr != macErr) {
-            CKMK_MACERR("Add cert to keychain Failed", macErr);
-            *pError = CKR_GENERAL_ERROR; /* need to map macErr */
-            goto loser;
-        }
-        /* these two are optional */
-        nickname = nss_ckmk_GetStringAttribute(CKA_LABEL, pTemplate,
-                                               ulAttributeCount, &dummy);
-        /* we've added a new one, update the attributes in the key ring */
-        if (nickname) {
-            ckmk_updateAttribute(itemRef, kSecLabelItemAttr, nickname,
-                                 strlen(nickname) + 1, "Modify Cert Label");
-            nss_ZFreeIf(nickname);
-        }
-        dummy = nss_ckmk_GetAttribute(CKA_ID, pTemplate,
-                                      ulAttributeCount, &keyID);
-        if (CKR_OK == dummy) {
-            dummy = ckmk_updateAttribute(itemRef, kSecPublicKeyHashItemAttr,
-                                         keyID.data, keyID.size, "Modify Cert ID");
-        }
-    }
-
-    io = nss_ckmk_NewInternalObject(CKO_CERTIFICATE, itemRef,
-                                    kSecCertificateItemClass, pError);
-    if ((ckmkInternalObject *)NULL != io) {
-        itemRef = 0;
-    }
-
-loser:
-    if (0 != itemRef) {
-        CFRelease(itemRef);
-    }
-    if (0 != keychainRef) {
-        CFRelease(keychainRef);
-    }
-
-    return io;
-}
-
-/*
- * PKCS #8 attributes
- */
-struct ckmk_AttributeStr {
-    SECItem attrType;
-    SECItem *attrValue;
-};
-typedef struct ckmk_AttributeStr ckmk_Attribute;
-
-/*
- ** A PKCS#8 private key info object
- */
-struct PrivateKeyInfoStr {
-    PLArenaPool *arena;
-    SECItem version;
-    SECAlgorithmID algorithm;
-    SECItem privateKey;
-    ckmk_Attribute **attributes;
-};
-typedef struct PrivateKeyInfoStr PrivateKeyInfo;
-
-const SEC_ASN1Template ckmk_RSAPrivateKeyTemplate[] = {
-    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey) },
-    { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, version) },
-    { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, modulus) },
-    { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, publicExponent) },
-    { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, privateExponent) },
-    { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime1) },
-    { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime2) },
-    { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent1) },
-    { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent2) },
-    { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, coefficient) },
-    { 0 }
-};
-
-const SEC_ASN1Template ckmk_AttributeTemplate[] = {
-    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ckmk_Attribute) },
-    { SEC_ASN1_OBJECT_ID, offsetof(ckmk_Attribute, attrType) },
-    { SEC_ASN1_SET_OF, offsetof(ckmk_Attribute, attrValue),
-      SEC_AnyTemplate },
-    { 0 }
-};
-
-const SEC_ASN1Template ckmk_SetOfAttributeTemplate[] = {
-    { SEC_ASN1_SET_OF, 0, ckmk_AttributeTemplate },
-};
-
-SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
-
-/* ASN1 Templates for new decoder/encoder */
-const SEC_ASN1Template ckmk_PrivateKeyInfoTemplate[] = {
-    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PrivateKeyInfo) },
-    { SEC_ASN1_INTEGER, offsetof(PrivateKeyInfo, version) },
-    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(PrivateKeyInfo, algorithm),
-      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
-    { SEC_ASN1_OCTET_STRING, offsetof(PrivateKeyInfo, privateKey) },
-    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
-      offsetof(PrivateKeyInfo, attributes), ckmk_SetOfAttributeTemplate },
-    { 0 }
-};
-
-#define CKMK_PRIVATE_KEY_INFO_VERSION 0
-static CK_RV
-ckmk_CreateRSAKeyBlob(
-    RSAPrivateKey *lk,
-    NSSItem *keyBlob)
-{
-    PrivateKeyInfo *pki = NULL;
-    PLArenaPool *arena = NULL;
-    SECOidTag algorithm = SEC_OID_UNKNOWN;
-    void *dummy;
-    SECStatus rv;
-    SECItem *encodedKey = NULL;
-    CK_RV error = CKR_OK;
-
-    arena = PORT_NewArena(2048); /* XXX different size? */
-    if (!arena) {
-        error = CKR_HOST_MEMORY;
-        goto loser;
-    }
-
-    pki = (PrivateKeyInfo *)PORT_ArenaZAlloc(arena, sizeof(PrivateKeyInfo));
-    if (!pki) {
-        error = CKR_HOST_MEMORY;
-        goto loser;
-    }
-    pki->arena = arena;
-
-    dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
-                               ckmk_RSAPrivateKeyTemplate);
-    algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION;
-
-    if (!dummy) {
-        error = CKR_DEVICE_ERROR; /* should map NSS SECError */
-        goto loser;
-    }
-
-    rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, algorithm,
-                               (SECItem *)NULL);
-    if (rv != SECSuccess) {
-        error = CKR_DEVICE_ERROR; /* should map NSS SECError */
-        goto loser;
-    }
-
-    dummy = SEC_ASN1EncodeInteger(arena, &pki->version,
-                                  CKMK_PRIVATE_KEY_INFO_VERSION);
-    if (!dummy) {
-        error = CKR_DEVICE_ERROR; /* should map NSS SECError */
-        goto loser;
-    }
-
-    encodedKey = SEC_ASN1EncodeItem(NULL, NULL, pki,
-                                    ckmk_PrivateKeyInfoTemplate);
-    if (!encodedKey) {
-        error = CKR_DEVICE_ERROR;
-        goto loser;
-    }
-
-    keyBlob->data = nss_ZNEWARRAY(NULL, char, encodedKey->len);
-    if (NULL == keyBlob->data) {
-        error = CKR_HOST_MEMORY;
-        goto loser;
-    }
-    nsslibc_memcpy(keyBlob->data, encodedKey->data, encodedKey->len);
-    keyBlob->size = encodedKey->len;
-
-loser:
-    if (arena) {
-        PORT_FreeArena(arena, PR_TRUE);
-    }
-    if (encodedKey) {
-        SECITEM_FreeItem(encodedKey, PR_TRUE);
-    }
-
-    return error;
-}
-/*
- * There MUST be a better way to do this. For now, find the key based on the
- * default name Apple gives it once we import.
- */
-#define IMPORTED_NAME "Imported Private Key"
-static CK_RV
-ckmk_FindImportedKey(
-    SecKeychainRef keychainRef,
-    SecItemClass itemClass,
-    SecKeychainItemRef *outItemRef)
-{
-    OSStatus macErr;
-    SecKeychainSearchRef searchRef = 0;
-    SecKeychainItemRef newItemRef;
-
-    macErr = SecKeychainSearchCreateFromAttributes(keychainRef, itemClass,
-                                                   NULL, &searchRef);
-    if (noErr != macErr) {
-        CKMK_MACERR("Can't search for Key", macErr);
-        return CKR_GENERAL_ERROR;
-    }
-    while (noErr == SecKeychainSearchCopyNext(searchRef, &newItemRef)) {
-        SecKeychainAttributeList *attrList = NULL;
-        SecKeychainAttributeInfo attrInfo;
-        SecItemAttr itemAttr = kSecKeyPrintName;
-        PRUint32 attrFormat = 0;
-        OSStatus macErr;
-
-        attrInfo.count = 1;
-        attrInfo.tag = &itemAttr;
-        attrInfo.format = &attrFormat;
-
-        macErr = SecKeychainItemCopyAttributesAndData(newItemRef,
-                                                      &attrInfo, NULL, &attrList, NULL, NULL);
-        if (noErr == macErr) {
-            if (nsslibc_memcmp(attrList->attr->data, IMPORTED_NAME,
-                               attrList->attr->length, NULL) == 0) {
-                *outItemRef = newItemRef;
-                CFRelease(searchRef);
-                SecKeychainItemFreeAttributesAndData(attrList, NULL);
-                return CKR_OK;
-            }
-            SecKeychainItemFreeAttributesAndData(attrList, NULL);
-        }
-        CFRelease(newItemRef);
-    }
-    CFRelease(searchRef);
-    return CKR_GENERAL_ERROR; /* we can come up with something better! */
-}
-
-static ckmkInternalObject *
-nss_ckmk_CreatePrivateKey(
-    NSSCKFWSession *fwSession,
-    CK_ATTRIBUTE_PTR pTemplate,
-    CK_ULONG ulAttributeCount,
-    CK_RV *pError)
-{
-    NSSItem attribute;
-    RSAPrivateKey lk;
-    NSSItem keyID;
-    char *nickname = NULL;
-    ckmkInternalObject *io = NULL;
-    CK_KEY_TYPE keyType;
-    OSStatus macErr;
-    SecKeychainItemRef itemRef = 0;
-    NSSItem keyBlob = { NULL, 0 };
-    CFDataRef dataRef = 0;
-    SecExternalFormat inputFormat = kSecFormatBSAFE;
-    /*SecExternalFormat inputFormat = kSecFormatOpenSSL;  */
-    SecExternalItemType itemType = kSecItemTypePrivateKey;
-    SecKeyImportExportParameters keyParams;
-    SecKeychainRef targetKeychain = 0;
-    unsigned char zero = 0;
-    CK_RV error;
-
-    keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
-    keyParams.flags = 0;
-    keyParams.passphrase = 0;
-    keyParams.alertTitle = 0;
-    keyParams.alertPrompt = 0;
-    keyParams.accessRef = 0;                          /* default */
-    keyParams.keyUsage = 0;                           /* will get filled in */
-    keyParams.keyAttributes = CSSM_KEYATTR_PERMANENT; /* will get filled in */
-    keyType = nss_ckmk_GetULongAttribute(CKA_KEY_TYPE, pTemplate, ulAttributeCount, pError);
-    if (CKR_OK != *pError) {
-        return (ckmkInternalObject *)NULL;
-    }
-    if (CKK_RSA != keyType) {
-        *pError = CKR_ATTRIBUTE_VALUE_INVALID;
-        return (ckmkInternalObject *)NULL;
-    }
-    if (nss_ckmk_GetBoolAttribute(CKA_DECRYPT,
-                                  pTemplate, ulAttributeCount, CK_TRUE)) {
-        keyParams.keyUsage |= CSSM_KEYUSE_DECRYPT;
-    }
-    if (nss_ckmk_GetBoolAttribute(CKA_UNWRAP,
-                                  pTemplate, ulAttributeCount, CK_TRUE)) {
-        keyParams.keyUsage |= CSSM_KEYUSE_UNWRAP;
-    }
-    if (nss_ckmk_GetBoolAttribute(CKA_SIGN,
-                                  pTemplate, ulAttributeCount, CK_TRUE)) {
-        keyParams.keyUsage |= CSSM_KEYUSE_SIGN;
-    }
-    if (nss_ckmk_GetBoolAttribute(CKA_DERIVE,
-                                  pTemplate, ulAttributeCount, CK_FALSE)) {
-        keyParams.keyUsage |= CSSM_KEYUSE_DERIVE;
-    }
-    if (nss_ckmk_GetBoolAttribute(CKA_SENSITIVE,
-                                  pTemplate, ulAttributeCount, CK_TRUE)) {
-        keyParams.keyAttributes |= CSSM_KEYATTR_SENSITIVE;
-    }
-    if (nss_ckmk_GetBoolAttribute(CKA_EXTRACTABLE,
-                                  pTemplate, ulAttributeCount, CK_TRUE)) {
-        keyParams.keyAttributes |= CSSM_KEYATTR_EXTRACTABLE;
-    }
-
-    lk.version.type = siUnsignedInteger;
-    lk.version.data = &zero;
-    lk.version.len = 1;
-
-    *pError = nss_ckmk_GetAttribute(CKA_MODULUS, pTemplate,
-                                    ulAttributeCount, &attribute);
-    if (CKR_OK != *pError) {
-        return (ckmkInternalObject *)NULL;
-    }
-    lk.modulus.type = siUnsignedInteger;
-    lk.modulus.data = attribute.data;
-    lk.modulus.len = attribute.size;
-
-    *pError = nss_ckmk_GetAttribute(CKA_PUBLIC_EXPONENT, pTemplate,
-                                    ulAttributeCount, &attribute);
-    if (CKR_OK != *pError) {
-        return (ckmkInternalObject *)NULL;
-    }
-    lk.publicExponent.type = siUnsignedInteger;
-    lk.publicExponent.data = attribute.data;
-    lk.publicExponent.len = attribute.size;
-
-    *pError = nss_ckmk_GetAttribute(CKA_PRIVATE_EXPONENT, pTemplate,
-                                    ulAttributeCount, &attribute);
-    if (CKR_OK != *pError) {
-        return (ckmkInternalObject *)NULL;
-    }
-    lk.privateExponent.type = siUnsignedInteger;
-    lk.privateExponent.data = attribute.data;
-    lk.privateExponent.len = attribute.size;
-
-    *pError = nss_ckmk_GetAttribute(CKA_PRIME_1, pTemplate,
-                                    ulAttributeCount, &attribute);
-    if (CKR_OK != *pError) {
-        return (ckmkInternalObject *)NULL;
-    }
-    lk.prime1.type = siUnsignedInteger;
-    lk.prime1.data = attribute.data;
-    lk.prime1.len = attribute.size;
-
-    *pError = nss_ckmk_GetAttribute(CKA_PRIME_2, pTemplate,
-                                    ulAttributeCount, &attribute);
-    if (CKR_OK != *pError) {
-        return (ckmkInternalObject *)NULL;
-    }
-    lk.prime2.type = siUnsignedInteger;
-    lk.prime2.data = attribute.data;
-    lk.prime2.len = attribute.size;
-
-    *pError = nss_ckmk_GetAttribute(CKA_EXPONENT_1, pTemplate,
-                                    ulAttributeCount, &attribute);
-    if (CKR_OK != *pError) {
-        return (ckmkInternalObject *)NULL;
-    }
-    lk.exponent1.type = siUnsignedInteger;
-    lk.exponent1.data = attribute.data;
-    lk.exponent1.len = attribute.size;
-
-    *pError = nss_ckmk_GetAttribute(CKA_EXPONENT_2, pTemplate,
-                                    ulAttributeCount, &attribute);
-    if (CKR_OK != *pError) {
-        return (ckmkInternalObject *)NULL;
-    }
-    lk.exponent2.type = siUnsignedInteger;
-    lk.exponent2.data = attribute.data;
-    lk.exponent2.len = attribute.size;
-
-    *pError = nss_ckmk_GetAttribute(CKA_COEFFICIENT, pTemplate,
-                                    ulAttributeCount, &attribute);
-    if (CKR_OK != *pError) {
-        return (ckmkInternalObject *)NULL;
-    }
-    lk.coefficient.type = siUnsignedInteger;
-    lk.coefficient.data = attribute.data;
-    lk.coefficient.len = attribute.size;
-
-    /* ASN1 Encode the pkcs8 structure... look at softoken to see how this
-     * is done... */
-    error = ckmk_CreateRSAKeyBlob(&lk, &keyBlob);
-    if (CKR_OK != error) {
-        goto loser;
-    }
-
-    dataRef = CFDataCreate(NULL, (UInt8 *)keyBlob.data, keyBlob.size);
-    if (0 == dataRef) {
-        *pError = CKR_HOST_MEMORY;
-        goto loser;
-    }
-
-    *pError == ckmk_GetSafeDefaultKeychain(&targetKeychain);
-    if (CKR_OK != *pError) {
-        goto loser;
-    }
-
-    /* the itemArray that is returned is useless. the item does not
-     * is 'not on the key chain' so none of the modify calls work on it.
-     * It also has a key that isn't the same key as the one in the actual
-     * key chain. In short it isn't the item we want, and it gives us zero
-     * information about the item we want, so don't even bother with it...
-     */
-    macErr = SecKeychainItemImport(dataRef, NULL, &inputFormat, &itemType, 0,
-                                   &keyParams, targetKeychain, NULL);
-    if (noErr != macErr) {
-        CKMK_MACERR("Import Private Key", macErr);
-        *pError = CKR_GENERAL_ERROR;
-        goto loser;
-    }
-
-    *pError = ckmk_FindImportedKey(targetKeychain,
-                                   CSSM_DL_DB_RECORD_PRIVATE_KEY,
-                                   &itemRef);
-    if (CKR_OK != *pError) {
-#ifdef DEBUG
-        fprintf(stderr, "couldn't find key in keychain \n");
-#endif
-        goto loser;
-    }
-
-    /* set the CKA_ID and  the CKA_LABEL */
-    error = nss_ckmk_GetAttribute(CKA_ID, pTemplate,
-                                  ulAttributeCount, &keyID);
-    if (CKR_OK == error) {
-        error = ckmk_updateAttribute(itemRef, kSecKeyLabel,
-                                     keyID.data, keyID.size, "Modify Key ID");
-#ifdef DEBUG
-        itemdump("key id: ", keyID.data, keyID.size, error);
-#endif
-    }
-    nickname = nss_ckmk_GetStringAttribute(CKA_LABEL, pTemplate,
-                                           ulAttributeCount, &error);
-    if (nickname) {
-        ckmk_updateAttribute(itemRef, kSecKeyPrintName, nickname,
-                             strlen(nickname) + 1, "Modify Key Label");
-    } else {
-#define DEFAULT_NICKNAME "NSS Imported Key"
-        ckmk_updateAttribute(itemRef, kSecKeyPrintName, DEFAULT_NICKNAME,
-                             sizeof(DEFAULT_NICKNAME), "Modify Key Label");
-    }
-
-    io = nss_ckmk_NewInternalObject(CKO_PRIVATE_KEY, itemRef,
-                                    CSSM_DL_DB_RECORD_PRIVATE_KEY, pError);
-    if ((ckmkInternalObject *)NULL == io) {
-        CFRelease(itemRef);
-    }
-
-    return io;
-
-loser:
-    /* free the key blob */
-    if (keyBlob.data) {
-        nss_ZFreeIf(keyBlob.data);
-    }
-    if (0 != targetKeychain) {
-        CFRelease(targetKeychain);
-    }
-    if (0 != dataRef) {
-        CFRelease(dataRef);
-    }
-    return io;
-}
-
-NSS_EXTERN NSSCKMDObject *
-nss_ckmk_CreateObject(
-    NSSCKFWSession *fwSession,
-    CK_ATTRIBUTE_PTR pTemplate,
-    CK_ULONG ulAttributeCount,
-    CK_RV *pError)
-{
-    CK_OBJECT_CLASS objClass;
-    ckmkInternalObject *io = NULL;
-    CK_BBOOL isToken;
-
-    /*
-     * only create token objects
-     */
-    isToken = nss_ckmk_GetBoolAttribute(CKA_TOKEN, pTemplate,
-                                        ulAttributeCount, CK_FALSE);
-    if (!isToken) {
-        *pError = CKR_ATTRIBUTE_VALUE_INVALID;
-        return (NSSCKMDObject *)NULL;
-    }
-
-    /*
-     * only create keys and certs.
-     */
-    objClass = nss_ckmk_GetULongAttribute(CKA_CLASS, pTemplate,
-                                          ulAttributeCount, pError);
-    if (CKR_OK != *pError) {
-        return (NSSCKMDObject *)NULL;
-    }
-#ifdef notdef
-    if (objClass == CKO_PUBLIC_KEY) {
-        return CKR_OK; /* fake public key creation, happens as a side effect of
-                        * private key creation */
-    }
-#endif
-    if (objClass == CKO_CERTIFICATE) {
-        io = nss_ckmk_CreateCertificate(fwSession, pTemplate,
-                                        ulAttributeCount, pError);
-    } else if (objClass == CKO_PRIVATE_KEY) {
-        io = nss_ckmk_CreatePrivateKey(fwSession, pTemplate,
-                                       ulAttributeCount, pError);
-    } else {
-        *pError = CKR_ATTRIBUTE_VALUE_INVALID;
-    }
-
-    if ((ckmkInternalObject *)NULL == io) {
-        return (NSSCKMDObject *)NULL;
-    }
-    return nss_ckmk_CreateMDObject(NULL, io, pError);
-}
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/mrsa.c
+++ /dev/null
@@ -1,479 +0,0 @@
-/* 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 "ckmk.h"
-
-/* Sigh, For all the talk about 'ease of use', apple has hidden the interfaces
- * needed to be able to truly use CSSM. These came from their modification
- * to NSS's S/MIME code. The following two functions currently are not
- * part of the SecKey.h interface.
- */
-OSStatus
-SecKeyGetCredentials(
-    SecKeyRef keyRef,
-    CSSM_ACL_AUTHORIZATION_TAG authTag,
-    int type,
-    const CSSM_ACCESS_CREDENTIALS **creds);
-
-/* this function could be implemented using 'SecKeychainItemCopyKeychain' and
- * 'SecKeychainGetCSPHandle' */
-OSStatus
-SecKeyGetCSPHandle(
-    SecKeyRef keyRef,
-    CSSM_CSP_HANDLE *cspHandle);
-
-typedef struct ckmkInternalCryptoOperationRSAPrivStr
-    ckmkInternalCryptoOperationRSAPriv;
-struct ckmkInternalCryptoOperationRSAPrivStr {
-    NSSCKMDCryptoOperation mdOperation;
-    NSSCKMDMechanism *mdMechanism;
-    ckmkInternalObject *iKey;
-    NSSItem *buffer;
-    CSSM_CC_HANDLE cssmContext;
-};
-
-typedef enum {
-    CKMK_DECRYPT,
-    CKMK_SIGN
-} ckmkRSAOpType;
-
-/*
- * ckmk_mdCryptoOperationRSAPriv_Create
- */
-static NSSCKMDCryptoOperation *
-ckmk_mdCryptoOperationRSAPriv_Create(
-    const NSSCKMDCryptoOperation *proto,
-    NSSCKMDMechanism *mdMechanism,
-    NSSCKMDObject *mdKey,
-    ckmkRSAOpType type,
-    CK_RV *pError)
-{
-    ckmkInternalObject *iKey = (ckmkInternalObject *)mdKey->etc;
-    const NSSItem *classItem = nss_ckmk_FetchAttribute(iKey, CKA_CLASS, pError);
-    const NSSItem *keyType = nss_ckmk_FetchAttribute(iKey, CKA_KEY_TYPE, pError);
-    ckmkInternalCryptoOperationRSAPriv *iOperation;
-    SecKeyRef privateKey;
-    OSStatus macErr;
-    CSSM_RETURN cssmErr;
-    const CSSM_KEY *cssmKey;
-    CSSM_CSP_HANDLE cspHandle;
-    const CSSM_ACCESS_CREDENTIALS *creds = NULL;
-    CSSM_CC_HANDLE cssmContext;
-    CSSM_ACL_AUTHORIZATION_TAG authType;
-
-    /* make sure we have the right objects */
-    if (((const NSSItem *)NULL == classItem) ||
-        (sizeof(CK_OBJECT_CLASS) != classItem->size) ||
-        (CKO_PRIVATE_KEY != *(CK_OBJECT_CLASS *)classItem->data) ||
-        ((const NSSItem *)NULL == keyType) ||
-        (sizeof(CK_KEY_TYPE) != keyType->size) ||
-        (CKK_RSA != *(CK_KEY_TYPE *)keyType->data)) {
-        *pError = CKR_KEY_TYPE_INCONSISTENT;
-        return (NSSCKMDCryptoOperation *)NULL;
-    }
-
-    privateKey = (SecKeyRef)iKey->u.item.itemRef;
-    macErr = SecKeyGetCSSMKey(privateKey, &cssmKey);
-    if (noErr != macErr) {
-        CKMK_MACERR("Getting CSSM Key", macErr);
-        *pError = CKR_KEY_HANDLE_INVALID;
-        return (NSSCKMDCryptoOperation *)NULL;
-    }
-    macErr = SecKeyGetCSPHandle(privateKey, &cspHandle);
-    if (noErr != macErr) {
-        CKMK_MACERR("Getting CSP for Key", macErr);
-        *pError = CKR_KEY_HANDLE_INVALID;
-        return (NSSCKMDCryptoOperation *)NULL;
-    }
-    switch (type) {
-        case CKMK_DECRYPT:
-            authType = CSSM_ACL_AUTHORIZATION_DECRYPT;
-            break;
-        case CKMK_SIGN:
-            authType = CSSM_ACL_AUTHORIZATION_SIGN;
-            break;
-        default:
-            *pError = CKR_GENERAL_ERROR;
-#ifdef DEBUG
-            fprintf(stderr, "RSAPriv_Create: bad type = %d\n", type);
-#endif
-            return (NSSCKMDCryptoOperation *)NULL;
-    }
-
-    macErr = SecKeyGetCredentials(privateKey, authType, 0, &creds);
-    if (noErr != macErr) {
-        CKMK_MACERR("Getting Credentials for Key", macErr);
-        *pError = CKR_KEY_HANDLE_INVALID;
-        return (NSSCKMDCryptoOperation *)NULL;
-    }
-
-    switch (type) {
-        case CKMK_DECRYPT:
-            cssmErr = CSSM_CSP_CreateAsymmetricContext(cspHandle, CSSM_ALGID_RSA,
-                                                       creds, cssmKey, CSSM_PADDING_PKCS1, &cssmContext);
-            break;
-        case CKMK_SIGN:
-            cssmErr = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,
-                                                      creds, cssmKey, &cssmContext);
-            break;
-        default:
-            *pError = CKR_GENERAL_ERROR;
-#ifdef DEBUG
-            fprintf(stderr, "RSAPriv_Create: bad type = %d\n", type);
-#endif
-            return (NSSCKMDCryptoOperation *)NULL;
-    }
-    if (noErr != cssmErr) {
-        CKMK_MACERR("Getting Context for Key", cssmErr);
-        *pError = CKR_GENERAL_ERROR;
-        return (NSSCKMDCryptoOperation *)NULL;
-    }
-
-    iOperation = nss_ZNEW(NULL, ckmkInternalCryptoOperationRSAPriv);
-    if ((ckmkInternalCryptoOperationRSAPriv *)NULL == iOperation) {
-        *pError = CKR_HOST_MEMORY;
-        return (NSSCKMDCryptoOperation *)NULL;
-    }
-    iOperation->mdMechanism = mdMechanism;
-    iOperation->iKey = iKey;
-    iOperation->cssmContext = cssmContext;
-
-    nsslibc_memcpy(&iOperation->mdOperation,
-                   proto, sizeof(NSSCKMDCryptoOperation));
-    iOperation->mdOperation.etc = iOperation;
-
-    return &iOperation->mdOperation;
-}
-
-static void
-ckmk_mdCryptoOperationRSAPriv_Destroy(
-    NSSCKMDCryptoOperation *mdOperation,
-    NSSCKFWCryptoOperation *fwOperation,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance)
-{
-    ckmkInternalCryptoOperationRSAPriv *iOperation =
-        (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc;
-
-    if (iOperation->buffer) {
-        nssItem_Destroy(iOperation->buffer);
-    }
-    if (iOperation->cssmContext) {
-        CSSM_DeleteContext(iOperation->cssmContext);
-    }
-    nss_ZFreeIf(iOperation);
-    return;
-}
-
-static CK_ULONG
-ckmk_mdCryptoOperationRSA_GetFinalLength(
-    NSSCKMDCryptoOperation *mdOperation,
-    NSSCKFWCryptoOperation *fwOperation,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_RV *pError)
-{
-    ckmkInternalCryptoOperationRSAPriv *iOperation =
-        (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc;
-    const NSSItem *modulus =
-        nss_ckmk_FetchAttribute(iOperation->iKey, CKA_MODULUS, pError);
-
-    return modulus->size;
-}
-
-/*
- * ckmk_mdCryptoOperationRSADecrypt_GetOperationLength
- * we won't know the length until we actually decrypt the
- * input block. Since we go to all the work to decrypt the
- * the block, we'll save if for when the block is asked for
- */
-static CK_ULONG
-ckmk_mdCryptoOperationRSADecrypt_GetOperationLength(
-    NSSCKMDCryptoOperation *mdOperation,
-    NSSCKFWCryptoOperation *fwOperation,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    const NSSItem *input,
-    CK_RV *pError)
-{
-    ckmkInternalCryptoOperationRSAPriv *iOperation =
-        (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc;
-    CSSM_DATA cssmInput;
-    CSSM_DATA cssmOutput = { 0, NULL };
-    PRUint32 bytesDecrypted;
-    CSSM_DATA remainder = { 0, NULL };
-    NSSItem output;
-    CSSM_RETURN cssmErr;
-
-    if (iOperation->buffer) {
-        return iOperation->buffer->size;
-    }
-
-    cssmInput.Data = input->data;
-    cssmInput.Length = input->size;
-
-    cssmErr = CSSM_DecryptData(iOperation->cssmContext,
-                               &cssmInput, 1, &cssmOutput, 1,
-                               &bytesDecrypted, &remainder);
-    if (CSSM_OK != cssmErr) {
-        CKMK_MACERR("Decrypt Failed", cssmErr);
-        *pError = CKR_DATA_INVALID;
-        return 0;
-    }
-    /* we didn't suppy any buffers, so it should all be in remainder */
-    output.data = nss_ZNEWARRAY(NULL, char, bytesDecrypted + remainder.Length);
-    if (NULL == output.data) {
-        free(cssmOutput.Data);
-        free(remainder.Data);
-        *pError = CKR_HOST_MEMORY;
-        return 0;
-    }
-    output.size = bytesDecrypted + remainder.Length;
-
-    if (0 != bytesDecrypted) {
-        nsslibc_memcpy(output.data, cssmOutput.Data, bytesDecrypted);
-        free(cssmOutput.Data);
-    }
-    if (0 != remainder.Length) {
-        nsslibc_memcpy(((char *)output.data) + bytesDecrypted,
-                       remainder.Data, remainder.Length);
-        free(remainder.Data);
-    }
-
-    iOperation->buffer = nssItem_Duplicate(&output, NULL, NULL);
-    nss_ZFreeIf(output.data);
-    if ((NSSItem *)NULL == iOperation->buffer) {
-        *pError = CKR_HOST_MEMORY;
-        return 0;
-    }
-
-    return iOperation->buffer->size;
-}
-
-/*
- * ckmk_mdCryptoOperationRSADecrypt_UpdateFinal
- *
- * NOTE: ckmk_mdCryptoOperationRSADecrypt_GetOperationLength is presumed to
- * have been called previously.
- */
-static CK_RV
-ckmk_mdCryptoOperationRSADecrypt_UpdateFinal(
-    NSSCKMDCryptoOperation *mdOperation,
-    NSSCKFWCryptoOperation *fwOperation,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    const NSSItem *input,
-    NSSItem *output)
-{
-    ckmkInternalCryptoOperationRSAPriv *iOperation =
-        (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc;
-    NSSItem *buffer = iOperation->buffer;
-
-    if ((NSSItem *)NULL == buffer) {
-        return CKR_GENERAL_ERROR;
-    }
-    nsslibc_memcpy(output->data, buffer->data, buffer->size);
-    output->size = buffer->size;
-    return CKR_OK;
-}
-
-/*
- * ckmk_mdCryptoOperationRSASign_UpdateFinal
- *
- */
-static CK_RV
-ckmk_mdCryptoOperationRSASign_UpdateFinal(
-    NSSCKMDCryptoOperation *mdOperation,
-    NSSCKFWCryptoOperation *fwOperation,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    const NSSItem *input,
-    NSSItem *output)
-{
-    ckmkInternalCryptoOperationRSAPriv *iOperation =
-        (ckmkInternalCryptoOperationRSAPriv *)mdOperation->etc;
-    CSSM_DATA cssmInput;
-    CSSM_DATA cssmOutput = { 0, NULL };
-    CSSM_RETURN cssmErr;
-
-    cssmInput.Data = input->data;
-    cssmInput.Length = input->size;
-
-    cssmErr = CSSM_SignData(iOperation->cssmContext, &cssmInput, 1,
-                            CSSM_ALGID_NONE, &cssmOutput);
-    if (CSSM_OK != cssmErr) {
-        CKMK_MACERR("Signed Failed", cssmErr);
-        return CKR_FUNCTION_FAILED;
-    }
-    if (cssmOutput.Length > output->size) {
-        free(cssmOutput.Data);
-        return CKR_BUFFER_TOO_SMALL;
-    }
-    nsslibc_memcpy(output->data, cssmOutput.Data, cssmOutput.Length);
-    free(cssmOutput.Data);
-    output->size = cssmOutput.Length;
-
-    return CKR_OK;
-}
-
-NSS_IMPLEMENT_DATA const NSSCKMDCryptoOperation
-    ckmk_mdCryptoOperationRSADecrypt_proto = {
-        NULL, /* etc */
-        ckmk_mdCryptoOperationRSAPriv_Destroy,
-        NULL, /* GetFinalLengh - not needed for one shot Decrypt/Encrypt */
-        ckmk_mdCryptoOperationRSADecrypt_GetOperationLength,
-        NULL, /* Final - not needed for one shot operation */
-        NULL, /* Update - not needed for one shot operation */
-        NULL, /* DigetUpdate - not needed for one shot operation */
-        ckmk_mdCryptoOperationRSADecrypt_UpdateFinal,
-        NULL,        /* UpdateCombo - not needed for one shot operation */
-        NULL,        /* DigetKey - not needed for one shot operation */
-        (void *)NULL /* null terminator */
-    };
-
-NSS_IMPLEMENT_DATA const NSSCKMDCryptoOperation
-    ckmk_mdCryptoOperationRSASign_proto = {
-        NULL, /* etc */
-        ckmk_mdCryptoOperationRSAPriv_Destroy,
-        ckmk_mdCryptoOperationRSA_GetFinalLength,
-        NULL, /* GetOperationLengh - not needed for one shot Sign/Verify */
-        NULL, /* Final - not needed for one shot operation */
-        NULL, /* Update - not needed for one shot operation */
-        NULL, /* DigetUpdate - not needed for one shot operation */
-        ckmk_mdCryptoOperationRSASign_UpdateFinal,
-        NULL,        /* UpdateCombo - not needed for one shot operation */
-        NULL,        /* DigetKey - not needed for one shot operation */
-        (void *)NULL /* null terminator */
-    };
-
-/********** NSSCKMDMechansim functions ***********************/
-/*
- * ckmk_mdMechanismRSA_Destroy
- */
-static void
-ckmk_mdMechanismRSA_Destroy(
-    NSSCKMDMechanism *mdMechanism,
-    NSSCKFWMechanism *fwMechanism,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance)
-{
-    nss_ZFreeIf(fwMechanism);
-}
-
-/*
- * ckmk_mdMechanismRSA_GetMinKeySize
- */
-static CK_ULONG
-ckmk_mdMechanismRSA_GetMinKeySize(
-    NSSCKMDMechanism *mdMechanism,
-    NSSCKFWMechanism *fwMechanism,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_RV *pError)
-{
-    return 384;
-}
-
-/*
- * ckmk_mdMechanismRSA_GetMaxKeySize
- */
-static CK_ULONG
-ckmk_mdMechanismRSA_GetMaxKeySize(
-    NSSCKMDMechanism *mdMechanism,
-    NSSCKFWMechanism *fwMechanism,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_RV *pError)
-{
-    return 16384;
-}
-
-/*
- * ckmk_mdMechanismRSA_DecryptInit
- */
-static NSSCKMDCryptoOperation *
-ckmk_mdMechanismRSA_DecryptInit(
-    NSSCKMDMechanism *mdMechanism,
-    NSSCKFWMechanism *fwMechanism,
-    CK_MECHANISM *pMechanism,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    NSSCKMDObject *mdKey,
-    NSSCKFWObject *fwKey,
-    CK_RV *pError)
-{
-    return ckmk_mdCryptoOperationRSAPriv_Create(
-        &ckmk_mdCryptoOperationRSADecrypt_proto,
-        mdMechanism, mdKey, CKMK_DECRYPT, pError);
-}
-
-/*
- * ckmk_mdMechanismRSA_SignInit
- */
-static NSSCKMDCryptoOperation *
-ckmk_mdMechanismRSA_SignInit(
-    NSSCKMDMechanism *mdMechanism,
-    NSSCKFWMechanism *fwMechanism,
-    CK_MECHANISM *pMechanism,
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    NSSCKMDObject *mdKey,
-    NSSCKFWObject *fwKey,
-    CK_RV *pError)
-{
-    return ckmk_mdCryptoOperationRSAPriv_Create(
-        &ckmk_mdCryptoOperationRSASign_proto,
-        mdMechanism, mdKey, CKMK_SIGN, pError);
-}
-
-NSS_IMPLEMENT_DATA const NSSCKMDMechanism
-    nss_ckmk_mdMechanismRSA = {
-        (void *)NULL, /* etc */
-        ckmk_mdMechanismRSA_Destroy,
-        ckmk_mdMechanismRSA_GetMinKeySize,
-        ckmk_mdMechanismRSA_GetMaxKeySize,
-        NULL, /* GetInHardware - default false */
-        NULL, /* EncryptInit - default errs */
-        ckmk_mdMechanismRSA_DecryptInit,
-        NULL, /* DigestInit - default errs*/
-        ckmk_mdMechanismRSA_SignInit,
-        NULL,                         /* VerifyInit - default errs */
-        ckmk_mdMechanismRSA_SignInit, /* SignRecoverInit */
-        NULL,                         /* VerifyRecoverInit - default errs */
-        NULL,                         /* GenerateKey - default errs */
-        NULL,                         /* GenerateKeyPair - default errs */
-        NULL,                         /* GetWrapKeyLength - default errs */
-        NULL,                         /* WrapKey - default errs */
-        NULL,                         /* UnwrapKey - default errs */
-        NULL,                         /* DeriveKey - default errs */
-        (void *)NULL                  /* null terminator */
-    };
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/msession.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/* 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 "ckmk.h"
-
-/*
- * nssmkey/msession.c
- *
- * This file implements the NSSCKMDSession object for the
- * "nssmkey" cryptoki module.
- */
-
-static NSSCKMDFindObjects *
-ckmk_mdSession_FindObjectsInit(
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_ATTRIBUTE_PTR pTemplate,
-    CK_ULONG ulAttributeCount,
-    CK_RV *pError)
-{
-    return nss_ckmk_FindObjectsInit(fwSession, pTemplate, ulAttributeCount, pError);
-}
-
-static NSSCKMDObject *
-ckmk_mdSession_CreateObject(
-    NSSCKMDSession *mdSession,
-    NSSCKFWSession *fwSession,
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    NSSArena *arena,
-    CK_ATTRIBUTE_PTR pTemplate,
-    CK_ULONG ulAttributeCount,
-    CK_RV *pError)
-{
-    return nss_ckmk_CreateObject(fwSession, pTemplate, ulAttributeCount, pError);
-}
-
-NSS_IMPLEMENT NSSCKMDSession *
-nss_ckmk_CreateSession(
-    NSSCKFWSession *fwSession,
-    CK_RV *pError)
-{
-    NSSArena *arena;
-    NSSCKMDSession *rv;
-
-    arena = NSSCKFWSession_GetArena(fwSession, pError);
-    if ((NSSArena *)NULL == arena) {
-        return (NSSCKMDSession *)NULL;
-    }
-
-    rv = nss_ZNEW(arena, NSSCKMDSession);
-    if ((NSSCKMDSession *)NULL == rv) {
-        *pError = CKR_HOST_MEMORY;
-        return (NSSCKMDSession *)NULL;
-    }
-
-    /*
-     * rv was zeroed when allocated, so we only
-     * need to set the non-zero members.
-     */
-
-    rv->etc = (void *)fwSession;
-    /* rv->Close */
-    /* rv->GetDeviceError */
-    /* rv->Login */
-    /* rv->Logout */
-    /* rv->InitPIN */
-    /* rv->SetPIN */
-    /* rv->GetOperationStateLen */
-    /* rv->GetOperationState */
-    /* rv->SetOperationState */
-    rv->CreateObject = ckmk_mdSession_CreateObject;
-    /* rv->CopyObject */
-    rv->FindObjectsInit = ckmk_mdSession_FindObjectsInit;
-    /* rv->SeedRandom */
-    /* rv->GetRandom */
-    /* rv->null */
-
-    return rv;
-}
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/mslot.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/* 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 "ckmk.h"
-
-/*
- * nssmkey/mslot.c
- *
- * This file implements the NSSCKMDSlot object for the
- * "nssmkey" cryptoki module.
- */
-
-static NSSUTF8 *
-ckmk_mdSlot_GetSlotDescription(
-    NSSCKMDSlot *mdSlot,
-    NSSCKFWSlot *fwSlot,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_RV *pError)
-{
-    return (NSSUTF8 *)nss_ckmk_SlotDescription;
-}
-
-static NSSUTF8 *
-ckmk_mdSlot_GetManufacturerID(
-    NSSCKMDSlot *mdSlot,
-    NSSCKFWSlot *fwSlot,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_RV *pError)
-{
-    return (NSSUTF8 *)nss_ckmk_ManufacturerID;
-}
-
-static CK_VERSION
-ckmk_mdSlot_GetHardwareVersion(
-    NSSCKMDSlot *mdSlot,
-    NSSCKFWSlot *fwSlot,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance)
-{
-    return nss_ckmk_HardwareVersion;
-}
-
-static CK_VERSION
-ckmk_mdSlot_GetFirmwareVersion(
-    NSSCKMDSlot *mdSlot,
-    NSSCKFWSlot *fwSlot,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance)
-{
-    return nss_ckmk_FirmwareVersion;
-}
-
-static NSSCKMDToken *
-ckmk_mdSlot_GetToken(
-    NSSCKMDSlot *mdSlot,
-    NSSCKFWSlot *fwSlot,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_RV *pError)
-{
-    return (NSSCKMDToken *)&nss_ckmk_mdToken;
-}
-
-NSS_IMPLEMENT_DATA const NSSCKMDSlot
-    nss_ckmk_mdSlot = {
-        (void *)NULL, /* etc */
-        NULL,         /* Initialize */
-        NULL,         /* Destroy */
-        ckmk_mdSlot_GetSlotDescription,
-        ckmk_mdSlot_GetManufacturerID,
-        NULL, /* GetTokenPresent -- defaults to true */
-        NULL, /* GetRemovableDevice -- defaults to false */
-        NULL, /* GetHardwareSlot -- defaults to false */
-        ckmk_mdSlot_GetHardwareVersion,
-        ckmk_mdSlot_GetFirmwareVersion,
-        ckmk_mdSlot_GetToken,
-        (void *)NULL /* null terminator */
-    };
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/mtoken.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* 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 "ckmk.h"
-
-/*
- * nssmkey/mtoken.c
- *
- * This file implements the NSSCKMDToken object for the
- * "nssmkey" cryptoki module.
- */
-
-static NSSUTF8 *
-ckmk_mdToken_GetLabel(
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_RV *pError)
-{
-    return (NSSUTF8 *)nss_ckmk_TokenLabel;
-}
-
-static NSSUTF8 *
-ckmk_mdToken_GetManufacturerID(
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_RV *pError)
-{
-    return (NSSUTF8 *)nss_ckmk_ManufacturerID;
-}
-
-static NSSUTF8 *
-ckmk_mdToken_GetModel(
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_RV *pError)
-{
-    return (NSSUTF8 *)nss_ckmk_TokenModel;
-}
-
-static NSSUTF8 *
-ckmk_mdToken_GetSerialNumber(
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_RV *pError)
-{
-    return (NSSUTF8 *)nss_ckmk_TokenSerialNumber;
-}
-
-static CK_BBOOL
-ckmk_mdToken_GetIsWriteProtected(
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance)
-{
-    return CK_FALSE;
-}
-
-/* fake out Mozilla so we don't try to initialize the token */
-static CK_BBOOL
-ckmk_mdToken_GetUserPinInitialized(
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance)
-{
-    return CK_TRUE;
-}
-
-static CK_VERSION
-ckmk_mdToken_GetHardwareVersion(
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance)
-{
-    return nss_ckmk_HardwareVersion;
-}
-
-static CK_VERSION
-ckmk_mdToken_GetFirmwareVersion(
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance)
-{
-    return nss_ckmk_FirmwareVersion;
-}
-
-static NSSCKMDSession *
-ckmk_mdToken_OpenSession(
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    NSSCKFWSession *fwSession,
-    CK_BBOOL rw,
-    CK_RV *pError)
-{
-    return nss_ckmk_CreateSession(fwSession, pError);
-}
-
-static CK_ULONG
-ckmk_mdToken_GetMechanismCount(
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance)
-{
-    return (CK_ULONG)1;
-}
-
-static CK_RV
-ckmk_mdToken_GetMechanismTypes(
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_MECHANISM_TYPE types[])
-{
-    types[0] = CKM_RSA_PKCS;
-    return CKR_OK;
-}
-
-static NSSCKMDMechanism *
-ckmk_mdToken_GetMechanism(
-    NSSCKMDToken *mdToken,
-    NSSCKFWToken *fwToken,
-    NSSCKMDInstance *mdInstance,
-    NSSCKFWInstance *fwInstance,
-    CK_MECHANISM_TYPE which,
-    CK_RV *pError)
-{
-    if (which != CKM_RSA_PKCS) {
-        *pError = CKR_MECHANISM_INVALID;
-        return (NSSCKMDMechanism *)NULL;
-    }
-    return (NSSCKMDMechanism *)&nss_ckmk_mdMechanismRSA;
-}
-
-NSS_IMPLEMENT_DATA const NSSCKMDToken
-    nss_ckmk_mdToken = {
-        (void *)NULL, /* etc */
-        NULL,         /* Setup */
-        NULL,         /* Invalidate */
-        NULL,         /* InitToken -- default errs */
-        ckmk_mdToken_GetLabel,
-        ckmk_mdToken_GetManufacturerID,
-        ckmk_mdToken_GetModel,
-        ckmk_mdToken_GetSerialNumber,
-        NULL, /* GetHasRNG -- default is false */
-        ckmk_mdToken_GetIsWriteProtected,
-        NULL, /* GetLoginRequired -- default is false */
-        ckmk_mdToken_GetUserPinInitialized,
-        NULL, /* GetRestoreKeyNotNeeded -- irrelevant */
-        NULL, /* GetHasClockOnToken -- default is false */
-        NULL, /* GetHasProtectedAuthenticationPath -- default is false */
-        NULL, /* GetSupportsDualCryptoOperations -- default is false */
-        NULL, /* GetMaxSessionCount -- default is CK_UNAVAILABLE_INFORMATION */
-        NULL, /* GetMaxRwSessionCount -- default is CK_UNAVAILABLE_INFORMATION */
-        NULL, /* GetMaxPinLen -- irrelevant */
-        NULL, /* GetMinPinLen -- irrelevant */
-        NULL, /* GetTotalPublicMemory -- default is CK_UNAVAILABLE_INFORMATION */
-        NULL, /* GetFreePublicMemory -- default is CK_UNAVAILABLE_INFORMATION */
-        NULL, /* GetTotalPrivateMemory -- default is CK_UNAVAILABLE_INFORMATION */
-        NULL, /* GetFreePrivateMemory -- default is CK_UNAVAILABLE_INFORMATION */
-        ckmk_mdToken_GetHardwareVersion,
-        ckmk_mdToken_GetFirmwareVersion,
-        NULL, /* GetUTCTime -- no clock */
-        ckmk_mdToken_OpenSession,
-        ckmk_mdToken_GetMechanismCount,
-        ckmk_mdToken_GetMechanismTypes,
-        ckmk_mdToken_GetMechanism,
-        (void *)NULL /* null terminator */
-    };
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/nssmkey.def
+++ /dev/null
@@ -1,26 +0,0 @@
-;+#
-;+# 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/.
-;+#
-;+# OK, this file is meant to support SUN, LINUX, AIX and WINDOWS
-;+#   1. For all unix platforms, the string ";-"  means "remove this line"
-;+#   2. For all unix platforms, the string " DATA " will be removed from any 
-;+#     line on which it occurs.
-;+#   3. Lines containing ";+" will have ";+" removed on SUN and LINUX.
-;+#      On AIX, lines containing ";+" will be removed.
-;+#   4. For all unix platforms, the string ";;" will thave the ";;" removed.
-;+#   5. For all unix platforms, after the above processing has taken place,
-;+#    all characters after the first ";" on the line will be removed.
-;+#    And for AIX, the first ";" will also be removed.
-;+#  This file is passed directly to windows. Since ';' is a comment, all UNIX
-;+#   directives are hidden behind ";", ";+", and ";-"
-;+
-;+NSSMKEY_3.0 {       # First release of nssmkey
-;+    global:
-LIBRARY nssmkey ;-
-EXPORTS ;-
-C_GetFunctionList;
-;+    local:
-;+*;
-;+};
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/nssmkey.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* 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 NSSMKEY_H
-#define NSSMKEY_H
-
-/*
- * NSS CKMK Version numbers.
- *
- * These are the version numbers for the nssmkey module packaged with
- * this release on NSS. To determine the version numbers of the builtin
- * module you are using, use the appropriate PKCS #11 calls.
- *
- * These version numbers detail changes to the PKCS #11 interface. They map
- * to the PKCS #11 spec versions.
- */
-#define NSS_CKMK_CRYPTOKI_VERSION_MAJOR 2
-#define NSS_CKMK_CRYPTOKI_VERSION_MINOR 20
-
-/* These version numbers detail the changes
- * to the list of trusted certificates.
- *
- * NSS_CKMK_LIBRARY_VERSION_MINOR is a CK_BYTE.  It's not clear
- * whether we may use its full range (0-255) or only 0-99 because
- * of the comment in the CK_VERSION type definition.
- */
-#define NSS_CKMK_LIBRARY_VERSION_MAJOR 1
-#define NSS_CKMK_LIBRARY_VERSION_MINOR 1
-#define NSS_CKMK_LIBRARY_VERSION "1.1"
-
-/* These version numbers detail the semantic changes to the ckfw engine. */
-#define NSS_CKMK_HARDWARE_VERSION_MAJOR 1
-#define NSS_CKMK_HARDWARE_VERSION_MINOR 0
-
-/* These version numbers detail the semantic changes to ckbi itself
- * (new PKCS #11 objects), etc. */
-#define NSS_CKMK_FIRMWARE_VERSION_MAJOR 1
-#define NSS_CKMK_FIRMWARE_VERSION_MINOR 0
-
-#endif /* NSSMKEY_H */
deleted file mode 100644
--- a/security/nss/lib/ckfw/nssmkey/staticobj.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* 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 CKMK_H
-#include "ckmk.h"
-#endif /* CKMK_H */
-
-static const CK_TRUST ckt_netscape_valid = CKT_NETSCAPE_VALID;
-static const CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE;
-static const CK_TRUST ckt_netscape_trusted_delegator = CKT_NETSCAPE_TRUSTED_DELEGATOR;
-static const CK_OBJECT_CLASS cko_netscape_trust = CKO_NETSCAPE_TRUST;
-static const CK_BBOOL ck_true = CK_TRUE;
-static const CK_OBJECT_CLASS cko_data = CKO_DATA;
-static const CK_CERTIFICATE_TYPE ckc_x_509 = CKC_X_509;
-static const CK_BBOOL ck_false = CK_FALSE;
-static const CK_OBJECT_CLASS cko_netscape_builtin_root_list = CKO_NETSCAPE_BUILTIN_ROOT_LIST;
-
-/* example of a static object */
-static const CK_ATTRIBUTE_TYPE nss_ckmk_types_1[] = {
-    CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_MODIFIABLE, CKA_LABEL
-};
-
-static const NSSItem nss_ckmk_items_1[] = {
-    { (void *)&cko_data, (PRUint32)sizeof(CK_OBJECT_CLASS) },
-    { (void *)&ck_true, (PRUint32)sizeof(CK_BBOOL) },
-    { (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL) },
-    { (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL) },
-    { (void *)"Mozilla Mac Key Ring Access", (PRUint32)28 }
-};
-
-ckmkInternalObject nss_ckmk_data[] = {
-    { ckmkRaw, { { 5, nss_ckmk_types_1, nss_ckmk_items_1 } }, CKO_DATA, { NULL } },
-};
-
-const PRUint32 nss_ckmk_nObjects = 1;
--- a/security/nss/lib/freebl/dsa.c
+++ b/security/nss/lib/freebl/dsa.c
@@ -11,24 +11,21 @@
 #include "prerror.h"
 #include "secerr.h"
 
 #include "prtypes.h"
 #include "prinit.h"
 #include "blapi.h"
 #include "nssilock.h"
 #include "secitem.h"
-#include "blapi.h"
+#include "blapit.h"
 #include "mpi.h"
 #include "secmpi.h"
 #include "pqg.h"
 
-/* XXX to be replaced by define in blapit.h */
-#define NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE 2048
-
 /*
  * FIPS 186-2 requires result from random output to be reduced mod q when
  * generating random numbers for DSA.
  *
  * Input: w, 2*qLen bytes
  *        q, qLen bytes
  * Output: xj, qLen bytes
  */
@@ -163,17 +160,17 @@ dsa_NewKeyExtended(const PQGParams *para
     PLArenaPool *arena;
     DSAPrivateKey *key;
     /* Check args. */
     if (!params || !privKey || !seed || !seed->data) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
     /* Initialize an arena for the DSA key. */
-    arena = PORT_NewArena(NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE);
+    arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
     if (!arena) {
         PORT_SetError(SEC_ERROR_NO_MEMORY);
         return SECFailure;
     }
     key = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey));
     if (!key) {
         PORT_SetError(SEC_ERROR_NO_MEMORY);
         PORT_FreeArena(arena, PR_TRUE);
@@ -208,18 +205,19 @@ dsa_NewKeyExtended(const PQGParams *para
     MPINT_TO_SECITEM(&y, &key->publicValue, arena);
     *privKey = key;
     key = NULL;
 cleanup:
     mp_clear(&p);
     mp_clear(&g);
     mp_clear(&x);
     mp_clear(&y);
-    if (key)
+    if (key) {
         PORT_FreeArena(key->params.arena, PR_TRUE);
+    }
     if (err) {
         translate_mpi_error(err);
         return SECFailure;
     }
     return SECSuccess;
 }
 
 SECStatus
@@ -316,16 +314,17 @@ DSA_NewKeyFromSeed(const PQGParams *para
 static SECStatus
 dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest,
                const unsigned char *kb)
 {
     mp_int p, q, g; /* PQG parameters */
     mp_int x, k;    /* private key & pseudo-random integer */
     mp_int r, s;    /* tuple (r, s) is signature) */
     mp_int t;       /* holding tmp values */
+    mp_int ar;      /* holding blinding values */
     mp_err err = MP_OKAY;
     SECStatus rv = SECSuccess;
     unsigned int dsa_subprime_len, dsa_signature_len, offset;
     SECItem localDigest;
     unsigned char localDigestData[DSA_MAX_SUBPRIME_LEN];
     SECItem t2 = { siBuffer, NULL, 0 };
 
     /* FIPS-compliance dictates that digest is a SHA hash. */
@@ -359,24 +358,26 @@ dsa_SignDigest(DSAPrivateKey *key, SECIt
     MP_DIGITS(&p) = 0;
     MP_DIGITS(&q) = 0;
     MP_DIGITS(&g) = 0;
     MP_DIGITS(&x) = 0;
     MP_DIGITS(&k) = 0;
     MP_DIGITS(&r) = 0;
     MP_DIGITS(&s) = 0;
     MP_DIGITS(&t) = 0;
+    MP_DIGITS(&ar) = 0;
     CHECK_MPI_OK(mp_init(&p));
     CHECK_MPI_OK(mp_init(&q));
     CHECK_MPI_OK(mp_init(&g));
     CHECK_MPI_OK(mp_init(&x));
     CHECK_MPI_OK(mp_init(&k));
     CHECK_MPI_OK(mp_init(&r));
     CHECK_MPI_OK(mp_init(&s));
     CHECK_MPI_OK(mp_init(&t));
+    CHECK_MPI_OK(mp_init(&ar));
     /*
     ** Convert stored PQG and private key into MPI integers.
     */
     SECITEM_TO_MPINT(key->params.prime, &p);
     SECITEM_TO_MPINT(key->params.subPrime, &q);
     SECITEM_TO_MPINT(key->params.base, &g);
     SECITEM_TO_MPINT(key->privateValue, &x);
     OCTETS_TO_MPINT(kb, &k, dsa_subprime_len);
@@ -392,24 +393,38 @@ dsa_SignDigest(DSAPrivateKey *key, SECIt
     **
     ** s = (k**-1 * (HASH(M) + x*r)) mod q
     */
     if (DSA_NewRandom(NULL, &key->params.subPrime, &t2) != SECSuccess) {
         PORT_SetError(SEC_ERROR_NEED_RANDOM);
         rv = SECFailure;
         goto cleanup;
     }
-    SECITEM_TO_MPINT(t2, &t);                /* t <-$ Zq */
+    SECITEM_TO_MPINT(t2, &t); /* t <-$ Zq */
+    SECITEM_FreeItem(&t2, PR_FALSE);
+    if (DSA_NewRandom(NULL, &key->params.subPrime, &t2) != SECSuccess) {
+        PORT_SetError(SEC_ERROR_NEED_RANDOM);
+        rv = SECFailure;
+        goto cleanup;
+    }
+    SECITEM_TO_MPINT(t2, &ar); /* ar <-$ Zq */
+    SECITEM_FreeItem(&t2, PR_FALSE);
+
+    /* Using mp_invmod on k directly would leak bits from k. */
+    CHECK_MPI_OK(mp_mul(&k, &ar, &k));       /* k = k * ar */
     CHECK_MPI_OK(mp_mulmod(&k, &t, &q, &k)); /* k = k * t mod q */
     CHECK_MPI_OK(mp_invmod(&k, &q, &k));     /* k = k**-1 mod q */
     CHECK_MPI_OK(mp_mulmod(&k, &t, &q, &k)); /* k = k * t mod q */
     SECITEM_TO_MPINT(localDigest, &s);       /* s = HASH(M)     */
-    CHECK_MPI_OK(mp_mulmod(&x, &r, &q, &x)); /* x = x * r mod q */
-    CHECK_MPI_OK(mp_addmod(&s, &x, &q, &s)); /* s = s + x mod q */
-    CHECK_MPI_OK(mp_mulmod(&s, &k, &q, &s)); /* s = s * k mod q */
+    /* To avoid leaking secret bits here the addition is blinded. */
+    CHECK_MPI_OK(mp_mul(&x, &ar, &x));        /* x = x * ar */
+    CHECK_MPI_OK(mp_mulmod(&x, &r, &q, &x));  /* x = x * r mod q */
+    CHECK_MPI_OK(mp_mulmod(&s, &ar, &q, &t)); /* t = s * ar mod q */
+    CHECK_MPI_OK(mp_add(&t, &x, &s));         /* s = t + x */
+    CHECK_MPI_OK(mp_mulmod(&s, &k, &q, &s));  /* s = s * k mod q */
     /*
     ** verify r != 0 and s != 0
     ** mentioned as optional in FIPS 186-1.
     */
     if (mp_cmp_z(&r) == 0 || mp_cmp_z(&s) == 0) {
         PORT_SetError(SEC_ERROR_NEED_RANDOM);
         rv = SECFailure;
         goto cleanup;
@@ -433,17 +448,17 @@ cleanup:
     mp_clear(&p);
     mp_clear(&q);
     mp_clear(&g);
     mp_clear(&x);
     mp_clear(&k);
     mp_clear(&r);
     mp_clear(&s);
     mp_clear(&t);
-    SECITEM_FreeItem(&t2, PR_FALSE);
+    mp_clear(&ar);
     if (err) {
         translate_mpi_error(err);
         rv = SECFailure;
     }
     return rv;
 }
 
 /* signature is caller-supplied buffer of at least 40 bytes.
--- a/security/nss/lib/freebl/ec.c
+++ b/security/nss/lib/freebl/ec.c
@@ -648,16 +648,17 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *k
                          const SECItem *digest, const unsigned char *kb, const int kblen)
 {
     SECStatus rv = SECFailure;
     mp_int x1;
     mp_int d, k; /* private key, random integer */
     mp_int r, s; /* tuple (r, s) is the signature */
     mp_int t;    /* holding tmp values */
     mp_int n;
+    mp_int ar; /* blinding value */
     mp_err err = MP_OKAY;
     ECParams *ecParams = NULL;
     SECItem kGpoint = { siBuffer, NULL, 0 };
     int flen = 0;   /* length in bytes of the field size */
     unsigned olen;  /* length in bytes of the base point order */
     unsigned obits; /* length in bits  of the base point order */
     unsigned char *t2 = NULL;
 
@@ -669,16 +670,17 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *k
     /* must happen before the first potential call to cleanup */
     MP_DIGITS(&x1) = 0;
     MP_DIGITS(&d) = 0;
     MP_DIGITS(&k) = 0;
     MP_DIGITS(&r) = 0;
     MP_DIGITS(&s) = 0;
     MP_DIGITS(&n) = 0;
     MP_DIGITS(&t) = 0;
+    MP_DIGITS(&ar) = 0;
 
     /* Check args */
     if (!key || !signature || !digest || !kb || (kblen < 0)) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         goto cleanup;
     }
 
     ecParams = &(key->ecParams);
@@ -695,16 +697,17 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *k
 
     CHECK_MPI_OK(mp_init(&x1));
     CHECK_MPI_OK(mp_init(&d));
     CHECK_MPI_OK(mp_init(&k));
     CHECK_MPI_OK(mp_init(&r));
     CHECK_MPI_OK(mp_init(&s));
     CHECK_MPI_OK(mp_init(&n));
     CHECK_MPI_OK(mp_init(&t));
+    CHECK_MPI_OK(mp_init(&ar));
 
     SECITEM_TO_MPINT(ecParams->order, &n);
     SECITEM_TO_MPINT(key->privateValue, &d);
 
     CHECK_MPI_OK(mp_read_unsigned_octets(&k, kb, kblen));
     /* Make sure k is in the interval [1, n-1] */
     if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) {
 #if EC_DEBUG
@@ -810,22 +813,35 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *k
         goto cleanup;
     }
     if (RNG_GenerateGlobalRandomBytes(t2, 2 * ecParams->order.len) != SECSuccess) {
         PORT_SetError(SEC_ERROR_NEED_RANDOM);
         rv = SECFailure;
         goto cleanup;
     }
     CHECK_MPI_OK(mp_read_unsigned_octets(&t, t2, 2 * ecParams->order.len)); /* t <-$ Zn */
-    CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k));                                /* k = k * t mod n */
-    CHECK_MPI_OK(mp_invmod(&k, &n, &k));                                    /* k = k**-1 mod n */
-    CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k));                                /* k = k * t mod n */
-    CHECK_MPI_OK(mp_mulmod(&d, &r, &n, &d));                                /* d = d * r mod n */
-    CHECK_MPI_OK(mp_addmod(&s, &d, &n, &s));                                /* s = s + d mod n */
-    CHECK_MPI_OK(mp_mulmod(&s, &k, &n, &s));                                /* s = s * k mod n */
+    PORT_Memset(t2, 0, 2 * ecParams->order.len);
+    if (RNG_GenerateGlobalRandomBytes(t2, 2 * ecParams->order.len) != SECSuccess) {
+        PORT_SetError(SEC_ERROR_NEED_RANDOM);
+        rv = SECFailure;
+        goto cleanup;
+    }
+    CHECK_MPI_OK(mp_read_unsigned_octets(&ar, t2, 2 * ecParams->order.len)); /* ar <-$ Zn */
+
+    /* Using mp_invmod on k directly would leak bits from k. */
+    CHECK_MPI_OK(mp_mul(&k, &ar, &k));       /* k = k * ar */
+    CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k)); /* k = k * t mod n */
+    CHECK_MPI_OK(mp_invmod(&k, &n, &k));     /* k = k**-1 mod n */
+    CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k)); /* k = k * t mod n */
+    /* To avoid leaking secret bits here the addition is blinded. */
+    CHECK_MPI_OK(mp_mul(&d, &ar, &t));        /* t = d * ar */
+    CHECK_MPI_OK(mp_mulmod(&t, &r, &n, &d));  /* d = t * r mod n */
+    CHECK_MPI_OK(mp_mulmod(&s, &ar, &n, &t)); /* t = s * ar mod n */
+    CHECK_MPI_OK(mp_add(&t, &d, &s));         /* s = t + d */
+    CHECK_MPI_OK(mp_mulmod(&s, &k, &n, &s));  /* s = s * k mod n */
 
 #if EC_DEBUG
     mp_todecimal(&s, mpstr);
     printf("s : %s (dec)\n", mpstr);
     mp_tohex(&s, mpstr);
     printf("s : %s\n", mpstr);
 #endif
 
@@ -853,16 +869,17 @@ finish:
 cleanup:
     mp_clear(&x1);
     mp_clear(&d);
     mp_clear(&k);
     mp_clear(&r);
     mp_clear(&s);
     mp_clear(&n);
     mp_clear(&t);
+    mp_clear(&ar);
 
     if (t2) {
         PORT_Free(t2);
     }
 
     if (kGpoint.data) {
         PORT_ZFree(kGpoint.data, kGpoint.len);
     }
--- a/security/nss/lib/pkcs12/p12e.c
+++ b/security/nss/lib/pkcs12/p12e.c
@@ -879,17 +879,19 @@ sec_PKCS12AddAttributeToBag(SEC_PKCS12Ex
     sec_PKCS12Attribute *attribute;
     void *mark = NULL, *dummy = NULL;
     SECOidData *oiddata = NULL;
     SECItem unicodeName = { siBuffer, NULL, 0 };
     void *src = NULL;
     unsigned int nItems = 0;
     SECStatus rv;
 
-    if (!safeBag || !p12ctxt) {
+    PORT_Assert(p12ctxt->arena == safeBag->arena);
+    if (!safeBag || !p12ctxt || p12ctxt->arena != safeBag->arena) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
     mark = PORT_ArenaMark(safeBag->arena);
 
     /* allocate the attribute */
     attribute = (sec_PKCS12Attribute *)PORT_ArenaZAlloc(safeBag->arena,
                                                         sizeof(sec_PKCS12Attribute));
@@ -1584,16 +1586,17 @@ sec_pkcs12_encoder_start_context(SEC_PKC
             /*
              * This code only works with PKCS #12 Mac using PKCS #5 v1
              * PBA keygens. PKCS #5 v2 support will require a change to
              * the PKCS #12 spec.
              */
             params = PK11_CreatePBEParams(salt, &pwd,
                                           NSS_PBE_DEFAULT_ITERATION_COUNT);
             SECITEM_ZfreeItem(salt, PR_TRUE);
+            salt = NULL;
             SECITEM_ZfreeItem(&pwd, PR_FALSE);
 
             /* get the PBA Mechanism to generate the key */
             switch (p12exp->integrityInfo.pwdInfo.algorithm) {
                 case SEC_OID_SHA1:
                     integrityMechType = CKM_PBA_SHA1_WITH_SHA1_HMAC;
                     break;
                 case SEC_OID_MD5:
--- a/security/nss/lib/softoken/legacydb/pcertdb.c
+++ b/security/nss/lib/softoken/legacydb/pcertdb.c
@@ -2572,24 +2572,23 @@ ReadDBSubjectEntry(NSSLOWCERTCertDBHandl
     PLArenaPool *arena = NULL;
     PORTCheapArenaPool tmpArena;
 
     certDBEntrySubject *entry;
     SECItem dbkey;
     SECItem dbentry;
     SECStatus rv;
 
+    PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     if (arena == NULL) {
         PORT_SetError(SEC_ERROR_NO_MEMORY);
         goto loser;
     }
 
-    PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
-
     entry = (certDBEntrySubject *)PORT_ArenaAlloc(arena,
                                                   sizeof(certDBEntrySubject));
     if (entry == NULL) {
         PORT_SetError(SEC_ERROR_NO_MEMORY);
         goto loser;
     }
     entry->common.arena = arena;
     entry->common.type = certDBEntryTypeSubject;
--- a/security/nss/lib/softoken/sftkpwd.c
+++ b/security/nss/lib/softoken/sftkpwd.c
@@ -133,22 +133,24 @@ const SEC_ASN1Template sftkdb_EncryptedD
  */
 static SECStatus
 sftkdb_decodeCipherText(SECItem *cipherText, sftkCipherValue *cipherValue)
 {
     PLArenaPool *arena = NULL;
     SFTKDBEncryptedDataInfo edi;
     SECStatus rv;
 
+    PORT_Assert(cipherValue);
+    cipherValue->arena = NULL;
+    cipherValue->param = NULL;
+
     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     if (arena == NULL) {
         return SECFailure;
     }
-    cipherValue->arena = NULL;
-    cipherValue->param = NULL;
 
     rv = SEC_QuickDERDecodeItem(arena, &edi, sftkdb_EncryptedDataInfoTemplate,
                                 cipherText);
     if (rv != SECSuccess) {
         goto loser;
     }
     cipherValue->alg = SECOID_GetAlgorithmTag(&edi.algorithm);
     cipherValue->param = nsspkcs5_AlgidToParam(&edi.algorithm);
--- a/security/nss/lib/ssl/dtlscon.c
+++ b/security/nss/lib/ssl/dtlscon.c
@@ -719,23 +719,26 @@ dtls_FragmentHandshake(sslSocket *ss, DT
                      SSL_GETPID(), ss->fd, msgSeq, fragmentOffset, end));
 
         /* Cut down to the data we have available. */
         PORT_Assert(fragmentOffset <= contentLen);
         PORT_Assert(fragmentOffset <= end);
         PORT_Assert(end <= contentLen);
         fragmentLen = PR_MIN(end, contentLen) - fragmentOffset;
 
-        /* Reduce to the space remaining in the MTU.  Allow for any existing
-         * messages, record expansion, and the handshake header. */
+        /* Limit further by the record size limit.  Account for the header. */
+        fragmentLen = PR_MIN(fragmentLen,
+                             msg->cwSpec->recordSizeLimit - DTLS_HS_HDR_LEN);
+
+        /* Reduce to the space remaining in the MTU. */
         fragmentLen = PR_MIN(fragmentLen,
                              ss->ssl3.mtu -           /* MTU estimate. */
-                                 ss->pendingBuf.len - /* Less unsent records. */
+                                 ss->pendingBuf.len - /* Less any unsent records. */
                                  DTLS_MAX_EXPANSION - /* Allow for expansion. */
-                                 DTLS_HS_HDR_LEN);    /* + handshake header. */
+                                 DTLS_HS_HDR_LEN);    /* And the handshake header. */
         PORT_Assert(fragmentLen > 0 || fragmentOffset == 0);
 
         /* Make totally sure that we will fit in the buffer. This should be
          * impossible; DTLS_MAX_MTU should always be more than ss->ssl3.mtu. */
         if (fragmentLen >= (DTLS_MAX_MTU - DTLS_HS_HDR_LEN)) {
             PORT_Assert(0);
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             return SECFailure;
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -238,16 +238,38 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRF
  * the rest of the TLS data. See [draft-ietf-tls-tls13; Section 8]
  * for more details.
  *
  * Note: when DTLS 1.3 is in use, any 0-RTT data received after EndOfEarlyData
  * (e.g., because of reordering) is discarded.
  */
 #define SSL_ENABLE_0RTT_DATA 33
 
+/* Sets a limit to the size of encrypted records (see
+ * draft-ietf-tls-record-limit). This is the value that is advertised to peers,
+ * not a limit on the size of records that will be created.  Setting this value
+ * reduces the size of records that will be received (not sent).
+ *
+ * This limit applies to the plaintext, but the records that appear on the wire
+ * will be bigger.  This doesn't include record headers, IVs, block cipher
+ * padding, and authentication tags or MACs.
+ *
+ * NSS always advertises the record size limit extension.  If this option is not
+ * set, the extension will contain the maximum allowed size for the selected TLS
+ * version (currently this is 16384 or 2^14 for TLS 1.2 and lower and 16385 for
+ * TLS 1.3).
+ *
+ * By default, NSS creates records that are the maximum size possible, using all
+ * the data that was written by the application.  Writes larger than the maximum
+ * are split into maximum sized records, and any remainder (unless
+ * SSL_CBC_RANDOM_IV is enabled and active).  If a peer advertises a record size
+ * limit then that value is used instead.
+ */
+#define SSL_RECORD_SIZE_LIMIT 34
+
 /* Enables TLS 1.3 compatibility mode.  In this mode, the client includes a fake
  * session ID in the handshake and sends a ChangeCipherSpec.  A server will
  * always use the setting chosen by the client, so the value of this option has
  * no effect for a server. This setting is ignored for DTLS. */
 #define SSL_ENABLE_TLS13_COMPAT_MODE 35
 
 /* Enables the sending of DTLS records using the short (two octet) record
  * header.  Only do this if there are 2^10 or fewer packets in flight at a time;
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -1471,16 +1471,23 @@ ssl3_SetupBothPendingCipherSpecs(sslSock
         goto loser;
     }
     rv = ssl3_SetupPendingCipherSpec(ss, CipherSpecWrite, suiteDef,
                                      &ss->ssl3.pwSpec);
     if (rv != SECSuccess) {
         goto loser;
     }
 
+    if (ssl3_ExtensionNegotiated(ss, ssl_record_size_limit_xtn)) {
+        ss->ssl3.prSpec->recordSizeLimit = PR_MIN(MAX_FRAGMENT_LENGTH,
+                                                  ss->opt.recordSizeLimit);
+        ss->ssl3.pwSpec->recordSizeLimit = PR_MIN(MAX_FRAGMENT_LENGTH,
+                                                  ss->xtnData.recordSizeLimit);
+    }
+
     ssl_ReleaseSpecWriteLock(ss); /*******************************/
     return SECSuccess;
 
 loser:
     ssl_ReleaseSpecWriteLock(ss);
     return SECFailure;
 }
 
@@ -2267,17 +2274,17 @@ ssl_ProtectNextRecord(sslSocket *ss, ssl
                       const PRUint8 *pIn, unsigned int nIn,
                       unsigned int *written)
 {
     sslBuffer *wrBuf = &ss->sec.writeBuf;
     unsigned int contentLen;
     unsigned int spaceNeeded;
     SECStatus rv;
 
-    contentLen = PR_MIN(nIn, MAX_FRAGMENT_LENGTH);
+    contentLen = PR_MIN(nIn, spec->recordSizeLimit);
     spaceNeeded = contentLen + SSL3_BUFFER_FUDGE;
     if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_1 &&
         spec->cipherDef->type == type_block) {
         spaceNeeded += spec->cipherDef->iv_size;
     }
     if (spaceNeeded > SSL_BUFFER_SPACE(wrBuf)) {
         rv = sslBuffer_Grow(wrBuf, spaceNeeded);
         if (rv != SECSuccess) {
@@ -12142,16 +12149,21 @@ ssl3_GetCipherSpec(sslSocket *ss, SSL3Ci
             return newSpec;
         }
     }
     SSL_TRC(10, ("%d: DTLS[%d]: Couldn't find cipherspec from epoch %d",
                  SSL_GETPID(), ss->fd, epoch));
     return NULL;
 }
 
+/* MAX_EXPANSION is the amount by which a record might plausibly be expanded
+ * when protected.  It's the worst case estimate, so the sum of block cipher
+ * padding (up to 256 octets) and HMAC (48 octets for SHA-384). */
+#define MAX_EXPANSION (256 + 48)
+
 /* if cText is non-null, then decipher and check the MAC of 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
@@ -12171,16 +12183,17 @@ ssl3_GetCipherSpec(sslSocket *ss, SSL3Ci
  */
 SECStatus
 ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
 {
     SECStatus rv;
     PRBool isTLS;
     DTLSEpoch epoch;
     ssl3CipherSpec *spec = NULL;
+    PRUint16 recordSizeLimit;
     PRBool outOfOrderSpec = PR_FALSE;
     SSL3ContentType rType;
     sslBuffer *plaintext = &ss->gs.buf;
     SSL3AlertDescription alert = internal_error;
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
 
     /* check for Token Presence */
     if (!ssl3_ClientAuthTokenPresent(ss->sec.ci.sid)) {
@@ -12225,22 +12238,30 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Cip
     if (cText->seqNum >= spec->cipherDef->max_records) {
         ssl_ReleaseSpecReadLock(ss); /*****************************/
         SSL_TRC(3, ("%d: SSL[%d]: read sequence number at limit 0x%0llx",
                     SSL_GETPID(), ss->fd, cText->seqNum));
         PORT_SetError(SSL_ERROR_TOO_MANY_RECORDS);
         return SECFailure;
     }
 
-    if (plaintext->space < MAX_FRAGMENT_LENGTH) {
-        rv = sslBuffer_Grow(plaintext, MAX_FRAGMENT_LENGTH + 2048);
+    recordSizeLimit = spec->recordSizeLimit;
+    if (cText->buf->len > recordSizeLimit + MAX_EXPANSION) {
+        ssl_ReleaseSpecReadLock(ss); /*****************************/
+        SSL3_SendAlert(ss, alert_fatal, record_overflow);
+        PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
+        return SECFailure;
+    }
+
+    if (plaintext->space < recordSizeLimit + MAX_EXPANSION) {
+        rv = sslBuffer_Grow(plaintext, recordSizeLimit + MAX_EXPANSION);
         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));
+                     SSL_GETPID(), ss->fd, recordSizeLimit + MAX_EXPANSION));
             /* sslBuffer_Grow has set a memory error code. */
             /* Perhaps we should send an alert. (but we have no memory!) */
             return SECFailure;
         }
     }
 
     /* Most record types aside from protected TLS 1.3 records carry the content
      * type in the first octet. TLS 1.3 will override this value later. */
@@ -12289,17 +12310,20 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Cip
             cText->buf->buf[0] == change_cipher_spec_choice) {
             /* Ignore the CCS. */
             return SECSuccess;
         }
 
         if (IS_DTLS(ss) ||
             (ss->sec.isServer &&
              ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_trial)) {
-            /* Silently drop the packet */
+            /* Silently drop the packet unless we sent a fatal alert. */
+            if (ss->ssl3.fatalAlertSent) {
+                return SECFailure;
+            }
             return SECSuccess;
         }
 
         int errCode = PORT_GetError();
         SSL3_SendAlert(ss, alert_fatal, alert);
         /* Reset the error code in case SSL3_SendAlert called
          * PORT_SetError(). */
         PORT_SetError(errCode);
@@ -12325,17 +12349,17 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Cip
      * from the wrong epoch. Divert to a divert processing function to make
      * sure we don't accidentally use the data unsafely. */
     if (outOfOrderSpec) {
         PORT_Assert(IS_DTLS(ss) && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
         return dtls13_HandleOutOfEpochRecord(ss, spec, rType, plaintext);
     }
 
     /* Check the length of the plaintext. */
-    if (isTLS && plaintext->len > MAX_FRAGMENT_LENGTH) {
+    if (isTLS && plaintext->len > recordSizeLimit) {
         plaintext->len = 0;
         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.
--- a/security/nss/lib/ssl/ssl3ext.c
+++ b/security/nss/lib/ssl/ssl3ext.c
@@ -45,16 +45,17 @@ static const ssl3ExtensionHandler client
     { ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn },
     { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
     { ssl_signed_cert_timestamp_xtn, &ssl3_ServerHandleSignedCertTimestampXtn },
     { ssl_tls13_key_share_xtn, &tls13_ServerHandleKeyShareXtn },
     { ssl_tls13_pre_shared_key_xtn, &tls13_ServerHandlePreSharedKeyXtn },
     { ssl_tls13_early_data_xtn, &tls13_ServerHandleEarlyDataXtn },
     { ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ServerHandlePskModesXtn },
     { ssl_tls13_cookie_xtn, &tls13_ServerHandleCookieXtn },
+    { ssl_record_size_limit_xtn, &ssl_HandleRecordSizeLimitXtn },
     { 0, NULL }
 };
 
 /* These two tables are used by the client, to handle server hello
  * extensions. */
 static const ssl3ExtensionHandler serverHelloHandlersTLS[] = {
     { ssl_server_name_xtn, &ssl3_HandleServerNameXtn },
     /* TODO: add a handler for ssl_ec_point_formats_xtn */
@@ -63,16 +64,17 @@ static const ssl3ExtensionHandler server
     { ssl_app_layer_protocol_xtn, &ssl3_ClientHandleAppProtoXtn },
     { ssl_use_srtp_xtn, &ssl3_ClientHandleUseSRTPXtn },
     { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
     { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
     { ssl_signed_cert_timestamp_xtn, &ssl3_ClientHandleSignedCertTimestampXtn },
     { ssl_tls13_key_share_xtn, &tls13_ClientHandleKeyShareXtn },
     { ssl_tls13_pre_shared_key_xtn, &tls13_ClientHandlePreSharedKeyXtn },
     { ssl_tls13_early_data_xtn, &tls13_ClientHandleEarlyDataXtn },
+    { ssl_record_size_limit_xtn, &ssl_HandleRecordSizeLimitXtn },
     { 0, NULL }
 };
 
 static const ssl3ExtensionHandler helloRetryRequestHandlers[] = {
     { ssl_tls13_key_share_xtn, tls13_ClientHandleKeyShareXtnHrr },
     { ssl_tls13_cookie_xtn, tls13_ClientHandleHrrCookie },
     { 0, NULL }
 };
@@ -129,16 +131,17 @@ static const sslExtensionBuilder clientH
       /* Some servers (e.g. WebSphere Application Server 7.0 and Tomcat) will
        * time out or terminate the connection if the last extension in the
        * client hello is empty. They are not intolerant of TLS 1.2, so list
        * signature_algorithms at the end. See bug 1243641. */
       { ssl_tls13_supported_versions_xtn, &tls13_ClientSendSupportedVersionsXtn },
       { ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn },
       { ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn },
       { ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskModesXtn },
+      { ssl_record_size_limit_xtn, &ssl_SendRecordSizeLimitXtn },
       /* The pre_shared_key extension MUST be last. */
       { ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn },
       { 0, NULL }
     };
 
 static const sslExtensionBuilder clientHelloSendersSSL3[] = {
     { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
     { 0, NULL }
--- a/security/nss/lib/ssl/ssl3ext.h
+++ b/security/nss/lib/ssl/ssl3ext.h
@@ -93,16 +93,19 @@ struct TLSExtensionDataStr {
     SECItem pskBinder;                     /* The binder for the first PSK. */
     unsigned int pskBindersLen;            /* The length of the binders. */
     PRUint32 ticketAge;                    /* Used to accept early data. */
     SECItem cookie;                        /* HRR Cookie. */
     const sslNamedGroupDef *selectedGroup; /* For HRR. */
     /* The application token contains a value that was passed to the client via
      * a session ticket, or the cookie in a HelloRetryRequest. */
     SECItem applicationToken;
+
+    /* The record size limit set by the peer. Our value is kept in ss->opt. */
+    PRUint16 recordSizeLimit;
 };
 
 typedef struct TLSExtensionStr {
     PRCList link;  /* The linked list link */
     PRUint16 type; /* Extension type */
     SECItem data;  /* Pointers into the handshake data. */
 } TLSExtension;
 
--- a/security/nss/lib/ssl/ssl3exthandle.c
+++ b/security/nss/lib/ssl/ssl3exthandle.c
@@ -1863,8 +1863,72 @@ ssl_HandleSupportedGroupsXtn(const sslSo
         }
     }
 
     /* Remember that we negotiated this extension. */
     xtnData->negotiated[xtnData->numNegotiated++] = ssl_supported_groups_xtn;
 
     return SECSuccess;
 }
+
+SECStatus
+ssl_HandleRecordSizeLimitXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                             SECItem *data)
+{
+    SECStatus rv;
+    PRUint32 limit;
+    PRUint32 maxLimit = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3)
+                            ? (MAX_FRAGMENT_LENGTH + 1)
+                            : MAX_FRAGMENT_LENGTH;
+
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &limit, 2, &data->data, &data->len);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+    if (data->len != 0 || limit < 64) {
+        ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
+        return SECFailure;
+    }
+
+    if (ss->sec.isServer) {
+        rv = ssl3_RegisterExtensionSender(ss, xtnData, ssl_record_size_limit_xtn,
+                                          &ssl_SendRecordSizeLimitXtn);
+        if (rv != SECSuccess) {
+            return SECFailure; /* error already set. */
+        }
+    } else if (limit > maxLimit) {
+        /* The client can sensibly check the maximum. */
+        ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
+        return SECFailure;
+    }
+
+    /* We can't enforce the maximum on a server. But we do need to ensure
+     * that we don't apply a limit that is too large. */
+    xtnData->recordSizeLimit = PR_MIN(maxLimit, limit);
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_record_size_limit_xtn;
+    return SECSuccess;
+}
+
+SECStatus
+ssl_SendRecordSizeLimitXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                           sslBuffer *buf, PRBool *added)
+{
+    PRUint32 maxLimit;
+    if (ss->sec.isServer) {
+        maxLimit = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3)
+                       ? (MAX_FRAGMENT_LENGTH + 1)
+                       : MAX_FRAGMENT_LENGTH;
+    } else {
+        maxLimit = (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3)
+                       ? (MAX_FRAGMENT_LENGTH + 1)
+                       : MAX_FRAGMENT_LENGTH;
+    }
+    PRUint32 limit = PR_MIN(ss->opt.recordSizeLimit, maxLimit);
+    SECStatus rv = sslBuffer_AppendNumber(buf, limit, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    *added = PR_TRUE;
+    return SECSuccess;
+}
--- a/security/nss/lib/ssl/ssl3exthandle.h
+++ b/security/nss/lib/ssl/ssl3exthandle.h
@@ -114,9 +114,16 @@ SECStatus ssl3_ClientSendSessionTicketXt
                                           sslBuffer *buf, PRBool *added);
 
 SECStatus ssl_SendSupportedGroupsXtn(const sslSocket *ss,
                                      TLSExtensionData *xtnData,
                                      sslBuffer *buf, PRBool *added);
 SECStatus ssl3_SendSupportedPointFormatsXtn(const sslSocket *ss,
                                             TLSExtensionData *xtnData,
                                             sslBuffer *buf, PRBool *added);
+SECStatus ssl_HandleRecordSizeLimitXtn(const sslSocket *ss,
+                                       TLSExtensionData *xtnData,
+                                       SECItem *data);
+SECStatus ssl_SendRecordSizeLimitXtn(const sslSocket *ss,
+                                     TLSExtensionData *xtnData,
+                                     sslBuffer *buf, PRBool *added);
+
 #endif
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -231,16 +231,17 @@ typedef struct {
 
 /* MAX_SIGNATURE_SCHEMES allows for all the values we support. */
 #define MAX_SIGNATURE_SCHEMES 15
 
 typedef struct sslOptionsStr {
     /* If SSL_SetNextProtoNego has been called, then this contains the
      * list of supported protocols. */
     SECItem nextProtoNego;
+    PRUint16 recordSizeLimit;
 
     PRUint32 maxEarlyDataSize;
     unsigned int useSecurity : 1;
     unsigned int useSocks : 1;
     unsigned int requestCertificate : 1;
     unsigned int requireCertificate : 2;
     unsigned int handshakeAsClient : 1;
     unsigned int handshakeAsServer : 1;
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -50,16 +50,17 @@ static const sslSocketOps ssl_secure_ops
 };
 
 /*
 ** default settings for socket enables
 */
 static sslOptions ssl_defaults = {
     .nextProtoNego = { siBuffer, NULL, 0 },
     .maxEarlyDataSize = 1 << 16,
+    .recordSizeLimit = MAX_FRAGMENT_LENGTH + 1,
     .useSecurity = PR_TRUE,
     .useSocks = PR_FALSE,
     .requestCertificate = PR_FALSE,
     .requireCertificate = SSL_REQUIRE_FIRST_HANDSHAKE,
     .handshakeAsClient = PR_FALSE,
     .handshakeAsServer = PR_FALSE,
     .noCache = PR_FALSE,
     .fdx = PR_FALSE,
@@ -798,16 +799,25 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 wh
         case SSL_REQUIRE_DH_NAMED_GROUPS:
             ss->opt.requireDHENamedGroups = val;
             break;
 
         case SSL_ENABLE_0RTT_DATA:
             ss->opt.enable0RttData = val;
             break;
 
+        case SSL_RECORD_SIZE_LIMIT:
+            if (val < 64 || val > (MAX_FRAGMENT_LENGTH + 1)) {
+                PORT_SetError(SEC_ERROR_INVALID_ARGS);
+                rv = SECFailure;
+            } else {
+                ss->opt.recordSizeLimit = val;
+            }
+            break;
+
         case SSL_ENABLE_TLS13_COMPAT_MODE:
             ss->opt.enableTls13CompatMode = val;
             break;
 
         case SSL_ENABLE_DTLS_SHORT_HEADER:
             ss->opt.enableDtlsShortHeader = val;
             break;
 
@@ -939,16 +949,19 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 wh
             val = ss->opt.enableSignedCertTimestamps;
             break;
         case SSL_REQUIRE_DH_NAMED_GROUPS:
             val = ss->opt.requireDHENamedGroups;
             break;
         case SSL_ENABLE_0RTT_DATA:
             val = ss->opt.enable0RttData;
             break;
+        case SSL_RECORD_SIZE_LIMIT:
+            val = ss->opt.recordSizeLimit;
+            break;
         case SSL_ENABLE_TLS13_COMPAT_MODE:
             val = ss->opt.enableTls13CompatMode;
             break;
         case SSL_ENABLE_DTLS_SHORT_HEADER:
             val = ss->opt.enableDtlsShortHeader;
             break;
         default:
             PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -1062,16 +1075,19 @@ SSL_OptionGetDefault(PRInt32 which, PRIn
             val = ssl_defaults.enableExtendedMS;
             break;
         case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS:
             val = ssl_defaults.enableSignedCertTimestamps;
             break;
         case SSL_ENABLE_0RTT_DATA:
             val = ssl_defaults.enable0RttData;
             break;
+        case SSL_RECORD_SIZE_LIMIT:
+            val = ssl_defaults.recordSizeLimit;
+            break;
         case SSL_ENABLE_TLS13_COMPAT_MODE:
             val = ssl_defaults.enableTls13CompatMode;
             break;
         case SSL_ENABLE_DTLS_SHORT_HEADER:
             val = ssl_defaults.enableDtlsShortHeader;
             break;
         default:
             PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -1247,16 +1263,24 @@ SSL_OptionSetDefault(PRInt32 which, PRIn
         case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS:
             ssl_defaults.enableSignedCertTimestamps = val;
             break;
 
         case SSL_ENABLE_0RTT_DATA:
             ssl_defaults.enable0RttData = val;
             break;
 
+        case SSL_RECORD_SIZE_LIMIT:
+            if (val < 64 || val > (MAX_FRAGMENT_LENGTH + 1)) {
+                PORT_SetError(SEC_ERROR_INVALID_ARGS);
+                return SECFailure;
+            }
+            ssl_defaults.recordSizeLimit = val;
+            break;
+
         case SSL_ENABLE_TLS13_COMPAT_MODE:
             ssl_defaults.enableTls13CompatMode = val;
             break;
 
         case SSL_ENABLE_DTLS_SHORT_HEADER:
             ssl_defaults.enableDtlsShortHeader = val;
             break;
 
--- a/security/nss/lib/ssl/sslspec.c
+++ b/security/nss/lib/ssl/sslspec.c
@@ -138,16 +138,17 @@ ssl_CreateCipherSpec(sslSocket *ss, Ciph
 {
     ssl3CipherSpec *spec = PORT_ZNew(ssl3CipherSpec);
     if (!spec) {
         return NULL;
     }
     spec->refCt = 1;
     spec->version = ss->version;
     spec->direction = direction;
+    spec->recordSizeLimit = MAX_FRAGMENT_LENGTH;
     SSL_TRC(10, ("%d: SSL[%d]: new %s spec %d ct=%d",
                  SSL_GETPID(), ss->fd, SPEC_DIR(spec), spec,
                  spec->refCt));
     return spec;
 }
 
 void
 ssl_SaveCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
--- a/security/nss/lib/ssl/sslspec.h
+++ b/security/nss/lib/ssl/sslspec.h
@@ -165,16 +165,20 @@ struct ssl3CipherSpecStr {
 
     /* The next sequence number to be sent or received. */
     sslSequenceNumber nextSeqNum;
     DTLSRecvdRecords recvdRecords;
 
     /* The number of 0-RTT bytes that can be sent or received in TLS 1.3. This
      * will be zero for everything but 0-RTT. */
     PRUint32 earlyDataRemaining;
+    /* The maximum plaintext length.  This differs from the configured or
+     * negotiated value for TLS 1.3; it is reduced by one to account for the
+     * content type octet. */
+    PRUint16 recordSizeLimit;
 };
 
 typedef void (*sslCipherSpecChangedFunc)(void *arg,
                                          PRBool sending,
                                          ssl3CipherSpec *newSpec);
 
 const ssl3BulkCipherDef *ssl_GetBulkCipherDef(const ssl3CipherSuiteDef *cipher_def);
 const ssl3MACDef *ssl_GetMacDefByAlg(SSL3MACAlgorithm mac);
--- a/security/nss/lib/ssl/sslt.h
+++ b/security/nss/lib/ssl/sslt.h
@@ -427,16 +427,17 @@ typedef enum {
     ssl_ec_point_formats_xtn = 11,
     ssl_signature_algorithms_xtn = 13,
     ssl_use_srtp_xtn = 14,
     ssl_app_layer_protocol_xtn = 16,
     /* signed_certificate_timestamp extension, RFC 6962 */
     ssl_signed_cert_timestamp_xtn = 18,
     ssl_padding_xtn = 21,
     ssl_extended_master_secret_xtn = 23,
+    ssl_record_size_limit_xtn = 28,
     ssl_session_ticket_xtn = 35,
     /* 40 was used in draft versions of TLS 1.3; it is now reserved. */
     ssl_tls13_pre_shared_key_xtn = 41,
     ssl_tls13_early_data_xtn = 42,
     ssl_tls13_supported_versions_xtn = 43,
     ssl_tls13_cookie_xtn = 44,
     ssl_tls13_psk_key_exchange_modes_xtn = 45,
     ssl_tls13_ticket_early_data_info_xtn = 46, /* Deprecated. */
@@ -449,17 +450,17 @@ typedef enum {
 } SSLExtensionType;
 
 /* This is the old name for the supported_groups extensions. */
 #define ssl_elliptic_curves_xtn ssl_supported_groups_xtn
 
 /* SSL_MAX_EXTENSIONS includes the maximum number of extensions that are
  * supported for any single message type.  That is, a ClientHello; ServerHello
  * and TLS 1.3 NewSessionTicket and HelloRetryRequest extensions have fewer. */
-#define SSL_MAX_EXTENSIONS 20
+#define SSL_MAX_EXTENSIONS 21
 
 /* Deprecated */
 typedef enum {
     ssl_dhe_group_none = 0,
     ssl_ff_dhe_2048_group = 1,
     ssl_ff_dhe_3072_group = 2,
     ssl_ff_dhe_4096_group = 3,
     ssl_ff_dhe_6144_group = 4,
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -3249,16 +3249,27 @@ tls13_SetupPendingCipherSpec(sslSocket *
     }
 
     if (spec->epoch == TrafficKeyEarlyApplicationData) {
         spec->earlyDataRemaining =
             ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
     }
 
     tls13_SetSpecRecordVersion(ss, spec);
+
+    /* The record size limit is reduced by one so that the remainder of the
+     * record handling code can use the same checks for all versions. */
+    if (ssl3_ExtensionNegotiated(ss, ssl_record_size_limit_xtn)) {
+        spec->recordSizeLimit = ((spec->direction == CipherSpecRead)
+                                     ? ss->opt.recordSizeLimit
+                                     : ss->xtnData.recordSizeLimit) -
+                                1;
+    } else {
+        spec->recordSizeLimit = MAX_FRAGMENT_LENGTH;
+    }
     return SECSuccess;
 }
 
 /*
  * Called before sending alerts to set up the right key on the client.
  * We might encounter errors during the handshake where the current
  * key is ClearText or EarlyApplicationData. This
  * function switches to the Handshake key if possible.
@@ -4741,17 +4752,18 @@ static const struct {
                                     new_session_ticket) },
     { ssl_signed_cert_timestamp_xtn, _M3(client_hello, certificate_request,
                                          certificate) },
     { ssl_cert_status_xtn, _M3(client_hello, certificate_request,
                                certificate) },
     { ssl_tls13_cookie_xtn, _M2(client_hello, hello_retry_request) },
     { ssl_tls13_certificate_authorities_xtn, _M1(certificate_request) },
     { ssl_tls13_supported_versions_xtn, _M3(client_hello, server_hello,
-                                            hello_retry_request) }
+                                            hello_retry_request) },
+    { ssl_record_size_limit_xtn, _M2(client_hello, encrypted_extensions) }
 };
 
 tls13ExtensionStatus
 tls13_ExtensionStatus(PRUint16 extension, SSLHandshakeType message)
 {
     unsigned int i;
 
     PORT_Assert((message == ssl_hs_client_hello) ||
@@ -5010,16 +5022,26 @@ tls13_UnprotectRecord(sslSocket *ss,
     if (rv != SECSuccess) {
         SSL_TRC(3,
                 ("%d: TLS13[%d]: record has bogus MAC",
                  SSL_GETPID(), ss->fd));
         PORT_SetError(SSL_ERROR_BAD_MAC_READ);
         return SECFailure;
     }
 
+    /* There is a similar test in ssl3_HandleRecord, but this test is needed to
+     * account for padding.  It's safe to do this here (including the alert),
+     * because it only confirms that the record exceeded the size limit, which
+     * is apparent from the size of the ciphertext. */
+    if (plaintext->len > spec->recordSizeLimit + 1) {
+        SSL3_SendAlert(ss, alert_fatal, record_overflow);
+        PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
+        return SECFailure;
+    }
+
     /* The record is right-padded with 0s, followed by the true
      * content type, so read from the right until we receive a
      * nonzero byte. */
     while (plaintext->len > 0 && !(plaintext->buf[plaintext->len - 1])) {
         --plaintext->len;
     }
 
     /* Bogus padding. */