1c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 2c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Copyright (C) 2013 The Android Open Source Project 3c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 4c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Licensed under the Apache License, Version 2.0 (the "License"); 5c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// you may not use this file except in compliance with the License. 6c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// You may obtain a copy of the License at 7c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 8c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// http://www.apache.org/licenses/LICENSE-2.0 9c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 10c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Unless required by applicable law or agreed to in writing, software 11c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// distributed under the License is distributed on an "AS IS" BASIS, 12c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// See the License for the specific language governing permissions and 14c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// limitations under the License. 15c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 160d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 17cd47732488cd101eaf0d3558dde5a7d4e4fc260bBen Chan#include <unistd.h> 18cd47732488cd101eaf0d3558dde5a7d4e4fc260bBen Chan 190d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley#include <limits> 200d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley#include <string> 210d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley#include <vector> 220d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 230d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley#include <base/command_line.h> 240d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley#include <base/logging.h> 250d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley#include <base/posix/eintr_wrapper.h> 2603e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko#include <brillo/syslog_logging.h> 270d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley#include <openssl/bio.h> 280d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley#include <openssl/conf.h> 290d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley#include <openssl/err.h> 300d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley#include <openssl/evp.h> 310d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley#include <openssl/pem.h> 320d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley#include <openssl/rsa.h> 330d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley#include <openssl/sha.h> 340d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley#include <openssl/x509.h> 350d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 369151894faea5fa8ccd7d538976390fc95f37d13eSamuel Tan#include "shill/shims/protos/crypto_util.pb.h" 370d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 380d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wileyusing shill_protos::EncryptDataMessage; 390d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wileyusing shill_protos::EncryptDataResponse; 400d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wileyusing shill_protos::VerifyCredentialsMessage; 410d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wileyusing shill_protos::VerifyCredentialsResponse; 420d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wileyusing std::numeric_limits; 430d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wileyusing std::string; 440d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wileyusing std::vector; 450d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 460d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wileynamespace { 470d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 480d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wileyconst char kTrustedCAModulus[] = 490d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley "BC2280BD80F63A21003BAE765E357F3DC3645C559486342F058728CDF7698C17B350A7B8" 500d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley "82FADFC7432DD67EABA06FB7137280A44715C1209950CDEC1462095BA498CDD241B6364E" 510d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley "FFE82E32304A81A842A36C9B336ECAB2F55366E02753861A851EA7393F4A778EFB546666" 520d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley "FB5854C05E39C7F550060BE08AD4CEE16A551F8B1700E669A327E60825693C129D8D052C" 530d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley "D62EA231DEB45250D62049DE71A0F9AD204012F1DD25EBD5E6B836F4D68F7FCA43DCD710" 540d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley "5BE63F518A85B3F3FFF6032DCB234F9CAD18E793058CAC529AF74CE9997ABE6E7E4D0AE3" 550d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley "C61CA993FA3AA5915D1CBD66EBCC60DC8674CACFF8921C987D57FA61479EAB80B7E44880" 560d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley "2A92C51B"; 570d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wileyconst char kCommandVerify[] = "verify"; 580d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wileyconst char kCommandEncrypt[] = "encrypt"; 590d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wileyconst size_t kMacLength = 12; 600d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 610d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// Encrypt |data| with |public_key|. |public_key| is the raw bytes of a key in 620d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// RSAPublicKey format. |data| is some string of bytes smaller than the 630d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// maximum length permissable for encryption with a key of |public_key| size. 640d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// |rsa_ptr| should point to NULL (but should not be NULL). This function may 650d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// set *|rsa_ptr| to an RSA object which should be freed in the caller. 660d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// Returns the encrypted result in |encrypted_output| and returns true on 670d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// success. Returns false on failure. 68758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewartbool EncryptByteStringImpl(const string& public_key, 69758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart const string& data, 70758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart RSA** rsa_ptr, 71758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart string* encrypted_output) { 720d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley CHECK(rsa_ptr); 730d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley CHECK(!*rsa_ptr); 740d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley CHECK(encrypted_output); 750d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 760d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley // This pointer will be incremented internally by the parsing routine. 77758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart const unsigned char* throwaway_ptr = 78758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart reinterpret_cast<const unsigned char*>(public_key.data()); 790d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley *rsa_ptr = d2i_RSAPublicKey(NULL, &throwaway_ptr, public_key.length()); 80758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart RSA* rsa = *rsa_ptr; 810d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (!rsa) { 820d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Failed to parse public key."; 830d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 840d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 850d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 86cd47732488cd101eaf0d3558dde5a7d4e4fc260bBen Chan vector<unsigned char> rsa_output(RSA_size(rsa)); 870d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(INFO) << "Encrypting data with public key."; 880d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley const int encrypted_length = RSA_public_encrypt( 890d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley data.length(), 900d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley // The API helpfully tells us that this operation will treat this buffer 910d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley // as read only, but fails to mark the parameter const. 92758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart reinterpret_cast<unsigned char*>(const_cast<char*>(data.data())), 93cd47732488cd101eaf0d3558dde5a7d4e4fc260bBen Chan rsa_output.data(), 940d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley rsa, 950d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley RSA_PKCS1_PADDING); 960d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (encrypted_length <= 0) { 970d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Error during encryption."; 980d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 990d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 1000d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 101758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart encrypted_output->assign(reinterpret_cast<char*>(rsa_output.data()), 1020d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley encrypted_length); 1030d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return true; 1040d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley} 1050d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 1060d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// Parse the EncryptDataMessage contained in |raw_input| and return an 1070d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// EncryptDataResponse in output on success. Returns true on success and 1080d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// false otherwise. 109758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewartbool EncryptByteString(const string& raw_input, string* output) { 1100d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley EncryptDataMessage message; 1110d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (!message.ParseFromString(raw_input)) { 1120d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Failed to read VerifyCredentialsMessage from stdin."; 1130d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 1140d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 1150d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 1160d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (!message.has_public_key() || !message.has_data()) { 1170d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Request lacked necessary fields."; 1180d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 1190d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 1200d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 121758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart RSA* rsa = NULL; 1220d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley string encrypted_output; 1230d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley bool operation_successful = EncryptByteStringImpl( 1240d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley message.public_key(), message.data(), &rsa, &encrypted_output); 1250d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (rsa) { 1260d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley RSA_free(rsa); 1270d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley rsa = NULL; 1280d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 1290d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 1300d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (operation_successful) { 1310d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(INFO) << "Filling out protobuf."; 1320d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley EncryptDataResponse response; 1330d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley response.set_encrypted_data(encrypted_output); 1340d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley response.set_ret(shill_protos::OK); 1350d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley output->clear(); 1360d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(INFO) << "Serializing protobuf."; 1370d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (!response.SerializeToString(output)) { 1380d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Failed while writing encrypted data."; 1390d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 1400d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 1410d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(INFO) << "Encoding finished successfully."; 1420d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 1430d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 1440d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return operation_successful; 1450d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley} 1460d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 1470d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// Verify that the destination described by |certificate| is valid. 1480d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// 1490d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// 1) The MAC address listed in the certificate matches |connected_mac|. 150c97fc2d03a8dfddf55c55562c72d4d29d0fc2dc5Christopher Wiley// 2) The certificate is a valid PEM encoded certificate signed by our 1510d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// trusted CA. 152c97fc2d03a8dfddf55c55562c72d4d29d0fc2dc5Christopher Wiley// 3) |signed_data| matches the hashed |unsigned_data| encrypted with 1530d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// the public key in |certificate|. 1540d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// 155758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart// All pointers should be valid, but point to NULL values. Sets* ptr to 1560d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// NULL or a valid object which should be freed with the appropriate destructor 1570d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// upon completion. 158758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewartbool VerifyCredentialsImpl(const string& certificate, 159758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart const string& signed_data, 160758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart const string& unsigned_data, 161758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart const string& connected_mac, 162758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart RSA** rsa_ptr, 163758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart EVP_PKEY** pkey_ptr, 164758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart BIO** raw_certificate_bio_ptr, 165758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart X509** x509_ptr) { 1660d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley CHECK(rsa_ptr); 1670d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley CHECK(pkey_ptr); 1680d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley CHECK(raw_certificate_bio_ptr); 1690d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley CHECK(x509_ptr); 1700d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley CHECK(!*rsa_ptr); 1710d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley CHECK(!*pkey_ptr); 1720d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley CHECK(!*raw_certificate_bio_ptr); 1730d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley CHECK(!*x509_ptr); 1740d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 1750d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley *rsa_ptr = RSA_new(); 176758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart RSA* rsa = *rsa_ptr; 1770d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley *pkey_ptr = EVP_PKEY_new(); 178758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart EVP_PKEY* pkey = *pkey_ptr; 1790d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (!rsa || !pkey) { 1800d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Failed to allocate key."; 1810d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 1820d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 1830d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 1840d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley rsa->e = BN_new(); 1850d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley rsa->n = BN_new(); 1860d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (!rsa->e || !rsa->n || 1870d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley !BN_set_word(rsa->e, RSA_F4) || 1880d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley !BN_hex2bn(&rsa->n, kTrustedCAModulus)) { 1890d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Failed to allocate key pieces."; 1900d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 1910d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 1920d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 1930d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (!EVP_PKEY_assign_RSA(pkey, rsa)) { 1940d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Failed to assign RSA to PKEY."; 1950d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 1960d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 1970d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 198effb385f12068df2da38deb1e758f984f3792100Alex Vakulenko *rsa_ptr = NULL; // pkey took ownership 1990d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley // Another helpfully unmarked const interface. 2000d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley *raw_certificate_bio_ptr = BIO_new_mem_buf( 201758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart const_cast<char*>(certificate.data()), certificate.length()); 202758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart BIO* raw_certificate_bio = *raw_certificate_bio_ptr; 2030d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (!raw_certificate_bio) { 2040d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Failed to allocate openssl certificate buffer."; 2050d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 2060d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 2070d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 2080d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley // No callback for a passphrase, and no passphrase either. 2090d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley *x509_ptr = PEM_read_bio_X509(raw_certificate_bio, NULL, NULL, NULL); 210758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart X509* x509 = *x509_ptr; 2110d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (!x509) { 2120d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Failed to parse certificate."; 2130d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 2140d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 2150d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 2160d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (X509_verify(x509, pkey) <= 0) { 2170d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Failed to verify certificate."; 2180d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 2190d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 2200d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 2210d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley // Check that the device listed in the certificate is correct. 2220d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley char device_name[100]; // A longer CN will truncate. 2230d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley const int device_name_length = X509_NAME_get_text_by_NID( 2240d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley x509->cert_info->subject, 2250d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley NID_commonName, 2260d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley device_name, 2270d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley arraysize(device_name)); 2280d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (device_name_length == -1) { 2290d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Subject invalid."; 2300d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 2310d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 2320d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 2330d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley // Something like evt_e161 001a11ffacdf 2340d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley string device_cn(device_name, device_name_length); 2350d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley const size_t space_idx = device_cn.rfind(' '); 2360d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (space_idx == string::npos) { 2370d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Badly formatted subject"; 2380d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 2390d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 2400d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 241c97fc2d03a8dfddf55c55562c72d4d29d0fc2dc5Christopher Wiley string device_mac; 242c97fc2d03a8dfddf55c55562c72d4d29d0fc2dc5Christopher Wiley for (size_t i = space_idx + 1; i < device_cn.length(); ++i) { 243c97fc2d03a8dfddf55c55562c72d4d29d0fc2dc5Christopher Wiley device_mac.push_back(tolower(device_cn[i])); 244c97fc2d03a8dfddf55c55562c72d4d29d0fc2dc5Christopher Wiley } 2450d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (connected_mac != device_mac) { 2460d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "MAC addresses don't match."; 2470d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 2480d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 2490d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 2500d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley // Excellent, the certificate checks out, now make sure that the certificate 2510d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley // matches the unsigned data presented. 2520d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley // We're going to verify that hash(unsigned_data) == public(signed_data) 253758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart EVP_PKEY* cert_pubkey = X509_get_pubkey(x509); 2540d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (!cert_pubkey) { 2550d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Unable to extract public key from certificate."; 2560d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 2570d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 2580d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 259758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart RSA* cert_rsa = EVP_PKEY_get1_RSA(cert_pubkey); 2600d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (!cert_rsa) { 2610d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Failed to extract RSA key from certificate."; 2620d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 2630d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 2640d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 265758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart const unsigned char* signature = 266758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart reinterpret_cast<const unsigned char*>(signed_data.data()); 2670d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley const size_t signature_len = signed_data.length(); 268758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart unsigned char* unsigned_data_bytes = 269758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart reinterpret_cast<unsigned char*>(const_cast<char*>( 2700d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley unsigned_data.data())); 2710d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley const size_t unsigned_data_len = unsigned_data.length(); 2720d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley unsigned char digest[SHA_DIGEST_LENGTH]; 273effb385f12068df2da38deb1e758f984f3792100Alex Vakulenko if (signature_len > numeric_limits<unsigned int>::max()) { 2740d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Arguments to signature match were too large."; 2750d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 2760d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 2770d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley SHA1(unsigned_data_bytes, unsigned_data_len, digest); 2780d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (RSA_verify(NID_sha1, digest, arraysize(digest), 2790d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley signature, signature_len, cert_rsa) != 1) { 2800d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Signed blobs did not match."; 2810d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 2820d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 2830d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 2840d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return true; 2850d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley} 2860d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 2870d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// Verify the credentials of the destination described in |raw_input|. Takes 2880d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// a serialized VerifyCredentialsMessage protobuffer in |raw_input|, returns a 2890d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// serialized VerifyCredentialsResponse protobuffer in |output| on success. 2900d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// Returns false if the credentials fail to meet a check, and true on success. 291758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewartbool VerifyCredentials(const string& raw_input, string* output) { 2920d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley VerifyCredentialsMessage message; 2930d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (!message.ParseFromString(raw_input)) { 2940d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Failed to read VerifyCredentialsMessage from stdin."; 2950d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 2960d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 2970d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 2980d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (!message.has_certificate() || !message.has_signed_data() || 2990d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley !message.has_unsigned_data() || !message.has_mac_address()) { 3000d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Request lacked necessary fields."; 3010d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 3020d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 3030d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 3040d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley string connected_mac; 3050d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley for (size_t i = 0; i < message.mac_address().length(); ++i) { 3060d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley const char c = message.mac_address()[i]; 3070d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (c != ':') { 3080d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley connected_mac.push_back(tolower(c)); 3090d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 3100d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 3110d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (connected_mac.length() != kMacLength) { 3120d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "shill gave us a bad MAC?"; 3130d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 3140d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 3150d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 316758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart RSA* rsa = NULL; 317758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart EVP_PKEY* pkey = NULL; 318758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart BIO* raw_certificate_bio = NULL; 319758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart X509* x509 = NULL; 3200d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley bool operation_successful = VerifyCredentialsImpl(message.certificate(), 3210d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley message.signed_data(), message.unsigned_data(), connected_mac, 3220d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley &rsa, &pkey, &raw_certificate_bio, &x509); 3230d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (x509) { 3240d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley X509_free(x509); 3250d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley x509 = NULL; 3260d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 3270d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (raw_certificate_bio) { 3280d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley BIO_free(raw_certificate_bio); 3290d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley raw_certificate_bio = NULL; 3300d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 3310d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (pkey) { 3320d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley EVP_PKEY_free(pkey); 3330d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley pkey = NULL; 3340d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 3350d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (rsa) { 3360d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley RSA_free(rsa); 3370d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley rsa = NULL; 3380d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 3390d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 3400d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (operation_successful) { 3410d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(INFO) << "Filling out protobuf."; 3420d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley VerifyCredentialsResponse response; 3430d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley response.set_ret(shill_protos::OK); 3440d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley output->clear(); 3450d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(INFO) << "Serializing protobuf."; 3460d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (!response.SerializeToString(output)) { 3470d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Failed while writing encrypted data."; 3480d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 3490d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 3500d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(INFO) << "Encoding finished successfully."; 3510d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 3520d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 3530d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return operation_successful; 3540d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley} 3550d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 3560d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// Read the full stdin stream into a buffer, and execute the operation 3570d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// described in |command| with the contends of the stdin buffer. Write 3580d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley// the serialized protocol buffer output of the command to stdout. 359758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewartbool ParseAndExecuteCommand(const string& command) { 3600d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley string raw_input; 3610d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley char input_buffer[512]; 3620d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(INFO) << "Reading input for command " << command << "."; 3630d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley while (true) { 3640d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley const ssize_t bytes_read = HANDLE_EINTR(read(STDIN_FILENO, 3650d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley input_buffer, 3660d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley arraysize(input_buffer))); 3670d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (bytes_read < 0) { 3680d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley // Abort abort abort. 3690d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Failed while reading from stdin."; 3700d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 3710d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } else if (bytes_read > 0) { 3720d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley raw_input.append(input_buffer, bytes_read); 3730d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } else { 3740d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley break; 3750d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 3760d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 3770d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(INFO) << "Read " << raw_input.length() << " bytes."; 3780d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley ERR_clear_error(); 3790d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley string raw_output; 3800d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley bool ret = false; 3810d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (command == kCommandVerify) { 3820d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley ret = VerifyCredentials(raw_input, &raw_output); 3830d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } else if (command == kCommandEncrypt) { 3840d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley ret = EncryptByteString(raw_input, &raw_output); 3850d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } else { 3860d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Invalid usage."; 3870d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 3880d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 3890d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (!ret) { 3900d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Last OpenSSL error: " 3910d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley << ERR_reason_error_string(ERR_get_error()); 3920d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 3930d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley size_t total_bytes_written = 0; 3940d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley while (total_bytes_written < raw_output.length()) { 3950d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley const ssize_t bytes_written = HANDLE_EINTR(write( 3960d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley STDOUT_FILENO, 3970d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley raw_output.data() + total_bytes_written, 3980d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley raw_output.length() - total_bytes_written)); 3990d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (bytes_written < 0) { 4000d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Result write failed with: " << errno; 4010d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return false; 4020d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 4030d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley total_bytes_written += bytes_written; 4040d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 4050d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return ret; 4060d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley} 4070d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 4080d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley} // namespace 4090d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 410758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewartint main(int argc, char** argv) { 411127f2565a985650963d6109fc3a32c3da6a17d32Alex Vakulenko base::CommandLine::Init(argc, argv); 41203e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko brillo::InitLog(brillo::kLogToStderr | brillo::kLogHeader); 4130d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(INFO) << "crypto-util in action"; 4140d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 4150d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (argc != 2) { 4160d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Invalid usage"; 4170d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return EXIT_FAILURE; 4180d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 419758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart const char* command = argv[1]; 4200d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (strcmp(kCommandVerify, command) && strcmp(kCommandEncrypt, command)) { 4210d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley LOG(ERROR) << "Invalid command"; 4220d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return EXIT_FAILURE; 4230d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 4240d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 4250d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley CRYPTO_malloc_init(); 4260d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley ERR_load_crypto_strings(); 4270d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley OpenSSL_add_all_algorithms(); 4280d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley int return_code = EXIT_FAILURE; 4290d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley if (ParseAndExecuteCommand(command)) { 4300d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return_code = EXIT_SUCCESS; 4310d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley } 4320d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley close(STDOUT_FILENO); 4330d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley close(STDIN_FILENO); 4340d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 4350d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley CONF_modules_unload(1); 4360d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley OBJ_cleanup(); 4370d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley EVP_cleanup(); 4380d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley CRYPTO_cleanup_all_ex_data(); 4390d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley ERR_remove_thread_state(NULL); 4400d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley ERR_free_strings(); 4410d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley 4420d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley return return_code; 4430d05c11a21752aa82c598977bdd409a41d51cb55Christopher Wiley} 444