1 //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef ProtocolParser_h__ 7 #define ProtocolParser_h__ 8 9 #include "HashStore.h" 10 #include "nsICryptoHMAC.h" 11 #include "safebrowsing.pb.h" 12 13 namespace mozilla { 14 namespace safebrowsing { 15 16 /** 17 * Abstract base class for parsing update data in multiple formats. 18 */ 19 class ProtocolParser { 20 public: 21 struct ForwardedUpdate { 22 nsCString table; 23 nsCString url; 24 }; 25 26 ProtocolParser(); 27 virtual ~ProtocolParser(); 28 Status()29 nsresult Status() const { return mUpdateStatus; } 30 31 nsresult Init(nsICryptoHash* aHasher); 32 33 #ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES GetRawTableUpdates()34 nsCString GetRawTableUpdates() const { return mPending; } 35 #endif 36 37 virtual void SetCurrentTable(const nsACString& aTable) = 0; 38 SetRequestedTables(const nsTArray<nsCString> & aRequestTables)39 void SetRequestedTables(const nsTArray<nsCString>& aRequestTables) 40 { 41 mRequestedTables = aRequestTables; 42 } 43 44 nsresult Begin(); 45 virtual nsresult AppendStream(const nsACString& aData) = 0; 46 UpdateWaitSec()47 uint32_t UpdateWaitSec() { return mUpdateWaitSec; } 48 49 // Notify that the inbound data is ready for parsing if progressive 50 // parsing is not supported, for example in V4. 51 virtual void End() = 0; 52 53 // Forget the table updates that were created by this pass. It 54 // becomes the caller's responsibility to free them. This is shitty. 55 TableUpdate *GetTableUpdate(const nsACString& aTable); ForgetTableUpdates()56 void ForgetTableUpdates() { mTableUpdates.Clear(); } GetTableUpdates()57 nsTArray<TableUpdate*> &GetTableUpdates() { return mTableUpdates; } 58 59 // These are only meaningful to V2. Since they were originally public, 60 // moving them to ProtocolParserV2 requires a dymamic cast in the call 61 // sites. As a result, we will leave them until we remove support 62 // for V2 entirely.. Forwards()63 virtual const nsTArray<ForwardedUpdate> &Forwards() const { return mForwards; } ResetRequested()64 virtual bool ResetRequested() { return false; } 65 66 protected: 67 virtual TableUpdate* CreateTableUpdate(const nsACString& aTableName) const = 0; 68 69 nsCString mPending; 70 nsresult mUpdateStatus; 71 72 // Keep track of updates to apply before passing them to the DBServiceWorkers. 73 nsTArray<TableUpdate*> mTableUpdates; 74 75 nsTArray<ForwardedUpdate> mForwards; 76 nsCOMPtr<nsICryptoHash> mCryptoHash; 77 78 // The table names that were requested from the client. 79 nsTArray<nsCString> mRequestedTables; 80 81 // How long we should wait until the next update. 82 uint32_t mUpdateWaitSec; 83 84 private: 85 void CleanupUpdates(); 86 }; 87 88 /** 89 * Helpers to parse the "shavar", "digest256" and "simple" list formats. 90 */ 91 class ProtocolParserV2 final : public ProtocolParser { 92 public: 93 ProtocolParserV2(); 94 virtual ~ProtocolParserV2(); 95 96 virtual void SetCurrentTable(const nsACString& aTable) override; 97 virtual nsresult AppendStream(const nsACString& aData) override; 98 virtual void End() override; 99 100 // Update information. Forwards()101 virtual const nsTArray<ForwardedUpdate> &Forwards() const override { return mForwards; } ResetRequested()102 virtual bool ResetRequested() override { return mResetRequested; } 103 104 private: 105 virtual TableUpdate* CreateTableUpdate(const nsACString& aTableName) const override; 106 107 nsresult ProcessControl(bool* aDone); 108 nsresult ProcessExpirations(const nsCString& aLine); 109 nsresult ProcessChunkControl(const nsCString& aLine); 110 nsresult ProcessForward(const nsCString& aLine); 111 nsresult AddForward(const nsACString& aUrl); 112 nsresult ProcessChunk(bool* done); 113 // Remove this, it's only used for testing 114 nsresult ProcessPlaintextChunk(const nsACString& aChunk); 115 nsresult ProcessShaChunk(const nsACString& aChunk); 116 nsresult ProcessHostAdd(const Prefix& aDomain, uint8_t aNumEntries, 117 const nsACString& aChunk, uint32_t* aStart); 118 nsresult ProcessHostSub(const Prefix& aDomain, uint8_t aNumEntries, 119 const nsACString& aChunk, uint32_t* aStart); 120 nsresult ProcessHostAddComplete(uint8_t aNumEntries, const nsACString& aChunk, 121 uint32_t *aStart); 122 nsresult ProcessHostSubComplete(uint8_t numEntries, const nsACString& aChunk, 123 uint32_t* start); 124 // Digest chunks are very similar to shavar chunks, except digest chunks 125 // always contain the full hash, so there is no need for chunk data to 126 // contain prefix sizes. 127 nsresult ProcessDigestChunk(const nsACString& aChunk); 128 nsresult ProcessDigestAdd(const nsACString& aChunk); 129 nsresult ProcessDigestSub(const nsACString& aChunk); 130 bool NextLine(nsACString& aLine); 131 132 enum ParserState { 133 PROTOCOL_STATE_CONTROL, 134 PROTOCOL_STATE_CHUNK 135 }; 136 ParserState mState; 137 138 enum ChunkType { 139 // Types for shavar tables. 140 CHUNK_ADD, 141 CHUNK_SUB, 142 // Types for digest256 tables. digest256 tables differ in format from 143 // shavar tables since they only contain complete hashes. 144 CHUNK_ADD_DIGEST, 145 CHUNK_SUB_DIGEST 146 }; 147 148 struct ChunkState { 149 ChunkType type; 150 uint32_t num; 151 uint32_t hashSize; 152 uint32_t length; ClearChunkState153 void Clear() { num = 0; hashSize = 0; length = 0; } 154 }; 155 ChunkState mChunkState; 156 157 bool mResetRequested; 158 159 // Updates to apply to the current table being parsed. 160 TableUpdateV2 *mTableUpdate; 161 }; 162 163 // Helpers to parse the "proto" list format. 164 class ProtocolParserProtobuf final : public ProtocolParser { 165 public: 166 typedef FetchThreatListUpdatesResponse_ListUpdateResponse ListUpdateResponse; 167 typedef google::protobuf::RepeatedPtrField<ThreatEntrySet> ThreatEntrySetList; 168 169 public: 170 ProtocolParserProtobuf(); 171 172 virtual void SetCurrentTable(const nsACString& aTable) override; 173 virtual nsresult AppendStream(const nsACString& aData) override; 174 virtual void End() override; 175 176 private: 177 virtual ~ProtocolParserProtobuf(); 178 179 virtual TableUpdate* CreateTableUpdate(const nsACString& aTableName) const override; 180 181 // For parsing update info. 182 nsresult ProcessOneResponse(const ListUpdateResponse& aResponse); 183 184 nsresult ProcessAdditionOrRemoval(TableUpdateV4& aTableUpdate, 185 const ThreatEntrySetList& aUpdate, 186 bool aIsAddition); 187 188 nsresult ProcessRawAddition(TableUpdateV4& aTableUpdate, 189 const ThreatEntrySet& aAddition); 190 191 nsresult ProcessRawRemoval(TableUpdateV4& aTableUpdate, 192 const ThreatEntrySet& aRemoval); 193 194 nsresult ProcessEncodedAddition(TableUpdateV4& aTableUpdate, 195 const ThreatEntrySet& aAddition); 196 197 nsresult ProcessEncodedRemoval(TableUpdateV4& aTableUpdate, 198 const ThreatEntrySet& aRemoval); 199 }; 200 201 } // namespace safebrowsing 202 } // namespace mozilla 203 204 #endif 205