-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathStatelessReset.cpp
More file actions
118 lines (99 loc) · 3.2 KB
/
StatelessReset.cpp
File metadata and controls
118 lines (99 loc) · 3.2 KB
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
110
111
112
113
114
115
116
117
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Logging.h"
#include "MozQuic.h"
#include "MozQuicInternal.h"
#include "Sender.h"
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <sechash.h>
namespace mozquic {
uint32_t
MozQuic::StatelessResetEnsureKey()
{
// make a reset token if this was not provided as config
unsigned char empty[128];
memset(empty, 0, 128);
assert(sizeof(empty) == sizeof(mStatelessResetKey));
if (!memcmp(empty, mStatelessResetKey, 128)) {
assert((sizeof(mStatelessResetKey) % sizeof(uint16_t)) == 0);
for (unsigned int i=0; i < (sizeof(mStatelessResetKey) / sizeof (uint16_t)); i++) {
((uint16_t *)mStatelessResetKey)[i] = random() & 0xffff;
}
}
return MOZQUIC_OK;
}
uint32_t
MozQuic::StatelessResetSend(CID &connID, const struct sockaddr *peer)
{
if (mIsClient) {
return MOZQUIC_ERR_GENERAL;
}
assert(!mIsChild);
assert(!mParent);
ConnectionLog1("Generate Stateless Reset of connection %lx\n", connID);
unsigned char out[kMaxMTU];
out[0] = 0x30;
// dcid
for (unsigned int i = 0; i < mPeerCID.Len(); i++) {
out[1 + i] = random() & 0xff;
}
// 1 byte packet number
out[1 + mPeerCID.Len()] = random() & 0x7f;
// pad
uint32_t pad = mMTU - 16 - mPeerCID.Len() - 2;
pad = (random() % pad) & ~0x1; // force even
pad = (pad > 0) ? pad : 1;
assert((pad + 16 + 2 + mPeerCID.Len()) <= kMaxMTU);
assert((pad + 16 + 2 + mPeerCID.Len()) <= mMTU);
for (unsigned int i = 0; i < pad; i++) {
out[2 + mPeerCID.Len() + i] = random() & 0xff;
}
// 16 bytes of reset
StatelessResetCalculateToken(mStatelessResetKey, connID, out + 2 + mPeerCID.Len() + pad); // from key and CID
return mSendState->Transmit(0, true, false, false, out, 2 + 16 + mPeerCID.Len() + pad, peer);
}
uint32_t
MozQuic::StatelessResetCalculateToken(const unsigned char *key128,
CID &connID, unsigned char *out)
{
// out needs to be at least 16
// derive the public resetToken from the resetKey and connectionID
unsigned char digest[SHA256_LENGTH];
unsigned int digestLen;
assert(SHA256_LENGTH >= 16);
HASHContext *hcontext = HASH_Create(HASH_AlgSHA256);
HASH_Begin(hcontext);
HASH_Update(hcontext, key128, 128);
HASH_Update(hcontext, connID.Data(), connID.Len());
HASH_End(hcontext, digest, &digestLen, sizeof(digest));
assert(digestLen == sizeof(digest));
memcpy(out, digest, 16);
return MOZQUIC_OK;
}
bool
MozQuic::StatelessResetCheckForReceipt(const unsigned char *pkt, uint32_t pktSize)
{
if (pktSize < 36) {
return false;
}
if (mConnectionState != CLIENT_STATE_CONNECTED) {
return false;
}
if ((pkt[0] & 0x80) != 0x00) { // only short form packets
return false;
}
if (mValidStatelessResetToken &&
memcmp(mStatelessResetToken, pkt + pktSize - 16, 16)) {
return false;
}
ConnectionLog1("client recvd verified public reset\n");
if (mConnEventCB) {
mConnEventCB(mClosure, MOZQUIC_EVENT_ERROR, this);
}
return true;
}
}