/* * Read PEM certificate from a file and return as a new X509 structure. */ scoped_ptr<X509> read_x509 (const std::string& path) { const auto bio = make_scoped (BIO_new_file (path.c_str (), "r"), BIO_free); if (!bio) { throw std::runtime_error ("Cannot open file: " + path); } X509 *const cert = PEM_read_bio_X509 (bio.get (), nullptr, nullptr, nullptr); if (!cert) { throw std::runtime_error ("Cannot read certificate: " + path); } return make_scoped (cert, X509_free); }
int main (int argc, char* argv[]) { // help if (argc == 2 && help_requested (argv[1])) { usage (argv[0], std::cout); return EXIT_SUCCESS; } // misuse if (argc != 4) { usage (argv[0], std::cerr); return EXIT_FAILURE; } // This has to be called before the verification where a number of cryptographic // algorithms is used (they might not be available by default). OpenSSL_add_all_algorithms (); try { // read the certificate const auto cert = read_x509 (argv[1]); // get the public key from the certificate (the signature was created with // the private key) const auto key = make_scoped (X509_get_pubkey (cert.get ()), EVP_PKEY_free); if (!key) { throw std::runtime_error ("Cannot get public key"); } // create an enveloped message digest context const auto ctx = make_scoped (EVP_MD_CTX_create (), EVP_MD_CTX_destroy); // initialize the MD context with SHA1 algorithm (the choice of the // algorithm should be more flexible in most real cases) if (!EVP_VerifyInit_ex (ctx.get (), EVP_sha1 (), nullptr)) { throw std::runtime_error("Cannot initialize verification"); } // the data about to be digested const std::vector<byte_t> data = read_file (argv[2]); // the signature signed by the private key paired with the public key we're // about to use (the public key is delivered with the certificate so it's // authenticity can be verified) const std::vector<byte_t> signature = read_file (argv[3]); // calculate the digest if (!EVP_VerifyUpdate (ctx.get (), data.data (), data.size ())) { throw std::runtime_error("Failed to process data"); } // verify the digest const int result = EVP_VerifyFinal ( ctx.get (), signature.data (), signature.size (), key.get ()); if (result < 0) { throw std::runtime_error ("Verification error"); } if (result != 0) { std::cout << "Verification OK" << std::endl; return EXIT_SUCCESS; } else { std::cerr << "Verification failed\n"; return EXIT_FAILURE; } } catch (const std::exception& e) { std::cerr << "Error: " << e.what () << '\n'; return EXIT_FAILURE; } catch (...) { std::cerr << "Unknown error\n"; return EXIT_FAILURE; } }
int main() { auto t1 = make_scoped( [] (auto x) noexcept { } | options, [] (auto x) noexcept { } | options, [] (auto x) noexcept { } | on_termination ); auto t2 = make_scoped( [] (auto x) noexcept { } | options, [] (auto x) noexcept { } | options, [] (auto x) noexcept { } | on_termination ); auto t3 = make_scoped( [] (auto x) noexcept { } | options, [] (auto x) noexcept { } | options, [] (auto x) noexcept { } | on_termination ); // Assumptions: // - Logical task expressions only store lvalue refs to tasks. So the // tasks must have been created earlier, and if the tasks go out of // scope before the task created from the logical task expression, bad // things will happen. // - Don't make abort_early the default. Unexpected behavior will result // in situations, say, where the programmer wants to run a task after at // least one task in a set finishes, but allow the new task to run // concurrently while the other tasks that have yet to be finished // continue to run. // - Note how the same task can appear in multiple subexpressions. // We must prepare for this with respect to synchronization. // - When a task expression tree is run, it should run each task that // appears in a subexpression. Here, also, we can make the assumption // that none of the tasks in the expression tree have already been // started or terminated. // - To abort early, use cancellation tokens. auto t4 = ((t1 && t2) || (t2 && t3)). make_scoped( [] (auto x) noexcept { // } | options, [] (auto x) noexcept { // } | options ); }
/* * A RAII wrapper around read_x509_raw(). */ scoped_ptr<X509> read_x509 (const std::string& path) { return make_scoped (read_x509_raw (path), X509_free); }