diff options
Diffstat (limited to 'verifier.cpp')
-rw-r--r-- | verifier.cpp | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/verifier.cpp b/verifier.cpp index 283e04300..1dc52a0ef 100644 --- a/verifier.cpp +++ b/verifier.cpp @@ -27,9 +27,13 @@ #include <vector> #include <android-base/logging.h> +#include <openssl/bio.h> #include <openssl/bn.h> #include <openssl/ecdsa.h> +#include <openssl/evp.h> #include <openssl/obj_mac.h> +#include <openssl/pem.h> +#include <openssl/rsa.h> #include "asn1_decoder.h" #include "otautil/print_sha1.h" @@ -441,6 +445,70 @@ std::unique_ptr<EC_KEY, ECKEYDeleter> parse_ec_key(FILE* file) { return key; } +bool LoadCertificateFromBuffer(const std::vector<uint8_t>& pem_content, Certificate* cert) { + std::unique_ptr<BIO, decltype(&BIO_free)> content( + BIO_new_mem_buf(pem_content.data(), pem_content.size()), BIO_free); + + 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"; + return false; + } + + 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); + return false; + } + + 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"; + return false; + } + + int key_type = EVP_PKEY_id(public_key.get()); + // TODO(xunchang) check the rsa key has exponent 3 or 65537 with RSA_get0_key; and ec key is + // 256 bits. + 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) { + LOG(ERROR) << "Failed to get the rsa key info from public key"; + return false; + } + } else if (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) { + LOG(ERROR) << "Failed to get the ec key info from the public key"; + return false; + } + } else { + LOG(ERROR) << "Unrecognized public key type " << OBJ_nid2ln(key_type); + return false; + } + + return true; +} + // Reads a file containing one or more public keys as produced by // DumpPublicKey: this is an RSAPublicKey struct as it would appear // as a C source literal, eg: |