summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk5
-rw-r--r--applypatch/Android.mk15
-rw-r--r--applypatch/imgdiff.cpp185
-rw-r--r--applypatch/imgpatch.cpp25
-rw-r--r--applypatch/utils.cpp65
-rw-r--r--applypatch/utils.h31
-rw-r--r--asn1_decoder.cpp12
-rw-r--r--asn1_decoder.h6
-rw-r--r--install.cpp40
-rw-r--r--minui/events.cpp2
-rw-r--r--tests/Android.mk10
-rw-r--r--tests/component/imgdiff_test.cpp9
-rw-r--r--tests/component/updater_test.cpp120
-rw-r--r--tests/component/verifier_test.cpp208
-rw-r--r--tests/unit/asn1_decoder_test.cpp28
-rw-r--r--ui.cpp1
-rw-r--r--updater/Android.mk20
-rw-r--r--updater/blockimg.cpp269
-rw-r--r--verifier.cpp422
-rw-r--r--verifier.h14
20 files changed, 672 insertions, 815 deletions
diff --git a/Android.mk b/Android.mk
index 58b8a2240..f8e5ac24a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -144,12 +144,15 @@ include $(BUILD_EXECUTABLE)
# libverifier (static library)
# ===============================
include $(CLEAR_VARS)
+LOCAL_CLANG := true
LOCAL_MODULE := libverifier
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
asn1_decoder.cpp \
- verifier.cpp
+ verifier.cpp \
+ ui.cpp
LOCAL_STATIC_LIBRARIES := \
+ libminui \
libcrypto_utils \
libcrypto \
libbase
diff --git a/applypatch/Android.mk b/applypatch/Android.mk
index a7412d238..8be5c36be 100644
--- a/applypatch/Android.mk
+++ b/applypatch/Android.mk
@@ -21,7 +21,8 @@ LOCAL_SRC_FILES := \
applypatch.cpp \
bspatch.cpp \
freecache.cpp \
- imgpatch.cpp
+ imgpatch.cpp \
+ utils.cpp
LOCAL_MODULE := libapplypatch
LOCAL_MODULE_TAGS := eng
LOCAL_C_INCLUDES := \
@@ -45,7 +46,8 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
bspatch.cpp \
- imgpatch.cpp
+ imgpatch.cpp \
+ utils.cpp
LOCAL_MODULE := libimgpatch
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include \
@@ -54,7 +56,6 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_STATIC_LIBRARIES := \
libcrypto \
libbspatch \
- libbase \
libbz \
libz
LOCAL_CFLAGS := \
@@ -67,7 +68,8 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
bspatch.cpp \
- imgpatch.cpp
+ imgpatch.cpp \
+ utils.cpp
LOCAL_MODULE := libimgpatch
LOCAL_MODULE_HOST_OS := linux
LOCAL_C_INCLUDES := \
@@ -77,7 +79,6 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_STATIC_LIBRARIES := \
libcrypto \
libbspatch \
- libbase \
libbz \
libz
LOCAL_CFLAGS := \
@@ -122,7 +123,9 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
-libimgdiff_src_files := imgdiff.cpp
+libimgdiff_src_files := \
+ imgdiff.cpp \
+ utils.cpp
# libbsdiff is compiled with -D_FILE_OFFSET_BITS=64.
libimgdiff_cflags := \
diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp
index 41d73ab98..fba74e836 100644
--- a/applypatch/imgdiff.cpp
+++ b/applypatch/imgdiff.cpp
@@ -145,22 +145,12 @@
#include <bsdiff.h>
#include <zlib.h>
+#include "utils.h"
+
using android::base::get_unaligned;
static constexpr auto BUFFER_SIZE = 0x8000;
-// If we use this function to write the offset and length (type size_t), their values should not
-// exceed 2^63; because the signed bit will be casted away.
-static inline bool Write8(int fd, int64_t value) {
- return android::base::WriteFully(fd, &value, sizeof(int64_t));
-}
-
-// Similarly, the value should not exceed 2^31 if we are casting from size_t (e.g. target chunk
-// size).
-static inline bool Write4(int fd, int32_t value) {
- return android::base::WriteFully(fd, &value, sizeof(int32_t));
-}
-
class ImageChunk {
public:
static constexpr auto WINDOWBITS = -15; // 32kb window; negative to indicate a raw stream.
@@ -173,12 +163,11 @@ class ImageChunk {
start_(start),
input_file_ptr_(file_content),
raw_data_len_(raw_data_len),
+ entry_name_(""),
compress_level_(6),
source_start_(0),
source_len_(0),
- source_uncompressed_len_(0) {
- CHECK(file_content != nullptr) << "input file container can't be nullptr";
- }
+ source_uncompressed_len_(0) {}
int GetType() const {
return type_;
@@ -210,8 +199,7 @@ class ImageChunk {
}
size_t GetHeaderSize(size_t patch_size) const;
- // Return the offset of the next patch into the patch data.
- size_t WriteHeaderToFd(int fd, const std::vector<uint8_t>& patch, size_t offset);
+ size_t WriteHeaderToFile(FILE* f, const std::vector<uint8_t> patch, size_t offset);
/*
* Cause a gzip chunk to be treated as a normal chunk (ie, as a blob
@@ -234,9 +222,9 @@ class ImageChunk {
void MergeAdjacentNormal(const ImageChunk& other);
private:
- int type_; // CHUNK_NORMAL, CHUNK_DEFLATE, CHUNK_RAW
- size_t start_; // offset of chunk in the original input file
- const std::vector<uint8_t>* input_file_ptr_; // ptr to the full content of original input file
+ int type_; // CHUNK_NORMAL, CHUNK_DEFLATE, CHUNK_RAW
+ size_t start_; // offset of chunk in the original input file
+ const std::vector<uint8_t>* input_file_ptr_; // pointer to the full content of original input file
size_t raw_data_len_;
// --- for CHUNK_DEFLATE chunks only: ---
@@ -292,11 +280,11 @@ void ImageChunk::SetSourceInfo(const ImageChunk& src) {
}
void ImageChunk::SetEntryName(std::string entryname) {
- entry_name_ = std::move(entryname);
+ entry_name_ = entryname;
}
void ImageChunk::SetUncompressedData(std::vector<uint8_t> data) {
- uncompressed_data_ = std::move(data);
+ uncompressed_data_ = data;
}
bool ImageChunk::SetBonusData(const std::vector<uint8_t>& bonus_data) {
@@ -307,7 +295,7 @@ bool ImageChunk::SetBonusData(const std::vector<uint8_t>& bonus_data) {
return true;
}
-// Convert CHUNK_NORMAL & CHUNK_DEFLATE to CHUNK_RAW if the target size is
+// Convert CHUNK_NORMAL & CHUNK_DEFLATE to CHUNK_RAW if the terget size is
// smaller. Also take the header size into account during size comparison.
bool ImageChunk::ChangeChunkToRaw(size_t patch_size) {
if (type_ == CHUNK_RAW) {
@@ -322,7 +310,6 @@ bool ImageChunk::ChangeChunkToRaw(size_t patch_size) {
void ImageChunk::ChangeDeflateChunkToNormal() {
if (type_ != CHUNK_DEFLATE) return;
type_ = CHUNK_NORMAL;
- entry_name_.clear();
uncompressed_data_.clear();
}
@@ -330,7 +317,7 @@ void ImageChunk::ChangeDeflateChunkToNormal() {
// header_type 4 bytes
// CHUNK_NORMAL 8*3 = 24 bytes
// CHUNK_DEFLATE 8*5 + 4*5 = 60 bytes
-// CHUNK_RAW 4 bytes + patch_size
+// CHUNK_RAW 4 bytes
size_t ImageChunk::GetHeaderSize(size_t patch_size) const {
switch (type_) {
case CHUNK_NORMAL:
@@ -340,43 +327,43 @@ size_t ImageChunk::GetHeaderSize(size_t patch_size) const {
case CHUNK_RAW:
return 4 + 4 + patch_size;
default:
- CHECK(false) << "unexpected chunk type: " << type_; // Should not reach here.
+ printf("unexpected chunk type: %d\n", type_); // should not reach here.
+ CHECK(false);
return 0;
}
}
-size_t ImageChunk::WriteHeaderToFd(int fd, const std::vector<uint8_t>& patch, size_t offset) {
- Write4(fd, type_);
+size_t ImageChunk::WriteHeaderToFile(FILE* f, const std::vector<uint8_t> patch, size_t offset) {
+ Write4(type_, f);
switch (type_) {
case CHUNK_NORMAL:
printf("normal (%10zu, %10zu) %10zu\n", start_, raw_data_len_, patch.size());
- Write8(fd, static_cast<int64_t>(source_start_));
- Write8(fd, static_cast<int64_t>(source_len_));
- Write8(fd, static_cast<int64_t>(offset));
+ Write8(source_start_, f);
+ Write8(source_len_, f);
+ Write8(offset, f);
return offset + patch.size();
case CHUNK_DEFLATE:
printf("deflate (%10zu, %10zu) %10zu %s\n", start_, raw_data_len_, patch.size(),
entry_name_.c_str());
- Write8(fd, static_cast<int64_t>(source_start_));
- Write8(fd, static_cast<int64_t>(source_len_));
- Write8(fd, static_cast<int64_t>(offset));
- Write8(fd, static_cast<int64_t>(source_uncompressed_len_));
- Write8(fd, static_cast<int64_t>(uncompressed_data_.size()));
- Write4(fd, compress_level_);
- Write4(fd, METHOD);
- Write4(fd, WINDOWBITS);
- Write4(fd, MEMLEVEL);
- Write4(fd, STRATEGY);
+ Write8(source_start_, f);
+ Write8(source_len_, f);
+ Write8(offset, f);
+ Write8(source_uncompressed_len_, f);
+ Write8(uncompressed_data_.size(), f);
+ Write4(compress_level_, f);
+ Write4(METHOD, f);
+ Write4(WINDOWBITS, f);
+ Write4(MEMLEVEL, f);
+ Write4(STRATEGY, f);
return offset + patch.size();
case CHUNK_RAW:
printf("raw (%10zu, %10zu)\n", start_, raw_data_len_);
- Write4(fd, static_cast<int32_t>(patch.size()));
- if (!android::base::WriteFully(fd, patch.data(), patch.size())) {
- CHECK(false) << "failed to write " << patch.size() <<" bytes patch";
- }
+ Write4(patch.size(), f);
+ fwrite(patch.data(), 1, patch.size(), f);
return offset;
default:
- CHECK(false) << "unexpected chunk type: " << type_;
+ printf("unexpected chunk type: %d\n", type_);
+ CHECK(false);
return offset;
}
}
@@ -493,21 +480,20 @@ static bool GetZipFileSize(const std::vector<uint8_t>& zip_file, size_t* input_f
static bool ReadZip(const char* filename, std::vector<ImageChunk>* chunks,
std::vector<uint8_t>* zip_file, bool include_pseudo_chunk) {
- CHECK(chunks != nullptr && zip_file != nullptr);
-
- android::base::unique_fd fd(open(filename, O_RDONLY));
- if (fd == -1) {
- printf("failed to open \"%s\" %s\n", filename, strerror(errno));
- return false;
- }
+ CHECK(zip_file != nullptr);
struct stat st;
- if (fstat(fd, &st) != 0) {
+ if (stat(filename, &st) != 0) {
printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
return false;
}
size_t sz = static_cast<size_t>(st.st_size);
zip_file->resize(sz);
+ android::base::unique_fd fd(open(filename, O_RDONLY));
+ if (fd == -1) {
+ printf("failed to open \"%s\" %s\n", filename, strerror(errno));
+ return false;
+ }
if (!android::base::ReadFully(fd, zip_file->data(), sz)) {
printf("failed to read \"%s\" %s\n", filename, strerror(errno));
return false;
@@ -610,21 +596,20 @@ static bool ReadZip(const char* filename, std::vector<ImageChunk>* chunks,
// Read the given file and break it up into chunks, and putting the data in to a vector.
static bool ReadImage(const char* filename, std::vector<ImageChunk>* chunks,
std::vector<uint8_t>* img) {
- CHECK(chunks != nullptr && img != nullptr);
-
- android::base::unique_fd fd(open(filename, O_RDONLY));
- if (fd == -1) {
- printf("failed to open \"%s\" %s\n", filename, strerror(errno));
- return false;
- }
+ CHECK(img != nullptr);
struct stat st;
- if (fstat(fd, &st) != 0) {
+ if (stat(filename, &st) != 0) {
printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
return false;
}
size_t sz = static_cast<size_t>(st.st_size);
img->resize(sz);
+ android::base::unique_fd fd(open(filename, O_RDONLY));
+ if (fd == -1) {
+ printf("failed to open \"%s\" %s\n", filename, strerror(errno));
+ return false;
+ }
if (!android::base::ReadFully(fd, img->data(), sz)) {
printf("failed to read \"%s\" %s\n", filename, strerror(errno));
return false;
@@ -633,8 +618,9 @@ static bool ReadImage(const char* filename, std::vector<ImageChunk>* chunks,
size_t pos = 0;
while (pos < sz) {
- // 0x00 no header flags, 0x08 deflate compression, 0x1f8b gzip magic number
- if (sz - pos >= 4 && get_unaligned<uint32_t>(img->data() + pos) == 0x00088b1f) {
+ if (sz - pos >= 4 && img->at(pos) == 0x1f && img->at(pos + 1) == 0x8b &&
+ img->at(pos + 2) == 0x08 && // deflate compression
+ img->at(pos + 3) == 0x00) { // no header flags
// 'pos' is the offset of the start of a gzip chunk.
size_t chunk_offset = pos;
@@ -709,7 +695,7 @@ static bool ReadImage(const char* filename, std::vector<ImageChunk>* chunks,
// the uncompressed data. Double-check to make sure that it
// matches the size of the data we got when we actually did
// the decompression.
- size_t footer_size = get_unaligned<uint32_t>(img->data() + pos - 4);
+ size_t footer_size = Read4(img->data() + pos - 4);
if (footer_size != body.DataLengthForPatch()) {
printf("Error: footer size %zu != decompressed size %zu\n", footer_size,
body.GetRawDataLength());
@@ -722,8 +708,9 @@ static bool ReadImage(const char* filename, std::vector<ImageChunk>* chunks,
// Scan forward until we find a gzip header.
size_t data_len = 0;
while (data_len + pos < sz) {
- if (data_len + pos + 4 <= sz &&
- get_unaligned<uint32_t>(img->data() + pos + data_len) == 0x00088b1f) {
+ if (data_len + pos + 4 <= sz && img->at(pos + data_len) == 0x1f &&
+ img->at(pos + data_len + 1) == 0x8b && img->at(pos + data_len + 2) == 0x08 &&
+ img->at(pos + data_len + 3) == 0x00) {
break;
}
data_len++;
@@ -772,19 +759,13 @@ static bool MakePatch(const ImageChunk* src, ImageChunk* tgt, std::vector<uint8_
return false;
}
- android::base::unique_fd patch_fd(open(ptemp, O_RDONLY));
- if (patch_fd == -1) {
- printf("failed to open %s: %s\n", ptemp, strerror(errno));
- return false;
- }
struct stat st;
- if (fstat(patch_fd, &st) != 0) {
+ if (stat(ptemp, &st) != 0) {
printf("failed to stat patch file %s: %s\n", ptemp, strerror(errno));
return false;
}
size_t sz = static_cast<size_t>(st.st_size);
- // Change the chunk type to raw if the patch takes less space that way.
if (tgt->ChangeChunkToRaw(sz)) {
unlink(ptemp);
size_t patch_size = tgt->DataLengthForPatch();
@@ -792,6 +773,12 @@ static bool MakePatch(const ImageChunk* src, ImageChunk* tgt, std::vector<uint8_
std::copy(tgt->DataForPatch(), tgt->DataForPatch() + patch_size, patch_data->begin());
return true;
}
+
+ android::base::unique_fd patch_fd(open(ptemp, O_RDONLY));
+ if (patch_fd == -1) {
+ printf("failed to open %s: %s\n", ptemp, strerror(errno));
+ return false;
+ }
patch_data->resize(sz);
if (!android::base::ReadFully(patch_fd, patch_data->data(), sz)) {
printf("failed to read \"%s\" %s\n", ptemp, strerror(errno));
@@ -858,19 +845,18 @@ int imgdiff(int argc, const char** argv) {
std::vector<uint8_t> bonus_data;
if (argc >= 3 && strcmp(argv[1], "-b") == 0) {
- android::base::unique_fd fd(open(argv[2], O_RDONLY));
- if (fd == -1) {
- printf("failed to open bonus file %s: %s\n", argv[2], strerror(errno));
- return 1;
- }
struct stat st;
- if (fstat(fd, &st) != 0) {
+ if (stat(argv[2], &st) != 0) {
printf("failed to stat bonus file %s: %s\n", argv[2], strerror(errno));
return 1;
}
-
size_t bonus_size = st.st_size;
bonus_data.resize(bonus_size);
+ android::base::unique_fd fd(open(argv[2], O_RDONLY));
+ if (fd == -1) {
+ printf("failed to open bonus file %s: %s\n", argv[2], strerror(errno));
+ return 1;
+ }
if (!android::base::ReadFully(fd, bonus_data.data(), bonus_size)) {
printf("failed to read bonus file %s: %s\n", argv[2], strerror(errno));
return 1;
@@ -1013,15 +999,9 @@ int imgdiff(int argc, const char** argv) {
ImageChunk* src;
if (tgt_chunks[i].GetType() == CHUNK_DEFLATE &&
(src = FindChunkByName(tgt_chunks[i].GetEntryName(), src_chunks))) {
- if (!MakePatch(src, &tgt_chunks[i], &patch_data[i], nullptr)) {
- printf("Failed to generate patch for target chunk %zu: ", i);
- return 1;
- }
+ MakePatch(src, &tgt_chunks[i], &patch_data[i], nullptr);
} else {
- if (!MakePatch(&src_chunks[0], &tgt_chunks[i], &patch_data[i], &bsdiff_cache)) {
- printf("Failed to generate patch for target chunk %zu: ", i);
- return 1;
- }
+ MakePatch(&src_chunks[0], &tgt_chunks[i], &patch_data[i], &bsdiff_cache);
}
} else {
if (i == 1 && !bonus_data.empty()) {
@@ -1029,10 +1009,7 @@ int imgdiff(int argc, const char** argv) {
src_chunks[i].SetBonusData(bonus_data);
}
- if (!MakePatch(&src_chunks[i], &tgt_chunks[i], &patch_data[i], nullptr)) {
- printf("Failed to generate patch for target chunk %zu: ", i);
- return 1;
- }
+ MakePatch(&src_chunks[i], &tgt_chunks[i], &patch_data[i], nullptr);
}
printf("patch %3zu is %zu bytes (of %zu)\n", i, patch_data[i].size(),
src_chunks[i].GetRawDataLength());
@@ -1053,32 +1030,28 @@ int imgdiff(int argc, const char** argv) {
size_t offset = total_header_size;
- android::base::unique_fd patch_fd(open(argv[3], O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR));
- if (patch_fd == -1) {
+ FILE* f = fopen(argv[3], "wb");
+ if (f == nullptr) {
printf("failed to open \"%s\": %s\n", argv[3], strerror(errno));
- return 1;
}
// Write out the headers.
- if (!android::base::WriteStringToFd("IMGDIFF2", patch_fd)) {
- printf("failed to write \"IMGDIFF2\" to \"%s\": %s\n", argv[3], strerror(errno));
- return 1;
- }
- Write4(patch_fd, static_cast<int32_t>(tgt_chunks.size()));
+
+ fwrite("IMGDIFF2", 1, 8, f);
+ Write4(static_cast<int32_t>(tgt_chunks.size()), f);
for (size_t i = 0; i < tgt_chunks.size(); ++i) {
printf("chunk %zu: ", i);
- offset = tgt_chunks[i].WriteHeaderToFd(patch_fd, patch_data[i], offset);
+ offset = tgt_chunks[i].WriteHeaderToFile(f, patch_data[i], offset);
}
// Append each chunk's bsdiff patch, in order.
for (size_t i = 0; i < tgt_chunks.size(); ++i) {
if (tgt_chunks[i].GetType() != CHUNK_RAW) {
- if (!android::base::WriteFully(patch_fd, patch_data[i].data(), patch_data[i].size())) {
- CHECK(false) << "failed to write " << patch_data[i].size() << " bytes patch for chunk "
- << i;
- }
+ fwrite(patch_data[i].data(), 1, patch_data[i].size(), f);
}
}
+ fclose(f);
+
return 0;
}
diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp
index adcc61fd6..8f4a2a42b 100644
--- a/applypatch/imgpatch.cpp
+++ b/applypatch/imgpatch.cpp
@@ -31,17 +31,10 @@
#include <applypatch/applypatch.h>
#include <applypatch/imgdiff.h>
-#include <android-base/memory.h>
#include <openssl/sha.h>
#include <zlib.h>
-static inline int64_t Read8(const void *address) {
- return android::base::get_unaligned<int64_t>(address);
-}
-
-static inline int32_t Read4(const void *address) {
- return android::base::get_unaligned<int32_t>(address);
-}
+#include "utils.h"
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
const unsigned char* patch_data, ssize_t patch_size,
@@ -93,9 +86,9 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value
return -1;
}
- size_t src_start = static_cast<size_t>(Read8(normal_header));
- size_t src_len = static_cast<size_t>(Read8(normal_header + 8));
- size_t patch_offset = static_cast<size_t>(Read8(normal_header + 16));
+ size_t src_start = Read8(normal_header);
+ size_t src_len = Read8(normal_header + 8);
+ size_t patch_offset = Read8(normal_header + 16);
if (src_start + src_len > static_cast<size_t>(old_size)) {
printf("source data too short\n");
@@ -132,11 +125,11 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value
return -1;
}
- size_t src_start = static_cast<size_t>(Read8(deflate_header));
- size_t src_len = static_cast<size_t>(Read8(deflate_header + 8));
- size_t patch_offset = static_cast<size_t>(Read8(deflate_header + 16));
- size_t expanded_len = static_cast<size_t>(Read8(deflate_header + 24));
- size_t target_len = static_cast<size_t>(Read8(deflate_header + 32));
+ size_t src_start = Read8(deflate_header);
+ size_t src_len = Read8(deflate_header + 8);
+ size_t patch_offset = Read8(deflate_header + 16);
+ size_t expanded_len = Read8(deflate_header + 24);
+ size_t target_len = Read8(deflate_header + 32);
int level = Read4(deflate_header + 40);
int method = Read4(deflate_header + 44);
int windowBits = Read4(deflate_header + 48);
diff --git a/applypatch/utils.cpp b/applypatch/utils.cpp
new file mode 100644
index 000000000..450dc8d76
--- /dev/null
+++ b/applypatch/utils.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#include "utils.h"
+
+/** Write a 4-byte value to f in little-endian order. */
+void Write4(int value, FILE* f) {
+ fputc(value & 0xff, f);
+ fputc((value >> 8) & 0xff, f);
+ fputc((value >> 16) & 0xff, f);
+ fputc((value >> 24) & 0xff, f);
+}
+
+/** Write an 8-byte value to f in little-endian order. */
+void Write8(int64_t value, FILE* f) {
+ fputc(value & 0xff, f);
+ fputc((value >> 8) & 0xff, f);
+ fputc((value >> 16) & 0xff, f);
+ fputc((value >> 24) & 0xff, f);
+ fputc((value >> 32) & 0xff, f);
+ fputc((value >> 40) & 0xff, f);
+ fputc((value >> 48) & 0xff, f);
+ fputc((value >> 56) & 0xff, f);
+}
+
+int Read2(const void* pv) {
+ const unsigned char* p = reinterpret_cast<const unsigned char*>(pv);
+ return (int)(((unsigned int)p[1] << 8) |
+ (unsigned int)p[0]);
+}
+
+int Read4(const void* pv) {
+ const unsigned char* p = reinterpret_cast<const unsigned char*>(pv);
+ return (int)(((unsigned int)p[3] << 24) |
+ ((unsigned int)p[2] << 16) |
+ ((unsigned int)p[1] << 8) |
+ (unsigned int)p[0]);
+}
+
+int64_t Read8(const void* pv) {
+ const unsigned char* p = reinterpret_cast<const unsigned char*>(pv);
+ return (int64_t)(((uint64_t)p[7] << 56) |
+ ((uint64_t)p[6] << 48) |
+ ((uint64_t)p[5] << 40) |
+ ((uint64_t)p[4] << 32) |
+ ((uint64_t)p[3] << 24) |
+ ((uint64_t)p[2] << 16) |
+ ((uint64_t)p[1] << 8) |
+ (uint64_t)p[0]);
+}
diff --git a/applypatch/utils.h b/applypatch/utils.h
new file mode 100644
index 000000000..c7c8e90e2
--- /dev/null
+++ b/applypatch/utils.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _BUILD_TOOLS_APPLYPATCH_UTILS_H
+#define _BUILD_TOOLS_APPLYPATCH_UTILS_H
+
+#include <inttypes.h>
+#include <stdio.h>
+
+// Read and write little-endian values of various sizes.
+
+void Write4(int value, FILE* f);
+void Write8(int64_t value, FILE* f);
+int Read2(const void* p);
+int Read4(const void* p);
+int64_t Read8(const void* p);
+
+#endif // _BUILD_TOOLS_APPLYPATCH_UTILS_H
diff --git a/asn1_decoder.cpp b/asn1_decoder.cpp
index ca4ee5267..e7aef781c 100644
--- a/asn1_decoder.cpp
+++ b/asn1_decoder.cpp
@@ -22,9 +22,9 @@
typedef struct asn1_context {
- size_t length;
- const uint8_t* p;
- int app_type;
+ size_t length;
+ uint8_t* p;
+ int app_type;
} asn1_context_t;
@@ -38,7 +38,7 @@ static const int kTagSequence = 0x30;
static const int kTagSet = 0x31;
static const int kTagConstructed = 0xA0;
-asn1_context_t* asn1_context_new(const uint8_t* buffer, size_t length) {
+asn1_context_t* asn1_context_new(uint8_t* buffer, size_t length) {
asn1_context_t* ctx = (asn1_context_t*) calloc(1, sizeof(asn1_context_t));
if (ctx == NULL) {
return NULL;
@@ -168,7 +168,7 @@ bool asn1_sequence_next(asn1_context_t* ctx) {
return true;
}
-bool asn1_oid_get(asn1_context_t* ctx, const uint8_t** oid, size_t* length) {
+bool asn1_oid_get(asn1_context_t* ctx, uint8_t** oid, size_t* length) {
if (get_byte(ctx) != kTagOid) {
return false;
}
@@ -179,7 +179,7 @@ bool asn1_oid_get(asn1_context_t* ctx, const uint8_t** oid, size_t* length) {
return true;
}
-bool asn1_octet_string_get(asn1_context_t* ctx, const uint8_t** octet_string, size_t* length) {
+bool asn1_octet_string_get(asn1_context_t* ctx, uint8_t** octet_string, size_t* length) {
if (get_byte(ctx) != kTagOctetString) {
return false;
}
diff --git a/asn1_decoder.h b/asn1_decoder.h
index fbd118f90..b17141c44 100644
--- a/asn1_decoder.h
+++ b/asn1_decoder.h
@@ -22,7 +22,7 @@
typedef struct asn1_context asn1_context_t;
-asn1_context_t* asn1_context_new(const uint8_t* buffer, size_t length);
+asn1_context_t* asn1_context_new(uint8_t* buffer, size_t length);
void asn1_context_free(asn1_context_t* ctx);
asn1_context_t* asn1_constructed_get(asn1_context_t* ctx);
bool asn1_constructed_skip_all(asn1_context_t* ctx);
@@ -30,7 +30,7 @@ int asn1_constructed_type(asn1_context_t* ctx);
asn1_context_t* asn1_sequence_get(asn1_context_t* ctx);
asn1_context_t* asn1_set_get(asn1_context_t* ctx);
bool asn1_sequence_next(asn1_context_t* seq);
-bool asn1_oid_get(asn1_context_t* ctx, const uint8_t** oid, size_t* length);
-bool asn1_octet_string_get(asn1_context_t* ctx, const uint8_t** octet_string, size_t* length);
+bool asn1_oid_get(asn1_context_t* ctx, uint8_t** oid, size_t* length);
+bool asn1_octet_string_get(asn1_context_t* ctx, uint8_t** octet_string, size_t* length);
#endif /* ASN1_DECODER_H_ */
diff --git a/install.cpp b/install.cpp
index a256d9b13..f51bbf05c 100644
--- a/install.cpp
+++ b/install.cpp
@@ -27,7 +27,6 @@
#include <unistd.h>
#include <chrono>
-#include <functional>
#include <limits>
#include <map>
#include <string>
@@ -579,24 +578,23 @@ install_package(const char* path, bool* wipe_cache, const char* install_file,
}
bool verify_package(const unsigned char* package_data, size_t package_size) {
- std::vector<Certificate> loadedKeys;
- if (!load_keys(PUBLIC_KEYS_FILE, loadedKeys)) {
- LOG(ERROR) << "Failed to load keys";
- return false;
- }
- LOG(INFO) << loadedKeys.size() << " key(s) loaded from " << PUBLIC_KEYS_FILE;
-
- // Verify package.
- ui->Print("Verifying update package...\n");
- auto t0 = std::chrono::system_clock::now();
- int err = verify_file(package_data, package_size, loadedKeys,
- std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1));
- std::chrono::duration<double> duration = std::chrono::system_clock::now() - t0;
- ui->Print("Update package verification took %.1f s (result %d).\n", duration.count(), err);
- if (err != VERIFY_SUCCESS) {
- LOG(ERROR) << "Signature verification failed";
- LOG(ERROR) << "error: " << kZipVerificationFailure;
- return false;
- }
- return true;
+ std::vector<Certificate> loadedKeys;
+ if (!load_keys(PUBLIC_KEYS_FILE, loadedKeys)) {
+ LOG(ERROR) << "Failed to load keys";
+ return false;
+ }
+ LOG(INFO) << loadedKeys.size() << " key(s) loaded from " << PUBLIC_KEYS_FILE;
+
+ // Verify package.
+ ui->Print("Verifying update package...\n");
+ auto t0 = std::chrono::system_clock::now();
+ int err = verify_file(const_cast<unsigned char*>(package_data), package_size, loadedKeys);
+ std::chrono::duration<double> duration = std::chrono::system_clock::now() - t0;
+ ui->Print("Update package verification took %.1f s (result %d).\n", duration.count(), err);
+ if (err != VERIFY_SUCCESS) {
+ LOG(ERROR) << "Signature verification failed";
+ LOG(ERROR) << "error: " << kZipVerificationFailure;
+ return false;
+ }
+ return true;
}
diff --git a/minui/events.cpp b/minui/events.cpp
index 0e1fd44a0..fa44033d2 100644
--- a/minui/events.cpp
+++ b/minui/events.cpp
@@ -24,8 +24,6 @@
#include <sys/ioctl.h>
#include <unistd.h>
-#include <functional>
-
#include "minui/minui.h"
#define MAX_DEVICES 16
diff --git a/tests/Android.mk b/tests/Android.mk
index ff6e14c9b..ec971b38c 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -81,10 +81,7 @@ include $(BUILD_NATIVE_TEST)
# Component tests
include $(CLEAR_VARS)
-LOCAL_CFLAGS := \
- -Werror \
- -D_FILE_OFFSET_BITS=64
-
+LOCAL_CFLAGS := -Werror
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE := recovery_component_test
LOCAL_C_INCLUDES := bootable/recovery
@@ -120,6 +117,7 @@ LOCAL_STATIC_LIBRARIES := \
libupdater \
libbootloader_message \
libverifier \
+ libminui \
libotautil \
libmounts \
libdivsufsort \
@@ -138,10 +136,6 @@ LOCAL_STATIC_LIBRARIES := \
libz \
libbase \
libtune2fs \
- libfec \
- libfec_rs \
- libsquashfs_utils \
- libcutils \
$(tune2fs_static_libraries)
testdata_files := $(call find-subdir-files, testdata/*)
diff --git a/tests/component/imgdiff_test.cpp b/tests/component/imgdiff_test.cpp
index 2f648501c..be2dd385b 100644
--- a/tests/component/imgdiff_test.cpp
+++ b/tests/component/imgdiff_test.cpp
@@ -18,14 +18,13 @@
#include <vector>
#include <android-base/file.h>
-#include <android-base/memory.h>
#include <android-base/test_utils.h>
#include <applypatch/imgdiff.h>
#include <applypatch/imgpatch.h>
#include <gtest/gtest.h>
#include <ziparchive/zip_writer.h>
-using android::base::get_unaligned;
+#include "applypatch/utils.h"
static ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) {
std::string* s = static_cast<std::string*>(token);
@@ -42,7 +41,7 @@ static void verify_patch_header(const std::string& patch, size_t* num_normal, si
ASSERT_GE(size, 12U);
ASSERT_EQ("IMGDIFF2", std::string(data, 8));
- const int num_chunks = get_unaligned<int32_t>(data + 8);
+ const int num_chunks = Read4(data + 8);
ASSERT_GE(num_chunks, 0);
size_t normal = 0;
@@ -52,7 +51,7 @@ static void verify_patch_header(const std::string& patch, size_t* num_normal, si
size_t pos = 12;
for (int i = 0; i < num_chunks; ++i) {
ASSERT_LE(pos + 4, size);
- int type = get_unaligned<int32_t>(data + pos);
+ int type = Read4(data + pos);
pos += 4;
if (type == CHUNK_NORMAL) {
pos += 24;
@@ -60,7 +59,7 @@ static void verify_patch_header(const std::string& patch, size_t* num_normal, si
normal++;
} else if (type == CHUNK_RAW) {
ASSERT_LE(pos + 4, size);
- ssize_t data_len = get_unaligned<int32_t>(data + pos);
+ ssize_t data_len = Read4(data + pos);
ASSERT_GT(data_len, 0);
pos += 4 + data_len;
ASSERT_LE(pos, size);
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
index 4f8349e2f..8c4bdbaa4 100644
--- a/tests/component/updater_test.cpp
+++ b/tests/component/updater_test.cpp
@@ -20,7 +20,6 @@
#include <unistd.h>
#include <string>
-#include <vector>
#include <android-base/file.h>
#include <android-base/properties.h>
@@ -28,17 +27,12 @@
#include <android-base/strings.h>
#include <android-base/test_utils.h>
#include <bootloader_message/bootloader_message.h>
-#include <bsdiff.h>
#include <gtest/gtest.h>
#include <ziparchive/zip_archive.h>
-#include <ziparchive/zip_writer.h>
#include "common/test_constants.h"
#include "edify/expr.h"
#include "error_code.h"
-#include "otautil/SysUtil.h"
-#include "print_sha1.h"
-#include "updater/blockimg.h"
#include "updater/install.h"
#include "updater/updater.h"
@@ -70,19 +64,12 @@ static void expect(const char* expected, const char* expr_str, CauseCode cause_c
ASSERT_EQ(cause_code, state.cause_code);
}
-static std::string get_sha1(const std::string& content) {
- uint8_t digest[SHA_DIGEST_LENGTH];
- SHA1(reinterpret_cast<const uint8_t*>(content.c_str()), content.size(), digest);
- return print_sha1(digest);
-}
-
class UpdaterTest : public ::testing::Test {
- protected:
- virtual void SetUp() override {
- RegisterBuiltins();
- RegisterInstallFunctions();
- RegisterBlockImageFunctions();
- }
+ protected:
+ virtual void SetUp() {
+ RegisterBuiltins();
+ RegisterInstallFunctions();
+ }
};
TEST_F(UpdaterTest, getprop) {
@@ -460,100 +447,3 @@ TEST_F(UpdaterTest, show_progress) {
// recovery-updater protocol expects 3 tokens ("progress <frac> <secs>").
ASSERT_EQ(3U, android::base::Split(cmd, " ").size());
}
-
-TEST_F(UpdaterTest, block_image_update) {
- // Create a zip file with new_data and patch_data.
- TemporaryFile zip_file;
- FILE* zip_file_ptr = fdopen(zip_file.fd, "wb");
- ZipWriter zip_writer(zip_file_ptr);
-
- // Add a dummy new data.
- ASSERT_EQ(0, zip_writer.StartEntry("new_data", 0));
- ASSERT_EQ(0, zip_writer.FinishEntry());
-
- // Generate and add the patch data.
- std::string src_content = std::string(4096, 'a') + std::string(4096, 'c');
- std::string tgt_content = std::string(4096, 'b') + std::string(4096, 'd');
- TemporaryFile patch_file;
- ASSERT_EQ(0, bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(src_content.data()),
- src_content.size(), reinterpret_cast<const uint8_t*>(tgt_content.data()),
- tgt_content.size(), patch_file.path, nullptr));
- std::string patch_content;
- ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch_content));
- ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0));
- ASSERT_EQ(0, zip_writer.WriteBytes(patch_content.data(), patch_content.size()));
- ASSERT_EQ(0, zip_writer.FinishEntry());
-
- // Add two transfer lists. The first one contains a bsdiff; and we expect the update to succeed.
- std::string src_hash = get_sha1(src_content);
- std::string tgt_hash = get_sha1(tgt_content);
- std::vector<std::string> transfer_list = {
- "4",
- "2",
- "0",
- "2",
- "stash " + src_hash + " 2,0,2",
- android::base::StringPrintf("bsdiff 0 %zu %s %s 2,0,2 2 - %s:2,0,2", patch_content.size(),
- src_hash.c_str(), tgt_hash.c_str(), src_hash.c_str()),
- "free " + src_hash,
- };
- ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0));
- std::string commands = android::base::Join(transfer_list, '\n');
- ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size()));
- ASSERT_EQ(0, zip_writer.FinishEntry());
-
- // Stash and free some blocks, then fail the 2nd update intentionally.
- std::vector<std::string> fail_transfer_list = {
- "4",
- "2",
- "0",
- "2",
- "stash " + tgt_hash + " 2,0,2",
- "free " + tgt_hash,
- "fail",
- };
- ASSERT_EQ(0, zip_writer.StartEntry("fail_transfer_list", 0));
- std::string fail_commands = android::base::Join(fail_transfer_list, '\n');
- ASSERT_EQ(0, zip_writer.WriteBytes(fail_commands.data(), fail_commands.size()));
- ASSERT_EQ(0, zip_writer.FinishEntry());
- ASSERT_EQ(0, zip_writer.Finish());
- ASSERT_EQ(0, fclose(zip_file_ptr));
-
- MemMapping map;
- ASSERT_EQ(0, sysMapFile(zip_file.path, &map));
- ZipArchiveHandle handle;
- ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
-
- // Set up the handler, command_pipe, patch offset & length.
- UpdaterInfo updater_info;
- updater_info.package_zip = handle;
- TemporaryFile temp_pipe;
- updater_info.cmd_pipe = fopen(temp_pipe.path, "wb");
- updater_info.package_zip_addr = map.addr;
- updater_info.package_zip_len = map.length;
-
- // Execute the commands in the 1st transfer list.
- TemporaryFile update_file;
- ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
- std::string script = "block_image_update(\"" + std::string(update_file.path) +
- R"(", package_extract_file("transfer_list"), "new_data", "patch_data"))";
- expect("t", script.c_str(), kNoCause, &updater_info);
- // The update_file should be patched correctly.
- std::string updated_content;
- ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_content));
- ASSERT_EQ(tgt_hash, get_sha1(updated_content));
-
- // Expect the 2nd update to fail, but expect the stashed blocks to be freed.
- script = "block_image_update(\"" + std::string(update_file.path) +
- R"(", package_extract_file("fail_transfer_list"), "new_data", "patch_data"))";
- expect("", script.c_str(), kNoCause, &updater_info);
- // Updater generates the stash name based on the input file name.
- std::string name_digest = get_sha1(update_file.path);
- std::string stash_base = "/cache/recovery/" + name_digest;
- ASSERT_EQ(0, access(stash_base.c_str(), F_OK));
- ASSERT_EQ(-1, access((stash_base + tgt_hash).c_str(), F_OK));
- ASSERT_EQ(0, rmdir(stash_base.c_str()));
-
- ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
- CloseArchive(handle);
-}
diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp
index 4993716f4..4294d90eb 100644
--- a/tests/component/verifier_test.cpp
+++ b/tests/component/verifier_test.cpp
@@ -22,34 +22,93 @@
#include <sys/stat.h>
#include <sys/types.h>
+#include <memory>
#include <string>
#include <vector>
-#include <android-base/file.h>
+#include <openssl/sha.h>
+
#include <android-base/stringprintf.h>
-#include <android-base/test_utils.h>
+#include <ziparchive/zip_archive.h>
+#include "common.h"
#include "common/test_constants.h"
#include "otautil/SysUtil.h"
+#include "ui.h"
#include "verifier.h"
+RecoveryUI* ui = NULL;
+
+class MockUI : public RecoveryUI {
+ bool Init(const std::string&) override {
+ return true;
+ }
+ void SetStage(int, int) override {}
+ void SetBackground(Icon /*icon*/) override {}
+ void SetSystemUpdateText(bool /*security_update*/) override {}
+
+ void SetProgressType(ProgressType /*determinate*/) override {}
+ void ShowProgress(float /*portion*/, float /*seconds*/) override {}
+ void SetProgress(float /*fraction*/) override {}
+
+ void ShowText(bool /*visible*/) override {}
+ bool IsTextVisible() override {
+ return false;
+ }
+ bool WasTextEverVisible() override {
+ return false;
+ }
+ void Print(const char* fmt, ...) override {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+ void PrintOnScreenOnly(const char* fmt, ...) override {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+ void ShowFile(const char*) override {}
+
+ void StartMenu(const char* const* /*headers*/, const char* const* /*items*/,
+ int /*initial_selection*/) override {}
+ int SelectMenu(int /*sel*/) override {
+ return 0;
+ }
+ void EndMenu() override {}
+};
+
+void
+ui_print(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ vfprintf(stdout, format, ap);
+ va_end(ap);
+}
+
class VerifierTest : public testing::TestWithParam<std::vector<std::string>> {
- protected:
- void SetUp() override {
- std::vector<std::string> args = GetParam();
- std::string package = from_testdata_base(args[0]);
- if (sysMapFile(package.c_str(), &memmap) != 0) {
- FAIL() << "Failed to mmap " << package << ": " << strerror(errno) << "\n";
+ public:
+ MemMapping memmap;
+ std::vector<Certificate> certs;
+
+ virtual void SetUp() {
+ std::vector<std::string> args = GetParam();
+ std::string package = from_testdata_base(args[0]);
+ if (sysMapFile(package.c_str(), &memmap) != 0) {
+ FAIL() << "Failed to mmap " << package << ": " << strerror(errno) << "\n";
+ }
+
+ for (auto it = ++(args.cbegin()); it != args.cend(); ++it) {
+ std::string public_key_file = from_testdata_base("testkey_" + *it + ".txt");
+ ASSERT_TRUE(load_keys(public_key_file.c_str(), certs));
+ }
}
- for (auto it = ++args.cbegin(); it != args.cend(); ++it) {
- std::string public_key_file = from_testdata_base("testkey_" + *it + ".txt");
- ASSERT_TRUE(load_keys(public_key_file.c_str(), certs));
+ static void SetUpTestCase() {
+ ui = new MockUI();
}
- }
-
- MemMapping memmap;
- std::vector<Certificate> certs;
};
class VerifierSuccessTest : public VerifierTest {
@@ -58,106 +117,49 @@ class VerifierSuccessTest : public VerifierTest {
class VerifierFailureTest : public VerifierTest {
};
-TEST(VerifierTest, load_keys_multiple_keys) {
- std::string testkey_v4;
- ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v4.txt"), &testkey_v4));
-
- std::string testkey_v3;
- ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v3.txt"), &testkey_v3));
-
- std::string keys = testkey_v4 + "," + testkey_v3 + "," + testkey_v4;
- TemporaryFile key_file1;
- ASSERT_TRUE(android::base::WriteStringToFile(keys, key_file1.path));
- std::vector<Certificate> certs;
- ASSERT_TRUE(load_keys(key_file1.path, certs));
- ASSERT_EQ(3U, certs.size());
-}
-
-TEST(VerifierTest, load_keys_invalid_keys) {
- std::vector<Certificate> certs;
- ASSERT_FALSE(load_keys("/doesntexist", certs));
-
- // Empty file.
- TemporaryFile key_file1;
- ASSERT_FALSE(load_keys(key_file1.path, certs));
-
- // Invalid contents.
- ASSERT_TRUE(android::base::WriteStringToFile("invalid", key_file1.path));
- ASSERT_FALSE(load_keys(key_file1.path, certs));
-
- std::string testkey_v4;
- ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v4.txt"), &testkey_v4));
-
- // Invalid key version: "v4 ..." => "v6 ...".
- std::string invalid_key2(testkey_v4);
- invalid_key2[1] = '6';
- TemporaryFile key_file2;
- ASSERT_TRUE(android::base::WriteStringToFile(invalid_key2, key_file2.path));
- ASSERT_FALSE(load_keys(key_file2.path, certs));
-
- // Invalid key content: inserted extra bytes ",2209831334".
- std::string invalid_key3(testkey_v4);
- invalid_key3.insert(invalid_key2.size() - 2, ",2209831334");
- TemporaryFile key_file3;
- ASSERT_TRUE(android::base::WriteStringToFile(invalid_key3, key_file3.path));
- ASSERT_FALSE(load_keys(key_file3.path, certs));
-
- // Invalid key: the last key must not end with an extra ','.
- std::string invalid_key4 = testkey_v4 + ",";
- TemporaryFile key_file4;
- ASSERT_TRUE(android::base::WriteStringToFile(invalid_key4, key_file4.path));
- ASSERT_FALSE(load_keys(key_file4.path, certs));
-
- // Invalid key separator.
- std::string invalid_key5 = testkey_v4 + ";" + testkey_v4;
- TemporaryFile key_file5;
- ASSERT_TRUE(android::base::WriteStringToFile(invalid_key5, key_file5.path));
- ASSERT_FALSE(load_keys(key_file5.path, certs));
-}
-
TEST_P(VerifierSuccessTest, VerifySucceed) {
- ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs, nullptr), VERIFY_SUCCESS);
+ ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_SUCCESS);
}
TEST_P(VerifierFailureTest, VerifyFailure) {
- ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs, nullptr), VERIFY_FAILURE);
+ ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_FAILURE);
}
INSTANTIATE_TEST_CASE_P(SingleKeySuccess, VerifierSuccessTest,
- ::testing::Values(
- std::vector<std::string>({"otasigned_v1.zip", "v1"}),
- std::vector<std::string>({"otasigned_v2.zip", "v2"}),
- std::vector<std::string>({"otasigned_v3.zip", "v3"}),
- std::vector<std::string>({"otasigned_v4.zip", "v4"}),
- std::vector<std::string>({"otasigned_v5.zip", "v5"})));
+ ::testing::Values(
+ std::vector<std::string>({"otasigned_v1.zip", "v1"}),
+ std::vector<std::string>({"otasigned_v2.zip", "v2"}),
+ std::vector<std::string>({"otasigned_v3.zip", "v3"}),
+ std::vector<std::string>({"otasigned_v4.zip", "v4"}),
+ std::vector<std::string>({"otasigned_v5.zip", "v5"})));
INSTANTIATE_TEST_CASE_P(MultiKeySuccess, VerifierSuccessTest,
- ::testing::Values(
- std::vector<std::string>({"otasigned_v1.zip", "v1", "v2"}),
- std::vector<std::string>({"otasigned_v2.zip", "v5", "v2"}),
- std::vector<std::string>({"otasigned_v3.zip", "v5", "v1", "v3"}),
- std::vector<std::string>({"otasigned_v4.zip", "v5", "v1", "v4"}),
- std::vector<std::string>({"otasigned_v5.zip", "v4", "v1", "v5"})));
+ ::testing::Values(
+ std::vector<std::string>({"otasigned_v1.zip", "v1", "v2"}),
+ std::vector<std::string>({"otasigned_v2.zip", "v5", "v2"}),
+ std::vector<std::string>({"otasigned_v3.zip", "v5", "v1", "v3"}),
+ std::vector<std::string>({"otasigned_v4.zip", "v5", "v1", "v4"}),
+ std::vector<std::string>({"otasigned_v5.zip", "v4", "v1", "v5"})));
INSTANTIATE_TEST_CASE_P(WrongKey, VerifierFailureTest,
- ::testing::Values(
- std::vector<std::string>({"otasigned_v1.zip", "v2"}),
- std::vector<std::string>({"otasigned_v2.zip", "v1"}),
- std::vector<std::string>({"otasigned_v3.zip", "v5"}),
- std::vector<std::string>({"otasigned_v4.zip", "v5"}),
- std::vector<std::string>({"otasigned_v5.zip", "v3"})));
+ ::testing::Values(
+ std::vector<std::string>({"otasigned_v1.zip", "v2"}),
+ std::vector<std::string>({"otasigned_v2.zip", "v1"}),
+ std::vector<std::string>({"otasigned_v3.zip", "v5"}),
+ std::vector<std::string>({"otasigned_v4.zip", "v5"}),
+ std::vector<std::string>({"otasigned_v5.zip", "v3"})));
INSTANTIATE_TEST_CASE_P(WrongHash, VerifierFailureTest,
- ::testing::Values(
- std::vector<std::string>({"otasigned_v1.zip", "v3"}),
- std::vector<std::string>({"otasigned_v2.zip", "v4"}),
- std::vector<std::string>({"otasigned_v3.zip", "v1"}),
- std::vector<std::string>({"otasigned_v4.zip", "v2"})));
+ ::testing::Values(
+ std::vector<std::string>({"otasigned_v1.zip", "v3"}),
+ std::vector<std::string>({"otasigned_v2.zip", "v4"}),
+ std::vector<std::string>({"otasigned_v3.zip", "v1"}),
+ std::vector<std::string>({"otasigned_v4.zip", "v2"})));
INSTANTIATE_TEST_CASE_P(BadPackage, VerifierFailureTest,
- ::testing::Values(
- std::vector<std::string>({"random.zip", "v1"}),
- std::vector<std::string>({"fake-eocd.zip", "v1"}),
- std::vector<std::string>({"alter-metadata.zip", "v1"}),
- std::vector<std::string>({"alter-footer.zip", "v1"}),
- std::vector<std::string>({"signature-boundary.zip", "v1"})));
+ ::testing::Values(
+ std::vector<std::string>({"random.zip", "v1"}),
+ std::vector<std::string>({"fake-eocd.zip", "v1"}),
+ std::vector<std::string>({"alter-metadata.zip", "v1"}),
+ std::vector<std::string>({"alter-footer.zip", "v1"}),
+ std::vector<std::string>({"signature-boundary.zip", "v1"})));
diff --git a/tests/unit/asn1_decoder_test.cpp b/tests/unit/asn1_decoder_test.cpp
index 997639d8a..af96d87d2 100644
--- a/tests/unit/asn1_decoder_test.cpp
+++ b/tests/unit/asn1_decoder_test.cpp
@@ -39,7 +39,7 @@ TEST_F(Asn1DecoderTest, Empty_Failure) {
EXPECT_EQ(NULL, asn1_set_get(ctx));
EXPECT_FALSE(asn1_sequence_next(ctx));
- const uint8_t* junk;
+ uint8_t* junk;
size_t length;
EXPECT_FALSE(asn1_oid_get(ctx, &junk, &length));
EXPECT_FALSE(asn1_octet_string_get(ctx, &junk, &length));
@@ -68,7 +68,7 @@ TEST_F(Asn1DecoderTest, ConstructedGet_TooSmallForChild_Failure) {
asn1_context_t* ptr = asn1_constructed_get(ctx);
ASSERT_NE((asn1_context_t*)NULL, ptr);
EXPECT_EQ(5, asn1_constructed_type(ptr));
- const uint8_t* oid;
+ uint8_t* oid;
size_t length;
EXPECT_FALSE(asn1_oid_get(ptr, &oid, &length));
asn1_context_free(ptr);
@@ -81,7 +81,7 @@ TEST_F(Asn1DecoderTest, ConstructedGet_Success) {
asn1_context_t* ptr = asn1_constructed_get(ctx);
ASSERT_NE((asn1_context_t*)NULL, ptr);
EXPECT_EQ(5, asn1_constructed_type(ptr));
- const uint8_t* oid;
+ uint8_t* oid;
size_t length;
ASSERT_TRUE(asn1_oid_get(ptr, &oid, &length));
EXPECT_EQ(1U, length);
@@ -103,7 +103,7 @@ TEST_F(Asn1DecoderTest, ConstructedSkipAll_Success) {
0x06, 0x01, 0xA5, };
asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
ASSERT_TRUE(asn1_constructed_skip_all(ctx));
- const uint8_t* oid;
+ uint8_t* oid;
size_t length;
ASSERT_TRUE(asn1_oid_get(ctx, &oid, &length));
EXPECT_EQ(1U, length);
@@ -123,7 +123,7 @@ TEST_F(Asn1DecoderTest, SequenceGet_TooSmallForChild_Failure) {
asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
asn1_context_t* ptr = asn1_sequence_get(ctx);
ASSERT_NE((asn1_context_t*)NULL, ptr);
- const uint8_t* oid;
+ uint8_t* oid;
size_t length;
EXPECT_FALSE(asn1_oid_get(ptr, &oid, &length));
asn1_context_free(ptr);
@@ -135,7 +135,7 @@ TEST_F(Asn1DecoderTest, SequenceGet_Success) {
asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
asn1_context_t* ptr = asn1_sequence_get(ctx);
ASSERT_NE((asn1_context_t*)NULL, ptr);
- const uint8_t* oid;
+ uint8_t* oid;
size_t length;
ASSERT_TRUE(asn1_oid_get(ptr, &oid, &length));
EXPECT_EQ(1U, length);
@@ -156,7 +156,7 @@ TEST_F(Asn1DecoderTest, SetGet_TooSmallForChild_Failure) {
asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
asn1_context_t* ptr = asn1_set_get(ctx);
ASSERT_NE((asn1_context_t*)NULL, ptr);
- const uint8_t* oid;
+ uint8_t* oid;
size_t length;
EXPECT_FALSE(asn1_oid_get(ptr, &oid, &length));
asn1_context_free(ptr);
@@ -168,7 +168,7 @@ TEST_F(Asn1DecoderTest, SetGet_Success) {
asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
asn1_context_t* ptr = asn1_set_get(ctx);
ASSERT_NE((asn1_context_t*)NULL, ptr);
- const uint8_t* oid;
+ uint8_t* oid;
size_t length;
ASSERT_TRUE(asn1_oid_get(ptr, &oid, &length));
EXPECT_EQ(1U, length);
@@ -180,7 +180,7 @@ TEST_F(Asn1DecoderTest, SetGet_Success) {
TEST_F(Asn1DecoderTest, OidGet_LengthZero_Failure) {
uint8_t data[] = { 0x06, 0x00, 0x01, };
asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- const uint8_t* oid;
+ uint8_t* oid;
size_t length;
EXPECT_FALSE(asn1_oid_get(ctx, &oid, &length));
asn1_context_free(ctx);
@@ -189,7 +189,7 @@ TEST_F(Asn1DecoderTest, OidGet_LengthZero_Failure) {
TEST_F(Asn1DecoderTest, OidGet_TooSmall_Failure) {
uint8_t data[] = { 0x06, 0x01, };
asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- const uint8_t* oid;
+ uint8_t* oid;
size_t length;
EXPECT_FALSE(asn1_oid_get(ctx, &oid, &length));
asn1_context_free(ctx);
@@ -198,7 +198,7 @@ TEST_F(Asn1DecoderTest, OidGet_TooSmall_Failure) {
TEST_F(Asn1DecoderTest, OidGet_Success) {
uint8_t data[] = { 0x06, 0x01, 0x99, };
asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- const uint8_t* oid;
+ uint8_t* oid;
size_t length;
ASSERT_TRUE(asn1_oid_get(ctx, &oid, &length));
EXPECT_EQ(1U, length);
@@ -209,7 +209,7 @@ TEST_F(Asn1DecoderTest, OidGet_Success) {
TEST_F(Asn1DecoderTest, OctetStringGet_LengthZero_Failure) {
uint8_t data[] = { 0x04, 0x00, 0x55, };
asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- const uint8_t* string;
+ uint8_t* string;
size_t length;
ASSERT_FALSE(asn1_octet_string_get(ctx, &string, &length));
asn1_context_free(ctx);
@@ -218,7 +218,7 @@ TEST_F(Asn1DecoderTest, OctetStringGet_LengthZero_Failure) {
TEST_F(Asn1DecoderTest, OctetStringGet_TooSmall_Failure) {
uint8_t data[] = { 0x04, 0x01, };
asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- const uint8_t* string;
+ uint8_t* string;
size_t length;
ASSERT_FALSE(asn1_octet_string_get(ctx, &string, &length));
asn1_context_free(ctx);
@@ -227,7 +227,7 @@ TEST_F(Asn1DecoderTest, OctetStringGet_TooSmall_Failure) {
TEST_F(Asn1DecoderTest, OctetStringGet_Success) {
uint8_t data[] = { 0x04, 0x01, 0xAA, };
asn1_context_t* ctx = asn1_context_new(data, sizeof(data));
- const uint8_t* string;
+ uint8_t* string;
size_t length;
ASSERT_TRUE(asn1_octet_string_get(ctx, &string, &length));
EXPECT_EQ(1U, length);
diff --git a/ui.cpp b/ui.cpp
index a796461c8..3ecd6d125 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -30,7 +30,6 @@
#include <time.h>
#include <unistd.h>
-#include <functional>
#include <string>
#include <android-base/file.h>
diff --git a/updater/Android.mk b/updater/Android.mk
index a113fe86c..3a47dacd5 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -110,11 +110,21 @@ LOCAL_STATIC_LIBRARIES := \
# any subsidiary static libraries required for your registered
# extension libs.
-LOCAL_MODULE_CLASS := EXECUTABLES
-inc := $(call local-generated-sources-dir)/register.inc
+inc := $(call intermediates-dir-for,PACKAGING,updater_extensions)/register.inc
+
+# Encode the value of TARGET_RECOVERY_UPDATER_LIBS into the filename of the dependency.
+# So if TARGET_RECOVERY_UPDATER_LIBS is changed, a new dependency file will be generated.
+# Note that we have to remove any existing depency files before creating new one,
+# so no obsolete dependecy file gets used if you switch back to an old value.
+inc_dep_file := $(inc).dep.$(subst $(space),-,$(sort $(TARGET_RECOVERY_UPDATER_LIBS)))
+$(inc_dep_file): stem := $(inc).dep
+$(inc_dep_file) :
+ $(hide) mkdir -p $(dir $@)
+ $(hide) rm -f $(stem).*
+ $(hide) touch $@
$(inc) : libs := $(TARGET_RECOVERY_UPDATER_LIBS)
-$(inc) :
+$(inc) : $(inc_dep_file)
$(hide) mkdir -p $(dir $@)
$(hide) echo "" > $@
$(hide) $(foreach lib,$(libs),echo "extern void Register_$(lib)(void);" >> $@;)
@@ -122,9 +132,11 @@ $(inc) :
$(hide) $(foreach lib,$(libs),echo " Register_$(lib)();" >> $@;)
$(hide) echo "}" >> $@
-LOCAL_GENERATED_SOURCES := $(inc)
+$(call intermediates-dir-for,EXECUTABLES,updater,,,$(TARGET_PREFER_32_BIT))/updater.o : $(inc)
+LOCAL_C_INCLUDES += $(dir $(inc))
inc :=
+inc_dep_file :=
LOCAL_FORCE_STATIC_EXECUTABLE := true
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp
index 0fa83d9d5..03ce4136e 100644
--- a/updater/blockimg.cpp
+++ b/updater/blockimg.cpp
@@ -32,7 +32,6 @@
#include <unistd.h>
#include <fec/io.h>
-#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
@@ -67,21 +66,6 @@ struct RangeSet {
size_t count; // Limit is INT_MAX.
size_t size;
std::vector<size_t> pos; // Actual limit is INT_MAX.
-
- // Get the block number for the ith(starting from 0) block in the range set.
- int get_block(size_t idx) const {
- if (idx >= size) {
- LOG(ERROR) << "index: " << idx << " is greater than range set size: " << size;
- return -1;
- }
- for (size_t i = 0; i < pos.size(); i += 2) {
- if (idx < pos[i + 1] - pos[i]) {
- return pos[i] + idx;
- }
- idx -= (pos[i + 1] - pos[i]);
- }
- return -1;
- }
};
static CauseCode failure_type = kNoCause;
@@ -457,117 +441,6 @@ static int LoadSrcTgtVersion1(CommandParameters& params, RangeSet& tgt, size_t&
return rc;
}
-// Print the hash in hex for corrupted source blocks (excluding the stashed blocks which is
-// handled separately).
-static void PrintHashForCorruptedSourceBlocks(const CommandParameters& params,
- const std::vector<uint8_t>& buffer) {
- LOG(INFO) << "unexpected contents of source blocks in cmd:\n" << params.cmdline;
- if (params.version < 3) {
- // TODO handle version 1,2
- LOG(WARNING) << "version number " << params.version << " is not supported to print hashes";
- return;
- }
-
- CHECK(params.tokens[0] == "move" || params.tokens[0] == "bsdiff" ||
- params.tokens[0] == "imgdiff");
-
- size_t pos = 0;
- // Command example:
- // move <onehash> <tgt_range> <src_blk_count> <src_range> [<loc_range> <stashed_blocks>]
- // bsdiff <offset> <len> <src_hash> <tgt_hash> <tgt_range> <src_blk_count> <src_range>
- // [<loc_range> <stashed_blocks>]
- if (params.tokens[0] == "move") {
- // src_range for move starts at the 4th position.
- if (params.tokens.size() < 5) {
- LOG(ERROR) << "failed to parse source range in cmd:\n" << params.cmdline;
- return;
- }
- pos = 4;
- } else {
- // src_range for diff starts at the 7th position.
- if (params.tokens.size() < 8) {
- LOG(ERROR) << "failed to parse source range in cmd:\n" << params.cmdline;
- return;
- }
- pos = 7;
- }
-
- // Source blocks in stash only, no work to do.
- if (params.tokens[pos] == "-") {
- return;
- }
-
- RangeSet src = parse_range(params.tokens[pos++]);
-
- RangeSet locs;
- // If there's no stashed blocks, content in the buffer is consecutive and has the same
- // order as the source blocks.
- if (pos == params.tokens.size()) {
- locs.count = 1;
- locs.size = src.size;
- locs.pos = { 0, src.size };
- } else {
- // Otherwise, the next token is the offset of the source blocks in the target range.
- // Example: for the tokens <4,63946,63947,63948,63979> <4,6,7,8,39> <stashed_blocks>;
- // We want to print SHA-1 for the data in buffer[6], buffer[8], buffer[9] ... buffer[38];
- // this corresponds to the 32 src blocks #63946, #63948, #63949 ... #63978.
- locs = parse_range(params.tokens[pos++]);
- CHECK_EQ(src.size, locs.size);
- CHECK_EQ(locs.pos.size() % 2, static_cast<size_t>(0));
- }
-
- LOG(INFO) << "printing hash in hex for " << src.size << " source blocks";
- for (size_t i = 0; i < src.size; i++) {
- int block_num = src.get_block(i);
- CHECK_NE(block_num, -1);
- int buffer_index = locs.get_block(i);
- CHECK_NE(buffer_index, -1);
- CHECK_LE((buffer_index + 1) * BLOCKSIZE, buffer.size());
-
- uint8_t digest[SHA_DIGEST_LENGTH];
- SHA1(buffer.data() + buffer_index * BLOCKSIZE, BLOCKSIZE, digest);
- std::string hexdigest = print_sha1(digest);
- LOG(INFO) << " block number: " << block_num << ", SHA-1: " << hexdigest;
- }
-}
-
-// If the calculated hash for the whole stash doesn't match the stash id, print the SHA-1
-// in hex for each block.
-static void PrintHashForCorruptedStashedBlocks(const std::string& id,
- const std::vector<uint8_t>& buffer,
- const RangeSet& src) {
- LOG(INFO) << "printing hash in hex for stash_id: " << id;
- CHECK_EQ(src.size * BLOCKSIZE, buffer.size());
-
- for (size_t i = 0; i < src.size; i++) {
- int block_num = src.get_block(i);
- CHECK_NE(block_num, -1);
-
- uint8_t digest[SHA_DIGEST_LENGTH];
- SHA1(buffer.data() + i * BLOCKSIZE, BLOCKSIZE, digest);
- std::string hexdigest = print_sha1(digest);
- LOG(INFO) << " block number: " << block_num << ", SHA-1: " << hexdigest;
- }
-}
-
-// If the stash file doesn't exist, read the source blocks this stash contains and print the
-// SHA-1 for these blocks.
-static void PrintHashForMissingStashedBlocks(const std::string& id, int fd) {
- if (stash_map.find(id) == stash_map.end()) {
- LOG(ERROR) << "No stash saved for id: " << id;
- return;
- }
-
- LOG(INFO) << "print hash in hex for source blocks in missing stash: " << id;
- const RangeSet& src = stash_map[id];
- std::vector<uint8_t> buffer(src.size * BLOCKSIZE);
- if (ReadBlocks(src, buffer, fd) == -1) {
- LOG(ERROR) << "failed to read source blocks for stash: " << id;
- return;
- }
- PrintHashForCorruptedStashedBlocks(id, buffer, src);
-}
-
static int VerifyBlocks(const std::string& expected, const std::vector<uint8_t>& buffer,
const size_t blocks, bool printerror) {
uint8_t digest[SHA_DIGEST_LENGTH];
@@ -600,54 +473,88 @@ static std::string GetStashFileName(const std::string& base, const std::string&
return fn;
}
-// Does a best effort enumeration of stash files. Ignores possible non-file items in the stash
-// directory and continues despite of errors. Calls the 'callback' function for each file.
-static void EnumerateStash(const std::string& dirname,
- const std::function<void(const std::string&)>& callback) {
- if (dirname.empty()) return;
+typedef void (*StashCallback)(const std::string&, void*);
+
+// Does a best effort enumeration of stash files. Ignores possible non-file
+// items in the stash directory and continues despite of errors. Calls the
+// 'callback' function for each file and passes 'data' to the function as a
+// parameter.
- std::unique_ptr<DIR, decltype(&closedir)> directory(opendir(dirname.c_str()), closedir);
+static void EnumerateStash(const std::string& dirname, StashCallback callback, void* data) {
+ if (dirname.empty() || callback == nullptr) {
+ return;
+ }
- if (directory == nullptr) {
- if (errno != ENOENT) {
- PLOG(ERROR) << "opendir \"" << dirname << "\" failed";
+ std::unique_ptr<DIR, int(*)(DIR*)> directory(opendir(dirname.c_str()), closedir);
+
+ if (directory == nullptr) {
+ if (errno != ENOENT) {
+ PLOG(ERROR) << "opendir \"" << dirname << "\" failed";
+ }
+ return;
}
+
+ struct dirent* item;
+ while ((item = readdir(directory.get())) != nullptr) {
+ if (item->d_type != DT_REG) {
+ continue;
+ }
+
+ std::string fn = dirname + "/" + std::string(item->d_name);
+ callback(fn, data);
+ }
+}
+
+static void UpdateFileSize(const std::string& fn, void* data) {
+ if (fn.empty() || !data) {
return;
}
- dirent* item;
- while ((item = readdir(directory.get())) != nullptr) {
- if (item->d_type != DT_REG) continue;
- callback(dirname + "/" + item->d_name);
+ struct stat sb;
+ if (stat(fn.c_str(), &sb) == -1) {
+ PLOG(ERROR) << "stat \"" << fn << "\" failed";
+ return;
}
+
+ size_t* size = static_cast<size_t*>(data);
+ *size += sb.st_size;
}
// Deletes the stash directory and all files in it. Assumes that it only
// contains files. There is nothing we can do about unlikely, but possible
// errors, so they are merely logged.
-static void DeleteFile(const std::string& fn) {
- if (fn.empty()) return;
- LOG(INFO) << "deleting " << fn;
+static void DeleteFile(const std::string& fn, void* /* data */) {
+ if (!fn.empty()) {
+ LOG(INFO) << "deleting " << fn;
- if (unlink(fn.c_str()) == -1 && errno != ENOENT) {
- PLOG(ERROR) << "unlink \"" << fn << "\" failed";
- }
+ if (unlink(fn.c_str()) == -1 && errno != ENOENT) {
+ PLOG(ERROR) << "unlink \"" << fn << "\" failed";
+ }
+ }
+}
+
+static void DeletePartial(const std::string& fn, void* data) {
+ if (android::base::EndsWith(fn, ".partial")) {
+ DeleteFile(fn, data);
+ }
}
static void DeleteStash(const std::string& base) {
- if (base.empty()) return;
+ if (base.empty()) {
+ return;
+ }
- LOG(INFO) << "deleting stash " << base;
+ LOG(INFO) << "deleting stash " << base;
- std::string dirname = GetStashFileName(base, "", "");
- EnumerateStash(dirname, DeleteFile);
+ std::string dirname = GetStashFileName(base, "", "");
+ EnumerateStash(dirname, DeleteFile, nullptr);
- if (rmdir(dirname.c_str()) == -1) {
- if (errno != ENOENT && errno != ENOTDIR) {
- PLOG(ERROR) << "rmdir \"" << dirname << "\" failed";
+ if (rmdir(dirname.c_str()) == -1) {
+ if (errno != ENOENT && errno != ENOTDIR) {
+ PLOG(ERROR) << "rmdir \"" << dirname << "\" failed";
+ }
}
- }
}
static int LoadStash(CommandParameters& params, const std::string& base, const std::string& id,
@@ -666,7 +573,6 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s
}
if (VerifyBlocks(id, buffer, src.size, true) != 0) {
LOG(ERROR) << "failed to verify loaded source blocks in stash map.";
- PrintHashForCorruptedStashedBlocks(id, buffer, src);
return -1;
}
return 0;
@@ -691,7 +597,6 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s
if (res == -1) {
if (errno != ENOENT || printnoent) {
PLOG(ERROR) << "stat \"" << fn << "\" failed";
- PrintHashForMissingStashedBlocks(id, params.fd);
}
return -1;
}
@@ -719,14 +624,7 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s
if (verify && VerifyBlocks(id, buffer, *blocks, true) != 0) {
LOG(ERROR) << "unexpected contents in " << fn;
- if (stash_map.find(id) == stash_map.end()) {
- LOG(ERROR) << "failed to find source blocks number for stash " << id
- << " when executing command: " << params.cmdname;
- } else {
- const RangeSet& src = stash_map[id];
- PrintHashForCorruptedStashedBlocks(id, buffer, src);
- }
- DeleteFile(fn);
+ DeleteFile(fn, nullptr);
return -1;
}
@@ -852,24 +750,13 @@ static int CreateStash(State* state, size_t maxblocks, const std::string& blockd
LOG(INFO) << "using existing stash " << dirname;
- // If the directory already exists, calculate the space already allocated to stash files and check
- // if there's enough for all required blocks. Delete any partially completed stash files first.
- EnumerateStash(dirname, [](const std::string& fn) {
- if (android::base::EndsWith(fn, ".partial")) {
- DeleteFile(fn);
- }
- });
+ // If the directory already exists, calculate the space already allocated to
+ // stash files and check if there's enough for all required blocks. Delete any
+ // partially completed stash files first.
+ EnumerateStash(dirname, DeletePartial, nullptr);
size_t existing = 0;
- EnumerateStash(dirname, [&existing](const std::string& fn) {
- if (fn.empty()) return;
- struct stat sb;
- if (stat(fn.c_str(), &sb) == -1) {
- PLOG(ERROR) << "stat \"" << fn << "\" failed";
- return;
- }
- existing += static_cast<size_t>(sb.st_size);
- });
+ EnumerateStash(dirname, UpdateFileSize, &existing);
if (max_stash_size > existing) {
size_t needed = max_stash_size - existing;
@@ -908,7 +795,6 @@ static int SaveStash(CommandParameters& params, const std::string& base,
return -1;
}
blocks = src.size;
- stash_map[id] = src;
if (usehash && VerifyBlocks(id, buffer, blocks, true) != 0) {
// Source blocks have unexpected contents. If we actually need this
@@ -919,8 +805,9 @@ static int SaveStash(CommandParameters& params, const std::string& base,
return 0;
}
- // In verify mode, we don't need to stash any blocks.
+ // In verify mode, save source range_set instead of stashing blocks.
if (!params.canwrite && usehash) {
+ stash_map[id] = src;
return 0;
}
@@ -930,13 +817,14 @@ static int SaveStash(CommandParameters& params, const std::string& base,
}
static int FreeStash(const std::string& base, const std::string& id) {
- if (base.empty() || id.empty()) {
- return -1;
- }
+ if (base.empty() || id.empty()) {
+ return -1;
+ }
- DeleteFile(GetStashFileName(base, id, ""));
+ std::string fn = GetStashFileName(base, id, "");
+ DeleteFile(fn, nullptr);
- return 0;
+ return 0;
}
static void MoveRange(std::vector<uint8_t>& dest, const RangeSet& locs,
@@ -1138,8 +1026,6 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t&
// Valid source data not available, update cannot be resumed
LOG(ERROR) << "partition has unexpected contents";
- PrintHashForCorruptedSourceBlocks(params, params.buffer);
-
params.isunresumable = true;
return -1;
@@ -1208,8 +1094,9 @@ static int PerformCommandFree(CommandParameters& params) {
const std::string& id = params.tokens[params.cpos++];
- if (stash_map.find(id) != stash_map.end()) {
+ if (!params.canwrite && stash_map.find(id) != stash_map.end()) {
stash_map.erase(id);
+ return 0;
}
if (params.createdstash || params.canwrite) {
@@ -1351,8 +1238,10 @@ static int PerformCommandDiff(CommandParameters& params) {
if (params.canwrite) {
if (status == 0) {
LOG(INFO) << "patching " << blocks << " blocks to " << tgt.size;
+
Value patch_value(VAL_BLOB,
std::string(reinterpret_cast<const char*>(params.patch_start + offset), len));
+
RangeSinkState rss(tgt);
rss.fd = params.fd;
rss.p_block = 0;
diff --git a/verifier.cpp b/verifier.cpp
index 7f165860e..82454867b 100644
--- a/verifier.cpp
+++ b/verifier.cpp
@@ -22,9 +22,7 @@
#include <string.h>
#include <algorithm>
-#include <functional>
#include <memory>
-#include <vector>
#include <android-base/logging.h>
#include <openssl/bn.h>
@@ -32,7 +30,9 @@
#include <openssl/obj_mac.h>
#include "asn1_decoder.h"
+#include "common.h"
#include "print_sha1.h"
+#include "ui.h"
static constexpr size_t MiB = 1024 * 1024;
@@ -61,244 +61,254 @@ static constexpr size_t MiB = 1024 * 1024;
* SEQUENCE (SignatureAlgorithmIdentifier)
* OCTET STRING (SignatureValue)
*/
-static bool read_pkcs7(const uint8_t* pkcs7_der, size_t pkcs7_der_len,
- std::vector<uint8_t>* sig_der) {
- CHECK(sig_der != nullptr);
- sig_der->clear();
-
- asn1_context_t* ctx = asn1_context_new(pkcs7_der, pkcs7_der_len);
- if (ctx == NULL) {
- return false;
- }
+static bool read_pkcs7(uint8_t* pkcs7_der, size_t pkcs7_der_len, uint8_t** sig_der,
+ size_t* sig_der_length) {
+ asn1_context_t* ctx = asn1_context_new(pkcs7_der, pkcs7_der_len);
+ if (ctx == NULL) {
+ return false;
+ }
- asn1_context_t* pkcs7_seq = asn1_sequence_get(ctx);
- if (pkcs7_seq != NULL && asn1_sequence_next(pkcs7_seq)) {
- asn1_context_t *signed_data_app = asn1_constructed_get(pkcs7_seq);
- if (signed_data_app != NULL) {
- asn1_context_t* signed_data_seq = asn1_sequence_get(signed_data_app);
- if (signed_data_seq != NULL
- && asn1_sequence_next(signed_data_seq)
- && asn1_sequence_next(signed_data_seq)
- && asn1_sequence_next(signed_data_seq)
- && asn1_constructed_skip_all(signed_data_seq)) {
- asn1_context_t *sig_set = asn1_set_get(signed_data_seq);
- if (sig_set != NULL) {
- asn1_context_t* sig_seq = asn1_sequence_get(sig_set);
- if (sig_seq != NULL
- && asn1_sequence_next(sig_seq)
- && asn1_sequence_next(sig_seq)
- && asn1_sequence_next(sig_seq)
- && asn1_sequence_next(sig_seq)) {
- const uint8_t* sig_der_ptr;
- size_t sig_der_length;
- if (asn1_octet_string_get(sig_seq, &sig_der_ptr, &sig_der_length)) {
- sig_der->resize(sig_der_length);
- std::copy(sig_der_ptr, sig_der_ptr + sig_der_length, sig_der->begin());
+ asn1_context_t* pkcs7_seq = asn1_sequence_get(ctx);
+ if (pkcs7_seq != NULL && asn1_sequence_next(pkcs7_seq)) {
+ asn1_context_t *signed_data_app = asn1_constructed_get(pkcs7_seq);
+ if (signed_data_app != NULL) {
+ asn1_context_t* signed_data_seq = asn1_sequence_get(signed_data_app);
+ if (signed_data_seq != NULL
+ && asn1_sequence_next(signed_data_seq)
+ && asn1_sequence_next(signed_data_seq)
+ && asn1_sequence_next(signed_data_seq)
+ && asn1_constructed_skip_all(signed_data_seq)) {
+ asn1_context_t *sig_set = asn1_set_get(signed_data_seq);
+ if (sig_set != NULL) {
+ asn1_context_t* sig_seq = asn1_sequence_get(sig_set);
+ if (sig_seq != NULL
+ && asn1_sequence_next(sig_seq)
+ && asn1_sequence_next(sig_seq)
+ && asn1_sequence_next(sig_seq)
+ && asn1_sequence_next(sig_seq)) {
+ uint8_t* sig_der_ptr;
+ if (asn1_octet_string_get(sig_seq, &sig_der_ptr, sig_der_length)) {
+ *sig_der = (uint8_t*) malloc(*sig_der_length);
+ if (*sig_der != NULL) {
+ memcpy(*sig_der, sig_der_ptr, *sig_der_length);
+ }
+ }
+ asn1_context_free(sig_seq);
+ }
+ asn1_context_free(sig_set);
+ }
+ asn1_context_free(signed_data_seq);
}
- asn1_context_free(sig_seq);
- }
- asn1_context_free(sig_set);
+ asn1_context_free(signed_data_app);
}
- asn1_context_free(signed_data_seq);
- }
- asn1_context_free(signed_data_app);
+ asn1_context_free(pkcs7_seq);
}
- asn1_context_free(pkcs7_seq);
- }
- asn1_context_free(ctx);
+ asn1_context_free(ctx);
- return !sig_der->empty();
+ return *sig_der != NULL;
}
-/*
- * Looks for an RSA signature embedded in the .ZIP file comment given the path to the zip. Verifies
- * that it matches one of the given public keys. A callback function can be optionally provided for
- * posting the progress.
- *
- * Returns VERIFY_SUCCESS or VERIFY_FAILURE (if any error is encountered or no key matches the
- * signature).
- */
-int verify_file(const unsigned char* addr, size_t length, const std::vector<Certificate>& keys,
- const std::function<void(float)>& set_progress) {
- if (set_progress) {
- set_progress(0.0);
- }
-
- // An archive with a whole-file signature will end in six bytes:
- //
- // (2-byte signature start) $ff $ff (2-byte comment size)
- //
- // (As far as the ZIP format is concerned, these are part of the archive comment.) We start by
- // reading this footer, this tells us how far back from the end we have to start reading to find
- // the whole comment.
+// Look for an RSA signature embedded in the .ZIP file comment given
+// the path to the zip. Verify it matches one of the given public
+// keys.
+//
+// Return VERIFY_SUCCESS, VERIFY_FAILURE (if any error is encountered
+// or no key matches the signature).
+
+int verify_file(unsigned char* addr, size_t length,
+ const std::vector<Certificate>& keys) {
+ ui->SetProgress(0.0);
+
+ // An archive with a whole-file signature will end in six bytes:
+ //
+ // (2-byte signature start) $ff $ff (2-byte comment size)
+ //
+ // (As far as the ZIP format is concerned, these are part of the
+ // archive comment.) We start by reading this footer, this tells
+ // us how far back from the end we have to start reading to find
+ // the whole comment.
#define FOOTER_SIZE 6
- if (length < FOOTER_SIZE) {
- LOG(ERROR) << "not big enough to contain footer";
- return VERIFY_FAILURE;
- }
+ if (length < FOOTER_SIZE) {
+ LOG(ERROR) << "not big enough to contain footer";
+ return VERIFY_FAILURE;
+ }
- const unsigned char* footer = addr + length - FOOTER_SIZE;
+ unsigned char* footer = addr + length - FOOTER_SIZE;
- if (footer[2] != 0xff || footer[3] != 0xff) {
- LOG(ERROR) << "footer is wrong";
- return VERIFY_FAILURE;
- }
+ if (footer[2] != 0xff || footer[3] != 0xff) {
+ LOG(ERROR) << "footer is wrong";
+ return VERIFY_FAILURE;
+ }
- size_t comment_size = footer[4] + (footer[5] << 8);
- size_t signature_start = footer[0] + (footer[1] << 8);
- LOG(INFO) << "comment is " << comment_size << " bytes; signature is " << signature_start
- << " bytes from end";
+ size_t comment_size = footer[4] + (footer[5] << 8);
+ size_t signature_start = footer[0] + (footer[1] << 8);
+ LOG(INFO) << "comment is " << comment_size << " bytes; signature is " << signature_start
+ << " bytes from end";
- if (signature_start > comment_size) {
- LOG(ERROR) << "signature start: " << signature_start << " is larger than comment size: "
- << comment_size;
- return VERIFY_FAILURE;
- }
+ if (signature_start > comment_size) {
+ LOG(ERROR) << "signature start: " << signature_start << " is larger than comment size: "
+ << comment_size;
+ return VERIFY_FAILURE;
+ }
- if (signature_start <= FOOTER_SIZE) {
- LOG(ERROR) << "Signature start is in the footer";
- return VERIFY_FAILURE;
- }
+ if (signature_start <= FOOTER_SIZE) {
+ LOG(ERROR) << "Signature start is in the footer";
+ return VERIFY_FAILURE;
+ }
#define EOCD_HEADER_SIZE 22
- // The end-of-central-directory record is 22 bytes plus any comment length.
- size_t eocd_size = comment_size + EOCD_HEADER_SIZE;
+ // The end-of-central-directory record is 22 bytes plus any
+ // comment length.
+ size_t eocd_size = comment_size + EOCD_HEADER_SIZE;
- if (length < eocd_size) {
- LOG(ERROR) << "not big enough to contain EOCD";
- return VERIFY_FAILURE;
- }
+ if (length < eocd_size) {
+ LOG(ERROR) << "not big enough to contain EOCD";
+ return VERIFY_FAILURE;
+ }
- // Determine how much of the file is covered by the signature. This is everything except the
- // signature data and length, which includes all of the EOCD except for the comment length field
- // (2 bytes) and the comment data.
- size_t signed_len = length - eocd_size + EOCD_HEADER_SIZE - 2;
+ // Determine how much of the file is covered by the signature.
+ // This is everything except the signature data and length, which
+ // includes all of the EOCD except for the comment length field (2
+ // bytes) and the comment data.
+ size_t signed_len = length - eocd_size + EOCD_HEADER_SIZE - 2;
- const unsigned char* eocd = addr + length - eocd_size;
+ unsigned char* eocd = addr + length - eocd_size;
- // If this is really is the EOCD record, it will begin with the magic number $50 $4b $05 $06.
- if (eocd[0] != 0x50 || eocd[1] != 0x4b || eocd[2] != 0x05 || eocd[3] != 0x06) {
- LOG(ERROR) << "signature length doesn't match EOCD marker";
- return VERIFY_FAILURE;
- }
+ // If this is really is the EOCD record, it will begin with the
+ // magic number $50 $4b $05 $06.
+ if (eocd[0] != 0x50 || eocd[1] != 0x4b ||
+ eocd[2] != 0x05 || eocd[3] != 0x06) {
+ LOG(ERROR) << "signature length doesn't match EOCD marker";
+ return VERIFY_FAILURE;
+ }
- for (size_t i = 4; i < eocd_size-3; ++i) {
- if (eocd[i] == 0x50 && eocd[i+1] == 0x4b && eocd[i+2] == 0x05 && eocd[i+3] == 0x06) {
- // If the sequence $50 $4b $05 $06 appears anywhere after the real one, libziparchive will
- // find the later (wrong) one, which could be exploitable. Fail the verification if this
- // sequence occurs anywhere after the real one.
- LOG(ERROR) << "EOCD marker occurs after start of EOCD";
- return VERIFY_FAILURE;
+ for (size_t i = 4; i < eocd_size-3; ++i) {
+ if (eocd[i ] == 0x50 && eocd[i+1] == 0x4b &&
+ eocd[i+2] == 0x05 && eocd[i+3] == 0x06) {
+ // if the sequence $50 $4b $05 $06 appears anywhere after
+ // the real one, libziparchive will find the later (wrong) one,
+ // which could be exploitable. Fail verification if
+ // this sequence occurs anywhere after the real one.
+ LOG(ERROR) << "EOCD marker occurs after start of EOCD";
+ return VERIFY_FAILURE;
+ }
}
- }
- bool need_sha1 = false;
- bool need_sha256 = false;
- for (const auto& key : keys) {
- switch (key.hash_len) {
- case SHA_DIGEST_LENGTH: need_sha1 = true; break;
- case SHA256_DIGEST_LENGTH: need_sha256 = true; break;
+ bool need_sha1 = false;
+ bool need_sha256 = false;
+ for (const auto& key : keys) {
+ switch (key.hash_len) {
+ case SHA_DIGEST_LENGTH: need_sha1 = true; break;
+ case SHA256_DIGEST_LENGTH: need_sha256 = true; break;
+ }
}
- }
- SHA_CTX sha1_ctx;
- SHA256_CTX sha256_ctx;
- SHA1_Init(&sha1_ctx);
- SHA256_Init(&sha256_ctx);
-
- double frac = -1.0;
- size_t so_far = 0;
- while (so_far < signed_len) {
- // On a Nexus 5X, experiment showed 16MiB beat 1MiB by 6% faster for a
- // 1196MiB full OTA and 60% for an 89MiB incremental OTA.
- // http://b/28135231.
- size_t size = std::min(signed_len - so_far, 16 * MiB);
-
- if (need_sha1) SHA1_Update(&sha1_ctx, addr + so_far, size);
- if (need_sha256) SHA256_Update(&sha256_ctx, addr + so_far, size);
- so_far += size;
-
- if (set_progress) {
- double f = so_far / (double)signed_len;
- if (f > frac + 0.02 || size == so_far) {
- set_progress(f);
- frac = f;
- }
+ SHA_CTX sha1_ctx;
+ SHA256_CTX sha256_ctx;
+ SHA1_Init(&sha1_ctx);
+ SHA256_Init(&sha256_ctx);
+
+ double frac = -1.0;
+ size_t so_far = 0;
+ while (so_far < signed_len) {
+ // On a Nexus 5X, experiment showed 16MiB beat 1MiB by 6% faster for a
+ // 1196MiB full OTA and 60% for an 89MiB incremental OTA.
+ // http://b/28135231.
+ size_t size = std::min(signed_len - so_far, 16 * MiB);
+
+ if (need_sha1) SHA1_Update(&sha1_ctx, addr + so_far, size);
+ if (need_sha256) SHA256_Update(&sha256_ctx, addr + so_far, size);
+ so_far += size;
+
+ double f = so_far / (double)signed_len;
+ if (f > frac + 0.02 || size == so_far) {
+ ui->SetProgress(f);
+ frac = f;
+ }
}
- }
- uint8_t sha1[SHA_DIGEST_LENGTH];
- SHA1_Final(sha1, &sha1_ctx);
- uint8_t sha256[SHA256_DIGEST_LENGTH];
- SHA256_Final(sha256, &sha256_ctx);
+ uint8_t sha1[SHA_DIGEST_LENGTH];
+ SHA1_Final(sha1, &sha1_ctx);
+ uint8_t sha256[SHA256_DIGEST_LENGTH];
+ SHA256_Final(sha256, &sha256_ctx);
- const uint8_t* signature = eocd + eocd_size - signature_start;
- size_t signature_size = signature_start - FOOTER_SIZE;
+ uint8_t* sig_der = nullptr;
+ size_t sig_der_length = 0;
- LOG(INFO) << "signature (offset: " << std::hex << (length - signature_start) << ", length: "
- << signature_size << "): " << print_hex(signature, signature_size);
+ uint8_t* signature = eocd + eocd_size - signature_start;
+ size_t signature_size = signature_start - FOOTER_SIZE;
- std::vector<uint8_t> sig_der;
- if (!read_pkcs7(signature, signature_size, &sig_der)) {
- LOG(ERROR) << "Could not find signature DER block";
- return VERIFY_FAILURE;
- }
+ LOG(INFO) << "signature (offset: " << std::hex << (length - signature_start) << ", length: "
+ << signature_size << "): " << print_hex(signature, signature_size);
- // Check to make sure at least one of the keys matches the signature. Since any key can match,
- // we need to try each before determining a verification failure has happened.
- size_t i = 0;
- for (const auto& key : keys) {
- const uint8_t* hash;
- int hash_nid;
- switch (key.hash_len) {
- case SHA_DIGEST_LENGTH:
- hash = sha1;
- hash_nid = NID_sha1;
- break;
- case SHA256_DIGEST_LENGTH:
- hash = sha256;
- hash_nid = NID_sha256;
- break;
- default:
- continue;
- }
-
- // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that the signing tool appends
- // after the signature itself.
- if (key.key_type == Certificate::KEY_TYPE_RSA) {
- if (!RSA_verify(hash_nid, hash, key.hash_len, sig_der.data(), sig_der.size(),
- key.rsa.get())) {
- LOG(INFO) << "failed to verify against RSA key " << i;
- continue;
- }
-
- LOG(INFO) << "whole-file signature verified against RSA key " << i;
- return VERIFY_SUCCESS;
- } else if (key.key_type == Certificate::KEY_TYPE_EC && key.hash_len == SHA256_DIGEST_LENGTH) {
- if (!ECDSA_verify(0, hash, key.hash_len, sig_der.data(), sig_der.size(), key.ec.get())) {
- LOG(INFO) << "failed to verify against EC key " << i;
- continue;
- }
-
- LOG(INFO) << "whole-file signature verified against EC key " << i;
- return VERIFY_SUCCESS;
- } else {
- LOG(INFO) << "Unknown key type " << key.key_type;
- }
- i++;
- }
+ if (!read_pkcs7(signature, signature_size, &sig_der, &sig_der_length)) {
+ LOG(ERROR) << "Could not find signature DER block";
+ return VERIFY_FAILURE;
+ }
- if (need_sha1) {
- LOG(INFO) << "SHA-1 digest: " << print_hex(sha1, SHA_DIGEST_LENGTH);
- }
- if (need_sha256) {
- LOG(INFO) << "SHA-256 digest: " << print_hex(sha256, SHA256_DIGEST_LENGTH);
- }
- LOG(ERROR) << "failed to verify whole-file signature";
- return VERIFY_FAILURE;
+ /*
+ * Check to make sure at least one of the keys matches the signature. Since
+ * any key can match, we need to try each before determining a verification
+ * failure has happened.
+ */
+ size_t i = 0;
+ for (const auto& key : keys) {
+ const uint8_t* hash;
+ int hash_nid;
+ switch (key.hash_len) {
+ case SHA_DIGEST_LENGTH:
+ hash = sha1;
+ hash_nid = NID_sha1;
+ break;
+ case SHA256_DIGEST_LENGTH:
+ hash = sha256;
+ hash_nid = NID_sha256;
+ break;
+ default:
+ continue;
+ }
+
+ // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that
+ // the signing tool appends after the signature itself.
+ if (key.key_type == Certificate::KEY_TYPE_RSA) {
+ if (!RSA_verify(hash_nid, hash, key.hash_len, sig_der,
+ sig_der_length, key.rsa.get())) {
+ LOG(INFO) << "failed to verify against RSA key " << i;
+ continue;
+ }
+
+ LOG(INFO) << "whole-file signature verified against RSA key " << i;
+ free(sig_der);
+ return VERIFY_SUCCESS;
+ } else if (key.key_type == Certificate::KEY_TYPE_EC
+ && key.hash_len == SHA256_DIGEST_LENGTH) {
+ if (!ECDSA_verify(0, hash, key.hash_len, sig_der,
+ sig_der_length, key.ec.get())) {
+ LOG(INFO) << "failed to verify against EC key " << i;
+ continue;
+ }
+
+ LOG(INFO) << "whole-file signature verified against EC key " << i;
+ free(sig_der);
+ return VERIFY_SUCCESS;
+ } else {
+ LOG(INFO) << "Unknown key type " << key.key_type;
+ }
+ i++;
+ }
+
+ if (need_sha1) {
+ LOG(INFO) << "SHA-1 digest: " << print_hex(sha1, SHA_DIGEST_LENGTH);
+ }
+ if (need_sha256) {
+ LOG(INFO) << "SHA-256 digest: " << print_hex(sha256, SHA256_DIGEST_LENGTH);
+ }
+ free(sig_der);
+ LOG(ERROR) << "failed to verify whole-file signature";
+ return VERIFY_FAILURE;
}
std::unique_ptr<RSA, RSADeleter> parse_rsa_key(FILE* file, uint32_t exponent) {
diff --git a/verifier.h b/verifier.h
index 6bee74947..58083fe14 100644
--- a/verifier.h
+++ b/verifier.h
@@ -17,7 +17,6 @@
#ifndef _RECOVERY_VERIFIER_H
#define _RECOVERY_VERIFIER_H
-#include <functional>
#include <memory>
#include <vector>
@@ -59,14 +58,13 @@ struct Certificate {
std::unique_ptr<EC_KEY, ECKEYDeleter> ec;
};
-/*
- * 'addr' and 'length' define an update package file that has been loaded (or mmap'ed, or
- * whatever) into memory. Verifies that the file is signed and the signature matches one of the
- * given keys. It optionally accepts a callback function for posting the progress to. Returns one
- * of the constants of VERIFY_SUCCESS and VERIFY_FAILURE.
+/* addr and length define a an update package file that has been
+ * loaded (or mmap'ed, or whatever) into memory. Verify that the file
+ * is signed and the signature matches one of the given keys. Return
+ * one of the constants below.
*/
-int verify_file(const unsigned char* addr, size_t length, const std::vector<Certificate>& keys,
- const std::function<void(float)>& set_progress = nullptr);
+int verify_file(unsigned char* addr, size_t length,
+ const std::vector<Certificate>& keys);
bool load_keys(const char* filename, std::vector<Certificate>& certs);