summaryrefslogtreecommitdiffstats
path: root/security/nss/cpputil
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-06-06 21:27:04 +0200
committerwolfbeast <mcwerewolf@gmail.com>2018-06-06 21:27:04 +0200
commit4a71b30364a4b6d1eaf16fcfdc8e873e6697f293 (patch)
treea47014077c14579249859ad34afcc5a8f2f0730a /security/nss/cpputil
parentd7da72799521386c110dbba73b1e483b00a0a56a (diff)
parent2dad0ec41d0b69c0a815012e6ea4bdde81b2875b (diff)
downloadUXP-4a71b30364a4b6d1eaf16fcfdc8e873e6697f293.tar
UXP-4a71b30364a4b6d1eaf16fcfdc8e873e6697f293.tar.gz
UXP-4a71b30364a4b6d1eaf16fcfdc8e873e6697f293.tar.lz
UXP-4a71b30364a4b6d1eaf16fcfdc8e873e6697f293.tar.xz
UXP-4a71b30364a4b6d1eaf16fcfdc8e873e6697f293.zip
Merge branch 'NSS-335'
Diffstat (limited to 'security/nss/cpputil')
-rw-r--r--security/nss/cpputil/.clang-format4
-rw-r--r--security/nss/cpputil/Makefile49
-rw-r--r--security/nss/cpputil/README11
-rw-r--r--security/nss/cpputil/config.mk15
-rw-r--r--security/nss/cpputil/cpputil.gyp29
-rw-r--r--security/nss/cpputil/cpputil.h12
-rw-r--r--security/nss/cpputil/databuffer.cc127
-rw-r--r--security/nss/cpputil/databuffer.h110
-rw-r--r--security/nss/cpputil/dummy_io.cc225
-rw-r--r--security/nss/cpputil/dummy_io.h62
-rw-r--r--security/nss/cpputil/dummy_io_fwd.cc162
-rw-r--r--security/nss/cpputil/manifest.mn24
-rw-r--r--security/nss/cpputil/scoped_ptrs.h74
-rw-r--r--security/nss/cpputil/scoped_ptrs_util.h39
-rw-r--r--security/nss/cpputil/tls_parser.cc73
-rw-r--r--security/nss/cpputil/tls_parser.h145
16 files changed, 1161 insertions, 0 deletions
diff --git a/security/nss/cpputil/.clang-format b/security/nss/cpputil/.clang-format
new file mode 100644
index 000000000..06e3c5115
--- /dev/null
+++ b/security/nss/cpputil/.clang-format
@@ -0,0 +1,4 @@
+---
+Language: Cpp
+BasedOnStyle: Google
+...
diff --git a/security/nss/cpputil/Makefile b/security/nss/cpputil/Makefile
new file mode 100644
index 000000000..7adfc6117
--- /dev/null
+++ b/security/nss/cpputil/Makefile
@@ -0,0 +1,49 @@
+#! gmake
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY). #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL) #
+#######################################################################
+
+ifeq (WINNT,$(OS_ARCH))
+OS_CFLAGS += -EHsc
+else
+CXXFLAGS += -std=c++0x
+endif
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL). #
+#######################################################################
+
+include config.mk
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL). #
+#######################################################################
diff --git a/security/nss/cpputil/README b/security/nss/cpputil/README
new file mode 100644
index 000000000..22297dd33
--- /dev/null
+++ b/security/nss/cpputil/README
@@ -0,0 +1,11 @@
+######################################
+## PLEASE READ BEFORE USING CPPUTIL ##
+######################################
+
+This is a static library supposed to be mainly used by NSS internally. We use
+it for testing, fuzzing, and a few new tools written in C++ that we're
+experimenting with.
+
+You might find it handy to use for your own projects but please be aware that
+we will make no promises your application won't break in the future. We will
+provide no support if you decide to link against it.
diff --git a/security/nss/cpputil/config.mk b/security/nss/cpputil/config.mk
new file mode 100644
index 000000000..b8c03de79
--- /dev/null
+++ b/security/nss/cpputil/config.mk
@@ -0,0 +1,15 @@
+#
+# 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/.
+
+#
+# Override TARGETS variable so that only static libraries
+# are specifed as dependencies within rules.mk.
+#
+
+TARGETS = $(LIBRARY)
+SHARED_LIBRARY =
+IMPORT_LIBRARY =
+PROGRAM =
+
diff --git a/security/nss/cpputil/cpputil.gyp b/security/nss/cpputil/cpputil.gyp
new file mode 100644
index 000000000..5042acf5c
--- /dev/null
+++ b/security/nss/cpputil/cpputil.gyp
@@ -0,0 +1,29 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+{
+ 'includes': [
+ '../coreconf/config.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'cpputil',
+ 'type': 'static_library',
+ 'sources': [
+ 'databuffer.cc',
+ 'dummy_io.cc',
+ 'dummy_io_fwd.cc',
+ 'tls_parser.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '<(DEPTH)/cpputil',
+ ],
+ },
+ },
+ ],
+}
+
diff --git a/security/nss/cpputil/cpputil.h b/security/nss/cpputil/cpputil.h
new file mode 100644
index 000000000..017ce9bfc
--- /dev/null
+++ b/security/nss/cpputil/cpputil.h
@@ -0,0 +1,12 @@
+/* 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 cpputil_h__
+#define cpputil_h__
+
+static unsigned char* toUcharPtr(const uint8_t* v) {
+ return const_cast<unsigned char*>(static_cast<const unsigned char*>(v));
+}
+
+#endif // cpputil_h__
diff --git a/security/nss/cpputil/databuffer.cc b/security/nss/cpputil/databuffer.cc
new file mode 100644
index 000000000..d60ebccb3
--- /dev/null
+++ b/security/nss/cpputil/databuffer.cc
@@ -0,0 +1,127 @@
+/* -*- 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 "databuffer.h"
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+#include <iomanip>
+#include <iostream>
+#if defined(WIN32) || defined(WIN64)
+#include <winsock2.h>
+#else
+#include <arpa/inet.h>
+#endif
+
+namespace nss_test {
+
+void DataBuffer::Assign(const uint8_t* data, size_t len) {
+ if (data) {
+ Allocate(len);
+ memcpy(static_cast<void*>(data_), static_cast<const void*>(data), len);
+ } else {
+ assert(len == 0);
+ data_ = nullptr;
+ len_ = 0;
+ }
+}
+
+// Write will do a new allocation and expand the size of the buffer if needed.
+// Returns the offset of the end of the write.
+size_t DataBuffer::Write(size_t index, const uint8_t* val, size_t count) {
+ assert(val);
+ if (index + count > len_) {
+ size_t newlen = index + count;
+ uint8_t* tmp = new uint8_t[newlen]; // Always > 0.
+ if (data_) {
+ memcpy(static_cast<void*>(tmp), static_cast<const void*>(data_), len_);
+ }
+ if (index > len_) {
+ memset(static_cast<void*>(tmp + len_), 0, index - len_);
+ }
+ delete[] data_;
+ data_ = tmp;
+ len_ = newlen;
+ }
+ if (data_) {
+ memcpy(static_cast<void*>(data_ + index), static_cast<const void*>(val),
+ count);
+ }
+ return index + count;
+}
+
+// Write an integer, also performing host-to-network order conversion.
+// Returns the offset of the end of the write.
+size_t DataBuffer::Write(size_t index, uint32_t val, size_t count) {
+ assert(count <= sizeof(uint32_t));
+ uint32_t nvalue = htonl(val);
+ auto* addr = reinterpret_cast<const uint8_t*>(&nvalue);
+ return Write(index, addr + sizeof(uint32_t) - count, count);
+}
+
+void DataBuffer::Splice(const uint8_t* ins, size_t ins_len, size_t index,
+ size_t remove) {
+ assert(ins);
+ uint8_t* old_value = data_;
+ size_t old_len = len_;
+
+ // The amount of stuff remaining from the tail of the old.
+ size_t tail_len = old_len - (std::min)(old_len, index + remove);
+ // The new length: the head of the old, the new, and the tail of the old.
+ len_ = index + ins_len + tail_len;
+ data_ = new uint8_t[len_ ? len_ : 1];
+
+ // The head of the old.
+ if (old_value) {
+ Write(0, old_value, (std::min)(old_len, index));
+ }
+ // Maybe a gap.
+ if (old_value && index > old_len) {
+ memset(old_value + index, 0, index - old_len);
+ }
+ // The new.
+ Write(index, ins, ins_len);
+ // The tail of the old.
+ if (tail_len > 0) {
+ Write(index + ins_len, old_value + index + remove, tail_len);
+ }
+
+ delete[] old_value;
+}
+
+// This can't use the same trick as Write(), since we might be reading from a
+// smaller data source.
+bool DataBuffer::Read(size_t index, size_t count, uint64_t* val) const {
+ assert(count <= sizeof(uint64_t));
+ assert(val);
+ if ((index > len()) || (count > (len() - index))) {
+ return false;
+ }
+ *val = 0;
+ for (size_t i = 0; i < count; ++i) {
+ *val = (*val << 8) | data()[index + i];
+ }
+ return true;
+}
+
+bool DataBuffer::Read(size_t index, size_t count, uint32_t* val) const {
+ assert(count <= sizeof(uint32_t));
+ uint64_t tmp;
+
+ if (!Read(index, count, &tmp)) {
+ return false;
+ }
+ *val = tmp & 0xffffffff;
+ return true;
+}
+
+size_t DataBuffer::logging_limit = 32;
+
+/* static */ void DataBuffer::SetLogLimit(size_t limit) {
+ DataBuffer::logging_limit = limit;
+}
+
+} // namespace nss_test
diff --git a/security/nss/cpputil/databuffer.h b/security/nss/cpputil/databuffer.h
new file mode 100644
index 000000000..58e07efe1
--- /dev/null
+++ b/security/nss/cpputil/databuffer.h
@@ -0,0 +1,110 @@
+/* -*- 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/. */
+
+#ifndef databuffer_h__
+#define databuffer_h__
+
+#include <algorithm>
+#include <cstring>
+#include <iomanip>
+#include <iostream>
+
+namespace nss_test {
+
+class DataBuffer {
+ public:
+ DataBuffer() : data_(nullptr), len_(0) {}
+ DataBuffer(const uint8_t* data, size_t len) : data_(nullptr), len_(0) {
+ Assign(data, len);
+ }
+ DataBuffer(const DataBuffer& other) : data_(nullptr), len_(0) {
+ Assign(other);
+ }
+ ~DataBuffer() { delete[] data_; }
+
+ DataBuffer& operator=(const DataBuffer& other) {
+ if (&other != this) {
+ Assign(other);
+ }
+ return *this;
+ }
+
+ void Allocate(size_t len) {
+ delete[] data_;
+ data_ = new uint8_t[len ? len : 1]; // Don't depend on new [0].
+ len_ = len;
+ }
+
+ void Truncate(size_t len) { len_ = (std::min)(len_, len); }
+
+ void Assign(const DataBuffer& other) { Assign(other.data(), other.len()); }
+
+ void Assign(const uint8_t* data, size_t len);
+
+ // Write will do a new allocation and expand the size of the buffer if needed.
+ // Returns the offset of the end of the write.
+ size_t Write(size_t index, const uint8_t* val, size_t count);
+ size_t Write(size_t index, const DataBuffer& buf) {
+ return Write(index, buf.data(), buf.len());
+ }
+
+ // Write an integer, also performing host-to-network order conversion.
+ // Returns the offset of the end of the write.
+ size_t Write(size_t index, uint32_t val, size_t count);
+
+ // Starting at |index|, remove |remove| bytes and replace them with the
+ // contents of |buf|.
+ void Splice(const DataBuffer& buf, size_t index, size_t remove = 0) {
+ Splice(buf.data(), buf.len(), index, remove);
+ }
+
+ void Splice(const uint8_t* ins, size_t ins_len, size_t index,
+ size_t remove = 0);
+ void Append(const DataBuffer& buf) { Splice(buf, len_); }
+
+ bool Read(size_t index, size_t count, uint64_t* val) const;
+ bool Read(size_t index, size_t count, uint32_t* val) const;
+
+ const uint8_t* data() const { return data_; }
+ uint8_t* data() { return data_; }
+ size_t len() const { return len_; }
+ bool empty() const { return len_ == 0; }
+
+ static void SetLogLimit(size_t limit);
+ friend std::ostream& operator<<(std::ostream& stream, const DataBuffer& buf);
+
+ private:
+ static size_t logging_limit;
+ uint8_t* data_;
+ size_t len_;
+};
+
+inline std::ostream& operator<<(std::ostream& stream, const DataBuffer& buf) {
+ stream << "[" << buf.len() << "] ";
+ for (size_t i = 0; i < buf.len(); ++i) {
+ if (i >= DataBuffer::logging_limit) {
+ stream << "...";
+ break;
+ }
+ stream << std::hex << std::setfill('0') << std::setw(2)
+ << static_cast<unsigned>(buf.data()[i]);
+ }
+ stream << std::dec;
+ return stream;
+}
+
+inline bool operator==(const DataBuffer& a, const DataBuffer& b) {
+ return (a.empty() && b.empty()) ||
+ (a.len() == b.len() && 0 == memcmp(a.data(), b.data(), a.len()));
+}
+
+inline bool operator!=(const DataBuffer& a, const DataBuffer& b) {
+ return !(a == b);
+}
+
+} // namespace nss_test
+
+#endif
diff --git a/security/nss/cpputil/dummy_io.cc b/security/nss/cpputil/dummy_io.cc
new file mode 100644
index 000000000..ef45db833
--- /dev/null
+++ b/security/nss/cpputil/dummy_io.cc
@@ -0,0 +1,225 @@
+/* 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 <assert.h>
+#include <iostream>
+
+#include "prerror.h"
+#include "prio.h"
+
+#include "dummy_io.h"
+
+#define UNIMPLEMENTED() \
+ std::cerr << "Unimplemented: " << __FUNCTION__ << std::endl; \
+ assert(false);
+
+extern const struct PRIOMethods DummyMethodsForward;
+
+ScopedPRFileDesc DummyIOLayerMethods::CreateFD(PRDescIdentity id,
+ DummyIOLayerMethods *methods) {
+ ScopedPRFileDesc fd(PR_CreateIOLayerStub(id, &DummyMethodsForward));
+ assert(fd);
+ if (!fd) {
+ return nullptr;
+ }
+ fd->secret = reinterpret_cast<PRFilePrivate *>(methods);
+ return fd;
+}
+
+PRStatus DummyIOLayerMethods::Close(PRFileDesc *f) {
+ f->secret = nullptr;
+ f->dtor(f);
+ return PR_SUCCESS;
+}
+
+int32_t DummyIOLayerMethods::Read(PRFileDesc *f, void *buf, int32_t length) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+int32_t DummyIOLayerMethods::Write(PRFileDesc *f, const void *buf,
+ int32_t length) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+int32_t DummyIOLayerMethods::Available(PRFileDesc *f) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+int64_t DummyIOLayerMethods::Available64(PRFileDesc *f) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+PRStatus DummyIOLayerMethods::Sync(PRFileDesc *f) {
+ UNIMPLEMENTED();
+ return PR_FAILURE;
+}
+
+int32_t DummyIOLayerMethods::Seek(PRFileDesc *f, int32_t offset,
+ PRSeekWhence how) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+int64_t DummyIOLayerMethods::Seek64(PRFileDesc *f, int64_t offset,
+ PRSeekWhence how) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+PRStatus DummyIOLayerMethods::FileInfo(PRFileDesc *f, PRFileInfo *info) {
+ UNIMPLEMENTED();
+ return PR_FAILURE;
+}
+
+PRStatus DummyIOLayerMethods::FileInfo64(PRFileDesc *f, PRFileInfo64 *info) {
+ UNIMPLEMENTED();
+ return PR_FAILURE;
+}
+
+int32_t DummyIOLayerMethods::Writev(PRFileDesc *f, const PRIOVec *iov,
+ int32_t iov_size, PRIntervalTime to) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+PRStatus DummyIOLayerMethods::Connect(PRFileDesc *f, const PRNetAddr *addr,
+ PRIntervalTime to) {
+ UNIMPLEMENTED();
+ return PR_FAILURE;
+}
+
+PRFileDesc *DummyIOLayerMethods::Accept(PRFileDesc *sd, PRNetAddr *addr,
+ PRIntervalTime to) {
+ UNIMPLEMENTED();
+ return nullptr;
+}
+
+PRStatus DummyIOLayerMethods::Bind(PRFileDesc *f, const PRNetAddr *addr) {
+ UNIMPLEMENTED();
+ return PR_FAILURE;
+}
+
+PRStatus DummyIOLayerMethods::Listen(PRFileDesc *f, int32_t depth) {
+ UNIMPLEMENTED();
+ return PR_FAILURE;
+}
+
+PRStatus DummyIOLayerMethods::Shutdown(PRFileDesc *f, int32_t how) {
+ return PR_SUCCESS;
+}
+
+int32_t DummyIOLayerMethods::Recv(PRFileDesc *f, void *buf, int32_t buflen,
+ int32_t flags, PRIntervalTime to) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+// Note: this is always nonblocking and assumes a zero timeout.
+int32_t DummyIOLayerMethods::Send(PRFileDesc *f, const void *buf,
+ int32_t amount, int32_t flags,
+ PRIntervalTime to) {
+ return Write(f, buf, amount);
+}
+
+int32_t DummyIOLayerMethods::Recvfrom(PRFileDesc *f, void *buf, int32_t amount,
+ int32_t flags, PRNetAddr *addr,
+ PRIntervalTime to) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+int32_t DummyIOLayerMethods::Sendto(PRFileDesc *f, const void *buf,
+ int32_t amount, int32_t flags,
+ const PRNetAddr *addr, PRIntervalTime to) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+int16_t DummyIOLayerMethods::Poll(PRFileDesc *f, int16_t in_flags,
+ int16_t *out_flags) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+int32_t DummyIOLayerMethods::AcceptRead(PRFileDesc *sd, PRFileDesc **nd,
+ PRNetAddr **raddr, void *buf,
+ int32_t amount, PRIntervalTime t) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+int32_t DummyIOLayerMethods::TransmitFile(PRFileDesc *sd, PRFileDesc *f,
+ const void *headers, int32_t hlen,
+ PRTransmitFileFlags flags,
+ PRIntervalTime t) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+// TODO: Modify to return unique names for each channel
+// somehow, as opposed to always the same static address. The current
+// implementation messes up the session cache, which is why it's off
+// elsewhere
+PRStatus DummyIOLayerMethods::Getpeername(PRFileDesc *f, PRNetAddr *addr) {
+ addr->inet.family = PR_AF_INET;
+ addr->inet.port = 0;
+ addr->inet.ip = 0;
+
+ return PR_SUCCESS;
+}
+
+PRStatus DummyIOLayerMethods::Getsockname(PRFileDesc *f, PRNetAddr *addr) {
+ UNIMPLEMENTED();
+ return PR_FAILURE;
+}
+
+PRStatus DummyIOLayerMethods::Getsockoption(PRFileDesc *f,
+ PRSocketOptionData *opt) {
+ switch (opt->option) {
+ case PR_SockOpt_Nonblocking:
+ opt->value.non_blocking = PR_TRUE;
+ return PR_SUCCESS;
+ default:
+ UNIMPLEMENTED();
+ break;
+ }
+
+ return PR_FAILURE;
+}
+
+PRStatus DummyIOLayerMethods::Setsockoption(PRFileDesc *f,
+ const PRSocketOptionData *opt) {
+ switch (opt->option) {
+ case PR_SockOpt_Nonblocking:
+ return PR_SUCCESS;
+ case PR_SockOpt_NoDelay:
+ return PR_SUCCESS;
+ default:
+ UNIMPLEMENTED();
+ break;
+ }
+
+ return PR_FAILURE;
+}
+
+int32_t DummyIOLayerMethods::Sendfile(PRFileDesc *out, PRSendFileData *in,
+ PRTransmitFileFlags flags,
+ PRIntervalTime to) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+PRStatus DummyIOLayerMethods::ConnectContinue(PRFileDesc *f, int16_t flags) {
+ UNIMPLEMENTED();
+ return PR_FAILURE;
+}
+
+int32_t DummyIOLayerMethods::Reserved(PRFileDesc *f) {
+ UNIMPLEMENTED();
+ return -1;
+}
diff --git a/security/nss/cpputil/dummy_io.h b/security/nss/cpputil/dummy_io.h
new file mode 100644
index 000000000..797ac6113
--- /dev/null
+++ b/security/nss/cpputil/dummy_io.h
@@ -0,0 +1,62 @@
+/* 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 dummy_io_h__
+#define dummy_io_h__
+
+#include "prerror.h"
+#include "prio.h"
+
+#include "scoped_ptrs.h"
+
+class DummyIOLayerMethods {
+ public:
+ static ScopedPRFileDesc CreateFD(PRDescIdentity id,
+ DummyIOLayerMethods *methods);
+
+ virtual PRStatus Close(PRFileDesc *f);
+ virtual int32_t Read(PRFileDesc *f, void *buf, int32_t length);
+ virtual int32_t Write(PRFileDesc *f, const void *buf, int32_t length);
+ virtual int32_t Available(PRFileDesc *f);
+ virtual int64_t Available64(PRFileDesc *f);
+ virtual PRStatus Sync(PRFileDesc *f);
+ virtual int32_t Seek(PRFileDesc *f, int32_t offset, PRSeekWhence how);
+ virtual int64_t Seek64(PRFileDesc *f, int64_t offset, PRSeekWhence how);
+ virtual PRStatus FileInfo(PRFileDesc *f, PRFileInfo *info);
+ virtual PRStatus FileInfo64(PRFileDesc *f, PRFileInfo64 *info);
+ virtual int32_t Writev(PRFileDesc *f, const PRIOVec *iov, int32_t iov_size,
+ PRIntervalTime to);
+ virtual PRStatus Connect(PRFileDesc *f, const PRNetAddr *addr,
+ PRIntervalTime to);
+ virtual PRFileDesc *Accept(PRFileDesc *sd, PRNetAddr *addr,
+ PRIntervalTime to);
+ virtual PRStatus Bind(PRFileDesc *f, const PRNetAddr *addr);
+ virtual PRStatus Listen(PRFileDesc *f, int32_t depth);
+ virtual PRStatus Shutdown(PRFileDesc *f, int32_t how);
+ virtual int32_t Recv(PRFileDesc *f, void *buf, int32_t buflen, int32_t flags,
+ PRIntervalTime to);
+ virtual int32_t Send(PRFileDesc *f, const void *buf, int32_t amount,
+ int32_t flags, PRIntervalTime to);
+ virtual int32_t Recvfrom(PRFileDesc *f, void *buf, int32_t amount,
+ int32_t flags, PRNetAddr *addr, PRIntervalTime to);
+ virtual int32_t Sendto(PRFileDesc *f, const void *buf, int32_t amount,
+ int32_t flags, const PRNetAddr *addr,
+ PRIntervalTime to);
+ virtual int16_t Poll(PRFileDesc *f, int16_t in_flags, int16_t *out_flags);
+ virtual int32_t AcceptRead(PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
+ void *buf, int32_t amount, PRIntervalTime t);
+ virtual int32_t TransmitFile(PRFileDesc *sd, PRFileDesc *f,
+ const void *headers, int32_t hlen,
+ PRTransmitFileFlags flags, PRIntervalTime t);
+ virtual PRStatus Getpeername(PRFileDesc *f, PRNetAddr *addr);
+ virtual PRStatus Getsockname(PRFileDesc *f, PRNetAddr *addr);
+ virtual PRStatus Getsockoption(PRFileDesc *f, PRSocketOptionData *opt);
+ virtual PRStatus Setsockoption(PRFileDesc *f, const PRSocketOptionData *opt);
+ virtual int32_t Sendfile(PRFileDesc *out, PRSendFileData *in,
+ PRTransmitFileFlags flags, PRIntervalTime to);
+ virtual PRStatus ConnectContinue(PRFileDesc *f, int16_t flags);
+ virtual int32_t Reserved(PRFileDesc *f);
+};
+
+#endif // dummy_io_h__
diff --git a/security/nss/cpputil/dummy_io_fwd.cc b/security/nss/cpputil/dummy_io_fwd.cc
new file mode 100644
index 000000000..5e53d9e1b
--- /dev/null
+++ b/security/nss/cpputil/dummy_io_fwd.cc
@@ -0,0 +1,162 @@
+/* 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 "prio.h"
+
+#include "dummy_io.h"
+
+static DummyIOLayerMethods *ToMethods(PRFileDesc *f) {
+ return reinterpret_cast<DummyIOLayerMethods *>(f->secret);
+}
+
+static PRStatus DummyClose(PRFileDesc *f) { return ToMethods(f)->Close(f); }
+
+static int32_t DummyRead(PRFileDesc *f, void *buf, int32_t length) {
+ return ToMethods(f)->Read(f, buf, length);
+}
+
+static int32_t DummyWrite(PRFileDesc *f, const void *buf, int32_t length) {
+ return ToMethods(f)->Write(f, buf, length);
+}
+
+static int32_t DummyAvailable(PRFileDesc *f) {
+ return ToMethods(f)->Available(f);
+}
+
+static int64_t DummyAvailable64(PRFileDesc *f) {
+ return ToMethods(f)->Available64(f);
+}
+
+static PRStatus DummySync(PRFileDesc *f) { return ToMethods(f)->Sync(f); }
+
+static int32_t DummySeek(PRFileDesc *f, int32_t offset, PRSeekWhence how) {
+ return ToMethods(f)->Seek(f, offset, how);
+}
+
+static int64_t DummySeek64(PRFileDesc *f, int64_t offset, PRSeekWhence how) {
+ return ToMethods(f)->Seek64(f, offset, how);
+}
+
+static PRStatus DummyFileInfo(PRFileDesc *f, PRFileInfo *info) {
+ return ToMethods(f)->FileInfo(f, info);
+}
+
+static PRStatus DummyFileInfo64(PRFileDesc *f, PRFileInfo64 *info) {
+ return ToMethods(f)->FileInfo64(f, info);
+}
+
+static int32_t DummyWritev(PRFileDesc *f, const PRIOVec *iov, int32_t iov_size,
+ PRIntervalTime to) {
+ return ToMethods(f)->Writev(f, iov, iov_size, to);
+}
+
+static PRStatus DummyConnect(PRFileDesc *f, const PRNetAddr *addr,
+ PRIntervalTime to) {
+ return ToMethods(f)->Connect(f, addr, to);
+}
+
+static PRFileDesc *DummyAccept(PRFileDesc *f, PRNetAddr *addr,
+ PRIntervalTime to) {
+ return ToMethods(f)->Accept(f, addr, to);
+}
+
+static PRStatus DummyBind(PRFileDesc *f, const PRNetAddr *addr) {
+ return ToMethods(f)->Bind(f, addr);
+}
+
+static PRStatus DummyListen(PRFileDesc *f, int32_t depth) {
+ return ToMethods(f)->Listen(f, depth);
+}
+
+static PRStatus DummyShutdown(PRFileDesc *f, int32_t how) {
+ return ToMethods(f)->Shutdown(f, how);
+}
+
+static int32_t DummyRecv(PRFileDesc *f, void *buf, int32_t buflen,
+ int32_t flags, PRIntervalTime to) {
+ return ToMethods(f)->Recv(f, buf, buflen, flags, to);
+}
+
+static int32_t DummySend(PRFileDesc *f, const void *buf, int32_t amount,
+ int32_t flags, PRIntervalTime to) {
+ return ToMethods(f)->Send(f, buf, amount, flags, to);
+}
+
+static int32_t DummyRecvfrom(PRFileDesc *f, void *buf, int32_t amount,
+ int32_t flags, PRNetAddr *addr,
+ PRIntervalTime to) {
+ return ToMethods(f)->Recvfrom(f, buf, amount, flags, addr, to);
+}
+
+static int32_t DummySendto(PRFileDesc *f, const void *buf, int32_t amount,
+ int32_t flags, const PRNetAddr *addr,
+ PRIntervalTime to) {
+ return ToMethods(f)->Sendto(f, buf, amount, flags, addr, to);
+}
+
+static int16_t DummyPoll(PRFileDesc *f, int16_t in_flags, int16_t *out_flags) {
+ return ToMethods(f)->Poll(f, in_flags, out_flags);
+}
+
+static int32_t DummyAcceptRead(PRFileDesc *f, PRFileDesc **nd,
+ PRNetAddr **raddr, void *buf, int32_t amount,
+ PRIntervalTime t) {
+ return ToMethods(f)->AcceptRead(f, nd, raddr, buf, amount, t);
+}
+
+static int32_t DummyTransmitFile(PRFileDesc *sd, PRFileDesc *f,
+ const void *headers, int32_t hlen,
+ PRTransmitFileFlags flags, PRIntervalTime t) {
+ return ToMethods(f)->TransmitFile(sd, f, headers, hlen, flags, t);
+}
+
+static PRStatus DummyGetpeername(PRFileDesc *f, PRNetAddr *addr) {
+ return ToMethods(f)->Getpeername(f, addr);
+}
+
+static PRStatus DummyGetsockname(PRFileDesc *f, PRNetAddr *addr) {
+ return ToMethods(f)->Getsockname(f, addr);
+}
+
+static PRStatus DummyGetsockoption(PRFileDesc *f, PRSocketOptionData *opt) {
+ return ToMethods(f)->Getsockoption(f, opt);
+}
+
+static PRStatus DummySetsockoption(PRFileDesc *f,
+ const PRSocketOptionData *opt) {
+ return ToMethods(f)->Setsockoption(f, opt);
+}
+
+static int32_t DummySendfile(PRFileDesc *f, PRSendFileData *in,
+ PRTransmitFileFlags flags, PRIntervalTime to) {
+ return ToMethods(f)->Sendfile(f, in, flags, to);
+}
+
+static PRStatus DummyConnectContinue(PRFileDesc *f, int16_t flags) {
+ return ToMethods(f)->ConnectContinue(f, flags);
+}
+
+static int32_t DummyReserved(PRFileDesc *f) {
+ return ToMethods(f)->Reserved(f);
+}
+
+extern const struct PRIOMethods DummyMethodsForward = {
+ PR_DESC_LAYERED, DummyClose,
+ DummyRead, DummyWrite,
+ DummyAvailable, DummyAvailable64,
+ DummySync, DummySeek,
+ DummySeek64, DummyFileInfo,
+ DummyFileInfo64, DummyWritev,
+ DummyConnect, DummyAccept,
+ DummyBind, DummyListen,
+ DummyShutdown, DummyRecv,
+ DummySend, DummyRecvfrom,
+ DummySendto, DummyPoll,
+ DummyAcceptRead, DummyTransmitFile,
+ DummyGetsockname, DummyGetpeername,
+ DummyReserved, DummyReserved,
+ DummyGetsockoption, DummySetsockoption,
+ DummySendfile, DummyConnectContinue,
+ DummyReserved, DummyReserved,
+ DummyReserved, DummyReserved};
diff --git a/security/nss/cpputil/manifest.mn b/security/nss/cpputil/manifest.mn
new file mode 100644
index 000000000..b3ccad8b5
--- /dev/null
+++ b/security/nss/cpputil/manifest.mn
@@ -0,0 +1,24 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+CORE_DEPTH = ..
+DEPTH = ..
+
+MODULE = nss
+LIBRARY_NAME = cpputil
+
+ifeq ($(NSS_BUILD_UTIL_ONLY),1)
+CPPSRCS = \
+ $(NULL)
+else
+CPPSRCS = \
+ databuffer.cc \
+ dummy_io.cc \
+ dummy_io_fwd.cc \
+ tls_parser.cc \
+ $(NULL)
+endif
+
+EXPORTS = \
+ $(NULL)
diff --git a/security/nss/cpputil/scoped_ptrs.h b/security/nss/cpputil/scoped_ptrs.h
new file mode 100644
index 000000000..b92b8132b
--- /dev/null
+++ b/security/nss/cpputil/scoped_ptrs.h
@@ -0,0 +1,74 @@
+/* -*- 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/. */
+
+#ifndef scoped_ptrs_h__
+#define scoped_ptrs_h__
+
+#include <memory>
+#include "cert.h"
+#include "keyhi.h"
+#include "pk11pub.h"
+#include "pkcs11uri.h"
+
+struct ScopedDelete {
+ void operator()(CERTCertificate* cert) { CERT_DestroyCertificate(cert); }
+ void operator()(CERTCertificateList* list) {
+ CERT_DestroyCertificateList(list);
+ }
+ void operator()(CERTName* name) { CERT_DestroyName(name); }
+ void operator()(CERTCertList* list) { CERT_DestroyCertList(list); }
+ void operator()(CERTSubjectPublicKeyInfo* spki) {
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+ }
+ void operator()(PK11SlotInfo* slot) { PK11_FreeSlot(slot); }
+ void operator()(PK11SymKey* key) { PK11_FreeSymKey(key); }
+ void operator()(PRFileDesc* fd) { PR_Close(fd); }
+ void operator()(SECAlgorithmID* id) { SECOID_DestroyAlgorithmID(id, true); }
+ void operator()(SECItem* item) { SECITEM_FreeItem(item, true); }
+ void operator()(SECKEYPublicKey* key) { SECKEY_DestroyPublicKey(key); }
+ void operator()(SECKEYPrivateKey* key) { SECKEY_DestroyPrivateKey(key); }
+ void operator()(SECKEYPrivateKeyList* list) {
+ SECKEY_DestroyPrivateKeyList(list);
+ }
+ void operator()(PK11URI* uri) { PK11URI_DestroyURI(uri); }
+ void operator()(PLArenaPool* arena) { PORT_FreeArena(arena, PR_FALSE); }
+ void operator()(PK11Context* context) { PK11_DestroyContext(context, true); }
+ void operator()(PK11GenericObject* obj) { PK11_DestroyGenericObject(obj); }
+};
+
+template <class T>
+struct ScopedMaybeDelete {
+ void operator()(T* ptr) {
+ if (ptr) {
+ ScopedDelete del;
+ del(ptr);
+ }
+ }
+};
+
+#define SCOPED(x) typedef std::unique_ptr<x, ScopedMaybeDelete<x> > Scoped##x
+
+SCOPED(CERTCertificate);
+SCOPED(CERTCertificateList);
+SCOPED(CERTCertList);
+SCOPED(CERTName);
+SCOPED(CERTSubjectPublicKeyInfo);
+SCOPED(PK11SlotInfo);
+SCOPED(PK11SymKey);
+SCOPED(PRFileDesc);
+SCOPED(SECAlgorithmID);
+SCOPED(SECItem);
+SCOPED(SECKEYPublicKey);
+SCOPED(SECKEYPrivateKey);
+SCOPED(SECKEYPrivateKeyList);
+SCOPED(PK11URI);
+SCOPED(PLArenaPool);
+SCOPED(PK11Context);
+SCOPED(PK11GenericObject);
+
+#undef SCOPED
+
+#endif // scoped_ptrs_h__
diff --git a/security/nss/cpputil/scoped_ptrs_util.h b/security/nss/cpputil/scoped_ptrs_util.h
new file mode 100644
index 000000000..2dbf34e1d
--- /dev/null
+++ b/security/nss/cpputil/scoped_ptrs_util.h
@@ -0,0 +1,39 @@
+/* -*- 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/. */
+
+#ifndef scoped_ptrs_util_h__
+#define scoped_ptrs_util_h__
+
+#include <memory>
+#include "pkcs11uri.h"
+#include "secoid.h"
+
+struct ScopedDelete {
+ void operator()(SECAlgorithmID* id) { SECOID_DestroyAlgorithmID(id, true); }
+ void operator()(SECItem* item) { SECITEM_FreeItem(item, true); }
+ void operator()(PK11URI* uri) { PK11URI_DestroyURI(uri); }
+ void operator()(PLArenaPool* arena) { PORT_FreeArena(arena, PR_FALSE); }
+};
+
+template <class T>
+struct ScopedMaybeDelete {
+ void operator()(T* ptr) {
+ if (ptr) {
+ ScopedDelete del;
+ del(ptr);
+ }
+ }
+};
+
+#define SCOPED(x) typedef std::unique_ptr<x, ScopedMaybeDelete<x> > Scoped##x
+
+SCOPED(SECAlgorithmID);
+SCOPED(SECItem);
+SCOPED(PK11URI);
+
+#undef SCOPED
+
+#endif // scoped_ptrs_util_h__
diff --git a/security/nss/cpputil/tls_parser.cc b/security/nss/cpputil/tls_parser.cc
new file mode 100644
index 000000000..e4c06aa91
--- /dev/null
+++ b/security/nss/cpputil/tls_parser.cc
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "tls_parser.h"
+
+namespace nss_test {
+
+bool TlsParser::Read(uint8_t* val) {
+ if (remaining() < 1) {
+ return false;
+ }
+ *val = *ptr();
+ consume(1);
+ return true;
+}
+
+bool TlsParser::Read(uint32_t* val, size_t size) {
+ if (size > sizeof(uint32_t)) {
+ return false;
+ }
+
+ uint32_t v = 0;
+ for (size_t i = 0; i < size; ++i) {
+ uint8_t tmp;
+ if (!Read(&tmp)) {
+ return false;
+ }
+
+ v = (v << 8) | tmp;
+ }
+
+ *val = v;
+ return true;
+}
+
+bool TlsParser::Read(DataBuffer* val, size_t len) {
+ if (remaining() < len) {
+ return false;
+ }
+
+ val->Assign(ptr(), len);
+ consume(len);
+ return true;
+}
+
+bool TlsParser::ReadVariable(DataBuffer* val, size_t len_size) {
+ uint32_t len;
+ if (!Read(&len, len_size)) {
+ return false;
+ }
+ return Read(val, len);
+}
+
+bool TlsParser::Skip(size_t len) {
+ if (len > remaining()) {
+ return false;
+ }
+ consume(len);
+ return true;
+}
+
+bool TlsParser::SkipVariable(size_t len_size) {
+ uint32_t len;
+ if (!Read(&len, len_size)) {
+ return false;
+ }
+ return Skip(len);
+}
+
+} // namespace nss_test
diff --git a/security/nss/cpputil/tls_parser.h b/security/nss/cpputil/tls_parser.h
new file mode 100644
index 000000000..a5f5771d5
--- /dev/null
+++ b/security/nss/cpputil/tls_parser.h
@@ -0,0 +1,145 @@
+/* -*- 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/. */
+
+#ifndef tls_parser_h_
+#define tls_parser_h_
+
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#if defined(WIN32) || defined(WIN64)
+#include <winsock2.h>
+#else
+#include <arpa/inet.h>
+#endif
+#include "databuffer.h"
+#include "sslt.h"
+
+namespace nss_test {
+
+const uint8_t kTlsChangeCipherSpecType = 20;
+const uint8_t kTlsAlertType = 21;
+const uint8_t kTlsHandshakeType = 22;
+const uint8_t kTlsApplicationDataType = 23;
+const uint8_t kTlsAltHandshakeType = 24;
+const uint8_t kTlsAckType = 25;
+
+const uint8_t kTlsHandshakeClientHello = 1;
+const uint8_t kTlsHandshakeServerHello = 2;
+const uint8_t kTlsHandshakeNewSessionTicket = 4;
+const uint8_t kTlsHandshakeHelloRetryRequest = 6;
+const uint8_t kTlsHandshakeEncryptedExtensions = 8;
+const uint8_t kTlsHandshakeCertificate = 11;
+const uint8_t kTlsHandshakeServerKeyExchange = 12;
+const uint8_t kTlsHandshakeCertificateRequest = 13;
+const uint8_t kTlsHandshakeCertificateVerify = 15;
+const uint8_t kTlsHandshakeClientKeyExchange = 16;
+const uint8_t kTlsHandshakeFinished = 20;
+
+const uint8_t kTlsAlertWarning = 1;
+const uint8_t kTlsAlertFatal = 2;
+
+const uint8_t kTlsAlertCloseNotify = 0;
+const uint8_t kTlsAlertUnexpectedMessage = 10;
+const uint8_t kTlsAlertBadRecordMac = 20;
+const uint8_t kTlsAlertRecordOverflow = 22;
+const uint8_t kTlsAlertHandshakeFailure = 40;
+const uint8_t kTlsAlertIllegalParameter = 47;
+const uint8_t kTlsAlertDecodeError = 50;
+const uint8_t kTlsAlertDecryptError = 51;
+const uint8_t kTlsAlertProtocolVersion = 70;
+const uint8_t kTlsAlertInternalError = 80;
+const uint8_t kTlsAlertInappropriateFallback = 86;
+const uint8_t kTlsAlertMissingExtension = 109;
+const uint8_t kTlsAlertUnsupportedExtension = 110;
+const uint8_t kTlsAlertUnrecognizedName = 112;
+const uint8_t kTlsAlertNoApplicationProtocol = 120;
+
+const uint8_t kTlsFakeChangeCipherSpec[] = {
+ kTlsChangeCipherSpecType, // Type
+ 0xfe,
+ 0xff, // Version
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x10, // Fictitious sequence #
+ 0x00,
+ 0x01, // Length
+ 0x01 // Value
+};
+
+static const uint8_t kTls13PskKe = 0;
+static const uint8_t kTls13PskDhKe = 1;
+static const uint8_t kTls13PskAuth = 0;
+static const uint8_t kTls13PskSignAuth = 1;
+
+inline std::ostream& operator<<(std::ostream& os, SSLProtocolVariant v) {
+ return os << ((v == ssl_variant_stream) ? "TLS" : "DTLS");
+}
+
+inline bool IsDtls(uint16_t version) { return (version & 0x8000) == 0x8000; }
+
+inline uint16_t NormalizeTlsVersion(uint16_t version) {
+ if (version == 0xfeff) {
+ return 0x0302; // special: DTLS 1.0 == TLS 1.1
+ }
+ if (IsDtls(version)) {
+ return (version ^ 0xffff) + 0x0201;
+ }
+ return version;
+}
+
+inline uint16_t TlsVersionToDtlsVersion(uint16_t version) {
+ if (version == 0x0302) {
+ return 0xfeff;
+ }
+ if (version == 0x0304) {
+ return version;
+ }
+ return 0xffff - version + 0x0201;
+}
+
+inline size_t WriteVariable(DataBuffer* target, size_t index,
+ const DataBuffer& buf, size_t len_size) {
+ index = target->Write(index, static_cast<uint32_t>(buf.len()), len_size);
+ return target->Write(index, buf.data(), buf.len());
+}
+
+class TlsParser {
+ public:
+ TlsParser(const uint8_t* data, size_t len) : buffer_(data, len), offset_(0) {}
+ explicit TlsParser(const DataBuffer& buf) : buffer_(buf), offset_(0) {}
+
+ bool Read(uint8_t* val);
+ // Read an integral type of specified width.
+ bool Read(uint32_t* val, size_t size);
+ // Reads len bytes into dest buffer, overwriting it.
+ bool Read(DataBuffer* dest, size_t len);
+ // Reads bytes into dest buffer, overwriting it. The number of bytes is
+ // determined by reading from len_size bytes from the stream first.
+ bool ReadVariable(DataBuffer* dest, size_t len_size);
+
+ bool Skip(size_t len);
+ bool SkipVariable(size_t len_size);
+
+ size_t consumed() const { return offset_; }
+ size_t remaining() const { return buffer_.len() - offset_; }
+
+ private:
+ void consume(size_t len) { offset_ += len; }
+ const uint8_t* ptr() const { return buffer_.data() + offset_; }
+
+ DataBuffer buffer_;
+ size_t offset_;
+};
+
+} // namespace nss_test
+
+#endif