TClSession.cxx

Go to the documentation of this file.
00001 // @(#)root/clarens:$Id: TClSession.cxx 20882 2007-11-19 11:31:26Z rdm $
00002 // Author: Maarten Ballintijn   25/10/2004
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // TClSession                                                           //
00015 //                                                                      //
00016 //                                                                      //
00017 //////////////////////////////////////////////////////////////////////////
00018 
00019 #include "TClSession.h"
00020 
00021 
00022 #include <openssl/x509.h>
00023 #include <openssl/pem.h>
00024 #include <openssl/bio.h>
00025 #include <openssl/err.h>
00026 #include <openssl/evp.h>
00027 #include <openssl/bn.h>
00028 
00029 
00030 #include "Riostream.h"
00031 #include "TEnv.h"
00032 #include "TError.h"
00033 #include "TList.h"
00034 #include "TRandom.h"
00035 #include "TString.h"
00036 #include "TSystem.h"
00037 #include "TTimeStamp.h"
00038 #include "TUrl.h"
00039 
00040 
00041 ClassImp(TClSession)
00042 
00043 
00044 Bool_t   TClSession::fgInitialized  = kFALSE;
00045 void    *TClSession::fgPrivRSA      = 0;
00046 void    *TClSession::fgPubRSA       = 0;
00047 TString  TClSession::fgUserCert;
00048 
00049 //______________________________________________________________________________
00050 unsigned char *B64Encode(xmlrpc_env *env,unsigned char *instring,int len)
00051 {
00052    // Utility function that encodes instring in base64, and returns a new
00053    // string with its own memory reference. Free this memory upon
00054    // deconstruction.
00055 
00056     xmlrpc_mem_block *mem;
00057     mem=xmlrpc_base64_encode (env,instring,len);
00058     if (env->fault_occurred) {
00059        cerr<<"XML-RPC Fault: "<<env->fault_string<<"("<< env->fault_code<<")"<<endl;
00060        if (mem) xmlrpc_mem_block_free (mem);
00061        return 0;
00062     }
00063 
00064     if (!mem) return 0;
00065     int olen=xmlrpc_mem_block_size (mem);
00066 
00067     unsigned char *outstring=new unsigned char[olen+1];
00068     memcpy((void *) outstring,(void *)xmlrpc_mem_block_contents(mem),olen);
00069     outstring[olen]='\0';// Make a proper null-terminated string
00070 
00071     xmlrpc_mem_block_free (mem);
00072     return outstring;
00073 }
00074 
00075 //______________________________________________________________________________
00076 unsigned char *B64Decode(xmlrpc_env *env, unsigned char *instring,int *len)
00077 {
00078    // Utility function that encodes instring in base64, and returns a new
00079    // string with its own memory reference. Free this memory upon
00080    // deconstruction.
00081 
00082     xmlrpc_mem_block *mem;
00083     mem=xmlrpc_base64_decode (env,(char *)instring,strlen((const char *)instring));
00084     if (env->fault_occurred) {
00085        cerr<<"XML-RPC Fault: "<<env->fault_string<<"("<< env->fault_code<<")"<<endl;
00086        if (mem) xmlrpc_mem_block_free (mem);
00087        return 0;
00088     }
00089 
00090     if (!mem) return 0;
00091     int olen=xmlrpc_mem_block_size (mem);
00092     unsigned char *outstring=new unsigned char[olen+1];
00093     memcpy((void *) outstring,(void *)xmlrpc_mem_block_contents(mem),olen);
00094     outstring[olen]='\0';// Make a proper null-terminated string
00095     *len=olen;
00096     xmlrpc_mem_block_free (mem);
00097     return outstring;
00098 }
00099 
00100 //______________________________________________________________________________
00101 TClSession::TClSession(const Char_t *url, const Char_t *user, const Char_t *pw,
00102                        xmlrpc_server_info *info, void *serverPubRSA)
00103    : fUrl(url), fUser(user), fPassword(pw), fServerInfo(info), fServerPubRSA(serverPubRSA)
00104 {
00105 }
00106 
00107 //______________________________________________________________________________
00108 TClSession *TClSession::Create(const Char_t *url)
00109 {
00110    if (!InitAuthentication()) return 0;
00111 
00112    if (TString(url).EndsWith("/") == kFALSE) {
00113       ::Error("TClSession::Create", "URL must end with \"/\" (%s)", url);
00114       return 0;
00115    }
00116 
00117    // Construct user nonce value
00118    unsigned char nonce[SHA_DIGEST_LENGTH];
00119    Long_t ns = TTimeStamp().GetNanoSec();
00120    TRandom rndm(ns);
00121    SHA1((UChar_t*) Form("%x_%lx_%lx", gSystem->GetPid(), ns, (Long_t)rndm.Uniform(1e8)),
00122         22, nonce);
00123 
00124    xmlrpc_env env;
00125    xmlrpc_env_init(&env);
00126 
00127    TString user = (char *) B64Encode(&env, nonce, SHA_DIGEST_LENGTH);
00128 
00129    xmlrpc_server_info *info = xmlrpc_server_info_new(&env, (char*)url);
00130    if (env.fault_occurred) {
00131       ::Error("TClSession::Create", "creating server info: %s (%d)",
00132             env.fault_string, env.fault_code);
00133       return 0;
00134    }
00135 
00136    xmlrpc_server_info_set_basic_auth (&env, info, (char*)user.Data(), (char*)fgUserCert.Data());
00137    if (env.fault_occurred) {
00138       ::Error("TClSession::Create", "setting basic auth: %s (%d)",
00139             env.fault_string, env.fault_code);
00140       return 0;
00141    }
00142 
00143    xmlrpc_value *val = xmlrpc_client_call_server (&env, info, "system.auth", "()");
00144    if (env.fault_occurred) {
00145       ::Error("TClSession::Create", "call system.auth(): %s (%d)",
00146             env.fault_string, env.fault_code);
00147       return 0;
00148    }
00149 
00150    char *cert;
00151    unsigned char *cryptServerNonce64, *cryptUserNonce64;
00152    xmlrpc_parse_value(&env, val, "(sss)", &cert, &cryptServerNonce64, &cryptUserNonce64);
00153    if (env.fault_occurred) {
00154       ::Error("TClSession::Create", "parsing result: %s (%d)",
00155             env.fault_string, env.fault_code);
00156       return 0;
00157    }
00158 
00159    BIO *b = BIO_new_mem_buf(cert,strlen(cert));
00160    X509 *serverCert = PEM_read_bio_X509(b, 0, 0, 0);
00161    BIO_free(b);
00162    if (serverCert == 0) {
00163       ::Error("TClSession::Create", "reading cert from server response: %s",
00164             ERR_reason_error_string(ERR_get_error()));
00165       return 0;
00166    }
00167 
00168    EVP_PKEY *serverPubKey = X509_get_pubkey(serverCert);
00169    if (serverPubKey == 0) {
00170       ::Error("TClSession::Create", "extracting cert from server response: %s",
00171             ERR_reason_error_string(ERR_get_error()));
00172       return 0;
00173    }
00174 
00175    void* serverPubRSA = EVP_PKEY_get1_RSA(serverPubKey);
00176    if (serverPubRSA == 0) {
00177       ::Error("TClSession::Create", "extracting pub key from cert: %s",
00178             ERR_reason_error_string(ERR_get_error()));
00179       return 0;
00180    }
00181 
00182    // user nonce first
00183    int len;
00184 
00185    unsigned char *cryptNonce = B64Decode(&env, cryptUserNonce64, &len);
00186    unsigned char *serverUstring = new unsigned char[RSA_size((RSA*)serverPubRSA)];
00187    len = RSA_public_decrypt(len, cryptNonce, serverUstring,
00188                             (RSA*) serverPubRSA, RSA_PKCS1_PADDING);
00189    if (len == -1) {
00190       ::Error("TClSession::Create", "recovering digest: %s",
00191             ERR_reason_error_string(ERR_get_error()));
00192       delete [] cryptNonce;
00193       return 0;
00194    }
00195    serverUstring[len] = '\0';
00196    delete [] cryptNonce;
00197 
00198    // server nonce next
00199    cryptNonce = B64Decode(&env, cryptServerNonce64, &len);
00200    unsigned char *serverNonce = new unsigned char[RSA_size((RSA*)fgPrivRSA)];
00201 
00202    len = RSA_private_decrypt(len, cryptNonce, serverNonce,
00203                              (RSA*) fgPrivRSA, RSA_PKCS1_PADDING);
00204    if (len == -1) {
00205       ::Error("TClSession::Create", "decoding server nonce: %s",
00206             ERR_reason_error_string(ERR_get_error()));
00207       delete [] cryptNonce;
00208       return 0;
00209    }
00210    serverNonce[len] = '\0';
00211    delete [] cryptNonce;
00212    xmlrpc_DECREF (val);
00213 
00214    // calculate hash of server nonce
00215 
00216    SHA1(serverNonce, len, nonce);
00217    TString password = (char *) B64Encode(&env, nonce, SHA_DIGEST_LENGTH);
00218 
00219    xmlrpc_server_info_set_basic_auth (&env, info, (char*)user.Data(), (char*)password.Data());
00220 
00221    return new TClSession(url, user, password, info, serverPubRSA);
00222 }
00223 
00224 //______________________________________________________________________________
00225 Bool_t TClSession::InitAuthentication()
00226 {
00227    if (fgInitialized) return kTRUE;
00228 
00229    // Initialize SSL
00230    OpenSSL_add_all_algorithms();
00231    OpenSSL_add_all_ciphers();
00232    OpenSSL_add_all_digests();
00233    ERR_load_crypto_strings();
00234 
00235    // Load user certificate and public key
00236 
00237 
00238    BIO *bio = 0;
00239    TString certFile(gEnv->GetValue("Clarens.CertFile", ""));
00240    if (certFile.Length() > 0) {
00241       bio = BIO_new_file(certFile,"r");
00242    } else {
00243       certFile = Form("/tmp/x509up_u%d", gSystem->GetUid());
00244       if (gSystem->AccessPathName(certFile) == kFALSE) {
00245          // yes, file exists
00246          bio = BIO_new_file(certFile,"r");
00247       } else {
00248          certFile = gSystem->HomeDirectory();
00249          certFile += "/.globus/usercert.pem";
00250          bio = BIO_new_file(certFile,"r");
00251       }
00252    }
00253 
00254    if (bio == 0) {
00255       ::Error("TClSession::InitAuthentication", "cannot open '%s' (%s)",
00256               certFile.Data(), gSystem->GetError());
00257       return kFALSE;
00258    }
00259 
00260    if (gDebug > 0) ::Info("TClSession::InitAuthentication",
00261       "using public key: '%s'", certFile.Data());
00262 
00263    X509* userCert = PEM_read_bio_X509(bio, 0,0,0);
00264    if (!userCert) {
00265       ::Error("TClSession::InitAuthentication", "reading user public key: %s (%ld)",
00266          ERR_reason_error_string(ERR_get_error()), ERR_get_error());
00267       BIO_free(bio);
00268       return kFALSE;
00269    }
00270 
00271    BIO_free(bio);
00272 
00273    TString line;
00274    Bool_t incert=kFALSE;
00275    fgUserCert = "";
00276    ifstream fin(certFile);
00277    while (!fin.eof()) {
00278       line.ReadToDelim(fin,'\n');
00279 
00280       if (line.Contains("-----BEGIN CERTIFICATE-----") ||
00281           line.Contains("-----BEGIN X509 CERTIFICATE-----")) incert=kTRUE;
00282 
00283       if (incert) fgUserCert += line + "\n";
00284 
00285       if (line.Contains("-----END CERTIFICATE-----") ||
00286           line.Contains("-----END X509 CERTIFICATE-----")) incert=kFALSE;
00287    }
00288    fin.close();
00289 
00290    EVP_PKEY *userPubKey = X509_get_pubkey(userCert);
00291    if (userPubKey == 0) {
00292       ::Error("TClSession::InitAuthentication", "extracting user public key: %s (%ld)",
00293          ERR_reason_error_string(ERR_get_error()), ERR_get_error());
00294       X509_free(userCert);
00295       return kFALSE;
00296    }
00297 
00298    X509_free(userCert);
00299    fgPubRSA = EVP_PKEY_get1_RSA(userPubKey);
00300    if (fgPubRSA == 0) {
00301       ::Error("TClSession::InitAuthentication", "extracting RSA structure from user public key: %s (%ld)",
00302          ERR_reason_error_string(ERR_get_error()), ERR_get_error());
00303       EVP_PKEY_free(userPubKey);
00304       return kFALSE;
00305    }
00306 
00307    EVP_PKEY_free(userPubKey);
00308 
00309    // Load private key
00310 
00311    TString privfile(gEnv->GetValue("Clarens.KeyFile", ""));
00312    if (privfile.Length() > 0) {
00313       bio = BIO_new_file(privfile,"r");
00314    } else {
00315       privfile = Form("/tmp/x509up_u%d", gSystem->GetUid());
00316       if (gSystem->AccessPathName(privfile) == kFALSE) {
00317          // yes, file exists
00318          bio = BIO_new_file(privfile,"r");
00319       } else {
00320          privfile = gSystem->HomeDirectory();
00321          privfile += "/.globus/userkey.pem";
00322          bio = BIO_new_file(privfile,"r");
00323       }
00324    }
00325 
00326    if (bio == 0) {
00327       ::Error("TClSession::InitAuthentication", "cannot open '%s' (%s)",
00328               privfile.Data(), gSystem->GetError());
00329       RSA_free((RSA*)fgPubRSA); fgPubRSA = 0;
00330       return kFALSE;
00331    }
00332 
00333    if (gDebug > 0) ::Info("TClSession::InitAuthentication",
00334       "using private key: '%s'", privfile.Data());
00335 
00336    fgPrivRSA = PEM_read_bio_RSAPrivateKey(bio, 0, 0, 0);
00337    BIO_free(bio);
00338 
00339    if (fgPrivRSA == 0) {
00340       ::Error("TClSession::InitAuthentication", "extracting RSA structure from user private key: %s (%ld)",
00341          ERR_reason_error_string(ERR_get_error()), ERR_get_error());
00342       RSA_free((RSA*)fgPubRSA); fgPubRSA = 0;
00343       return kFALSE;
00344    }
00345 
00346    fgInitialized = kTRUE;
00347    return kTRUE;
00348 }

Generated on Tue Jul 5 14:50:48 2011 for ROOT_528-00b_version by  doxygen 1.5.1