Fix merge conflicts and update for 4.4 kitkat
Make a copy of libmincrypt in TWRP source so we do not have to ifdef verifier.cpp for various versions of mincrypt. Remove reboot tool from toolbox (it was removed from 4.4 and did not compile properly on some devices in older trees)
This commit is contained in:
+6
-5
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
+12
-6
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
@@ -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__
|
||||
@@ -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
|
||||
@@ -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__
|
||||
@@ -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__
|
||||
@@ -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.
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+14
-13
@@ -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;
|
||||
|
||||
+101
-26
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+40
-11
@@ -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);
|
||||
}
|
||||
|
||||
+8
-1
@@ -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);
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
+25
@@ -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-----
|
||||
Vendored
BIN
Binary file not shown.
Vendored
+27
@@ -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-----
|
||||
Vendored
+27
@@ -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-----
|
||||
+11
-7
@@ -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 := \
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+310
-31
@@ -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);
|
||||
|
||||
+12
-12
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+68
-39
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -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
|
||||
|
||||
+80
-71
@@ -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");
|
||||
|
||||
+22
-16
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user