1 // 2 // Copyright (C) 2013 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include <unistd.h> 18 19 #include <limits> 20 #include <string> 21 #include <vector> 22 23 #include <base/command_line.h> 24 #include <base/logging.h> 25 #include <base/posix/eintr_wrapper.h> 26 #include <brillo/syslog_logging.h> 27 #include <openssl/bio.h> 28 #include <openssl/conf.h> 29 #include <openssl/err.h> 30 #include <openssl/evp.h> 31 #include <openssl/pem.h> 32 #include <openssl/rsa.h> 33 #include <openssl/sha.h> 34 #include <openssl/x509.h> 35 36 #include "shill/shims/protos/crypto_util.pb.h" 37 38 using shill_protos::EncryptDataMessage; 39 using shill_protos::EncryptDataResponse; 40 using shill_protos::VerifyCredentialsMessage; 41 using shill_protos::VerifyCredentialsResponse; 42 using std::numeric_limits; 43 using std::string; 44 using std::vector; 45 46 namespace { 47 48 const char kTrustedCAModulus[] = 49 "BC2280BD80F63A21003BAE765E357F3DC3645C559486342F058728CDF7698C17B350A7B8" 50 "82FADFC7432DD67EABA06FB7137280A44715C1209950CDEC1462095BA498CDD241B6364E" 51 "FFE82E32304A81A842A36C9B336ECAB2F55366E02753861A851EA7393F4A778EFB546666" 52 "FB5854C05E39C7F550060BE08AD4CEE16A551F8B1700E669A327E60825693C129D8D052C" 53 "D62EA231DEB45250D62049DE71A0F9AD204012F1DD25EBD5E6B836F4D68F7FCA43DCD710" 54 "5BE63F518A85B3F3FFF6032DCB234F9CAD18E793058CAC529AF74CE9997ABE6E7E4D0AE3" 55 "C61CA993FA3AA5915D1CBD66EBCC60DC8674CACFF8921C987D57FA61479EAB80B7E44880" 56 "2A92C51B"; 57 const char kCommandVerify[] = "verify"; 58 const char kCommandEncrypt[] = "encrypt"; 59 const size_t kMacLength = 12; 60 61 // Encrypt |data| with |public_key|. |public_key| is the raw bytes of a key in 62 // RSAPublicKey format. |data| is some string of bytes smaller than the 63 // maximum length permissable for encryption with a key of |public_key| size. 64 // |rsa_ptr| should point to NULL (but should not be NULL). This function may 65 // set *|rsa_ptr| to an RSA object which should be freed in the caller. 66 // Returns the encrypted result in |encrypted_output| and returns true on 67 // success. Returns false on failure. 68 bool EncryptByteStringImpl(const string& public_key, 69 const string& data, 70 RSA** rsa_ptr, 71 string* encrypted_output) { 72 CHECK(rsa_ptr); 73 CHECK(!*rsa_ptr); 74 CHECK(encrypted_output); 75 76 // This pointer will be incremented internally by the parsing routine. 77 const unsigned char* throwaway_ptr = 78 reinterpret_cast<const unsigned char*>(public_key.data()); 79 *rsa_ptr = d2i_RSAPublicKey(NULL, &throwaway_ptr, public_key.length()); 80 RSA* rsa = *rsa_ptr; 81 if (!rsa) { 82 LOG(ERROR) << "Failed to parse public key."; 83 return false; 84 } 85 86 vector<unsigned char> rsa_output(RSA_size(rsa)); 87 LOG(INFO) << "Encrypting data with public key."; 88 const int encrypted_length = RSA_public_encrypt( 89 data.length(), 90 // The API helpfully tells us that this operation will treat this buffer 91 // as read only, but fails to mark the parameter const. 92 reinterpret_cast<unsigned char*>(const_cast<char*>(data.data())), 93 rsa_output.data(), 94 rsa, 95 RSA_PKCS1_PADDING); 96 if (encrypted_length <= 0) { 97 LOG(ERROR) << "Error during encryption."; 98 return false; 99 } 100 101 encrypted_output->assign(reinterpret_cast<char*>(rsa_output.data()), 102 encrypted_length); 103 return true; 104 } 105 106 // Parse the EncryptDataMessage contained in |raw_input| and return an 107 // EncryptDataResponse in output on success. Returns true on success and 108 // false otherwise. 109 bool EncryptByteString(const string& raw_input, string* output) { 110 EncryptDataMessage message; 111 if (!message.ParseFromString(raw_input)) { 112 LOG(ERROR) << "Failed to read VerifyCredentialsMessage from stdin."; 113 return false; 114 } 115 116 if (!message.has_public_key() || !message.has_data()) { 117 LOG(ERROR) << "Request lacked necessary fields."; 118 return false; 119 } 120 121 RSA* rsa = NULL; 122 string encrypted_output; 123 bool operation_successful = EncryptByteStringImpl( 124 message.public_key(), message.data(), &rsa, &encrypted_output); 125 if (rsa) { 126 RSA_free(rsa); 127 rsa = NULL; 128 } 129 130 if (operation_successful) { 131 LOG(INFO) << "Filling out protobuf."; 132 EncryptDataResponse response; 133 response.set_encrypted_data(encrypted_output); 134 response.set_ret(shill_protos::OK); 135 output->clear(); 136 LOG(INFO) << "Serializing protobuf."; 137 if (!response.SerializeToString(output)) { 138 LOG(ERROR) << "Failed while writing encrypted data."; 139 return false; 140 } 141 LOG(INFO) << "Encoding finished successfully."; 142 } 143 144 return operation_successful; 145 } 146 147 // Verify that the destination described by |certificate| is valid. 148 // 149 // 1) The MAC address listed in the certificate matches |connected_mac|. 150 // 2) The certificate is a valid PEM encoded certificate signed by our 151 // trusted CA. 152 // 3) |signed_data| matches the hashed |unsigned_data| encrypted with 153 // the public key in |certificate|. 154 // 155 // All pointers should be valid, but point to NULL values. Sets* ptr to 156 // NULL or a valid object which should be freed with the appropriate destructor 157 // upon completion. 158 bool VerifyCredentialsImpl(const string& certificate, 159 const string& signed_data, 160 const string& unsigned_data, 161 const string& connected_mac, 162 RSA** rsa_ptr, 163 EVP_PKEY** pkey_ptr, 164 BIO** raw_certificate_bio_ptr, 165 X509** x509_ptr) { 166 CHECK(rsa_ptr); 167 CHECK(pkey_ptr); 168 CHECK(raw_certificate_bio_ptr); 169 CHECK(x509_ptr); 170 CHECK(!*rsa_ptr); 171 CHECK(!*pkey_ptr); 172 CHECK(!*raw_certificate_bio_ptr); 173 CHECK(!*x509_ptr); 174 175 *rsa_ptr = RSA_new(); 176 RSA* rsa = *rsa_ptr; 177 *pkey_ptr = EVP_PKEY_new(); 178 EVP_PKEY* pkey = *pkey_ptr; 179 if (!rsa || !pkey) { 180 LOG(ERROR) << "Failed to allocate key."; 181 return false; 182 } 183 184 rsa->e = BN_new(); 185 rsa->n = BN_new(); 186 if (!rsa->e || !rsa->n || 187 !BN_set_word(rsa->e, RSA_F4) || 188 !BN_hex2bn(&rsa->n, kTrustedCAModulus)) { 189 LOG(ERROR) << "Failed to allocate key pieces."; 190 return false; 191 } 192 193 if (!EVP_PKEY_assign_RSA(pkey, rsa)) { 194 LOG(ERROR) << "Failed to assign RSA to PKEY."; 195 return false; 196 } 197 198 *rsa_ptr = NULL; // pkey took ownership 199 // Another helpfully unmarked const interface. 200 *raw_certificate_bio_ptr = BIO_new_mem_buf( 201 const_cast<char*>(certificate.data()), certificate.length()); 202 BIO* raw_certificate_bio = *raw_certificate_bio_ptr; 203 if (!raw_certificate_bio) { 204 LOG(ERROR) << "Failed to allocate openssl certificate buffer."; 205 return false; 206 } 207 208 // No callback for a passphrase, and no passphrase either. 209 *x509_ptr = PEM_read_bio_X509(raw_certificate_bio, NULL, NULL, NULL); 210 X509* x509 = *x509_ptr; 211 if (!x509) { 212 LOG(ERROR) << "Failed to parse certificate."; 213 return false; 214 } 215 216 if (X509_verify(x509, pkey) <= 0) { 217 LOG(ERROR) << "Failed to verify certificate."; 218 return false; 219 } 220 221 // Check that the device listed in the certificate is correct. 222 char device_name[100]; // A longer CN will truncate. 223 const int device_name_length = X509_NAME_get_text_by_NID( 224 x509->cert_info->subject, 225 NID_commonName, 226 device_name, 227 arraysize(device_name)); 228 if (device_name_length == -1) { 229 LOG(ERROR) << "Subject invalid."; 230 return false; 231 } 232 233 // Something like evt_e161 001a11ffacdf 234 string device_cn(device_name, device_name_length); 235 const size_t space_idx = device_cn.rfind(' '); 236 if (space_idx == string::npos) { 237 LOG(ERROR) << "Badly formatted subject"; 238 return false; 239 } 240 241 string device_mac; 242 for (size_t i = space_idx + 1; i < device_cn.length(); ++i) { 243 device_mac.push_back(tolower(device_cn[i])); 244 } 245 if (connected_mac != device_mac) { 246 LOG(ERROR) << "MAC addresses don't match."; 247 return false; 248 } 249 250 // Excellent, the certificate checks out, now make sure that the certificate 251 // matches the unsigned data presented. 252 // We're going to verify that hash(unsigned_data) == public(signed_data) 253 EVP_PKEY* cert_pubkey = X509_get_pubkey(x509); 254 if (!cert_pubkey) { 255 LOG(ERROR) << "Unable to extract public key from certificate."; 256 return false; 257 } 258 259 RSA* cert_rsa = EVP_PKEY_get1_RSA(cert_pubkey); 260 if (!cert_rsa) { 261 LOG(ERROR) << "Failed to extract RSA key from certificate."; 262 return false; 263 } 264 265 const unsigned char* signature = 266 reinterpret_cast<const unsigned char*>(signed_data.data()); 267 const size_t signature_len = signed_data.length(); 268 unsigned char* unsigned_data_bytes = 269 reinterpret_cast<unsigned char*>(const_cast<char*>( 270 unsigned_data.data())); 271 const size_t unsigned_data_len = unsigned_data.length(); 272 unsigned char digest[SHA_DIGEST_LENGTH]; 273 if (signature_len > numeric_limits<unsigned int>::max()) { 274 LOG(ERROR) << "Arguments to signature match were too large."; 275 return false; 276 } 277 SHA1(unsigned_data_bytes, unsigned_data_len, digest); 278 if (RSA_verify(NID_sha1, digest, arraysize(digest), 279 signature, signature_len, cert_rsa) != 1) { 280 LOG(ERROR) << "Signed blobs did not match."; 281 return false; 282 } 283 284 return true; 285 } 286 287 // Verify the credentials of the destination described in |raw_input|. Takes 288 // a serialized VerifyCredentialsMessage protobuffer in |raw_input|, returns a 289 // serialized VerifyCredentialsResponse protobuffer in |output| on success. 290 // Returns false if the credentials fail to meet a check, and true on success. 291 bool VerifyCredentials(const string& raw_input, string* output) { 292 VerifyCredentialsMessage message; 293 if (!message.ParseFromString(raw_input)) { 294 LOG(ERROR) << "Failed to read VerifyCredentialsMessage from stdin."; 295 return false; 296 } 297 298 if (!message.has_certificate() || !message.has_signed_data() || 299 !message.has_unsigned_data() || !message.has_mac_address()) { 300 LOG(ERROR) << "Request lacked necessary fields."; 301 return false; 302 } 303 304 string connected_mac; 305 for (size_t i = 0; i < message.mac_address().length(); ++i) { 306 const char c = message.mac_address()[i]; 307 if (c != ':') { 308 connected_mac.push_back(tolower(c)); 309 } 310 } 311 if (connected_mac.length() != kMacLength) { 312 LOG(ERROR) << "shill gave us a bad MAC?"; 313 return false; 314 } 315 316 RSA* rsa = NULL; 317 EVP_PKEY* pkey = NULL; 318 BIO* raw_certificate_bio = NULL; 319 X509* x509 = NULL; 320 bool operation_successful = VerifyCredentialsImpl(message.certificate(), 321 message.signed_data(), message.unsigned_data(), connected_mac, 322 &rsa, &pkey, &raw_certificate_bio, &x509); 323 if (x509) { 324 X509_free(x509); 325 x509 = NULL; 326 } 327 if (raw_certificate_bio) { 328 BIO_free(raw_certificate_bio); 329 raw_certificate_bio = NULL; 330 } 331 if (pkey) { 332 EVP_PKEY_free(pkey); 333 pkey = NULL; 334 } 335 if (rsa) { 336 RSA_free(rsa); 337 rsa = NULL; 338 } 339 340 if (operation_successful) { 341 LOG(INFO) << "Filling out protobuf."; 342 VerifyCredentialsResponse response; 343 response.set_ret(shill_protos::OK); 344 output->clear(); 345 LOG(INFO) << "Serializing protobuf."; 346 if (!response.SerializeToString(output)) { 347 LOG(ERROR) << "Failed while writing encrypted data."; 348 return false; 349 } 350 LOG(INFO) << "Encoding finished successfully."; 351 } 352 353 return operation_successful; 354 } 355 356 // Read the full stdin stream into a buffer, and execute the operation 357 // described in |command| with the contends of the stdin buffer. Write 358 // the serialized protocol buffer output of the command to stdout. 359 bool ParseAndExecuteCommand(const string& command) { 360 string raw_input; 361 char input_buffer[512]; 362 LOG(INFO) << "Reading input for command " << command << "."; 363 while (true) { 364 const ssize_t bytes_read = HANDLE_EINTR(read(STDIN_FILENO, 365 input_buffer, 366 arraysize(input_buffer))); 367 if (bytes_read < 0) { 368 // Abort abort abort. 369 LOG(ERROR) << "Failed while reading from stdin."; 370 return false; 371 } else if (bytes_read > 0) { 372 raw_input.append(input_buffer, bytes_read); 373 } else { 374 break; 375 } 376 } 377 LOG(INFO) << "Read " << raw_input.length() << " bytes."; 378 ERR_clear_error(); 379 string raw_output; 380 bool ret = false; 381 if (command == kCommandVerify) { 382 ret = VerifyCredentials(raw_input, &raw_output); 383 } else if (command == kCommandEncrypt) { 384 ret = EncryptByteString(raw_input, &raw_output); 385 } else { 386 LOG(ERROR) << "Invalid usage."; 387 return false; 388 } 389 if (!ret) { 390 LOG(ERROR) << "Last OpenSSL error: " 391 << ERR_reason_error_string(ERR_get_error()); 392 } 393 size_t total_bytes_written = 0; 394 while (total_bytes_written < raw_output.length()) { 395 const ssize_t bytes_written = HANDLE_EINTR(write( 396 STDOUT_FILENO, 397 raw_output.data() + total_bytes_written, 398 raw_output.length() - total_bytes_written)); 399 if (bytes_written < 0) { 400 LOG(ERROR) << "Result write failed with: " << errno; 401 return false; 402 } 403 total_bytes_written += bytes_written; 404 } 405 return ret; 406 } 407 408 } // namespace 409 410 int main(int argc, char** argv) { 411 base::CommandLine::Init(argc, argv); 412 brillo::InitLog(brillo::kLogToStderr | brillo::kLogHeader); 413 LOG(INFO) << "crypto-util in action"; 414 415 if (argc != 2) { 416 LOG(ERROR) << "Invalid usage"; 417 return EXIT_FAILURE; 418 } 419 const char* command = argv[1]; 420 if (strcmp(kCommandVerify, command) && strcmp(kCommandEncrypt, command)) { 421 LOG(ERROR) << "Invalid command"; 422 return EXIT_FAILURE; 423 } 424 425 CRYPTO_malloc_init(); 426 ERR_load_crypto_strings(); 427 OpenSSL_add_all_algorithms(); 428 int return_code = EXIT_FAILURE; 429 if (ParseAndExecuteCommand(command)) { 430 return_code = EXIT_SUCCESS; 431 } 432 close(STDOUT_FILENO); 433 close(STDIN_FILENO); 434 435 CONF_modules_unload(1); 436 OBJ_cleanup(); 437 EVP_cleanup(); 438 CRYPTO_cleanup_all_ex_data(); 439 ERR_remove_thread_state(NULL); 440 ERR_free_strings(); 441 442 return return_code; 443 } 444