static SigVerifyResult verify_signature_with_key(const char *path, const char *sig_path, EVP_PKEY &public_key) { ScopedBIO bio_data_in(BIO_new_file(path, "rb"), BIO_free); if (!bio_data_in) { LOGE("%s: Failed to open input file", path); openssl_log_errors(); return SigVerifyResult::Failure; } ScopedBIO bio_sig_in(BIO_new_file(sig_path, "rb"), BIO_free); if (!bio_sig_in) { LOGE("%s: Failed to open signature file", sig_path); openssl_log_errors(); return SigVerifyResult::Failure; } auto ret = sign::verify_data(*bio_data_in, *bio_sig_in, public_key); if (!ret) { if (ret.error().ec == sign::Error::BadSignature) { return SigVerifyResult::Invalid; } else { LOGE("%s: Failed to verify signature: %s", sig_path, ret.error().ec.message().c_str()); if (ret.error().has_openssl_error) { openssl_log_errors(); } return SigVerifyResult::Failure; } } return SigVerifyResult::Valid; }
SigVerifyResult verify_signature(const char *path, const char *sig_path) { for (const std::string &hex_der : valid_certs) { std::string der; if (!hex2bin(hex_der, der)) { LOGE("Failed to convert hex-encoded certificate to binary: %s", hex_der.c_str()); return SigVerifyResult::Failure; } // Cast to (void *) is okay since BIO_new_mem_buf() creates a read-only // BIO object ScopedBIO bio_x509_cert(BIO_new_mem_buf( der.data(), static_cast<int>(der.size())), BIO_free); if (!bio_x509_cert) { LOGE("Failed to create BIO for X509 certificate: %s", hex_der.c_str()); openssl_log_errors(); return SigVerifyResult::Failure; } // Load DER-encoded certificate ScopedX509 cert(d2i_X509_bio(bio_x509_cert.get(), nullptr), X509_free); if (!cert) { LOGE("Failed to load X509 certificate: %s", hex_der.c_str()); openssl_log_errors(); return SigVerifyResult::Failure; } // Get public key from certificate ScopedEVP_PKEY public_key(X509_get_pubkey(cert.get()), EVP_PKEY_free); if (!public_key) { LOGE("Failed to load public key from X509 certificate: %s", hex_der.c_str()); openssl_log_errors(); return SigVerifyResult::Failure; } SigVerifyResult result = verify_signature_with_key(path, sig_path, *public_key); if (result == SigVerifyResult::Invalid) { // Keep trying ... continue; } return result; } return SigVerifyResult::Invalid; }
static bool generate_keys(ScopedEVP_PKEY &private_key_out, ScopedEVP_PKEY &public_key_out) { ScopedEVP_PKEY private_key(EVP_PKEY_new(), EVP_PKEY_free); ScopedEVP_PKEY public_key(EVP_PKEY_new(), EVP_PKEY_free); ScopedRSA rsa(RSA_new(), RSA_free); ScopedBIGNUM e(BN_new(), BN_free); if (!private_key) { LOGE("Failed to allocate private key"); openssl_log_errors(); return false; } if (!public_key) { LOGE("Failed to allocate public key"); openssl_log_errors(); return false; } if (!rsa) { LOGE("Failed to allocate RSA"); openssl_log_errors(); return false; } if (!e) { LOGE("Failed to allocate BIGNUM"); openssl_log_errors(); return false; } BN_set_word(e.get(), RSA_F4); if (RSA_generate_key_ex(rsa.get(), 2048, e.get(), nullptr) < 0) { LOGE("RSA_generate_key_ex() failed"); openssl_log_errors(); return false; } if (!EVP_PKEY_assign_RSA(private_key.get(), RSAPrivateKey_dup(rsa.get()))) { LOGE("EVP_PKEY_assign_RSA() failed for private key"); openssl_log_errors(); return false; } if (!EVP_PKEY_assign_RSA(public_key.get(), RSAPublicKey_dup(rsa.get()))) { LOGE("EVP_PKEY_assign_RSA() failed for public key"); openssl_log_errors(); return false; } private_key_out = std::move(private_key); public_key_out = std::move(public_key); return true; }