summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quic/tools/simple_ticket_crypter.cc
blob: 3da114e55269fc3995489f934ae47b5cd04b94b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/third_party/quiche/src/quic/tools/simple_ticket_crypter.h"

#include "third_party/boringssl/src/include/openssl/aead.h"
#include "third_party/boringssl/src/include/openssl/rand.h"

namespace quic {

namespace {

constexpr QuicTime::Delta kTicketKeyLifetime =
    QuicTime::Delta::FromSeconds(60 * 60 * 24 * 7);

// The format of an encrypted ticket is 1 byte for the key epoch, followed by
// 16 bytes of IV, followed by the output from the AES-GCM Seal operation. The
// seal operation has an overhead of 16 bytes for its auth tag.
constexpr size_t kEpochSize = 1;
constexpr size_t kIVSize = 16;
constexpr size_t kAuthTagSize = 16;

// Offsets into the ciphertext to make message parsing easier.
constexpr size_t kIVOffset = kEpochSize;
constexpr size_t kMessageOffset = kIVOffset + kIVSize;

}  // namespace

SimpleTicketCrypter::SimpleTicketCrypter(QuicClock* clock) : clock_(clock) {
  RAND_bytes(&key_epoch_, 1);
  current_key_ = NewKey();
}

SimpleTicketCrypter::~SimpleTicketCrypter() = default;

size_t SimpleTicketCrypter::MaxOverhead() {
  return kEpochSize + kIVSize + kAuthTagSize;
}

std::vector<uint8_t> SimpleTicketCrypter::Encrypt(
    quiche::QuicheStringPiece in) {
  MaybeRotateKeys();
  std::vector<uint8_t> out(in.size() + MaxOverhead());
  out[0] = key_epoch_;
  RAND_bytes(out.data() + kIVOffset, kIVSize);
  size_t out_len;
  const EVP_AEAD_CTX* ctx = current_key_->aead_ctx.get();
  if (!EVP_AEAD_CTX_seal(ctx, out.data() + kMessageOffset, &out_len,
                         out.size() - kMessageOffset, out.data() + kIVOffset,
                         kIVSize, reinterpret_cast<const uint8_t*>(in.data()),
                         in.size(), nullptr, 0)) {
    return std::vector<uint8_t>();
  }
  out.resize(out_len + kMessageOffset);
  return out;
}

std::vector<uint8_t> SimpleTicketCrypter::Decrypt(
    quiche::QuicheStringPiece in) {
  MaybeRotateKeys();
  if (in.size() < kMessageOffset) {
    return std::vector<uint8_t>();
  }
  const uint8_t* input = reinterpret_cast<const uint8_t*>(in.data());
  std::vector<uint8_t> out(in.size() - kMessageOffset);
  size_t out_len;
  const EVP_AEAD_CTX* ctx = current_key_->aead_ctx.get();
  if (input[0] != key_epoch_) {
    if (input[0] == static_cast<uint8_t>(key_epoch_ - 1) && previous_key_) {
      ctx = previous_key_->aead_ctx.get();
    } else {
      return std::vector<uint8_t>();
    }
  }
  if (!EVP_AEAD_CTX_open(ctx, out.data(), &out_len, out.size(),
                         input + kIVOffset, kIVSize, input + kMessageOffset,
                         in.size() - kMessageOffset, nullptr, 0)) {
    return std::vector<uint8_t>();
  }
  out.resize(out_len);
  return out;
}

void SimpleTicketCrypter::Decrypt(
    quiche::QuicheStringPiece in,
    std::unique_ptr<quic::ProofSource::DecryptCallback> callback) {
  callback->Run(Decrypt(in));
}

void SimpleTicketCrypter::MaybeRotateKeys() {
  QuicTime now = clock_->ApproximateNow();
  if (current_key_->expiration < now) {
    previous_key_ = std::move(current_key_);
    current_key_ = NewKey();
    key_epoch_++;
  }
}

std::unique_ptr<SimpleTicketCrypter::Key> SimpleTicketCrypter::NewKey() {
  auto key = std::make_unique<SimpleTicketCrypter::Key>();
  RAND_bytes(key->key, kKeySize);
  EVP_AEAD_CTX_init(key->aead_ctx.get(), EVP_aead_aes_128_gcm(), key->key,
                    kKeySize, EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr);
  key->expiration = clock_->ApproximateNow() + kTicketKeyLifetime;
  return key;
}

}  // namespace quic