Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / browser / api / cast_channel / cast_auth_util.cc
blob759ee7d1c3325ea3d9e7a4d852845d6d67b07e02
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 <vector>
9 #include "base/logging.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "extensions/browser/api/cast_channel/cast_message_util.h"
13 #include "extensions/common/api/cast_channel/cast_channel.pb.h"
14 #include "extensions/common/cast/cast_cert_validator.h"
16 namespace extensions {
17 namespace api {
18 namespace cast_channel {
19 namespace {
21 const char* const kParseErrorPrefix = "Failed to parse auth message: ";
23 const unsigned char kAudioOnlyPolicy[] =
24 {0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0xD6, 0x79, 0x02, 0x05, 0x02};
26 namespace cast_crypto = ::extensions::api::cast_crypto;
28 // Extracts an embedded DeviceAuthMessage payload from an auth challenge reply
29 // message.
30 AuthResult ParseAuthMessage(const CastMessage& challenge_reply,
31 DeviceAuthMessage* auth_message) {
32 if (challenge_reply.payload_type() != CastMessage_PayloadType_BINARY) {
33 return AuthResult::CreateWithParseError(
34 "Wrong payload type in challenge reply",
35 AuthResult::ERROR_WRONG_PAYLOAD_TYPE);
37 if (!challenge_reply.has_payload_binary()) {
38 return AuthResult::CreateWithParseError(
39 "Payload type is binary but payload_binary field not set",
40 AuthResult::ERROR_NO_PAYLOAD);
42 if (!auth_message->ParseFromString(challenge_reply.payload_binary())) {
43 return AuthResult::CreateWithParseError(
44 "Cannot parse binary payload into DeviceAuthMessage",
45 AuthResult::ERROR_PAYLOAD_PARSING_FAILED);
48 VLOG(1) << "Auth message: " << AuthMessageToString(*auth_message);
50 if (auth_message->has_error()) {
51 return AuthResult::CreateWithParseError(
52 "Auth message error: " +
53 base::IntToString(auth_message->error().error_type()),
54 AuthResult::ERROR_MESSAGE_ERROR);
56 if (!auth_message->has_response()) {
57 return AuthResult::CreateWithParseError(
58 "Auth message has no response field", AuthResult::ERROR_NO_RESPONSE);
60 return AuthResult();
63 AuthResult TranslateVerificationResult(
64 const cast_crypto::VerificationResult& result) {
65 AuthResult translated;
66 translated.error_message = result.error_message;
67 translated.nss_error_code = result.library_error_code;
68 switch (result.error_type) {
69 case cast_crypto::VerificationResult::ERROR_NONE:
70 translated.error_type = AuthResult::ERROR_NONE;
71 break;
72 case cast_crypto::VerificationResult::ERROR_CERT_INVALID:
73 translated.error_type = AuthResult::ERROR_CERT_PARSING_FAILED;
74 break;
75 case cast_crypto::VerificationResult::ERROR_CERT_UNTRUSTED:
76 translated.error_type = AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA;
77 break;
78 case cast_crypto::VerificationResult::ERROR_SIGNATURE_INVALID:
79 translated.error_type = AuthResult::ERROR_SIGNED_BLOBS_MISMATCH;
80 break;
81 case cast_crypto::VerificationResult::ERROR_INTERNAL:
82 translated.error_type = AuthResult::ERROR_UNEXPECTED_AUTH_LIBRARY_RESULT;
83 break;
84 default:
85 translated.error_type = AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA;
87 return translated;
90 } // namespace
92 AuthResult::AuthResult()
93 : error_type(ERROR_NONE), nss_error_code(0), channel_policies(POLICY_NONE) {
96 AuthResult::~AuthResult() {
99 // static
100 AuthResult AuthResult::CreateWithParseError(const std::string& error_message,
101 ErrorType error_type) {
102 return AuthResult(kParseErrorPrefix + error_message, error_type, 0);
105 // static
106 AuthResult AuthResult::CreateWithNSSError(const std::string& error_message,
107 ErrorType error_type,
108 int nss_error_code) {
109 return AuthResult(error_message, error_type, nss_error_code);
112 AuthResult::AuthResult(const std::string& error_message,
113 ErrorType error_type,
114 int nss_error_code)
115 : error_message(error_message),
116 error_type(error_type),
117 nss_error_code(nss_error_code) {
120 AuthResult AuthenticateChallengeReply(const CastMessage& challenge_reply,
121 const std::string& peer_cert) {
122 if (peer_cert.empty()) {
123 AuthResult result = AuthResult::CreateWithParseError(
124 "Peer cert was empty.", AuthResult::ERROR_PEER_CERT_EMPTY);
125 return result;
128 DeviceAuthMessage auth_message;
129 AuthResult result = ParseAuthMessage(challenge_reply, &auth_message);
130 if (!result.success()) {
131 return result;
134 const AuthResponse& response = auth_message.response();
135 result = VerifyCredentials(response, peer_cert);
136 if (!result.success()) {
137 return result;
140 const std::string& audio_policy =
141 std::string(reinterpret_cast<const char*>(kAudioOnlyPolicy),
142 (arraysize(kAudioOnlyPolicy) / sizeof(unsigned char)));
143 if (response.client_auth_certificate().find(audio_policy) !=
144 std::string::npos) {
145 result.channel_policies |= AuthResult::POLICY_AUDIO_ONLY;
148 return result;
151 // This function does the following
152 // * Verifies that the trusted CA |response.intermediate_certificate| is
153 // whitelisted for use.
154 // * Verifies that |response.client_auth_certificate| is signed
155 // by the trusted CA certificate.
156 // * Verifies that |response.signature| matches the signature
157 // of |peer_cert| by |response.client_auth_certificate|'s public
158 // key.
159 AuthResult VerifyCredentials(const AuthResponse& response,
160 const std::string& peer_cert) {
161 // Verify the certificate
162 scoped_ptr<cast_crypto::CertVerificationContext> verification_context;
163 cast_crypto::VerificationResult ret = cast_crypto::VerifyDeviceCert(
164 response.client_auth_certificate(),
165 std::vector<std::string>(response.intermediate_certificate().begin(),
166 response.intermediate_certificate().end()),
167 &verification_context);
169 if (ret.Success())
170 ret = verification_context->VerifySignatureOverData(response.signature(),
171 peer_cert);
173 return TranslateVerificationResult(ret);
176 } // namespace cast_channel
177 } // namespace api
178 } // namespace extensions