Revert of Refactoring of Cast-related crypto code (patchset #19 id:350001 of https...
[chromium-blink-merge.git] / extensions / browser / api / cast_channel / cast_auth_util_nss.cc
blob97f16d7c8e04fb3f20568d0ec81748b80cd7609c
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/browser/api/cast_channel/cast_auth_util.h"
7 #include <cert.h>
8 #include <cryptohi.h>
9 #include <pk11pub.h>
10 #include <seccomon.h>
11 #include <string>
13 #include "base/logging.h"
14 #include "base/strings/string_piece.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 #include "extensions/browser/api/cast_channel/cast_message_util.h"
19 #include "extensions/common/api/cast_channel/cast_channel.pb.h"
20 #include "net/base/hash_value.h"
21 #include "net/cert/x509_certificate.h"
23 namespace extensions {
24 namespace core_api {
25 namespace cast_channel {
26 namespace {
28 typedef scoped_ptr<
29 CERTCertificate,
30 crypto::NSSDestroyer<CERTCertificate, CERT_DestroyCertificate> >
31 ScopedCERTCertificate;
33 } // namespace
35 // Authenticates the given credentials:
36 // 1. |signature| verification of |peer_cert| using |certificate|.
37 // 2. |certificate| is signed by a trusted CA.
38 AuthResult VerifyCredentials(const AuthResponse& response,
39 const std::string& peer_cert) {
40 const std::string kErrorPrefix("Failed to verify credentials: ");
41 const std::string& certificate = response.client_auth_certificate();
42 const std::string& signature = response.signature();
44 // If the list of intermediates is empty then use kPublicKeyICA1 as
45 // the trusted CA (legacy case).
46 // Otherwise, use the first intermediate in the list as long as it
47 // is in the allowed list of intermediates.
48 int num_intermediates = response.intermediate_certificate_size();
50 VLOG(1) << "Response has " << num_intermediates << " intermediates";
52 base::StringPiece ica;
53 if (num_intermediates <= 0) {
54 ica = GetDefaultTrustedICAPublicKey();
55 } else {
56 ica = GetTrustedICAPublicKey(response.intermediate_certificate(0));
58 if (ica.empty()) {
59 return AuthResult::CreateWithParseError(
60 "Disallowed intermediate cert",
61 AuthResult::ERROR_FINGERPRINT_NOT_FOUND);
64 SECItem trusted_ca_key_der;
65 trusted_ca_key_der.type = SECItemType::siDERCertBuffer;
66 trusted_ca_key_der.data =
67 const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(ica.data()));
68 trusted_ca_key_der.len = ica.size();
70 crypto::EnsureNSSInit();
71 SECItem der_cert;
72 der_cert.type = siDERCertBuffer;
73 // Make a copy of certificate string so it is safe to type cast.
74 der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(
75 certificate.data()));
76 der_cert.len = certificate.length();
78 // Parse into a certificate structure.
79 ScopedCERTCertificate cert(CERT_NewTempCertificate(
80 CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE));
81 if (!cert.get()) {
82 return AuthResult::CreateWithNSSError(
83 "Failed to parse certificate.",
84 AuthResult::ERROR_CERT_PARSING_FAILED, PORT_GetError());
87 // Check that the certificate is signed by trusted CA.
88 // NOTE: We const_cast trusted_ca_key_der since on some platforms
89 // SECKEY_ImportDERPublicKey API takes in SECItem* and not const
90 // SECItem*.
91 crypto::ScopedSECKEYPublicKey ca_public_key(
92 SECKEY_ImportDERPublicKey(&trusted_ca_key_der, CKK_RSA));
93 if (!ca_public_key) {
94 return AuthResult::CreateWithNSSError(
95 "Failed to import public key from CA certificate.",
96 AuthResult::ERROR_CERT_PARSING_FAILED, PORT_GetError());
98 SECStatus verified = CERT_VerifySignedDataWithPublicKey(
99 &cert->signatureWrap, ca_public_key.get(), NULL);
100 if (verified != SECSuccess) {
101 return AuthResult::CreateWithNSSError(
102 "Cert not signed by trusted CA",
103 AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA, PORT_GetError());
106 VLOG(1) << "Cert signed by trusted CA";
108 // Verify that the |signature| matches |peer_cert|.
109 crypto::ScopedSECKEYPublicKey public_key(CERT_ExtractPublicKey(cert.get()));
110 if (!public_key.get()) {
111 return AuthResult::CreateWithNSSError(
112 "Unable to extract public key from certificate",
113 AuthResult::ERROR_CANNOT_EXTRACT_PUBLIC_KEY, PORT_GetError());
115 SECItem signature_item;
116 signature_item.type = siBuffer;
117 signature_item.data = reinterpret_cast<unsigned char*>(
118 const_cast<char*>(signature.data()));
119 signature_item.len = signature.length();
120 verified = VFY_VerifyDataDirect(
121 reinterpret_cast<unsigned char*>(const_cast<char*>(peer_cert.data())),
122 peer_cert.size(),
123 public_key.get(),
124 &signature_item,
125 SEC_OID_PKCS1_RSA_ENCRYPTION,
126 SEC_OID_SHA1, NULL, NULL);
128 if (verified != SECSuccess) {
129 return AuthResult::CreateWithNSSError(
130 "Signed blobs did not match",
131 AuthResult::ERROR_SIGNED_BLOBS_MISMATCH,
132 PORT_GetError());
135 VLOG(1) << "Signature verification succeeded";
137 return AuthResult();
140 } // namespace cast_channel
141 } // namespace core_api
142 } // namespace extensions