XrdCryptosslX509.cc

Go to the documentation of this file.
00001 // $Id: XrdCryptosslX509.cc 31508 2009-12-02 19:11:01Z brun $
00002 
00003 const char *XrdCryptosslX509CVSID = "$Id: XrdCryptosslX509.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 c                    */
00007 /*                                                                            */
00008 /* (c) 2005 G. Ganis , CERN                                                   */
00009 /*                                                                            */
00010 /******************************************************************************/
00011 
00012 
00013 /* ************************************************************************** */
00014 /*                                                                            */
00015 /* OpenSSL implementation of XrdCryptoX509                                    */
00016 /*                                                                            */
00017 /* ************************************************************************** */
00018 #include <sys/types.h>
00019 #include <sys/stat.h>
00020 #include <unistd.h>
00021 #include <errno.h>
00022 
00023 #include <XrdCrypto/XrdCryptosslRSA.hh>
00024 #include <XrdCrypto/XrdCryptosslX509.hh>
00025 #include <XrdCrypto/XrdCryptosslAux.hh>
00026 #include <XrdCrypto/XrdCryptosslTrace.hh>
00027 
00028 #include <openssl/pem.h>
00029 
00030 //_____________________________________________________________________________
00031 XrdCryptosslX509::XrdCryptosslX509(const char *cf, const char *kf)
00032                  : XrdCryptoX509()
00033 {
00034    // Constructor certificate from file 'cf'. If 'kf' is defined,
00035    // complete the key of the certificate with the private key in kf.
00036    EPNAME("X509::XrdCryptosslX509_file");
00037 
00038    // Init private members
00039    cert = 0;        // The certificate object
00040    notbefore = -1;  // begin-validity time in secs since Epoch
00041    notafter = -1;   // end-validity time in secs since Epoch
00042    subject = "";    // subject;
00043    issuer = "";     // issuer;
00044    subjecthash = ""; // hash of subject;
00045    issuerhash = "";  // hash of issuer;
00046    srcfile = "";    // source file;
00047    bucket = 0;      // bucket for serialization
00048    pki = 0;         // PKI of the certificate
00049 
00050    // Make sure file name is defined;
00051    if (!cf) {
00052       DEBUG("file name undefined");
00053       return;
00054    }
00055    // Make sure file exists;
00056    struct stat st;
00057    if (stat(cf, &st) != 0) {
00058       if (errno == ENOENT) {
00059          DEBUG("file "<<cf<<" does not exist - do nothing");
00060       } else {
00061          DEBUG("cannot stat file "<<cf<<" (errno: "<<errno<<")");
00062       }
00063       return;
00064    }
00065    //
00066    // Open file in read mode
00067    FILE *fc = fopen(cf, "r");
00068    if (!fc) {
00069       DEBUG("cannot open file "<<cf<<" (errno: "<<errno<<")");
00070       return;
00071    }
00072    //
00073    // Read the content:
00074    if (!PEM_read_X509(fc, &cert, 0, 0)) {
00075       DEBUG("Unable to load certificate from file");
00076       return;
00077    } else {
00078       DEBUG("certificate successfully loaded");
00079    }
00080    //
00081    // Close the file
00082    fclose(fc);
00083    //
00084    // Save source file name
00085    srcfile = cf;
00086    // Init some of the private members (the others upon need)
00087    Subject();
00088    Issuer();
00089    //
00090    // Find out type of certificate
00091    if (IsCA()) {
00092       type = kCA;
00093    } else {
00094       XrdOucString common(issuer,0,issuer.find('/',issuer.find("/CN=")+1));
00095       if (subject.beginswith(common))
00096          type = kProxy;
00097       else
00098          type = kEEC;
00099    }
00100    // Get the public key
00101    EVP_PKEY *evpp = X509_get_pubkey(cert);
00102    //
00103    if (evpp) {
00104       // Read the private key file, if specified
00105       if (kf) {
00106          if (stat(kf, &st) == -1) {
00107             DEBUG("cannot stat private key file "<<kf<<" (errno:"<<errno<<")");
00108             return;
00109          }
00110          if (!S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) ||
00111              (st.st_mode & (S_IWGRP | S_IWOTH)) != 0 ||
00112              (st.st_mode & (S_IRGRP | S_IROTH)) != 0 ||
00113              (st.st_mode & (S_IWUSR)) != 0) {
00114             DEBUG("private key file "<<kf<<" has wrong permissions "<<
00115                   (st.st_mode & 0777) << " (should be 0400)");
00116             return;
00117          }
00118          // Open file in read mode
00119          FILE *fk = fopen(kf, "r");
00120          if (!fk) {
00121             DEBUG("cannot open file "<<kf<<" (errno: "<<errno<<")");
00122             return;
00123          }
00124          if (PEM_read_PrivateKey(fk,&evpp,0,0)) {
00125             DEBUG("RSA key completed ");
00126             // Test consistency
00127             if (RSA_check_key(evpp->pkey.rsa) != 0) {
00128                // Save it in pki
00129                pki = new XrdCryptosslRSA(evpp);
00130             }
00131          } else {
00132             DEBUG("cannot read the key from file");
00133          }
00134          // Close the file
00135          fclose(fk);
00136       }
00137       // If there were no private key or we did not manage to import it
00138       // init pki with the partial key
00139       if (!pki)
00140          pki = new XrdCryptosslRSA(evpp, 0);
00141    } else {
00142       DEBUG("could not access the public key");
00143    }
00144 }
00145 
00146 //_____________________________________________________________________________
00147 XrdCryptosslX509::XrdCryptosslX509(XrdSutBucket *buck) : XrdCryptoX509()
00148 {
00149    // Constructor certificate from BIO 'bcer'
00150    EPNAME("X509::XrdCryptosslX509_bio");
00151 
00152    // Init private members
00153    cert = 0;        // The certificate object
00154    notbefore = -1;  // begin-validity time in secs since Epoch
00155    notafter = -1;   // end-validity time in secs since Epoch
00156    subject = "";    // subject;
00157    issuer = "";     // issuer;
00158    subjecthash = ""; // hash of subject;
00159    issuerhash = "";  // hash of issuer;
00160    srcfile = "";    // source file;
00161    bucket = 0;      // bucket for serialization
00162    pki = 0;         // PKI of the certificate
00163 
00164    // Make sure we got something;
00165    if (!buck) {
00166       DEBUG("got undefined opaque buffer");
00167       return;
00168    }
00169 
00170    //
00171    // Create a bio_mem to store the certificates
00172    BIO *bmem = BIO_new(BIO_s_mem());
00173    if (!bmem) {
00174       DEBUG("unable to create BIO for memory operations");
00175       return; 
00176    }
00177 
00178    // Write data to BIO
00179    int nw = BIO_write(bmem,(const void *)(buck->buffer),buck->size);
00180    if (nw != buck->size) {
00181       DEBUG("problems writing data to memory BIO (nw: "<<nw<<")");
00182       return; 
00183    }
00184 
00185    // Get certificate from BIO
00186    if (!PEM_read_bio_X509(bmem,&cert,0,0)) {
00187       DEBUG("unable to read certificate to memory BIO");
00188       return;
00189    }
00190    //
00191    // Free BIO
00192    BIO_free(bmem);
00193    //
00194    // Init some of the private members (the others upon need)
00195    Subject();
00196    Issuer();
00197    //
00198    // Find out type of certificate
00199    if (IsCA()) {
00200       type = kCA;
00201    } else {
00202       XrdOucString common(issuer,0,issuer.find('/',issuer.find("/CN=")+1));
00203       if (subject.beginswith(common))
00204          type = kProxy;
00205       else
00206          type = kEEC;
00207    }
00208    // Get the public key
00209    EVP_PKEY *evpp = X509_get_pubkey(cert);
00210    //
00211    if (evpp) {
00212       // init pki with the partial key
00213       if (!pki)
00214          pki = new XrdCryptosslRSA(evpp, 0);
00215    } else {
00216       DEBUG("could not access the public key");
00217    }
00218 }
00219 
00220 //_____________________________________________________________________________
00221 XrdCryptosslX509::XrdCryptosslX509(X509 *xc) : XrdCryptoX509()
00222 {
00223    // Constructor: import X509 object
00224    EPNAME("X509::XrdCryptosslX509_x509");
00225 
00226    // Init private members
00227    cert = 0;        // The certificate object
00228    notbefore = -1;  // begin-validity time in secs since Epoch
00229    notafter = -1;   // end-validity time in secs since Epoch
00230    subject = "";    // subject;
00231    issuer = "";     // issuer;
00232    subjecthash = ""; // hash of subject;
00233    issuerhash = "";  // hash of issuer;
00234    srcfile = "";    // source file;
00235    bucket = 0;      // bucket for serialization
00236    pki = 0;         // PKI of the certificate
00237 
00238    // Make sure we got something;
00239    if (!xc) {
00240       DEBUG("got undefined X509 object");
00241       return;
00242    }
00243 
00244    // Set certificate
00245    cert = xc;
00246    //
00247    // Init some of the private members (the others upon need)
00248    Subject();
00249    Issuer();
00250    //
00251    // Find out type of certificate
00252    if (IsCA()) {
00253       type = kCA;
00254    } else {
00255       XrdOucString common(issuer,0,issuer.find('/',issuer.find("/CN=")+1));
00256       if (subject.beginswith(common))
00257          type = kProxy;
00258       else
00259          type = kEEC;
00260    }
00261    // Get the public key
00262    EVP_PKEY *evpp = X509_get_pubkey(cert);
00263    //
00264    if (evpp) {
00265       // init pki with the partial key
00266       if (!pki)
00267          pki = new XrdCryptosslRSA(evpp, 0);
00268    } else {
00269       DEBUG("could not access the public key");
00270    }
00271 }
00272 
00273 //_____________________________________________________________________________
00274 XrdCryptosslX509::~XrdCryptosslX509()
00275 {
00276    // Destructor
00277 
00278    // Cleanup certificate
00279    if (cert) X509_free(cert);
00280    // Cleanup key
00281    if (pki) delete pki;
00282 }
00283 
00284 //_____________________________________________________________________________
00285 void XrdCryptosslX509::SetPKI(XrdCryptoX509data newpki)
00286 {
00287    // Set PKI
00288 
00289    // Cleanup key first
00290    if (pki)
00291       delete pki;
00292    if (newpki)
00293       pki = new XrdCryptosslRSA((EVP_PKEY *)newpki, 1);
00294 
00295 }
00296 
00297 //_____________________________________________________________________________
00298 int XrdCryptosslX509::NotBefore()
00299 {
00300    // Begin-validity time in secs since Epoch
00301 
00302    // If we do not have it already, try extraction
00303    if (notbefore < 0) {
00304       // Make sure we have a certificate
00305       if (cert)
00306          // Extract UTC time in secs from Epoch
00307          notbefore = XrdCryptosslASN1toUTC(X509_get_notBefore(cert));
00308    }
00309    // return what we have
00310    return notbefore;
00311 }
00312 
00313 //_____________________________________________________________________________
00314 int XrdCryptosslX509::NotAfter()
00315 {
00316    // End-validity time in secs since Epoch
00317 
00318    // If we do not have it already, try extraction
00319    if (notafter < 0) {
00320       // Make sure we have a certificate
00321       if (cert)
00322          // Extract UTC time in secs from Epoch
00323          notafter = XrdCryptosslASN1toUTC(X509_get_notAfter(cert));
00324    }
00325    // return what we have
00326    return notafter;
00327 }
00328 
00329 //_____________________________________________________________________________
00330 const char *XrdCryptosslX509::Subject()
00331 {
00332    // Return subject name
00333    EPNAME("X509::Subject");
00334 
00335    // If we do not have it already, try extraction
00336    if (subject.length() <= 0) {
00337 
00338       // Make sure we have a certificate
00339       if (!cert) {
00340          DEBUG("WARNING: no certificate available - cannot extract subject name");
00341          return (const char *)0;
00342       }
00343 
00344       // Extract subject name
00345       subject = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
00346    }
00347 
00348    // return what we have
00349    return (subject.length() > 0) ? subject.c_str() : (const char *)0;
00350 }
00351 
00352 //_____________________________________________________________________________
00353 const char *XrdCryptosslX509::Issuer()
00354 {
00355    // Return issuer name
00356    EPNAME("X509::Issuer");
00357 
00358    // If we do not have it already, try extraction
00359    if (issuer.length() <= 0) {
00360 
00361       // Make sure we have a certificate
00362       if (!cert) {
00363          DEBUG("WARNING: no certificate available - cannot extract issuer name");
00364          return (const char *)0;
00365       }
00366 
00367       // Extract issuer name
00368       issuer = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
00369    }
00370 
00371    // return what we have
00372    return (issuer.length() > 0) ? issuer.c_str() : (const char *)0;
00373 }
00374 
00375 //_____________________________________________________________________________
00376 const char *XrdCryptosslX509::IssuerHash()
00377 {
00378    // Return issuer name
00379    EPNAME("X509::IssuerHash");
00380 
00381    // If we do not have it already, try extraction
00382    if (issuerhash.length() <= 0) {
00383 
00384       // Make sure we have a certificate
00385       if (cert) {
00386          char chash[15];
00387 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
00388          sprintf(chash,"%08lx.0",X509_NAME_hash_old(cert->cert_info->issuer));
00389 #else
00390          sprintf(chash,"%08lx.0",X509_NAME_hash(cert->cert_info->issuer));
00391 #endif
00392          issuerhash = chash;
00393       } else {
00394          DEBUG("WARNING: no certificate available - cannot extract issuer hash");
00395       }
00396    }
00397 
00398    // return what we have
00399    return (issuerhash.length() > 0) ? issuerhash.c_str() : (const char *)0;
00400 }
00401 
00402 //_____________________________________________________________________________
00403 const char *XrdCryptosslX509::SubjectHash()
00404 {
00405    // Return issuer name
00406    EPNAME("X509::SubjectHash");
00407 
00408    // If we do not have it already, try extraction
00409    if (subjecthash.length() <= 0) {
00410 
00411       // Make sure we have a certificate
00412       if (cert) {
00413          char chash[15];
00414 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
00415          sprintf(chash,"%08lx.0",X509_NAME_hash_old(cert->cert_info->subject));
00416 #else
00417          sprintf(chash,"%08lx.0",X509_NAME_hash(cert->cert_info->subject));
00418 #endif
00419          subjecthash = chash;
00420       } else {
00421          DEBUG("WARNING: no certificate available - cannot extract subject hash");
00422       }
00423    }
00424 
00425    // return what we have
00426    return (subjecthash.length() > 0) ? subjecthash.c_str() : (const char *)0;
00427 }
00428 
00429 //_____________________________________________________________________________
00430 kXR_int64 XrdCryptosslX509::SerialNumber()
00431 {
00432    // Return serial number as a kXR_int64
00433 
00434    kXR_int64 sernum = -1;
00435    if (cert && X509_get_serialNumber(cert)) {
00436       BIGNUM *bn = BN_new();
00437       ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), bn);
00438       char *sn = BN_bn2dec(bn);
00439       sernum = strtoll(sn, 0, 10);
00440       BN_free(bn);
00441       OPENSSL_free(sn);
00442    }
00443 
00444    return sernum;
00445 }
00446 
00447 //_____________________________________________________________________________
00448 XrdOucString XrdCryptosslX509::SerialNumberString()
00449 {
00450    // Return serial number as a hex string
00451 
00452    XrdOucString sernum;
00453    if (cert && X509_get_serialNumber(cert)) {
00454       BIGNUM *bn = BN_new();
00455       ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), bn);
00456       char *sn = BN_bn2hex(bn);
00457       sernum = sn;
00458       BN_free(bn);
00459       OPENSSL_free(sn);
00460    }
00461 
00462    return sernum;
00463 }
00464 
00465 //_____________________________________________________________________________
00466 XrdCryptoX509data XrdCryptosslX509::GetExtension(const char *oid)
00467 {
00468    // Return pointer to extension with OID oid, if any, in
00469    // opaque form
00470    EPNAME("X509::GetExtension");
00471    XrdCryptoX509data ext = 0;
00472 
00473    // Make sure we got something to look for
00474    if (!oid) {
00475       DEBUG("OID string not defined");
00476       return ext;
00477    }
00478  
00479    // Make sure we got something to look for
00480    if (!cert) {
00481       DEBUG("certificate is not initialized");
00482       return ext;
00483    }
00484 
00485    // Are there any extension?
00486    int numext = X509_get_ext_count(cert);
00487    if (numext <= 0) {
00488       DEBUG("certificate has got no extensions");
00489       return ext;
00490    }
00491    DEBUG("certificate has "<<numext<<" extensions");
00492 
00493    // If the string is the Standard Name of a known extension check
00494    // searche the corresponding NID
00495    int nid = OBJ_sn2nid(oid);
00496    bool usenid = (nid > 0);
00497 
00498    // Loop to identify the one we would like
00499    int i = 0;
00500    X509_EXTENSION *wext = 0;
00501    for (i = 0; i< numext; i++) {
00502       wext = X509_get_ext(cert, i);
00503       if (usenid) {
00504          int enid = OBJ_obj2nid(X509_EXTENSION_get_object(wext));
00505          if (enid == nid)
00506             break;
00507       } else {
00508          // Try matching of the text
00509          char s[256];
00510          OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(wext), 1);
00511          if (!strcmp(s, oid)) 
00512             break;
00513       }
00514       // Do not free the extension: its owned by the certificate
00515       wext = 0;
00516    }
00517 
00518    // We are done if nothing was found
00519    if (!wext) {
00520       DEBUG("Extension "<<oid<<" not found"); 
00521       return ext;
00522    }
00523 
00524    // We are done
00525    return (XrdCryptoX509data)wext;
00526 }
00527 
00528 //_____________________________________________________________________________
00529 bool XrdCryptosslX509::IsCA() 
00530 {
00531    // Check if this certificate is a CA certificate
00532    EPNAME("X509::IsCA");
00533 
00534    // Make sure we got something to look for
00535    if (!cert) {
00536       DEBUG("certificate is not initialized");
00537       return 0;
00538    }
00539 
00540    // Are there any extension?
00541    int numext = X509_get_ext_count(cert);
00542    if (numext <= 0) {
00543       DEBUG("certificate has got no extensions");
00544       return 0;
00545    }
00546    TRACE(ALL,"certificate has "<<numext<<" extensions");
00547 
00548    X509_EXTENSION *ext = 0;
00549    int i = 0;
00550    for (; i < numext; i++) {
00551       // Get the extension
00552       ext = X509_get_ext(cert,i);
00553       // We are looking for a "basicConstraints"
00554       if (OBJ_obj2nid(X509_EXTENSION_get_object(ext)) ==
00555           OBJ_sn2nid("basicConstraints")) {
00556          break;
00557       }
00558       // Do not free the extension: its owned by the certificate
00559       ext = 0;
00560    }
00561 
00562    // Return it there were none
00563    if (!ext) 
00564       return 0;
00565 
00566    // Analyse the structure
00567    unsigned char *p = ext->value->data;
00568 #ifdef R__SSL_GE_098
00569    BASIC_CONSTRAINTS *bc =
00570       d2i_BASIC_CONSTRAINTS(0, const_cast<const unsigned char**>(&p), ext->value->length);
00571 #else
00572    BASIC_CONSTRAINTS *bc = d2i_BASIC_CONSTRAINTS(0, &p, ext->value->length);
00573 #endif
00574 
00575    // CA?
00576    bool isca = (bc->ca != 0);
00577    if (isca) {
00578       DEBUG("CA certificate"); 
00579    }
00580 
00581    // We are done
00582    return isca;
00583 }
00584 
00585 //_____________________________________________________________________________
00586 XrdSutBucket *XrdCryptosslX509::Export()
00587 {
00588    // Export in form of bucket
00589    EPNAME("X509::Export");
00590 
00591    // If we have already done it, return the previous result
00592    if (bucket) {
00593       DEBUG("serialization already performed:"
00594             " return previous result ("<<bucket->size<<" bytes)");
00595       return bucket;
00596    }
00597 
00598    // Make sure we got something to export
00599    if (!cert) {
00600       DEBUG("certificate is not initialized");
00601       return 0;
00602    }
00603 
00604    //
00605    // Now we create a bio_mem to serialize the certificate
00606    BIO *bmem = BIO_new(BIO_s_mem());
00607    if (!bmem) {
00608       DEBUG("unable to create BIO for memory operations");
00609       return 0;
00610    }
00611 
00612    // Write certificate to BIO
00613    if (!PEM_write_bio_X509(bmem, cert)) {
00614       DEBUG("unable to write certificate to memory BIO");
00615       return 0;
00616    }
00617 
00618    // Extract pointer to BIO data and length of segment
00619    char *bdata = 0;  
00620    int blen = BIO_get_mem_data(bmem, &bdata);
00621    DEBUG("BIO data: "<<blen<<" bytes at 0x"<<(int *)bdata);
00622 
00623    // create the bucket now
00624    bucket = new XrdSutBucket(0,0,kXRS_x509);
00625    if (bucket) {
00626       // Fill bucket
00627       bucket->SetBuf(bdata, blen);
00628       DEBUG("result of serialization: "<<bucket->size<<" bytes");
00629    } else {
00630       DEBUG("unable to create bucket for serialized format");
00631       BIO_free(bmem);
00632       return 0;
00633    }
00634    //
00635    // Free BIO
00636    BIO_free(bmem);
00637    //
00638    // We are done
00639    return bucket;
00640 }
00641 
00642 //_____________________________________________________________________________
00643 bool XrdCryptosslX509::Verify(XrdCryptoX509 *ref)
00644 {
00645    // Verify certificate signature with pub key of ref cert
00646    EPNAME("X509::Verify");
00647 
00648    // We must have been initialized
00649    if (!cert)
00650       return 0;
00651 
00652    // We must have something to check with
00653    X509 *r = ref ? (X509 *)(ref->Opaque()) : 0;
00654    EVP_PKEY *rk = r ? X509_get_pubkey(r) : 0;
00655    if (!rk)
00656       return 0;
00657 
00658    // Ok: we can verify
00659    int rc = X509_verify(cert, rk);
00660    if (rc <= 0) {
00661       if (rc == 0) {
00662          // Signatures are not OK
00663          DEBUG("signature not OK");
00664       } else {
00665          // General failure
00666          DEBUG("could not verify signature");
00667       }
00668       return 0;
00669    }
00670    // Success
00671    return 1;
00672 }

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