nacl_validation_query.cc 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // Copyright 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/nacl/loader/nacl_validation_query.h"
  5. #include <stdint.h>
  6. #include <string.h>
  7. #include "base/check.h"
  8. #include "components/nacl/loader/nacl_validation_db.h"
  9. #include "crypto/nss_util.h"
  10. #include "native_client/src/public/validation_cache.h"
  11. NaClValidationQueryContext::NaClValidationQueryContext(
  12. NaClValidationDB* db,
  13. const std::string& profile_key,
  14. const std::string& nacl_version)
  15. : db_(db),
  16. profile_key_(profile_key),
  17. nacl_version_(nacl_version) {
  18. // Sanity checks.
  19. CHECK(profile_key.length() >= 8);
  20. CHECK(nacl_version.length() >= 4);
  21. }
  22. NaClValidationQuery* NaClValidationQueryContext::CreateQuery() {
  23. NaClValidationQuery* query = new NaClValidationQuery(db_, profile_key_);
  24. // Changing the version effectively invalidates existing hashes.
  25. query->AddData(nacl_version_);
  26. return query;
  27. }
  28. NaClValidationQuery::NaClValidationQuery(NaClValidationDB* db,
  29. const std::string& profile_key)
  30. : state_(READY),
  31. hasher_(crypto::HMAC::SHA256),
  32. db_(db),
  33. buffer_length_(0) {
  34. CHECK(hasher_.Init(profile_key));
  35. }
  36. void NaClValidationQuery::AddData(const char* data, size_t length) {
  37. CHECK(state_ == READY);
  38. CHECK(buffer_length_ <= sizeof(buffer_));
  39. // Chrome's HMAC class doesn't support incremental signing. Work around
  40. // this by using a (small) temporary buffer to accumulate data.
  41. // Check if there is space in the buffer.
  42. if (buffer_length_ + kDigestLength > sizeof(buffer_)) {
  43. // Hash the buffer to make space.
  44. CompressBuffer();
  45. }
  46. // Hash the input data into the buffer. Assumes that sizeof(buffer_) >=
  47. // kDigestLength * 2 (the buffer can store at least two digests.)
  48. CHECK(hasher_.Sign(base::StringPiece(data, length),
  49. reinterpret_cast<unsigned char*>(buffer_ + buffer_length_),
  50. kDigestLength));
  51. buffer_length_ += kDigestLength;
  52. }
  53. void NaClValidationQuery::AddData(const unsigned char* data, size_t length) {
  54. AddData(reinterpret_cast<const char*>(data), length);
  55. }
  56. void NaClValidationQuery::AddData(const base::StringPiece& data) {
  57. AddData(data.data(), data.length());
  58. }
  59. int NaClValidationQuery::QueryKnownToValidate() {
  60. CHECK(state_ == READY);
  61. // It is suspicious if we have less than a digest's worth of data.
  62. CHECK(buffer_length_ >= kDigestLength);
  63. CHECK(buffer_length_ <= sizeof(buffer_));
  64. state_ = GET_CALLED;
  65. // Ensure the buffer contains only one digest worth of data.
  66. CompressBuffer();
  67. return db_->QueryKnownToValidate(std::string(buffer_, buffer_length_));
  68. }
  69. void NaClValidationQuery::SetKnownToValidate() {
  70. CHECK(state_ == GET_CALLED);
  71. CHECK(buffer_length_ == kDigestLength);
  72. state_ = SET_CALLED;
  73. db_->SetKnownToValidate(std::string(buffer_, buffer_length_));
  74. }
  75. // Reduce the size of the data in the buffer by hashing it and writing it back
  76. // to the buffer.
  77. void NaClValidationQuery::CompressBuffer() {
  78. // Calculate the digest into a temp buffer. It is likely safe to calculate it
  79. // directly back into the buffer, but this is an "accidental" semantic we're
  80. // avoiding depending on.
  81. unsigned char temp[kDigestLength];
  82. CHECK(hasher_.Sign(base::StringPiece(buffer_, buffer_length_), temp,
  83. kDigestLength));
  84. memcpy(buffer_, temp, kDigestLength);
  85. buffer_length_ = kDigestLength;
  86. }
  87. // OO wrappers
  88. static void* CreateQuery(void* handle) {
  89. return static_cast<NaClValidationQueryContext*>(handle)->CreateQuery();
  90. }
  91. static void AddData(void* query, const uint8_t* data, size_t length) {
  92. static_cast<NaClValidationQuery*>(query)->AddData(data, length);
  93. }
  94. static int QueryKnownToValidate(void* query) {
  95. return static_cast<NaClValidationQuery*>(query)->QueryKnownToValidate();
  96. }
  97. static void SetKnownToValidate(void* query) {
  98. static_cast<NaClValidationQuery*>(query)->SetKnownToValidate();
  99. }
  100. static void DestroyQuery(void* query) {
  101. delete static_cast<NaClValidationQuery*>(query);
  102. }
  103. struct NaClValidationCache* CreateValidationCache(
  104. NaClValidationDB* db, const std::string& profile_key,
  105. const std::string& nacl_version) {
  106. NaClValidationCache* cache =
  107. static_cast<NaClValidationCache*>(malloc(sizeof(NaClValidationCache)));
  108. // Make sure any fields introduced in a cross-repo change are zeroed.
  109. memset(cache, 0, sizeof(*cache));
  110. cache->handle = new NaClValidationQueryContext(db, profile_key, nacl_version);
  111. cache->CreateQuery = CreateQuery;
  112. cache->AddData = AddData;
  113. cache->QueryKnownToValidate = QueryKnownToValidate;
  114. cache->SetKnownToValidate = SetKnownToValidate;
  115. cache->DestroyQuery = DestroyQuery;
  116. return cache;
  117. }