/******************************************************************************/ /* */ /* X r d S e c g s i t e s t . c c */ /* */ /* (c) 2005, G. Ganis / CERN */ /* */ /* This file is part of the XRootD software suite. */ /* */ /* XRootD is free software: you can redistribute it and/or modify it under */ /* the terms of the GNU Lesser General Public License as published by the */ /* Free Software Foundation, either version 3 of the License, or (at your */ /* option) any later version. */ /* */ /* XRootD is distributed in the hope that it will be useful, but WITHOUT */ /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */ /* License for more details. */ /* */ /* You should have received a copy of the GNU Lesser General Public License */ /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */ /* COPYING (GPL license). If not, see . */ /* */ /* The copyright holder's institutional names and contributor's names may not */ /* be used to endorse or promote products derived from this software without */ /* specific prior written permission of the institution or contributor. */ /* */ /******************************************************************************/ // // Test program for XrdSecgsi // #include #include #include #include #include #include "XrdOuc/XrdOucString.hh" #include "XrdSys/XrdSysLogger.hh" #include "XrdSys/XrdSysError.hh" #include "XrdSut/XrdSutAux.hh" #include "XrdCrypto/XrdCryptoAux.hh" #include "XrdCrypto/XrdCryptoFactory.hh" #include "XrdCrypto/XrdCryptoX509.hh" #include "XrdCrypto/XrdCryptoX509Req.hh" #include "XrdCrypto/XrdCryptoX509Chain.hh" #include "XrdCrypto/XrdCryptoX509Crl.hh" #include "XrdCrypto/XrdCryptosslAux.hh" #include "XrdCrypto/XrdCryptogsiX509Chain.hh" #include "XrdSecgsi/XrdSecgsiTrace.hh" #include #include // // Globals // #define PRINT(x) {cerr < 0) { printf("|| %s ---", t); } else { printf("|| ----"); } for (; i < np ; i++) { printf("-"); } printf("\n"); } static void printHelp() { printf(" \n"); printf(" Basic test program for crypto functionality in relation to GSI.\n"); printf(" The program needs access to a user certificate file and its private key, and the related\n"); printf(" CA file(s); the CRL is downloaded using the information found in the CA certificate.\n"); printf(" The location of the files are the standard ones and they can modified by the standard\n"); printf(" environment variables:\n"); printf(" \n"); printf(" X509_USER_CERT [$HOME/.globus/usercert.pem] user certificate\n"); printf(" X509_USER_KEY [$HOME/.globus/userkey.pem] user private key\n"); printf(" X509_USER_PROXY [/tmp/x509up_u] user proxy\n"); printf(" X509_CERT_DIR [/etc/grid-security/certificates/] CA certificates and CRL directories\n"); printf(" \n"); printf(" Usage:\n"); printf(" xrdgsitest [-v,--verbose] [-h,--help] \n"); printf(" \n"); printf(" -h, --help Print this screen\n"); printf(" -v, --verbose Dump all details\n"); printf(" \n"); printf(" The output is a list of PASSED/FAILED test, interleaved with details when the verbose option\n"); printf(" is chosen.\n"); printf(" \n"); } int main( int argc, char **argv ) { // Test implemented functionality EPNAME("main"); char cryptomod[64] = "ssl"; char outname[256] = {0}; // Basic argument parsing int i = 1; for (; i < argc; i++) { // Verbosity level if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) Dbg = 1; if (!strcmp(argv[i], "-vv")) Dbg = 2; // Help if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) Help = 1; } // Print help if required if (Help) { printHelp(); exit(0); } // // Initiate error logging and tracing eDest.logger(&Logger); if (!gsiTrace) gsiTrace = new XrdOucTrace(&eDest); if (gsiTrace && Dbg > 0) { // Medium level gsiTrace->What |= (TRACE_Authen | TRACE_Debug); } // // Set debug flags in other modules kXR_int32 tracesut = (Dbg > 0) ? sutTRACE_Debug : 0; kXR_int32 tracecrypto = (Dbg > 0) ? cryptoTRACE_Debug : 0; XrdSutSetTrace(tracesut); XrdCryptoSetTrace(tracecrypto); // // Determine application name char *p = argv[0]; int k = strlen(argv[0]); while (k--) if (p[k] == '/') break; strcpy(outname,p+k+1); // // Load the crypto factory if (!(gCryptoFactory = XrdCryptoFactory::GetCryptoFactory(cryptomod))) { pdots(" Cannot instantiate factory", 0); exit(1); } if (Dbg > 0) gCryptoFactory->SetTrace(cryptoTRACE_Debug); pline(""); pline("Crypto functionality tests for GSI"); pline(""); // // Find out the username and locate the relevant certificates and directories struct passwd *pw = getpwuid(geteuid()); if (!pw) { pdots(" Could not resolve user info - exit", 0); exit(1); } NOTIFY("effective user is : "<pw_name<<", $HOME : "<pw_dir); // // User certificate EEcert = pw->pw_dir; EEcert += "/.globus/usercert.pem"; if (getenv("X509_USER_CERT")) EEcert = getenv("X509_USER_CERT"); NOTIFY("user EE certificate: "<X509(EEcert.c_str()); if (xEE) { if (Dbg > 0) xEE->Dump(); } else { pdots(" Problems loading user EE cert", 0); } if (xEE) pdots("Loading EEC", 1); // // User key EEkey = pw->pw_dir; EEkey += "/.globus/userkey.pem"; if (getenv("X509_USER_KEY")) EEkey = getenv("X509_USER_KEY"); NOTIFY("user EE key: "<pw_uid; if (getenv("X509_USER_PROXY")) PXcert = getenv("X509_USER_PROXY"); NOTIFY("user proxy certificate: "<X509(PXcert.c_str()); if (xPX) { if (Dbg > 0) xPX->Dump(); } else { pdots(" Problems loading user proxy cert", 0); } if (xPX) pdots("Loading User Proxy", 1); // pline(""); pline("Recreate the proxy certificate"); XrdProxyOpt_t *pxopt = 0; // defaults XrdCryptogsiX509Chain *cPXp = new XrdCryptogsiX509Chain(); XrdCryptoRSA *kPXp = 0; XrdCryptoX509 *xPXp = 0; X509_EXTENSION *ext = 0; int prc = gCryptoFactory->X509CreateProxy()(EEcert.c_str(), EEkey.c_str(), pxopt, cPXp, &kPXp, PXcert.c_str()); if (prc == 0) { if (Dbg > 0) cPXp->Dump(); if ((xPXp = (XrdCryptoX509 *)(cPXp->Begin()))) { pdots("Recreating User Proxy", 1); if ((ext = (X509_EXTENSION *)(xPXp->GetExtension("1.3.6.1.4.1.3536.1.222")))) { pdots("proxyCertInfo extension OK", 1); } } } else { pdots("Recreating User Proxy", 0); exit(1); } // pline(""); pline("Load CA certificates"); // Load CA certificates now XrdCryptoX509 *xCA[5], *xCAref = 0; if (getenv("X509_CERT_DIR")) CAdir = getenv("X509_CERT_DIR"); if (!CAdir.endswith("/")) CAdir += "/"; XrdCryptoX509 *xc = xEE; bool rCAfound = 0; int nCA = 0; while (!rCAfound && nCA < 5) { CAcert[nCA] = CAdir; CAcert[nCA] += xc->IssuerHash(); NOTIFY("issuer CA certificate path "<X509(CAcert[nCA].c_str()); if (xCA[nCA]) { if (Dbg > 0) xCA[nCA]->Dump(); pdots("Loading CA certificate", 1); } else { pdots("Loading CA certificate", 0); } // Check if self-signed if (!strcmp(xCA[nCA]->IssuerHash(), xCA[nCA]->SubjectHash())) { rCAfound = 1; break; } // If not, parse the issuer ... xc = xCA[nCA]; nCA++; } // pline(""); pline("Testing ParseFile"); XrdCryptoX509ParseFile_t ParseFile = gCryptoFactory->X509ParseFile(); XrdCryptoRSA *key = 0; XrdCryptoX509Chain *chain = new XrdCryptoX509Chain(); if (ParseFile) { int nci = (*ParseFile)(PXcert.c_str(), chain); if (!(key = chain->Begin()->PKI())) { pdots("getting PKI", 0); } NOTIFY(nci <<" certificates found parsing file"); if (Dbg > 0) chain->Dump(); int jCA = nCA + 1; while (jCA--) { chain->PushBack(xCA[jCA]); } if (Dbg > 0) chain->Dump(); int rorc = chain->Reorder(); if (rCAfound) { if (Dbg > 0) chain->Dump(); pdots("Chain reorder: ", (rorc != -1)); XrdCryptoX509Chain::EX509ChainErr ecod = XrdCryptoX509Chain::kNone; int verc = chain->Verify(ecod); pdots("Chain verify: ", verc); } else { pdots("Full CA chain verification", 0); } } else { pdots("attaching to X509ParseFile", 0); exit (1); } // pline(""); pline("Testing ExportChain"); XrdCryptoX509ExportChain_t ExportChain = gCryptoFactory->X509ExportChain(); XrdSutBucket *chainbck = 0; if (ExportChain) { chainbck = (*ExportChain)(chain, 0); pdots("Attach to X509ExportChain", 1); } else { pdots("Attach to X509ExportChain", 0); exit (1); } // pline(""); pline("Testing Chain Import"); XrdCryptoX509ParseBucket_t ParseBucket = gCryptoFactory->X509ParseBucket(); if (!ParseBucket) pdots("attaching to X509ParseBucket", 0); // Init new chain with CA certificate int jCA = nCA; XrdCryptoX509Chain *CAchain = new XrdCryptoX509Chain(xCA[jCA]); while (jCA) { CAchain->PushBack(xCA[--jCA]); } if (ParseBucket && CAchain) { int nci = (*ParseBucket)(chainbck, CAchain); NOTIFY(nci <<" certificates found parsing bucket"); if (Dbg > 0) CAchain->Dump(); int rorc = CAchain->Reorder(); pdots("Chain reorder: ", (rorc != -1)); if (Dbg > 0) CAchain->Dump(); XrdCryptoX509Chain::EX509ChainErr ecod = XrdCryptoX509Chain::kNone; int verc = CAchain->Verify(ecod); pdots("Chain verify: ", verc); } else { pdots("creating new X509Chain", 0); exit (1); } // pline(""); pline("Testing GSI chain import and verification"); // Init new GSI chain with CA certificate jCA = nCA; XrdCryptogsiX509Chain *GSIchain = new XrdCryptogsiX509Chain(xCA[jCA], gCryptoFactory); while (jCA) { GSIchain->PushBack(xCA[--jCA]); } if (ParseBucket && GSIchain) { int nci = (*ParseBucket)(chainbck, GSIchain); NOTIFY(nci <<" certificates found parsing bucket"); if (Dbg > 0) GSIchain->Dump(); XrdCryptoX509Chain::EX509ChainErr ecod = XrdCryptoX509Chain::kNone; x509ChainVerifyOpt_t vopt = { kOptsRfc3820, 0, -1, 0}; int verc = GSIchain->Verify(ecod, &vopt); pdots("GSI chain verify: ", verc); if (!verc) NOTIFY("GSI chain verify ERROR: "<LastError()); if (Dbg > 0) GSIchain->Dump(); } else { pdots("Creating new gsiX509Chain", 0); exit (1); } // pline(""); pline("Testing GSI chain copy"); // Init new GSI chain with CA certificate XrdCryptogsiX509Chain *GSInew = new XrdCryptogsiX509Chain(GSIchain, gCryptoFactory); if (GSInew) { if (Dbg > 0) GSInew->Dump(); XrdCryptoX509Chain::EX509ChainErr ecod = XrdCryptoX509Chain::kNone; x509ChainVerifyOpt_t vopt = { kOptsRfc3820, 0, -1, 0}; int verc = GSInew->Verify(ecod, &vopt); if (!verc) NOTIFY("GSI chain copy verify ERROR: "<LastError()); pdots("GSI chain verify: ", verc); if (Dbg > 0) GSInew->Dump(); } else { pdots("Creating new gsiX509Chain with copy", 0); exit (1); } // pline(""); pline("Testing Cert verification"); XrdCryptoX509VerifyCert_t VerifyCert = gCryptoFactory->X509VerifyCert(); if (VerifyCert) { bool ok; jCA = nCA; while (jCA >= 0) { ok = xEE->Verify(xCA[jCA]); NOTIFY( ": verify cert: EE signed by CA? " <Subject()<<")"); if (ok) xCAref = xCA[jCA]; jCA--; } pdots("verify cert: EE signed by CA", (xCAref ? 1 : 0)); ok = xPX->Verify(xEE); pdots("verify cert: PX signed by EE", ok); jCA = nCA; bool refok = 0; while (jCA >= 0) { ok = xPX->Verify(xCA[jCA]); NOTIFY( ": verify cert: PX signed by CA? " <Subject()<<")"); if (!refok && ok) refok = 1; jCA--; } pdots("verify cert: PX not signed by CA", !refok); } else { pdots("Attaching to X509VerifyCert", 0); exit (1); } // pline(""); pline("Testing request creation"); XrdCryptoX509Req *rPXp = 0; XrdCryptoRSA *krPXp = 0; prc = gCryptoFactory->X509CreateProxyReq()(xPX, &rPXp, &krPXp); if (prc == 0) { pdots("Creating request", 1); if (Dbg > 0) rPXp->Dump(); } else { pdots("Creating request", 0); exit(1); } // pline(""); pline("Testing request signature"); XrdCryptoX509 *xPXpp = 0; prc = gCryptoFactory->X509SignProxyReq()(xPX, kPXp, rPXp, &xPXpp); if (prc == 0) { if (Dbg > 0) xPXpp->Dump(); xPXpp->SetPKI((XrdCryptoX509data) krPXp->Opaque()); bool extok = 0; if ((ext = (X509_EXTENSION *)xPXpp->GetExtension(gsiProxyCertInfo_OID))) extok = 1; pdots("Check proxyCertInfo extension", extok); } else { pdots("Signing request", 0); exit(1); } // pline(""); pline("Testing export of signed proxy"); PPXcert = PXcert; PPXcert += "p"; NOTIFY(": file for signed proxy chain: "<X509ChainToFile(); // Init the proxy chain XrdCryptoX509Chain *PXchain = new XrdCryptoX509Chain(xPXpp); PXchain->PushBack(xPX); PXchain->PushBack(xEE); if (ChainToFile && PXchain) { if ((*ChainToFile)(PXchain, PPXcert.c_str()) != 0) { NOTIFY(": problems saving signed proxy chain to file: "<GetExtension("crlDistributionPoints"))) { pdots("Check CRL distribution points extension OK", 1); } else { pdots("Getting extension", 0); } } // pline(""); pline("Testing CRL loading"); XrdCryptoX509Crl *xCRL1 = gCryptoFactory->X509Crl(xCAref); if (xCRL1) { if (Dbg > 0) xCRL1->Dump(); pdots("Loading CA1 crl", 1); // Verify CRL signature bool crlsig = 0, xsig = 0; for (jCA = 0; jCA <= nCA; jCA++) { xsig = xCRL1->Verify(xCA[jCA]); NOTIFY( ": CRL signature OK? "<Subject()<<")"); if (!crlsig && xsig) crlsig = 1; } pdots("CRL signature OK", crlsig); // Verify a serial number bool snrev = xCRL1->IsRevoked(25, 0); NOTIFY( ": SN: 25 revoked? "<IsRevoked(0x20, 0); NOTIFY( ": SN: 32 revoked? "<