RealityServer
RealityServer tunnel سمت server برای Reality v2 است. هر line ابتدا visitor محسوب و به شاخه destination فرستاده میشود و binding واقعی TLS بهصورت passive استخراج میگردد. TLS 1.3 فقط پس از handoff احرازشده request/ack/confirm شاخه visitor را میبندد و همان line را به next محافظتشده میبرد؛ TLS 1.2 authorization فوری و profile-aware فعلی را حفظ میکند.
سرور TLS مربوط به visitorها را خاتمه نمیدهد؛ فقط به اندازهای recordهای شبیه TLS را بررسی میکند که تشخیص دهد peer یک Reality client معتبر است یا ترافیک عادی visitor.
جایگاه رایج
TcpListener -> RealityServer -> protected-chain
|
+-> destination visitor branch
نود next ترافیک مجاز Reality را دریافت میکند. گزینه destination نام شاخه معمول visitor است که اغلب یک TcpConnector برای سایت واقعی visitor خواهد بود.
نمونه تنظیمات
{
"name": "reality-server",
"type": "RealityServer",
"settings": {
"destination": "visitor-site",
"password": "replace-with-a-strong-secret",
"algorithm": "chacha20-poly1305",
"sniffing-attempts": 8
},
"next": "protected-chain"
}
مقصد visitor:
{
"name": "visitor-site",
"type": "TcpConnector",
"settings": {
"address": "www.example.com",
"port": 443
}
}
فیلدهای اجباری
| فیلد | نوع | توضیح |
|---|---|---|
type | string | باید RealityServer باشد. |
next | string | نودی که payload decrypt شده و تاییدشده Reality را میگیرد. |
settings | object | باید object غیرخالی باشد. |
settings.destination | string | نام نود مربوط به ترافیک visitor. نود باید وجود داشته باشد و نمیتواند خود RealityServer یا نود مجاز next باشد. |
settings.password | string | secret مشترک Reality شامل ۱ تا ۳۲ بایت UTF-8؛ باید با client یکسان باشد. |
تنظیمات
| گزینه | پیشفرض | توضیح |
|---|---|---|
destination | اجباری | شاخه visitor. تا پیش از authorization، handshake، TLS معمول visitor، probeهای نامعتبر و candidateهای ناموفق Reality به این شاخه فرستاده میشوند. |
password | اجباری | secret مشترک شامل ۱ تا ۳۲ بایت UTF-8 برای key derivation. |
algorithm | chacha20-poly1305 | یکی از chacha20-poly1305، chacha20poly1305، aes-gcm، aes-256-gcm یا aes256gcm. |
method | مثل algorithm | alias برای algorithm، وقتی algorithm وجود نداشته باشد. |
salt | waterwall-reality | salt برای key derivation. مقدار صریح باید شامل ۱ تا ۳۲ بایت UTF-8 باشد و با client یکی باشد. |
kdf-iterations | 12000 | تعداد integer roundهای key derivation در بازه 1 تا 1000000؛ عدد اعشاری رد میشود. |
sniffing-attempts | 8 | تعداد integer candidateهای Reality ناموفق پس از allowance یک-recordی پیش از REQUEST در TLS 1.3، قبل از اینکه line بهصورت دائم visitor فرض شود. بازه معتبر 1 تا 1024 است؛ TLS 1.2 این allowance را ندارد. |
sniffing-counter | مثل sniffing-attempts | alias integer قدیمی با همان بازه، فقط وقتی sniffing-attempts وجود نداشته باشد. |
tls12-gcm-server-nonce-policy | auto | policy مربوط به explicit nonce جهت downstream در TLS 1.2 GCM: یکی از auto، sequence، counter یا random. |
اگر aes-gcm انتخاب شود اما crypto backend فعال از AES-GCM پشتیبانی نکند، ساخت tunnel شکست میخورد.
محدودیت credential برحسب بایت UTF-8 سنجیده میشود، نه تعداد character، و همان طولی است که به BLAKE2s داده میشود. مقدار پیشفرض فقط وقتی اعمال میشود که key اختیاری وجود نداشته باشد؛ key موجود با نوع JSON اشتباه خطای startup است. فیلد primary حتی وقتی نامعتبر باشد بر alias اولویت دارد: method نمیتواند algorithm نامعتبر را نجات دهد و sniffing-counter نیز نمیتواند sniffing-attempts نامعتبر را نجات دهد.
شاخه Visitor و Protected
در upstream Init، RealityServer state مربوط به line را مقداردهی اولیه میکند و بیدرنگ شاخه destination را آماده میسازد. chain محافظتشده next در این مرحله هنوز initialize نشده است.
تا قبل از authorization:
- یک streaming parser محدود، پیامهای ClientHello و ServerHello تکهتکهشده و در TLS 1.2، epoch مربوط به protected record در هر جهت را در حالی مشاهده میکند که بایتها همچنان به شاخه visitor فرستاده میشوند
- extension مربوط به TLS 1.3
supported_versionsرعایت میشود و HelloRetryRequest تا رسیدن ServerHello نهایی نادیده گرفته میشود - handshake نامعتبر یا پشتیبانینشده، line را به رفتار عادی visitor منتقل میکند
- پیش از آماده شدن هر دو hello، recordهایی که شبیه application-data هستند همچنان ترافیک visitor محسوب میشوند و هرگز با root key آزمایش نمیشوند
- پس از مشتقکردن keyهای هر جهت در v2، از candidate recordها کپی گرفته میشود و احراز اصالت با sequence دقیق بعدی client-to-server انجام میگیرد
- اگر احراز اصالت در حالت pending شکست بخورد، record اصلی به
destinationفرستاده میشود و هیچ trial decrypt مربوط به v1 انجام نمیشود - در TLS 1.2 authorization فوری حفظ میشود؛ در TLS 1.3 فقط
HANDOFF_REQUESTبا sequence صفر میتواند handoff را آغاز کند
پس از مشتقشدن session keyهای TLS 1.3، server یک allowance داخلی، غیرقابل reset و یک-recordی پیش از REQUEST برای Finished رمزشده واقعی client در نظر میگیرد. candidate ناموفقی که این allowance را مصرف میکند بدون تغییر و byte-for-byte به destination فرستاده میشود، بدون اینکه sniffing-attempts افزایش یابد یا Reality sequence جلو برود. این allowance نمیتواند client را authorize کند، پس از احراز HANDOFF_REQUEST کنار گذاشته میشود و در TLS 1.2 کاربرد ندارد. candidateهای ناموفق بعدی budget تنظیمشده را به شکل عادی مصرف میکنند.
پس از احراز REQUEST در TLS 1.3، server فقط record TLS مقصدی را که قبلاً شروع شده تا boundary کامل ادامه میدهد. tracker streaming در اولین boundary امن split میکند، همه bytes بعدی downstream مقصد را سرکوب میکند و HANDOFF_ACK را با sequence صفر server-to-client میفرستد. protocol output واقعی TLS که client پیش از پردازش ACK ساخته هنوز میتواند upstream به مقصد برسد. trial ناموفق HANDOFF_CONFIRM record و sequence را حفظ میکند ولی از نظر تعداد record و bytes محدود است. CONFIRM با sequence یک client-to-server، جهت باقیمانده مقصد را یکبار میبندد، next محافظتشده را یکبار init میکند و رفتار سختگیرانه Authorized را فعال میسازد. application record در TLS 1.3 بهتنهایی authorize نمیکند.
بعد از authorization:
| جهت | رفتار |
|---|---|
| Upstream payload | باید Reality record معتبر باشد؛ پس از احراز اصالت و رمزگشایی، cleartext به next میرود. |
| Downstream payload | cleartext مربوط به next رمزنگاری میشود و در قالب TLS-like application-data record به نود قبلی برمیگردد. |
اگر بعد از authorization upstream نامعتبر باشد، TLS record غیر Reality برسد، یا authentication شکست بخورد، server در صورت writable بودن wire حداکثر یک fatal bad_record_mac احرازشده میفرستد و سپس هر دو جهت را میبندد.
server پس از authorization مالک shutdown عادی Reality است. Finish سمت protected دقیقاً یک close_notify میفرستد و سپس بدون انتظار سمت wire را میبندد. RealityClient آن را بدون پاسخ مصرف میکند. fatal alert دریافتی پاسخ ندارد و raw wire Finish قابل پاسخ نیست. حالت Pending، Visitor و هر دو مرحله handoff در TLS 1.3 بدون alert مصنوعی Reality بسته میشوند، چون client ممکن است هنوز downstream را cover TLS بداند.
قوانین Visitor Fallback
line در یکی از این حالتها به ترافیک visitor تبدیل میشود:
- bytes pending یک TLS record محتمل نباشند
- پس از allowance محدود پیش از REQUEST در TLS 1.3 (در صورت کاربرد)، تعداد Reality candidateهای ناموفق به
sniffing-attemptsبرسد
prefix عمومی TLS record بدون مصرفشدن بهصورت تدریجی طبقهبندی میشود: content type پشتیبانینشده پس از byte اول، major نامعتبر legacy version پس از byte دوم و minor بزرگتر از 0x04 پس از byte سوم نتیجه را قطعی میکنند. prefix محتمل یک تا چهار byte تا وقتی connection باز است در حالت Pending میماند. اگر در حالت Pending از upstream یک Finish برسد، همان byteهای bufferشده بدون تغییر و پیش از Finish مقصد به destination منتقل میشوند.
بعد از visitor شدن، upstream به destination میرود و downstream همان شاخه به نود قبلی برمیگردد. chain محافظتشده next برای آن line init نمیشود.
شکست در حالت Pending یا Visitor هرگز alert مخصوص Reality تولید نمیکند. candidate ناموفق Pending بهصورت byte-for-byte در مالکیت destination باقی میماند؛ بنابراین هر پاسخ احتمالی متعلق به cover endpoint واقعی است و oracle مخصوص Reality ایجاد نمیشود.
قالب Record
| cover مذاکرهشده | body قابلمشاهده Reality |
|---|---|
| TLS 1.3 | Reality-AEAD(payload + encrypted inner type 0x17) + 16-byte tag؛ بدون nonce/prefix قابلمشاهده، با طول body برابر P + 17 و حداکثر 16401. |
| TLS 1.2 ChaCha20-Poly1305 | Reality-AEAD(payload) + 16-byte tag؛ بدون nonce/prefix قابلمشاهده، با طول body برابر P + 16 و حداکثر 16400. |
| TLS 1.2 AES-GCM | 8-byte explicit nonce + Reality ciphertext + 16-byte tag؛ حداکثر body برابر 16408. |
| TLS 1.2 AES-CBC/SHA-1 | 16-byte random explicit IV + block-aligned opaque body؛ حداکثر body برابر 16432. |
طول public در CBC با فرمول TLS MAC و minimum padding هماهنگ است، ولی Reality عملیات CBC encryption انجام نمیدهد.
header شبیه TLS از این مقادیر استفاده میکند:
| فیلد | مقدار |
|---|---|
| Content type | 0x17 application data |
| Version | 0x0303 |
| Length | visible prefix پروفایل انتخابشده بهعلاوه opaque body احرازشده |
visible prefix احرازشده است اما Reality AEAD nonce نیست. Reality replay sequence و TLS facade sequence مستقل هستند و profile ID و طول prefix نیز در associated data قرار میگیرند.
alertهای احرازشده شکل public سازگار با BoringSSL دارند:
| cover مذاکرهشده | header و body مربوط به alert |
|---|---|
| TLS 1.3 | outer type برابر 0x17 و body برابر 19 بایت با inner alert type رمزشده 0x15. |
| TLS 1.2 AES-GCM | outer type برابر 0x15 و body برابر 26 بایت با ادامه policy مربوط به explicit nonce. |
| TLS 1.2 AES-CBC/SHA-1 | outer type برابر 0x15 و body برابر 48 بایت با IV تازه 16 بایتی. |
| TLS 1.2 ChaCha20-Poly1305 | outer type برابر 0x15 و body برابر 18 بایت. |
semantic رمزشده 01 00 برای close_notify و 02 14 برای fatal bad_record_mac است. alert و data در هر جهت sequence مشترک دارند و record kind و نسخه TLS نیز در associated data قرار میگیرند. اینها recordهای camouflage محافظتشده با Reality AEAD هستند، نه TLS closure واقعی یا alert رمزشده با keyهای TLS.
HANDOFF_REQUEST، HANDOFF_ACK و HANDOFF_CONFIRM در TLS 1.3 outer/inner type مربوط به application-data دارند. plaintext نسخهدار آنها control code مورد انتظار و padding احرازشده CSPRNG بر اساس policy مشترک طول عمومی را حمل میکند. طول body در TLS بهطور یکنواخت از بازه 22..1172 byte نمونهبرداری میشود (3..1153 byte padding)؛ این بازه در مسیرهای post-handshake تحت پوشش BoringSSL مشاهده شده است. controlها داخل tunnel مصرف میشوند، sequence عادی Reality را مصرف میکنند و طول قابل تنظیم JSON ندارند. الگوی timing و توزیع طول آنها همچنان بخشی از بازبینی camouflage روی wire است.
برای TLS 1.2 GCM، حالت auto در صورت مطابقت sampleهای cover با TLS sequence، حالت sequence را انتخاب میکند؛ اگر حداقل دو sample افزایشی باشند counter و در غیر این صورت random انتخاب میشود. حالت دستی counter به یک nonce مشاهدهشده نیاز دارد. یک sample غیر-sequence برای تشخیص قطعی counter از random کافی نیست؛ در صورت شناخت رفتار cover server میتوان policy را صریح تنظیم کرد.
هر جهت فقط sequence دقیق بعدی خود را میپذیرد؛ بنابراین recordهای تکراری، حذفشده، جابهجاشده، بازتابیافته یا متعلق به connection دیگر شکست میخورند. شکست authentication پس از authorization خطای نهایی است و counterها پیش از امکان استفاده از UINT64_MAX بسته میشوند.
نکتههای Buffer و Lifecycle
RealityServerبهازای هر line state نگه میدارد که شامل parser محدود hello، TLS binding، session ID، keyها و IVها و counterهای هر جهت، mode فعلی و state مربوط به انتقال میان شاخهها است.- این نود line معمولی را نه ایجاد میکند و نه از بین میبرد و فقط state خودش را پیش از فرستادن callbackهای
Finishپاک میکند. - این نود
21بایت required left padding اعلام میکند:5بایت header و حداکثر16بایت explicit IV مربوط به CBC. - bufferهای خالی payload در جهت downstream از chain محافظتشده، بدون فرستادن Reality record به pool برگردانده میشوند.
- حداکثر plaintext هر fragment بهصورت خودکار برابر limit بومی TLS یعنی
16384بایت است. callbackهای بزرگتر فوراً split میشوند؛32768بایت دقیقاً دو record کامل میسازد و buffering بین callbackها وجود ندارد. - هنگام انتقال به حالت authorized، callbackهای downstream ناشی از بستن شاخه visitor نادیده گرفته میشوند تا به سمتی که در حال تغییر مسیر است بازتاب پیدا نکنند.
- alert نهایی پیش از
Finishمنتقل میشود؛ guardهای terminal بازتاب synchronous مربوط به Pause/Resume/Payload/Est را متوقف میکنند و مرگ line هنگام send یا نخستین finish باعث توقف فوری teardown میشود.
مدل تهدید و محدودیتهای امنیتی
مدل تهدید بررسیشده برای camouflage یک ناظر در مسیر است که TLS را terminate نمیکند. این ناظر میتواند stream کامل دوطرفه را capture و reassemble کند؛ type، version، length، direction، ordering و timing مربوط به TLS recordها، nonce/IVهای قابلمشاهده و رفتار close را ببیند؛ bytes را دستکاری کند؛ و با آگاهی از implementation اتصال probe ایجاد کند. فرض میشود ناظر password مربوط به Reality یا traffic secretهای TLS واقعی را نمیداند، TLS را terminate نمیکند و cover destination تنظیمشده را کنترل نمیکند یا با آن تبانی ندارد. همچنین نمیتواند handshake کاملشده را بدون شکست TLS Finished verification تغییر دهد.
تازگی material هر نشست Reality به client random و server random تازه در handshake واقعی TLS وابسته است. Reality هیچ server challenge مستقل مخصوص تازگی نشست ندارد. بنابراین محافظت در برابر replay میان connectionها فرض میکند ناظر نمیتواند هر دو handshake random را پیشبینی یا کنترل کند. cover destination مخرب یا همدستی که عمداً به بازسازی binding یک handshake قبلی کمک کند خارج از این مدل است؛ دفاع در برابر چنین مدل قویتری به server challenge مستقل و احرازشده نیاز دارد.
camouflage در Reality فقط ویژگیهای public انتخابشده TLS را بازسازی میکند؛ از جمله شکل و طول record متناسب با suite، nonce/IV صریح، controlها، alertها و رفتار close. با این حال، پس از takeover، recordها ciphertext مربوط به Reality-AEAD را حمل میکنند، نه ciphertext واقعی ساختهشده با TLS traffic keyهای اتصال cover. Reality ادعا نمیکند در برابر TLS termination پنهان میماند یا همه timing distributionها، write sizeها، burst patternها و semanticهای application در Chrome را بازسازی میکند. ناظری که TLS را terminate کند میتواند traffic keyهای واقعی را روی recordهای بعدی آزمایش کند و خارج از محدوده camouflage بررسیشده است.
نکتههای عملیاتی
destinationبرای ترافیک عادی visitor است و بهتر است همان visitor domain مربوط بهRealityClient.settings.sniرا سرو یا proxy کند.nextفقط برای ترافیک مجاز واتروال است.password،salt،kdf-iterationsوalgorithmباید باRealityClientیکی باشند.- handoff احرازشده TLS 1.3 جای cutover منتشرنشده قبلی در پایان handshake اصلی را میگیرد. هر دو peer را همزمان ارتقا دهید؛ layout و counterهای TLS 1.2 تغییر نکردهاند، fallback به v1 یا layout قدیمی وجود ندارد و setting منسوخ
max-frame-sizeدر startup رد میشود. - مقدار مشتقشده از password یک root key برای material مستقل هر جهت در هر نشست TLS است. چرخش password نشستهای آینده را نامعتبر میکند و به replay database در سمت server نیازی نیست.
- این نود یک stream tunnel است، نه packet tunnel.
مشخصات نود
| ویژگی | مقدار |
|---|---|
| جایگاه | Middle stream tunnel با visitor branch |
نیاز به next | بله |
نیاز به destination | بله |
| Previous layer | Anything |
| Next layer | Anything |
| Per-line state | دارد |
| ایجاد line | خیر |
| از بین بردن line | خیر |
| Required left padding | 21 |