ffead.server.doc
SSLClient.cpp
1 /*
2  Copyright 2010, Sumeet Chhetri
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 /*
17  * SSLClient.cpp
18  *
19  * Created on: Dec 14, 2010
20  * Author: sumeet
21  */
22 
23 #include "SSLClient.h"
24 
25 SSLClient::SSLClient() {
26  logger = Logger::getLogger("SSLClient");
27 }
28 
29 SSLClient::~SSLClient() {
30 }
31 static char *pass;
32 
33 static void sigpipe_handle(int x){
34 }
35 
36 static int password_cb(char *buf,int num,
37  int rwflag,void *userdata)
38  {
39  if(num<(int)(strlen(pass)+1))
40  return(0);
41 
42  strcpy(buf,pass);
43  return(strlen(pass));
44  }
45 
46 SSL_CTX *SSLClient::initialize_ctx(char *keyfile,char *password)
47  {
48  SSL_METHOD *meth;
49  SSL_CTX *ctx;
50 
51  /* Global system initialization*/
52  SSL_library_init();
53  SSL_load_error_strings();
54 
55  /* Set up a SIGPIPE handler */
56  signal(SIGPIPE,sigpipe_handle);
57 
58  /* Create our context*/
59  meth=(SSL_METHOD*)SSLv23_method();
60  ctx=SSL_CTX_new(meth);
61 
62  /* Load our keys and certificates*/
63  if(!(SSL_CTX_use_certificate_chain_file(ctx,
64  keyfile)))
65  logger << "Can't read certificate file" << flush;
66 
67  pass=password;
68  SSL_CTX_set_default_passwd_cb(ctx,
69  password_cb);
70  if(!(SSL_CTX_use_PrivateKey_file(ctx,
71  keyfile,SSL_FILETYPE_PEM)))
72  logger << "Can't read key file" << flush;
73 
74  /* Load the CAs we trust*/
75  if(!(SSL_CTX_load_verify_locations(ctx,
76  CA_LIST,0)))
77  logger << "Can't read CA list" << flush;
78 #if (OPENSSL_VERSION_NUMBER < 0x00905100L)
79  SSL_CTX_set_verify_depth(ctx,1);
80 #endif
81 
82  return ctx;
83 }
84 
85 void SSLClient::destroy_ctx(SSL_CTX *ctx)
86 {
87  SSL_CTX_free(ctx);
88 }
89 
90 void SSLClient::closeSSL()
91 {
92  int r=SSL_shutdown(ssl);
93  if(!r){
94  /*If we called SSL_shutdown() first then
95  we always get return value of '0'. In
96  this case, try again, but first send a
97  TCP FIN to trigger the other side's
98  close_notify*/
99  shutdown(sockfd,1);
100  r=SSL_shutdown(ssl);
101  }
102  switch(r){
103  case 1:
104  break; /* Success */
105  case 0:
106  case -1:
107  default:
108  logger << "shutdown failed" << flush;
109  }
110  BIO_free_all(io);
111  SSL_free(ssl);
112 }
113 
114 bool SSLClient::connection(string host,int port)
115 {
116  if(host=="localhost")
117  {
118  return connectionUnresolv(host, port);
119  }
120 
121  struct sockaddr_in *remote;
122  int tmpres;
123  char *ip;
124 
125  sockfd = create_tcp_socket();
126  ip = get_ip((char*)host.c_str());
127  fprintf(stderr, "IP is %s\n", ip);
128  remote = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in *));
129  remote->sin_family = AF_INET;
130  tmpres = inet_pton(AF_INET, ip, (void *)(&(remote->sin_addr.s_addr)));
131  if( tmpres < 0)
132  {
133  perror("Can't set remote->sin_addr.s_addr");
134  return false;
135  }
136  else if(tmpres == 0)
137  {
138  fprintf(stderr, "%s is not a valid IP address\n", ip);
139  return false;
140  }
141  remote->sin_port = htons(port);
142 
143  if(connect(sockfd, (struct sockaddr *)remote, sizeof(struct sockaddr)) < 0){
144  perror("Could not connect");
145  connected = false;
146  } else {
147  connected = true;
148  }
149 
150  free(remote);
151  free(ip);
152 
153  /* Build our SSL context*/
154  ctx=initialize_ctx((char*)KEYFILE,(char*)PASSWORD);
155 
156  /* Connect the SSL socket */
157  ssl=SSL_new(ctx);
158  sbio=BIO_new_socket(sockfd,BIO_CLOSE);
159  SSL_set_bio(ssl,sbio,sbio);
160  io=BIO_new(BIO_f_buffer());
161  ssl_bio=BIO_new(BIO_f_ssl());
162  BIO_set_ssl(ssl_bio,ssl,BIO_NOCLOSE);
163  BIO_push(io,ssl_bio);
164 
165  if(SSL_connect(ssl)<=0)
166  {
167  logger << "SSL connect error";
168  return false;
169  }
170  ERR_clear_error();
171  connected = true;
172  return true;
173 }
174 
175 bool SSLClient::connectionUnresolv(string host,int port)
176 {
177  struct addrinfo hints, *servinfo, *p;
178  int rv;
179  char s[INET6_ADDRSTRLEN];
180 
181  memset(&hints, 0, sizeof hints);
182  hints.ai_family = AF_UNSPEC;
183  hints.ai_socktype = SOCK_STREAM;
184  string sport = CastUtil::lexical_cast<string>(port);
185  if ((rv = getaddrinfo(host.c_str(), sport.c_str(), &hints, &servinfo)) != 0) {
186  fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
187  return false;
188  }
189 
190  // loop through all the results and connect to the first we can
191  for(p = servinfo; p != NULL; p = p->ai_next) {
192  if ((sockfd = socket(p->ai_family, p->ai_socktype,
193  p->ai_protocol)) == -1) {
194  perror("client: socket");
195  continue;
196  }
197 
198  if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
199  close(sockfd);
200  perror("client: connect");
201  connected = false;
202  continue;
203  } else {
204  connected = true;
205  }
206  break;
207  }
208 
209  if (p == NULL) {
210  fprintf(stderr, "client: failed to connect\n");
211  return false;
212  }
213 
214  inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
215  s, sizeof s);
216  //printf("client: connecting to %s\n", s);
217 
218  freeaddrinfo(servinfo); // all done with this structure
219 
220  /* Build our SSL context*/
221  ctx=initialize_ctx((char*)KEYFILE,(char*)PASSWORD);
222 
223  /* Connect the SSL socket */
224  ssl=SSL_new(ctx);
225  sbio=BIO_new_socket(sockfd,BIO_CLOSE);
226  SSL_set_bio(ssl,sbio,sbio);
227  io=BIO_new(BIO_f_buffer());
228  ssl_bio=BIO_new(BIO_f_ssl());
229  BIO_set_ssl(ssl_bio,ssl,BIO_NOCLOSE);
230  BIO_push(io,ssl_bio);
231 
232  if(SSL_connect(ssl)<=0)
233  {
234  logger << "SSL connect error";
235  return false;
236  }
237  ERR_clear_error();
238  return connected;
239 }
240 
241 int SSLClient::sendData(string data)
242 {
243  ERR_clear_error();
244  while(data.length()>0)
245  {
246  int bytes = SSL_write(ssl, data.c_str(), data.length());
247  switch(SSL_get_error(ssl,bytes)){
248  case SSL_ERROR_NONE:
249  break;
250  default:
251  logger << "SSL write problem" ;
252  return 0;
253  }
254  data = data.substr(bytes);
255  }
256  return 1;
257 }
258 
259 string SSLClient::getData(string hdrdelm,string cntlnhdr)
260 {
261  return getTextData(hdrdelm, cntlnhdr);
262 }
263 
264 string SSLClient::getTextData(string hdrdelm,string cntlnhdr)
265 {
266  int er=-1;
267  bool flag = true;
268  string alldat;
269  int cntlen;
270  char buf[MAXBUFLE];
271  while(flag)
272  {
273  er = BIO_gets(io,buf,MAXBUFLE-1);
274  switch(SSL_get_error(ssl,er))
275  {
276  case SSL_ERROR_NONE:
277  break;
278  case SSL_ERROR_ZERO_RETURN:
279  {
280  logger << "SSL - Connection closed\n";
281  return alldat;
282  }
283  default:
284  {
285  logger << "SSL read problem";
286  return alldat;
287  }
288  }
289  if(!strcmp(buf,hdrdelm.c_str()))
290  {
291  string tt(buf, er);
292  alldat += tt;
293  break;
294  }
295  string temp(buf, er);
296  temp = temp.substr(0,temp.length()-1);
297  alldat += (temp + "\n");
298  if(temp.find(cntlnhdr)!=string::npos)
299  {
300  std::string cntle = temp.substr(temp.find(": ")+2);
301  cntle = cntle.substr(0,cntle.length()-1);
302  try
303  {
304  cntlen = CastUtil::lexical_cast<int>(cntle);
305  }
306  catch(...)
307  {
308  logger << "bad lexical cast" <<endl;
309  }
310  }
311  memset(&buf[0], 0, sizeof(buf));
312  }
313  while(cntlen>0)
314  {
315  //logger << "reading conetnt " << cntlen;
316  int toRead = cntlen;
317  if(cntlen>MAXBUFLE)
318  toRead = MAXBUFLE - 1;
319  er = BIO_read(io,buf,toRead);
320  switch(SSL_get_error(ssl,er))
321  {
322  case SSL_ERROR_NONE:
323  cntlen -= er;
324  break;
325  case SSL_ERROR_ZERO_RETURN:
326  {
327  logger << "SSL - Connection closed\n";
328  return alldat;
329  }
330  default:
331  {
332  logger << "SSL read problem";
333  return alldat;
334  }
335  }
336  string temp(buf, er);
337  alldat += temp;
338  memset(&buf[0], 0, sizeof(buf));
339  }
340  return alldat;
341 }
342 
343 string SSLClient::getData(int cntlen)
344 {
345  string alldat;
346  char buf[MAXBUFLE];
347  int er;
348  while(cntlen>0)
349  {
350  //logger << "reading content " << cntlen;
351  er = BIO_read(io,buf,cntlen);
352  switch(SSL_get_error(ssl,er))
353  {
354  case SSL_ERROR_NONE:
355  cntlen -= er;
356  break;
357  case SSL_ERROR_ZERO_RETURN:
358  {
359  logger << "SSL - Connection closed\n";
360  return alldat;
361  }
362  default:
363  {
364  logger << "SSL read problem\n";
365  return alldat;
366  }
367  }
368  alldat += (buf);
369  memset(&buf[0], 0, sizeof(buf));
370  }
371  return alldat;
372 }
373 
374 string SSLClient::getBinaryData(int len, bool isLengthIncluded)
375 {
376  //logger << len;
377  string alldat = getData(len);
378 
379  int leng = getLengthCl(alldat, len);
380  if(isLengthIncluded)
381  {
382  leng -= len;
383  }
384  //logger << "done reading header length " << leng;
385  alldat = getData(leng);
386  logger << alldat.length();
387  return alldat;
388 }
389 
390 void SSLClient::closeConnection()
391 {
392  connected = false;
393  destroy_ctx(ctx);
394  closeSSL();
395 }
396 
397 bool SSLClient::isConnected()
398 {
399  return connected && ClientInterface::isConnected(sockfd);
400 }