XrdCryptosslX509Crl.cc

Go to the documentation of this file.
00001 // $Id: XrdCryptosslX509Crl.cc 31508 2009-12-02 19:11:01Z brun $
00002 
00003 const char *XrdCryptosslX509CrlCVSID = "$Id: XrdCryptosslX509Crl.cc 31508 2009-12-02 19:11:01Z brun $";
00004 /******************************************************************************/
00005 /*                                                                            */
00006 /*                X r d C r y p t o s s l X 5 0 9 C r l. c c                  */
00007 /*                                                                            */
00008 /* (c) 2005 G. Ganis , CERN                                                   */
00009 /*                                                                            */
00010 /******************************************************************************/
00011 
00012 
00013 /* ************************************************************************** */
00014 /*                                                                            */
00015 /* OpenSSL implementation of XrdCryptoX509Crl                                 */
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    // Constructor certificate from file 'cf'.
00037    EPNAME("X509Crl::XrdCryptosslX509Crl_file");
00038 
00039    // Init private members
00040    crl = 0;         // The crl object
00041    lastupdate = -1;  // begin-validity time in secs since Epoch
00042    nextupdate = -1;   // end-validity time in secs since Epoch
00043    issuer = "";     // issuer;
00044    issuerhash = "";  // hash of issuer;
00045    srcfile = "";    // source file;
00046    nrevoked = 0;    // number of revoked certificates
00047 
00048    // Make sure file name is defined;
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    // Constructor certificate from CA certificate 'cacert'. This constructor
00067    // extracts the information about the location of the CRL cerificate from the
00068    // CA certificate extension 'crlDistributionPoints', downloads the file and
00069    // loads it in the cache
00070    EPNAME("X509Crl::XrdCryptosslX509Crl_CA");
00071 
00072    // Init private members
00073    crl = 0;         // The crl object
00074    lastupdate = -1;  // begin-validity time in secs since Epoch
00075    nextupdate = -1;   // end-validity time in secs since Epoch
00076    issuer = "";     // issuer;
00077    issuerhash = "";  // hash of issuer;
00078    srcfile = "";    // source file;
00079    nrevoked = 0;    // number of revoked certificates
00080 
00081    // The CA certificate must be defined
00082    if (!cacert || cacert->type != XrdCryptoX509::kCA) {
00083       DEBUG("the CA certificate is undefined or not CA! ("<<cacert<<")");
00084       return;
00085    }
00086 
00087    // Get the extension
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    // Bio for exporting the extension
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    // data length
00100    char *cbio = 0;
00101    int lbio = (int) BIO_get_mem_data(bext, &cbio);
00102    char *buf = (char *) malloc(lbio+1);
00103    // Read key from BIO to buf
00104    memcpy(buf, cbio, lbio);
00105    buf[lbio] = 0;
00106    BIO_free(bext);
00107    // Save it
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             // We are done
00122             break;
00123          }
00124       }
00125    }
00126 }
00127 
00128 //_____________________________________________________________________________
00129 XrdCryptosslX509Crl::~XrdCryptosslX509Crl()
00130 {
00131    // Destructor
00132 
00133    // Cleanup CRL
00134    if (crl)
00135       X509_CRL_free(crl);
00136 }
00137 
00138 //_____________________________________________________________________________
00139 int XrdCryptosslX509Crl::Init(const char *cf)
00140 {
00141    // Constructor certificate from file 'cf'.
00142    // Return 0 on success, -1 on failure
00143    EPNAME("X509Crl::Init");
00144 
00145    // Make sure file name is defined;
00146    if (!cf) {
00147       DEBUG("file name undefined");
00148       return -1;
00149    }
00150    // Make sure file exists;
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    // Open file in read mode
00162    FILE *fc = fopen(cf, "r");
00163    if (!fc) {
00164       DEBUG("cannot open file "<<cf<<" (errno: "<<errno<<")");
00165       return -1;
00166    }
00167    //
00168    // Read the content:
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    // Close the file
00177    fclose(fc);
00178    //
00179    // Save source file name
00180    srcfile = cf;
00181    //
00182    // Init some of the private members (the others upon need)
00183    Issuer();
00184    //
00185    // Load into cache
00186    LoadCache();
00187    //
00188    // Done
00189    return 0;
00190 }
00191 
00192 //_____________________________________________________________________________
00193 int XrdCryptosslX509Crl::InitFromURI(const char *uri, const char *hash)
00194 {
00195    // Initialize the CRL taking the file indicated by URI. Download and
00196    // reformat the file first.
00197    // Returns 0 on success, -1 on failure.
00198    EPNAME("X509Crl::InitFromURI");
00199 
00200    // Make sure file name is defined;
00201    if (!uri) {
00202       DEBUG("uri undefined");
00203       return -1;
00204    }
00205    XrdOucString u(uri), h(hash);
00206    if (h == "") h = "hashtmp";
00207 
00208    // Create local output file path
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    // Prepare 'wget' command
00222    XrdOucString cmd("wget ");
00223    cmd += uri;
00224    cmd += " -O ";
00225    cmd += outder;
00226 
00227    // Execute 'wget'
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       // Put it in PEM format
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       // Execute 'openssl crl'
00250       DEBUG("executing ... "<<cmd);
00251       if (system(cmd.c_str()) == -1) {
00252         DEBUG("system: problem executing: "<<cmd);
00253         return -1;
00254       }
00255 
00256       // Cleanup the temporary files
00257       if (unlink(outder.c_str()) != 0) {
00258         DEBUG("problems removing "<<outder);
00259       }
00260    }
00261 
00262    // Make sure the file is there
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    // Now init from the new file
00269    if (Init(outpem.c_str()) != 0) {
00270       DEBUG("could not initialize the CRL from "<<outpem);
00271       return -1;
00272    }
00273 
00274    // Cleanup the temporary files
00275    unlink(outpem.c_str());
00276 
00277    //
00278    // Done
00279    return 0;
00280 }
00281 
00282 //_____________________________________________________________________________
00283 int XrdCryptosslX509Crl::LoadCache()
00284 {
00285    // Load relevant info into the cache
00286    // Return 0 if ok, -1 in case of error
00287    EPNAME("LoadCache");
00288 
00289    // The CRL must exists
00290    if (!crl) {
00291       DEBUG("CRL undefined");
00292       return -1;
00293    }
00294 
00295    // Parse CRL
00296 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
00297    STACK_OF(X509_REVOKED *) rsk = X509_CRL_get_REVOKED(crl);
00298 #else /* OPENSSL */
00299    STACK_OF(X509_REVOKED *) *rsk = X509_CRL_get_REVOKED(crl);
00300 #endif /* OPENSSL */
00301    if (!rsk) {
00302       DEBUG("could not get stack of revoked instances");
00303       return -1;
00304    }
00305 
00306    // Number of revocations
00307 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
00308    nrevoked = sk_X509_REVOKED_num(rsk);
00309 #else /* OPENSSL */
00310    nrevoked = sk_num(rsk);
00311 #endif /* OPENSSL */
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    // Init cache
00319    if (cache.Init(nrevoked) != 0) {
00320       DEBUG("problems init cache for CRL info");
00321       return -1;
00322    }
00323 
00324    // Get serial numbers of revoked certificates
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 /* OPENSSL */
00331       X509_REVOKED *rev = (X509_REVOKED *)sk_value(rsk,i);
00332 #endif /* OPENSSL */
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          // Add to the cache
00341          XrdSutPFEntry *cent = cache.Add((const char *)tagser);
00342          if (!cent) {
00343             DEBUG("problems updating the cache");
00344             return -1;
00345          }
00346          // Add revocation date
00347          cent->mtime = XrdCryptosslASN1toUTC(rev->revocationDate);
00348          // Release the string for the serial number
00349          OPENSSL_free(tagser);
00350       }
00351    }
00352 
00353    // rehash the cache
00354    cache.Rehash(1);
00355 
00356    return 0;
00357 }
00358 
00359 //_____________________________________________________________________________
00360 int XrdCryptosslX509Crl::LastUpdate()
00361 {
00362    // Time of last update
00363 
00364    // If we do not have it already, try extraction
00365    if (lastupdate < 0) {
00366       // Make sure we have a CRL
00367       if (crl)
00368          // Extract UTC time in secs from Epoch
00369          lastupdate = XrdCryptosslASN1toUTC(X509_CRL_get_lastUpdate(crl));
00370    }
00371    // return what we have
00372    return lastupdate;
00373 }
00374 
00375 //_____________________________________________________________________________
00376 int XrdCryptosslX509Crl::NextUpdate()
00377 {
00378    // Time of next update
00379 
00380    // If we do not have it already, try extraction
00381    if (nextupdate < 0) {
00382       // Make sure we have a CRL
00383       if (crl)
00384          // Extract UTC time in secs from Epoch
00385          nextupdate = XrdCryptosslASN1toUTC(X509_CRL_get_nextUpdate(crl));
00386    }
00387    // return what we have
00388    return nextupdate;
00389 }
00390 
00391 //_____________________________________________________________________________
00392 const char *XrdCryptosslX509Crl::Issuer()
00393 {
00394    // Return issuer name
00395    EPNAME("X509Crl::Issuer");
00396 
00397    // If we do not have it already, try extraction
00398    if (issuer.length() <= 0) {
00399 
00400       // Make sure we have a CRL
00401       if (!crl) {
00402          DEBUG("WARNING: no CRL available - cannot extract issuer name");
00403          return (const char *)0;
00404       }
00405 
00406       // Extract issuer name
00407       issuer = X509_NAME_oneline(X509_CRL_get_issuer(crl), 0, 0);
00408    }
00409 
00410    // return what we have
00411    return (issuer.length() > 0) ? issuer.c_str() : (const char *)0;
00412 }
00413 
00414 //_____________________________________________________________________________
00415 const char *XrdCryptosslX509Crl::IssuerHash()
00416 {
00417    // Return issuer name
00418    EPNAME("X509Crl::IssuerHash");
00419 
00420    // If we do not have it already, try extraction
00421    if (issuerhash.length() <= 0) {
00422 
00423       // Make sure we have a CRL
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    // return what we have
00438    return (issuerhash.length() > 0) ? issuerhash.c_str() : (const char *)0;
00439 }
00440 
00441 //_____________________________________________________________________________
00442 bool XrdCryptosslX509Crl::Verify(XrdCryptoX509 *ref)
00443 {
00444    // Verify certificate signature with pub key of ref cert
00445 
00446    // We must have been initialized
00447    if (!crl)
00448       return 0;
00449 
00450    // We must have something to check with
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    // Ok: we can verify
00457    return (X509_CRL_verify(crl, rk) > 0);
00458 }
00459 
00460 //_____________________________________________________________________________
00461 bool XrdCryptosslX509Crl::IsRevoked(int serialnumber, int when)
00462 {
00463    // Check if certificate with serialnumber is in the
00464    // list of revocated certificates
00465    EPNAME("IsRevoked");
00466 
00467    // Reference time
00468    int now = (when > 0) ? when : time(0);
00469 
00470    // Warn if CRL should be updated
00471    if (now > NextUpdate()) {
00472       DEBUG("WARNING: CRL is expired: you should download the updated one");
00473    }
00474 
00475    // We must have something to check against
00476    if (nrevoked <= 0) {
00477       DEBUG("No certificate in the list");
00478       return 0;
00479    }
00480 
00481    // Ok, build the tag
00482    char tagser[20] = {0};
00483    sprintf(tagser,"%x",serialnumber);
00484 
00485    // Look into the cache
00486    XrdSutPFEntry *cent = cache.Get((const char *)tagser);
00487    if (cent) {
00488       // Check the revocation time
00489       if (now > cent->mtime) {
00490          DEBUG("certificate "<<tagser<<" has been revoked");
00491          return 1;
00492       }
00493    }
00494 
00495    // Certificate not revoked
00496    return 0;
00497 }
00498 
00499 //_____________________________________________________________________________
00500 bool XrdCryptosslX509Crl::IsRevoked(const char *sernum, int when)
00501 {
00502    // Check if certificate with 'sernum' is in the
00503    // list of revocated certificates
00504    EPNAME("IsRevoked");
00505 
00506    // Reference time
00507    int now = (when > 0) ? when : time(0);
00508 
00509    // Warn if CRL should be updated
00510    if (now > NextUpdate()) {
00511       DEBUG("WARNING: CRL is expired: you should download the updated one");
00512    }
00513 
00514    // We must have something to check against
00515    if (nrevoked <= 0) {
00516       DEBUG("No certificate in the list");
00517       return 0;
00518    }
00519 
00520    // Look into the cache
00521    XrdSutPFEntry *cent = cache.Get((const char *)sernum);
00522    if (cent) {
00523       // Check the revocation time
00524       if (now > cent->mtime) {
00525          DEBUG("certificate "<<sernum<<" has been revoked");
00526          return 1;
00527       }
00528    }
00529 
00530    // Certificate not revoked
00531    return 0;
00532 }
00533 
00534 //_____________________________________________________________________________
00535 void XrdCryptosslX509Crl::Dump()
00536 {
00537    // Dump content
00538    EPNAME("X509Crl::Dump");
00539 
00540    // Time strings
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 }

Generated on Tue Jul 5 14:46:34 2011 for ROOT_528-00b_version by  doxygen 1.5.1