Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / extensions / browser / api / cast_channel / cast_auth_util_nss.cc
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/browser/api/cast_channel/cast_auth_util.h"
6
7 #include <cert.h>
8 #include <cryptohi.h>
9 #include <pk11pub.h>
10 #include <seccomon.h>
11 #include <string>
12
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"
22
23 namespace extensions {
24 namespace core_api {
25 namespace cast_channel {
26 namespace {
27
28 typedef scoped_ptr<
29     CERTCertificate,
30     crypto::NSSDestroyer<CERTCertificate, CERT_DestroyCertificate> >
31         ScopedCERTCertificate;
32
33 }  // namespace
34
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();
43
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();
49
50   VLOG(1) << "Response has " << num_intermediates << " intermediates";
51
52   base::StringPiece ica;
53   if (num_intermediates <= 0) {
54     ica = GetDefaultTrustedICAPublicKey();
55   } else {
56     ica = GetTrustedICAPublicKey(response.intermediate_certificate(0));
57   }
58   if (ica.empty()) {
59     return AuthResult::CreateWithParseError(
60         "Disallowed intermediate cert",
61         AuthResult::ERROR_FINGERPRINT_NOT_FOUND);
62   }
63
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();
69
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();
77
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());
85   }
86
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());
97   }
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());
104   }
105
106   VLOG(1) << "Cert signed by trusted CA";
107
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());
114   }
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);
127
128   if (verified != SECSuccess) {
129     return AuthResult::CreateWithNSSError(
130         "Signed blobs did not match",
131         AuthResult::ERROR_SIGNED_BLOBS_MISMATCH,
132         PORT_GetError());
133   }
134
135   VLOG(1) << "Signature verification succeeded";
136
137   return AuthResult();
138 }
139
140 }  // namespace cast_channel
141 }  // namespace core_api
142 }  // namespace extensions