1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * $Id: qssl.c,v 1.13 2008-05-20 10:21:50 patrickm Exp $
22  ***************************************************************************/
23 
24 #include "setup.h"
25 
26 #ifdef USE_QSOSSL
27 #include <qsossl.h>
28 #include <errno.h>
29 #include <string.h>
30 
31 #include <curl/curl.h>
32 #include "urldata.h"
33 #include "sendf.h"
34 #include "qssl.h"
35 #include "sslgen.h"
36 #include "connect.h" /* for the connect timeout */
37 #include "select.h"
38 #include "memory.h"
39 /* The last #include file should be: */
40 #include "memdebug.h"
41 
42 
Curl_qsossl_init(void)43 int Curl_qsossl_init(void)
44 
45 {
46   /* Nothing to do here. We must have connection data to initialize ssl, so
47    * defer.
48    */
49 
50   return 1;
51 }
52 
53 
Curl_qsossl_cleanup(void)54 void Curl_qsossl_cleanup(void)
55 
56 {
57   /* Nothing to do. */
58 }
59 
60 
Curl_qsossl_init_session(struct SessionHandle * data)61 static CURLcode Curl_qsossl_init_session(struct SessionHandle * data)
62 
63 {
64   int rc;
65   char * certname;
66   SSLInit initstr;
67   SSLInitApp initappstr;
68 
69   /* Initialize the job for SSL according to the current parameters.
70    * QsoSSL offers two ways to do it: SSL_Init_Application() that uses an
71    *  application identifier to select certificates in the main certificate
72    *  store, and SSL_Init() that uses named keyring files and a password.
73    * It is not possible to have different keyrings for the CAs and the
74    *  local certificate. We thus use the certificate name to identify the
75    *  keyring if given, else the CA file name.
76    * If the key file name is given, it is taken as the password for the
77    *  keyring in certificate file.
78    * We first try to SSL_Init_Application(), then SSL_Init() if it failed.
79    */
80 
81   certname = data->set.str[STRING_CERT];
82 
83   if(!certname) {
84     certname = data->set.str[STRING_SSL_CAFILE];
85 
86     if(!certname)
87       return CURLE_OK;          /* Use previous setup. */
88     }
89 
90   memset((char *) &initappstr, 0, sizeof initappstr);
91   initappstr.applicationID = certname;
92   initappstr.applicationIDLen = strlen(certname);
93   initappstr.protocol = SSL_VERSION_CURRENT;    /* TLSV1 compat. SSLV[23]. */
94   initappstr.sessionType = SSL_REGISTERED_AS_CLIENT;
95   rc = SSL_Init_Application(&initappstr);
96 
97   if(rc == SSL_ERROR_NOT_REGISTERED) {
98     initstr.keyringFileName = certname;
99     initstr.keyringPassword = data->set.str[STRING_KEY];
100     initstr.cipherSuiteList = NULL;    /* Use default. */
101     initstr.cipherSuiteListLen = 0;
102     rc = SSL_Init(&initstr);
103     }
104 
105   switch (rc) {
106 
107   case 0:                             /* No error. */
108     break;
109 
110   case SSL_ERROR_IO:
111     failf(data, "SSL_Init() I/O error: %s", strerror(errno));
112     return CURLE_SSL_CONNECT_ERROR;
113 
114   case SSL_ERROR_BAD_CIPHER_SUITE:
115     return CURLE_SSL_CIPHER;
116 
117   case SSL_ERROR_KEYPASSWORD_EXPIRED:
118   case SSL_ERROR_NOT_REGISTERED:
119     return CURLE_SSL_CONNECT_ERROR;
120 
121   case SSL_ERROR_NO_KEYRING:
122     return CURLE_SSL_CACERT;
123 
124   case SSL_ERROR_CERT_EXPIRED:
125     return CURLE_SSL_CERTPROBLEM;
126 
127   default:
128     failf(data, "SSL_Init(): %s", SSL_Strerror(rc, NULL));
129     return CURLE_SSL_CONNECT_ERROR;
130   }
131 
132   return CURLE_OK;
133 }
134 
135 
Curl_qsossl_create(struct connectdata * conn,int sockindex)136 static CURLcode Curl_qsossl_create(struct connectdata * conn, int sockindex)
137 
138 {
139   SSLHandle * h;
140   struct ssl_connect_data * connssl = &conn->ssl[sockindex];
141 
142   h = SSL_Create(conn->sock[sockindex], SSL_ENCRYPT);
143 
144   if(!h) {
145     failf(conn->data, "SSL_Create() I/O error: %s", strerror(errno));
146     return CURLE_SSL_CONNECT_ERROR;
147   }
148 
149   connssl->handle = h;
150   return CURLE_OK;
151 }
152 
153 
Curl_qsossl_trap_cert(SSLHandle * h)154 static int Curl_qsossl_trap_cert(SSLHandle * h)
155 
156 {
157   return 1;       /* Accept certificate. */
158 }
159 
160 
Curl_qsossl_handshake(struct connectdata * conn,int sockindex)161 static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex)
162 
163 {
164   int rc;
165   struct SessionHandle * data = conn->data;
166   struct ssl_connect_data * connssl = &conn->ssl[sockindex];
167   SSLHandle * h = connssl->handle;
168   long timeout_ms;
169 
170   h->exitPgm = NULL;
171 
172   if(!data->set.ssl.verifyhost)
173     h->exitPgm = Curl_qsossl_trap_cert;
174 
175   /* figure out how long time we should wait at maximum */
176   timeout_ms = Curl_timeleft(conn, NULL, TRUE);
177 
178   if(timeout_ms < 0) {
179     /* time-out, bail out, go home */
180     failf(data, "Connection time-out");
181     return CURLE_OPERATION_TIMEDOUT;
182   }
183 
184   /* SSL_Handshake() timeout resolution is second, so round up. */
185   h->timeout = (timeout_ms + 1000 - 1) / 1000;
186 
187   /* Set-up protocol. */
188 
189   switch (data->set.ssl.version) {
190 
191   default:
192   case CURL_SSLVERSION_DEFAULT:
193     h->protocol = SSL_VERSION_CURRENT;          /* TLSV1 compat. SSLV[23]. */
194     break;
195 
196   case CURL_SSLVERSION_TLSv1:
197     h->protocol = TLS_VERSION_1;
198     break;
199 
200   case CURL_SSLVERSION_SSLv2:
201     h->protocol = SSL_VERSION_2;
202     break;
203 
204   case CURL_SSLVERSION_SSLv3:
205     h->protocol = SSL_VERSION_3;
206     break;
207   }
208 
209   rc = SSL_Handshake(h, SSL_HANDSHAKE_AS_CLIENT);
210 
211   switch (rc) {
212 
213   case 0:                             /* No error. */
214     break;
215 
216   case SSL_ERROR_BAD_CERTIFICATE:
217   case SSL_ERROR_BAD_CERT_SIG:
218   case SSL_ERROR_NOT_TRUSTED_ROOT:
219     return CURLE_PEER_FAILED_VERIFICATION;
220 
221   case SSL_ERROR_BAD_CIPHER_SUITE:
222   case SSL_ERROR_NO_CIPHERS:
223     return CURLE_SSL_CIPHER;
224 
225   case SSL_ERROR_CERTIFICATE_REJECTED:
226   case SSL_ERROR_CERT_EXPIRED:
227   case SSL_ERROR_NO_CERTIFICATE:
228     return CURLE_SSL_CERTPROBLEM;
229 
230   case SSL_ERROR_IO:
231     failf(data, "SSL_Handshake() I/O error: %s", strerror(errno));
232     return CURLE_SSL_CONNECT_ERROR;
233 
234   default:
235     failf(data, "SSL_Handshake(): %s", SSL_Strerror(rc, NULL));
236     return CURLE_SSL_CONNECT_ERROR;
237   }
238 
239   return CURLE_OK;
240 }
241 
242 
Curl_qsossl_connect(struct connectdata * conn,int sockindex)243 CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex)
244 
245 {
246   struct SessionHandle * data = conn->data;
247   struct ssl_connect_data * connssl = &conn->ssl[sockindex];
248   int rc;
249 
250   rc = Curl_qsossl_init_session(data);
251 
252   if(rc == CURLE_OK) {
253     rc = Curl_qsossl_create(conn, sockindex);
254 
255     if(rc == CURLE_OK)
256       rc = Curl_qsossl_handshake(conn, sockindex);
257     else {
258       SSL_Destroy(connssl->handle);
259       connssl->handle = NULL;
260       connssl->use = FALSE;
261       connssl->state = ssl_connection_none;
262     }
263   }
264   if (rc == CURLE_OK)
265     connssl->state = ssl_connection_complete;
266 
267   return rc;
268 }
269 
270 
Curl_qsossl_close_one(struct ssl_connect_data * conn,struct SessionHandle * data)271 static int Curl_qsossl_close_one(struct ssl_connect_data * conn,
272                                  struct SessionHandle * data)
273 
274 {
275   int rc;
276 
277   if(!conn->handle)
278     return 0;
279 
280   rc = SSL_Destroy(conn->handle);
281 
282   if(rc) {
283     if(rc == SSL_ERROR_IO) {
284       failf(data, "SSL_Destroy() I/O error: %s", strerror(errno));
285       return -1;
286     }
287 
288     /* An SSL error. */
289     failf(data, "SSL_Destroy() returned error %d", SSL_Strerror(rc, NULL));
290     return -1;
291   }
292 
293   conn->handle = NULL;
294   return 0;
295 }
296 
297 
Curl_qsossl_close(struct connectdata * conn,int sockindex)298 void Curl_qsossl_close(struct connectdata *conn, int sockindex)
299 
300 {
301   struct SessionHandle *data = conn->data;
302   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
303 
304   if(connssl->use)
305     (void) Curl_qsossl_close_one(connssl, data);
306 }
307 
308 
Curl_qsossl_close_all(struct SessionHandle * data)309 int Curl_qsossl_close_all(struct SessionHandle * data)
310 
311 {
312   /* Unimplemented. */
313   (void) data;
314   return 0;
315 }
316 
317 
Curl_qsossl_shutdown(struct connectdata * conn,int sockindex)318 int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex)
319 
320 {
321   struct ssl_connect_data * connssl = &conn->ssl[sockindex];
322   struct SessionHandle *data = conn->data;
323   ssize_t nread;
324   int what;
325   int rc;
326   char buf[120];
327 
328   if(!connssl->handle)
329     return 0;
330 
331   if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
332     return 0;
333 
334   if(Curl_qsossl_close_one(connssl, data))
335     return -1;
336 
337   rc = 0;
338 
339   what = Curl_socket_ready(conn->sock[sockindex],
340                            CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
341 
342   for (;;) {
343     if(what < 0) {
344       /* anything that gets here is fatally bad */
345       failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
346       rc = -1;
347       break;
348     }
349 
350     if(!what) {                                /* timeout */
351       failf(data, "SSL shutdown timeout");
352       break;
353     }
354 
355     /* Something to read, let's do it and hope that it is the close
356        notify alert from the server. No way to SSL_Read now, so use read(). */
357 
358     nread = read(conn->sock[sockindex], buf, sizeof(buf));
359 
360     if(nread < 0) {
361       failf(data, "read: %s", strerror(errno));
362       rc = -1;
363     }
364 
365     if(nread <= 0)
366       break;
367 
368     what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
369   }
370 
371   return rc;
372 }
373 
374 
Curl_qsossl_send(struct connectdata * conn,int sockindex,const void * mem,size_t len)375 ssize_t Curl_qsossl_send(struct connectdata * conn, int sockindex,
376                          const void * mem, size_t len)
377 
378 {
379   /* SSL_Write() is said to return 'int' while write() and send() returns
380      'size_t' */
381   int rc;
382 
383   rc = SSL_Write(conn->ssl[sockindex].handle, (void *) mem, (int) len);
384 
385   if(rc < 0) {
386     switch(rc) {
387 
388     case SSL_ERROR_BAD_STATE:
389       /* The operation did not complete; the same SSL I/O function
390          should be called again later. This is basicly an EWOULDBLOCK
391          equivalent. */
392       return 0;
393 
394     case SSL_ERROR_IO:
395       switch (errno) {
396       case EWOULDBLOCK:
397       case EINTR:
398         return 0;
399         }
400 
401       failf(conn->data, "SSL_Write() I/O error: %s", strerror(errno));
402       return -1;
403     }
404 
405     /* An SSL error. */
406     failf(conn->data, "SSL_Write() returned error %d",
407           SSL_Strerror(rc, NULL));
408     return -1;
409   }
410 
411   return (ssize_t) rc; /* number of bytes */
412 }
413 
414 
Curl_qsossl_recv(struct connectdata * conn,int num,char * buf,size_t buffersize,bool * wouldblock)415 ssize_t Curl_qsossl_recv(struct connectdata * conn, int num, char * buf,
416                          size_t buffersize, bool * wouldblock)
417 
418 {
419   char error_buffer[120]; /* OpenSSL documents that this must be at
420                              least 120 bytes long. */
421   unsigned long sslerror;
422   int nread;
423 
424   nread = SSL_Read(conn->ssl[num].handle, buf, (int) buffersize);
425   *wouldblock = FALSE;
426 
427   if(nread < 0) {
428     /* failed SSL_read */
429 
430     switch (nread) {
431 
432     case SSL_ERROR_BAD_STATE:
433       /* there's data pending, re-invoke SSL_Read(). */
434       *wouldblock = TRUE;
435       return -1; /* basically EWOULDBLOCK */
436 
437     case SSL_ERROR_IO:
438       switch (errno) {
439       case EWOULDBLOCK:
440         *wouldblock = TRUE;
441         return -1;
442         }
443 
444       failf(conn->data, "SSL_Read() I/O error: %s", strerror(errno));
445       return -1;
446 
447     default:
448       failf(conn->data, "SSL read error: %s", SSL_Strerror(nread, NULL));
449       return -1;
450     }
451   }
452   return (ssize_t) nread;
453 }
454 
455 
Curl_qsossl_version(char * buffer,size_t size)456 size_t Curl_qsossl_version(char * buffer, size_t size)
457 
458 {
459   strncpy(buffer, "IBM OS/400 SSL", size);
460   return strlen(buffer);
461 }
462 
463 
Curl_qsossl_check_cxn(struct connectdata * cxn)464 int Curl_qsossl_check_cxn(struct connectdata * cxn)
465 
466 {
467   int err;
468   int errlen;
469 
470   /* The only thing that can be tested here is at the socket level. */
471 
472   if(!cxn->ssl[FIRSTSOCKET].handle)
473     return 0; /* connection has been closed */
474 
475   err = 0;
476   errlen = sizeof err;
477 
478   if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
479                  (unsigned char *) &err, &errlen) ||
480       errlen != sizeof err || err)
481     return 0; /* connection has been closed */
482 
483   return -1;  /* connection status unknown */
484 }
485 
486 #endif /* USE_QSOSSL */
487