15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/internal_auth.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <deque>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base64.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/rand_util.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/lock.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_checker.h"
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/hmac.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef std::map<std::string, std::string> VarValueMap;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Size of a tick in microseconds. This determines upper bound for average
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// number of passports generated per time unit. This bound equals to
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (kMicrosecondsPerSecond / TickUs) calls per second.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int64 kTickUs = 10000;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Verification window size in ticks; that means any passport expires in
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (kVerificationWindowTicks * TickUs / kMicrosecondsPerSecond) seconds.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kVerificationWindowTicks = 2000;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Generation window determines how well we are able to cope with bursts of
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GeneratePassport calls those exceed upper bound on average speed.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kGenerationWindowTicks = 20;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Makes no sense to compare other way round.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMPILE_ASSERT(kGenerationWindowTicks <= kVerificationWindowTicks,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    makes_no_sense_to_have_generation_window_larger_than_verification_one);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We are not optimized for high value of kGenerationWindowTicks.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMPILE_ASSERT(kGenerationWindowTicks < 30, too_large_generation_window);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Regenerate key after this number of ticks.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kKeyRegenerationSoftTicks = 500000;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Reject passports if key has not been regenerated in that number of ticks.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kKeyRegenerationHardTicks = kKeyRegenerationSoftTicks * 2;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Limit for number of accepted var=value pairs. Feel free to bump this limit
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// higher once needed.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kVarsLimit = 16;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Limit for length of caller-supplied strings. Feel free to bump this limit
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// higher once needed.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kStringLengthLimit = 512;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Character used as a separator for construction of message to take HMAC of.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It is critical to validate all caller-supplied data (used to construct
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// message) to be clear of this separator because it could allow attacks.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kItemSeparator = '\n';
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Character used for var=value separation.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kVarValueSeparator = '=';
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kKeySizeInBytes = 128 / 8;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kHMACSizeInBytes = 256 / 8;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Length of base64 string required to encode given number of raw octets.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define BASE64_PER_RAW(X) (X > 0 ? ((X - 1) / 3 + 1) * 4 : 0)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Size of decimal string representing 64-bit tick.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kTickStringLength = 20;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A passport consists of 2 parts: HMAC and tick.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kPassportSize =
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BASE64_PER_RAW(kHMACSizeInBytes) + kTickStringLength;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 GetCurrentTick() {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 tick = base::Time::Now().ToInternalValue() / kTickUs;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tick < kVerificationWindowTicks ||
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tick < kKeyRegenerationHardTicks ||
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tick > kint64max - kKeyRegenerationHardTicks) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return tick;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsDomainSane(const std::string& domain) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !domain.empty() &&
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      domain.size() <= kStringLengthLimit &&
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IsStringUTF8(domain) &&
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      domain.find_first_of(kItemSeparator) == std::string::npos;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsVarSane(const std::string& var) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char kAllowedChars[] =
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "abcdefghijklmnopqrstuvwxyz"
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "0123456789"
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "_";
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  COMPILE_ASSERT(
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sizeof(kAllowedChars) == 26 + 26 + 10 + 1 + 1, some_mess_with_chars);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We must not allow kItemSeparator in anything used as an input to construct
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // message to sign.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(std::find(kAllowedChars, kAllowedChars + arraysize(kAllowedChars),
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kItemSeparator) == kAllowedChars + arraysize(kAllowedChars));
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(std::find(kAllowedChars, kAllowedChars + arraysize(kAllowedChars),
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kVarValueSeparator) == kAllowedChars + arraysize(kAllowedChars));
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !var.empty() &&
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var.size() <= kStringLengthLimit &&
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IsStringASCII(var) &&
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var.find_first_not_of(kAllowedChars) == std::string::npos &&
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !IsAsciiDigit(var[0]);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsValueSane(const std::string& value) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return value.size() <= kStringLengthLimit &&
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IsStringUTF8(value) &&
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      value.find_first_of(kItemSeparator) == std::string::npos;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsVarValueMapSane(const VarValueMap& map) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (map.size() > kVarsLimit)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (VarValueMap::const_iterator it = map.begin(); it != map.end(); ++it) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& var = it->first;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& value = it->second;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!IsVarSane(var) || !IsValueSane(value))
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ConvertVarValueMapToBlob(const VarValueMap& map, std::string* out) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out->clear();
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsVarValueMapSane(map));
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (VarValueMap::const_iterator it = map.begin(); it != map.end(); ++it)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *out += it->first + kVarValueSeparator + it->second + kItemSeparator;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CreatePassport(const std::string& domain,
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const VarValueMap& map,
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    int64 tick,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const crypto::HMAC* engine,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    std::string* out) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(engine);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(out);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsDomainSane(domain));
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsVarValueMapSane(map));
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out->clear();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string result(kPassportSize, '0');
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string blob;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  blob = domain + kItemSeparator;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string tmp;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConvertVarValueMapToBlob(map, &tmp);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  blob += tmp + kItemSeparator + base::Uint64ToString(tick);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string hmac;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* hmac_data = reinterpret_cast<unsigned char*>(
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WriteInto(&hmac, kHMACSizeInBytes + 1));
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!engine->Sign(blob, hmac_data, kHMACSizeInBytes)) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string hmac_base64;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::Base64Encode(hmac, &hmac_base64)) {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (hmac_base64.size() != BASE64_PER_RAW(kHMACSizeInBytes)) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(hmac_base64.size() < result.size());
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::copy(hmac_base64.begin(), hmac_base64.end(), result.begin());
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string tick_decimal = base::Uint64ToString(tick);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(tick_decimal.size() <= kTickStringLength);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::copy(
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tick_decimal.begin(),
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tick_decimal.end(),
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result.begin() + kPassportSize - tick_decimal.size());
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out->swap(result);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chrome {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class InternalAuthVerificationService {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InternalAuthVerificationService()
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : key_change_tick_(0),
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dark_tick_(0) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool VerifyPassport(
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& passport,
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& domain,
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const VarValueMap& map) {
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 current_tick = GetCurrentTick();
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 tick = PreVerifyPassport(passport, domain, current_tick);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (tick == 0)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!IsVarValueMapSane(map))
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string reference_passport;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CreatePassport(domain, map, tick, engine_.get(), &reference_passport);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (passport != reference_passport) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Consider old key.
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (key_change_tick_ + get_verification_window_ticks() < tick) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (old_key_.empty() || old_engine_ == NULL)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CreatePassport(domain, map, tick, old_engine_.get(), &reference_passport);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (passport != reference_passport)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Record used tick to prevent reuse.
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::deque<int64>::iterator it = std::lower_bound(
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        used_ticks_.begin(), used_ticks_.end(), tick);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(it == used_ticks_.end() || *it != tick);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    used_ticks_.insert(it, tick);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Consider pruning |used_ticks_|.
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (used_ticks_.size() > 50) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dark_tick_ = std::max(dark_tick_,
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          current_tick - get_verification_window_ticks());
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      used_ticks_.erase(
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          used_ticks_.begin(),
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          std::lower_bound(used_ticks_.begin(), used_ticks_.end(),
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           dark_tick_ + 1));
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ChangeKey(const std::string& key) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    old_key_.swap(key_);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key_.clear();
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    old_engine_.swap(engine_);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    engine_.reset(NULL);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (key.size() != kKeySizeInBytes)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<crypto::HMAC> new_engine(
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new crypto::HMAC(crypto::HMAC::SHA256));
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!new_engine->Init(key))
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    engine_.swap(new_engine);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key_ = key;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key_change_tick_ = GetCurrentTick();
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int get_verification_window_ticks() {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return InternalAuthVerification::get_verification_window_ticks();
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns tick bound to given passport on success or zero on failure.
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 PreVerifyPassport(
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& passport,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& domain,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 current_tick) {
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (passport.size() != kPassportSize ||
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !IsStringASCII(passport) ||
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !IsDomainSane(domain) ||
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_tick <= dark_tick_ ||
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_tick > key_change_tick_  + kKeyRegenerationHardTicks ||
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        key_.empty() ||
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        engine_ == NULL) {
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Passport consists of 2 parts: first hmac and then tick.
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string tick_decimal =
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        passport.substr(BASE64_PER_RAW(kHMACSizeInBytes));
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(tick_decimal.size() == kTickStringLength);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 tick = 0;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!base::StringToInt64(tick_decimal, &tick) ||
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tick <= dark_tick_ ||
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tick > key_change_tick_ + kKeyRegenerationHardTicks ||
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tick < current_tick - get_verification_window_ticks() ||
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::binary_search(used_ticks_.begin(), used_ticks_.end(), tick)) {
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return tick;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Current key.
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string key_;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We keep previous key in order to be able to verify passports during
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // regeneration time.  Keys are regenerated on a regular basis.
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string old_key_;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Corresponding HMAC engines.
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<crypto::HMAC> engine_;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<crypto::HMAC> old_engine_;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tick at a time of recent key regeneration.
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 key_change_tick_;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Keeps track of ticks of successfully verified passports to prevent their
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reuse. Size of this container is kept reasonably low by purging outdated
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ticks.
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::deque<int64> used_ticks_;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Some ticks before |dark_tick_| were purged from |used_ticks_| container.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // That means that we must not trust any tick less than or equal to dark tick.
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 dark_tick_;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(InternalAuthVerificationService);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chrome
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static base::LazyInstance<chrome::InternalAuthVerificationService>
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_verification_service = LAZY_INSTANCE_INITIALIZER;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static base::LazyInstance<base::Lock>::Leaky
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_verification_service_lock = LAZY_INSTANCE_INITIALIZER;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chrome {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class InternalAuthGenerationService : public base::ThreadChecker {
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InternalAuthGenerationService() : key_regeneration_tick_(0) {
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GenerateNewKey();
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void GenerateNewKey() {
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(CalledOnValidThread());
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<crypto::HMAC> new_engine(new crypto::HMAC(crypto::HMAC::SHA256));
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string key = base::RandBytesAsString(kKeySizeInBytes);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!new_engine->Init(key))
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    engine_.swap(new_engine);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key_regeneration_tick_ = GetCurrentTick();
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_verification_service.Get().ChangeKey(key);
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::fill(key.begin(), key.end(), 0);
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns zero on failure.
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 GetUnusedTick(const std::string& domain) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(CalledOnValidThread());
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (engine_ == NULL) {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!IsDomainSane(domain))
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 current_tick = GetCurrentTick();
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!used_ticks_.empty() && used_ticks_.back() > current_tick)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      current_tick = used_ticks_.back();
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (bool first_iteration = true;; first_iteration = false) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (current_tick < key_regeneration_tick_ + kKeyRegenerationHardTicks)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!first_iteration)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return 0;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GenerateNewKey();
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Forget outdated ticks if any.
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    used_ticks_.erase(
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        used_ticks_.begin(),
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::lower_bound(used_ticks_.begin(), used_ticks_.end(),
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         current_tick - kGenerationWindowTicks + 1));
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(used_ticks_.size() <= kGenerationWindowTicks + 0u);
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (used_ticks_.size() >= kGenerationWindowTicks + 0u) {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Average speed of GeneratePassport calls exceeds limit.
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int64 tick = current_tick;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tick > current_tick - kGenerationWindowTicks;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        --tick) {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int idx = static_cast<int>(used_ticks_.size()) -
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static_cast<int>(current_tick - tick + 1);
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (idx < 0 || used_ticks_[idx] != tick) {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(used_ticks_.end() ==
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            std::find(used_ticks_.begin(), used_ticks_.end(), tick));
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return tick;
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string GeneratePassport(
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& domain, const VarValueMap& map, int64 tick) {
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(CalledOnValidThread());
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (tick == 0) {
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tick = GetUnusedTick(domain);
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (tick == 0)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return std::string();
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!IsVarValueMapSane(map))
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return std::string();
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string result;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CreatePassport(domain, map, tick, engine_.get(), &result);
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    used_ticks_.insert(
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::lower_bound(used_ticks_.begin(), used_ticks_.end(), tick), tick);
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int get_verification_window_ticks() {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return InternalAuthVerification::get_verification_window_ticks();
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<crypto::HMAC> engine_;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 key_regeneration_tick_;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::deque<int64> used_ticks_;
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(InternalAuthGenerationService);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chrome
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static base::LazyInstance<chrome::InternalAuthGenerationService>
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_generation_service = LAZY_INSTANCE_INITIALIZER;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chrome {
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InternalAuthVerification::VerifyPassport(
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& passport,
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& domain,
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const VarValueMap& var_value_map) {
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock alk(g_verification_service_lock.Get());
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_verification_service.Get().VerifyPassport(
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      passport, domain, var_value_map);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InternalAuthVerification::ChangeKey(const std::string& key) {
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock alk(g_verification_service_lock.Get());
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_verification_service.Get().ChangeKey(key);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int InternalAuthVerification::get_verification_window_ticks() {
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int candidate = kVerificationWindowTicks;
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (verification_window_seconds_ > 0)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    candidate = verification_window_seconds_ *
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Time::kMicrosecondsPerSecond / kTickUs;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::max(1, std::min(candidate, kVerificationWindowTicks));
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int InternalAuthVerification::verification_window_seconds_ = 0;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string InternalAuthGeneration::GeneratePassport(
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& domain, const VarValueMap& var_value_map) {
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_generation_service.Get().GeneratePassport(domain, var_value_map, 0);
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InternalAuthGeneration::GenerateNewKey() {
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_generation_service.Get().GenerateNewKey();
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chrome
478