OLD | NEW |
| (Empty) |
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 "extensions/common/cast/cast_cert_validator.h" | |
6 | |
7 #include <cert.h> | |
8 #include <cryptohi.h> | |
9 #include <pk11pub.h> | |
10 #include <seccomon.h> | |
11 | |
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" | |
18 | |
19 namespace extensions { | |
20 namespace core_api { | |
21 namespace cast_crypto { | |
22 | |
23 namespace { | |
24 | |
25 typedef scoped_ptr< | |
26 CERTCertificate, | |
27 crypto::NSSDestroyer<CERTCertificate, CERT_DestroyCertificate>> | |
28 ScopedCERTCertificate; | |
29 | |
30 class CertVerificationContextNSS : public CertVerificationContext { | |
31 public: | |
32 explicit CertVerificationContextNSS(CERTCertificate* certificate) | |
33 : certificate_(certificate) {} | |
34 | |
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); | |
45 } | |
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()); | |
60 } | |
61 return VerificationResult(); | |
62 } | |
63 | |
64 std::string GetCommonName() const override { | |
65 char* common_name = CERT_GetCommonName(&certificate_->subject); | |
66 if (!common_name) | |
67 return std::string(); | |
68 | |
69 std::string result(common_name); | |
70 PORT_Free(common_name); | |
71 return result; | |
72 } | |
73 | |
74 private: | |
75 ScopedCERTCertificate certificate_; | |
76 }; | |
77 | |
78 } // namespace | |
79 | |
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(); | |
85 | |
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]); | |
94 | |
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); | |
99 } | |
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(); | |
106 | |
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()); | |
113 } | |
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(); | |
120 | |
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()); | |
128 } | |
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()); | |
135 } | |
136 if (context) { | |
137 scoped_ptr<CertVerificationContext> tmp_context( | |
138 new CertVerificationContextNSS(device_cert_obj.release())); | |
139 tmp_context.swap(*context); | |
140 } | |
141 | |
142 return VerificationResult(); | |
143 } | |
144 | |
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; | |
151 } | |
152 | |
153 } // namespace cast_crypto | |
154 } // namespace core_api | |
155 } // namespace extensions | |
OLD | NEW |