00001
00002
00003 const char *XrdCryptosslX509CrlCVSID = "$Id: XrdCryptosslX509Crl.cc 31508 2009-12-02 19:11:01Z brun $";
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <sys/types.h>
00019 #include <sys/stat.h>
00020 #include <unistd.h>
00021 #include <errno.h>
00022 #include <time.h>
00023
00024 #include <XrdCrypto/XrdCryptosslRSA.hh>
00025 #include <XrdCrypto/XrdCryptosslX509Crl.hh>
00026 #include <XrdCrypto/XrdCryptosslAux.hh>
00027 #include <XrdCrypto/XrdCryptosslTrace.hh>
00028
00029 #include <openssl/bn.h>
00030 #include <openssl/pem.h>
00031
00032
00033 XrdCryptosslX509Crl::XrdCryptosslX509Crl(const char *cf, int opt)
00034 : XrdCryptoX509Crl()
00035 {
00036
00037 EPNAME("X509Crl::XrdCryptosslX509Crl_file");
00038
00039
00040 crl = 0;
00041 lastupdate = -1;
00042 nextupdate = -1;
00043 issuer = "";
00044 issuerhash = "";
00045 srcfile = "";
00046 nrevoked = 0;
00047
00048
00049 if (opt == 0) {
00050 if (Init(cf) != 0) {
00051 DEBUG("could not initialize the CRL from "<<cf);
00052 return;
00053 }
00054 } else {
00055 if (InitFromURI(cf, 0) != 0) {
00056 DEBUG("could not initialize the CRL from URI"<<cf);
00057 return;
00058 }
00059 }
00060 }
00061
00062
00063 XrdCryptosslX509Crl::XrdCryptosslX509Crl(XrdCryptoX509 *cacert)
00064 : XrdCryptoX509Crl()
00065 {
00066
00067
00068
00069
00070 EPNAME("X509Crl::XrdCryptosslX509Crl_CA");
00071
00072
00073 crl = 0;
00074 lastupdate = -1;
00075 nextupdate = -1;
00076 issuer = "";
00077 issuerhash = "";
00078 srcfile = "";
00079 nrevoked = 0;
00080
00081
00082 if (!cacert || cacert->type != XrdCryptoX509::kCA) {
00083 DEBUG("the CA certificate is undefined or not CA! ("<<cacert<<")");
00084 return;
00085 }
00086
00087
00088 X509_EXTENSION *crlext = (X509_EXTENSION *) cacert->GetExtension("crlDistributionPoints");
00089 if (!crlext) {
00090 DEBUG("extension 'crlDistributionPoints' not found in the CA certificate");
00091 return;
00092 }
00093
00094
00095 BIO *bext = BIO_new(BIO_s_mem());
00096 ASN1_OBJECT *obj = X509_EXTENSION_get_object(crlext);
00097 i2a_ASN1_OBJECT(bext, obj);
00098 X509V3_EXT_print(bext, crlext, 0, 4);
00099
00100 char *cbio = 0;
00101 int lbio = (int) BIO_get_mem_data(bext, &cbio);
00102 char *buf = (char *) malloc(lbio+1);
00103
00104 memcpy(buf, cbio, lbio);
00105 buf[lbio] = 0;
00106 BIO_free(bext);
00107
00108 XrdOucString uris(buf);
00109 free(buf);
00110
00111 DEBUG("URI string: "<< uris);
00112
00113 XrdOucString uri;
00114 int from = 0;
00115 while ((from = uris.tokenize(uri, from, ' ')) != -1) {
00116 if (uri.beginswith("URI:")) {
00117 uri.replace("URI:","");
00118 uri.replace("\n","");
00119 if (InitFromURI(uri.c_str(), cacert->SubjectHash()) == 0) {
00120 crluri = uri;
00121
00122 break;
00123 }
00124 }
00125 }
00126 }
00127
00128
00129 XrdCryptosslX509Crl::~XrdCryptosslX509Crl()
00130 {
00131
00132
00133
00134 if (crl)
00135 X509_CRL_free(crl);
00136 }
00137
00138
00139 int XrdCryptosslX509Crl::Init(const char *cf)
00140 {
00141
00142
00143 EPNAME("X509Crl::Init");
00144
00145
00146 if (!cf) {
00147 DEBUG("file name undefined");
00148 return -1;
00149 }
00150
00151 struct stat st;
00152 if (stat(cf, &st) != 0) {
00153 if (errno == ENOENT) {
00154 DEBUG("file "<<cf<<" does not exist - do nothing");
00155 } else {
00156 DEBUG("cannot stat file "<<cf<<" (errno: "<<errno<<")");
00157 }
00158 return -1;
00159 }
00160
00161
00162 FILE *fc = fopen(cf, "r");
00163 if (!fc) {
00164 DEBUG("cannot open file "<<cf<<" (errno: "<<errno<<")");
00165 return -1;
00166 }
00167
00168
00169 if (!PEM_read_X509_CRL(fc, &crl, 0, 0)) {
00170 DEBUG("Unable to load CRL from file");
00171 return -1;
00172 } else {
00173 DEBUG("CRL successfully loaded");
00174 }
00175
00176
00177 fclose(fc);
00178
00179
00180 srcfile = cf;
00181
00182
00183 Issuer();
00184
00185
00186 LoadCache();
00187
00188
00189 return 0;
00190 }
00191
00192
00193 int XrdCryptosslX509Crl::InitFromURI(const char *uri, const char *hash)
00194 {
00195
00196
00197
00198 EPNAME("X509Crl::InitFromURI");
00199
00200
00201 if (!uri) {
00202 DEBUG("uri undefined");
00203 return -1;
00204 }
00205 XrdOucString u(uri), h(hash);
00206 if (h == "") h = "hashtmp";
00207
00208
00209 bool needsopenssl = 0;
00210 XrdOucString outder(getenv("TMPDIR")), outpem;
00211 if (outder.length() <= 0) outder = "/tmp";
00212 if (!outder.endswith("/")) outder += "/";
00213 outder += hash;
00214 if (u.endswith(".pem")) {
00215 outder += ".pem";
00216 } else {
00217 outder += "_crl.der";
00218 needsopenssl = 1;
00219 }
00220
00221
00222 XrdOucString cmd("wget ");
00223 cmd += uri;
00224 cmd += " -O ";
00225 cmd += outder;
00226
00227
00228 DEBUG("executing ... "<<cmd);
00229 if (system(cmd.c_str()) == -1) {
00230 DEBUG("'system' could not fork to execute command '"<<cmd<<"'");
00231 return -1;
00232 }
00233 struct stat st;
00234 if (stat(outder.c_str(), &st) != 0) {
00235 DEBUG("did not manage to get the CRL file from "<<uri);
00236 return -1;
00237 }
00238 outpem = outder;
00239
00240 if (needsopenssl) {
00241
00242 outpem.replace("_crl.der", ".pem");
00243 cmd = "openssl crl -inform DER -in ";
00244 cmd += outder;
00245 cmd += " -out ";
00246 cmd += outpem;
00247 cmd += " -text";
00248
00249
00250 DEBUG("executing ... "<<cmd);
00251 if (system(cmd.c_str()) == -1) {
00252 DEBUG("system: problem executing: "<<cmd);
00253 return -1;
00254 }
00255
00256
00257 if (unlink(outder.c_str()) != 0) {
00258 DEBUG("problems removing "<<outder);
00259 }
00260 }
00261
00262
00263 if (stat(outpem.c_str(), &st) != 0) {
00264 DEBUG("did not manage to change format from DER to PEM ("<<outpem<<")");
00265 return -1;
00266 }
00267
00268
00269 if (Init(outpem.c_str()) != 0) {
00270 DEBUG("could not initialize the CRL from "<<outpem);
00271 return -1;
00272 }
00273
00274
00275 unlink(outpem.c_str());
00276
00277
00278
00279 return 0;
00280 }
00281
00282
00283 int XrdCryptosslX509Crl::LoadCache()
00284 {
00285
00286
00287 EPNAME("LoadCache");
00288
00289
00290 if (!crl) {
00291 DEBUG("CRL undefined");
00292 return -1;
00293 }
00294
00295
00296 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
00297 STACK_OF(X509_REVOKED *) rsk = X509_CRL_get_REVOKED(crl);
00298 #else
00299 STACK_OF(X509_REVOKED *) *rsk = X509_CRL_get_REVOKED(crl);
00300 #endif
00301 if (!rsk) {
00302 DEBUG("could not get stack of revoked instances");
00303 return -1;
00304 }
00305
00306
00307 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
00308 nrevoked = sk_X509_REVOKED_num(rsk);
00309 #else
00310 nrevoked = sk_num(rsk);
00311 #endif
00312 DEBUG(nrevoked << "certificates have been revoked");
00313 if (nrevoked <= 0) {
00314 DEBUG("no valid certificate has been revoked - nothing to do");
00315 return 0;
00316 }
00317
00318
00319 if (cache.Init(nrevoked) != 0) {
00320 DEBUG("problems init cache for CRL info");
00321 return -1;
00322 }
00323
00324
00325 char *tagser = 0;
00326 int i = 0;
00327 for (; i < nrevoked; i++ ){
00328 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
00329 X509_REVOKED *rev = sk_X509_REVOKED_value(rsk,i);
00330 #else
00331 X509_REVOKED *rev = (X509_REVOKED *)sk_value(rsk,i);
00332 #endif
00333 if (rev) {
00334 BIGNUM *bn = BN_new();
00335 ASN1_INTEGER_to_BN(rev->serialNumber, bn);
00336 tagser = BN_bn2hex(bn);
00337 BN_free(bn);
00338 TRACE(Dump, "certificate with serial number: "<<tagser<<
00339 " has been revoked");
00340
00341 XrdSutPFEntry *cent = cache.Add((const char *)tagser);
00342 if (!cent) {
00343 DEBUG("problems updating the cache");
00344 return -1;
00345 }
00346
00347 cent->mtime = XrdCryptosslASN1toUTC(rev->revocationDate);
00348
00349 OPENSSL_free(tagser);
00350 }
00351 }
00352
00353
00354 cache.Rehash(1);
00355
00356 return 0;
00357 }
00358
00359
00360 int XrdCryptosslX509Crl::LastUpdate()
00361 {
00362
00363
00364
00365 if (lastupdate < 0) {
00366
00367 if (crl)
00368
00369 lastupdate = XrdCryptosslASN1toUTC(X509_CRL_get_lastUpdate(crl));
00370 }
00371
00372 return lastupdate;
00373 }
00374
00375
00376 int XrdCryptosslX509Crl::NextUpdate()
00377 {
00378
00379
00380
00381 if (nextupdate < 0) {
00382
00383 if (crl)
00384
00385 nextupdate = XrdCryptosslASN1toUTC(X509_CRL_get_nextUpdate(crl));
00386 }
00387
00388 return nextupdate;
00389 }
00390
00391
00392 const char *XrdCryptosslX509Crl::Issuer()
00393 {
00394
00395 EPNAME("X509Crl::Issuer");
00396
00397
00398 if (issuer.length() <= 0) {
00399
00400
00401 if (!crl) {
00402 DEBUG("WARNING: no CRL available - cannot extract issuer name");
00403 return (const char *)0;
00404 }
00405
00406
00407 issuer = X509_NAME_oneline(X509_CRL_get_issuer(crl), 0, 0);
00408 }
00409
00410
00411 return (issuer.length() > 0) ? issuer.c_str() : (const char *)0;
00412 }
00413
00414
00415 const char *XrdCryptosslX509Crl::IssuerHash()
00416 {
00417
00418 EPNAME("X509Crl::IssuerHash");
00419
00420
00421 if (issuerhash.length() <= 0) {
00422
00423
00424 if (crl) {
00425 char chash[15];
00426 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
00427 sprintf(chash,"%08lx.0",X509_NAME_hash_old(crl->crl->issuer));
00428 #else
00429 sprintf(chash,"%08lx.0",X509_NAME_hash(crl->crl->issuer));
00430 #endif
00431 issuerhash = chash;
00432 } else {
00433 DEBUG("WARNING: no CRL available - cannot extract issuer hash");
00434 }
00435 }
00436
00437
00438 return (issuerhash.length() > 0) ? issuerhash.c_str() : (const char *)0;
00439 }
00440
00441
00442 bool XrdCryptosslX509Crl::Verify(XrdCryptoX509 *ref)
00443 {
00444
00445
00446
00447 if (!crl)
00448 return 0;
00449
00450
00451 X509 *r = ref ? (X509 *)(ref->Opaque()) : 0;
00452 EVP_PKEY *rk = r ? X509_get_pubkey(r) : 0;
00453 if (!rk)
00454 return 0;
00455
00456
00457 return (X509_CRL_verify(crl, rk) > 0);
00458 }
00459
00460
00461 bool XrdCryptosslX509Crl::IsRevoked(int serialnumber, int when)
00462 {
00463
00464
00465 EPNAME("IsRevoked");
00466
00467
00468 int now = (when > 0) ? when : time(0);
00469
00470
00471 if (now > NextUpdate()) {
00472 DEBUG("WARNING: CRL is expired: you should download the updated one");
00473 }
00474
00475
00476 if (nrevoked <= 0) {
00477 DEBUG("No certificate in the list");
00478 return 0;
00479 }
00480
00481
00482 char tagser[20] = {0};
00483 sprintf(tagser,"%x",serialnumber);
00484
00485
00486 XrdSutPFEntry *cent = cache.Get((const char *)tagser);
00487 if (cent) {
00488
00489 if (now > cent->mtime) {
00490 DEBUG("certificate "<<tagser<<" has been revoked");
00491 return 1;
00492 }
00493 }
00494
00495
00496 return 0;
00497 }
00498
00499
00500 bool XrdCryptosslX509Crl::IsRevoked(const char *sernum, int when)
00501 {
00502
00503
00504 EPNAME("IsRevoked");
00505
00506
00507 int now = (when > 0) ? when : time(0);
00508
00509
00510 if (now > NextUpdate()) {
00511 DEBUG("WARNING: CRL is expired: you should download the updated one");
00512 }
00513
00514
00515 if (nrevoked <= 0) {
00516 DEBUG("No certificate in the list");
00517 return 0;
00518 }
00519
00520
00521 XrdSutPFEntry *cent = cache.Get((const char *)sernum);
00522 if (cent) {
00523
00524 if (now > cent->mtime) {
00525 DEBUG("certificate "<<sernum<<" has been revoked");
00526 return 1;
00527 }
00528 }
00529
00530
00531 return 0;
00532 }
00533
00534
00535 void XrdCryptosslX509Crl::Dump()
00536 {
00537
00538 EPNAME("X509Crl::Dump");
00539
00540
00541 struct tm tst;
00542 char stbeg[256] = {0};
00543 time_t tbeg = LastUpdate();
00544 localtime_r(&tbeg,&tst);
00545 asctime_r(&tst,stbeg);
00546 stbeg[strlen(stbeg)-1] = 0;
00547 char stend[256] = {0};
00548 time_t tend = NextUpdate();
00549 localtime_r(&tend,&tst);
00550 asctime_r(&tst,stend);
00551 stend[strlen(stend)-1] = 0;
00552
00553 PRINT("+++++++++++++++ X509 CRL dump +++++++++++++++++++++++");
00554 PRINT("+");
00555 PRINT("+ File: "<<ParentFile());
00556 PRINT("+");
00557 PRINT("+ Issuer: "<<Issuer());
00558 PRINT("+ Issuer hash: "<<IssuerHash());
00559 PRINT("+");
00560 if (IsExpired()) {
00561 PRINT("+ Validity: (expired!)");
00562 } else {
00563 PRINT("+ Validity:");
00564 }
00565 PRINT("+ LastUpdate: "<<tbeg<<" UTC - "<<stbeg);
00566 PRINT("+ NextUpdate: "<<tend<<" UTC - "<<stend);
00567 PRINT("+");
00568 PRINT("+ Number of revoked certificates: "<<nrevoked);
00569 PRINT("+");
00570 PRINT("+++++++++++++++++++++++++++++++++++++++++++++++++");
00571 }