Back to index

im-sdk  12.3.91
IMTLS.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #ifdef HAVE_TLS
00006 
00007 #include "IMTLS.hh"
00008 #include "IMUtil.hh"
00009 #include "IMLog.hh"
00010 #include <unistd.h>
00011 #include <pthread.h>
00012 
00013 #include <openssl/ssl.h>
00014 #include <openssl/err.h>
00015 
00016 bool IMTLS::initialized = false;
00017 IMTLS* IMTLS::ptls = NULL;
00018 
00019 class IMTLSImpl : public IMTLS
00020 {
00021     enum {
00022         NEVER_CHECK,
00023         ALLOW,
00024         TRY,
00025         REQUIRED
00026     };
00027 
00028     int verify_func;
00029     int verify_client;
00030     int verify_depth;
00031     string cert_file;
00032     string key_file;
00033     string ca_file;
00034     string ca_path;
00035     SSL_CTX *ctx;
00036 
00037     // lock
00038     static pthread_mutex_t locks[CRYPTO_NUM_LOCKS];
00039 
00040     static int verify(
00041         int ok,
00042         X509_STORE_CTX *ctx
00043     );
00044     static int verify_notfailed(
00045         int ok,
00046         X509_STORE_CTX *ctx
00047     );
00048     static RSA* get_rsa_cb(
00049         SSL *ssl,
00050         int is_export,
00051         int key_length
00052     );
00053     static void lock_callback(
00054         int mode,
00055         int type,
00056         const char *file,
00057         int line
00058     );
00059     static unsigned long id_callback();
00060 
00061   public:
00062     IMTLSImpl();
00063     ~IMTLSImpl();
00064 
00065     static void tls_error();
00066 
00067     virtual bool set_certificate_file(
00068         const string& filename
00069     );
00070     virtual bool set_certificate_key_file(
00071         const string &filename
00072     );
00073     virtual bool set_cacertificate_file(
00074         const string &filename
00075     );
00076     virtual bool set_cacertificate_path(
00077         const string &filename
00078     );
00079     virtual bool set_verify_client(
00080         const string &value
00081     );
00082     virtual bool set_verify_depth(
00083         const string &value
00084     );
00085 
00086     virtual bool setup();
00087 
00088     virtual IMSocketTrans *create_trans(
00089         int fd,
00090         int x_trans
00091     );
00092 };
00093 
00094 class IMSocketTransTLS : public IMSocketTrans
00095 {
00096     SSL *ssl;
00097     bool err;
00098   public:
00099     virtual int send(
00100         const void *,
00101         size_t n
00102     );
00103     virtual int recv(
00104         void *,
00105         size_t n
00106     );
00107     bool error()
00108     { return err; }
00109 
00110     bool check_peer();
00111 
00112     IMSocketTransTLS(SSL_CTX *ctx, int fd);
00113     ~IMSocketTransTLS();
00114 };
00115 
00116 
00117 IMTLS*
00118 IMTLS::construct()
00119 {
00120     if (initialized) {
00121         return get_instance();
00122     }
00123     IMTLS *tls = new IMTLSImpl();
00124     tls->register_singleton();
00125     initialized = true;
00126 
00127     return get_instance();
00128 }
00129 
00130 bool
00131 IMTLSImpl::set_verify_depth(
00132     const string &value
00133 )
00134 {
00135     char *ptr;
00136     int num;
00137 
00138     num = strtol(value.c_str(), &ptr, 10);
00139     if (*ptr != '\0') {
00140         LOG_WARNING("SSLVerifyDepth: (%s) is not an integer value.", value.c_str());
00141         return false;
00142     }
00143     verify_depth = num;
00144     return true;
00145 }
00146 
00147 bool
00148 IMTLSImpl::set_verify_client(
00149     const string &value
00150 )
00151 {
00152     if(value.compare("demand")) {
00153         verify_client = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
00154         verify_func = 1;
00155     } else if (value.compare("allow")) {
00156         verify_client = SSL_VERIFY_PEER;
00157     } else if (value.compare("never")) {
00158         verify_client = SSL_VERIFY_NONE;
00159     } else if (value.compare("try")) {
00160         verify_client = SSL_VERIFY_PEER;
00161         verify_func = 1;
00162     } else {
00163         LOG_WARNING("SSLVerifyClient should be one of (never|allow|try|demand)");
00164         return false;
00165     }
00166     return true;
00167 }
00168 
00169 bool
00170 IMTLSImpl::set_certificate_file(
00171     const string &filename
00172 )
00173 {
00174     cert_file = filename;
00175     if(!SSL_CTX_use_certificate_file(ctx, filename.c_str(), SSL_FILETYPE_PEM)) {
00176         tls_error();
00177     }
00178     return true;
00179 }
00180 
00181 bool
00182 IMTLSImpl::set_certificate_key_file(
00183     const string &filename
00184 )
00185 {
00186     key_file = filename;
00187     if (!SSL_CTX_use_PrivateKey_file(ctx, filename.c_str(), SSL_FILETYPE_PEM)) {
00188         tls_error();
00189     }
00190     return true;
00191 }
00192 
00193 bool
00194 IMTLSImpl::set_cacertificate_file(
00195     const string &filename
00196 )
00197 {
00198     ca_file = filename;
00199     return true;
00200 }
00201 
00202 bool
00203 IMTLSImpl::set_cacertificate_path(
00204     const string &dirname
00205 )
00206 {
00207     ca_path = dirname;
00208     return true;
00209 }
00210 
00211 void
00212 IMTLSImpl::tls_error()
00213 {
00214     unsigned long err;
00215     char buf[BUFSIZ];
00216 
00217     while ((err = ERR_get_error()) != 0) {
00218         ERR_error_string(err, buf);
00219         LOG_WARNING("TLS error: %s", buf);
00220     }
00221 }
00222 
00223 unsigned long
00224 IMTLSImpl::id_callback()
00225 {
00226     unsigned long ret;
00227 
00228     // dirty hack
00229     ret = (unsigned long) pthread_self();
00230     return ret;
00231 }
00232 
00233 void
00234 IMTLSImpl::lock_callback(
00235     int mode,
00236     int type,
00237     const char *file,
00238     int line
00239 )
00240 {
00241     if (mode & CRYPTO_LOCK) {
00242         pthread_mutex_lock(&locks[type]);
00243     } else {
00244         pthread_mutex_unlock(&locks[type]);
00245     }
00246 }
00247 
00248 int
00249 IMTLSImpl::verify(
00250     int ok,
00251     X509_STORE_CTX *ctx
00252 )
00253 {
00254     char buf[256];
00255     X509 *cert;
00256     int err;
00257     int depth;
00258 
00259     cert = X509_STORE_CTX_get_current_cert(ctx);
00260     err = X509_STORE_CTX_get_error(ctx);
00261     depth = X509_STORE_CTX_get_error_depth(ctx);
00262 
00263     X509_NAME_oneline(X509_get_subject_name(cert), buf, 256);
00264 
00265     LOG_DEBUG("%s(depth %d):%s", buf, depth, X509_verify_cert_error_string(err));
00266     return ok;
00267 }
00268 
00269 int
00270 IMTLSImpl::verify_notfailed(
00271     int ok,
00272     X509_STORE_CTX *ctx
00273 )
00274 {
00275     verify(ok, ctx);
00276     return 1;
00277 }
00278 
00279 RSA*
00280 IMTLSImpl::get_rsa_cb(
00281     SSL *ssl,
00282     int is_export,
00283     int key_length
00284 )
00285 {
00286     RSA *rsa;
00287 
00288     rsa = RSA_generate_key(key_length, RSA_F4, NULL, NULL);
00289 
00290     return rsa;
00291 }
00292 
00293 bool
00294 IMTLSImpl::setup()
00295 {
00296 
00297     // when user specifies a certificate file, but doesn't specify a private key file,
00298     // use the certificate file as a private key file.
00299     if (!cert_file.empty() && key_file.empty()) {
00300         set_certificate_key_file(cert_file);
00301     }
00302 
00303     // user specifies a CA file or CA dir.
00304     if (verify_depth > 0) SSL_CTX_set_verify_depth(ctx, verify_depth);
00305     if (!ca_file.empty() || !ca_path.empty()) {
00306         if (!SSL_CTX_load_verify_locations(ctx, 
00307                                 ca_file.empty() ? NULL : ca_file.c_str(),
00308                                 ca_path.empty() ? NULL : ca_path.c_str()) ||
00309             !SSL_CTX_set_default_verify_paths(ctx)) {
00310             tls_error();
00311         }
00312         STACK_OF(X509_NAME) *ca_list = NULL;
00313         // get CAs from the CA file.
00314         if (!ca_file.empty()) {
00315             ca_list = SSL_load_client_CA_file (ca_file.c_str());
00316             if (!ca_list) {
00317                 tls_error();
00318             }
00319         }
00320         // set CAs from the specified dir.
00321         if (!ca_path.empty()) {
00322            if (!ca_list) ca_list = sk_X509_NAME_new_null();
00323            if (!SSL_add_dir_cert_subjects_to_stack(ca_list, ca_path.c_str())) {
00324                tls_error();
00325            }
00326         }
00327         if (ca_list) {
00328             // finally, set CAs to the context.
00329             SSL_CTX_set_client_CA_list(ctx, ca_list);
00330         }
00331     }
00332 
00333     if(!SSL_CTX_set_cipher_list(ctx, SSL_DEFAULT_CIPHER_LIST)) {
00334          tls_error();
00335     }
00336 
00337     if (!cert_file.empty() && !key_file.empty()) {
00338         if (!SSL_CTX_check_private_key (ctx)) {
00339             tls_error();
00340         }
00341     }
00342 
00343     SSL_CTX_set_tmp_rsa_callback (ctx, &IMTLSImpl::get_rsa_cb);
00344 
00345     SSL_CTX_set_verify(ctx, verify_client, verify_func ? &IMTLSImpl::verify : &IMTLSImpl::verify_notfailed);
00346     return true;
00347 }
00348 
00349 IMSocketTrans *
00350 IMTLSImpl::create_trans(
00351     int x_fd,
00352     int x_trans
00353 )
00354 {
00355     if (x_trans == IMSocketAddress::NORMAL)
00356         return new IMSocketTrans(x_fd);
00357     if (x_trans == IMSocketAddress::TLS) {
00358         IMSocketTransTLS *tls = new IMSocketTransTLS(ctx, x_fd);
00359         if (tls->error()) {
00360             tls_error();
00361             delete tls;
00362             return NULL;
00363         }
00364         // check peer's certificate
00365         tls->check_peer();
00366         return tls;
00367     }
00368     return NULL;
00369 }
00370 
00371 IMTLS::~IMTLS()
00372 {
00373 }
00374 
00375 pthread_mutex_t IMTLSImpl::locks[CRYPTO_NUM_LOCKS];
00376 
00377 IMTLSImpl::IMTLSImpl() :
00378 verify_client(SSL_VERIFY_PEER), verify_depth(1), verify_func(0)
00379 {
00380     SSL_load_error_strings();
00381     SSL_library_init();
00382     ctx = SSL_CTX_new(SSLv23_server_method());
00383 
00384     int i;
00385     // initialize mutexes
00386     for (i = 0; i < CRYPTO_NUM_LOCKS; i++) {
00387         pthread_mutex_init(&locks[i], NULL);
00388     }
00389     // set callback  for locking
00390     CRYPTO_set_locking_callback(&IMTLSImpl::lock_callback);
00391     CRYPTO_set_id_callback(&IMTLSImpl::id_callback);
00392 }
00393 
00394 IMTLSImpl::~IMTLSImpl()
00395 {
00396     if (ctx) {
00397         SSL_CTX_free(ctx);
00398         ctx = NULL;
00399     }
00400     EVP_cleanup();
00401     ERR_remove_state(0);
00402     ERR_free_strings();
00403 }
00404 
00405 int
00406 IMSocketTransTLS::send(
00407     const void *p,
00408     size_t n
00409 )
00410 {
00411     return SSL_write(ssl, p, n);
00412 }
00413 
00414 int
00415 IMSocketTransTLS::recv(
00416     void *p,
00417     size_t n
00418 )
00419 {
00420     return SSL_read(ssl, p, n);
00421 }
00422 
00423 IMSocketTransTLS::IMSocketTransTLS(
00424     SSL_CTX *ctx,
00425     int x_fd
00426 ) : IMSocketTrans(x_fd), err(false)
00427 {
00428     ssl = SSL_new(ctx);
00429     SSL_set_fd (ssl, get_fd());
00430     if(SSL_accept(ssl) <= 0) {
00431         err = true;
00432     }
00433 }
00434 
00435 IMSocketTransTLS::~IMSocketTransTLS()
00436 {
00437    if (ssl) {
00438        int fd = SSL_get_fd (ssl);
00439        SSL_shutdown (ssl);
00440        close (fd);
00441        SSL_free(ssl);
00442    }
00443 }
00444 
00445 bool
00446 IMSocketTransTLS::check_peer()
00447 {
00448    X509 *peer;
00449    bool retval = true;
00450   
00451    if ((peer = SSL_get_peer_certificate(ssl)) != NULL) {
00452        if (SSL_get_verify_result(ssl) != X509_V_OK) {
00453          IMTLSImpl::tls_error();
00454         retval = false;
00455        }
00456        X509_free (peer);
00457    }
00458    return retval;
00459 }
00460 
00461 #endif