OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
SSLServer.cc
Go to the documentation of this file.
1 // SSLServer.cc
2 
3 // This file is part of bes, A C++ back-end server implementation framework
4 // for the OPeNDAP Data Access Protocol.
5 
6 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research
7 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 //
23 // You can contact University Corporation for Atmospheric Research at
24 // 3080 Center Green Drive, Boulder, CO 80301
25 
26 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
27 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
28 //
29 // Authors:
30 // pwest Patrick West <pwest@ucar.edu>
31 // jgarcia Jose Garcia <jgarcia@ucar.edu>
32 
33 #include "config.h"
34 
35 #include <openssl/ssl.h>
36 #include <openssl/err.h>
37 #include <sys/types.h> // not needed in POSIX 2001, still safer
38 #include <sys/socket.h> // for accept setsockopt bind listen
39 #include <netinet/in.h>
40 #include <arpa/inet.h> // for htons
41 #include <netdb.h>
42 
43 #include <iostream>
44 #include <cstring>
45 
46 #ifndef HAVE_SYS_ERRLIST
47 #include <cerrno>
48 #endif
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52 
53 using std::endl ;
54 
55 #include "SSLServer.h"
56 #include "BESInternalError.h"
57 #include "BESDebug.h"
58 
59 SSLServer::SSLServer( int portVal,
60  const string &cert_file,
61  const string &cert_auth_file,
62  const string &key_file )
63  : SSLConnection(),
64  _port( portVal ),
65  _cfile( cert_file ),
66  _cafile( cert_auth_file ),
67  _kfile( key_file )
68 {
69 }
70 
72 {
73 }
74 
75 void
77 {
78  BESDEBUG( "ppt", "Loading SSL error strings ... " << endl ) ;
79  SSL_load_error_strings() ;
80  BESDEBUG( "ppt", "OK" << endl ) ;
81 
82  BESDEBUG( "ppt", "Initializing SSL library ... " << endl ) ;
83  SSL_library_init() ;
84  BESDEBUG( "ppt", "OK" << endl ) ;
85 
86 #if OPENSSL_VERSION_NUMBER < 0x10000000L
87  SSL_METHOD *method = NULL ;
88 #else
89  const SSL_METHOD *method = NULL ;
90 #endif
91  SSL_CTX *context = NULL ;
92  BESDEBUG( "ppt", "Creating method and context ... " << endl ) ;
93  method = SSLv3_server_method() ;
94  if( method )
95  {
96  context = SSL_CTX_new( method ) ;
97  }
98  if( !context )
99  {
100  BESDEBUG( "ppt", "FAILED" << endl ) ;
101  string msg = "Failed to create SSL context\n" ;
102  msg += ERR_error_string( ERR_get_error(), NULL ) ;
103  throw BESInternalError( msg, __FILE__, __LINE__ ) ;
104  }
105  else
106  {
107  BESDEBUG( "ppt", "OK" << endl ) ;
108  }
109 
110  bool ok_2_continue = false ;
111  string err_msg ;
112 
113  BESDEBUG( "ppt", "Setting certificate and key ... " << endl ) ;
114  if( SSL_CTX_use_certificate_file( context, _cfile.c_str(), SSL_FILETYPE_PEM ) <= 0 )
115  {
116  BESDEBUG( "ppt", "FAILED" << endl ) ;
117  err_msg = "FAILED to use certificate file " + _cfile + "\n" ;
118  err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
119  }
120  else if( SSL_CTX_use_PrivateKey_file( context, _kfile.c_str(), SSL_FILETYPE_PEM ) <= 0 )
121  {
122  BESDEBUG( "ppt", "FAILED" << endl ) ;
123  err_msg = "FAILED to use private key file " + _kfile + "\n" ;
124  err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
125  }
126  else if( !SSL_CTX_check_private_key( context ) )
127  {
128  BESDEBUG( "ppt", "FAILED" << endl ) ;
129  err_msg = "FAILED to authenticate private key\n" ;
130  err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
131  }
132  else
133  {
134  ok_2_continue = true ;
135  }
136 
137  if( ok_2_continue )
138  {
139  BESDEBUG( "ppt", "OK" << endl ) ;
140  BESDEBUG( "ppt", "Certificate setup ... " << endl ) ;
141  SSL_CTX_set_verify( context, SSL_VERIFY_PEER, verify_client ) ;
142  SSL_CTX_set_client_CA_list( context, SSL_load_client_CA_file( _cafile.c_str() ));
143  if( ( !SSL_CTX_load_verify_locations( context, _cafile.c_str(), NULL )) ||
144  ( !SSL_CTX_set_default_verify_paths( context ) ) )
145  {
146  BESDEBUG( "ppt", "FAILED" << endl ) ;
147  err_msg = "Certificate setup failed\n" ;
148  err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
149  ok_2_continue = false ;
150  }
151  }
152 
153  int port_fd = -1 ;
154  if( ok_2_continue )
155  {
156  BESDEBUG( "ppt", "OK" << endl ) ;
157 
158  BESDEBUG( "ppt", "Opening port " << _port << "... " << endl ) ;
159  port_fd = open_port( ) ;
160  if( port_fd < 0 )
161  {
162  BESDEBUG( "ppt", "FAILED" << endl ) ;
163  err_msg = "Failed to open port: " ;
164 #ifdef HAVE_SYS_ERRLIST
165  err_msg += sys_errlist[errno] ;
166 #else
167  err_msg += strerror( errno ) ;
168 #endif
169  ok_2_continue = false ;
170  }
171  }
172 
173  int sock_fd = -1 ;
174  if( ok_2_continue )
175  {
176  BESDEBUG( "ppt", "OK" << endl ) ;
177 
178  BESDEBUG( "ppt", "Waiting for client connection ... " << endl ) ;
179  sock_fd = accept( port_fd, NULL, NULL ) ;
180  if( sock_fd < 0 )
181  {
182  BESDEBUG( "ppt", "FAILED" << endl ) ;
183  err_msg = "Failed to accept connection: " ;
184 #ifdef HAVE_SYS_ERRLIST
185  err_msg += sys_errlist[errno] ;
186 #else
187  err_msg += strerror( errno ) ;
188 #endif
189  ok_2_continue = false ;
190  }
191  }
192 
193  if( ok_2_continue )
194  {
195  BESDEBUG( "ppt", "OK" << endl ) ;
196 
197  BESDEBUG( "ppt", "Establishing secure connection ... " << endl ) ;
198  int ssl_ret = 0 ;
199  _connection = SSL_new( context ) ;
200  if( !_connection )
201  {
202  err_msg = "FAILED to create new connection\n" ;
203  err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
204  ok_2_continue = false ;
205  }
206  else if( SSL_set_fd( _connection, sock_fd ) < 0 )
207  {
208  err_msg = "FAILED to set the socket descriptor\n" ;
209  err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
210  ok_2_continue = false ;
211  }
212  else if( ( ssl_ret = SSL_accept( _connection ) ) < 0 )
213  {
214  err_msg = "FAILED to create SSL connection\n" ;
215  err_msg += ERR_error_string( SSL_get_error( _connection, ssl_ret ), NULL ) ;
216  ok_2_continue = false ;
217  }
218  else if( verify_connection( ) < 0 )
219  {
220  err_msg = "FAILED to verify SSL connection\n" ;
221  err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
222  ok_2_continue = false ;
223  }
224  }
225 
226  if( ok_2_continue )
227  {
228  BESDEBUG( "ppt", "OK" << endl ) ;
229  }
230  else
231  {
232  BESDEBUG( "ppt", "FAILED" << endl ) ;
233  if( _context ) SSL_CTX_free( _context ) ; _context = NULL ;
234  throw BESInternalError( err_msg, __FILE__, __LINE__ ) ;
235  }
236 
237  _connected = true ;
238 }
239 
240 int
241 SSLServer::open_port( )
242 {
243  int fd = -1 ;
244  struct sockaddr_in addr ;
245  int on = 1 ;
246 
247  fd = socket( PF_INET, SOCK_STREAM, 0 ) ;
248  if( fd < 0 ) return fd ;
249 
250  setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof( on ) ) ;
251 
252  memset( &addr, 0, sizeof( addr ) ) ;
253  addr.sin_family = AF_INET ;
254  addr.sin_addr.s_addr = INADDR_ANY ;
255  addr.sin_port = htons( _port ) ;
256 
257  if( bind( fd, (struct sockaddr *)&addr, sizeof( addr ) ) < 0 )
258  {
259  close( fd ) ;
260  return -1 ;
261  }
262  if( listen( fd, SOMAXCONN ) < 0 )
263  {
264  close( fd ) ;
265  return -1 ;
266  }
267 
268  return fd ;
269 }
270 
271 int
272 SSLServer::verify_connection( )
273 {
274  X509 *server_cert = NULL ;
275  char *str = NULL ;
276 
277  /*
278  server_cert = SSL_get_peer_certificate( _connection ) ;
279  if( server_cert == NULL )
280  {
281  cout << "server doesn't have a certificate" << endl ;
282  }
283  */
284 
285  return 1 ;
286 }
287 
288 int
289 SSLServer::verify_client( int ok, X509_STORE_CTX *ctx )
290 {
291  if( ok )
292  {
293  BESDEBUG( "ppt", "VERIFIED " << endl ) ;
294  X509 *user_cert = X509_STORE_CTX_get_current_cert( ctx ) ;
295  // FIX: Need to save this certificate somewhere, right?
296  }
297  else
298  {
299  char mybuf[256] ;
300  X509 *err_cert ;
301  int err ;
302 
303  err_cert = X509_STORE_CTX_get_current_cert( ctx ) ;
304  err = X509_STORE_CTX_get_error( ctx ) ;
305  X509_NAME_oneline( X509_get_subject_name( err_cert ), mybuf, 256 ) ;
306  BESDEBUG( "ppt", "FAILED for " << mybuf << endl ) ;
307  BESDEBUG( "ppt", " " << X509_verify_cert_error_string( err )
308  << endl ) ;
309  switch( ctx->error )
310  {
311  case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
312  {
313  X509_NAME_oneline( X509_get_issuer_name( err_cert ), mybuf, 256 ) ;
314  BESDEBUG( "ppt", " issuer = " << mybuf << endl ) ;
315  break ;
316  }
317 
318  case X509_V_ERR_CERT_NOT_YET_VALID:
319  case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
320  {
321  BESDEBUG( "ppt", " not yet valid!" << endl ) ;
322  break ;
323  }
324 
325  case X509_V_ERR_CERT_HAS_EXPIRED:
326  case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
327  {
328  BESDEBUG( "ppt", " expired!" << endl ) ;
329  break ;
330  }
331  default:
332  {
333  BESDEBUG( "ppt", " unknown!" << endl ) ;
334  break ;
335  }
336  }
337  }
338 
339  return 1 ;
340 }
341 
348 void
349 SSLServer::dump( ostream &strm ) const
350 {
351  strm << BESIndent::LMarg << "SSLServer::dump - ("
352  << (void *)this << ")" << endl ;
354  strm << BESIndent::LMarg << "port: " << _port << endl ;
355  strm << BESIndent::LMarg << "cert file: " << _cfile << endl ;
356  strm << BESIndent::LMarg << "cert authority file: " << _cafile << endl ;
357  strm << BESIndent::LMarg << "key file: " << _kfile << endl ;
358  SSLConnection::dump( strm ) ;
360 }
361 
virtual void dump(ostream &strm) const
dumps information about this object
exception thrown if inernal error encountered
virtual void dump(ostream &strm) const
dumps information about this object
Definition: SSLServer.cc:349
~SSLServer()
Definition: SSLServer.cc:71
static void Indent()
Definition: BESIndent.cc:38
static ostream & LMarg(ostream &strm)
Definition: BESIndent.cc:73
SSL_CTX * _context
Definition: SSLConnection.h:50
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
virtual void initConnection()
Definition: SSLServer.cc:76
static void UnIndent()
Definition: BESIndent.cc:44
SSLServer(int portVal, const string &cert_file, const string &cert_auth_file, const string &key_file)
Definition: SSLServer.cc:59