2 #define _POSIX_SOURCE /* For getaddrinfo(3) */
6 #define _BSD_SOURCE /* For NI_MAXHOST up to glibc-2.19 */
8 #ifndef _DEFAULT_SOURCE
9 #define _DEFAULT_SOURCE /* For NI_MAXHOST since glibc-2.20 */
12 #include "../test-tools.h"
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <errno.h> /* For EINTR */
27 #include <gnutls/gnutls.h>
28 #include <gnutls/x509.h>
30 char *server_error
= NULL
;
32 static const char *as_path_hotp
= "/as/processLogin?type=hotp&uri=";
33 static const char *as_path_sendsms
= "/as/processLogin?type=totp&sendSms=true&uri=";
34 static const char *as_path_dontsendsms
= "/as/processLogin?type=totp&uri=";
35 static const char *as_path_logout
= "/as/processLogout?uri=";
36 static const char *asws_path
= "/asws/changePassword";
37 static const char *ws_path
= "/apps/DS/dz";
39 static const char *ws_base_path_basic
= "/";
40 static const char *ws_base_path_commercial_certificate_with_password
= "/certds/";
41 static const char *ws_base_path_otp
= "/apps/";
43 static const char *authorization_cookie_name
= "IPCZ-X-COOKIE";
44 static char *authorization_cookie_value
= NULL
;
47 static gnutls_certificate_credentials_t x509_credentials
;
48 static gnutls_priority_t priority_cache
;
49 static gnutls_dh_params_t dh_parameters
;
50 static gnutls_datum_t ticket_key
;
51 static const char *client_required_dn
= NULL
;
53 /* Save error message if not yet set. The message will be duplicated.
54 * @message is printf(3) formatting string. */
55 void set_server_error(const char *message
, ...) {
56 if (server_error
== NULL
) {
58 va_start(ap
, message
);
59 test_vasprintf(&server_error
, message
, ap
);
65 /* Creates listening TCP socket on localhost.
66 * Returns the socket descriptor or -1. */
67 int listen_on_socket(void) {
69 struct addrinfo hints
;
70 struct addrinfo
*addresses
, *address
;
73 memset(&hints
, 0, sizeof(hints
));
74 hints
.ai_family
= AF_UNSPEC
;
75 hints
.ai_socktype
= SOCK_STREAM
;
76 retval
= getaddrinfo("localhost", NULL
, &hints
, &addresses
);
78 set_server_error("Could not resolve `localhost'");
82 for (address
= addresses
; address
!= NULL
; address
= address
->ai_next
) {
83 fd
= socket(address
->ai_family
, address
->ai_socktype
,
84 address
->ai_protocol
);
85 if (fd
== -1) continue;
87 retval
= bind(fd
, address
->ai_addr
, address
->ai_addrlen
);
93 retval
= listen(fd
, 0);
95 freeaddrinfo(addresses
);
102 freeaddrinfo(addresses
);
103 set_server_error("Could not start listening on TCP/localhost");
108 /* Format socket address as printable string.
109 * @return allocated string or NULL in case of error. */
110 char *socket2address(int socket
) {
111 struct sockaddr_storage storage
;
112 socklen_t length
= (socklen_t
) sizeof(storage
);
113 char host
[NI_MAXHOST
];
114 char service
[NI_MAXSERV
];
115 char *address
= NULL
;
117 if (-1 == getsockname(socket
, (struct sockaddr
*)&storage
, &length
)) {
118 set_server_error("Could not get address of server socket");
122 if (0 != getnameinfo((struct sockaddr
*)&storage
, length
,
123 host
, sizeof(host
), service
, sizeof(service
),
124 NI_NUMERICHOST
|NI_NUMERICSERV
)) {
125 set_server_error("Could not resolve address of server socket");
129 if (-1 == test_asprintf(&address
,
130 (strchr(host
, ':') == NULL
) ? "%s:%s" : "[%s]:%s",
132 set_server_error("Could not format server address");
140 /* Format HTTP(s) socket address as printable URL string.
141 * @socket is listening TCP socket of HTTP server
142 * @tls is true for HTTPS, false for plain HTTP
143 * @return allocated string or NULL in case of error. */
144 static char *socket2url(int socket
, _Bool tls
) {
145 char *socket_address
= NULL
;
146 char *address
= NULL
;
148 socket_address
= socket2address(socket
);
149 if (NULL
== socket_address
) {
150 set_server_error("Could not format server address");
151 free(socket_address
);
155 if (-1 == test_asprintf(&address
, "%s://%s/",
156 (tls
) ? "https" : "http", socket_address
)) {
157 set_server_error("Could not format server address");
158 free(socket_address
);
162 free(socket_address
);
167 /* Process ISDS web service */
168 static void do_ws(const struct http_connection
*connection
,
169 const struct service_configuration
*ws_configuration
,
170 const struct http_request
*request
, const char *required_base_path
) {
171 char *end_point
= request
->uri
; /* Pointer to string in the request */
173 if (request
->method
!= HTTP_METHOD_POST
) {
174 http_send_response_400(connection
,
175 "Regular ISDS web service request must be POST");
179 if (required_base_path
!= NULL
) {
180 size_t required_base_path_length
= strlen(required_base_path
);
181 if (strncmp(end_point
, required_base_path
, required_base_path_length
)) {
182 http_send_response_400(connection
, "Request sent to invalid path");
185 end_point
+= required_base_path_length
;
188 soap(connection
, ws_configuration
, request
->body
, request
->body_length
,
193 /* Do the server protocol.
194 * @connection is HTTP connection
195 * @server_arguments is pointer to structure arguments_basic_authentication
196 * @request is parsed HTTP client request
197 * @prefix is HTTP URI path prefix (directory) where all ISDS services live
198 * @return 0 to accept new client, return -1 in case of fatal error. */
199 static int server_prefixed_basic_authentication(
200 const struct http_connection
*connection
, const void *server_arguments
,
201 const struct http_request
*request
, const char *prefix
) {
202 const struct arguments_basic_authentication
*arguments
=
203 (const struct arguments_basic_authentication
*) server_arguments
;
205 if (NULL
== arguments
|| NULL
== request
|| NULL
== prefix
) {
209 if (request
->method
== HTTP_METHOD_POST
) {
210 /* Only POST requests are used in Basic authentication mode */
211 if (arguments
->username
!= NULL
) {
212 if (http_client_authenticates(request
)) {
213 switch(http_authenticate_basic(request
,
214 arguments
->username
, arguments
->password
)) {
215 case HTTP_ERROR_SUCCESS
:
216 do_ws(connection
, arguments
->services
, request
,
219 case HTTP_ERROR_CLIENT
:
220 if (arguments
->isds_deviations
)
221 http_send_response_401_basic(connection
);
223 http_send_response_403(connection
);
226 http_send_response_500(connection
,
227 "Server error while verifying Basic "
231 http_send_response_401_basic(connection
);
234 do_ws(connection
, arguments
->services
, request
,
238 /* HTTP method unsupported per ISDS specification */
239 http_send_response_400(connection
,
240 "Only POST method is allowed");
247 /* Do the server protocol.
248 * @connection is HTTP connection
249 * @server_arguments is pointer to structure arguments_basic_authentication
250 * @request is parsed HTTP client request
251 * @return 0 to accept new client, return -1 in case of fatal error. */
252 int server_basic_authentication(const struct http_connection
*connection
,
253 const void *server_arguments
, const struct http_request
*request
) {
254 return server_prefixed_basic_authentication(connection
, server_arguments
,
255 request
, ws_base_path_basic
);
259 /* Do the server protocol.
260 * @connection is HTTP connection
261 * @server_arguments is pointer to structure arguments_basic_authentication
262 * @request is parsed HTTP client request
263 * @return 0 to accept new client, return -1 in case of fatal error. */
264 int server_certificate_with_password_authentication(
265 const struct http_connection
*connection
,
266 const void *server_arguments
, const struct http_request
*request
) {
267 return server_prefixed_basic_authentication(connection
, server_arguments
,
268 request
, ws_base_path_commercial_certificate_with_password
);
272 /* Process first phase of TOTP request */
273 static void do_as_sendsms(const struct http_connection
*connection
,
274 const struct http_request
*request
,
275 const struct arguments_otp_authentication
*arguments
) {
276 if (arguments
== NULL
) {
277 http_send_response_500(connection
,
278 "Third argument of do_as_sendsms() is NULL");
282 if (request
->method
!= HTTP_METHOD_POST
) {
283 http_send_response_400(connection
,
284 "First phase TOTP request must be POST");
288 if (!http_client_authenticates(request
)) {
289 http_send_response_401_otp(connection
,
291 "authentication.error.userIsNotAuthenticated",
292 "Client did not send any authentication header");
296 switch(http_authenticate_basic(request
,
297 arguments
->username
, arguments
->password
)) {
298 case HTTP_ERROR_SUCCESS
: {
300 char *uri
= strstr(request
->uri
, "&uri=");
302 http_send_response_400(connection
,
303 "Missing uri parameter in Request URI");
307 /* Build new location for second OTP phase */
308 char *location
= NULL
;
309 if (-1 == test_asprintf(&location
, "%s%s", as_path_dontsendsms
, uri
)) {
310 http_send_response_500(connection
,
311 "Could not build new localtion for "
315 char *terminator
= strchr(uri
, '&');
316 if (NULL
!= terminator
)
317 location
[strlen(as_path_dontsendsms
) + (uri
- terminator
)] = '\0';
318 http_send_response_302_totp(connection
,
319 "authentication.info.totpSended",
320 "=?UTF-8?B?SmVkbm9yw6F6b3bDvSBrw7NkIG9kZXNsw6FuLg==?=",
325 case HTTP_ERROR_CLIENT
:
326 if (arguments
->isds_deviations
)
327 http_send_response_401_otp(connection
,
329 "authentication.error.userIsNotAuthenticated",
330 " Retry: Bad user name or password in first OTP phase.\r\n"
331 " This is very long header\r\n"
332 " which should span to more lines.\r\n"
333 " Surrounding LWS are meaning-less. ");
335 http_send_response_403(connection
);
338 http_send_response_500(connection
,
339 "Could not verify Basic authentication");
344 /* Return static string representation of HTTP OTP authentication method.
345 * Or NULL in case of error. */
346 static const char *auth_otp_method2string(enum auth_otp_method method
) {
348 case AUTH_OTP_HMAC
: return "hotp";
349 case AUTH_OTP_TIME
: return "totp";
350 default: return NULL
;
355 /* Process second phase of OTP request */
356 static void do_as_phase_two(const struct http_connection
*connection
,
357 const struct http_request
*request
,
358 const struct arguments_otp_authentication
*arguments
) {
359 if (arguments
== NULL
) {
360 http_send_response_500(connection
,
361 "Third argument of do_as_phase_two() is NULL");
365 if (request
->method
!= HTTP_METHOD_POST
) {
366 http_send_response_400(connection
,
367 "Second phase OTP request must be POST");
371 if (!http_client_authenticates(request
)) {
372 http_send_response_401_otp(connection
,
373 auth_otp_method2string(arguments
->method
),
374 "authentication.error.userIsNotAuthenticated",
375 "Client did not send any authentication header");
379 switch(http_authenticate_otp(request
,
380 arguments
->username
, arguments
->password
, arguments
->otp
)) {
381 case HTTP_ERROR_SUCCESS
: {
383 char *uri
= strstr(request
->uri
, "&uri=");
385 http_send_response_400(connection
,
386 "Missing uri parameter in Request URI");
390 /* Build new location for final request */
391 char *location
= NULL
;
392 if (NULL
== (location
= strdup(uri
))) {
393 http_send_response_500(connection
,
394 "Could not build new location for final request");
397 char *terminator
= strchr(location
, '&');
398 if (NULL
!= terminator
)
400 /* Generate pseudo-random cookie value. This is to prevent
401 * client from reusing the cookie accidentally. We use the
402 * same seed to get reproducible tests. */
403 if (-1 == test_asprintf(&authorization_cookie_value
, "%d",
405 http_send_response_500(connection
,
406 "Could not generate cookie value");
410 /* XXX: Add Path parameter to cookie, otherwise
411 * different paths will not match.
412 * FIXME: Domain argument does not work with cURL. Report a bug. */
413 http_send_response_302_cookie(connection
,
414 authorization_cookie_name
,
415 authorization_cookie_value
,
416 /*http_find_host(request)*/NULL
,
422 case HTTP_ERROR_CLIENT
:
423 if (arguments
->isds_deviations
)
424 http_send_response_401_otp(connection
,
425 auth_otp_method2string(arguments
->method
),
426 "authentication.error.userIsNotAuthenticated",
427 " Retry: Bad user name or password in second OTP phase.\r\n"
428 " This is very long header\r\n"
429 " which should span to more lines.\r\n"
430 " Surrounding LWS are meaning-less. ");
432 http_send_response_403(connection
);
435 http_send_response_500(connection
,
436 "Could not verify OTP authentication");
441 /* Process ASWS for changing OTP password requests */
442 /* FIXME: The ASWS URI hosts two services: for sending TOTP code for password
443 * change and for changing OTP password. The problem is the former one is
444 * basic-authenticated, the later one is otp-authenticated. But we cannot
445 * decide which authentication to enforce without understadning request body.
446 * I will just try both of them to choose the service.
447 * But I hope official server implementation does it in more clever way. */
448 static void do_asws(const struct http_connection
*connection
,
449 const struct http_request
*request
,
450 const struct arguments_otp_authentication
*arguments
) {
452 if (arguments
== NULL
) {
453 http_send_response_500(connection
,
454 "Third argument of do_asws() is NULL");
458 if (request
->method
!= HTTP_METHOD_POST
) {
459 http_send_response_400(connection
, "ASWS request must be POST");
463 if (!http_client_authenticates(request
)) {
464 http_send_response_401_otp(connection
,
465 auth_otp_method2string(arguments
->method
),
466 "authentication.error.userIsNotAuthenticated",
467 "Client did not send any authentication header");
472 error
= http_authenticate_otp(request
,
473 arguments
->username
, arguments
->password
, arguments
->otp
);
474 if (HTTP_ERROR_SUCCESS
== error
) {
475 /* This will be request for password change because OTP
476 * authentication succeeded. */
477 do_ws(connection
, arguments
->services
, request
, NULL
);
481 if (AUTH_OTP_TIME
== arguments
->method
) {
483 error
= http_authenticate_basic(request
,
484 arguments
->username
, arguments
->password
);
485 if (HTTP_ERROR_SUCCESS
== error
) {
486 /* This will be request for time code for password change because
487 * basic authentication succeeded. */
488 do_ws(connection
, arguments
->services
, request
, NULL
);
493 if (HTTP_ERROR_CLIENT
== error
) {
494 if (arguments
->isds_deviations
)
495 http_send_response_401_otp(connection
,
496 auth_otp_method2string(arguments
->method
),
497 "authentication.error.userIsNotAuthenticated",
498 " Retry: Bad user name or password in Authorization.\r\n"
499 " This is very long header\r\n"
500 " which should span to more lines.\r\n"
501 " Surrounding LWS are meaning-less. ");
503 http_send_response_403(connection
);
507 http_send_response_500(connection
,
508 "Could not verify OTP authentication");
512 /* Process OTP session cookie invalidation request */
513 static void do_as_logout(const struct http_connection
*connection
,
514 const struct http_request
*request
,
515 const struct arguments_otp_authentication
*arguments
) {
516 if (arguments
== NULL
) {
517 http_send_response_500(connection
,
518 "Third argument of do_as_logout() is NULL");
522 if (request
->method
!= HTTP_METHOD_GET
) {
523 http_send_response_400(connection
,
524 "OTP cookie invalidation request must be GET");
528 const char *received_cookie
=
529 http_find_cookie(request
, authorization_cookie_name
);
531 if (authorization_cookie_value
== NULL
|| received_cookie
== NULL
||
532 strcmp(authorization_cookie_value
, received_cookie
)) {
533 http_send_response_403(connection
);
537 /* XXX: Add Path parameter to cookie, otherwise
538 * different paths will not match.
539 * FIXME: Domain argument does not work with cURL. Report a bug. */
540 http_send_response_200_cookie(connection
,
541 authorization_cookie_name
,
543 /*http_find_host(request)*/ NULL
,
549 /* Process ISDS WS ping authorized by cookie */
550 static void do_ws_with_cookie(const struct http_connection
*connection
,
551 const struct http_request
*request
,
552 const struct arguments_otp_authentication
*arguments
,
553 const char *valid_base_path
) {
554 const char *received_cookie
=
555 http_find_cookie(request
, authorization_cookie_name
);
557 if (authorization_cookie_value
!= NULL
&& received_cookie
!= NULL
&&
558 !strcmp(authorization_cookie_value
, received_cookie
))
559 do_ws(connection
, arguments
->services
, request
, valid_base_path
);
561 http_send_response_403(connection
);
565 /* Do the server protocol with OTP authentication.
566 * @connection is HTTP connection
567 * @server_arguments is pointer to structure arguments_otp_authentication. It
568 * selects OTP method to enable.
569 * @request is parsed HTTP client requrest
570 * @return 0 to accept new client, return -1 in case of fatal error. */
571 int server_otp_authentication(const struct http_connection
*connection
,
572 const void *server_arguments
, const struct http_request
*request
) {
573 const struct arguments_otp_authentication
*arguments
=
574 (const struct arguments_otp_authentication
*) server_arguments
;
576 if (NULL
== arguments
|| NULL
== request
) {
580 if (arguments
->username
!= NULL
) {
581 if (arguments
->method
== AUTH_OTP_HMAC
&&
582 !strncmp(request
->uri
, as_path_hotp
, strlen(as_path_hotp
))) {
583 do_as_phase_two(connection
, request
, arguments
);
584 } else if (arguments
->method
== AUTH_OTP_TIME
&&
585 !strncmp(request
->uri
, as_path_sendsms
,
586 strlen(as_path_sendsms
))) {
587 do_as_sendsms(connection
, request
, arguments
);
588 } else if (arguments
->method
== AUTH_OTP_TIME
&&
589 !strncmp(request
->uri
, as_path_dontsendsms
,
590 strlen(as_path_dontsendsms
))) {
591 do_as_phase_two(connection
, request
, arguments
);
592 } else if (!strncmp(request
->uri
, as_path_logout
,
593 strlen(as_path_logout
))) {
594 do_as_logout(connection
, request
, arguments
);
595 } else if (!strcmp(request
->uri
, asws_path
)) {
596 do_asws(connection
, request
, arguments
);
597 } else if (!strcmp(request
->uri
, ws_path
)) {
598 do_ws_with_cookie(connection
, request
, arguments
,
601 http_send_response_400(connection
,
602 "Unknown path for OTP authenticating service");
605 if (!strcmp(request
->uri
, ws_path
)) {
606 do_ws(connection
, arguments
->services
, request
,
609 http_send_response_400(connection
,
610 "Unknown path for OTP authenticating service");
618 /* Implementation of server that is out of order.
619 * It always sends back SOAP Fault with HTTP error 503.
620 * @connection is HTTP connection
621 * @server_arguments is ununsed pointer
622 * @request is parsed HTTP client request
623 * @return 0 to accept new client, return -1 in case of fatal error. */
624 int server_out_of_order(const struct http_connection
*connection
,
625 const void *server_arguments
, const struct http_request
*request
) {
626 const char *soap_mime_type
= "text/xml"; /* SOAP/1.1 requires text/xml */
627 const char *fault
= "<?xml version='1.0' encoding='UTF-8'?><SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode xsi:type=\"xsd:string\">Probíhá plánovaná údržba</faultcode><faultstring xsi:type=\"xsd:string\">Omlouváme se všem uživatelům datových schránek za dočasné omezení přístupu do systému datových schránek z důvodu plánované údržby systému. Děkujeme za pochopení.</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>";
629 http_send_response_503(connection
, fault
, strlen(fault
),
635 /* Call-back for HTTP to receive data from socket
636 * API is equivalent to recv(2) except automatic interrupt handling. */
637 static ssize_t
recv_plain(const struct http_connection
*connection
,
638 void *buffer
, size_t length
) {
641 retval
= recv(connection
->socket
, buffer
, length
, 0);
642 } while (-1 == retval
&& EINTR
== errno
);
647 /* Call-back for HTTP to sending data to socket
648 * API is equivalent to send(2) except automatic interrupt handling. */
649 static ssize_t
send_plain(const struct http_connection
*connection
,
650 const void *buffer
, size_t length
) {
653 retval
= send(connection
->socket
, buffer
, length
, MSG_NOSIGNAL
);
654 } while (-1 == retval
&& EINTR
== errno
);
659 /* Call-back for HTTP to receive data from TLS socket
660 * API is equivalent to recv(2) except automatic interrupt handling. */
661 static ssize_t
recv_tls(const struct http_connection
*connection
,
662 void *buffer
, size_t length
) {
665 retval
= gnutls_record_recv(connection
->callback_data
, buffer
, length
);
666 if (GNUTLS_E_REHANDSHAKE
== retval
) {
669 error
= gnutls_handshake(connection
->callback_data
);
670 } while (error
< 0 && !gnutls_error_is_fatal(error
));
672 fprintf(stderr
, "TLS rehandshake failed: %s\n",
673 gnutls_strerror(error
));
677 } while (GNUTLS_E_INTERRUPTED
== retval
|| GNUTLS_E_AGAIN
== retval
);
678 return (retval
< 0) ? -1 : retval
;
682 /* Call-back for HTTP to sending data to TLS socket
683 * API is equivalent to send(2) except automatic interrupt handling. */
684 static ssize_t
send_tls(const struct http_connection
*connection
,
685 const void *buffer
, size_t length
) {
688 retval
= gnutls_record_send(connection
->callback_data
, buffer
, length
);
689 } while (GNUTLS_E_INTERRUPTED
== retval
|| GNUTLS_E_AGAIN
== retval
);
690 return (retval
< 0) ? -1 : retval
;
694 /* Call-back fot GnuTLS to receive data from TCP socket.
695 * We override default implementation to unify passing http_connection as
696 * @context. Also otherwise there is need for ugly type cast from integer to
698 static ssize_t
tls_pull(gnutls_transport_ptr_t context
, void* buffer
,
700 return recv( ((struct http_connection
*)context
)->socket
,
705 /* Call-back fot GnuTLS to send data to TCP socket.
706 * GnuTLS does not call send(2) with MSG_NOSIGNAL, we must do it manually. */
707 static ssize_t
tls_push(gnutls_transport_ptr_t context
, const void* buffer
,
709 return send( ((struct http_connection
*)context
)->socket
,
710 buffer
, length
, MSG_NOSIGNAL
);
714 /* Verify client certificate from current TLS session.
715 * @tls_session is session in TLS handshake when client sent certificate
716 * @return 0 for acceptance, return non-0 for denial. */
717 static int tls_verify_client(gnutls_session_t tls_session
) {
718 const gnutls_datum_t
*chain
; /* Pointer to static data */
719 unsigned int chain_length
;
720 gnutls_x509_crt_t certificate
;
721 gnutls_datum_t certificate_text
;
727 /* Obtain client's certificate chain */
728 chain
= gnutls_certificate_get_peers(tls_session
, &chain_length
);
730 fprintf(stderr
, "Error while obtaining client's certificate\n");
733 if (chain_length
< 1) {
734 fprintf(stderr
, "Client did not send any certificate\n");
738 /* Print client's certificate */
739 error
= gnutls_x509_crt_init(&certificate
);
741 fprintf(stderr
, "Could not initialize certificate storage: %s\n",
742 gnutls_strerror(error
));
745 error
= gnutls_x509_crt_import(certificate
, chain
,
746 GNUTLS_X509_FMT_DER
);
748 fprintf(stderr
, "Could not parse client's X.509 certificate: %s\n",
749 gnutls_strerror(error
));
750 gnutls_x509_crt_deinit(certificate
);
753 error
= gnutls_x509_crt_print(certificate
, GNUTLS_CRT_PRINT_ONELINE
,
756 fprintf(stderr
, "Could not print client's certificate: %s\n",
757 gnutls_strerror(error
));
758 gnutls_x509_crt_deinit(certificate
);
761 fprintf(stderr
, "Client sent certificate: %s\n", certificate_text
.data
);
762 gnutls_free(certificate_text
.data
);
764 /* Verify certificate signature and path */
765 error
= gnutls_certificate_verify_peers2(tls_session
, &status
);
767 fprintf(stderr
, "Could not verify client's certificate: %s\n",
768 gnutls_strerror(error
));
769 gnutls_x509_crt_deinit(certificate
);
773 fprintf(stderr
, "Client's certificate is not valid.\n");
774 gnutls_x509_crt_deinit(certificate
);
777 fprintf(stderr
, "Client's certificate is valid.\n");
780 /* Authorize client */
781 error
= gnutls_x509_crt_get_dn(certificate
, NULL
, &dn_size
);
782 if (error
!= GNUTLS_E_SHORT_MEMORY_BUFFER
) {
783 fprintf(stderr
, "Could not determine client's "
784 "distinguished name size: %s.\n",
785 gnutls_strerror(error
));
786 gnutls_x509_crt_deinit(certificate
);
789 dn_text
= gnutls_malloc(dn_size
);
790 if (NULL
== dn_text
) {
791 fprintf(stderr
, "Could not allocate memory for client's "
792 "distinguished name.\n");
793 gnutls_x509_crt_deinit(certificate
);
796 error
= gnutls_x509_crt_get_dn(certificate
, dn_text
, &dn_size
);
798 fprintf(stderr
, "Could obtain client's "
799 "distinguished name size: %s.\n",
800 gnutls_strerror(error
));
801 gnutls_free(dn_text
);
802 gnutls_x509_crt_deinit(certificate
);
805 gnutls_x509_crt_deinit(certificate
);
806 if (client_required_dn
!= NULL
&&
807 strcmp(client_required_dn
, dn_text
)) {
808 fprintf(stderr
, "Client is not authorized: "
809 "Client's distinguished name `%s' does not match "
810 "required name `%s'.\n",
811 dn_text
, client_required_dn
);
812 gnutls_free(dn_text
);
815 fprintf(stderr
, "Client is authorized.\n");
816 gnutls_free(dn_text
);
821 /* Start sever in separate process.
822 * @server_process is PID of forked server
823 * @server_address is automatically allocated TCP address of listening server
824 * @server_implementation points to kind of server to implement. Valid values
825 * are addresses of server_basic_authentication(),
826 * server_otp_authentication(), or server_out_of_order().
827 * @server_arguments is pointer to argument pass to @server_implementation. It
829 * @username sets required user name server has to require. Set NULL to
830 * disable HTTP authentication.
831 * @password sets required password server has to require
833 * @isds_deviations is flag to set conformance level. If false, server is
834 * compliant to standards (HTTP, SOAP) if not conflicts with ISDS
835 * specification. Otherwise server mimics real ISDS implementation as much
837 * @tls sets TLS layer. Pass NULL for plain HTTP.
838 * @return -1 in case of error. */
839 int start_server(pid_t
*server_process
, char **server_address
,
840 int (*server_implementation
)(const struct http_connection
*,
841 const void *, const struct http_request
*),
842 const void *server_arguments
, const struct tls_authentication
*tls
) {
846 if (server_address
== NULL
) {
847 set_server_error("start_server(): Got invalid server_address pointer");
850 *server_address
= NULL
;
852 if (server_process
== NULL
) {
853 set_server_error("start_server(): Got invalid server_process pointer");
857 if (NULL
!= tls
&& NULL
== tls
->server_certificate
) {
858 /* XXX: X.509 TLS server requires server certificate. */
862 server_socket
= listen_on_socket();
863 if (server_socket
== -1) {
864 set_server_error("Could not create listening socket");
868 *server_address
= socket2url(server_socket
, NULL
!= tls
);
869 if (*server_address
== NULL
) {
870 close(server_socket
);
871 set_server_error("Could not format address of listening socket");
876 const char *error_position
;
877 if ((error
= gnutls_global_init())) {
878 close(server_socket
);
879 set_server_error("Could not initialize GnuTLS: %s",
880 gnutls_strerror(error
));
884 gnutls_certificate_allocate_credentials(&x509_credentials
))) {
885 close(server_socket
);
886 gnutls_global_deinit();
887 set_server_error("Could not allocate X.509 credentials: %s",
888 gnutls_strerror(error
));
891 if (NULL
!= tls
->authority_certificate
) {
892 if (0 > (error
= gnutls_certificate_set_x509_trust_file(
893 x509_credentials
, tls
->authority_certificate
,
894 GNUTLS_X509_FMT_PEM
))) {
895 close(server_socket
);
896 gnutls_certificate_free_credentials(x509_credentials
);
897 gnutls_global_deinit();
898 set_server_error("Could not load authority certificate `%s': %s",
899 tls
->authority_certificate
, gnutls_strerror(error
));
903 if ((error
= gnutls_certificate_set_x509_key_file(x509_credentials
,
904 tls
->server_certificate
, tls
->server_key
,
905 GNUTLS_X509_FMT_PEM
))) {
906 close(server_socket
);
907 gnutls_certificate_free_credentials(x509_credentials
);
908 gnutls_global_deinit();
909 set_server_error("Could not load server certificate or "
910 "private key `%s': %s", tls
->server_certificate
,
911 gnutls_strerror(error
));
914 if ((error
= gnutls_priority_init(&priority_cache
,
915 "PERFORMANCE", &error_position
))) {
916 close(server_socket
);
917 gnutls_certificate_free_credentials(x509_credentials
);
918 gnutls_global_deinit();
919 if (error
== GNUTLS_E_INVALID_REQUEST
) {
920 set_server_error("Could not set TLS algorithm preferences: "
922 gnutls_strerror(error
), error_position
);
923 set_server_error("Could not set TLS algorithm preferences: %s",
924 gnutls_strerror(error
));
928 /* XXX: priority_cache is linked from x509_credentials now.
929 * Deinitialization must free x509_credentials before priority_cache. */
931 if ((error
= gnutls_dh_params_init(&dh_parameters
))) {
932 close(server_socket
);
933 gnutls_certificate_free_credentials(x509_credentials
);
934 gnutls_priority_deinit(priority_cache
);
935 gnutls_global_deinit();
936 set_server_error("Could not allocate Diffie-Hellman parameters: "
937 "%s", gnutls_strerror(error
));
940 if ((error
= gnutls_dh_params_generate2(dh_parameters
,
941 gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH
,
942 GNUTLS_SEC_PARAM_LOW
)))) {
943 close(server_socket
);
944 gnutls_certificate_free_credentials(x509_credentials
);
945 gnutls_priority_deinit(priority_cache
);
946 gnutls_dh_params_deinit(dh_parameters
);
947 gnutls_global_deinit();
948 set_server_error("Could not generate Diffie-Hellman parameters: %s",
949 gnutls_strerror(error
));
952 gnutls_certificate_set_dh_params(x509_credentials
, dh_parameters
);
953 /* XXX: dh_parameters are linked from x509_credentials now.
954 * Deinitialization must free x509_credentials before dh_parameters. */
955 if ((error
= gnutls_session_ticket_key_generate(&ticket_key
))) {
956 fprintf(stderr
, "Could not generate TLS session ticket key: %s\n",
957 gnutls_strerror(error
));
958 ticket_key
.data
= NULL
;
962 *server_process
= fork();
963 if (*server_process
== -1) {
964 close(server_socket
);
966 gnutls_free(ticket_key
.data
);
967 gnutls_certificate_free_credentials(x509_credentials
);
968 gnutls_priority_deinit(priority_cache
);
969 gnutls_dh_params_deinit(dh_parameters
);
970 gnutls_global_deinit();
972 set_server_error("Server could not been forked");
976 if (*server_process
== 0) {
978 gnutls_session_t tls_session
;
979 struct http_connection connection
;
980 struct http_request
*request
= NULL
;
986 if ((error
= gnutls_init(&tls_session
, GNUTLS_SERVER
))) {
987 set_server_error("Could not initialize TLS session: %s",
988 gnutls_strerror(error
));
992 if ((error
= gnutls_priority_set(tls_session
,
995 "Could not set priorities to TLS session: %s",
996 gnutls_strerror(error
));
998 gnutls_deinit(tls_session
);
1001 if ((error
= gnutls_credentials_set(tls_session
,
1002 GNUTLS_CRD_CERTIFICATE
, x509_credentials
))) {
1003 set_server_error("Could not set X509 credentials to TLS "
1004 "session: %s", gnutls_strerror(error
));
1006 gnutls_deinit(tls_session
);
1009 if (NULL
!= ticket_key
.data
) {
1010 if ((error
= gnutls_session_ticket_enable_server(
1011 tls_session
, &ticket_key
))) {
1012 fprintf(stderr
, "Could not register ticket key to "
1013 "TLS session: %s\n", gnutls_strerror(error
));
1016 /* XXX: Credentials are linked from session now.
1017 * Deinitializition must free session before x509_credentials.
1019 if (NULL
!= tls
->client_name
) {
1020 client_required_dn
= tls
->client_name
;
1021 /* Require client certificate */
1022 gnutls_certificate_server_set_request(tls_session
,
1023 GNUTLS_CERT_REQUIRE
);
1024 /* And verify it in TLS handshake */
1025 gnutls_certificate_set_verify_function(x509_credentials
,
1030 if (0 > (client_socket
= accept(server_socket
, NULL
, NULL
))) {
1033 gnutls_deinit(tls_session
);
1036 fprintf(stderr
, "Connection accepted\n");
1037 connection
.socket
= client_socket
;
1040 connection
.recv_callback
= recv_plain
;
1041 connection
.send_callback
= send_plain
;
1042 connection
.callback_data
= NULL
;
1044 connection
.recv_callback
= recv_tls
;
1045 connection
.send_callback
= send_tls
;
1046 connection
.callback_data
= tls_session
;
1047 gnutls_transport_set_pull_function(tls_session
, tls_pull
);
1048 gnutls_transport_set_push_function(tls_session
, tls_push
);
1049 gnutls_transport_set_ptr2(tls_session
,
1050 &connection
, &connection
);
1052 error
= gnutls_handshake(tls_session
);
1053 } while (error
< 0 && !gnutls_error_is_fatal(error
));
1055 fprintf(stderr
, "TLS handshake failed: %s\n",
1056 gnutls_strerror(error
));
1057 close(client_socket
);
1058 gnutls_deinit(tls_session
);
1063 error
= http_read_request(&connection
, &request
);
1065 fprintf(stderr
, "Error while reading request\n");
1066 if (error
== HTTP_ERROR_CLIENT
)
1067 http_send_response_400(&connection
, "Error in request");
1069 http_send_response_500(&connection
,
1070 "Could not read request");
1071 close(client_socket
);
1073 gnutls_deinit(tls_session
);
1077 terminate
= server_implementation(&connection
, server_arguments
,
1080 http_request_free(&request
);
1081 close(client_socket
);
1083 gnutls_deinit(tls_session
);
1088 if (NULL
!= ticket_key
.data
) {
1089 gnutls_free(ticket_key
.data
);
1092 close(server_socket
);
1093 free(authorization_cookie_value
);
1095 /* Does not return */
1102 /* Kill the server process.
1103 * Return 0. Return -1 if server could not been stopped. Return 1 if server
1105 int stop_server(pid_t server_process
) {
1107 if (server_process
<= 0) {
1108 set_server_error("Invalid server PID to kill");
1111 if (-1 == kill(server_process
, SIGTERM
)) {
1112 set_server_error("Could not terminate server");
1115 if (-1 == waitpid(server_process
, &status
, 0)) {
1116 set_server_error("Could not wait for server termination");
1119 if (WIFSIGNALED(status
) && WTERMSIG(status
) != SIGTERM
) {
1120 set_server_error("Server terminated by signal %d violently",