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"
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
{
21 namespace cast_crypto
{
27 crypto::NSSDestroyer
<CERTCertificate
, CERT_DestroyCertificate
>>
28 ScopedCERTCertificate
;
30 class CertVerificationContextNSS
: public CertVerificationContext
{
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
);
47 SECItem signature_item
;
48 signature_item
.type
= siBuffer
;
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
,
61 return VerificationResult();
64 std::string
GetCommonName() const override
{
65 char* common_name
= CERT_GetCommonName(&certificate_
->subject
);
69 std::string
result(common_name
);
70 PORT_Free(common_name
);
75 ScopedCERTCertificate certificate_
;
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
,
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
,
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
,
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
153 } // namespace cast_crypto
154 } // namespace core_api
155 } // namespace extensions