crypto.h 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  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. #ifndef INC_SRT_CRYPTO_H
  15. #define INC_SRT_CRYPTO_H
  16. #include <cstring>
  17. #include <string>
  18. // UDT
  19. #include "udt.h"
  20. #include "packet.h"
  21. #include "utilities.h"
  22. #include "logging.h"
  23. #include <haicrypt.h>
  24. #include <hcrypt_msg.h>
  25. namespace srt_logging
  26. {
  27. std::string KmStateStr(SRT_KM_STATE state);
  28. #if ENABLE_LOGGING
  29. extern Logger cnlog;
  30. #endif
  31. }
  32. namespace srt
  33. {
  34. class CUDT;
  35. struct CSrtConfig;
  36. // For KMREQ/KMRSP. Only one field is used.
  37. const size_t SRT_KMR_KMSTATE = 0;
  38. #define SRT_CMD_MAXSZ HCRYPT_MSG_KM_MAX_SZ /* Maximum SRT custom messages payload size (bytes) */
  39. const size_t SRTDATA_MAXSIZE = SRT_CMD_MAXSZ/sizeof(uint32_t);
  40. class CCryptoControl
  41. {
  42. SRTSOCKET m_SocketID;
  43. size_t m_iSndKmKeyLen; //Key length
  44. size_t m_iRcvKmKeyLen; //Key length from rx KM
  45. // Temporarily allow these to be accessed.
  46. public:
  47. SRT_KM_STATE m_SndKmState; //Sender Km State (imposed by agent)
  48. SRT_KM_STATE m_RcvKmState; //Receiver Km State (informed by peer)
  49. private:
  50. // Partial haicrypt configuration, consider
  51. // putting the whole HaiCrypt_Cfg object here.
  52. int m_KmRefreshRatePkt;
  53. int m_KmPreAnnouncePkt;
  54. int m_iCryptoMode;
  55. HaiCrypt_Secret m_KmSecret; //Key material shared secret
  56. // Sender
  57. sync::steady_clock::time_point m_SndKmLastTime;
  58. sync::Mutex m_mtxLock; // A mutex to protect concurrent access to CCryptoControl.
  59. struct {
  60. unsigned char Msg[HCRYPT_MSG_KM_MAX_SZ];
  61. size_t MsgLen;
  62. int iPeerRetry;
  63. } m_SndKmMsg[2];
  64. HaiCrypt_Handle m_hSndCrypto;
  65. // Receiver
  66. HaiCrypt_Handle m_hRcvCrypto;
  67. bool m_bErrorReported;
  68. public:
  69. static void globalInit();
  70. static bool isAESGCMSupported();
  71. bool sendingAllowed()
  72. {
  73. // This function is called to state as to whether the
  74. // crypter allows the packet to be sent over the link.
  75. // This is possible in two cases:
  76. // - when Agent didn't set a password, no matter the crypto state
  77. if (m_KmSecret.len == 0)
  78. return true;
  79. // - when Agent did set a password and the crypto state is SECURED.
  80. if (m_KmSecret.len > 0 && m_SndKmState == SRT_KM_S_SECURED
  81. // && m_iRcvPeerKmState == SRT_KM_S_SECURED ?
  82. )
  83. return true;
  84. return false;
  85. }
  86. bool hasPassphrase() const
  87. {
  88. return m_KmSecret.len > 0;
  89. }
  90. int getCryptoMode() const
  91. {
  92. return m_iCryptoMode;
  93. }
  94. /// Regenerate cryptographic key material if needed.
  95. /// @param[in] sock If not null, the socket will be used to send the KM message to the peer (e.g. KM refresh).
  96. /// @param[in] bidirectional If true, the key material will be regenerated for both directions (receiver and sender).
  97. SRT_ATTR_EXCLUDES(m_mtxLock)
  98. void regenCryptoKm(CUDT* sock, bool bidirectional);
  99. size_t KeyLen() { return m_iSndKmKeyLen; }
  100. // Needed for CUDT
  101. void updateKmState(int cmd, size_t srtlen);
  102. // Detailed processing
  103. int processSrtMsg_KMREQ(const uint32_t* srtdata, size_t len, int hsv,
  104. uint32_t srtdata_out[], size_t&);
  105. // This returns:
  106. // 1 - the given payload is the same as the currently used key
  107. // 0 - there's no key in agent or the payload is error message with agent NOSECRET.
  108. // -1 - the payload is error message with other state or it doesn't match the key
  109. int processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len, int hsv);
  110. void createFakeSndContext();
  111. const unsigned char* getKmMsg_data(size_t ki) const { return m_SndKmMsg[ki].Msg; }
  112. size_t getKmMsg_size(size_t ki) const { return m_SndKmMsg[ki].MsgLen; }
  113. /// Check if the key stored at @c ki shall be sent. When during the handshake,
  114. /// it only matters if the KM message for that index is recorded at all.
  115. /// Otherwise returns true only if also the retry counter didn't expire.
  116. ///
  117. /// @param ki Key index (0 or 1)
  118. /// @param runtime True, if this happens as a key update
  119. /// during transmission (otherwise it's during the handshake)
  120. /// @return Whether the KM message at given index needs to be sent.
  121. bool getKmMsg_needSend(size_t ki, bool runtime) const
  122. {
  123. if (runtime)
  124. return (m_SndKmMsg[ki].iPeerRetry > 0 && m_SndKmMsg[ki].MsgLen > 0);
  125. else
  126. return m_SndKmMsg[ki].MsgLen > 0;
  127. }
  128. /// Mark the key as already sent. When no 'runtime' (during the handshake)
  129. /// it actually does nothing so that this will be retried as long as the handshake
  130. /// itself is being retried. Otherwise this is during transmission and will expire
  131. /// after several retries.
  132. ///
  133. /// @param ki Key index (0 or 1)
  134. /// @param runtime True, if this happens as a key update
  135. /// during transmission (otherwise it's during the handshake)
  136. void getKmMsg_markSent(size_t ki, bool runtime)
  137. {
  138. #if ENABLE_LOGGING
  139. using srt_logging::cnlog;
  140. #endif
  141. m_SndKmLastTime = sync::steady_clock::now();
  142. if (runtime)
  143. {
  144. m_SndKmMsg[ki].iPeerRetry--;
  145. HLOGC(cnlog.Debug, log << "getKmMsg_markSent: key[" << ki << "]: len=" << m_SndKmMsg[ki].MsgLen << " retry=" << m_SndKmMsg[ki].iPeerRetry);
  146. }
  147. else
  148. {
  149. HLOGC(cnlog.Debug, log << "getKmMsg_markSent: key[" << ki << "]: len=" << m_SndKmMsg[ki].MsgLen << " STILL IN USE.");
  150. }
  151. }
  152. /// Check if the response returned by KMRSP matches the recorded KM message.
  153. /// When it is, set also the retry counter to 0 to prevent further retries.
  154. ///
  155. /// @param ki KM message index (0 or 1)
  156. /// @param srtmsg Message received through KMRSP
  157. /// @param bytesize Size of the message
  158. /// @return True if the message is identical to the recorded KM message at given index.
  159. bool getKmMsg_acceptResponse(size_t ki, const uint32_t* srtmsg, size_t bytesize)
  160. {
  161. if ( m_SndKmMsg[ki].MsgLen == bytesize
  162. && 0 == memcmp(m_SndKmMsg[ki].Msg, srtmsg, m_SndKmMsg[ki].MsgLen))
  163. {
  164. m_SndKmMsg[ki].iPeerRetry = 0;
  165. return true;
  166. }
  167. return false;
  168. }
  169. CCryptoControl(SRTSOCKET id);
  170. // DEBUG PURPOSES:
  171. std::string CONID() const;
  172. std::string FormatKmMessage(std::string hdr, int cmd, size_t srtlen);
  173. bool init(HandshakeSide, const CSrtConfig&, bool);
  174. SRT_ATTR_EXCLUDES(m_mtxLock)
  175. void close();
  176. /// (Re)send KM request to a peer on timeout.
  177. /// This function is used in:
  178. /// - HSv4 (initial key material exchange - in HSv5 it's attached to handshake).
  179. /// - The case of key regeneration (KM refresh), when a new key has to be sent again.
  180. /// In this case the first sending happens in regenCryptoKm(..). This function
  181. /// retransmits the KM request by timeout if not KM response has been received.
  182. SRT_ATTR_EXCLUDES(m_mtxLock)
  183. void sendKeysToPeer(CUDT* sock, int iSRTT);
  184. void setCryptoSecret(const HaiCrypt_Secret& secret)
  185. {
  186. m_KmSecret = secret;
  187. }
  188. void setCryptoKeylen(size_t keylen)
  189. {
  190. m_iSndKmKeyLen = keylen;
  191. m_iRcvKmKeyLen = keylen;
  192. }
  193. bool createCryptoCtx(HaiCrypt_Handle& rh, size_t keylen, HaiCrypt_CryptoDir tx, bool bAESGCM);
  194. int getSndCryptoFlags() const
  195. {
  196. #ifdef SRT_ENABLE_ENCRYPTION
  197. return(m_hSndCrypto ?
  198. HaiCrypt_Tx_GetKeyFlags(m_hSndCrypto) :
  199. // When encryption isn't on, check if it was required
  200. // If it was, return -1 as flags, which means that
  201. // encryption was requested and not possible.
  202. hasPassphrase() ? -1 :
  203. 0);
  204. #else
  205. return 0;
  206. #endif
  207. }
  208. bool isSndEncryptionOK() const
  209. {
  210. // Similar to this above, just quickly check if the encryption
  211. // is required and possible, or not possible
  212. if (!hasPassphrase())
  213. return true; // no encryption required
  214. if (m_hSndCrypto)
  215. return true; // encryption is required and possible
  216. return false;
  217. }
  218. /// Encrypts the packet. If encryption is not turned on, it
  219. /// does nothing. If the encryption is not correctly configured,
  220. /// the encryption will fail.
  221. /// XXX Encryption flags in the PH_MSGNO
  222. /// field in the header must be correctly set before calling.
  223. EncryptionStatus encrypt(CPacket& w_packet);
  224. /// Decrypts the packet. If the packet has ENCKEYSPEC part
  225. /// in PH_MSGNO set to EK_NOENC, it does nothing. It decrypts
  226. /// only if the encryption correctly configured, otherwise it
  227. /// fails. After successful decryption, the ENCKEYSPEC part
  228. // in PH_MSGNO is set to EK_NOENC.
  229. EncryptionStatus decrypt(CPacket& w_packet);
  230. ~CCryptoControl();
  231. };
  232. } // namespace srt
  233. #endif // SRT_CONGESTION_CONTROL_H