BBS2chProxySecureSocket.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. #ifdef USE_MITM
  2. #include <stdexcept>
  3. #include <stdio.h>
  4. #include <unistd.h>
  5. #include <openssl/pem.h>
  6. #include <openssl/x509v3.h>
  7. #include <openssl/err.h>
  8. #ifdef _WIN32
  9. #include <winsock2.h>
  10. #define CLOSESOCKET(x) closesocket(x)
  11. #define SHUT_RDWR SD_BOTH
  12. #else
  13. #define CLOSESOCKET(x) ::close(x)
  14. #endif
  15. #include "BBS2chProxySecureSocket.h"
  16. static X509 *ca_cert;
  17. static EVP_PKEY *ca_privkey;
  18. static EVP_PKEY *server_privkey;
  19. static int add_ext(X509 *cert, int nid, const char *value)
  20. {
  21. X509_EXTENSION *ex;
  22. X509V3_CTX ctx;
  23. X509V3_set_ctx_nodb(&ctx);
  24. X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
  25. ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
  26. if (!ex)
  27. return 0;
  28. X509_add_ext(cert,ex,-1);
  29. X509_EXTENSION_free(ex);
  30. return 1;
  31. }
  32. int BBS2chProxySecureSocket::initializeCerts(const char *certPath, const char *keyPath)
  33. {
  34. static int initialized;
  35. if (initialized) return 0;
  36. FILE *fp = fopen(certPath, "rb");
  37. if (!fp) {
  38. fprintf(stderr, "Unable to open CA certificate from %s\n", certPath);
  39. return -1;
  40. }
  41. ca_cert = PEM_read_X509(fp, NULL, NULL, NULL);
  42. if (!ca_cert) {
  43. fprintf(stderr, "Error loading CA certificate: ");
  44. ERR_print_errors_fp(stderr);
  45. return -1;
  46. }
  47. fclose(fp);
  48. fp = fopen(keyPath, "rb");
  49. if (!fp) {
  50. fprintf(stderr, "Unable to open CA private key from %s\n", keyPath);
  51. return -1;
  52. }
  53. ca_privkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
  54. if (!ca_privkey) {
  55. fprintf(stderr, "Error loading CA private key: ");
  56. ERR_print_errors_fp(stderr);
  57. return -1;
  58. }
  59. fclose(fp);
  60. server_privkey = EVP_PKEY_new();
  61. BIGNUM *bn = BN_new();
  62. BN_set_word(bn, RSA_F4);
  63. RSA *rsa = RSA_new();
  64. RSA_generate_key_ex(rsa, 2048, bn, NULL);
  65. EVP_PKEY_assign_RSA(server_privkey, rsa);
  66. BN_free(bn);
  67. initialized = 1;
  68. return 0;
  69. }
  70. void BBS2chProxySecureSocket::generateAndPrintSelfSignedCertificate(void)
  71. {
  72. EVP_PKEY *key = EVP_PKEY_new();
  73. BIGNUM *bn = BN_new();
  74. BN_set_word(bn, RSA_F4);
  75. RSA *rsa = RSA_new();
  76. RSA_generate_key_ex(rsa, 2048, bn, NULL);
  77. EVP_PKEY_assign_RSA(key, rsa);
  78. BN_free(bn);
  79. X509 *cert = X509_new();
  80. X509_set_version(cert, 2);
  81. ASN1_INTEGER *serial = ASN1_INTEGER_new();
  82. bn = BN_new();
  83. BN_rand(bn, 64, 0, 0);
  84. BN_to_ASN1_INTEGER(bn, serial);
  85. X509_set_serialNumber(cert, serial);
  86. ASN1_INTEGER_free(serial);
  87. BN_free(bn);
  88. X509_name_st *name = X509_get_subject_name(cert);
  89. X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"JP", -1, -1, 0);
  90. X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)"proxy2ch certificate generator", -1, -1, 0);
  91. X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"proxy2ch", -1, -1, 0);
  92. X509_set_subject_name(cert, name);
  93. X509_set_issuer_name(cert, name);
  94. X509_set_pubkey(cert, key);
  95. X509_gmtime_adj(X509_get_notBefore(cert), 0);
  96. X509_gmtime_adj(X509_get_notAfter(cert), 31536000*3);
  97. add_ext(cert, NID_basic_constraints, "critical,CA:TRUE");
  98. add_ext(cert, NID_key_usage, "critical,digitalSignature,keyCertSign,cRLSign");
  99. add_ext(cert, NID_ext_key_usage, "serverAuth,clientAuth");
  100. add_ext(cert, NID_subject_key_identifier, "hash");
  101. X509_sign(cert, key, EVP_sha256());
  102. PEM_write_X509(stdout, cert);
  103. PEM_write_PrivateKey(stdout, key, NULL, NULL, 0, NULL, NULL);
  104. X509_free(cert);
  105. EVP_PKEY_free(key);
  106. }
  107. BBS2chProxySecureSocket::BBS2chProxySecureSocket(int sock, const char *host) :
  108. socket(sock), ctx(NULL), ssl(NULL)
  109. {
  110. bool hostIsDomain = false;
  111. for (int i=strlen(host)-1; i>=0; i--) {
  112. if (host[i] != '.' && !(host[i] >= '0' && host[i] <= '9')) {
  113. hostIsDomain = true;
  114. break;
  115. }
  116. }
  117. X509 *cert = X509_new();
  118. X509_set_version(cert, 2);
  119. ASN1_INTEGER *serial = ASN1_INTEGER_new();
  120. BIGNUM *bn = BN_new();
  121. BN_rand(bn, 64, 0, 0);
  122. BN_to_ASN1_INTEGER(bn, serial);
  123. X509_set_serialNumber(cert, serial);
  124. ASN1_INTEGER_free(serial);
  125. BN_free(bn);
  126. X509_name_st *name = X509_get_subject_name(cert);
  127. X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"JP", -1, -1, 0);
  128. X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)"proxy2ch", -1, -1, 0);
  129. X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)host, -1, -1, 0);
  130. X509_set_subject_name(cert, name);
  131. X509_set_issuer_name(cert, X509_get_subject_name(ca_cert));
  132. X509_set_pubkey(cert, server_privkey);
  133. X509_gmtime_adj(X509_get_notBefore(cert), 0);
  134. X509_gmtime_adj(X509_get_notAfter(cert), 31536000);
  135. add_ext(cert, NID_basic_constraints, "critical,CA:FALSE");
  136. add_ext(cert, NID_key_usage, "critical,digitalSignature,keyEncipherment");
  137. add_ext(cert, NID_ext_key_usage, "serverAuth,clientAuth");
  138. add_ext(cert, NID_subject_key_identifier, "hash");
  139. std::string sni(hostIsDomain ? "DNS:" : "IP:");
  140. sni += host;
  141. sni += ",DNS:*.5ch.net,DNS:*.2ch.net,DNS:*.bbspink.com";
  142. add_ext(cert, NID_subject_alt_name, sni.c_str());
  143. X509_sign(cert, ca_privkey, EVP_sha256());
  144. ctx = SSL_CTX_new(TLS_server_method());
  145. if (!ctx) {
  146. X509_free(cert);
  147. throw std::runtime_error("Unable to create SSL context");
  148. }
  149. if (SSL_CTX_use_certificate(ctx, cert) <= 0) {
  150. fprintf(stderr, "Unable to load server certificate\n");
  151. }
  152. if (SSL_CTX_use_PrivateKey(ctx, server_privkey) <= 0) {
  153. fprintf(stderr, "Unable to load server private key\n");
  154. }
  155. X509_free(cert);
  156. ssl = SSL_new(ctx);
  157. SSL_set_fd(ssl, socket);
  158. if (SSL_accept(ssl) <= 0) {
  159. char errbuf[256];
  160. ERR_error_string_n(ERR_get_error(), errbuf, 256);
  161. SSL_free(ssl);
  162. SSL_CTX_free(ctx);
  163. std::string str("Unable to establish SSL/TLS connection: ");
  164. str += errbuf;
  165. throw std::runtime_error(str);
  166. }
  167. }
  168. BBS2chProxySecureSocket::~BBS2chProxySecureSocket()
  169. {
  170. }
  171. int BBS2chProxySecureSocket::read(char *buffer, int length)
  172. {
  173. return SSL_read(ssl, buffer, length);
  174. }
  175. int BBS2chProxySecureSocket::readLine(char *buffer, int maxLength)
  176. {
  177. char *ptr = buffer;
  178. while (ptr < buffer + maxLength - 1) {
  179. int read = SSL_read(ssl, ptr, 1);
  180. if (read != 1) {
  181. return 0;
  182. }
  183. if (*ptr++ == '\n') {
  184. break;
  185. }
  186. }
  187. *ptr = 0;
  188. return 1;
  189. }
  190. int BBS2chProxySecureSocket::write(const char *buffer, int length)
  191. {
  192. return SSL_write(ssl, buffer, length);
  193. }
  194. int BBS2chProxySecureSocket::writeString(const std::string &str)
  195. {
  196. return SSL_write(ssl, str.data(), str.length());
  197. }
  198. void BBS2chProxySecureSocket::close(void)
  199. {
  200. if (ssl) {
  201. SSL_shutdown(ssl);
  202. SSL_free(ssl);
  203. ssl = NULL;
  204. }
  205. if (socket >= 0) {
  206. CLOSESOCKET(socket);
  207. socket = -1;
  208. }
  209. if (ctx) {
  210. SSL_CTX_free(ctx);
  211. ctx = NULL;
  212. }
  213. }
  214. #endif