Chromium Code Reviews| Index: extensions/browser/api/cast_channel/cast_auth_util.cc |
| diff --git a/extensions/browser/api/cast_channel/cast_auth_util.cc b/extensions/browser/api/cast_channel/cast_auth_util.cc |
| index 6ed1cdc78fdab1e546371d2d6bc1d19724588caa..a6573443706882e8d91a496df9603fcaa6afb446 100644 |
| --- a/extensions/browser/api/cast_channel/cast_auth_util.cc |
| +++ b/extensions/browser/api/cast_channel/cast_auth_util.cc |
| @@ -38,6 +38,15 @@ const int kMaxSelfSignedCertLifetimeInDays = 4; |
| const base::Feature kEnforceRevocationChecking{ |
| "CastCertificateRevocation", base::FEATURE_DISABLED_BY_DEFAULT}; |
| +// Enforce nonce checking when enabled. |
| +// If disabled, the nonce value returned from the device is not checked against |
| +// the one sent to the device. As a result, the nonce can be empty and omitted |
| +// from the signature. This allows backwards compatibility with legacy Cast |
| +// receivers. |
| + |
| +const base::Feature kEnforceNonceChecking{"CastNonceEnforced", |
| + base::FEATURE_DISABLED_BY_DEFAULT}; |
| + |
| namespace cast_crypto = ::cast_certificate; |
| // Extracts an embedded DeviceAuthMessage payload from an auth challenge reply |
| @@ -85,6 +94,13 @@ enum CertVerificationStatus { |
| CERT_STATUS_COUNT, |
| }; |
| +enum NonceVerificationStatus { |
| + NONCE_MATCH, |
| + NONCE_MISMATCH, |
| + NONCE_MISSING, |
| + NONCE_COUNT, |
| +}; |
| + |
| } // namespace |
| AuthResult::AuthResult() |
| @@ -103,7 +119,8 @@ AuthResult AuthResult::CreateWithParseError(const std::string& error_message, |
| } |
| AuthResult AuthenticateChallengeReply(const CastMessage& challenge_reply, |
| - const net::X509Certificate& peer_cert) { |
| + const net::X509Certificate& peer_cert, |
| + const std::string& nonce) { |
| DeviceAuthMessage auth_message; |
| AuthResult result = ParseAuthMessage(challenge_reply, &auth_message); |
| if (!result.success()) { |
| @@ -145,7 +162,24 @@ AuthResult AuthenticateChallengeReply(const CastMessage& challenge_reply, |
| } |
| const AuthResponse& response = auth_message.response(); |
| - return VerifyCredentials(response, peer_cert_der); |
| + |
| + if (nonce != response.sender_nonce()) { |
| + if (response.sender_nonce().empty()) { |
|
mark a. foltz
2017/02/27 23:04:31
It seems like you should only be collecting metric
ryanchung
2017/03/01 20:09:47
We want to be able to see the impact on the user e
|
| + UMA_HISTOGRAM_ENUMERATION("Cast.Channel.Nonce", NONCE_MISSING, |
| + NONCE_COUNT); |
| + } else { |
| + UMA_HISTOGRAM_ENUMERATION("Cast.Channel.Nonce", NONCE_MISMATCH, |
| + NONCE_COUNT); |
| + } |
| + if (base::FeatureList::IsEnabled(kEnforceNonceChecking)) { |
| + return AuthResult("Sender nonce mismatched.", |
| + AuthResult::ERROR_SENDER_NONCE_MISMATCH); |
| + } |
| + } else { |
| + UMA_HISTOGRAM_ENUMERATION("Cast.Channel.Nonce", NONCE_MATCH, NONCE_COUNT); |
| + } |
| + |
| + return VerifyCredentials(response, nonce + peer_cert_der); |
|
mark a. foltz
2017/02/27 23:04:31
Don't you want to conditionally include |nonce| in
ryanchung
2017/03/01 20:09:47
I should be using response.sender_nonce() here ins
|
| } |
| // This function does the following |