/src/libmanos/manos_tls.c

http://github.com/jacksonh/manos · C · 298 lines · 230 code · 68 blank · 0 comment · 50 complexity · 3a0857615db16b39ffa4b77a0dabc081 MD5 · raw file

  1. #include "config.h"
  2. #ifdef false && HAVE_LIBGNUTLS
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <unistd.h>
  6. #include <fcntl.h>
  7. #include <errno.h>
  8. #include <string.h>
  9. #include <sys/ioctl.h>
  10. #include <sys/socket.h>
  11. #include <sys/un.h>
  12. #include <sys/types.h>
  13. #include <arpa/inet.h>
  14. #include <netdb.h>
  15. #include <netinet/in.h>
  16. #include <netinet/tcp.h>
  17. #include <gnutls/gnutls.h>
  18. #include "manos.h"
  19. gnutls_priority_t priority_cache;
  20. gnutls_dh_params_t dh_params;
  21. static int
  22. get_dh_params (gnutls_session_t session, gnutls_params_type_t type, gnutls_params_st *res)
  23. {
  24. if (type != GNUTLS_PARAMS_DH) {
  25. return -1;
  26. }
  27. res->type = type;
  28. res->deinit = 0;
  29. res->params.dh = dh_params;
  30. return 0;
  31. }
  32. int
  33. manos_tls_global_init (const char *priorities)
  34. {
  35. int err;
  36. priority_cache = NULL;
  37. dh_params = NULL;
  38. err = gnutls_global_init ();
  39. if (err != 0) {
  40. return -1;
  41. }
  42. err = gnutls_priority_init (&priority_cache, priorities, NULL);
  43. if (err != 0) {
  44. return -2;
  45. }
  46. return 0;
  47. }
  48. void
  49. manos_tls_global_end ()
  50. {
  51. gnutls_priority_deinit (priority_cache);
  52. gnutls_dh_params_deinit (dh_params);
  53. gnutls_global_deinit ();
  54. }
  55. int
  56. manos_tls_regenerate_dhparams (int bits)
  57. {
  58. gnutls_dh_params_t params, oldparams;
  59. int err;
  60. err = gnutls_dh_params_init (&params);
  61. if (err != 0) {
  62. return err;
  63. }
  64. err = gnutls_dh_params_generate2 (params, bits);
  65. if (err != 0) {
  66. gnutls_dh_params_deinit (params);
  67. return err;
  68. }
  69. oldparams = dh_params;
  70. dh_params = params;
  71. if (oldparams != NULL) {
  72. gnutls_dh_params_deinit (oldparams);
  73. }
  74. return 0;
  75. }
  76. int
  77. manos_tls_init (manos_tls_socket_t *tls, const char *cert, const char *key)
  78. {
  79. manos_tls_socket_t socket;
  80. int err;
  81. socket = malloc (sizeof (*socket));
  82. if (socket == NULL) {
  83. return ENOMEM;
  84. }
  85. memset (socket, 0, sizeof (*socket));
  86. err = gnutls_certificate_allocate_credentials (&socket->credentials);
  87. if (err != 0) {
  88. return err;
  89. }
  90. err = gnutls_certificate_set_x509_key_file (socket->credentials, cert, key, GNUTLS_X509_FMT_PEM);
  91. if (err != 0) {
  92. return err;
  93. }
  94. gnutls_certificate_set_params_function(socket->credentials, get_dh_params);
  95. *tls = socket;
  96. return 0;
  97. }
  98. int
  99. manos_tls_listen (manos_tls_socket_t tls, const char *host, int port, int backlog, int *reserr)
  100. {
  101. int err;
  102. *reserr = 0;
  103. tls->socket = manos_socket_listen (host, port, backlog, &err);
  104. if (tls->socket == -1) {
  105. *reserr = err;
  106. return -1;
  107. }
  108. return tls->socket;
  109. }
  110. static int
  111. do_handshake (manos_tls_socket_t tls)
  112. {
  113. int err;
  114. if (tls->handshake_done) {
  115. return 0;
  116. }
  117. err = gnutls_handshake (tls->tls_session);
  118. if (err != 0) {
  119. return err;
  120. } else {
  121. tls->handshake_done = 1;
  122. return 0;
  123. }
  124. }
  125. int
  126. manos_tls_accept (manos_tls_socket_t server, manos_tls_socket_t *client, manos_socket_info_t *info)
  127. {
  128. int err, inner_err;
  129. manos_tls_socket_t client_socket;
  130. err = manos_socket_accept (server->socket, info, &inner_err);
  131. if (err < 0) {
  132. if (inner_err == 0) {
  133. return EAGAIN;
  134. } else {
  135. return inner_err;
  136. }
  137. }
  138. client_socket = malloc (sizeof (*client_socket));
  139. if (client_socket == NULL) {
  140. close (info->fd);
  141. return ENOMEM;
  142. }
  143. memset (client_socket, 0, sizeof (*client_socket));
  144. client_socket->socket = info->fd;
  145. err = gnutls_init (&(client_socket->tls_session), GNUTLS_SERVER);
  146. if (err != 0) {
  147. close (info->fd);
  148. if (err != GNUTLS_E_MEMORY_ERROR) {
  149. gnutls_deinit (client_socket->tls_session);
  150. } else {
  151. err = ENOMEM;
  152. }
  153. free (client_socket);
  154. return err;
  155. }
  156. gnutls_priority_set (client_socket->tls_session, priority_cache);
  157. gnutls_credentials_set (client_socket->tls_session, GNUTLS_CRD_CERTIFICATE, server->credentials);
  158. gnutls_transport_set_ptr (client_socket->tls_session, (gnutls_transport_ptr_t) info->fd);
  159. *client = client_socket;
  160. do_handshake(client_socket);
  161. return 0;
  162. }
  163. static int
  164. tls_errno_or_again (int tlserror)
  165. {
  166. if (tlserror == GNUTLS_E_AGAIN || tlserror == GNUTLS_E_INTERRUPTED) {
  167. return 0;
  168. } else {
  169. return tlserror;
  170. }
  171. }
  172. int
  173. manos_tls_receive (manos_tls_socket_t tls, char *data, int len, int *reserr)
  174. {
  175. int recvd, err;
  176. *reserr = 0;
  177. err = do_handshake (tls);
  178. if (err != 0) {
  179. *reserr = tls_errno_or_again (err);
  180. return -1;
  181. }
  182. recvd = gnutls_record_recv (tls->tls_session, data, len);
  183. if (recvd < 0) {
  184. *reserr = tls_errno_or_again (recvd);
  185. return -1;
  186. }
  187. return recvd;
  188. }
  189. int
  190. manos_tls_send (manos_tls_socket_t tls, const char *data, int offset, int len, int *reserr)
  191. {
  192. int sent, err;
  193. *reserr = 0;
  194. err = do_handshake (tls);
  195. if (err != 0) {
  196. *reserr = tls_errno_or_again (err);
  197. return -1;
  198. }
  199. sent = gnutls_record_send (tls->tls_session, data + offset, len);
  200. if (sent < 0) {
  201. *reserr = tls_errno_or_again (sent);
  202. return -1;
  203. }
  204. return sent;
  205. }
  206. int
  207. manos_tls_redo_handshake (manos_tls_socket_t tls)
  208. {
  209. int err;
  210. err = gnutls_rehandshake (tls->tls_session);
  211. if (err != 0) {
  212. return err;
  213. }
  214. tls->handshake_done = 0;
  215. return 0;
  216. }
  217. int
  218. manos_tls_close (manos_tls_socket_t tls)
  219. {
  220. int err;
  221. err = gnutls_bye (tls->tls_session, GNUTLS_SHUT_RDWR);
  222. close (tls->socket);
  223. if (tls->credentials) {
  224. gnutls_certificate_free_credentials (tls->credentials);
  225. }
  226. gnutls_deinit (tls->tls_session);
  227. free (tls);
  228. return 0;
  229. }
  230. #endif