Wrong licensing texts removed and GPL code eliminated.
[igd2-for-linux:jeevans-deviceprotection.git] / pupnp_branch-1.6.x / upnp / src / genlib / miniserver / httpsserver.c
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2009-2011  Nokia Corporation and/or its subsidiary(-ies).
4 // All rights reserved. 
5 //
6 // Contact: mika.saaranen@nokia.com
7 // Developer(s): jaakko.pasanen@tieto.com, opensource@tieto.com
8 //
9 // Redistribution and use in source and binary forms, with or without 
10 // modification, are permitted provided that the following conditions are met: 
11 //
12 // * Redistributions of source code must retain the above copyright notice, 
13 // this list of conditions and the following disclaimer. 
14 // * Redistributions in binary form must reproduce the above copyright notice, 
15 // this list of conditions and the following disclaimer in the documentation 
16 // and/or other materials provided with the distribution. 
17 // * Neither name of Nokia Corporation nor the names of its contributors 
18 // may be used to endorse or promote products derived from this software 
19 // without specific prior written permission.
20 // 
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NOKIA OR 
25 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
26 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
27 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
28 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
29 // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
31 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 ///////////////////////////////////////////////////////////////////////////
34
35
36 #include <arpa/inet.h>
37 #include <netinet/in.h>
38 #include <sys/socket.h>
39 #include <sys/wait.h>
40
41 #include <resolv.h>
42 #include <gnutls/gnutls.h>
43 #include <gnutls/x509.h>
44
45 #include "httpsserver.h"
46 #include "httpreadwrite.h"
47 #include "upnpapi.h"
48 #include "miniserver.h"
49 #include "statcodes.h"
50 #include "pki.h"
51
52 #define DH_BITS 1024
53
54 static gnutls_certificate_credentials_t x509_cred;
55 static gnutls_priority_t priority_cache;
56 static gnutls_dh_params_t dh_params;
57 static unsigned int server_crt_size = MAX_CRT;
58 static gnutls_x509_crt_t server_crt[MAX_CRT];
59 static gnutls_x509_privkey_t server_privkey= NULL;
60
61 static int RUNNING = 0;
62 static int PORT = 0;
63
64 /* Static function declarations */
65 static SOCKET get_listener_socket(int port);
66 static gnutls_session_t initialize_tls_session (void);
67 static int generate_dh_params (void);
68 static void RunHttpsServer( SOCKET listen_sd );
69 static int tcp_connect (void);
70 static void tcp_close (int sd);
71
72  
73 /************************************************************************
74  * Function: verify_certificate
75  *
76  * Parameters:
77  *  IN gnutls_session_t session - Gnutls session
78  *  IN const char *hostname - Value of Common Name (CN) element in peer certificate.
79  *
80  * Description:
81  *  This function will try to verify the peer's certificate, and
82  *  also check if the hostname matches, and the activation, expiration dates.
83  *
84  * Return: int
85  *  GNU TLS error codes or -1
86  *  GNUTLS_E_SUCCESS - on success
87  ************************************************************************/ 
88 static int verify_certificate (gnutls_session_t session, const char *hostname)
89 {
90     unsigned int status;
91     const gnutls_datum_t *cert_list;
92     unsigned int cert_list_size;
93     int ret;
94     gnutls_x509_crt_t cert;
95
96
97     /* This verification function uses the trusted CAs in the credentials
98      * structure. So you must have installed one or more CA certificates.
99      */
100     ret = gnutls_certificate_verify_peers2 (session, &status);
101
102     if (ret != GNUTLS_E_SUCCESS)
103     {
104         UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__,
105             "Error verifying peer certificates: %s\n", gnutls_strerror(ret) );
106         return ret;
107     }
108
109     if (status & GNUTLS_CERT_INVALID)
110     {
111         UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__,
112             "Peer certificate is not trusted\n");
113         return GNUTLS_CERT_INVALID;
114     }
115
116     if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
117     {
118         UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__,
119             "Peer certificate hasn't got a known issuer\n");
120         return GNUTLS_CERT_SIGNER_NOT_FOUND;
121     }
122
123     if (status & GNUTLS_CERT_REVOKED)
124     {
125         UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__,
126             "Peer certificate has been revoked\n");
127         return GNUTLS_CERT_REVOKED;
128     }
129
130
131     /* Up to here the process is the same for X.509 certificates and
132      * OpenPGP keys. From now on X.509 certificates are assumed. This can
133      * be easily extended to work with openpgp keys as well.
134      */
135     if ((ret = gnutls_certificate_type_get (session)) != GNUTLS_CRT_X509)
136     {
137         UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__,
138             "Peer certificate type must be X.509. Wrong type received.\n");
139         return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
140     }
141
142     if ((ret = gnutls_x509_crt_init (&cert)) != GNUTLS_E_SUCCESS)
143     {
144         UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__,
145             "Peer certificate failed to initialize: %s\n",gnutls_strerror(ret) );
146         return ret;
147     }
148
149     cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
150     if (cert_list == NULL)
151     {
152         UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__,
153             "No Peer certificate was found\n");
154         return GNUTLS_E_NO_CERTIFICATE_FOUND;
155     }
156
157     int i;
158     for (i = 0; i < cert_list_size; i++)
159     {
160         if ((ret = gnutls_x509_crt_import (cert, &cert_list[i], GNUTLS_X509_FMT_DER)) != GNUTLS_E_SUCCESS)
161         {
162             UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__,
163                 "Error parsing Peer certificate: %s\n",gnutls_strerror(ret) );
164             gnutls_x509_crt_deinit (cert);
165             return ret;
166         }
167
168         // validate expiration times and hostname
169         ret = validate_x509_certificate(&cert, hostname, NULL);
170         gnutls_x509_crt_deinit (cert);
171
172         if (ret != 0) return ret;
173     }
174
175     return GNUTLS_E_SUCCESS;
176 }
177
178
179
180 /************************************************************************
181  * Function: get_listener_socket
182  *
183  * Parameters:
184  *  IN int port - Port number which is binded for socket
185  *
186  * Description:
187  *  Create listener socket for https-server. 
188  *
189  * Return: int
190  *  Created socket on success, else:
191  *  UPNP_E_OUTOF_SOCKET - Failed to create a socket
192  *  UPNP_E_SOCKET_BIND - Bind() failed
193  *  UPNP_E_LISTEN   - Listen() failed   
194  *  UPNP_E_SOCKET_ERROR - Setsockopt() failed
195  ************************************************************************/
196 static SOCKET get_listener_socket(int port)
197 {
198     struct sockaddr_in sa_serv;
199     SOCKET listen_sd;
200     int err;
201     int optval = 1;
202
203     listen_sd = socket (AF_INET, SOCK_STREAM, 0);
204     if (listen_sd == -1)
205     {
206         UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__,
207             "Error in creating HTTPS socket!!!\n" );
208         return UPNP_E_OUTOF_SOCKET;
209     }
210
211     memset (&sa_serv, '\0', sizeof (sa_serv));
212     sa_serv.sin_family = AF_INET;
213     sa_serv.sin_addr.s_addr = INADDR_ANY;
214     sa_serv.sin_port = htons (port);  /* Server Port number */
215
216     err = setsockopt (listen_sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int));
217     if (err == -1)
218     {
219         UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__,
220             "Error in setsockopt() HTTPS socket!!!\n" );
221         return UPNP_E_SOCKET_ERROR;
222     }
223
224     err = bind (listen_sd, (struct sockaddr *) & sa_serv, sizeof (sa_serv));
225     if (err == -1)
226     {
227         UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__,
228             "Error in binding HTTPS socket!!!\n" );
229         return UPNP_E_SOCKET_BIND;
230     }
231     err = listen (listen_sd, 1024);
232     if (err == -1)
233     {
234         UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__,
235             "Error in listen() HTTPS socket!!!\n" );
236         return UPNP_E_LISTEN;
237     }
238
239     return listen_sd;
240 }
241
242 /************************************************************************
243  * Function: initialize_tls_session
244  *
245  * Parameters:
246  *  void
247  *
248  * Description:
249  *  Create and initialize new gnutls session object for https-server
250  *
251  * Return: gnutls_session_t
252  *  Created session.
253  ************************************************************************/
254 static gnutls_session_t initialize_tls_session (void)
255 {
256     gnutls_session_t session;
257     int ret;
258
259     ret = gnutls_init (&session, GNUTLS_SERVER);
260     if (ret != GNUTLS_E_SUCCESS)
261         return ( gnutls_session_t ) ret;
262
263     ret = gnutls_priority_set (session, priority_cache);
264     if (ret != GNUTLS_E_SUCCESS)
265         return ( gnutls_session_t ) ret;
266
267     ret = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
268     if (ret != GNUTLS_E_SUCCESS)
269         return ( gnutls_session_t ) ret;
270
271     /* request client certificate if any. */
272     gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
273
274     return session;
275 }
276
277
278 /************************************************************************
279  * Function: generate_dh_params
280  *
281  * Parameters:
282  *  void
283  *
284  * Description:
285  *  Generate Diffie Hellman parameters - for use with DHE
286  *  kx algorithms. When short bit length is used, it might
287  *  be wise to regenerate parameters.
288  *
289  *  Check the ex-serv-export.c example for using static
290  *  parameters.
291  *
292  * Return: int
293  *  Return alway 0.
294  ************************************************************************/
295 static int
296 generate_dh_params (void)
297 {
298     gnutls_dh_params_init (&dh_params);
299     gnutls_dh_params_generate2 (dh_params, DH_BITS);
300
301     return 0;
302 }
303
304 /************************************************************************
305  * Function: free_handle_https_request_arg
306  *
307  * Parameters:
308  *  void *args - Request Message to be freed
309  *
310  * Description:
311  *  Free memory assigned for handling request and unitialize socket
312  *  functionality
313  *
314  * Return: void
315  ************************************************************************/
316 static void
317 free_handle_https_request_arg( void *args )
318 {
319     SOCKET sock = ( SOCKET )args;
320     shutdown( sock, SD_BOTH );
321     UpnpCloseSocket( sock );
322 }
323
324 /************************************************************************
325  * Function: handle_https_request
326  *
327  * Parameters:
328  *  void *args - Socket Descriptor on which connection is accepted
329  *
330  * Description:
331  *  Create tls session, receive the request and dispatch it for handling
332  *
333  * Return: void
334  ************************************************************************/
335 static void 
336 handle_https_request(void *args)
337 {
338     int http_error_code = 0;
339     int major = 1;
340     int minor = 1;
341     http_parser_t arser;
342     http_parser_t *parser = &arser;
343     http_message_t *hmsg = NULL;
344     int ret;
345     gnutls_session_t session;
346     struct mserv_request_t *request = ( struct mserv_request_t * )args;
347     int sock = request->connfd;
348     int line = 0;
349     parse_status_t status;
350     int num_read;
351     xboolean ok_on_close = FALSE;
352     int max_record_size = 0;
353     char *buf = NULL;
354
355     /* create session */
356     session = initialize_tls_session();
357     if (session < 0)
358     {
359         UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__,
360             "Error initialising tls session: %s\n", gnutls_strerror(( int )session) );
361         goto ExitFunction;
362     }
363
364     /* require that client provide a certificate */
365     gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUIRE);
366
367     gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sock);
368
369     ret = gnutls_handshake (session);
370
371     if (ret != GNUTLS_E_SUCCESS) {
372         UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__,
373             "Handshake has failed: %s\n", gnutls_strerror(ret) );
374         goto ExitFunction;
375     }
376
377     // TODO: what is hostname value?????????! Is this even needed?
378     // check client certificate. Is it trusted and such
379     if ((ret = verify_certificate(session, "TestDevice")) != GNUTLS_E_SUCCESS) {
380         //goto error_handler;
381     }
382
383     SOCKINFO info;
384     info.tls_session = session;
385     info.socket = sock;
386     info.foreign_ip_addr = request->foreign_ip_addr;
387     info.foreign_ip_port = request->foreign_ip_port;
388
389
390     // following is copy from http_RecvMessage
391     ret = UPNP_E_SUCCESS;
392     max_record_size = gnutls_record_get_max_size(session);
393     buf = malloc(max_record_size);
394
395     // init parser
396     parser_request_init(parser);
397
398     // this loop serves one SSL session
399     while (TRUE) {
400         memset (buf, 0, max_record_size);
401         num_read = gnutls_record_recv (session, buf, max_record_size);
402         if (num_read > 0) {
403             // got data
404             status = parser_append(parser, buf, num_read);
405
406             if (status == PARSE_SUCCESS) {
407                 UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
408                     "<<< (RECVD) <<<\n%s\n-----------------\n",
409                     parser->msg.msg.buf );
410                 print_http_headers( &parser->msg );
411                 if (parser->content_length > (unsigned int)g_maxContentLength) {
412                     http_error_code = HTTP_REQ_ENTITY_TOO_LARGE;
413                     line = __LINE__;
414                     ret = UPNP_E_OUTOF_BOUNDS;
415                     goto ExitFunction;
416                 }
417
418                 // whole message is parsed. Dispatch message
419                 http_error_code = dispatch_request( &info, parser );
420                 if( http_error_code != 0 ) {
421                     goto ExitFunction;
422                 }
423
424                 // init parser for next message
425                 httpmsg_destroy(&parser->msg);
426                 parser_request_init(parser);
427             } else if (status == PARSE_FAILURE) {
428                 http_error_code = parser->http_error_code;
429                 line = __LINE__;
430                 ret = UPNP_E_BAD_HTTPMSG;
431                 goto ExitFunction;
432             } else if (status == PARSE_INCOMPLETE_ENTITY) {
433                 // read until close
434                 ok_on_close = TRUE;
435             } else if (status == PARSE_CONTINUE_1) {
436                 // Web post request.
437                 line = __LINE__;
438                 ret = PARSE_SUCCESS;
439                 goto ExitFunction;
440             }
441         } else if (num_read == 0) {
442             //peer has closed connection
443             http_error_code = UPNP_E_SUCCESS;
444             UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
445                     "(handle_https_request): Peer has closed SSL connection\n");
446             // because client has closed session, we can deinit session 
447             gnutls_deinit (session);
448             session = NULL;
449             goto ExitFunction;
450         } else {
451             // received corrupted data
452             http_error_code = parser->http_error_code;
453             line = __LINE__;
454             ret = num_read;
455             UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
456                     "(handle_https_request): gnutls received corrupted data\n");
457             session = NULL;         // session may not exist anymore
458             goto ExitFunction;
459         }
460     }
461
462
463 ExitFunction:
464     if( http_error_code != UPNP_E_SUCCESS ) {
465         UpnpPrintf(UPNP_ALL, HTTP, __FILE__, line,
466             "(handle_https_request): Error %d, http_error_code = %d.\n",
467             ret,
468             http_error_code);
469
470         if( hmsg ) {
471             major = hmsg->major_version;
472             minor = hmsg->minor_version;
473         }
474         handle_error( &info, http_error_code, major, minor );
475     }
476
477     if (session != NULL)
478     {
479         gnutls_bye (session, GNUTLS_SHUT_RDWR);
480         gnutls_deinit (session);
481     }
482     close (sock);
483     free(request);
484     free(buf);
485 }
486
487 /************************************************************************
488  * Function: schedule_https_request_job
489  *
490  * Parameters:
491  *  IN int sock - Socket Descriptor on which connection is accepted
492  *  IN struct sockaddr_in* clientAddr - Clients Address information
493  *
494  * Description:
495  *  Initilize the thread pool to handle a request.
496  *  Sets priority for the job and adds the job to the thread pool
497  *
498  * Return: void
499  ************************************************************************/
500 static UPNP_INLINE void
501 schedule_https_request_job( IN SOCKET sock,
502                             IN struct sockaddr_in *clientAddr )
503 {
504     struct mserv_request_t *request;
505     ThreadPoolJob job;
506
507     request =
508         ( struct mserv_request_t * )
509         malloc( sizeof( struct mserv_request_t ) );
510     if( request == NULL ) {
511         UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
512             "mserv (https) %d: out of memory\n", sock );
513         shutdown( sock, SD_BOTH );
514         UpnpCloseSocket( sock );
515         return;
516     }
517
518     request->connfd = sock;
519     request->foreign_ip_addr = clientAddr->sin_addr;
520     request->foreign_ip_port = ntohs( clientAddr->sin_port );
521
522     TPJobInit( &job, ( start_routine ) handle_https_request, ( void * ) request );
523     TPJobSetFreeFunction( &job, free_handle_https_request_arg );
524     TPJobSetPriority( &job, MED_PRIORITY );
525
526     if( ThreadPoolAdd( &gHttpsServerThreadPool, &job, NULL ) != 0 ) {
527         UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
528             "https: cannot schedule request\n" );
529         shutdown( sock, SD_BOTH );
530         UpnpCloseSocket( sock );
531         return;
532     }
533 }
534
535 /************************************************************************
536  * Function: RunHttpsServer
537  *
538  * Parameters:
539  *  SOCKET listen_sd - Socket Descriptor on which Https-server is listening
540  *
541  * Description:
542  *  Function runs the https server. The HttpsServer accepts a 
543  *  new request and schedules a thread to handle the new request.
544  *  Checks for socket state and invokes appropriate read and shutdown 
545  *  actions for the https server 
546  *
547  * Return: void
548  ************************************************************************/
549 static void
550 RunHttpsServer( SOCKET listen_sd )
551 {
552     struct sockaddr_in addr;
553     socklen_t len = sizeof(addr);
554     SOCKET sd;
555
556     RUNNING = 1;
557
558     while (RUNNING) {
559         sd = accept(listen_sd, ( struct sockaddr * )&addr, &len);
560
561         /* is there really a connection */
562         if (sd > 0)
563         {
564             UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
565                 "Https Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
566
567             schedule_https_request_job(sd, &addr);
568         }
569     }
570     tcp_close (listen_sd);
571 }
572
573 /************************************************************************
574  * Function: StartHttpsServer
575  *
576  * Parameters :
577  *  unsigned short listen_port - Port on which the server listens for incoming connections
578  *  const char *directory: Path to directory where files locate or where files are created
579  *  const char *CertFile: Selfsigned certificate file of server. If NULL, new certificate and private key is created
580  *  const char *PrivKeyFile: Private key file of server. If NULL, new private key is created
581  *  const char *TrustFile: File containing trusted certificates. (PEM format). May be NULL
582  *  const char *CRLFile: Certificate revocation list. Untrusted certificates. (PEM format). May be NULL
583  *  char* cn - Common name value used in certificate, name of device or something similar
584  * 
585  * Description:
586  *  Initialize gnutls for the https server. Initialize a thread pool job to run the server
587  *  and the job to the thread pool.
588  *  All files must be in PEM format.
589  *
590  * Return: int
591  *  Actual port socket is bound to - On Success
592  *  A negative number, either UPNP or gnutls error - On Error
593  ************************************************************************/
594 int
595 StartHttpsServer( IN unsigned short listen_port,
596                   IN const char *directory,
597                   IN const char *CertFile,
598                   IN const char *PrivKeyFile,
599                   IN const char *TrustFile,
600                   IN const char *CRLFile,
601                   IN const char *cn)
602 {
603     /* for shutdown purposes */
604     PORT = listen_port;
605     SOCKET listen_sd;
606     int retVal;
607
608     retVal = init_crypto_libraries();
609     if (retVal != 0) {
610         UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
611             "StartHttpsServer: Crypto library initialization failed\n");
612         return retVal;
613     }
614
615     if (CertFile && PrivKeyFile) {
616         // put certificate and private key in global variables for use in tls handshake
617         retVal = load_x509_self_signed_certificate(server_crt, &server_crt_size, &server_privkey, directory, CertFile, PrivKeyFile, cn, UPNP_X509_CERT_MODULUS_SIZE, UPNP_X509_CERT_LIFETIME, 0);
618         if ( retVal != GNUTLS_E_SUCCESS ) {
619             UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
620                 "StartHttpsServer: Certificate loading failed \n" );
621             return retVal;
622         }
623         retVal = init_x509_certificate_credentials(&x509_cred, directory, CertFile, PrivKeyFile, TrustFile, CRLFile);
624         if ( retVal != GNUTLS_E_SUCCESS ) {
625             UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
626                 "StartHttpsServer: Certificate credentials creating failed \n" );
627             return retVal;
628         }
629     }
630     else {
631         // create own private key and self signed certificate or use default file
632         retVal = load_x509_self_signed_certificate(server_crt, &server_crt_size, &server_privkey, directory, UPNP_X509_SERVER_CERT_FILE, UPNP_X509_SERVER_PRIVKEY_FILE, cn, UPNP_X509_CERT_MODULUS_SIZE, UPNP_X509_CERT_LIFETIME, 0);
633         if ( retVal != GNUTLS_E_SUCCESS ) {
634             UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
635                 "StartHttpsServer: Certificate loading failed \n" );
636             return retVal;
637         }
638         retVal = init_x509_certificate_credentials(&x509_cred, directory, UPNP_X509_SERVER_CERT_FILE, UPNP_X509_SERVER_PRIVKEY_FILE, TrustFile, CRLFile);
639         if ( retVal != GNUTLS_E_SUCCESS ) {
640             UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
641                 "StartHttpsServer: Certificate credentials creating failed \n" );
642             return retVal;
643         }
644     }
645
646     generate_dh_params ();
647
648     // Sets priorities for the ciphers, key exchange methods, macs and compression methods.
649     retVal = gnutls_priority_init (&priority_cache, "NORMAL", NULL);
650     if (retVal != GNUTLS_E_SUCCESS) {
651         UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
652             "StartHttpsServer: gnutls_priority_init failed. (%s)\n\n", gnutls_strerror (retVal));
653         return retVal;
654     }
655
656     gnutls_certificate_set_dh_params (x509_cred, dh_params);
657
658     /* create listen socket */
659     listen_sd = get_listener_socket(listen_port);
660
661     if (listen_sd < 0) {
662         return listen_sd; /* failure in creating socket */
663     }
664
665     ThreadPoolJob job;
666
667     TPJobInit( &job, (start_routine)RunHttpsServer, (void *)listen_sd );
668     TPJobSetPriority( &job, MED_PRIORITY );
669     TPJobSetFreeFunction( &job, ( free_routine ) free );
670
671     int success = ThreadPoolAddPersistent( &gHttpsServerThreadPool, &job, NULL );
672     if ( success < 0 ) {
673         StopHttpsServer();
674         return UPNP_E_OUTOF_MEMORY;
675     }
676
677     return listen_port;
678 }
679
680 /************************************************************************
681  * Function: StopHttpsServer
682  *
683  * Parameters:
684  *  void
685  *
686  * Description:
687  *  Send ShutDown message for local https server. Creates ssl session for
688  *  message sending.
689  *
690  * Return: int
691  *      Always returns 0 
692  ************************************************************************/
693 int
694 StopHttpsServer(void)
695 {
696     RUNNING = 0; /* this stops RunHttpsServer() */
697
698     /* this will get execution out of accept() in RunHttpsServer */
699     tcp_close(tcp_connect());
700
701     /* this will give time for server to try to create tls session with our "client" and exit,
702      * before we free all the certificates and stuff from the server */
703     sleep(1);
704
705     //gnutls_x509_crt_deinit(server_crt);
706     gnutls_x509_privkey_deinit(server_privkey);
707     gnutls_certificate_free_credentials (x509_cred);
708     gnutls_priority_deinit (priority_cache);
709     gnutls_global_deinit ();
710
711     return 0;
712 }
713
714 /************************************************************************
715  * Function: StopHttpsServer
716  *
717  * Parameters:
718  *  void
719  *
720  * Description:
721  *  Create socket and connect it to local https server.
722  *  Code from gnutls examples.
723  *
724  * Return: int
725  *      Created socket descriptor 
726  ************************************************************************/
727 static int
728 tcp_connect (void)
729 {
730     const char *SERVER = "127.0.0.1";
731     int err, sd;
732     struct sockaddr_in sa;
733
734     /* connects to server */
735     sd = socket (AF_INET, SOCK_STREAM, 0);
736
737     memset (&sa, '\0', sizeof (sa));
738     sa.sin_family = AF_INET;
739     sa.sin_port = htons (PORT);
740     inet_pton (AF_INET, SERVER, &sa.sin_addr);
741
742     err = connect (sd, (struct sockaddr *) & sa, sizeof (sa));
743     if (err < 0)
744     {
745         UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
746             "Https shutdown client failed to create socket\n");
747         return UPNP_E_OUTOF_SOCKET;
748     }
749
750     return sd;
751 }
752
753 /************************************************************************
754  * Function: tcp_close
755  *
756  * Parameters:
757  *  int sd - Socket descriptor
758  *
759  * Description:
760  *  Close given socket descriptor.
761  *  Code from gnutls examples.
762  *
763  * Return: void 
764  ************************************************************************/
765 static void
766 tcp_close (int sd)
767 {
768     shutdown (sd, SHUT_RDWR); /* no more receptions */
769     close (sd);
770 }
771
772 /************************************************************************
773  * Function: export_server_cert
774  *
775  * Parameters:
776  *  unsigned char *data - Certificate is returned in DER format here
777  *  int *data_size - Pointer to integer which represents length of certificate
778  *
779  * Description:
780  *  Get X.509 certificate that HTTPS server uses in DER format.
781  *
782  * Return: int
783  *      0 on success, gnutls error else. 
784  ************************************************************************/
785 int
786 export_server_cert (unsigned char *data, int *data_size)
787 {
788     int ret;
789
790     if (server_crt == NULL)
791         return GNUTLS_E_X509_CERTIFICATE_ERROR;
792
793     // export first certificate from the chain to data
794     ret = gnutls_x509_crt_export(server_crt[0], GNUTLS_X509_FMT_DER, data, (size_t *)data_size);
795     if (ret < 0) {
796         UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
797             "Error: gnutls_x509_crt_export failed. %s", gnutls_strerror(ret) );
798         return ret;
799     }
800
801     return UPNP_E_SUCCESS;
802 }