00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
00053
00054
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';
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
00079
00080
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';
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
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
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
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
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
00230 OpenSSL_add_all_algorithms();
00231 OpenSSL_add_all_ciphers();
00232 OpenSSL_add_all_digests();
00233 ERR_load_crypto_strings();
00234
00235
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
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
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
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 }