LeaseSet.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944
  1. #include <string.h>
  2. #include "I2PEndian.h"
  3. #include "Crypto.h"
  4. #include "Log.h"
  5. #include "Tag.h"
  6. #include "Timestamp.h"
  7. #include "NetDb.hpp"
  8. #include "Tunnel.h"
  9. #include "LeaseSet.h"
  10. namespace i2p
  11. {
  12. namespace data
  13. {
  14. LeaseSet::LeaseSet (bool storeLeases):
  15. m_IsValid (false), m_StoreLeases (storeLeases), m_ExpirationTime (0), m_EncryptionKey (nullptr),
  16. m_Buffer (nullptr), m_BufferLen (0)
  17. {
  18. }
  19. LeaseSet::LeaseSet (const uint8_t * buf, size_t len, bool storeLeases):
  20. m_IsValid (true), m_StoreLeases (storeLeases), m_ExpirationTime (0), m_EncryptionKey (nullptr)
  21. {
  22. m_Buffer = new uint8_t[len];
  23. memcpy (m_Buffer, buf, len);
  24. m_BufferLen = len;
  25. ReadFromBuffer ();
  26. }
  27. void LeaseSet::Update (const uint8_t * buf, size_t len, bool verifySignature)
  28. {
  29. if (len > m_BufferLen)
  30. {
  31. auto oldBuffer = m_Buffer;
  32. m_Buffer = new uint8_t[len];
  33. delete[] oldBuffer;
  34. }
  35. memcpy (m_Buffer, buf, len);
  36. m_BufferLen = len;
  37. ReadFromBuffer (false, verifySignature);
  38. }
  39. void LeaseSet::PopulateLeases ()
  40. {
  41. m_StoreLeases = true;
  42. ReadFromBuffer (false);
  43. }
  44. void LeaseSet::ReadFromBuffer (bool readIdentity, bool verifySignature)
  45. {
  46. if (readIdentity || !m_Identity)
  47. m_Identity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen);
  48. size_t size = m_Identity->GetFullLen ();
  49. if (size > m_BufferLen)
  50. {
  51. LogPrint (eLogError, "LeaseSet: identity length ", size, " exceeds buffer size ", m_BufferLen);
  52. m_IsValid = false;
  53. return;
  54. }
  55. if (m_StoreLeases)
  56. {
  57. if (!m_EncryptionKey) m_EncryptionKey = new uint8_t[256];
  58. memcpy (m_EncryptionKey, m_Buffer + size, 256);
  59. }
  60. size += 256; // encryption key
  61. size += m_Identity->GetSigningPublicKeyLen (); // unused signing key
  62. uint8_t num = m_Buffer[size];
  63. size++; // num
  64. LogPrint (eLogDebug, "LeaseSet: read num=", (int)num);
  65. if (!num || num > MAX_NUM_LEASES)
  66. {
  67. LogPrint (eLogError, "LeaseSet: incorrect number of leases", (int)num);
  68. m_IsValid = false;
  69. return;
  70. }
  71. UpdateLeasesBegin ();
  72. // process leases
  73. m_ExpirationTime = 0;
  74. auto ts = i2p::util::GetMillisecondsSinceEpoch ();
  75. const uint8_t * leases = m_Buffer + size;
  76. for (int i = 0; i < num; i++)
  77. {
  78. Lease lease;
  79. lease.tunnelGateway = leases;
  80. leases += 32; // gateway
  81. lease.tunnelID = bufbe32toh (leases);
  82. leases += 4; // tunnel ID
  83. lease.endDate = bufbe64toh (leases);
  84. leases += 8; // end date
  85. UpdateLease (lease, ts);
  86. }
  87. if (!m_ExpirationTime)
  88. {
  89. LogPrint (eLogWarning, "LeaseSet: all leases are expired. Dropped");
  90. m_IsValid = false;
  91. return;
  92. }
  93. m_ExpirationTime += LEASE_ENDDATE_THRESHOLD;
  94. UpdateLeasesEnd ();
  95. // verify
  96. if (verifySignature && !m_Identity->Verify (m_Buffer, leases - m_Buffer, leases))
  97. {
  98. LogPrint (eLogWarning, "LeaseSet: verification failed");
  99. m_IsValid = false;
  100. }
  101. }
  102. void LeaseSet::UpdateLeasesBegin ()
  103. {
  104. // reset existing leases
  105. if (m_StoreLeases)
  106. for (auto& it: m_Leases)
  107. it->isUpdated = false;
  108. else
  109. m_Leases.clear ();
  110. }
  111. void LeaseSet::UpdateLeasesEnd ()
  112. {
  113. // delete old leases
  114. if (m_StoreLeases)
  115. {
  116. for (auto it = m_Leases.begin (); it != m_Leases.end ();)
  117. {
  118. if (!(*it)->isUpdated)
  119. {
  120. (*it)->endDate = 0; // somebody might still hold it
  121. m_Leases.erase (it++);
  122. }
  123. else
  124. ++it;
  125. }
  126. }
  127. }
  128. void LeaseSet::UpdateLease (const Lease& lease, uint64_t ts)
  129. {
  130. if (ts < lease.endDate + LEASE_ENDDATE_THRESHOLD)
  131. {
  132. if (lease.endDate > m_ExpirationTime)
  133. m_ExpirationTime = lease.endDate;
  134. if (m_StoreLeases)
  135. {
  136. auto ret = m_Leases.insert (std::make_shared<Lease>(lease));
  137. if (!ret.second) (*ret.first)->endDate = lease.endDate; // update existing
  138. (*ret.first)->isUpdated = true;
  139. // check if lease's gateway is in our netDb
  140. if (!netdb.FindRouter (lease.tunnelGateway))
  141. {
  142. // if not found request it
  143. LogPrint (eLogInfo, "LeaseSet: Lease's tunnel gateway not found, requesting");
  144. netdb.RequestDestination (lease.tunnelGateway);
  145. }
  146. }
  147. }
  148. else
  149. LogPrint (eLogWarning, "LeaseSet: Lease is expired already ");
  150. }
  151. uint64_t LeaseSet::ExtractTimestamp (const uint8_t * buf, size_t len) const
  152. {
  153. if (!m_Identity) return 0;
  154. size_t size = m_Identity->GetFullLen ();
  155. if (size > len) return 0;
  156. size += 256; // encryption key
  157. size += m_Identity->GetSigningPublicKeyLen (); // unused signing key
  158. if (size > len) return 0;
  159. uint8_t num = buf[size];
  160. size++; // num
  161. if (size + num*LEASE_SIZE > len) return 0;
  162. uint64_t timestamp= 0 ;
  163. for (int i = 0; i < num; i++)
  164. {
  165. size += 36; // gateway (32) + tunnelId(4)
  166. auto endDate = bufbe64toh (buf + size);
  167. size += 8; // end date
  168. if (!timestamp || endDate < timestamp)
  169. timestamp = endDate;
  170. }
  171. return timestamp;
  172. }
  173. bool LeaseSet::IsNewer (const uint8_t * buf, size_t len) const
  174. {
  175. return ExtractTimestamp (buf, len) > ExtractTimestamp (m_Buffer, m_BufferLen);
  176. }
  177. bool LeaseSet::ExpiresSoon(const uint64_t dlt, const uint64_t fudge) const
  178. {
  179. auto now = i2p::util::GetMillisecondsSinceEpoch ();
  180. if (fudge) now += rand() % fudge;
  181. if (now >= m_ExpirationTime) return true;
  182. return m_ExpirationTime - now <= dlt;
  183. }
  184. const std::vector<std::shared_ptr<const Lease> > LeaseSet::GetNonExpiredLeases (bool withThreshold) const
  185. {
  186. return GetNonExpiredLeasesExcluding( [] (const Lease & l) -> bool { return false; }, withThreshold);
  187. }
  188. const std::vector<std::shared_ptr<const Lease> > LeaseSet::GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, bool withThreshold) const
  189. {
  190. auto ts = i2p::util::GetMillisecondsSinceEpoch ();
  191. std::vector<std::shared_ptr<const Lease> > leases;
  192. for (const auto& it: m_Leases)
  193. {
  194. auto endDate = it->endDate;
  195. if (withThreshold)
  196. endDate += LEASE_ENDDATE_THRESHOLD;
  197. else
  198. endDate -= LEASE_ENDDATE_THRESHOLD;
  199. if (ts < endDate && !exclude(*it))
  200. leases.push_back (it);
  201. }
  202. return leases;
  203. }
  204. bool LeaseSet::HasExpiredLeases () const
  205. {
  206. auto ts = i2p::util::GetMillisecondsSinceEpoch ();
  207. for (const auto& it: m_Leases)
  208. if (ts >= it->endDate) return true;
  209. return false;
  210. }
  211. bool LeaseSet::IsExpired () const
  212. {
  213. if (m_StoreLeases && IsEmpty ()) return true;
  214. auto ts = i2p::util::GetMillisecondsSinceEpoch ();
  215. return ts > m_ExpirationTime;
  216. }
  217. void LeaseSet::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const
  218. {
  219. if (!m_EncryptionKey) return;
  220. auto encryptor = m_Identity->CreateEncryptor (m_EncryptionKey);
  221. if (encryptor)
  222. encryptor->Encrypt (data, encrypted, ctx, true);
  223. }
  224. void LeaseSet::SetBuffer (const uint8_t * buf, size_t len)
  225. {
  226. if (m_Buffer) delete[] m_Buffer;
  227. m_Buffer = new uint8_t[len];
  228. m_BufferLen = len;
  229. memcpy (m_Buffer, buf, len);
  230. }
  231. LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases):
  232. LeaseSet (storeLeases), m_StoreType (storeType), m_OrigStoreType (storeType)
  233. {
  234. SetBuffer (buf, len);
  235. if (storeType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
  236. ReadFromBufferEncrypted (buf, len, nullptr, nullptr);
  237. else
  238. ReadFromBuffer (buf, len);
  239. }
  240. LeaseSet2::LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key, const uint8_t * secret):
  241. LeaseSet (true), m_StoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2), m_OrigStoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
  242. {
  243. ReadFromBufferEncrypted (buf, len, key, secret);
  244. }
  245. void LeaseSet2::Update (const uint8_t * buf, size_t len, bool verifySignature)
  246. {
  247. SetBuffer (buf, len);
  248. if (GetStoreType () != NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
  249. ReadFromBuffer (buf, len, false, verifySignature);
  250. // TODO: implement encrypted
  251. }
  252. void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len, bool readIdentity, bool verifySignature)
  253. {
  254. // standard LS2 header
  255. std::shared_ptr<const IdentityEx> identity;
  256. if (readIdentity)
  257. {
  258. identity = std::make_shared<IdentityEx>(buf, len);
  259. SetIdentity (identity);
  260. }
  261. else
  262. identity = GetIdentity ();
  263. size_t offset = identity->GetFullLen ();
  264. if (offset + 8 >= len) return;
  265. m_PublishedTimestamp = bufbe32toh (buf + offset); offset += 4; // published timestamp (seconds)
  266. uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds)
  267. SetExpirationTime ((m_PublishedTimestamp + expires)*1000LL); // in milliseconds
  268. uint16_t flags = bufbe16toh (buf + offset); offset += 2; // flags
  269. if (flags & LEASESET2_FLAG_OFFLINE_KEYS)
  270. {
  271. // transient key
  272. m_TransientVerifier = ProcessOfflineSignature (identity, buf, len, offset);
  273. if (!m_TransientVerifier)
  274. {
  275. LogPrint (eLogError, "LeaseSet2: offline signature failed");
  276. return;
  277. }
  278. }
  279. if (flags & LEASESET2_FLAG_UNPUBLISHED_LEASESET) m_IsPublic = false;
  280. // type specific part
  281. size_t s = 0;
  282. switch (m_StoreType)
  283. {
  284. case NETDB_STORE_TYPE_STANDARD_LEASESET2:
  285. s = ReadStandardLS2TypeSpecificPart (buf + offset, len - offset);
  286. break;
  287. case NETDB_STORE_TYPE_META_LEASESET2:
  288. s = ReadMetaLS2TypeSpecificPart (buf + offset, len - offset);
  289. break;
  290. default:
  291. LogPrint (eLogWarning, "LeaseSet2: Unexpected store type ", (int)m_StoreType);
  292. }
  293. if (!s) return;
  294. offset += s;
  295. if (verifySignature || m_TransientVerifier)
  296. {
  297. // verify signature
  298. bool verified = m_TransientVerifier ? VerifySignature (m_TransientVerifier, buf, len, offset) :
  299. VerifySignature (identity, buf, len, offset);
  300. SetIsValid (verified);
  301. }
  302. }
  303. template<typename Verifier>
  304. bool LeaseSet2::VerifySignature (Verifier& verifier, const uint8_t * buf, size_t len, size_t signatureOffset)
  305. {
  306. if (signatureOffset + verifier->GetSignatureLen () > len) return false;
  307. // we assume buf inside DatabaseStore message, so buf[-1] is valid memory
  308. // change it for signature verification, and restore back
  309. uint8_t c = buf[-1];
  310. const_cast<uint8_t *>(buf)[-1] = m_StoreType;
  311. bool verified = verifier->Verify (buf - 1, signatureOffset + 1, buf + signatureOffset);
  312. const_cast<uint8_t *>(buf)[-1] = c;
  313. if (!verified)
  314. LogPrint (eLogWarning, "LeaseSet2: verification failed");
  315. return verified;
  316. }
  317. size_t LeaseSet2::ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len)
  318. {
  319. size_t offset = 0;
  320. // properties
  321. uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2;
  322. offset += propertiesLen; // skip for now. TODO: implement properties
  323. if (offset + 1 >= len) return 0;
  324. // key sections
  325. uint16_t currentKeyType = 0;
  326. int numKeySections = buf[offset]; offset++;
  327. for (int i = 0; i < numKeySections; i++)
  328. {
  329. uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption key type
  330. if (offset + 2 >= len) return 0;
  331. uint16_t encryptionKeyLen = bufbe16toh (buf + offset); offset += 2;
  332. if (offset + encryptionKeyLen >= len) return 0;
  333. if (IsStoreLeases ()) // create encryptor with leases only
  334. {
  335. // we pick first valid key, higher key type has higher priority 4-1-0
  336. // if two keys with of the same type, pick first
  337. auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset);
  338. if (encryptor && (!m_Encryptor || keyType > currentKeyType))
  339. {
  340. m_Encryptor = encryptor; // TODO: atomic
  341. currentKeyType = keyType;
  342. }
  343. }
  344. offset += encryptionKeyLen;
  345. }
  346. // leases
  347. if (offset + 1 >= len) return 0;
  348. int numLeases = buf[offset]; offset++;
  349. auto ts = i2p::util::GetMillisecondsSinceEpoch ();
  350. if (IsStoreLeases ())
  351. {
  352. UpdateLeasesBegin ();
  353. for (int i = 0; i < numLeases; i++)
  354. {
  355. if (offset + LEASE2_SIZE > len) return 0;
  356. Lease lease;
  357. lease.tunnelGateway = buf + offset; offset += 32; // gateway
  358. lease.tunnelID = bufbe32toh (buf + offset); offset += 4; // tunnel ID
  359. lease.endDate = bufbe32toh (buf + offset)*1000LL; offset += 4; // end date
  360. UpdateLease (lease, ts);
  361. }
  362. UpdateLeasesEnd ();
  363. }
  364. else
  365. offset += numLeases*LEASE2_SIZE; // 40 bytes per lease
  366. return offset;
  367. }
  368. size_t LeaseSet2::ReadMetaLS2TypeSpecificPart (const uint8_t * buf, size_t len)
  369. {
  370. size_t offset = 0;
  371. // properties
  372. uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2;
  373. offset += propertiesLen; // skip for now. TODO: implement properties
  374. // entries
  375. if (offset + 1 >= len) return 0;
  376. int numEntries = buf[offset]; offset++;
  377. for (int i = 0; i < numEntries; i++)
  378. {
  379. if (offset + 40 >= len) return 0;
  380. offset += 32; // hash
  381. offset += 3; // flags
  382. offset += 1; // cost
  383. offset += 4; // expires
  384. }
  385. // revocations
  386. if (offset + 1 >= len) return 0;
  387. int numRevocations = buf[offset]; offset++;
  388. for (int i = 0; i < numRevocations; i++)
  389. {
  390. if (offset + 32 > len) return 0;
  391. offset += 32; // hash
  392. }
  393. return offset;
  394. }
  395. void LeaseSet2::ReadFromBufferEncrypted (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key, const uint8_t * secret)
  396. {
  397. size_t offset = 0;
  398. // blinded key
  399. if (len < 2) return;
  400. const uint8_t * stA1 = buf + offset; // stA1 = blinded signature type, 2 bytes big endian
  401. uint16_t blindedKeyType = bufbe16toh (stA1); offset += 2;
  402. std::unique_ptr<i2p::crypto::Verifier> blindedVerifier (i2p::data::IdentityEx::CreateVerifier (blindedKeyType));
  403. if (!blindedVerifier) return;
  404. auto blindedKeyLen = blindedVerifier->GetPublicKeyLen ();
  405. if (offset + blindedKeyLen >= len) return;
  406. const uint8_t * blindedPublicKey = buf + offset;
  407. blindedVerifier->SetPublicKey (blindedPublicKey); offset += blindedKeyLen;
  408. // expiration
  409. if (offset + 8 >= len) return;
  410. const uint8_t * publishedTimestamp = buf + offset;
  411. m_PublishedTimestamp = bufbe32toh (publishedTimestamp); offset += 4; // published timestamp (seconds)
  412. uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds)
  413. SetExpirationTime ((m_PublishedTimestamp + expires)*1000LL); // in milliseconds
  414. uint16_t flags = bufbe16toh (buf + offset); offset += 2; // flags
  415. if (flags & LEASESET2_FLAG_OFFLINE_KEYS)
  416. {
  417. // transient key
  418. m_TransientVerifier = ProcessOfflineSignature (blindedVerifier, buf, len, offset);
  419. if (!m_TransientVerifier)
  420. {
  421. LogPrint (eLogError, "LeaseSet2: offline signature failed");
  422. return;
  423. }
  424. }
  425. // outer ciphertext
  426. if (offset + 2 > len) return;
  427. uint16_t lenOuterCiphertext = bufbe16toh (buf + offset); offset += 2;
  428. const uint8_t * outerCiphertext = buf + offset;
  429. offset += lenOuterCiphertext;
  430. // verify signature
  431. bool verified = m_TransientVerifier ? VerifySignature (m_TransientVerifier, buf, len, offset) :
  432. VerifySignature (blindedVerifier, buf, len, offset);
  433. SetIsValid (verified);
  434. // handle ciphertext
  435. if (verified && key && lenOuterCiphertext >= 32)
  436. {
  437. SetIsValid (false); // we must verify it again in Layer 2
  438. if (blindedKeyType == key->GetBlindedSigType ())
  439. {
  440. // verify blinding
  441. char date[9];
  442. i2p::util::GetDateString (m_PublishedTimestamp, date);
  443. std::vector<uint8_t> blinded (blindedKeyLen);
  444. key->GetBlindedKey (date, blinded.data ());
  445. if (memcmp (blindedPublicKey, blinded.data (), blindedKeyLen))
  446. {
  447. LogPrint (eLogError, "LeaseSet2: blinded public key doesn't match");
  448. return;
  449. }
  450. }
  451. else
  452. {
  453. LogPrint (eLogError, "LeaseSet2: Unexpected blinded key type ", blindedKeyType, " instead ", key->GetBlindedSigType ());
  454. return;
  455. }
  456. // outer key
  457. // outerInput = subcredential || publishedTimestamp
  458. uint8_t subcredential[36];
  459. key->GetSubcredential (blindedPublicKey, blindedKeyLen, subcredential);
  460. memcpy (subcredential + 32, publishedTimestamp, 4);
  461. // outerSalt = outerCiphertext[0:32]
  462. // keys = HKDF(outerSalt, outerInput, "ELS2_L1K", 44)
  463. uint8_t keys[64]; // 44 bytes actual data
  464. i2p::crypto::HKDF (outerCiphertext, subcredential, 36, "ELS2_L1K", keys);
  465. // decrypt Layer 1
  466. // outerKey = keys[0:31]
  467. // outerIV = keys[32:43]
  468. size_t lenOuterPlaintext = lenOuterCiphertext - 32;
  469. std::vector<uint8_t> outerPlainText (lenOuterPlaintext);
  470. i2p::crypto::ChaCha20 (outerCiphertext + 32, lenOuterPlaintext, keys, keys + 32, outerPlainText.data ());
  471. // inner key
  472. // innerInput = authCookie || subcredential || publishedTimestamp
  473. // innerSalt = innerCiphertext[0:32]
  474. // keys = HKDF(innerSalt, innerInput, "ELS2_L2K", 44)
  475. uint8_t innerInput[68];
  476. size_t authDataLen = ExtractClientAuthData (outerPlainText.data (), lenOuterPlaintext, secret, subcredential, innerInput);
  477. if (authDataLen > 0)
  478. {
  479. memcpy (innerInput + 32, subcredential, 36);
  480. i2p::crypto::HKDF (outerPlainText.data () + 1 + authDataLen, innerInput, 68, "ELS2_L2K", keys);
  481. }
  482. else
  483. // no authData presented, innerInput = subcredential || publishedTimestamp
  484. // skip 1 byte flags
  485. i2p::crypto::HKDF (outerPlainText.data () + 1, subcredential, 36, "ELS2_L2K", keys); // no authCookie
  486. // decrypt Layer 2
  487. // innerKey = keys[0:31]
  488. // innerIV = keys[32:43]
  489. size_t lenInnerPlaintext = lenOuterPlaintext - 32 - 1 - authDataLen;
  490. std::vector<uint8_t> innerPlainText (lenInnerPlaintext);
  491. i2p::crypto::ChaCha20 (outerPlainText.data () + 32 + 1 + authDataLen, lenInnerPlaintext, keys, keys + 32, innerPlainText.data ());
  492. if (innerPlainText[0] == NETDB_STORE_TYPE_STANDARD_LEASESET2 || innerPlainText[0] == NETDB_STORE_TYPE_META_LEASESET2)
  493. {
  494. // override store type and buffer
  495. m_StoreType = innerPlainText[0];
  496. SetBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1);
  497. // parse and verify Layer 2
  498. ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1);
  499. }
  500. else
  501. LogPrint (eLogError, "LeaseSet2: unexpected LeaseSet type ", (int)innerPlainText[0], " inside encrypted LeaseSet");
  502. }
  503. }
  504. // helper for ExtractClientAuthData
  505. static inline bool GetAuthCookie (const uint8_t * authClients, int numClients, const uint8_t * okm, uint8_t * authCookie)
  506. {
  507. // try to find clientCookie_i for clientID_i = okm[44:51]
  508. for (int i = 0; i < numClients; i++)
  509. {
  510. if (!memcmp (okm + 44, authClients + i*40, 8)) // clientID_i
  511. {
  512. // clientKey_i = okm[0:31]
  513. // clientIV_i = okm[32:43]
  514. i2p::crypto::ChaCha20 (authClients + i*40 + 8, 32, okm, okm + 32, authCookie); // clientCookie_i
  515. return true;
  516. }
  517. }
  518. return false;
  519. }
  520. size_t LeaseSet2::ExtractClientAuthData (const uint8_t * buf, size_t len, const uint8_t * secret, const uint8_t * subcredential, uint8_t * authCookie) const
  521. {
  522. size_t offset = 0;
  523. uint8_t flag = buf[offset]; offset++; // flag
  524. if (flag & 0x01) // client auth
  525. {
  526. if (!(flag & 0x0E)) // DH, bit 1-3 all zeroes
  527. {
  528. const uint8_t * ephemeralPublicKey = buf + offset; offset += 32; // ephemeralPublicKey
  529. uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients
  530. const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients
  531. if (offset > len)
  532. {
  533. LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in DH auth data");
  534. return 0;
  535. }
  536. // calculate authCookie
  537. if (secret)
  538. {
  539. i2p::crypto::X25519Keys ck (secret, nullptr); // derive cpk_i from csk_i
  540. uint8_t authInput[100];
  541. ck.Agree (ephemeralPublicKey, authInput); // sharedSecret is first 32 bytes of authInput
  542. memcpy (authInput + 32, ck.GetPublicKey (), 32); // cpk_i
  543. memcpy (authInput + 64, subcredential, 36);
  544. uint8_t okm[64]; // 52 actual data
  545. i2p::crypto::HKDF (ephemeralPublicKey, authInput, 100, "ELS2_XCA", okm);
  546. if (!GetAuthCookie (authClients, numClients, okm, authCookie))
  547. LogPrint (eLogError, "LeaseSet2: Client cookie DH not found");
  548. }
  549. else
  550. LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: csk_i is not provided");
  551. }
  552. else if (flag & 0x02) // PSK, bit 1 is set to 1
  553. {
  554. const uint8_t * authSalt = buf + offset; offset += 32; // authSalt
  555. uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients
  556. const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients
  557. if (offset > len)
  558. {
  559. LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in PSK auth data");
  560. return 0;
  561. }
  562. // calculate authCookie
  563. if (secret)
  564. {
  565. uint8_t authInput[68];
  566. memcpy (authInput, secret, 32);
  567. memcpy (authInput + 32, subcredential, 36);
  568. uint8_t okm[64]; // 52 actual data
  569. i2p::crypto::HKDF (authSalt, authInput, 68, "ELS2PSKA", okm);
  570. if (!GetAuthCookie (authClients, numClients, okm, authCookie))
  571. LogPrint (eLogError, "LeaseSet2: Client cookie PSK not found");
  572. }
  573. else
  574. LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: psk_i is not provided");
  575. }
  576. else
  577. LogPrint (eLogError, "LeaseSet2: unknown client auth type ", (int)flag);
  578. }
  579. return offset - 1;
  580. }
  581. void LeaseSet2::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const
  582. {
  583. auto encryptor = m_Encryptor; // TODO: atomic
  584. if (encryptor)
  585. encryptor->Encrypt (data, encrypted, ctx, true);
  586. }
  587. uint64_t LeaseSet2::ExtractTimestamp (const uint8_t * buf, size_t len) const
  588. {
  589. if (len < 8) return 0;
  590. if (m_StoreType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
  591. {
  592. // encrypted LS2
  593. size_t offset = 0;
  594. uint16_t blindedKeyType = bufbe16toh (buf + offset); offset += 2;
  595. std::unique_ptr<i2p::crypto::Verifier> blindedVerifier (i2p::data::IdentityEx::CreateVerifier (blindedKeyType));
  596. if (!blindedVerifier) return 0 ;
  597. auto blindedKeyLen = blindedVerifier->GetPublicKeyLen ();
  598. if (offset + blindedKeyLen + 6 >= len) return 0;
  599. offset += blindedKeyLen;
  600. uint32_t timestamp = bufbe32toh (buf + offset); offset += 4;
  601. uint16_t expires = bufbe16toh (buf + offset); offset += 2;
  602. return (timestamp + expires)* 1000LL;
  603. }
  604. else
  605. {
  606. auto identity = GetIdentity ();
  607. if (!identity) return 0;
  608. size_t offset = identity->GetFullLen ();
  609. if (offset + 6 >= len) return 0;
  610. uint32_t timestamp = bufbe32toh (buf + offset); offset += 4;
  611. uint16_t expires = bufbe16toh (buf + offset); offset += 2;
  612. return (timestamp + expires)* 1000LL;
  613. }
  614. }
  615. LocalLeaseSet::LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * encryptionPublicKey, std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels):
  616. m_ExpirationTime (0), m_Identity (identity)
  617. {
  618. int num = tunnels.size ();
  619. if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES;
  620. // identity
  621. auto signingKeyLen = m_Identity->GetSigningPublicKeyLen ();
  622. m_BufferLen = m_Identity->GetFullLen () + 256 + signingKeyLen + 1 + num*LEASE_SIZE + m_Identity->GetSignatureLen ();
  623. m_Buffer = new uint8_t[m_BufferLen];
  624. auto offset = m_Identity->ToBuffer (m_Buffer, m_BufferLen);
  625. memcpy (m_Buffer + offset, encryptionPublicKey, 256);
  626. offset += 256;
  627. memset (m_Buffer + offset, 0, signingKeyLen);
  628. offset += signingKeyLen;
  629. // num leases
  630. m_Buffer[offset] = num;
  631. offset++;
  632. // leases
  633. m_Leases = m_Buffer + offset;
  634. auto currentTime = i2p::util::GetMillisecondsSinceEpoch ();
  635. for (int i = 0; i < num; i++)
  636. {
  637. memcpy (m_Buffer + offset, tunnels[i]->GetNextIdentHash (), 32);
  638. offset += 32; // gateway id
  639. htobe32buf (m_Buffer + offset, tunnels[i]->GetNextTunnelID ());
  640. offset += 4; // tunnel id
  641. uint64_t ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration
  642. ts *= 1000; // in milliseconds
  643. if (ts > m_ExpirationTime) m_ExpirationTime = ts;
  644. // make sure leaseset is newer than previous, but adding some time to expiration date
  645. ts += (currentTime - tunnels[i]->GetCreationTime ()*1000LL)*2/i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT; // up to 2 secs
  646. htobe64buf (m_Buffer + offset, ts);
  647. offset += 8; // end date
  648. }
  649. // we don't sign it yet. must be signed later on
  650. }
  651. LocalLeaseSet::LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len):
  652. m_ExpirationTime (0), m_Identity (identity)
  653. {
  654. if (buf)
  655. {
  656. m_BufferLen = len;
  657. m_Buffer = new uint8_t[m_BufferLen];
  658. memcpy (m_Buffer, buf, len);
  659. }
  660. else
  661. {
  662. m_Buffer = nullptr;
  663. m_BufferLen = 0;
  664. }
  665. }
  666. bool LocalLeaseSet::IsExpired () const
  667. {
  668. auto ts = i2p::util::GetMillisecondsSinceEpoch ();
  669. return ts > m_ExpirationTime;
  670. }
  671. bool LeaseSetBufferValidate(const uint8_t * ptr, size_t sz, uint64_t & expires)
  672. {
  673. IdentityEx ident(ptr, sz);
  674. size_t size = ident.GetFullLen ();
  675. if (size > sz)
  676. {
  677. LogPrint (eLogError, "LeaseSet: identity length ", size, " exceeds buffer size ", sz);
  678. return false;
  679. }
  680. // encryption key
  681. size += 256;
  682. // signing key (unused)
  683. size += ident.GetSigningPublicKeyLen ();
  684. uint8_t numLeases = ptr[size];
  685. ++size;
  686. if (!numLeases || numLeases > MAX_NUM_LEASES)
  687. {
  688. LogPrint (eLogError, "LeaseSet: incorrect number of leases", (int)numLeases);
  689. return false;
  690. }
  691. const uint8_t * leases = ptr + size;
  692. expires = 0;
  693. /** find lease with the max expiration timestamp */
  694. for (int i = 0; i < numLeases; i++)
  695. {
  696. leases += 36; // gateway + tunnel ID
  697. uint64_t endDate = bufbe64toh (leases);
  698. leases += 8; // end date
  699. if(endDate > expires)
  700. expires = endDate;
  701. }
  702. return ident.Verify(ptr, leases - ptr, leases);
  703. }
  704. LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
  705. uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey,
  706. std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels, bool isPublic):
  707. LocalLeaseSet (keys.GetPublic (), nullptr, 0)
  708. {
  709. auto identity = keys.GetPublic ();
  710. // assume standard LS2
  711. int num = tunnels.size ();
  712. if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES;
  713. m_BufferLen = identity->GetFullLen () + 4/*published*/ + 2/*expires*/ + 2/*flag*/ + 2/*properties len*/ +
  714. 1/*num keys*/ + 2/*key type*/ + 2/*key len*/ + keyLen/*key*/ + 1/*num leases*/ + num*LEASE2_SIZE + keys.GetSignatureLen ();
  715. uint16_t flags = 0;
  716. if (keys.IsOfflineSignature ())
  717. {
  718. flags |= LEASESET2_FLAG_OFFLINE_KEYS;
  719. m_BufferLen += keys.GetOfflineSignature ().size ();
  720. }
  721. if (!isPublic) flags |= LEASESET2_FLAG_UNPUBLISHED_LEASESET;
  722. m_Buffer = new uint8_t[m_BufferLen + 1];
  723. m_Buffer[0] = storeType;
  724. // LS2 header
  725. auto offset = identity->ToBuffer (m_Buffer + 1, m_BufferLen) + 1;
  726. auto timestamp = i2p::util::GetSecondsSinceEpoch ();
  727. htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds)
  728. uint8_t * expiresBuf = m_Buffer + offset; offset += 2; // expires, fill later
  729. htobe16buf (m_Buffer + offset, flags); offset += 2; // flags
  730. if (keys.IsOfflineSignature ())
  731. {
  732. // offline signature
  733. const auto& offlineSignature = keys.GetOfflineSignature ();
  734. memcpy (m_Buffer + offset, offlineSignature.data (), offlineSignature.size ());
  735. offset += offlineSignature.size ();
  736. }
  737. htobe16buf (m_Buffer + offset, 0); offset += 2; // properties len
  738. // keys
  739. m_Buffer[offset] = 1; offset++; // 1 key
  740. htobe16buf (m_Buffer + offset, keyType); offset += 2; // key type
  741. htobe16buf (m_Buffer + offset, keyLen); offset += 2; // key len
  742. memcpy (m_Buffer + offset, encryptionPublicKey, keyLen); offset += keyLen; // key
  743. // leases
  744. uint32_t expirationTime = 0; // in seconds
  745. m_Buffer[offset] = num; offset++; // num leases
  746. for (int i = 0; i < num; i++)
  747. {
  748. memcpy (m_Buffer + offset, tunnels[i]->GetNextIdentHash (), 32);
  749. offset += 32; // gateway id
  750. htobe32buf (m_Buffer + offset, tunnels[i]->GetNextTunnelID ());
  751. offset += 4; // tunnel id
  752. auto ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // in seconds, 1 minute before expiration
  753. if (ts > expirationTime) expirationTime = ts;
  754. htobe32buf (m_Buffer + offset, ts);
  755. offset += 4; // end date
  756. }
  757. // update expiration
  758. SetExpirationTime (expirationTime*1000LL);
  759. auto expires = expirationTime - timestamp;
  760. htobe16buf (expiresBuf, expires > 0 ? expires : 0);
  761. // sign
  762. keys.Sign (m_Buffer, offset, m_Buffer + offset); // LS + leading store type
  763. }
  764. LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len):
  765. LocalLeaseSet (identity, nullptr, 0)
  766. {
  767. m_BufferLen = len;
  768. m_Buffer = new uint8_t[m_BufferLen + 1];
  769. memcpy (m_Buffer + 1, buf, len);
  770. m_Buffer[0] = storeType;
  771. }
  772. LocalEncryptedLeaseSet2::LocalEncryptedLeaseSet2 (std::shared_ptr<const LocalLeaseSet2> ls, const i2p::data::PrivateKeys& keys,
  773. int authType, std::shared_ptr<std::vector<AuthPublicKey> > authKeys):
  774. LocalLeaseSet2 (ls->GetIdentity ()), m_InnerLeaseSet (ls)
  775. {
  776. size_t lenInnerPlaintext = ls->GetBufferLen () + 1, lenOuterPlaintext = lenInnerPlaintext + 32 + 1,
  777. lenOuterCiphertext = lenOuterPlaintext + 32;
  778. m_BufferLen = 2/*blinded sig type*/ + 32/*blinded pub key*/ + 4/*published*/ + 2/*expires*/ + 2/*flags*/ + 2/*lenOuterCiphertext*/ + lenOuterCiphertext + 64/*signature*/;
  779. uint8_t layer1Flags = 0;
  780. if (authKeys)
  781. {
  782. if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_DH) layer1Flags |= 0x01; // DH, authentication scheme 0, auth bit 1
  783. else if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_PSK) layer1Flags |= 0x03; // PSK, authentication scheme 1, auth bit 1
  784. if (layer1Flags) m_BufferLen += authKeys->size ()*40 + 2; // auth data len
  785. }
  786. m_Buffer = new uint8_t[m_BufferLen + 1];
  787. m_Buffer[0] = NETDB_STORE_TYPE_ENCRYPTED_LEASESET2;
  788. BlindedPublicKey blindedKey (ls->GetIdentity ());
  789. auto timestamp = i2p::util::GetSecondsSinceEpoch ();
  790. char date[9];
  791. i2p::util::GetDateString (timestamp, date);
  792. uint8_t blindedPriv[64], blindedPub[128]; // 64 and 128 max
  793. size_t publicKeyLen = blindedKey.BlindPrivateKey (keys.GetSigningPrivateKey (), date, blindedPriv, blindedPub);
  794. std::unique_ptr<i2p::crypto::Signer> blindedSigner (i2p::data::PrivateKeys::CreateSigner (blindedKey.GetBlindedSigType (), blindedPriv));
  795. auto offset = 1;
  796. htobe16buf (m_Buffer + offset, blindedKey.GetBlindedSigType ()); offset += 2; // Blinded Public Key Sig Type
  797. memcpy (m_Buffer + offset, blindedPub, publicKeyLen); offset += publicKeyLen; // Blinded Public Key
  798. htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds)
  799. auto nextMidnight = (timestamp/86400LL + 1)*86400LL; // 86400 = 24*3600 seconds
  800. auto expirationTime = ls->GetExpirationTime ()/1000LL;
  801. if (expirationTime > nextMidnight) expirationTime = nextMidnight;
  802. SetExpirationTime (expirationTime*1000LL);
  803. htobe16buf (m_Buffer + offset, expirationTime > timestamp ? expirationTime - timestamp : 0); offset += 2; // expires
  804. uint16_t flags = 0;
  805. htobe16buf (m_Buffer + offset, flags); offset += 2; // flags
  806. htobe16buf (m_Buffer + offset, lenOuterCiphertext); offset += 2; // lenOuterCiphertext
  807. // outerChipherText
  808. // Layer 1
  809. uint8_t subcredential[36];
  810. blindedKey.GetSubcredential (blindedPub, 32, subcredential);
  811. htobe32buf (subcredential + 32, timestamp); // outerInput = subcredential || publishedTimestamp
  812. // keys = HKDF(outerSalt, outerInput, "ELS2_L1K", 44)
  813. uint8_t keys1[64]; // 44 bytes actual data
  814. RAND_bytes (m_Buffer + offset, 32); // outerSalt = CSRNG(32)
  815. i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L1K", keys1);
  816. offset += 32; // outerSalt
  817. uint8_t * outerPlainText = m_Buffer + offset;
  818. m_Buffer[offset] = layer1Flags; offset++; // layer 1 flags
  819. // auth data
  820. uint8_t innerInput[68]; // authCookie || subcredential || publishedTimestamp
  821. if (layer1Flags)
  822. {
  823. RAND_bytes (innerInput, 32); // authCookie
  824. htobe16buf (m_Buffer + offset, authKeys->size ()); offset += 2; // num clients
  825. CreateClientAuthData (subcredential, authType, authKeys, innerInput, m_Buffer);
  826. offset += authKeys->size ()*40; // auth clients
  827. }
  828. // Layer 2
  829. // keys = HKDF(outerSalt, outerInput, "ELS2_L2K", 44)
  830. uint8_t keys2[64]; // 44 bytes actual data
  831. RAND_bytes (m_Buffer + offset, 32); // innerSalt = CSRNG(32)
  832. if (layer1Flags)
  833. {
  834. memcpy (innerInput + 32, subcredential, 36); // + subcredential || publishedTimestamp
  835. i2p::crypto::HKDF (m_Buffer + offset, innerInput, 68, "ELS2_L2K", keys2);
  836. }
  837. else
  838. i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L2K", keys2); // no authCookie
  839. offset += 32; // innerSalt
  840. m_Buffer[offset] = ls->GetStoreType ();
  841. memcpy (m_Buffer + offset + 1, ls->GetBuffer (), ls->GetBufferLen ());
  842. i2p::crypto::ChaCha20 (m_Buffer + offset, lenInnerPlaintext, keys2, keys2 + 32, m_Buffer + offset); // encrypt Layer 2
  843. offset += lenInnerPlaintext;
  844. i2p::crypto::ChaCha20 (outerPlainText, lenOuterPlaintext, keys1, keys1 + 32, outerPlainText); // encrypt Layer 1
  845. // signature
  846. blindedSigner->Sign (m_Buffer, offset, m_Buffer + offset);
  847. // store hash
  848. m_StoreHash = blindedKey.GetStoreHash (date);
  849. }
  850. LocalEncryptedLeaseSet2::LocalEncryptedLeaseSet2 (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len):
  851. LocalLeaseSet2 (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2, identity, buf, len)
  852. {
  853. // fill inner LeaseSet2
  854. auto blindedKey = std::make_shared<BlindedPublicKey>(identity);
  855. i2p::data::LeaseSet2 ls (buf, len, blindedKey); // inner layer
  856. if (ls.IsValid ())
  857. {
  858. m_InnerLeaseSet = std::make_shared<LocalLeaseSet2>(ls.GetStoreType (), identity, ls.GetBuffer (), ls.GetBufferLen ());
  859. m_StoreHash = blindedKey->GetStoreHash ();
  860. }
  861. else
  862. LogPrint (eLogError, "LeaseSet2: couldn't extract inner layer");
  863. }
  864. void LocalEncryptedLeaseSet2::CreateClientAuthData (const uint8_t * subcredential, int authType, std::shared_ptr<std::vector<AuthPublicKey> > authKeys, const uint8_t * authCookie, uint8_t * authClients) const
  865. {
  866. if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_DH)
  867. {
  868. i2p::crypto::X25519Keys ek;
  869. ek.GenerateKeys (); // esk and epk
  870. uint8_t authInput[100]; // sharedSecret || cpk_i || subcredential || publishedTimestamp
  871. memcpy (authInput + 64, subcredential, 36);
  872. for (auto& it: *authKeys)
  873. {
  874. ek.Agree (it, authInput); // sharedSecret = DH(esk, cpk_i)
  875. memcpy (authInput + 32, it, 32);
  876. uint8_t okm[64]; // 52 actual data
  877. i2p::crypto::HKDF (ek.GetPublicKey (), authInput, 100, "ELS2_XCA", okm);
  878. memcpy (authClients, okm + 44, 8); authClients += 8; // clientID_i
  879. i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authClients); authClients += 32; // clientCookie_i
  880. }
  881. }
  882. else // assume PSK
  883. {
  884. uint8_t authSalt[32];
  885. RAND_bytes (authSalt, 32);
  886. uint8_t authInput[68]; // authInput = psk_i || subcredential || publishedTimestamp
  887. memcpy (authInput + 32, subcredential, 36);
  888. for (auto& it: *authKeys)
  889. {
  890. memcpy (authInput, it, 32);
  891. uint8_t okm[64]; // 52 actual data
  892. i2p::crypto::HKDF (authSalt, authInput, 68, "ELS2PSKA", okm);
  893. memcpy (authClients, okm + 44, 8); authClients += 8; // clientID_i
  894. i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authClients); authClients += 32; // clientCookie_i
  895. }
  896. }
  897. }
  898. }
  899. }