Chromium Code Reviews| Index: chromeos/network/onc/onc_utils.cc |
| diff --git a/chromeos/network/onc/onc_utils.cc b/chromeos/network/onc/onc_utils.cc |
| index 79768268f09ec41f31b9502247deed0676cb0167..5d4a0c7ada71d68bcd97465712fd435a79cd9b59 100644 |
| --- a/chromeos/network/onc/onc_utils.cc |
| +++ b/chromeos/network/onc/onc_utils.cc |
| @@ -8,6 +8,7 @@ |
| #include "base/json/json_reader.h" |
| #include "base/logging.h" |
| #include "base/metrics/histogram.h" |
| +#include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/values.h" |
| #include "chromeos/network/network_event_log.h" |
| @@ -18,7 +19,9 @@ |
| #include "crypto/encryptor.h" |
| #include "crypto/hmac.h" |
| #include "crypto/symmetric_key.h" |
| +#include "net/base/hash_value.h" |
| #include "net/cert/pem_tokenizer.h" |
| +#include "net/cert/x509_certificate.h" |
| #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message) |
| #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message) |
| @@ -347,9 +350,50 @@ bool ParseAndValidateOncForImport(const std::string& onc_blob, |
| return success; |
| } |
| +std::string GetHexFingerprintOfCert(const net::X509Certificate& cert) { |
| + net::SHA1HashValue fingerprint = cert.fingerprint(); |
| + return base::HexEncode(fingerprint.data, sizeof(fingerprint.data)); |
| +} |
| + |
| +net::X509Certificate* FindCertByFingerprint( |
| + const net::CertificateList& cert_list, const std::string& fingerprint) { |
| + net::X509Certificate* found = NULL; |
| + for (net::CertificateList::const_iterator it = cert_list.begin(); |
| + it != cert_list.end(); ++it) { |
| + if (GetHexFingerprintOfCert(**it) != fingerprint) |
| + continue; |
| + if (found != NULL) { |
| + LOG(ERROR) << "Fingerprint not unique in list."; |
|
Mattias Nissler (ping if slow)
2013/06/24 12:45:09
Rather, cert present twice in list. I don't think
pneubeck (no reviews)
2013/06/24 15:35:41
Done.
|
| + return NULL; |
| + } |
| + found = it->get(); |
| + } |
| + return found; |
| +} |
| + |
| +std::string GetPEMEncodedCertFromFingerprint( |
| + const net::CertificateList& cert_list, |
| + const std::string& fingerprint) { |
| + net::X509Certificate* cert = FindCertByFingerprint(cert_list, fingerprint); |
| + if (!cert) { |
| + LOG(ERROR) << "Couldn't find a certificate with fingerprint " |
| + << fingerprint; |
| + return std::string(); |
| + } |
| + |
| + std::string pem_encoded_cert; |
| + if (!net::X509Certificate::GetPEMEncoded(cert->os_cert_handle(), |
| + &pem_encoded_cert)) { |
| + LOG(ERROR) << "Couldn't PEM-encode certificate with fingerprint " |
| + << fingerprint; |
| + return std::string(); |
| + } |
| + |
| + return pem_encoded_cert; |
| +} |
| + |
| scoped_refptr<net::X509Certificate> DecodePEMCertificate( |
| - const std::string& pem_encoded, |
| - const std::string& nickname) { |
| + const std::string& pem_encoded) { |
| // The PEM block header used for DER certificates |
| static const char kCertificateHeader[] = "CERTIFICATE"; |
| // This is an older PEM marker for DER certificates. |
| @@ -374,13 +418,112 @@ scoped_refptr<net::X509Certificate> DecodePEMCertificate( |
| } |
| scoped_refptr<net::X509Certificate> cert = |
| - net::X509Certificate::CreateFromBytesWithNickname(decoded.data(), |
| - decoded.size(), |
| - nickname.c_str()); |
| + net::X509Certificate::CreateFromBytes(decoded.data(), decoded.size()); |
| LOG_IF(ERROR, !cert) << "Couldn't create certificate from X509 data: " |
| << decoded; |
| return cert; |
| } |
| +namespace { |
| + |
| +bool ResolveCertRef( |
| + const std::map<std::string, |
| + scoped_refptr<net::X509Certificate> >& certs_by_guid, |
| + const std::string& key_guid_ref, |
| + const std::string& key_fingerprint, |
| + base::DictionaryValue* dict) { |
| + std::string guid_ref; |
| + if (!dict->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref)) |
| + return true; |
| + std::map<std::string, scoped_refptr<net::X509Certificate> >::const_iterator |
| + it = certs_by_guid.find(guid_ref); |
| + if (it == certs_by_guid.end()) { |
| + LOG(ERROR) << "Couldn't resolve certificate reference " << guid_ref; |
| + return false; |
| + } |
| + |
| + dict->SetStringWithoutPathExpansion( |
| + key_fingerprint, |
| + GetHexFingerprintOfCert(*it->second)); |
| + return true; |
| +} |
| + |
| +bool ResolveServerCertRefsInObject( |
| + const std::map<std::string, |
| + scoped_refptr<net::X509Certificate> >& certs_by_guid, |
| + const OncValueSignature& signature, |
| + base::DictionaryValue* onc_object) { |
| + if (&signature == &kEAPSignature) { |
| + if (!ResolveCertRef(certs_by_guid, eap::kServerCARef, |
| + eap::kServerCAFingerprint, onc_object)) { |
| + return false; |
| + } |
| + } else if (&signature == &kL2TPSignature || |
| + &signature == &kOpenVPNSignature) { |
| + if (!ResolveCertRef(certs_by_guid, vpn::kServerCARef, |
| + vpn::kServerCAFingerprint, onc_object) || |
| + !ResolveCertRef(certs_by_guid, vpn::kServerCertRef, |
| + vpn::kServerCertFingerprint, onc_object)) { |
| + return false;; |
| + } |
| + } |
| + |
| + // Recurse into nested objects. |
| + for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd(); |
| + it.Advance()) { |
| + base::DictionaryValue* inner_object = NULL; |
| + if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object)) |
| + continue; |
| + |
| + const OncFieldSignature* field_signature = |
| + GetFieldSignature(signature, it.key()); |
| + if (!field_signature) |
| + continue; |
| + |
| + if (!ResolveServerCertRefsInObject(certs_by_guid, |
| + *field_signature->value_signature, |
| + inner_object)) { |
| + return false; |
| + } |
| + } |
| + return true; |
| +} |
| + |
| +} // namespace |
| + |
| +bool ResolveServerCertRefsInNetworks( |
| + const std::map<std::string, |
| + scoped_refptr<net::X509Certificate> >& certs_by_guid, |
| + base::ListValue* network_configs) { |
| + bool success = true; |
| + for (base::ListValue::iterator it = network_configs->begin(); |
| + it != network_configs->end(); ) { |
| + base::DictionaryValue* network = NULL; |
| + (*it)->GetAsDictionary(&network); |
| + if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) { |
| + std::string guid; |
| + network->GetStringWithoutPathExpansion(network_config::kGUID, &guid); |
| + // This might happen even with correct validation, if the referenced |
| + // certificate couldn't be imported. |
| + LOG(ERROR) << "Couldn't resolve some certificate reference of network " |
| + << guid; |
| + it = network_configs->Erase(it, NULL); |
| + success = false; |
| + continue; |
| + } |
| + ++it; |
| + } |
| + return success; |
| +} |
| + |
| +bool ResolveServerCertRefsInNetwork( |
| + const std::map<std::string, |
| + scoped_refptr<net::X509Certificate> >& certs_by_guid, |
| + base::DictionaryValue* network_config) { |
| + return ResolveServerCertRefsInObject(certs_by_guid, |
| + kNetworkConfigurationSignature, |
| + network_config); |
| +} |
| + |
| } // namespace onc |
| } // namespace chromeos |