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