1// Copyright (c) 2012 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 "net/quic/quic_crypto_server_stream.h"
6
7#include "base/base64.h"
8#include "crypto/secure_hash.h"
9#include "net/quic/crypto/crypto_protocol.h"
10#include "net/quic/crypto/crypto_server_config.h"
11#include "net/quic/crypto/crypto_utils.h"
12#include "net/quic/quic_config.h"
13#include "net/quic/quic_protocol.h"
14#include "net/quic/quic_session.h"
15
16namespace net {
17
18QuicCryptoServerStream::QuicCryptoServerStream(
19    const QuicCryptoServerConfig& crypto_config,
20    QuicSession* session)
21    : QuicCryptoStream(session),
22      crypto_config_(crypto_config) {
23}
24
25QuicCryptoServerStream::~QuicCryptoServerStream() {
26}
27
28void QuicCryptoServerStream::OnHandshakeMessage(
29    const CryptoHandshakeMessage& message) {
30  // Do not process handshake messages after the handshake is confirmed.
31  if (handshake_confirmed_) {
32    CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
33    return;
34  }
35
36  if (message.tag() != kCHLO) {
37    CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
38    return;
39  }
40
41  string error_details;
42  CryptoHandshakeMessage reply;
43
44  QuicErrorCode error = ProcessClientHello(message, &reply, &error_details);
45
46  if (error != QUIC_NO_ERROR) {
47    CloseConnectionWithDetails(error, error_details);
48    return;
49  }
50
51  if (reply.tag() != kSHLO) {
52    SendHandshakeMessage(reply);
53    return;
54  }
55
56  // If we are returning a SHLO then we accepted the handshake.
57  QuicConfig* config = session()->config();
58  error = config->ProcessClientHello(message, &error_details);
59  if (error != QUIC_NO_ERROR) {
60    CloseConnectionWithDetails(error, error_details);
61    return;
62  }
63
64  config->ToHandshakeMessage(&reply);
65
66  // Receiving a full CHLO implies the client is prepared to decrypt with
67  // the new server write key.  We can start to encrypt with the new server
68  // write key.
69  //
70  // NOTE: the SHLO will be encrypted with the new server write key.
71  session()->connection()->SetEncrypter(
72      ENCRYPTION_INITIAL,
73      crypto_negotiated_params_.initial_crypters.encrypter.release());
74  session()->connection()->SetDefaultEncryptionLevel(
75      ENCRYPTION_INITIAL);
76  // Set the decrypter immediately so that we no longer accept unencrypted
77  // packets.
78  session()->connection()->SetDecrypter(
79      crypto_negotiated_params_.initial_crypters.decrypter.release());
80  SendHandshakeMessage(reply);
81
82  session()->connection()->SetEncrypter(
83      ENCRYPTION_FORWARD_SECURE,
84      crypto_negotiated_params_.forward_secure_crypters.encrypter.release());
85  session()->connection()->SetDefaultEncryptionLevel(
86      ENCRYPTION_FORWARD_SECURE);
87  session()->connection()->SetAlternativeDecrypter(
88      crypto_negotiated_params_.forward_secure_crypters.decrypter.release(),
89      false /* don't latch */);
90
91  encryption_established_ = true;
92  handshake_confirmed_ = true;
93  session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
94}
95
96bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID(
97    string* output) const {
98  if (!encryption_established_ ||
99      crypto_negotiated_params_.channel_id.empty()) {
100    return false;
101  }
102
103  const string& channel_id(crypto_negotiated_params_.channel_id);
104  scoped_ptr<crypto::SecureHash> hash(
105      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
106  hash->Update(channel_id.data(), channel_id.size());
107  uint8 digest[32];
108  hash->Finish(digest, sizeof(digest));
109
110  base::Base64Encode(string(
111      reinterpret_cast<const char*>(digest), sizeof(digest)), output);
112  // Remove padding.
113  size_t len = output->size();
114  if (len >= 2) {
115    if ((*output)[len - 1] == '=') {
116      len--;
117      if ((*output)[len - 1] == '=') {
118        len--;
119      }
120      output->resize(len);
121    }
122  }
123  return true;
124}
125
126QuicErrorCode QuicCryptoServerStream::ProcessClientHello(
127    const CryptoHandshakeMessage& message,
128    CryptoHandshakeMessage* reply,
129    string* error_details) {
130  return crypto_config_.ProcessClientHello(
131      message,
132      session()->connection()->version(),
133      session()->connection()->guid(),
134      session()->connection()->peer_address(),
135      session()->connection()->clock(),
136      session()->connection()->random_generator(),
137      &crypto_negotiated_params_, reply, error_details);
138}
139
140}  // namespace net
141