1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * $Id: qssl.c,v 1.1.1.1 2008-09-23 16:32:05 hoffman Exp $
22 ***************************************************************************/
31 #include <curl/curl.h>
36 #include "connect.h" /* for the connect timeout */
39 /* The last #include file should be: */
43 int Curl_qsossl_init(void)
46 /* Nothing to do here. We must have connection data to initialize ssl, so
54 void Curl_qsossl_cleanup(void)
61 static CURLcode
Curl_qsossl_init_session(struct SessionHandle
* data
)
67 SSLInitApp initappstr
;
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.
81 certname
= data
->set
.str
[STRING_CERT
];
84 certname
= data
->set
.str
[STRING_SSL_CAFILE
];
87 return CURLE_OK
; /* Use previous setup. */
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
);
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
);
107 case 0: /* No error. */
111 failf(data
, "SSL_Init() I/O error: %s", strerror(errno
));
112 return CURLE_SSL_CONNECT_ERROR
;
114 case SSL_ERROR_BAD_CIPHER_SUITE
:
115 return CURLE_SSL_CIPHER
;
117 case SSL_ERROR_KEYPASSWORD_EXPIRED
:
118 case SSL_ERROR_NOT_REGISTERED
:
119 return CURLE_SSL_CONNECT_ERROR
;
121 case SSL_ERROR_NO_KEYRING
:
122 return CURLE_SSL_CACERT
;
124 case SSL_ERROR_CERT_EXPIRED
:
125 return CURLE_SSL_CERTPROBLEM
;
128 failf(data
, "SSL_Init(): %s", SSL_Strerror(rc
, NULL
));
129 return CURLE_SSL_CONNECT_ERROR
;
136 static CURLcode
Curl_qsossl_create(struct connectdata
* conn
, int sockindex
)
140 struct ssl_connect_data
* connssl
= &conn
->ssl
[sockindex
];
142 h
= SSL_Create(conn
->sock
[sockindex
], SSL_ENCRYPT
);
145 failf(conn
->data
, "SSL_Create() I/O error: %s", strerror(errno
));
146 return CURLE_SSL_CONNECT_ERROR
;
154 static int Curl_qsossl_trap_cert(SSLHandle
* h
)
157 return 1; /* Accept certificate. */
161 static CURLcode
Curl_qsossl_handshake(struct connectdata
* conn
, int sockindex
)
165 struct SessionHandle
* data
= conn
->data
;
166 struct ssl_connect_data
* connssl
= &conn
->ssl
[sockindex
];
167 SSLHandle
* h
= connssl
->handle
;
172 if(!data
->set
.ssl
.verifyhost
)
173 h
->exitPgm
= Curl_qsossl_trap_cert
;
175 /* figure out how long time we should wait at maximum */
176 timeout_ms
= Curl_timeleft(conn
, NULL
, TRUE
);
179 /* time-out, bail out, go home */
180 failf(data
, "Connection time-out");
181 return CURLE_OPERATION_TIMEDOUT
;
184 /* SSL_Handshake() timeout resolution is second, so round up. */
185 h
->timeout
= (timeout_ms
+ 1000 - 1) / 1000;
187 /* Set-up protocol. */
189 switch (data
->set
.ssl
.version
) {
192 case CURL_SSLVERSION_DEFAULT
:
193 h
->protocol
= SSL_VERSION_CURRENT
; /* TLSV1 compat. SSLV[23]. */
196 case CURL_SSLVERSION_TLSv1
:
197 h
->protocol
= TLS_VERSION_1
;
200 case CURL_SSLVERSION_SSLv2
:
201 h
->protocol
= SSL_VERSION_2
;
204 case CURL_SSLVERSION_SSLv3
:
205 h
->protocol
= SSL_VERSION_3
;
209 rc
= SSL_Handshake(h
, SSL_HANDSHAKE_AS_CLIENT
);
213 case 0: /* No error. */
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
;
221 case SSL_ERROR_BAD_CIPHER_SUITE
:
222 case SSL_ERROR_NO_CIPHERS
:
223 return CURLE_SSL_CIPHER
;
225 case SSL_ERROR_CERTIFICATE_REJECTED
:
226 case SSL_ERROR_CERT_EXPIRED
:
227 case SSL_ERROR_NO_CERTIFICATE
:
228 return CURLE_SSL_CERTPROBLEM
;
231 failf(data
, "SSL_Handshake() I/O error: %s", strerror(errno
));
232 return CURLE_SSL_CONNECT_ERROR
;
235 failf(data
, "SSL_Handshake(): %s", SSL_Strerror(rc
, NULL
));
236 return CURLE_SSL_CONNECT_ERROR
;
243 CURLcode
Curl_qsossl_connect(struct connectdata
* conn
, int sockindex
)
246 struct SessionHandle
* data
= conn
->data
;
247 struct ssl_connect_data
* connssl
= &conn
->ssl
[sockindex
];
250 rc
= Curl_qsossl_init_session(data
);
253 rc
= Curl_qsossl_create(conn
, sockindex
);
256 rc
= Curl_qsossl_handshake(conn
, sockindex
);
258 SSL_Destroy(connssl
->handle
);
259 connssl
->handle
= NULL
;
260 connssl
->use
= FALSE
;
261 connssl
->state
= ssl_connection_none
;
265 connssl
->state
= ssl_connection_complete
;
271 static int Curl_qsossl_close_one(struct ssl_connect_data
* conn
,
272 struct SessionHandle
* data
)
280 rc
= SSL_Destroy(conn
->handle
);
283 if(rc
== SSL_ERROR_IO
) {
284 failf(data
, "SSL_Destroy() I/O error: %s", strerror(errno
));
289 failf(data
, "SSL_Destroy() returned error %d", SSL_Strerror(rc
, NULL
));
298 void Curl_qsossl_close(struct connectdata
*conn
, int sockindex
)
301 struct SessionHandle
*data
= conn
->data
;
302 struct ssl_connect_data
*connssl
= &conn
->ssl
[sockindex
];
305 (void) Curl_qsossl_close_one(connssl
, data
);
309 int Curl_qsossl_close_all(struct SessionHandle
* data
)
318 int Curl_qsossl_shutdown(struct connectdata
* conn
, int sockindex
)
321 struct ssl_connect_data
* connssl
= &conn
->ssl
[sockindex
];
322 struct SessionHandle
*data
= conn
->data
;
331 if(data
->set
.ftp_ccc
!= CURLFTPSSL_CCC_ACTIVE
)
334 if(Curl_qsossl_close_one(connssl
, data
))
339 what
= Curl_socket_ready(conn
->sock
[sockindex
],
340 CURL_SOCKET_BAD
, SSL_SHUTDOWN_TIMEOUT
);
344 /* anything that gets here is fatally bad */
345 failf(data
, "select/poll on SSL socket, errno: %d", SOCKERRNO
);
350 if(!what
) { /* timeout */
351 failf(data
, "SSL shutdown timeout");
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(). */
358 nread
= read(conn
->sock
[sockindex
], buf
, sizeof(buf
));
361 failf(data
, "read: %s", strerror(errno
));
368 what
= Curl_socket_ready(conn
->sock
[sockindex
], CURL_SOCKET_BAD
, 0);
375 ssize_t
Curl_qsossl_send(struct connectdata
* conn
, int sockindex
,
376 const void * mem
, size_t len
)
379 /* SSL_Write() is said to return 'int' while write() and send() returns
383 rc
= SSL_Write(conn
->ssl
[sockindex
].handle
, (void *) mem
, (int) len
);
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
401 failf(conn
->data
, "SSL_Write() I/O error: %s", strerror(errno
));
406 failf(conn
->data
, "SSL_Write() returned error %d",
407 SSL_Strerror(rc
, NULL
));
411 return (ssize_t
) rc
; /* number of bytes */
415 ssize_t
Curl_qsossl_recv(struct connectdata
* conn
, int num
, char * buf
,
416 size_t buffersize
, bool * wouldblock
)
419 char error_buffer
[120]; /* OpenSSL documents that this must be at
420 least 120 bytes long. */
421 unsigned long sslerror
;
424 nread
= SSL_Read(conn
->ssl
[num
].handle
, buf
, (int) buffersize
);
428 /* failed SSL_read */
432 case SSL_ERROR_BAD_STATE
:
433 /* there's data pending, re-invoke SSL_Read(). */
435 return -1; /* basically EWOULDBLOCK */
444 failf(conn
->data
, "SSL_Read() I/O error: %s", strerror(errno
));
448 failf(conn
->data
, "SSL read error: %s", SSL_Strerror(nread
, NULL
));
452 return (ssize_t
) nread
;
456 size_t Curl_qsossl_version(char * buffer
, size_t size
)
459 strncpy(buffer
, "IBM OS/400 SSL", size
);
460 return strlen(buffer
);
464 int Curl_qsossl_check_cxn(struct connectdata
* cxn
)
470 /* The only thing that can be tested here is at the socket level. */
472 if(!cxn
->ssl
[FIRSTSOCKET
].handle
)
473 return 0; /* connection has been closed */
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 */
483 return -1; /* connection status unknown */
486 #endif /* USE_QSOSSL */