no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / dom / security / SRIMetadata.cpp
blob02144f0f1365cb8e3192a7a0e220e9de305dc9b7
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "SRIMetadata.h"
9 #include "hasht.h"
10 #include "mozilla/Logging.h"
11 #include "nsICryptoHash.h"
13 static mozilla::LogModule* GetSriMetadataLog() {
14 static mozilla::LazyLogModule gSriMetadataPRLog("SRIMetadata");
15 return gSriMetadataPRLog;
18 #define SRIMETADATALOG(args) \
19 MOZ_LOG(GetSriMetadataLog(), mozilla::LogLevel::Debug, args)
20 #define SRIMETADATAERROR(args) \
21 MOZ_LOG(GetSriMetadataLog(), mozilla::LogLevel::Error, args)
23 namespace mozilla::dom {
25 SRIMetadata::SRIMetadata(const nsACString& aToken)
26 : mAlgorithmType(SRIMetadata::UNKNOWN_ALGORITHM), mEmpty(false) {
27 MOZ_ASSERT(!aToken.IsEmpty()); // callers should check this first
29 SRIMETADATALOG(("SRIMetadata::SRIMetadata, aToken='%s'",
30 PromiseFlatCString(aToken).get()));
32 int32_t hyphen = aToken.FindChar('-');
33 if (hyphen == -1) {
34 SRIMETADATAERROR(("SRIMetadata::SRIMetadata, invalid (no hyphen)"));
35 return; // invalid metadata
38 // split the token into its components
39 mAlgorithm = Substring(aToken, 0, hyphen);
40 uint32_t hashStart = hyphen + 1;
41 if (hashStart >= aToken.Length()) {
42 SRIMETADATAERROR(("SRIMetadata::SRIMetadata, invalid (missing digest)"));
43 return; // invalid metadata
45 int32_t question = aToken.FindChar('?');
46 if (question == -1) {
47 mHashes.AppendElement(
48 Substring(aToken, hashStart, aToken.Length() - hashStart));
49 } else {
50 MOZ_ASSERT(question > 0);
51 if (static_cast<uint32_t>(question) <= hashStart) {
52 SRIMETADATAERROR(
53 ("SRIMetadata::SRIMetadata, invalid (options w/o digest)"));
54 return; // invalid metadata
56 mHashes.AppendElement(Substring(aToken, hashStart, question - hashStart));
59 if (mAlgorithm.EqualsLiteral("sha256")) {
60 mAlgorithmType = nsICryptoHash::SHA256;
61 } else if (mAlgorithm.EqualsLiteral("sha384")) {
62 mAlgorithmType = nsICryptoHash::SHA384;
63 } else if (mAlgorithm.EqualsLiteral("sha512")) {
64 mAlgorithmType = nsICryptoHash::SHA512;
67 SRIMETADATALOG(("SRIMetadata::SRIMetadata, hash='%s'; alg='%s'",
68 mHashes[0].get(), mAlgorithm.get()));
71 bool SRIMetadata::operator<(const SRIMetadata& aOther) const {
72 static_assert(nsICryptoHash::SHA256 < nsICryptoHash::SHA384,
73 "We rely on the order indicating relative alg strength");
74 static_assert(nsICryptoHash::SHA384 < nsICryptoHash::SHA512,
75 "We rely on the order indicating relative alg strength");
76 MOZ_ASSERT(mAlgorithmType == SRIMetadata::UNKNOWN_ALGORITHM ||
77 mAlgorithmType == nsICryptoHash::SHA256 ||
78 mAlgorithmType == nsICryptoHash::SHA384 ||
79 mAlgorithmType == nsICryptoHash::SHA512);
80 MOZ_ASSERT(aOther.mAlgorithmType == SRIMetadata::UNKNOWN_ALGORITHM ||
81 aOther.mAlgorithmType == nsICryptoHash::SHA256 ||
82 aOther.mAlgorithmType == nsICryptoHash::SHA384 ||
83 aOther.mAlgorithmType == nsICryptoHash::SHA512);
85 if (mEmpty) {
86 SRIMETADATALOG(("SRIMetadata::operator<, first metadata is empty"));
87 return true; // anything beats the empty metadata (incl. invalid ones)
90 SRIMETADATALOG(("SRIMetadata::operator<, alg1='%d'; alg2='%d'",
91 mAlgorithmType, aOther.mAlgorithmType));
92 return (mAlgorithmType < aOther.mAlgorithmType);
95 bool SRIMetadata::operator>(const SRIMetadata& aOther) const {
96 MOZ_ASSERT(false);
97 return false;
100 SRIMetadata& SRIMetadata::operator+=(const SRIMetadata& aOther) {
101 MOZ_ASSERT(!aOther.IsEmpty() && !IsEmpty());
102 MOZ_ASSERT(aOther.IsValid() && IsValid());
103 MOZ_ASSERT(mAlgorithmType == aOther.mAlgorithmType);
105 // We only pull in the first element of the other metadata
106 MOZ_ASSERT(aOther.mHashes.Length() == 1);
107 if (mHashes.Length() < SRIMetadata::MAX_ALTERNATE_HASHES) {
108 SRIMETADATALOG((
109 "SRIMetadata::operator+=, appending another '%s' hash (new length=%zu)",
110 mAlgorithm.get(), mHashes.Length()));
111 mHashes.AppendElement(aOther.mHashes[0]);
114 MOZ_ASSERT(mHashes.Length() > 1);
115 MOZ_ASSERT(mHashes.Length() <= SRIMetadata::MAX_ALTERNATE_HASHES);
116 return *this;
119 bool SRIMetadata::operator==(const SRIMetadata& aOther) const {
120 if (IsEmpty() || !IsValid()) {
121 return false;
123 return mAlgorithmType == aOther.mAlgorithmType;
126 void SRIMetadata::GetHash(uint32_t aIndex, nsCString* outHash) const {
127 MOZ_ASSERT(aIndex < SRIMetadata::MAX_ALTERNATE_HASHES);
128 if (NS_WARN_IF(aIndex >= mHashes.Length())) {
129 *outHash = nullptr;
130 return;
132 *outHash = mHashes[aIndex];
135 void SRIMetadata::GetHashType(int8_t* outType, uint32_t* outLength) const {
136 // these constants are defined in security/nss/lib/util/hasht.h and
137 // netwerk/base/public/nsICryptoHash.idl
138 switch (mAlgorithmType) {
139 case nsICryptoHash::SHA256:
140 *outLength = SHA256_LENGTH;
141 break;
142 case nsICryptoHash::SHA384:
143 *outLength = SHA384_LENGTH;
144 break;
145 case nsICryptoHash::SHA512:
146 *outLength = SHA512_LENGTH;
147 break;
148 default:
149 *outLength = 0;
151 *outType = mAlgorithmType;
154 bool SRIMetadata::CanTrustBeDelegatedTo(const SRIMetadata& aOther) const {
155 if (IsEmpty()) {
156 // No integrity requirements enforced, just let go.
157 return true;
160 if (aOther.IsEmpty()) {
161 // This metadata requires a check and the other has none, can't delegate.
162 return false;
165 if (mAlgorithmType != aOther.mAlgorithmType) {
166 // They must use the same hash algorithm.
167 return false;
170 // They must be completely identical, except for the order of hashes.
171 // We don't know which hash is the one passing eventually the check, so only
172 // option is to require this metadata to contain the same set of hashes as the
173 // one we want to delegate the trust to.
174 if (mHashes.Length() != aOther.mHashes.Length()) {
175 return false;
178 for (const auto& hash : mHashes) {
179 if (!aOther.mHashes.Contains(hash)) {
180 return false;
184 return true;
187 } // namespace mozilla::dom