Back to index

nordugrid-arc-nox  1.1.0~rc6
XMLSecNode.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <cstring>
00006 
00007 #ifdef WIN32
00008 #include <arc/win32.h>
00009 #endif
00010 
00011 #include <xmlsec/base64.h>
00012 #include <xmlsec/errors.h>
00013 #include <xmlsec/xmltree.h>
00014 #include <xmlsec/xmldsig.h>
00015 #include <xmlsec/xmlenc.h>
00016 #include <xmlsec/templates.h>
00017 #include <xmlsec/crypto.h>
00018 #include <xmlsec/keys.h>
00019 #include <xmlsec/keyinfo.h>
00020 
00021 #include <xmlsec/openssl/app.h>
00022 #include <openssl/bio.h>
00023 
00024 #include <openssl/evp.h>
00025 #include <openssl/sha.h>
00026 #include <openssl/rand.h>
00027 #ifdef CHARSET_EBCDIC
00028 #include <openssl/ebcdic.h>
00029 #endif 
00030 
00031 #include "XmlSecUtils.h"
00032 #include "XMLSecNode.h"
00033 
00034 namespace Arc {
00035 
00036 #define SAML_NAMESPACE "urn:oasis:names:tc:SAML:1.0:assertion"
00037 #define SAML2_NAMESPACE "urn:oasis:names:tc:SAML:2.0:assertion"
00038 #define SAMLP_NAMESPACE "urn:oasis:names:tc:SAML:2.0:protocol"
00039 
00040 #define XENC_NAMESPACE   "http://www.w3.org/2001/04/xmlenc#"
00041 #define DSIG_NAMESPACE   "http://www.w3.org/2000/09/xmldsig#"
00042 
00043 XMLSecNode::XMLSecNode(XMLNode& node):XMLNode(node) {
00044   if(!node_) return;
00045   if(node_->type != XML_ELEMENT_NODE) { node_=NULL; return; };
00046 }
00047 
00048 XMLSecNode::~XMLSecNode(void) {
00049 }
00050 
00051 void XMLSecNode::AddSignatureTemplate(const std::string& id_name, const SignatureMethod sign_method, 
00052   const std::string& incl_namespaces) {
00053   xmlNodePtr signature = NULL;
00054   xmlNodePtr reference = NULL;
00055   if(sign_method == RSA_SHA1)
00056     signature = xmlSecTmplSignatureCreate(NULL, xmlSecTransformExclC14NId, xmlSecTransformRsaSha1Id, NULL);
00057   else
00058     signature = xmlSecTmplSignatureCreate(NULL, xmlSecTransformExclC14NId, xmlSecTransformDsaSha1Id, NULL);
00059  
00060   //Add signature to the node
00061   xmlNodePtr nd = this->node_;
00062   xmlAddChild(nd, signature);
00063 
00064   //Add reference for signature
00065   xmlDocPtr docPtr = nd->doc;
00066   xmlChar* id = NULL;
00067   id =  xmlGetProp(nd, (xmlChar *)(id_name.c_str()));
00068   if(!id) { std::cerr<<"There is not "<<id_name<<" attribute in xml node"<<std::endl; return; }
00069 
00070   std::string uri; uri.append("#"); uri.append((char*)id);
00071 
00072   reference = xmlSecTmplSignatureAddReference(signature, xmlSecTransformSha1Id,
00073                                               NULL, (xmlChar *)(uri.c_str()), NULL);
00074   xmlSecTmplReferenceAddTransform(reference, xmlSecTransformEnvelopedId);
00075   xmlNodePtr transform = NULL;
00076   transform = xmlSecTmplReferenceAddTransform(reference, xmlSecTransformExclC14NId);
00077   if(!incl_namespaces.empty())
00078     xmlSecTmplTransformAddC14NInclNamespaces(transform, (const xmlChar*)(incl_namespaces.c_str()));
00079 
00080   xmlAttrPtr id_attr = xmlHasProp(nd, (xmlChar *)(id_name.c_str()));
00081   xmlAddID(NULL, docPtr, (xmlChar *)id, id_attr);
00082   xmlFree(id);
00083   
00084   xmlNodePtr key_info = xmlSecTmplSignatureEnsureKeyInfo(signature, NULL);
00085   xmlSecTmplKeyInfoAddX509Data(key_info);
00086 }
00087 
00088 bool XMLSecNode::SignNode(const std::string& privkey_file, const std::string& cert_file) {
00089   //Generate signature according to the information inside signature template;
00090   XMLNode signature = (*this)["Signature"];
00091   xmlNodePtr signatureptr = ((XMLSecNode*)(&signature))->node_;
00092   xmlSecDSigCtx *dsigCtx = xmlSecDSigCtxCreate(NULL);
00093   //load private key, assuming there is no need for passphrase
00094   dsigCtx->signKey = xmlSecCryptoAppKeyLoad(privkey_file.c_str(), xmlSecKeyDataFormatPem, NULL, NULL, NULL);
00095   if(dsigCtx->signKey == NULL) {
00096     xmlSecDSigCtxDestroy(dsigCtx);
00097     std::cerr<<"Can not load key"<<std::endl; return false;
00098   }
00099   if(xmlSecCryptoAppKeyCertLoad(dsigCtx->signKey, cert_file.c_str(), xmlSecKeyDataFormatPem) < 0) {
00100     xmlSecDSigCtxDestroy(dsigCtx);
00101     std::cerr<<"Can not load certificate"<<std::endl; return false;
00102   }
00103   if (xmlSecDSigCtxSign(dsigCtx, signatureptr) < 0) {
00104     xmlSecDSigCtxDestroy(dsigCtx);
00105     std::cerr<<"Can not sign node"<<std::endl; return false;
00106   }
00107   if(dsigCtx != NULL)xmlSecDSigCtxDestroy(dsigCtx);
00108   return true;
00109 }
00110 
00111 bool XMLSecNode::VerifyNode(const std::string& id_name, const std::string& ca_file, const std::string& ca_path, bool verify_trusted) {
00112   xmlNodePtr node = this->node_;
00113   xmlDocPtr docPtr = node->doc;
00114   xmlChar* id = xmlGetProp(node, (xmlChar *)(id_name.c_str()));
00115   xmlAttrPtr id_attr = xmlHasProp(node, (xmlChar *)(id_name.c_str()));
00116   xmlAddID(NULL, docPtr, (xmlChar *)id, id_attr);
00117   xmlFree(id);
00118  
00119   XMLNode signature = (*this)["Signature"];
00120   if(!signature) { std::cerr<<"No signature node under this node"<<std::endl; return false; }
00121   xmlNodePtr signatureptr = ((XMLSecNode*)(&signature))->node_;
00122   XMLNode keyinfo = signature["KeyInfo"];
00123   XMLNode x509data = signature["KeyInfo"]["X509Data"];
00124 
00125   xmlSecKeysMngr* keys_manager = NULL;
00126   xmlSecDSigCtx *dsigCtx;
00127   
00128   if(verify_trusted) {
00129     //Verify the signature under the signature node (this node) 
00130     if((bool)x509data && (!ca_file.empty() || !ca_path.empty())) {
00131       keys_manager = load_trusted_certs(&keys_manager, ca_file.c_str(), ca_path.c_str());
00132       if(keys_manager == NULL) { std::cerr<<"Can not load trusted certificates"<<std::endl; return false; }
00133     } 
00134     else if((bool)x509data)
00135       { std::cerr<<"No trusted certificates exists"<<std::endl; return false;}
00136     if(keys_manager == NULL){ std::cerr<<"No <X509Data/> exists, or no trusted certificates configured"<<std::endl; return false;}
00137     dsigCtx = xmlSecDSigCtxCreate(keys_manager);
00138   }
00139   else {
00140     dsigCtx = xmlSecDSigCtxCreate(NULL);
00141     if((bool)x509data) {
00142       //Since xmlsec automatically needs to check trusted certificates
00143       //if the KeyInfo is composed by X509Data, here we manualy extract 
00144       //the public key from X509Data
00145       XMLNode x509cert = x509data["X509Certificate"];
00146       std::string certstr = (std::string)x509cert;
00147       xmlSecKey* pubkey = get_key_from_certstr(certstr);
00148       if (pubkey == NULL){
00149         xmlSecDSigCtxDestroy(dsigCtx);
00150         std::cerr<<"Can not load public key"<<std::endl; return false;
00151       }
00152       dsigCtx->signKey = pubkey;
00153     }
00154     else {
00155       //Use xmlSecKeyInfoNodeRead to extract public key
00156       dsigCtx->flags |= XMLSEC_DSIG_FLAGS_STORE_SIGNEDINFO_REFERENCES;
00157       dsigCtx->signKey = xmlSecKeyCreate();
00158       if(!keyinfo) {  
00159         std::cerr<<"No KeyInfo node exists"<<std::endl;         
00160         xmlSecDSigCtxDestroy(dsigCtx); return false;
00161       }
00162       xmlNodePtr keyinfoptr = ((XMLSecNode*)(&keyinfo))->node_;
00163       xmlSecKeyInfoCtxPtr keyInfo;
00164       keyInfo = xmlSecKeyInfoCtxCreate(NULL);
00165       if(!keyInfo) { xmlSecDSigCtxDestroy(dsigCtx); return false; }
00166       xmlSecKeyInfoNodeRead(keyinfoptr, dsigCtx->signKey,keyInfo);
00167       xmlSecKeyInfoCtxDestroy(keyInfo);
00168     }
00169   }
00170 
00171 
00172 #if 0
00173 if(//(xmlSecDSigCtxEnableReferenceTransform(dsigCtx, xmlSecTransformInclC14NId) < 0) ||
00174                         (xmlSecDSigCtxEnableReferenceTransform(dsigCtx, xmlSecTransformExclC14NId) < 0) ||
00175                         (xmlSecDSigCtxEnableReferenceTransform(dsigCtx, xmlSecTransformSha1Id) < 0) || 
00176                         (xmlSecDSigCtxEnableReferenceTransform(dsigCtx, xmlSecTransformEnvelopedId) < 0)
00177                         )
00178 #endif
00179     
00180   if (xmlSecDSigCtxVerify(dsigCtx, signatureptr) < 0) {
00181     xmlSecDSigCtxDestroy(dsigCtx);
00182     if (keys_manager) xmlSecKeysMngrDestroy(keys_manager);
00183     std::cerr<<"Signature verification failed"<<std::endl;
00184     return false;
00185   } 
00186   if(keys_manager != NULL)xmlSecKeysMngrDestroy(keys_manager);
00187   if(dsigCtx->status == xmlSecDSigStatusSucceeded) {
00188     std::cout<<"Succeed to verify the signature under this node"<<std::endl;
00189     xmlSecDSigCtxDestroy(dsigCtx); return true;
00190   } 
00191   else { std::cerr<<"Invalid signature in this node"<<std::endl; xmlSecDSigCtxDestroy(dsigCtx); return false; }
00192 }
00193 
00194 bool XMLSecNode::EncryptNode(const std::string& cert_file, const SymEncryptionType encrpt_type) {
00195   xmlNodePtr data_nd = this->node_;
00196   xmlDocPtr doc_nd = data_nd->doc;
00197 
00198   xmlNodePtr encDataNode = NULL;
00199   xmlNodePtr keyInfoNode = NULL;
00200   xmlNodePtr encKeyNode = NULL;
00201   xmlNodePtr keyInfoNode2 = NULL;
00202   xmlSecEncCtxPtr encCtx = NULL;
00203 
00204   xmlSecTransformId encryption_sym_key_type;
00205   switch (encrpt_type) {
00206     case AES_256:
00207       encryption_sym_key_type = xmlSecTransformAes256CbcId;
00208       break;
00209     case TRIPLEDES:
00210       encryption_sym_key_type = xmlSecTransformDes3CbcId;
00211       break;
00212     case AES_128:
00213     default:
00214       encryption_sym_key_type = xmlSecTransformAes128CbcId;
00215       break;
00216   }
00217   //Create encryption template for a specific symetric key type
00218   encDataNode = xmlSecTmplEncDataCreate(doc_nd , encryption_sym_key_type,
00219                       NULL, xmlSecTypeEncElement, NULL, NULL);
00220   if(encDataNode == NULL) { std::cerr<<"Failed to create encryption template"<<std::endl; return false; }
00221 
00222   // Put encrypted data in the <enc:CipherValue/> node
00223   if(xmlSecTmplEncDataEnsureCipherValue(encDataNode) == NULL){
00224     std::cerr<<"Failed to add CipherValue node"<<std::endl;
00225     if(encDataNode != NULL) xmlFreeNode(encDataNode); return false;
00226   }
00227   // Add <dsig:KeyInfo/>
00228   keyInfoNode = xmlSecTmplEncDataEnsureKeyInfo(encDataNode, NULL);
00229   if(keyInfoNode == NULL) {
00230     std::cerr<<"Failed to add key info"<<std::endl;
00231     if(encDataNode != NULL) xmlFreeNode(encDataNode); return false;
00232   }
00233 
00234   // Add <enc:EncryptedKey/> to store the encrypted session key
00235   encKeyNode = xmlSecTmplKeyInfoAddEncryptedKey(keyInfoNode, xmlSecTransformRsaPkcs1Id, NULL, NULL, NULL);
00236   if(encKeyNode == NULL) {
00237     std::cerr<<"Failed to add key info"<<std::endl;
00238     if(encDataNode != NULL) xmlFreeNode(encDataNode); return false;
00239   }
00240 
00241   // Put encrypted key in the <enc:CipherValue/> node
00242   if(xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == NULL) {
00243     std::cerr<<"Error: failed to add CipherValue node"<<std::endl;
00244     if(encDataNode != NULL) xmlFreeNode(encDataNode); return false;
00245   }
00246 
00247   // Add <dsig:KeyInfo/> and <dsig:KeyName/> nodes to <enc:EncryptedKey/>
00248   keyInfoNode2 = xmlSecTmplEncDataEnsureKeyInfo(encKeyNode, NULL);
00249   if(keyInfoNode2 == NULL){
00250     std::cerr<<"Failed to add key info"<<std::endl;
00251     if(encDataNode != NULL) xmlFreeNode(encDataNode); return false;
00252   }
00253 
00254   //Create encryption context
00255   xmlSecKeysMngr* keys_mngr = NULL;
00256   keys_mngr = load_key_from_certfile(&keys_mngr, cert_file.c_str());
00257   encCtx = xmlSecEncCtxCreate(keys_mngr);
00258   if(encCtx == NULL) {
00259     std::cerr<<"Failed to create encryption context"<<std::endl;
00260     if(encDataNode != NULL) xmlFreeNode(encDataNode); return false;
00261   }
00262   
00263   //Generate a symmetric key
00264   switch (encrpt_type) {
00265     case AES_256:
00266        encCtx->encKey = xmlSecKeyGenerate(xmlSecKeyDataAesId, 256, xmlSecKeyDataTypeSession);
00267       break;
00268     case TRIPLEDES:
00269        encCtx->encKey = xmlSecKeyGenerate(xmlSecKeyDataDesId, 192, xmlSecKeyDataTypeSession);
00270       break;
00271     case AES_128:
00272     default:
00273        encCtx->encKey = xmlSecKeyGenerate(xmlSecKeyDataAesId, 128, xmlSecKeyDataTypeSession);
00274       break;
00275   }
00276   if(encCtx->encKey == NULL) {
00277     std::cerr<<"Failed to generate session des key"<<std::endl;
00278     if(encCtx != NULL) xmlSecEncCtxDestroy(encCtx);
00279     if(encDataNode != NULL) xmlFreeNode(encDataNode);
00280     return false;
00281   }
00282   //Encrypt the node  
00283   if(xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, data_nd) < 0) {
00284     std::cerr<<"Encryption failed"<<std::endl;
00285     if(encCtx != NULL) xmlSecEncCtxDestroy(encCtx);
00286     if(encDataNode != NULL) xmlFreeNode(encDataNode);
00287     return false;
00288   }
00289 
00290     //The template has been inserted in the doc
00291   this->node_ = (data_nd=encDataNode);
00292   encDataNode = NULL;
00293 
00294   if(encCtx != NULL) xmlSecEncCtxDestroy(encCtx);
00295   if(keys_mngr != NULL)xmlSecKeysMngrDestroy(keys_mngr);
00296   return true;
00297 }
00298 
00299 bool XMLSecNode::DecryptNode(const std::string& privkey_file, XMLNode& decrypted_node) {
00300   XMLNode encrypted_data = (*this)["xenc:EncryptedData"];
00301   XMLNode enc_method1 = encrypted_data["xenc:EncryptionMethod"];
00302   std::string algorithm = (std::string)(enc_method1.Attribute("Algorithm"));
00303   if(algorithm.empty()) { std::cerr<<"No EncryptionMethod"<<std::endl; return false; }
00304   xmlSecKeyDataId key_type;
00305   if(algorithm.find("#aes")!=std::string::npos) { key_type = xmlSecKeyDataAesId;}
00306   else if(algorithm.find("#des")!=std::string::npos) { key_type = xmlSecKeyDataDesId;}
00307   else { std::cerr<<"Unknown EncryptionMethod"<<std::endl; return false; }  
00308 
00309   xmlNodePtr todecrypt_data_nd = ((XMLSecNode*)(&encrypted_data))->node_;
00310 
00311   XMLNode encrypted_key = encrypted_data["KeyInfo"]["EncryptedKey"]; 
00312   //Copy the encrypted key, because it will be replaced by decrypted node after
00313   //decryption, and then it will affect the decryption if encrypted data
00314   xmlNodePtr todecrypt_key_nd = xmlCopyNode(((XMLSecNode*)(&encrypted_key))->node_, 1);
00315 
00316   xmlDocPtr doc_key_nd = NULL;
00317   doc_key_nd = xmlNewDoc((xmlChar*)"1.0");
00318   xmlDocSetRootElement(doc_key_nd, todecrypt_key_nd);
00319 
00320   xmlSecKeyPtr private_key = get_key_from_keyfile(privkey_file.c_str());
00321 
00322   xmlSecEncCtxPtr encCtx = NULL;
00323   xmlSecKeyPtr symmetric_key = NULL;
00324   xmlSecBufferPtr key_buffer; 
00325   encCtx = xmlSecEncCtxCreate(NULL);
00326   if (encCtx == NULL) { std::cerr<<"Failed to create encryption context"<<std::endl; xmlFreeDoc(doc_key_nd); return false; }
00327   encCtx->encKey = private_key;
00328   encCtx->mode = xmlEncCtxModeEncryptedKey;
00329   key_buffer = xmlSecEncCtxDecryptToBuffer(encCtx, todecrypt_key_nd);
00330   if (key_buffer == NULL) { 
00331     std::cerr<<"Failed to decrypt EncryptedKey"<<std::endl;  
00332     xmlSecEncCtxDestroy(encCtx);  xmlFreeDoc(doc_key_nd); return false;
00333   }
00334   symmetric_key = xmlSecKeyReadBuffer(key_type, key_buffer);
00335   if (symmetric_key == NULL) { 
00336     std::cerr<<"Failed to decrypt EncryptedKey"<<std::endl; 
00337     xmlSecEncCtxDestroy(encCtx);  xmlFreeDoc(doc_key_nd); return false;
00338   }
00339   xmlSecEncCtxDestroy(encCtx);
00340 
00341   xmlDocPtr doc_data_nd = NULL;
00342   doc_data_nd = xmlNewDoc((xmlChar*)"1.0");
00343   xmlDocSetRootElement(doc_data_nd, todecrypt_data_nd);
00344   encCtx = xmlSecEncCtxCreate(NULL);
00345   if (encCtx == NULL) { std::cerr<<"Failed to create encryption context"<<std::endl; xmlFreeDoc(doc_key_nd); xmlFreeDoc(doc_data_nd); return false; }
00346   encCtx->encKey = symmetric_key;
00347   encCtx->mode = xmlEncCtxModeEncryptedData;
00348   xmlSecBufferPtr decrypted_buf;
00349   decrypted_buf = xmlSecEncCtxDecryptToBuffer(encCtx, todecrypt_data_nd);
00350   if(decrypted_buf == NULL) {
00351     std::cerr<<"Failed to decrypt EncryptedData"<<std::endl;
00352     xmlSecEncCtxDestroy(encCtx); xmlFreeDoc(doc_key_nd);  xmlFreeDoc(doc_data_nd); return false;
00353   }
00354 
00355   std::string decrypted_str((const char*)decrypted_buf->data);
00356   //std::cout<<"Decrypted node: "<<decrypted_str<<std::endl;
00357 
00358   // TODO: less copies
00359   XMLNode decrypted_data(decrypted_str);
00360   decrypted_data.New(decrypted_node);
00361 
00362   xmlSecEncCtxDestroy(encCtx);
00363   xmlFreeDoc(doc_key_nd);
00364   xmlFreeDoc(doc_data_nd);
00365 
00366   return true;
00367 }
00368 
00369 } // namespace Arc