summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDees Troy <dees_troy@teamw.in>2013-11-02 21:25:14 +0100
committerDees Troy <dees_troy@teamw.in>2013-11-02 21:43:26 +0100
commitbb4c0cbc4bdbff65e3c997bc5bd0ad6d6afa19d6 (patch)
tree9c28e5243024d0755d15e981a21f2fbb35a41ead
parentUpdate licenses to all match (diff)
parentmerge in klp-release history after reset to klp-dev (diff)
downloadandroid_bootable_recovery-bb4c0cbc4bdbff65e3c997bc5bd0ad6d6afa19d6.tar
android_bootable_recovery-bb4c0cbc4bdbff65e3c997bc5bd0ad6d6afa19d6.tar.gz
android_bootable_recovery-bb4c0cbc4bdbff65e3c997bc5bd0ad6d6afa19d6.tar.bz2
android_bootable_recovery-bb4c0cbc4bdbff65e3c997bc5bd0ad6d6afa19d6.tar.lz
android_bootable_recovery-bb4c0cbc4bdbff65e3c997bc5bd0ad6d6afa19d6.tar.xz
android_bootable_recovery-bb4c0cbc4bdbff65e3c997bc5bd0ad6d6afa19d6.tar.zst
android_bootable_recovery-bb4c0cbc4bdbff65e3c997bc5bd0ad6d6afa19d6.zip
-rw-r--r--Android.mk11
-rw-r--r--applypatch/applypatch.c2
-rw-r--r--edify/expr.c4
-rw-r--r--edify/main.c10
-rw-r--r--etc/init.rc8
-rw-r--r--install.cpp18
-rw-r--r--libmincrypt/Android.mk16
-rw-r--r--libmincrypt/NOTICE23
-rw-r--r--libmincrypt/includes/mincrypt/hash-internal.h40
-rw-r--r--libmincrypt/includes/mincrypt/rsa.h58
-rw-r--r--libmincrypt/includes/mincrypt/sha.h30
-rw-r--r--libmincrypt/includes/mincrypt/sha256.h29
-rw-r--r--libmincrypt/rsa.c308
-rw-r--r--libmincrypt/sha.c155
-rw-r--r--libmincrypt/sha256.c184
-rw-r--r--minui/graphics.c4
-rw-r--r--mtdutils/mtdutils.c27
-rw-r--r--recovery.cpp127
-rw-r--r--roots.cpp19
-rw-r--r--roots.h4
-rw-r--r--screen_ui.cpp51
-rw-r--r--screen_ui.h9
-rw-r--r--testdata/otasigned_f4_sha256.zipbin0 -> 5319 bytes
-rw-r--r--testdata/otasigned_sha256.zipbin0 -> 5326 bytes
-rw-r--r--testdata/test_f4_sha256.x509.pem25
-rw-r--r--testdata/testkey.pk8bin0 -> 1217 bytes
-rw-r--r--testdata/testkey.x509.pem27
-rw-r--r--testdata/testkey_sha256.x509.pem27
-rw-r--r--toolbox/Android.mk18
-rw-r--r--ui.cpp41
-rw-r--r--ui.h21
-rw-r--r--updater/install.c341
-rw-r--r--updater/updater.c24
-rw-r--r--verifier.cpp107
-rw-r--r--verifier.h7
-rw-r--r--verifier_test.cpp151
-rwxr-xr-xverifier_test.sh38
37 files changed, 1706 insertions, 258 deletions
diff --git a/Android.mk b/Android.mk
index bec425a94..9781541ef 100644
--- a/Android.mk
+++ b/Android.mk
@@ -306,13 +306,13 @@ include $(CLEAR_VARS)
LOCAL_MODULE := libaosprecovery
LOCAL_MODULE_TAGS := eng
LOCAL_MODULES_TAGS = optional
-LOCAL_CFLAGS =
-ifneq ($(wildcard system/core/libmincrypt/rsa_e_3.c),)
- LOCAL_CFLAGS += -DHAS_EXPONENT
+ifeq ($(TARGET_BOARD_PLATFORM),rk30xx)
+ LOCAL_CFLAGS += -DRK3066
endif
+LOCAL_C_INCLUDES := bootable/recovery/libmincrypt/includes
LOCAL_SRC_FILES = adb_install.cpp bootloader.cpp verifier.cpp mtdutils/mtdutils.c
LOCAL_SHARED_LIBRARIES += libc liblog libcutils libmtdutils
-LOCAL_STATIC_LIBRARIES += libmincrypt
+LOCAL_STATIC_LIBRARIES += libmincrypttwrp
include $(BUILD_SHARED_LIBRARY)
@@ -343,7 +343,8 @@ include $(commands_recovery_local_path)/injecttwrp/Android.mk \
$(commands_recovery_local_path)/libblkid/Android.mk \
$(commands_recovery_local_path)/minuitwrp/Android.mk \
$(commands_recovery_local_path)/openaes/Android.mk \
- $(commands_recovery_local_path)/toolbox/Android.mk
+ $(commands_recovery_local_path)/toolbox/Android.mk \
+ $(commands_recovery_local_path)/libmincrypt/Android.mk
ifeq ($(TW_INCLUDE_CRYPTO_SAMSUNG), true)
include $(commands_recovery_local_path)/crypto/libcrypt_samsung/Android.mk
diff --git a/applypatch/applypatch.c b/applypatch/applypatch.c
index 0dcdce0b1..6b8da2a8a 100644
--- a/applypatch/applypatch.c
+++ b/applypatch/applypatch.c
@@ -101,7 +101,7 @@ int LoadFileContents(const char* filename, FileContents* file,
}
}
- SHA(file->data, file->size, file->sha1);
+ SHA_hash(file->data, file->size, file->sha1);
return 0;
}
diff --git a/edify/expr.c b/edify/expr.c
index 07a8ceb6a..a2f1f99d7 100644
--- a/edify/expr.c
+++ b/edify/expr.c
@@ -287,13 +287,13 @@ Value* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
long l_int = strtol(left, &end, 10);
if (left[0] == '\0' || *end != '\0') {
- fprintf(stderr, "[%s] is not an int\n", left);
+ printf("[%s] is not an int\n", left);
goto done;
}
long r_int = strtol(right, &end, 10);
if (right[0] == '\0' || *end != '\0') {
- fprintf(stderr, "[%s] is not an int\n", right);
+ printf("[%s] is not an int\n", right);
goto done;
}
diff --git a/edify/main.c b/edify/main.c
index 855704385..9e6bab7ca 100644
--- a/edify/main.c
+++ b/edify/main.c
@@ -34,8 +34,8 @@ int expect(const char* expr_str, const char* expected, int* errors) {
int error_count = 0;
error = yyparse(&e, &error_count);
if (error > 0 || error_count > 0) {
- fprintf(stderr, "error parsing \"%s\" (%d errors)\n",
- expr_str, error_count);
+ printf("error parsing \"%s\" (%d errors)\n",
+ expr_str, error_count);
++*errors;
return 0;
}
@@ -49,7 +49,7 @@ int expect(const char* expr_str, const char* expected, int* errors) {
free(state.errmsg);
free(state.script);
if (result == NULL && expected != NULL) {
- fprintf(stderr, "error evaluating \"%s\"\n", expr_str);
+ printf("error evaluating \"%s\"\n", expr_str);
++*errors;
return 0;
}
@@ -59,8 +59,8 @@ int expect(const char* expr_str, const char* expected, int* errors) {
}
if (strcmp(result, expected) != 0) {
- fprintf(stderr, "evaluating \"%s\": expected \"%s\", got \"%s\"\n",
- expr_str, expected, result);
+ printf("evaluating \"%s\": expected \"%s\", got \"%s\"\n",
+ expr_str, expected, result);
++*errors;
free(result);
return 0;
diff --git a/etc/init.rc b/etc/init.rc
index 5e5bbf45a..aeec483a3 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -2,6 +2,7 @@ import /init.recovery.${ro.hardware}.rc
on early-init
start ueventd
+ start healthd
on init
export PATH /sbin
@@ -37,13 +38,20 @@ on boot
class_start default
+on property:sys.powerctl=*
+ powerctl ${sys.powerctl}
+
service ueventd /sbin/ueventd
critical
+service healthd /sbin/healthd -n
+ critical
+
service recovery /sbin/recovery
service adbd /sbin/adbd recovery
disabled
+ socket adbd stream 660 system system
# Always start adbd on userdebug and eng builds
on property:ro.debuggable=1
diff --git a/install.cpp b/install.cpp
index 0f3298f1d..797a525fd 100644
--- a/install.cpp
+++ b/install.cpp
@@ -154,6 +154,7 @@ try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
} else {
ui->Print("\n");
}
+ fflush(stdout);
} else if (strcmp(command, "wipe_cache") == 0) {
*wipe_cache = 1;
} else if (strcmp(command, "clear_display") == 0) {
@@ -179,7 +180,9 @@ really_install_package(const char *path, int* wipe_cache)
{
ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
ui->Print("Finding update package...\n");
- ui->SetProgressType(RecoveryUI::INDETERMINATE);
+ // Give verification half the progress bar...
+ ui->SetProgressType(RecoveryUI::DETERMINATE);
+ ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME);
LOGI("Update location: %s\n", path);
if (ensure_path_mounted(path) != 0) {
@@ -190,17 +193,14 @@ really_install_package(const char *path, int* wipe_cache)
ui->Print("Opening update package...\n");
int numKeys;
- RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);
+ Certificate* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);
if (loadedKeys == NULL) {
LOGE("Failed to load keys\n");
return INSTALL_CORRUPT;
}
LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);
- // Give verification half the progress bar...
ui->Print("Verifying update package...\n");
- ui->SetProgressType(RecoveryUI::DETERMINATE);
- ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME);
int err;
err = verify_file(path, loadedKeys, numKeys);
@@ -236,7 +236,13 @@ install_package(const char* path, int* wipe_cache, const char* install_file)
} else {
LOGE("failed to open last_install: %s\n", strerror(errno));
}
- int result = really_install_package(path, wipe_cache);
+ int result;
+ if (setup_install_mounts() != 0) {
+ LOGE("failed to set up expected mounts for install; aborting\n");
+ result = INSTALL_ERROR;
+ } else {
+ result = really_install_package(path, wipe_cache);
+ }
if (install_log) {
fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log);
fputc('\n', install_log);
diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk
new file mode 100644
index 000000000..c111f4b1a
--- /dev/null
+++ b/libmincrypt/Android.mk
@@ -0,0 +1,16 @@
+# Copyright 2008 The Android Open Source Project
+#
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libmincrypttwrp
+LOCAL_C_INCLUDES := bootable/recovery/libmincrypt/includes
+LOCAL_SRC_FILES := rsa.c sha.c sha256.c
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libmincrypttwrp
+LOCAL_SRC_FILES := rsa.c sha.c sha256.c
+include $(BUILD_HOST_STATIC_LIBRARY)
+
diff --git a/libmincrypt/NOTICE b/libmincrypt/NOTICE
new file mode 100644
index 000000000..430d3d62c
--- /dev/null
+++ b/libmincrypt/NOTICE
@@ -0,0 +1,23 @@
+ Copyright 2008, The Android Open Source Project
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of Google Inc. nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/libmincrypt/includes/mincrypt/hash-internal.h b/libmincrypt/includes/mincrypt/hash-internal.h
new file mode 100644
index 000000000..96806f7c6
--- /dev/null
+++ b/libmincrypt/includes/mincrypt/hash-internal.h
@@ -0,0 +1,40 @@
+// Copyright 2007 Google Inc. All Rights Reserved.
+// Author: mschilder@google.com (Marius Schilder)
+
+#ifndef SECURITY_UTIL_LITE_HASH_INTERNAL_H__
+#define SECURITY_UTIL_LITE_HASH_INTERNAL_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+struct HASH_CTX; // forward decl
+
+typedef struct HASH_VTAB {
+ void (* const init)(struct HASH_CTX*);
+ void (* const update)(struct HASH_CTX*, const void*, int);
+ const uint8_t* (* const final)(struct HASH_CTX*);
+ const uint8_t* (* const hash)(const void*, int, uint8_t*);
+ int size;
+} HASH_VTAB;
+
+typedef struct HASH_CTX {
+ const HASH_VTAB * f;
+ uint64_t count;
+ uint8_t buf[64];
+ uint32_t state[8]; // upto SHA2
+} HASH_CTX;
+
+#define HASH_init(ctx) (ctx)->f->init(ctx)
+#define HASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len)
+#define HASH_final(ctx) (ctx)->f->final(ctx)
+#define HASH_hash(data, len, digest) (ctx)->f->hash(data, len, digest)
+#define HASH_size(ctx) (ctx)->f->size
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // SECURITY_UTIL_LITE_HASH_INTERNAL_H__
diff --git a/libmincrypt/includes/mincrypt/rsa.h b/libmincrypt/includes/mincrypt/rsa.h
new file mode 100644
index 000000000..cc0e80024
--- /dev/null
+++ b/libmincrypt/includes/mincrypt/rsa.h
@@ -0,0 +1,58 @@
+/* rsa.h
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of Google Inc. nor the names of its contributors may
+** be used to endorse or promote products derived from this software
+** without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _EMBEDDED_RSA_H_
+#define _EMBEDDED_RSA_H_
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RSANUMBYTES 256 /* 2048 bit key length */
+#define RSANUMWORDS (RSANUMBYTES / sizeof(uint32_t))
+
+typedef struct RSAPublicKey {
+ int len; /* Length of n[] in number of uint32_t */
+ uint32_t n0inv; /* -1 / n[0] mod 2^32 */
+ uint32_t n[RSANUMWORDS]; /* modulus as little endian array */
+ uint32_t rr[RSANUMWORDS]; /* R^2 as little endian array */
+ int exponent; /* 3 or 65537 */
+} RSAPublicKey;
+
+int RSA_verify(const RSAPublicKey *key,
+ const uint8_t* signature,
+ const int len,
+ const uint8_t* hash,
+ const int hash_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmincrypt/includes/mincrypt/sha.h b/libmincrypt/includes/mincrypt/sha.h
new file mode 100644
index 000000000..120ddcb4f
--- /dev/null
+++ b/libmincrypt/includes/mincrypt/sha.h
@@ -0,0 +1,30 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+// Author: mschilder@google.com (Marius Schilder)
+
+#ifndef SECURITY_UTIL_LITE_SHA1_H__
+#define SECURITY_UTIL_LITE_SHA1_H__
+
+#include <stdint.h>
+#include "hash-internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+typedef HASH_CTX SHA_CTX;
+
+void SHA_init(SHA_CTX* ctx);
+void SHA_update(SHA_CTX* ctx, const void* data, int len);
+const uint8_t* SHA_final(SHA_CTX* ctx);
+
+// Convenience method. Returns digest address.
+// NOTE: *digest needs to hold SHA_DIGEST_SIZE bytes.
+const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest);
+
+#define SHA_DIGEST_SIZE 20
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // SECURITY_UTIL_LITE_SHA1_H__
diff --git a/libmincrypt/includes/mincrypt/sha256.h b/libmincrypt/includes/mincrypt/sha256.h
new file mode 100644
index 000000000..0f3efb7f0
--- /dev/null
+++ b/libmincrypt/includes/mincrypt/sha256.h
@@ -0,0 +1,29 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+// Author: mschilder@google.com (Marius Schilder)
+
+#ifndef SECURITY_UTIL_LITE_SHA256_H__
+#define SECURITY_UTIL_LITE_SHA256_H__
+
+#include <stdint.h>
+#include "hash-internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+typedef HASH_CTX SHA256_CTX;
+
+void SHA256_init(SHA256_CTX* ctx);
+void SHA256_update(SHA256_CTX* ctx, const void* data, int len);
+const uint8_t* SHA256_final(SHA256_CTX* ctx);
+
+// Convenience method. Returns digest address.
+const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest);
+
+#define SHA256_DIGEST_SIZE 32
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // SECURITY_UTIL_LITE_SHA256_H__
diff --git a/libmincrypt/rsa.c b/libmincrypt/rsa.c
new file mode 100644
index 000000000..9061b3ae3
--- /dev/null
+++ b/libmincrypt/rsa.c
@@ -0,0 +1,308 @@
+/* rsa.c
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of Google Inc. nor the names of its contributors may
+** be used to endorse or promote products derived from this software
+** without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mincrypt/rsa.h"
+#include "mincrypt/sha.h"
+#include "mincrypt/sha256.h"
+
+// a[] -= mod
+static void subM(const RSAPublicKey* key,
+ uint32_t* a) {
+ int64_t A = 0;
+ int i;
+ for (i = 0; i < key->len; ++i) {
+ A += (uint64_t)a[i] - key->n[i];
+ a[i] = (uint32_t)A;
+ A >>= 32;
+ }
+}
+
+// return a[] >= mod
+static int geM(const RSAPublicKey* key,
+ const uint32_t* a) {
+ int i;
+ for (i = key->len; i;) {
+ --i;
+ if (a[i] < key->n[i]) return 0;
+ if (a[i] > key->n[i]) return 1;
+ }
+ return 1; // equal
+}
+
+// montgomery c[] += a * b[] / R % mod
+static void montMulAdd(const RSAPublicKey* key,
+ uint32_t* c,
+ const uint32_t a,
+ const uint32_t* b) {
+ uint64_t A = (uint64_t)a * b[0] + c[0];
+ uint32_t d0 = (uint32_t)A * key->n0inv;
+ uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
+ int i;
+
+ for (i = 1; i < key->len; ++i) {
+ A = (A >> 32) + (uint64_t)a * b[i] + c[i];
+ B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
+ c[i - 1] = (uint32_t)B;
+ }
+
+ A = (A >> 32) + (B >> 32);
+
+ c[i - 1] = (uint32_t)A;
+
+ if (A >> 32) {
+ subM(key, c);
+ }
+}
+
+// montgomery c[] = a[] * b[] / R % mod
+static void montMul(const RSAPublicKey* key,
+ uint32_t* c,
+ const uint32_t* a,
+ const uint32_t* b) {
+ int i;
+ for (i = 0; i < key->len; ++i) {
+ c[i] = 0;
+ }
+ for (i = 0; i < key->len; ++i) {
+ montMulAdd(key, c, a[i], b);
+ }
+}
+
+// In-place public exponentiation.
+// Input and output big-endian byte array in inout.
+static void modpow(const RSAPublicKey* key,
+ uint8_t* inout) {
+ uint32_t a[RSANUMWORDS];
+ uint32_t aR[RSANUMWORDS];
+ uint32_t aaR[RSANUMWORDS];
+ uint32_t* aaa = 0;
+ int i;
+
+ // Convert from big endian byte array to little endian word array.
+ for (i = 0; i < key->len; ++i) {
+ uint32_t tmp =
+ (inout[((key->len - 1 - i) * 4) + 0] << 24) |
+ (inout[((key->len - 1 - i) * 4) + 1] << 16) |
+ (inout[((key->len - 1 - i) * 4) + 2] << 8) |
+ (inout[((key->len - 1 - i) * 4) + 3] << 0);
+ a[i] = tmp;
+ }
+
+ if (key->exponent == 65537) {
+ aaa = aaR; // Re-use location.
+ montMul(key, aR, a, key->rr); // aR = a * RR / R mod M
+ for (i = 0; i < 16; i += 2) {
+ montMul(key, aaR, aR, aR); // aaR = aR * aR / R mod M
+ montMul(key, aR, aaR, aaR); // aR = aaR * aaR / R mod M
+ }
+ montMul(key, aaa, aR, a); // aaa = aR * a / R mod M
+ } else if (key->exponent == 3) {
+ aaa = aR; // Re-use location.
+ montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */
+ montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */
+ montMul(key, aaa, aaR, a); /* aaa = aaR * a / R mod M */
+ }
+
+ // Make sure aaa < mod; aaa is at most 1x mod too large.
+ if (geM(key, aaa)) {
+ subM(key, aaa);
+ }
+
+ // Convert to bigendian byte array
+ for (i = key->len - 1; i >= 0; --i) {
+ uint32_t tmp = aaa[i];
+ *inout++ = tmp >> 24;
+ *inout++ = tmp >> 16;
+ *inout++ = tmp >> 8;
+ *inout++ = tmp >> 0;
+ }
+}
+
+// Expected PKCS1.5 signature padding bytes, for a keytool RSA signature.
+// Has the 0-length optional parameter encoded in the ASN1 (as opposed to the
+// other flavor which omits the optional parameter entirely). This code does not
+// accept signatures without the optional parameter.
+
+/*
+static const uint8_t sha_padding[RSANUMBYTES] = {
+ 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x21, 0x30,
+ 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a,
+ 0x05, 0x00, 0x04, 0x14,
+
+ // 20 bytes of hash go here.
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
+*/
+
+// SHA-1 of PKCS1.5 signature sha_padding for 2048 bit, as above.
+// At the location of the bytes of the hash all 00 are hashed.
+static const uint8_t kExpectedPadShaRsa2048[SHA_DIGEST_SIZE] = {
+ 0xdc, 0xbd, 0xbe, 0x42, 0xd5, 0xf5, 0xa7, 0x2e,
+ 0x6e, 0xfc, 0xf5, 0x5d, 0xaf, 0x9d, 0xea, 0x68,
+ 0x7c, 0xfb, 0xf1, 0x67
+};
+
+/*
+static const uint8_t sha256_padding[RSANUMBYTES] = {
+ 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x31, 0x30,
+ 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
+ 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20,
+
+ // 32 bytes of hash go here.
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+*/
+
+// SHA-256 of PKCS1.5 signature sha256_padding for 2048 bit, as above.
+// At the location of the bytes of the hash all 00 are hashed.
+static const uint8_t kExpectedPadSha256Rsa2048[SHA256_DIGEST_SIZE] = {
+ 0xab, 0x28, 0x8d, 0x8a, 0xd7, 0xd9, 0x59, 0x92,
+ 0xba, 0xcc, 0xf8, 0x67, 0x20, 0xe1, 0x15, 0x2e,
+ 0x39, 0x8d, 0x80, 0x36, 0xd6, 0x6f, 0xf0, 0xfd,
+ 0x90, 0xe8, 0x7d, 0x8b, 0xe1, 0x7c, 0x87, 0x59,
+};
+
+// Verify a 2048-bit RSA PKCS1.5 signature against an expected hash.
+// Both e=3 and e=65537 are supported. hash_len may be
+// SHA_DIGEST_SIZE (== 20) to indicate a SHA-1 hash, or
+// SHA256_DIGEST_SIZE (== 32) to indicate a SHA-256 hash. No other
+// values are supported.
+//
+// Returns 1 on successful verification, 0 on failure.
+int RSA_verify(const RSAPublicKey *key,
+ const uint8_t *signature,
+ const int len,
+ const uint8_t *hash,
+ const int hash_len) {
+ uint8_t buf[RSANUMBYTES];
+ int i;
+ const uint8_t* padding_hash;
+
+ if (key->len != RSANUMWORDS) {
+ return 0; // Wrong key passed in.
+ }
+
+ if (len != sizeof(buf)) {
+ return 0; // Wrong input length.
+ }
+
+ if (hash_len != SHA_DIGEST_SIZE &&
+ hash_len != SHA256_DIGEST_SIZE) {
+ return 0; // Unsupported hash.
+ }
+
+ if (key->exponent != 3 && key->exponent != 65537) {
+ return 0; // Unsupported exponent.
+ }
+
+ for (i = 0; i < len; ++i) { // Copy input to local workspace.
+ buf[i] = signature[i];
+ }
+
+ modpow(key, buf); // In-place exponentiation.
+
+ // Xor sha portion, so it all becomes 00 iff equal.
+ for (i = len - hash_len; i < len; ++i) {
+ buf[i] ^= *hash++;
+ }
+
+ // Hash resulting buf, in-place.
+ switch (hash_len) {
+ case SHA_DIGEST_SIZE:
+ padding_hash = kExpectedPadShaRsa2048;
+ SHA_hash(buf, len, buf);
+ break;
+ case SHA256_DIGEST_SIZE:
+ padding_hash = kExpectedPadSha256Rsa2048;
+ SHA256_hash(buf, len, buf);
+ break;
+ default:
+ return 0;
+ }
+
+ // Compare against expected hash value.
+ for (i = 0; i < hash_len; ++i) {
+ if (buf[i] != padding_hash[i]) {
+ return 0;
+ }
+ }
+
+ return 1; // All checked out OK.
+}
diff --git a/libmincrypt/sha.c b/libmincrypt/sha.c
new file mode 100644
index 000000000..5bef32e42
--- /dev/null
+++ b/libmincrypt/sha.c
@@ -0,0 +1,155 @@
+/* sha.c
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of Google Inc. nor the names of its contributors may
+** be used to endorse or promote products derived from this software
+** without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Optimized for minimal code size.
+
+#include "mincrypt/sha.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+static void SHA1_Transform(SHA_CTX* ctx) {
+ uint32_t W[80];
+ uint32_t A, B, C, D, E;
+ uint8_t* p = ctx->buf;
+ int t;
+
+ for(t = 0; t < 16; ++t) {
+ uint32_t tmp = *p++ << 24;
+ tmp |= *p++ << 16;
+ tmp |= *p++ << 8;
+ tmp |= *p++;
+ W[t] = tmp;
+ }
+
+ for(; t < 80; t++) {
+ W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+ }
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+
+ for(t = 0; t < 80; t++) {
+ uint32_t tmp = rol(5,A) + E + W[t];
+
+ if (t < 20)
+ tmp += (D^(B&(C^D))) + 0x5A827999;
+ else if ( t < 40)
+ tmp += (B^C^D) + 0x6ED9EBA1;
+ else if ( t < 60)
+ tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;
+ else
+ tmp += (B^C^D) + 0xCA62C1D6;
+
+ E = D;
+ D = C;
+ C = rol(30,B);
+ B = A;
+ A = tmp;
+ }
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+}
+
+static const HASH_VTAB SHA_VTAB = {
+ SHA_init,
+ SHA_update,
+ SHA_final,
+ SHA_hash,
+ SHA_DIGEST_SIZE
+};
+
+void SHA_init(SHA_CTX* ctx) {
+ ctx->f = &SHA_VTAB;
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0xC3D2E1F0;
+ ctx->count = 0;
+}
+
+
+void SHA_update(SHA_CTX* ctx, const void* data, int len) {
+ int i = (int) (ctx->count & 63);
+ const uint8_t* p = (const uint8_t*)data;
+
+ ctx->count += len;
+
+ while (len--) {
+ ctx->buf[i++] = *p++;
+ if (i == 64) {
+ SHA1_Transform(ctx);
+ i = 0;
+ }
+ }
+}
+
+
+const uint8_t* SHA_final(SHA_CTX* ctx) {
+ uint8_t *p = ctx->buf;
+ uint64_t cnt = ctx->count * 8;
+ int i;
+
+ SHA_update(ctx, (uint8_t*)"\x80", 1);
+ while ((ctx->count & 63) != 56) {
+ SHA_update(ctx, (uint8_t*)"\0", 1);
+ }
+ for (i = 0; i < 8; ++i) {
+ uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
+ SHA_update(ctx, &tmp, 1);
+ }
+
+ for (i = 0; i < 5; i++) {
+ uint32_t tmp = ctx->state[i];
+ *p++ = tmp >> 24;
+ *p++ = tmp >> 16;
+ *p++ = tmp >> 8;
+ *p++ = tmp >> 0;
+ }
+
+ return ctx->buf;
+}
+
+/* Convenience function */
+const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest) {
+ SHA_CTX ctx;
+ SHA_init(&ctx);
+ SHA_update(&ctx, data, len);
+ memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE);
+ return digest;
+}
diff --git a/libmincrypt/sha256.c b/libmincrypt/sha256.c
new file mode 100644
index 000000000..eb6e308e8
--- /dev/null
+++ b/libmincrypt/sha256.c
@@ -0,0 +1,184 @@
+/* sha256.c
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of Google Inc. nor the names of its contributors may
+** be used to endorse or promote products derived from this software
+** without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Optimized for minimal code size.
+
+#include "mincrypt/sha256.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits))))
+#define shr(value, bits) ((value) >> (bits))
+
+static const uint32_t K[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 };
+
+static void SHA256_Transform(SHA256_CTX* ctx) {
+ uint32_t W[64];
+ uint32_t A, B, C, D, E, F, G, H;
+ uint8_t* p = ctx->buf;
+ int t;
+
+ for(t = 0; t < 16; ++t) {
+ uint32_t tmp = *p++ << 24;
+ tmp |= *p++ << 16;
+ tmp |= *p++ << 8;
+ tmp |= *p++;
+ W[t] = tmp;
+ }
+
+ for(; t < 64; t++) {
+ uint32_t s0 = ror(W[t-15], 7) ^ ror(W[t-15], 18) ^ shr(W[t-15], 3);
+ uint32_t s1 = ror(W[t-2], 17) ^ ror(W[t-2], 19) ^ shr(W[t-2], 10);
+ W[t] = W[t-16] + s0 + W[t-7] + s1;
+ }
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+ F = ctx->state[5];
+ G = ctx->state[6];
+ H = ctx->state[7];
+
+ for(t = 0; t < 64; t++) {
+ uint32_t s0 = ror(A, 2) ^ ror(A, 13) ^ ror(A, 22);
+ uint32_t maj = (A & B) ^ (A & C) ^ (B & C);
+ uint32_t t2 = s0 + maj;
+ uint32_t s1 = ror(E, 6) ^ ror(E, 11) ^ ror(E, 25);
+ uint32_t ch = (E & F) ^ ((~E) & G);
+ uint32_t t1 = H + s1 + ch + K[t] + W[t];
+
+ H = G;
+ G = F;
+ F = E;
+ E = D + t1;
+ D = C;
+ C = B;
+ B = A;
+ A = t1 + t2;
+ }
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+ ctx->state[5] += F;
+ ctx->state[6] += G;
+ ctx->state[7] += H;
+}
+
+static const HASH_VTAB SHA256_VTAB = {
+ SHA256_init,
+ SHA256_update,
+ SHA256_final,
+ SHA256_hash,
+ SHA256_DIGEST_SIZE
+};
+
+void SHA256_init(SHA256_CTX* ctx) {
+ ctx->f = &SHA256_VTAB;
+ ctx->state[0] = 0x6a09e667;
+ ctx->state[1] = 0xbb67ae85;
+ ctx->state[2] = 0x3c6ef372;
+ ctx->state[3] = 0xa54ff53a;
+ ctx->state[4] = 0x510e527f;
+ ctx->state[5] = 0x9b05688c;
+ ctx->state[6] = 0x1f83d9ab;
+ ctx->state[7] = 0x5be0cd19;
+ ctx->count = 0;
+}
+
+
+void SHA256_update(SHA256_CTX* ctx, const void* data, int len) {
+ int i = (int) (ctx->count & 63);
+ const uint8_t* p = (const uint8_t*)data;
+
+ ctx->count += len;
+
+ while (len--) {
+ ctx->buf[i++] = *p++;
+ if (i == 64) {
+ SHA256_Transform(ctx);
+ i = 0;
+ }
+ }
+}
+
+
+const uint8_t* SHA256_final(SHA256_CTX* ctx) {
+ uint8_t *p = ctx->buf;
+ uint64_t cnt = ctx->count * 8;
+ int i;
+
+ SHA256_update(ctx, (uint8_t*)"\x80", 1);
+ while ((ctx->count & 63) != 56) {
+ SHA256_update(ctx, (uint8_t*)"\0", 1);
+ }
+ for (i = 0; i < 8; ++i) {
+ uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
+ SHA256_update(ctx, &tmp, 1);
+ }
+
+ for (i = 0; i < 8; i++) {
+ uint32_t tmp = ctx->state[i];
+ *p++ = tmp >> 24;
+ *p++ = tmp >> 16;
+ *p++ = tmp >> 8;
+ *p++ = tmp >> 0;
+ }
+
+ return ctx->buf;
+}
+
+/* Convenience function */
+const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest) {
+ SHA256_CTX ctx;
+ SHA256_init(&ctx);
+ SHA256_update(&ctx, data, len);
+ memcpy(digest, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
+ return digest;
+}
diff --git a/minui/graphics.c b/minui/graphics.c
index 9ee77b3aa..8998d9fd1 100644
--- a/minui/graphics.c
+++ b/minui/graphics.c
@@ -390,8 +390,8 @@ int gr_init(void)
get_memory_surface(&gr_mem_surface);
- fprintf(stderr, "framebuffer: fd %d (%d x %d)\n",
- gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height);
+ printf("framebuffer: fd %d (%d x %d)\n",
+ gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height);
/* start with 0 as front (displayed) and 1 as back (drawing) */
gr_active_fb = 0;
diff --git a/mtdutils/mtdutils.c b/mtdutils/mtdutils.c
index 032b04bac..6229d4851 100644
--- a/mtdutils/mtdutils.c
+++ b/mtdutils/mtdutils.c
@@ -286,7 +286,7 @@ static int read_block(const MtdPartition *partition, int fd, char *data)
{
struct mtd_ecc_stats before, after;
if (ioctl(fd, ECCGETSTATS, &before)) {
- fprintf(stderr, "mtd: ECCGETSTATS error (%s)\n", strerror(errno));
+ printf("mtd: ECCGETSTATS error (%s)\n", strerror(errno));
return -1;
}
@@ -297,13 +297,13 @@ static int read_block(const MtdPartition *partition, int fd, char *data)
while (pos + size <= (int) partition->size) {
if (lseek64(fd, pos, SEEK_SET) != pos || read(fd, data, size) != size) {
- fprintf(stderr, "mtd: read error at 0x%08llx (%s)\n",
+ printf("mtd: read error at 0x%08llx (%s)\n",
pos, strerror(errno));
} else if (ioctl(fd, ECCGETSTATS, &after)) {
- fprintf(stderr, "mtd: ECCGETSTATS error (%s)\n", strerror(errno));
+ printf("mtd: ECCGETSTATS error (%s)\n", strerror(errno));
return -1;
} else if (after.failed != before.failed) {
- fprintf(stderr, "mtd: ECC errors (%d soft, %d hard) at 0x%08llx\n",
+ printf("mtd: ECC errors (%d soft, %d hard) at 0x%08llx\n",
after.corrected - before.corrected,
after.failed - before.failed, pos);
// copy the comparison baseline for the next read.
@@ -435,43 +435,44 @@ static int write_block(MtdWriteContext *ctx, const char *data)
}
#else
if (ioctl(fd, MEMERASE, &erase_info) < 0) {
- fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n",
+ printf("mtd: erase failure at 0x%08lx (%s)\n",
pos, strerror(errno));
continue;
}
#endif
if (lseek(fd, pos, SEEK_SET) != pos ||
write(fd, data, size) != size) {
- fprintf(stderr, "mtd: write error at 0x%08lx (%s)\n",
+ printf("mtd: write error at 0x%08lx (%s)\n",
pos, strerror(errno));
}
char verify[size];
if (lseek(fd, pos, SEEK_SET) != pos ||
read(fd, verify, size) != size) {
- fprintf(stderr, "mtd: re-read error at 0x%08lx (%s)\n",
+ printf("mtd: re-read error at 0x%08lx (%s)\n",
pos, strerror(errno));
continue;
}
if (memcmp(data, verify, size) != 0) {
- fprintf(stderr, "mtd: verification error at 0x%08lx (%s)\n",
+ printf("mtd: verification error at 0x%08lx (%s)\n",
pos, strerror(errno));
continue;
}
if (retry > 0) {
- fprintf(stderr, "mtd: wrote block after %d retries\n", retry);
+ printf("mtd: wrote block after %d retries\n", retry);
}
- fprintf(stderr, "mtd: successfully wrote block at %llx\n", pos);
+ printf("mtd: successfully wrote block at %lx\n", pos);
return 0; // Success!
}
// Try to erase it once more as we give up on this block
add_bad_block_offset(ctx, pos);
- fprintf(stderr, "mtd: skipping write block at 0x%08lx\n", pos);
+ printf("mtd: skipping write block at 0x%08lx\n", pos);
#ifdef RK3066
rk30_zero_out(fd, pos, size);
#else
+
ioctl(fd, MEMERASE, &erase_info);
#endif
pos += partition->erase_size;
@@ -535,7 +536,7 @@ off_t mtd_erase_blocks(MtdWriteContext *ctx, int blocks)
while (blocks-- > 0) {
loff_t bpos = pos;
if (ioctl(ctx->fd, MEMGETBADBLOCK, &bpos) > 0) {
- fprintf(stderr, "mtd: not erasing bad block at 0x%08lx\n", pos);
+ printf("mtd: not erasing bad block at 0x%08lx\n", pos);
pos += ctx->partition->erase_size;
continue; // Don't try to erase known factory-bad blocks.
}
@@ -549,7 +550,7 @@ off_t mtd_erase_blocks(MtdWriteContext *ctx, int blocks)
}
#else
if (ioctl(ctx->fd, MEMERASE, &erase_info) < 0) {
- fprintf(stderr, "mtd: erase failure at 0x%08lx\n", pos);
+ printf("mtd: erase failure at 0x%08lx\n", pos);
}
#endif
pos += ctx->partition->erase_size;
diff --git a/recovery.cpp b/recovery.cpp
index 28c26cefc..de9939357 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -77,6 +77,7 @@ static const struct option OPTIONS[] = {
#define LAST_LOG_FILE "/cache/recovery/last_log"
+static const char *CACHE_LOG_DIR = "/cache/recovery";
static const char *COMMAND_FILE = "/cache/recovery/command";
static const char *INTENT_FILE = "/cache/recovery/intent";
static const char *LOG_FILE = "/cache/recovery/log";
@@ -90,6 +91,7 @@ static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
RecoveryUI* ui = NULL;
char* locale = NULL;
+char recovery_version[PROPERTY_VALUE_MAX+1];
/*
* The recovery tool communicates with the main system through /cache files.
@@ -299,6 +301,19 @@ rotate_last_logs(int max) {
}
}
+static void
+copy_logs() {
+ // Copy logs to cache so the system can find out what happened.
+ copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true);
+ copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false);
+ copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false);
+ chmod(LOG_FILE, 0600);
+ chown(LOG_FILE, 1000, 1000); // system user
+ chmod(LAST_LOG_FILE, 0640);
+ chmod(LAST_INSTALL_FILE, 0644);
+ sync();
+}
+
// clear the recovery command and prepare to boot a (hopefully working) system,
// copy our log file to cache as well (for the system to read), and
// record any intent we were asked to communicate back to the system.
@@ -328,14 +343,7 @@ finish_recovery(const char *send_intent) {
check_and_fclose(fp, LOCALE_FILE);
}
- // Copy logs to cache so the system can find out what happened.
- copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true);
- copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false);
- copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false);
- chmod(LOG_FILE, 0600);
- chown(LOG_FILE, 1000, 1000); // system user
- chmod(LAST_LOG_FILE, 0640);
- chmod(LAST_INSTALL_FILE, 0644);
+ copy_logs();
// Reset to normal system boot so recovery won't cycle indefinitely.
struct bootloader_message boot;
@@ -352,22 +360,95 @@ finish_recovery(const char *send_intent) {
sync(); // For good measure.
}
+typedef struct _saved_log_file {
+ char* name;
+ struct stat st;
+ unsigned char* data;
+ struct _saved_log_file* next;
+} saved_log_file;
+
static int
erase_volume(const char *volume) {
+ bool is_cache = (strcmp(volume, CACHE_ROOT) == 0);
+
ui->SetBackground(RecoveryUI::ERASING);
ui->SetProgressType(RecoveryUI::INDETERMINATE);
+
+ saved_log_file* head = NULL;
+
+ if (is_cache) {
+ // If we're reformatting /cache, we load any
+ // "/cache/recovery/last*" files into memory, so we can restore
+ // them after the reformat.
+
+ ensure_path_mounted(volume);
+
+ DIR* d;
+ struct dirent* de;
+ d = opendir(CACHE_LOG_DIR);
+ if (d) {
+ char path[PATH_MAX];
+ strcpy(path, CACHE_LOG_DIR);
+ strcat(path, "/");
+ int path_len = strlen(path);
+ while ((de = readdir(d)) != NULL) {
+ if (strncmp(de->d_name, "last", 4) == 0) {
+ saved_log_file* p = (saved_log_file*) malloc(sizeof(saved_log_file));
+ strcpy(path+path_len, de->d_name);
+ p->name = strdup(path);
+ if (stat(path, &(p->st)) == 0) {
+ // truncate files to 512kb
+ if (p->st.st_size > (1 << 19)) {
+ p->st.st_size = 1 << 19;
+ }
+ p->data = (unsigned char*) malloc(p->st.st_size);
+ FILE* f = fopen(path, "rb");
+ fread(p->data, 1, p->st.st_size, f);
+ fclose(f);
+ p->next = head;
+ head = p;
+ } else {
+ free(p);
+ }
+ }
+ }
+ closedir(d);
+ } else {
+ if (errno != ENOENT) {
+ printf("opendir failed: %s\n", strerror(errno));
+ }
+ }
+ }
+
ui->Print("Formatting %s...\n", volume);
ensure_path_unmounted(volume);
+ int result = format_volume(volume);
+
+ if (is_cache) {
+ while (head) {
+ FILE* f = fopen_path(head->name, "wb");
+ if (f) {
+ fwrite(head->data, 1, head->st.st_size, f);
+ fclose(f);
+ chmod(head->name, head->st.st_mode);
+ chown(head->name, head->st.st_uid, head->st.st_gid);
+ }
+ free(head->name);
+ free(head->data);
+ saved_log_file* temp = head->next;
+ free(head);
+ head = temp;
+ }
- if (strcmp(volume, "/cache") == 0) {
// Any part of the log we'd copied to cache is now gone.
// Reset the pointer so we copy from the beginning of the temp
// log.
tmplog_offset = 0;
+ copy_logs();
}
- return format_volume(volume);
+ return result;
}
static char*
@@ -462,21 +543,17 @@ copy_sideloaded_package(const char* original_path) {
static const char**
prepend_title(const char* const* headers) {
- const char* title[] = { "Android system recovery <"
- EXPAND(RECOVERY_API_VERSION) "e>",
- "",
- NULL };
-
// count the number of lines in our title, plus the
// caller-provided headers.
- int count = 0;
+ int count = 3; // our title has 3 lines
const char* const* p;
- for (p = title; *p; ++p, ++count);
for (p = headers; *p; ++p, ++count);
const char** new_headers = (const char**)malloc((count+1) * sizeof(char*));
const char** h = new_headers;
- for (p = title; *p; ++p, ++h) *h = *p;
+ *(h++) = "Android system recovery <" EXPAND(RECOVERY_API_VERSION) "e>";
+ *(h++) = recovery_version;
+ *(h++) = "";
for (p = headers; *p; ++p, ++h) *h = *p;
*h = NULL;
@@ -750,10 +827,6 @@ prompt_and_wait(Device* device, int status) {
break;
case Device::APPLY_EXT:
- // Some packages expect /cache to be mounted (eg,
- // standard incremental packages expect to use /cache
- // as scratch space).
- ensure_path_mounted(CACHE_ROOT);
status = update_directory(SDCARD_ROOT, SDCARD_ROOT, &wipe_cache, device);
if (status == INSTALL_SUCCESS && wipe_cache) {
ui->Print("\n-- Wiping cache (at package request)...\n");
@@ -799,12 +872,12 @@ prompt_and_wait(Device* device, int status) {
break;
case Device::APPLY_ADB_SIDELOAD:
- ensure_path_mounted(CACHE_ROOT);
status = apply_from_adb(ui, &wipe_cache, TEMPORARY_INSTALL_FILE);
if (status >= 0) {
if (status != INSTALL_SUCCESS) {
ui->SetBackground(RecoveryUI::ERROR);
ui->Print("Installation aborted.\n");
+ copy_logs();
} else if (!ui->IsTextVisible()) {
return; // reboot if logs aren't visible
} else {
@@ -910,8 +983,8 @@ main(int argc, char **argv) {
load_volume_table();
ensure_path_mounted(LAST_LOG_FILE);
- rotate_last_logs(5);
+ rotate_last_logs(10);
get_args(&argc, &argv);
int previous_runs = 0;
@@ -959,8 +1032,7 @@ main(int argc, char **argv) {
sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
if (!sehandle) {
- fprintf(stderr, "Warning: No file_contexts\n");
- ui->Print("Warning: No file_contexts\n");
+ ui->Print("Warning: No file_contexts\n");
}
//device->StartRecovery();
@@ -988,6 +1060,7 @@ main(int argc, char **argv) {
printf("\n");
property_list(print_property, NULL);
+ property_get("ro.build.display.id", recovery_version, "");
printf("\n");
// Check for and run startup script if script exists
@@ -1110,6 +1183,7 @@ main(int argc, char **argv) {
}
if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) {
+ copy_logs();
ui->SetBackground(RecoveryUI::ERROR);
}
if (status != INSTALL_SUCCESS || ui->IsTextVisible()) {
@@ -1138,5 +1212,6 @@ main(int argc, char **argv) {
#else
reboot(RB_AUTOBOOT);
#endif
+ property_set(ANDROID_RB_PROPERTY, "reboot,");
return EXIT_SUCCESS;
}
diff --git a/roots.cpp b/roots.cpp
index c52cf591d..63a8eaf3b 100644
--- a/roots.cpp
+++ b/roots.cpp
@@ -217,3 +217,22 @@ int format_volume(const char* volume) {
LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type);
return -1;
}
+
+int setup_install_mounts() {
+ if (fstab == NULL) {
+ LOGE("can't set up install mounts: no fstab loaded\n");
+ return -1;
+ }
+ for (int i = 0; i < fstab->num_entries; ++i) {
+ Volume* v = fstab->recs + i;
+
+ if (strcmp(v->mount_point, "/tmp") == 0 ||
+ strcmp(v->mount_point, "/cache") == 0) {
+ if (ensure_path_mounted(v->mount_point) != 0) return -1;
+
+ } else {
+ if (ensure_path_unmounted(v->mount_point) != 0) return -1;
+ }
+ }
+ return 0;
+}
diff --git a/roots.h b/roots.h
index 8abe18fb7..230d9ded3 100644
--- a/roots.h
+++ b/roots.h
@@ -42,6 +42,10 @@ int ensure_path_unmounted(const char* path);
// it is mounted.
int format_volume(const char* volume);
+// Ensure that all and only the volumes that packages expect to find
+// mounted (/tmp and /cache) are mounted. Returns 0 on success.
+int setup_install_mounts();
+
#ifdef __cplusplus
}
#endif
diff --git a/screen_ui.cpp b/screen_ui.cpp
index 4a83a5c73..7e7bd8a99 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -202,9 +202,29 @@ void ScreenRecoveryUI::draw_progress_locked()
}
}
-#define C_HEADER 247,0,6
-#define C_MENU 0,106,157
-#define C_LOG 249,194,0
+void ScreenRecoveryUI::SetColor(UIElement e) {
+ switch (e) {
+ case HEADER:
+ gr_color(247, 0, 6, 255);
+ break;
+ case MENU:
+ case MENU_SEL_BG:
+ gr_color(0, 106, 157, 255);
+ break;
+ case MENU_SEL_FG:
+ gr_color(255, 255, 255, 255);
+ break;
+ case LOG:
+ gr_color(249, 194, 0, 255);
+ break;
+ case TEXT_FILL:
+ gr_color(0, 0, 0, 160);
+ break;
+ default:
+ gr_color(255, 255, 255, 255);
+ break;
+ }
+}
// Redraw everything on the screen. Does not flip pages.
// Should only be called with updateMutex locked.
@@ -214,37 +234,38 @@ void ScreenRecoveryUI::draw_screen_locked()
draw_progress_locked();
if (show_text) {
- gr_color(0, 0, 0, 160);
+ SetColor(TEXT_FILL);
gr_fill(0, 0, gr_fb_width(), gr_fb_height());
int y = 0;
int i = 0;
if (show_menu) {
- gr_color(C_HEADER, 255);
+ SetColor(HEADER);
for (; i < menu_top + menu_items; ++i) {
- if (i == menu_top) gr_color(C_MENU, 255);
+ if (i == menu_top) SetColor(MENU);
if (i == menu_top + menu_sel) {
// draw the highlight bar
+ SetColor(MENU_SEL_BG);
gr_fill(0, y-2, gr_fb_width(), y+char_height+2);
// white text of selected item
- gr_color(255, 255, 255, 255);
+ SetColor(MENU_SEL_FG);
if (menu[i][0]) gr_text(4, y, menu[i], 1);
- gr_color(C_MENU, 255);
+ SetColor(MENU);
} else {
if (menu[i][0]) gr_text(4, y, menu[i], i < menu_top);
}
y += char_height+4;
}
- gr_color(C_MENU, 255);
+ SetColor(MENU);
y += 4;
gr_fill(0, y, gr_fb_width(), y+2);
y += 4;
++i;
}
- gr_color(C_LOG, 255);
+ SetColor(LOG);
// display from the bottom up, until we hit the top of the
// screen, the bottom of the menu, or we've displayed the
@@ -452,10 +473,11 @@ void ScreenRecoveryUI::SetProgressType(ProgressType type)
pthread_mutex_lock(&updateMutex);
if (progressBarType != type) {
progressBarType = type;
- update_progress_locked();
}
progressScopeStart = 0;
+ progressScopeSize = 0;
progress = 0;
+ update_progress_locked();
pthread_mutex_unlock(&updateMutex);
}
@@ -599,3 +621,10 @@ void ScreenRecoveryUI::ShowText(bool visible)
update_screen_locked();
pthread_mutex_unlock(&updateMutex);
}
+
+void ScreenRecoveryUI::Redraw()
+{
+ pthread_mutex_lock(&updateMutex);
+ update_screen_locked();
+ pthread_mutex_unlock(&updateMutex);
+}
diff --git a/screen_ui.h b/screen_ui.h
index fe0de46e8..fc35d95b6 100644
--- a/screen_ui.h
+++ b/screen_ui.h
@@ -53,6 +53,14 @@ class ScreenRecoveryUI : public RecoveryUI {
int SelectMenu(int sel);
void EndMenu();
+ void Redraw();
+
+ enum UIElement { HEADER, MENU, MENU_SEL_BG, MENU_SEL_FG, LOG, TEXT_FILL };
+ virtual void SetColor(UIElement e);
+
+ protected:
+ int install_overlay_offset_x, install_overlay_offset_y;
+
private:
Icon currentIcon;
int installingFrame;
@@ -94,7 +102,6 @@ class ScreenRecoveryUI : public RecoveryUI {
int animation_fps;
int indeterminate_frames;
int installing_frames;
- int install_overlay_offset_x, install_overlay_offset_y;
int overlay_offset_x, overlay_offset_y;
void draw_install_overlay_locked(int frame);
diff --git a/testdata/otasigned_f4_sha256.zip b/testdata/otasigned_f4_sha256.zip
new file mode 100644
index 000000000..3af408c40
--- /dev/null
+++ b/testdata/otasigned_f4_sha256.zip
Binary files differ
diff --git a/testdata/otasigned_sha256.zip b/testdata/otasigned_sha256.zip
new file mode 100644
index 000000000..0ed4409b3
--- /dev/null
+++ b/testdata/otasigned_sha256.zip
Binary files differ
diff --git a/testdata/test_f4_sha256.x509.pem b/testdata/test_f4_sha256.x509.pem
new file mode 100644
index 000000000..9d5376b45
--- /dev/null
+++ b/testdata/test_f4_sha256.x509.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIJAKhkCO1dDYMaMA0GCSqGSIb3DQEBCwUAMG8xCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBW
+aWV3MQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMT
+B1Rlc3QxMjMwHhcNMTMwNDEwMTcyMzUyWhcNMTMwNTEwMTcyMzUyWjBvMQswCQYD
+VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
+VmlldzEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRAwDgYDVQQD
+EwdUZXN0MTIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu8WwMN9x
+4Mz7YgkG2qy9g8/kl5ZoYrUM0ApHhaITAcL7RXLZaNipCf0w/YjYTQgj+75MK30x
+TsnPeWNOEwA62gkHrZyyWfxBRO6kBYuIuI4roGDBJOmKQ1OEaDeIRKu7q5V8v3Cs
+0wQDAQWTbhpxBZr9UYFgJUg8XWBfPrGJLVwsoiy4xrMhoTlNZKHfwOMMqVtSHkZX
+qydYrcIzyjh+TO0e/xSNQ8MMRRbtqWgCHN6Rzhog3IHZu0RaPoukariopjXM/s0V
+gTm3rHDHCOpna2pNblyiFlvbkoCs769mtNmx/yrDShO30jg/xaG8RypKDvTChzOT
+oWW/XQ5VEXjbHwIDAQABo4HUMIHRMB0GA1UdDgQWBBRlT2dEZJY1tmUM8mZ0xnhS
+GdD9TTCBoQYDVR0jBIGZMIGWgBRlT2dEZJY1tmUM8mZ0xnhSGdD9TaFzpHEwbzEL
+MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50
+YWluIFZpZXcxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHQW5kcm9pZDEQMA4G
+A1UEAxMHVGVzdDEyM4IJAKhkCO1dDYMaMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
+AQELBQADggEBAKWWQ9S0V9wWjrMJe8exj1gklwD1Ysi0vi+h2tfixahelrpsNkWi
+EFjoUSHEkW9ThLmtui646uAlwSiWtSn1XkGGmIJ3s+gmAFUcMc0CaK0dgoq/M9zn
+fQ0Vkzc1tK4MLsf+CbPDywPycb6+T3dBkerbWn9GUpjGl1ANWlciXZZ3657m61sL
+HhwUOBxbZZ6sYP4ed2SVCf45GgMyJ0VoUg5yI2JzPAgOkGfeEIPVXE1M94edJY4G
+8eHYvXovJZwXvKFI+ZyS0KBPx8cpfw89RB9qmkxqNBIm8qWb3qBiuBEIPj+NF/7w
+sC/Fv8NNXkVquy0xa0qdyJBABzWE18zGcXs=
+-----END CERTIFICATE-----
diff --git a/testdata/testkey.pk8 b/testdata/testkey.pk8
new file mode 100644
index 000000000..586c1bd5c
--- /dev/null
+++ b/testdata/testkey.pk8
Binary files differ
diff --git a/testdata/testkey.x509.pem b/testdata/testkey.x509.pem
new file mode 100644
index 000000000..e242d83e2
--- /dev/null
+++ b/testdata/testkey.x509.pem
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD
+VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
+VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
+AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
+Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
+A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
+ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
+hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM
+qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4
+wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy
+4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU
+RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s
+zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw
+HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ
+AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
+QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
+CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud
+EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa
+J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y
+LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe
++ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX
+31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr
+sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0=
+-----END CERTIFICATE-----
diff --git a/testdata/testkey_sha256.x509.pem b/testdata/testkey_sha256.x509.pem
new file mode 100644
index 000000000..002ce8968
--- /dev/null
+++ b/testdata/testkey_sha256.x509.pem
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYD
+VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
+VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
+AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
+Fw0xMzA0MTAxODA1MzZaFw0xMzA1MTAxODA1MzZaMIGUMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
+A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
+ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
+hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM
+qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4
+wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy
+4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU
+RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s
+zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw
+HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ
+AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
+QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
+CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud
+EwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKRVj9hOaozH1W8Wb4CNj7sCWixh
+UMMZJXkxUtvUVHZGefp6MdtYiD/ZM7YRwZphm9aNhkykbHJdZ3lPzeL2csCa+sDQ
+8sIzGu0/aD6p4zgIKQZmz0mZHqPGbHoLWOmA9EexRCFZ7vO/kO56ZbyhfFz2DI3S
+Yez65CabErOFhNX6WukSPbV3zfsHRDD5JUStb/ko6t99HXsvIO0Ax9poj60PpCC1
+SiFzHZUY9mOnUfJFs+3NWCwKtP9nho3mZ3pJ1i+SeF6JiqbE3KHl4CDBeVGcu3CK
+fiUZ8e8iXVN471Cgc5GD6Ud1pS7ifNZJsKhbETQ63KmvHCLRPi4NmP67uDE=
+-----END CERTIFICATE-----
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index ef0593a04..afe66a3a8 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -21,18 +21,22 @@ ifeq ($(TWHAVE_SELINUX), true)
endif
LOCAL_SRC_FILES := \
- dynarray.c \
toolbox.c \
$(patsubst %,%.c,$(TOOLS))
-TOOLS += reboot
-
-ifeq ($(BOARD_USES_BOOTMENU),true)
- LOCAL_SRC_FILES += ../../../external/bootmenu/libreboot/reboot.c
-else
- LOCAL_SRC_FILES += reboot.c
+ifneq ($(wildcard system/core/toolbox/dynarray.c),)
+ LOCAL_SRC_FILES += dynarray.c
endif
+# reboot.c was removed in 4.4 kitkat
+#TOOLS += reboot
+
+#ifeq ($(BOARD_USES_BOOTMENU),true)
+# LOCAL_SRC_FILES += ../../../external/bootmenu/libreboot/reboot.c
+#else
+# LOCAL_SRC_FILES += reboot.c
+#endif
+
LOCAL_C_INCLUDES := bionic/libc/bionic
LOCAL_SHARED_LIBRARIES := \
diff --git a/ui.cpp b/ui.cpp
index 042da2eb7..44656d10f 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -48,7 +48,8 @@ static RecoveryUI* self = NULL;
RecoveryUI::RecoveryUI() :
key_queue_len(0),
key_last_down(-1),
- key_down_time(0) {
+ key_long_press(false),
+ key_down_count(0) {
pthread_mutex_init(&key_queue_mutex, NULL);
pthread_cond_init(&key_queue_cond, NULL);
self = this;
@@ -114,19 +115,22 @@ void RecoveryUI::process_key(int key_code, int updown) {
bool register_key = false;
bool long_press = false;
- const long long_threshold = CLOCKS_PER_SEC * 750 / 1000;
-
pthread_mutex_lock(&key_queue_mutex);
key_pressed[key_code] = updown;
if (updown) {
+ ++key_down_count;
key_last_down = key_code;
- key_down_time = clock();
+ key_long_press = false;
+ pthread_t th;
+ key_timer_t* info = new key_timer_t;
+ info->ui = this;
+ info->key_code = key_code;
+ info->count = key_down_count;
+ pthread_create(&th, NULL, &RecoveryUI::time_key_helper, info);
+ pthread_detach(th);
} else {
if (key_last_down == key_code) {
- long duration = clock() - key_down_time;
- if (duration > long_threshold) {
- long_press = true;
- }
+ long_press = key_long_press;
register_key = true;
}
key_last_down = -1;
@@ -156,6 +160,24 @@ void RecoveryUI::process_key(int key_code, int updown) {
}
}
+void* RecoveryUI::time_key_helper(void* cookie) {
+ key_timer_t* info = (key_timer_t*) cookie;
+ info->ui->time_key(info->key_code, info->count);
+ delete info;
+ return NULL;
+}
+
+void RecoveryUI::time_key(int key_code, int count) {
+ usleep(750000); // 750 ms == "long"
+ bool long_press = false;
+ pthread_mutex_lock(&key_queue_mutex);
+ if (key_last_down == key_code && key_down_count == count) {
+ long_press = key_long_press = true;
+ }
+ pthread_mutex_unlock(&key_queue_mutex);
+ if (long_press) KeyLongPress(key_code);
+}
+
void RecoveryUI::EnqueueKey(int key_code) {
pthread_mutex_lock(&key_queue_mutex);
const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
@@ -246,3 +268,6 @@ RecoveryUI::KeyAction RecoveryUI::CheckKey(int key) {
void RecoveryUI::NextCheckKeyIsLong(bool is_long_press) {
}
+
+void RecoveryUI::KeyLongPress(int key) {
+}
diff --git a/ui.h b/ui.h
index aca7b7b87..6c8987a33 100644
--- a/ui.h
+++ b/ui.h
@@ -80,8 +80,17 @@ class RecoveryUI {
enum KeyAction { ENQUEUE, TOGGLE, REBOOT, IGNORE };
virtual KeyAction CheckKey(int key);
+ // Called immediately before each call to CheckKey(), tell you if
+ // the key was long-pressed.
virtual void NextCheckKeyIsLong(bool is_long_press);
+ // Called when a key is held down long enough to have been a
+ // long-press (but before the key is released). This means that
+ // if the key is eventually registered (released without any other
+ // keys being pressed in the meantime), NextCheckKeyIsLong() will
+ // be called with "true".
+ virtual void KeyLongPress(int key);
+
// --- menu display ---
// Display some header text followed by a menu of items, which appears
@@ -108,15 +117,25 @@ private:
int key_queue[256], key_queue_len;
char key_pressed[KEY_MAX + 1]; // under key_queue_mutex
int key_last_down; // under key_queue_mutex
- clock_t key_down_time; // under key_queue_mutex
+ bool key_long_press; // under key_queue_mutex
+ int key_down_count; // under key_queue_mutex
int rel_sum;
+ typedef struct {
+ RecoveryUI* ui;
+ int key_code;
+ int count;
+ } key_timer_t;
+
pthread_t input_t;
static void* input_thread(void* cookie);
static int input_callback(int fd, short revents, void* data);
void process_key(int key_code, int updown);
bool usb_connected();
+
+ static void* time_key_helper(void* cookie);
+ void time_key(int key_code, int count);
};
#endif // RECOVERY_UI_H
diff --git a/updater/install.c b/updater/install.c
index d8c6dc249..ff4dd5829 100644
--- a/updater/install.c
+++ b/updater/install.c
@@ -27,6 +27,12 @@
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
+#include <selinux/selinux.h>
+#include <ftw.h>
+#include <sys/capability.h>
+#include <sys/xattr.h>
+#include <linux/xattr.h>
+#include <inttypes.h>
#include "cutils/misc.h"
#include "cutils/properties.h"
@@ -98,13 +104,13 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
const MtdPartition* mtd;
mtd = mtd_find_partition_by_name(location);
if (mtd == NULL) {
- fprintf(stderr, "%s: no mtd partition named \"%s\"",
+ printf("%s: no mtd partition named \"%s\"",
name, location);
result = strdup("");
goto done;
}
if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) {
- fprintf(stderr, "mtd mount of %s failed: %s\n",
+ printf("mtd mount of %s failed: %s\n",
location, strerror(errno));
result = strdup("");
goto done;
@@ -113,7 +119,7 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
} else {
if (mount(location, mount_point, fs_type,
MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
- fprintf(stderr, "%s: failed to mount %s at %s: %s\n",
+ printf("%s: failed to mount %s at %s: %s\n",
name, location, mount_point, strerror(errno));
result = strdup("");
} else {
@@ -176,7 +182,7 @@ Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
scan_mounted_volumes();
const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
if (vol == NULL) {
- fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point);
+ printf("unmount of %s failed; no such volume\n", mount_point);
result = strdup("");
} else {
unmount_mounted_volume(vol);
@@ -234,25 +240,25 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
mtd_scan_partitions();
const MtdPartition* mtd = mtd_find_partition_by_name(location);
if (mtd == NULL) {
- fprintf(stderr, "%s: no mtd partition named \"%s\"",
+ printf("%s: no mtd partition named \"%s\"",
name, location);
result = strdup("");
goto done;
}
MtdWriteContext* ctx = mtd_write_partition(mtd);
if (ctx == NULL) {
- fprintf(stderr, "%s: can't write \"%s\"", name, location);
+ printf("%s: can't write \"%s\"", name, location);
result = strdup("");
goto done;
}
if (mtd_erase_blocks(ctx, -1) == -1) {
mtd_write_close(ctx);
- fprintf(stderr, "%s: failed to erase \"%s\"", name, location);
+ printf("%s: failed to erase \"%s\"", name, location);
result = strdup("");
goto done;
}
if (mtd_write_close(ctx) != 0) {
- fprintf(stderr, "%s: failed to close \"%s\"", name, location);
+ printf("%s: failed to close \"%s\"", name, location);
result = strdup("");
goto done;
}
@@ -261,7 +267,7 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
} else if (strcmp(fs_type, "ext4") == 0) {
int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle);
if (status != 0) {
- fprintf(stderr, "%s: make_ext4fs failed (%d) on %s",
+ printf("%s: make_ext4fs failed (%d) on %s",
name, status, location);
result = strdup("");
goto done;
@@ -269,7 +275,7 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
result = location;
#endif
} else {
- fprintf(stderr, "%s: unsupported fs_type \"%s\" partition_type \"%s\"",
+ printf("%s: unsupported fs_type \"%s\" partition_type \"%s\"",
name, fs_type, partition_type);
}
@@ -395,13 +401,13 @@ Value* PackageExtractFileFn(const char* name, State* state,
ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
const ZipEntry* entry = mzFindZipEntry(za, zip_path);
if (entry == NULL) {
- fprintf(stderr, "%s: no %s in package\n", name, zip_path);
+ printf("%s: no %s in package\n", name, zip_path);
goto done2;
}
FILE* f = fopen(dest_path, "wb");
if (f == NULL) {
- fprintf(stderr, "%s: can't open %s for write: %s\n",
+ printf("%s: can't open %s for write: %s\n",
name, dest_path, strerror(errno));
goto done2;
}
@@ -427,14 +433,14 @@ Value* PackageExtractFileFn(const char* name, State* state,
ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
const ZipEntry* entry = mzFindZipEntry(za, zip_path);
if (entry == NULL) {
- fprintf(stderr, "%s: no %s in package\n", name, zip_path);
+ printf("%s: no %s in package\n", name, zip_path);
goto done1;
}
v->size = mzGetZipEntryUncompLen(entry);
v->data = malloc(v->size);
if (v->data == NULL) {
- fprintf(stderr, "%s: failed to allocate %ld bytes for %s\n",
+ printf("%s: failed to allocate %ld bytes for %s\n",
name, (long)v->size, zip_path);
goto done1;
}
@@ -461,13 +467,13 @@ static int make_parents(char* name) {
*p = '\0';
if (make_parents(name) < 0) return -1;
int result = mkdir(name, 0700);
- if (result == 0) fprintf(stderr, "symlink(): created [%s]\n", name);
+ if (result == 0) printf("symlink(): created [%s]\n", name);
*p = '/';
if (result == 0 || errno == EEXIST) {
// successfully created or already existed; we're done
return 0;
} else {
- fprintf(stderr, "failed to mkdir %s: %s\n", name, strerror(errno));
+ printf("failed to mkdir %s: %s\n", name, strerror(errno));
return -1;
}
}
@@ -495,18 +501,18 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
for (i = 0; i < argc-1; ++i) {
if (unlink(srcs[i]) < 0) {
if (errno != ENOENT) {
- fprintf(stderr, "%s: failed to remove %s: %s\n",
+ printf("%s: failed to remove %s: %s\n",
name, srcs[i], strerror(errno));
++bad;
}
}
if (make_parents(srcs[i])) {
- fprintf(stderr, "%s: failed to symlink %s to %s: making parents failed\n",
+ printf("%s: failed to symlink %s to %s: making parents failed\n",
name, srcs[i], target);
++bad;
}
if (symlink(target, srcs[i]) < 0) {
- fprintf(stderr, "%s: failed to symlink %s to %s: %s\n",
+ printf("%s: failed to symlink %s to %s: %s\n",
name, srcs[i], target, strerror(errno));
++bad;
}
@@ -575,12 +581,12 @@ Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
for (i = 3; i < argc; ++i) {
if (chown(args[i], uid, gid) < 0) {
- fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n",
+ printf("%s: chown of %s to %d %d failed: %s\n",
name, args[i], uid, gid, strerror(errno));
++bad;
}
if (chmod(args[i], mode) < 0) {
- fprintf(stderr, "%s: chmod of %s to %o failed: %s\n",
+ printf("%s: chmod of %s to %o failed: %s\n",
name, args[i], mode, strerror(errno));
++bad;
}
@@ -601,6 +607,264 @@ done:
return StringValue(result);
}
+struct perm_parsed_args {
+ bool has_uid;
+ uid_t uid;
+ bool has_gid;
+ gid_t gid;
+ bool has_mode;
+ mode_t mode;
+ bool has_fmode;
+ mode_t fmode;
+ bool has_dmode;
+ mode_t dmode;
+ bool has_selabel;
+ char* selabel;
+ bool has_capabilities;
+ uint64_t capabilities;
+};
+
+static struct perm_parsed_args ParsePermArgs(int argc, char** args) {
+ int i;
+ struct perm_parsed_args parsed;
+ int bad = 0;
+ static int max_warnings = 20;
+
+ memset(&parsed, 0, sizeof(parsed));
+
+ for (i = 1; i < argc; i += 2) {
+ if (strcmp("uid", args[i]) == 0) {
+ int64_t uid;
+ if (sscanf(args[i+1], "%" SCNd64, &uid) == 1) {
+ parsed.uid = uid;
+ parsed.has_uid = true;
+ } else {
+ printf("ParsePermArgs: invalid UID \"%s\"\n", args[i + 1]);
+ bad++;
+ }
+ continue;
+ }
+ if (strcmp("gid", args[i]) == 0) {
+ int64_t gid;
+ if (sscanf(args[i+1], "%" SCNd64, &gid) == 1) {
+ parsed.gid = gid;
+ parsed.has_gid = true;
+ } else {
+ printf("ParsePermArgs: invalid GID \"%s\"\n", args[i + 1]);
+ bad++;
+ }
+ continue;
+ }
+ if (strcmp("mode", args[i]) == 0) {
+ int32_t mode;
+ if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) {
+ parsed.mode = mode;
+ parsed.has_mode = true;
+ } else {
+ printf("ParsePermArgs: invalid mode \"%s\"\n", args[i + 1]);
+ bad++;
+ }
+ continue;
+ }
+ if (strcmp("dmode", args[i]) == 0) {
+ int32_t mode;
+ if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) {
+ parsed.dmode = mode;
+ parsed.has_dmode = true;
+ } else {
+ printf("ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1]);
+ bad++;
+ }
+ continue;
+ }
+ if (strcmp("fmode", args[i]) == 0) {
+ int32_t mode;
+ if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) {
+ parsed.fmode = mode;
+ parsed.has_fmode = true;
+ } else {
+ printf("ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1]);
+ bad++;
+ }
+ continue;
+ }
+ if (strcmp("capabilities", args[i]) == 0) {
+ int64_t capabilities;
+ if (sscanf(args[i+1], "%" SCNi64, &capabilities) == 1) {
+ parsed.capabilities = capabilities;
+ parsed.has_capabilities = true;
+ } else {
+ printf("ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1]);
+ bad++;
+ }
+ continue;
+ }
+ if (strcmp("selabel", args[i]) == 0) {
+ if (args[i+1][0] != '\0') {
+ parsed.selabel = args[i+1];
+ parsed.has_selabel = true;
+ } else {
+ printf("ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1]);
+ bad++;
+ }
+ continue;
+ }
+ if (max_warnings != 0) {
+ printf("ParsedPermArgs: unknown key \"%s\", ignoring\n", args[i]);
+ max_warnings--;
+ if (max_warnings == 0) {
+ printf("ParsedPermArgs: suppressing further warnings\n");
+ }
+ }
+ }
+ return parsed;
+}
+
+static int ApplyParsedPerms(
+ const char* filename,
+ const struct stat *statptr,
+ struct perm_parsed_args parsed)
+{
+ int bad = 0;
+
+ /* ignore symlinks */
+ if (S_ISLNK(statptr->st_mode)) {
+ return 0;
+ }
+
+ if (parsed.has_uid) {
+ if (chown(filename, parsed.uid, -1) < 0) {
+ printf("ApplyParsedPerms: chown of %s to %d failed: %s\n",
+ filename, parsed.uid, strerror(errno));
+ bad++;
+ }
+ }
+
+ if (parsed.has_gid) {
+ if (chown(filename, -1, parsed.gid) < 0) {
+ printf("ApplyParsedPerms: chgrp of %s to %d failed: %s\n",
+ filename, parsed.gid, strerror(errno));
+ bad++;
+ }
+ }
+
+ if (parsed.has_mode) {
+ if (chmod(filename, parsed.mode) < 0) {
+ printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n",
+ filename, parsed.mode, strerror(errno));
+ bad++;
+ }
+ }
+
+ if (parsed.has_dmode && S_ISDIR(statptr->st_mode)) {
+ if (chmod(filename, parsed.dmode) < 0) {
+ printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n",
+ filename, parsed.dmode, strerror(errno));
+ bad++;
+ }
+ }
+
+ if (parsed.has_fmode && S_ISREG(statptr->st_mode)) {
+ if (chmod(filename, parsed.fmode) < 0) {
+ printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n",
+ filename, parsed.fmode, strerror(errno));
+ bad++;
+ }
+ }
+
+ if (parsed.has_selabel) {
+ // TODO: Don't silently ignore ENOTSUP
+ if (lsetfilecon(filename, parsed.selabel) && (errno != ENOTSUP)) {
+ printf("ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n",
+ filename, parsed.selabel, strerror(errno));
+ bad++;
+ }
+ }
+
+ if (parsed.has_capabilities && S_ISREG(statptr->st_mode)) {
+ if (parsed.capabilities == 0) {
+ if ((removexattr(filename, XATTR_NAME_CAPS) == -1) && (errno != ENODATA)) {
+ // Report failure unless it's ENODATA (attribute not set)
+ printf("ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n",
+ filename, parsed.capabilities, strerror(errno));
+ bad++;
+ }
+ } else {
+ struct vfs_cap_data cap_data;
+ memset(&cap_data, 0, sizeof(cap_data));
+ cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
+ cap_data.data[0].permitted = (uint32_t) (parsed.capabilities & 0xffffffff);
+ cap_data.data[0].inheritable = 0;
+ cap_data.data[1].permitted = (uint32_t) (parsed.capabilities >> 32);
+ cap_data.data[1].inheritable = 0;
+ if (setxattr(filename, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) < 0) {
+ printf("ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n",
+ filename, parsed.capabilities, strerror(errno));
+ bad++;
+ }
+ }
+ }
+
+ return bad;
+}
+
+// nftw doesn't allow us to pass along context, so we need to use
+// global variables. *sigh*
+static struct perm_parsed_args recursive_parsed_args;
+
+static int do_SetMetadataRecursive(const char* filename, const struct stat *statptr,
+ int fileflags, struct FTW *pfwt) {
+ return ApplyParsedPerms(filename, statptr, recursive_parsed_args);
+}
+
+static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv[]) {
+ int i;
+ int bad = 0;
+ static int nwarnings = 0;
+ struct stat sb;
+ Value* result = NULL;
+
+ bool recursive = (strcmp(name, "set_metadata_recursive") == 0);
+
+ if ((argc % 2) != 1) {
+ return ErrorAbort(state, "%s() expects an odd number of arguments, got %d",
+ name, argc);
+ }
+
+ char** args = ReadVarArgs(state, argc, argv);
+ if (args == NULL) return NULL;
+
+ if (lstat(args[0], &sb) == -1) {
+ result = ErrorAbort(state, "%s: Error on lstat of \"%s\": %s", name, args[0], strerror(errno));
+ goto done;
+ }
+
+ struct perm_parsed_args parsed = ParsePermArgs(argc, args);
+
+ if (recursive) {
+ recursive_parsed_args = parsed;
+ bad += nftw(args[0], do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS);
+ memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args));
+ } else {
+ bad += ApplyParsedPerms(args[0], &sb, parsed);
+ }
+
+done:
+ for (i = 0; i < argc; ++i) {
+ free(args[i]);
+ }
+ free(args);
+
+ if (result != NULL) {
+ return result;
+ }
+
+ if (bad > 0) {
+ return ErrorAbort(state, "%s: some changes failed", name);
+ }
+
+ return StringValue(strdup(""));
+}
Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 1) {
@@ -721,7 +985,7 @@ static bool write_raw_image_cb(const unsigned char* data,
int data_len, void* ctx) {
int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
if (r == data_len) return true;
- fprintf(stderr, "%s\n", strerror(errno));
+ printf("%s\n", strerror(errno));
return false;
}
@@ -937,23 +1201,23 @@ Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
memcpy(args2, args, sizeof(char*) * argc);
args2[argc] = NULL;
- fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc);
+ printf("about to run program [%s] with %d args\n", args2[0], argc);
pid_t child = fork();
if (child == 0) {
execv(args2[0], args2);
- fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno));
+ printf("run_program: execv failed: %s\n", strerror(errno));
_exit(1);
}
int status;
waitpid(child, &status, 0);
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != 0) {
- fprintf(stderr, "run_program: child exited with status %d\n",
+ printf("run_program: child exited with status %d\n",
WEXITSTATUS(status));
}
} else if (WIFSIGNALED(status)) {
- fprintf(stderr, "run_program: child terminated by signal %d\n",
+ printf("run_program: child terminated by signal %d\n",
WTERMSIG(status));
}
@@ -1002,11 +1266,11 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
}
if (args[0]->size < 0) {
- fprintf(stderr, "%s(): no file contents received", name);
+ printf("%s(): no file contents received", name);
return StringValue(strdup(""));
}
uint8_t digest[SHA_DIGEST_SIZE];
- SHA(args[0]->data, args[0]->size, digest);
+ SHA_hash(args[0]->data, args[0]->size, digest);
FreeValue(args[0]);
if (argc == 1) {
@@ -1017,12 +1281,12 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE);
for (i = 1; i < argc; ++i) {
if (args[i]->type != VAL_STRING) {
- fprintf(stderr, "%s(): arg %d is not a string; skipping",
+ printf("%s(): arg %d is not a string; skipping",
name, i);
} else if (ParseSha1(args[i]->data, arg_digest) != 0) {
// Warn about bad args and skip them.
- fprintf(stderr, "%s(): error parsing \"%s\" as sha-1; skipping",
- name, args[i]->data);
+ printf("%s(): error parsing \"%s\" as sha-1; skipping",
+ name, args[i]->data);
} else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) {
break;
}
@@ -1082,9 +1346,24 @@ void RegisterInstallFunctions() {
RegisterFunction("package_extract_dir", PackageExtractDirFn);
RegisterFunction("package_extract_file", PackageExtractFileFn);
RegisterFunction("symlink", SymlinkFn);
+
+ // Maybe, at some future point, we can delete these functions? They have been
+ // replaced by perm_set and perm_set_recursive.
RegisterFunction("set_perm", SetPermFn);
RegisterFunction("set_perm_recursive", SetPermFn);
+ // Usage:
+ // set_metadata("filename", "key1", "value1", "key2", "value2", ...)
+ // Example:
+ // set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0);
+ RegisterFunction("set_metadata", SetMetadataFn);
+
+ // Usage:
+ // set_metadata_recursive("dirname", "key1", "value1", "key2", "value2", ...)
+ // Example:
+ // set_metadata_recursive("/system", "uid", 0, "gid", 0, "fmode", 0644, "dmode", 0755, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0);
+ RegisterFunction("set_metadata_recursive", SetMetadataFn);
+
RegisterFunction("getprop", GetPropFn);
RegisterFunction("file_getprop", FileGetPropFn);
RegisterFunction("write_raw_image", WriteRawImageFn);
diff --git a/updater/updater.c b/updater/updater.c
index 7aa95e761..39c52b49d 100644
--- a/updater/updater.c
+++ b/updater/updater.c
@@ -39,13 +39,14 @@ struct selabel_handle *sehandle;
int main(int argc, char** argv) {
// Various things log information to stdout or stderr more or less
- // at random. The log file makes more sense if buffering is
- // turned off so things appear in the right order.
+ // at random (though we've tried to standardize on stdout). The
+ // log file makes more sense if buffering is turned off so things
+ // appear in the right order.
setbuf(stdout, NULL);
setbuf(stderr, NULL);
if (argc != 4) {
- fprintf(stderr, "unexpected number of arguments (%d)\n", argc);
+ printf("unexpected number of arguments (%d)\n", argc);
return 1;
}
@@ -53,7 +54,7 @@ int main(int argc, char** argv) {
if ((version[0] != '1' && version[0] != '2' && version[0] != '3') ||
version[1] != '\0') {
// We support version 1, 2, or 3.
- fprintf(stderr, "wrong updater binary API; expected 1, 2, or 3; "
+ printf("wrong updater binary API; expected 1, 2, or 3; "
"got %s\n",
argv[1]);
return 2;
@@ -72,20 +73,20 @@ int main(int argc, char** argv) {
int err;
err = mzOpenZipArchive(package_data, &za);
if (err != 0) {
- fprintf(stderr, "failed to open package %s: %s\n",
+ printf("failed to open package %s: %s\n",
package_data, strerror(err));
return 3;
}
const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME);
if (script_entry == NULL) {
- fprintf(stderr, "failed to find %s in %s\n", SCRIPT_NAME, package_data);
+ printf("failed to find %s in %s\n", SCRIPT_NAME, package_data);
return 4;
}
char* script = malloc(script_entry->uncompLen+1);
if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) {
- fprintf(stderr, "failed to read script from package\n");
+ printf("failed to read script from package\n");
return 5;
}
script[script_entry->uncompLen] = '\0';
@@ -121,7 +122,7 @@ int main(int argc, char** argv) {
yy_scan_string(script);
int error = yyparse(&root, &error_count);
if (error != 0 || error_count > 0) {
- fprintf(stderr, "%d parse errors\n", error_count);
+ printf("%d parse errors\n", error_count);
return 6;
}
@@ -140,7 +141,6 @@ int main(int argc, char** argv) {
}
if (!sehandle) {
- fprintf(stderr, "Warning: No file_contexts\n");
fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n");
}
@@ -159,10 +159,10 @@ int main(int argc, char** argv) {
char* result = Evaluate(&state, root);
if (result == NULL) {
if (state.errmsg == NULL) {
- fprintf(stderr, "script aborted (no error message)\n");
+ printf("script aborted (no error message)\n");
fprintf(cmd_pipe, "ui_print script aborted (no error message)\n");
} else {
- fprintf(stderr, "script aborted: %s\n", state.errmsg);
+ printf("script aborted: %s\n", state.errmsg);
char* line = strtok(state.errmsg, "\n");
while (line) {
fprintf(cmd_pipe, "ui_print %s\n", line);
@@ -173,7 +173,7 @@ int main(int argc, char** argv) {
free(state.errmsg);
return 7;
} else {
- fprintf(stderr, "script result was [%s]\n", result);
+ fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result);
free(result);
}
diff --git a/verifier.cpp b/verifier.cpp
index a93e8d18b..ccc0742d2 100644
--- a/verifier.cpp
+++ b/verifier.cpp
@@ -20,6 +20,7 @@
#include "mincrypt/rsa.h"
#include "mincrypt/sha.h"
+#include "mincrypt/sha256.h"
#include <string.h>
#include <stdio.h>
@@ -38,23 +39,13 @@
int verify_file(const char* path) {
//ui->SetProgress(0.0);
- int numKeys;
- RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);
- if (loadedKeys == NULL) {
+ int numKeys;
+ Certificate* pKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);
+ if (pKeys == NULL) {
LOGE("Failed to load keys\n");
- return VERIFY_FAILURE;
+ return INSTALL_CORRUPT;
}
- /*
- LOGI("%d key(s) loaded from %s\n\n RSA Key:\n\n", numKeys, PUBLIC_KEYS_FILE);
- int rsa_size = sizeof(RSAPublicKey);
- unsigned char* ptr = (unsigned char*) loadedKeys;
- unsigned int valuedees;
- for (int dees2 = 0; dees2 < rsa_size; dees2++) {
- valuedees = *ptr;
- printf("%02x ", valuedees);
- ptr++;
- }
- printf("\n\n");*/
+ LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);
FILE* f = fopen(path, "rb");
if (f == NULL) {
@@ -87,6 +78,7 @@ int verify_file(const char* path) {
}
if (footer[2] != 0xff || footer[3] != 0xff) {
+ LOGE("footer is wrong\n");
fclose(f);
return VERIFY_FAILURE;
}
@@ -158,8 +150,19 @@ int verify_file(const char* path) {
#define BUFFER_SIZE 4096
- SHA_CTX ctx;
- SHA_init(&ctx);
+ bool need_sha1 = false;
+ bool need_sha256 = false;
+ for (i = 0; i < numKeys; ++i) {
+ switch (pKeys[i].hash_len) {
+ case SHA_DIGEST_SIZE: need_sha1 = true; break;
+ case SHA256_DIGEST_SIZE: need_sha256 = true; break;
+ }
+ }
+
+ SHA_CTX sha1_ctx;
+ SHA256_CTX sha256_ctx;
+ SHA_init(&sha1_ctx);
+ SHA256_init(&sha256_ctx);
unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE);
if (buffer == NULL) {
LOGE("failed to alloc memory for sha1 buffer\n");
@@ -178,7 +181,8 @@ int verify_file(const char* path) {
fclose(f);
return VERIFY_FAILURE;
}
- SHA_update(&ctx, buffer, size);
+ if (need_sha1) SHA_update(&sha1_ctx, buffer, size);
+ if (need_sha256) SHA256_update(&sha256_ctx, buffer, size);
so_far += size;
double f = so_far / (double)signed_len;
if (f > frac + 0.02 || size == so_far) {
@@ -189,20 +193,28 @@ int verify_file(const char* path) {
fclose(f);
free(buffer);
- const uint8_t* sha1 = SHA_final(&ctx);
+ const uint8_t* sha1 = SHA_final(&sha1_ctx);
+ const uint8_t* sha256 = SHA256_final(&sha256_ctx);
+
for (i = 0; i < numKeys; ++i) {
+ const uint8_t* hash;
+ switch (pKeys[i].hash_len) {
+ case SHA_DIGEST_SIZE: hash = sha1; break;
+ case SHA256_DIGEST_SIZE: hash = sha256; break;
+ default: continue;
+ }
+
// The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that
// the signing tool appends after the signature itself.
- int dees = RSA_verify(loadedKeys+i, eocd + eocd_size - 6 - RSANUMBYTES,
- RSANUMBYTES, sha1);
- if (dees) {
+ if (RSA_verify(pKeys[i].public_key, eocd + eocd_size - 6 - RSANUMBYTES,
+ RSANUMBYTES, hash, pKeys[i].hash_len)) {
LOGI("whole-file signature verified against key %d\n", i);
free(eocd);
return VERIFY_SUCCESS;
} else {
LOGI("failed to verify against key %d\n", i);
}
- LOGI("i: %i, eocd_size: %i, RSANUMBYTES: %i, returned %i\n", i, eocd_size, RSANUMBYTES, dees);
+ LOGI("i: %i, eocd_size: %i, RSANUMBYTES: %i\n", i, eocd_size, RSANUMBYTES);
}
free(eocd);
LOGE("failed to verify whole-file signature\n");
@@ -228,10 +240,19 @@ int verify_file(const char* path) {
// The file may contain multiple keys in this format, separated by
// commas. The last key must not be followed by a comma.
//
+// A Certificate is a pair of an RSAPublicKey and a particular hash
+// (we support SHA-1 and SHA-256; we store the hash length to signify
+// which is being used). The hash used is implied by the version number.
+//
+// 1: 2048-bit RSA key with e=3 and SHA-1 hash
+// 2: 2048-bit RSA key with e=65537 and SHA-1 hash
+// 3: 2048-bit RSA key with e=3 and SHA-256 hash
+// 4: 2048-bit RSA key with e=65537 and SHA-256 hash
+//
// Returns NULL if the file failed to parse, or if it contain zero keys.
-RSAPublicKey*
+Certificate*
load_keys(const char* filename, int* numKeys) {
- RSAPublicKey* out = NULL;
+ Certificate* out = NULL;
*numKeys = 0;
FILE* f = fopen(filename, "r");
@@ -245,29 +266,39 @@ load_keys(const char* filename, int* numKeys) {
bool done = false;
while (!done) {
++*numKeys;
- out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey));
- RSAPublicKey* key = out + (*numKeys - 1);
+ out = (Certificate*)realloc(out, *numKeys * sizeof(Certificate));
+ Certificate* cert = out + (*numKeys - 1);
+ cert->public_key = (RSAPublicKey*)malloc(sizeof(RSAPublicKey));
-#ifdef HAS_EXPONENT
char start_char;
if (fscanf(f, " %c", &start_char) != 1) goto exit;
if (start_char == '{') {
// a version 1 key has no version specifier.
- key->exponent = 3;
+ cert->public_key->exponent = 3;
+ cert->hash_len = SHA_DIGEST_SIZE;
} else if (start_char == 'v') {
int version;
if (fscanf(f, "%d {", &version) != 1) goto exit;
- if (version == 2) {
- key->exponent = 65537;
- } else {
- goto exit;
+ switch (version) {
+ case 2:
+ cert->public_key->exponent = 65537;
+ cert->hash_len = SHA_DIGEST_SIZE;
+ break;
+ case 3:
+ cert->public_key->exponent = 3;
+ cert->hash_len = SHA256_DIGEST_SIZE;
+ break;
+ case 4:
+ cert->public_key->exponent = 65537;
+ cert->hash_len = SHA256_DIGEST_SIZE;
+ break;
+ default:
+ goto exit;
}
}
+ RSAPublicKey* key = cert->public_key;
if (fscanf(f, " %i , 0x%x , { %u",
-#else
- if (fscanf(f, " { %i , 0x%x , { %u",
-#endif
&(key->len), &(key->n0inv), &(key->n[0])) != 3) {
goto exit;
}
@@ -298,9 +329,7 @@ load_keys(const char* filename, int* numKeys) {
LOGE("unexpected character between keys\n");
goto exit;
}
-#ifdef HAS_EXPONENT
- LOGI("read key e=%d\n", key->exponent);
-#endif
+ LOGI("read key e=%d hash=%d\n", key->exponent, cert->hash_len);
}
}
diff --git a/verifier.h b/verifier.h
index b355b3eb7..d70417340 100644
--- a/verifier.h
+++ b/verifier.h
@@ -25,12 +25,17 @@ enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT };
static const float VERIFICATION_PROGRESS_FRACTION = 0.25;
+typedef struct Certificate {
+ int hash_len; // SHA_DIGEST_SIZE (SHA-1) or SHA256_DIGEST_SIZE (SHA-256)
+ RSAPublicKey* public_key;
+} Certificate;
+
/* Look in the file for a signature footer, and verify that it
* matches one of the given keys. Return one of the constants below.
*/
int verify_file(const char* path);
-RSAPublicKey* load_keys(const char* filename, int* numKeys);
+Certificate* load_keys(const char* filename, int* numKeys);
#define VERIFY_SUCCESS 0
#define VERIFY_FAILURE 1
diff --git a/verifier_test.cpp b/verifier_test.cpp
index 2ef52a0f7..1063cbae5 100644
--- a/verifier_test.cpp
+++ b/verifier_test.cpp
@@ -21,80 +21,82 @@
#include "common.h"
#include "verifier.h"
#include "ui.h"
+#include "mincrypt/sha.h"
+#include "mincrypt/sha256.h"
// This is build/target/product/security/testkey.x509.pem after being
// dumped out by dumpkey.jar.
RSAPublicKey test_key =
{ 64, 0xc926ad21,
- { 1795090719, 2141396315, 950055447, -1713398866,
- -26044131, 1920809988, 546586521, -795969498,
- 1776797858, -554906482, 1805317999, 1429410244,
- 129622599, 1422441418, 1783893377, 1222374759,
- -1731647369, 323993566, 28517732, 609753416,
- 1826472888, 215237850, -33324596, -245884705,
- -1066504894, 774857746, 154822455, -1797768399,
- -1536767878, -1275951968, -1500189652, 87251430,
- -1760039318, 120774784, 571297800, -599067824,
- -1815042109, -483341846, -893134306, -1900097649,
- -1027721089, 950095497, 555058928, 414729973,
- 1136544882, -1250377212, 465547824, -236820568,
- -1563171242, 1689838846, -404210357, 1048029507,
- 895090649, 247140249, 178744550, -747082073,
- -1129788053, 109881576, -350362881, 1044303212,
- -522594267, -1309816990, -557446364, -695002876},
- { -857949815, -510492167, -1494742324, -1208744608,
- 251333580, 2131931323, 512774938, 325948880,
- -1637480859, 2102694287, -474399070, 792812816,
- 1026422502, 2053275343, -1494078096, -1181380486,
- 165549746, -21447327, -229719404, 1902789247,
- 772932719, -353118870, -642223187, 216871947,
- -1130566647, 1942378755, -298201445, 1055777370,
- 964047799, 629391717, -2062222979, -384408304,
- 191868569, -1536083459, -612150544, -1297252564,
- -1592438046, -724266841, -518093464, -370899750,
- -739277751, -1536141862, 1323144535, 61311905,
- 1997411085, 376844204, 213777604, -217643712,
- 9135381, 1625809335, -1490225159, -1342673351,
- 1117190829, -57654514, 1825108855, -1281819325,
- 1111251351, -1726129724, 1684324211, -1773988491,
- 367251975, 810756730, -1941182952, 1175080310 },
+ { 0x6afee91fu, 0x7fa31d5bu, 0x38a0b217u, 0x99df9baeu,
+ 0xfe72991du, 0x727d3c04u, 0x20943f99u, 0xd08e7826u,
+ 0x69e7c8a2u, 0xdeeccc8eu, 0x6b9af76fu, 0x553311c4u,
+ 0x07b9e247u, 0x54c8bbcau, 0x6a540d81u, 0x48dbf567u,
+ 0x98c92877u, 0x134fbfdeu, 0x01b32564u, 0x24581948u,
+ 0x6cddc3b8u, 0x0cd444dau, 0xfe0381ccu, 0xf15818dfu,
+ 0xc06e6d42u, 0x2e2f6412u, 0x093a6737u, 0x94d83b31u,
+ 0xa466c87au, 0xb3f284a0u, 0xa694ec2cu, 0x053359e6u,
+ 0x9717ee6au, 0x0732e080u, 0x220d5008u, 0xdc4af350u,
+ 0x93d0a7c3u, 0xe330c9eau, 0xcac3da1eu, 0x8ebecf8fu,
+ 0xc2be387fu, 0x38a14e89u, 0x211586f0u, 0x18b846f5u,
+ 0x43be4c72u, 0xb578c204u, 0x1bbfb230u, 0xf1e267a8u,
+ 0xa2d3e656u, 0x64b8e4feu, 0xe7e83d4bu, 0x3e77a943u,
+ 0x3559ffd9u, 0x0ebb0f99u, 0x0aa76ce6u, 0xd3786ea7u,
+ 0xbca8cd6bu, 0x068ca8e8u, 0xeb1de2ffu, 0x3e3ecd6cu,
+ 0xe0d9d825u, 0xb1edc762u, 0xdec60b24u, 0xd6931904u},
+ { 0xccdcb989u, 0xe19281f9u, 0xa6e80accu, 0xb7f40560u,
+ 0x0efb0bccu, 0x7f12b0bbu, 0x1e90531au, 0x136d95d0u,
+ 0x9e660665u, 0x7d54918fu, 0xe3b93ea2u, 0x2f415d10u,
+ 0x3d2df6e6u, 0x7a627ecfu, 0xa6f22d70u, 0xb995907au,
+ 0x09de16b2u, 0xfeb8bd61u, 0xf24ec294u, 0x716a427fu,
+ 0x2e12046fu, 0xeaf3d56au, 0xd9b873adu, 0x0ced340bu,
+ 0xbc9cec09u, 0x73c65903u, 0xee39ce9bu, 0x3eede25au,
+ 0x397633b7u, 0x2583c165u, 0x8514f97du, 0xe9166510u,
+ 0x0b6fae99u, 0xa47139fdu, 0xdb8352f0u, 0xb2ad7f2cu,
+ 0xa11552e2u, 0xd4d490a7u, 0xe11e8568u, 0xe9e484dau,
+ 0xd3ef8449u, 0xa47055dau, 0x4edd9557u, 0x03a78ba1u,
+ 0x770e130du, 0x16762facu, 0x0cbdfcc4u, 0xf3070540u,
+ 0x008b6515u, 0x60e7e1b7u, 0xa72cf7f9u, 0xaff86e39u,
+ 0x4296faadu, 0xfc90430eu, 0x6cc8f377u, 0xb398fd43u,
+ 0x423c5997u, 0x991d59c4u, 0x6464bf73u, 0x96431575u,
+ 0x15e3d207u, 0x30532a7au, 0x8c4be618u, 0x460a4d76u },
3
};
RSAPublicKey test_f4_key =
{ 64, 0xc9bd1f21,
- { 293133087u, 3210546773u, 865313125u, 250921607u,
- 3158780490u, 943703457u, 1242806226u, 2986289859u,
- 2942743769u, 2457906415u, 2719374299u, 1783459420u,
- 149579627u, 3081531591u, 3440738617u, 2788543742u,
- 2758457512u, 1146764939u, 3699497403u, 2446203424u,
- 1744968926u, 1159130537u, 2370028300u, 3978231572u,
- 3392699980u, 1487782451u, 1180150567u, 2841334302u,
- 3753960204u, 961373345u, 3333628321u, 748825784u,
- 2978557276u, 1566596926u, 1613056060u, 2600292737u,
- 1847226629u, 50398611u, 1890374404u, 2878700735u,
- 2286201787u, 1401186359u, 619285059u, 731930817u,
- 2340993166u, 1156490245u, 2992241729u, 151498140u,
- 318782170u, 3480838990u, 2100383433u, 4223552555u,
- 3628927011u, 4247846280u, 1759029513u, 4215632601u,
- 2719154626u, 3490334597u, 1751299340u, 3487864726u,
- 3668753795u, 4217506054u, 3748782284u, 3150295088u },
- { 1772626313u, 445326068u, 3477676155u, 1758201194u,
- 2986784722u, 491035581u, 3922936562u, 702212696u,
- 2979856666u, 3324974564u, 2488428922u, 3056318590u,
- 1626954946u, 664714029u, 398585816u, 3964097931u,
- 3356701905u, 2298377729u, 2040082097u, 3025491477u,
- 539143308u, 3348777868u, 2995302452u, 3602465520u,
- 212480763u, 2691021393u, 1307177300u, 704008044u,
- 2031136606u, 1054106474u, 3838318865u, 2441343869u,
- 1477566916u, 700949900u, 2534790355u, 3353533667u,
- 336163563u, 4106790558u, 2701448228u, 1571536379u,
- 1103842411u, 3623110423u, 1635278839u, 1577828979u,
- 910322800u, 715583630u, 138128831u, 1017877531u,
- 2289162787u, 447994798u, 1897243165u, 4121561445u,
- 4150719842u, 2131821093u, 2262395396u, 3305771534u,
- 980753571u, 3256525190u, 3128121808u, 1072869975u,
- 3507939515u, 4229109952u, 118381341u, 2209831334u },
+ { 0x1178db1fu, 0xbf5d0e55u, 0x3393a165u, 0x0ef4c287u,
+ 0xbc472a4au, 0x383fc5a1u, 0x4a13b7d2u, 0xb1ff2ac3u,
+ 0xaf66b4d9u, 0x9280acefu, 0xa2165bdbu, 0x6a4d6e5cu,
+ 0x08ea676bu, 0xb7ac70c7u, 0xcd158139u, 0xa635ccfeu,
+ 0xa46ab8a8u, 0x445a3e8bu, 0xdc81d9bbu, 0x91ce1a20u,
+ 0x68021cdeu, 0x4516eda9u, 0x8d43c30cu, 0xed1eff14u,
+ 0xca387e4cu, 0x58adc233u, 0x4657ab27u, 0xa95b521eu,
+ 0xdfc0e30cu, 0x394d64a1u, 0xc6b321a1u, 0x2ca22cb8u,
+ 0xb1892d5cu, 0x5d605f3eu, 0x6025483cu, 0x9afd5181u,
+ 0x6e1a7105u, 0x03010593u, 0x70acd304u, 0xab957cbfu,
+ 0x8844abbbu, 0x53846837u, 0x24e98a43u, 0x2ba060c1u,
+ 0x8b88b88eu, 0x44eea405u, 0xb259fc41u, 0x0907ad9cu,
+ 0x13003adau, 0xcf79634eu, 0x7d314ec9u, 0xfbbe4c2bu,
+ 0xd84d0823u, 0xfd30fd88u, 0x68d8a909u, 0xfb4572d9u,
+ 0xa21301c2u, 0xd00a4785u, 0x6862b50cu, 0xcfe49796u,
+ 0xdaacbd83u, 0xfb620906u, 0xdf71e0ccu, 0xbbc5b030u },
+ { 0x69a82189u, 0x1a8b22f4u, 0xcf49207bu, 0x68cc056au,
+ 0xb206b7d2u, 0x1d449bbdu, 0xe9d342f2u, 0x29daea58u,
+ 0xb19d011au, 0xc62f15e4u, 0x9452697au, 0xb62bb87eu,
+ 0x60f95cc2u, 0x279ebb2du, 0x17c1efd8u, 0xec47558bu,
+ 0xc81334d1u, 0x88fe7601u, 0x79992eb1u, 0xb4555615u,
+ 0x2022ac8cu, 0xc79a4b8cu, 0xb288b034u, 0xd6b942f0u,
+ 0x0caa32fbu, 0xa065ba51u, 0x4de9f154u, 0x29f64f6cu,
+ 0x7910af5eu, 0x3ed4636au, 0xe4c81911u, 0x9183f37du,
+ 0x5811e1c4u, 0x29c7a58cu, 0x9715d4d3u, 0xc7e2dce3u,
+ 0x140972ebu, 0xf4c8a69eu, 0xa104d424u, 0x5dabbdfbu,
+ 0x41cb4c6bu, 0xd7f44717u, 0x61785ff7u, 0x5e0bc273u,
+ 0x36426c70u, 0x2aa6f08eu, 0x083badbfu, 0x3cab941bu,
+ 0x8871da23u, 0x1ab3dbaeu, 0x7115a21du, 0xf5aa0965u,
+ 0xf766f562u, 0x7f110225u, 0x86d96a04u, 0xc50a120eu,
+ 0x3a751ca3u, 0xc21aa186u, 0xba7359d0u, 0x3ff2b257u,
+ 0xd116e8bbu, 0xfc1318c0u, 0x070e5b1du, 0x83b759a6u },
65537
};
@@ -136,30 +138,37 @@ ui_print(const char* format, ...) {
int main(int argc, char **argv) {
if (argc < 2 || argc > 4) {
- fprintf(stderr, "Usage: %s [-f4 | -file <keys>] <package>\n", argv[0]);
+ fprintf(stderr, "Usage: %s [-sha256] [-f4 | -file <keys>] <package>\n", argv[0]);
return 2;
}
- RSAPublicKey* key = &test_key;
+ Certificate default_cert;
+ Certificate* cert = &default_cert;
+ cert->public_key = &test_key;
+ cert->hash_len = SHA_DIGEST_SIZE;
int num_keys = 1;
++argv;
+ if (strcmp(argv[0], "-sha256") == 0) {
+ ++argv;
+ cert->hash_len = SHA256_DIGEST_SIZE;
+ }
if (strcmp(argv[0], "-f4") == 0) {
++argv;
- key = &test_f4_key;
+ cert->public_key = &test_f4_key;
} else if (strcmp(argv[0], "-file") == 0) {
++argv;
- key = load_keys(argv[0], &num_keys);
+ cert = load_keys(argv[0], &num_keys);
++argv;
}
ui = new FakeUI();
- int result = verify_file(*argv, key, num_keys);
+ int result = verify_file(*argv, cert, num_keys);
if (result == VERIFY_SUCCESS) {
- printf("SUCCESS\n");
+ printf("VERIFIED\n");
return 0;
} else if (result == VERIFY_FAILURE) {
- printf("FAILURE\n");
+ printf("NOT VERIFIED\n");
return 1;
} else {
printf("bad return value\n");
diff --git a/verifier_test.sh b/verifier_test.sh
index 378b0e5ff..65f77f401 100755
--- a/verifier_test.sh
+++ b/verifier_test.sh
@@ -64,33 +64,39 @@ $ADB push $ANDROID_PRODUCT_OUT/system/bin/verifier_test \
expect_succeed() {
testname "$1 (should succeed)"
$ADB push $DATA_DIR/$1 $WORK_DIR/package.zip
- run_command $WORK_DIR/verifier_test $WORK_DIR/package.zip || fail
+ shift
+ run_command $WORK_DIR/verifier_test "$@" $WORK_DIR/package.zip || fail
}
expect_fail() {
testname "$1 (should fail)"
$ADB push $DATA_DIR/$1 $WORK_DIR/package.zip
- run_command $WORK_DIR/verifier_test $WORK_DIR/package.zip && fail
-}
-
-expect_succeed_f4() {
- testname "$1 (should succeed)"
- $ADB push $DATA_DIR/$1 $WORK_DIR/package.zip
- run_command $WORK_DIR/verifier_test -f4 $WORK_DIR/package.zip || fail
-}
-
-expect_fail_f4() {
- testname "$1 (should fail)"
- $ADB push $DATA_DIR/$1 $WORK_DIR/package.zip
- run_command $WORK_DIR/verifier_test -f4 $WORK_DIR/package.zip && fail
+ shift
+ run_command $WORK_DIR/verifier_test "$@" $WORK_DIR/package.zip && fail
}
+# not signed at all
expect_fail unsigned.zip
+# signed in the pre-donut way
expect_fail jarsigned.zip
+
+# success cases
expect_succeed otasigned.zip
-expect_fail_f4 otasigned.zip
-expect_succeed_f4 otasigned_f4.zip
+expect_succeed otasigned_f4.zip -f4
+expect_succeed otasigned_sha256.zip -sha256
+expect_succeed otasigned_f4_sha256.zip -sha256 -f4
+
+# verified against different key
+expect_fail otasigned.zip -f4
expect_fail otasigned_f4.zip
+
+# verified against right key but wrong hash algorithm
+expect_fail otasigned.zip -sha256
+expect_fail otasigned_f4.zip -sha256 -f4
+expect_fail otasigned_sha256.zip
+expect_fail otasigned_f4_sha256.zip -f4
+
+# various other cases
expect_fail random.zip
expect_fail fake-eocd.zip
expect_fail alter-metadata.zip