json_reader.cc (5561B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=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 file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "json_reader.h" 8 9 #include "pk11pub.h" 10 11 JsonReader::JsonReader(const std::string& n) : buf_(), available_(0), i_(0) { 12 f_.reset(PR_Open(n.c_str(), PR_RDONLY, 00600)); 13 EXPECT_TRUE(f_) << "error opening vectors from: " << n; 14 buf_[0] = 0; 15 } 16 17 uint64_t JsonReader::ReadInt() { 18 SkipWhitespace(); 19 uint8_t c = peek(); 20 uint64_t v = 0; 21 while (c >= '0' && c <= '9') { 22 v = v * 10 + c - '0'; 23 next(); 24 c = peek(); 25 } 26 return v; 27 } 28 29 // No input checking, no unicode, no escaping (not even \"), just read ASCII. 30 std::string JsonReader::ReadString() { 31 SkipWhitespace(); 32 if (peek() != '"') { 33 return ""; 34 } 35 next(); 36 37 std::string s; 38 uint8_t c = take(); 39 while (c != '"') { 40 s.push_back(c); 41 c = take(); 42 } 43 return s; 44 } 45 46 std::string JsonReader::ReadLabel() { 47 std::string s = ReadString(); 48 SkipWhitespace(); 49 EXPECT_EQ(take(), ':'); 50 return s; 51 } 52 53 std::vector<uint8_t> JsonReader::ReadHex() { 54 SkipWhitespace(); 55 uint8_t c = take(); 56 EXPECT_EQ(c, '"'); 57 std::vector<uint8_t> v; 58 c = take(); 59 while (c != '"') { 60 v.push_back(JsonReader::Hex(c) << 4 | JsonReader::Hex(take())); 61 c = take(); 62 } 63 return v; 64 } 65 66 SECOidTag JsonReader::ReadHash() { 67 std::string s = ReadString(); 68 if (s == "SHA-1") { 69 return SEC_OID_SHA1; 70 } 71 if (s == "SHA-224") { 72 return SEC_OID_SHA224; 73 } 74 if (s == "SHA-256") { 75 return SEC_OID_SHA256; 76 } 77 if (s == "SHA-384") { 78 return SEC_OID_SHA384; 79 } 80 if (s == "SHA-512") { 81 return SEC_OID_SHA512; 82 } 83 ADD_FAILURE() << "unsupported hash"; 84 return SEC_OID_UNKNOWN; 85 } 86 87 SECStatus JsonReader::ReadSECStatus() { 88 std::string s = ReadString(); 89 if (s == "SECSuccess") { 90 return SECSuccess; 91 } else if (s == "SECFailure") { 92 return SECFailure; 93 } else if (s == "SECWouldBlock") { 94 return SECWouldBlock; 95 } 96 ADD_FAILURE() << "unknown SECStatus"; 97 return SECFailure; 98 } 99 100 bool JsonReader::ReadBool() { 101 std::string s = ReadString(); 102 if (s == "true") { 103 return true; 104 } else if (s == "false") { 105 return false; 106 } 107 ADD_FAILURE() << "not a bool"; 108 return false; 109 } 110 111 bool JsonReader::NextItem(uint8_t h, uint8_t t) { 112 SkipWhitespace(); 113 switch (uint8_t c = take()) { 114 case ',': 115 return true; 116 case '{': 117 case '[': 118 EXPECT_EQ(c, h); 119 SkipWhitespace(); 120 if (peek() == t) { 121 next(); 122 return false; 123 } 124 return true; 125 case '}': 126 case ']': 127 EXPECT_EQ(c, t); 128 return false; 129 default: 130 ADD_FAILURE() << "Unexpected '" << c << "'"; 131 } 132 return false; 133 } 134 135 void JsonReader::SkipValue() { 136 SkipWhitespace(); 137 138 uint8_t c = take(); 139 if (c == '"') { 140 do { 141 c = take(); 142 } while (c != '"'); 143 144 } else if (c >= '0' && c <= '9') { 145 c = peek(); 146 while (c >= '0' && c <= '9') { 147 next(); 148 c = peek(); 149 } 150 151 } else if (c == '[') { 152 do { 153 SkipWhitespace(); 154 if (peek() != ']') { 155 SkipValue(); 156 } 157 } while (NextItemArray()); 158 159 } else if (c == '{') { 160 do { 161 SkipWhitespace(); 162 if (peek() == '}') { 163 continue; 164 } 165 166 std::string n = ReadLabel(); 167 if (n == "") { 168 break; 169 } 170 SkipValue(); 171 } while (NextItem()); 172 173 } else { 174 ADD_FAILURE() << "No idea how to skip '" << c << "'"; 175 } 176 } 177 178 void JsonReader::TopUp() { 179 if (available_ > i_) { 180 return; 181 } 182 i_ = 0; 183 if (!f_) { 184 return; 185 } 186 PRInt32 res = PR_Read(f_.get(), buf_, sizeof(buf_)); 187 if (res > 0) { 188 available_ = static_cast<size_t>(res); 189 } else { 190 available_ = 1; 191 f_.reset(nullptr); 192 buf_[0] = 0; 193 } 194 } 195 196 void JsonReader::SkipWhitespace() { 197 uint8_t c = peek(); 198 while (c && (c == ' ' || c == '\t' || c == '\r' || c == '\n')) { 199 next(); 200 c = peek(); 201 } 202 } 203 204 // This only handles lowercase. 205 uint8_t JsonReader::Hex(uint8_t c) { 206 if (c >= '0' && c <= '9') { 207 return c - '0'; 208 } 209 EXPECT_TRUE(c >= 'a' && c <= 'f'); 210 return c - 'a' + 10; 211 } 212 213 extern std::string g_source_dir; 214 215 void WycheproofHeader(const std::string& name, const std::string& algorithm, 216 const std::string& schema, 217 std::function<void(JsonReader& r)> group_handler) { 218 std::string basename = name + "_test.json"; 219 std::string dir = ::g_source_dir + "/../common/wycheproof/source_vectors/"; 220 std::cout << "Reading tests from: " << basename << std::endl; 221 222 JsonReader r(dir + basename); 223 while (r.NextItem()) { 224 std::string n = r.ReadLabel(); 225 if (n == "") { 226 break; 227 } 228 if (n == "algorithm") { 229 ASSERT_EQ(algorithm, r.ReadString()); 230 } else if (n == "generatorVersion" || n == "numberOfTests") { 231 r.SkipValue(); 232 } else if (n == "header") { 233 while (r.NextItemArray()) { 234 std::cout << " " << r.ReadString() << std::endl; 235 } 236 } else if (n == "notes") { 237 while (r.NextItem()) { 238 std::string note = r.ReadLabel(); 239 if (note == "") { 240 break; 241 } 242 std::cout << " " << note << ": " << r.ReadString() << std::endl; 243 } 244 } else if (n == "schema") { 245 ASSERT_EQ(schema, r.ReadString()); 246 } else if (n == "testGroups") { 247 while (r.NextItemArray()) { 248 group_handler(r); 249 } 250 } else { 251 FAIL() << "unknown value in header"; 252 } 253 } 254 }