crypto.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. /*
  2. * SRT - Secure, Reliable, Transport
  3. * Copyright (c) 2018 Haivision Systems Inc.
  4. *
  5. * This Source Code Form is subject to the terms of the Mozilla Public
  6. * License, v. 2.0. If a copy of the MPL was not distributed with this
  7. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  8. *
  9. */
  10. /*****************************************************************************
  11. written by
  12. Haivision Systems Inc.
  13. *****************************************************************************/
  14. #include "platform_sys.h"
  15. #include <cstring>
  16. #include <string>
  17. #include <sstream>
  18. #include <iterator>
  19. #include "udt.h"
  20. #include "utilities.h"
  21. #include <haicrypt.h>
  22. #include "crypto.h"
  23. #include "logging.h"
  24. #include "core.h"
  25. #include "api.h"
  26. using namespace srt_logging;
  27. #define SRT_MAX_KMRETRY 10
  28. //#define SRT_CMD_KMREQ 3 /* HaiCryptTP SRT Keying Material */
  29. //#define SRT_CMD_KMRSP 4 /* HaiCryptTP SRT Keying Material ACK */
  30. #define SRT_CMD_KMREQ_SZ HCRYPT_MSG_KM_MAX_SZ /* */
  31. #if SRT_CMD_KMREQ_SZ > SRT_CMD_MAXSZ
  32. #error SRT_CMD_MAXSZ too small
  33. #endif
  34. /* Key Material Request (Network Order)
  35. See HaiCryptTP SRT (hcrypt_xpt_srt.c)
  36. */
  37. // 10* HAICRYPT_DEF_KM_PRE_ANNOUNCE
  38. const int SRT_CRYPT_KM_PRE_ANNOUNCE SRT_ATR_UNUSED = 0x10000;
  39. namespace srt_logging
  40. {
  41. std::string KmStateStr(SRT_KM_STATE state)
  42. {
  43. switch (state)
  44. {
  45. #define TAKE(val) case SRT_KM_S_##val : return #val
  46. TAKE(UNSECURED);
  47. TAKE(SECURED);
  48. TAKE(SECURING);
  49. TAKE(NOSECRET);
  50. TAKE(BADSECRET);
  51. #ifdef ENABLE_AEAD_API_PREVIEW
  52. TAKE(BADCRYPTOMODE);
  53. #endif
  54. #undef TAKE
  55. default:
  56. {
  57. char buf[256];
  58. #if defined(_MSC_VER) && _MSC_VER < 1900
  59. _snprintf(buf, sizeof(buf) - 1, "??? (%d)", state);
  60. #else
  61. snprintf(buf, sizeof(buf), "??? (%d)", state);
  62. #endif
  63. return buf;
  64. }
  65. }
  66. }
  67. } // namespace
  68. using srt_logging::KmStateStr;
  69. void srt::CCryptoControl::globalInit()
  70. {
  71. #ifdef SRT_ENABLE_ENCRYPTION
  72. // We need to force the Cryspr to be initialized during startup to avoid the
  73. // possibility of multiple threads initialzing the same static data later on.
  74. HaiCryptCryspr_Get_Instance();
  75. #endif
  76. }
  77. bool srt::CCryptoControl::isAESGCMSupported()
  78. {
  79. #ifdef SRT_ENABLE_ENCRYPTION
  80. return HaiCrypt_IsAESGCM_Supported() != 0;
  81. #else
  82. return false;
  83. #endif
  84. }
  85. #if ENABLE_LOGGING
  86. std::string srt::CCryptoControl::FormatKmMessage(std::string hdr, int cmd, size_t srtlen)
  87. {
  88. std::ostringstream os;
  89. os << hdr << ": cmd=" << cmd << "(" << (cmd == SRT_CMD_KMREQ ? "KMREQ":"KMRSP") <<") len="
  90. << size_t(srtlen*sizeof(int32_t)) << " KmState: SND="
  91. << KmStateStr(m_SndKmState)
  92. << " RCV=" << KmStateStr(m_RcvKmState);
  93. return os.str();
  94. }
  95. #endif
  96. void srt::CCryptoControl::updateKmState(int cmd, size_t srtlen SRT_ATR_UNUSED)
  97. {
  98. if (cmd == SRT_CMD_KMREQ)
  99. {
  100. if ( SRT_KM_S_UNSECURED == m_SndKmState)
  101. {
  102. m_SndKmState = SRT_KM_S_SECURING;
  103. }
  104. LOGP(cnlog.Note, FormatKmMessage("sendSrtMsg", cmd, srtlen));
  105. }
  106. else
  107. {
  108. LOGP(cnlog.Note, FormatKmMessage("sendSrtMsg", cmd, srtlen));
  109. }
  110. }
  111. void srt::CCryptoControl::createFakeSndContext()
  112. {
  113. if (!m_iSndKmKeyLen)
  114. m_iSndKmKeyLen = 16;
  115. if (!createCryptoCtx((m_hSndCrypto), m_iSndKmKeyLen, HAICRYPT_CRYPTO_DIR_TX, false))
  116. {
  117. HLOGC(cnlog.Debug, log << "Error: Can't create fake crypto context for sending - sending will return ERROR!");
  118. m_hSndCrypto = 0;
  119. }
  120. }
  121. int srt::CCryptoControl::processSrtMsg_KMREQ(
  122. const uint32_t* srtdata SRT_ATR_UNUSED,
  123. size_t bytelen SRT_ATR_UNUSED,
  124. int hsv SRT_ATR_UNUSED,
  125. uint32_t pw_srtdata_out[], size_t& w_srtlen)
  126. {
  127. //Receiver
  128. /* All 32-bit msg fields swapped on reception
  129. * But HaiCrypt expect network order message
  130. * Re-swap to cancel it.
  131. */
  132. #ifdef SRT_ENABLE_ENCRYPTION
  133. w_srtlen = bytelen/sizeof(srtdata[SRT_KMR_KMSTATE]);
  134. HtoNLA((pw_srtdata_out), srtdata, w_srtlen);
  135. unsigned char* kmdata = reinterpret_cast<unsigned char*>(pw_srtdata_out);
  136. // The side that has received KMREQ is always an HSD_RESPONDER, regardless of
  137. // what has called this function. The HSv5 handshake only enforces bidirectional
  138. // connection.
  139. const bool bidirectional = hsv > CUDT::HS_VERSION_UDT4;
  140. // Local macro to return rejection appropriately.
  141. // CHANGED. The first version made HSv5 reject the connection.
  142. // This isn't well handled by applications, so the connection is
  143. // still established, but unable to handle any transport.
  144. //#define KMREQ_RESULT_REJECTION() if (bidirectional) { return SRT_CMD_NONE; } else { w_srtlen = 1; goto HSv4_ErrorReport; }
  145. #define KMREQ_RESULT_REJECTION() { w_srtlen = 1; goto HSv4_ErrorReport; }
  146. int rc = HAICRYPT_OK; // needed before 'goto' run from KMREQ_RESULT_REJECTION macro
  147. bool wasb4 SRT_ATR_UNUSED = false;
  148. size_t sek_len = 0;
  149. const bool bUseGCM =
  150. (m_iCryptoMode == CSrtConfig::CIPHER_MODE_AUTO && kmdata[HCRYPT_MSG_KM_OFS_CIPHER] == HCRYPT_CIPHER_AES_GCM) ||
  151. (m_iCryptoMode == CSrtConfig::CIPHER_MODE_AES_GCM);
  152. // What we have to do:
  153. // If encryption is on (we know that by having m_KmSecret nonempty), create
  154. // the crypto context (if bidirectional, create for both sending and receiving).
  155. // Both crypto contexts should be set with the same length of the key.
  156. // The problem with interpretinting this should be reported as SRT_CMD_NONE,
  157. // should be appropriately handled by the caller, as it expects that this
  158. // function normally return SRT_CMD_KMRSP.
  159. if ( bytelen <= HCRYPT_MSG_KM_OFS_SALT ) //Sanity on message
  160. {
  161. LOGC(cnlog.Error, log << "processSrtMsg_KMREQ: size of the KM (" << bytelen << ") is too small, must be >" << HCRYPT_MSG_KM_OFS_SALT);
  162. m_RcvKmState = SRT_KM_S_BADSECRET;
  163. KMREQ_RESULT_REJECTION();
  164. }
  165. HLOGC(cnlog.Debug, log << "KMREQ: getting SEK and creating receiver crypto");
  166. sek_len = hcryptMsg_KM_GetSekLen(kmdata);
  167. if ( sek_len == 0 )
  168. {
  169. LOGC(cnlog.Error, log << "processSrtMsg_KMREQ: Received SEK is empty - REJECTING!");
  170. m_RcvKmState = SRT_KM_S_BADSECRET;
  171. KMREQ_RESULT_REJECTION();
  172. }
  173. // Write the key length
  174. m_iRcvKmKeyLen = sek_len;
  175. // Overwrite the key length anyway - it doesn't make sense to somehow
  176. // keep the original setting because it will only make KMX impossible.
  177. #if ENABLE_HEAVY_LOGGING
  178. if (m_iSndKmKeyLen != m_iRcvKmKeyLen)
  179. {
  180. LOGC(cnlog.Debug, log << "processSrtMsg_KMREQ: Agent's PBKEYLEN=" << m_iSndKmKeyLen
  181. << " overwritten by Peer's PBKEYLEN=" << m_iRcvKmKeyLen);
  182. }
  183. #endif
  184. m_iSndKmKeyLen = m_iRcvKmKeyLen;
  185. // This is checked only now so that the SRTO_PBKEYLEN return always the correct value,
  186. // even if encryption is not possible because Agent didn't set a password, or supplied
  187. // a wrong password.
  188. if (m_KmSecret.len == 0) //We have a shared secret <==> encryption is on
  189. {
  190. LOGC(cnlog.Warn, log << "processSrtMsg_KMREQ: Agent does not declare encryption - won't decrypt incoming packets!");
  191. m_RcvKmState = SRT_KM_S_NOSECRET;
  192. KMREQ_RESULT_REJECTION();
  193. }
  194. wasb4 = m_hRcvCrypto;
  195. if (!createCryptoCtx((m_hRcvCrypto), m_iRcvKmKeyLen, HAICRYPT_CRYPTO_DIR_RX, bUseGCM))
  196. {
  197. LOGC(cnlog.Error, log << "processSrtMsg_KMREQ: Can't create RCV CRYPTO CTX - must reject...");
  198. m_RcvKmState = SRT_KM_S_NOSECRET;
  199. KMREQ_RESULT_REJECTION();
  200. }
  201. // Deduce resulting mode.
  202. m_iCryptoMode = bUseGCM ? CSrtConfig::CIPHER_MODE_AES_GCM : CSrtConfig::CIPHER_MODE_AES_CTR;
  203. if (!wasb4)
  204. {
  205. HLOGC(cnlog.Debug, log << "processSrtMsg_KMREQ: created RX ENC with KeyLen=" << m_iRcvKmKeyLen);
  206. }
  207. // We have both sides set with password, so both are pending for security
  208. m_RcvKmState = SRT_KM_S_SECURING;
  209. // m_SndKmState is set to SECURING or UNSECURED in init(),
  210. // or it might have been set to SECURED, NOSECRET or BADSECRET in the previous
  211. // handshake iteration (handshakes may be sent multiple times for the same connection).
  212. rc = HaiCrypt_Rx_Process(m_hRcvCrypto, kmdata, bytelen, NULL, NULL, 0);
  213. switch(rc >= 0 ? HAICRYPT_OK : rc)
  214. {
  215. case HAICRYPT_OK:
  216. m_RcvKmState = SRT_KM_S_SECURED;
  217. HLOGC(cnlog.Debug, log << "KMREQ/rcv: (snd) Rx process successful - SECURED.");
  218. //Send back the whole message to confirm
  219. break;
  220. case HAICRYPT_ERROR_WRONG_SECRET: //Unmatched shared secret to decrypt wrapped key
  221. m_RcvKmState = m_SndKmState = SRT_KM_S_BADSECRET;
  222. //Send status KMRSP message to tel error
  223. w_srtlen = 1;
  224. LOGC(cnlog.Warn, log << "KMREQ/rcv: (snd) Rx process failure - BADSECRET");
  225. break;
  226. case HAICRYPT_ERROR_CIPHER:
  227. #ifdef ENABLE_AEAD_API_PREVIEW
  228. m_RcvKmState = m_SndKmState = SRT_KM_S_BADCRYPTOMODE;
  229. #else
  230. m_RcvKmState = m_SndKmState = SRT_KM_S_BADSECRET; // Use "bad secret" as a fallback.
  231. #endif
  232. w_srtlen = 1;
  233. LOGC(cnlog.Warn, log << "KMREQ/rcv: (snd) Rx process failure - BADCRYPTOMODE");
  234. break;
  235. case HAICRYPT_ERROR: //Other errors
  236. default:
  237. m_RcvKmState = m_SndKmState = SRT_KM_S_NOSECRET;
  238. w_srtlen = 1;
  239. LOGC(cnlog.Warn, log << "KMREQ/rcv: (snd) Rx process failure (IPE) - NOSECRET");
  240. break;
  241. }
  242. LOGP(cnlog.Note, FormatKmMessage("processSrtMsg_KMREQ", SRT_CMD_KMREQ, bytelen));
  243. // Since now, when CCryptoControl::decrypt() encounters an error, it will print it, ONCE,
  244. // until the next KMREQ is received as a key regeneration.
  245. m_bErrorReported = false;
  246. if (w_srtlen == 1)
  247. goto HSv4_ErrorReport;
  248. // Configure the sender context also, if it succeeded to configure the
  249. // receiver context and we are using bidirectional mode.
  250. if (bidirectional)
  251. {
  252. // Note: 'bidirectional' means that we want a bidirectional key update,
  253. // which happens only and exclusively with HSv5 handshake - not when the
  254. // usual key update through UMSG_EXT+SRT_CMD_KMREQ was done (which is used
  255. // in HSv4 versions also to initialize the first key, unlike HSv5).
  256. if (m_RcvKmState == SRT_KM_S_SECURED)
  257. {
  258. if (m_SndKmState == SRT_KM_S_SECURING && !m_hSndCrypto)
  259. {
  260. m_iSndKmKeyLen = m_iRcvKmKeyLen;
  261. if (HaiCrypt_Clone(m_hRcvCrypto, HAICRYPT_CRYPTO_DIR_TX, &m_hSndCrypto) != HAICRYPT_OK)
  262. {
  263. LOGC(cnlog.Error, log << "processSrtMsg_KMREQ: Can't create SND CRYPTO CTX - WILL NOT SEND-ENCRYPT correctly!");
  264. if (hasPassphrase())
  265. m_SndKmState = SRT_KM_S_BADSECRET;
  266. else
  267. m_SndKmState = SRT_KM_S_NOSECRET;
  268. }
  269. else
  270. {
  271. m_SndKmState = SRT_KM_S_SECURED;
  272. }
  273. LOGC(cnlog.Note, log << FormatKmMessage("processSrtMsg_KMREQ", SRT_CMD_KMREQ, bytelen)
  274. << " SndKeyLen=" << m_iSndKmKeyLen
  275. << " TX CRYPTO CTX CLONED FROM RX"
  276. );
  277. // Write the KM message into the field from which it will be next sent.
  278. memcpy((m_SndKmMsg[0].Msg), kmdata, bytelen);
  279. m_SndKmMsg[0].MsgLen = bytelen;
  280. m_SndKmMsg[0].iPeerRetry = 0; // Don't start sending them upon connection :)
  281. }
  282. else
  283. {
  284. HLOGC(cnlog.Debug, log << "processSrtMsg_KMREQ: NOT cloning RX to TX crypto: already in "
  285. << KmStateStr(m_SndKmState) << " state");
  286. }
  287. }
  288. else
  289. {
  290. HLOGP(cnlog.Debug, "processSrtMsg_KMREQ: NOT SECURED - not replaying failed security association to TX CRYPTO CTX");
  291. }
  292. }
  293. else
  294. {
  295. HLOGC(cnlog.Debug, log << "processSrtMsg_KMREQ: NOT REPLAYING the key update to TX CRYPTO CTX.");
  296. }
  297. return SRT_CMD_KMRSP;
  298. HSv4_ErrorReport:
  299. if (bidirectional && hasPassphrase())
  300. {
  301. // If the Forward KMX process has failed, the reverse-KMX process was not done at all.
  302. // This will lead to incorrect object configuration and will fail to properly declare
  303. // the transmission state.
  304. // Create the "fake crypto" with the passphrsae you currently have.
  305. createFakeSndContext();
  306. }
  307. #undef KMREQ_RESULT_REJECTION
  308. #else
  309. // It's ok that this is reported as error because this happens in a scenario,
  310. // when non-encryption-enabled SRT application is contacted by encryption-enabled SRT
  311. // application which tries to make a security association.
  312. LOGC(cnlog.Warn, log << "processSrtMsg_KMREQ: Encryption not enabled at compile time - must reject...");
  313. m_RcvKmState = SRT_KM_S_NOSECRET;
  314. #endif
  315. w_srtlen = 1;
  316. pw_srtdata_out[SRT_KMR_KMSTATE] = m_RcvKmState;
  317. return SRT_CMD_KMRSP;
  318. }
  319. int srt::CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len, int /* XXX unused? hsv*/)
  320. {
  321. /* All 32-bit msg fields (if present) swapped on reception
  322. * But HaiCrypt expect network order message
  323. * Re-swap to cancel it.
  324. */
  325. uint32_t srtd[SRTDATA_MAXSIZE];
  326. size_t srtlen = len/sizeof(uint32_t);
  327. HtoNLA(srtd, srtdata, srtlen);
  328. int retstatus = -1;
  329. // Unused?
  330. //bool bidirectional = hsv > CUDT::HS_VERSION_UDT4;
  331. // Since now, when CCryptoControl::decrypt() encounters an error, it will print it, ONCE,
  332. // until the next KMREQ is received as a key regeneration.
  333. m_bErrorReported = false;
  334. if (srtlen == 1) // Error report. Set accordingly.
  335. {
  336. SRT_KM_STATE peerstate = SRT_KM_STATE(srtd[SRT_KMR_KMSTATE]); /* Bad or no passphrase */
  337. m_SndKmMsg[0].iPeerRetry = 0;
  338. m_SndKmMsg[1].iPeerRetry = 0;
  339. switch (peerstate)
  340. {
  341. case SRT_KM_S_BADSECRET:
  342. m_SndKmState = m_RcvKmState = SRT_KM_S_BADSECRET;
  343. retstatus = -1;
  344. break;
  345. // Default embraces two cases:
  346. // NOSECRET: this KMRSP was sent by secured Peer, but Agent supplied no password.
  347. // UNSECURED: this KMRSP was sent by unsecure Peer because Agent sent KMREQ.
  348. case SRT_KM_S_NOSECRET:
  349. // This means that the peer did not set the password, while Agent did.
  350. m_RcvKmState = SRT_KM_S_UNSECURED;
  351. m_SndKmState = SRT_KM_S_NOSECRET;
  352. retstatus = -1;
  353. break;
  354. case SRT_KM_S_UNSECURED:
  355. // This means that KMRSP was sent without KMREQ, to inform the Agent,
  356. // that the Peer, unlike Agent, does use password. Agent can send then,
  357. // but can't decrypt what Peer would send.
  358. m_RcvKmState = SRT_KM_S_NOSECRET;
  359. m_SndKmState = SRT_KM_S_UNSECURED;
  360. retstatus = 0;
  361. break;
  362. #ifdef ENABLE_AEAD_API_PREVIEW
  363. case SRT_KM_S_BADCRYPTOMODE:
  364. // The peer expects to use a different cryptographic mode (e.g. AES-GCM, not AES-CTR).
  365. m_RcvKmState = SRT_KM_S_BADCRYPTOMODE;
  366. m_SndKmState = SRT_KM_S_BADCRYPTOMODE;
  367. retstatus = -1;
  368. break;
  369. #endif
  370. default:
  371. LOGC(cnlog.Fatal, log << "processSrtMsg_KMRSP: IPE: unknown peer error state: "
  372. << KmStateStr(peerstate) << " (" << int(peerstate) << ")");
  373. m_RcvKmState = SRT_KM_S_NOSECRET;
  374. m_SndKmState = SRT_KM_S_NOSECRET;
  375. retstatus = -1; //This is IPE
  376. break;
  377. }
  378. LOGC(cnlog.Warn, log << "processSrtMsg_KMRSP: received failure report. STATE: " << KmStateStr(m_RcvKmState));
  379. }
  380. else
  381. {
  382. HLOGC(cnlog.Debug, log << "processSrtMsg_KMRSP: received key response len=" << len);
  383. // XXX INSECURE << ": [" << FormatBinaryString((uint8_t*)srtd, len) << "]";
  384. bool key1 = getKmMsg_acceptResponse(0, srtd, len);
  385. bool key2 = true;
  386. if ( !key1 )
  387. key2 = getKmMsg_acceptResponse(1, srtd, len); // <--- NOTE SEQUENCING!
  388. if (key1 || key2)
  389. {
  390. m_SndKmState = m_RcvKmState = SRT_KM_S_SECURED;
  391. HLOGC(cnlog.Debug, log << "processSrtMsg_KMRSP: KM response matches " << (key1 ? "EVEN" : "ODD") << " key");
  392. retstatus = 1;
  393. }
  394. else
  395. {
  396. retstatus = -1;
  397. LOGC(cnlog.Error, log << "processSrtMsg_KMRSP: IPE??? KM response key matches no key");
  398. /* XXX INSECURE
  399. LOGC(cnlog.Error, log << "processSrtMsg_KMRSP: KM response: [" << FormatBinaryString((uint8_t*)srtd, len)
  400. << "] matches no key 0=[" << FormatBinaryString((uint8_t*)m_SndKmMsg[0].Msg, m_SndKmMsg[0].MsgLen)
  401. << "] 1=[" << FormatBinaryString((uint8_t*)m_SndKmMsg[1].Msg, m_SndKmMsg[1].MsgLen) << "]");
  402. */
  403. m_SndKmState = m_RcvKmState = SRT_KM_S_BADSECRET;
  404. }
  405. HLOGC(cnlog.Debug, log << "processSrtMsg_KMRSP: key[0]: len=" << m_SndKmMsg[0].MsgLen << " retry=" << m_SndKmMsg[0].iPeerRetry
  406. << "; key[1]: len=" << m_SndKmMsg[1].MsgLen << " retry=" << m_SndKmMsg[1].iPeerRetry);
  407. }
  408. LOGP(cnlog.Note, FormatKmMessage("processSrtMsg_KMRSP", SRT_CMD_KMRSP, len));
  409. return retstatus;
  410. }
  411. void srt::CCryptoControl::sendKeysToPeer(CUDT* sock SRT_ATR_UNUSED, int iSRTT SRT_ATR_UNUSED)
  412. {
  413. sync::ScopedLock lck(m_mtxLock);
  414. if (!m_hSndCrypto || m_SndKmState == SRT_KM_S_UNSECURED)
  415. {
  416. HLOGC(cnlog.Debug, log << "sendKeysToPeer: NOT sending/regenerating keys: "
  417. << (m_hSndCrypto ? "CONNECTION UNSECURED" : "NO TX CRYPTO CTX created"));
  418. return;
  419. }
  420. #ifdef SRT_ENABLE_ENCRYPTION
  421. srt::sync::steady_clock::time_point now = srt::sync::steady_clock::now();
  422. /*
  423. * Crypto Key Distribution to peer:
  424. * If...
  425. * - we want encryption; and
  426. * - we have not tried more than CSRTCC_MAXRETRY times (peer may not be SRT); and
  427. * - and did not get answer back from peer; and
  428. * - last sent Keying Material req should have been replied (RTT*1.5 elapsed);
  429. * then (re-)send handshake request.
  430. */
  431. if (((m_SndKmMsg[0].iPeerRetry > 0) || (m_SndKmMsg[1].iPeerRetry > 0))
  432. && ((m_SndKmLastTime + srt::sync::microseconds_from((iSRTT * 3)/2)) <= now))
  433. {
  434. for (int ki = 0; ki < 2; ki++)
  435. {
  436. if (m_SndKmMsg[ki].iPeerRetry > 0 && m_SndKmMsg[ki].MsgLen > 0)
  437. {
  438. m_SndKmMsg[ki].iPeerRetry--;
  439. HLOGC(cnlog.Debug, log << "sendKeysToPeer: SENDING ki=" << ki << " len=" << m_SndKmMsg[ki].MsgLen
  440. << " retry(updated)=" << m_SndKmMsg[ki].iPeerRetry);
  441. m_SndKmLastTime = now;
  442. sock->sendSrtMsg(SRT_CMD_KMREQ, (uint32_t *)m_SndKmMsg[ki].Msg, m_SndKmMsg[ki].MsgLen / sizeof(uint32_t));
  443. }
  444. }
  445. }
  446. #endif
  447. }
  448. void srt::CCryptoControl::regenCryptoKm(CUDT* sock SRT_ATR_UNUSED, bool bidirectional SRT_ATR_UNUSED)
  449. {
  450. #ifdef SRT_ENABLE_ENCRYPTION
  451. sync::ScopedLock lck(m_mtxLock);
  452. if (!m_hSndCrypto)
  453. return;
  454. void *out_p[2];
  455. size_t out_len_p[2];
  456. int nbo = HaiCrypt_Tx_ManageKeys(m_hSndCrypto, out_p, out_len_p, 2);
  457. int sent = 0;
  458. HLOGC(cnlog.Debug, log << "regenCryptoKm: regenerating crypto keys nbo=" << nbo <<
  459. " THEN=" << (sock ? "SEND" : "KEEP") << " DIR=" << (bidirectional ? "BOTH" : "SENDER"));
  460. for (int i = 0; i < nbo && i < 2; i++)
  461. {
  462. /*
  463. * New connection keying material
  464. * or regenerated after crypto_cfg.km_refresh_rate_pkt packets .
  465. * Send to peer
  466. */
  467. // XXX Need to make it clearer and less hardcoded values
  468. int kix = hcryptMsg_KM_GetKeyIndex((unsigned char *)(out_p[i]));
  469. int ki = kix & 0x1;
  470. if ((out_len_p[i] != m_SndKmMsg[ki].MsgLen)
  471. || (0 != memcmp(out_p[i], m_SndKmMsg[ki].Msg, m_SndKmMsg[ki].MsgLen)))
  472. {
  473. uint8_t* oldkey SRT_ATR_UNUSED = m_SndKmMsg[ki].Msg;
  474. HLOGC(cnlog.Debug, log << "new key[" << ki << "] index=" << kix
  475. << " OLD=[" << m_SndKmMsg[ki].MsgLen << "]"
  476. << FormatBinaryString(m_SndKmMsg[ki].Msg, m_SndKmMsg[ki].MsgLen)
  477. << " NEW=[" << out_len_p[i] << "]"
  478. << FormatBinaryString((const uint8_t*)out_p[i], out_len_p[i]));
  479. /* New Keying material, send to peer */
  480. memcpy((m_SndKmMsg[ki].Msg), out_p[i], out_len_p[i]);
  481. m_SndKmMsg[ki].MsgLen = out_len_p[i];
  482. m_SndKmMsg[ki].iPeerRetry = SRT_MAX_KMRETRY;
  483. if (bidirectional && !sock)
  484. {
  485. // "Send" this key also to myself, just to be applied to the receiver crypto,
  486. // exactly the same way how this key is interpreted on the peer side into its receiver crypto
  487. int rc = HaiCrypt_Rx_Process(m_hRcvCrypto, m_SndKmMsg[ki].Msg, m_SndKmMsg[ki].MsgLen, NULL, NULL, 0);
  488. if ( rc < 0 )
  489. {
  490. LOGC(cnlog.Fatal, log << "regenCryptoKm: IPE: applying key generated in snd crypto into rcv crypto: failed code=" << rc);
  491. // The party won't be able to decrypt incoming data!
  492. // Not sure if anything has to be reported.
  493. }
  494. }
  495. if (sock)
  496. {
  497. HLOGC(cnlog.Debug, log << "regenCryptoKm: SENDING ki=" << ki << " len=" << m_SndKmMsg[ki].MsgLen
  498. << " retry(updated)=" << m_SndKmMsg[ki].iPeerRetry);
  499. sock->sendSrtMsg(SRT_CMD_KMREQ, (uint32_t *)m_SndKmMsg[ki].Msg, m_SndKmMsg[ki].MsgLen / sizeof(uint32_t));
  500. sent++;
  501. }
  502. }
  503. else if (out_len_p[i] == 0)
  504. {
  505. HLOGC(cnlog.Debug, log << "no key[" << ki << "] index=" << kix << ": not generated");
  506. }
  507. else
  508. {
  509. HLOGC(cnlog.Debug, log << "no key[" << ki << "] index=" << kix << ": key unchanged");
  510. }
  511. }
  512. HLOGC(cnlog.Debug, log << "regenCryptoKm: key[0]: len=" << m_SndKmMsg[0].MsgLen << " retry=" << m_SndKmMsg[0].iPeerRetry
  513. << "; key[1]: len=" << m_SndKmMsg[1].MsgLen << " retry=" << m_SndKmMsg[1].iPeerRetry);
  514. if (sent)
  515. m_SndKmLastTime = srt::sync::steady_clock::now();
  516. #endif
  517. }
  518. srt::CCryptoControl::CCryptoControl(SRTSOCKET id)
  519. : m_SocketID(id)
  520. , m_iSndKmKeyLen(0)
  521. , m_iRcvKmKeyLen(0)
  522. , m_SndKmState(SRT_KM_S_UNSECURED)
  523. , m_RcvKmState(SRT_KM_S_UNSECURED)
  524. , m_KmRefreshRatePkt(0)
  525. , m_KmPreAnnouncePkt(0)
  526. , m_iCryptoMode(CSrtConfig::CIPHER_MODE_AUTO)
  527. , m_bErrorReported(false)
  528. {
  529. m_KmSecret.len = 0;
  530. //send
  531. m_SndKmMsg[0].MsgLen = 0;
  532. m_SndKmMsg[0].iPeerRetry = 0;
  533. m_SndKmMsg[1].MsgLen = 0;
  534. m_SndKmMsg[1].iPeerRetry = 0;
  535. m_hSndCrypto = NULL;
  536. //recv
  537. m_hRcvCrypto = NULL;
  538. }
  539. bool srt::CCryptoControl::init(HandshakeSide side, const CSrtConfig& cfg, bool bidirectional SRT_ATR_UNUSED)
  540. {
  541. // NOTE: initiator creates m_hSndCrypto. When bidirectional,
  542. // it creates also m_hRcvCrypto with the same key length.
  543. // Acceptor creates nothing - it will create appropriate
  544. // contexts when receiving KMREQ from the initiator.
  545. HLOGC(cnlog.Debug, log << "CCryptoControl::init: HS SIDE:"
  546. << (side == HSD_INITIATOR ? "INITIATOR" : "RESPONDER")
  547. << " DIRECTION:" << (bidirectional ? "BOTH" : (side == HSD_INITIATOR) ? "SENDER" : "RECEIVER"));
  548. // Set UNSECURED state as default
  549. m_RcvKmState = SRT_KM_S_UNSECURED;
  550. m_iCryptoMode = cfg.iCryptoMode;
  551. #ifdef SRT_ENABLE_ENCRYPTION
  552. if (!cfg.bTSBPD && m_iCryptoMode == CSrtConfig::CIPHER_MODE_AUTO)
  553. m_iCryptoMode = CSrtConfig::CIPHER_MODE_AES_CTR;
  554. const bool bUseGCM = m_iCryptoMode == CSrtConfig::CIPHER_MODE_AES_GCM;
  555. if (bUseGCM && !isAESGCMSupported())
  556. {
  557. LOGC(cnlog.Warn, log << "CCryptoControl: AES GCM is not supported by the crypto service provider.");
  558. return false;
  559. }
  560. #endif
  561. // Set security-pending state, if a password was set.
  562. m_SndKmState = hasPassphrase() ? SRT_KM_S_SECURING : SRT_KM_S_UNSECURED;
  563. m_KmPreAnnouncePkt = cfg.uKmPreAnnouncePkt;
  564. m_KmRefreshRatePkt = cfg.uKmRefreshRatePkt;
  565. if (side == HSD_INITIATOR)
  566. {
  567. if (hasPassphrase())
  568. {
  569. #ifdef SRT_ENABLE_ENCRYPTION
  570. if (m_iSndKmKeyLen == 0)
  571. {
  572. HLOGC(cnlog.Debug, log << "CCryptoControl::init: PBKEYLEN still 0, setting default 16");
  573. m_iSndKmKeyLen = 16;
  574. }
  575. bool ok = createCryptoCtx((m_hSndCrypto), m_iSndKmKeyLen, HAICRYPT_CRYPTO_DIR_TX, bUseGCM);
  576. HLOGC(cnlog.Debug, log << "CCryptoControl::init: creating SND crypto context: " << ok);
  577. if (ok && bidirectional)
  578. {
  579. m_iRcvKmKeyLen = m_iSndKmKeyLen;
  580. const int st = HaiCrypt_Clone(m_hSndCrypto, HAICRYPT_CRYPTO_DIR_RX, &m_hRcvCrypto);
  581. HLOGC(cnlog.Debug, log << "CCryptoControl::init: creating CLONED RCV crypto context: status=" << st);
  582. ok = st == 0;
  583. }
  584. // Note: this is sanity check, it should never happen.
  585. if (!ok)
  586. {
  587. m_SndKmState = SRT_KM_S_NOSECRET; // wanted to secure, but error occurred.
  588. if (bidirectional)
  589. m_RcvKmState = SRT_KM_S_NOSECRET;
  590. return false;
  591. }
  592. regenCryptoKm(
  593. NULL, // Do not send the key (the KM msg will be attached to the HSv5 handshake)
  594. bidirectional // replicate the key to the receiver context, if bidirectional
  595. );
  596. m_iCryptoMode = bUseGCM ? CSrtConfig::CIPHER_MODE_AES_GCM : CSrtConfig::CIPHER_MODE_AES_CTR;
  597. #else
  598. // This error would be a consequence of setting the passphrase, while encryption
  599. // is turned off at compile time. Setting the password itself should be not allowed
  600. // so this could only happen as a consequence of an IPE.
  601. LOGC(cnlog.Error, log << "CCryptoControl::init: IPE: encryption not supported");
  602. return false;
  603. #endif
  604. }
  605. else
  606. {
  607. HLOGC(cnlog.Debug, log << "CCryptoControl::init: CAN'T CREATE crypto: key length for SND = " << m_iSndKmKeyLen);
  608. }
  609. }
  610. else
  611. {
  612. HLOGC(cnlog.Debug, log << "CCryptoControl::init: NOT creating crypto contexts - will be created upon reception of KMREQ");
  613. }
  614. return true;
  615. }
  616. void srt::CCryptoControl::close()
  617. {
  618. /* Wipeout secrets */
  619. sync::ScopedLock lck(m_mtxLock);
  620. memset(&m_KmSecret, 0, sizeof(m_KmSecret));
  621. }
  622. std::string srt::CCryptoControl::CONID() const
  623. {
  624. if (m_SocketID == 0)
  625. return "";
  626. std::ostringstream os;
  627. os << "@" << m_SocketID << ":";
  628. return os.str();
  629. }
  630. #ifdef SRT_ENABLE_ENCRYPTION
  631. #if ENABLE_HEAVY_LOGGING
  632. namespace srt {
  633. static std::string CryptoFlags(int flg)
  634. {
  635. using namespace std;
  636. vector<string> f;
  637. if (flg & HAICRYPT_CFG_F_CRYPTO)
  638. f.push_back("crypto");
  639. if (flg & HAICRYPT_CFG_F_TX)
  640. f.push_back("TX");
  641. if (flg & HAICRYPT_CFG_F_FEC)
  642. f.push_back("fec");
  643. ostringstream os;
  644. copy(f.begin(), f.end(), ostream_iterator<string>(os, "|"));
  645. return os.str();
  646. }
  647. } // namespace srt
  648. #endif // ENABLE_HEAVY_LOGGING
  649. bool srt::CCryptoControl::createCryptoCtx(HaiCrypt_Handle& w_hCrypto, size_t keylen, HaiCrypt_CryptoDir cdir, bool bAESGCM)
  650. {
  651. if (w_hCrypto)
  652. {
  653. // XXX You can check here if the existing handle represents
  654. // a correctly defined crypto. But this doesn't seem to be
  655. // necessary - the whole CCryptoControl facility seems to be valid only
  656. // within the frames of one connection.
  657. return true;
  658. }
  659. if ((m_KmSecret.len <= 0) || (keylen <= 0))
  660. {
  661. LOGC(cnlog.Error, log << CONID() << "cryptoCtx: IPE missing secret (" << m_KmSecret.len << ") or key length (" << keylen << ")");
  662. return false;
  663. }
  664. HaiCrypt_Cfg crypto_cfg;
  665. memset(&crypto_cfg, 0, sizeof(crypto_cfg));
  666. #if 0//test key refresh (fast rate)
  667. m_KmRefreshRatePkt = 2000;
  668. m_KmPreAnnouncePkt = 500;
  669. #endif
  670. crypto_cfg.flags = HAICRYPT_CFG_F_CRYPTO | (cdir == HAICRYPT_CRYPTO_DIR_TX ? HAICRYPT_CFG_F_TX : 0) | (bAESGCM ? HAICRYPT_CFG_F_GCM : 0);
  671. crypto_cfg.xport = HAICRYPT_XPT_SRT;
  672. crypto_cfg.cryspr = HaiCryptCryspr_Get_Instance();
  673. crypto_cfg.key_len = (size_t)keylen;
  674. crypto_cfg.data_max_len = HAICRYPT_DEF_DATA_MAX_LENGTH; //MTU
  675. crypto_cfg.km_tx_period_ms = 0;//No HaiCrypt KM inject period, handled in SRT;
  676. crypto_cfg.km_refresh_rate_pkt = m_KmRefreshRatePkt == 0 ? HAICRYPT_DEF_KM_REFRESH_RATE : m_KmRefreshRatePkt;
  677. crypto_cfg.km_pre_announce_pkt = m_KmPreAnnouncePkt == 0 ? SRT_CRYPT_KM_PRE_ANNOUNCE : m_KmPreAnnouncePkt;
  678. crypto_cfg.secret = m_KmSecret;
  679. HLOGC(cnlog.Debug, log << "CRYPTO CFG: flags=" << CryptoFlags(crypto_cfg.flags) << " xport=" << crypto_cfg.xport << " cryspr=" << crypto_cfg.cryspr
  680. << " keylen=" << crypto_cfg.key_len << " passphrase_length=" << crypto_cfg.secret.len);
  681. if (HaiCrypt_Create(&crypto_cfg, (&w_hCrypto)) != HAICRYPT_OK)
  682. {
  683. LOGC(cnlog.Error, log << CONID() << "cryptoCtx: could not create " << (cdir == HAICRYPT_CRYPTO_DIR_TX ? "tx" : "rx") << " crypto ctx");
  684. return false;
  685. }
  686. HLOGC(cnlog.Debug, log << CONID() << "cryptoCtx: CREATED crypto for dir=" << (cdir == HAICRYPT_CRYPTO_DIR_TX ? "tx" : "rx") << " keylen=" << keylen);
  687. return true;
  688. }
  689. #else
  690. bool srt::CCryptoControl::createCryptoCtx(HaiCrypt_Handle&, size_t, HaiCrypt_CryptoDir, bool)
  691. {
  692. return false;
  693. }
  694. #endif // SRT_ENABLE_ENCRYPTION
  695. srt::EncryptionStatus srt::CCryptoControl::encrypt(CPacket& w_packet SRT_ATR_UNUSED)
  696. {
  697. #ifdef SRT_ENABLE_ENCRYPTION
  698. // Encryption not enabled - do nothing.
  699. if ( getSndCryptoFlags() == EK_NOENC )
  700. return ENCS_CLEAR;
  701. // Note that in case of GCM the header has to zero Retransmitted Packet Flag (R).
  702. // If TSBPD is disabled, timestamp also has to be zeroed.
  703. int rc = HaiCrypt_Tx_Data(m_hSndCrypto, ((uint8_t*)w_packet.getHeader()), ((uint8_t*)w_packet.m_pcData), w_packet.getLength());
  704. if (rc < 0)
  705. {
  706. return ENCS_FAILED;
  707. }
  708. else if ( rc > 0 )
  709. {
  710. // XXX what happens if the encryption is said to be "succeeded",
  711. // but the length is 0? Shouldn't this be treated as unwanted?
  712. w_packet.setLength(rc);
  713. }
  714. return ENCS_CLEAR;
  715. #else
  716. return ENCS_NOTSUP;
  717. #endif
  718. }
  719. srt::EncryptionStatus srt::CCryptoControl::decrypt(CPacket& w_packet SRT_ATR_UNUSED)
  720. {
  721. #ifdef SRT_ENABLE_ENCRYPTION
  722. if (w_packet.getMsgCryptoFlags() == EK_NOENC)
  723. {
  724. HLOGC(cnlog.Debug, log << "CPacket::decrypt: packet not encrypted");
  725. return ENCS_CLEAR; // not encrypted, no need do decrypt, no flags to be modified
  726. }
  727. if (m_RcvKmState == SRT_KM_S_UNSECURED)
  728. {
  729. if (m_KmSecret.len != 0)
  730. {
  731. // We were unaware that the peer has set password,
  732. // but now here we are.
  733. m_RcvKmState = SRT_KM_S_SECURING;
  734. LOGC(cnlog.Note, log << "SECURITY UPDATE: Peer has surprised Agent with encryption, but KMX is pending - current packet size="
  735. << w_packet.getLength() << " dropped");
  736. return ENCS_FAILED;
  737. }
  738. else
  739. {
  740. // Peer has set a password, but Agent did not,
  741. // which means that it will be unable to decrypt
  742. // sent payloads anyway.
  743. m_RcvKmState = SRT_KM_S_NOSECRET;
  744. LOGP(cnlog.Warn, "SECURITY FAILURE: Agent has no PW, but Peer sender has declared one, can't decrypt");
  745. // This only informs about the state change; it will be also caught by the condition below
  746. }
  747. }
  748. if (m_RcvKmState != SRT_KM_S_SECURED)
  749. {
  750. // If not "secured", it means that it won't be able to decrypt packets,
  751. // so there's no point to even try to send them to HaiCrypt_Rx_Data.
  752. // Actually the current conditions concerning m_hRcvCrypto are such that this object
  753. // is cretaed in case of SRT_KM_S_BADSECRET, so it will simply fail to decrypt,
  754. // but with SRT_KM_S_NOSECRET m_hRcvCrypto is not even created (is NULL), which
  755. // will then cause an error to be reported, misleadingly. Simply don't try to
  756. // decrypt anything as long as you are not sure that the connection is secured.
  757. // This problem will occur every time a packet comes in, it's worth reporting,
  758. // but not with every single packet arriving. Print it once and turn off the flag;
  759. // it will be restored at the next attempt of KMX.
  760. if (!m_bErrorReported)
  761. {
  762. m_bErrorReported = true;
  763. LOGC(cnlog.Error, log << "SECURITY STATUS: " << KmStateStr(m_RcvKmState) << " - can't decrypt w_packet.");
  764. }
  765. HLOGC(cnlog.Debug, log << "Packet still not decrypted, status=" << KmStateStr(m_RcvKmState)
  766. << " - dropping size=" << w_packet.getLength());
  767. return ENCS_FAILED;
  768. }
  769. const int rc = HaiCrypt_Rx_Data(m_hRcvCrypto, ((uint8_t *)w_packet.getHeader()), ((uint8_t *)w_packet.m_pcData), w_packet.getLength());
  770. if (rc <= 0)
  771. {
  772. LOGC(cnlog.Note, log << "decrypt ERROR: HaiCrypt_Rx_Data failure=" << rc << " - returning failed decryption");
  773. // -1: decryption failure
  774. // 0: key not received yet
  775. return ENCS_FAILED;
  776. }
  777. // Otherwise: rc == decrypted text length.
  778. w_packet.setLength(rc); /* In case clr txt size is different from cipher txt */
  779. // Decryption succeeded. Update flags.
  780. w_packet.setMsgCryptoFlags(EK_NOENC);
  781. HLOGC(cnlog.Debug, log << "decrypt: successfully decrypted, resulting length=" << rc);
  782. return ENCS_CLEAR;
  783. #else
  784. return ENCS_NOTSUP;
  785. #endif
  786. }
  787. srt::CCryptoControl::~CCryptoControl()
  788. {
  789. #ifdef SRT_ENABLE_ENCRYPTION
  790. close();
  791. if (m_hSndCrypto)
  792. {
  793. HaiCrypt_Close(m_hSndCrypto);
  794. }
  795. if (m_hRcvCrypto)
  796. {
  797. HaiCrypt_Close(m_hRcvCrypto);
  798. }
  799. #endif
  800. }