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