Bug 1403844 - Verify COSE signature on add-ons, r=keeler
authorFranziskus Kiefer <franziskuskiefer@gmail.com>
Mon, 08 Jan 2018 11:46:51 +0100
changeset 450260 8ae89b17787b7a67e3a7ce621e63fdf2d3c7bb26
parent 450259 a2b1db70bc89cb917a8cebf1314f11b21171bc56
child 450261 38614ffd21d195add38b50056b89d5f99b53baee
push id8527
push userCallek@gmail.com
push dateThu, 11 Jan 2018 21:05:50 +0000
treeherdermozilla-beta@95342d212a7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskeeler
bugs1403844
milestone59.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 1403844 - Verify COSE signature on add-ons, r=keeler Summary: MozReview-Commit-ID: 6YorBs4mY8B Check for COSE signatures in add-ons. Reviewers: keeler Bug #: 1403844 Differential Revision: https://phabricator.services.mozilla.com/D298
security/apps/AppSignatureVerification.cpp
security/apps/moz.build
security/manager/ssl/security-prefs.js
security/manager/ssl/tests/gtest/CoseTest.cpp
security/manager/ssl/tests/unit/sign_app.py
security/manager/ssl/tests/unit/test_signed_apps.js
security/manager/ssl/tests/unit/test_signed_apps/cose_int_signed_with_pkcs7.zip
security/manager/ssl/tests/unit/test_signed_apps/cose_multiple_signed.zip
security/manager/ssl/tests/unit/test_signed_apps/cose_multiple_signed_with_pkcs7.zip
security/manager/ssl/tests/unit/test_signed_apps/cose_signed.zip
security/manager/ssl/tests/unit/test_signed_apps/cose_signed_with_pkcs7.zip
security/manager/ssl/tests/unit/test_signed_apps/moz.build
security/manager/ssl/tests/unit/test_signed_apps/only_cose_multiple_signed.zip
security/manager/ssl/tests/unit/test_signed_apps/only_cose_signed.zip
third_party/rust/cose-c/.cargo-checksum.json
third_party/rust/cose-c/Cargo.toml
third_party/rust/cose-c/include/cosec.h
third_party/rust/cose-c/src/lib.rs
third_party/rust/cose/.cargo-checksum.json
third_party/rust/cose/.travis.yml
third_party/rust/cose/Cargo.toml
third_party/rust/cose/README.md
third_party/rust/cose/examples/sign_verify/main.rs
third_party/rust/cose/examples/sign_verify/nss.rs
third_party/rust/cose/examples/sign_verify/test_nss.rs
third_party/rust/cose/examples/sign_verify/test_setup.rs
third_party/rust/cose/examples/sign_verify/util_test.rs
third_party/rust/cose/src/cbor/decoder.rs
third_party/rust/cose/src/cbor/mod.rs
third_party/rust/cose/src/cbor/serializer.rs
third_party/rust/cose/src/cbor/test_decoder.rs
third_party/rust/cose/src/cbor/test_serializer.rs
third_party/rust/cose/src/cose.rs
third_party/rust/cose/src/decoder.rs
third_party/rust/cose/src/nss.rs
third_party/rust/cose/src/test_cose.rs
third_party/rust/cose/src/test_nss.rs
third_party/rust/cose/src/test_setup.rs
third_party/rust/cose/src/util.rs
third_party/rust/cose/src/util_test.rs
third_party/rust/moz_cbor/.cargo-checksum.json
third_party/rust/moz_cbor/.travis.yml
third_party/rust/moz_cbor/Cargo.toml
third_party/rust/moz_cbor/LICENSE
third_party/rust/moz_cbor/README.md
third_party/rust/moz_cbor/rustfmt.toml
third_party/rust/moz_cbor/src/decoder.rs
third_party/rust/moz_cbor/src/lib.rs
third_party/rust/moz_cbor/src/serializer.rs
third_party/rust/moz_cbor/src/test_decoder.rs
third_party/rust/moz_cbor/src/test_serializer.rs
toolkit/library/gtest/rust/Cargo.lock
toolkit/library/rust/Cargo.lock
toolkit/library/rust/shared/Cargo.toml
--- a/security/apps/AppSignatureVerification.cpp
+++ b/security/apps/AppSignatureVerification.cpp
@@ -8,16 +8,17 @@
 
 #include "AppTrustDomain.h"
 #include "CryptoTask.h"
 #include "NSSCertDBTrustDomain.h"
 #include "ScopedNSSTypes.h"
 #include "SharedCertVerifier.h"
 #include "certdb.h"
 #include "cms.h"
+#include "cosec.h"
 #include "mozilla/Base64.h"
 #include "mozilla/Casting.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
 #include "nsCOMPtr.h"
@@ -338,18 +339,20 @@ ReadLine(/*in/out*/ const char* & nextLi
     }
 
     ++nextLineStart; // skip space and keep appending
   }
 }
 
 // The header strings are defined in the JAR specification.
 #define JAR_MF_SEARCH_STRING "(M|/M)ETA-INF/(M|m)(ANIFEST|anifest).(MF|mf)$"
+#define JAR_COSE_MF_SEARCH_STRING "(M|/M)ETA-INF/cose.manifest$"
 #define JAR_SF_SEARCH_STRING "(M|/M)ETA-INF/*.(SF|sf)$"
 #define JAR_RSA_SEARCH_STRING "(M|/M)ETA-INF/*.(RSA|rsa)$"
+#define JAR_COSE_SEARCH_STRING "(M|/M)ETA-INF/cose.sig$"
 #define JAR_META_DIR "META-INF"
 #define JAR_MF_HEADER "Manifest-Version: 1.0"
 #define JAR_SF_HEADER "Signature-Version: 1.0"
 
 nsresult
 ParseAttribute(const nsAutoCString & curLine,
                /*out*/ nsAutoCString & attrName,
                /*out*/ nsAutoCString & attrValue)
@@ -835,27 +838,476 @@ VerifySignature(AppTrustedRoot trustedRo
     return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING;
   }
 
   return MapSECStatus(
     NSS_CMSSignerInfo_Verify(signerInfo, const_cast<SECItem*>(detachedDigest),
                              &pkcs7DataOid));
 }
 
+class CoseVerificationContext
+{
+public:
+  explicit CoseVerificationContext(AppTrustedRoot aTrustedRoot)
+    : mTrustedRoot(aTrustedRoot)
+    , mCertDER(nullptr)
+    , mCertDERLen(0)
+  {
+  }
+  ~CoseVerificationContext() {}
+
+  AppTrustedRoot GetTrustedRoot() { return mTrustedRoot; }
+  nsresult SetCert(SECItem* aCertDER)
+  {
+    mCertDERLen = aCertDER->len;
+    mCertDER = MakeUnique<uint8_t[]>(mCertDERLen);
+    if (!mCertDER) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    memcpy(mCertDER.get(), aCertDER->data, mCertDERLen);
+    return NS_OK;
+  }
+  uint8_t* GetCert() { return mCertDER.get(); }
+  unsigned int GetCertLen() { return mCertDERLen; }
+
+private:
+  AppTrustedRoot mTrustedRoot;
+  UniquePtr<uint8_t[]> mCertDER;
+  unsigned int mCertDERLen;
+};
+
+// Verification function called from cose-rust.
+// Returns true if everything goes well and the signature and certificate chain
+// are good, false in any other case.
+bool
+CoseVerificationCallback(const uint8_t* aPayload,
+                         size_t aPayloadLen,
+                         const uint8_t** aCertChain,
+                         size_t aCertChainLen,
+                         const size_t* aCertsLen,
+                         const uint8_t* aEECert,
+                         size_t aEECertLen,
+                         const uint8_t* aSignature,
+                         size_t aSignatureLen,
+                         uint8_t aSignatureAlgorithm,
+                         void* ctx)
+{
+  if (!ctx || !aPayload || !aEECert || !aSignature) {
+    return false;
+  }
+  // The ctx here is a pointer to a CoseVerificationContext object
+  CoseVerificationContext* context = static_cast<CoseVerificationContext*>(ctx);
+  AppTrustedRoot aTrustedRoot = context->GetTrustedRoot();
+
+  CK_MECHANISM_TYPE mechanism;
+  SECOidTag oid;
+  uint32_t hash_length;
+  SECItem param = { siBuffer, nullptr, 0 };
+  switch (aSignatureAlgorithm) {
+    case ES256:
+      mechanism = CKM_ECDSA;
+      oid = SEC_OID_SHA256;
+      hash_length = SHA256_LENGTH;
+      break;
+    case ES384:
+      mechanism = CKM_ECDSA;
+      oid = SEC_OID_SHA384;
+      hash_length = SHA384_LENGTH;
+      break;
+    case ES512:
+      mechanism = CKM_ECDSA;
+      oid = SEC_OID_SHA512;
+      hash_length = SHA512_LENGTH;
+      break;
+    default:
+      return false;
+  }
+
+  uint8_t hashBuf[HASH_LENGTH_MAX];
+  SECStatus rv = PK11_HashBuf(oid, hashBuf, aPayload, aPayloadLen);
+  if (rv != SECSuccess) {
+    return false;
+  }
+  SECItem hashItem = { siBuffer, hashBuf, hash_length };
+  CERTCertDBHandle* dbHandle = CERT_GetDefaultCertDB();
+  if (!dbHandle) {
+    return false;
+  }
+  SECItem derCert = { siBuffer,
+                      const_cast<uint8_t*>(aEECert),
+                      static_cast<unsigned int>(aEECertLen) };
+  UniqueCERTCertificate cert(
+    CERT_NewTempCertificate(dbHandle, &derCert, nullptr, false, true));
+  if (!cert) {
+    return false;
+  }
+  UniqueSECKEYPublicKey key(CERT_ExtractPublicKey(cert.get()));
+  if (!key) {
+    return false;
+  }
+  SECItem signatureItem = { siBuffer,
+                             const_cast<uint8_t*>(aSignature),
+                             static_cast<unsigned int>(aSignatureLen) };
+  rv = PK11_VerifyWithMechanism(
+    key.get(), mechanism, &param, &signatureItem, &hashItem, nullptr);
+  if (rv != SECSuccess) {
+    return false;
+  }
+
+  // Load intermediate certs into NSS so we can verify the cert chain.
+  UniqueCERTCertList tempCerts(CERT_NewCertList());
+  for (size_t i = 0; i < aCertChainLen; ++i) {
+    SECItem derCert = { siBuffer,
+                        const_cast<uint8_t*>(aCertChain[i]),
+                        static_cast<unsigned int>(aCertsLen[i]) };
+    UniqueCERTCertificate tempCert(
+      CERT_NewTempCertificate(dbHandle, &derCert, nullptr, false, true));
+    // Skip certs that we can't parse. If it was one we needed, the verification
+    // will fail later.
+    if (!tempCert) {
+      continue;
+    }
+    if (CERT_AddCertToListTail(tempCerts.get(), tempCert.get()) != SECSuccess) {
+      return false;
+    }
+    Unused << tempCert.release();
+  }
+
+  UniqueCERTCertList builtChain;
+  nsresult nrv = VerifyCertificate(cert.get(), aTrustedRoot, builtChain);
+  bool result = true;
+  if (NS_FAILED(nrv)) {
+    result = false;
+  }
+
+  // Passing back the signing certificate in form of the DER cert.
+  nrv = context->SetCert(&cert->derCert);
+  if (NS_FAILED(nrv)) {
+    result = false;
+  }
+
+  return result;
+}
+
+nsresult
+VerifyAppManifest(SECOidTag aDigestToUse, nsCOMPtr<nsIZipReader> aZip,
+                  nsTHashtable<nsCStringHashKey>& aIgnoredFiles,
+                  const SECItem& aManifestBuffer)
+{
+  // Allocate the I/O buffer only once per JAR, instead of once per entry, in
+  // order to minimize malloc/free calls and in order to avoid fragmenting
+  // memory.
+  ScopedAutoSECItem buf(128 * 1024);
+
+  nsTHashtable<nsCStringHashKey> items;
+
+  nsresult rv = ParseMF(BitwiseCast<char*, unsigned char*>(aManifestBuffer.data),
+    aZip, aDigestToUse, items, buf);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  // Verify every entry in the file.
+  nsCOMPtr<nsIUTF8StringEnumerator> entries;
+  rv = aZip->FindEntries(EmptyCString(), getter_AddRefs(entries));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  if (!entries) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  for (;;) {
+    bool hasMore;
+    rv = entries->HasMore(&hasMore);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (!hasMore) {
+      break;
+    }
+
+    nsAutoCString entryFilename;
+    rv = entries->GetNext(entryFilename);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    MOZ_LOG(gPIPNSSLog,
+            LogLevel::Debug,
+            ("Verifying digests for %s", entryFilename.get()));
+
+    if (entryFilename.Length() == 0) {
+      return NS_ERROR_SIGNED_JAR_ENTRY_INVALID;
+    }
+
+    // The files that comprise the signature mechanism are not covered by the
+    // signature. Ignore these files.
+    if (aIgnoredFiles.Contains(entryFilename)) {
+      continue;
+    }
+
+    // Entries with names that end in "/" are directory entries, which are not
+    // signed.
+    //
+    // Since bug 1415991 we don't support unpacked JARs. The "/" entries are
+    // therefore harmless.
+    if (entryFilename.Last() == '/') {
+      continue;
+    }
+
+    nsCStringHashKey* item = items.GetEntry(entryFilename);
+    if (!item) {
+      return NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY;
+    }
+
+    // Remove the item so we can check for leftover items later
+    items.RemoveEntry(item);
+  }
+
+  // We verified that every entry that we require to be signed is signed. But,
+  // were there any missing entries--that is, entries that are mentioned in the
+  // manifest but missing from the archive?
+  if (items.Count() != 0) {
+    return NS_ERROR_SIGNED_JAR_ENTRY_MISSING;
+  }
+
+  return NS_OK;
+}
+
 // This corresponds to the preference "security.signed_app_signatures.policy".
-enum class SignaturePolicy {
-  PKCS7WithSHA1OrSHA256 = 0,
-  PKCS7WithSHA256 = 1,
+// The lowest order bit determines which PKCS#7 algorithms are accepted.
+// xxx_0_: SHA-1 and/or SHA-256 PKCS#7 allowed
+// xxx_1_: SHA-256 PKCS#7 allowed
+// The next two bits determine whether COSE is required and PKCS#7 is allowed
+// x_00_x: COSE disabled, ignore files, PKCS#7 must verify
+// x_01_x: COSE is verified if present, PKCS#7 must verify
+// x_10_x: COSE is required, PKCS#7 must verify if present
+// x_11_x: COSE is required, PKCS#7 disabled (fail when present)
+class SignaturePolicy
+{
+public:
+  explicit SignaturePolicy(int32_t preference)
+    : mProcessCose(true)
+    , mCoseRequired(false)
+    , mProcessPK7(true)
+    , mPK7Required(true)
+    , mSHA1Allowed(true)
+    , mSHA256Allowed(true)
+  {
+    mCoseRequired = (preference & 0b100) != 0;
+    mProcessCose = (preference & 0b110) != 0;
+    mPK7Required = (preference & 0b100) == 0;
+    mProcessPK7 = (preference & 0b110) != 0b110;
+    if ((preference & 0b1) == 0) {
+      mSHA1Allowed = true;
+      mSHA256Allowed = true;
+    } else {
+      mSHA1Allowed = false;
+      mSHA256Allowed = true;
+    }
+  }
+  ~SignaturePolicy()
+  {
+  }
+  bool ProcessCOSE() { return mProcessCose; }
+  bool COSERequired() { return mCoseRequired; }
+  bool PK7Required() { return mPK7Required; }
+  bool ProcessPK7() { return mProcessPK7; }
+  bool IsPK7HashAllowed(SECOidTag aHashAlg)
+  {
+    if (aHashAlg == SEC_OID_SHA256 && mSHA256Allowed) {
+      return true;
+    }
+    if (aHashAlg == SEC_OID_SHA1 && mSHA1Allowed) {
+      return true;
+    }
+    return false;
+  }
+
+private:
+  bool mProcessCose;
+  bool mCoseRequired;
+  bool mProcessPK7;
+  bool mPK7Required;
+  bool mSHA1Allowed;
+  bool mSHA256Allowed;
 };
 
 nsresult
-OpenSignedAppFile(AppTrustedRoot aTrustedRoot, nsIFile* aJarFile,
+VerifyCOSESignature(AppTrustedRoot aTrustedRoot, nsIZipReader* aZip,
+                    SignaturePolicy& aPolicy,
+                    nsTHashtable<nsCStringHashKey>& aIgnoredFiles,
+                    /* out */ bool& aVerified,
+                    /* out */ UniqueSECItem* aCoseCertItem)
+{
+  NS_ENSURE_ARG_POINTER(aZip);
+  NS_ENSURE_ARG_POINTER(aCoseCertItem);
+  bool required = aPolicy.COSERequired();
+  aVerified = false;
+
+  // Read COSE signature file.
+  nsAutoCString coseFilename;
+  ScopedAutoSECItem coseBuffer;
+  nsresult rv = FindAndLoadOneEntry(
+    aZip, NS_LITERAL_CSTRING(JAR_COSE_SEARCH_STRING), coseFilename, coseBuffer);
+  if (NS_FAILED(rv)) {
+    return required ? NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE : NS_OK;
+  }
+
+  // Verify COSE signature.
+  nsAutoCString mfFilename;
+  ScopedAutoSECItem manifestBuffer;
+  rv = FindAndLoadOneEntry(aZip,
+                           NS_LITERAL_CSTRING(JAR_COSE_MF_SEARCH_STRING),
+                           mfFilename,
+                           manifestBuffer);
+  if (NS_FAILED(rv)) {
+    return required ? NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE : rv;
+  }
+  MOZ_ASSERT(manifestBuffer.len >= 1);
+  MOZ_ASSERT(coseBuffer.len >= 1);
+  CoseVerificationContext context(aTrustedRoot);
+  bool coseVerification = verify_cose_signature_ffi(manifestBuffer.data,
+                                                    manifestBuffer.len - 1,
+                                                    coseBuffer.data,
+                                                    coseBuffer.len - 1,
+                                                    &context,
+                                                    CoseVerificationCallback);
+  if (!coseVerification) {
+    return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
+  }
+  // CoseVerificationCallback sets the context certificate to the first cert
+  // it encounters.
+  const SECItem derCert = { siBuffer, context.GetCert(), context.GetCertLen() };
+  aCoseCertItem->reset(SECITEM_DupItem(&derCert));
+  if (!aCoseCertItem) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // aIgnoredFiles contains the PKCS#7 manifest and signature files iff the
+  // PKCS#7 verification was successful.
+  aIgnoredFiles.PutEntry(mfFilename);
+  aIgnoredFiles.PutEntry(coseFilename);
+  rv = VerifyAppManifest(SEC_OID_SHA256, aZip, aIgnoredFiles, manifestBuffer);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  aVerified = true;
+  return NS_OK;
+}
+
+nsresult
+VerifyPK7Signature(AppTrustedRoot aTrustedRoot, nsIZipReader* aZip,
+                   SignaturePolicy& aPolicy,
+                   /* out */ nsTHashtable<nsCStringHashKey>& aIgnoredFiles,
+                   /* out */ bool& aVerified,
+                   /* out */ UniqueCERTCertList& aBuiltChain)
+{
+  NS_ENSURE_ARG_POINTER(aZip);
+  bool required = aPolicy.PK7Required();
+  aVerified = false;
+
+  // Signature (RSA) file
+  nsAutoCString sigFilename;
+  ScopedAutoSECItem sigBuffer;
+  nsresult rv = FindAndLoadOneEntry(
+    aZip, nsLiteralCString(JAR_RSA_SEARCH_STRING), sigFilename, sigBuffer);
+  if (NS_FAILED(rv)) {
+    return required ? NS_ERROR_SIGNED_JAR_NOT_SIGNED : NS_OK;
+  }
+
+  // Signature (SF) file
+  nsAutoCString sfFilename;
+  ScopedAutoSECItem sfBuffer;
+  rv = FindAndLoadOneEntry(
+    aZip, NS_LITERAL_CSTRING(JAR_SF_SEARCH_STRING), sfFilename, sfBuffer);
+  if (NS_FAILED(rv)) {
+    return required ? NS_ERROR_SIGNED_JAR_MANIFEST_INVALID : NS_OK;
+  }
+
+  // Calculate both the SHA-1 and SHA-256 hashes of the signature file - we
+  // don't know what algorithm the PKCS#7 signature used.
+  Digest sfCalculatedSHA1Digest;
+  rv = sfCalculatedSHA1Digest.DigestBuf(
+    SEC_OID_SHA1, sfBuffer.data, sfBuffer.len - 1);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  Digest sfCalculatedSHA256Digest;
+  rv = sfCalculatedSHA256Digest.DigestBuf(
+    SEC_OID_SHA256, sfBuffer.data, sfBuffer.len - 1);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  // Verify PKCS#7 signature.
+  // If we get here, the signature has to verify even if PKCS#7 is not required.
+  sigBuffer.type = siBuffer;
+  SECOidTag digestToUse;
+  rv = VerifySignature(aTrustedRoot,
+                       sigBuffer,
+                       sfCalculatedSHA1Digest.get(),
+                       sfCalculatedSHA256Digest.get(),
+                       digestToUse,
+                       aBuiltChain);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  // Check the digest used for the signature against the policy.
+  if (!aPolicy.IsPK7HashAllowed(digestToUse)) {
+    return NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE;
+  }
+
+  nsAutoCString mfDigest;
+  rv = ParseSF(
+    BitwiseCast<char*, unsigned char*>(sfBuffer.data), digestToUse, mfDigest);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  // Read PK7 manifest (MF) file.
+  ScopedAutoSECItem manifestBuffer;
+  Digest mfCalculatedDigest;
+  nsAutoCString mfFilename;
+  rv = FindAndLoadOneEntry(aZip,
+                           NS_LITERAL_CSTRING(JAR_MF_SEARCH_STRING),
+                           mfFilename,
+                           manifestBuffer,
+                           digestToUse,
+                           &mfCalculatedDigest);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  nsDependentCSubstring calculatedDigest(
+    DigestToDependentString(mfCalculatedDigest));
+  if (!mfDigest.Equals(calculatedDigest)) {
+    return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
+  }
+
+  // Verify PKCS7 manifest file hashes.
+  aIgnoredFiles.PutEntry(sfFilename);
+  aIgnoredFiles.PutEntry(sigFilename);
+  aIgnoredFiles.PutEntry(mfFilename);
+  rv = VerifyAppManifest(digestToUse, aZip, aIgnoredFiles, manifestBuffer);
+  if (NS_FAILED(rv)) {
+    aIgnoredFiles.Clear();
+    return rv;
+  }
+
+  aVerified = true;
+  return NS_OK;
+}
+
+nsresult
+OpenSignedAppFile(AppTrustedRoot aTrustedRoot,
+                  nsIFile* aJarFile,
                   SignaturePolicy aPolicy,
-                  /*out, optional */ nsIZipReader** aZipReader,
-                  /*out, optional */ nsIX509Cert** aSignerCert)
+                  /* out, optional */ nsIZipReader** aZipReader,
+                  /* out, optional */ nsIX509Cert** aSignerCert)
 {
   NS_ENSURE_ARG_POINTER(aJarFile);
 
   if (aZipReader) {
     *aZipReader = nullptr;
   }
 
   if (aSignerCert) {
@@ -866,191 +1318,86 @@ OpenSignedAppFile(AppTrustedRoot aTruste
 
   static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
   nsCOMPtr<nsIZipReader> zip = do_CreateInstance(kZipReaderCID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = zip->Open(aJarFile);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Signature (RSA) file
-  nsAutoCString sigFilename;
-  ScopedAutoSECItem sigBuffer;
-  rv = FindAndLoadOneEntry(zip, nsLiteralCString(JAR_RSA_SEARCH_STRING),
-                           sigFilename, sigBuffer);
-  if (NS_FAILED(rv)) {
-    return NS_ERROR_SIGNED_JAR_NOT_SIGNED;
-  }
-
-  // Signature (SF) file
-  nsAutoCString sfFilename;
-  ScopedAutoSECItem sfBuffer;
-  rv = FindAndLoadOneEntry(zip, NS_LITERAL_CSTRING(JAR_SF_SEARCH_STRING),
-                           sfFilename, sfBuffer);
-  if (NS_FAILED(rv)) {
-    return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-  }
-
-  // Calculate both the SHA-1 and SHA-256 hashes of the signature file - we
-  // don't know what algorithm the PKCS#7 signature used.
-  Digest sfCalculatedSHA1Digest;
-  rv = sfCalculatedSHA1Digest.DigestBuf(SEC_OID_SHA1, sfBuffer.data,
-                                        sfBuffer.len - 1);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  Digest sfCalculatedSHA256Digest;
-  rv = sfCalculatedSHA256Digest.DigestBuf(SEC_OID_SHA256, sfBuffer.data,
-                                          sfBuffer.len - 1);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
+  bool pk7Verified = false;
+  bool coseVerified = false;
+  nsTHashtable<nsCStringHashKey> ignoredFiles;
+  UniqueCERTCertList pk7BuiltChain;
+  UniqueSECItem coseCertItem;
 
-  sigBuffer.type = siBuffer;
-  UniqueCERTCertList builtChain;
-  SECOidTag digestToUse;
-  rv = VerifySignature(aTrustedRoot, sigBuffer, sfCalculatedSHA1Digest.get(),
-                       sfCalculatedSHA256Digest.get(), digestToUse, builtChain);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  switch (aPolicy) {
-    case SignaturePolicy::PKCS7WithSHA256:
-      if (digestToUse != SEC_OID_SHA256) {
-        return NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE;
-      }
-      break;
-    case SignaturePolicy::PKCS7WithSHA1OrSHA256:
-      break;
-  }
-
-  nsAutoCString mfDigest;
-  rv = ParseSF(BitwiseCast<char*, unsigned char*>(sfBuffer.data), digestToUse,
-               mfDigest);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  // Manifest (MF) file
-  nsAutoCString mfFilename;
-  ScopedAutoSECItem manifestBuffer;
-  Digest mfCalculatedDigest;
-  rv = FindAndLoadOneEntry(zip, NS_LITERAL_CSTRING(JAR_MF_SEARCH_STRING),
-                           mfFilename, manifestBuffer, digestToUse,
-                           &mfCalculatedDigest);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  nsDependentCSubstring calculatedDigest(
-    DigestToDependentString(mfCalculatedDigest));
-  if (!mfDigest.Equals(calculatedDigest)) {
-    return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
+  // First we have to verify the PKCS#7 signature if there is one.
+  // This signature covers all files (except for the signature files itself),
+  // including the COSE signature files. Only when this verification is
+  // successful the respective files will be ignored in the subsequent COSE
+  // signature verification.
+  if (aPolicy.ProcessPK7()) {
+    rv = VerifyPK7Signature(
+      aTrustedRoot, zip, aPolicy, ignoredFiles, pk7Verified, pk7BuiltChain);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
   }
 
-  // Allocate the I/O buffer only once per JAR, instead of once per entry, in
-  // order to minimize malloc/free calls and in order to avoid fragmenting
-  // memory.
-  ScopedAutoSECItem buf(128 * 1024);
-
-  nsTHashtable<nsCStringHashKey> items;
-
-  rv = ParseMF(BitwiseCast<char*, unsigned char*>(manifestBuffer.data), zip,
-               digestToUse, items, buf);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  // Verify every entry in the file.
-  nsCOMPtr<nsIUTF8StringEnumerator> entries;
-  rv = zip->FindEntries(EmptyCString(), getter_AddRefs(entries));
-  if (NS_SUCCEEDED(rv) && !entries) {
-    rv = NS_ERROR_UNEXPECTED;
-  }
-  if (NS_FAILED(rv)) {
-    return rv;
+  if (aPolicy.ProcessCOSE()) {
+    rv = VerifyCOSESignature(
+      aTrustedRoot, zip, aPolicy, ignoredFiles, coseVerified, &coseCertItem);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
   }
 
-  for (;;) {
-    bool hasMore;
-    rv = entries->HasMore(&hasMore);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (!hasMore) {
-      break;
-    }
-
-    nsAutoCString entryFilename;
-    rv = entries->GetNext(entryFilename);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Verifying digests for %s",
-           entryFilename.get()));
-
-    // The files that comprise the signature mechanism are not covered by the
-    // signature.
-    //
-    // XXX: This is OK for a single signature, but doesn't work for
-    // multiple signatures, because the metadata for the other signatures
-    // is not signed either.
-    if (entryFilename == mfFilename ||
-        entryFilename == sfFilename ||
-        entryFilename == sigFilename) {
-      continue;
-    }
-
-    if (entryFilename.Length() == 0) {
-      return NS_ERROR_SIGNED_JAR_ENTRY_INVALID;
-    }
-
-    // Entries with names that end in "/" are directory entries, which are not
-    // signed.
-    //
-    // XXX: As long as we don't unpack the JAR into the filesystem, the "/"
-    // entries are harmless. But, it is not clear what the security
-    // implications of directory entries are if/when we were to unpackage the
-    // JAR into the filesystem.
-    if (entryFilename[entryFilename.Length() - 1] == '/') {
-      continue;
-    }
-
-    nsCStringHashKey * item = items.GetEntry(entryFilename);
-    if (!item) {
-      return NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY;
-    }
-
-    // Remove the item so we can check for leftover items later
-    items.RemoveEntry(item);
-  }
-
-  // We verified that every entry that we require to be signed is signed. But,
-  // were there any missing entries--that is, entries that are mentioned in the
-  // manifest but missing from the archive?
-  if (items.Count() != 0) {
-    return NS_ERROR_SIGNED_JAR_ENTRY_MISSING;
+  if ((aPolicy.PK7Required() && !pk7Verified) ||
+      (aPolicy.COSERequired() && !coseVerified)) {
+    return NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE;
   }
 
   // Return the reader to the caller if they want it
   if (aZipReader) {
     zip.forget(aZipReader);
   }
 
   // Return the signer's certificate to the reader if they want it.
   // XXX: We should return an nsIX509CertList with the whole validated chain.
   if (aSignerCert) {
-    CERTCertListNode* signerCertNode = CERT_LIST_HEAD(builtChain);
-    if (!signerCertNode || CERT_LIST_END(signerCertNode, builtChain) ||
-        !signerCertNode->cert) {
-      return NS_ERROR_FAILURE;
+    // The COSE certificate is authoritative.
+    if (aPolicy.COSERequired() || (coseCertItem && coseCertItem->len != 0)) {
+      if (!coseCertItem || coseCertItem->len == 0) {
+        return NS_ERROR_FAILURE;
+      }
+      CERTCertDBHandle* dbHandle = CERT_GetDefaultCertDB();
+      if (!dbHandle) {
+        return NS_ERROR_FAILURE;
+      }
+      UniqueCERTCertificate cert(CERT_NewTempCertificate(
+        dbHandle, coseCertItem.get(), nullptr, false, true));
+      if (!cert) {
+        return NS_ERROR_FAILURE;
+      }
+      nsCOMPtr<nsIX509Cert> signerCert = nsNSSCertificate::Create(cert.get());
+      if (!signerCert) {
+        return NS_ERROR_OUT_OF_MEMORY;
+      }
+      signerCert.forget(aSignerCert);
+    } else {
+      CERTCertListNode* signerCertNode = CERT_LIST_HEAD(pk7BuiltChain);
+      if (!signerCertNode || CERT_LIST_END(signerCertNode, pk7BuiltChain) ||
+          !signerCertNode->cert) {
+        return NS_ERROR_FAILURE;
+      }
+      nsCOMPtr<nsIX509Cert> signerCert =
+        nsNSSCertificate::Create(signerCertNode->cert);
+      NS_ENSURE_TRUE(signerCert, NS_ERROR_OUT_OF_MEMORY);
+      signerCert.forget(aSignerCert);
     }
-    nsCOMPtr<nsIX509Cert> signerCert =
-      nsNSSCertificate::Create(signerCertNode->cert);
-    NS_ENSURE_TRUE(signerCert, NS_ERROR_OUT_OF_MEMORY);
-    signerCert.forget(aSignerCert);
   }
 
   return NS_OK;
 }
 
 class OpenSignedAppFileTask final : public CryptoTask
 {
 public:
@@ -1085,44 +1432,34 @@ private:
   const AppTrustedRoot mTrustedRoot;
   const nsCOMPtr<nsIFile> mJarFile;
   const SignaturePolicy mPolicy;
   nsMainThreadPtrHandle<nsIOpenSignedAppFileCallback> mCallback;
   nsCOMPtr<nsIZipReader> mZipReader; // out
   nsCOMPtr<nsIX509Cert> mSignerCert; // out
 };
 
-static const SignaturePolicy sDefaultSignaturePolicy =
-  SignaturePolicy::PKCS7WithSHA1OrSHA256;
+static const int32_t sDefaultSignaturePolicy = 0b10;
 
 } // unnamed namespace
 
 NS_IMETHODIMP
 nsNSSCertificateDB::OpenSignedAppFileAsync(
   AppTrustedRoot aTrustedRoot, nsIFile* aJarFile,
   nsIOpenSignedAppFileCallback* aCallback)
 {
   NS_ENSURE_ARG_POINTER(aJarFile);
   NS_ENSURE_ARG_POINTER(aCallback);
   if (!NS_IsMainThread()) {
     return NS_ERROR_NOT_SAME_THREAD;
   }
-  SignaturePolicy policy =
-    static_cast<SignaturePolicy>(
-      Preferences::GetInt("security.signed_app_signatures.policy",
-                          static_cast<int32_t>(sDefaultSignaturePolicy)));
-  switch (policy) {
-    case SignaturePolicy::PKCS7WithSHA1OrSHA256:
-      break;
-    case SignaturePolicy::PKCS7WithSHA256:
-      break;
-    default:
-      policy = sDefaultSignaturePolicy;
-      break;
-  }
+  int32_t policyInt =
+    Preferences::GetInt("security.signed_app_signatures.policy",
+                        static_cast<int32_t>(sDefaultSignaturePolicy));
+  SignaturePolicy policy(policyInt);
   RefPtr<OpenSignedAppFileTask> task(new OpenSignedAppFileTask(aTrustedRoot,
                                                                aJarFile,
                                                                policy,
                                                                aCallback));
   return task->Dispatch("SignedJAR");
 }
 
 NS_IMETHODIMP
--- a/security/apps/moz.build
+++ b/security/apps/moz.build
@@ -13,16 +13,17 @@ UNIFIED_SOURCES += [
 ]
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '/security/certverifier',
     '/security/manager/ssl',
     '/security/pkix/include',
+    '/third_party/rust/cose-c/include',
 ]
 
 DEFINES['NSS_ENABLE_ECC'] = 'True'
 for var in ('DLL_PREFIX', 'DLL_SUFFIX'):
     DEFINES[var] = '"%s"' % CONFIG[var]
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CXXFLAGS += [
--- a/security/manager/ssl/security-prefs.js
+++ b/security/manager/ssl/security-prefs.js
@@ -63,20 +63,27 @@ pref("security.OCSP.timeoutMilliseconds.
 
 pref("security.pki.cert_short_lifetime_in_days", 10);
 // NB: Changes to this pref affect CERT_CHAIN_SHA1_POLICY_STATUS telemetry.
 // See the comment in CertVerifier.cpp.
 // 3 = only allow SHA-1 for certificates issued by an imported root.
 pref("security.pki.sha1_enforcement_level", 3);
 
 // This preference controls what signature algorithms are accepted for signed
-// apps (i.e. add-ons).
-// 0: SHA-1 and/or SHA-256 PKCS#7 allowed
-// 1: SHA-256 PKCS#7 allowed
-pref("security.signed_app_signatures.policy", 0);
+// apps (i.e. add-ons). The number is interpreted as a bit mask with the
+// following semantic:
+// The lowest order bit determines which PKCS#7 algorithms are accepted.
+// xxx_0_: SHA-1 and/or SHA-256 PKCS#7 allowed
+// xxx_1_: SHA-256 PKCS#7 allowed
+// The next two bits determine whether COSE is required and PKCS#7 is allowed
+// x_00_x: COSE disabled, ignore files, PKCS#7 must verify
+// x_01_x: COSE is verified if present, PKCS#7 must verify
+// x_10_x: COSE is required, PKCS#7 must verify if present
+// x_11_x: COSE is required, PKCS#7 disabled (fail when present)
+pref("security.signed_app_signatures.policy", 2);
 
 // security.pki.name_matching_mode controls how the platform matches hostnames
 // to name information in TLS certificates. The possible values are:
 // 0: always fall back to the subject common name if necessary (as in, if the
 //    subject alternative name extension is either not present or does not
 //    contain any DNS names or IP addresses)
 // 1: fall back to the subject common name for certificates valid before 23
 //    August 2016 if necessary
--- a/security/manager/ssl/tests/gtest/CoseTest.cpp
+++ b/security/manager/ssl/tests/gtest/CoseTest.cpp
@@ -103,22 +103,22 @@ const uint8_t SIGNATURE[] = {
   0xc4, 0x11, 0x9d, 0x07, 0x06, 0xe0, 0x0e, 0xed, 0xc8, 0xd1, 0x93, 0x90, 0xd7,
   0x99, 0x1b, 0x7b, 0x2d, 0x07, 0xa3, 0x04, 0xea, 0xa0, 0x4a, 0xa6, 0xc0, 0x30,
   0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48,
   0x00, 0x30, 0x45, 0x02, 0x20, 0x5c, 0x75, 0x51, 0x9f, 0x13, 0x11, 0x50, 0xcd,
   0x5d, 0x8a, 0xde, 0x20, 0xa3, 0xbc, 0x06, 0x30, 0x91, 0xff, 0xb2, 0x73, 0x75,
   0x5f, 0x31, 0x64, 0xec, 0xfd, 0xcb, 0x42, 0x80, 0x0a, 0x70, 0xe6, 0x02, 0x21,
   0x00, 0xff, 0x81, 0xbe, 0xa8, 0x0d, 0x03, 0x36, 0x6b, 0x75, 0xe2, 0x70, 0x6a,
   0xac, 0x07, 0x2e, 0x4c, 0xdc, 0xf9, 0xc5, 0x89, 0xc1, 0xcf, 0x88, 0xc2, 0xc8,
-  0x2a, 0x32, 0xf5, 0x42, 0x0c, 0xfa, 0x0b, 0xa0, 0x58, 0x40, 0xb7, 0x50, 0xae,
-  0x12, 0x41, 0xb2, 0x62, 0x28, 0x80, 0x0b, 0xaa, 0x99, 0xec, 0x5f, 0x1c, 0x91,
-  0x2f, 0xd8, 0x65, 0xd0, 0x1c, 0x38, 0x7c, 0x37, 0x63, 0x6d, 0xfa, 0x67, 0x9d,
-  0x21, 0xff, 0x54, 0x98, 0xf8, 0x97, 0x63, 0xc2, 0x2e, 0x3c, 0xfa, 0x25, 0x28,
-  0xec, 0x2c, 0x96, 0x8c, 0xca, 0xfc, 0x94, 0xd0, 0xc2, 0x19, 0x28, 0x28, 0x43,
-  0xe6, 0x64, 0xd4, 0x09, 0x2b, 0x0f, 0x01, 0xc3, 0x6e
+  0x2a, 0x32, 0xf5, 0x42, 0x0c, 0xfa, 0x0b, 0xa0, 0x58, 0x40, 0x1e, 0x6e, 0x08,
+  0xdf, 0x8f, 0x4f, 0xd6, 0xab, 0x23, 0xae, 0x84, 0xaa, 0xf3, 0x43, 0x35, 0x9a,
+  0x53, 0xb9, 0x8b, 0xf9, 0x81, 0xa1, 0xbc, 0x1e, 0x5c, 0x57, 0x5c, 0x0a, 0x20,
+  0x37, 0xf4, 0x3d, 0x11, 0x08, 0xa0, 0x97, 0x4b, 0x68, 0xa4, 0x0f, 0x80, 0xe9,
+  0x96, 0x30, 0x04, 0x24, 0x0e, 0x81, 0x3d, 0x2a, 0x8a, 0x64, 0x40, 0x61, 0x5a,
+  0x19, 0x00, 0xff, 0x74, 0x40, 0x71, 0x82, 0x65, 0xe9
 };
 
 // This is a COSE signature generated with the cose rust library (see
 // third-party/rust/cose). The payload is signed twice; with the P256 and the
 // RSA key from pykey.py.
 const uint8_t SIGNATURE_ES256_PS256[] = {
   0xd8, 0x62, 0x84, 0x59, 0x08, 0x52, 0xa1, 0x04, 0x84, 0x59, 0x01, 0x4e, 0x30,
   0x82, 0x01, 0x4a, 0x30, 0x81, 0xf1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14,
@@ -303,22 +303,22 @@ const uint8_t SIGNATURE_ES256_PS256[] = 
   0x11, 0x9d, 0x07, 0x06, 0xe0, 0x0e, 0xed, 0xc8, 0xd1, 0x93, 0x90, 0xd7, 0x99,
   0x1b, 0x7b, 0x2d, 0x07, 0xa3, 0x04, 0xea, 0xa0, 0x4a, 0xa6, 0xc0, 0x30, 0x0a,
   0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00,
   0x30, 0x45, 0x02, 0x20, 0x5c, 0x75, 0x51, 0x9f, 0x13, 0x11, 0x50, 0xcd, 0x5d,
   0x8a, 0xde, 0x20, 0xa3, 0xbc, 0x06, 0x30, 0x91, 0xff, 0xb2, 0x73, 0x75, 0x5f,
   0x31, 0x64, 0xec, 0xfd, 0xcb, 0x42, 0x80, 0x0a, 0x70, 0xe6, 0x02, 0x21, 0x00,
   0xff, 0x81, 0xbe, 0xa8, 0x0d, 0x03, 0x36, 0x6b, 0x75, 0xe2, 0x70, 0x6a, 0xac,
   0x07, 0x2e, 0x4c, 0xdc, 0xf9, 0xc5, 0x89, 0xc1, 0xcf, 0x88, 0xc2, 0xc8, 0x2a,
-  0x32, 0xf5, 0x42, 0x0c, 0xfa, 0x0b, 0xa0, 0x58, 0x40, 0xfa, 0xc6, 0xb7, 0xae,
-  0xec, 0x0b, 0x0b, 0xe2, 0xef, 0xae, 0xf7, 0x9d, 0x64, 0xe5, 0xaf, 0xbb, 0x2c,
-  0x4b, 0xe8, 0x7c, 0x61, 0xa9, 0x1e, 0xb9, 0x6d, 0x9c, 0xfa, 0xe3, 0x11, 0x77,
-  0xaf, 0x44, 0x9d, 0xc3, 0xa8, 0xa9, 0xbc, 0x58, 0xed, 0xc5, 0xe5, 0xa1, 0x92,
-  0x3b, 0x89, 0xa3, 0x3b, 0x1e, 0xbf, 0x6e, 0x33, 0x64, 0x21, 0x0b, 0x97, 0xee,
-  0xb7, 0xae, 0x84, 0x17, 0x5c, 0xff, 0x27, 0xa0, 0x83, 0x59, 0x02, 0xbb, 0xa2,
+  0x32, 0xf5, 0x42, 0x0c, 0xfa, 0x0b, 0xa0, 0x58, 0x40, 0xa3, 0xfb, 0x49, 0xe6,
+  0x45, 0x29, 0x64, 0x76, 0xeb, 0x9d, 0xbd, 0xf5, 0x38, 0x56, 0xbe, 0x6e, 0x31,
+  0x57, 0x73, 0xc1, 0x2d, 0x3e, 0xac, 0xee, 0xba, 0x55, 0x8e, 0x37, 0xd4, 0xea,
+  0x80, 0x25, 0x31, 0x99, 0x9f, 0x4a, 0xb0, 0xf9, 0xd8, 0xb0, 0xed, 0x74, 0xfc,
+  0x8c, 0x02, 0xf0, 0x9f, 0x95, 0xf1, 0xaa, 0x71, 0xcc, 0xd2, 0xe7, 0x1a, 0x6d,
+  0xd4, 0xed, 0xff, 0xf2, 0x78, 0x09, 0x83, 0x7e, 0x83, 0x59, 0x02, 0xbb, 0xa2,
   0x01, 0x38, 0x24, 0x04, 0x59, 0x02, 0xb3, 0x30, 0x82, 0x02, 0xaf, 0x30, 0x82,
   0x01, 0x99, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x07, 0x1c, 0x3b, 0x71,
   0x08, 0xbe, 0xd7, 0x9f, 0xfd, 0xaf, 0x26, 0xb6, 0x08, 0xa3, 0x99, 0x06, 0x77,
   0x69, 0x32, 0x7e, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
   0x01, 0x01, 0x0b, 0x30, 0x12, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04,
   0x03, 0x0c, 0x07, 0x69, 0x6e, 0x74, 0x2d, 0x72, 0x73, 0x61, 0x30, 0x22, 0x18,
   0x0f, 0x32, 0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30,
   0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32, 0x33, 0x31,
@@ -363,36 +363,36 @@ const uint8_t SIGNATURE_ES256_PS256[] = 
   0xd0, 0x67, 0xd2, 0x6b, 0x06, 0xfe, 0x60, 0x13, 0x42, 0x3d, 0xb7, 0xca, 0xcb,
   0xab, 0x7b, 0x5f, 0x5d, 0x01, 0x56, 0xd3, 0x99, 0x80, 0x0f, 0xde, 0x7f, 0x3a,
   0x61, 0x9c, 0xd3, 0x6b, 0x5e, 0xfe, 0xb5, 0xfc, 0x39, 0x8b, 0x8e, 0xf0, 0x8c,
   0x8b, 0x65, 0x46, 0x45, 0xff, 0x47, 0x8f, 0xd4, 0xdd, 0xae, 0xc9, 0x72, 0xc7,
   0x7f, 0x28, 0x86, 0xf1, 0xf7, 0x6e, 0xcb, 0x86, 0x03, 0xeb, 0x0c, 0x46, 0xe5,
   0xa0, 0x6b, 0xef, 0xd4, 0x5e, 0xa4, 0x0f, 0x53, 0xe1, 0xbc, 0xb4, 0xc9, 0x37,
   0x0e, 0x75, 0xdd, 0x93, 0xe8, 0x0f, 0x18, 0x0a, 0x02, 0x83, 0x17, 0x74, 0xbb,
   0x1a, 0x42, 0x5b, 0x63, 0x2c, 0x80, 0x80, 0xa6, 0x84, 0xa0, 0x59, 0x01, 0x00,
-  0x67, 0xbe, 0xe4, 0x81, 0xed, 0x1e, 0xce, 0x7d, 0x18, 0xf5, 0x85, 0xa2, 0xcb,
-  0x1d, 0x75, 0x6f, 0x8a, 0x34, 0xaa, 0x6b, 0x58, 0x91, 0xd2, 0xa4, 0x58, 0x4f,
-  0xe1, 0x8b, 0x6a, 0x36, 0xe1, 0x67, 0x23, 0x2c, 0x5d, 0x7e, 0x05, 0xe2, 0xa0,
-  0x18, 0xa8, 0x78, 0x7d, 0x85, 0xda, 0x07, 0x60, 0xc6, 0x8e, 0x44, 0x14, 0xad,
-  0xbc, 0x35, 0x2f, 0xf3, 0xd8, 0xda, 0x34, 0x65, 0x12, 0x45, 0x6a, 0xbe, 0x46,
-  0x53, 0x09, 0xc8, 0xcc, 0x96, 0x6b, 0x07, 0xd4, 0xc3, 0x4f, 0xd2, 0x7b, 0x88,
-  0xad, 0x10, 0x3b, 0x93, 0x3c, 0x9a, 0xc4, 0x1a, 0x98, 0x12, 0x2f, 0xf9, 0xc9,
-  0xb9, 0xd2, 0xda, 0x40, 0xe9, 0x9e, 0xd8, 0x74, 0x2f, 0x02, 0xf1, 0xf0, 0x9a,
-  0x31, 0x99, 0xb4, 0x82, 0xe1, 0x25, 0xee, 0x3f, 0xf9, 0xd5, 0xbb, 0x10, 0x8b,
-  0xff, 0x03, 0x0f, 0xcb, 0x96, 0x8f, 0x29, 0x51, 0x71, 0xfc, 0xe2, 0x0e, 0x9c,
-  0xf7, 0x3d, 0xc0, 0x95, 0xc6, 0x70, 0xfd, 0x8c, 0xb7, 0xf6, 0xa7, 0xfa, 0x7d,
-  0xd6, 0x44, 0x0b, 0xa3, 0xd3, 0x97, 0xf5, 0xcd, 0x6d, 0xc9, 0x17, 0xc6, 0xcb,
-  0xd5, 0x82, 0x01, 0x0e, 0xef, 0xb3, 0xbd, 0x33, 0x6e, 0x49, 0x57, 0xb1, 0x38,
-  0x57, 0x27, 0x91, 0x22, 0x5a, 0xeb, 0x02, 0x97, 0x53, 0xeb, 0x56, 0x01, 0xdc,
-  0xf9, 0xe9, 0x6c, 0x38, 0x7c, 0x0b, 0x1c, 0x7e, 0x19, 0xc7, 0x4b, 0x9d, 0x30,
-  0xad, 0x14, 0x2a, 0xb2, 0x07, 0x99, 0x80, 0x40, 0x42, 0x82, 0x49, 0x4e, 0xb5,
-  0x1a, 0x49, 0xa3, 0x31, 0x7f, 0xd9, 0x78, 0xd1, 0x08, 0x39, 0xaf, 0x0d, 0xeb,
-  0x8a, 0x93, 0x43, 0xab, 0x3d, 0x3f, 0x9b, 0xe3, 0x25, 0x3b, 0x09, 0xa9, 0x00,
-  0xfc, 0x98, 0xb9, 0xdc, 0x73, 0x91, 0x87, 0x58, 0x53, 0xd4, 0xc1, 0x8b, 0x05,
-  0xe6, 0x85, 0xc8, 0x48, 0xb8, 0x7e, 0x23, 0xcf, 0x12
+  0x51, 0xf4, 0xe6, 0x1c, 0x18, 0x7b, 0x28, 0xa0, 0x1f, 0x63, 0xbf, 0xa5, 0xbd,
+  0x89, 0x9f, 0xd9, 0x30, 0x46, 0x4b, 0x34, 0x9b, 0x9d, 0x0f, 0xb0, 0x33, 0x11,
+  0xf8, 0xaa, 0x84, 0x4e, 0xb2, 0xca, 0x29, 0x83, 0x54, 0x28, 0x99, 0x2a, 0x43,
+  0x7f, 0xe0, 0xe6, 0xd8, 0xdc, 0xd7, 0xf4, 0xb3, 0xd7, 0xf7, 0x39, 0xd5, 0xdc,
+  0xde, 0xdc, 0x23, 0x78, 0xd7, 0x90, 0xc0, 0x52, 0xf5, 0xd2, 0x14, 0x6f, 0xf9,
+  0x24, 0x48, 0xc8, 0x75, 0x4a, 0x9a, 0x4c, 0x61, 0x2f, 0x96, 0x4e, 0xc8, 0x02,
+  0x95, 0x72, 0xef, 0xbc, 0x91, 0xae, 0xf8, 0x23, 0xfb, 0xba, 0x9f, 0xfd, 0xe0,
+  0x1a, 0x8e, 0xa9, 0x03, 0x16, 0x76, 0xf4, 0xdb, 0x81, 0x5a, 0x69, 0xeb, 0xf5,
+  0x55, 0xd7, 0x68, 0x28, 0xe4, 0xce, 0xde, 0x1b, 0xb4, 0x90, 0xac, 0x97, 0x07,
+  0x15, 0xe0, 0xce, 0x5f, 0x3f, 0x89, 0xaf, 0xc1, 0xb8, 0x46, 0x5e, 0x87, 0xa1,
+  0x8d, 0xa7, 0x44, 0x09, 0x02, 0x4e, 0xbe, 0x6b, 0xfb, 0xab, 0xeb, 0x19, 0x62,
+  0x9e, 0xb0, 0xef, 0x0a, 0x6b, 0xcf, 0xe0, 0x00, 0xa9, 0x68, 0x2a, 0x8e, 0xfe,
+  0x8a, 0xb9, 0x57, 0x52, 0xb3, 0x08, 0x80, 0x5e, 0xa6, 0x88, 0x5f, 0x31, 0xd1,
+  0xe9, 0x6d, 0xf7, 0x54, 0x4e, 0xf8, 0x17, 0xb0, 0x1c, 0xca, 0xa6, 0xa6, 0x80,
+  0xf8, 0xd8, 0xf5, 0x94, 0xa4, 0xb2, 0xd0, 0x7e, 0xbb, 0x4f, 0xdb, 0x3a, 0x91,
+  0x5f, 0xb3, 0xc1, 0xfa, 0x60, 0xe4, 0xce, 0xe3, 0xe5, 0x14, 0x1f, 0x9c, 0x01,
+  0x60, 0xff, 0xe2, 0x09, 0xe6, 0x1a, 0x82, 0x69, 0xb6, 0xeb, 0x52, 0x1e, 0x3d,
+  0xc7, 0xfd, 0x69, 0x9d, 0x2a, 0xa5, 0xdb, 0xc1, 0x6a, 0x5a, 0x7d, 0x23, 0x2a,
+  0x00, 0xe4, 0x53, 0x16, 0x8e, 0xc1, 0x56, 0xf5, 0x5a, 0x8d, 0x59, 0x1f, 0x7f,
+  0xff, 0x77, 0x6f, 0x92, 0xea, 0x5d, 0x31, 0xe9, 0x18
 };
 
 // The RSA intermediate certificate that issued the EE cert used in the
 // signature above. The certificate was generated with pycert.py
 const uint8_t RSA_INT[] = {
   0x30, 0x82, 0x02, 0xd0, 0x30, 0x82, 0x01, 0xba, 0xa0, 0x03, 0x02, 0x01, 0x02,
   0x02, 0x14, 0x07, 0x10, 0xaf, 0xc4, 0x1a, 0x3a, 0x56, 0x4f, 0xd8, 0xc2, 0xcc,
   0x46, 0xd7, 0x5b, 0xdf, 0x1c, 0x4e, 0x2f, 0x49, 0x3a, 0x30, 0x0b, 0x06, 0x09,
@@ -625,17 +625,18 @@ verify_callback(const uint8_t* payload,
                 size_t payload_len,
                 const uint8_t** cert_chain,
                 size_t cert_chain_len,
                 const size_t* certs_len,
                 const uint8_t* ee_cert,
                 size_t ee_cert_len,
                 const uint8_t* signature,
                 size_t signature_len,
-                uint8_t signature_algorithm)
+                uint8_t signature_algorithm,
+                void* ctx)
 {
   UniquePK11SlotInfo slot(PK11_GetInternalSlot());
   if (!slot) {
     return false;
   }
 
   CK_MECHANISM_TYPE mechanism;
   SECOidTag oid;
@@ -698,41 +699,47 @@ verify_callback(const uint8_t* payload,
 class psm_COSE : public ::testing::Test
 {
 };
 
 TEST_F(psm_COSE, CoseTestingSingleSignature)
 {
   SECStatus rv = NSS_NoDB_Init(nullptr);
   ASSERT_EQ(SECSuccess, rv);
-  bool result = verify_cose_signature_ffi(
-    PAYLOAD, sizeof(PAYLOAD), SIGNATURE, sizeof(SIGNATURE), verify_callback);
+  bool result = verify_cose_signature_ffi(PAYLOAD,
+                                          sizeof(PAYLOAD),
+                                          SIGNATURE,
+                                          sizeof(SIGNATURE),
+                                          nullptr,
+                                          verify_callback);
   ASSERT_TRUE(result);
 }
 
 TEST_F(psm_COSE, CoseTestingTwoSignatures)
 {
   SECStatus rv = NSS_NoDB_Init(nullptr);
   ASSERT_EQ(SECSuccess, rv);
   bool result = verify_cose_signature_ffi(PAYLOAD,
                                           sizeof(PAYLOAD),
                                           SIGNATURE_ES256_PS256,
                                           sizeof(SIGNATURE_ES256_PS256),
+                                          nullptr,
                                           verify_callback);
   ASSERT_TRUE(result);
 }
 
 TEST_F(psm_COSE, CoseTestingAlteredPayload)
 {
   SECStatus rv = NSS_NoDB_Init(nullptr);
   ASSERT_EQ(SECSuccess, rv);
   uint8_t altered_payload[20] = { 84,  104, 105, 115, 32,  104, 115,
                                   32,  116, 104, 101, 32,  99,  111,
                                   110, 116, 101, 110, 116, 46 };
   bool result = verify_cose_signature_ffi(altered_payload,
                                           sizeof(altered_payload),
                                           SIGNATURE_ES256_PS256,
                                           sizeof(SIGNATURE_ES256_PS256),
+                                          nullptr,
                                           verify_callback);
   ASSERT_FALSE(result);
 }
 
 } // namespace mozilla
--- a/security/manager/ssl/tests/unit/sign_app.py
+++ b/security/manager/ssl/tests/unit/sign_app.py
@@ -116,16 +116,36 @@ def addManifestEntry(filename, hashes, c
     pairs to use, the contents of the file, and the current list
     of manifest entries."""
     entry = 'Name: %s\n' % filename
     for (hashFunc, name) in hashes:
         base64hash = b64encode(hashFunc(contents).digest())
         entry += '%s-Digest: %s\n' % (name, base64hash)
     entries.append(entry)
 
+def getCert(subject, keyName, issuerName, ee, issuerKey=""):
+    """Helper function to create an X509 cert from a specification.
+    Takes the subject, the subject key name to use, the issuer name,
+    a bool whether this is an EE cert or not, and optionally an issuer key
+    name."""
+    certSpecification = 'issuer:%s\n' % issuerName + \
+        'subject:' + subject + '\n' + \
+        'subjectKey:%s\n' % keyName
+    if ee:
+        certSpecification += 'extension:keyUsage:digitalSignature'
+    else:
+        certSpecification += 'extension:basicConstraints:cA,\n' + \
+            'extension:keyUsage:cRLSign,keyCertSign'
+    if issuerKey:
+        certSpecification += '\nissuerKey:%s' % issuerKey
+    certSpecificationStream = StringIO.StringIO()
+    print >>certSpecificationStream, certSpecification
+    certSpecificationStream.seek(0)
+    return pycert.Certificate(certSpecificationStream)
+
 def coseAlgorithmToSignatureParams(coseAlgorithm, issuerName):
     """Given a COSE algorithm ('ES256', 'ES384', 'ES512') and an issuer
     name, returns a (algorithm id, pykey.ECCKey, encoded certificate)
     triplet for use with coseSig.
     """
     if coseAlgorithm == 'ES256':
         keyName = 'secp256r1'
         algId = ES256
@@ -133,89 +153,87 @@ def coseAlgorithmToSignatureParams(coseA
         keyName = 'secp384r1'
         algId = ES384
     elif coseAlgorithm == 'ES512':
         keyName = 'secp521r1' # COSE uses the hash algorithm; this is the curve
         algId = ES512
     else:
         raise UnknownCOSEAlgorithmError(coseAlgorithm)
     key = pykey.ECCKey(keyName)
-    certSpecification = 'issuer:%s\n' % issuerName + \
-        'subject: xpcshell signed app test signer\n' + \
-        'subjectKey:%s\n' % keyName + \
-        'extension:keyUsage:digitalSignature'
-    certSpecificationStream = StringIO.StringIO()
-    print >>certSpecificationStream, certSpecification
-    certSpecificationStream.seek(0)
-    cert = pycert.Certificate(certSpecificationStream)
-    return (algId, key, cert.toDER())
+    # The subject must differ to avoid errors when importing into NSS later.
+    ee = getCert('xpcshell signed app test signer ' + keyName, keyName, issuerName, True, 'default')
+    return (algId, key, ee.toDER())
 
-def signZip(appDirectory, outputFile, issuerName, manifestHashes,
-            signatureHashes, pkcs7Hashes, doSign, coseAlgorithms):
+def signZip(appDirectory, outputFile, issuerName, rootName, manifestHashes,
+            signatureHashes, pkcs7Hashes, coseAlgorithms, emptySignerInfos):
     """Given a directory containing the files to package up,
     an output filename to write to, the name of the issuer of
-    the signing certificate, a list of hash algorithms to use in
-    the manifest file, a similar list for the signature file,
-    a similar list for the pkcs#7 signature, whether or not to
-    actually sign the resulting package, and a list of COSE
-    signature algorithms to include, packages up the files in the
-    directory and creates the output as appropriate."""
+    the signing certificate, the name of trust anchor, a list of hash algorithms
+    to use in the manifest file, a similar list for the signature file,
+    a similar list for the pkcs#7 signature, a list of COSE signature algorithms
+    to include, and whether the pkcs#7 signer info should be kept empty,
+    packages up the files in the directory and creates the output
+    as appropriate."""
     # This ensures each manifest file starts with the magic string and
     # then a blank line.
     mfEntries = ['Manifest-Version: 1.0', '']
 
     with zipfile.ZipFile(outputFile, 'w') as outZip:
         for (fullPath, internalPath) in walkDirectory(appDirectory):
             with open(fullPath) as inputFile:
                 contents = inputFile.read()
             outZip.writestr(internalPath, contents)
 
             # Add the entry to the manifest we're building
             addManifestEntry(internalPath, manifestHashes, contents, mfEntries)
 
-        # Just exit early if we're not actually signing.
-        if not doSign:
-            return
-
         if len(coseAlgorithms) > 0:
             coseManifest = '\n'.join(mfEntries)
             outZip.writestr('META-INF/cose.manifest', coseManifest)
             addManifestEntry('META-INF/cose.manifest', manifestHashes,
                              coseManifest, mfEntries)
+            intermediates = []
+            coseIssuerName = issuerName
+            if rootName:
+                coseIssuerName = 'xpcshell signed app test issuer'
+                intermediate = getCert(coseIssuerName, 'default', rootName, False)
+                intermediate = intermediate.toDER()
+                intermediates.append(intermediate)
             signatures = map(lambda coseAlgorithm:
-                coseAlgorithmToSignatureParams(coseAlgorithm, issuerName),
+                coseAlgorithmToSignatureParams(coseAlgorithm, coseIssuerName),
                 coseAlgorithms)
-            coseSignatureBytes = coseSig(coseManifest, [], signatures)
+            coseSignatureBytes = coseSig(coseManifest, intermediates, signatures)
             outZip.writestr('META-INF/cose.sig', coseSignatureBytes)
             addManifestEntry('META-INF/cose.sig', manifestHashes,
                              coseSignatureBytes, mfEntries)
 
-        mfContents = '\n'.join(mfEntries)
-        sfContents = 'Signature-Version: 1.0\n'
-        for (hashFunc, name) in signatureHashes:
-            base64hash = b64encode(hashFunc(mfContents).digest())
-            sfContents += '%s-Digest-Manifest: %s\n' % (name, base64hash)
+        if len(pkcs7Hashes) != 0 or emptySignerInfos:
+            mfContents = '\n'.join(mfEntries)
+            sfContents = 'Signature-Version: 1.0\n'
+            for (hashFunc, name) in signatureHashes:
+                base64hash = b64encode(hashFunc(mfContents).digest())
+                sfContents += '%s-Digest-Manifest: %s\n' % (name, base64hash)
 
-        cmsSpecification = ''
-        for name in pkcs7Hashes:
-            hashFunc, _ = hashNameToFunctionAndIdentifier(name)
-            cmsSpecification += '%s:%s\n' % (name,
-                                             hashFunc(sfContents).hexdigest())
-        cmsSpecification += 'signer:\n' + \
-            'issuer:%s\n' % issuerName + \
-            'subject:xpcshell signed app test signer\n' + \
-            'extension:keyUsage:digitalSignature'
-        cmsSpecificationStream = StringIO.StringIO()
-        print >>cmsSpecificationStream, cmsSpecification
-        cmsSpecificationStream.seek(0)
-        cms = pycms.CMS(cmsSpecificationStream)
-        p7 = cms.toDER()
-        outZip.writestr('META-INF/A.RSA', p7)
-        outZip.writestr('META-INF/A.SF', sfContents)
-        outZip.writestr('META-INF/MANIFEST.MF', mfContents)
+            cmsSpecification = ''
+            for name in pkcs7Hashes:
+                hashFunc, _ = hashNameToFunctionAndIdentifier(name)
+                cmsSpecification += '%s:%s\n' % (name,
+                                                 hashFunc(sfContents).hexdigest())
+            cmsSpecification += 'signer:\n' + \
+                'issuer:%s\n' % issuerName + \
+                'subject:xpcshell signed app test signer\n' + \
+                'extension:keyUsage:digitalSignature'
+            cmsSpecificationStream = StringIO.StringIO()
+            print >>cmsSpecificationStream, cmsSpecification
+            cmsSpecificationStream.seek(0)
+            cms = pycms.CMS(cmsSpecificationStream)
+            p7 = cms.toDER()
+            outZip.writestr('META-INF/A.RSA', p7)
+            outZip.writestr('META-INF/A.SF', sfContents)
+            outZip.writestr('META-INF/MANIFEST.MF', mfContents)
 
 class Error(Exception):
     """Base class for exceptions in this module."""
     pass
 
 
 class UnknownHashAlgorithmError(Error):
     """Helper exception type to handle unknown hash algorithms."""
@@ -247,20 +265,20 @@ def hashNameToFunctionAndIdentifier(name
     raise UnknownHashAlgorithmError(name)
 
 def main(outputFile, appPath, *args):
     """Main entrypoint. Given an already-opened file-like
     object, a path to the app directory to sign, and some
     optional arguments, signs the contents of the directory and
     writes the resulting package to the 'file'."""
     parser = argparse.ArgumentParser(description='Sign an app.')
-    parser.add_argument('-n', '--no-sign', action='store_true',
-                        help='Don\'t actually sign - only create zip')
     parser.add_argument('-i', '--issuer', action='store', help='Issuer name',
                         default='xpcshell signed apps test root')
+    parser.add_argument('-r', '--root', action='store', help='Root name',
+                        default='')
     parser.add_argument('-m', '--manifest-hash', action='append',
                         help='Hash algorithms to use in manifest',
                         default=[])
     parser.add_argument('-s', '--signature-hash', action='append',
                         help='Hash algorithms to use in signature file',
                         default=[])
     parser.add_argument('-c', '--cose-sign', action='append',
                         help='Append a COSE signature with the given ' +
@@ -272,14 +290,12 @@ def main(outputFile, appPath, *args):
                        default=[])
     group.add_argument('-e', '--empty-signerInfos', action='store_true',
                        help='Emit pkcs#7 SignedData with empty signerInfos')
     parsed = parser.parse_args(args)
     if len(parsed.manifest_hash) == 0:
         parsed.manifest_hash.append('sha256')
     if len(parsed.signature_hash) == 0:
         parsed.signature_hash.append('sha256')
-    if len(parsed.pkcs7_hash) == 0 and not parsed.empty_signerInfos:
-        parsed.pkcs7_hash.append('sha256')
-    signZip(appPath, outputFile, parsed.issuer,
+    signZip(appPath, outputFile, parsed.issuer, parsed.root,
             map(hashNameToFunctionAndIdentifier, parsed.manifest_hash),
             map(hashNameToFunctionAndIdentifier, parsed.signature_hash),
-            parsed.pkcs7_hash, not parsed.no_sign, parsed.cose_sign)
+            parsed.pkcs7_hash, parsed.cose_sign, parsed.empty_signerInfos)
--- a/security/manager/ssl/tests/unit/test_signed_apps.js
+++ b/security/manager/ssl/tests/unit/test_signed_apps.js
@@ -185,18 +185,24 @@ var hashTestcases = [
     expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID },
   { name: "app_mf-256_sf-1_p7-1",
     expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID },
   { name: "app_mf-256_sf-256_p7-1",
     expectedResult: Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID },
 ];
 
 // Policy values for the preference "security.signed_app_signatures.policy"
-const PKCS7WithSHA1OrSHA256 = 0;
-const PKCS7WithSHA256 = 1;
+const PKCS7WithSHA1OrSHA256 = 0b0;
+const PKCS7WithSHA256 = 0b1;
+const COSEAndPKCS7WithSHA1OrSHA256 = 0b10;
+const COSEAndPKCS7WithSHA256 = 0b11;
+const COSERequiredAndPKCS7WithSHA1OrSHA256 = 0b100;
+const COSERequiredAndPKCS7WithSHA256 = 0b101;
+const COSEOnly = 0b110;
+const COSEOnlyAgain = 0b111;
 
 function add_signature_test(policy, test) {
   // First queue up a test to set the desired policy:
   add_test(function () {
     Services.prefs.setIntPref("security.signed_app_signatures.policy", policy);
     run_next_test();
   });
   // Then queue up the test itself:
@@ -228,16 +234,106 @@ add_signature_test(PKCS7WithSHA1OrSHA256
 
 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
   certdb.openSignedAppFileAsync(
     Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("unknown_issuer_app"),
     check_open_result("unknown_issuer",
                       getXPCOMStatusFromNSS(SEC_ERROR_UNKNOWN_ISSUER)));
 });
 
+add_signature_test(COSEAndPKCS7WithSHA1OrSHA256, function () {
+  certdb.openSignedAppFileAsync(
+    Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("cose_signed_with_pkcs7"),
+    check_open_result("cose_signed_with_pkcs7", Cr.NS_OK));
+});
+
+add_signature_test(COSEAndPKCS7WithSHA256, function () {
+  certdb.openSignedAppFileAsync(
+    Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("app_mf-256_sf-256_p7-256"),
+    check_open_result("no COSE but correct PK#7", Cr.NS_OK));
+});
+
+add_signature_test(COSEAndPKCS7WithSHA256, function () {
+  certdb.openSignedAppFileAsync(
+    Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("app_mf-1_sf-256_p7-256"),
+    check_open_result("no COSE and wrong PK#7 hash", Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID));
+});
+
+add_signature_test(COSERequiredAndPKCS7WithSHA1OrSHA256, function () {
+  certdb.openSignedAppFileAsync(
+    Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("app_mf-256_sf-256_p7-256"),
+    check_open_result("COSE signature missing (SHA1 or 256)", Cr.NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE));
+});
+
+add_signature_test(COSERequiredAndPKCS7WithSHA256, function () {
+  certdb.openSignedAppFileAsync(
+    Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("app_mf-256_sf-256_p7-256"),
+    check_open_result("COSE signature missing (SHA256)", Cr.NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE));
+});
+
+add_signature_test(COSERequiredAndPKCS7WithSHA256, function () {
+  certdb.openSignedAppFileAsync(
+    Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("only_cose_signed"),
+    check_open_result("COSE signature only (PK#7 allowed, not present)", Cr.NS_OK));
+});
+
+add_signature_test(COSERequiredAndPKCS7WithSHA1OrSHA256, function () {
+  certdb.openSignedAppFileAsync(
+    Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("only_cose_signed"),
+    check_open_result("COSE signature only (PK#7 allowed, not present)", Cr.NS_OK));
+});
+
+add_signature_test(COSEAndPKCS7WithSHA1OrSHA256, function () {
+  certdb.openSignedAppFileAsync(
+    Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("cose_multiple_signed_with_pkcs7"),
+    check_open_result("cose_multiple_signed_with_pkcs7", Cr.NS_OK));
+});
+
+add_signature_test(COSEAndPKCS7WithSHA1OrSHA256, function () {
+  certdb.openSignedAppFileAsync(
+    Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("cose_int_signed_with_pkcs7"),
+    check_open_result("COSE signed with an intermediate", Cr.NS_OK));
+});
+
+add_signature_test(COSEAndPKCS7WithSHA1OrSHA256, function () {
+  certdb.openSignedAppFileAsync(
+    Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("only_cose_signed"),
+    check_open_result("PK7 signature missing", Cr.NS_ERROR_SIGNED_JAR_NOT_SIGNED));
+});
+
+add_signature_test(COSEOnly, function () {
+  certdb.openSignedAppFileAsync(
+    Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("cose_multiple_signed_with_pkcs7"),
+    check_open_result("Expected only COSE signature", Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY));
+});
+
+add_signature_test(COSEOnly, function () {
+  certdb.openSignedAppFileAsync(
+    Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("only_cose_multiple_signed"),
+    check_open_result("only Multiple COSE signatures", Cr.NS_OK));
+});
+
+add_signature_test(COSEOnly, function () {
+  certdb.openSignedAppFileAsync(
+    Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("only_cose_signed"),
+    check_open_result("only_cose_signed", Cr.NS_OK));
+});
+
+add_signature_test(COSEOnlyAgain, function () {
+  certdb.openSignedAppFileAsync(
+    Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("only_cose_signed"),
+    check_open_result("only_cose_signed (again)", Cr.NS_OK));
+});
+
+add_signature_test(COSEOnly, function () {
+  certdb.openSignedAppFileAsync(
+    Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("cose_signed_with_pkcs7"),
+    check_open_result("COSE only expected but also PK#7 signed", Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY));
+});
+
 // Sanity check to ensure a no-op tampering gives a valid result
 add_signature_test(PKCS7WithSHA1OrSHA256, function () {
   let tampered = tampered_app_path("identity_tampering");
   tamper(original_app_path("app_mf-1_sf-1_p7-1"), tampered, { }, []);
   certdb.openSignedAppFileAsync(
     Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("app_mf-1_sf-1_p7-1"),
     check_open_result("identity_tampering", Cr.NS_OK));
 });
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..da5a487b168a537b8d681bfd7a943dcfa2cbf884
GIT binary patch
literal 5002
zc%1E6X;c%*7EUK2NLZqvpb#-4C_CLDAgdTiVjw1jogk<I0)&JRlCa6J7+erg5oT~0
zP*KMX5dl#Yoxxq)MsY<DMMl(zvgoL|0k4B1lF@UVfA5_$oxZ25ZuR}Dy6S#6b&JhF
zp(i60mt2;^&<{1OWx-{IXu=Z574f5ZQkiwEG+va3B@m28HA|9s5-C4kWaLC3S}Gbu
z+&CUwG4h8S3DguBPc+gz(l++45oirsLq^ziEPGtXuj!Db1zc7L1{Pl`nZl&{$MB^D
z_?E@+2ofGQGLA=xikFO3Wr}Wiqup35!IjD#RdtaFghI4nT_jh=wc*Ecqj}b1QS=%%
zYk?+KAFKFCPdddHeikcaf}&>^AfXe10NOn%WdD@1o<C~T5a7hq)oq#oxuOkZCv08Z
z)>}B-KfmnX`~UXNH(V+<TJ}3$=a|A@JgF>7mHSfpcn|7U|9J-rKp+&N3+rHKBwKm1
zXf_e?Ql9lF3z(mtR)HTq+=&2LgIFvJ=7JMp9C@&QbTZM--ipGHhE+}kcYl$G*dMYZ
zv55A*A#o1jF_9FKZBTF|D2ufVkG7AGVnU9rg`S`{)pZo`BPo=T!a1POF(qMv7so@K
zz~Om;4EqEUB`ClrArXvYxzm^=I*At-6U+CC{){x956XyCcC3IElAOwQ47LzU5*G?n
z7Ff{89t)Efc#s@|14w?3@gd%1P#75K<ElhF=XrG9QWXS3A(Q?#ZBl-8OZW;7N@FW}
zIR}LS<tQX52fE8qNC1hPJVP|CcnN)0r0b?14%Bbl6BhjztOPYNYUZoxs|GXyKwSj^
znn80w6AUT<jnXho5l2X4ctRloh86K530$#Q`Y|p@;^SqY(Nr7}gzO-Q=m3sfAtMS0
zkO<m+Qh?@=DLDHh+>EcleMI9+rHMQVJW!)AM+2xJP;vl=fc03U8~_jvIX=57>vV6C
z2StZ+F!mE&U3BhrKeY3zd-f_ONNAjP;+)Cuj+Pm})s$gMMf$5=2s-zNBno096DBO%
z5weTAdH{dZxD1(b+2eyD|EdGQtY|Ocl;^{?BMVOogjzjQ<hbV<`}q1b*O5+n=H%X8
z;trhV+QBGwi)!P-U(=7|a8nCvf(l%(IiKk`OrNoP?)4mxzB#%r0rgQK6&c6^8>h61
zSs3F>c;Uu<#oR^poyFS66QS)I8`|qG41Cx(-Q>Dj-w{2nT`><1q}dq7^Z%^N{fRrh
zclIrlO?x*?VA)^98>1~7b@Obxp06*_gAN}U@|^Wf;&U3hiK=X!inZ%mi-f5HY@ZGq
zfEw_OPS-)JfG7YM2Gtcc92yNTGDc}RQHpt6Q8GPn^_IRH!+MKvymh{vwfa4|ZvR16
z(r){cXAGKN_rIF6x*z8RElsjCyjWPf%QK{Yb3^@kd3(0=4G)bd*TUoPA|LkR)f3ni
z^WWWTjfk~D<hE98JW5Y~@dh+*pP9@yw!GgmAf&nn)w@7{ZDCe!W<!X8Uo<R`5x44A
z%(zO{-|{~1!v<u18!mEPV^z5SX1$_3dhX4PYjYVzRk!cl&DK`$FYS_ARGBoKeb?!m
zsGZewNo$J_{Zif)!=4ZUcjqQ|!}gop8!q>T8xQ|*u5ZfBn{N!O<8T$v&tqD4ii2)n
z*IA|gn;QQ8OhePqlk>JT|JYYZuc-6LPPaJUrT(J)_3~^E(rp_s8_hvFfN~@Wb}9TP
zPN?Vjw+<U)ZdDgJXRTD3dFdIVs!^E}|HO&EhZH1;2!bE+%)W^?QkM{<ya+KIIwTOt
z0d+8{@UZ@Hh1Yq)NC5??qTCT^@5ZA?xgBrb*6hS`Dp#XBpQ)(3&vO~DE_Ac>PGwL-
z&H2}CsY3hHlQyYhI<$J4nu`i<ml&j3scuJimwW9zz8wc@e&I!`Szq&_U5A+3>2Z&a
z)Cvryy0g1Vs_A*eBjzWIny0bcMRH+l-OGD_hFe01!=_O2LwyIMG!`9%_K>`3J40d&
zU6u%JuNeQ_&nSH^xvDewE=|Y+p1K{}dOE)IUB*#C{_7iRIVZHpy0$^h>^tSJPe16*
ztt(p975;-2dkv<m-jNxEKUr98+dJ5HcGomNU$;4|d6s5dOjb_4sH@4TD(_M0x!pGq
z(bahWY^h#~C}OUERndb*sk2O6p4O*?IzD@)@p!92Eh+L4iSa8v2?EnHXOZ6)?mwzq
z-je%f4sM%)zFT9@gK6GRHFS4(Z*1sk^~z?vII_(;yZ=!-e&v-av4LGjPI>VB&_tgt
zI+NI!!*cHtwjaZQ8-{D8iA$i!XM-2rv#{bvq)gfRcGG;P3lKNJ7Qb=0B7;(sXA@Sv
zQKN(^p@*c7kL0axsfJI{2!ukkzKrB#YhOPyC`Uj3ya=kuayhyMR^31X0HhA8VN@)%
zP)L2)H`T{p0?OscH?VuZgx&k@C-)|2{Vvn5iD6T~qHA?0s$$Kjiyi(KLjFhZ{x{@*
zSIGY!dU^`;Ss^>kel=ZFNXcwlaAtPcl<c3+);X=g`IP-7$$YBYv`nYy>iwbn>BlAl
z_n=oig6muc*Fw~B*VE9*L;9f9%wMmx`CjEbY-B`LcTi{)Ver<RtDOT)!|RhW=Nt|&
z(Qgx$oxkOy_S4>XYnukAI3_=;I%XD^F|ZJ2e8jzaPw<<!=7Z6)b)2CY;k3bJy{=uY
z`z#~6AMmSBF%5Ex=T{DITf8@^vz*?zzuhs~DY5pT;7Q4yq1;#8CVXs*SUZ8anRveR
z5OnTR{xt3+H?Q(NEh<@^^b-`kUY6ayeGUHC%4+<>4*n?X*>Pcc1!^(Asdm!@X`?~9
z&t==}S{@ma1NE@m9DoS|lK+8Af14spSJ43;3XO!FvYY`<{XFGrDCkSlfi`0;Xvhdn
zz^@auZ_XEZx)k3TVm?V;<U4GU^E^Oi<_wsSfz4-+enD9PK+6Hd$~&DTtEc*zXEd#s
zpP5H7@84l@<6^JCRx7;T+3Gd*P2S=#+;eG(sqg-uitn}Iyw_{a$~^VD|4C0mi1DQ0
zMANN_!>VZ)(8S|1LBW{@hWtU9@8!zVhB51gro~&;yp_M~VNWbvd2UAGfxTH}-NEbE
z+pd3NsACTpyv!+Dv<GvuKcYF-3p(AI;j#N%tMkpa`*KfW6%a_Hp6g4yUJzH<d^j8a
z)8(&>x|Kd;b})GH+*rp<KZ7f$K17)k4YN8nNv{5)_x!g%C7EkDFZ2C2t?*$syvvCZ
zY^zS6v?13NVe>H1F?k(>me3rTUOG7Mv4cteD$aXiPQ@;HY;42*C+XwEBE5-d7Ydg{
zKV`^YghfA^AH0NIS)znDJ|7sjy|x<78Jq|XG9Q75zkP&bh))pP#?G4&6_^~C7(<d!
zneN_^VzxlWbo5x}z!W)>l=s=MwwA1}g;NuSO#X5hOft)pM)mWzX43vmPDT;Gp1dg|
zdpi&rQJf?SO)3<`dU(iK0tpyTVsgZ^=-_3sF%n{UGCwuN!685t@eO2{!pfl09Gk$1
zIL~mJFe!>1on*nV@QR?*{Hc6<Ur97W$`LUc)Iees1(GH!))+ueMt%D@X7tJe5Xy%$
z%BIQ(Dr2UppO06RZIn+<#%!AYc7~#CtDG;7*<w-O%AS=ml#|CX3^MvFsid;G@{VQ9
uTpg>te^ItoruCSu5l)HZ%BIRx95da6`#Le%43&{3nE?MD!&YlYKK8$n7cBJv
rename from security/manager/ssl/tests/unit/test_signed_apps/cose_multiple_signed.zip
rename to security/manager/ssl/tests/unit/test_signed_apps/cose_multiple_signed_with_pkcs7.zip
index 33a7740e46c3d7d398e64cd2590c1998c485ace1..56111b5ce5e0f38ffab0098bc0c5a186f4350126
GIT binary patch
literal 4929
zc%1E6X;c%*7EUK2K#)x~MUWUlcIbqFfTD&ZKv=>SmLRAB0trhJl7K7&LU0suL=;5@
z)ZhlFARvl3xTE5N<Dde9A~K2&ih_=^IKXRgK{9&YydUqJ_s*H_zNf2i_5G^4>-*}|
zEiX3&QXMvNh(%d$+QCNEG^jjbijc)Jxts`=P-GD$<Z)Bb7!3BaXJrCQAms44SbGfK
zY@&k8jAcO&SUOaRp(Kh}+{x<6x~X@upap1w!=h8sUeg+W?}9Tkg~}6#g3O0PBzsWk
zY>p5ET_QFMBVaMZV_BF8o?!A(G|>#}b2AoFaD`$!Sxq<$HepJTFPtf2T5@8Ukt_>7
zH*$j)%~=txjh^^Ostef%y5~=r+(gTZfw*oM40uQ-6X}UXeYdLQVW3JwWyhM|f0+qn
z#ucyVc(rxBe_7E#*Z=MH)7({jZ1PzhwfYIZP$@KWh2tvmbO!Y*>^z77V6X|(gnSSg
ziRM(AlVuoB$g=pX0*_C3bN`PFx5wZtKs1^LX~7;dO+08{7b4!;#+=NFgk1I*M>?0p
zr{k;%G`x*ZP^@hzJDg0g3J44bMN!tFkv6;t51bv%oeFwV96ken6ooWWC<BbKON?`N
zWsvxB43;bCW)nvs2l#o%#e=alM<)-03xO5Oj^emRenFb92Wdo#S5!1DXmt|PF3^-O
zh<A@kbT)M&lH6B2lL)qfegt1TUXUjdjPdvPc90U@kH)D49~nr$kg5LVw+T6sZJ}#P
z#mIEYdvPWMzGNS;0Lg$a1jTSGPz=nGAm9KTu5LN5n%sNENQ;x-P`oVP@^~S#*d0_v
z$(yWmSvRN%017fN&=_Y38lVt<NW_e}iTp4jn-vp-f$+Jka14{r7k-=|1U#My#LiO2
zgE(s(4sQ!i9zl~1TM!Rge{z5X93BKe!Wn-9?jzddvj8Jxh4G=^CBT6UPz@yu_3D-b
z96-rU77&0e!V!k_Jood@%&wu~szYeT(e=pgmof^DOBN4WY+Y*RndC+ZHsLf|QDSTw
zRCmjwx|I4Ff6dEn-8Co0Ty{UQSK@l;{C;In5mbOWq^pcXBH*&=Qs0jd0{|=%P1|v;
zJ0xjup?e#y$Ro>ab!(8jhJJSIK$4Cx|4B;T%AS`%9X<rFGuME6Ww*^vnIEi37ni12
z%5A+9yJ5MHf9cGuUthRnd!JlyrqZ0>9x%gjTWdl?f3somq7qoh+2yc0oyOU%7^Z1t
z+oR<{$6b_0=ifg~d~Z5)N5rw+<mbh=EA%+qnY%-78Wo=3-jh{mrFTd$=2NV05-3sb
zuUeUv^P<Fqy7YtD8`~lnxGi&W<dazSY_`EQnaX)@-KsYukpO=|&%6s)RsAB83%c90
z0v+KA&h@BPjIR1)r+X=|LCYMHTJmtc)dq?zO}i!FjDE^+9Pi1BJ+xXPuZSuMToxSf
zy;n`ut0^SA6SKb_1#TIy7RIl{g})rV;h2u*_XLW2>Jv8^sUHAH+iGiulbsz3UZ_MD
z-L!j$DtczHdL=}{;C+BC7GfbCVxbqrLfcO)l-;#DICkLb*`eDuvwk<_VN9s$n*U=g
zw6Y~YEKC4ZrdTLrnt_C25uq?-F<U^gF%3?cwc%}&hLc9|)ulC?UaeaKH`eG_m1AK3
zq*l$m^w!SjIA2;+(F_Io#umHs=Xli9(-{O|vEF{LE2Q)qmy|hXxZa^G4sq5f>z96b
zf6$<|-ou-jqQl&>TYrn998Zlm84aBssoGh$3hbA&7oJvK+@C$NsD*wYTi;a4SulV6
zTJ!ecGVF<%El*<@#z?LA=X$t9^N%RPwgN+`A)*1r%#3DgcWy?(GDFFqFBk)6k(<dK
zN9C%?$Di}lN3zcC4cNCguiG=%?q0_I0=`Pj#+>-H^z1*<Jo^(ia&s+$7oKS-DT~XM
zElgJtZO97fIrzY|TBh!p+{x(Qy5dWd<IP47_?C3sttr?F8~!lE5_^75t??Efa!^rY
zC}f%AWlZt$j?1~dvOi!<9dba9N%i{JLR)_4kA#eZ4m=*yk4*3}ZiyYS?Zd6r@3=m2
zrL!{tq1&qP^NLxG53t4iC4sB@P=-s2+4l6BHf@q<txNvmo+W29v=A>_9R&UR=qSeB
zmlUVx{?Ash{A%;c24QdinA<c@(w;egXP>YXA6P}XbfLD}<%%-z#fJ!*NGlj`bW38z
z;R_<1j_A(Ny{%_FeFElht15nhguy0E>FWuYXyM~a1jWc_Uj|7QE)gT!AlF?u0N@lr
zd5Anp2)H)HYlW$o0Erkr1WDr$NE#15NrRYvR-|3U_9BCM%{3P)qD*x8w*O^mnBa`S
z1s~z`{*5%Cj$*&=4KT??Wf<f~!zW02I?KD1oTJ%79Oa(OLfNP|ELOYU`^4I{=H)wf
zK#YFMg{uaoU2S@2s)|sBT<vvlqPvd;#Yabl$H^rh3@V|lAJn<0Uj$EUBK<j+bK4eU
zoOc9siTb3Y&i!I^j8dP5Sa~3=oTFWJ2X4R7g!rn2-=(a$X*5E?v{HZTfz-MzW>Rid
zK(0gcqRU;UT=Ys8-pL}pHq>nMtBnXcoCeRev`<k<N9o_xiP=$}&s<*Hoj>z@JZ}Gt
zEe~t15B^!MYj8*Yb)A+{3H$N!6iY0R^IJ{!cBbyD1uX`<k8F{n+1$|4N1C0}+-Ui9
zVDm05+^OSZ)cGR<?*`mG#L@OyXzRXBaA;8j{4M!XV}7Cq9Wp*(v|%fGO^5U41tA)l
zJFnE(Z&3CwdMjA-LbEYhE${ZDu}7)(DnKXh9Sh^I(2Z%z?Rr3+izNvk7aG&G3V-c9
zx&$2_R?!;}9Dx~aF}&S9*f_p9VU6J_KLhQKn4)Vf-tyazjBIKg)v#OLQ&Ddmn>Of<
z(64i>EDIbOHW`f+<uJzdLY+pFUpYK&FE<P8eaxx6<S{2Jf7#LTeJhS6bW2>$9eZdO
zX&+yGBKrBR`(xSfn2kD7ZTy*W9((ZD3Qyv$-u!7cQ+27Uq^wOQz1!siSw}0~y1e`}
zy}7809&%!vsPEwQjKhc(I*rx4<%H+vq<S}5WmdC@I5AKQ(dIZL5RmvEQ2P54S+&ju
zU?Grjh?EjHaMqV!E|0){EjrM0ss@R}A~CTQ7+ty2c6B?^82@*h<ztLaZqvoQN4{@5
zPRh@tkWYOjSpYza0ob~V56+agWdnybs}7bi3>)sx-}452#&OqSv#K5bUiDhS*SF=}
zPmXtQqt)z7B^Wi;0)rh3U&<`~VRmPH!3Z-^=>Cd4z}fdSU@3p3T{Sdi{n}PPk1eTh
zC4Dz;#UBY0wa?HnUsP#q!MoCwmUm$9o{GUvr?jC}n{xVz1HmhE4I)lne<p)%qCScM
zWLC_!G{Jl3kA<j?2udQ+kAL&4rw0dK&rBz<w-6s39-4n*PHHYed}_(T2J5od)$+3C
zb>d1j)OMX$-3PS{%OqAx!^<08`_=rfDGsZ9Y0133d%w(Qu8AjmPqtUD|Mn7{rUKVc
zn{od?P1AsG`i@?ep-Qdk(;^Cg=|(VA4*rzbel;!nI{89F$P~p3SkssB(^kdipO^af
zm;kB=7(fe4B-8waVfZ+@j}_hDMd0km!n>LJhB+tr;~3$jI1b5!U@N^mzH)uZ(P}88
zm@xIPyWv5kQJpBhbPErse{zb?h~Lh+q>(*s@oo`}1hSJbCOV2l649asAdld|;5$VI
zCP%Ra_|Vmyq(oa=KW^A}kRb_6gNmX9qwM@#eaUg*o<t(ZCfc!`d@SQd5m7j+gt!D3
zA3q%EOrhYzq9Z597=WuIzQ2p|`A7#~(t9e>q0;*xQ=v&;c15IPq&GXJVjBOl^&uTA
zo#sx(q7mOqdZjU>bG|7IBJvv<pmezOie)PNqP+C_MLJem)>E<fm83*29V#uwsnAu*
W-xj8qo6O{p$U)~bD2hD!vHt@3{sedc
rename from security/manager/ssl/tests/unit/test_signed_apps/cose_signed.zip
rename to security/manager/ssl/tests/unit/test_signed_apps/cose_signed_with_pkcs7.zip
index 918c715aded14f600b7a2e615f388bfc5dcef31b..4542e8a2337e689f5db78f7e1f3b8a6f55693d26
GIT binary patch
literal 4222
zc%1E5X;@O*8fF8cVrmYV$27^*a!B_^919Zx1rZb{z_da|KoJmdK9x~Vsi&+=Z4k@m
z(Mq#yuz9jhb<1vMvw1z$(QG)Uvbt$^qnSzd+<SlAANP6AW`ECK`&;{a*V=2n@8<g=
z87Q<RLVKuHMGTvS$@MI_tu<rVGWb$)sz9moNK?wB1y~%;VaPKpTcA*iWm1O#9Nt~q
zA?0TX;2Vb+xD!XsRSBd6-2;8Y&pLn}pa<lDor8@WG4NX&<n9KywT6K$ib|p|sWBq4
z5(l3ukpQO<@KZ7bxKx>9;8vv_MldvthYnno+F#!ai9l%01ooxyReVoz245)fkV}Qd
zk*rW-tPNKCl5`p+3cglq%|JWyG$6ABfdKB)DWsTOP0!UjLj*Yb?7qA6e*c>}upo28
z%)8IaKD`Xm{B{1{o=e8hmOJDhx3y@}@`X-iQT7DSR*z&*m(l7iC;)-bnicGW$w-<)
zXN7ns%aj6-Ar&w`U#G+kGCTkWd4O0f3)VsaZiINS(KHg?+h+<zEQDPFxZoHmSsnv<
z6IghksQ3)OBvA^5;KkvlfT}d_B%zNil?nN?!s%cHl{f@AC<<MqBpxX7&&>=C<B{c=
zJV6-9@W~`lII--^EHHx=9Ks~f2!aeznmA1O1!<%nbP=hMY3Z!^oIJii*G;a-3YX-D
zx`mL);W?pXf*&`Q5bZCEk061PxHvXZM|jTVoYG~m=(J|`&9W)Q!nUM^<PGS;nz!>8
z@Q{HU0cSK1=?kinUZ5HnSA#+VNTj9bC$s#n^OMJlE6;8Ss`T7nh29Vj8e<Gy7tt2=
z8Uuil9s+cMCV@^ER4f`bYJ9FdSt$}oBsdsfDoDZc<#OfV2SOo}sXzy7Q#=THLlE8%
z95~_!9DX1k^#1Gs2@oCx2jN`412>2^aIe5A1<7)FxfBq{11&K6@T{&9kpRYEpn(GP
zQNajw#EGLv`R(uC*KNh}b}vSEJkv7@4xHBOQ8wK@B9B2$a22<BQ6)ZS&8qb=?Iu0V
z*H<pTwPsww6#Y%;u9~o|CpVdb#-I^AAv;qv8imv^)OmlD8UPSNENj)pj>Nq6RpD)r
zhFRpEb1Oc4jAO~IS9!M4^3H;lvmQSK4&xK?w&R`X=c|2I>;3FSK0Uo~pF!D;jN%zl
zaof#{u6NT)*asK8k8Y{F!x=TH{8skamo1YLrfx$d9-o0YY}@?PEgauX*!FNn{C=8A
z-^ANTNN?TDSEcT)raawnZI8XUf?u6@d2-dsipND&UiMoR{ZSh%UAZ-;FY9I%m3D7q
z(x?B^{SQA40xVxJP1u=XSt4?}sJCyzpN#rtXfz;qemvpS1+&=H{Iwl-inzhZ?9e96
zEu5X@qmY{gh+fZ9vPJ&;Ca+?uKFg++bIh^eeWt8)<~mj*Nv5IKaDx)E*y}CKBCjNt
zJiu*g!hkD2)hn}RK`GDrehn_f${%ypkDGFrPPW_(kjonz-sguB*LIIi*If30gV8*3
z%9%Biy@l)Pgl;qfp*54Q*-P?>iY9?-^ph`}ppUFkquXHD-;n?S8G(ivJvS2+(gvoc
z(eOh+jT-q5X7_8D-S<ATn^bsQWm6}Lq<|}18cyv=bG4KE{g2u03QY!`2jT4h4ZGoq
zI($7FV1R3;2-uHBYDssbh`pUsYSl{WlO8O>_>3k_v$);W=^fVa?2U*caV$7>!D)MY
zoBgpm4W>$Jv*?fXj=k|&>1ipM2Kig!w^0}O+TL{3Am?5oe;hBq=7)1xxeIrO-g)<M
z_~~?sNzWLy>8rW5Vw<`f$bes5Nzb>*+f9v^_N5xR?Q<;KJm+u`KW}**XF0KD>bdqq
zH2dwoH;TwFCRw$`Hm1h!oQquU8Bj2~5aW2+R<f$Ll0T!dqtg6j7PM*9iu(<hdOz0M
zIo&XPad@oBHqoQ~1)dHv@jn_$D)@HKom-u%cdamB`TT0@h;~0=^^50kua>PD3mw|u
zPoMZf!9EM!MD4y~jrHzXiiH0Wfd5FIbjcD{{8pFElZ(qJ^X`V8b50zyVD<TifMQd&
z=1;}EZmZ^ei<Q?N_CK7{G#YpSy%FGuz6`#bwEZ4^yaQSJsLCZ~Y}NG#y92Q)$$Ppu
z38}cg)=AeodYeBj%bqvsP^^>9U5VymE8DPQ*N3IeePjG{9`9*#$(Y+4j&eL4yl)5h
z-Fw$Qp{kVEZ=V#>m;apj+nrkX<gQ2JeP@{CiYkM4f7&>6S9V7Y?Zn>u{=$H)`UB}t
z*WB(edBbnEO>2{zXEN8}FIF9dE?i#n6W?rlSj~<$y}}OKDT?jbLhstzBQY(Sx|qZR
z<*J@7m*($8&9rT<uQpJg7&nJ~#cM&mfCQ<5MwmAHVS#|8|ANv#mdNZyG(dntBVkh3
zFhJ`sOKymQz7`$mIoyMW9MHIof)dH;6&Y`e0~cn-ePlh?yz{W}%-M19dN$~JsAt0K
zuOtfqXf=R{@o2Hmme3c+m2ITouPnY^+5bDGs(t)sqQ#2Z%fw@^g93`*9OX#Y1*Wbm
z1*8XEF0|I4oE^rHm|4wBZoOC0yV%K|JT2g3>5ILA_FIHRm)d1ZloeAG?#(}|aAaBB
zFux-BU=<kUvZtagy3Fgyi?VapkJ?^e{kf_!G^+Z+YRiR8>x!NSURjxm8geMjT)&c}
zPkLviyfG0GCY~GiI{8|*QkZOfXhBcc%i!AwcH$Pt-cCJjH-T8$ZMy!$(VuY+Inlcs
zc^7yzaa)>m?)<FP7D?rX=ClUGv4-VPKXVrbVHcEWM$9yWmU6p0lh<Bj2<|=)uRo*4
zAA7p6o>N5}`B_ZRRPRiH+X<hmg0DV{(IL_B7V=eD3c<)6XhcdeWhhSyz$M2}a)lgn
z9LQ6q@#soOC1MM_)8l-&971*&HQkruD_6+45fOx}WZm52((Z<F^>8|-HOsH3!6dQh
zA=Ky?4`#?;3E2?h_Y+oK<On}JBbAp;2~kSY)5v5MD_sG~2uz+lM99rg6DjaXIpVxr
zKfhRM@(++<34b%)v?w<Ui_I3L^GHfxDkD@Zjo@?gVj!M4#ha1J4v8XgqiIPgxgvsg
zj{&45>c=JM&`}5=bPH15P~9SOI5h7|NvRv7TPY65G=Eb!>c;BU2*a^h)Q>6#T@2lX
zc^HF){!aR=8?KwN42OTh=;klFvAVJzj<p)4BXZqPT`3NSR*(9=Fe4dy16yJM|DM26
I^9N@8FVUaj4gdfE
--- a/security/manager/ssl/tests/unit/test_signed_apps/moz.build
+++ b/security/manager/ssl/tests/unit/test_signed_apps/moz.build
@@ -32,18 +32,18 @@ def SignedAppFile(name, flags):
 # hash algorithms are present in the corresponding file (both may be
 # present).
 # For example, "app_mf-1_sf-1-256_p7-256.zip" means that the manifest
 # file has sha-1 hashes, the signature file has sha-1 hashes and sha-256
 # hashes, and the pkcs#7 file only has sha-256.
 #
 # Temporarily disabled. See bug 1256495.
 #signed_app_files = (
-#    ['unknown_issuer_app.zip', '-i', 'unknown issuer'],
-#    ['unsigned_app.zip', '-n'],
+#    ['unknown_issuer_app.zip', '-i', 'unknown issuer', '-p', 'sha256'],
+#    ['unsigned_app.zip'],
 #    ['empty_signerInfos.zip', '-e'],
 #)
 #
 #for signed_app_file_params in signed_app_files:
 #    SignedAppFile(signed_app_file_params[0], signed_app_file_params[1:])
 #
 #for mf_algs in [['1'], ['256'], ['1', '256']]:
 #    for sf_algs in [['1'], ['256'], ['1', '256']]:
@@ -55,12 +55,15 @@ def SignedAppFile(name, flags):
 #                args.append('sha%s' % mf_alg)
 #            for sf_alg in sf_algs:
 #                args.append('-s')
 #                args.append('sha%s' % sf_alg)
 #            for p7_alg in p7_algs:
 #                args.append('-p')
 #                args.append('sha%s' % p7_alg)
 #            SignedAppFile(filename, args)
-
+#
 # COSE test-cases
-#SignedAppFile('cose_signed.zip', ['-c', 'ES256'])
-#SignedAppFile('cose_multiple_signed.zip', ['-c', 'ES256', '-c', 'ES384'])
+#SignedAppFile('cose_signed_with_pkcs7.zip', ['-c', 'ES256', '-p', 'sha256'])
+#SignedAppFile('cose_int_signed_with_pkcs7.zip', ['-c', 'ES256', '-r', 'xpcshell signed apps test root', '-p', 'sha256'])
+#SignedAppFile('cose_multiple_signed_with_pkcs7.zip', ['-c', 'ES256', '-c', 'ES384', '-p', 'sha256'])
+#SignedAppFile('only_cose_signed.zip', ['-c', 'ES256'])
+#SignedAppFile('only_cose_multiple_signed.zip', ['-c', 'ES384', '-c', 'ES256'])
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..69b03d154c5aefbd229a32d4f9b9e84276dafecc
GIT binary patch
literal 2822
zc$^FHW@Zs#00E(F4Iil(jZJ<)HVE?qac*K>W?E`-iC$K5eqJ?~f`SrEB)%-Qs5mn}
zPsvKbNCza5mzbLh<S2yzB^6vNN>cN{(qK7+S|tNL13g0}u3D}D6pO!k80u&P*&xgY
z#6hl(F21fI8JWcjKva^Es!)`gn39{Skd|Kr=9Yl0NrhRXhi2UDCQEiPCI$u&<^zhQ
zB$g!VXXYlRr|K2trFRDSx$|;Kae+MP>ERLtq^E%}2gqg{#==Jo42*X@T^vIy=Da<(
zk(0qd;K+vC^)Js0F*X-2jJy4A(*F+*b4JmSMLlu}1xi)>WQ6yC(u=37pUXO@geKG!
z^oo1NQf5X51`rkliUAX&qpqi)n|^YBajG6H7x+SH-7rWBw^A_FGvMO#1Lg%Q1(eLg
z73|??WNN1Cl9>(^vQlsg$#X6UF*G&tGcpT`%C$(!NO3VS4v$DND9JKSN;k_-^EI^e
z^YJwBceRBX2+0)aCM880<XBb|x_d=B7ZgUOdKq||6`Ht&hXxjw8sz#px%rxSn55=r
zWMz7#!%afX59lVk24rRXMU_`3T1IFW6qWkqRJd!qIXe54yE~g$M1-0ITjodkI~wGK
zg$3H8WxV|vPb7j^f%zAR1u=rHI5Yi5Qj7CKmWBo2nwle-Viqx4D6vE`g%~t31sF6j
zS}b5@Vq{_xk@xwh|D)-~&RZ|O%~${bF}gI$D$9VEjZ>@5qwPB{BO^B}gMp@@x`8Si
zb0`Zlk6cATa&bm#PL2Z5g1poeg~Wn_Vn_*5l%HQ>pd`U>WMF7!XlP_^00vQD0ZRiT
z15>Dgfr+7!fdRxgO)SPiOat?a6pB-m3ydvHiVO|P3<TKNfv!4d%f!gWs@=%Kpv0WS
zz_Ku-$k|Lgrdp!&bET-8=)&XnTYBHM*)eH~-cIOK)qS#ESa-#_87~Zj{j%opaC4rx
zX1Vr-5!=&UjV8ql<rf<~h+T0q&$;=Zdb{n)LgsxM9p^tVeTe!lC4cu!bIGc_mFE`o
z8}J%%16?c2&%(mY#NL1wILu9qj11+1N8kBa+P7Q_(ZBZ5dEwH~S!*}Qp1f)w@nPGe
z^a(fkOGD<IKK}DcwU6m*zZr+`-DYX=uq}Bed(PXwXz`2Xv$cX<LSyHvXuss;xZ1n(
z+>7vE`%@dI|7tlJBVE_v<n+f;e(}w8{;*Vsnu5-E92QS}3j=3~YMHfEozBq?>G~A0
z;iJ~s{0V8S9DL^z<HEjar0>$cpI^lBm1Aj$)tiJBtgQDla_cMQZdqCs9cn6`qTYJ>
zmk{@U{@ZVPHYWNm>~60Q?s`}K_2vzS3vZmiy?Ce0z42tIO-YRw3){+jO-dSOll5=R
zyk9f%*TaxW6ICakd9=NF)fF32Q6n}68+Oe+k?qqLL?parQ@2}~VHL9FhLm$ji^nvZ
zXLkD<#hKq+w=MdxD1<HY${Sa=7h%uiQbV^-UiqEjv-gt7=D9hA(?X}r<M`55`u5I)
zhgHV+&g$0MZcIFQaT9xlqT<CrYgQgV@4w`#pwGQFU=p@l#Ha>L!REjeYz$1n($Ex~
zuIK%-@VR;Q_WM7&`id>GQ+(`A23ZOQ=6GNVjx-QPq+kv(gPD<?*@=P0fB){?i4T7K
z+_;P@a!otSqc^PFPIflm^(NWt_*Z(n#%N_;GIq@|J0dujo$UeN+Y=WjPq;o)x>}cg
zG0Uq3Uds*;l}I@<W~-h(6wT<7c!T-6#pNo~)t)?&jQne(f;0|&&-Knz3$U4Gy=V8u
zjNE+wH;WxsU!SCQuIX~b_6fIFZTR=~{GN{8oH@!tNlePWwurvlmBKG1P&TXZc8~M%
z+r7KvS4b_gDH9YfY+AN!@y7J(+~ptcwz1tZ+H}%7F2Uzma#?8nZr+Q_p4+#4>8?*(
z>TqdIeM4~wTkC#?6R&(`HGj`%T(2vynP6%y?CSQ*$0&YkZkcfIMFrh^Wdht1o71H>
zub+MO&b>(&_9hqG?hV(rIatccyUJ_Un#Corgz`2AeGO*1oEIOwS+MnZ-l5s%ai8x*
zt+qIkt9aA-vd7v}6)$}Bw>Y*hh;WE04V*757;rYW>z=~mJ!}RO|8FWTjW<kr^Y^q<
z16RQ_1LwUy9~f#D@{8a9o-pV4gI(W?8v3+$tz79ji*uTL_LBf_MkWzv+-*1*XkcVO
zZ_%M^MQ?>6v{u5~WaxU(n_37xComdb=z7sBS%h9LW?WS+x*6y-4#Esa7A*BofHy1H
PXRJV|2ekGOCx{0CTnrq|
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..95fadc59cba10a5593a955f1cef77effd4bb4389
GIT binary patch
literal 2115
zc$^FHW@Zs#0D(!R9o|wg8k_upY!K!J;@rf%%(T?v61}YA{Jd%|1qCITNPJmpQE_H|
zo|2V<kq$^AFEKY2$WaObN-DTkl%(c?rNMFtwMqth26~1{T(w*QC>DS7Fx1fovO$;)
zh=W`mU3^_bGBS%5fT$!RRiP*~F(o%uAuYcM%q;;~lM1s&56!sQO_uCpObiSl%m)-p
zNi0d!&&*9sPt_~POYaQubLZuf;sSZn)59eQNKXS{4v@_@jD?RF7#Qz*x;TbZ%z1lm
zBPWA_z>y8N>tCK1Vr(v47<c>Kr2iir=8U2ti+bb|3Y4n$$q4TOr58_EKbLh*2~DUe
z=oR;jrOb>B3?M896aywkM_o@pH~r-N;#56YF7SoYx?zwMZlz$TXTZhf2h0mr3MiR}
zE7-%)$ka^NB{Ll;WToH~lIL6yVrXjOXJi%>m1~idk>X-v93GKkP?BYulx~)v=4)u_
z=i_PM?`jJ(5Rxg-O-hP1$g!*_boYvME+~vl^)m1_D>QKl4-G6VHOTdIa`QFuFiFkL
z$jbCehns|&AJ9#74amy&iz=^7w2aU$C@S^Isc_eJb9DA8cXu|ihzK<aw#<+6cQnWe
z3k$SG%Xn&2!u$GxnGS>nF@mi)GyO(Vi}OO3h6Udmn<JU*7BQ-^L^7EhG%*<)G%-pq
zU}j=uViM8+FIe^Jn1*=fv?B{0rs;2<&9czPfR~L^tIebBJ1-+6H!FjIrlGolDjRbs
z3p0;gML}|LMruxu0?_=t)D(rpf`Vd50a28nUt*vn!Ea<>XliI^WMKdXQD6ZJ10w@d
zsDOcqp^<?B#5heX#z9O2^NSRUQ<DpT!Bu2v5NROH#twAVIa?-1HV!a@nUS5@iGjs`
z|L)z14}SdIxQr`uO*_k@H>})Fb~fMjCfV!wS9-g~Xk}h9cFi$6A~=_w?E&B06Bj2>
zxIR<5T9<t>%c})m%ML8&H{dnk20BQVpM`~)iM;{M|IAH{j11{qe$!7rimjYK+vkSi
z9N!L|^6ODPqAFe2KUT^F7d)w+9RKVM<4&VkBN;hW&tr4VX0X;6J0G%d*uXLAa&BjI
zP}mBgj*G87x&pVg>j+$$b}O7meaiK+BOflQ$5=0Ch}{>>uv6xQ<aLEa?erV>qoX!^
z@cmW3xy$jJw$Svn^>bZbEWEHzK67f~+}JZ3vky#t)-l^yep%7KpoJn@5exV~Y>e;d
zd%fJ()Bd;4CyO}@22+}C(x2ptbY-ZXWZj_n*?Utz3kzd`+B3z2#|1;vs%Aa9)e+&u
zROY^i?Ye@j$V0cQ)ePVD`<#WVe(o{ubY=IGx)#1yrTS-K{*$<Qe%l@M=XfrNaEK`l
zoG&aGa5lE<p2FfiYz7nmZz?X0H%xi+_q0<3SHZK0re}L9dNo9rFgj1!zU60?yX~yk
z0@-uUSbk-j^IWw&KERuiNrV}91qcHTj11`2A-Y!dDh#2u5?-O9>p`!l5PD8v)LQ6z
o(Mu?VUM^-_<rTUa=-Cxvh9e7>%p2g%3icT*5b6P~{SW2=000^PSpWb4
--- a/third_party/rust/cose-c/.cargo-checksum.json
+++ b/third_party/rust/cose-c/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"6689411cf004e6ebc4645105de26492adbea6f690f9184119cf1689829ff098a","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","include/cosec.h":"9e952f6bf578c812e67a93c3c810f4aaa57d365932fe8d01f36f587e8aa32538","src/lib.rs":"d10a17e4840187711d85058bf4afdbfbda88c74a9483921ee48a1bfc0cc5ff70"},"package":"07cc8bb85ec2e93541ef9369b85a4b6fb7732bc7f4854d317eab20e726b0fc2f"}
\ No newline at end of file
+{"files":{"Cargo.toml":"6e5aa986e80c9f848f8219f46d5e6d445609a3db70da9793f920c56c18814b7d","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","include/cosec.h":"0c6ebd84b6e1ee61a710f86416fc9092653292479556c713c83f193f26ac09b9","src/lib.rs":"0fef8341439e55682d7a7e50dead28427832b5fbd28ca48f60b00277c8a4b9b1"},"package":"49726015ab0ca765144fcca61e4a7a543a16b795a777fa53f554da2fffff9a94"}
\ No newline at end of file
--- a/third_party/rust/cose-c/Cargo.toml
+++ b/third_party/rust/cose-c/Cargo.toml
@@ -7,20 +7,20 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "cose-c"
-version = "0.1.1"
+version = "0.1.5"
 authors = ["Franziskus Kiefer <franziskuskiefer@gmail.com>"]
 description = "C API for the cose crate"
 keywords = ["cose", "jose", "cbor"]
 license = "MPL-2.0"
 repository = "https://github.com/franziskuskiefer/cose-c-api"
 
 [lib]
 name = "cosec"
 path = "src/lib.rs"
 [dependencies.cose]
-version = "0.1.2"
+version = "0.1.4"
--- a/third_party/rust/cose-c/include/cosec.h
+++ b/third_party/rust/cose-c/include/cosec.h
@@ -17,16 +17,18 @@ typedef bool (*cose_verify_callback)(con
                                      size_t payload_len,
                                      const uint8_t** cert_chain,
                                      size_t cert_chain_len,
                                      const size_t* certs_len,
                                      const uint8_t* ee_cert,
                                      size_t ee_cert_len,
                                      const uint8_t* signature,
                                      size_t signature_len,
-                                     uint8_t algorithm);
+                                     uint8_t algorithm,
+                                     void* ctx);
 bool
 verify_cose_signature_ffi(const uint8_t* payload,
                           size_t payload_len,
                           const uint8_t* signature,
                           size_t signature_len,
+                          void* ctx,
                           cose_verify_callback);
 }
--- a/third_party/rust/cose-c/src/lib.rs
+++ b/third_party/rust/cose-c/src/lib.rs
@@ -2,39 +2,42 @@
  * 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/. */
 
 extern crate cose;
 
 use std::slice;
 use cose::decoder::decode_signature;
 use cose::SignatureAlgorithm;
+use std::os::raw;
 
 unsafe fn from_raw(ptr: *const u8, len: usize) -> Vec<u8> {
     slice::from_raw_parts(ptr, len).to_vec()
 }
 
 type VerifyCallback = extern "C" fn(*const u8, /* payload */
                                     usize, /* payload len */
                                     *const *const u8, /* cert_chain */
                                     usize, /* # certs */
                                     *const usize, /* cert lengths in cert_chain */
                                     *const u8, /* signer cert */
                                     usize, /* signer cert len */
                                     *const u8, /* signature bytes */
                                     usize, /* signature len */
-                                    u8 /* signature algorithm */)
+                                    u8, /* signature algorithm */
+                                    *const raw::c_void /* some context of the app */)
                                     -> bool;
 
 #[no_mangle]
 pub extern "C" fn verify_cose_signature_ffi(
     payload: *const u8,
     payload_len: usize,
     cose_signature: *const u8,
     cose_signature_len: usize,
+    ctx: *const raw::c_void,
     verify_callback: VerifyCallback,
 ) -> bool {
     if payload.is_null() || cose_signature.is_null() || payload_len == 0 ||
         cose_signature_len == 0
     {
         return false;
     }
 
@@ -75,11 +78,12 @@ pub extern "C" fn verify_cose_signature_
             certs.as_ptr(),
             certs.len(),
             cert_lens.as_ptr(),
             cose_signature.signer_cert.as_ptr(),
             cose_signature.signer_cert.len(),
             signature_bytes.as_ptr(),
             signature_bytes.len(),
             signature_type,
+            ctx,
         )
     });
 }
--- a/third_party/rust/cose/.cargo-checksum.json
+++ b/third_party/rust/cose/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".travis.yml":"be3532bc6d5d823090206ad957c8705436960d1918a2c577342f6914a233ca98","Cargo.toml":"5eb5257aced25840b3af43757478e4dfa38e2f222cb25794ffeeb681b6a46ce2","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"42a12b9a8944a2888ce2622bb03c06850163ab738917414e3413b63be9257a8a","build.rs":"a2b798bbeaf8ef19a9bd8c1e24b3fd3899a5b4b3e121e5e09794e4e2b35971dd","rustfmt.toml":"e97717e906fcd3eeb86dcee52ed26f13e1884597b016a27172229d9c78dd3d57","src/cbor/decoder.rs":"b9e375489131aea75fb461c9ee96e45595e08957c90179f2c449226a31b7e4c5","src/cbor/mod.rs":"f5b767eedbee01b3f697afb2dce777c6043e6fea6f9a7eab8387560caaa40100","src/cbor/serializer.rs":"d86f0123f364046c8c18b45e109437b16c24d29bc7ef01c12a7c465e89878836","src/cbor/test_decoder.rs":"6a47f0f98f54a343f12c78033c94c5892b0a5b5e62de251bef3a722f358978ab","src/cbor/test_serializer.rs":"984fbe0520e77d078fb2e2c60e4e0df077d40ede644b1b92651f3a0696377511","src/cose.rs":"1a5c23f31863c58838f4aa94c2940e9f18252929c990d2a9522490e56593710e","src/decoder.rs":"ce86fd2f72cf02185ea724d63e5cb24aaea9ff6a2f3137c20322764a3ea9d15e","src/nss.rs":"e17101aa957367ee025afd5af37d72a955d9b79098ab7db1631f93b6479230a3","src/test_cose.rs":"35798ef9ee5849204b36a69b07969c0b4f3976d0e44ccfff6f413a2e3684f76b","src/test_nss.rs":"51ececb4a8fd8ddba7e1af179b9326e38a838d4693998092f842db5f30e75703","src/test_setup.rs":"b2c8d5b4a20013fd89bcc9d5732af509331a648a1163a9e44b47e51dde2b6308","src/util.rs":"fbc1a2051230156c2504efcff5044fbf54a6f925aa7dfb97c211208348364425","src/util_test.rs":"49dde5be7202aa2fa3f7ac6d36de189739cd5538e378f5c0a27161b9185e9ca6","tools/certs/certs.md":"7a1acd946f5bb5b9b21ebd7653ef9d5746a1ea237131a69218a91dc26eda545a","tools/certs/certs.sh":"a06e1a7bf99316c7800e388d20c1630da7449937635600d9f21d8d93907011bf","tools/certs/ee-p256.certspec":"5a7246c0abf1ee08edb858ce2fd38010de7785a0e8652f2d9a0b7eee7aa39213","tools/certs/ee-p256.keyspec":"eabd2839f9e57cf2c372e686e5856cf651d7f07d0d396b3699d1d228b5931945","tools/certs/ee-p384.certspec":"d2e4fdd6d8f02f22bffa800ac2b7f899f5d826528e7b7d3248e1abea15cd33bd","tools/certs/ee-p521.certspec":"7ad1fc3cdf024dfa7213f3a2875af0ccfa2bd73fddcfaf73223aa25b24ee2cad","tools/certs/ee-rsa.certspec":"dd69ecbb1cdf322fb8ef6eb50c2f033b62e7983b5448b96f1965eee8f85b7bde","tools/certs/int-p256.certspec":"b42a2286339455626b9a8b6c0811b031bf269440c6fcef7478796d02c5491364","tools/certs/int-rsa.certspec":"a0942438c72a3ce83b54c04e4a5d4bff08036c2c9feb7d75a7105bfa4fdc5499","tools/certs/root-p256.certspec":"99c1bb07505ddfc3ada5737d8a1bf4cff7b1a70a79abda9fd45fc3a6e72061fc","tools/certs/root-rsa.certspec":"67903313b6058aa98be0d98564577b0c878c868b6f2a8758f27bb7af17616d8e"},"package":"ec10816629f38fa557f08e199a3474fab954f4c8d2645550367235afa6e5646b"}
\ No newline at end of file
+{"files":{".travis.yml":"c05a8cdd57b8969a1ab3547181b3d74079b8493132893c15cf3c4f479327359b","Cargo.toml":"40534ef8d01b0269e2ca3b00c4d14f7523222bc85611ee07afcffea45a71ef4b","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"7b9676ec9ed5d7ac38f461b1b257eb0bd80568e732994fb26fa929ce5fe503af","build.rs":"a2b798bbeaf8ef19a9bd8c1e24b3fd3899a5b4b3e121e5e09794e4e2b35971dd","examples/sign_verify/main.rs":"fbe4b9c73b23e1ef364126f453f749fefb67ab45703bf809a5eed910a25e461e","examples/sign_verify/nss.rs":"a1d133142efc0ac6564f0b9587890587f1ecaa7404ac0c4c8907de6d43de3267","examples/sign_verify/test_nss.rs":"be41ebe0a82b6172297b10c13767e4768f0b613ac331b554f6e8c2c7a20c0bc8","examples/sign_verify/test_setup.rs":"82330118e4284d9bf788dbec9e637ab4a3b53fd4ec9c7efaed0e996ffa084de4","examples/sign_verify/util_test.rs":"48d52f3ca3e93b670a1d69f8443358260c1ae61d7977a59d922696811320d4c3","rustfmt.toml":"e97717e906fcd3eeb86dcee52ed26f13e1884597b016a27172229d9c78dd3d57","src/cose.rs":"104e06843f4cdffe2ca6f42f46c51c79d685c18d2ad92b65811e3ceffbd90e07","src/decoder.rs":"a4d2dcd44d179fabdac6ce99cc3512ece3164ba48beab9f313ad85db466c3a55","src/test_cose.rs":"849ec936a00eb438a08eb85380b3e4ba8d8c5a5cf674b272e0fd8e671ab6d5ca","src/test_setup.rs":"e26f290831343cbb4e2b2ec7d1be34c7b900eb8c87abd6f40629372a87b6e992","src/util.rs":"8cdcdc8a120e71a772af61fa63ffa2d2d2eb572d8a53da3b5f1ce9da784f2662","tools/certs/certs.md":"7a1acd946f5bb5b9b21ebd7653ef9d5746a1ea237131a69218a91dc26eda545a","tools/certs/certs.sh":"a06e1a7bf99316c7800e388d20c1630da7449937635600d9f21d8d93907011bf","tools/certs/ee-p256.certspec":"5a7246c0abf1ee08edb858ce2fd38010de7785a0e8652f2d9a0b7eee7aa39213","tools/certs/ee-p256.keyspec":"eabd2839f9e57cf2c372e686e5856cf651d7f07d0d396b3699d1d228b5931945","tools/certs/ee-p384.certspec":"d2e4fdd6d8f02f22bffa800ac2b7f899f5d826528e7b7d3248e1abea15cd33bd","tools/certs/ee-p521.certspec":"7ad1fc3cdf024dfa7213f3a2875af0ccfa2bd73fddcfaf73223aa25b24ee2cad","tools/certs/ee-rsa.certspec":"dd69ecbb1cdf322fb8ef6eb50c2f033b62e7983b5448b96f1965eee8f85b7bde","tools/certs/int-p256.certspec":"b42a2286339455626b9a8b6c0811b031bf269440c6fcef7478796d02c5491364","tools/certs/int-rsa.certspec":"a0942438c72a3ce83b54c04e4a5d4bff08036c2c9feb7d75a7105bfa4fdc5499","tools/certs/root-p256.certspec":"99c1bb07505ddfc3ada5737d8a1bf4cff7b1a70a79abda9fd45fc3a6e72061fc","tools/certs/root-rsa.certspec":"67903313b6058aa98be0d98564577b0c878c868b6f2a8758f27bb7af17616d8e"},"package":"72fa26cb151d3ae4b70f63d67d0fed57ce04220feafafbae7f503bef7aae590d"}
\ No newline at end of file
--- a/third_party/rust/cose/.travis.yml
+++ b/third_party/rust/cose/.travis.yml
@@ -1,31 +1,33 @@
 sudo: true
+dist: trusty
 language: rust
 cache: cargo
 rust:
   - stable
   - beta
   - nightly
 
 addons:
   apt:
     packages:
       - build-essential
       - libnss3-dev
 
-install:
+#install:
 # Apparently cargo install returns a nonzero exit status if
 # caching succeeds, so just make this always "succeed".
-  - (cargo install rustfmt || true)
+#  - (cargo install rustfmt --force || true)
 
 script:
 # The NSS version in Ubuntu is too old. Get a newer one.
 - |
   wget http://de.archive.ubuntu.com/ubuntu/pool/main/n/nss/libnss3_3.32-1ubuntu3_amd64.deb
   wget http://de.archive.ubuntu.com/ubuntu/pool/main/n/nspr/libnspr4_4.16-1ubuntu2_amd64.deb
   sudo dpkg -i libnspr4_4.16-1ubuntu2_amd64.deb
   sudo dpkg -i libnss3_3.32-1ubuntu3_amd64.deb
-- |
-  cargo fmt -- --write-mode=diff
+#- |
+#  cargo fmt -- --write-mode=diff
 - |
   cargo build --features "$FEATURES" &&
-  cargo test
+  cargo test &&
+  cargo run --example sign_verify
--- a/third_party/rust/cose/Cargo.toml
+++ b/third_party/rust/cose/Cargo.toml
@@ -7,24 +7,26 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "cose"
-version = "0.1.2"
+version = "0.1.4"
 authors = ["Franziskus Kiefer <franziskuskiefer@gmail.com>", "David Keeler <dkeeler@mozilla.com>"]
 build = "build.rs"
 description = "Library to use COSE (https://tools.ietf.org/html/rfc8152) in Rust"
-keywords = ["cose", "jose", "cbor"]
+keywords = ["cose", "jose"]
 license = "MPL-2.0"
 repository = "https://github.com/franziskuskiefer/cose-rust"
 
 [lib]
 name = "cose"
 path = "src/cose.rs"
+[dependencies.moz_cbor]
+version = "0.1.0"
 [dev-dependencies.scopeguard]
 version = "0.3"
 
 [features]
 default = []
--- a/third_party/rust/cose/README.md
+++ b/third_party/rust/cose/README.md
@@ -8,8 +8,19 @@ A Rust library for [COSE](https://tools.
 **THIS IS WORK IN PROGRESS. DO NOT USE YET.**
 
 ## Build instructions
 
 If NSS is not installed in the path, use `NSS_LIB_DIR` to set the library path where
 we can find the NSS libraries.
 
     cargo build
+
+### Run Tests and Examples
+
+To run tests and examples you need NSS in your library path. Tests can be run
+with
+
+    cargo test
+
+and examples with
+
+    cargo run --example sign_verify
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cose/examples/sign_verify/main.rs
@@ -0,0 +1,259 @@
+extern crate moz_cbor as cbor;
+extern crate cose;
+
+#[macro_use(defer)]
+extern crate scopeguard;
+
+mod nss;
+mod test_nss;
+mod test_setup;
+mod util_test;
+
+use util_test::{sign, verify_signature};
+use test_setup as test;
+use std::str::FromStr;
+use cose::{CoseError, SignatureAlgorithm};
+
+// All keys here are from pykey.py/pycert.py from mozilla-central.
+// Certificates can be generated with tools/certs/certs.sh and mozilla-central.
+
+#[derive(Debug)]
+pub struct SignatureParameters<'a> {
+    certificate: &'a [u8],
+    algorithm: SignatureAlgorithm,
+    pkcs8: &'a [u8],
+}
+
+#[derive(Debug)]
+pub struct Signature<'a> {
+    parameter: &'a SignatureParameters<'a>,
+    signature_bytes: Vec<u8>,
+}
+
+const P256_PARAMS: SignatureParameters = SignatureParameters {
+    certificate: &test::P256_EE,
+    algorithm: SignatureAlgorithm::ES256,
+    pkcs8: &test::PKCS8_P256_EE,
+};
+const P384_PARAMS: SignatureParameters = SignatureParameters {
+    certificate: &test::P384_EE,
+    algorithm: SignatureAlgorithm::ES384,
+    pkcs8: &test::PKCS8_P384_EE,
+};
+const P521_PARAMS: SignatureParameters = SignatureParameters {
+    certificate: &test::P521_EE,
+    algorithm: SignatureAlgorithm::ES512,
+    pkcs8: &test::PKCS8_P521_EE,
+};
+
+fn test_verify(payload: &[u8], cert_chain: &[&[u8]], params_vec: Vec<SignatureParameters>) {
+    test::setup();
+    let cose_signature = sign(payload, cert_chain, &params_vec);
+    assert!(cose_signature.is_ok());
+    let cose_signature = cose_signature.unwrap();
+
+    // Verify signature.
+    assert!(verify_signature(payload, cose_signature).is_ok());
+}
+
+fn test_verify_modified_payload(
+    payload: &mut [u8],
+    cert_chain: &[&[u8]],
+    params_vec: Vec<SignatureParameters>,
+) {
+    test::setup();
+    let cose_signature = sign(payload, cert_chain, &params_vec);
+    assert!(cose_signature.is_ok());
+    let cose_signature = cose_signature.unwrap();
+
+    // Verify signature.
+    payload[0] = !payload[0];
+    let verify_result = verify_signature(payload, cose_signature);
+    assert!(verify_result.is_err());
+    assert_eq!(verify_result, Err(CoseError::VerificationFailed));
+}
+
+fn test_verify_modified_signature(
+    payload: &[u8],
+    cert_chain: &[&[u8]],
+    params_vec: Vec<SignatureParameters>,
+) {
+    test::setup();
+    let cose_signature = sign(payload, cert_chain, &params_vec);
+    assert!(cose_signature.is_ok());
+    let mut cose_signature = cose_signature.unwrap();
+
+    // Tamper with the cose signature.
+    let len = cose_signature.len();
+    cose_signature[len - 15] = !cose_signature[len - 15];
+
+    // Verify signature.
+    let verify_result = verify_signature(payload, cose_signature);
+    assert!(verify_result.is_err());
+    assert_eq!(verify_result, Err(CoseError::VerificationFailed));
+}
+
+// This can be used with inconsistent parameters that make the verification fail.
+// In particular, the signing key does not match the certificate used to verify.
+fn test_verify_verification_fails(
+    payload: &[u8],
+    cert_chain: &[&[u8]],
+    params_vec: Vec<SignatureParameters>,
+) {
+    test::setup();
+    let cose_signature = sign(payload, cert_chain, &params_vec);
+    assert!(cose_signature.is_ok());
+    let cose_signature = cose_signature.unwrap();
+
+    // Verify signature.
+    let verify_result = verify_signature(payload, cose_signature);
+    assert!(verify_result.is_err());
+    assert_eq!(verify_result, Err(CoseError::VerificationFailed));
+}
+
+fn test_cose_sign_verify() {
+    let payload = b"This is the content.";
+
+    // P256
+    let certs: [&[u8]; 2] = [&test::P256_ROOT,
+                             &test::P256_INT];
+    let params_vec = vec![P256_PARAMS];
+    test_verify(payload, &certs, params_vec);
+
+    // P256, no other certs.
+    let certs: [&[u8]; 0] = [];
+    let params_vec = vec![P256_PARAMS];
+    test_verify(payload, &certs, params_vec);
+
+    // P384
+    let params_vec = vec![P384_PARAMS];
+    test_verify(payload, &certs, params_vec);
+
+    // P521
+    let params_vec = vec![P521_PARAMS];
+    test_verify(payload, &certs, params_vec);
+}
+
+fn test_cose_verify_xpi_signature() {
+    // This signature was created with sign_app.py from m-c.
+    test::setup();
+    assert!(verify_signature(&test::XPI_PAYLOAD, test::XPI_SIGNATURE.to_vec()).is_ok());
+}
+
+fn test_cose_sign_verify_modified_payload() {
+    let mut payload = String::from_str("This is the content.")
+        .unwrap()
+        .into_bytes();
+    let certs: [&[u8]; 2] = [&test::P256_ROOT,
+                             &test::P256_INT];
+    let params_vec = vec![P256_PARAMS];
+    test_verify_modified_payload(&mut payload, &certs, params_vec);
+}
+
+fn test_cose_sign_verify_wrong_cert() {
+    let payload = b"This is the content.";
+    let certs: [&[u8]; 2] = [&test::P256_ROOT,
+                             &test::P256_INT];
+    let params = SignatureParameters {
+        certificate: &test::P384_EE,
+        algorithm: SignatureAlgorithm::ES256,
+        pkcs8: &test::PKCS8_P256_EE,
+    };
+    let params_vec = vec![params];
+    test_verify_verification_fails(payload, &certs, params_vec);
+}
+
+fn test_cose_sign_verify_tampered_signature() {
+    let payload = b"This is the content.";
+    let certs: [&[u8]; 2] = [&test::P256_ROOT,
+                             &test::P256_INT];
+    let params_vec = vec![P256_PARAMS];
+    test_verify_modified_signature(payload, &certs, params_vec);
+}
+
+const RSA_PARAMS: SignatureParameters = SignatureParameters {
+    certificate: &test::RSA_EE,
+    algorithm: SignatureAlgorithm::PS256,
+    pkcs8: &test::PKCS8_RSA_EE,
+};
+
+fn test_cose_sign_verify_rsa() {
+    let payload = b"This is the RSA-signed content.";
+    let certs: [&[u8]; 2] = [&test::RSA_ROOT,
+                             &test::RSA_INT];
+    let params_vec = vec![RSA_PARAMS];
+    test_verify(payload, &certs, params_vec);
+}
+
+fn test_cose_sign_verify_rsa_modified_payload() {
+    let mut payload = String::from_str("This is the RSA-signed content.")
+        .unwrap()
+        .into_bytes();
+    let certs: [&[u8]; 2] = [&test::RSA_ROOT,
+                             &test::RSA_INT];
+    let params_vec = vec![RSA_PARAMS];
+    test_verify_modified_payload(&mut payload, &certs, params_vec);
+}
+
+fn test_cose_sign_verify_rsa_tampered_signature() {
+    let payload = b"This is the RSA-signed content.";
+    let certs: [&[u8]; 2] = [&test::RSA_ROOT,
+                             &test::RSA_INT];
+    let params_vec = vec![RSA_PARAMS];
+    test_verify_modified_signature(payload, &certs, params_vec);
+}
+
+fn test_cose_sign_verify_two_signatures() {
+    let payload = b"This is the content.";
+    let certs: [&[u8]; 4] = [&test::P256_ROOT,
+                             &test::P256_INT,
+                             &test::RSA_ROOT,
+                             &test::RSA_INT];
+    let params_vec = vec![P256_PARAMS,
+                          RSA_PARAMS];
+    test_verify(payload, &certs, params_vec);
+}
+
+fn test_cose_sign_verify_two_signatures_tampered_payload() {
+    let mut payload = String::from_str("This is the content.")
+        .unwrap()
+        .into_bytes();
+    let certs: [&[u8]; 4] = [&test::P256_ROOT,
+                             &test::P256_INT,
+                             &test::RSA_ROOT,
+                             &test::RSA_INT];
+    let params_vec = vec![P256_PARAMS,
+                          RSA_PARAMS];
+    test_verify_modified_payload(&mut payload, &certs, params_vec);
+}
+
+fn test_cose_sign_verify_two_signatures_tampered_signature() {
+    let payload = b"This is the content.";
+    let certs: [&[u8]; 4] = [&test::P256_ROOT,
+                             &test::P256_INT,
+                             &test::RSA_ROOT,
+                             &test::RSA_INT];
+    let params_vec = vec![P256_PARAMS,
+                          RSA_PARAMS];
+    test_verify_modified_signature(payload, &certs, params_vec);
+}
+
+fn main() {
+    // Basic NSS exmaple usage.
+    test_nss::test_nss_sign_verify();
+    test_nss::test_nss_sign_verify_different_payload();
+    test_nss::test_nss_sign_verify_wrong_cert();
+
+    // COSE sign/verify example usages.
+    test_cose_sign_verify_two_signatures_tampered_signature();
+    test_cose_sign_verify_two_signatures_tampered_payload();
+    test_cose_sign_verify_two_signatures();
+    test_cose_sign_verify_rsa_tampered_signature();
+    test_cose_sign_verify_rsa_modified_payload();
+    test_cose_sign_verify_rsa();
+    test_cose_sign_verify_tampered_signature();
+    test_cose_sign_verify_wrong_cert();
+    test_cose_sign_verify_modified_payload();
+    test_cose_verify_xpi_signature();
+    test_cose_sign_verify();
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cose/examples/sign_verify/nss.rs
@@ -0,0 +1,356 @@
+use std::marker::PhantomData;
+use std::{mem, ptr};
+use std::os::raw;
+use std::os::raw::c_char;
+use cose::SignatureAlgorithm;
+
+type SECItemType = raw::c_uint; // TODO: actually an enum - is this the right size?
+const SI_BUFFER: SECItemType = 0; // called siBuffer in NSS
+
+#[repr(C)]
+struct SECItem {
+    typ: SECItemType,
+    data: *const u8,
+    len: raw::c_uint,
+}
+
+impl SECItem {
+    fn maybe_new(data: &[u8]) -> Result<SECItem, NSSError> {
+        if data.len() > u32::max_value() as usize {
+            return Err(NSSError::InputTooLarge);
+        }
+        Ok(SECItem {
+            typ: SI_BUFFER,
+            data: data.as_ptr(),
+            len: data.len() as u32,
+        })
+    }
+
+    fn maybe_from_parts(data: *const u8, len: usize) -> Result<SECItem, NSSError> {
+        if len > u32::max_value() as usize {
+            return Err(NSSError::InputTooLarge);
+        }
+        Ok(SECItem {
+            typ: SI_BUFFER,
+            data: data,
+            len: len as u32,
+        })
+    }
+}
+
+/// Many NSS APIs take constant data input as SECItems. Some, however, output data as SECItems.
+/// To represent this, we define another type of mutable SECItem.
+#[repr(C)]
+struct SECItemMut<'a> {
+    typ: SECItemType,
+    data: *mut u8,
+    len: raw::c_uint,
+    _marker: PhantomData<&'a mut Vec<u8>>,
+}
+
+impl<'a> SECItemMut<'a> {
+    /// Given a mutable reference to a Vec<u8> that has a particular allocated capacity, create a
+    /// SECItemMut that points to the vec and has the same capacity.
+    /// The input vec is not expected to have any actual contents, and in any case is cleared.
+    fn maybe_from_empty_preallocated_vec(vec: &'a mut Vec<u8>) -> Result<SECItemMut<'a>, NSSError> {
+        if vec.capacity() > u32::max_value() as usize {
+            return Err(NSSError::InputTooLarge);
+        }
+        vec.clear();
+        Ok(SECItemMut {
+            typ: SI_BUFFER,
+            data: vec.as_mut_ptr(),
+            len: vec.capacity() as u32,
+            _marker: PhantomData,
+        })
+    }
+}
+
+#[repr(C)]
+struct CkRsaPkcsPssParams {
+    // Called CK_RSA_PKCS_PSS_PARAMS in NSS
+    hash_alg: CkMechanismType, // Called hashAlg in NSS
+    mgf: CkRsaPkcsMgfType,
+    s_len: raw::c_ulong, // Called sLen in NSS
+}
+
+impl CkRsaPkcsPssParams {
+    fn new() -> CkRsaPkcsPssParams {
+        CkRsaPkcsPssParams {
+            hash_alg: CKM_SHA256,
+            mgf: CKG_MGF1_SHA256,
+            s_len: 32,
+        }
+    }
+
+    fn get_params_item(&self) -> Result<SECItem, NSSError> {
+        // This isn't entirely NSS' fault, but it mostly is.
+        let params_ptr: *const CkRsaPkcsPssParams = self;
+        let params_ptr: *const u8 = params_ptr as *const u8;
+        let params_secitem =
+            SECItem::maybe_from_parts(params_ptr, mem::size_of::<CkRsaPkcsPssParams>())?;
+        Ok(params_secitem)
+    }
+}
+
+type CkMechanismType = raw::c_ulong; // called CK_MECHANISM_TYPE in NSS
+const CKM_ECDSA: CkMechanismType = 0x0000_1041;
+const CKM_RSA_PKCS_PSS: CkMechanismType = 0x0000_000D;
+const CKM_SHA256: CkMechanismType = 0x0000_0250;
+
+type CkRsaPkcsMgfType = raw::c_ulong; // called CK_RSA_PKCS_MGF_TYPE in NSS
+const CKG_MGF1_SHA256: CkRsaPkcsMgfType = 0x0000_0002;
+
+type SECStatus = raw::c_int; // TODO: enum - right size?
+const SEC_SUCCESS: SECStatus = 0; // Called SECSuccess in NSS
+const SEC_FAILURE: SECStatus = -1; // Called SECFailure in NSS
+
+enum SECKEYPublicKey {}
+enum SECKEYPrivateKey {}
+enum PK11SlotInfo {}
+enum CERTCertificate {}
+enum CERTCertDBHandle {}
+
+const SHA256_LENGTH: usize = 32;
+const SHA384_LENGTH: usize = 48;
+const SHA512_LENGTH: usize = 64;
+
+// TODO: ugh this will probably have a platform-specific name...
+#[link(name = "nss3")]
+extern "C" {
+    fn PK11_HashBuf(
+        hashAlg: HashAlgorithm,
+        out: *mut u8,
+        data_in: *const u8, // called "in" in NSS
+        len: raw::c_int,
+    ) -> SECStatus;
+    fn PK11_VerifyWithMechanism(
+        key: *const SECKEYPublicKey,
+        mechanism: CkMechanismType,
+        param: *const SECItem,
+        sig: *const SECItem,
+        hash: *const SECItem,
+        wincx: *const raw::c_void,
+    ) -> SECStatus;
+
+    fn SECKEY_DestroyPublicKey(pubk: *const SECKEYPublicKey);
+
+    fn CERT_GetDefaultCertDB() -> *const CERTCertDBHandle;
+    fn CERT_DestroyCertificate(cert: *mut CERTCertificate);
+    fn CERT_NewTempCertificate(
+        handle: *const CERTCertDBHandle,
+        derCert: *const SECItem,
+        nickname: *const c_char,
+        isperm: bool,
+        copyDER: bool,
+    ) -> *mut CERTCertificate;
+    fn CERT_ExtractPublicKey(cert: *const CERTCertificate) -> *const SECKEYPublicKey;
+
+    fn PK11_ImportDERPrivateKeyInfoAndReturnKey(
+        slot: *mut PK11SlotInfo,
+        derPKI: *const SECItem,
+        nickname: *const SECItem,
+        publicValue: *const SECItem,
+        isPerm: bool,
+        isPrivate: bool,
+        keyUsage: u32,
+        privk: *mut *mut SECKEYPrivateKey,
+        wincx: *const u8,
+    ) -> SECStatus;
+    fn PK11_GetInternalSlot() -> *mut PK11SlotInfo;
+    fn PK11_FreeSlot(slot: *mut PK11SlotInfo);
+    fn PK11_SignatureLen(key: *const SECKEYPrivateKey) -> usize;
+    fn PK11_SignWithMechanism(
+        key: *const SECKEYPrivateKey,
+        mech: CkMechanismType,
+        param: *const SECItem,
+        sig: *mut SECItemMut,
+        hash: *const SECItem,
+    ) -> SECStatus;
+}
+
+/// An error type describing errors that may be encountered during verification.
+#[derive(Debug, PartialEq)]
+pub enum NSSError {
+    ImportCertError,
+    DecodingPKCS8Failed,
+    InputTooLarge,
+    LibraryFailure,
+    SignatureVerificationFailed,
+    SigningFailed,
+    ExtractPublicKeyFailed,
+}
+
+// https://searchfox.org/nss/rev/990c2e793aa731cd66238c6c4f00b9473943bc66/lib/util/secoidt.h#274
+#[derive(Debug, PartialEq, Clone)]
+#[repr(C)]
+enum HashAlgorithm {
+    SHA256 = 191,
+    SHA384 = 192,
+    SHA512 = 193,
+}
+
+fn hash(payload: &[u8], signature_algorithm: &SignatureAlgorithm) -> Result<Vec<u8>, NSSError> {
+    if payload.len() > raw::c_int::max_value() as usize {
+        return Err(NSSError::InputTooLarge);
+    }
+    let (hash_algorithm, digest_length) = match *signature_algorithm {
+        SignatureAlgorithm::ES256 => (HashAlgorithm::SHA256, SHA256_LENGTH),
+        SignatureAlgorithm::ES384 => (HashAlgorithm::SHA384, SHA384_LENGTH),
+        SignatureAlgorithm::ES512 => (HashAlgorithm::SHA512, SHA512_LENGTH),
+        SignatureAlgorithm::PS256 => (HashAlgorithm::SHA256, SHA256_LENGTH),
+    };
+    let mut hash_buf = vec![0; digest_length];
+    let len: raw::c_int = payload.len() as raw::c_int;
+    let hash_result =
+        unsafe { PK11_HashBuf(hash_algorithm, hash_buf.as_mut_ptr(), payload.as_ptr(), len) };
+    if hash_result != SEC_SUCCESS {
+        return Err(NSSError::LibraryFailure);
+    }
+    Ok(hash_buf)
+}
+
+/// Main entrypoint for verification. Given a signature algorithm, the bytes of a subject public key
+/// info, a payload, and a signature over the payload, returns a result based on the outcome of
+/// decoding the subject public key info and running the signature verification algorithm on the
+/// signed data.
+pub fn verify_signature(
+    signature_algorithm: &SignatureAlgorithm,
+    cert: &[u8],
+    payload: &[u8],
+    signature: &[u8],
+) -> Result<(), NSSError> {
+    let slot = unsafe { PK11_GetInternalSlot() };
+    if slot.is_null() {
+        return Err(NSSError::LibraryFailure);
+    }
+    defer!(unsafe {
+        PK11_FreeSlot(slot);
+    });
+
+    let hash_buf = hash(payload, signature_algorithm).unwrap();
+    let hash_item = SECItem::maybe_new(hash_buf.as_slice())?;
+
+    // Import DER cert into NSS.
+    let der_cert = SECItem::maybe_new(cert)?;
+    let db_handle = unsafe { CERT_GetDefaultCertDB() };
+    if db_handle.is_null() {
+        // TODO #28
+        return Err(NSSError::LibraryFailure);
+    }
+    let nss_cert =
+        unsafe { CERT_NewTempCertificate(db_handle, &der_cert, ptr::null(), false, true) };
+    if nss_cert.is_null() {
+        return Err(NSSError::ImportCertError);
+    }
+    defer!(unsafe {
+        CERT_DestroyCertificate(nss_cert);
+    });
+
+    let key = unsafe { CERT_ExtractPublicKey(nss_cert) };
+    if key.is_null() {
+        return Err(NSSError::ExtractPublicKeyFailed);
+    }
+    defer!(unsafe {
+        SECKEY_DestroyPublicKey(key);
+    });
+    let signature_item = SECItem::maybe_new(signature)?;
+    let mechanism = match *signature_algorithm {
+        SignatureAlgorithm::ES256 => CKM_ECDSA,
+        SignatureAlgorithm::ES384 => CKM_ECDSA,
+        SignatureAlgorithm::ES512 => CKM_ECDSA,
+        SignatureAlgorithm::PS256 => CKM_RSA_PKCS_PSS,
+    };
+    let rsa_pss_params = CkRsaPkcsPssParams::new();
+    let rsa_pss_params_item = rsa_pss_params.get_params_item()?;
+    let params_item = match *signature_algorithm {
+        SignatureAlgorithm::ES256 => ptr::null(),
+        SignatureAlgorithm::ES384 => ptr::null(),
+        SignatureAlgorithm::ES512 => ptr::null(),
+        SignatureAlgorithm::PS256 => &rsa_pss_params_item,
+    };
+    let null_cx_ptr: *const raw::c_void = ptr::null();
+    let result = unsafe {
+        PK11_VerifyWithMechanism(
+            key,
+            mechanism,
+            params_item,
+            &signature_item,
+            &hash_item,
+            null_cx_ptr,
+        )
+    };
+    match result {
+        SEC_SUCCESS => Ok(()),
+        SEC_FAILURE => Err(NSSError::SignatureVerificationFailed),
+        _ => Err(NSSError::LibraryFailure),
+    }
+}
+
+pub fn sign(
+    signature_algorithm: &SignatureAlgorithm,
+    pk8: &[u8],
+    payload: &[u8],
+) -> Result<Vec<u8>, NSSError> {
+    let slot = unsafe { PK11_GetInternalSlot() };
+    if slot.is_null() {
+        return Err(NSSError::LibraryFailure);
+    }
+    defer!(unsafe {
+        PK11_FreeSlot(slot);
+    });
+    let pkcs8item = SECItem::maybe_new(pk8)?;
+    let mut key: *mut SECKEYPrivateKey = ptr::null_mut();
+    let ku_all = 0xFF;
+    let rv = unsafe {
+        PK11_ImportDERPrivateKeyInfoAndReturnKey(
+            slot,
+            &pkcs8item,
+            ptr::null(),
+            ptr::null(),
+            false,
+            false,
+            ku_all,
+            &mut key,
+            ptr::null(),
+        )
+    };
+    if rv != SEC_SUCCESS || key.is_null() {
+        return Err(NSSError::DecodingPKCS8Failed);
+    }
+    let mechanism = match *signature_algorithm {
+        SignatureAlgorithm::ES256 => CKM_ECDSA,
+        SignatureAlgorithm::ES384 => CKM_ECDSA,
+        SignatureAlgorithm::ES512 => CKM_ECDSA,
+        SignatureAlgorithm::PS256 => CKM_RSA_PKCS_PSS,
+    };
+    let rsa_pss_params = CkRsaPkcsPssParams::new();
+    let rsa_pss_params_item = rsa_pss_params.get_params_item()?;
+    let params_item = match *signature_algorithm {
+        SignatureAlgorithm::ES256 => ptr::null(),
+        SignatureAlgorithm::ES384 => ptr::null(),
+        SignatureAlgorithm::ES512 => ptr::null(),
+        SignatureAlgorithm::PS256 => &rsa_pss_params_item,
+    };
+    let signature_len = unsafe { PK11_SignatureLen(key) };
+    // Allocate enough space for the signature.
+    let mut signature: Vec<u8> = Vec::with_capacity(signature_len);
+    let hash_buf = hash(payload, signature_algorithm).unwrap();
+    let hash_item = SECItem::maybe_new(hash_buf.as_slice())?;
+    {
+        // Get a mutable SECItem on the preallocated signature buffer. PK11_SignWithMechanism will
+        // fill the SECItem's buf with the bytes of the signature.
+        let mut signature_item = SECItemMut::maybe_from_empty_preallocated_vec(&mut signature)?;
+        let rv = unsafe {
+            PK11_SignWithMechanism(key, mechanism, params_item, &mut signature_item, &hash_item)
+        };
+        if rv != SEC_SUCCESS || signature_item.len as usize != signature_len {
+            return Err(NSSError::SigningFailed);
+        }
+    }
+    unsafe {
+        // Now that the bytes of the signature have been filled out, set its length.
+        signature.set_len(signature_len);
+    }
+    Ok(signature)
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cose/examples/sign_verify/test_nss.rs
@@ -0,0 +1,65 @@
+use test_setup as test;
+use nss;
+use nss::NSSError;
+use SignatureAlgorithm;
+
+pub fn test_nss_sign_verify() {
+    test::setup();
+    let payload = b"sample";
+
+    // Sign.
+    let signature_result = nss::sign(&SignatureAlgorithm::ES256, &test::PKCS8_P256_EE, payload);
+    assert!(signature_result.is_ok());
+    let signature_result = signature_result.unwrap();
+
+    // Verify the signature.
+    assert!(
+        nss::verify_signature(
+            &SignatureAlgorithm::ES256,
+            &test::P256_EE,
+            payload,
+            &signature_result,
+        ).is_ok()
+    );
+}
+
+pub fn test_nss_sign_verify_different_payload() {
+    test::setup();
+    let payload = b"sample";
+
+    // Sign.
+    let signature_result = nss::sign(&SignatureAlgorithm::ES256, &test::PKCS8_P256_EE, payload);
+    assert!(signature_result.is_ok());
+    let signature_result = signature_result.unwrap();
+
+    // Verify the signature with a different payload.
+    let payload = b"sampli";
+    let verify_result = nss::verify_signature(
+        &SignatureAlgorithm::ES256,
+        &test::P256_EE,
+        payload,
+        &signature_result,
+    );
+    assert!(verify_result.is_err());
+    assert_eq!(verify_result, Err(NSSError::SignatureVerificationFailed));
+}
+
+pub fn test_nss_sign_verify_wrong_cert() {
+    test::setup();
+    let payload = b"sample";
+
+    // Sign.
+    let signature_result = nss::sign(&SignatureAlgorithm::ES256, &test::PKCS8_P256_EE, payload);
+    assert!(signature_result.is_ok());
+    let signature_result = signature_result.unwrap();
+
+    // Verify the signature with a wrong cert.
+    let verify_result = nss::verify_signature(
+        &SignatureAlgorithm::ES256,
+        &test::P384_EE,
+        payload,
+        &signature_result,
+    );
+    assert!(verify_result.is_err());
+    assert_eq!(verify_result, Err(NSSError::SignatureVerificationFailed));
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cose/examples/sign_verify/test_setup.rs
@@ -0,0 +1,625 @@
+use std::os::raw;
+use std::ptr;
+use std::sync::{ONCE_INIT, Once};
+static START: Once = ONCE_INIT;
+
+type SECStatus = raw::c_int;
+const SEC_SUCCESS: SECStatus = 0;
+// TODO: ugh this will probably have a platform-specific name...
+#[link(name = "nss3")]
+extern "C" {
+    fn NSS_NoDB_Init(configdir: *const u8) -> SECStatus;
+}
+
+pub fn setup() {
+    START.call_once(|| {
+        let null_ptr: *const u8 = ptr::null();
+        unsafe {
+            assert_eq!(NSS_NoDB_Init(null_ptr), SEC_SUCCESS);
+        }
+    });
+}
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const PKCS8_P256_EE: [u8; 139] = [
+    0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a,
+    0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
+    0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01,
+    0x01, 0x04, 0x20, 0x21, 0x91, 0x40, 0x3d, 0x57, 0x10, 0xbf, 0x15,
+    0xa2, 0x65, 0x81, 0x8c, 0xd4, 0x2e, 0xd6, 0xfe, 0xdf, 0x09, 0xad,
+    0xd9, 0x2d, 0x78, 0xb1, 0x8e, 0x7a, 0x1e, 0x9f, 0xeb, 0x95, 0x52,
+    0x47, 0x02, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x4f, 0xbf, 0xbb,
+    0xbb, 0x61, 0xe0, 0xf8, 0xf9, 0xb1, 0xa6, 0x0a, 0x59, 0xac, 0x87,
+    0x04, 0xe2, 0xec, 0x05, 0x0b, 0x42, 0x3e, 0x3c, 0xf7, 0x2e, 0x92,
+    0x3f, 0x2c, 0x4f, 0x79, 0x4b, 0x45, 0x5c, 0x2a, 0x69, 0xd2, 0x33,
+    0x45, 0x6c, 0x36, 0xc4, 0x11, 0x9d, 0x07, 0x06, 0xe0, 0x0e, 0xed,
+    0xc8, 0xd1, 0x93, 0x90, 0xd7, 0x99, 0x1b, 0x7b, 0x2d, 0x07, 0xa3,
+    0x04, 0xea, 0xa0, 0x4a, 0xa6, 0xc0, 0x0a
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const P256_EE: [u8; 300] = [
+    0x30, 0x82, 0x01, 0x28, 0x30, 0x81, 0xcf, 0xa0, 0x03, 0x02, 0x01, 0x02,
+    0x02, 0x14, 0x2f, 0xc3, 0x5f, 0x05, 0x80, 0xb4, 0x49, 0x45, 0x13, 0x92,
+    0xd6, 0x93, 0xb7, 0x2d, 0x71, 0x19, 0xc5, 0x8c, 0x40, 0x39, 0x30, 0x0a,
+    0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x13,
+    0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x69,
+    0x6e, 0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x22, 0x18, 0x0f, 0x32,
+    0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30,
+    0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32, 0x33, 0x31,
+    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x12, 0x31, 0x10, 0x30,
+    0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, 0x65, 0x65, 0x2d, 0x70,
+    0x32, 0x35, 0x36, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48,
+    0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03,
+    0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4f, 0xbf, 0xbb, 0xbb, 0x61, 0xe0,
+    0xf8, 0xf9, 0xb1, 0xa6, 0x0a, 0x59, 0xac, 0x87, 0x04, 0xe2, 0xec, 0x05,
+    0x0b, 0x42, 0x3e, 0x3c, 0xf7, 0x2e, 0x92, 0x3f, 0x2c, 0x4f, 0x79, 0x4b,
+    0x45, 0x5c, 0x2a, 0x69, 0xd2, 0x33, 0x45, 0x6c, 0x36, 0xc4, 0x11, 0x9d,
+    0x07, 0x06, 0xe0, 0x0e, 0xed, 0xc8, 0xd1, 0x93, 0x90, 0xd7, 0x99, 0x1b,
+    0x7b, 0x2d, 0x07, 0xa3, 0x04, 0xea, 0xa0, 0x4a, 0xa6, 0xc0, 0x30, 0x0a,
+    0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48,
+    0x00, 0x30, 0x45, 0x02, 0x20, 0x5c, 0x75, 0x51, 0x9f, 0x13, 0x11, 0x50,
+    0xcd, 0x5d, 0x8a, 0xde, 0x20, 0xa3, 0xbc, 0x06, 0x30, 0x91, 0xff, 0xb2,
+    0x73, 0x75, 0x5f, 0x31, 0x64, 0xec, 0xfd, 0xcb, 0x42, 0x80, 0x0a, 0x70,
+    0xe6, 0x02, 0x21, 0x00, 0xff, 0x81, 0xbe, 0xa8, 0x0d, 0x03, 0x36, 0x6b,
+    0x75, 0xe2, 0x70, 0x6a, 0xac, 0x07, 0x2e, 0x4c, 0xdc, 0xf9, 0xc5, 0x89,
+    0xc1, 0xcf, 0x88, 0xc2, 0xc8, 0x2a, 0x32, 0xf5, 0x42, 0x0c, 0xfa, 0x0b
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const PKCS8_P384_EE: [u8; 185] = [
+    0x30, 0x81, 0xb6, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86,
+    0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22,
+    0x04, 0x81, 0x9e, 0x30, 0x81, 0x9b, 0x02, 0x01, 0x01, 0x04, 0x30, 0x03,
+    0x5c, 0x7a, 0x1b, 0x10, 0xd9, 0xfa, 0xfe, 0x83, 0x7b, 0x64, 0xad, 0x92,
+    0xf2, 0x2f, 0x5c, 0xed, 0x07, 0x89, 0x18, 0x65, 0x38, 0x66, 0x9b, 0x5c,
+    0x6d, 0x87, 0x2c, 0xec, 0x3d, 0x92, 0x61, 0x22, 0xb3, 0x93, 0x77, 0x2b,
+    0x57, 0x60, 0x2f, 0xf3, 0x13, 0x65, 0xef, 0xe1, 0x39, 0x32, 0x46, 0xa1,
+    0x64, 0x03, 0x62, 0x00, 0x04, 0xa1, 0x68, 0x72, 0x43, 0x36, 0x2b, 0x5c,
+    0x7b, 0x18, 0x89, 0xf3, 0x79, 0x15, 0x46, 0x15, 0xa1, 0xc7, 0x3f, 0xb4,
+    0x8d, 0xee, 0x86, 0x3e, 0x02, 0x29, 0x15, 0xdb, 0x60, 0x8e, 0x25, 0x2d,
+    0xe4, 0xb7, 0x13, 0x2d, 0xa8, 0xce, 0x98, 0xe8, 0x31, 0x53, 0x4e, 0x6a,
+    0x9c, 0x0c, 0x0b, 0x09, 0xc8, 0xd6, 0x39, 0xad, 0xe8, 0x32, 0x06, 0xe5,
+    0xba, 0x81, 0x34, 0x73, 0xa1, 0x1f, 0xa3, 0x30, 0xe0, 0x5d, 0xa8, 0xc9,
+    0x6e, 0x43, 0x83, 0xfe, 0x27, 0x87, 0x3d, 0xa9, 0x71, 0x03, 0xbe, 0x28,
+    0x88, 0xcf, 0xf0, 0x02, 0xf0, 0x5a, 0xf7, 0x1a, 0x1f, 0xdd, 0xcc, 0x83,
+    0x74, 0xaa, 0x6e, 0xa9, 0xce
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const PKCS8_P521_EE: [u8; 240] = [
+    0x30, 0x81, 0xed, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86,
+    0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23,
+    0x04, 0x81, 0xd5, 0x30, 0x81, 0xd2, 0x02, 0x01, 0x01, 0x04, 0x42, 0x01,
+    0x4f, 0x32, 0x84, 0xfa, 0x69, 0x8d, 0xd9, 0xfe, 0x11, 0x18, 0xdd, 0x33,
+    0x18, 0x51, 0xcd, 0xfa, 0xac, 0x5a, 0x38, 0x29, 0x27, 0x8e, 0xb8, 0x99,
+    0x48, 0x39, 0xde, 0x94, 0x71, 0xc9, 0x40, 0xb8, 0x58, 0xc6, 0x9d, 0x2d,
+    0x05, 0xe8, 0xc0, 0x17, 0x88, 0xa7, 0xd0, 0xb6, 0xe2, 0x35, 0xaa, 0x5e,
+    0x78, 0x3f, 0xc1, 0xbe, 0xe8, 0x07, 0xdc, 0xc3, 0x86, 0x5f, 0x92, 0x0e,
+    0x12, 0xcf, 0x8f, 0x2d, 0x29, 0xa1, 0x81, 0x88, 0x03, 0x81, 0x85, 0x00,
+    0x04, 0x18, 0x94, 0x55, 0x0d, 0x07, 0x85, 0x93, 0x2e, 0x00, 0xea, 0xa2,
+    0x3b, 0x69, 0x4f, 0x21, 0x3f, 0x8c, 0x31, 0x21, 0xf8, 0x6d, 0xc9, 0x7a,
+    0x04, 0xe5, 0xa7, 0x16, 0x7d, 0xb4, 0xe5, 0xbc, 0xd3, 0x71, 0x12, 0x3d,
+    0x46, 0xe4, 0x5d, 0xb6, 0xb5, 0xd5, 0x37, 0x0a, 0x7f, 0x20, 0xfb, 0x63,
+    0x31, 0x55, 0xd3, 0x8f, 0xfa, 0x16, 0xd2, 0xbd, 0x76, 0x1d, 0xca, 0xc4,
+    0x74, 0xb9, 0xa2, 0xf5, 0x02, 0x3a, 0x40, 0x49, 0x31, 0x01, 0xc9, 0x62,
+    0xcd, 0x4d, 0x2f, 0xdd, 0xf7, 0x82, 0x28, 0x5e, 0x64, 0x58, 0x41, 0x39,
+    0xc2, 0xf9, 0x1b, 0x47, 0xf8, 0x7f, 0xf8, 0x23, 0x54, 0xd6, 0x63, 0x0f,
+    0x74, 0x6a, 0x28, 0xa0, 0xdb, 0x25, 0x74, 0x1b, 0x5b, 0x34, 0xa8, 0x28,
+    0x00, 0x8b, 0x22, 0xac, 0xc2, 0x3f, 0x92, 0x4f, 0xaa, 0xfb, 0xd4, 0xd3,
+    0x3f, 0x81, 0xea, 0x66, 0x95, 0x6d, 0xfe, 0xaa, 0x2b, 0xfd, 0xfc, 0xf5
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const P521_EE: [u8; 367] = [
+    0x30, 0x82, 0x01, 0x6b, 0x30, 0x82, 0x01, 0x12, 0xa0, 0x03, 0x02, 0x01,
+    0x02, 0x02, 0x14, 0x49, 0xdb, 0x7d, 0xec, 0x87, 0x2b, 0x95, 0xfc, 0xfb,
+    0x57, 0xfb, 0xc8, 0xd5, 0x57, 0xb7, 0x3a, 0x10, 0xcc, 0xf1, 0x7a, 0x30,
+    0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30,
+    0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+    0x69, 0x6e, 0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x22, 0x18, 0x0f,
+    0x32, 0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32, 0x33,
+    0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x12, 0x31, 0x10,
+    0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, 0x65, 0x65, 0x2d,
+    0x70, 0x35, 0x32, 0x31, 0x30, 0x81, 0x9b, 0x30, 0x10, 0x06, 0x07, 0x2a,
+    0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00,
+    0x23, 0x03, 0x81, 0x86, 0x00, 0x04, 0x01, 0x4c, 0xdc, 0x9c, 0xac, 0xc4,
+    0x79, 0x41, 0x09, 0x6b, 0xc9, 0xcc, 0x66, 0x75, 0x2e, 0xc2, 0x7f, 0x59,
+    0x77, 0x34, 0xfa, 0x66, 0xc6, 0x2b, 0x79, 0x2f, 0x88, 0xc5, 0x19, 0xd6,
+    0xd3, 0x7f, 0x0d, 0x16, 0xea, 0x1c, 0x48, 0x3a, 0x18, 0x27, 0xa0, 0x10,
+    0xb9, 0x12, 0x8e, 0x3a, 0x08, 0x07, 0x0c, 0xa3, 0x3e, 0xf5, 0xf5, 0x78,
+    0x35, 0xb7, 0xc1, 0xba, 0x25, 0x1f, 0x6c, 0xc3, 0x52, 0x1d, 0xc4, 0x2b,
+    0x01, 0x06, 0x53, 0x45, 0x19, 0x81, 0xb4, 0x45, 0xd3, 0x43, 0xee, 0xd3,
+    0x78, 0x2a, 0x35, 0xd6, 0xcf, 0xf0, 0xff, 0x48, 0x4f, 0x5a, 0x88, 0x3d,
+    0x20, 0x9f, 0x1b, 0x90, 0x42, 0xb7, 0x26, 0x70, 0x35, 0x68, 0xb2, 0xf3,
+    0x26, 0xe1, 0x8b, 0x83, 0x3b, 0xdd, 0x8a, 0xa0, 0x73, 0x43, 0x92, 0xbc,
+    0xd1, 0x95, 0x01, 0xe1, 0x0d, 0x69, 0x8a, 0x79, 0xf5, 0x3e, 0x11, 0xe0,
+    0xa2, 0x2b, 0xdd, 0x2a, 0xad, 0x90, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86,
+    0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02,
+    0x20, 0x5c, 0x75, 0x51, 0x9f, 0x13, 0x11, 0x50, 0xcd, 0x5d, 0x8a, 0xde,
+    0x20, 0xa3, 0xbc, 0x06, 0x30, 0x91, 0xff, 0xb2, 0x73, 0x75, 0x5f, 0x31,
+    0x64, 0xec, 0xfd, 0xcb, 0x42, 0x80, 0x0a, 0x70, 0xe6, 0x02, 0x20, 0x35,
+    0x20, 0x7c, 0xff, 0x51, 0xf6, 0x68, 0xce, 0x1d, 0x00, 0xf9, 0xcc, 0x7f,
+    0xa7, 0xbc, 0x79, 0x52, 0xea, 0x56, 0xdf, 0xc1, 0x46, 0x7c, 0x0c, 0xa1,
+    0x2e, 0x32, 0xb1, 0x69, 0x4b, 0x20, 0xc4
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const P384_EE: [u8; 329] = [
+    0x30, 0x82, 0x01, 0x45, 0x30, 0x81, 0xec, 0xa0, 0x03, 0x02, 0x01, 0x02,
+    0x02, 0x14, 0x79, 0xe3, 0x1c, 0x60, 0x97, 0xa4, 0x3c, 0x3b, 0x82, 0x11,
+    0x42, 0x37, 0xaf, 0x57, 0x05, 0xa8, 0xde, 0xd3, 0x40, 0x58, 0x30, 0x0a,
+    0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x13,
+    0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x69,
+    0x6e, 0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x22, 0x18, 0x0f, 0x32,
+    0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30,
+    0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32, 0x33, 0x31,
+    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x12, 0x31, 0x10, 0x30,
+    0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, 0x65, 0x65, 0x2d, 0x70,
+    0x33, 0x38, 0x34, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48,
+    0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03,
+    0x62, 0x00, 0x04, 0xa1, 0x68, 0x72, 0x43, 0x36, 0x2b, 0x5c, 0x7b, 0x18,
+    0x89, 0xf3, 0x79, 0x15, 0x46, 0x15, 0xa1, 0xc7, 0x3f, 0xb4, 0x8d, 0xee,
+    0x86, 0x3e, 0x02, 0x29, 0x15, 0xdb, 0x60, 0x8e, 0x25, 0x2d, 0xe4, 0xb7,
+    0x13, 0x2d, 0xa8, 0xce, 0x98, 0xe8, 0x31, 0x53, 0x4e, 0x6a, 0x9c, 0x0c,
+    0x0b, 0x09, 0xc8, 0xd6, 0x39, 0xad, 0xe8, 0x32, 0x06, 0xe5, 0xba, 0x81,
+    0x34, 0x73, 0xa1, 0x1f, 0xa3, 0x30, 0xe0, 0x5d, 0xa8, 0xc9, 0x6e, 0x43,
+    0x83, 0xfe, 0x27, 0x87, 0x3d, 0xa9, 0x71, 0x03, 0xbe, 0x28, 0x88, 0xcf,
+    0xf0, 0x02, 0xf0, 0x5a, 0xf7, 0x1a, 0x1f, 0xdd, 0xcc, 0x83, 0x74, 0xaa,
+    0x6e, 0xa9, 0xce, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+    0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x20, 0x5c, 0x75,
+    0x51, 0x9f, 0x13, 0x11, 0x50, 0xcd, 0x5d, 0x8a, 0xde, 0x20, 0xa3, 0xbc,
+    0x06, 0x30, 0x91, 0xff, 0xb2, 0x73, 0x75, 0x5f, 0x31, 0x64, 0xec, 0xfd,
+    0xcb, 0x42, 0x80, 0x0a, 0x70, 0xe6, 0x02, 0x21, 0x00, 0xf3, 0x04, 0x26,
+    0xf2, 0xfd, 0xbc, 0x89, 0x3f, 0x29, 0x3b, 0x70, 0xbc, 0x72, 0xa6, 0xc2,
+    0x23, 0xcc, 0x43, 0x4d, 0x84, 0x71, 0xaf, 0x53, 0xe4, 0x4b, 0x3e, 0xc0,
+    0xbf, 0xe5, 0x68, 0x86, 0x49
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const P256_INT: [u8; 332] = [
+    0x30, 0x82, 0x01, 0x48, 0x30, 0x81, 0xf0, 0xa0, 0x03, 0x02, 0x01,
+    0x02, 0x02, 0x14, 0x43, 0x63, 0x59, 0xad, 0x04, 0x34, 0x56, 0x80,
+    0x43, 0xec, 0x90, 0x6a, 0xd4, 0x10, 0x64, 0x7c, 0x7f, 0x38, 0x32,
+    0xe2, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
+    0x03, 0x02, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
+    0x04, 0x03, 0x0c, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x32,
+    0x35, 0x36, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x32, 0x30,
+    0x31, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18,
+    0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32, 0x33, 0x31, 0x30, 0x30,
+    0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f,
+    0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x69, 0x6e, 0x74, 0x2d,
+    0x70, 0x32, 0x35, 0x36, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a,
+    0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
+    0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4f, 0xbf,
+    0xbb, 0xbb, 0x61, 0xe0, 0xf8, 0xf9, 0xb1, 0xa6, 0x0a, 0x59, 0xac,
+    0x87, 0x04, 0xe2, 0xec, 0x05, 0x0b, 0x42, 0x3e, 0x3c, 0xf7, 0x2e,
+    0x92, 0x3f, 0x2c, 0x4f, 0x79, 0x4b, 0x45, 0x5c, 0x2a, 0x69, 0xd2,
+    0x33, 0x45, 0x6c, 0x36, 0xc4, 0x11, 0x9d, 0x07, 0x06, 0xe0, 0x0e,
+    0xed, 0xc8, 0xd1, 0x93, 0x90, 0xd7, 0x99, 0x1b, 0x7b, 0x2d, 0x07,
+    0xa3, 0x04, 0xea, 0xa0, 0x4a, 0xa6, 0xc0, 0xa3, 0x1d, 0x30, 0x1b,
+    0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03,
+    0x01, 0x01, 0xff, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04,
+    0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86,
+    0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44,
+    0x02, 0x20, 0x63, 0x59, 0x02, 0x01, 0x89, 0xd7, 0x3e, 0x5b, 0xff,
+    0xd1, 0x16, 0x4e, 0xe3, 0xe2, 0x0a, 0xe0, 0x4a, 0xd8, 0x75, 0xaf,
+    0x77, 0x5c, 0x93, 0x60, 0xba, 0x10, 0x1f, 0x97, 0xdd, 0x27, 0x2d,
+    0x24, 0x02, 0x20, 0x3d, 0x87, 0x0f, 0xac, 0x22, 0x4d, 0x16, 0xd9,
+    0xa1, 0x95, 0xbb, 0x56, 0xe0, 0x21, 0x05, 0x93, 0xd1, 0x07, 0xb5,
+    0x25, 0x3b, 0xf4, 0x57, 0x20, 0x87, 0x13, 0xa2, 0xf7, 0x78, 0x15,
+    0x30, 0xa7
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const P256_ROOT: [u8; 334] = [
+    0x30, 0x82, 0x01, 0x4a, 0x30, 0x81, 0xf1, 0xa0, 0x03, 0x02, 0x01, 0x02,
+    0x02, 0x14, 0x5f, 0x3f, 0xae, 0x90, 0x49, 0x30, 0x2f, 0x33, 0x6e, 0x95,
+    0x23, 0xa7, 0xcb, 0x23, 0xd7, 0x65, 0x4f, 0xea, 0x3c, 0xf7, 0x30, 0x0a,
+    0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x14,
+    0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x72,
+    0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x22, 0x18, 0x0f,
+    0x32, 0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32, 0x33,
+    0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x14, 0x31, 0x12,
+    0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x72, 0x6f, 0x6f,
+    0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
+    0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
+    0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4f, 0xbf, 0xbb,
+    0xbb, 0x61, 0xe0, 0xf8, 0xf9, 0xb1, 0xa6, 0x0a, 0x59, 0xac, 0x87, 0x04,
+    0xe2, 0xec, 0x05, 0x0b, 0x42, 0x3e, 0x3c, 0xf7, 0x2e, 0x92, 0x3f, 0x2c,
+    0x4f, 0x79, 0x4b, 0x45, 0x5c, 0x2a, 0x69, 0xd2, 0x33, 0x45, 0x6c, 0x36,
+    0xc4, 0x11, 0x9d, 0x07, 0x06, 0xe0, 0x0e, 0xed, 0xc8, 0xd1, 0x93, 0x90,
+    0xd7, 0x99, 0x1b, 0x7b, 0x2d, 0x07, 0xa3, 0x04, 0xea, 0xa0, 0x4a, 0xa6,
+    0xc0, 0xa3, 0x1d, 0x30, 0x1b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+    0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0b, 0x06, 0x03, 0x55,
+    0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0a, 0x06, 0x08,
+    0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30,
+    0x45, 0x02, 0x20, 0x5c, 0x75, 0x51, 0x9f, 0x13, 0x11, 0x50, 0xcd, 0x5d,
+    0x8a, 0xde, 0x20, 0xa3, 0xbc, 0x06, 0x30, 0x91, 0xff, 0xb2, 0x73, 0x75,
+    0x5f, 0x31, 0x64, 0xec, 0xfd, 0xcb, 0x42, 0x80, 0x0a, 0x70, 0xe6, 0x02,
+    0x21, 0x00, 0xc2, 0xe4, 0xc1, 0xa8, 0xe2, 0x89, 0xdc, 0xa1, 0xbb, 0xe7,
+    0xd5, 0x4f, 0x5c, 0x88, 0xad, 0xeb, 0xa4, 0x78, 0xa1, 0x19, 0xbe, 0x22,
+    0x54, 0xc8, 0x9f, 0xef, 0xb8, 0x5d, 0xa2, 0x40, 0xd9, 0x8b
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const PKCS8_RSA_EE: [u8; 1218] = [
+    0x30, 0x82, 0x04, 0xbe, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
+    0x04, 0xa8, 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01,
+    0x01, 0x00, 0xba, 0x88, 0x51, 0xa8, 0x44, 0x8e, 0x16, 0xd6, 0x41, 0xfd,
+    0x6e, 0xb6, 0x88, 0x06, 0x36, 0x10, 0x3d, 0x3c, 0x13, 0xd9, 0xea, 0xe4,
+    0x35, 0x4a, 0xb4, 0xec, 0xf5, 0x68, 0x57, 0x6c, 0x24, 0x7b, 0xc1, 0xc7,
+    0x25, 0xa8, 0xe0, 0xd8, 0x1f, 0xbd, 0xb1, 0x9c, 0x06, 0x9b, 0x6e, 0x1a,
+    0x86, 0xf2, 0x6b, 0xe2, 0xaf, 0x5a, 0x75, 0x6b, 0x6a, 0x64, 0x71, 0x08,
+    0x7a, 0xa5, 0x5a, 0xa7, 0x45, 0x87, 0xf7, 0x1c, 0xd5, 0x24, 0x9c, 0x02,
+    0x7e, 0xcd, 0x43, 0xfc, 0x1e, 0x69, 0xd0, 0x38, 0x20, 0x29, 0x93, 0xab,
+    0x20, 0xc3, 0x49, 0xe4, 0xdb, 0xb9, 0x4c, 0xc2, 0x6b, 0x6c, 0x0e, 0xed,
+    0x15, 0x82, 0x0f, 0xf1, 0x7e, 0xad, 0x69, 0x1a, 0xb1, 0xd3, 0x02, 0x3a,
+    0x8b, 0x2a, 0x41, 0xee, 0xa7, 0x70, 0xe0, 0x0f, 0x0d, 0x8d, 0xfd, 0x66,
+    0x0b, 0x2b, 0xb0, 0x24, 0x92, 0xa4, 0x7d, 0xb9, 0x88, 0x61, 0x79, 0x90,
+    0xb1, 0x57, 0x90, 0x3d, 0xd2, 0x3b, 0xc5, 0xe0, 0xb8, 0x48, 0x1f, 0xa8,
+    0x37, 0xd3, 0x88, 0x43, 0xef, 0x27, 0x16, 0xd8, 0x55, 0xb7, 0x66, 0x5a,
+    0xaa, 0x7e, 0x02, 0x90, 0x2f, 0x3a, 0x7b, 0x10, 0x80, 0x06, 0x24, 0xcc,
+    0x1c, 0x6c, 0x97, 0xad, 0x96, 0x61, 0x5b, 0xb7, 0xe2, 0x96, 0x12, 0xc0,
+    0x75, 0x31, 0xa3, 0x0c, 0x91, 0xdd, 0xb4, 0xca, 0xf7, 0xfc, 0xad, 0x1d,
+    0x25, 0xd3, 0x09, 0xef, 0xb9, 0x17, 0x0e, 0xa7, 0x68, 0xe1, 0xb3, 0x7b,
+    0x2f, 0x22, 0x6f, 0x69, 0xe3, 0xb4, 0x8a, 0x95, 0x61, 0x1d, 0xee, 0x26,
+    0xd6, 0x25, 0x9d, 0xab, 0x91, 0x08, 0x4e, 0x36, 0xcb, 0x1c, 0x24, 0x04,
+    0x2c, 0xbf, 0x16, 0x8b, 0x2f, 0xe5, 0xf1, 0x8f, 0x99, 0x17, 0x31, 0xb8,
+    0xb3, 0xfe, 0x49, 0x23, 0xfa, 0x72, 0x51, 0xc4, 0x31, 0xd5, 0x03, 0xac,
+    0xda, 0x18, 0x0a, 0x35, 0xed, 0x8d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
+    0x82, 0x01, 0x01, 0x00, 0x9e, 0xcb, 0xce, 0x38, 0x61, 0xa4, 0x54, 0xec,
+    0xb1, 0xe0, 0xfe, 0x8f, 0x85, 0xdd, 0x43, 0xc9, 0x2f, 0x58, 0x25, 0xce,
+    0x2e, 0x99, 0x78, 0x84, 0xd0, 0xe1, 0xa9, 0x49, 0xda, 0xa2, 0xc5, 0xac,
+    0x55, 0x9b, 0x24, 0x04, 0x50, 0xe5, 0xac, 0x9f, 0xe0, 0xc3, 0xe3, 0x1c,
+    0x0e, 0xef, 0xa6, 0x52, 0x5a, 0x65, 0xf0, 0xc2, 0x21, 0x94, 0x00, 0x4e,
+    0xe1, 0xab, 0x46, 0x3d, 0xde, 0x9e, 0xe8, 0x22, 0x87, 0xcc, 0x93, 0xe7,
+    0x46, 0xa9, 0x19, 0x29, 0xc5, 0xe6, 0xac, 0x3d, 0x88, 0x75, 0x3f, 0x6c,
+    0x25, 0xba, 0x59, 0x79, 0xe7, 0x3e, 0x5d, 0x8f, 0xb2, 0x39, 0x11, 0x1a,
+    0x3c, 0xda, 0xb8, 0xa4, 0xb0, 0xcd, 0xf5, 0xf9, 0xca, 0xb0, 0x5f, 0x12,
+    0x33, 0xa3, 0x83, 0x35, 0xc6, 0x4b, 0x55, 0x60, 0x52, 0x5e, 0x7e, 0x3b,
+    0x92, 0xad, 0x7c, 0x75, 0x04, 0xcf, 0x1d, 0xc7, 0xcb, 0x00, 0x57, 0x88,
+    0xaf, 0xcb, 0xe1, 0xe8, 0xf9, 0x5d, 0xf7, 0x40, 0x2a, 0x15, 0x15, 0x30,
+    0xd5, 0x80, 0x83, 0x46, 0x86, 0x4e, 0xb3, 0x70, 0xaa, 0x79, 0x95, 0x6a,
+    0x58, 0x78, 0x62, 0xcb, 0x53, 0x37, 0x91, 0x30, 0x7f, 0x70, 0xd9, 0x1c,
+    0x96, 0xd2, 0x2d, 0x00, 0x1a, 0x69, 0x00, 0x9b, 0x92, 0x3c, 0x68, 0x33,
+    0x88, 0xc9, 0xf3, 0x6c, 0xb9, 0xb5, 0xeb, 0xe6, 0x43, 0x02, 0x04, 0x1c,
+    0x78, 0xd9, 0x08, 0x20, 0x6b, 0x87, 0x00, 0x9c, 0xb8, 0xca, 0xba, 0xca,
+    0xd3, 0xdb, 0xdb, 0x27, 0x92, 0xfb, 0x91, 0x1b, 0x2c, 0xf4, 0xdb, 0x66,
+    0x03, 0x58, 0x5b, 0xe9, 0xae, 0x0c, 0xa3, 0xb8, 0xe6, 0x41, 0x7a, 0xa0,
+    0x4b, 0x06, 0xe4, 0x70, 0xea, 0x1a, 0x3b, 0x58, 0x1c, 0xa0, 0x3a, 0x67,
+    0x81, 0xc9, 0x31, 0x5b, 0x62, 0xb3, 0x0e, 0x60, 0x11, 0xf2, 0x24, 0x72,
+    0x59, 0x46, 0xee, 0xc5, 0x7c, 0x6d, 0x94, 0x41, 0x02, 0x81, 0x81, 0x00,
+    0xdd, 0x6e, 0x1d, 0x4f, 0xff, 0xeb, 0xf6, 0x8d, 0x88, 0x9c, 0x4d, 0x11,
+    0x4c, 0xda, 0xaa, 0x9c, 0xaa, 0x63, 0xa5, 0x93, 0x74, 0x28, 0x6c, 0x8a,
+    0x5c, 0x29, 0xa7, 0x17, 0xbb, 0xa6, 0x03, 0x75, 0x64, 0x4d, 0x5c, 0xaa,
+    0x67, 0x4c, 0x4b, 0x8b, 0xc7, 0x32, 0x63, 0x58, 0x64, 0x62, 0x20, 0xe4,
+    0x55, 0x0d, 0x76, 0x08, 0xac, 0x27, 0xd5, 0x5b, 0x6d, 0xb7, 0x4f, 0x8d,
+    0x81, 0x27, 0xef, 0x8f, 0xa0, 0x90, 0x98, 0xb6, 0x91, 0x47, 0xde, 0x06,
+    0x55, 0x73, 0x44, 0x7e, 0x18, 0x3d, 0x22, 0xfe, 0x7d, 0x88, 0x5a, 0xce,
+    0xb5, 0x13, 0xd9, 0x58, 0x1d, 0xd5, 0xe0, 0x7c, 0x1a, 0x90, 0xf5, 0xce,
+    0x08, 0x79, 0xde, 0x13, 0x13, 0x71, 0xec, 0xef, 0xc9, 0xce, 0x72, 0xe9,
+    0xc4, 0x3d, 0xc1, 0x27, 0xd2, 0x38, 0x19, 0x0d, 0xe8, 0x11, 0x77, 0x3c,
+    0xa5, 0xd1, 0x93, 0x01, 0xf4, 0x8c, 0x74, 0x2b, 0x02, 0x81, 0x81, 0x00,
+    0xd7, 0xa7, 0x73, 0xd9, 0xeb, 0xc3, 0x80, 0xa7, 0x67, 0xd2, 0xfe, 0xc0,
+    0x93, 0x4a, 0xd4, 0xe8, 0xb5, 0x66, 0x72, 0x40, 0x77, 0x1a, 0xcd, 0xeb,
+    0xb5, 0xad, 0x79, 0x6f, 0x47, 0x8f, 0xec, 0x4d, 0x45, 0x98, 0x5e, 0xfb,
+    0xc9, 0x53, 0x29, 0x68, 0x28, 0x9c, 0x8d, 0x89, 0x10, 0x2f, 0xad, 0xf2,
+    0x1f, 0x34, 0xe2, 0xdd, 0x49, 0x40, 0xeb, 0xa8, 0xc0, 0x9d, 0x6d, 0x1f,
+    0x16, 0xdc, 0xc2, 0x97, 0x29, 0x77, 0x4c, 0x43, 0x27, 0x5e, 0x92, 0x51,
+    0xdd, 0xbe, 0x49, 0x09, 0xe1, 0xfd, 0x3b, 0xf1, 0xe4, 0xbe, 0xdf, 0x46,
+    0xa3, 0x9b, 0x8b, 0x38, 0x33, 0x28, 0xef, 0x4a, 0xe3, 0xb9, 0x5b, 0x92,
+    0xf2, 0x07, 0x0a, 0xf2, 0x6c, 0x9e, 0x7c, 0x5c, 0x9b, 0x58, 0x7f, 0xed,
+    0xde, 0x05, 0xe8, 0xe7, 0xd8, 0x6c, 0xa5, 0x78, 0x86, 0xfb, 0x16, 0x58,
+    0x10, 0xa7, 0x7b, 0x98, 0x45, 0xbc, 0x31, 0x27, 0x02, 0x81, 0x81, 0x00,
+    0x96, 0x47, 0x2b, 0x41, 0xa6, 0x10, 0xc0, 0xad, 0xe1, 0xaf, 0x22, 0x66,
+    0xc1, 0x60, 0x0e, 0x36, 0x71, 0x35, 0x5b, 0xa4, 0x2d, 0x4b, 0x5a, 0x0e,
+    0xb4, 0xe9, 0xd7, 0xeb, 0x35, 0x81, 0x40, 0x0b, 0xa5, 0xdd, 0x13, 0x2c,
+    0xdb, 0x1a, 0x5e, 0x93, 0x28, 0xc7, 0xbb, 0xc0, 0xbb, 0xb0, 0x15, 0x5e,
+    0xa1, 0x92, 0x97, 0x2e, 0xdf, 0x97, 0xd1, 0x27, 0x51, 0xd8, 0xfc, 0xf6,
+    0xae, 0x57, 0x2a, 0x30, 0xb1, 0xea, 0x30, 0x9a, 0x87, 0x12, 0xdd, 0x4e,
+    0x33, 0x24, 0x1d, 0xb1, 0xee, 0x45, 0x5f, 0xc0, 0x93, 0xf5, 0xbc, 0x9b,
+    0x59, 0x2d, 0x75, 0x6e, 0x66, 0x21, 0x47, 0x4f, 0x32, 0xc0, 0x7a, 0xf2,
+    0x2f, 0xb2, 0x75, 0xd3, 0x40, 0x79, 0x2b, 0x32, 0xba, 0x25, 0x90, 0xbb,
+    0xb2, 0x61, 0xae, 0xfb, 0x95, 0xa2, 0x58, 0xee, 0xa5, 0x37, 0x65, 0x53,
+    0x15, 0xbe, 0x9c, 0x24, 0xd1, 0x91, 0x99, 0x2d, 0x02, 0x81, 0x80, 0x28,
+    0xb4, 0x50, 0xa7, 0xa7, 0x5a, 0x85, 0x64, 0x13, 0xb2, 0xbd, 0xa6, 0xf7,
+    0xa6, 0x3e, 0x3d, 0x96, 0x4f, 0xb9, 0xec, 0xf5, 0x0e, 0x38, 0x23, 0xef,
+    0x6c, 0xc8, 0xe8, 0xfa, 0x26, 0xee, 0x41, 0x3f, 0x8b, 0x9d, 0x12, 0x05,
+    0x54, 0x0f, 0x12, 0xbb, 0xe7, 0xa0, 0xc7, 0x68, 0x28, 0xb7, 0xba, 0x65,
+    0xad, 0x83, 0xcc, 0xa4, 0xd0, 0xfe, 0x2a, 0x22, 0x01, 0x14, 0xe1, 0xb3,
+    0x5d, 0x03, 0xd5, 0xa8, 0x5b, 0xfe, 0x27, 0x06, 0xbd, 0x50, 0xfc, 0xe6,
+    0xcf, 0xcd, 0xd5, 0x71, 0xb4, 0x6c, 0xa6, 0x21, 0xb8, 0xed, 0x47, 0xd6,
+    0x05, 0xbb, 0xe7, 0x65, 0xb0, 0xaa, 0x4a, 0x06, 0x65, 0xac, 0x25, 0x36,
+    0x4d, 0xa2, 0x01, 0x54, 0x03, 0x2e, 0x12, 0x04, 0xb8, 0x55, 0x9d, 0x3e,
+    0x34, 0xfb, 0x5b, 0x17, 0x7c, 0x9a, 0x56, 0xff, 0x93, 0x51, 0x0a, 0x5a,
+    0x4a, 0x62, 0x87, 0xc1, 0x51, 0xde, 0x2d, 0x02, 0x81, 0x80, 0x28, 0x06,
+    0x7b, 0x93, 0x55, 0x80, 0x1d, 0x2e, 0xf5, 0x2d, 0xfa, 0x96, 0xd8, 0xad,
+    0xb5, 0x89, 0x67, 0x3c, 0xf8, 0xee, 0x8a, 0x9c, 0x6f, 0xf7, 0x2a, 0xee,
+    0xab, 0xe9, 0xef, 0x6b, 0xe5, 0x8a, 0x4f, 0x4a, 0xbf, 0x05, 0xf7, 0x88,
+    0x94, 0x7d, 0xc8, 0x51, 0xfd, 0xaa, 0x34, 0x54, 0x21, 0x47, 0xa7, 0x1a,
+    0x24, 0x6b, 0xfb, 0x05, 0x4e, 0xe7, 0x6a, 0xa3, 0x46, 0xab, 0xcd, 0x26,
+    0x92, 0xcf, 0xc9, 0xe4, 0x4c, 0x51, 0xe6, 0xf0, 0x69, 0xc7, 0x35, 0xe0,
+    0x73, 0xba, 0x01, 0x9f, 0x6a, 0x72, 0x14, 0x96, 0x1c, 0x91, 0xb2, 0x68,
+    0x71, 0xca, 0xea, 0xbf, 0x8f, 0x06, 0x44, 0x18, 0xa0, 0x26, 0x90, 0xe3,
+    0x9a, 0x8d, 0x5f, 0xf3, 0x06, 0x7b, 0x7c, 0xdb, 0x7f, 0x50, 0xb1, 0xf5,
+    0x34, 0x18, 0xa7, 0x03, 0x96, 0x6c, 0x4f, 0xc7, 0x74, 0xbf, 0x74, 0x02,
+    0xaf, 0x6c, 0x43, 0x24, 0x7f, 0x43
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const RSA_EE: [u8; 691] = [
+    0x30, 0x82, 0x02, 0xaf, 0x30, 0x82, 0x01, 0x99, 0xa0, 0x03, 0x02, 0x01,
+    0x02, 0x02, 0x14, 0x07, 0x1c, 0x3b, 0x71, 0x08, 0xbe, 0xd7, 0x9f, 0xfd,
+    0xaf, 0x26, 0xb6, 0x08, 0xa3, 0x99, 0x06, 0x77, 0x69, 0x32, 0x7e, 0x30,
+    0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+    0x30, 0x12, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+    0x07, 0x69, 0x6e, 0x74, 0x2d, 0x72, 0x73, 0x61, 0x30, 0x22, 0x18, 0x0f,
+    0x32, 0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32, 0x33,
+    0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x11, 0x31, 0x0f,
+    0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x65, 0x65, 0x2d,
+    0x72, 0x73, 0x61, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
+    0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00,
+    0xba, 0x88, 0x51, 0xa8, 0x44, 0x8e, 0x16, 0xd6, 0x41, 0xfd, 0x6e, 0xb6,
+    0x88, 0x06, 0x36, 0x10, 0x3d, 0x3c, 0x13, 0xd9, 0xea, 0xe4, 0x35, 0x4a,
+    0xb4, 0xec, 0xf5, 0x68, 0x57, 0x6c, 0x24, 0x7b, 0xc1, 0xc7, 0x25, 0xa8,
+    0xe0, 0xd8, 0x1f, 0xbd, 0xb1, 0x9c, 0x06, 0x9b, 0x6e, 0x1a, 0x86, 0xf2,
+    0x6b, 0xe2, 0xaf, 0x5a, 0x75, 0x6b, 0x6a, 0x64, 0x71, 0x08, 0x7a, 0xa5,
+    0x5a, 0xa7, 0x45, 0x87, 0xf7, 0x1c, 0xd5, 0x24, 0x9c, 0x02, 0x7e, 0xcd,
+    0x43, 0xfc, 0x1e, 0x69, 0xd0, 0x38, 0x20, 0x29, 0x93, 0xab, 0x20, 0xc3,
+    0x49, 0xe4, 0xdb, 0xb9, 0x4c, 0xc2, 0x6b, 0x6c, 0x0e, 0xed, 0x15, 0x82,
+    0x0f, 0xf1, 0x7e, 0xad, 0x69, 0x1a, 0xb1, 0xd3, 0x02, 0x3a, 0x8b, 0x2a,
+    0x41, 0xee, 0xa7, 0x70, 0xe0, 0x0f, 0x0d, 0x8d, 0xfd, 0x66, 0x0b, 0x2b,
+    0xb0, 0x24, 0x92, 0xa4, 0x7d, 0xb9, 0x88, 0x61, 0x79, 0x90, 0xb1, 0x57,
+    0x90, 0x3d, 0xd2, 0x3b, 0xc5, 0xe0, 0xb8, 0x48, 0x1f, 0xa8, 0x37, 0xd3,
+    0x88, 0x43, 0xef, 0x27, 0x16, 0xd8, 0x55, 0xb7, 0x66, 0x5a, 0xaa, 0x7e,
+    0x02, 0x90, 0x2f, 0x3a, 0x7b, 0x10, 0x80, 0x06, 0x24, 0xcc, 0x1c, 0x6c,
+    0x97, 0xad, 0x96, 0x61, 0x5b, 0xb7, 0xe2, 0x96, 0x12, 0xc0, 0x75, 0x31,
+    0xa3, 0x0c, 0x91, 0xdd, 0xb4, 0xca, 0xf7, 0xfc, 0xad, 0x1d, 0x25, 0xd3,
+    0x09, 0xef, 0xb9, 0x17, 0x0e, 0xa7, 0x68, 0xe1, 0xb3, 0x7b, 0x2f, 0x22,
+    0x6f, 0x69, 0xe3, 0xb4, 0x8a, 0x95, 0x61, 0x1d, 0xee, 0x26, 0xd6, 0x25,
+    0x9d, 0xab, 0x91, 0x08, 0x4e, 0x36, 0xcb, 0x1c, 0x24, 0x04, 0x2c, 0xbf,
+    0x16, 0x8b, 0x2f, 0xe5, 0xf1, 0x8f, 0x99, 0x17, 0x31, 0xb8, 0xb3, 0xfe,
+    0x49, 0x23, 0xfa, 0x72, 0x51, 0xc4, 0x31, 0xd5, 0x03, 0xac, 0xda, 0x18,
+    0x0a, 0x35, 0xed, 0x8d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0b, 0x06,
+    0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x03, 0x82,
+    0x01, 0x01, 0x00, 0x44, 0x92, 0xbb, 0x8e, 0x83, 0x58, 0x56, 0x2e, 0x7a,
+    0x86, 0xfa, 0x1d, 0x77, 0x50, 0x3f, 0x45, 0x8d, 0x90, 0xc4, 0x62, 0x27,
+    0x21, 0x96, 0x5a, 0xef, 0x51, 0x78, 0xd7, 0x7d, 0x0d, 0x02, 0x2d, 0x5a,
+    0x0e, 0x3c, 0x82, 0x6f, 0x1d, 0x92, 0x87, 0xd5, 0x1a, 0x44, 0xae, 0xa7,
+    0x92, 0xd1, 0x8b, 0xfa, 0x16, 0x53, 0x7f, 0xa3, 0x22, 0x96, 0x1a, 0x51,
+    0x8c, 0xeb, 0xa1, 0xe6, 0xf6, 0x37, 0x11, 0xfe, 0x7d, 0x53, 0x3f, 0xae,
+    0xf0, 0x6b, 0xb9, 0xb1, 0x7a, 0x73, 0x07, 0x14, 0xcf, 0x04, 0x05, 0x93,
+    0x9e, 0xe3, 0xd2, 0x4d, 0x9d, 0x6d, 0x35, 0x68, 0xf9, 0x36, 0xe5, 0x10,
+    0x0a, 0x36, 0xd9, 0x48, 0xb0, 0x83, 0xd0, 0xb9, 0x58, 0x74, 0x53, 0xb3,
+    0xbc, 0x99, 0xab, 0xe1, 0x3e, 0xd5, 0x01, 0x8e, 0xcf, 0x3a, 0x69, 0x93,
+    0x9e, 0xa7, 0x88, 0xd4, 0xad, 0x95, 0xf9, 0x2a, 0xb4, 0x7f, 0x95, 0x97,
+    0x86, 0x50, 0x38, 0xb1, 0x04, 0x0a, 0xe4, 0x7a, 0xd5, 0x2d, 0x6c, 0xde,
+    0x3e, 0x1a, 0x47, 0x17, 0x88, 0x63, 0x20, 0x9d, 0x21, 0x3e, 0x0c, 0x6f,
+    0xfd, 0x20, 0x54, 0xd0, 0x67, 0xd2, 0x6b, 0x06, 0xfe, 0x60, 0x13, 0x42,
+    0x3d, 0xb7, 0xca, 0xcb, 0xab, 0x7b, 0x5f, 0x5d, 0x01, 0x56, 0xd3, 0x99,
+    0x80, 0x0f, 0xde, 0x7f, 0x3a, 0x61, 0x9c, 0xd3, 0x6b, 0x5e, 0xfe, 0xb5,
+    0xfc, 0x39, 0x8b, 0x8e, 0xf0, 0x8c, 0x8b, 0x65, 0x46, 0x45, 0xff, 0x47,
+    0x8f, 0xd4, 0xdd, 0xae, 0xc9, 0x72, 0xc7, 0x7f, 0x28, 0x86, 0xf1, 0xf7,
+    0x6e, 0xcb, 0x86, 0x03, 0xeb, 0x0c, 0x46, 0xe5, 0xa0, 0x6b, 0xef, 0xd4,
+    0x5e, 0xa4, 0x0f, 0x53, 0xe1, 0xbc, 0xb4, 0xc9, 0x37, 0x0e, 0x75, 0xdd,
+    0x93, 0xe8, 0x0f, 0x18, 0x0a, 0x02, 0x83, 0x17, 0x74, 0xbb, 0x1a, 0x42,
+    0x5b, 0x63, 0x2c, 0x80, 0x80, 0xa6, 0x84
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const RSA_INT: [u8; 724] = [
+    0x30, 0x82, 0x02, 0xd0, 0x30, 0x82, 0x01, 0xba, 0xa0, 0x03, 0x02, 0x01,
+    0x02, 0x02, 0x14, 0x07, 0x10, 0xaf, 0xc4, 0x1a, 0x3a, 0x56, 0x4f, 0xd8,
+    0xc2, 0xcc, 0x46, 0xd7, 0x5b, 0xdf, 0x1c, 0x4e, 0x2f, 0x49, 0x3a, 0x30,
+    0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+    0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+    0x08, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x72, 0x73, 0x61, 0x30, 0x22, 0x18,
+    0x0f, 0x32, 0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32,
+    0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x12, 0x31,
+    0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, 0x69, 0x6e,
+    0x74, 0x2d, 0x72, 0x73, 0x61, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06,
+    0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+    0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01,
+    0x01, 0x00, 0xba, 0x88, 0x51, 0xa8, 0x44, 0x8e, 0x16, 0xd6, 0x41, 0xfd,
+    0x6e, 0xb6, 0x88, 0x06, 0x36, 0x10, 0x3d, 0x3c, 0x13, 0xd9, 0xea, 0xe4,
+    0x35, 0x4a, 0xb4, 0xec, 0xf5, 0x68, 0x57, 0x6c, 0x24, 0x7b, 0xc1, 0xc7,
+    0x25, 0xa8, 0xe0, 0xd8, 0x1f, 0xbd, 0xb1, 0x9c, 0x06, 0x9b, 0x6e, 0x1a,
+    0x86, 0xf2, 0x6b, 0xe2, 0xaf, 0x5a, 0x75, 0x6b, 0x6a, 0x64, 0x71, 0x08,
+    0x7a, 0xa5, 0x5a, 0xa7, 0x45, 0x87, 0xf7, 0x1c, 0xd5, 0x24, 0x9c, 0x02,
+    0x7e, 0xcd, 0x43, 0xfc, 0x1e, 0x69, 0xd0, 0x38, 0x20, 0x29, 0x93, 0xab,
+    0x20, 0xc3, 0x49, 0xe4, 0xdb, 0xb9, 0x4c, 0xc2, 0x6b, 0x6c, 0x0e, 0xed,
+    0x15, 0x82, 0x0f, 0xf1, 0x7e, 0xad, 0x69, 0x1a, 0xb1, 0xd3, 0x02, 0x3a,
+    0x8b, 0x2a, 0x41, 0xee, 0xa7, 0x70, 0xe0, 0x0f, 0x0d, 0x8d, 0xfd, 0x66,
+    0x0b, 0x2b, 0xb0, 0x24, 0x92, 0xa4, 0x7d, 0xb9, 0x88, 0x61, 0x79, 0x90,
+    0xb1, 0x57, 0x90, 0x3d, 0xd2, 0x3b, 0xc5, 0xe0, 0xb8, 0x48, 0x1f, 0xa8,
+    0x37, 0xd3, 0x88, 0x43, 0xef, 0x27, 0x16, 0xd8, 0x55, 0xb7, 0x66, 0x5a,
+    0xaa, 0x7e, 0x02, 0x90, 0x2f, 0x3a, 0x7b, 0x10, 0x80, 0x06, 0x24, 0xcc,
+    0x1c, 0x6c, 0x97, 0xad, 0x96, 0x61, 0x5b, 0xb7, 0xe2, 0x96, 0x12, 0xc0,
+    0x75, 0x31, 0xa3, 0x0c, 0x91, 0xdd, 0xb4, 0xca, 0xf7, 0xfc, 0xad, 0x1d,
+    0x25, 0xd3, 0x09, 0xef, 0xb9, 0x17, 0x0e, 0xa7, 0x68, 0xe1, 0xb3, 0x7b,
+    0x2f, 0x22, 0x6f, 0x69, 0xe3, 0xb4, 0x8a, 0x95, 0x61, 0x1d, 0xee, 0x26,
+    0xd6, 0x25, 0x9d, 0xab, 0x91, 0x08, 0x4e, 0x36, 0xcb, 0x1c, 0x24, 0x04,
+    0x2c, 0xbf, 0x16, 0x8b, 0x2f, 0xe5, 0xf1, 0x8f, 0x99, 0x17, 0x31, 0xb8,
+    0xb3, 0xfe, 0x49, 0x23, 0xfa, 0x72, 0x51, 0xc4, 0x31, 0xd5, 0x03, 0xac,
+    0xda, 0x18, 0x0a, 0x35, 0xed, 0x8d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
+    0x1d, 0x30, 0x1b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
+    0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f,
+    0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86,
+    0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00,
+    0x5e, 0xba, 0x69, 0x55, 0x9f, 0xf8, 0xeb, 0x16, 0x21, 0x98, 0xde, 0xb7,
+    0x31, 0x3e, 0x66, 0xe1, 0x3b, 0x0c, 0x29, 0xf7, 0x48, 0x73, 0x05, 0xd9,
+    0xce, 0x5e, 0x4c, 0xbe, 0x03, 0xc4, 0x51, 0xd6, 0x21, 0x92, 0x40, 0x38,
+    0xaa, 0x5b, 0x28, 0xb5, 0xa1, 0x10, 0x52, 0x57, 0xff, 0x91, 0x54, 0x82,
+    0x86, 0x9e, 0x74, 0xd5, 0x3d, 0x82, 0x29, 0xee, 0xd1, 0xcf, 0x93, 0xb1,
+    0x24, 0x76, 0xbb, 0x95, 0x41, 0x06, 0x7e, 0x40, 0x9b, 0xb4, 0xab, 0x44,
+    0x34, 0x10, 0x8f, 0xb1, 0x51, 0x6f, 0xc0, 0x89, 0xd1, 0xa3, 0xc4, 0x9f,
+    0xb3, 0x48, 0xe1, 0xcd, 0x73, 0xad, 0xff, 0x42, 0x5f, 0x76, 0x05, 0x60,
+    0xc5, 0xe0, 0x45, 0x79, 0x18, 0xa1, 0x19, 0xb8, 0xa7, 0x3a, 0x64, 0xb3,
+    0x19, 0xba, 0x14, 0xa1, 0xb5, 0xdc, 0x32, 0xec, 0x09, 0x39, 0x58, 0x54,
+    0x5b, 0x04, 0xdc, 0x1b, 0x66, 0x0d, 0x1d, 0x0d, 0xce, 0x7f, 0xfa, 0x24,
+    0x52, 0x6a, 0xad, 0xe2, 0xc8, 0x30, 0xaf, 0xf2, 0xaf, 0x63, 0xc5, 0xe2,
+    0xbf, 0xe2, 0x20, 0x1b, 0x9e, 0xf9, 0x3d, 0xbc, 0xfb, 0x04, 0x8e, 0xda,
+    0x7a, 0x1a, 0x5d, 0xd3, 0x13, 0xd7, 0x00, 0x8e, 0x9b, 0x5d, 0x85, 0x51,
+    0xda, 0xd3, 0x91, 0x25, 0xf5, 0x67, 0x85, 0x3e, 0x25, 0x89, 0x5e, 0xcb,
+    0x89, 0x8a, 0xec, 0x8a, 0xde, 0x8b, 0xf4, 0x33, 0x5f, 0x76, 0xdb, 0x3d,
+    0xfc, 0x6a, 0x05, 0x21, 0x43, 0xb2, 0x41, 0xd8, 0x33, 0x8d, 0xfd, 0x05,
+    0x5c, 0x22, 0x0a, 0xf6, 0x90, 0x65, 0x9c, 0x4f, 0x8c, 0x44, 0x9f, 0x2d,
+    0xca, 0xf3, 0x49, 0x9c, 0x3a, 0x14, 0x88, 0xab, 0xe4, 0xce, 0xb7, 0xbc,
+    0x95, 0x22, 0x2e, 0xb1, 0x82, 0x4c, 0xbf, 0x83, 0x3e, 0x49, 0x72, 0x03,
+    0x2a, 0x68, 0xe7, 0x2d, 0xe5, 0x2d, 0x4b, 0x61, 0xb0, 0x8d, 0x0d, 0x0c,
+    0x87, 0xc6, 0x5c, 0x51
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const RSA_ROOT: [u8; 725] = [
+    0x30, 0x82, 0x02, 0xd1, 0x30, 0x82, 0x01, 0xbb, 0xa0, 0x03, 0x02, 0x01,
+    0x02, 0x02, 0x14, 0x29, 0x6c, 0x1a, 0xd8, 0x20, 0xcd, 0x74, 0x6d, 0x4b,
+    0x00, 0xf3, 0x16, 0x88, 0xd9, 0x66, 0x87, 0x5f, 0x28, 0x56, 0x6a, 0x30,
+    0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+    0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+    0x08, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x72, 0x73, 0x61, 0x30, 0x22, 0x18,
+    0x0f, 0x32, 0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32,
+    0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x13, 0x31,
+    0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x72, 0x6f,
+    0x6f, 0x74, 0x2d, 0x72, 0x73, 0x61, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
+    0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+    0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
+    0x01, 0x01, 0x00, 0xba, 0x88, 0x51, 0xa8, 0x44, 0x8e, 0x16, 0xd6, 0x41,
+    0xfd, 0x6e, 0xb6, 0x88, 0x06, 0x36, 0x10, 0x3d, 0x3c, 0x13, 0xd9, 0xea,
+    0xe4, 0x35, 0x4a, 0xb4, 0xec, 0xf5, 0x68, 0x57, 0x6c, 0x24, 0x7b, 0xc1,
+    0xc7, 0x25, 0xa8, 0xe0, 0xd8, 0x1f, 0xbd, 0xb1, 0x9c, 0x06, 0x9b, 0x6e,
+    0x1a, 0x86, 0xf2, 0x6b, 0xe2, 0xaf, 0x5a, 0x75, 0x6b, 0x6a, 0x64, 0x71,
+    0x08, 0x7a, 0xa5, 0x5a, 0xa7, 0x45, 0x87, 0xf7, 0x1c, 0xd5, 0x24, 0x9c,
+    0x02, 0x7e, 0xcd, 0x43, 0xfc, 0x1e, 0x69, 0xd0, 0x38, 0x20, 0x29, 0x93,
+    0xab, 0x20, 0xc3, 0x49, 0xe4, 0xdb, 0xb9, 0x4c, 0xc2, 0x6b, 0x6c, 0x0e,
+    0xed, 0x15, 0x82, 0x0f, 0xf1, 0x7e, 0xad, 0x69, 0x1a, 0xb1, 0xd3, 0x02,
+    0x3a, 0x8b, 0x2a, 0x41, 0xee, 0xa7, 0x70, 0xe0, 0x0f, 0x0d, 0x8d, 0xfd,
+    0x66, 0x0b, 0x2b, 0xb0, 0x24, 0x92, 0xa4, 0x7d, 0xb9, 0x88, 0x61, 0x79,
+    0x90, 0xb1, 0x57, 0x90, 0x3d, 0xd2, 0x3b, 0xc5, 0xe0, 0xb8, 0x48, 0x1f,
+    0xa8, 0x37, 0xd3, 0x88, 0x43, 0xef, 0x27, 0x16, 0xd8, 0x55, 0xb7, 0x66,
+    0x5a, 0xaa, 0x7e, 0x02, 0x90, 0x2f, 0x3a, 0x7b, 0x10, 0x80, 0x06, 0x24,
+    0xcc, 0x1c, 0x6c, 0x97, 0xad, 0x96, 0x61, 0x5b, 0xb7, 0xe2, 0x96, 0x12,
+    0xc0, 0x75, 0x31, 0xa3, 0x0c, 0x91, 0xdd, 0xb4, 0xca, 0xf7, 0xfc, 0xad,
+    0x1d, 0x25, 0xd3, 0x09, 0xef, 0xb9, 0x17, 0x0e, 0xa7, 0x68, 0xe1, 0xb3,
+    0x7b, 0x2f, 0x22, 0x6f, 0x69, 0xe3, 0xb4, 0x8a, 0x95, 0x61, 0x1d, 0xee,
+    0x26, 0xd6, 0x25, 0x9d, 0xab, 0x91, 0x08, 0x4e, 0x36, 0xcb, 0x1c, 0x24,
+    0x04, 0x2c, 0xbf, 0x16, 0x8b, 0x2f, 0xe5, 0xf1, 0x8f, 0x99, 0x17, 0x31,
+    0xb8, 0xb3, 0xfe, 0x49, 0x23, 0xfa, 0x72, 0x51, 0xc4, 0x31, 0xd5, 0x03,
+    0xac, 0xda, 0x18, 0x0a, 0x35, 0xed, 0x8d, 0x02, 0x03, 0x01, 0x00, 0x01,
+    0xa3, 0x1d, 0x30, 0x1b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04,
+    0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d,
+    0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0b, 0x06, 0x09, 0x2a,
+    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01,
+    0x00, 0x23, 0x2f, 0x9f, 0x72, 0xeb, 0x70, 0x6d, 0x9e, 0x3e, 0x9f, 0xd7,
+    0x9c, 0xd9, 0x19, 0x7c, 0x99, 0x07, 0xc5, 0x5c, 0x9d, 0xf5, 0x66, 0x9f,
+    0x28, 0x8d, 0xfe, 0x0e, 0x3f, 0x38, 0x75, 0xed, 0xee, 0x4e, 0x3f, 0xf6,
+    0x6e, 0x35, 0xe0, 0x95, 0x3f, 0x08, 0x4a, 0x71, 0x5a, 0xf2, 0x4f, 0xc9,
+    0x96, 0x61, 0x8d, 0x45, 0x4b, 0x97, 0x85, 0xff, 0xb0, 0xe3, 0xbb, 0xb5,
+    0xd7, 0x7e, 0xfb, 0xd2, 0xfc, 0xec, 0xfe, 0x42, 0x9f, 0x4e, 0x7b, 0xbf,
+    0x97, 0xbb, 0xb4, 0x3a, 0x93, 0x0b, 0x13, 0x61, 0x90, 0x0c, 0x3a, 0xce,
+    0xf7, 0x8e, 0xef, 0x80, 0xf5, 0x4a, 0x92, 0xc5, 0xa5, 0x03, 0x78, 0xc2,
+    0xee, 0xb8, 0x66, 0x60, 0x6b, 0x76, 0x4f, 0x32, 0x5a, 0x1a, 0xa2, 0x4b,
+    0x7e, 0x2b, 0xa6, 0x1a, 0x89, 0x01, 0xe3, 0xbb, 0x55, 0x13, 0x7c, 0x4c,
+    0xf4, 0x6a, 0x99, 0x94, 0xd1, 0xa0, 0x84, 0x1c, 0x1a, 0xc2, 0x7b, 0xb4,
+    0xa0, 0xb0, 0x3b, 0xdc, 0x5a, 0x7b, 0xc7, 0xe0, 0x44, 0xb2, 0x1f, 0x46,
+    0xd5, 0x8b, 0x39, 0x8b, 0xdc, 0x9e, 0xce, 0xa8, 0x7f, 0x85, 0x1d, 0x4b,
+    0x63, 0x06, 0x1e, 0x8e, 0xe5, 0xe5, 0x99, 0xd9, 0xf7, 0x4d, 0x89, 0x0b,
+    0x1d, 0x5c, 0x27, 0x33, 0x66, 0x21, 0xcf, 0x9a, 0xbd, 0x98, 0x68, 0x23,
+    0x3a, 0x66, 0x9d, 0xd4, 0x46, 0xed, 0x63, 0x58, 0xf3, 0x42, 0xe4, 0x1d,
+    0xe2, 0x47, 0x65, 0x13, 0x8d, 0xd4, 0x1f, 0x4b, 0x7e, 0xde, 0x11, 0x56,
+    0xf8, 0x6d, 0x01, 0x0c, 0x99, 0xbd, 0x8d, 0xca, 0x8a, 0x2e, 0xe3, 0x8a,
+    0x9c, 0x3d, 0x83, 0x8d, 0x69, 0x62, 0x8d, 0x05, 0xea, 0xb7, 0xf5, 0xa3,
+    0x4b, 0xfc, 0x96, 0xcf, 0x18, 0x21, 0x0a, 0xc7, 0xf3, 0x23, 0x7e, 0x1c,
+    0xab, 0xe2, 0xa2, 0xd1, 0x83, 0xc4, 0x25, 0x93, 0x37, 0x80, 0xca, 0xda,
+    0xf0, 0xef, 0x7d, 0x94, 0xb5
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const XPI_SIGNATURE: [u8; 646] = [
+    0xd8, 0x62, 0x84, 0x43, 0xa1, 0x04, 0x80, 0xa0, 0xf6, 0x81, 0x83, 0x59,
+    0x02, 0x35, 0xa2, 0x01, 0x26, 0x04, 0x59, 0x02, 0x2e, 0x30, 0x82, 0x02,
+    0x2a, 0x30, 0x82, 0x01, 0x12, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14,
+    0x17, 0x03, 0x6b, 0xc1, 0xfe, 0xb4, 0x38, 0xe1, 0x83, 0x8f, 0xe5, 0xa7,
+    0xca, 0xf1, 0x54, 0x32, 0x4c, 0x8b, 0xf3, 0x05, 0x30, 0x0d, 0x06, 0x09,
+    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
+    0x29, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1e,
+    0x78, 0x70, 0x63, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x20, 0x73, 0x69, 0x67,
+    0x6e, 0x65, 0x64, 0x20, 0x61, 0x70, 0x70, 0x73, 0x20, 0x74, 0x65, 0x73,
+    0x74, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30,
+    0x31, 0x35, 0x31, 0x31, 0x32, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+    0x5a, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x38, 0x30, 0x32, 0x30, 0x35, 0x30,
+    0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x2b, 0x31, 0x29, 0x30, 0x27,
+    0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x20, 0x20, 0x78, 0x70, 0x63, 0x73,
+    0x68, 0x65, 0x6c, 0x6c, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20,
+    0x61, 0x70, 0x70, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69, 0x67,
+    0x6e, 0x65, 0x72, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48,
+    0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03,
+    0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4f, 0xbf, 0xbb, 0xbb, 0x61, 0xe0,
+    0xf8, 0xf9, 0xb1, 0xa6, 0x0a, 0x59, 0xac, 0x87, 0x04, 0xe2, 0xec, 0x05,
+    0x0b, 0x42, 0x3e, 0x3c, 0xf7, 0x2e, 0x92, 0x3f, 0x2c, 0x4f, 0x79, 0x4b,
+    0x45, 0x5c, 0x2a, 0x69, 0xd2, 0x33, 0x45, 0x6c, 0x36, 0xc4, 0x11, 0x9d,
+    0x07, 0x06, 0xe0, 0x0e, 0xed, 0xc8, 0xd1, 0x93, 0x90, 0xd7, 0x99, 0x1b,
+    0x7b, 0x2d, 0x07, 0xa3, 0x04, 0xea, 0xa0, 0x4a, 0xa6, 0xc0, 0xa3, 0x0f,
+    0x30, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03,
+    0x02, 0x07, 0x80, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+    0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x4f,
+    0x5c, 0xcb, 0x1d, 0xea, 0x71, 0x58, 0xfe, 0xe2, 0x49, 0x11, 0x16, 0x65,
+    0xbc, 0x23, 0x6d, 0xda, 0x46, 0x7e, 0x98, 0x93, 0x5d, 0x48, 0x2a, 0xa0,
+    0xbb, 0x7f, 0x4e, 0xbd, 0x01, 0x0a, 0x1a, 0x30, 0xff, 0xce, 0x03, 0xf5,
+    0x9c, 0xd9, 0x84, 0x69, 0x7a, 0x5a, 0xe3, 0x43, 0xd2, 0xd4, 0xbc, 0xab,
+    0x4d, 0x17, 0x8f, 0x10, 0x6a, 0xcf, 0xde, 0x17, 0x1d, 0x7d, 0x16, 0x03,
+    0x7e, 0x21, 0xf0, 0x32, 0x02, 0x89, 0x67, 0x32, 0x5a, 0xfe, 0xd5, 0xd9,
+    0x31, 0x53, 0xdc, 0xd7, 0xba, 0x2a, 0x9f, 0xd3, 0x59, 0x8d, 0x61, 0xb9,
+    0x6e, 0xf7, 0x6e, 0x86, 0x61, 0xdd, 0xfd, 0xe1, 0x73, 0xfe, 0xef, 0x9d,
+    0xe9, 0x99, 0x9e, 0x51, 0xe8, 0x5d, 0xf7, 0x48, 0x77, 0x8e, 0xc6, 0xe8,
+    0x53, 0x05, 0x7b, 0x5c, 0x2c, 0x28, 0xe7, 0x0a, 0x07, 0xbf, 0xea, 0xc1,
+    0x06, 0x11, 0x0d, 0xe7, 0x60, 0xd0, 0x79, 0x94, 0xe9, 0x26, 0xf1, 0x93,
+    0x71, 0x7b, 0x5b, 0x02, 0x3b, 0x5d, 0x51, 0xb8, 0x19, 0x38, 0x16, 0xab,
+    0x48, 0x30, 0xf3, 0xec, 0xd9, 0xd5, 0x8f, 0xc7, 0x9a, 0x02, 0xfd, 0x12,
+    0x57, 0x82, 0x0e, 0xde, 0xce, 0xfc, 0x50, 0x42, 0x2a, 0x41, 0xc7, 0xc6,
+    0xa8, 0x80, 0x37, 0x7c, 0xc4, 0x47, 0xad, 0xf5, 0xd8, 0xcb, 0xe8, 0xae,
+    0x0c, 0x01, 0x80, 0x60, 0x35, 0x93, 0x0a, 0x21, 0x81, 0x33, 0xd1, 0xd6,
+    0x6a, 0x1b, 0xe7, 0xb6, 0xd9, 0x91, 0x50, 0xc2, 0xbd, 0x16, 0xda, 0xb7,
+    0x68, 0x60, 0xf2, 0x20, 0xaa, 0x72, 0x8c, 0x76, 0x0a, 0x54, 0x7a, 0x05,
+    0xd8, 0xa1, 0xcd, 0xe9, 0x07, 0x8a, 0x02, 0x07, 0x4b, 0x87, 0x7d, 0xb5,
+    0x27, 0xca, 0x38, 0xb3, 0x30, 0xaf, 0x97, 0xe0, 0xb7, 0x35, 0x14, 0x08,
+    0xab, 0x01, 0xb0, 0x14, 0x08, 0x5c, 0x4b, 0xfb, 0x76, 0x0a, 0x95, 0xfc,
+    0xb4, 0xb8, 0x34, 0xa0, 0x58, 0x40, 0x5c, 0x75, 0x51, 0x9f, 0x13, 0x11,
+    0x50, 0xcd, 0x5d, 0x8a, 0xde, 0x20, 0xa3, 0xbc, 0x06, 0x30, 0x91, 0xff,
+    0xb2, 0x73, 0x75, 0x5f, 0x31, 0x64, 0xec, 0xfd, 0xcb, 0x42, 0x80, 0x0a,
+    0x70, 0xe6, 0x82, 0x02, 0x0a, 0xe8, 0x69, 0x13, 0xd5, 0xf4, 0x1b, 0xab,
+    0xb6, 0xbb, 0x59, 0x93, 0x08, 0x48, 0x68, 0x9c, 0xbd, 0x72, 0xc7, 0xcb,
+    0x37, 0xde, 0x26, 0xbc, 0xe9, 0x83, 0x0e, 0xd8, 0x90, 0xa3
+];
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+pub const XPI_PAYLOAD: [u8; 236] = [
+    0x4E, 0x61, 0x6D, 0x65, 0x3A, 0x20, 0x6D, 0x61, 0x6E, 0x69, 0x66, 0x65,
+    0x73, 0x74, 0x2E, 0x6A, 0x73, 0x6F, 0x6E, 0x0A, 0x53, 0x48, 0x41, 0x32,
+    0x35, 0x36, 0x2D, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x3A, 0x20, 0x42,
+    0x54, 0x6E, 0x43, 0x70, 0x54, 0x31, 0x35, 0x34, 0x4E, 0x32, 0x36, 0x52,
+    0x5A, 0x6D, 0x38, 0x62, 0x68, 0x64, 0x44, 0x34, 0x33, 0x57, 0x58, 0x64,
+    0x30, 0x74, 0x6A, 0x35, 0x62, 0x67, 0x36, 0x6F, 0x66, 0x4D, 0x31, 0x39,
+    0x4E, 0x4C, 0x49, 0x30, 0x4F, 0x45, 0x3D, 0x0A, 0x0A, 0x4E, 0x61, 0x6D,
+    0x65, 0x3A, 0x20, 0x52, 0x45, 0x41, 0x44, 0x4D, 0x45, 0x0A, 0x53, 0x48,
+    0x41, 0x32, 0x35, 0x36, 0x2D, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x3A,
+    0x20, 0x62, 0x59, 0x30, 0x6C, 0x39, 0x78, 0x71, 0x47, 0x4A, 0x59, 0x43,
+    0x70, 0x71, 0x59, 0x65, 0x4A, 0x30, 0x4B, 0x36, 0x71, 0x34, 0x44, 0x57,
+    0x55, 0x51, 0x71, 0x75, 0x30, 0x6D, 0x4E, 0x42, 0x46, 0x4D, 0x34, 0x48,
+    0x34, 0x65, 0x6D, 0x68, 0x6A, 0x69, 0x4A, 0x67, 0x3D, 0x0A, 0x0A, 0x4E,
+    0x61, 0x6D, 0x65, 0x3A, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2F, 0x69, 0x6D,
+    0x61, 0x67, 0x65, 0x2E, 0x70, 0x6E, 0x67, 0x0A, 0x53, 0x48, 0x41, 0x32,
+    0x35, 0x36, 0x2D, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x3A, 0x20, 0x45,
+    0x50, 0x6A, 0x6B, 0x4E, 0x5A, 0x77, 0x79, 0x61, 0x39, 0x58, 0x2B, 0x70,
+    0x72, 0x75, 0x4C, 0x6C, 0x78, 0x47, 0x2B, 0x46, 0x41, 0x43, 0x4C, 0x77,
+    0x47, 0x43, 0x34, 0x38, 0x58, 0x55, 0x34, 0x53, 0x39, 0x6F, 0x5A, 0x4F,
+    0x41, 0x30, 0x6C, 0x56, 0x56, 0x51, 0x3D, 0x0A
+];
new file mode 100644
--- /dev/null
+++ b/third_party/rust/cose/examples/sign_verify/util_test.rs
@@ -0,0 +1,194 @@
+/// We don't need COSE signing at the moment. But we need to generate test files.
+/// This module implements basic COSE signing.
+use nss;
+use {CoseError, Signature, SignatureAlgorithm, SignatureParameters};
+use std::collections::BTreeMap;
+use cbor::CborType;
+use cose::util::get_sig_struct_bytes;
+use cose::decoder::decode_signature;
+use cose::decoder::{COSE_TYPE_ES256, COSE_TYPE_ES384, COSE_TYPE_ES512, COSE_TYPE_PS256};
+
+/// Converts a `SignatureAlgorithm` to its corresponding `CborType`.
+/// See RFC 8152 section 8.1 and RFC 8230 section 5.1.
+pub fn signature_type_to_cbor_value(signature_type: &SignatureAlgorithm) -> CborType {
+    CborType::SignedInteger(match signature_type {
+        &SignatureAlgorithm::ES256 => COSE_TYPE_ES256,
+        &SignatureAlgorithm::ES384 => COSE_TYPE_ES384,
+        &SignatureAlgorithm::ES512 => COSE_TYPE_ES512,
+        &SignatureAlgorithm::PS256 => COSE_TYPE_PS256,
+    })
+}
+
+pub fn build_protected_sig_header(ee_cert: &[u8], alg: &SignatureAlgorithm) -> CborType {
+    // Protected signature header
+    let mut header_map: BTreeMap<CborType, CborType> = BTreeMap::new();
+
+    // Signature type.
+    let signature_type_value = signature_type_to_cbor_value(alg);
+    header_map.insert(CborType::Integer(1), signature_type_value);
+
+    // Signer certificate.
+    header_map.insert(CborType::Integer(4), CborType::Bytes(ee_cert.to_vec()));
+
+    let header_map = CborType::Map(header_map).serialize();
+    CborType::Bytes(header_map)
+}
+
+pub fn build_protected_header(cert_chain: &[&[u8]]) -> CborType {
+    let mut cert_array: Vec<CborType> = Vec::new();
+    for cert in cert_chain {
+        cert_array.push(CborType::Bytes(cert.to_vec()));
+    }
+    let mut protected_body_header: BTreeMap<CborType, CborType> = BTreeMap::new();
+    protected_body_header.insert(CborType::Integer(4), CborType::Array(cert_array));
+    let protected_body_header = CborType::Map(protected_body_header).serialize();
+
+    CborType::Bytes(protected_body_header)
+}
+
+pub fn build_sig_struct(ee_cert: &[u8], alg: &SignatureAlgorithm, sig_bytes: &Vec<u8>) -> CborType {
+    // Build the signature item.
+    let mut signature_item: Vec<CborType> = Vec::new();
+
+    // Protected signature header
+    signature_item.push(build_protected_sig_header(ee_cert, alg));
+
+    // The unprotected signature header is empty.
+    let empty_map: BTreeMap<CborType, CborType> = BTreeMap::new();
+    signature_item.push(CborType::Map(empty_map));
+
+    // And finally the signature bytes.
+    signature_item.push(CborType::Bytes(sig_bytes.clone()));
+    CborType::Array(signature_item)
+}
+
+// 98(
+//  [
+//    / protected / h'..', / {
+//          \ kid \ 4:'..' \ Array of DER encoded intermediate certificates  \
+//      } / ,
+//    / unprotected / {},
+//    / payload / nil, / The payload is the contents of the manifest file /
+//    / signatures / [
+//      [
+//        / protected / h'a2012604..' / {
+//            \ alg \ 1:-7, \ ECDSA with SHA-256 \
+//            \ kid \ 4:'..' \ DER encoded signing certificate \
+//          } / ,
+//        / unprotected / {},
+//        / signature / h'e2ae..'
+//      ],
+//      [
+//        / protected / h'a201382404..' / {
+//            \ alg \ 1:-37, \ RSASSA-PSS with SHA-256 \
+//            \ kid \ 4:'..' \ DER encoded signing certificate \
+//          } / ,
+//        / unprotected / {},
+//        / signature / h'00a2..'
+//      ]
+//    ]
+//  ]
+pub fn build_cose_signature(cert_chain: &[&[u8]], signature_vec: &Vec<Signature>) -> Vec<u8> {
+    // Building the COSE signature content.
+    let mut cose_signature: Vec<CborType> = Vec::new();
+
+    // add cert chain as protected header
+    cose_signature.push(build_protected_header(cert_chain));
+
+    // Empty map (unprotected header)
+    let empty_map: BTreeMap<CborType, CborType> = BTreeMap::new();
+    cose_signature.push(CborType::Map(empty_map));
+
+    // No payload (nil).
+    cose_signature.push(CborType::Null);
+
+    // Create signature items.
+    let mut signatures: Vec<CborType> = Vec::new();
+    for signature in signature_vec {
+        let signature_item = build_sig_struct(
+            signature.parameter.certificate,
+            &signature.parameter.algorithm,
+            &signature.signature_bytes,
+        );
+        signatures.push(signature_item);
+    }
+
+    // Pack the signature item and add everything to the cose signature object.
+    cose_signature.push(CborType::Array(signatures));
+
+    // A COSE signature is a tagged array (98).
+    let signature_struct = CborType::Tag(98, Box::new(CborType::Array(cose_signature).clone()));
+
+    return signature_struct.serialize();
+}
+
+pub fn sign(
+    payload: &[u8],
+    cert_chain: &[&[u8]],
+    parameters: &Vec<SignatureParameters>,
+) -> Result<Vec<u8>, CoseError> {
+    assert!(parameters.len() > 0);
+    if parameters.len() < 1 {
+        return Err(CoseError::InvalidArgument);
+    }
+
+    let mut signatures: Vec<Signature> = Vec::new();
+    for param in parameters {
+        // Build the signature structure containing the protected headers and the
+        // payload to generate the payload that is actually signed.
+        let protected_sig_header_serialized =
+            build_protected_sig_header(param.certificate, &param.algorithm);
+        let protected_header_serialized = build_protected_header(cert_chain);
+        let payload = get_sig_struct_bytes(
+            protected_header_serialized,
+            protected_sig_header_serialized,
+            payload,
+        );
+
+        let signature_bytes = match nss::sign(&param.algorithm, &param.pkcs8, &payload) {
+            Err(_) => return Err(CoseError::SigningFailed),
+            Ok(signature) => signature,
+        };
+        let signature = Signature {
+            parameter: param,
+            signature_bytes: signature_bytes,
+        };
+        signatures.push(signature);
+    }
+
+    assert!(signatures.len() > 0);
+    if signatures.len() < 1 {
+        return Err(CoseError::MalformedInput);
+    }
+
+    let cose_signature = build_cose_signature(cert_chain, &signatures);
+    Ok(cose_signature)
+}
+
+/// Verify a COSE signature.
+pub fn verify_signature(payload: &[u8], cose_signature: Vec<u8>) -> Result<(), CoseError> {
+    // Parse COSE signature.
+    let cose_signatures = decode_signature(&cose_signature, payload)?;
+    if cose_signatures.len() < 1 {
+        return Err(CoseError::MalformedInput);
+    }
+
+    for signature in cose_signatures {
+        let signature_algorithm = &signature.signature_type;
+        let signature_bytes = &signature.signature;
+        let real_payload = &signature.to_verify;
+
+        // Verify the parsed signatures.
+        // We ignore the certs field here because we don't verify the certificate.
+        let verify_result = nss::verify_signature(
+            &signature_algorithm,
+            &signature.signer_cert,
+            real_payload,
+            signature_bytes,
+        );
+        if !verify_result.is_ok() {
+            return Err(CoseError::VerificationFailed);
+        }
+    }
+    Ok(())
+}
deleted file mode 100644
--- a/third_party/rust/cose/src/cbor/decoder.rs
+++ /dev/null
@@ -1,150 +0,0 @@
-use std::collections::BTreeMap;
-use std::io::{Cursor, Read, Seek, SeekFrom};
-use cbor::{CborError, CborType};
-
-// We limit the length of any cbor byte array to 128MiB. This is a somewhat
-// arbitrary limit that should work on all platforms and is large enough for
-// any benign data.
-pub const MAX_ARRAY_SIZE: usize = 134_217_728;
-
-/// Struct holding a cursor and additional information for decoding.
-#[derive(Debug)]
-struct DecoderCursor<'a> {
-    cursor: Cursor<&'a [u8]>,
-}
-
-/// Apply this mask (with &) to get the value part of the initial byte of a CBOR item.
-const INITIAL_VALUE_MASK: u64 = 0b0001_1111;
-
-impl<'a> DecoderCursor<'a> {
-    /// Read and return the given number of bytes from the cursor. Advances the cursor.
-    fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>, CborError> {
-        if len > MAX_ARRAY_SIZE {
-            return Err(CborError::InputTooLarge);
-        }
-        let mut buf: Vec<u8> = vec![0; len];
-        if self.cursor.read_exact(&mut buf).is_err() {
-            Err(CborError::TruncatedInput)
-        } else {
-            Ok(buf)
-        }
-    }
-
-    /// Convert num bytes to a u64
-    fn read_uint_from_bytes(&mut self, num: usize) -> Result<u64, CborError> {
-        let x = self.read_bytes(num)?;
-        let mut result: u64 = 0;
-        for i in (0..num).rev() {
-            result += u64::from(x[num - 1 - i]) << (i * 8);
-        }
-        Ok(result)
-    }
-
-    /// Read an integer and return it as u64.
-    fn read_int(&mut self) -> Result<u64, CborError> {
-        let first_value = self.read_uint_from_bytes(1)? & INITIAL_VALUE_MASK;
-        match first_value {
-            0...23 => Ok(first_value),
-            24 => self.read_uint_from_bytes(1),
-            25 => self.read_uint_from_bytes(2),
-            26 => self.read_uint_from_bytes(4),
-            27 => self.read_uint_from_bytes(8),
-            _ => Err(CborError::MalformedInput),
-        }
-    }
-
-    fn read_negative_int(&mut self) -> Result<CborType, CborError> {
-        let uint = self.read_int()?;
-        if uint > i64::max_value() as u64 {
-            return Err(CborError::InputValueOutOfRange);
-        }
-        let result: i64 = -1 - uint as i64;
-        Ok(CborType::SignedInteger(result))
-    }
-
-    /// Read an array of data items and return it.
-    fn read_array(&mut self) -> Result<CborType, CborError> {
-        // Create a new array.
-        let mut array: Vec<CborType> = Vec::new();
-        // Read the length of the array.
-        let num_items = self.read_int()?;
-        // Decode each of the num_items data items.
-        for _ in 0..num_items {
-            let new_item = self.decode_item()?;
-            array.push(new_item);
-        }
-        Ok(CborType::Array(array))
-    }
-
-    /// Read a byte string and return it.
-    fn read_byte_string(&mut self) -> Result<CborType, CborError> {
-        let length = self.read_int()?;
-        if length > MAX_ARRAY_SIZE as u64 {
-            return Err(CborError::InputTooLarge);
-        }
-        let byte_string = self.read_bytes(length as usize)?;
-        Ok(CborType::Bytes(byte_string))
-    }
-
-    /// Read a map.
-    fn read_map(&mut self) -> Result<CborType, CborError> {
-        let num_items = self.read_int()?;
-        // Create a new array.
-        let mut map: BTreeMap<CborType, CborType> = BTreeMap::new();
-        // Decode each of the num_items (key, data item) pairs.
-        for _ in 0..num_items {
-            let key_val = self.decode_item()?;
-            let item_value = self.decode_item()?;
-            if map.insert(key_val, item_value).is_some() {
-                return Err(CborError::DuplicateMapKey);
-            }
-        }
-        Ok(CborType::Map(map))
-    }
-
-    fn read_null(&mut self) -> Result<CborType, CborError> {
-        let value = self.read_uint_from_bytes(1)? & INITIAL_VALUE_MASK;
-        if value != 22 {
-            return Err(CborError::UnsupportedType);
-        }
-        Ok(CborType::Null)
-    }
-
-    /// Peeks at the next byte in the cursor, but does not change the position.
-    fn peek_byte(&mut self) -> Result<u8, CborError> {
-        let x = self.read_bytes(1)?;
-        if self.cursor.seek(SeekFrom::Current(-1)).is_err() {
-            return Err(CborError::LibraryError);
-        };
-        Ok(x[0])
-    }
-
-    /// Decodes the next CBOR item.
-    pub fn decode_item(&mut self) -> Result<CborType, CborError> {
-        let major_type = self.peek_byte()? >> 5;
-        match major_type {
-            0 => {
-                let value = self.read_int()?;
-                Ok(CborType::Integer(value))
-            }
-            1 => self.read_negative_int(),
-            2 => self.read_byte_string(),
-            4 => self.read_array(),
-            5 => self.read_map(),
-            6 => {
-                let tag = self.read_int()?;
-                let item = self.decode_item()?;
-                Ok(CborType::Tag(tag, Box::new(item)))
-            }
-            7 => self.read_null(),
-            _ => Err(CborError::UnsupportedType),
-        }
-    }
-}
-
-/// Read the CBOR structure in bytes and return it as a `CborType`.
-pub fn decode(bytes: &[u8]) -> Result<CborType, CborError> {
-    let mut decoder_cursor = DecoderCursor { cursor: Cursor::new(bytes) };
-    decoder_cursor.decode_item()
-    // TODO: check cursor at end?
-}
deleted file mode 100644
--- a/third_party/rust/cose/src/cbor/serializer.rs
+++ /dev/null
@@ -1,121 +0,0 @@
-use std::collections::BTreeMap;
-use cbor::CborType;
-
-/// Given a vector of bytes to append to, a tag to use, and an unsigned value to encode, uses the
-/// CBOR unsigned integer encoding to represent the given value.
-fn common_encode_unsigned(output: &mut Vec<u8>, tag: u8, value: u64) {
-    assert!(tag < 8);
-    let shifted_tag = tag << 5;
-    match value {
-        0...23 => {
-            output.push(shifted_tag | (value as u8));
-        }
-        24...255 => {
-            output.push(shifted_tag | 24);
-            output.push(value as u8);
-        }
-        256...65_535 => {
-            output.push(shifted_tag | 25);
-            output.push((value >> 8) as u8);
-            output.push((value & 255) as u8);
-        }
-        65_536...4_294_967_295 => {
-            output.push(shifted_tag | 26);
-            output.push((value >> 24) as u8);
-            output.push(((value >> 16) & 255) as u8);
-            output.push(((value >> 8) & 255) as u8);
-            output.push((value & 255) as u8);
-        }
-        _ => {
-            output.push(shifted_tag | 27);
-            output.push((value >> 56) as u8);
-            output.push(((value >> 48) & 255) as u8);
-            output.push(((value >> 40) & 255) as u8);
-            output.push(((value >> 32) & 255) as u8);
-            output.push(((value >> 24) & 255) as u8);
-            output.push(((value >> 16) & 255) as u8);
-            output.push(((value >> 8) & 255) as u8);
-            output.push((value & 255) as u8);
-        }
-    };
-}
-
-/// The major type is 0. For values 0 through 23, the 5 bits of additional information is just the
-/// value of the unsigned number. For values representable in one byte, the additional information
-/// has the value 24. If two bytes are necessary, the value is 25. If four bytes are necessary, the
-/// value is 26. If 8 bytes are necessary, the value is 27. The following bytes are the value of the
-/// unsigned number in as many bytes were indicated in network byte order (big endian).
-fn encode_unsigned(output: &mut Vec<u8>, unsigned: u64) {
-    common_encode_unsigned(output, 0, unsigned);
-}
-
-/// The major type is 1. The encoding is the same as for positive (i.e. unsigned) integers, except
-/// the value encoded is -1 minus the value of the negative number.
-fn encode_negative(output: &mut Vec<u8>, negative: i64) {
-    assert!(negative < 0);
-    let value_to_encode: u64 = (-1 - negative) as u64;
-    common_encode_unsigned(output, 1, value_to_encode);
-}
-
-/// The major type is 2. The length of the data is encoded as with positive integers, followed by
-/// the actual data.
-fn encode_bytes(output: &mut Vec<u8>, bstr: &[u8]) {
-    common_encode_unsigned(output, 2, bstr.len() as u64);
-    output.extend_from_slice(bstr);
-}
-
-/// The major type is 3. The length is as with bstr. The UTF-8-encoded bytes of the string follow.
-fn encode_string(output: &mut Vec<u8>, tstr: &str) {
-    let utf8_bytes = tstr.as_bytes();
-    common_encode_unsigned(output, 3, utf8_bytes.len() as u64);
-    output.extend_from_slice(utf8_bytes);
-}
-
-/// The major type is 4. The number of items is encoded as with positive integers. Then follows the
-/// encodings of the items themselves.
-fn encode_array(output: &mut Vec<u8>, array: &[CborType]) {
-    common_encode_unsigned(output, 4, array.len() as u64);
-    for element in array {
-        output.append(&mut element.serialize());
-    }
-}
-
-/// The major type is 5. The number of pairs is encoded as with positive integers. Then follows the
-/// encodings of each key, value pair. In Canonical CBOR, the keys must be sorted lowest value to
-/// highest.
-fn encode_map(output: &mut Vec<u8>, map: &BTreeMap<CborType, CborType>) {
-    common_encode_unsigned(output, 5, map.len() as u64);
-    for (key, value) in map {
-        output.append(&mut key.serialize());
-        output.append(&mut value.serialize());
-    }
-}
-
-fn encode_tag(output: &mut Vec<u8>, tag: &u64, val: &CborType) {
-    common_encode_unsigned(output, 6, *tag);
-    output.append(&mut val.serialize());
-}
-
-/// The major type is 7. The only supported value for this type is 22, which is Null.
-/// This makes the encoded value 246, or 0xf6.
-fn encode_null(output: &mut Vec<u8>) {
-    output.push(0xf6);
-}
-
-impl CborType {
-    /// Serialize a Cbor object.
-    pub fn serialize(&self) -> Vec<u8> {
-        let mut bytes: Vec<u8> = Vec::new();
-        match *self {
-            CborType::Integer(ref unsigned) => encode_unsigned(&mut bytes, *unsigned),
-            CborType::SignedInteger(ref negative) => encode_negative(&mut bytes, *negative),
-            CborType::Bytes(ref bstr) => encode_bytes(&mut bytes, bstr),
-            CborType::String(ref tstr) => encode_string(&mut bytes, tstr),
-            CborType::Array(ref arr) => encode_array(&mut bytes, arr),
-            CborType::Map(ref map) => encode_map(&mut bytes, map),
-            CborType::Tag(ref t, ref val) => encode_tag(&mut bytes, t, val),
-            CborType::Null => encode_null(&mut bytes),
-        };
-        bytes
-    }
-}
deleted file mode 100644
--- a/third_party/rust/cose/src/cbor/test_decoder.rs
+++ /dev/null
@@ -1,405 +0,0 @@
-use cbor::decoder::*;
-use cbor::*;
-use std::collections::BTreeMap;
-
-// First test all the basic types
-fn test_decoder(bytes: Vec<u8>, expected: CborType) {
-    let result = decode(&bytes);
-    assert!(result.is_ok());
-    assert_eq!(result.unwrap(), expected);
-}
-
-fn test_decoder_error(bytes: Vec<u8>, expected_error: CborError) {
-    let result = decode(&bytes);
-    assert!(result.is_err());
-    assert_eq!(result.unwrap_err(), expected_error);
-}
-
-fn test_integer(bytes: Vec<u8>, expected: u64) {
-    let decoded = decode(&bytes).unwrap();
-    match decoded {
-        CborType::Integer(val) => assert_eq!(val, expected),
-        _ => assert_eq!(1, 0),
-    }
-}
-
-fn test_integer_all(bytes: Vec<u8>, expected_value: u64) {
-    let expected = CborType::Integer(expected_value);
-    test_decoder(bytes.clone(), expected);
-    test_integer(bytes, expected_value);
-}
-
-#[test]
-fn test_integer_objects() {
-    let bytes: Vec<u8> = vec![0x00];
-    test_integer_all(bytes, 0);
-
-    let bytes = vec![0x01];
-    test_integer_all(bytes, 1);
-
-    let bytes = vec![0x0A];
-    test_integer_all(bytes, 10);
-
-    let bytes = vec![0x17];
-    test_integer_all(bytes, 23);
-
-    let bytes = vec![0x18, 0x18];
-    test_integer_all(bytes, 24);
-
-    let bytes = vec![0x18, 0x19];
-    test_integer_all(bytes, 25);
-
-    let bytes = vec![0x18, 0x64];
-    test_integer_all(bytes, 100);
-
-    let bytes = vec![0x19, 0x03, 0xe8];
-    test_integer_all(bytes, 1000);
-
-    let bytes = vec![0x1a, 0x00, 0x0f, 0x42, 0x40];
-    test_integer_all(bytes, 1000000);
-
-    let bytes = vec![0x1b, 0x00, 0x00, 0x00, 0xe8, 0xd4, 0xa5, 0x10, 0x00];
-    test_integer_all(bytes, 1000000000000);
-
-    let bytes = vec![0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
-    test_integer_all(bytes, 18446744073709551615);
-}
-
-#[cfg(test)]
-fn test_tag(bytes: Vec<u8>, expected_tag: u64, expected_value: CborType) {
-    let decoded = decode(&bytes).unwrap();
-    match decoded {
-        CborType::Tag(tag, value) => {
-            assert_eq!(expected_tag, tag);
-            assert_eq!(expected_value, *value);
-        }
-        _ => assert_eq!(1, 0),
-    }
-}
-
-#[test]
-fn test_tagged_objects() {
-    let bytes: Vec<u8> = vec![0xD2, 0x02];
-    let expected_tag_value = 0x12;
-    let expected_value = CborType::Integer(2);
-    let expected = CborType::Tag(expected_tag_value, Box::new(expected_value.clone()));
-    test_decoder(bytes.clone(), expected);
-    test_tag(bytes, expected_tag_value, expected_value);
-}
-
-#[test]
-#[cfg_attr(rustfmt, rustfmt_skip)]
-fn test_arrays() {
-    // []
-    let bytes: Vec<u8> = vec![0x80];
-    let expected = CborType::Array(vec![]);
-    test_decoder(bytes, expected);
-
-    // [1, 2, 3]
-    let bytes: Vec<u8> = vec![0x83, 0x01, 0x02, 0x03];
-    let tmp = vec![
-        CborType::Integer(1),
-        CborType::Integer(2),
-        CborType::Integer(3),
-    ];
-    let expected = CborType::Array(tmp);
-    test_decoder(bytes, expected);
-
-    // [1, [2, 3], [4, 5]]
-    let bytes: Vec<u8> = vec![0x83, 0x01, 0x82, 0x02, 0x03, 0x82, 0x04, 0x05];
-    let tmp1 = vec![CborType::Integer(2), CborType::Integer(3)];
-    let tmp2 = vec![CborType::Integer(4), CborType::Integer(5)];
-    let tmp = vec![
-        CborType::Integer(1),
-        CborType::Array(tmp1),
-        CborType::Array(tmp2),
-    ];
-    let expected = CborType::Array(tmp);
-    test_decoder(bytes, expected);
-
-    // [1, [[[[1]]]], [1]]
-    let bytes: Vec<u8> = vec![0x83, 0x01, 0x81, 0x81, 0x81, 0x81, 0x01, 0x81, 0x02];
-    let tmp = vec![
-        CborType::Integer(1),
-        CborType::Array(vec![
-            CborType::Array(vec![
-                CborType::Array(vec![
-                    CborType::Array(vec![
-                        CborType::Integer(1)])])])]),
-        CborType::Array(vec![CborType::Integer(2)]),
-    ];
-    let expected = CborType::Array(tmp);
-    test_decoder(bytes, expected);
-
-    let bytes: Vec<u8> = vec![0x98, 0x1A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
-                              0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
-                              0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
-                              0x17, 0x18, 0x18, 0x18, 0x19, 0x82, 0x81, 0x81,
-                              0x81, 0x05, 0x81, 0x1A, 0x49, 0x96, 0x02, 0xD2];
-    // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
-    //  21, 22, 23, 24, 25, [[[[5]]], [1234567890]]]
-    let tmp = vec![
-        CborType::Integer(1),
-        CborType::Integer(2),
-        CborType::Integer(3),
-        CborType::Integer(4),
-        CborType::Integer(5),
-        CborType::Integer(6),
-        CborType::Integer(7),
-        CborType::Integer(8),
-        CborType::Integer(9),
-        CborType::Integer(10),
-        CborType::Integer(11),
-        CborType::Integer(12),
-        CborType::Integer(13),
-        CborType::Integer(14),
-        CborType::Integer(15),
-        CborType::Integer(16),
-        CborType::Integer(17),
-        CborType::Integer(18),
-        CborType::Integer(19),
-        CborType::Integer(20),
-        CborType::Integer(21),
-        CborType::Integer(22),
-        CborType::Integer(23),
-        CborType::Integer(24),
-        CborType::Integer(25),
-        CborType::Array(vec![
-            CborType::Array(vec![
-                CborType::Array(vec![
-                    CborType::Array(vec![
-                        CborType::Integer(5)])])]),
-            CborType::Array(vec![CborType::Integer(1234567890)])])
-    ];
-    let expected = CborType::Array(tmp);
-    test_decoder(bytes, expected);
-}
-
-#[test]
-fn test_signed_integer() {
-    let bytes: Vec<u8> = vec![0x20];
-    let expected = CborType::SignedInteger(-1);
-    test_decoder(bytes, expected);
-
-    let bytes = vec![0x29];
-    let expected = CborType::SignedInteger(-10);
-    test_decoder(bytes, expected);
-
-    let bytes = vec![0x38, 0x63];
-    let expected = CborType::SignedInteger(-100);
-    test_decoder(bytes, expected);
-
-    let bytes = vec![0x39, 0x03, 0xe7];
-    let expected = CborType::SignedInteger(-1000);
-    test_decoder(bytes, expected);
-
-    let bytes = vec![0x39, 0x27, 0x0F];
-    let expected = CborType::SignedInteger(-10000);
-    test_decoder(bytes, expected);
-
-    let bytes = vec![0x3A, 0x00, 0x01, 0x86, 0x9F];
-    let expected = CborType::SignedInteger(-100000);
-    test_decoder(bytes, expected);
-
-    let bytes = vec![0x3B, 0x00, 0x00, 0x00, 0xE8, 0xD4, 0xA5, 0x0F, 0xFF];
-    let expected = CborType::SignedInteger(-1000000000000);
-    test_decoder(bytes, expected);
-}
-
-#[test]
-fn test_byte_strings() {
-    let bytes: Vec<u8> = vec![0x40];
-    let expected = CborType::Bytes(vec![]);
-    test_decoder(bytes, expected);
-
-    // 01020304
-    let bytes: Vec<u8> = vec![0x44, 0x01, 0x02, 0x03, 0x04];
-    let expected = CborType::Bytes(vec![0x01, 0x02, 0x03, 0x04]);
-    test_decoder(bytes, expected);
-
-    // 0102030405060708090A0B0C0D0E0F10203040506070
-    let bytes: Vec<u8> = vec![0x56, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
-                              0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60,
-                              0x70];
-    let expected = CborType::Bytes(vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
-         0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x20, 0x30,
-         0x40, 0x50, 0x60, 0x70]);
-    test_decoder(bytes, expected);
-
-    let bytes: Vec<u8> =
-        vec![0x59, 0x01, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
-    let expected = CborType::Bytes(vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
-    test_decoder(bytes, expected);
-}
-
-#[test]
-fn test_maps() {
-    // {}
-    let bytes: Vec<u8> = vec![0xa0];
-    let expected: BTreeMap<CborType, CborType> = BTreeMap::new();
-    test_decoder(bytes, CborType::Map(expected));
-
-    // {1: 2, 3: 4}
-    let bytes: Vec<u8> = vec![0xa2, 0x01, 0x02, 0x03, 0x04];
-    let mut expected: BTreeMap<CborType, CborType> = BTreeMap::new();
-    expected.insert(CborType::Integer(1), CborType::Integer(2));
-    expected.insert(CborType::Integer(3), CborType::Integer(4));
-    test_decoder(bytes, CborType::Map(expected));
-
-    // TODO: strings aren't properly supported as keys yet.
-    // {"a": 1, "b": [2, 3]}
-    // let bytes: Vec<u8> = vec![0xa2, 0x61, 0x61, 0x01, 0x61, 0x62, 0x82, 0x02, 0x03];
-    // let expected =
-    //     CborType::Map(vec![
-    //         CborMap{key: CborType::Integer(1), value: CborType::Integer(2)},
-    //         CborMap{key: CborType::Integer(3), value: CborType::Integer(4)}]);
-    // test_decoder(bytes, expected);
-
-    // let bytes: Vec<u8> = vec![0x82, 0x61, 0x61, 0xa1, 0x61, 0x62, 0x61, 0x63];
-    // test_decoder(bytes, "[a, {b: c}]");
-
-    // let bytes: Vec<u8> = vec![0xa5, 0x61, 0x61, 0x61, 0x41, 0x61, 0x62, 0x61,
-    //                           0x42, 0x61, 0x63, 0x61, 0x43, 0x61, 0x64, 0x61,
-    //                           0x44, 0x61, 0x65, 0x61, 0x45];
-    // test_decoder(bytes, "{a: A, b: B, c: C, d: D, e: E}");
-}
-
-#[test]
-fn test_map_duplicate_keys() {
-    let bytes: Vec<u8> = vec![0xa4, 0x01, 0x02, 0x02, 0x03, 0x01, 0x03, 0x04, 0x04];
-    test_decoder_error(bytes, CborError::DuplicateMapKey);
-}
-
-#[test]
-fn test_tag_with_no_value() {
-    let bytes: Vec<u8> = vec![0xc0];
-    test_decoder_error(bytes, CborError::TruncatedInput);
-}
-
-#[test]
-fn test_truncated_int() {
-    let bytes: Vec<u8> = vec![0x19, 0x03];
-    test_decoder_error(bytes, CborError::TruncatedInput);
-}
-
-#[test]
-fn test_truncated_array() {
-    let bytes: Vec<u8> = vec![0x83, 0x01, 0x02];
-    test_decoder_error(bytes, CborError::TruncatedInput);
-}
-
-#[test]
-fn test_truncated_map() {
-    let bytes: Vec<u8> = vec![0xa2, 0x01, 0x02, 0x00];
-    test_decoder_error(bytes, CborError::TruncatedInput);
-}
-
-#[test]
-fn test_malformed_integer() {
-    let bytes: Vec<u8> = vec![0x1c];
-    test_decoder_error(bytes, CborError::MalformedInput);
-}
-
-#[test]
-fn test_signed_integer_too_large() {
-    let bytes = vec![0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
-    test_decoder_error(bytes, CborError::InputValueOutOfRange);
-}
-
-#[test]
-fn test_null() {
-    let bytes = vec![0xf6];
-    test_decoder(bytes, CborType::Null);
-}
-
-#[test]
-fn test_null_in_array() {
-    let bytes = vec![0x82, 0xf6, 0xf6];
-    test_decoder(
-        bytes,
-        CborType::Array(vec![CborType::Null,
-             CborType::Null]),
-    );
-}
-
-#[test]
-fn test_major_type_7() {
-    for i in 0..0x20 {
-        if i != 22 {
-            let bytes = vec![0xe0 | i];
-            test_decoder_error(bytes, CborError::UnsupportedType);
-        }
-    }
-}
-
-#[test]
-fn test_large_input() {
-    let array = vec![0xFF; MAX_ARRAY_SIZE];
-    let expected = CborType::Bytes(array.clone());
-    let mut bytes = vec![0x5A, 0x08, 0x00, 0x00, 0x00];
-    bytes.extend_from_slice(&array);
-    test_decoder(bytes, expected);
-}
-
-#[test]
-fn test_too_large_input() {
-    let array = vec![0xFF; MAX_ARRAY_SIZE + 1];
-    let mut bytes = vec![0x5A, 0x08, 0x00, 0x00, 0x01];
-    bytes.extend_from_slice(&array);
-    test_decoder_error(bytes, CborError::InputTooLarge);
-}
-
-// We currently don't support CBOR strings (issue #39).
-#[test]
-fn test_invalid_input() {
-    let bytes = vec![0x60];
-    test_decoder_error(bytes, CborError::UnsupportedType);
-}
deleted file mode 100644
--- a/third_party/rust/cose/src/cbor/test_serializer.rs
+++ /dev/null
@@ -1,310 +0,0 @@
-use cbor::CborType;
-use std::collections::BTreeMap;
-
-#[test]
-fn test_nint() {
-    struct Testcase {
-        value: i64,
-        expected: Vec<u8>,
-    }
-    let testcases: Vec<Testcase> = vec![Testcase {
-                                            value: -1,
-                                            expected: vec![0x20],
-                                        },
-                                        Testcase {
-                                            value: -10,
-                                            expected: vec![0x29],
-                                        },
-                                        Testcase {
-                                            value: -100,
-                                            expected: vec![0x38, 0x63],
-                                        },
-                                        Testcase {
-                                            value: -1000,
-                                            expected: vec![0x39, 0x03, 0xe7],
-                                        },
-                                        Testcase {
-                                            value: -1000000,
-                                            expected: vec![0x3a, 0x00, 0x0f, 0x42, 0x3f],
-                                        },
-                                        Testcase {
-                                            value: -4611686018427387903,
-                                            expected: vec![0x3b, 0x3f, 0xff, 0xff, 0xff, 0xff,
-                                                           0xff, 0xff, 0xfe],
-                                        }];
-    for testcase in testcases {
-        let cbor = CborType::SignedInteger(testcase.value);
-        assert_eq!(testcase.expected, cbor.serialize());
-    }
-}
-
-#[test]
-fn test_bstr() {
-    struct Testcase {
-        value: Vec<u8>,
-        expected: Vec<u8>,
-    }
-    let testcases: Vec<Testcase> =
-        vec![Testcase {
-                 value: vec![],
-                 expected: vec![0x40],
-             },
-             Testcase {
-                 value: vec![0x01, 0x02, 0x03, 0x04],
-                 expected: vec![0x44, 0x01, 0x02, 0x03, 0x04],
-             },
-             Testcase {
-                 value: vec![0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
-                             0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
-                             0xaf, 0xaf, 0xaf],
-                 expected: vec![0x58, 0x19, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
-                                0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
-                                0xaf, 0xaf, 0xaf, 0xaf, 0xaf],
-             }];
-    for testcase in testcases {
-        let cbor = CborType::Bytes(testcase.value);
-        assert_eq!(testcase.expected, cbor.serialize());
-    }
-}
-
-#[test]
-fn test_tstr() {
-    struct Testcase {
-        value: String,
-        expected: Vec<u8>,
-    }
-    let testcases: Vec<Testcase> = vec![Testcase {
-                                            value: String::new(),
-                                            expected: vec![0x60],
-                                        },
-                                        Testcase {
-                                            value: String::from("a"),
-                                            expected: vec![0x61, 0x61],
-                                        },
-                                        Testcase {
-                                            value: String::from("IETF"),
-                                            expected: vec![0x64, 0x49, 0x45, 0x54, 0x46],
-                                        },
-                                        Testcase {
-                                            value: String::from("\"\\"),
-                                            expected: vec![0x62, 0x22, 0x5c],
-                                        },
-                                        Testcase {
-                                            value: String::from("水"),
-                                            expected: vec![0x63, 0xe6, 0xb0, 0xb4],
-                                        }];
-    for testcase in testcases {
-        let cbor = CborType::String(testcase.value);
-        assert_eq!(testcase.expected, cbor.serialize());
-    }
-}
-
-#[test]
-fn test_arr() {
-    struct Testcase {
-        value: Vec<CborType>,
-        expected: Vec<u8>,
-    }
-    let nested_arr_1 = vec![CborType::Integer(2),
-                            CborType::Integer(3)];
-    let nested_arr_2 = vec![CborType::Integer(4),
-                            CborType::Integer(5)];
-    let testcases: Vec<Testcase> =
-        vec![Testcase {
-                 value: vec![],
-                 expected: vec![0x80],
-             },
-             Testcase {
-                 value: vec![CborType::Integer(1),
-                             CborType::Integer(2),
-                             CborType::Integer(3)],
-                 expected: vec![0x83, 0x01, 0x02, 0x03],
-             },
-             Testcase {
-                 value: vec![CborType::Integer(1),
-                             CborType::Array(nested_arr_1),
-                             CborType::Array(nested_arr_2)],
-                 expected: vec![0x83, 0x01, 0x82, 0x02, 0x03, 0x82, 0x04, 0x05],
-             },
-             Testcase {
-                 value: vec![CborType::Integer(1),
-                             CborType::Integer(2),
-                             CborType::Integer(3),
-                             CborType::Integer(4),
-                             CborType::Integer(5),
-                             CborType::Integer(6),
-                             CborType::Integer(7),
-                             CborType::Integer(8),
-                             CborType::Integer(9),
-                             CborType::Integer(10),
-                             CborType::Integer(11),
-                             CborType::Integer(12),
-                             CborType::Integer(13),
-                             CborType::Integer(14),
-                             CborType::Integer(15),
-                             CborType::Integer(16),
-                             CborType::Integer(17),
-                             CborType::Integer(18),
-                             CborType::Integer(19),
-                             CborType::Integer(20),
-                             CborType::Integer(21),
-                             CborType::Integer(22),
-                             CborType::Integer(23),
-                             CborType::Integer(24),
-                             CborType::Integer(25)],
-                 expected: vec![0x98, 0x19, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
-                                0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
-                                0x15, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19],
-             }];
-    for testcase in testcases {
-        let cbor = CborType::Array(testcase.value);
-        assert_eq!(testcase.expected, cbor.serialize());
-    }
-}
-
-#[test]
-fn test_map() {
-    let empty_map: BTreeMap<CborType, CborType> = BTreeMap::new();
-    assert_eq!(vec![0xa0], CborType::Map(empty_map).serialize());
-
-    let mut positive_map: BTreeMap<CborType, CborType> = BTreeMap::new();
-    positive_map.insert(CborType::Integer(20), CborType::Integer(10));
-    positive_map.insert(CborType::Integer(10), CborType::Integer(20));
-    positive_map.insert(CborType::Integer(15), CborType::Integer(15));
-    assert_eq!(
-        vec![0xa3, 0x0a, 0x14, 0x0f, 0x0f, 0x14, 0x0a],
-        CborType::Map(positive_map).serialize()
-    );
-
-    let mut negative_map: BTreeMap<CborType, CborType> = BTreeMap::new();
-    negative_map.insert(CborType::SignedInteger(-4), CborType::Integer(10));
-    negative_map.insert(CborType::SignedInteger(-1), CborType::Integer(20));
-    negative_map.insert(CborType::SignedInteger(-5), CborType::Integer(15));
-    negative_map.insert(CborType::SignedInteger(-6), CborType::Integer(10));
-    assert_eq!(
-        vec![0xa4, 0x20, 0x14, 0x23, 0x0a, 0x24, 0x0f, 0x25, 0x0a],
-        CborType::Map(negative_map).serialize()
-    );
-
-    let mut mixed_map: BTreeMap<CborType, CborType> = BTreeMap::new();
-    mixed_map.insert(CborType::Integer(0), CborType::Integer(10));
-    mixed_map.insert(CborType::SignedInteger(-10), CborType::Integer(20));
-    mixed_map.insert(CborType::Integer(15), CborType::Integer(15));
-    assert_eq!(
-        vec![0xa3, 0x00, 0x0a, 0x0f, 0x0f, 0x29, 0x14],
-        CborType::Map(mixed_map).serialize()
-    );
-
-    let mut very_mixed_map: BTreeMap<CborType, CborType> = BTreeMap::new();
-    very_mixed_map.insert(CborType::Integer(0), CborType::Integer(10));
-    very_mixed_map.insert(
-        CborType::SignedInteger(-10000),
-        CborType::String("low".to_string()),
-    );
-    very_mixed_map.insert(CborType::SignedInteger(-10), CborType::Integer(20));
-    very_mixed_map.insert(
-        CborType::Integer(10001),
-        CborType::String("high".to_string()),
-    );
-    very_mixed_map.insert(
-        CborType::Integer(10000),
-        CborType::String("high".to_string()),
-    );
-    very_mixed_map.insert(CborType::Integer(15), CborType::Integer(15));
-    let expected = vec![0xa6, 0x00, 0x0a, 0x0f, 0x0f, 0x29, 0x14, 0x19, 0x27, 0x10, 0x64, 0x68,
-                        0x69, 0x67, 0x68, 0x19, 0x27, 0x11, 0x64, 0x68, 0x69, 0x67, 0x68, 0x39,
-                        0x27, 0x0F, 0x63, 0x6C, 0x6F, 0x77];
-    assert_eq!(expected, CborType::Map(very_mixed_map).serialize());
-}
-
-#[test]
-#[ignore]
-// XXX: The string isn't put into the map at the moment, so we can't actually
-//      test this.
-fn test_invalid_map() {
-    let mut invalid_map: BTreeMap<CborType, CborType> = BTreeMap::new();
-    invalid_map.insert(CborType::SignedInteger(-10), CborType::Integer(20));
-    invalid_map.insert(CborType::String("0".to_string()), CborType::Integer(10));
-    invalid_map.insert(CborType::Integer(15), CborType::Integer(15));
-    let expected: Vec<u8> = vec![];
-    assert_eq!(expected, CborType::Map(invalid_map).serialize());
-}
-
-#[test]
-fn test_integer() {
-    struct Testcase {
-        value: u64,
-        expected: Vec<u8>,
-    }
-    let testcases: Vec<Testcase> =
-        vec![Testcase {
-                 value: 0,
-                 expected: vec![0],
-             },
-             Testcase {
-                 value: 1,
-                 expected: vec![1],
-             },
-             Testcase {
-                 value: 10,
-                 expected: vec![0x0a],
-             },
-             Testcase {
-                 value: 23,
-                 expected: vec![0x17],
-             },
-             Testcase {
-                 value: 24,
-                 expected: vec![0x18, 0x18],
-             },
-             Testcase {
-                 value: 25,
-                 expected: vec![0x18, 0x19],
-             },
-             Testcase {
-                 value: 100,
-                 expected: vec![0x18, 0x64],
-             },
-             Testcase {
-                 value: 1000,
-                 expected: vec![0x19, 0x03, 0xe8],
-             },
-             Testcase {
-                 value: 1000000,
-                 expected: vec![0x1a, 0x00, 0x0f, 0x42, 0x40],
-             },
-             Testcase {
-                 value: 1000000000000,
-                 expected: vec![0x1b, 0x00, 0x00, 0x00, 0xe8, 0xd4, 0xa5, 0x10, 0x00],
-             },
-             Testcase {
-                 value: 18446744073709551615,
-                 expected: vec![0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
-             }];
-    for testcase in testcases {
-        let cbor = CborType::Integer(testcase.value);
-        assert_eq!(testcase.expected, cbor.serialize());
-    }
-}
-
-#[test]
-fn test_tagged_item() {
-    let cbor = CborType::Tag(0x12, Box::new(CborType::Integer(2).clone()));
-    assert_eq!(vec![0xD2, 0x02], cbor.serialize());
-
-    let cbor = CborType::Tag(0x62, Box::new(CborType::Array(vec![]).clone()));
-    assert_eq!(vec![0xD8, 0x62, 0x80], cbor.serialize());
-}
-
-#[test]
-fn test_null() {
-    let cbor = CborType::Null;
-    assert_eq!(vec![0xf6], cbor.serialize());
-}
-
-#[test]
-fn test_null_in_array() {
-    let cbor = CborType::Array(vec![CborType::Null,
-         CborType::Null]);
-    assert_eq!(vec![0x82, 0xf6, 0xf6], cbor.serialize());
-}
--- a/third_party/rust/cose/src/cose.rs
+++ b/third_party/rust/cose/src/cose.rs
@@ -25,21 +25,20 @@
 //!     result &= verify_callback(cose_signature);
 //!
 //!     // We can stop early. The cose_signature is not valid.
 //!     if !result {
 //!         return result;
 //!     }
 //! }
 //!```
+extern crate moz_cbor as cbor;
 
-#[macro_use]
 pub mod decoder;
-mod cbor;
-mod util;
+pub mod util;
 
 /// Errors that can be returned from COSE functions.
 #[derive(Debug, PartialEq)]
 pub enum CoseError {
     DecodingFailure,
     LibraryFailure,
     MalformedInput,
     MissingHeader,
@@ -63,36 +62,11 @@ pub enum CoseError {
 pub enum SignatureAlgorithm {
     ES256,
     ES384,
     ES512,
     PS256,
 }
 
 #[cfg(test)]
-#[macro_use(defer)]
-extern crate scopeguard;
-
-#[cfg(test)]
-mod nss;
-#[cfg(test)]
 mod test_setup;
 #[cfg(test)]
-mod test_nss;
-#[cfg(test)]
-mod util_test;
-#[cfg(test)]
 mod test_cose;
-
-#[derive(Debug)]
-#[cfg(test)]
-pub struct SignatureParameters<'a> {
-    certificate: &'a [u8],
-    algorithm: SignatureAlgorithm,
-    pkcs8: &'a [u8],
-}
-
-#[derive(Debug)]
-#[cfg(test)]
-pub struct Signature<'a> {
-    parameter: &'a SignatureParameters<'a>,
-    signature_bytes: Vec<u8>,
-}
--- a/third_party/rust/cose/src/decoder.rs
+++ b/third_party/rust/cose/src/decoder.rs
@@ -1,55 +1,66 @@
 //! Parse and decode COSE signatures.
 
 use cbor::CborType;
 use cbor::decoder::decode;
 use {CoseError, SignatureAlgorithm};
 use util::get_sig_struct_bytes;
+use std::collections::BTreeMap;
 
-const COSE_SIGN_TAG: u64 = 98;
+pub const COSE_SIGN_TAG: u64 = 98;
 
 /// The result of `decode_signature` holding a decoded COSE signature.
 #[derive(Debug)]
 pub struct CoseSignature {
     pub signature_type: SignatureAlgorithm,
     pub signature: Vec<u8>,
     pub signer_cert: Vec<u8>,
     pub certs: Vec<Vec<u8>>,
     pub to_verify: Vec<u8>,
 }
 
 pub const COSE_TYPE_ES256: i64 = -7;
 pub const COSE_TYPE_ES384: i64 = -35;
 pub const COSE_TYPE_ES512: i64 = -36;
 pub const COSE_TYPE_PS256: i64 = -37;
 
+pub const COSE_HEADER_ALG: u64 = 1;
+pub const COSE_HEADER_KID: u64 = 4;
+
 macro_rules! unpack {
    ($to:tt, $var:ident) => (
         match *$var {
             CborType::$to(ref cbor_object) => {
                 cbor_object
             }
             _ => return Err(CoseError::UnexpectedType),
         };
     )
 }
 
-fn get_map_value(map: &CborType, key: &CborType) -> Result<CborType, CoseError> {
-    match *map {
-        CborType::Map(ref values) => {
-            match values.get(key) {
-                Some(x) => Ok(x.clone()),
-                _ => Err(CoseError::MissingHeader),
-            }
-        }
-        _ => Err(CoseError::UnexpectedType),
+fn get_map_value(
+    map: &BTreeMap<CborType, CborType>,
+    key: &CborType,
+) -> Result<CborType, CoseError> {
+    match map.get(key) {
+        Some(x) => Ok(x.clone()),
+        _ => Err(CoseError::MissingHeader),
     }
 }
 
+/// Ensure that the referenced `CborType` is an empty map.
+fn ensure_empty_map(map: &CborType) -> Result<(), CoseError> {
+    let unpacked = unpack!(Map, map);
+    if !unpacked.is_empty() {
+        return Err(CoseError::MalformedInput);
+    }
+    Ok(())
+}
+
 // This syntax is a little unintuitive. Taken together, the two previous definitions essentially
 // mean:
 //
 // COSE_Sign = [
 //     protected : empty_or_serialized_map,
 //     unprotected : header_map
 //     payload : bstr / nil,
 //     signatures : [+ COSE_Signature]
@@ -80,53 +91,75 @@ fn decode_signature_struct(
     let cose_signature = unpack!(Array, cose_signature);
     if cose_signature.len() != 3 {
         return Err(CoseError::MalformedInput);
     }
     let protected_signature_header_serialized = &cose_signature[0];
     let protected_signature_header_bytes = unpack!(Bytes, protected_signature_header_serialized);
 
     // Parse the protected signature header.
-    let protected_signature_header = match decode(&protected_signature_header_bytes) {
+    let protected_signature_header = &match decode(protected_signature_header_bytes) {
         Err(_) => return Err(CoseError::DecodingFailure),
         Ok(value) => value,
     };
-    let signature_algorithm = get_map_value(&protected_signature_header, &CborType::Integer(1))?;
+    let protected_signature_header = unpack!(Map, protected_signature_header);
+    if protected_signature_header.len() != 2 {
+        return Err(CoseError::MalformedInput);
+    }
+    let signature_algorithm = get_map_value(
+        protected_signature_header,
+        &CborType::Integer(COSE_HEADER_ALG),
+    )?;
     let signature_algorithm = match signature_algorithm {
         CborType::SignedInteger(val) => {
             match val {
                 COSE_TYPE_ES256 => SignatureAlgorithm::ES256,
                 COSE_TYPE_ES384 => SignatureAlgorithm::ES384,
                 COSE_TYPE_ES512 => SignatureAlgorithm::ES512,
                 COSE_TYPE_PS256 => SignatureAlgorithm::PS256,
                 _ => return Err(CoseError::UnexpectedHeaderValue),
             }
         }
         _ => return Err(CoseError::UnexpectedType),
     };
 
-    let ee_cert = &get_map_value(&protected_signature_header, &CborType::Integer(4))?;
+    let ee_cert = &get_map_value(
+        protected_signature_header,
+        &CborType::Integer(COSE_HEADER_KID),
+    )?;
     let ee_cert = unpack!(Bytes, ee_cert).clone();
 
+    // The unprotected header section is expected to be an empty map.
+    ensure_empty_map(&cose_signature[1])?;
+
     // Build signature structure to verify.
     let signature_bytes = &cose_signature[2];
     let signature_bytes = unpack!(Bytes, signature_bytes).clone();
     let sig_structure_bytes = get_sig_struct_bytes(
         protected_body_head.clone(),
         protected_signature_header_serialized.clone(),
         payload,
     );
 
     // Read intermediate certificates from protected_body_head.
-    let protected_body_head = unpack!(Bytes, protected_body_head);
-    let protected_body_head_map = match decode(protected_body_head) {
+    // Any tampering of the protected header during transport will be detected
+    // because it is input to the signature verification.
+    // Note that a protected header has to be present and hold a kid with an
+    // empty list of intermediate certificates.
+    let protected_body_head_bytes = unpack!(Bytes, protected_body_head);
+    let protected_body_head_map = &match decode(protected_body_head_bytes) {
         Ok(value) => value,
         Err(_) => return Err(CoseError::DecodingFailure),
     };
-    let intermediate_certs_array = &get_map_value(&protected_body_head_map, &CborType::Integer(4))?;
+    let protected_body_head_map = unpack!(Map, protected_body_head_map);
+    if protected_body_head_map.len() != 1 {
+        return Err(CoseError::MalformedInput);
+    }
+    let intermediate_certs_array =
+        &get_map_value(protected_body_head_map, &CborType::Integer(COSE_HEADER_KID))?;
     let intermediate_certs = unpack!(Array, intermediate_certs_array);
     let mut certs: Vec<Vec<u8>> = Vec::new();
     for cert in intermediate_certs {
         let cert = unpack!(Bytes, cert);
         certs.push(cert.clone());
     }
 
     Ok(CoseSignature {
@@ -149,17 +182,17 @@ fn decode_signature_struct(
 ///
 /// Headers = (
 ///     protected : empty_or_serialized_map,
 ///     unprotected : header_map
 /// )
 ///```
 pub fn decode_signature(bytes: &[u8], payload: &[u8]) -> Result<Vec<CoseSignature>, CoseError> {
     // This has to be a COSE_Sign object, which is a tagged array.
-    let tagged_cose_sign = match decode(&bytes) {
+    let tagged_cose_sign = match decode(bytes) {
         Err(_) => return Err(CoseError::DecodingFailure),
         Ok(value) => value,
     };
     let cose_sign_array = match tagged_cose_sign {
         CborType::Tag(tag, cose_sign) => {
             if tag != COSE_SIGN_TAG {
                 return Err(CoseError::UnexpectedTag);
             }
@@ -168,25 +201,35 @@ pub fn decode_signature(bytes: &[u8], pa
                 _ => return Err(CoseError::UnexpectedType),
             }
         }
         _ => return Err(CoseError::UnexpectedType),
     };
     if cose_sign_array.len() != 4 {
         return Err(CoseError::MalformedInput);
     }
+
+    // The unprotected header section is expected to be an empty map.
+    ensure_empty_map(&cose_sign_array[1])?;
+
+    // The payload is expected to be Null (i.e. this is a detached signature).
+    match cose_sign_array[2] {
+        CborType::Null => {}
+        _ => return Err(CoseError::UnexpectedType),
+    };
+
     let signatures = &cose_sign_array[3];
     let signatures = unpack!(Array, signatures);
 
     // Decode COSE_Signatures.
     // There has to be at least one signature to make this a valid COSE signature.
     if signatures.len() < 1 {
         return Err(CoseError::MalformedInput);
     }
     let mut result = Vec::new();
     for cose_signature in signatures {
-        // cose_sign_array holds the protected body header.
+        // cose_sign_array[0] holds the protected body header.
         let signature = decode_signature_struct(cose_signature, payload, &cose_sign_array[0])?;
         result.push(signature);
     }
 
     Ok(result)
 }
deleted file mode 100644
--- a/third_party/rust/cose/src/nss.rs
+++ /dev/null
@@ -1,356 +0,0 @@
-use std::marker::PhantomData;
-use std::{mem, ptr};
-use std::os::raw;
-use std::os::raw::c_char;
-use SignatureAlgorithm;
-
-type SECItemType = raw::c_uint; // TODO: actually an enum - is this the right size?
-const SI_BUFFER: SECItemType = 0; // called siBuffer in NSS
-
-#[repr(C)]
-struct SECItem {
-    typ: SECItemType,
-    data: *const u8,
-    len: raw::c_uint,
-}
-
-impl SECItem {
-    fn maybe_new(data: &[u8]) -> Result<SECItem, NSSError> {
-        if data.len() > u32::max_value() as usize {
-            return Err(NSSError::InputTooLarge);
-        }
-        Ok(SECItem {
-            typ: SI_BUFFER,
-            data: data.as_ptr(),
-            len: data.len() as u32,
-        })
-    }
-
-    fn maybe_from_parts(data: *const u8, len: usize) -> Result<SECItem, NSSError> {
-        if len > u32::max_value() as usize {
-            return Err(NSSError::InputTooLarge);
-        }
-        Ok(SECItem {
-            typ: SI_BUFFER,
-            data: data,
-            len: len as u32,
-        })
-    }
-}
-
-/// Many NSS APIs take constant data input as SECItems. Some, however, output data as SECItems.
-/// To represent this, we define another type of mutable SECItem.
-#[repr(C)]
-struct SECItemMut<'a> {
-    typ: SECItemType,
-    data: *mut u8,
-    len: raw::c_uint,
-    _marker: PhantomData<&'a mut Vec<u8>>,
-}
-
-impl<'a> SECItemMut<'a> {
-    /// Given a mutable reference to a Vec<u8> that has a particular allocated capacity, create a
-    /// SECItemMut that points to the vec and has the same capacity.
-    /// The input vec is not expected to have any actual contents, and in any case is cleared.
-    fn maybe_from_empty_preallocated_vec(vec: &'a mut Vec<u8>) -> Result<SECItemMut<'a>, NSSError> {
-        if vec.capacity() > u32::max_value() as usize {
-            return Err(NSSError::InputTooLarge);
-        }
-        vec.clear();
-        Ok(SECItemMut {
-            typ: SI_BUFFER,
-            data: vec.as_mut_ptr(),
-            len: vec.capacity() as u32,
-            _marker: PhantomData,
-        })
-    }
-}
-
-#[repr(C)]
-struct CkRsaPkcsPssParams {
-    // Called CK_RSA_PKCS_PSS_PARAMS in NSS
-    hash_alg: CkMechanismType, // Called hashAlg in NSS
-    mgf: CkRsaPkcsMgfType,
-    s_len: raw::c_ulong, // Called sLen in NSS
-}
-
-impl CkRsaPkcsPssParams {
-    fn new() -> CkRsaPkcsPssParams {
-        CkRsaPkcsPssParams {
-            hash_alg: CKM_SHA256,
-            mgf: CKG_MGF1_SHA256,
-            s_len: 32,
-        }
-    }
-
-    fn get_params_item(&self) -> Result<SECItem, NSSError> {
-        // This isn't entirely NSS' fault, but it mostly is.
-        let params_ptr: *const CkRsaPkcsPssParams = self;
-        let params_ptr: *const u8 = params_ptr as *const u8;
-        let params_secitem =
-            SECItem::maybe_from_parts(params_ptr, mem::size_of::<CkRsaPkcsPssParams>())?;
-        Ok(params_secitem)
-    }
-}
-
-type CkMechanismType = raw::c_ulong; // called CK_MECHANISM_TYPE in NSS
-const CKM_ECDSA: CkMechanismType = 0x0000_1041;
-const CKM_RSA_PKCS_PSS: CkMechanismType = 0x0000_000D;
-const CKM_SHA256: CkMechanismType = 0x0000_0250;
-
-type CkRsaPkcsMgfType = raw::c_ulong; // called CK_RSA_PKCS_MGF_TYPE in NSS
-const CKG_MGF1_SHA256: CkRsaPkcsMgfType = 0x0000_0002;
-
-type SECStatus = raw::c_int; // TODO: enum - right size?
-const SEC_SUCCESS: SECStatus = 0; // Called SECSuccess in NSS
-const SEC_FAILURE: SECStatus = -1; // Called SECFailure in NSS
-
-enum SECKEYPublicKey {}
-enum SECKEYPrivateKey {}
-enum PK11SlotInfo {}
-enum CERTCertificate {}
-enum CERTCertDBHandle {}
-
-const SHA256_LENGTH: usize = 32;
-const SHA384_LENGTH: usize = 48;
-const SHA512_LENGTH: usize = 64;
-
-// TODO: ugh this will probably have a platform-specific name...
-#[link(name = "nss3")]
-extern "C" {
-    fn PK11_HashBuf(
-        hashAlg: HashAlgorithm,
-        out: *mut u8,
-        data_in: *const u8, // called "in" in NSS
-        len: raw::c_int,
-    ) -> SECStatus;
-    fn PK11_VerifyWithMechanism(
-        key: *const SECKEYPublicKey,
-        mechanism: CkMechanismType,
-        param: *const SECItem,
-        sig: *const SECItem,
-        hash: *const SECItem,
-        wincx: *const raw::c_void,
-    ) -> SECStatus;
-
-    fn SECKEY_DestroyPublicKey(pubk: *const SECKEYPublicKey);
-
-    fn CERT_GetDefaultCertDB() -> *const CERTCertDBHandle;
-    fn CERT_DestroyCertificate(cert: *mut CERTCertificate);
-    fn CERT_NewTempCertificate(
-        handle: *const CERTCertDBHandle,
-        derCert: *const SECItem,
-        nickname: *const c_char,
-        isperm: bool,
-        copyDER: bool,
-    ) -> *mut CERTCertificate;
-    fn CERT_ExtractPublicKey(cert: *const CERTCertificate) -> *const SECKEYPublicKey;
-
-    fn PK11_ImportDERPrivateKeyInfoAndReturnKey(
-        slot: *mut PK11SlotInfo,
-        derPKI: *const SECItem,
-        nickname: *const SECItem,
-        publicValue: *const SECItem,
-        isPerm: bool,
-        isPrivate: bool,
-        keyUsage: u32,
-        privk: *mut *mut SECKEYPrivateKey,
-        wincx: *const u8,
-    ) -> SECStatus;
-    fn PK11_GetInternalSlot() -> *mut PK11SlotInfo;
-    fn PK11_FreeSlot(slot: *mut PK11SlotInfo);
-    fn PK11_SignatureLen(key: *const SECKEYPrivateKey) -> usize;
-    fn PK11_SignWithMechanism(
-        key: *const SECKEYPrivateKey,
-        mech: CkMechanismType,
-        param: *const SECItem,
-        sig: *mut SECItemMut,
-        hash: *const SECItem,
-    ) -> SECStatus;
-}
-
-/// An error type describing errors that may be encountered during verification.
-#[derive(Debug, PartialEq)]
-pub enum NSSError {
-    ImportCertError,
-    DecodingPKCS8Failed,
-    InputTooLarge,
-    LibraryFailure,
-    SignatureVerificationFailed,
-    SigningFailed,
-    ExtractPublicKeyFailed,
-}
-
-// https://searchfox.org/nss/rev/990c2e793aa731cd66238c6c4f00b9473943bc66/lib/util/secoidt.h#274
-#[derive(Debug, PartialEq, Clone)]
-#[repr(C)]
-enum HashAlgorithm {
-    SHA256 = 191,
-    SHA384 = 192,
-    SHA512 = 193,
-}
-
-fn hash(payload: &[u8], signature_algorithm: &SignatureAlgorithm) -> Result<Vec<u8>, NSSError> {
-    if payload.len() > raw::c_int::max_value() as usize {
-        return Err(NSSError::InputTooLarge);
-    }
-    let (hash_algorithm, digest_length) = match *signature_algorithm {
-        SignatureAlgorithm::ES256 => (HashAlgorithm::SHA256, SHA256_LENGTH),
-        SignatureAlgorithm::ES384 => (HashAlgorithm::SHA384, SHA384_LENGTH),
-        SignatureAlgorithm::ES512 => (HashAlgorithm::SHA512, SHA512_LENGTH),
-        SignatureAlgorithm::PS256 => (HashAlgorithm::SHA256, SHA256_LENGTH),
-    };
-    let mut hash_buf = vec![0; digest_length];
-    let len: raw::c_int = payload.len() as raw::c_int;
-    let hash_result =
-        unsafe { PK11_HashBuf(hash_algorithm, hash_buf.as_mut_ptr(), payload.as_ptr(), len) };
-    if hash_result != SEC_SUCCESS {
-        return Err(NSSError::LibraryFailure);
-    }
-    Ok(hash_buf)
-}
-
-/// Main entrypoint for verification. Given a signature algorithm, the bytes of a subject public key
-/// info, a payload, and a signature over the payload, returns a result based on the outcome of
-/// decoding the subject public key info and running the signature verification algorithm on the
-/// signed data.
-pub fn verify_signature(
-    signature_algorithm: &SignatureAlgorithm,
-    cert: &[u8],
-    payload: &[u8],
-    signature: &[u8],
-) -> Result<(), NSSError> {
-    let slot = unsafe { PK11_GetInternalSlot() };
-    if slot.is_null() {
-        return Err(NSSError::LibraryFailure);
-    }
-    defer!(unsafe {
-        PK11_FreeSlot(slot);
-    });
-
-    let hash_buf = hash(payload, signature_algorithm).unwrap();
-    let hash_item = SECItem::maybe_new(hash_buf.as_slice())?;
-
-    // Import DER cert into NSS.
-    let der_cert = SECItem::maybe_new(cert)?;
-    let db_handle = unsafe { CERT_GetDefaultCertDB() };
-    if db_handle.is_null() {
-        // TODO #28
-        return Err(NSSError::LibraryFailure);
-    }
-    let nss_cert =
-        unsafe { CERT_NewTempCertificate(db_handle, &der_cert, ptr::null(), false, true) };
-    if nss_cert.is_null() {
-        return Err(NSSError::ImportCertError);
-    }
-    defer!(unsafe {
-        CERT_DestroyCertificate(nss_cert);
-    });
-
-    let key = unsafe { CERT_ExtractPublicKey(nss_cert) };
-    if key.is_null() {
-        return Err(NSSError::ExtractPublicKeyFailed);
-    }
-    defer!(unsafe {
-        SECKEY_DestroyPublicKey(key);
-    });
-    let signature_item = SECItem::maybe_new(signature)?;
-    let mechanism = match *signature_algorithm {
-        SignatureAlgorithm::ES256 => CKM_ECDSA,
-        SignatureAlgorithm::ES384 => CKM_ECDSA,
-        SignatureAlgorithm::ES512 => CKM_ECDSA,
-        SignatureAlgorithm::PS256 => CKM_RSA_PKCS_PSS,
-    };
-    let rsa_pss_params = CkRsaPkcsPssParams::new();
-    let rsa_pss_params_item = rsa_pss_params.get_params_item()?;
-    let params_item = match *signature_algorithm {
-        SignatureAlgorithm::ES256 => ptr::null(),
-        SignatureAlgorithm::ES384 => ptr::null(),
-        SignatureAlgorithm::ES512 => ptr::null(),
-        SignatureAlgorithm::PS256 => &rsa_pss_params_item,
-    };
-    let null_cx_ptr: *const raw::c_void = ptr::null();
-    let result = unsafe {
-        PK11_VerifyWithMechanism(
-            key,
-            mechanism,
-            params_item,
-            &signature_item,
-            &hash_item,
-            null_cx_ptr,
-        )
-    };
-    match result {
-        SEC_SUCCESS => Ok(()),
-        SEC_FAILURE => Err(NSSError::SignatureVerificationFailed),
-        _ => Err(NSSError::LibraryFailure),
-    }
-}
-
-pub fn sign(
-    signature_algorithm: &SignatureAlgorithm,
-    pk8: &[u8],
-    payload: &[u8],
-) -> Result<Vec<u8>, NSSError> {
-    let slot = unsafe { PK11_GetInternalSlot() };
-    if slot.is_null() {
-        return Err(NSSError::LibraryFailure);
-    }
-    defer!(unsafe {
-        PK11_FreeSlot(slot);
-    });
-    let pkcs8item = SECItem::maybe_new(pk8)?;
-    let mut key: *mut SECKEYPrivateKey = ptr::null_mut();
-    let ku_all = 0xFF;
-    let rv = unsafe {
-        PK11_ImportDERPrivateKeyInfoAndReturnKey(
-            slot,
-            &pkcs8item,
-            ptr::null(),
-            ptr::null(),
-            false,
-            false,
-            ku_all,
-            &mut key,
-            ptr::null(),
-        )
-    };
-    if rv != SEC_SUCCESS || key.is_null() {
-        return Err(NSSError::DecodingPKCS8Failed);
-    }
-    let mechanism = match *signature_algorithm {
-        SignatureAlgorithm::ES256 => CKM_ECDSA,
-        SignatureAlgorithm::ES384 => CKM_ECDSA,
-        SignatureAlgorithm::ES512 => CKM_ECDSA,
-        SignatureAlgorithm::PS256 => CKM_RSA_PKCS_PSS,
-    };
-    let rsa_pss_params = CkRsaPkcsPssParams::new();
-    let rsa_pss_params_item = rsa_pss_params.get_params_item()?;
-    let params_item = match *signature_algorithm {
-        SignatureAlgorithm::ES256 => ptr::null(),
-        SignatureAlgorithm::ES384 => ptr::null(),
-        SignatureAlgorithm::ES512 => ptr::null(),
-        SignatureAlgorithm::PS256 => &rsa_pss_params_item,
-    };
-    let signature_len = unsafe { PK11_SignatureLen(key) };
-    // Allocate enough space for the signature.
-    let mut signature: Vec<u8> = Vec::with_capacity(signature_len);
-    let hash_buf = hash(payload, signature_algorithm).unwrap();
-    let hash_item = SECItem::maybe_new(hash_buf.as_slice())?;
-    {
-        // Get a mutable SECItem on the preallocated signature buffer. PK11_SignWithMechanism will
-        // fill the SECItem's buf with the bytes of the signature.
-        let mut signature_item = SECItemMut::maybe_from_empty_preallocated_vec(&mut signature)?;
-        let rv = unsafe {
-            PK11_SignWithMechanism(key, mechanism, params_item, &mut signature_item, &hash_item)
-        };
-        if rv != SEC_SUCCESS || signature_item.len as usize != signature_len {
-            return Err(NSSError::SigningFailed);
-        }
-    }
-    unsafe {
-        // Now that the bytes of the signature have been filled out, set its length.
-        signature.set_len(signature_len);
-    }
-    Ok(signature)
-}
--- a/third_party/rust/cose/src/test_cose.rs
+++ b/third_party/rust/cose/src/test_cose.rs
@@ -1,230 +1,496 @@
 use test_setup as test;
-use util_test::{sign, verify_signature};
-use {CoseError, SignatureAlgorithm, SignatureParameters};
-use std::str::FromStr;
-use decoder::decode_signature;
+use {CoseError, SignatureAlgorithm};
+use decoder::{COSE_HEADER_ALG, COSE_HEADER_KID, COSE_SIGN_TAG, COSE_TYPE_ES256, decode_signature};
+use cbor::CborType;
+use std::collections::BTreeMap;
 
 #[test]
 fn test_cose_decode() {
     let payload = b"This is the content.";
     let cose_signatures = decode_signature(&test::COSE_SIGNATURE_BYTES, payload).unwrap();
     assert_eq!(cose_signatures.len(), 1);
     assert_eq!(cose_signatures[0].signature_type, SignatureAlgorithm::ES256);
     assert_eq!(cose_signatures[0].signature, test::SIGNATURE_BYTES.to_vec());
     assert_eq!(cose_signatures[0].certs[0], test::P256_ROOT.to_vec());
     assert_eq!(cose_signatures[0].certs[1], test::P256_INT.to_vec());
 }
 
-// All keys here are from pykey.py/pycert.py from mozilla-central.
-// Certificates can be generated with tools/certs/certs.sh and mozilla-central.
+fn test_cose_format_error(bytes: &[u8], expected_error: CoseError) {
+    let payload = vec![0];
+    let result = decode_signature(bytes, &payload);
+    assert!(result.is_err());
+    assert_eq!(result.err(), Some(expected_error));
+}
+
+// Helper function to take a `Vec<CborType>`, wrap it in a `CborType::Array`, tag it with the
+// COSE_Sign tag (COSE_SIGN_TAG = 98), and serialize it to a `Vec<u8>`.
+fn wrap_tag_and_encode_array(array: Vec<CborType>) -> Vec<u8> {
+    CborType::Tag(COSE_SIGN_TAG, Box::new(CborType::Array(array))).serialize()
+}
+
+// Helper function to create an encoded protected header for a COSE_Sign or COSE_Signature
+// structure.
+fn encode_test_protected_header(keys: Vec<CborType>, values: Vec<CborType>) -> Vec<u8> {
+    assert_eq!(keys.len(), values.len());
+    let mut map: BTreeMap<CborType, CborType> = BTreeMap::new();
+    for (key, value) in keys.iter().zip(values) {
+        map.insert(key.clone(), value.clone());
+    }
+    CborType::Map(map).serialize()
+}
+
+// Helper function to create a test COSE_Signature structure with the given protected header.
+fn build_test_cose_signature(protected_header: Vec<u8>) -> CborType {
+    CborType::Array(vec![CborType::Bytes(protected_header),
+         CborType::Map(BTreeMap::new()),
+         CborType::Bytes(Vec::new())])
+}
+
+// Helper function to create the minimally-valid COSE_Sign (i.e. "body") protected header.
+fn make_minimally_valid_cose_sign_protected_header() -> Vec<u8> {
+    encode_test_protected_header(
+        vec![CborType::Integer(COSE_HEADER_KID)],
+        vec![CborType::Array(Vec::new())],
+    )
+}
+
+// Helper function to create a minimally-valid COSE_Signature (i.e. "body").
+fn make_minimally_valid_cose_signature_protected_header() -> Vec<u8> {
+    encode_test_protected_header(
+        vec![CborType::Integer(COSE_HEADER_ALG),
+             CborType::Integer(COSE_HEADER_KID)],
+        vec![CborType::SignedInteger(COSE_TYPE_ES256),
+             CborType::Bytes(Vec::new())],
+    )
+}
 
-const P256_PARAMS: SignatureParameters = SignatureParameters {
-    certificate: &test::P256_EE,
-    algorithm: SignatureAlgorithm::ES256,
-    pkcs8: &test::PKCS8_P256_EE,
-};
-const P384_PARAMS: SignatureParameters = SignatureParameters {
-    certificate: &test::P384_EE,
-    algorithm: SignatureAlgorithm::ES384,
-    pkcs8: &test::PKCS8_P384_EE,
-};
-const P521_PARAMS: SignatureParameters = SignatureParameters {
-    certificate: &test::P521_EE,
-    algorithm: SignatureAlgorithm::ES512,
-    pkcs8: &test::PKCS8_P521_EE,
-};
+// This tests the minimally-valid COSE_Sign structure according to this implementation.
+// The structure must be a CBOR array of length 4 tagged with the integer 98.
+// The COSE_Sign protected header must have the `kid` integer key and no others. The value for `kid`
+// must be an array (although it may be empty). Each element of the array must be of type bytes.
+// The COSE_Sign unprotected header must be an empty map.
+// The COSE_Sign payload must be nil.
+// The COSE_Sign signatures must be an array with at least one COSE_Signature.
+// Each COSE_Signature must be an array of length 3.
+// Each COSE_Signature protected header must have the `alg` and `kid` integer keys and no others.
+// The value for `alg` must be a valid algorithm identifier. The value for `kid` must be bytes,
+// although it may be empty.
+// Each COSE_Signature unprotected header must be an empty map.
+// Each COSE_Signature signature must be of type bytes (although it may be empty).
+#[test]
+fn test_cose_sign_minimally_valid() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+    let signature = build_test_cose_signature(signature_protected_header);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    let payload = vec![0];
+    let result = decode_signature(&bytes, &payload);
+    assert!(result.is_ok());
+    let decoded = result.unwrap();
+    assert_eq!(decoded.len(), 1);
+    assert_eq!(decoded[0].signer_cert.len(), 0);
+    assert_eq!(decoded[0].certs.len(), 0);
+}
 
-#[cfg(test)]
-fn test_verify(payload: &[u8], cert_chain: &[&[u8]], params_vec: Vec<SignatureParameters>) {
-    test::setup();
-    let cose_signature = sign(payload, cert_chain, &params_vec);
-    assert!(cose_signature.is_ok());
-    let cose_signature = cose_signature.unwrap();
+#[test]
+fn test_cose_sign_not_tagged() {
+    let bytes = CborType::Array(vec![CborType::Integer(0)]).serialize();
+    test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
+
+#[test]
+fn test_cose_sign_wrong_tag() {
+    // The expected COSE_Sign tag is 98.
+    let bytes = CborType::Tag(99, Box::new(CborType::Integer(0))).serialize();
+    test_cose_format_error(&bytes, CoseError::UnexpectedTag);
+}
 
-    // Verify signature.
-    assert!(verify_signature(payload, cose_signature).is_ok());
+#[test]
+fn test_cose_sign_right_tag_wrong_contents() {
+    // The COSE_Sign tag is 98, but the contents should be an array.
+    let bytes = CborType::Tag(98, Box::new(CborType::Integer(0))).serialize();
+    test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
+
+#[test]
+fn test_cose_sign_too_small() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::MalformedInput);
 }
 
-#[cfg(test)]
-fn test_verify_modified_payload(
-    payload: &mut [u8],
-    cert_chain: &[&[u8]],
-    params_vec: Vec<SignatureParameters>,
-) {
-    test::setup();
-    let cose_signature = sign(payload, cert_chain, &params_vec);
-    assert!(cose_signature.is_ok());
-    let cose_signature = cose_signature.unwrap();
+#[test]
+fn test_cose_sign_too_large() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(Vec::new()),
+                      CborType::Array(Vec::new())];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
+
+#[test]
+fn test_cose_sign_protected_header_empty() {
+    let body_protected_header = encode_test_protected_header(Vec::new(), Vec::new());
+    let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+    let signature = build_test_cose_signature(signature_protected_header);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
 
-    // Verify signature.
-    payload[0] = !payload[0];
-    let verify_result = verify_signature(payload, cose_signature);
-    assert!(verify_result.is_err());
-    assert_eq!(verify_result, Err(CoseError::VerificationFailed));
+#[test]
+fn test_cose_sign_protected_header_missing_kid() {
+    let body_protected_header =
+        encode_test_protected_header(vec![CborType::Integer(2)], vec![CborType::Integer(2)]);
+    let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+    let signature = build_test_cose_signature(signature_protected_header);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::MissingHeader);
+}
+
+#[test]
+fn test_cose_sign_protected_header_kid_wrong_type() {
+    let body_protected_header = encode_test_protected_header(
+        vec![CborType::Integer(COSE_HEADER_KID)],
+        vec![CborType::Integer(2)],
+    );
+    let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+    let signature = build_test_cose_signature(signature_protected_header);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::UnexpectedType);
 }
 
-#[cfg(test)]
-fn test_verify_modified_signature(
-    payload: &[u8],
-    cert_chain: &[&[u8]],
-    params_vec: Vec<SignatureParameters>,
-) {
-    test::setup();
-    let cose_signature = sign(payload, cert_chain, &params_vec);
-    assert!(cose_signature.is_ok());
-    let mut cose_signature = cose_signature.unwrap();
+#[test]
+fn test_cose_sign_protected_header_extra_header_key() {
+    let body_protected_header = encode_test_protected_header(
+        vec![CborType::Integer(COSE_HEADER_KID),
+             CborType::Integer(2)],
+        vec![CborType::Bytes(Vec::new()),
+             CborType::Integer(2)],
+    );
+    let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+    let signature = build_test_cose_signature(signature_protected_header);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
 
-    // Tamper with the cose signature.
-    let len = cose_signature.len();
-    cose_signature[len - 15] = !cose_signature[len - 15];
-
-    // Verify signature.
-    let verify_result = verify_signature(payload, cose_signature);
-    assert!(verify_result.is_err());
-    assert_eq!(verify_result, Err(CoseError::VerificationFailed));
+#[test]
+fn test_cose_sign_unprotected_header_wrong_type() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+    let signature = build_test_cose_signature(signature_protected_header);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Integer(1),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::UnexpectedType);
 }
 
-// This can be used with inconsistent parameters that make the verification fail.
-// In particular, the signing key does not match the certificate used to verify.
-#[cfg(test)]
-fn test_verify_verification_fails(
-    payload: &[u8],
-    cert_chain: &[&[u8]],
-    params_vec: Vec<SignatureParameters>,
-) {
-    test::setup();
-    let cose_signature = sign(payload, cert_chain, &params_vec);
-    assert!(cose_signature.is_ok());
-    let cose_signature = cose_signature.unwrap();
+#[test]
+fn test_cose_sign_unprotected_header_not_empty() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+    let signature = build_test_cose_signature(signature_protected_header);
+    let mut unprotected_header_map: BTreeMap<CborType, CborType> = BTreeMap::new();
+    unprotected_header_map.insert(CborType::Integer(0), CborType::SignedInteger(-1));
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(unprotected_header_map),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
 
-    // Verify signature.
-    let verify_result = verify_signature(payload, cose_signature);
-    assert!(verify_result.is_err());
-    assert_eq!(verify_result, Err(CoseError::VerificationFailed));
+#[test]
+fn test_cose_sign_payload_not_null() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+    let signature = build_test_cose_signature(signature_protected_header);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Integer(0),
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
+
+#[test]
+fn test_cose_signatures_not_array() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Integer(0)];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::UnexpectedType);
 }
 
 #[test]
-fn test_cose_sign_verify() {
-    let payload = b"This is the content.";
+fn test_cose_signatures_empty() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(Vec::new())];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
 
-    // P256
-    let certs: [&[u8]; 2] = [&test::P256_ROOT,
-                             &test::P256_INT];
-    let params_vec = vec![P256_PARAMS];
-    test_verify(payload, &certs, params_vec);
+#[test]
+fn test_cose_signature_protected_header_wrong_type() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature = CborType::Array(vec![CborType::Null,
+         CborType::Map(BTreeMap::new()),
+         CborType::SignedInteger(-1)]);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
 
-    // P384
-    let params_vec = vec![P384_PARAMS];
-    test_verify(payload, &certs, params_vec);
-
-    // P521
-    let params_vec = vec![P521_PARAMS];
-    test_verify(payload, &certs, params_vec);
+#[test]
+fn test_cose_signature_protected_header_empty() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = encode_test_protected_header(Vec::new(), Vec::new());
+    let signature = build_test_cose_signature(signature_protected_header);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::MalformedInput);
 }
 
 #[test]
-fn test_cose_sign_verify_modified_payload() {
-    let mut payload = String::from_str("This is the content.")
-        .unwrap()
-        .into_bytes();
-    let certs: [&[u8]; 2] = [&test::P256_ROOT,
-                             &test::P256_INT];
-    let params_vec = vec![P256_PARAMS];
-    test_verify_modified_payload(&mut payload, &certs, params_vec);
+fn test_cose_signature_protected_header_too_large() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+    let signature = CborType::Array(vec![CborType::Bytes(signature_protected_header),
+         CborType::Map(BTreeMap::new()),
+         CborType::Bytes(Vec::new()),
+         CborType::Null]);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::MalformedInput);
+}
+
+#[test]
+fn test_cose_signature_protected_header_bad_encoding() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    // The bytes here are a truncated integer encoding.
+    let signature = CborType::Array(vec![CborType::Bytes(vec![0x1a, 0x00, 0x00]),
+         CborType::Map(BTreeMap::new()),
+         CborType::Bytes(Vec::new())]);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::DecodingFailure);
 }
 
 #[test]
-fn test_cose_sign_verify_wrong_cert() {
-    let payload = b"This is the content.";
-    let certs: [&[u8]; 2] = [&test::P256_ROOT,
-                             &test::P256_INT];
-    let params = SignatureParameters {
-        certificate: &test::P384_EE,
-        algorithm: SignatureAlgorithm::ES256,
-        pkcs8: &test::PKCS8_P256_EE,
-    };
-    let params_vec = vec![params];
-    test_verify_verification_fails(payload, &certs, params_vec);
+fn test_cose_signature_protected_header_missing_alg() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = encode_test_protected_header(
+        vec![CborType::Integer(2),
+             CborType::Integer(COSE_HEADER_KID)],
+        vec![CborType::SignedInteger(COSE_TYPE_ES256),
+             CborType::Bytes(Vec::new())],
+    );
+    let signature = build_test_cose_signature(signature_protected_header);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::MissingHeader);
+}
+
+#[test]
+fn test_cose_signature_protected_header_missing_kid() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = encode_test_protected_header(
+        vec![CborType::Integer(COSE_HEADER_ALG),
+             CborType::Integer(3)],
+        vec![CborType::SignedInteger(COSE_TYPE_ES256),
+             CborType::Bytes(Vec::new())],
+    );
+    let signature = build_test_cose_signature(signature_protected_header);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::MissingHeader);
 }
 
 #[test]
-fn test_cose_sign_verify_tampered_signature() {
-    let payload = b"This is the content.";
-    let certs: [&[u8]; 2] = [&test::P256_ROOT,
-                             &test::P256_INT];
-    let params_vec = vec![P256_PARAMS];
-    test_verify_modified_signature(payload, &certs, params_vec);
-}
-
-const RSA_PARAMS: SignatureParameters = SignatureParameters {
-    certificate: &test::RSA_EE,
-    algorithm: SignatureAlgorithm::PS256,
-    pkcs8: &test::PKCS8_RSA_EE,
-};
-
-#[test]
-fn test_cose_sign_verify_rsa() {
-    let payload = b"This is the RSA-signed content.";
-    let certs: [&[u8]; 2] = [&test::RSA_ROOT,
-                             &test::RSA_INT];
-    let params_vec = vec![RSA_PARAMS];
-    test_verify(payload, &certs, params_vec);
+fn test_cose_signature_protected_header_wrong_key_types() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = encode_test_protected_header(
+        vec![CborType::SignedInteger(-1),
+             CborType::Bytes(vec![0])],
+        vec![CborType::SignedInteger(COSE_TYPE_ES256),
+             CborType::Bytes(Vec::new())],
+    );
+    let signature = build_test_cose_signature(signature_protected_header);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::MissingHeader);
 }
 
 #[test]
-fn test_cose_sign_verify_rsa_modified_payload() {
-    let mut payload = String::from_str("This is the RSA-signed content.")
-        .unwrap()
-        .into_bytes();
-    let certs: [&[u8]; 2] = [&test::RSA_ROOT,
-                             &test::RSA_INT];
-    let params_vec = vec![RSA_PARAMS];
-    test_verify_modified_payload(&mut payload, &certs, params_vec);
+fn test_cose_signature_protected_header_unexpected_alg_type() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = encode_test_protected_header(
+        vec![CborType::Integer(COSE_HEADER_ALG),
+             CborType::Integer(COSE_HEADER_KID)],
+        vec![CborType::Integer(10),
+             CborType::Integer(4)],
+    );
+    let signature = build_test_cose_signature(signature_protected_header);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
+
+#[test]
+fn test_cose_signature_protected_header_unsupported_alg() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = encode_test_protected_header(
+        vec![CborType::Integer(COSE_HEADER_ALG),
+             CborType::Integer(COSE_HEADER_KID)],
+        vec![CborType::SignedInteger(-10),
+             CborType::Bytes(Vec::new())],
+    );
+    let signature = build_test_cose_signature(signature_protected_header);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::UnexpectedHeaderValue);
 }
 
 #[test]
-fn test_cose_sign_verify_rsa_tampered_signature() {
-    let payload = b"This is the RSA-signed content.";
-    let certs: [&[u8]; 2] = [&test::RSA_ROOT,
-                             &test::RSA_INT];
-    let params_vec = vec![RSA_PARAMS];
-    test_verify_modified_signature(payload, &certs, params_vec);
+fn test_cose_signature_protected_header_unexpected_kid_type() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = encode_test_protected_header(
+        vec![CborType::Integer(COSE_HEADER_ALG),
+             CborType::Integer(COSE_HEADER_KID)],
+        vec![CborType::SignedInteger(COSE_TYPE_ES256),
+             CborType::Integer(0)],
+    );
+    let signature = build_test_cose_signature(signature_protected_header);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::UnexpectedType);
 }
 
 #[test]
-fn test_cose_sign_verify_two_signatures() {
-    let payload = b"This is the content.";
-    let certs: [&[u8]; 4] = [&test::P256_ROOT,
-                             &test::P256_INT,
-                             &test::RSA_ROOT,
-                             &test::RSA_INT];
-    let params_vec = vec![P256_PARAMS,
-                          RSA_PARAMS];
-    test_verify(payload, &certs, params_vec);
+fn test_cose_signature_protected_header_extra_key() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = encode_test_protected_header(
+        vec![CborType::Integer(COSE_HEADER_ALG),
+             CborType::Integer(COSE_HEADER_KID),
+             CborType::Integer(5)],
+        vec![CborType::SignedInteger(COSE_TYPE_ES256),
+             CborType::Bytes(Vec::new()),
+             CborType::Integer(5)],
+    );
+    let signature = build_test_cose_signature(signature_protected_header);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::MalformedInput);
 }
 
 #[test]
-fn test_cose_sign_verify_two_signatures_tampered_payload() {
-    let mut payload = String::from_str("This is the content.")
-        .unwrap()
-        .into_bytes();
-    let certs: [&[u8]; 4] = [&test::P256_ROOT,
-                             &test::P256_INT,
-                             &test::RSA_ROOT,
-                             &test::RSA_INT];
-    let params_vec = vec![P256_PARAMS,
-                          RSA_PARAMS];
-    test_verify_modified_payload(&mut payload, &certs, params_vec);
+fn test_cose_signature_unprotected_header_wrong_type() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+    let signature = CborType::Array(vec![CborType::Bytes(signature_protected_header),
+         CborType::Integer(1),
+         CborType::Bytes(Vec::new())]);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::UnexpectedType);
 }
 
 #[test]
-fn test_cose_sign_verify_two_signatures_tampered_signature() {
-    let payload = b"This is the content.";
-    let certs: [&[u8]; 4] = [&test::P256_ROOT,
-                             &test::P256_INT,
-                             &test::RSA_ROOT,
-                             &test::RSA_INT];
-    let params_vec = vec![P256_PARAMS,
-                          RSA_PARAMS];
-    test_verify_modified_signature(payload, &certs, params_vec);
+fn test_cose_signature_unprotected_header_not_empty() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+    let mut unprotected_header_map: BTreeMap<CborType, CborType> = BTreeMap::new();
+    unprotected_header_map.insert(CborType::Integer(0), CborType::SignedInteger(-1));
+    let signature = CborType::Array(vec![CborType::Bytes(signature_protected_header),
+         CborType::Map(unprotected_header_map),
+         CborType::Bytes(Vec::new())]);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::MalformedInput);
 }
+
+#[test]
+fn test_cose_signature_signature_wrong_type() {
+    let body_protected_header = make_minimally_valid_cose_sign_protected_header();
+    let signature_protected_header = make_minimally_valid_cose_signature_protected_header();
+    let signature = CborType::Array(vec![CborType::Bytes(signature_protected_header),
+         CborType::Map(BTreeMap::new()),
+         CborType::SignedInteger(-1)]);
+    let values = vec![CborType::Bytes(body_protected_header),
+                      CborType::Map(BTreeMap::new()),
+                      CborType::Null,
+                      CborType::Array(vec![signature])];
+    let bytes = wrap_tag_and_encode_array(values);
+    test_cose_format_error(&bytes, CoseError::UnexpectedType);
+}
deleted file mode 100644
--- a/third_party/rust/cose/src/test_nss.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-use test_setup as test;
-use nss;
-use nss::NSSError;
-use SignatureAlgorithm;
-
-#[test]
-fn test_nss_sign_verify() {
-    test::setup();
-    let payload = b"sample";
-
-    // Sign.
-    let signature_result = nss::sign(&SignatureAlgorithm::ES256, &test::PKCS8_P256_EE, payload);
-    assert!(signature_result.is_ok());
-    let signature_result = signature_result.unwrap();
-
-    // Verify the signature.
-    assert!(
-        nss::verify_signature(
-            &SignatureAlgorithm::ES256,
-            &test::P256_EE,
-            payload,
-            &signature_result,
-        ).is_ok()
-    );
-}
-
-#[test]
-fn test_nss_sign_verify_different_payload() {
-    test::setup();
-    let payload = b"sample";
-
-    // Sign.
-    let signature_result = nss::sign(&SignatureAlgorithm::ES256, &test::PKCS8_P256_EE, payload);
-    assert!(signature_result.is_ok());
-    let signature_result = signature_result.unwrap();
-
-    // Verify the signature with a different payload.
-    let payload = b"sampli";
-    let verify_result = nss::verify_signature(
-        &SignatureAlgorithm::ES256,
-        &test::P256_EE,
-        payload,
-        &signature_result,
-    );
-    assert!(verify_result.is_err());
-    assert_eq!(verify_result, Err(NSSError::SignatureVerificationFailed));
-}
-
-#[test]
-fn test_nss_sign_verify_wrong_cert() {
-    test::setup();
-    let payload = b"sample";
-
-    // Sign.
-    let signature_result = nss::sign(&SignatureAlgorithm::ES256, &test::PKCS8_P256_EE, payload);
-    assert!(signature_result.is_ok());
-    let signature_result = signature_result.unwrap();
-
-    // Verify the signature with a wrong cert.
-    let verify_result = nss::verify_signature(
-        &SignatureAlgorithm::ES256,
-        &test::P384_EE,
-        payload,
-        &signature_result,
-    );
-    assert!(verify_result.is_err());
-    assert_eq!(verify_result, Err(NSSError::SignatureVerificationFailed));
-}
--- a/third_party/rust/cose/src/test_setup.rs
+++ b/third_party/rust/cose/src/test_setup.rs
@@ -1,187 +1,8 @@
-use std::os::raw;
-use std::ptr;
-use std::sync::{ONCE_INIT, Once};
-static START: Once = ONCE_INIT;
-
-type SECStatus = raw::c_int;
-const SEC_SUCCESS: SECStatus = 0;
-// TODO: ugh this will probably have a platform-specific name...
-#[link(name = "nss3")]
-extern "C" {
-    fn NSS_NoDB_Init(configdir: *const u8) -> SECStatus;
-}
-
-pub fn setup() {
-    START.call_once(|| {
-        let null_ptr: *const u8 = ptr::null();
-        unsafe {
-            assert_eq!(NSS_NoDB_Init(null_ptr), SEC_SUCCESS);
-        }
-    });
-}
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
-pub const PKCS8_P256_EE: [u8; 139] = [
-    0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a,
-    0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
-    0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01,
-    0x01, 0x04, 0x20, 0x21, 0x91, 0x40, 0x3d, 0x57, 0x10, 0xbf, 0x15,
-    0xa2, 0x65, 0x81, 0x8c, 0xd4, 0x2e, 0xd6, 0xfe, 0xdf, 0x09, 0xad,
-    0xd9, 0x2d, 0x78, 0xb1, 0x8e, 0x7a, 0x1e, 0x9f, 0xeb, 0x95, 0x52,
-    0x47, 0x02, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x4f, 0xbf, 0xbb,
-    0xbb, 0x61, 0xe0, 0xf8, 0xf9, 0xb1, 0xa6, 0x0a, 0x59, 0xac, 0x87,
-    0x04, 0xe2, 0xec, 0x05, 0x0b, 0x42, 0x3e, 0x3c, 0xf7, 0x2e, 0x92,
-    0x3f, 0x2c, 0x4f, 0x79, 0x4b, 0x45, 0x5c, 0x2a, 0x69, 0xd2, 0x33,
-    0x45, 0x6c, 0x36, 0xc4, 0x11, 0x9d, 0x07, 0x06, 0xe0, 0x0e, 0xed,
-    0xc8, 0xd1, 0x93, 0x90, 0xd7, 0x99, 0x1b, 0x7b, 0x2d, 0x07, 0xa3,
-    0x04, 0xea, 0xa0, 0x4a, 0xa6, 0xc0, 0x0a
-];
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
-pub const P256_EE: [u8; 300] = [
-    0x30, 0x82, 0x01, 0x28, 0x30, 0x81, 0xcf, 0xa0, 0x03, 0x02, 0x01, 0x02,
-    0x02, 0x14, 0x2f, 0xc3, 0x5f, 0x05, 0x80, 0xb4, 0x49, 0x45, 0x13, 0x92,
-    0xd6, 0x93, 0xb7, 0x2d, 0x71, 0x19, 0xc5, 0x8c, 0x40, 0x39, 0x30, 0x0a,
-    0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x13,
-    0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x69,
-    0x6e, 0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x22, 0x18, 0x0f, 0x32,
-    0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30,
-    0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32, 0x33, 0x31,
-    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x12, 0x31, 0x10, 0x30,
-    0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, 0x65, 0x65, 0x2d, 0x70,
-    0x32, 0x35, 0x36, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48,
-    0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03,
-    0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4f, 0xbf, 0xbb, 0xbb, 0x61, 0xe0,
-    0xf8, 0xf9, 0xb1, 0xa6, 0x0a, 0x59, 0xac, 0x87, 0x04, 0xe2, 0xec, 0x05,
-    0x0b, 0x42, 0x3e, 0x3c, 0xf7, 0x2e, 0x92, 0x3f, 0x2c, 0x4f, 0x79, 0x4b,
-    0x45, 0x5c, 0x2a, 0x69, 0xd2, 0x33, 0x45, 0x6c, 0x36, 0xc4, 0x11, 0x9d,
-    0x07, 0x06, 0xe0, 0x0e, 0xed, 0xc8, 0xd1, 0x93, 0x90, 0xd7, 0x99, 0x1b,
-    0x7b, 0x2d, 0x07, 0xa3, 0x04, 0xea, 0xa0, 0x4a, 0xa6, 0xc0, 0x30, 0x0a,
-    0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48,
-    0x00, 0x30, 0x45, 0x02, 0x20, 0x5c, 0x75, 0x51, 0x9f, 0x13, 0x11, 0x50,
-    0xcd, 0x5d, 0x8a, 0xde, 0x20, 0xa3, 0xbc, 0x06, 0x30, 0x91, 0xff, 0xb2,
-    0x73, 0x75, 0x5f, 0x31, 0x64, 0xec, 0xfd, 0xcb, 0x42, 0x80, 0x0a, 0x70,
-    0xe6, 0x02, 0x21, 0x00, 0xff, 0x81, 0xbe, 0xa8, 0x0d, 0x03, 0x36, 0x6b,
-    0x75, 0xe2, 0x70, 0x6a, 0xac, 0x07, 0x2e, 0x4c, 0xdc, 0xf9, 0xc5, 0x89,
-    0xc1, 0xcf, 0x88, 0xc2, 0xc8, 0x2a, 0x32, 0xf5, 0x42, 0x0c, 0xfa, 0x0b
-];
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
-pub const PKCS8_P384_EE: [u8; 185] = [
-    0x30, 0x81, 0xb6, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86,
-    0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22,
-    0x04, 0x81, 0x9e, 0x30, 0x81, 0x9b, 0x02, 0x01, 0x01, 0x04, 0x30, 0x03,
-    0x5c, 0x7a, 0x1b, 0x10, 0xd9, 0xfa, 0xfe, 0x83, 0x7b, 0x64, 0xad, 0x92,
-    0xf2, 0x2f, 0x5c, 0xed, 0x07, 0x89, 0x18, 0x65, 0x38, 0x66, 0x9b, 0x5c,
-    0x6d, 0x87, 0x2c, 0xec, 0x3d, 0x92, 0x61, 0x22, 0xb3, 0x93, 0x77, 0x2b,
-    0x57, 0x60, 0x2f, 0xf3, 0x13, 0x65, 0xef, 0xe1, 0x39, 0x32, 0x46, 0xa1,
-    0x64, 0x03, 0x62, 0x00, 0x04, 0xa1, 0x68, 0x72, 0x43, 0x36, 0x2b, 0x5c,
-    0x7b, 0x18, 0x89, 0xf3, 0x79, 0x15, 0x46, 0x15, 0xa1, 0xc7, 0x3f, 0xb4,
-    0x8d, 0xee, 0x86, 0x3e, 0x02, 0x29, 0x15, 0xdb, 0x60, 0x8e, 0x25, 0x2d,
-    0xe4, 0xb7, 0x13, 0x2d, 0xa8, 0xce, 0x98, 0xe8, 0x31, 0x53, 0x4e, 0x6a,
-    0x9c, 0x0c, 0x0b, 0x09, 0xc8, 0xd6, 0x39, 0xad, 0xe8, 0x32, 0x06, 0xe5,
-    0xba, 0x81, 0x34, 0x73, 0xa1, 0x1f, 0xa3, 0x30, 0xe0, 0x5d, 0xa8, 0xc9,
-    0x6e, 0x43, 0x83, 0xfe, 0x27, 0x87, 0x3d, 0xa9, 0x71, 0x03, 0xbe, 0x28,
-    0x88, 0xcf, 0xf0, 0x02, 0xf0, 0x5a, 0xf7, 0x1a, 0x1f, 0xdd, 0xcc, 0x83,
-    0x74, 0xaa, 0x6e, 0xa9, 0xce
-];
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
-pub const PKCS8_P521_EE: [u8; 240] = [
-    0x30, 0x81, 0xed, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86,
-    0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23,
-    0x04, 0x81, 0xd5, 0x30, 0x81, 0xd2, 0x02, 0x01, 0x01, 0x04, 0x42, 0x01,
-    0x4f, 0x32, 0x84, 0xfa, 0x69, 0x8d, 0xd9, 0xfe, 0x11, 0x18, 0xdd, 0x33,
-    0x18, 0x51, 0xcd, 0xfa, 0xac, 0x5a, 0x38, 0x29, 0x27, 0x8e, 0xb8, 0x99,
-    0x48, 0x39, 0xde, 0x94, 0x71, 0xc9, 0x40, 0xb8, 0x58, 0xc6, 0x9d, 0x2d,
-    0x05, 0xe8, 0xc0, 0x17, 0x88, 0xa7, 0xd0, 0xb6, 0xe2, 0x35, 0xaa, 0x5e,
-    0x78, 0x3f, 0xc1, 0xbe, 0xe8, 0x07, 0xdc, 0xc3, 0x86, 0x5f, 0x92, 0x0e,
-    0x12, 0xcf, 0x8f, 0x2d, 0x29, 0xa1, 0x81, 0x88, 0x03, 0x81, 0x85, 0x00,
-    0x04, 0x18, 0x94, 0x55, 0x0d, 0x07, 0x85, 0x93, 0x2e, 0x00, 0xea, 0xa2,
-    0x3b, 0x69, 0x4f, 0x21, 0x3f, 0x8c, 0x31, 0x21, 0xf8, 0x6d, 0xc9, 0x7a,
-    0x04, 0xe5, 0xa7, 0x16, 0x7d, 0xb4, 0xe5, 0xbc, 0xd3, 0x71, 0x12, 0x3d,
-    0x46, 0xe4, 0x5d, 0xb6, 0xb5, 0xd5, 0x37, 0x0a, 0x7f, 0x20, 0xfb, 0x63,
-    0x31, 0x55, 0xd3, 0x8f, 0xfa, 0x16, 0xd2, 0xbd, 0x76, 0x1d, 0xca, 0xc4,
-    0x74, 0xb9, 0xa2, 0xf5, 0x02, 0x3a, 0x40, 0x49, 0x31, 0x01, 0xc9, 0x62,
-    0xcd, 0x4d, 0x2f, 0xdd, 0xf7, 0x82, 0x28, 0x5e, 0x64, 0x58, 0x41, 0x39,
-    0xc2, 0xf9, 0x1b, 0x47, 0xf8, 0x7f, 0xf8, 0x23, 0x54, 0xd6, 0x63, 0x0f,
-    0x74, 0x6a, 0x28, 0xa0, 0xdb, 0x25, 0x74, 0x1b, 0x5b, 0x34, 0xa8, 0x28,
-    0x00, 0x8b, 0x22, 0xac, 0xc2, 0x3f, 0x92, 0x4f, 0xaa, 0xfb, 0xd4, 0xd3,
-    0x3f, 0x81, 0xea, 0x66, 0x95, 0x6d, 0xfe, 0xaa, 0x2b, 0xfd, 0xfc, 0xf5
-];
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
-pub const P521_EE: [u8; 367] = [
-    0x30, 0x82, 0x01, 0x6b, 0x30, 0x82, 0x01, 0x12, 0xa0, 0x03, 0x02, 0x01,
-    0x02, 0x02, 0x14, 0x49, 0xdb, 0x7d, 0xec, 0x87, 0x2b, 0x95, 0xfc, 0xfb,
-    0x57, 0xfb, 0xc8, 0xd5, 0x57, 0xb7, 0x3a, 0x10, 0xcc, 0xf1, 0x7a, 0x30,
-    0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30,
-    0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
-    0x69, 0x6e, 0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x22, 0x18, 0x0f,
-    0x32, 0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30,
-    0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32, 0x33,
-    0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x12, 0x31, 0x10,
-    0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, 0x65, 0x65, 0x2d,
-    0x70, 0x35, 0x32, 0x31, 0x30, 0x81, 0x9b, 0x30, 0x10, 0x06, 0x07, 0x2a,
-    0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00,
-    0x23, 0x03, 0x81, 0x86, 0x00, 0x04, 0x01, 0x4c, 0xdc, 0x9c, 0xac, 0xc4,
-    0x79, 0x41, 0x09, 0x6b, 0xc9, 0xcc, 0x66, 0x75, 0x2e, 0xc2, 0x7f, 0x59,
-    0x77, 0x34, 0xfa, 0x66, 0xc6, 0x2b, 0x79, 0x2f, 0x88, 0xc5, 0x19, 0xd6,
-    0xd3, 0x7f, 0x0d, 0x16, 0xea, 0x1c, 0x48, 0x3a, 0x18, 0x27, 0xa0, 0x10,
-    0xb9, 0x12, 0x8e, 0x3a, 0x08, 0x07, 0x0c, 0xa3, 0x3e, 0xf5, 0xf5, 0x78,
-    0x35, 0xb7, 0xc1, 0xba, 0x25, 0x1f, 0x6c, 0xc3, 0x52, 0x1d, 0xc4, 0x2b,
-    0x01, 0x06, 0x53, 0x45, 0x19, 0x81, 0xb4, 0x45, 0xd3, 0x43, 0xee, 0xd3,
-    0x78, 0x2a, 0x35, 0xd6, 0xcf, 0xf0, 0xff, 0x48, 0x4f, 0x5a, 0x88, 0x3d,
-    0x20, 0x9f, 0x1b, 0x90, 0x42, 0xb7, 0x26, 0x70, 0x35, 0x68, 0xb2, 0xf3,
-    0x26, 0xe1, 0x8b, 0x83, 0x3b, 0xdd, 0x8a, 0xa0, 0x73, 0x43, 0x92, 0xbc,
-    0xd1, 0x95, 0x01, 0xe1, 0x0d, 0x69, 0x8a, 0x79, 0xf5, 0x3e, 0x11, 0xe0,
-    0xa2, 0x2b, 0xdd, 0x2a, 0xad, 0x90, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86,
-    0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02,
-    0x20, 0x5c, 0x75, 0x51, 0x9f, 0x13, 0x11, 0x50, 0xcd, 0x5d, 0x8a, 0xde,
-    0x20, 0xa3, 0xbc, 0x06, 0x30, 0x91, 0xff, 0xb2, 0x73, 0x75, 0x5f, 0x31,
-    0x64, 0xec, 0xfd, 0xcb, 0x42, 0x80, 0x0a, 0x70, 0xe6, 0x02, 0x20, 0x35,
-    0x20, 0x7c, 0xff, 0x51, 0xf6, 0x68, 0xce, 0x1d, 0x00, 0xf9, 0xcc, 0x7f,
-    0xa7, 0xbc, 0x79, 0x52, 0xea, 0x56, 0xdf, 0xc1, 0x46, 0x7c, 0x0c, 0xa1,
-    0x2e, 0x32, 0xb1, 0x69, 0x4b, 0x20, 0xc4
-];
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
-pub const P384_EE: [u8; 329] = [
-    0x30, 0x82, 0x01, 0x45, 0x30, 0x81, 0xec, 0xa0, 0x03, 0x02, 0x01, 0x02,
-    0x02, 0x14, 0x79, 0xe3, 0x1c, 0x60, 0x97, 0xa4, 0x3c, 0x3b, 0x82, 0x11,
-    0x42, 0x37, 0xaf, 0x57, 0x05, 0xa8, 0xde, 0xd3, 0x40, 0x58, 0x30, 0x0a,
-    0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x13,
-    0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x69,
-    0x6e, 0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x22, 0x18, 0x0f, 0x32,
-    0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30,
-    0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32, 0x33, 0x31,
-    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x12, 0x31, 0x10, 0x30,
-    0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, 0x65, 0x65, 0x2d, 0x70,
-    0x33, 0x38, 0x34, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48,
-    0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03,
-    0x62, 0x00, 0x04, 0xa1, 0x68, 0x72, 0x43, 0x36, 0x2b, 0x5c, 0x7b, 0x18,
-    0x89, 0xf3, 0x79, 0x15, 0x46, 0x15, 0xa1, 0xc7, 0x3f, 0xb4, 0x8d, 0xee,
-    0x86, 0x3e, 0x02, 0x29, 0x15, 0xdb, 0x60, 0x8e, 0x25, 0x2d, 0xe4, 0xb7,
-    0x13, 0x2d, 0xa8, 0xce, 0x98, 0xe8, 0x31, 0x53, 0x4e, 0x6a, 0x9c, 0x0c,
-    0x0b, 0x09, 0xc8, 0xd6, 0x39, 0xad, 0xe8, 0x32, 0x06, 0xe5, 0xba, 0x81,
-    0x34, 0x73, 0xa1, 0x1f, 0xa3, 0x30, 0xe0, 0x5d, 0xa8, 0xc9, 0x6e, 0x43,
-    0x83, 0xfe, 0x27, 0x87, 0x3d, 0xa9, 0x71, 0x03, 0xbe, 0x28, 0x88, 0xcf,
-    0xf0, 0x02, 0xf0, 0x5a, 0xf7, 0x1a, 0x1f, 0xdd, 0xcc, 0x83, 0x74, 0xaa,
-    0x6e, 0xa9, 0xce, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
-    0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x20, 0x5c, 0x75,
-    0x51, 0x9f, 0x13, 0x11, 0x50, 0xcd, 0x5d, 0x8a, 0xde, 0x20, 0xa3, 0xbc,
-    0x06, 0x30, 0x91, 0xff, 0xb2, 0x73, 0x75, 0x5f, 0x31, 0x64, 0xec, 0xfd,
-    0xcb, 0x42, 0x80, 0x0a, 0x70, 0xe6, 0x02, 0x21, 0x00, 0xf3, 0x04, 0x26,
-    0xf2, 0xfd, 0xbc, 0x89, 0x3f, 0x29, 0x3b, 0x70, 0xbc, 0x72, 0xa6, 0xc2,
-    0x23, 0xcc, 0x43, 0x4d, 0x84, 0x71, 0xaf, 0x53, 0xe4, 0x4b, 0x3e, 0xc0,
-    0xbf, 0xe5, 0x68, 0x86, 0x49
-];
-
 #[cfg_attr(rustfmt, rustfmt_skip)]
 pub const P256_INT: [u8; 332] = [
     0x30, 0x82, 0x01, 0x48, 0x30, 0x81, 0xf0, 0xa0, 0x03, 0x02, 0x01,
     0x02, 0x02, 0x14, 0x43, 0x63, 0x59, 0xad, 0x04, 0x34, 0x56, 0x80,
     0x43, 0xec, 0x90, 0x6a, 0xd4, 0x10, 0x64, 0x7c, 0x7f, 0x38, 0x32,
     0xe2, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
     0x03, 0x02, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
     0x04, 0x03, 0x0c, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x32,
@@ -240,314 +61,16 @@ pub const P256_ROOT: [u8; 334] = [
     0x8a, 0xde, 0x20, 0xa3, 0xbc, 0x06, 0x30, 0x91, 0xff, 0xb2, 0x73, 0x75,
     0x5f, 0x31, 0x64, 0xec, 0xfd, 0xcb, 0x42, 0x80, 0x0a, 0x70, 0xe6, 0x02,
     0x21, 0x00, 0xc2, 0xe4, 0xc1, 0xa8, 0xe2, 0x89, 0xdc, 0xa1, 0xbb, 0xe7,
     0xd5, 0x4f, 0x5c, 0x88, 0xad, 0xeb, 0xa4, 0x78, 0xa1, 0x19, 0xbe, 0x22,
     0x54, 0xc8, 0x9f, 0xef, 0xb8, 0x5d, 0xa2, 0x40, 0xd9, 0x8b
 ];
 
 #[cfg_attr(rustfmt, rustfmt_skip)]
-pub const PKCS8_RSA_EE: [u8; 1218] = [
-    0x30, 0x82, 0x04, 0xbe, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
-    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
-    0x04, 0xa8, 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01,
-    0x01, 0x00, 0xba, 0x88, 0x51, 0xa8, 0x44, 0x8e, 0x16, 0xd6, 0x41, 0xfd,
-    0x6e, 0xb6, 0x88, 0x06, 0x36, 0x10, 0x3d, 0x3c, 0x13, 0xd9, 0xea, 0xe4,
-    0x35, 0x4a, 0xb4, 0xec, 0xf5, 0x68, 0x57, 0x6c, 0x24, 0x7b, 0xc1, 0xc7,
-    0x25, 0xa8, 0xe0, 0xd8, 0x1f, 0xbd, 0xb1, 0x9c, 0x06, 0x9b, 0x6e, 0x1a,
-    0x86, 0xf2, 0x6b, 0xe2, 0xaf, 0x5a, 0x75, 0x6b, 0x6a, 0x64, 0x71, 0x08,
-    0x7a, 0xa5, 0x5a, 0xa7, 0x45, 0x87, 0xf7, 0x1c, 0xd5, 0x24, 0x9c, 0x02,
-    0x7e, 0xcd, 0x43, 0xfc, 0x1e, 0x69, 0xd0, 0x38, 0x20, 0x29, 0x93, 0xab,
-    0x20, 0xc3, 0x49, 0xe4, 0xdb, 0xb9, 0x4c, 0xc2, 0x6b, 0x6c, 0x0e, 0xed,
-    0x15, 0x82, 0x0f, 0xf1, 0x7e, 0xad, 0x69, 0x1a, 0xb1, 0xd3, 0x02, 0x3a,
-    0x8b, 0x2a, 0x41, 0xee, 0xa7, 0x70, 0xe0, 0x0f, 0x0d, 0x8d, 0xfd, 0x66,
-    0x0b, 0x2b, 0xb0, 0x24, 0x92, 0xa4, 0x7d, 0xb9, 0x88, 0x61, 0x79, 0x90,
-    0xb1, 0x57, 0x90, 0x3d, 0xd2, 0x3b, 0xc5, 0xe0, 0xb8, 0x48, 0x1f, 0xa8,
-    0x37, 0xd3, 0x88, 0x43, 0xef, 0x27, 0x16, 0xd8, 0x55, 0xb7, 0x66, 0x5a,
-    0xaa, 0x7e, 0x02, 0x90, 0x2f, 0x3a, 0x7b, 0x10, 0x80, 0x06, 0x24, 0xcc,
-    0x1c, 0x6c, 0x97, 0xad, 0x96, 0x61, 0x5b, 0xb7, 0xe2, 0x96, 0x12, 0xc0,
-    0x75, 0x31, 0xa3, 0x0c, 0x91, 0xdd, 0xb4, 0xca, 0xf7, 0xfc, 0xad, 0x1d,
-    0x25, 0xd3, 0x09, 0xef, 0xb9, 0x17, 0x0e, 0xa7, 0x68, 0xe1, 0xb3, 0x7b,
-    0x2f, 0x22, 0x6f, 0x69, 0xe3, 0xb4, 0x8a, 0x95, 0x61, 0x1d, 0xee, 0x26,
-    0xd6, 0x25, 0x9d, 0xab, 0x91, 0x08, 0x4e, 0x36, 0xcb, 0x1c, 0x24, 0x04,
-    0x2c, 0xbf, 0x16, 0x8b, 0x2f, 0xe5, 0xf1, 0x8f, 0x99, 0x17, 0x31, 0xb8,
-    0xb3, 0xfe, 0x49, 0x23, 0xfa, 0x72, 0x51, 0xc4, 0x31, 0xd5, 0x03, 0xac,
-    0xda, 0x18, 0x0a, 0x35, 0xed, 0x8d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
-    0x82, 0x01, 0x01, 0x00, 0x9e, 0xcb, 0xce, 0x38, 0x61, 0xa4, 0x54, 0xec,
-    0xb1, 0xe0, 0xfe, 0x8f, 0x85, 0xdd, 0x43, 0xc9, 0x2f, 0x58, 0x25, 0xce,
-    0x2e, 0x99, 0x78, 0x84, 0xd0, 0xe1, 0xa9, 0x49, 0xda, 0xa2, 0xc5, 0xac,
-    0x55, 0x9b, 0x24, 0x04, 0x50, 0xe5, 0xac, 0x9f, 0xe0, 0xc3, 0xe3, 0x1c,
-    0x0e, 0xef, 0xa6, 0x52, 0x5a, 0x65, 0xf0, 0xc2, 0x21, 0x94, 0x00, 0x4e,
-    0xe1, 0xab, 0x46, 0x3d, 0xde, 0x9e, 0xe8, 0x22, 0x87, 0xcc, 0x93, 0xe7,
-    0x46, 0xa9, 0x19, 0x29, 0xc5, 0xe6, 0xac, 0x3d, 0x88, 0x75, 0x3f, 0x6c,
-    0x25, 0xba, 0x59, 0x79, 0xe7, 0x3e, 0x5d, 0x8f, 0xb2, 0x39, 0x11, 0x1a,
-    0x3c, 0xda, 0xb8, 0xa4, 0xb0, 0xcd, 0xf5, 0xf9, 0xca, 0xb0, 0x5f, 0x12,
-    0x33, 0xa3, 0x83, 0x35, 0xc6, 0x4b, 0x55, 0x60, 0x52, 0x5e, 0x7e, 0x3b,
-    0x92, 0xad, 0x7c, 0x75, 0x04, 0xcf, 0x1d, 0xc7, 0xcb, 0x00, 0x57, 0x88,
-    0xaf, 0xcb, 0xe1, 0xe8, 0xf9, 0x5d, 0xf7, 0x40, 0x2a, 0x15, 0x15, 0x30,
-    0xd5, 0x80, 0x83, 0x46, 0x86, 0x4e, 0xb3, 0x70, 0xaa, 0x79, 0x95, 0x6a,
-    0x58, 0x78, 0x62, 0xcb, 0x53, 0x37, 0x91, 0x30, 0x7f, 0x70, 0xd9, 0x1c,
-    0x96, 0xd2, 0x2d, 0x00, 0x1a, 0x69, 0x00, 0x9b, 0x92, 0x3c, 0x68, 0x33,
-    0x88, 0xc9, 0xf3, 0x6c, 0xb9, 0xb5, 0xeb, 0xe6, 0x43, 0x02, 0x04, 0x1c,
-    0x78, 0xd9, 0x08, 0x20, 0x6b, 0x87, 0x00, 0x9c, 0xb8, 0xca, 0xba, 0xca,
-    0xd3, 0xdb, 0xdb, 0x27, 0x92, 0xfb, 0x91, 0x1b, 0x2c, 0xf4, 0xdb, 0x66,
-    0x03, 0x58, 0x5b, 0xe9, 0xae, 0x0c, 0xa3, 0xb8, 0xe6, 0x41, 0x7a, 0xa0,
-    0x4b, 0x06, 0xe4, 0x70, 0xea, 0x1a, 0x3b, 0x58, 0x1c, 0xa0, 0x3a, 0x67,
-    0x81, 0xc9, 0x31, 0x5b, 0x62, 0xb3, 0x0e, 0x60, 0x11, 0xf2, 0x24, 0x72,
-    0x59, 0x46, 0xee, 0xc5, 0x7c, 0x6d, 0x94, 0x41, 0x02, 0x81, 0x81, 0x00,
-    0xdd, 0x6e, 0x1d, 0x4f, 0xff, 0xeb, 0xf6, 0x8d, 0x88, 0x9c, 0x4d, 0x11,
-    0x4c, 0xda, 0xaa, 0x9c, 0xaa, 0x63, 0xa5, 0x93, 0x74, 0x28, 0x6c, 0x8a,
-    0x5c, 0x29, 0xa7, 0x17, 0xbb, 0xa6, 0x03, 0x75, 0x64, 0x4d, 0x5c, 0xaa,
-    0x67, 0x4c, 0x4b, 0x8b, 0xc7, 0x32, 0x63, 0x58, 0x64, 0x62, 0x20, 0xe4,
-    0x55, 0x0d, 0x76, 0x08, 0xac, 0x27, 0xd5, 0x5b, 0x6d, 0xb7, 0x4f, 0x8d,
-    0x81, 0x27, 0xef, 0x8f, 0xa0, 0x90, 0x98, 0xb6, 0x91, 0x47, 0xde, 0x06,
-    0x55, 0x73, 0x44, 0x7e, 0x18, 0x3d, 0x22, 0xfe, 0x7d, 0x88, 0x5a, 0xce,
-    0xb5, 0x13, 0xd9, 0x58, 0x1d, 0xd5, 0xe0, 0x7c, 0x1a, 0x90, 0xf5, 0xce,
-    0x08, 0x79, 0xde, 0x13, 0x13, 0x71, 0xec, 0xef, 0xc9, 0xce, 0x72, 0xe9,
-    0xc4, 0x3d, 0xc1, 0x27, 0xd2, 0x38, 0x19, 0x0d, 0xe8, 0x11, 0x77, 0x3c,
-    0xa5, 0xd1, 0x93, 0x01, 0xf4, 0x8c, 0x74, 0x2b, 0x02, 0x81, 0x81, 0x00,
-    0xd7, 0xa7, 0x73, 0xd9, 0xeb, 0xc3, 0x80, 0xa7, 0x67, 0xd2, 0xfe, 0xc0,
-    0x93, 0x4a, 0xd4, 0xe8, 0xb5, 0x66, 0x72, 0x40, 0x77, 0x1a, 0xcd, 0xeb,
-    0xb5, 0xad, 0x79, 0x6f, 0x47, 0x8f, 0xec, 0x4d, 0x45, 0x98, 0x5e, 0xfb,
-    0xc9, 0x53, 0x29, 0x68, 0x28, 0x9c, 0x8d, 0x89, 0x10, 0x2f, 0xad, 0xf2,
-    0x1f, 0x34, 0xe2, 0xdd, 0x49, 0x40, 0xeb, 0xa8, 0xc0, 0x9d, 0x6d, 0x1f,
-    0x16, 0xdc, 0xc2, 0x97, 0x29, 0x77, 0x4c, 0x43, 0x27, 0x5e, 0x92, 0x51,
-    0xdd, 0xbe, 0x49, 0x09, 0xe1, 0xfd, 0x3b, 0xf1, 0xe4, 0xbe, 0xdf, 0x46,
-    0xa3, 0x9b, 0x8b, 0x38, 0x33, 0x28, 0xef, 0x4a, 0xe3, 0xb9, 0x5b, 0x92,
-    0xf2, 0x07, 0x0a, 0xf2, 0x6c, 0x9e, 0x7c, 0x5c, 0x9b, 0x58, 0x7f, 0xed,
-    0xde, 0x05, 0xe8, 0xe7, 0xd8, 0x6c, 0xa5, 0x78, 0x86, 0xfb, 0x16, 0x58,
-    0x10, 0xa7, 0x7b, 0x98, 0x45, 0xbc, 0x31, 0x27, 0x02, 0x81, 0x81, 0x00,
-    0x96, 0x47, 0x2b, 0x41, 0xa6, 0x10, 0xc0, 0xad, 0xe1, 0xaf, 0x22, 0x66,
-    0xc1, 0x60, 0x0e, 0x36, 0x71, 0x35, 0x5b, 0xa4, 0x2d, 0x4b, 0x5a, 0x0e,
-    0xb4, 0xe9, 0xd7, 0xeb, 0x35, 0x81, 0x40, 0x0b, 0xa5, 0xdd, 0x13, 0x2c,
-    0xdb, 0x1a, 0x5e, 0x93, 0x28, 0xc7, 0xbb, 0xc0, 0xbb, 0xb0, 0x15, 0x5e,
-    0xa1, 0x92, 0x97, 0x2e, 0xdf, 0x97, 0xd1, 0x27, 0x51, 0xd8, 0xfc, 0xf6,
-    0xae, 0x57, 0x2a, 0x30, 0xb1, 0xea, 0x30, 0x9a, 0x87, 0x12, 0xdd, 0x4e,
-    0x33, 0x24, 0x1d, 0xb1, 0xee, 0x45, 0x5f, 0xc0, 0x93, 0xf5, 0xbc, 0x9b,
-    0x59, 0x2d, 0x75, 0x6e, 0x66, 0x21, 0x47, 0x4f, 0x32, 0xc0, 0x7a, 0xf2,
-    0x2f, 0xb2, 0x75, 0xd3, 0x40, 0x79, 0x2b, 0x32, 0xba, 0x25, 0x90, 0xbb,
-    0xb2, 0x61, 0xae, 0xfb, 0x95, 0xa2, 0x58, 0xee, 0xa5, 0x37, 0x65, 0x53,
-    0x15, 0xbe, 0x9c, 0x24, 0xd1, 0x91, 0x99, 0x2d, 0x02, 0x81, 0x80, 0x28,
-    0xb4, 0x50, 0xa7, 0xa7, 0x5a, 0x85, 0x64, 0x13, 0xb2, 0xbd, 0xa6, 0xf7,
-    0xa6, 0x3e, 0x3d, 0x96, 0x4f, 0xb9, 0xec, 0xf5, 0x0e, 0x38, 0x23, 0xef,
-    0x6c, 0xc8, 0xe8, 0xfa, 0x26, 0xee, 0x41, 0x3f, 0x8b, 0x9d, 0x12, 0x05,
-    0x54, 0x0f, 0x12, 0xbb, 0xe7, 0xa0, 0xc7, 0x68, 0x28, 0xb7, 0xba, 0x65,
-    0xad, 0x83, 0xcc, 0xa4, 0xd0, 0xfe, 0x2a, 0x22, 0x01, 0x14, 0xe1, 0xb3,
-    0x5d, 0x03, 0xd5, 0xa8, 0x5b, 0xfe, 0x27, 0x06, 0xbd, 0x50, 0xfc, 0xe6,
-    0xcf, 0xcd, 0xd5, 0x71, 0xb4, 0x6c, 0xa6, 0x21, 0xb8, 0xed, 0x47, 0xd6,
-    0x05, 0xbb, 0xe7, 0x65, 0xb0, 0xaa, 0x4a, 0x06, 0x65, 0xac, 0x25, 0x36,
-    0x4d, 0xa2, 0x01, 0x54, 0x03, 0x2e, 0x12, 0x04, 0xb8, 0x55, 0x9d, 0x3e,
-    0x34, 0xfb, 0x5b, 0x17, 0x7c, 0x9a, 0x56, 0xff, 0x93, 0x51, 0x0a, 0x5a,
-    0x4a, 0x62, 0x87, 0xc1, 0x51, 0xde, 0x2d, 0x02, 0x81, 0x80, 0x28, 0x06,
-    0x7b, 0x93, 0x55, 0x80, 0x1d, 0x2e, 0xf5, 0x2d, 0xfa, 0x96, 0xd8, 0xad,
-    0xb5, 0x89, 0x67, 0x3c, 0xf8, 0xee, 0x8a, 0x9c, 0x6f, 0xf7, 0x2a, 0xee,
-    0xab, 0xe9, 0xef, 0x6b, 0xe5, 0x8a, 0x4f, 0x4a, 0xbf, 0x05, 0xf7, 0x88,
-    0x94, 0x7d, 0xc8, 0x51, 0xfd, 0xaa, 0x34, 0x54, 0x21, 0x47, 0xa7, 0x1a,
-    0x24, 0x6b, 0xfb, 0x05, 0x4e, 0xe7, 0x6a, 0xa3, 0x46, 0xab, 0xcd, 0x26,
-    0x92, 0xcf, 0xc9, 0xe4, 0x4c, 0x51, 0xe6, 0xf0, 0x69, 0xc7, 0x35, 0xe0,
-    0x73, 0xba, 0x01, 0x9f, 0x6a, 0x72, 0x14, 0x96, 0x1c, 0x91, 0xb2, 0x68,
-    0x71, 0xca, 0xea, 0xbf, 0x8f, 0x06, 0x44, 0x18, 0xa0, 0x26, 0x90, 0xe3,
-    0x9a, 0x8d, 0x5f, 0xf3, 0x06, 0x7b, 0x7c, 0xdb, 0x7f, 0x50, 0xb1, 0xf5,
-    0x34, 0x18, 0xa7, 0x03, 0x96, 0x6c, 0x4f, 0xc7, 0x74, 0xbf, 0x74, 0x02,
-    0xaf, 0x6c, 0x43, 0x24, 0x7f, 0x43
-];
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
-pub const RSA_EE: [u8; 691] = [
-    0x30, 0x82, 0x02, 0xaf, 0x30, 0x82, 0x01, 0x99, 0xa0, 0x03, 0x02, 0x01,
-    0x02, 0x02, 0x14, 0x07, 0x1c, 0x3b, 0x71, 0x08, 0xbe, 0xd7, 0x9f, 0xfd,
-    0xaf, 0x26, 0xb6, 0x08, 0xa3, 0x99, 0x06, 0x77, 0x69, 0x32, 0x7e, 0x30,
-    0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
-    0x30, 0x12, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
-    0x07, 0x69, 0x6e, 0x74, 0x2d, 0x72, 0x73, 0x61, 0x30, 0x22, 0x18, 0x0f,
-    0x32, 0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30, 0x30,
-    0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32, 0x33,
-    0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x11, 0x31, 0x0f,
-    0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x65, 0x65, 0x2d,
-    0x72, 0x73, 0x61, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
-    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
-    0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00,
-    0xba, 0x88, 0x51, 0xa8, 0x44, 0x8e, 0x16, 0xd6, 0x41, 0xfd, 0x6e, 0xb6,
-    0x88, 0x06, 0x36, 0x10, 0x3d, 0x3c, 0x13, 0xd9, 0xea, 0xe4, 0x35, 0x4a,
-    0xb4, 0xec, 0xf5, 0x68, 0x57, 0x6c, 0x24, 0x7b, 0xc1, 0xc7, 0x25, 0xa8,
-    0xe0, 0xd8, 0x1f, 0xbd, 0xb1, 0x9c, 0x06, 0x9b, 0x6e, 0x1a, 0x86, 0xf2,
-    0x6b, 0xe2, 0xaf, 0x5a, 0x75, 0x6b, 0x6a, 0x64, 0x71, 0x08, 0x7a, 0xa5,
-    0x5a, 0xa7, 0x45, 0x87, 0xf7, 0x1c, 0xd5, 0x24, 0x9c, 0x02, 0x7e, 0xcd,
-    0x43, 0xfc, 0x1e, 0x69, 0xd0, 0x38, 0x20, 0x29, 0x93, 0xab, 0x20, 0xc3,
-    0x49, 0xe4, 0xdb, 0xb9, 0x4c, 0xc2, 0x6b, 0x6c, 0x0e, 0xed, 0x15, 0x82,
-    0x0f, 0xf1, 0x7e, 0xad, 0x69, 0x1a, 0xb1, 0xd3, 0x02, 0x3a, 0x8b, 0x2a,
-    0x41, 0xee, 0xa7, 0x70, 0xe0, 0x0f, 0x0d, 0x8d, 0xfd, 0x66, 0x0b, 0x2b,
-    0xb0, 0x24, 0x92, 0xa4, 0x7d, 0xb9, 0x88, 0x61, 0x79, 0x90, 0xb1, 0x57,
-    0x90, 0x3d, 0xd2, 0x3b, 0xc5, 0xe0, 0xb8, 0x48, 0x1f, 0xa8, 0x37, 0xd3,
-    0x88, 0x43, 0xef, 0x27, 0x16, 0xd8, 0x55, 0xb7, 0x66, 0x5a, 0xaa, 0x7e,
-    0x02, 0x90, 0x2f, 0x3a, 0x7b, 0x10, 0x80, 0x06, 0x24, 0xcc, 0x1c, 0x6c,
-    0x97, 0xad, 0x96, 0x61, 0x5b, 0xb7, 0xe2, 0x96, 0x12, 0xc0, 0x75, 0x31,
-    0xa3, 0x0c, 0x91, 0xdd, 0xb4, 0xca, 0xf7, 0xfc, 0xad, 0x1d, 0x25, 0xd3,
-    0x09, 0xef, 0xb9, 0x17, 0x0e, 0xa7, 0x68, 0xe1, 0xb3, 0x7b, 0x2f, 0x22,
-    0x6f, 0x69, 0xe3, 0xb4, 0x8a, 0x95, 0x61, 0x1d, 0xee, 0x26, 0xd6, 0x25,
-    0x9d, 0xab, 0x91, 0x08, 0x4e, 0x36, 0xcb, 0x1c, 0x24, 0x04, 0x2c, 0xbf,
-    0x16, 0x8b, 0x2f, 0xe5, 0xf1, 0x8f, 0x99, 0x17, 0x31, 0xb8, 0xb3, 0xfe,
-    0x49, 0x23, 0xfa, 0x72, 0x51, 0xc4, 0x31, 0xd5, 0x03, 0xac, 0xda, 0x18,
-    0x0a, 0x35, 0xed, 0x8d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0b, 0x06,
-    0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x03, 0x82,
-    0x01, 0x01, 0x00, 0x44, 0x92, 0xbb, 0x8e, 0x83, 0x58, 0x56, 0x2e, 0x7a,
-    0x86, 0xfa, 0x1d, 0x77, 0x50, 0x3f, 0x45, 0x8d, 0x90, 0xc4, 0x62, 0x27,
-    0x21, 0x96, 0x5a, 0xef, 0x51, 0x78, 0xd7, 0x7d, 0x0d, 0x02, 0x2d, 0x5a,
-    0x0e, 0x3c, 0x82, 0x6f, 0x1d, 0x92, 0x87, 0xd5, 0x1a, 0x44, 0xae, 0xa7,
-    0x92, 0xd1, 0x8b, 0xfa, 0x16, 0x53, 0x7f, 0xa3, 0x22, 0x96, 0x1a, 0x51,
-    0x8c, 0xeb, 0xa1, 0xe6, 0xf6, 0x37, 0x11, 0xfe, 0x7d, 0x53, 0x3f, 0xae,
-    0xf0, 0x6b, 0xb9, 0xb1, 0x7a, 0x73, 0x07, 0x14, 0xcf, 0x04, 0x05, 0x93,
-    0x9e, 0xe3, 0xd2, 0x4d, 0x9d, 0x6d, 0x35, 0x68, 0xf9, 0x36, 0xe5, 0x10,
-    0x0a, 0x36, 0xd9, 0x48, 0xb0, 0x83, 0xd0, 0xb9, 0x58, 0x74, 0x53, 0xb3,
-    0xbc, 0x99, 0xab, 0xe1, 0x3e, 0xd5, 0x01, 0x8e, 0xcf, 0x3a, 0x69, 0x93,
-    0x9e, 0xa7, 0x88, 0xd4, 0xad, 0x95, 0xf9, 0x2a, 0xb4, 0x7f, 0x95, 0x97,
-    0x86, 0x50, 0x38, 0xb1, 0x04, 0x0a, 0xe4, 0x7a, 0xd5, 0x2d, 0x6c, 0xde,
-    0x3e, 0x1a, 0x47, 0x17, 0x88, 0x63, 0x20, 0x9d, 0x21, 0x3e, 0x0c, 0x6f,
-    0xfd, 0x20, 0x54, 0xd0, 0x67, 0xd2, 0x6b, 0x06, 0xfe, 0x60, 0x13, 0x42,
-    0x3d, 0xb7, 0xca, 0xcb, 0xab, 0x7b, 0x5f, 0x5d, 0x01, 0x56, 0xd3, 0x99,
-    0x80, 0x0f, 0xde, 0x7f, 0x3a, 0x61, 0x9c, 0xd3, 0x6b, 0x5e, 0xfe, 0xb5,
-    0xfc, 0x39, 0x8b, 0x8e, 0xf0, 0x8c, 0x8b, 0x65, 0x46, 0x45, 0xff, 0x47,
-    0x8f, 0xd4, 0xdd, 0xae, 0xc9, 0x72, 0xc7, 0x7f, 0x28, 0x86, 0xf1, 0xf7,
-    0x6e, 0xcb, 0x86, 0x03, 0xeb, 0x0c, 0x46, 0xe5, 0xa0, 0x6b, 0xef, 0xd4,
-    0x5e, 0xa4, 0x0f, 0x53, 0xe1, 0xbc, 0xb4, 0xc9, 0x37, 0x0e, 0x75, 0xdd,
-    0x93, 0xe8, 0x0f, 0x18, 0x0a, 0x02, 0x83, 0x17, 0x74, 0xbb, 0x1a, 0x42,
-    0x5b, 0x63, 0x2c, 0x80, 0x80, 0xa6, 0x84
-];
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
-pub const RSA_INT: [u8; 724] = [
-    0x30, 0x82, 0x02, 0xd0, 0x30, 0x82, 0x01, 0xba, 0xa0, 0x03, 0x02, 0x01,
-    0x02, 0x02, 0x14, 0x07, 0x10, 0xaf, 0xc4, 0x1a, 0x3a, 0x56, 0x4f, 0xd8,
-    0xc2, 0xcc, 0x46, 0xd7, 0x5b, 0xdf, 0x1c, 0x4e, 0x2f, 0x49, 0x3a, 0x30,
-    0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
-    0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
-    0x08, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x72, 0x73, 0x61, 0x30, 0x22, 0x18,
-    0x0f, 0x32, 0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30,
-    0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32,
-    0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x12, 0x31,
-    0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, 0x69, 0x6e,
-    0x74, 0x2d, 0x72, 0x73, 0x61, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06,
-    0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
-    0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01,
-    0x01, 0x00, 0xba, 0x88, 0x51, 0xa8, 0x44, 0x8e, 0x16, 0xd6, 0x41, 0xfd,
-    0x6e, 0xb6, 0x88, 0x06, 0x36, 0x10, 0x3d, 0x3c, 0x13, 0xd9, 0xea, 0xe4,
-    0x35, 0x4a, 0xb4, 0xec, 0xf5, 0x68, 0x57, 0x6c, 0x24, 0x7b, 0xc1, 0xc7,
-    0x25, 0xa8, 0xe0, 0xd8, 0x1f, 0xbd, 0xb1, 0x9c, 0x06, 0x9b, 0x6e, 0x1a,
-    0x86, 0xf2, 0x6b, 0xe2, 0xaf, 0x5a, 0x75, 0x6b, 0x6a, 0x64, 0x71, 0x08,
-    0x7a, 0xa5, 0x5a, 0xa7, 0x45, 0x87, 0xf7, 0x1c, 0xd5, 0x24, 0x9c, 0x02,
-    0x7e, 0xcd, 0x43, 0xfc, 0x1e, 0x69, 0xd0, 0x38, 0x20, 0x29, 0x93, 0xab,
-    0x20, 0xc3, 0x49, 0xe4, 0xdb, 0xb9, 0x4c, 0xc2, 0x6b, 0x6c, 0x0e, 0xed,
-    0x15, 0x82, 0x0f, 0xf1, 0x7e, 0xad, 0x69, 0x1a, 0xb1, 0xd3, 0x02, 0x3a,
-    0x8b, 0x2a, 0x41, 0xee, 0xa7, 0x70, 0xe0, 0x0f, 0x0d, 0x8d, 0xfd, 0x66,
-    0x0b, 0x2b, 0xb0, 0x24, 0x92, 0xa4, 0x7d, 0xb9, 0x88, 0x61, 0x79, 0x90,
-    0xb1, 0x57, 0x90, 0x3d, 0xd2, 0x3b, 0xc5, 0xe0, 0xb8, 0x48, 0x1f, 0xa8,
-    0x37, 0xd3, 0x88, 0x43, 0xef, 0x27, 0x16, 0xd8, 0x55, 0xb7, 0x66, 0x5a,
-    0xaa, 0x7e, 0x02, 0x90, 0x2f, 0x3a, 0x7b, 0x10, 0x80, 0x06, 0x24, 0xcc,
-    0x1c, 0x6c, 0x97, 0xad, 0x96, 0x61, 0x5b, 0xb7, 0xe2, 0x96, 0x12, 0xc0,
-    0x75, 0x31, 0xa3, 0x0c, 0x91, 0xdd, 0xb4, 0xca, 0xf7, 0xfc, 0xad, 0x1d,
-    0x25, 0xd3, 0x09, 0xef, 0xb9, 0x17, 0x0e, 0xa7, 0x68, 0xe1, 0xb3, 0x7b,
-    0x2f, 0x22, 0x6f, 0x69, 0xe3, 0xb4, 0x8a, 0x95, 0x61, 0x1d, 0xee, 0x26,
-    0xd6, 0x25, 0x9d, 0xab, 0x91, 0x08, 0x4e, 0x36, 0xcb, 0x1c, 0x24, 0x04,
-    0x2c, 0xbf, 0x16, 0x8b, 0x2f, 0xe5, 0xf1, 0x8f, 0x99, 0x17, 0x31, 0xb8,
-    0xb3, 0xfe, 0x49, 0x23, 0xfa, 0x72, 0x51, 0xc4, 0x31, 0xd5, 0x03, 0xac,
-    0xda, 0x18, 0x0a, 0x35, 0xed, 0x8d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
-    0x1d, 0x30, 0x1b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
-    0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f,
-    0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86,
-    0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00,
-    0x5e, 0xba, 0x69, 0x55, 0x9f, 0xf8, 0xeb, 0x16, 0x21, 0x98, 0xde, 0xb7,
-    0x31, 0x3e, 0x66, 0xe1, 0x3b, 0x0c, 0x29, 0xf7, 0x48, 0x73, 0x05, 0xd9,
-    0xce, 0x5e, 0x4c, 0xbe, 0x03, 0xc4, 0x51, 0xd6, 0x21, 0x92, 0x40, 0x38,
-    0xaa, 0x5b, 0x28, 0xb5, 0xa1, 0x10, 0x52, 0x57, 0xff, 0x91, 0x54, 0x82,
-    0x86, 0x9e, 0x74, 0xd5, 0x3d, 0x82, 0x29, 0xee, 0xd1, 0xcf, 0x93, 0xb1,
-    0x24, 0x76, 0xbb, 0x95, 0x41, 0x06, 0x7e, 0x40, 0x9b, 0xb4, 0xab, 0x44,
-    0x34, 0x10, 0x8f, 0xb1, 0x51, 0x6f, 0xc0, 0x89, 0xd1, 0xa3, 0xc4, 0x9f,
-    0xb3, 0x48, 0xe1, 0xcd, 0x73, 0xad, 0xff, 0x42, 0x5f, 0x76, 0x05, 0x60,
-    0xc5, 0xe0, 0x45, 0x79, 0x18, 0xa1, 0x19, 0xb8, 0xa7, 0x3a, 0x64, 0xb3,
-    0x19, 0xba, 0x14, 0xa1, 0xb5, 0xdc, 0x32, 0xec, 0x09, 0x39, 0x58, 0x54,
-    0x5b, 0x04, 0xdc, 0x1b, 0x66, 0x0d, 0x1d, 0x0d, 0xce, 0x7f, 0xfa, 0x24,
-    0x52, 0x6a, 0xad, 0xe2, 0xc8, 0x30, 0xaf, 0xf2, 0xaf, 0x63, 0xc5, 0xe2,
-    0xbf, 0xe2, 0x20, 0x1b, 0x9e, 0xf9, 0x3d, 0xbc, 0xfb, 0x04, 0x8e, 0xda,
-    0x7a, 0x1a, 0x5d, 0xd3, 0x13, 0xd7, 0x00, 0x8e, 0x9b, 0x5d, 0x85, 0x51,
-    0xda, 0xd3, 0x91, 0x25, 0xf5, 0x67, 0x85, 0x3e, 0x25, 0x89, 0x5e, 0xcb,
-    0x89, 0x8a, 0xec, 0x8a, 0xde, 0x8b, 0xf4, 0x33, 0x5f, 0x76, 0xdb, 0x3d,
-    0xfc, 0x6a, 0x05, 0x21, 0x43, 0xb2, 0x41, 0xd8, 0x33, 0x8d, 0xfd, 0x05,
-    0x5c, 0x22, 0x0a, 0xf6, 0x90, 0x65, 0x9c, 0x4f, 0x8c, 0x44, 0x9f, 0x2d,
-    0xca, 0xf3, 0x49, 0x9c, 0x3a, 0x14, 0x88, 0xab, 0xe4, 0xce, 0xb7, 0xbc,
-    0x95, 0x22, 0x2e, 0xb1, 0x82, 0x4c, 0xbf, 0x83, 0x3e, 0x49, 0x72, 0x03,
-    0x2a, 0x68, 0xe7, 0x2d, 0xe5, 0x2d, 0x4b, 0x61, 0xb0, 0x8d, 0x0d, 0x0c,
-    0x87, 0xc6, 0x5c, 0x51
-];
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
-pub const RSA_ROOT: [u8; 725] = [
-    0x30, 0x82, 0x02, 0xd1, 0x30, 0x82, 0x01, 0xbb, 0xa0, 0x03, 0x02, 0x01,
-    0x02, 0x02, 0x14, 0x29, 0x6c, 0x1a, 0xd8, 0x20, 0xcd, 0x74, 0x6d, 0x4b,
-    0x00, 0xf3, 0x16, 0x88, 0xd9, 0x66, 0x87, 0x5f, 0x28, 0x56, 0x6a, 0x30,
-    0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
-    0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
-    0x08, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x72, 0x73, 0x61, 0x30, 0x22, 0x18,
-    0x0f, 0x32, 0x30, 0x31, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x30, 0x30,
-    0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x31, 0x31, 0x32,
-    0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x13, 0x31,
-    0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x72, 0x6f,
-    0x6f, 0x74, 0x2d, 0x72, 0x73, 0x61, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
-    0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
-    0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
-    0x01, 0x01, 0x00, 0xba, 0x88, 0x51, 0xa8, 0x44, 0x8e, 0x16, 0xd6, 0x41,
-    0xfd, 0x6e, 0xb6, 0x88, 0x06, 0x36, 0x10, 0x3d, 0x3c, 0x13, 0xd9, 0xea,
-    0xe4, 0x35, 0x4a, 0xb4, 0xec, 0xf5, 0x68, 0x57, 0x6c, 0x24, 0x7b, 0xc1,
-    0xc7, 0x25, 0xa8, 0xe0, 0xd8, 0x1f, 0xbd, 0xb1, 0x9c, 0x06, 0x9b, 0x6e,
-    0x1a, 0x86, 0xf2, 0x6b, 0xe2, 0xaf, 0x5a, 0x75, 0x6b, 0x6a, 0x64, 0x71,
-    0x08, 0x7a, 0xa5, 0x5a, 0xa7, 0x45, 0x87, 0xf7, 0x1c, 0xd5, 0x24, 0x9c,
-    0x02, 0x7e, 0xcd, 0x43, 0xfc, 0x1e, 0x69, 0xd0, 0x38, 0x20, 0x29, 0x93,
-    0xab, 0x20, 0xc3, 0x49, 0xe4, 0xdb, 0xb9, 0x4c, 0xc2, 0x6b, 0x6c, 0x0e,
-    0xed, 0x15, 0x82, 0x0f, 0xf1, 0x7e, 0xad, 0x69, 0x1a, 0xb1, 0xd3, 0x02,
-    0x3a, 0x8b, 0x2a, 0x41, 0xee, 0xa7, 0x70, 0xe0, 0x0f, 0x0d, 0x8d, 0xfd,
-    0x66, 0x0b, 0x2b, 0xb0, 0x24, 0x92, 0xa4, 0x7d, 0xb9, 0x88, 0x61, 0x79,
-    0x90, 0xb1, 0x57, 0x90, 0x3d, 0xd2, 0x3b, 0xc5, 0xe0, 0xb8, 0x48, 0x1f,
-    0xa8, 0x37, 0xd3, 0x88, 0x43, 0xef, 0x27, 0x16, 0xd8, 0x55, 0xb7, 0x66,
-    0x5a, 0xaa, 0x7e, 0x02, 0x90, 0x2f, 0x3a, 0x7b, 0x10, 0x80, 0x06, 0x24,
-    0xcc, 0x1c, 0x6c, 0x97, 0xad, 0x96, 0x61, 0x5b, 0xb7, 0xe2, 0x96, 0x12,
-    0xc0, 0x75, 0x31, 0xa3, 0x0c, 0x91, 0xdd, 0xb4, 0xca, 0xf7, 0xfc, 0xad,
-    0x1d, 0x25, 0xd3, 0x09, 0xef, 0xb9, 0x17, 0x0e, 0xa7, 0x68, 0xe1, 0xb3,
-    0x7b, 0x2f, 0x22, 0x6f, 0x69, 0xe3, 0xb4, 0x8a, 0x95, 0x61, 0x1d, 0xee,
-    0x26, 0xd6, 0x25, 0x9d, 0xab, 0x91, 0x08, 0x4e, 0x36, 0xcb, 0x1c, 0x24,
-    0x04, 0x2c, 0xbf, 0x16, 0x8b, 0x2f, 0xe5, 0xf1, 0x8f, 0x99, 0x17, 0x31,
-    0xb8, 0xb3, 0xfe, 0x49, 0x23, 0xfa, 0x72, 0x51, 0xc4, 0x31, 0xd5, 0x03,
-    0xac, 0xda, 0x18, 0x0a, 0x35, 0xed, 0x8d, 0x02, 0x03, 0x01, 0x00, 0x01,
-    0xa3, 0x1d, 0x30, 0x1b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04,
-    0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d,
-    0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0b, 0x06, 0x09, 0x2a,
-    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01,
-    0x00, 0x23, 0x2f, 0x9f, 0x72, 0xeb, 0x70, 0x6d, 0x9e, 0x3e, 0x9f, 0xd7,
-    0x9c, 0xd9, 0x19, 0x7c, 0x99, 0x07, 0xc5, 0x5c, 0x9d, 0xf5, 0x66, 0x9f,
-    0x28, 0x8d, 0xfe, 0x0e, 0x3f, 0x38, 0x75, 0xed, 0xee, 0x4e, 0x3f, 0xf6,
-    0x6e, 0x35, 0xe0, 0x95, 0x3f, 0x08, 0x4a, 0x71, 0x5a, 0xf2, 0x4f, 0xc9,
-    0x96, 0x61, 0x8d, 0x45, 0x4b, 0x97, 0x85, 0xff, 0xb0, 0xe3, 0xbb, 0xb5,
-    0xd7, 0x7e, 0xfb, 0xd2, 0xfc, 0xec, 0xfe, 0x42, 0x9f, 0x4e, 0x7b, 0xbf,
-    0x97, 0xbb, 0xb4, 0x3a, 0x93, 0x0b, 0x13, 0x61, 0x90, 0x0c, 0x3a, 0xce,
-    0xf7, 0x8e, 0xef, 0x80, 0xf5, 0x4a, 0x92, 0xc5, 0xa5, 0x03, 0x78, 0xc2,
-    0xee, 0xb8, 0x66, 0x60, 0x6b, 0x76, 0x4f, 0x32, 0x5a, 0x1a, 0xa2, 0x4b,
-    0x7e, 0x2b, 0xa6, 0x1a, 0x89, 0x01, 0xe3, 0xbb, 0x55, 0x13, 0x7c, 0x4c,
-    0xf4, 0x6a, 0x99, 0x94, 0xd1, 0xa0, 0x84, 0x1c, 0x1a, 0xc2, 0x7b, 0xb4,
-    0xa0, 0xb0, 0x3b, 0xdc, 0x5a, 0x7b, 0xc7, 0xe0, 0x44, 0xb2, 0x1f, 0x46,
-    0xd5, 0x8b, 0x39, 0x8b, 0xdc, 0x9e, 0xce, 0xa8, 0x7f, 0x85, 0x1d, 0x4b,
-    0x63, 0x06, 0x1e, 0x8e, 0xe5, 0xe5, 0x99, 0xd9, 0xf7, 0x4d, 0x89, 0x0b,
-    0x1d, 0x5c, 0x27, 0x33, 0x66, 0x21, 0xcf, 0x9a, 0xbd, 0x98, 0x68, 0x23,
-    0x3a, 0x66, 0x9d, 0xd4, 0x46, 0xed, 0x63, 0x58, 0xf3, 0x42, 0xe4, 0x1d,
-    0xe2, 0x47, 0x65, 0x13, 0x8d, 0xd4, 0x1f, 0x4b, 0x7e, 0xde, 0x11, 0x56,
-    0xf8, 0x6d, 0x01, 0x0c, 0x99, 0xbd, 0x8d, 0xca, 0x8a, 0x2e, 0xe3, 0x8a,
-    0x9c, 0x3d, 0x83, 0x8d, 0x69, 0x62, 0x8d, 0x05, 0xea, 0xb7, 0xf5, 0xa3,
-    0x4b, 0xfc, 0x96, 0xcf, 0x18, 0x21, 0x0a, 0xc7, 0xf3, 0x23, 0x7e, 0x1c,
-    0xab, 0xe2, 0xa2, 0xd1, 0x83, 0xc4, 0x25, 0x93, 0x37, 0x80, 0xca, 0xda,
-    0xf0, 0xef, 0x7d, 0x94, 0xb5
-];
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
 pub const COSE_SIGNATURE_BYTES: [u8; 1062] = [
     0xd8, 0x62, 0x84, 0x59, 0x02, 0xa3, 0xa1, 0x04, 0x82, 0x59, 0x01, 0x4e,
     0x30, 0x82, 0x01, 0x4a, 0x30, 0x81, 0xf1, 0xa0, 0x03, 0x02, 0x01, 0x02,
     0x02, 0x14, 0x5f, 0x3f, 0xae, 0x90, 0x49, 0x30, 0x2f, 0x33, 0x6e, 0x95,
     0x23, 0xa7, 0xcb, 0x23, 0xd7, 0x65, 0x4f, 0xea, 0x3c, 0xf7, 0x30, 0x0a,
     0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x14,
     0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x72,
     0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x32, 0x35, 0x36, 0x30, 0x22, 0x18, 0x0f,
--- a/third_party/rust/cose/src/util.rs
+++ b/third_party/rust/cose/src/util.rs
@@ -1,27 +1,27 @@
 use cbor::CborType;
 
-// Sig_structure is a CBOR array:
-//
-// Sig_structure = [
-//   context : "Signature" / "Signature1" / "CounterSignature",
-//   body_protected : empty_or_serialized_map,
-//   ? sign_protected : empty_or_serialized_map,
-//   external_aad : bstr,
-//   payload : bstr
-// ]
-//
-// In this case, the context is "Signature". There is no external_aad, so this defaults to a
-// zero-length bstr.
+/// Sig_structure is a CBOR array:
+///
+/// Sig_structure = [
+///   context : "Signature" / "Signature1" / "CounterSignature",
+///   body_protected : empty_or_serialized_map,
+///   ? sign_protected : empty_or_serialized_map,
+///   external_aad : bstr,
+///   payload : bstr
+/// ]
+///
+/// In this case, the context is "Signature". There is no external_aad, so this defaults to a
+/// zero-length bstr.
 pub fn get_sig_struct_bytes(
     protected_body_header_serialized: CborType,
     protected_signature_header_serialized: CborType,
     payload: &[u8],
 ) -> Vec<u8> {
     let sig_structure_array: Vec<CborType> = vec![CborType::String(String::from("Signature")),
                                                   protected_body_header_serialized,
                                                   protected_signature_header_serialized,
-                                                  CborType::Bytes(Vec::new()),
+                                                  CborType::Null,
                                                   CborType::Bytes(payload.to_vec())];
 
     CborType::Array(sig_structure_array).serialize()
 }
deleted file mode 100644
--- a/third_party/rust/cose/src/util_test.rs
+++ /dev/null
@@ -1,194 +0,0 @@
-/// We don't need COSE signing at the moment. But we need to generate test files.
-/// This module implements basic COSE signing.
-use nss;
-use {CoseError, Signature, SignatureAlgorithm, SignatureParameters};
-use std::collections::BTreeMap;
-use cbor::CborType;
-use util::get_sig_struct_bytes;
-use decoder::decode_signature;
-use decoder::{COSE_TYPE_ES256, COSE_TYPE_ES384, COSE_TYPE_ES512, COSE_TYPE_PS256};
-
-/// Converts a `SignatureAlgorithm` to its corresponding `CborType`.
-/// See RFC 8152 section 8.1 and RFC 8230 section 5.1.
-pub fn signature_type_to_cbor_value(signature_type: &SignatureAlgorithm) -> CborType {
-    CborType::SignedInteger(match signature_type {
-        &SignatureAlgorithm::ES256 => COSE_TYPE_ES256,
-        &SignatureAlgorithm::ES384 => COSE_TYPE_ES384,
-        &SignatureAlgorithm::ES512 => COSE_TYPE_ES512,
-        &SignatureAlgorithm::PS256 => COSE_TYPE_PS256,
-    })
-}
-
-pub fn build_protected_sig_header(ee_cert: &[u8], alg: &SignatureAlgorithm) -> CborType {
-    // Protected signature header
-    let mut header_map: BTreeMap<CborType, CborType> = BTreeMap::new();
-
-    // Signature type.
-    let signature_type_value = signature_type_to_cbor_value(alg);
-    header_map.insert(CborType::Integer(1), signature_type_value);
-
-    // Signer certificate.
-    header_map.insert(CborType::Integer(4), CborType::Bytes(ee_cert.to_vec()));
-
-    let header_map = CborType::Map(header_map).serialize();
-    CborType::Bytes(header_map)
-}
-
-pub fn build_protected_header(cert_chain: &[&[u8]]) -> CborType {
-    let mut cert_array: Vec<CborType> = Vec::new();
-    for cert in cert_chain {
-        cert_array.push(CborType::Bytes(cert.to_vec()));
-    }
-    let mut protected_body_header: BTreeMap<CborType, CborType> = BTreeMap::new();
-    protected_body_header.insert(CborType::Integer(4), CborType::Array(cert_array));
-    let protected_body_header = CborType::Map(protected_body_header).serialize();
-
-    CborType::Bytes(protected_body_header)
-}
-
-pub fn build_sig_struct(ee_cert: &[u8], alg: &SignatureAlgorithm, sig_bytes: &Vec<u8>) -> CborType {
-    // Build the signature item.
-    let mut signature_item: Vec<CborType> = Vec::new();
-
-    // Protected signature header
-    signature_item.push(build_protected_sig_header(ee_cert, alg));
-
-    // The unprotected signature header is empty.
-    let empty_map: BTreeMap<CborType, CborType> = BTreeMap::new();
-    signature_item.push(CborType::Map(empty_map));
-
-    // And finally the signature bytes.
-    signature_item.push(CborType::Bytes(sig_bytes.clone()));
-    CborType::Array(signature_item)
-}
-
-// 98(
-//  [
-//    / protected / h'..', / {
-//          \ kid \ 4:'..' \ Array of DER encoded intermediate certificates  \
-//      } / ,
-//    / unprotected / {},
-//    / payload / nil, / The payload is the contents of the manifest file /
-//    / signatures / [
-//      [
-//        / protected / h'a2012604..' / {
-//            \ alg \ 1:-7, \ ECDSA with SHA-256 \
-//            \ kid \ 4:'..' \ DER encoded signing certificate \
-//          } / ,
-//        / unprotected / {},
-//        / signature / h'e2ae..'
-//      ],
-//      [
-//        / protected / h'a201382404..' / {
-//            \ alg \ 1:-37, \ RSASSA-PSS with SHA-256 \
-//            \ kid \ 4:'..' \ DER encoded signing certificate \
-//          } / ,
-//        / unprotected / {},
-//        / signature / h'00a2..'
-//      ]
-//    ]
-//  ]
-pub fn build_cose_signature(cert_chain: &[&[u8]], signature_vec: &Vec<Signature>) -> Vec<u8> {
-    // Building the COSE signature content.
-    let mut cose_signature: Vec<CborType> = Vec::new();
-
-    // add cert chain as protected header
-    cose_signature.push(build_protected_header(cert_chain));
-
-    // Empty map (unprotected header)
-    let empty_map: BTreeMap<CborType, CborType> = BTreeMap::new();
-    cose_signature.push(CborType::Map(empty_map));
-
-    // No payload (nil).
-    cose_signature.push(CborType::Null);
-
-    // Create signature items.
-    let mut signatures: Vec<CborType> = Vec::new();
-    for signature in signature_vec {
-        let signature_item = build_sig_struct(
-            signature.parameter.certificate,
-            &signature.parameter.algorithm,
-            &signature.signature_bytes,
-        );
-        signatures.push(signature_item);
-    }
-
-    // Pack the signature item and add everything to the cose signature object.
-    cose_signature.push(CborType::Array(signatures));
-
-    // A COSE signature is a tagged array (98).
-    let signature_struct = CborType::Tag(98, Box::new(CborType::Array(cose_signature).clone()));
-
-    return signature_struct.serialize();
-}
-
-pub fn sign(
-    payload: &[u8],
-    cert_chain: &[&[u8]],
-    parameters: &Vec<SignatureParameters>,
-) -> Result<Vec<u8>, CoseError> {
-    assert!(parameters.len() > 0);
-    if parameters.len() < 1 {
-        return Err(CoseError::InvalidArgument);
-    }
-
-    let mut signatures: Vec<Signature> = Vec::new();
-    for param in parameters {
-        // Build the signature structure containing the protected headers and the
-        // payload to generate the payload that is actually signed.
-        let protected_sig_header_serialized =
-            build_protected_sig_header(param.certificate, &param.algorithm);
-        let protected_header_serialized = build_protected_header(cert_chain);
-        let payload = get_sig_struct_bytes(
-            protected_header_serialized,
-            protected_sig_header_serialized,
-            payload,
-        );
-
-        let signature_bytes = match nss::sign(&param.algorithm, &param.pkcs8, &payload) {
-            Err(_) => return Err(CoseError::SigningFailed),
-            Ok(signature) => signature,
-        };
-        let signature = Signature {
-            parameter: param,
-            signature_bytes: signature_bytes,
-        };
-        signatures.push(signature);
-    }
-
-    assert!(signatures.len() > 0);
-    if signatures.len() < 1 {
-        return Err(CoseError::MalformedInput);
-    }
-
-    let cose_signature = build_cose_signature(cert_chain, &signatures);
-    Ok(cose_signature)
-}
-
-/// Verify a COSE signature.
-pub fn verify_signature(payload: &[u8], cose_signature: Vec<u8>) -> Result<(), CoseError> {
-    // Parse COSE signature.
-    let cose_signatures = decode_signature(&cose_signature, payload)?;
-    if cose_signatures.len() < 1 {
-        return Err(CoseError::MalformedInput);
-    }
-
-    for signature in cose_signatures {
-        let signature_algorithm = &signature.signature_type;
-        let signature_bytes = &signature.signature;
-        let real_payload = &signature.to_verify;
-
-        // Verify the parsed signatures.
-        // We ignore the certs field here because we don't verify the certificate.
-        let verify_result = nss::verify_signature(
-            &signature_algorithm,
-            &signature.signer_cert,
-            real_payload,
-            signature_bytes,
-        );
-        if !verify_result.is_ok() {
-            return Err(CoseError::VerificationFailed);
-        }
-    }
-    Ok(())
-}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/moz_cbor/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".travis.yml":"43ea459b6292b21edfd4589bf83c1c774f56e336df27b1c48066f2333a207c21","Cargo.toml":"a1d8d6927afdd25f903e6d6198fd5577165f15b5cb4a85754626124f9a34d013","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"900075da16923e46236926014f2ce8a0a404dfcedceee43d9ad50e6202ab1184","rustfmt.toml":"e97717e906fcd3eeb86dcee52ed26f13e1884597b016a27172229d9c78dd3d57","src/decoder.rs":"421ade90bb4646fc2229bc0b62aea415e01576abdb64dee7d31d1836b86d6f6b","src/lib.rs":"f5b767eedbee01b3f697afb2dce777c6043e6fea6f9a7eab8387560caaa40100","src/serializer.rs":"edf3d39ef2d70cfc01968d88097897501b110d3db5f7d4e137ec1cd5f6f794d2","src/test_decoder.rs":"29a0b81e8a3e5cf85c97bc04deb421cb2071849aa7b667e9f3537e165b7bef77","src/test_serializer.rs":"3ca4b66feb7dded36ab8755fd0868bed962d689de7a401fc6ae814f12ba40e31"},"package":"9f0dc96d1e40041ad9e6f9986e72e65d45d70dc31cef9d852b47646b2970f238"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/moz_cbor/.travis.yml
@@ -0,0 +1,24 @@
+sudo: true
+language: rust
+cache: cargo
+rust:
+  - stable
+  - beta
+  - nightly
+
+addons:
+  apt:
+    packages:
+      - build-essential
+
+install:
+# Apparently cargo install returns a nonzero exit status if
+# caching succeeds, so just make this always "succeed".
+  - (cargo install rustfmt || true)
+
+script:
+- |
+  cargo fmt -- --write-mode=diff
+- |
+  cargo build &&
+  cargo test
new file mode 100644
--- /dev/null
+++ b/third_party/rust/moz_cbor/Cargo.toml
@@ -0,0 +1,23 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g. crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "moz_cbor"
+version = "0.1.0"
+authors = ["Franziskus Kiefer <franziskuskiefer@gmail.com>"]
+description = "Library to use CBOR (https://tools.ietf.org/html/rfc7049) in Rust"
+keywords = ["jose", "cbor"]
+license = "MPL-2.0"
+repository = "https://github.com/franziskuskiefer/cbor-rust"
+
+[features]
+default = []
new file mode 100644
--- /dev/null
+++ b/third_party/rust/moz_cbor/LICENSE
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  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/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/moz_cbor/README.md
@@ -0,0 +1,8 @@
+# cbor-rust
+
+A Rust library for [CBOR](https://tools.ietf.org/html/rfc7049).
+
+[![Build Status](https://travis-ci.org/franziskuskiefer/cbor-rust.svg?branch=master)](https://travis-ci.org/franziskuskiefer/cbor-rust/)
+![Maturity Level](https://img.shields.io/badge/maturity-alpha-red.svg)
+
+**THIS IS WORK IN PROGRESS. DO NOT USE YET.**
new file mode 100644
--- /dev/null
+++ b/third_party/rust/moz_cbor/rustfmt.toml
@@ -0,0 +1,4 @@
+array_layout = "Visual"
+array_width = 0
+reorder_imported_names = true
+array_horizontal_layout_threshold = 0
new file mode 100644
--- /dev/null
+++ b/third_party/rust/moz_cbor/src/decoder.rs
@@ -0,0 +1,150 @@
+use std::collections::BTreeMap;
+use std::io::{Cursor, Read, Seek, SeekFrom};
+use {CborError, CborType};
+
+// We limit the length of any cbor byte array to 128MiB. This is a somewhat
+// arbitrary limit that should work on all platforms and is large enough for
+// any benign data.
+pub const MAX_ARRAY_SIZE: usize = 134_217_728;
+
+/// Struct holding a cursor and additional information for decoding.
+#[derive(Debug)]
+struct DecoderCursor<'a> {
+    cursor: Cursor<&'a [u8]>,
+}
+
+/// Apply this mask (with &) to get the value part of the initial byte of a CBOR item.
+const INITIAL_VALUE_MASK: u64 = 0b0001_1111;
+
+impl<'a> DecoderCursor<'a> {
+    /// Read and return the given number of bytes from the cursor. Advances the cursor.
+    fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>, CborError> {
+        if len > MAX_ARRAY_SIZE {
+            return Err(CborError::InputTooLarge);
+        }
+        let mut buf: Vec<u8> = vec![0; len];
+        if self.cursor.read_exact(&mut buf).is_err() {
+            Err(CborError::TruncatedInput)
+        } else {
+            Ok(buf)
+        }
+    }
+
+    /// Convert num bytes to a u64
+    fn read_uint_from_bytes(&mut self, num: usize) -> Result<u64, CborError> {
+        let x = self.read_bytes(num)?;
+        let mut result: u64 = 0;
+        for i in (0..num).rev() {
+            result += u64::from(x[num - 1 - i]) << (i * 8);
+        }
+        Ok(result)
+    }
+
+    /// Read an integer and return it as u64.
+    fn read_int(&mut self) -> Result<u64, CborError> {
+        let first_value = self.read_uint_from_bytes(1)? & INITIAL_VALUE_MASK;
+        match first_value {
+            0...23 => Ok(first_value),
+            24 => self.read_uint_from_bytes(1),
+            25 => self.read_uint_from_bytes(2),
+            26 => self.read_uint_from_bytes(4),
+            27 => self.read_uint_from_bytes(8),
+            _ => Err(CborError::MalformedInput),
+        }
+    }
+
+    fn read_negative_int(&mut self) -> Result<CborType, CborError> {
+        let uint = self.read_int()?;
+        if uint > i64::max_value() as u64 {
+            return Err(CborError::InputValueOutOfRange);
+        }
+        let result: i64 = -1 - uint as i64;
+        Ok(CborType::SignedInteger(result))
+    }
+
+    /// Read an array of data items and return it.
+    fn read_array(&mut self) -> Result<CborType, CborError> {
+        // Create a new array.
+        let mut array: Vec<CborType> = Vec::new();
+        // Read the length of the array.
+        let num_items = self.read_int()?;
+        // Decode each of the num_items data items.
+        for _ in 0..num_items {
+            let new_item = self.decode_item()?;
+            array.push(new_item);
+        }
+        Ok(CborType::Array(array))
+    }
+
+    /// Read a byte string and return it.
+    fn read_byte_string(&mut self) -> Result<CborType, CborError> {
+        let length = self.read_int()?;
+        if length > MAX_ARRAY_SIZE as u64 {
+            return Err(CborError::InputTooLarge);
+        }
+        let byte_string = self.read_bytes(length as usize)?;
+        Ok(CborType::Bytes(byte_string))
+    }
+
+    /// Read a map.
+    fn read_map(&mut self) -> Result<CborType, CborError> {
+        let num_items = self.read_int()?;
+        // Create a new array.
+        let mut map: BTreeMap<CborType, CborType> = BTreeMap::new();
+        // Decode each of the num_items (key, data item) pairs.
+        for _ in 0..num_items {
+            let key_val = self.decode_item()?;
+            let item_value = self.decode_item()?;
+            if map.insert(key_val, item_value).is_some() {
+                return Err(CborError::DuplicateMapKey);
+            }
+        }
+        Ok(CborType::Map(map))
+    }
+
+    fn read_null(&mut self) -> Result<CborType, CborError> {
+        let value = self.read_uint_from_bytes(1)? & INITIAL_VALUE_MASK;
+        if value != 22 {
+            return Err(CborError::UnsupportedType);
+        }
+        Ok(CborType::Null)
+    }
+
+    /// Peeks at the next byte in the cursor, but does not change the position.
+    fn peek_byte(&mut self) -> Result<u8, CborError> {
+        let x = self.read_bytes(1)?;
+        if self.cursor.seek(SeekFrom::Current(-1)).is_err() {
+            return Err(CborError::LibraryError);
+        };
+        Ok(x[0])
+    }
+
+    /// Decodes the next CBOR item.
+    pub fn decode_item(&mut self) -> Result<CborType, CborError> {
+        let major_type = self.peek_byte()? >> 5;
+        match major_type {
+            0 => {
+                let value = self.read_int()?;
+                Ok(CborType::Integer(value))
+            }
+            1 => self.read_negative_int(),
+            2 => self.read_byte_string(),
+            4 => self.read_array(),
+            5 => self.read_map(),
+            6 => {
+                let tag = self.read_int()?;
+                let item = self.decode_item()?;
+                Ok(CborType::Tag(tag, Box::new(item)))
+            }
+            7 => self.read_null(),
+            _ => Err(CborError::UnsupportedType),
+        }
+    }
+}
+
+/// Read the CBOR structure in bytes and return it as a `CborType`.
+pub fn decode(bytes: &[u8]) -> Result<CborType, CborError> {
+    let mut decoder_cursor = DecoderCursor { cursor: Cursor::new(bytes) };
+    decoder_cursor.decode_item()
+    // TODO: check cursor at end?
+}
rename from third_party/rust/cose/src/cbor/mod.rs
rename to third_party/rust/moz_cbor/src/lib.rs
new file mode 100644
--- /dev/null
+++ b/third_party/rust/moz_cbor/src/serializer.rs
@@ -0,0 +1,121 @@
+use std::collections::BTreeMap;
+use CborType;
+
+/// Given a vector of bytes to append to, a tag to use, and an unsigned value to encode, uses the
+/// CBOR unsigned integer encoding to represent the given value.
+fn common_encode_unsigned(output: &mut Vec<u8>, tag: u8, value: u64) {
+    assert!(tag < 8);
+    let shifted_tag = tag << 5;
+    match value {
+        0...23 => {
+            output.push(shifted_tag | (value as u8));
+        }
+        24...255 => {
+            output.push(shifted_tag | 24);
+            output.push(value as u8);
+        }
+        256...65_535 => {
+            output.push(shifted_tag | 25);
+            output.push((value >> 8) as u8);
+            output.push((value & 255) as u8);
+        }
+        65_536...4_294_967_295 => {
+            output.push(shifted_tag | 26);
+            output.push((value >> 24) as u8);
+            output.push(((value >> 16) & 255) as u8);
+            output.push(((value >> 8) & 255) as u8);
+            output.push((value & 255) as u8);
+        }
+        _ => {
+            output.push(shifted_tag | 27);
+            output.push((value >> 56) as u8);
+            output.push(((value >> 48) & 255) as u8);
+            output.push(((value >> 40) & 255) as u8);
+            output.push(((value >> 32) & 255) as u8);
+            output.push(((value >> 24) & 255) as u8);
+            output.push(((value >> 16) & 255) as u8);
+            output.push(((value >> 8) & 255) as u8);
+            output.push((value & 255) as u8);
+        }
+    };
+}
+
+/// The major type is 0. For values 0 through 23, the 5 bits of additional information is just the
+/// value of the unsigned number. For values representable in one byte, the additional information
+/// has the value 24. If two bytes are necessary, the value is 25. If four bytes are necessary, the
+/// value is 26. If 8 bytes are necessary, the value is 27. The following bytes are the value of the
+/// unsigned number in as many bytes were indicated in network byte order (big endian).
+fn encode_unsigned(output: &mut Vec<u8>, unsigned: u64) {
+    common_encode_unsigned(output, 0, unsigned);
+}
+
+/// The major type is 1. The encoding is the same as for positive (i.e. unsigned) integers, except
+/// the value encoded is -1 minus the value of the negative number.
+fn encode_negative(output: &mut Vec<u8>, negative: i64) {
+    assert!(negative < 0);
+    let value_to_encode: u64 = (-1 - negative) as u64;
+    common_encode_unsigned(output, 1, value_to_encode);
+}
+
+/// The major type is 2. The length of the data is encoded as with positive integers, followed by
+/// the actual data.
+fn encode_bytes(output: &mut Vec<u8>, bstr: &[u8]) {
+    common_encode_unsigned(output, 2, bstr.len() as u64);
+    output.extend_from_slice(bstr);
+}
+
+/// The major type is 3. The length is as with bstr. The UTF-8-encoded bytes of the string follow.
+fn encode_string(output: &mut Vec<u8>, tstr: &str) {
+    let utf8_bytes = tstr.as_bytes();
+    common_encode_unsigned(output, 3, utf8_bytes.len() as u64);
+    output.extend_from_slice(utf8_bytes);
+}
+
+/// The major type is 4. The number of items is encoded as with positive integers. Then follows the
+/// encodings of the items themselves.
+fn encode_array(output: &mut Vec<u8>, array: &[CborType]) {
+    common_encode_unsigned(output, 4, array.len() as u64);
+    for element in array {
+        output.append(&mut element.serialize());
+    }
+}
+
+/// The major type is 5. The number of pairs is encoded as with positive integers. Then follows the
+/// encodings of each key, value pair. In Canonical CBOR, the keys must be sorted lowest value to
+/// highest.
+fn encode_map(output: &mut Vec<u8>, map: &BTreeMap<CborType, CborType>) {
+    common_encode_unsigned(output, 5, map.len() as u64);
+    for (key, value) in map {
+        output.append(&mut key.serialize());
+        output.append(&mut value.serialize());
+    }
+}
+
+fn encode_tag(output: &mut Vec<u8>, tag: &u64, val: &CborType) {
+    common_encode_unsigned(output, 6, *tag);
+    output.append(&mut val.serialize());
+}
+
+/// The major type is 7. The only supported value for this type is 22, which is Null.
+/// This makes the encoded value 246, or 0xf6.
+fn encode_null(output: &mut Vec<u8>) {
+    output.push(0xf6);
+}
+
+impl CborType {
+    /// Serialize a Cbor object.
+    pub fn serialize(&self) -> Vec<u8> {
+        let mut bytes: Vec<u8> = Vec::new();
+        match *self {
+            CborType::Integer(ref unsigned) => encode_unsigned(&mut bytes, *unsigned),
+            CborType::SignedInteger(ref negative) => encode_negative(&mut bytes, *negative),
+            CborType::Bytes(ref bstr) => encode_bytes(&mut bytes, bstr),
+            CborType::String(ref tstr) => encode_string(&mut bytes, tstr),
+            CborType::Array(ref arr) => encode_array(&mut bytes, arr),
+            CborType::Map(ref map) => encode_map(&mut bytes, map),
+            CborType::Tag(ref t, ref val) => encode_tag(&mut bytes, t, val),
+            CborType::Null => encode_null(&mut bytes),
+        };
+        bytes
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/moz_cbor/src/test_decoder.rs
@@ -0,0 +1,405 @@
+use {CborError, CborType};
+use decoder::{MAX_ARRAY_SIZE, decode};
+use std::collections::BTreeMap;
+
+// First test all the basic types
+fn test_decoder(bytes: Vec<u8>, expected: CborType) {
+    let result = decode(&bytes);
+    assert!(result.is_ok());
+    assert_eq!(result.unwrap(), expected);
+}
+
+fn test_decoder_error(bytes: Vec<u8>, expected_error: CborError) {
+    let result = decode(&bytes);
+    assert!(result.is_err());
+    assert_eq!(result.unwrap_err(), expected_error);
+}
+
+fn test_integer(bytes: Vec<u8>, expected: u64) {
+    let decoded = decode(&bytes).unwrap();
+    match decoded {
+        CborType::Integer(val) => assert_eq!(val, expected),
+        _ => assert_eq!(1, 0),
+    }
+}
+
+fn test_integer_all(bytes: Vec<u8>, expected_value: u64) {
+    let expected = CborType::Integer(expected_value);
+    test_decoder(bytes.clone(), expected);
+    test_integer(bytes, expected_value);
+}
+
+#[test]
+fn test_integer_objects() {
+    let bytes: Vec<u8> = vec![0x00];
+    test_integer_all(bytes, 0);
+
+    let bytes = vec![0x01];
+    test_integer_all(bytes, 1);
+
+    let bytes = vec![0x0A];
+    test_integer_all(bytes, 10);
+
+    let bytes = vec![0x17];
+    test_integer_all(bytes, 23);
+
+    let bytes = vec![0x18, 0x18];
+    test_integer_all(bytes, 24);
+
+    let bytes = vec![0x18, 0x19];
+    test_integer_all(bytes, 25);
+
+    let bytes = vec![0x18, 0x64];
+    test_integer_all(bytes, 100);
+
+    let bytes = vec![0x19, 0x03, 0xe8];
+    test_integer_all(bytes, 1000);
+
+    let bytes = vec![0x1a, 0x00, 0x0f, 0x42, 0x40];
+    test_integer_all(bytes, 1000000);
+
+    let bytes = vec![0x1b, 0x00, 0x00, 0x00, 0xe8, 0xd4, 0xa5, 0x10, 0x00];
+    test_integer_all(bytes, 1000000000000);
+
+    let bytes = vec![0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
+    test_integer_all(bytes, 18446744073709551615);
+}
+
+#[cfg(test)]
+fn test_tag(bytes: Vec<u8>, expected_tag: u64, expected_value: CborType) {
+    let decoded = decode(&bytes).unwrap();
+    match decoded {
+        CborType::Tag(tag, value) => {
+            assert_eq!(expected_tag, tag);
+            assert_eq!(expected_value, *value);
+        }
+        _ => assert_eq!(1, 0),
+    }
+}
+
+#[test]
+fn test_tagged_objects() {
+    let bytes: Vec<u8> = vec![0xD2, 0x02];
+    let expected_tag_value = 0x12;
+    let expected_value = CborType::Integer(2);
+    let expected = CborType::Tag(expected_tag_value, Box::new(expected_value.clone()));
+    test_decoder(bytes.clone(), expected);
+    test_tag(bytes, expected_tag_value, expected_value);
+}
+
+#[test]
+#[cfg_attr(rustfmt, rustfmt_skip)]
+fn test_arrays() {
+    // []
+    let bytes: Vec<u8> = vec![0x80];
+    let expected = CborType::Array(vec![]);
+    test_decoder(bytes, expected);
+
+    // [1, 2, 3]
+    let bytes: Vec<u8> = vec![0x83, 0x01, 0x02, 0x03];
+    let tmp = vec![
+        CborType::Integer(1),
+        CborType::Integer(2),
+        CborType::Integer(3),
+    ];
+    let expected = CborType::Array(tmp);
+    test_decoder(bytes, expected);
+
+    // [1, [2, 3], [4, 5]]
+    let bytes: Vec<u8> = vec![0x83, 0x01, 0x82, 0x02, 0x03, 0x82, 0x04, 0x05];
+    let tmp1 = vec![CborType::Integer(2), CborType::Integer(3)];
+    let tmp2 = vec![CborType::Integer(4), CborType::Integer(5)];
+    let tmp = vec![
+        CborType::Integer(1),
+        CborType::Array(tmp1),
+        CborType::Array(tmp2),
+    ];
+    let expected = CborType::Array(tmp);
+    test_decoder(bytes, expected);
+
+    // [1, [[[[1]]]], [1]]
+    let bytes: Vec<u8> = vec![0x83, 0x01, 0x81, 0x81, 0x81, 0x81, 0x01, 0x81, 0x02];
+    let tmp = vec![
+        CborType::Integer(1),
+        CborType::Array(vec![
+            CborType::Array(vec![
+                CborType::Array(vec![
+                    CborType::Array(vec![
+                        CborType::Integer(1)])])])]),
+        CborType::Array(vec![CborType::Integer(2)]),
+    ];
+    let expected = CborType::Array(tmp);
+    test_decoder(bytes, expected);
+
+    let bytes: Vec<u8> = vec![0x98, 0x1A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+                              0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+                              0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+                              0x17, 0x18, 0x18, 0x18, 0x19, 0x82, 0x81, 0x81,
+                              0x81, 0x05, 0x81, 0x1A, 0x49, 0x96, 0x02, 0xD2];
+    // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+    //  21, 22, 23, 24, 25, [[[[5]]], [1234567890]]]
+    let tmp = vec![
+        CborType::Integer(1),
+        CborType::Integer(2),
+        CborType::Integer(3),
+        CborType::Integer(4),
+        CborType::Integer(5),
+        CborType::Integer(6),
+        CborType::Integer(7),
+        CborType::Integer(8),
+        CborType::Integer(9),
+        CborType::Integer(10),
+        CborType::Integer(11),
+        CborType::Integer(12),
+        CborType::Integer(13),
+        CborType::Integer(14),
+        CborType::Integer(15),
+        CborType::Integer(16),
+        CborType::Integer(17),
+        CborType::Integer(18),
+        CborType::Integer(19),
+        CborType::Integer(20),
+        CborType::Integer(21),
+        CborType::Integer(22),
+        CborType::Integer(23),
+        CborType::Integer(24),
+        CborType::Integer(25),
+        CborType::Array(vec![
+            CborType::Array(vec![
+                CborType::Array(vec![
+                    CborType::Array(vec![
+                        CborType::Integer(5)])])]),
+            CborType::Array(vec![CborType::Integer(1234567890)])])
+    ];
+    let expected = CborType::Array(tmp);
+    test_decoder(bytes, expected);
+}
+
+#[test]
+fn test_signed_integer() {
+    let bytes: Vec<u8> = vec![0x20];
+    let expected = CborType::SignedInteger(-1);
+    test_decoder(bytes, expected);
+
+    let bytes = vec![0x29];
+    let expected = CborType::SignedInteger(-10);
+    test_decoder(bytes, expected);
+
+    let bytes = vec![0x38, 0x63];
+    let expected = CborType::SignedInteger(-100);
+    test_decoder(bytes, expected);
+
+    let bytes = vec![0x39, 0x03, 0xe7];
+    let expected = CborType::SignedInteger(-1000);
+    test_decoder(bytes, expected);
+
+    let bytes = vec![0x39, 0x27, 0x0F];
+    let expected = CborType::SignedInteger(-10000);
+    test_decoder(bytes, expected);
+
+    let bytes = vec![0x3A, 0x00, 0x01, 0x86, 0x9F];
+    let expected = CborType::SignedInteger(-100000);
+    test_decoder(bytes, expected);
+
+    let bytes = vec![0x3B, 0x00, 0x00, 0x00, 0xE8, 0xD4, 0xA5, 0x0F, 0xFF];
+    let expected = CborType::SignedInteger(-1000000000000);
+    test_decoder(bytes, expected);
+}
+
+#[test]
+fn test_byte_strings() {
+    let bytes: Vec<u8> = vec![0x40];
+    let expected = CborType::Bytes(vec![]);
+    test_decoder(bytes, expected);
+
+    // 01020304
+    let bytes: Vec<u8> = vec![0x44, 0x01, 0x02, 0x03, 0x04];
+    let expected = CborType::Bytes(vec![0x01, 0x02, 0x03, 0x04]);
+    test_decoder(bytes, expected);
+
+    // 0102030405060708090A0B0C0D0E0F10203040506070
+    let bytes: Vec<u8> = vec![0x56, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+                              0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60,
+                              0x70];
+    let expected = CborType::Bytes(vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+         0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x20, 0x30,
+         0x40, 0x50, 0x60, 0x70]);
+    test_decoder(bytes, expected);
+
+    let bytes: Vec<u8> =
+        vec![0x59, 0x01, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
+    let expected = CborType::Bytes(vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
+    test_decoder(bytes, expected);
+}
+
+#[test]
+fn test_maps() {
+    // {}
+    let bytes: Vec<u8> = vec![0xa0];
+    let expected: BTreeMap<CborType, CborType> = BTreeMap::new();
+    test_decoder(bytes, CborType::Map(expected));
+
+    // {1: 2, 3: 4}
+    let bytes: Vec<u8> = vec![0xa2, 0x01, 0x02, 0x03, 0x04];
+    let mut expected: BTreeMap<CborType, CborType> = BTreeMap::new();
+    expected.insert(CborType::Integer(1), CborType::Integer(2));
+    expected.insert(CborType::Integer(3), CborType::Integer(4));
+    test_decoder(bytes, CborType::Map(expected));
+
+    // TODO: strings aren't properly supported as keys yet.
+    // {"a": 1, "b": [2, 3]}
+    // let bytes: Vec<u8> = vec![0xa2, 0x61, 0x61, 0x01, 0x61, 0x62, 0x82, 0x02, 0x03];
+    // let expected =
+    //     CborType::Map(vec![
+    //         CborMap{key: CborType::Integer(1), value: CborType::Integer(2)},
+    //         CborMap{key: CborType::Integer(3), value: CborType::Integer(4)}]);
+    // test_decoder(bytes, expected);
+
+    // let bytes: Vec<u8> = vec![0x82, 0x61, 0x61, 0xa1, 0x61, 0x62, 0x61, 0x63];
+    // test_decoder(bytes, "[a, {b: c}]");
+
+    // let bytes: Vec<u8> = vec![0xa5, 0x61, 0x61, 0x61, 0x41, 0x61, 0x62, 0x61,
+    //                           0x42, 0x61, 0x63, 0x61, 0x43, 0x61, 0x64, 0x61,
+    //                           0x44, 0x61, 0x65, 0x61, 0x45];
+    // test_decoder(bytes, "{a: A, b: B, c: C, d: D, e: E}");
+}
+
+#[test]
+fn test_map_duplicate_keys() {
+    let bytes: Vec<u8> = vec![0xa4, 0x01, 0x02, 0x02, 0x03, 0x01, 0x03, 0x04, 0x04];
+    test_decoder_error(bytes, CborError::DuplicateMapKey);
+}
+
+#[test]
+fn test_tag_with_no_value() {
+    let bytes: Vec<u8> = vec![0xc0];
+    test_decoder_error(bytes, CborError::TruncatedInput);
+}
+
+#[test]
+fn test_truncated_int() {
+    let bytes: Vec<u8> = vec![0x19, 0x03];
+    test_decoder_error(bytes, CborError::TruncatedInput);
+}
+
+#[test]
+fn test_truncated_array() {
+    let bytes: Vec<u8> = vec![0x83, 0x01, 0x02];
+    test_decoder_error(bytes, CborError::TruncatedInput);
+}
+
+#[test]
+fn test_truncated_map() {
+    let bytes: Vec<u8> = vec![0xa2, 0x01, 0x02, 0x00];
+    test_decoder_error(bytes, CborError::TruncatedInput);
+}
+
+#[test]
+fn test_malformed_integer() {
+    let bytes: Vec<u8> = vec![0x1c];
+    test_decoder_error(bytes, CborError::MalformedInput);
+}
+
+#[test]
+fn test_signed_integer_too_large() {
+    let bytes = vec![0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
+    test_decoder_error(bytes, CborError::InputValueOutOfRange);
+}
+
+#[test]
+fn test_null() {
+    let bytes = vec![0xf6];
+    test_decoder(bytes, CborType::Null);
+}
+
+#[test]
+fn test_null_in_array() {
+    let bytes = vec![0x82, 0xf6, 0xf6];
+    test_decoder(
+        bytes,
+        CborType::Array(vec![CborType::Null,
+             CborType::Null]),
+    );
+}
+
+#[test]
+fn test_major_type_7() {
+    for i in 0..0x20 {
+        if i != 22 {
+            let bytes = vec![0xe0 | i];
+            test_decoder_error(bytes, CborError::UnsupportedType);
+        }
+    }
+}
+
+#[test]
+fn test_large_input() {
+    let array = vec![0xFF; MAX_ARRAY_SIZE];
+    let expected = CborType::Bytes(array.clone());
+    let mut bytes = vec![0x5A, 0x08, 0x00, 0x00, 0x00];
+    bytes.extend_from_slice(&array);
+    test_decoder(bytes, expected);
+}
+
+#[test]
+fn test_too_large_input() {
+    let array = vec![0xFF; MAX_ARRAY_SIZE + 1];
+    let mut bytes = vec![0x5A, 0x08, 0x00, 0x00, 0x01];
+    bytes.extend_from_slice(&array);
+    test_decoder_error(bytes, CborError::InputTooLarge);
+}
+
+// We currently don't support CBOR strings (issue #39).
+#[test]
+fn test_invalid_input() {
+    let bytes = vec![0x60];
+    test_decoder_error(bytes, CborError::UnsupportedType);
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/moz_cbor/src/test_serializer.rs
@@ -0,0 +1,310 @@
+use CborType;
+use std::collections::BTreeMap;
+
+#[test]
+fn test_nint() {
+    struct Testcase {
+        value: i64,
+        expected: Vec<u8>,
+    }
+    let testcases: Vec<Testcase> = vec![Testcase {
+                                            value: -1,
+                                            expected: vec![0x20],
+                                        },
+                                        Testcase {
+                                            value: -10,
+                                            expected: vec![0x29],
+                                        },
+                                        Testcase {
+                                            value: -100,
+                                            expected: vec![0x38, 0x63],
+                                        },
+                                        Testcase {
+                                            value: -1000,
+                                            expected: vec![0x39, 0x03, 0xe7],
+                                        },
+                                        Testcase {
+                                            value: -1000000,
+                                            expected: vec![0x3a, 0x00, 0x0f, 0x42, 0x3f],
+                                        },
+                                        Testcase {
+                                            value: -4611686018427387903,
+                                            expected: vec![0x3b, 0x3f, 0xff, 0xff, 0xff, 0xff,
+                                                           0xff, 0xff, 0xfe],
+                                        }];
+    for testcase in testcases {
+        let cbor = CborType::SignedInteger(testcase.value);
+        assert_eq!(testcase.expected, cbor.serialize());
+    }
+}
+
+#[test]
+fn test_bstr() {
+    struct Testcase {
+        value: Vec<u8>,
+        expected: Vec<u8>,
+    }
+    let testcases: Vec<Testcase> =
+        vec![Testcase {
+                 value: vec![],
+                 expected: vec![0x40],
+             },
+             Testcase {
+                 value: vec![0x01, 0x02, 0x03, 0x04],
+                 expected: vec![0x44, 0x01, 0x02, 0x03, 0x04],
+             },
+             Testcase {
+                 value: vec![0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+                             0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+                             0xaf, 0xaf, 0xaf],
+                 expected: vec![0x58, 0x19, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+                                0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+                                0xaf, 0xaf, 0xaf, 0xaf, 0xaf],
+             }];
+    for testcase in testcases {
+        let cbor = CborType::Bytes(testcase.value);
+        assert_eq!(testcase.expected, cbor.serialize());
+    }
+}
+
+#[test]
+fn test_tstr() {
+    struct Testcase {
+        value: String,
+        expected: Vec<u8>,
+    }
+    let testcases: Vec<Testcase> = vec![Testcase {
+                                            value: String::new(),
+                                            expected: vec![0x60],
+                                        },
+                                        Testcase {
+                                            value: String::from("a"),
+                                            expected: vec![0x61, 0x61],
+                                        },
+                                        Testcase {
+                                            value: String::from("IETF"),
+                                            expected: vec![0x64, 0x49, 0x45, 0x54, 0x46],
+                                        },
+                                        Testcase {
+                                            value: String::from("\"\\"),
+                                            expected: vec![0x62, 0x22, 0x5c],
+                                        },
+                                        Testcase {
+                                            value: String::from("水"),
+                                            expected: vec![0x63, 0xe6, 0xb0, 0xb4],
+                                        }];
+    for testcase in testcases {
+        let cbor = CborType::String(testcase.value);
+        assert_eq!(testcase.expected, cbor.serialize());
+    }
+}
+
+#[test]
+fn test_arr() {
+    struct Testcase {
+        value: Vec<CborType>,
+        expected: Vec<u8>,
+    }
+    let nested_arr_1 = vec![CborType::Integer(2),
+                            CborType::Integer(3)];
+    let nested_arr_2 = vec![CborType::Integer(4),
+                            CborType::Integer(5)];
+    let testcases: Vec<Testcase> =
+        vec![Testcase {
+                 value: vec![],
+                 expected: vec![0x80],
+             },
+             Testcase {
+                 value: vec![CborType::Integer(1),
+                             CborType::Integer(2),
+                             CborType::Integer(3)],
+                 expected: vec![0x83, 0x01, 0x02, 0x03],
+             },
+             Testcase {
+                 value: vec![CborType::Integer(1),
+                             CborType::Array(nested_arr_1),
+                             CborType::Array(nested_arr_2)],
+                 expected: vec![0x83, 0x01, 0x82, 0x02, 0x03, 0x82, 0x04, 0x05],
+             },
+             Testcase {
+                 value: vec![CborType::Integer(1),
+                             CborType::Integer(2),
+                             CborType::Integer(3),
+                             CborType::Integer(4),
+                             CborType::Integer(5),
+                             CborType::Integer(6),
+                             CborType::Integer(7),
+                             CborType::Integer(8),
+                             CborType::Integer(9),
+                             CborType::Integer(10),
+                             CborType::Integer(11),
+                             CborType::Integer(12),
+                             CborType::Integer(13),
+                             CborType::Integer(14),
+                             CborType::Integer(15),
+                             CborType::Integer(16),
+                             CborType::Integer(17),
+                             CborType::Integer(18),
+                             CborType::Integer(19),
+                             CborType::Integer(20),
+                             CborType::Integer(21),
+                             CborType::Integer(22),
+                             CborType::Integer(23),
+                             CborType::Integer(24),
+                             CborType::Integer(25)],
+                 expected: vec![0x98, 0x19, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+                                0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+                                0x15, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19],
+             }];
+    for testcase in testcases {
+        let cbor = CborType::Array(testcase.value);
+        assert_eq!(testcase.expected, cbor.serialize());
+    }
+}
+
+#[test]
+fn test_map() {
+    let empty_map: BTreeMap<CborType, CborType> = BTreeMap::new();
+    assert_eq!(vec![0xa0], CborType::Map(empty_map).serialize());
+
+    let mut positive_map: BTreeMap<CborType, CborType> = BTreeMap::new();
+    positive_map.insert(CborType::Integer(20), CborType::Integer(10));
+    positive_map.insert(CborType::Integer(10), CborType::Integer(20));
+    positive_map.insert(CborType::Integer(15), CborType::Integer(15));
+    assert_eq!(
+        vec![0xa3, 0x0a, 0x14, 0x0f, 0x0f, 0x14, 0x0a],
+        CborType::Map(positive_map).serialize()
+    );
+
+    let mut negative_map: BTreeMap<CborType, CborType> = BTreeMap::new();
+    negative_map.insert(CborType::SignedInteger(-4), CborType::Integer(10));
+    negative_map.insert(CborType::SignedInteger(-1), CborType::Integer(20));
+    negative_map.insert(CborType::SignedInteger(-5), CborType::Integer(15));
+    negative_map.insert(CborType::SignedInteger(-6), CborType::Integer(10));
+    assert_eq!(
+        vec![0xa4, 0x20, 0x14, 0x23, 0x0a, 0x24, 0x0f, 0x25, 0x0a],
+        CborType::Map(negative_map).serialize()
+    );
+
+    let mut mixed_map: BTreeMap<CborType, CborType> = BTreeMap::new();
+    mixed_map.insert(CborType::Integer(0), CborType::Integer(10));
+    mixed_map.insert(CborType::SignedInteger(-10), CborType::Integer(20));
+    mixed_map.insert(CborType::Integer(15), CborType::Integer(15));
+    assert_eq!(
+        vec![0xa3, 0x00, 0x0a, 0x0f, 0x0f, 0x29, 0x14],
+        CborType::Map(mixed_map).serialize()
+    );
+
+    let mut very_mixed_map: BTreeMap<CborType, CborType> = BTreeMap::new();
+    very_mixed_map.insert(CborType::Integer(0), CborType::Integer(10));
+    very_mixed_map.insert(
+        CborType::SignedInteger(-10000),
+        CborType::String("low".to_string()),
+    );
+    very_mixed_map.insert(CborType::SignedInteger(-10), CborType::Integer(20));
+    very_mixed_map.insert(
+        CborType::Integer(10001),
+        CborType::String("high".to_string()),
+    );
+    very_mixed_map.insert(
+        CborType::Integer(10000),
+        CborType::String("high".to_string()),
+    );
+    very_mixed_map.insert(CborType::Integer(15), CborType::Integer(15));
+    let expected = vec![0xa6, 0x00, 0x0a, 0x0f, 0x0f, 0x29, 0x14, 0x19, 0x27, 0x10, 0x64, 0x68,
+                        0x69, 0x67, 0x68, 0x19, 0x27, 0x11, 0x64, 0x68, 0x69, 0x67, 0x68, 0x39,
+                        0x27, 0x0F, 0x63, 0x6C, 0x6F, 0x77];
+    assert_eq!(expected, CborType::Map(very_mixed_map).serialize());
+}
+
+#[test]
+#[ignore]
+// XXX: The string isn't put into the map at the moment, so we can't actually
+//      test this.
+fn test_invalid_map() {
+    let mut invalid_map: BTreeMap<CborType, CborType> = BTreeMap::new();
+    invalid_map.insert(CborType::SignedInteger(-10), CborType::Integer(20));
+    invalid_map.insert(CborType::String("0".to_string()), CborType::Integer(10));
+    invalid_map.insert(CborType::Integer(15), CborType::Integer(15));
+    let expected: Vec<u8> = vec![];
+    assert_eq!(expected, CborType::Map(invalid_map).serialize());
+}
+
+#[test]
+fn test_integer() {
+    struct Testcase {
+        value: u64,
+        expected: Vec<u8>,
+    }
+    let testcases: Vec<Testcase> =
+        vec![Testcase {
+                 value: 0,
+                 expected: vec![0],
+             },
+             Testcase {
+                 value: 1,
+                 expected: vec![1],
+             },
+             Testcase {
+                 value: 10,
+                 expected: vec![0x0a],
+             },
+             Testcase {
+                 value: 23,
+                 expected: vec![0x17],
+             },
+             Testcase {
+                 value: 24,
+                 expected: vec![0x18, 0x18],
+             },
+             Testcase {
+                 value: 25,
+                 expected: vec![0x18, 0x19],
+             },
+             Testcase {
+                 value: 100,
+                 expected: vec![0x18, 0x64],
+             },
+             Testcase {
+                 value: 1000,
+                 expected: vec![0x19, 0x03, 0xe8],
+             },
+             Testcase {
+                 value: 1000000,
+                 expected: vec![0x1a, 0x00, 0x0f, 0x42, 0x40],
+             },
+             Testcase {
+                 value: 1000000000000,
+                 expected: vec![0x1b, 0x00, 0x00, 0x00, 0xe8, 0xd4, 0xa5, 0x10, 0x00],
+             },
+             Testcase {
+                 value: 18446744073709551615,
+                 expected: vec![0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
+             }];
+    for testcase in testcases {
+        let cbor = CborType::Integer(testcase.value);
+        assert_eq!(testcase.expected, cbor.serialize());
+    }
+}
+
+#[test]
+fn test_tagged_item() {
+    let cbor = CborType::Tag(0x12, Box::new(CborType::Integer(2).clone()));
+    assert_eq!(vec![0xD2, 0x02], cbor.serialize());
+
+    let cbor = CborType::Tag(0x62, Box::new(CborType::Array(vec![]).clone()));
+    assert_eq!(vec![0xD8, 0x62, 0x80], cbor.serialize());
+}
+
+#[test]
+fn test_null() {
+    let cbor = CborType::Null;
+    assert_eq!(vec![0xf6], cbor.serialize());
+}
+
+#[test]
+fn test_null_in_array() {
+    let cbor = CborType::Array(vec![CborType::Null,
+         CborType::Null]);
+    assert_eq!(vec![0x82, 0xf6, 0xf6], cbor.serialize());
+}
--- a/toolkit/library/gtest/rust/Cargo.lock
+++ b/toolkit/library/gtest/rust/Cargo.lock
@@ -259,25 +259,28 @@ dependencies = [
  "core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cose"
-version = "0.1.2"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "moz_cbor 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
 
 [[package]]
 name = "cose-c"
-version = "0.1.1"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cose 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cssparser"
 version = "0.23.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -556,17 +559,17 @@ dependencies = [
 ]
 
 [[package]]
 name = "gkrust-shared"
 version = "0.1.0"
 dependencies = [
  "audioipc-client 0.1.0",
  "audioipc-server 0.1.0",
- "cose-c 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "cubeb 0.3.0",
  "cubeb-backend 0.2.0",
  "cubeb-core 0.1.0",
  "cubeb-pulse 0.0.1",
  "encoding_c 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding_glue 0.1.0",
  "geckoservo 0.0.1",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -799,16 +802,21 @@ source = "registry+https://github.com/ru
 dependencies = [
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "moz_cbor"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "mp4parse"
 version = "0.9.1"
 dependencies = [
  "bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "mp4parse_fallible 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1571,18 +1579,18 @@ dependencies = [
 "checksum clang-sys 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00048189ee171715296dfe3b2fcfd439563c7bfec0d98d3976ce3402d62c8f07"
 "checksum clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "110d43e343eb29f4f51c1db31beb879d546db27998577e5715270a54bcf41d3f"
 "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd"
 "checksum core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8047f547cd6856d45b1cdd75ef8d2f21f3d0e4bf1dab0a0041b0ae9a5dda9c0e"
 "checksum core-foundation-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "41115a6aa5d3e1e5ef98148373f25971d1fad53818553f216495f9e67e90a624"
 "checksum core-foundation-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "152195421a2e6497a8179195672e9d4ee8e45ed8c465b626f1606d27a08ebcd5"
 "checksum core-graphics 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5dc0a78ab2ac23b6ea7b3fe5fe93b227900dc0956979735b8f68032417976dd4"
 "checksum core-text 8.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bcad23756dd1dc4b47bf6a914ace27aadb8fa68889db5837af2308d018d0467c"
-"checksum cose 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ec10816629f38fa557f08e199a3474fab954f4c8d2645550367235afa6e5646b"
-"checksum cose-c 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "07cc8bb85ec2e93541ef9369b85a4b6fb7732bc7f4854d317eab20e726b0fc2f"
+"checksum cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72fa26cb151d3ae4b70f63d67d0fed57ce04220feafafbae7f503bef7aae590d"
+"checksum cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "49726015ab0ca765144fcca61e4a7a543a16b795a777fa53f554da2fffff9a94"
 "checksum cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8a807ac3ab7a217829c2a3b65732b926b2befe6a35f33b4bf8b503692430f223"
 "checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df"
 "checksum darling 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9861a8495606435477df581bc858ccf15a3469747edf175b94a4704fd9aaedac"
 "checksum darling_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1486a8b00b45062c997f767738178b43219133dd0c8c826cb811e60563810821"
 "checksum darling_macro 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a86ec160aa0c3dd492dd4a14ec8104ad8f1a9400a820624db857998cc1f80f9"
 "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
 "checksum dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "068d4026697c1a18f0b0bb8cfcad1b0c151b90d8edb9bf4c235ad68128920d1d"
 "checksum dwrote 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a207eb7b40e25d1d28dc679f451d321fb6954b73ceaa47986702575865469461"
@@ -1619,16 +1627,17 @@ dependencies = [
 "checksum libudev 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea626d3bdf40a1c5aee3bcd4f40826970cae8d80a8fec934c82a63840094dcfe"
 "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
 "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
 "checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
 "checksum memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46f3c7359028b31999287dae4e5047ddfe90a23b7dca2282ce759b491080c99b"
 "checksum mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9e965267d4d58496fc4f740e9861118367f13570cadf66316ed2c3f2f14d87c7"
 "checksum mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673"
 "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
+"checksum moz_cbor 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f0dc96d1e40041ad9e6f9986e72e65d45d70dc31cef9d852b47646b2970f238"
 "checksum mp4parse_fallible 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6626c2aef76eb8f984eef02e475883d3fe9112e114720446c5810fc5f045cd30"
 "checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09"
 "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
 "checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
 "checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba"
 "checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070"
 "checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d"
 "checksum ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da12c96037889ae0be29dd2bdd260e5a62a7df24e6466d5a15bb8131c1c200a8"
--- a/toolkit/library/rust/Cargo.lock
+++ b/toolkit/library/rust/Cargo.lock
@@ -259,25 +259,28 @@ dependencies = [
  "core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cose"
-version = "0.1.2"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "moz_cbor 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
 
 [[package]]
 name = "cose-c"
-version = "0.1.1"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cose 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cssparser"
 version = "0.23.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -555,17 +558,17 @@ dependencies = [
 ]
 
 [[package]]
 name = "gkrust-shared"
 version = "0.1.0"
 dependencies = [
  "audioipc-client 0.1.0",
  "audioipc-server 0.1.0",
- "cose-c 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "cubeb 0.3.0",
  "cubeb-backend 0.2.0",
  "cubeb-core 0.1.0",
  "cubeb-pulse 0.0.1",
  "encoding_c 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding_glue 0.1.0",
  "geckoservo 0.0.1",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -798,16 +801,21 @@ source = "registry+https://github.com/ru
 dependencies = [
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "moz_cbor"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "mp4parse"
 version = "0.9.1"
 dependencies = [
  "bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "mp4parse_fallible 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1583,18 +1591,18 @@ dependencies = [
 "checksum clang-sys 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00048189ee171715296dfe3b2fcfd439563c7bfec0d98d3976ce3402d62c8f07"
 "checksum clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "110d43e343eb29f4f51c1db31beb879d546db27998577e5715270a54bcf41d3f"
 "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd"
 "checksum core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8047f547cd6856d45b1cdd75ef8d2f21f3d0e4bf1dab0a0041b0ae9a5dda9c0e"
 "checksum core-foundation-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "41115a6aa5d3e1e5ef98148373f25971d1fad53818553f216495f9e67e90a624"
 "checksum core-foundation-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "152195421a2e6497a8179195672e9d4ee8e45ed8c465b626f1606d27a08ebcd5"
 "checksum core-graphics 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5dc0a78ab2ac23b6ea7b3fe5fe93b227900dc0956979735b8f68032417976dd4"
 "checksum core-text 8.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bcad23756dd1dc4b47bf6a914ace27aadb8fa68889db5837af2308d018d0467c"
-"checksum cose 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ec10816629f38fa557f08e199a3474fab954f4c8d2645550367235afa6e5646b"
-"checksum cose-c 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "07cc8bb85ec2e93541ef9369b85a4b6fb7732bc7f4854d317eab20e726b0fc2f"
+"checksum cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72fa26cb151d3ae4b70f63d67d0fed57ce04220feafafbae7f503bef7aae590d"
+"checksum cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "49726015ab0ca765144fcca61e4a7a543a16b795a777fa53f554da2fffff9a94"
 "checksum cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8a807ac3ab7a217829c2a3b65732b926b2befe6a35f33b4bf8b503692430f223"
 "checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df"
 "checksum darling 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9861a8495606435477df581bc858ccf15a3469747edf175b94a4704fd9aaedac"
 "checksum darling_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1486a8b00b45062c997f767738178b43219133dd0c8c826cb811e60563810821"
 "checksum darling_macro 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a86ec160aa0c3dd492dd4a14ec8104ad8f1a9400a820624db857998cc1f80f9"
 "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
 "checksum dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "068d4026697c1a18f0b0bb8cfcad1b0c151b90d8edb9bf4c235ad68128920d1d"
 "checksum dwrote 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a207eb7b40e25d1d28dc679f451d321fb6954b73ceaa47986702575865469461"
@@ -1631,16 +1639,17 @@ dependencies = [
 "checksum libudev 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea626d3bdf40a1c5aee3bcd4f40826970cae8d80a8fec934c82a63840094dcfe"
 "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
 "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
 "checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
 "checksum memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46f3c7359028b31999287dae4e5047ddfe90a23b7dca2282ce759b491080c99b"
 "checksum mio 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9e965267d4d58496fc4f740e9861118367f13570cadf66316ed2c3f2f14d87c7"
 "checksum mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673"
 "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
+"checksum moz_cbor 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f0dc96d1e40041ad9e6f9986e72e65d45d70dc31cef9d852b47646b2970f238"
 "checksum mp4parse_fallible 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6626c2aef76eb8f984eef02e475883d3fe9112e114720446c5810fc5f045cd30"
 "checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09"
 "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
 "checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
 "checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba"
 "checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070"
 "checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d"
 "checksum ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da12c96037889ae0be29dd2bdd260e5a62a7df24e6466d5a15bb8131c1c200a8"
--- a/toolkit/library/rust/shared/Cargo.toml
+++ b/toolkit/library/rust/shared/Cargo.toml
@@ -20,17 +20,17 @@ cubeb-backend = { path = "../../../../me
 encoding_c = "0.8.0"
 encoding_glue = { path = "../../../../intl/encoding_glue" }
 audioipc-client = { path = "../../../../media/audioipc/client", optional = true }
 audioipc-server = { path = "../../../../media/audioipc/server", optional = true }
 u2fhid = { path = "../../../../dom/webauthn/u2f-hid-rs" }
 # We have these to enforce common feature sets for said crates.
 log = {version = "0.3", features = ["release_max_level_info"]}
 syn = { version = "0.11", features = ["full", "visit", "parsing"] }
-cose-c = { version = "0.1.1" }
+cose-c = { version = "0.1.5" }
 
 [features]
 default = []
 bindgen = ["geckoservo/bindgen"]
 servo = ["geckoservo"]
 quantum_render = ["webrender_bindings"]
 cubeb-remoting = ["cubeb-core", "cubeb", "cubeb-backend", "audioipc-client", "audioipc-server"]
 cubeb_pulse_rust = ["cubeb-pulse"]