diff options
Diffstat (limited to 'otautil/include')
-rw-r--r-- | otautil/include/otautil/package.h | 62 | ||||
-rw-r--r-- | otautil/include/otautil/verifier.h | 101 | ||||
-rw-r--r-- | otautil/include/private/asn1_decoder.h | 56 |
3 files changed, 219 insertions, 0 deletions
diff --git a/otautil/include/otautil/package.h b/otautil/include/otautil/package.h new file mode 100644 index 000000000..f4f4d348b --- /dev/null +++ b/otautil/include/otautil/package.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <stdint.h> + +#include <functional> +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include <ziparchive/zip_archive.h> + +#include "otautil/verifier.h" + +enum class PackageType { + kMemory, + kFile, +}; + +// This class serves as a wrapper for an OTA update package. It aims to provide the common +// interface for both packages loaded in memory and packages read from fd. +class Package : public VerifierInterface { + public: + static std::unique_ptr<Package> CreateMemoryPackage( + const std::string& path, const std::function<void(float)>& set_progress); + static std::unique_ptr<Package> CreateMemoryPackage( + std::vector<uint8_t> content, const std::function<void(float)>& set_progress); + static std::unique_ptr<Package> CreateFilePackage(const std::string& path, + const std::function<void(float)>& set_progress); + + virtual ~Package() = default; + + virtual PackageType GetType() const = 0; + + virtual std::string GetPath() const = 0; + + // Opens the package as a zip file and returns the ZipArchiveHandle. + virtual ZipArchiveHandle GetZipArchiveHandle() = 0; + + // Updates the progress in fraction during package verification. + void SetProgress(float progress) override; + + protected: + // An optional function to update the progress. + std::function<void(float)> set_progress_; +}; diff --git a/otautil/include/otautil/verifier.h b/otautil/include/otautil/verifier.h new file mode 100644 index 000000000..f9e947580 --- /dev/null +++ b/otautil/include/otautil/verifier.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <stdint.h> + +#include <functional> +#include <memory> +#include <vector> + +#include <openssl/ec_key.h> +#include <openssl/rsa.h> +#include <openssl/sha.h> + +constexpr size_t MiB = 1024 * 1024; + +using HasherUpdateCallback = std::function<void(const uint8_t* addr, uint64_t size)>; + +struct RSADeleter { + void operator()(RSA* rsa) const { + RSA_free(rsa); + } +}; + +struct ECKEYDeleter { + void operator()(EC_KEY* ec_key) const { + EC_KEY_free(ec_key); + } +}; + +struct Certificate { + typedef enum { + KEY_TYPE_RSA, + KEY_TYPE_EC, + } KeyType; + + Certificate(int hash_len_, KeyType key_type_, std::unique_ptr<RSA, RSADeleter>&& rsa_, + std::unique_ptr<EC_KEY, ECKEYDeleter>&& ec_) + : hash_len(hash_len_), key_type(key_type_), rsa(std::move(rsa_)), ec(std::move(ec_)) {} + + // SHA_DIGEST_LENGTH (SHA-1) or SHA256_DIGEST_LENGTH (SHA-256) + int hash_len; + KeyType key_type; + std::unique_ptr<RSA, RSADeleter> rsa; + std::unique_ptr<EC_KEY, ECKEYDeleter> ec; +}; + +class VerifierInterface { + public: + virtual ~VerifierInterface() = default; + + // Returns the package size in bytes. + virtual uint64_t GetPackageSize() const = 0; + + // Reads |byte_count| data starting from |offset|, and puts the result in |buffer|. + virtual bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) = 0; + + // Updates the hash contexts for |length| bytes data starting from |start|. + virtual bool UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers, uint64_t start, + uint64_t length) = 0; + + // Updates the progress in fraction during package verification. + virtual void SetProgress(float progress) = 0; +}; + +// Looks for an RSA signature embedded in the .ZIP file comment given the path to the zip. +// Verifies that it matches one of the given public keys. Returns VERIFY_SUCCESS or +// VERIFY_FAILURE (if any error is encountered or no key matches the signature). +int verify_file(VerifierInterface* package, const std::vector<Certificate>& keys); + +// Checks that the RSA key has a modulus of 2048 or 4096 bits long, and public exponent is 3 or +// 65537. +bool CheckRSAKey(const std::unique_ptr<RSA, RSADeleter>& rsa); + +// Checks that the field size of the curve for the EC key is 256 bits. +bool CheckECKey(const std::unique_ptr<EC_KEY, ECKEYDeleter>& ec_key); + +// Parses a PEM-encoded x509 certificate from the given buffer and saves it into |cert|. Returns +// false if there is a parsing failure or the signature's encryption algorithm is not supported. +bool LoadCertificateFromBuffer(const std::vector<uint8_t>& pem_content, Certificate* cert); + +// Iterates over the zip entries with the suffix "x509.pem" and returns a list of recognized +// certificates. Returns an empty list if we fail to parse any of the entries. +std::vector<Certificate> LoadKeysFromZipfile(const std::string& zip_name); + +#define VERIFY_SUCCESS 0 +#define VERIFY_FAILURE 1 diff --git a/otautil/include/private/asn1_decoder.h b/otautil/include/private/asn1_decoder.h new file mode 100644 index 000000000..e5337d9c4 --- /dev/null +++ b/otautil/include/private/asn1_decoder.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ASN1_DECODER_H_ +#define ASN1_DECODER_H_ + +#include <stddef.h> +#include <stdint.h> + +class asn1_context { + public: + asn1_context(const uint8_t* buffer, size_t length) : p_(buffer), length_(length), app_type_(0) {} + int asn1_constructed_type() const; + asn1_context* asn1_constructed_get(); + bool asn1_constructed_skip_all(); + asn1_context* asn1_sequence_get(); + asn1_context* asn1_set_get(); + bool asn1_sequence_next(); + bool asn1_oid_get(const uint8_t** oid, size_t* length); + bool asn1_octet_string_get(const uint8_t** octet_string, size_t* length); + + private: + static constexpr int kMaskConstructed = 0xE0; + static constexpr int kMaskTag = 0x7F; + static constexpr int kMaskAppType = 0x1F; + + static constexpr int kTagOctetString = 0x04; + static constexpr int kTagOid = 0x06; + static constexpr int kTagSequence = 0x30; + static constexpr int kTagSet = 0x31; + static constexpr int kTagConstructed = 0xA0; + + int peek_byte() const; + int get_byte(); + bool skip_bytes(size_t num_skip); + bool decode_length(size_t* out_len); + + const uint8_t* p_; + size_t length_; + int app_type_; +}; + +#endif /* ASN1_DECODER_H_ */ |