| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/common/extensions/api/networking_private/networking_private_cry
pto.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 | |
| 9 #include <memory> | |
| 10 | |
| 11 #include "base/logging.h" | |
| 12 #include "base/strings/string_util.h" | |
| 13 #include "components/cast_certificate/cast_cert_validator.h" | |
| 14 #include "crypto/openssl_util.h" | |
| 15 #include "crypto/rsa_private_key.h" | |
| 16 #include "net/cert/pem_tokenizer.h" | |
| 17 #include "third_party/boringssl/src/include/openssl/digest.h" | |
| 18 #include "third_party/boringssl/src/include/openssl/evp.h" | |
| 19 #include "third_party/boringssl/src/include/openssl/rsa.h" | |
| 20 #include "third_party/boringssl/src/include/openssl/x509.h" | |
| 21 | |
| 22 namespace { | |
| 23 | |
| 24 namespace cast_crypto = ::cast_certificate; | |
| 25 | |
| 26 // Parses |pem_data| for a PEM block of |pem_type|. | |
| 27 // Returns true if a |pem_type| block is found, storing the decoded result in | |
| 28 // |der_output|. | |
| 29 bool GetDERFromPEM(const std::string& pem_data, | |
| 30 const std::string& pem_type, | |
| 31 std::vector<uint8_t>* der_output) { | |
| 32 std::vector<std::string> headers; | |
| 33 headers.push_back(pem_type); | |
| 34 net::PEMTokenizer pem_tokenizer(pem_data, headers); | |
| 35 if (!pem_tokenizer.GetNext()) { | |
| 36 return false; | |
| 37 } | |
| 38 | |
| 39 der_output->assign(pem_tokenizer.data().begin(), pem_tokenizer.data().end()); | |
| 40 return true; | |
| 41 } | |
| 42 | |
| 43 } // namespace | |
| 44 | |
| 45 namespace networking_private_crypto { | |
| 46 | |
| 47 bool VerifyCredentials( | |
| 48 const std::string& certificate, | |
| 49 const std::vector<std::string>& intermediate_certificates, | |
| 50 const std::string& signature, | |
| 51 const std::string& data, | |
| 52 const std::string& connected_mac) { | |
| 53 base::Time now = base::Time::Now(); | |
| 54 return VerifyCredentialsAtTime(certificate, intermediate_certificates, | |
| 55 signature, data, connected_mac, now); | |
| 56 } | |
| 57 | |
| 58 bool VerifyCredentialsAtTime( | |
| 59 const std::string& certificate, | |
| 60 const std::vector<std::string>& intermediate_certificates, | |
| 61 const std::string& signature, | |
| 62 const std::string& data, | |
| 63 const std::string& connected_mac, | |
| 64 const base::Time& time) { | |
| 65 static const char kErrorPrefix[] = "Device verification failed. "; | |
| 66 | |
| 67 std::vector<std::string> headers; | |
| 68 headers.push_back("CERTIFICATE"); | |
| 69 | |
| 70 // Convert certificate from PEM to raw DER | |
| 71 net::PEMTokenizer pem_tokenizer(certificate, headers); | |
| 72 if (!pem_tokenizer.GetNext()) { | |
| 73 LOG(ERROR) << kErrorPrefix << "Failed to parse device certificate."; | |
| 74 return false; | |
| 75 } | |
| 76 | |
| 77 // |certs| is a vector with the DER for all the certificates. | |
| 78 std::vector<std::string> certs; | |
| 79 certs.push_back(pem_tokenizer.data()); | |
| 80 | |
| 81 // Convert intermediate certificates from PEM to raw DER | |
| 82 for (size_t idx = 0; idx < intermediate_certificates.size(); ++idx) { | |
| 83 net::PEMTokenizer ica_pem_tokenizer(intermediate_certificates[idx], | |
| 84 headers); | |
| 85 if (ica_pem_tokenizer.GetNext()) { | |
| 86 certs.push_back(ica_pem_tokenizer.data()); | |
| 87 } else { | |
| 88 LOG(WARNING) << "Failed to parse intermediate certificates."; | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 // Note that the device certificate's policy is not enforced here. The goal | |
| 93 // is simply to verify that the device belongs to the Cast ecosystem. | |
| 94 cast_crypto::CastDeviceCertPolicy unused_policy; | |
| 95 | |
| 96 std::unique_ptr<cast_crypto::CertVerificationContext> verification_context; | |
| 97 if (!cast_crypto::VerifyDeviceCert(certs, time, &verification_context, | |
| 98 &unused_policy, nullptr, | |
| 99 cast_crypto::CRLPolicy::CRL_OPTIONAL)) { | |
| 100 LOG(ERROR) << kErrorPrefix << "Failed verifying cast device cert"; | |
| 101 return false; | |
| 102 } | |
| 103 | |
| 104 // Check that the device listed in the certificate is correct. | |
| 105 // Something like evt_e161 001a11ffacdf | |
| 106 std::string common_name = verification_context->GetCommonName(); | |
| 107 std::string translated_mac; | |
| 108 base::RemoveChars(connected_mac, ":", &translated_mac); | |
| 109 if (!base::EndsWith(common_name, translated_mac, | |
| 110 base::CompareCase::INSENSITIVE_ASCII)) { | |
| 111 LOG(ERROR) << kErrorPrefix << "MAC addresses don't match."; | |
| 112 return false; | |
| 113 } | |
| 114 | |
| 115 // Use the public key from verified certificate to verify |signature| over | |
| 116 // |data|. | |
| 117 if (!verification_context->VerifySignatureOverData(signature, data)) { | |
| 118 LOG(ERROR) << kErrorPrefix | |
| 119 << "Failed verifying signature using cast device cert"; | |
| 120 return false; | |
| 121 } | |
| 122 return true; | |
| 123 } | |
| 124 | |
| 125 bool EncryptByteString(const std::vector<uint8_t>& pub_key_der, | |
| 126 const std::string& data, | |
| 127 std::vector<uint8_t>* encrypted_output) { | |
| 128 crypto::EnsureOpenSSLInit(); | |
| 129 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
| 130 | |
| 131 bssl::UniquePtr<RSA> rsa( | |
| 132 RSA_public_key_from_bytes(pub_key_der.data(), pub_key_der.size())); | |
| 133 if (!rsa || RSA_size(rsa.get()) == 0) { | |
| 134 LOG(ERROR) << "Failed to parse public key"; | |
| 135 return false; | |
| 136 } | |
| 137 | |
| 138 encrypted_output->resize(RSA_size(rsa.get())); | |
| 139 int encrypted_length = RSA_public_encrypt( | |
| 140 data.size(), reinterpret_cast<const uint8_t*>(data.data()), | |
| 141 encrypted_output->data(), rsa.get(), RSA_PKCS1_PADDING); | |
| 142 if (encrypted_length < 0) { | |
| 143 LOG(ERROR) << "Error during decryption"; | |
| 144 return false; | |
| 145 } | |
| 146 encrypted_output->resize(encrypted_length); | |
| 147 return true; | |
| 148 } | |
| 149 | |
| 150 bool DecryptByteString(const std::string& private_key_pem, | |
| 151 const std::vector<uint8_t>& encrypted_data, | |
| 152 std::string* decrypted_output) { | |
| 153 crypto::EnsureOpenSSLInit(); | |
| 154 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
| 155 | |
| 156 std::vector<uint8_t> private_key_data; | |
| 157 if (!GetDERFromPEM(private_key_pem, "PRIVATE KEY", &private_key_data)) { | |
| 158 LOG(ERROR) << "Failed to parse private key PEM."; | |
| 159 return false; | |
| 160 } | |
| 161 std::unique_ptr<crypto::RSAPrivateKey> private_key( | |
| 162 crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(private_key_data)); | |
| 163 if (!private_key || !private_key->key()) { | |
| 164 LOG(ERROR) << "Failed to parse private key DER."; | |
| 165 return false; | |
| 166 } | |
| 167 | |
| 168 RSA* rsa = EVP_PKEY_get0_RSA(private_key->key()); | |
| 169 if (!rsa || RSA_size(rsa) == 0) { | |
| 170 LOG(ERROR) << "Failed to get RSA key."; | |
| 171 return false; | |
| 172 } | |
| 173 | |
| 174 uint8_t* output = reinterpret_cast<uint8_t*>( | |
| 175 base::WriteInto(decrypted_output, RSA_size(rsa) + 1)); | |
| 176 int output_length = | |
| 177 RSA_private_decrypt(encrypted_data.size(), &encrypted_data[0], output, | |
| 178 rsa, RSA_PKCS1_PADDING); | |
| 179 if (output_length < 0) { | |
| 180 LOG(ERROR) << "Error during decryption."; | |
| 181 return false; | |
| 182 } | |
| 183 decrypted_output->resize(output_length); | |
| 184 return true; | |
| 185 } | |
| 186 | |
| 187 } // namespace networking_private_crypto | |
| OLD | NEW |