int verify_file(VerifierInterface* package, const std::vector<Certificate>& keys) {
CHECK(package);
package->SetProgress(0.0);
// An archive with a whole-file signature will end in six bytes: // // (2-byte signature start) $ff $ff (2-byte comment size) // // (As far as the ZIP format is concerned, these are part of the archive comment.) We start by // reading this footer, this tells us how far back from the end we have to start reading to find // the whole comment.
if (signature_start > comment_size) {
LOG(ERROR) << "signature start: " << signature_start
<< " is larger than comment size: " << comment_size; return VERIFY_FAILURE;
}
if (signature_start <= FOOTER_SIZE) {
LOG(ERROR) << "Signature start is in the footer"; return VERIFY_FAILURE;
}
#define EOCD_HEADER_SIZE 22
// The end-of-central-directory record is 22 bytes plus any comment length.
size_t eocd_size = comment_size + EOCD_HEADER_SIZE;
if (length < eocd_size) {
LOG(ERROR) << "not big enough to contain EOCD"; return VERIFY_FAILURE;
}
// Determine how much of the file is covered by the signature. This is everything except the // signature data and length, which includes all of the EOCD except for the comment length field // (2 bytes) and the comment data.
uint64_t signed_len = length - eocd_size + EOCD_HEADER_SIZE - 2;
uint8_t eocd[eocd_size]; if (!package->ReadFullyAtOffset(eocd, eocd_size, length - eocd_size)) {
LOG(ERROR) << "Failed to read EOCD of " << eocd_size << " bytes"; return VERIFY_FAILURE;
}
// If this is really is the EOCD record, it will begin with the magic number $50 $4b $05 $06. if (eocd[0] != 0x50 || eocd[1] != 0x4b || eocd[2] != 0x05 || eocd[3] != 0x06) {
LOG(ERROR) << "signature length doesn't match EOCD marker"; return VERIFY_FAILURE;
}
for (size_t i = 4; i < eocd_size - 3; ++i) { if (eocd[i] == 0x50 && eocd[i + 1] == 0x4b && eocd[i + 2] == 0x05 && eocd[i + 3] == 0x06) { // If the sequence $50 $4b $05 $06 appears anywhere after the real one, libziparchive will // find the later (wrong) one, which could be exploitable. Fail the verification if this // sequence occurs anywhere after the real one.
LOG(ERROR) << "EOCD marker occurs after start of EOCD"; return VERIFY_FAILURE;
}
}
std::vector<HasherUpdateCallback> hashers; if (need_sha1) {
hashers.emplace_back(
std::bind(&SHA1_Update, &sha1_ctx, std::placeholders::_1, std::placeholders::_2));
} if (need_sha256) {
hashers.emplace_back(
std::bind(&SHA256_Update, &sha256_ctx, std::placeholders::_1, std::placeholders::_2));
}
double frac = -1.0;
uint64_t so_far = 0; while (so_far < signed_len) { // On a Nexus 5X, experiment showed 16MiB beat 1MiB by 6% faster for a 1196MiB full OTA and // 60% for an 89MiB incremental OTA. http://b/28135231.
uint64_t read_size = std::min<uint64_t>(signed_len - so_far, 16 * MiB);
package->UpdateHashAtOffset(hashers, so_far, read_size);
so_far += read_size;
std::vector<uint8_t> sig_der; if (!read_pkcs7(signature, signature_size, &sig_der)) {
LOG(ERROR) << "Could not find signature DER block"; return VERIFY_FAILURE;
}
// Check to make sure at least one of the keys matches the signature. Since any key can match, // we need to try each before determining a verification failure has happened. for (size_t i = 0; i < keys.size(); i++) { constauto& key = keys[i]; const uint8_t* hash; int hash_nid; switch (key.hash_len) { case SHA_DIGEST_LENGTH:
hash = sha1;
hash_nid = NID_sha1; break; case SHA256_DIGEST_LENGTH:
hash = sha256;
hash_nid = NID_sha256; break; default: continue;
}
// The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that the signing tool appends // after the signature itself. if (key.key_type == Certificate::KEY_TYPE_RSA) { if (!RSA_verify(hash_nid, hash, key.hash_len, sig_der.data(), sig_der.size(),
key.rsa.get())) {
LOG(INFO) << "failed to verify against RSA key " << i; continue;
}
int32_t iter_status = StartIteration(handle, &cookie, "", "x509.pem"); if (iter_status != 0) {
LOG(ERROR) << "Failed to iterate over entries in the certificate zipfile: "
<< ErrorCodeString(iter_status); return {};
}
std::unique_ptr<void, decltype(&EndIteration)> cookie_guard(cookie, &EndIteration);
std::vector<Certificate> result;
std::string_view name;
ZipEntry64 entry; while ((iter_status = Next(cookie, &entry, &name)) == 0) { if (entry.uncompressed_length > std::numeric_limits<size_t>::max()) {
LOG(ERROR) << "Failed to extract " << name
<< " because's uncompressed size exceeds size of address space. "
<< entry.uncompressed_length; return {};
}
std::vector<uint8_t> pem_content(entry.uncompressed_length); if (int32_t extract_status =
ExtractToMemory(handle, &entry, pem_content.data(), pem_content.size());
extract_status != 0) {
LOG(ERROR) << "Failed to extract " << name; return {};
}
Certificate cert(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr); // Aborts the parsing if we fail to load one of the key file. if (!LoadCertificateFromBuffer(pem_content, &cert)) {
LOG(ERROR) << "Failed to load keys from " << name; return {};
}
result.emplace_back(std::move(cert));
}
if (iter_status != -1) {
LOG(ERROR) << "Error while iterating over zip entries: " << ErrorCodeString(iter_status); return {};
}
const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key.get()); if (!ec_group) {
LOG(ERROR) << "Failed to get the ec_group from the ec_key"; returnfalse;
} auto degree = EC_GROUP_get_degree(ec_group); if (degree != 256) {
LOG(ERROR) << "Field size of the ec key should be 256 bits long, actual: " << degree; returnfalse;
}
std::unique_ptr<X509, decltype(&X509_free)> x509(
PEM_read_bio_X509(content.get(), nullptr, nullptr, nullptr), X509_free); if (!x509) {
LOG(ERROR) << "Failed to read x509 certificate"; returnfalse;
}
int nid = X509_get_signature_nid(x509.get()); switch (nid) { // SignApk has historically accepted md5WithRSA certificates, but treated them as // sha1WithRSA anyway. Continue to do so for backwards compatibility. case NID_md5WithRSA: case NID_md5WithRSAEncryption: case NID_sha1WithRSA: case NID_sha1WithRSAEncryption:
cert->hash_len = SHA_DIGEST_LENGTH; break; case NID_sha256WithRSAEncryption: case NID_ecdsa_with_SHA256:
cert->hash_len = SHA256_DIGEST_LENGTH; break; default:
LOG(ERROR) << "Unrecognized signature nid " << OBJ_nid2ln(nid); returnfalse;
}
std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> public_key(X509_get_pubkey(x509.get()),
EVP_PKEY_free); if (!public_key) {
LOG(ERROR) << "Failed to extract the public key from x509 certificate"; returnfalse;
}
int key_type = EVP_PKEY_id(public_key.get()); if (key_type == EVP_PKEY_RSA) {
cert->key_type = Certificate::KEY_TYPE_RSA;
cert->ec.reset();
cert->rsa.reset(EVP_PKEY_get1_RSA(public_key.get())); if (!cert->rsa || !CheckRSAKey(cert->rsa)) {
LOG(ERROR) << "Failed to validate the rsa key info from public key"; returnfalse;
}
} elseif (key_type == EVP_PKEY_EC) {
cert->key_type = Certificate::KEY_TYPE_EC;
cert->rsa.reset();
cert->ec.reset(EVP_PKEY_get1_EC_KEY(public_key.get())); if (!cert->ec || !CheckECKey(cert->ec)) {
LOG(ERROR) << "Failed to validate the ec key info from the public key"; returnfalse;
}
} else {
LOG(ERROR) << "Unrecognized public key type " << OBJ_nid2ln(key_type); returnfalse;
}
returntrue;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-07-01)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.