Guest User

Untitled

a guest
Feb 18th, 2018
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.91 KB | None | 0 0
  1. import base64
  2. import cffi
  3.  
  4. ffi = cffi.FFI()
  5. ffi.cdef("""
  6. typedef struct bio_st BIO;
  7. typedef struct bio_method_st BIO_METHOD;
  8. typedef struct env_md_st EVP_MD;
  9. typedef struct ssl_ctx_st SSL_CTX;
  10. typedef struct ssl_method_st SSL_METHOD;
  11. typedef struct ssl_st SSL;
  12. typedef struct x509_st X509;
  13. typedef struct x509_store_ctx_st X509_STORE_CTX;
  14.  
  15. BIO_METHOD *BIO_s_mem(void);
  16. BIO *BIO_new(BIO_METHOD *type);
  17. int BIO_free(BIO *a);
  18. size_t BIO_ctrl_pending(BIO *b);
  19. int BIO_read(BIO *b, void *data, int len);
  20. int BIO_write(BIO *b, const void *data, int len);
  21.  
  22. const SSL_METHOD *DTLSv1_method(void);
  23. SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth);
  24. void SSL_CTX_free(SSL_CTX *);
  25. long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg);
  26. int SSL_CTX_set_cipher_list(SSL_CTX *, const char *str);
  27. int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, const char *profiles);
  28. void SSL_CTX_set_verify(SSL_CTX *ctx, int mode,
  29. int (*verify_callback)(int, X509_STORE_CTX *));
  30. int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type);
  31. int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type);
  32.  
  33. SSL *SSL_new(SSL_CTX *ctx);
  34. void SSL_free(SSL *ssl);
  35. int SSL_do_handshake(SSL *s);
  36. int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen,
  37. const char *label, size_t llen,
  38. const unsigned char *context,
  39. size_t contextlen, int use_context);
  40. X509 *SSL_get_certificate(const SSL *ssl);
  41. int SSL_get_error(const SSL *s, int ret_code);
  42. X509 *SSL_get_peer_certificate(const SSL *ssl);
  43. void SSL_set_accept_state(SSL *s);
  44. void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio);
  45. void SSL_set_connect_state(SSL *s);
  46.  
  47. const EVP_MD *EVP_get_digestbyname(const char *name);
  48. int X509_digest(const X509 *data, const EVP_MD *type,
  49. unsigned char *md, unsigned int *len);
  50. """)
  51.  
  52. lib = ffi.dlopen('libssl.so.1.1')
  53.  
  54. EVP_MAX_MD_SIZE = 36
  55. SSL_CTRL_GET_READ_AHEAD = 40
  56. SSL_CTRL_SET_READ_AHEAD = 41
  57. SSL_ERROR_WANT_READ = 2
  58. SSL_ERROR_WANT_WRITE = 3
  59. SSL_FILETYPE_PEM = 1
  60. SSL_VERIFY_PEER = 1
  61. SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 2
  62.  
  63. SRTP_KEY_LEN = 16
  64. SRTP_SALT_LEN = 14
  65.  
  66.  
  67. def certificate_digest(x509):
  68. digest = lib.EVP_get_digestbyname(b'SHA256')
  69. if digest == ffi.NULL:
  70. raise ValueError("No such digest method")
  71.  
  72. result_buffer = ffi.new("unsigned char[]", EVP_MAX_MD_SIZE)
  73. result_length = ffi.new("unsigned int[]", 1)
  74. result_length[0] = len(result_buffer)
  75.  
  76. digest_result = lib.X509_digest(x509, digest, result_buffer, result_length)
  77. assert digest_result == 1
  78.  
  79. return b":".join([
  80. base64.b16encode(ch).upper() for ch
  81. in ffi.buffer(result_buffer, result_length[0])]).decode('ascii')
  82.  
  83.  
  84. def get_srtp_key_salt(dest, src, idx):
  85. # key
  86. start = idx * SRTP_KEY_LEN
  87. dest[0:SRTP_KEY_LEN] = src[start:start + SRTP_KEY_LEN]
  88.  
  89. # salt
  90. start = 2 * SRTP_KEY_LEN + idx * SRTP_SALT_LEN
  91. dest[SRTP_KEY_LEN:SRTP_KEY_LEN + SRTP_SALT_LEN] = src[start:start + SRTP_SALT_LEN]
  92.  
  93.  
  94. @ffi.callback('int(int, X509_STORE_CTX *)')
  95. def verify_callback(x, y):
  96. return 1
  97.  
  98.  
  99. class DtlsSrtpContext:
  100. def __init__(self):
  101. self.ctx = lib.SSL_CTX_new(lib.DTLSv1_method())
  102. lib.SSL_CTX_set_verify(self.ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
  103. verify_callback)
  104. if not lib.SSL_CTX_use_certificate_file(self.ctx, b'bogus-client.crt', SSL_FILETYPE_PEM):
  105. print("SSL could not use certificate")
  106. if not lib.SSL_CTX_use_PrivateKey_file(self.ctx, b'bogus-client.key', SSL_FILETYPE_PEM):
  107. print("SSL could not use private key")
  108. if not lib.SSL_CTX_set_cipher_list(self.ctx, b'HIGH:!CAMELLIA:!aNULL'):
  109. print("SSL could not set cipher list")
  110. if lib.SSL_CTX_set_tlsext_use_srtp(self.ctx, b'SRTP_AES128_CM_SHA1_80'):
  111. print("SSL could not enable SRTP extension")
  112. if lib.SSL_CTX_ctrl(self.ctx, SSL_CTRL_SET_READ_AHEAD, 1, ffi.NULL):
  113. print("SSL could not enable read ahead")
  114.  
  115. def close(self):
  116. lib.SSL_CTX_free(self.ctx)
  117.  
  118.  
  119. class DtlsSrtpSession:
  120. def __init__(self, context, is_server, transport):
  121. self.encrypted = False
  122. self.is_server = is_server
  123. self.remote_fingerprint = None
  124. self.ssl = lib.SSL_new(context.ctx)
  125. self.srtp_tx_key = ffi.new('char[]', SRTP_KEY_LEN + SRTP_SALT_LEN)
  126. self.srtp_rx_key = ffi.new('char[]', SRTP_KEY_LEN + SRTP_SALT_LEN)
  127. self.transport = transport
  128.  
  129. self.read_bio = lib.BIO_new(lib.BIO_s_mem())
  130. self.write_bio = lib.BIO_new(lib.BIO_s_mem())
  131. lib.SSL_set_bio(self.ssl, self.read_bio, self.write_bio)
  132.  
  133. if self.is_server:
  134. lib.SSL_set_accept_state(self.ssl)
  135. else:
  136. lib.SSL_set_connect_state(self.ssl)
  137.  
  138. @property
  139. def local_fingerprint(self):
  140. x509 = lib.SSL_get_certificate(self.ssl)
  141. return certificate_digest(x509)
  142.  
  143. async def connect(self):
  144. while not self.encrypted:
  145. result = lib.SSL_do_handshake(self.ssl)
  146. if result > 0:
  147. self.encrypted = True
  148. break
  149.  
  150. error = lib.SSL_get_error(self.ssl, result)
  151. if error == SSL_ERROR_WANT_READ:
  152. data = await self.transport.recv()
  153. lib.BIO_write(self.read_bio, data, len(data))
  154. elif error != SSL_ERROR_WANT_WRITE:
  155. raise Exception('DTLS handshake failed (error %d)' % error)
  156.  
  157. pending = lib.BIO_ctrl_pending(self.write_bio)
  158. if pending > 0:
  159. buf = ffi.new("char[]", pending)
  160. lib.BIO_read(self.write_bio, buf, len(buf))
  161. data = b''.join(buf)
  162. await self.transport.send(data)
  163.  
  164. # check remote fingerprint
  165. x509 = lib.SSL_get_peer_certificate(self.ssl)
  166. remote_fingerprint = certificate_digest(x509)
  167. if remote_fingerprint != self.remote_fingerprint.upper():
  168. raise Exception('DTLS fingerprint does not match')
  169.  
  170. # generate keying material
  171. buf = ffi.new("char[]", 2 * (SRTP_KEY_LEN + SRTP_SALT_LEN))
  172. extractor = b'EXTRACTOR-dtls_srtp'
  173. if not lib.SSL_export_keying_material(self.ssl, buf, len(buf),
  174. extractor, len(extractor),
  175. ffi.NULL, 0, 0):
  176. raise Exception('DTLS could not extract SRTP keying material')
  177.  
  178. if self.is_server:
  179. get_srtp_key_salt(self.srtp_tx_key, buf, 1)
  180. get_srtp_key_salt(self.srtp_rx_key, buf, 0)
  181. else:
  182. get_srtp_key_salt(self.srtp_tx_key, buf, 0)
  183. get_srtp_key_salt(self.srtp_rx_key, buf, 1)
  184.  
  185. print('DTLS handshake complete')
  186.  
  187. def close(self):
  188. lib.SSL_free(self.ssl)
  189.  
  190.  
  191. if __name__ == '__main__':
  192. context = DtlsSrtpContext()
  193. session = DtlsSrtpSession(context, is_server=True, transport=None)
  194. print(session.local_fingerprint)
  195. session.close()
  196. context.close()
Add Comment
Please, Sign In to add comment