Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(110)

Unified Diff: extensions/common/cast/cast_cert_validator_nss.cc

Issue 792353002: Refactoring of Cast-related crypto code (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: s/NetworkingPrivateCredentialsGetterCrOs/NetworkingPrivateCredentialsGetterChromeos/g Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: extensions/common/cast/cast_cert_validator_nss.cc
diff --git a/extensions/common/cast/cast_cert_validator_nss.cc b/extensions/common/cast/cast_cert_validator_nss.cc
new file mode 100644
index 0000000000000000000000000000000000000000..776aae28e22c235f3188de11b2bf939ef3dcacf1
--- /dev/null
+++ b/extensions/common/cast/cast_cert_validator_nss.cc
@@ -0,0 +1,159 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/common/cast/cast_cert_validator.h"
+
+#include <cert.h>
+#include <cryptohi.h>
+#include <pk11pub.h>
+#include <seccomon.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "crypto/nss_util.h"
+#include "crypto/scoped_nss_types.h"
+#include "extensions/browser/api/cast_channel/cast_auth_ica.h"
+
+namespace extensions {
+namespace core_api {
+namespace cast_crypto {
+
+namespace {
+
+typedef scoped_ptr<
+ CERTCertificate,
+ crypto::NSSDestroyer<CERTCertificate, CERT_DestroyCertificate>>
+ ScopedCERTCertificate;
+
+class CertVerificationContextNSS : public CertVerificationContext {
+ public:
+ explicit CertVerificationContextNSS(CERTCertificate* x509) : x509_(x509) {}
Ryan Sleevi 2014/12/15 21:43:00 NAMING: s/x509/certificate/ (throughout)
sheretov 2014/12/16 08:44:21 Done.
+
+ VerificationResult VerifySignatureOverData(
+ const base::StringPiece& signature,
+ const base::StringPiece& data) const override {
+ // Verify that the |signature| matches |peer_cert|.
+ crypto::ScopedSECKEYPublicKey public_key(
+ CERT_ExtractPublicKey(x509_.get()));
+ if (!public_key.get()) {
+ return VerificationResult(
+ "Unable to extract public key from certificate",
+ VerificationResult::ERROR_CANNOT_EXTRACT_PUBLIC_KEY, PORT_GetError());
+ }
+ SECItem signature_item;
+ signature_item.type = siBuffer;
+ signature_item.data =
+ reinterpret_cast<unsigned char*>(const_cast<char*>(signature.data()));
+ signature_item.len = signature.length();
+ SECStatus verified = VFY_VerifyDataDirect(
+ reinterpret_cast<unsigned char*>(const_cast<char*>(data.data())),
+ data.size(), public_key.get(), &signature_item,
+ SEC_OID_PKCS1_RSA_ENCRYPTION, SEC_OID_SHA1, NULL, NULL);
+
+ if (verified != SECSuccess) {
+ return VerificationResult("Signature verification failed.",
+ VerificationResult::ERROR_SIGNATURE_INVALID,
+ PORT_GetError());
+ }
+ VLOG(1) << "Signature verification succeeded";
+ return VerificationResult();
+ }
+
+ std::string getCommonName() const override {
+ char* common_name = CERT_GetCommonName(&x509_->subject);
+ if (!common_name) {
+ LOG(ERROR) << "Certificate does not have common name.";
+ return "";
Ryan Sleevi 2014/12/15 21:43:00 s/""/std::string()
sheretov 2014/12/16 08:44:21 Done.
+ } else {
+ std::string result(common_name);
+ PORT_Free(common_name);
+ return result;
+ }
+ }
+
+ private:
+ ScopedCERTCertificate x509_;
+};
+
+} // namespace
+
+VerificationResult VerifyCert(const base::StringPiece& device_cert,
+ const std::vector<std::string>& ica_certs,
+ CertVerificationContext** out_context) {
+ const std::string kErrorPrefix("Failed to verify credentials: ");
+
+ // If the list of intermediates is empty then use kPublicKeyICA1 as
+ // the trusted CA (legacy case).
+ // Otherwise, use the first intermediate in the list as long as it
+ // is in the allowed list of intermediates.
+ int num_intermediates = ica_certs.size();
+
+ VLOG(1) << "Response has " << num_intermediates << " intermediates";
Ryan Sleevi 2014/12/15 21:43:00 SPAM: This is spammy. Don't log like this. It does
sheretov 2014/12/16 08:44:21 Done.
+
+ base::StringPiece ica;
+ if (num_intermediates <= 0) {
+ ica = cast_channel::GetDefaultTrustedICAPublicKey();
+ } else {
+ ica = cast_channel::GetTrustedICAPublicKey(ica_certs[0]);
+ }
+ if (ica.empty()) {
+ return VerificationResult(
+ "Disallowed intermediate cert",
+ VerificationResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA);
+ }
+
+ SECItem trusted_ca_key_der;
+ trusted_ca_key_der.type = SECItemType::siDERCertBuffer;
+ trusted_ca_key_der.data =
+ const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(ica.data()));
+ trusted_ca_key_der.len = ica.size();
+
+ crypto::EnsureNSSInit();
+ SECItem der_cert;
+ der_cert.type = siDERCertBuffer;
+ // Make a copy of certificate string so it is safe to type cast.
+ der_cert.data =
+ reinterpret_cast<unsigned char*>(const_cast<char*>(device_cert.data()));
+ der_cert.len = device_cert.length();
+
+ // Parse into a certificate structure.
+ ScopedCERTCertificate cert(CERT_NewTempCertificate(
+ CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE));
+ if (!cert.get()) {
+ return VerificationResult("Failed to parse certificate.",
+ VerificationResult::ERROR_CERT_PARSING_FAILED,
+ PORT_GetError());
+ }
+
+ // Check that the certificate is signed by trusted CA.
+ // NOTE: We const_cast trusted_ca_key_der since on some platforms
+ // SECKEY_ImportDERPublicKey API takes in SECItem* and not const
+ // SECItem*.
+ crypto::ScopedSECKEYPublicKey ca_public_key(
+ SECKEY_ImportDERPublicKey(&trusted_ca_key_der, CKK_RSA));
+ if (!ca_public_key) {
+ return VerificationResult(
+ "Failed to import public key from CA certificate.",
+ VerificationResult::ERROR_CERT_PARSING_FAILED, PORT_GetError());
+ }
+ SECStatus verified = CERT_VerifySignedDataWithPublicKey(
+ &cert->signatureWrap, ca_public_key.get(), NULL);
+ if (verified != SECSuccess) {
+ return VerificationResult(
+ "Cert not signed by trusted CA",
+ VerificationResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA,
+ PORT_GetError());
+ }
+
+ VLOG(1) << "Cert signed by trusted CA";
Ryan Sleevi 2014/12/15 21:43:00 SPAM: This is also spammy. Considering you don't l
sheretov 2014/12/16 08:44:21 Done.
+
+ if (out_context)
+ *out_context = new CertVerificationContextNSS(cert.release());
+
+ return VerificationResult();
+}
+
+} // namespace cast_crypto
+} // namespace core_api
+} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698