Fix crash on app list start page contents not existing.
[chromium-blink-merge.git] / extensions / common / cast / cast_cert_validator_nss.cc
blob425da28f30649f649085d63a2ddd0c3d6bc31a14
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.
5 #include "extensions/common/cast/cast_cert_validator.h"
7 #include <cert.h>
8 #include <cryptohi.h>
9 #include <pk11pub.h>
10 #include <seccomon.h>
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "crypto/nss_util.h"
16 #include "crypto/scoped_nss_types.h"
17 #include "extensions/browser/api/cast_channel/cast_auth_ica.h"
19 namespace extensions {
20 namespace core_api {
21 namespace cast_crypto {
23 namespace {
25 typedef scoped_ptr<
26 CERTCertificate,
27 crypto::NSSDestroyer<CERTCertificate, CERT_DestroyCertificate>>
28 ScopedCERTCertificate;
30 class CertVerificationContextNSS : public CertVerificationContext {
31 public:
32 explicit CertVerificationContextNSS(CERTCertificate* certificate)
33 : certificate_(certificate) {}
35 VerificationResult VerifySignatureOverData(
36 const base::StringPiece& signature,
37 const base::StringPiece& data) const override {
38 // Retrieve public key object
39 crypto::ScopedSECKEYPublicKey public_key_obj(
40 CERT_ExtractPublicKey(certificate_.get()));
41 if (!public_key_obj.get()) {
42 return VerificationResult(
43 "Failed to extract device certificate public key.",
44 VerificationResult::ERROR_CERT_INVALID);
46 // Verify signature.
47 SECItem signature_item;
48 signature_item.type = siBuffer;
49 signature_item.data =
50 reinterpret_cast<unsigned char*>(const_cast<char*>(signature.data()));
51 signature_item.len = signature.length();
52 if (VFY_VerifyDataDirect(
53 reinterpret_cast<unsigned char*>(const_cast<char*>(data.data())),
54 data.size(), public_key_obj.get(), &signature_item,
55 SEC_OID_PKCS1_RSA_ENCRYPTION, SEC_OID_SHA1, NULL,
56 NULL) != SECSuccess) {
57 return VerificationResult("Signature verification failed.",
58 VerificationResult::ERROR_SIGNATURE_INVALID,
59 PORT_GetError());
61 return VerificationResult();
64 std::string GetCommonName() const override {
65 char* common_name = CERT_GetCommonName(&certificate_->subject);
66 if (!common_name)
67 return std::string();
69 std::string result(common_name);
70 PORT_Free(common_name);
71 return result;
74 private:
75 ScopedCERTCertificate certificate_;
78 } // namespace
80 VerificationResult VerifyDeviceCert(
81 const base::StringPiece& device_cert,
82 const std::vector<std::string>& ica_certs,
83 scoped_ptr<CertVerificationContext>* context) {
84 crypto::EnsureNSSInit();
86 // If the list of intermediates is empty then use kPublicKeyICA1 as
87 // the trusted CA (legacy case).
88 // Otherwise, use the first intermediate in the list as long as it
89 // is in the allowed list of intermediates.
90 base::StringPiece ica_public_key_der =
91 (ica_certs.size() == 0)
92 ? cast_channel::GetDefaultTrustedICAPublicKey()
93 : cast_channel::GetTrustedICAPublicKey(ica_certs[0]);
95 if (ica_public_key_der.empty()) {
96 return VerificationResult(
97 "Device certificate is not signed by a trusted CA",
98 VerificationResult::ERROR_CERT_UNTRUSTED);
100 // Initialize the ICA public key.
101 SECItem ica_public_key_der_item;
102 ica_public_key_der_item.type = SECItemType::siDERCertBuffer;
103 ica_public_key_der_item.data = const_cast<uint8_t*>(
104 reinterpret_cast<const uint8_t*>(ica_public_key_der.data()));
105 ica_public_key_der_item.len = ica_public_key_der.size();
107 crypto::ScopedSECKEYPublicKey ica_public_key_obj(
108 SECKEY_ImportDERPublicKey(&ica_public_key_der_item, CKK_RSA));
109 if (!ica_public_key_obj) {
110 return VerificationResult("Failed to import trusted public key.",
111 VerificationResult::ERROR_INTERNAL,
112 PORT_GetError());
114 SECItem device_cert_der_item;
115 device_cert_der_item.type = siDERCertBuffer;
116 // Make a copy of certificate string so it is safe to type cast.
117 device_cert_der_item.data =
118 reinterpret_cast<unsigned char*>(const_cast<char*>(device_cert.data()));
119 device_cert_der_item.len = device_cert.length();
121 // Parse into a certificate structure.
122 ScopedCERTCertificate device_cert_obj(CERT_NewTempCertificate(
123 CERT_GetDefaultCertDB(), &device_cert_der_item, NULL, PR_FALSE, PR_TRUE));
124 if (!device_cert_obj.get()) {
125 return VerificationResult("Failed to parse device certificate.",
126 VerificationResult::ERROR_CERT_INVALID,
127 PORT_GetError());
129 if (CERT_VerifySignedDataWithPublicKey(&device_cert_obj->signatureWrap,
130 ica_public_key_obj.get(),
131 NULL) != SECSuccess) {
132 return VerificationResult("Signature verification failed.",
133 VerificationResult::ERROR_SIGNATURE_INVALID,
134 PORT_GetError());
136 if (context) {
137 scoped_ptr<CertVerificationContext> tmp_context(
138 new CertVerificationContextNSS(device_cert_obj.release()));
139 tmp_context.swap(*context);
142 return VerificationResult();
145 std::string VerificationResult::GetLogString() const {
146 std::string nssError = "NSS Error Code: ";
147 nssError += base::IntToString(library_error_code);
148 return error_message.size()
149 ? std::string("Error: ") + error_message + ", " + nssError
150 : nssError;
153 } // namespace cast_crypto
154 } // namespace core_api
155 } // namespace extensions