XRootD
XrdSecgsitest.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d S e c g s i t e s t . c c */
4 /* */
5 /* (c) 2005, G. Ganis / CERN */
6 /* */
7 /* This file is part of the XRootD software suite. */
8 /* */
9 /* XRootD is free software: you can redistribute it and/or modify it under */
10 /* the terms of the GNU Lesser General Public License as published by the */
11 /* Free Software Foundation, either version 3 of the License, or (at your */
12 /* option) any later version. */
13 /* */
14 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
15 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
16 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
17 /* License for more details. */
18 /* */
19 /* You should have received a copy of the GNU Lesser General Public License */
20 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
21 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
22 /* */
23 /* The copyright holder's institutional names and contributor's names may not */
24 /* be used to endorse or promote products derived from this software without */
25 /* specific prior written permission of the institution or contributor. */
26 /* */
27 /******************************************************************************/
28 
29 //
30 // Test program for XrdSecgsi
31 //
32 
33 #include <cstdio>
34 #include <cstdlib>
35 #include <cstring>
36 
37 #include <sys/types.h>
38 #include <pwd.h>
39 
40 #include "XrdOuc/XrdOucString.hh"
41 #include "XrdSys/XrdSysLogger.hh"
42 #include "XrdSys/XrdSysError.hh"
43 
44 #include "XrdSut/XrdSutAux.hh"
45 
52 
54 
56 
58 
59 #include <openssl/x509v3.h>
60 #include <openssl/x509.h>
61 
62 //
63 // Globals
64 
65 // #define PRINT(x) {std::cerr <<x <<std::endl;}
67 
72 XrdOucString CAdir = "/etc/grid-security/certificates/";
73 int CAnum = 0;
75 int Dbg = 0;
76 int Help = 0;
77 
78 //
79 // For error logging and tracing
81 static XrdSysError eDest(0,"gsitest_");
83 
84 #define PRTWIDTH 80
85 static void pdots(const char *t, bool ok = 1)
86 {
87  unsigned int i = 0;
88  unsigned int l = (t) ? strlen (t) : 0;
89  unsigned int np = PRTWIDTH - l - 8;
90  if (l > 0) {
91  printf("|| %s ", t);
92  } else {
93  printf("|| ");
94  }
95  for (; i < np ; i++) { printf("."); }
96  printf(" %s\n", (ok ? "PASSED" : "FAILED"));
97 }
98 static void pline(const char *t)
99 {
100  unsigned int i = 0;
101  unsigned int l = (t) ? strlen (t) : 0;
102  unsigned int np = PRTWIDTH - l - 3;
103  if (l > 0) {
104  printf("|| %s ---", t);
105  } else {
106  printf("|| ----");
107  }
108  for (; i < np ; i++) { printf("-"); }
109  printf("\n");
110 }
111 
112 static void printHelp()
113 {
114  printf(" \n");
115  printf(" Basic test program for crypto functionality in relation to GSI.\n");
116  printf(" The program needs access to a user certificate file and its private key, and the related\n");
117  printf(" CA file(s); the CRL is downloaded using the information found in the CA certificate.\n");
118  printf(" The location of the files are the standard ones and they can modified by the standard\n");
119  printf(" environment variables:\n");
120  printf(" \n");
121  printf(" X509_USER_CERT [$HOME/.globus/usercert.pem] user certificate\n");
122  printf(" X509_USER_KEY [$HOME/.globus/userkey.pem] user private key\n");
123  printf(" X509_USER_PROXY [/tmp/x509up_u<uid>] user proxy\n");
124  printf(" X509_CERT_DIR [/etc/grid-security/certificates/] CA certificates and CRL directories\n");
125  printf(" \n");
126  printf(" Usage:\n");
127  printf(" xrdgsitest [-v,--verbose] [-h,--help] \n");
128  printf(" \n");
129  printf(" -h, --help Print this screen\n");
130  printf(" -v, --verbose Dump all details\n");
131  printf(" \n");
132  printf(" The output is a list of PASSED/FAILED test, interleaved with details when the verbose option\n");
133  printf(" is chosen.\n");
134  printf(" \n");
135 }
136 
137 int main( int argc, char **argv )
138 {
139  // Test implemented functionality
140  EPNAME("main");
141  char cryptomod[64] = "ssl";
142  char outname[256] = {0};
143 
144  // Basic argument parsing
145  int i = 1;
146  for (; i < argc; i++) {
147  // Verbosity level
148  if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) Dbg = 1;
149  if (!strcmp(argv[i], "-vv")) Dbg = 2;
150  // Help
151  if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) Help = 1;
152  }
153 
154  // Print help if required
155  if (Help) {
156  printHelp();
157  exit(0);
158  }
159 
160  //
161  // Initiate error logging and tracing
162  eDest.logger(&Logger);
163  if (!gsiTrace)
164  gsiTrace = new XrdOucTrace(&eDest);
165  if (gsiTrace && Dbg > 0) {
166  // Medium level
168  }
169  //
170  // Set debug flags in other modules
171  kXR_int32 tracesut = (Dbg > 0) ? sutTRACE_Debug : 0;
172  kXR_int32 tracecrypto = (Dbg > 0) ? cryptoTRACE_Debug : 0;
173  XrdSutSetTrace(tracesut);
174  XrdCryptoSetTrace(tracecrypto);
175 
176  //
177  // Determine application name
178  char *p = argv[0];
179  int k = strlen(argv[0]);
180  while (k--)
181  if (p[k] == '/') break;
182  strcpy(outname,p+k+1);
183 
184  //
185  // Load the crypto factory
187  pdots(" Cannot instantiate factory", 0);
188  exit(1);
189  }
190  if (Dbg > 0)
192 
193  pline("");
194  pline("Crypto functionality tests for GSI");
195  pline("");
196 
197  //
198  // Find out the username and locate the relevant certificates and directories
199  struct passwd *pw = getpwuid(geteuid());
200  if (!pw) {
201  pdots(" Could not resolve user info - exit", 0);
202  exit(1);
203  }
204  NOTIFY("effective user is : "<<pw->pw_name<<", $HOME : "<<pw->pw_dir);
205 
206  //
207  // User certificate
208  EEcert = pw->pw_dir;
209  EEcert += "/.globus/usercert.pem";
210  if (getenv("X509_USER_CERT")) EEcert = getenv("X509_USER_CERT");
211  NOTIFY("user EE certificate: "<<EEcert);
213  if (xEE) {
214  if (Dbg > 0) xEE->Dump();
215  } else {
216  pdots(" Problems loading user EE cert", 0);
217  }
218  if (xEE) pdots("Loading EEC", 1);
219 
220  //
221  // User key
222  EEkey = pw->pw_dir;
223  EEkey += "/.globus/userkey.pem";
224  if (getenv("X509_USER_KEY")) EEkey = getenv("X509_USER_KEY");
225  NOTIFY("user EE key: "<<EEkey);
226  //
227  // User Proxy certificate
228  PXcert = "/tmp/x509up_u";
229  PXcert += (int) pw->pw_uid;
230  if (getenv("X509_USER_PROXY")) PXcert = getenv("X509_USER_PROXY");
231  NOTIFY("user proxy certificate: "<<PXcert);
233  if (xPX) {
234  if (Dbg > 0) xPX->Dump();
235  } else {
236  pdots(" Problems loading user proxy cert", 0);
237  }
238  if (xPX) pdots("Loading User Proxy", 1);
239 
240  //
241  pline("");
242  pline("Recreate the proxy certificate");
243  XrdProxyOpt_t *pxopt = 0; // defaults
245  XrdCryptoRSA *kPXp = 0;
246  XrdCryptoX509 *xPXp = 0;
247  X509_EXTENSION *ext = 0;
249  pxopt, cPXp, &kPXp, PXcert.c_str());
250  if (prc == 0) {
251  if (Dbg > 0) cPXp->Dump();
252  if ((xPXp = (XrdCryptoX509 *)(cPXp->Begin()))) {
253  pdots("Recreating User Proxy", 1);
254  if ((ext = (X509_EXTENSION *)(xPXp->GetExtension("1.3.6.1.4.1.3536.1.222")))) {
255  pdots("proxyCertInfo extension OK", 1);
256  }
257  }
258  } else {
259  pdots("Recreating User Proxy", 0);
260  exit(1);
261  }
262 
263  // use recreated proxy certificate if it a proxy was not already set
264  if (!xPX)
265  xPX = xPXp;
266 
267  //
268  pline("");
269  pline("Load CA certificates");
270  // Load CA certificates now
271  XrdCryptoX509 *xCA[5], *xCAref = 0;
272  if (getenv("X509_CERT_DIR")) CAdir = getenv("X509_CERT_DIR");
273  if (!CAdir.endswith("/")) CAdir += "/";
274  XrdCryptoX509 *xc = xEE;
275  bool rCAfound = 0;
276  int nCA = 0;
277  while (!rCAfound && nCA < 5) {
278  CAcert[nCA] = CAdir;
279  CAcert[nCA] += xc->IssuerHash();
280  NOTIFY("issuer CA certificate path "<<CAcert[nCA]);
281  xCA[nCA] = gCryptoFactory->X509(CAcert[nCA].c_str());
282  if (xCA[nCA]) {
283  if (Dbg > 0) xCA[nCA]->Dump();
284  pdots("Loading CA certificate", 1);
285  } else {
286  pdots("Loading CA certificate", 0);
287  rCAfound = 0;
288  break;
289  }
290  // Check if self-signed
291  if (!strcmp(xCA[nCA]->IssuerHash(), xCA[nCA]->SubjectHash())) {
292  rCAfound = 1;
293  break;
294  }
295  // If not, parse the issuer ...
296  xc = xCA[nCA];
297  nCA++;
298  }
299 
300  //
301  pline("");
302  pline("Testing ParseFile");
304  XrdCryptoRSA *key = 0;
305  XrdCryptoX509Chain *chain = new XrdCryptoX509Chain();
306  if (ParseFile) {
307  int nci = (*ParseFile)(PXcert.c_str(), chain, 0);
308  if (!(key = chain->Begin()->PKI())) {
309  pdots("getting PKI", 0);
310  }
311  NOTIFY(nci <<" certificates found parsing file");
312  if (Dbg > 0) chain->Dump();
313  int jCA = nCA + 1;
314  while (jCA--) {
315  chain->PushBack(xCA[jCA]);
316  }
317  if (Dbg > 0) chain->Dump();
318  int rorc = chain->Reorder();
319  if (rCAfound) {
320  if (Dbg > 0) chain->Dump();
321  pdots("Chain reorder: ", (rorc != -1));
323  int verc = chain->Verify(ecod);
324  pdots("Chain verify: ", verc);
325  } else {
326  pdots("Full CA chain verification", 0);
327  }
328  } else {
329  pdots("attaching to X509ParseFile", 0);
330  exit (1);
331  }
332 
333  //
334  pline("");
335  pline("Testing ExportChain");
337  XrdSutBucket *chainbck = 0;
338  if (ExportChain && chain->End()) {
339  chainbck = (*ExportChain)(chain, 0);
340  pdots("Attach to X509ExportChain", 1);
341  } else {
342  pdots("Attach to X509ExportChain", 0);
343  exit (1);
344  }
345  //
346  pline("");
347  pline("Testing Chain Import");
349  if (!ParseBucket) pdots("attaching to X509ParseBucket", 0);
350  // Init new chain with CA certificate
351  int jCA = nCA;
352  XrdCryptoX509Chain *CAchain = new XrdCryptoX509Chain(xCA[jCA]);
353  while (jCA) { CAchain->PushBack(xCA[--jCA]); }
354  if (ParseBucket && CAchain) {
355  int nci = (*ParseBucket)(chainbck, CAchain);
356  NOTIFY(nci <<" certificates found parsing bucket");
357  if (Dbg > 0) CAchain->Dump();
358  int rorc = CAchain->Reorder();
359  pdots("Chain reorder: ", (rorc != -1));
360  if (Dbg > 0) CAchain->Dump();
362  int verc = CAchain->Verify(ecod);
363  pdots("Chain verify: ", verc);
364  } else {
365  pdots("creating new X509Chain", 0);
366  exit (1);
367  }
368 
369  //
370  pline("");
371  pline("Testing GSI chain import and verification");
372  // Init new GSI chain with CA certificate
373  jCA = nCA;
375  while (jCA) { GSIchain->PushBack(xCA[--jCA]); }
376  if (ParseBucket && GSIchain) {
377  int nci = (*ParseBucket)(chainbck, GSIchain);
378  NOTIFY(nci <<" certificates found parsing bucket");
379  if (Dbg > 0) GSIchain->Dump();
381  x509ChainVerifyOpt_t vopt = { kOptsRfc3820, 0, -1, 0};
382  int verc = GSIchain->Verify(ecod, &vopt);
383  pdots("GSI chain verify: ", verc);
384  if (!verc) NOTIFY("GSI chain verify ERROR: "<<GSIchain->LastError());
385  if (Dbg > 0) GSIchain->Dump();
386  } else {
387  pdots("Creating new gsiX509Chain", 0);
388  exit (1);
389  }
390 
391  //
392  pline("");
393  pline("Testing GSI chain copy");
394  // Init new GSI chain with CA certificate
396  if (GSInew) {
397  if (Dbg > 0) GSInew->Dump();
399  x509ChainVerifyOpt_t vopt = { kOptsRfc3820, 0, -1, 0};
400  int verc = GSInew->Verify(ecod, &vopt);
401  if (!verc) NOTIFY("GSI chain copy verify ERROR: "<<GSInew->LastError());
402  pdots("GSI chain verify: ", verc);
403  if (Dbg > 0) GSInew->Dump();
404  } else {
405  pdots("Creating new gsiX509Chain with copy", 0);
406  exit (1);
407  }
408 
409  //
410  pline("");
411  pline("Testing Cert verification");
413  if (VerifyCert) {
414  bool ok;
415  jCA = nCA;
416  while (jCA >= 0) {
417  ok = xEE->Verify(xCA[jCA]);
418  NOTIFY( ": verify cert: EE signed by CA? " <<ok<<" ("<<xCA[jCA]->Subject()<<")");
419  if (ok) xCAref = xCA[jCA];
420  jCA--;
421  }
422  pdots("verify cert: EE signed by CA", (xCAref ? 1 : 0));
423  ok = xPX->Verify(xEE);
424  pdots("verify cert: PX signed by EE", ok);
425  jCA = nCA;
426  bool refok = 0;
427  while (jCA >= 0) {
428  ok = xPX->Verify(xCA[jCA]);
429  NOTIFY( ": verify cert: PX signed by CA? " <<ok<<" ("<<xCA[jCA]->Subject()<<")");
430  if (!refok && ok) refok = 1;
431  jCA--;
432  }
433  pdots("verify cert: PX not signed by CA", !refok);
434  } else {
435  pdots("Attaching to X509VerifyCert", 0);
436  exit (1);
437  }
438 
439 
440  //
441  pline("");
442  pline("Testing request creation");
443  XrdCryptoX509Req *rPXp = 0;
444  XrdCryptoRSA *krPXp = 0;
445  prc = gCryptoFactory->X509CreateProxyReq()(xPX, &rPXp, &krPXp);
446  if (prc == 0) {
447  pdots("Creating request", 1);
448  if (Dbg > 0) rPXp->Dump();
449  } else {
450  pdots("Creating request", 0);
451  exit(1);
452  }
453 
454  //
455  pline("");
456  pline("Testing request signature");
457  XrdCryptoX509 *xPXpp = 0;
458  prc = gCryptoFactory->X509SignProxyReq()(xPX, kPXp, rPXp, &xPXpp);
459  if (prc == 0) {
460  if (Dbg > 0) xPXpp->Dump();
461  xPXpp->SetPKI((XrdCryptoX509data) krPXp->Opaque());
462  bool extok = 0;
463  if ((ext = (X509_EXTENSION *)xPXpp->GetExtension(gsiProxyCertInfo_OID))) extok = 1;
464  pdots("Check proxyCertInfo extension", extok);
465  } else {
466  pdots("Signing request", 0);
467  exit(1);
468  }
469 
470  //
471  pline("");
472  pline("Testing export of signed proxy");
473  PPXcert = PXcert;
474  PPXcert += "p";
475  NOTIFY(": file for signed proxy chain: "<<PPXcert);
477  // Init the proxy chain
478  XrdCryptoX509Chain *PXchain = new XrdCryptoX509Chain(xPXpp);
479  PXchain->PushBack(xPX);
480  PXchain->PushBack(xEE);
481  if (ChainToFile && PXchain) {
482  if ((*ChainToFile)(PXchain, PPXcert.c_str()) != 0) {
483  NOTIFY(": problems saving signed proxy chain to file: "<<PPXcert);
484  pdots("Saving signed proxy chain to file", 0);
485  } else {
486  pdots("Saving signed proxy chain to file", 1);
487  }
488  } else {
489  pdots("Creating new X509Chain", 0);
490  exit (1);
491  }
492 
493  //
494  pline("");
495  pline("Testing CRL identification");
496  X509_EXTENSION *crlext = 0;
497  if (xCAref) {
498  if ((crlext = (X509_EXTENSION *)xCAref->GetExtension("crlDistributionPoints"))) {
499  pdots("Check CRL distribution points extension OK", 1);
500  } else {
501  pdots("Getting extension", 0);
502  }
503  }
504 
505  //
506  pline("");
507  pline("Testing CRL loading");
508  XrdCryptoX509Crl *xCRL1 = gCryptoFactory->X509Crl(xCAref);
509  if (xCRL1) {
510  if (Dbg > 0) xCRL1->Dump();
511  pdots("Loading CA1 crl", 1);
512  // Verify CRL signature
513  bool crlsig = 0, xsig = 0;
514  for (jCA = 0; jCA <= nCA; jCA++) {
515  xsig = xCRL1->Verify(xCA[jCA]);
516  NOTIFY( ": CRL signature OK? "<<xsig<<" ("<<xCA[jCA]->Subject()<<")");
517  if (!crlsig && xsig) crlsig = 1;
518  }
519  pdots("CRL signature OK", crlsig);
520  // Verify a serial number
521  bool snrev = xCRL1->IsRevoked(25, 0);
522  NOTIFY( ": SN: 25 revoked? "<<snrev);
523  // Verify another serial number
524  snrev = xCRL1->IsRevoked(0x20, 0);
525  NOTIFY( ": SN: 32 revoked? "<<snrev);
526  } else {
527  pdots("Loading CA1 crl", 0);
528  }
529 
530  pline("");
531  exit(0);
532 }
int kXR_int32
Definition: XPtypes.hh:89
#define EPNAME(x)
Definition: XrdBwmTrace.hh:56
#define TRACE_Debug
Definition: XrdCmsTrace.hh:37
void XrdCryptoSetTrace(kXR_int32 trace)
Definition: XrdCryptoAux.cc:49
#define cryptoTRACE_Debug
Definition: XrdCryptoAux.hh:48
int(* XrdCryptoX509ChainToFile_t)(XrdCryptoX509Chain *, const char *)
#define gsiProxyCertInfo_OID
int(* XrdCryptoX509ParseBucket_t)(XrdSutBucket *, XrdCryptoX509Chain *)
bool(* XrdCryptoX509VerifyCert_t)(XrdCryptoX509 *c, XrdCryptoX509 *r)
XrdSutBucket *(* XrdCryptoX509ExportChain_t)(XrdCryptoX509Chain *, bool)
int(* XrdCryptoX509ParseFile_t)(const char *fname, XrdCryptoX509Chain *, const char *)
void * XrdCryptoX509data
const int kOptsRfc3820
#define TRACE_Authen
Definition: XrdSecTrace.hh:62
XrdCryptoX509ParseFile_t ParseFile
#define NOTIFY(y)
XrdOucString CAdir
XrdOucString CAcert[5]
int main(int argc, char **argv)
XrdOucString PPXcert
#define PRTWIDTH
static void pline(const char *t)
XrdOucString PXcert
static void printHelp()
static XrdSysLogger Logger
int Help
XrdCryptoFactory * gCryptoFactory
int CAnum
XrdOucTrace * gsiTrace
static XrdSysError eDest(0,"gsitest_")
static void pdots(const char *t, bool ok=1)
int Dbg
XrdOucString EEcert
XrdOucString EEkey
void XrdSutSetTrace(kXR_int32 trace)
Definition: XrdSutAux.cc:93
#define sutTRACE_Debug
Definition: XrdSutAux.hh:99
if(Avsz)
virtual XrdCryptoX509ParseBucket_t X509ParseBucket()
virtual XrdCryptoX509CreateProxyReq_t X509CreateProxyReq()
virtual XrdCryptoX509 * X509(const char *cf, const char *kf=0)
virtual void SetTrace(kXR_int32 trace)
virtual XrdCryptoX509ParseFile_t X509ParseFile()
virtual XrdCryptoX509CreateProxy_t X509CreateProxy()
virtual XrdCryptoX509ChainToFile_t X509ChainToFile()
virtual XrdCryptoX509Crl * X509Crl(const char *crlfile, int opt=0)
static XrdCryptoFactory * GetCryptoFactory(const char *factoryname)
virtual XrdCryptoX509SignProxyReq_t X509SignProxyReq()
virtual XrdCryptoX509ExportChain_t X509ExportChain()
virtual XrdCryptoX509VerifyCert_t X509VerifyCert()
virtual XrdCryptoRSAdata Opaque()
Definition: XrdCryptoRSA.cc:51
virtual bool Verify(EX509ChainErr &e, x509ChainVerifyOpt_t *vopt=0)
XrdCryptoX509 * Begin()
XrdCryptoX509 * End() const
void PushBack(XrdCryptoX509 *c)
const char * LastError() const
virtual void Dump()
virtual bool IsRevoked(int serialnumber, int when)
virtual bool Verify(XrdCryptoX509 *ref)
virtual void Dump()
virtual bool Verify(XrdCryptoX509 *ref)
virtual XrdCryptoX509data GetExtension(const char *oid)
virtual void SetPKI(XrdCryptoX509data pki)
virtual void Dump()
virtual XrdCryptoRSA * PKI()
virtual const char * IssuerHash(int)
bool Verify(EX509ChainErr &e, x509ChainVerifyOpt_t *vopt=0)
const char * c_str() const
bool endswith(char c)
XrdSysLogger * logger(XrdSysLogger *lp=0)
Definition: XrdSysError.hh:141