networking_private_crypto_openssl.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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_crypto.h" 6 7#include <openssl/digest.h> 8#include <openssl/evp.h> 9#include <openssl/rsa.h> 10#include <openssl/x509.h> 11 12#include "base/logging.h" 13#include "base/strings/string_util.h" 14#include "crypto/openssl_util.h" 15#include "crypto/rsa_private_key.h" 16#include "crypto/scoped_openssl_types.h" 17#include "net/cert/pem_tokenizer.h" 18 19namespace { 20 21typedef crypto::ScopedOpenSSL<X509, X509_free>::Type ScopedX509; 22 23// Parses |pem_data| for a PEM block of |pem_type|. 24// Returns true if a |pem_type| block is found, storing the decoded result in 25// |der_output|. 26bool GetDERFromPEM(const std::string& pem_data, 27 const std::string& pem_type, 28 std::vector<uint8_t>* der_output) { 29 std::vector<std::string> headers; 30 headers.push_back(pem_type); 31 net::PEMTokenizer pem_tok(pem_data, headers); 32 if (!pem_tok.GetNext()) { 33 return false; 34 } 35 36 der_output->assign(pem_tok.data().begin(), pem_tok.data().end()); 37 return true; 38} 39 40} // namespace 41 42namespace networking_private_crypto { 43 44bool VerifyCredentials(const std::string& certificate, 45 const std::string& signature, 46 const std::string& data, 47 const std::string& connected_mac) { 48 crypto::EnsureOpenSSLInit(); 49 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); 50 51 std::vector<uint8_t> cert_data; 52 if (!GetDERFromPEM(certificate, "CERTIFICATE", &cert_data)) { 53 LOG(ERROR) << "Failed to parse certificate."; 54 return false; 55 } 56 57 // Parse into an OpenSSL X509. 58 const uint8_t* ptr = cert_data.empty() ? NULL : &cert_data[0]; 59 const uint8_t* end = ptr + cert_data.size(); 60 ScopedX509 cert(d2i_X509(NULL, &ptr, cert_data.size())); 61 if (!cert || ptr != end) { 62 LOG(ERROR) << "Failed to parse certificate."; 63 return false; 64 } 65 66 // Import the trusted public key. 67 ptr = kTrustedCAPublicKeyDER; 68 crypto::ScopedRSA ca_public_key_rsa( 69 d2i_RSAPublicKey(NULL, &ptr, kTrustedCAPublicKeyDERLength)); 70 if (!ca_public_key_rsa || 71 ptr != kTrustedCAPublicKeyDER + kTrustedCAPublicKeyDERLength) { 72 NOTREACHED(); 73 LOG(ERROR) << "Failed to import trusted public key."; 74 return false; 75 } 76 crypto::ScopedEVP_PKEY ca_public_key(EVP_PKEY_new()); 77 if (!ca_public_key || 78 !EVP_PKEY_set1_RSA(ca_public_key.get(), ca_public_key_rsa.get())) { 79 LOG(ERROR) << "Failed to initialize EVP_PKEY"; 80 return false; 81 } 82 83 // Check that the certificate is signed by the trusted public key. 84 if (X509_verify(cert.get(), ca_public_key.get()) <= 0) { 85 LOG(ERROR) << "Certificate is not issued by the trusted CA."; 86 return false; 87 } 88 89 // Check that the device listed in the certificate is correct. 90 // Something like evt_e161 001a11ffacdf 91 std::string common_name; 92 int common_name_length = X509_NAME_get_text_by_NID( 93 cert->cert_info->subject, NID_commonName, NULL, 0); 94 if (common_name_length < 0) { 95 LOG(ERROR) << "Certificate does not have common name."; 96 return false; 97 } 98 if (common_name_length > 0) { 99 common_name_length = X509_NAME_get_text_by_NID( 100 cert->cert_info->subject, 101 NID_commonName, 102 WriteInto(&common_name, common_name_length + 1), 103 common_name_length + 1); 104 DCHECK_EQ((int)common_name.size(), common_name_length); 105 if (common_name_length < 0) { 106 LOG(ERROR) << "Certificate does not have common name."; 107 return false; 108 } 109 common_name.resize(common_name_length); 110 } 111 112 std::string translated_mac; 113 base::RemoveChars(connected_mac, ":", &translated_mac); 114 if (!EndsWith(common_name, translated_mac, false)) { 115 LOG(ERROR) << "MAC addresses don't match."; 116 return false; 117 } 118 119 // Make sure that the certificate matches the unsigned data presented. 120 // Verify that the |signature| matches |data|. 121 crypto::ScopedEVP_PKEY public_key(X509_get_pubkey(cert.get())); 122 if (!public_key) { 123 LOG(ERROR) << "Unable to extract public key from certificate."; 124 return false; 125 } 126 127 crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create()); 128 if (!ctx) { 129 LOG(ERROR) << "Unable to allocate EVP_MD_CTX."; 130 return false; 131 } 132 if (EVP_DigestVerifyInit( 133 ctx.get(), NULL, EVP_sha1(), NULL, public_key.get()) <= 0 || 134 EVP_DigestVerifyUpdate(ctx.get(), data.data(), data.size()) <= 0 || 135 EVP_DigestVerifyFinal(ctx.get(), 136 reinterpret_cast<const uint8_t*>(signature.data()), 137 signature.size()) <= 0) { 138 LOG(ERROR) << "Signed blobs did not match."; 139 return false; 140 } 141 return true; 142} 143 144bool EncryptByteString(const std::vector<uint8_t>& pub_key_der, 145 const std::string& data, 146 std::vector<uint8_t>* encrypted_output) { 147 crypto::EnsureOpenSSLInit(); 148 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); 149 150 const uint8_t* ptr = pub_key_der.empty() ? NULL : &pub_key_der[0]; 151 const uint8_t* end = ptr + pub_key_der.size(); 152 crypto::ScopedRSA rsa(d2i_RSAPublicKey(NULL, &ptr, pub_key_der.size())); 153 if (!rsa || ptr != end || RSA_size(rsa.get()) == 0) { 154 LOG(ERROR) << "Failed to parse public key"; 155 return false; 156 } 157 158 scoped_ptr<uint8_t[]> rsa_output(new uint8_t[RSA_size(rsa.get())]); 159 int encrypted_length = 160 RSA_public_encrypt(data.size(), 161 reinterpret_cast<const uint8_t*>(data.data()), 162 rsa_output.get(), 163 rsa.get(), 164 RSA_PKCS1_PADDING); 165 if (encrypted_length < 0) { 166 LOG(ERROR) << "Error during decryption"; 167 return false; 168 } 169 encrypted_output->assign(rsa_output.get(), 170 rsa_output.get() + encrypted_length); 171 return true; 172} 173 174bool DecryptByteString(const std::string& private_key_pem, 175 const std::vector<uint8_t>& encrypted_data, 176 std::string* decrypted_output) { 177 crypto::EnsureOpenSSLInit(); 178 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); 179 180 std::vector<uint8_t> private_key_data; 181 if (!GetDERFromPEM(private_key_pem, "PRIVATE KEY", &private_key_data)) { 182 LOG(ERROR) << "Failed to parse private key PEM."; 183 return false; 184 } 185 scoped_ptr<crypto::RSAPrivateKey> private_key( 186 crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(private_key_data)); 187 if (!private_key || !private_key->key()) { 188 LOG(ERROR) << "Failed to parse private key DER."; 189 return false; 190 } 191 192 crypto::ScopedRSA rsa(EVP_PKEY_get1_RSA(private_key->key())); 193 if (!rsa || RSA_size(rsa.get()) == 0) { 194 LOG(ERROR) << "Failed to get RSA key."; 195 return false; 196 } 197 198 scoped_ptr<uint8_t[]> rsa_output(new uint8_t[RSA_size(rsa.get())]); 199 int output_length = RSA_private_decrypt(encrypted_data.size(), 200 &encrypted_data[0], 201 rsa_output.get(), 202 rsa.get(), 203 RSA_PKCS1_PADDING); 204 if (output_length < 0) { 205 LOG(ERROR) << "Error during decryption."; 206 return false; 207 } 208 decrypted_output->assign(reinterpret_cast<char*>(rsa_output.get()), 209 output_length); 210 return true; 211} 212 213} // namespace networking_private_crypto 214