github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/src/tao/util.cc (about)

     1  //  File: util.cc
     2  //  Author: Tom Roeder <tmroeder@google.com>
     3  //
     4  //  Description: Implementation of utility methods for the Tao.
     5  //
     6  //  Copyright (c) 2013, Google Inc.  All rights reserved.
     7  //
     8  // Licensed under the Apache License, Version 2.0 (the "License");
     9  // you may not use this file except in compliance with the License.
    10  // You may obtain a copy of the License at
    11  //
    12  //     http://www.apache.org/licenses/LICENSE-2.0
    13  //
    14  // Unless required by applicable law or agreed to in writing, software
    15  // distributed under the License is distributed on an "AS IS" BASIS,
    16  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    17  // See the License for the specific language governing permissions and
    18  // limitations under the License.
    19  #include "tao/util.h"
    20  
    21  #include <arpa/inet.h>
    22  #include <dirent.h>
    23  #include <fcntl.h>
    24  #include <netdb.h>
    25  #include <netinet/in.h>
    26  #include <signal.h>
    27  #include <string.h>
    28  #include <sys/socket.h>
    29  #include <sys/stat.h>
    30  #include <sys/types.h>
    31  #include <sys/un.h>
    32  #include <sys/unistd.h>
    33  
    34  #include <memory>
    35  #include <mutex>
    36  #include <sstream>
    37  #include <vector>
    38  
    39  #include <gflags/gflags.h>
    40  #include <glog/logging.h>
    41  #include <google/protobuf/io/coded_stream.h>
    42  #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
    43  #include <modp/modp_b64w.h>
    44  #include <openssl/bio.h>
    45  #include <openssl/crypto.h>
    46  #include <openssl/err.h>
    47  #include <openssl/rand.h>
    48  #include <openssl/ssl.h>
    49  
    50  #include "tao/tao.h"
    51  
    52  using std::lock_guard;
    53  using std::mutex;
    54  using std::shared_ptr;
    55  using std::stringstream;
    56  using std::vector;
    57  
    58  using google::protobuf::io::StringOutputStream;
    59  using google::protobuf::io::CodedOutputStream;
    60  
    61  namespace tao {
    62  
    63  void SecureStringErase(string *s) {
    64    // TODO(kwalsh) Keyczar has a nice 'fixme' note about making sure the memset
    65    // isn't optimized away, and a commented-out call to openssl's cleanse. What
    66    // to do?
    67    OPENSSL_cleanse(str2uchar(s), s->size());
    68    memset(str2uchar(s), 0, s->size());
    69  }
    70  
    71  void SecureStringFree(string *s) {
    72    SecureStringErase(s);
    73    delete s;
    74  }
    75  
    76  void fd_close(int *fd) {
    77    if (fd && *fd >= 0) {
    78      if (close(*fd) < 0) {
    79        PLOG(ERROR) << "Could not close file descriptor " << *fd;
    80      }
    81      delete fd;
    82    }
    83  }
    84  
    85  void file_close(FILE *file) {
    86    if (file) fclose(file);
    87  }
    88  
    89  void temp_file_cleaner(string *dir) {
    90    if (dir) {
    91      if (!DeleteFile(*dir, true /* recursive */))
    92        PLOG(ERROR) << "Could not remove temp directory " << *dir;
    93      delete dir;
    94    }
    95  }
    96  
    97  vector<shared_ptr<mutex>> locks;
    98  
    99  static void locking_function(int mode, int n, const char *file, int line) {
   100    if (mode & CRYPTO_LOCK) {
   101      locks[n]->lock();
   102    } else {
   103      locks[n]->unlock();
   104    }
   105  }
   106  
   107  bool OpenSSLSuccess() {
   108    uint32_t last_error = ERR_get_error();
   109    if (last_error) {
   110      LOG(ERROR) << "OpenSSL errors:";
   111      while (last_error) {
   112        const char *lib = ERR_lib_error_string(last_error);
   113        const char *func = ERR_func_error_string(last_error);
   114        const char *reason = ERR_reason_error_string(last_error);
   115        LOG(ERROR) << " * " << last_error << ":" << (lib ? lib : "unknown") << ":"
   116                   << (func ? func : "unknown") << ":"
   117                   << (reason ? reason : "unknown");
   118        last_error = ERR_get_error();
   119      }
   120      return false;
   121    } else {
   122      return true;
   123    }
   124  }
   125  
   126  bool InitializeOpenSSL() {
   127    SSL_load_error_strings();
   128    ERR_load_BIO_strings();
   129    ERR_load_crypto_strings();
   130    OpenSSL_add_all_algorithms();
   131    SSL_library_init();
   132  
   133    // set up locking in OpenSSL
   134    int lock_count = CRYPTO_num_locks();
   135    locks.resize(lock_count);
   136    for (int i = 0; i < lock_count; i++) {
   137      locks[i].reset(new mutex());
   138    }
   139    CRYPTO_set_locking_callback(locking_function);
   140    return true;
   141  }
   142  
   143  bool InitializeApp(int *argc, char ***argv, bool remove_args) {
   144    GOOGLE_PROTOBUF_VERIFY_VERSION;
   145    // FLAGS_alsologtostderr = true;
   146    google::ParseCommandLineFlags(argc, argv, remove_args);
   147    string log_area((*argv)[0]);
   148    log_area.append("_log");
   149    google::InitGoogleLogging(log_area.c_str());
   150    google::InstallFailureSignalHandler();
   151    signal(SIGPIPE, SIG_IGN);
   152    return InitializeOpenSSL();
   153  }
   154  
   155  bool MakeSealedSecret(Tao *tao, const string &path, const string &policy,
   156                        int secret_size, string *secret) {
   157    if (secret == nullptr) {
   158      LOG(ERROR) << "Could not seal null secret";
   159      return false;
   160    }
   161    if (!tao->GetRandomBytes(secret_size, secret)) {
   162      LOG(ERROR) << "Could not generate a random secret to seal";
   163      return false;
   164    }
   165    string sealed_secret;
   166    if (!tao->Seal(*secret, policy, &sealed_secret)) {
   167      LOG(ERROR) << "Can't seal the secret";
   168      return false;
   169    }
   170    if (!CreateDirectory(FilePath(path).DirName())) {
   171      LOG(ERROR) << "Can't create directory for " << path;
   172      return false;
   173    }
   174    if (!WriteStringToFile(path, sealed_secret)) {
   175      LOG(ERROR) << "Can't write the sealed secret to " << path;
   176      return false;
   177    }
   178    VLOG(2) << "Sealed a secret of size " << secret_size;
   179    return true;
   180  }
   181  
   182  bool GetSealedSecret(Tao *tao, const string &path, const string &policy,
   183                       string *secret) {
   184    if (secret == nullptr) {
   185      LOG(ERROR) << "Could not unseal null secret";
   186      return false;
   187    }
   188    string sealed_secret;
   189    if (!ReadFileToString(path, &sealed_secret)) {
   190      LOG(ERROR) << "Can't read the sealed secret from " << path;
   191      return false;
   192    }
   193    string unseal_policy;
   194    if (!tao->Unseal(sealed_secret, secret, &unseal_policy)) {
   195      LOG(ERROR) << "Can't unseal the secret";
   196      return false;
   197    }
   198    if (unseal_policy != policy) {
   199      LOG(ERROR) << "Unsealed secret, but provenance is uncertain";
   200      return false;
   201    }
   202    VLOG(2) << "Unsealed a secret of size " << secret->size();
   203    return true;
   204  }
   205  
   206  bool CreateTempDir(const string &prefix, ScopedTempDir *dir) {
   207    // Get a temporary directory to use for the files.
   208    string dir_template = string("/tmp/temp_") + prefix + string("_XXXXXX");
   209    unique_ptr<char[]> temp_name(new char[dir_template.size() + 1]);
   210    memcpy(temp_name.get(), dir_template.data(), dir_template.size() + 1);
   211  
   212    if (!mkdtemp(temp_name.get())) {
   213      LOG(ERROR) << "Could not create the temporary directory";
   214      return false;
   215    }
   216  
   217    dir->reset(new string(temp_name.get()));
   218    return true;
   219  }
   220  
   221  bool ConnectToTCPServer(const string &host, const string &port, int *sock) {
   222    // Set up a socket to communicate with the TCCA.
   223    *sock = socket(AF_INET, SOCK_STREAM, 0);
   224  
   225    struct addrinfo hints;
   226    memset(&hints, 0, sizeof(struct addrinfo));
   227    hints.ai_family = AF_INET;
   228    hints.ai_socktype = SOCK_STREAM;
   229  
   230    struct addrinfo *addrs = nullptr;
   231    int info_err = getaddrinfo(host.c_str(), port.c_str(), &hints, &addrs);
   232    if (info_err == -1) {
   233      PLOG(ERROR) << "Could not get address information for " << host << ":"
   234                  << port;
   235      return false;
   236    }
   237  
   238    int connect_err = connect(*sock, addrs->ai_addr, addrs->ai_addrlen);
   239    if (connect_err == -1) {
   240      PLOG(ERROR) << "Could not connect to TCP server at " << host << ":" << port;
   241      freeaddrinfo(addrs);
   242      return false;
   243    }
   244  
   245    freeaddrinfo(addrs);
   246  
   247    return true;
   248  }
   249  
   250  string quotedString(const string &s) {
   251    stringstream out;
   252    out << '\"';
   253    for (const char &c : s) {
   254      if (c == '\\' || c == '\"') out << '\\';
   255      out << c;
   256    }
   257    out << '\"';
   258    return out.str();
   259  }
   260  
   261  stringstream &getQuotedString(stringstream &in, string *s) {  // NOLINT
   262    stringstream out;
   263    char c;
   264    while (in.get(c) && (c == ' ' || c == '\t')) {
   265    }
   266    if (!in || c != '\"') {
   267      in.setstate(std::ios::failbit);
   268      return in;
   269    }
   270    bool escape = false;
   271    while (in.get(c)) {
   272      if (!escape) {
   273        if (c == '\"') {
   274          s->assign(out.str());
   275          return in;
   276        } else if (c == '\\') {
   277          escape = true;
   278        } else {
   279          out << c;
   280        }
   281      } else {
   282        if ((c == '\"') || (c == '\\')) {
   283          out << c;
   284          escape = false;
   285        } else {
   286          in.setstate(std::ios::failbit);
   287          return in;
   288        }
   289      }
   290    }
   291    in.setstate(std::ios::failbit);
   292    return in;
   293  }
   294  
   295  stringstream &skip(stringstream &in, const string &s) {  // NOLINT
   296    for (unsigned int i = 0; in && i < s.size(); i++) {
   297      char c;
   298      in.get(c);
   299      if (c != s[i]) in.setstate(std::ios::failbit);
   300    }
   301    return in;
   302  }
   303  
   304  /// Elide a already-escaped string if necessary. If the string is short, it will
   305  /// be returned as-is. Otherwise, a few characters at the beginning and end
   306  /// will be left, and the middle replaced with ellipses. Escape sequences will
   307  /// not be broken, and it is assumed that all backslashes are followed by
   308  /// either a 3-character octal escape or a 1-character non-octal escape.
   309  /// @param s The string to be elided.
   310  /// @param thresh If s is no longer than this, it will be returned as-is.
   311  /// @param prefix At least this many characters will be left before the
   312  /// ellipses.
   313  /// @param suffix At least this many characters will be left after the ellipses.
   314  static string elideQuote(const string &s, size_t thresh, size_t prefix,
   315                           size_t suffix) {
   316    if (s.size() < thresh) return s;
   317    size_t i = 0;
   318    while (i < prefix) {
   319      if (s[i] == '\\' && '0' <= s[i + 1] && s[i + 1] <= '7')
   320        i += 4;  // skip octal escape
   321      else if (s[i] == '\\')
   322        i += 2;  // skip other escape
   323      else
   324        i++;
   325    }
   326    prefix = i;
   327    size_t j = i;
   328    while (s.size() - i >= suffix) {
   329      j = i;
   330      if (s[i] == '\\' && '0' <= s[i + 1] && s[i + 1] <= '7')
   331        i += 4;  // skip octal escape
   332      else if (s[i] == '\\')
   333        i += 2;  // skip other escape
   334      else
   335        i++;
   336    }
   337    suffix = j;
   338    return s.substr(0, prefix) + "..." + s.substr(suffix);
   339  }
   340  
   341  string elideString(const string &s) {
   342    stringstream out, elided;
   343    bool inQuote = false;
   344    for (auto &c : s) {
   345      if (c == '\0')
   346        out << "\0";
   347      else if (c == '\a')
   348        out << "\\a";
   349      else if (c == '\b')
   350        out << "\\b";
   351      else if (c == '\t')
   352        out << "\\t";
   353      else if (c == '\n')
   354        out << "\\n";
   355      else if (c == '\v')
   356        out << "\\v";
   357      else if (c == '\f')
   358        out << "\\f";
   359      else if (c == '\r')
   360        out << "\\r";
   361      else if (c == '\\')
   362        out << "\\\\";
   363      else if (c < ' ' || c > '~') {
   364        out << "\\" << ('0' + ((c >> 6) & 0x7)) << ('0' + ((c >> 3) & 0xf))
   365            << ('0' + ((c >> 0) & 0x7));
   366      } else if (c == '\"') {
   367        if (!inQuote)
   368          elided << out.str() << "\"";
   369        else
   370          elided << elideQuote(out.str(), 30, 10, 10) << "\"";
   371        out.str("");
   372        inQuote = !inQuote;
   373      } else {
   374        out << c;
   375      }
   376    }
   377    elided << out.str();
   378    return elided.str();
   379  }
   380  
   381  string elideBytes(const string &s) {
   382    if (s.length() <= 20)
   383      return bytesToHex(s);
   384    else
   385      return bytesToHex(s.substr(0, 4)) + "..." +
   386             bytesToHex(s.substr(s.size() - 5));
   387  }
   388  
   389  string bytesToHex(const string &s) {
   390    stringstream out;
   391    string hex = "0123456789abcdef";
   392    for (auto &c : s) out << hex[(c >> 4) & 0xf] << hex[(c >> 0) & 0xf];
   393    return out.str();
   394  }
   395  
   396  static int hexToInt(char c, int *i) {
   397    if ('0' <= c && c <= '9')
   398      *i = (c - '0');
   399    else if ('a' <= c && c <= 'f')
   400      *i = 10 + (c - 'a');
   401    else if ('A' <= c && c <= 'F')
   402      *i = 10 + (c - 'A');
   403    else
   404      return false;
   405    return true;
   406  }
   407  
   408  bool bytesFromHex(const string &hex, string *s) {
   409    stringstream out;
   410    if (hex.size() % 2) return false;
   411    for (unsigned int i = 0; i < hex.size(); i += 2) {
   412      int x, y;
   413      if (!hexToInt(hex[i], &x) || !hexToInt(hex[i + 1], &y)) return false;
   414      out.put((x << 4) | y);
   415    }
   416    s->assign(out.str());
   417    return true;
   418  }
   419  
   420  bool split(const string &s, const string &delim, list<string> *values) {
   421    values->clear();
   422    if (s == "") return true;
   423    stringstream in(s);
   424    while (in) {
   425      // no errors yet, still strings to be read
   426      string value;
   427      getline(in, value, delim[0]);
   428      // no errors yet, eof set if last string, maybe other chars
   429      values->push_back(value);
   430      if (in.eof()) return true;
   431      // no errors yet, not last string, maybe other chars
   432      skip(in, delim.substr(1));
   433      // errors if delim was missing, else still strings to be read
   434    }
   435    return false;
   436  }
   437  
   438  bool split(const string &s, const string &delim, list<int> *values) {
   439    values->clear();
   440    if (s == "") return true;
   441    stringstream in(s);
   442    while (in) {
   443      // no errors yet, still values to be read
   444      int value;
   445      in >> value;
   446      if (!in) return false;
   447      // no errors yet, eof set if last int, maybe other chars
   448      values->push_back(value);
   449      if (in.eof()) return true;
   450      // no errors yet, not last int, maybe other chars
   451      skip(in, delim);
   452      // errors if delim was missing, else still values to be read
   453    }
   454    return false;
   455  }
   456  
   457  time_t FileModificationTime(const string &path) {
   458    struct stat st;
   459    if (stat(path.c_str(), &st) != 0) {
   460      LOG(ERROR) << "File does not exist: " << path;
   461      return 0;
   462    }
   463    return st.st_mtime;
   464  }
   465  
   466  bool WeakRandBytes(size_t size, string *s) {
   467    // Use openssl.
   468    s->resize(size);
   469    return (RAND_bytes(str2uchar(s), size) == 1);
   470  }
   471  
   472  string Base64WEncode(const string &in) {
   473    string out;
   474    Base64WEncode(in, &out);  // does not fail
   475    return out;
   476  }
   477  
   478  bool Base64WEncode(const string &in, string *out) {
   479    if (out == nullptr) {
   480      return false;
   481    }
   482    size_t in_len = in.size();
   483    out->resize(modp_b64w_encode_len(in_len));
   484    size_t out_len = modp_b64w_encode(str2char(out), str2char(in), in_len);
   485    out->resize(out_len);
   486    return true;
   487  }
   488  
   489  bool Base64WDecode(const string &in, string *out) {
   490    if (out == nullptr) {
   491      return false;
   492    }
   493    size_t in_len = in.size();
   494    out->resize(modp_b64w_decode_len(in_len));
   495    int out_len = modp_b64w_decode(str2char(out), str2char(in), in_len);
   496    if (out_len < 0) {
   497      out->clear();
   498      return false;
   499    }
   500    out->resize(out_len);
   501    return true;
   502  }
   503  
   504  // These constants give the tags needed to encode a key auth.Prin in binary form
   505  // in a Speaksfor statement.
   506  static int tagPrin = 0x1;
   507  static int tagBytes = 0x4;
   508  static int tagSpeaksfor = 0xd;
   509  static int tagSubPrin = 0x11;
   510  bool MarshalSpeaksfor(const string &key, const string &binaryTaoName,
   511                        string *out) {
   512  
   513    StringOutputStream *sos = new StringOutputStream(out);
   514    CodedOutputStream *cos = new CodedOutputStream(sos);
   515    // Tag this as a Speaksfor object.
   516    cos->WriteVarint32(tagSpeaksfor);
   517  
   518    string delegate;
   519    if (!MarshalKeyPrin(key, &delegate)) {
   520      delete cos;
   521      delete sos;
   522      return false;
   523    }
   524  
   525    cos->WriteRaw(delegate.data(), delegate.size());
   526  
   527    // The delegator is written directly, since it's already a binary-encoded
   528    // Term.
   529    cos->WriteRaw(binaryTaoName.data(), binaryTaoName.size());
   530  
   531    delete cos;
   532    delete sos;
   533    return true;
   534  }
   535  
   536  bool MarshalKeyPrin(const string &key, string *out) {
   537    StringOutputStream *sos = new StringOutputStream(out);
   538    CodedOutputStream *cos = new CodedOutputStream(sos);
   539  
   540    // auth.Prin is tagPrin, then a string type "key", then a Key buffer, and no
   541    // extensions (this is marshaled as tagSubPrin, 0).
   542    cos->WriteVarint32(tagPrin);
   543  
   544    // Type: "key"
   545    string keyType("key");
   546    cos->WriteVarint32(keyType.size());
   547    cos->WriteRaw(keyType.data(), keyType.size());
   548  
   549    // Key: auth.Bytes[...]
   550    cos->WriteVarint32(tagBytes);
   551    cos->WriteVarint32(key.size());
   552    cos->WriteRaw(key.data(), key.size());
   553  
   554    // Ext: auth.SubPrin of length 0
   555    cos->WriteVarint32(tagSubPrin);
   556    cos->WriteVarint32(0);
   557  
   558    delete cos;
   559    delete sos;
   560    return true;
   561  }
   562  
   563  bool InitNewCounter(Tao *tao, const string &label, const int64_t& c) {
   564  /*
   565    if (!tao->GetRandomBytes(secret_size, secret)) {
   566      LOG(ERROR) << "Could not generate a random secret to seal";
   567      return false;
   568    }
   569  */
   570    return false;
   571  }
   572  
   573  bool GetACounter(Tao *tao, const string &label, const int64_t* c) {
   574    return false;
   575  }
   576  
   577  bool MakeRollbackProtectedSealedSecret(Tao *tao, const string &path,
   578        const string &policy, int secret_size, string *secret) {
   579    return false;
   580  }
   581  
   582  bool GetRollbackProtectedSealedSecret(Tao *tao, const string &path,
   583        const string &policy, string *secret) {
   584    return false;
   585  }
   586  
   587  }  // namespace tao