diff options
author | pneubeck@chromium.org <pneubeck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-21 16:42:18 +0000 |
---|---|---|
committer | pneubeck@chromium.org <pneubeck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-21 16:42:18 +0000 |
commit | d46dc78255481d716d3be4da48f70a0bf06dabe6 (patch) | |
tree | ad93eec88d64b552cd6718f41ea9c0a0b30902ae /chromeos/network/onc | |
parent | 5e5ce0faaee95df25a9ec4b1daa4ad50651ae8ee (diff) | |
download | chromium_src-d46dc78255481d716d3be4da48f70a0bf06dabe6.zip chromium_src-d46dc78255481d716d3be4da48f70a0bf06dabe6.tar.gz chromium_src-d46dc78255481d716d3be4da48f70a0bf06dabe6.tar.bz2 |
Move PEM certificate decoding to onc_utils.
This prepares usage of the decoding in NetworkLibrary.
While there, removed redundant namespace qualifiers from onc_utils.*.
BUG=208986
Review URL: https://chromiumcodereview.appspot.com/17471005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207861 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos/network/onc')
-rw-r--r-- | chromeos/network/onc/onc_certificate_importer.cc | 45 | ||||
-rw-r--r-- | chromeos/network/onc/onc_utils.cc | 110 | ||||
-rw-r--r-- | chromeos/network/onc/onc_utils.h | 18 |
3 files changed, 90 insertions, 83 deletions
diff --git a/chromeos/network/onc/onc_certificate_importer.cc b/chromeos/network/onc/onc_certificate_importer.cc index fe8e66b..72c715e 100644 --- a/chromeos/network/onc/onc_certificate_importer.cc +++ b/chromeos/network/onc/onc_certificate_importer.cc @@ -13,10 +13,10 @@ #include "base/values.h" #include "chromeos/network/network_event_log.h" #include "chromeos/network/onc/onc_constants.h" +#include "chromeos/network/onc/onc_utils.h" #include "net/base/crypto_module.h" #include "net/base/net_errors.h" #include "net/cert/nss_cert_database.h" -#include "net/cert/pem_tokenizer.h" #include "net/cert/x509_certificate.h" #define ONC_LOG_WARNING(message) \ @@ -24,15 +24,6 @@ #define ONC_LOG_ERROR(message) \ NET_LOG_ERROR("ONC Certificate Import Error", message) -namespace { - -// The PEM block header used for DER certificates -const char kCertificateHeader[] = "CERTIFICATE"; -// This is an older PEM marker for DER certificates. -const char kX509CertificateHeader[] = "X509 CERTIFICATE"; - -} // namespace - namespace chromeos { namespace onc { @@ -206,34 +197,11 @@ bool CertificateImporter::ParseServerOrCaCertificate( return false; } - // Parse PEM certificate, and get the decoded data for use in creating - // certificate below. - std::vector<std::string> pem_headers; - pem_headers.push_back(kCertificateHeader); - pem_headers.push_back(kX509CertificateHeader); - - net::PEMTokenizer pem_tokenizer(x509_data, pem_headers); - std::string decoded_x509; - if (!pem_tokenizer.GetNext()) { - // If we failed to read the data as a PEM file, then let's just try plain - // base64 decode: some versions of Spigots didn't apply the PEM marker - // strings. For this to work, there has to be no white space, and it has to - // only contain the base64-encoded data. - if (!base::Base64Decode(x509_data, &decoded_x509)) { - ONC_LOG_ERROR("Unable to base64 decode X509 data: " + x509_data); - return false; - } - } else { - decoded_x509 = pem_tokenizer.data(); - } - scoped_refptr<net::X509Certificate> x509_cert = - net::X509Certificate::CreateFromBytesWithNickname( - decoded_x509.data(), - decoded_x509.size(), - guid.c_str()); + DecodePEMCertificate(x509_data, guid); if (!x509_cert.get()) { - ONC_LOG_ERROR("Unable to create X509 certificate from bytes."); + ONC_LOG_ERROR("Unable to create certificate from PEM encoding, type: " + + cert_type); return false; } @@ -264,10 +232,7 @@ bool CertificateImporter::ParseServerOrCaCertificate( } // Reload the cert here to get an actual temporary cert instance. - x509_cert = net::X509Certificate::CreateFromBytesWithNickname( - decoded_x509.data(), - decoded_x509.size(), - guid.c_str()); + x509_cert = DecodePEMCertificate(x509_data, guid); if (!x509_cert.get()) { ONC_LOG_ERROR("Unable to create X509 certificate from bytes."); return false; diff --git a/chromeos/network/onc/onc_utils.cc b/chromeos/network/onc/onc_utils.cc index 4dbbfba..7976826 100644 --- a/chromeos/network/onc/onc_utils.cc +++ b/chromeos/network/onc/onc_utils.cc @@ -18,6 +18,7 @@ #include "crypto/encryptor.h" #include "crypto/hmac.h" #include "crypto/symmetric_key.h" +#include "net/cert/pem_tokenizer.h" #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message) #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message) @@ -179,14 +180,14 @@ void ExpandField(const std::string fieldname, std::string login_id; if (substitution.GetSubstitute(substitutes::kLoginIDField, &login_id)) { ReplaceSubstringsAfterOffset(&user_string, 0, - onc::substitutes::kLoginIDField, + substitutes::kLoginIDField, login_id); } std::string email; if (substitution.GetSubstitute(substitutes::kEmailField, &email)) { ReplaceSubstringsAfterOffset(&user_string, 0, - onc::substitutes::kEmailField, + substitutes::kEmailField, email); } @@ -224,10 +225,10 @@ void ExpandStringsInOncObject( namespace { -class OncMaskValues : public onc::Mapper { +class OncMaskValues : public Mapper { public: static scoped_ptr<base::DictionaryValue> Mask( - const onc::OncValueSignature& signature, + const OncValueSignature& signature, const base::DictionaryValue& onc_object, const std::string& mask) { OncMaskValues masker(mask); @@ -242,15 +243,15 @@ class OncMaskValues : public onc::Mapper { virtual scoped_ptr<base::Value> MapField( const std::string& field_name, - const onc::OncValueSignature& object_signature, + const OncValueSignature& object_signature, const base::Value& onc_value, bool* found_unknown_field, bool* error) OVERRIDE { - if (onc::FieldIsCredential(object_signature, field_name)) { + if (FieldIsCredential(object_signature, field_name)) { return scoped_ptr<base::Value>(new base::StringValue(mask_)); } else { - return onc::Mapper::MapField(field_name, object_signature, onc_value, - found_unknown_field, error); + return Mapper::MapField(field_name, object_signature, onc_value, + found_unknown_field, error); } } @@ -261,92 +262,125 @@ class OncMaskValues : public onc::Mapper { } // namespace scoped_ptr<base::DictionaryValue> MaskCredentialsInOncObject( - const onc::OncValueSignature& signature, + const OncValueSignature& signature, const base::DictionaryValue& onc_object, const std::string& mask) { return OncMaskValues::Mask(signature, onc_object, mask); } -bool ParseAndValidateOncForImport( - const std::string& onc_blob, - chromeos::onc::ONCSource onc_source, - const std::string& passphrase, - base::ListValue* network_configs, - base::ListValue* certificates) { +bool ParseAndValidateOncForImport(const std::string& onc_blob, + ONCSource onc_source, + const std::string& passphrase, + base::ListValue* network_configs, + base::ListValue* certificates) { certificates->Clear(); network_configs->Clear(); if (onc_blob.empty()) return true; scoped_ptr<base::DictionaryValue> toplevel_onc = - onc::ReadDictionaryFromJson(onc_blob); + ReadDictionaryFromJson(onc_blob); if (toplevel_onc.get() == NULL) { - LOG(ERROR) << "ONC loaded from " << onc::GetSourceAsString(onc_source) + LOG(ERROR) << "ONC loaded from " << GetSourceAsString(onc_source) << " is not a valid JSON dictionary."; return false; } // Check and see if this is an encrypted ONC file. If so, decrypt it. std::string onc_type; - toplevel_onc->GetStringWithoutPathExpansion(onc::toplevel_config::kType, + toplevel_onc->GetStringWithoutPathExpansion(toplevel_config::kType, &onc_type); - if (onc_type == onc::toplevel_config::kEncryptedConfiguration) { - toplevel_onc = onc::Decrypt(passphrase, *toplevel_onc); + if (onc_type == toplevel_config::kEncryptedConfiguration) { + toplevel_onc = Decrypt(passphrase, *toplevel_onc); if (toplevel_onc.get() == NULL) { LOG(ERROR) << "Couldn't decrypt the ONC from " - << onc::GetSourceAsString(onc_source); + << GetSourceAsString(onc_source); return false; } } - bool from_policy = (onc_source == onc::ONC_SOURCE_USER_POLICY || - onc_source == onc::ONC_SOURCE_DEVICE_POLICY); + bool from_policy = (onc_source == ONC_SOURCE_USER_POLICY || + onc_source == ONC_SOURCE_DEVICE_POLICY); // Validate the ONC dictionary. We are liberal and ignore unknown field // names and ignore invalid field names in kRecommended arrays. - onc::Validator validator(false, // Ignore unknown fields. - false, // Ignore invalid recommended field names. - true, // Fail on missing fields. - from_policy); + Validator validator(false, // Ignore unknown fields. + false, // Ignore invalid recommended field names. + true, // Fail on missing fields. + from_policy); validator.SetOncSource(onc_source); - onc::Validator::Result validation_result; + Validator::Result validation_result; toplevel_onc = validator.ValidateAndRepairObject( - &onc::kToplevelConfigurationSignature, + &kToplevelConfigurationSignature, *toplevel_onc, &validation_result); if (from_policy) { UMA_HISTOGRAM_BOOLEAN("Enterprise.ONC.PolicyValidation", - validation_result == onc::Validator::VALID); + validation_result == Validator::VALID); } bool success = true; - if (validation_result == onc::Validator::VALID_WITH_WARNINGS) { - LOG(WARNING) << "ONC from " << onc::GetSourceAsString(onc_source) + if (validation_result == Validator::VALID_WITH_WARNINGS) { + LOG(WARNING) << "ONC from " << GetSourceAsString(onc_source) << " produced warnings."; success = false; - } else if (validation_result == onc::Validator::INVALID || - toplevel_onc == NULL) { - LOG(ERROR) << "ONC from " << onc::GetSourceAsString(onc_source) + } else if (validation_result == Validator::INVALID || toplevel_onc == NULL) { + LOG(ERROR) << "ONC from " << GetSourceAsString(onc_source) << " is invalid and couldn't be repaired."; return false; } base::ListValue* validated_certs = NULL; - if (toplevel_onc->GetListWithoutPathExpansion( - onc::toplevel_config::kCertificates, &validated_certs)) { + if (toplevel_onc->GetListWithoutPathExpansion(toplevel_config::kCertificates, + &validated_certs)) { certificates->Swap(validated_certs); } base::ListValue* validated_networks = NULL; if (toplevel_onc->GetListWithoutPathExpansion( - onc::toplevel_config::kNetworkConfigurations, &validated_networks)) { + toplevel_config::kNetworkConfigurations, &validated_networks)) { network_configs->Swap(validated_networks); } return success; } +scoped_refptr<net::X509Certificate> DecodePEMCertificate( + const std::string& pem_encoded, + const std::string& nickname) { + // The PEM block header used for DER certificates + static const char kCertificateHeader[] = "CERTIFICATE"; + // This is an older PEM marker for DER certificates. + static const char kX509CertificateHeader[] = "X509 CERTIFICATE"; + + std::vector<std::string> pem_headers; + pem_headers.push_back(kCertificateHeader); + pem_headers.push_back(kX509CertificateHeader); + + net::PEMTokenizer pem_tokenizer(pem_encoded, pem_headers); + std::string decoded; + if (pem_tokenizer.GetNext()) { + decoded = pem_tokenizer.data(); + } else { + // If we failed to read the data as a PEM file, then try plain base64 decode + // in case the PEM marker strings are missing. For this to work, there has + // to be no white space, and it has to only contain the base64-encoded data. + if (!base::Base64Decode(pem_encoded, &decoded)) { + LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded; + return scoped_refptr<net::X509Certificate>(); + } + } + + scoped_refptr<net::X509Certificate> cert = + net::X509Certificate::CreateFromBytesWithNickname(decoded.data(), + decoded.size(), + nickname.c_str()); + LOG_IF(ERROR, !cert) << "Couldn't create certificate from X509 data: " + << decoded; + return cert; +} + } // namespace onc } // namespace chromeos diff --git a/chromeos/network/onc/onc_utils.h b/chromeos/network/onc/onc_utils.h index 6a6d273..d604cfc 100644 --- a/chromeos/network/onc/onc_utils.h +++ b/chromeos/network/onc/onc_utils.h @@ -8,9 +8,11 @@ #include <string> #include "base/basictypes.h" +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "chromeos/chromeos_export.h" #include "chromeos/network/onc/onc_constants.h" +#include "net/cert/x509_certificate.h" namespace base { class DictionaryValue; @@ -49,8 +51,8 @@ class CHROMEOS_EXPORT StringSubstitution { virtual ~StringSubstitution() {} // Returns the replacement string for |placeholder| in - // |substitute|. Currently, onc::substitutes::kLoginIDField and - // onc::substitutes::kEmailField are supported. + // |substitute|. Currently, substitutes::kLoginIDField and + // substitutes::kEmailField are supported. virtual bool GetSubstitute(std::string placeholder, std::string* substitute) const = 0; private: @@ -59,8 +61,8 @@ class CHROMEOS_EXPORT StringSubstitution { // Replaces all expandable fields that are mentioned in the ONC // specification. The object of |onc_object| is modified in place. Currently -// onc::substitutes::kLoginIDField and onc::substitutes::kEmailField are -// expanded. The replacement strings are obtained from |substitution|. +// substitutes::kLoginIDField and substitutes::kEmailField are expanded. The +// replacement strings are obtained from |substitution|. CHROMEOS_EXPORT void ExpandStringsInOncObject( const OncValueSignature& signature, const StringSubstitution& substitution, @@ -81,11 +83,17 @@ CHROMEOS_EXPORT scoped_ptr<base::DictionaryValue> MaskCredentialsInOncObject( // output lists and should be further processed by the caller. CHROMEOS_EXPORT bool ParseAndValidateOncForImport( const std::string& onc_blob, - chromeos::onc::ONCSource onc_source, + ONCSource onc_source, const std::string& passphrase, base::ListValue* network_configs, base::ListValue* certificates); +// Parse the given PEM encoded certificate |pem_encoded| and create a +// X509Certificate from it. +CHROMEOS_EXPORT scoped_refptr<net::X509Certificate> DecodePEMCertificate( + const std::string& pem_encoded, + const std::string& nickname); + } // namespace onc } // namespace chromeos |