Line data Source code
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/. */
6 :
7 : #include "SRIMetadata.h"
8 :
9 : #include "hasht.h"
10 : #include "mozilla/dom/URLSearchParams.h"
11 : #include "mozilla/Logging.h"
12 : #include "mozilla/SizePrintfMacros.h"
13 : #include "nsICryptoHash.h"
14 :
15 : static mozilla::LogModule*
16 0 : GetSriMetadataLog()
17 : {
18 : static mozilla::LazyLogModule gSriMetadataPRLog("SRIMetadata");
19 0 : return gSriMetadataPRLog;
20 : }
21 :
22 : #define SRIMETADATALOG(args) MOZ_LOG(GetSriMetadataLog(), mozilla::LogLevel::Debug, args)
23 : #define SRIMETADATAERROR(args) MOZ_LOG(GetSriMetadataLog(), mozilla::LogLevel::Error, args)
24 :
25 : namespace mozilla {
26 : namespace dom {
27 :
28 0 : SRIMetadata::SRIMetadata(const nsACString& aToken)
29 0 : : mAlgorithmType(SRIMetadata::UNKNOWN_ALGORITHM), mEmpty(false)
30 : {
31 0 : MOZ_ASSERT(!aToken.IsEmpty()); // callers should check this first
32 :
33 0 : SRIMETADATALOG(("SRIMetadata::SRIMetadata, aToken='%s'",
34 : PromiseFlatCString(aToken).get()));
35 :
36 0 : int32_t hyphen = aToken.FindChar('-');
37 0 : if (hyphen == -1) {
38 0 : SRIMETADATAERROR(("SRIMetadata::SRIMetadata, invalid (no hyphen)"));
39 0 : return; // invalid metadata
40 : }
41 :
42 : // split the token into its components
43 0 : mAlgorithm = Substring(aToken, 0, hyphen);
44 0 : uint32_t hashStart = hyphen + 1;
45 0 : if (hashStart >= aToken.Length()) {
46 0 : SRIMETADATAERROR(("SRIMetadata::SRIMetadata, invalid (missing digest)"));
47 0 : return; // invalid metadata
48 : }
49 0 : int32_t question = aToken.FindChar('?');
50 0 : if (question == -1) {
51 0 : mHashes.AppendElement(Substring(aToken, hashStart,
52 0 : aToken.Length() - hashStart));
53 : } else {
54 0 : MOZ_ASSERT(question > 0);
55 0 : if (static_cast<uint32_t>(question) <= hashStart) {
56 0 : SRIMETADATAERROR(("SRIMetadata::SRIMetadata, invalid (options w/o digest)"));
57 0 : return; // invalid metadata
58 : }
59 0 : mHashes.AppendElement(Substring(aToken, hashStart,
60 0 : question - hashStart));
61 : }
62 :
63 0 : if (mAlgorithm.EqualsLiteral("sha256")) {
64 0 : mAlgorithmType = nsICryptoHash::SHA256;
65 0 : } else if (mAlgorithm.EqualsLiteral("sha384")) {
66 0 : mAlgorithmType = nsICryptoHash::SHA384;
67 0 : } else if (mAlgorithm.EqualsLiteral("sha512")) {
68 0 : mAlgorithmType = nsICryptoHash::SHA512;
69 : }
70 :
71 0 : SRIMETADATALOG(("SRIMetadata::SRIMetadata, hash='%s'; alg='%s'",
72 : mHashes[0].get(), mAlgorithm.get()));
73 : }
74 :
75 : bool
76 0 : SRIMetadata::operator<(const SRIMetadata& aOther) const
77 : {
78 : static_assert(nsICryptoHash::SHA256 < nsICryptoHash::SHA384,
79 : "We rely on the order indicating relative alg strength");
80 : static_assert(nsICryptoHash::SHA384 < nsICryptoHash::SHA512,
81 : "We rely on the order indicating relative alg strength");
82 0 : MOZ_ASSERT(mAlgorithmType == SRIMetadata::UNKNOWN_ALGORITHM ||
83 : mAlgorithmType == nsICryptoHash::SHA256 ||
84 : mAlgorithmType == nsICryptoHash::SHA384 ||
85 : mAlgorithmType == nsICryptoHash::SHA512);
86 0 : MOZ_ASSERT(aOther.mAlgorithmType == SRIMetadata::UNKNOWN_ALGORITHM ||
87 : aOther.mAlgorithmType == nsICryptoHash::SHA256 ||
88 : aOther.mAlgorithmType == nsICryptoHash::SHA384 ||
89 : aOther.mAlgorithmType == nsICryptoHash::SHA512);
90 :
91 0 : if (mEmpty) {
92 0 : SRIMETADATALOG(("SRIMetadata::operator<, first metadata is empty"));
93 0 : return true; // anything beats the empty metadata (incl. invalid ones)
94 : }
95 :
96 0 : SRIMETADATALOG(("SRIMetadata::operator<, alg1='%d'; alg2='%d'",
97 : mAlgorithmType, aOther.mAlgorithmType));
98 0 : return (mAlgorithmType < aOther.mAlgorithmType);
99 : }
100 :
101 : bool
102 0 : SRIMetadata::operator>(const SRIMetadata& aOther) const
103 : {
104 0 : MOZ_ASSERT(false);
105 : return false;
106 : }
107 :
108 : SRIMetadata&
109 0 : SRIMetadata::operator+=(const SRIMetadata& aOther)
110 : {
111 0 : MOZ_ASSERT(!aOther.IsEmpty() && !IsEmpty());
112 0 : MOZ_ASSERT(aOther.IsValid() && IsValid());
113 0 : MOZ_ASSERT(mAlgorithmType == aOther.mAlgorithmType);
114 :
115 : // We only pull in the first element of the other metadata
116 0 : MOZ_ASSERT(aOther.mHashes.Length() == 1);
117 0 : if (mHashes.Length() < SRIMetadata::MAX_ALTERNATE_HASHES) {
118 0 : SRIMETADATALOG(("SRIMetadata::operator+=, appending another '%s' hash (new length=%" PRIuSIZE ")",
119 : mAlgorithm.get(), mHashes.Length()));
120 0 : mHashes.AppendElement(aOther.mHashes[0]);
121 : }
122 :
123 0 : MOZ_ASSERT(mHashes.Length() > 1);
124 0 : MOZ_ASSERT(mHashes.Length() <= SRIMetadata::MAX_ALTERNATE_HASHES);
125 0 : return *this;
126 : }
127 :
128 : bool
129 0 : SRIMetadata::operator==(const SRIMetadata& aOther) const
130 : {
131 0 : if (IsEmpty() || !IsValid()) {
132 0 : return false;
133 : }
134 0 : return mAlgorithmType == aOther.mAlgorithmType;
135 : }
136 :
137 : void
138 0 : SRIMetadata::GetHash(uint32_t aIndex, nsCString* outHash) const
139 : {
140 0 : MOZ_ASSERT(aIndex < SRIMetadata::MAX_ALTERNATE_HASHES);
141 0 : if (NS_WARN_IF(aIndex >= mHashes.Length())) {
142 0 : *outHash = nullptr;
143 0 : return;
144 : }
145 0 : *outHash = mHashes[aIndex];
146 : }
147 :
148 : void
149 0 : SRIMetadata::GetHashType(int8_t* outType, uint32_t* outLength) const
150 : {
151 : // these constants are defined in security/nss/lib/util/hasht.h and
152 : // netwerk/base/public/nsICryptoHash.idl
153 0 : switch (mAlgorithmType) {
154 : case nsICryptoHash::SHA256:
155 0 : *outLength = SHA256_LENGTH;
156 0 : break;
157 : case nsICryptoHash::SHA384:
158 0 : *outLength = SHA384_LENGTH;
159 0 : break;
160 : case nsICryptoHash::SHA512:
161 0 : *outLength = SHA512_LENGTH;
162 0 : break;
163 : default:
164 0 : *outLength = 0;
165 : }
166 0 : *outType = mAlgorithmType;
167 0 : }
168 :
169 : } // namespace dom
170 : } // namespace mozilla
|