Back to index

nordugrid-arc-nox  1.1.0~rc6
XmlSecUtils.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #ifdef WIN32
00006 #include <arc/win32.h>
00007 #endif
00008 #include <cstring>
00009 #include <stdlib.h>
00010 #include <sys/time.h>
00011 
00012 #include <string>
00013 #include <sstream>
00014 #include <fstream>
00015 #include <iostream>
00016 
00017 #include <glibmm.h>
00018 
00019 #include <xmlsec/base64.h>
00020 #include <xmlsec/errors.h>
00021 #include <xmlsec/xmltree.h>
00022 #include <xmlsec/xmldsig.h>
00023 #include <xmlsec/xmlenc.h>
00024 #include <xmlsec/templates.h>
00025 #include <xmlsec/crypto.h>
00026 
00027 #include <xmlsec/openssl/app.h>
00028 #include <openssl/bio.h>
00029 
00030 #include <openssl/err.h>
00031 #include <openssl/ssl.h>
00032 #include <openssl/evp.h>
00033 #include <openssl/sha.h>
00034 #include <openssl/rand.h>
00035 #ifdef CHARSET_EBCDIC
00036 #include <openssl/ebcdic.h>
00037 #endif 
00038 
00039 #include <arc/Thread.h>
00040 
00041 #include "XmlSecUtils.h"
00042 
00043 namespace Arc {
00044 
00045 int passphrase_callback(char* buf, int size, int rwflag, void *) {
00046   int len;
00047   char prompt[128];
00048   snprintf(prompt, sizeof(prompt), "Enter passphrase for the key file: \n");
00049   int r = EVP_read_pw_string(buf, size, prompt, 0);
00050   if(r != 0) {
00051     std::cerr<<"Failed to read passphrase from stdin"<<std::endl;
00052     return -1;
00053   }
00054   len = strlen(buf);
00055   if(buf[len-1] == '\n') {
00056     buf[len-1] = '\0';
00057     len--;
00058   }
00059   return len;
00060 }
00061 
00062 static Glib::Mutex init_lock_;
00063 static bool has_init = false;
00064 
00065 bool init_xmlsec(void) {
00066   if(!has_init) {
00067     init_lock_.lock();
00068     has_init = true;
00069     init_lock_.unlock();
00070 
00071     //Init libxml and libxslt libraries
00072     xmlInitParser();
00073 
00074     //Init xmlsec library
00075     if(xmlSecInit() < 0) {
00076       std::cerr<<"XMLSec initialization failed"<<std::endl;
00077       goto err;
00078     }
00079 
00080     /* Load default crypto engine if we are supporting dynamic
00081      * loading for xmlsec-crypto libraries. Use the crypto library
00082      * name ("openssl", "nss", etc.) to load corresponding
00083      * xmlsec-crypto library.
00084      */
00085 #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
00086     if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) {
00087       std::cerr<<"Unable to load default xmlsec-crypto library. Make sure"
00088                         "that you have it installed and check shared libraries path"
00089                         "(LD_LIBRARY_PATH) envornment variable."<<std::endl;
00090       goto err;
00091     }
00092 #endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */
00093 
00094     // Init crypto library
00095     if(xmlSecCryptoAppInit(NULL) < 0) {
00096       std::cerr<<"crypto initialization failed"<<std::endl;
00097       goto err;
00098     }
00099 
00100     //Init xmlsec-crypto library
00101     if(xmlSecCryptoInit() < 0) {
00102       std::cerr<<"xmlsec-crypto initialization failed"<<std::endl;
00103       goto err;
00104     }
00105 
00106     return true;
00107 
00108 err:
00109     init_lock_.lock();
00110     has_init = false;
00111     init_lock_.unlock();
00112     return false;
00113   }
00114   return true;
00115 }
00116 
00117 bool final_xmlsec(void) {
00118   if(has_init) {
00119     init_lock_.lock();
00120     has_init = false;
00121     init_lock_.unlock();
00122 
00123     //Shutdown xmlsec-crypto library
00124     xmlSecCryptoShutdown();
00125     //Shutdown crypto library 
00126     xmlSecCryptoAppShutdown();  
00127     //Shutdown xmlsec library
00128     xmlSecShutdown();
00129     //Shutdown libxml
00130     xmlCleanupParser();
00131   }
00132 }
00133 
00134 //Get certificate piece (the string under BEGIN CERTIFICATE : END CERTIFICATE) from a certificate file
00135 std::string get_cert_str(const char* certfile) {
00136   std::ifstream is(certfile);
00137   std::string cert;
00138   std::getline(is,cert, char(0));
00139   std::size_t pos = cert.find("BEGIN CERTIFICATE");
00140   if(pos != std::string::npos) {
00141     std::size_t pos1 = cert.find_first_of("---", pos);
00142     std::size_t pos2 = cert.find_first_not_of("-", pos1);
00143     std::size_t pos3 = cert.find_first_of("---", pos2);
00144     std::string str = cert.substr(pos2+1, pos3-pos2-2);
00145     return str;
00146   }
00147   return ("");
00148 }
00149 
00150 xmlSecKey* get_key_from_keyfile(const char* keyfile) {
00151   std::string key_str;
00152   std::ifstream is(keyfile);
00153   std::getline(is,key_str, char(0));
00154 
00155   xmlSecKeyPtr key = NULL;
00156   key = get_key_from_keystr(key_str);
00157   return key;
00158 }
00159 
00160 //Get key from a binary key 
00161 xmlSecKey* get_key_from_keystr(const std::string& value) {//, const bool usage) { 
00162   xmlSecKey *key = NULL;
00163   xmlSecKeyDataFormat key_formats[] = {
00164     xmlSecKeyDataFormatDer,
00165     xmlSecKeyDataFormatCertDer,
00166     xmlSecKeyDataFormatPkcs8Der,
00167     xmlSecKeyDataFormatCertPem,
00168     xmlSecKeyDataFormatPkcs8Pem,
00169     xmlSecKeyDataFormatPem,
00170     xmlSecKeyDataFormatBinary,
00171     (xmlSecKeyDataFormat)0
00172   };
00173 
00174   int rc;
00175 
00176   //We need to remove the "BEGIN RSA PRIVATE KEY" and "END RSA PRIVATE KEY" 
00177   //if they exit in the input parameter
00178   std::string v;
00179   std::size_t pos1, pos2;
00180   pos1 = value.find("BEGIN RSA PRIVATE KEY");
00181   if(pos1 == std::string::npos) {
00182     pos1 = value.find("BEGIN RSA PUBLIC KEY");
00183   }
00184   if(pos1 != std::string::npos) {
00185     pos1 = pos1 + 21;
00186     pos2 = value.find_first_not_of("-", pos1);
00187     v = value.substr(pos2);
00188     pos2 = v.find_first_of("-");
00189     v.resize(pos2);
00190   }
00191   else v = value;
00192 
00193   xmlSecErrorsDefaultCallbackEnableOutput(FALSE);
00194   xmlSecByte* tmp_str = new xmlSecByte[v.size()];
00195   memset(tmp_str,0,v.size());
00196 
00197   rc = xmlSecBase64Decode((const xmlChar*)(v.c_str()), tmp_str, v.size());
00198   if (rc < 0) {
00199     //bad base-64
00200     memcpy(tmp_str,v.c_str(),v.size());
00201     rc = v.size();
00202   }
00203   for (int i=0; key_formats[i] && key == NULL; i++) {
00204     key = xmlSecCryptoAppKeyLoadMemory(tmp_str, rc, key_formats[i], NULL, NULL, NULL);
00205   }
00206   delete[] tmp_str;
00207   xmlSecErrorsDefaultCallbackEnableOutput(TRUE);
00208 
00209   return key;
00210 }
00211 
00212 //Get key from a cert file, return string
00213 std::string get_key_from_certfile(const char* certfile) {
00214   BIO* certbio = NULL;
00215   certbio = BIO_new_file(certfile, "r");
00216   X509* cert = NULL;
00217   cert = PEM_read_bio_X509(certbio, NULL, NULL, NULL); 
00218   EVP_PKEY* key = NULL;
00219   key = X509_get_pubkey(cert);
00220 
00221   BIO* out = NULL;
00222   out = BIO_new(BIO_s_mem());
00223   PEM_write_bio_PUBKEY(out, key);
00224 
00225   std::string pubkey_str;
00226   for(;;) {
00227     char s[256];
00228     int l = BIO_read(out,s,sizeof(s));
00229     if(l <= 0) break;
00230     pubkey_str.append(s,l);;
00231   }
00232 
00233   EVP_PKEY_free(key);
00234   X509_free(cert);
00235   BIO_free_all(certbio);
00236   BIO_free_all(out);
00237 
00238   if(!pubkey_str.empty()) {
00239     std::size_t pos = pubkey_str.find("BEGIN PUBLIC KEY");
00240     if(pos != std::string::npos) {
00241       std::size_t pos1 = pubkey_str.find_first_of("---", pos);
00242       std::size_t pos2 = pubkey_str.find_first_not_of("-", pos1);
00243       std::size_t pos3 = pubkey_str.find_first_of("---", pos2);
00244       std::string str = pubkey_str.substr(pos2+1, pos3-pos2-2);
00245       return str;
00246     }
00247     return ("");
00248   }
00249   return pubkey_str;
00250 }
00251 
00252 //Get key from a cert string
00253 xmlSecKey* get_key_from_certstr(const std::string& value) {
00254   xmlSecKey *key = NULL;
00255   xmlSecKeyDataFormat key_formats[] = {
00256     xmlSecKeyDataFormatDer,
00257     xmlSecKeyDataFormatCertDer,
00258     xmlSecKeyDataFormatPkcs8Der,
00259     xmlSecKeyDataFormatCertPem,
00260     xmlSecKeyDataFormatPkcs8Pem,
00261     xmlSecKeyDataFormatPem,
00262     xmlSecKeyDataFormatBinary,
00263     (xmlSecKeyDataFormat)0
00264   };
00265 
00266   int rc;
00267   xmlSecErrorsDefaultCallbackEnableOutput(FALSE);
00268 
00269   BIO* certbio = NULL;
00270   std::string cert_value;
00271   //Here need to compose a complete certificate
00272   cert_value.append("-----BEGIN CERTIFICATE-----").append("\n").append(value).append("\n").append("-----END CERTIFICATE-----"
00273 );
00274 
00275   for (int i=0; key_formats[i] && key == NULL; i++) {
00276     certbio = BIO_new_mem_buf((void*)(cert_value.c_str()), cert_value.size());
00277     key = xmlSecOpenSSLAppKeyFromCertLoadBIO(certbio, key_formats[i]);
00278     BIO_free(certbio);
00279     if(key != NULL) break;
00280     unsigned long e = ERR_get_error();
00281     while(e != SSL_ERROR_NONE) {
00282       e = ERR_get_error();
00283     }
00284   }
00285 
00286   xmlSecErrorsDefaultCallbackEnableOutput(TRUE);
00287 
00288   return key;
00289 }
00290 
00291 //Load private or public key from a key file into key manager
00292 xmlSecKeysMngrPtr load_key_from_keyfile(xmlSecKeysMngrPtr* keys_manager, const char* keyfile) {
00293   xmlSecKeysMngrPtr keys_mngr;
00294   if((keys_manager != NULL) && (*keys_manager != NULL)) keys_mngr = *keys_manager;
00295   else {
00296     keys_mngr = xmlSecKeysMngrCreate();
00297     //initialize keys manager
00298     if (xmlSecCryptoAppDefaultKeysMngrInit(keys_mngr)<0) {
00299       std::cerr<<"Can not initialize xmlSecKeysMngr object"<<std::endl;
00300       xmlSecKeysMngrDestroy(keys_mngr); return NULL;
00301     }
00302   }
00303   if(keys_mngr == NULL) { std::cerr<<"Can not create xmlSecKeysMngr object"<<std::endl; return NULL;}
00304 
00305   std::string key_str;
00306   std::ifstream is(keyfile);
00307   std::getline(is,key_str, char(0));
00308 
00309   xmlSecKeyPtr key = get_key_from_keystr(key_str);
00310 
00311   if(xmlSecCryptoAppDefaultKeysMngrAdoptKey(keys_mngr, key) < 0) {
00312     std::cerr<<"Failed to add key from "<<keyfile<<" to keys manager"<<std::endl;
00313     xmlSecKeyDestroy(key);
00314     xmlSecKeysMngrDestroy(keys_mngr);
00315     return NULL;
00316   }
00317   if(keys_manager != NULL) keys_manager = &keys_mngr;
00318   return keys_mngr;
00319 }
00320 
00321 //Load public key from a certificate file into key manager
00322 xmlSecKeysMngrPtr load_key_from_certfile(xmlSecKeysMngrPtr* keys_manager, const char* certfile) {
00323   xmlSecKeysMngrPtr keys_mngr;
00324   if((keys_manager != NULL) && (*keys_manager != NULL)) keys_mngr = *keys_manager;
00325   else {
00326     keys_mngr = xmlSecKeysMngrCreate();
00327     //initialize keys manager
00328     if (xmlSecCryptoAppDefaultKeysMngrInit(keys_mngr)<0) {
00329       std::cerr<<"Can not initialize xmlSecKeysMngr object"<<std::endl;
00330       xmlSecKeysMngrDestroy(keys_mngr); return NULL;
00331     }
00332   }
00333   if(keys_mngr == NULL) { std::cerr<<"Can not create xmlSecKeysMngr object"<<std::endl; return NULL;}
00334 
00335   std::string cert_str;
00336   cert_str = get_cert_str(certfile);
00337   xmlSecKeyPtr key = get_key_from_certstr(cert_str);
00338 
00339   if(xmlSecCryptoAppDefaultKeysMngrAdoptKey(keys_mngr, key) < 0) {
00340     std::cerr<<"Failed to add key from "<<certfile<<" to keys manager"<<std::endl;
00341     xmlSecKeyDestroy(key);
00342     xmlSecKeysMngrDestroy(keys_mngr);
00343     return NULL;
00344   }
00345   if(keys_manager != NULL) keys_manager = &keys_mngr;
00346   return keys_mngr;
00347 }
00348 
00349 //Load public key from a certificate string into key manager
00350 xmlSecKeysMngrPtr load_key_from_certstr(xmlSecKeysMngrPtr* keys_manager, const std::string& certstr) {
00351   xmlSecKeysMngrPtr keys_mngr;
00352   if((keys_manager != NULL) && (*keys_manager != NULL)) keys_mngr = *keys_manager;
00353   else {
00354     keys_mngr = xmlSecKeysMngrCreate();
00355     //initialize keys manager
00356     if (xmlSecCryptoAppDefaultKeysMngrInit(keys_mngr)<0) {
00357       std::cerr<<"Can not initialize xmlSecKeysMngr object"<<std::endl;
00358       xmlSecKeysMngrDestroy(keys_mngr); return NULL;
00359     }
00360   }
00361   if(keys_mngr == NULL) { std::cerr<<"Can not create xmlSecKeysMngr object"<<std::endl; return NULL;}
00362 
00363   xmlSecKeyPtr key = get_key_from_certstr(certstr);
00364   if(xmlSecCryptoAppDefaultKeysMngrAdoptKey(keys_mngr, key) < 0) {
00365     std::cerr<<"Failed to add key from "<<certstr<<" to keys manager"<<std::endl;
00366     xmlSecKeyDestroy(key);
00367     xmlSecKeysMngrDestroy(keys_mngr);
00368     return NULL;
00369   }
00370   if(keys_manager != NULL) keys_manager = &keys_mngr;
00371   return keys_mngr;
00372 }
00373 
00374 
00375 //Load trusted certificate from file
00376 xmlSecKeysMngrPtr load_trusted_cert_file(xmlSecKeysMngrPtr* keys_manager, const char* cert_file) {
00377   xmlSecKeysMngrPtr keys_mngr;
00378   if((keys_manager != NULL) && (*keys_manager != NULL)) keys_mngr = *keys_manager;
00379   else {
00380     keys_mngr = xmlSecKeysMngrCreate();
00381     //initialize keys manager
00382     if (xmlSecCryptoAppDefaultKeysMngrInit(keys_mngr)<0) {
00383       std::cerr<<"Can not initialize xmlSecKeysMngr object"<<std::endl;
00384       xmlSecKeysMngrDestroy(keys_mngr); return NULL;
00385     }
00386   }
00387   if(keys_mngr == NULL) { std::cerr<<"Can not create xmlSecKeysMngr object"<<std::endl; return NULL;}
00388   //load cert from file
00389   if(cert_file && (strlen(cert_file) != 0))
00390     if(xmlSecCryptoAppKeysMngrCertLoad(keys_mngr, cert_file, xmlSecKeyDataFormatPem, xmlSecKeyDataTypeTrusted) < 0) {
00391       xmlSecKeysMngrDestroy(keys_mngr);
00392       return NULL;
00393     }
00394   if(keys_manager != NULL) keys_manager = &keys_mngr;
00395   return keys_mngr;
00396 }
00397 
00398 //Could be used for many trusted certificates in string
00399 xmlSecKeysMngrPtr load_trusted_cert_str(xmlSecKeysMngrPtr* keys_manager, const std::string& cert_str) {
00400   xmlSecKeysMngrPtr keys_mngr;
00401   if((keys_manager != NULL) && (*keys_manager != NULL)) keys_mngr = *keys_manager;
00402   else {
00403     keys_mngr = xmlSecKeysMngrCreate();
00404     //initialize keys manager
00405     if (xmlSecCryptoAppDefaultKeysMngrInit(keys_mngr)<0) {
00406       std::cerr<<"Can not initialize xmlSecKeysMngr object"<<std::endl;
00407       xmlSecKeysMngrDestroy(keys_mngr); return NULL;
00408     }
00409   }
00410   if(keys_mngr == NULL) { std::cerr<<"Can not create xmlSecKeysMngr object"<<std::endl; return NULL;}
00411 
00412   //load cert from memory
00413   if(!cert_str.empty())
00414     if(xmlSecCryptoAppKeysMngrCertLoadMemory(keys_mngr, (const xmlSecByte*)(cert_str.c_str()), 
00415           (xmlSecSize)(cert_str.size()), xmlSecKeyDataFormatPem, xmlSecKeyDataTypeTrusted) < 0) {
00416       xmlSecKeysMngrDestroy(keys_mngr);
00417       return NULL;
00418     }
00419   if(keys_manager != NULL) keys_manager = &keys_mngr;
00420   return keys_mngr;
00421 }
00422 
00423 //Load trusted cetificates into key manager
00424 xmlSecKeysMngrPtr load_trusted_certs(xmlSecKeysMngrPtr* keys_manager, const char* cafile, const char* capath) {
00425   xmlSecKeysMngrPtr keys_mngr;
00426   if((keys_manager != NULL) && (*keys_manager != NULL)) keys_mngr = *keys_manager;
00427   else {
00428     keys_mngr = xmlSecKeysMngrCreate();
00429     //initialize keys manager
00430     if (xmlSecCryptoAppDefaultKeysMngrInit(keys_mngr)<0) {
00431       std::cerr<<"Can not initialize xmlSecKeysMngr object"<<std::endl;
00432       xmlSecKeysMngrDestroy(keys_mngr); return NULL;
00433     }
00434   }
00435   if(keys_mngr == NULL) { std::cerr<<"Can not create xmlSecKeysMngr object"<<std::endl; return NULL;}
00436 
00437   //load ca certs into keys manager, the two method used here could not work in some old xmlsec verion,
00438   //because of some bug about X509_FILETYPE_DEFAULT and X509_FILETYPE_PEM 
00439   //load a ca path
00440   if(capath && (strlen(capath) != 0))
00441     if(xmlSecOpenSSLAppKeysMngrAddCertsPath(keys_mngr, capath) < 0) {
00442       xmlSecKeysMngrDestroy(keys_mngr);
00443       return NULL;
00444     }
00445 #if 0
00446   //load a ca file  TODO: can only be used in some new version of xmlsec
00447   if(cafile && (strlen(cafile) != 0))  
00448     if(xmlSecOpenSSLAppKeysMngrAddCertsFile(keys_mngr, cafile) < 0) {
00449       xmlSecKeysMngrDestroy(keys_mngr);
00450       return NULL;
00451   }
00452 #endif
00453   if(cafile && (strlen(cafile) != 0))
00454     if(xmlSecCryptoAppKeysMngrCertLoad(keys_mngr, cafile, xmlSecKeyDataFormatPem, xmlSecKeyDataTypeTrusted) < 0) {
00455       xmlSecKeysMngrDestroy(keys_mngr);
00456       return NULL;
00457     }
00458 
00459   if(keys_manager != NULL) keys_manager = &keys_mngr;
00460   return keys_mngr;
00461 } 
00462 
00463 XMLNode get_node(XMLNode& parent,const char* name) {
00464   XMLNode n = parent[name];
00465   if(!n) n=parent.NewChild(name);
00466   return n;
00467 }
00468 
00469 } // namespace Arc
00470