ddd-03-fd-blocking.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. #include <openssl/ssl.h>
  2. /*
  3. * Demo 3: Client — Client Creates FD — Blocking
  4. * =============================================
  5. *
  6. * This is an example of (part of) an application which uses libssl in a simple,
  7. * synchronous, blocking fashion. The client is responsible for creating the
  8. * socket and passing it to libssl. The functions show all interactions with
  9. * libssl the application makes, and would hypothetically be linked into a
  10. * larger application.
  11. */
  12. /*
  13. * The application is initializing and wants an SSL_CTX which it will use for
  14. * some number of outgoing connections, which it creates in subsequent calls to
  15. * new_conn. The application may also call this function multiple times to
  16. * create multiple SSL_CTX.
  17. */
  18. SSL_CTX *create_ssl_ctx(void)
  19. {
  20. SSL_CTX *ctx;
  21. #ifdef USE_QUIC
  22. ctx = SSL_CTX_new(OSSL_QUIC_client_method());
  23. #else
  24. ctx = SSL_CTX_new(TLS_client_method());
  25. #endif
  26. if (ctx == NULL)
  27. return NULL;
  28. /* Enable trust chain verification. */
  29. SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
  30. /* Load default root CA store. */
  31. if (SSL_CTX_set_default_verify_paths(ctx) == 0) {
  32. SSL_CTX_free(ctx);
  33. return NULL;
  34. }
  35. return ctx;
  36. }
  37. /*
  38. * The application wants to create a new outgoing connection using a given
  39. * SSL_CTX.
  40. *
  41. * hostname is a string like "openssl.org" used for certificate validation.
  42. */
  43. SSL *new_conn(SSL_CTX *ctx, int fd, const char *bare_hostname)
  44. {
  45. SSL *ssl;
  46. #ifdef USE_QUIC
  47. static const unsigned char alpn[] = {5, 'd', 'u', 'm', 'm', 'y'};
  48. #endif
  49. ssl = SSL_new(ctx);
  50. if (ssl == NULL)
  51. return NULL;
  52. SSL_set_connect_state(ssl); /* cannot fail */
  53. if (SSL_set_fd(ssl, fd) <= 0) {
  54. SSL_free(ssl);
  55. return NULL;
  56. }
  57. if (SSL_set1_host(ssl, bare_hostname) <= 0) {
  58. SSL_free(ssl);
  59. return NULL;
  60. }
  61. if (SSL_set_tlsext_host_name(ssl, bare_hostname) <= 0) {
  62. SSL_free(ssl);
  63. return NULL;
  64. }
  65. #ifdef USE_QUIC
  66. /* Configure ALPN, which is required for QUIC. */
  67. if (SSL_set_alpn_protos(ssl, alpn, sizeof(alpn))) {
  68. /* Note: SSL_set_alpn_protos returns 1 for failure. */
  69. SSL_free(ssl);
  70. return NULL;
  71. }
  72. #endif
  73. return ssl;
  74. }
  75. /*
  76. * The application wants to send some block of data to the peer.
  77. * This is a blocking call.
  78. */
  79. int tx(SSL *ssl, const void *buf, int buf_len)
  80. {
  81. return SSL_write(ssl, buf, buf_len);
  82. }
  83. /*
  84. * The application wants to receive some block of data from
  85. * the peer. This is a blocking call.
  86. */
  87. int rx(SSL *ssl, void *buf, int buf_len)
  88. {
  89. return SSL_read(ssl, buf, buf_len);
  90. }
  91. /*
  92. * The application wants to close the connection and free bookkeeping
  93. * structures.
  94. */
  95. void teardown(SSL *ssl)
  96. {
  97. SSL_free(ssl);
  98. }
  99. /*
  100. * The application is shutting down and wants to free a previously
  101. * created SSL_CTX.
  102. */
  103. void teardown_ctx(SSL_CTX *ctx)
  104. {
  105. SSL_CTX_free(ctx);
  106. }
  107. /*
  108. * ============================================================================
  109. * Example driver for the above code. This is just to demonstrate that the code
  110. * works and is not intended to be representative of a real application.
  111. */
  112. #include <sys/types.h>
  113. #include <sys/socket.h>
  114. #include <sys/signal.h>
  115. #include <netdb.h>
  116. #include <unistd.h>
  117. int main(int argc, char **argv)
  118. {
  119. int rc, fd = -1, l, mlen, res = 1;
  120. static char msg[300];
  121. struct addrinfo hints = {0}, *result = NULL;
  122. SSL *ssl = NULL;
  123. SSL_CTX *ctx = NULL;
  124. char buf[2048];
  125. if (argc < 3) {
  126. fprintf(stderr, "usage: %s host port\n", argv[0]);
  127. goto fail;
  128. }
  129. mlen = snprintf(msg, sizeof(msg),
  130. "GET / HTTP/1.0\r\nHost: %s\r\n\r\n", argv[1]);
  131. ctx = create_ssl_ctx();
  132. if (ctx == NULL) {
  133. fprintf(stderr, "cannot create context\n");
  134. goto fail;
  135. }
  136. hints.ai_family = AF_INET;
  137. hints.ai_socktype = SOCK_STREAM;
  138. hints.ai_flags = AI_PASSIVE;
  139. rc = getaddrinfo(argv[1], argv[2], &hints, &result);
  140. if (rc < 0) {
  141. fprintf(stderr, "cannot resolve\n");
  142. goto fail;
  143. }
  144. signal(SIGPIPE, SIG_IGN);
  145. #ifdef USE_QUIC
  146. fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  147. #else
  148. fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  149. #endif
  150. if (fd < 0) {
  151. fprintf(stderr, "cannot create socket\n");
  152. goto fail;
  153. }
  154. rc = connect(fd, result->ai_addr, result->ai_addrlen);
  155. if (rc < 0) {
  156. fprintf(stderr, "cannot connect\n");
  157. goto fail;
  158. }
  159. ssl = new_conn(ctx, fd, argv[1]);
  160. if (ssl == NULL) {
  161. fprintf(stderr, "cannot create connection\n");
  162. goto fail;
  163. }
  164. l = tx(ssl, msg, mlen);
  165. if (l < mlen) {
  166. fprintf(stderr, "tx error\n");
  167. goto fail;
  168. }
  169. for (;;) {
  170. l = rx(ssl, buf, sizeof(buf));
  171. if (l <= 0)
  172. break;
  173. fwrite(buf, 1, l, stdout);
  174. }
  175. res = 0;
  176. fail:
  177. if (ssl != NULL)
  178. teardown(ssl);
  179. if (ctx != NULL)
  180. teardown_ctx(ctx);
  181. if (fd >= 0)
  182. close(fd);
  183. if (result != NULL)
  184. freeaddrinfo(result);
  185. return res;
  186. }