wvx509mgr.cc

00001 #include "wvbase64.h"
00002 #include "wvsslhacks.h"
00003 #include "wvx509mgr.h"
00004 
00005 #include <openssl/pem.h>
00006 #include <openssl/x509v3.h>
00007 #include <openssl/err.h>
00008 #include <openssl/ssl.h>
00009 #include <openssl/sha.h>
00010 #include <openssl/pkcs12.h>
00011 
00012 
00013 namespace {
00014 class AutoClose {
00015 public:
00016     AutoClose(FILE *fp): fp(fp) { }
00017     ~AutoClose()
00018     {
00019         if (fp)
00020             fclose(fp);
00021     }
00022     
00023     operator FILE *() const
00024     {
00025         return fp;
00026     }
00027     
00028 private:
00029     FILE *fp;
00030 };
00031 } // anomymous namespace...
00032 
00033 
00034 WvX509Mgr::WvX509Mgr()
00035     : WvX509(), 
00036       debug("X509 Manager", WvLog::Debug5)
00037 {
00038     rsa = NULL;
00039 }
00040 
00041 
00042 WvX509Mgr::WvX509Mgr(WvStringParm _dname, WvRSAKey *_rsa, bool ca)
00043     : WvX509(),
00044       debug("X509 Manager", WvLog::Debug5)
00045 {
00046     debug("Creating new certificate+key pair for %s.\n", _dname);
00047     rsa = _rsa;
00048 
00049     if (!!_dname)
00050     {
00051         create_selfissued(_dname, ca);
00052         debug("Ok - Parameters set... now signing certificate.\n");
00053         signcert(*this);
00054     }
00055     else
00056         debug("Sorry, can't create an anonymous certificate.");
00057 }
00058 
00059 
00060 WvX509Mgr::WvX509Mgr(WvStringParm _dname, int bits, bool ca)
00061     : WvX509(), 
00062       debug("X509 Manager", WvLog::Debug5)
00063 {
00064     debug("Creating new certificate+key pair for %s.\n", _dname);
00065     rsa = NULL;
00066     
00067     if (!!_dname)
00068     {
00069         rsa = new WvRSAKey(bits);
00070         create_selfissued(_dname, ca);
00071         debug("Ok - Parameters set... now signing certificate.\n");
00072         signcert(*this);
00073     }
00074     else
00075         debug("Sorry, can't create an anonymous certificate.");
00076 }
00077 
00078 
00079 void WvX509Mgr::create_selfissued(WvStringParm dname, bool is_ca)
00080 {
00081     if (cert)
00082     {
00083         debug("Replacing already existant certificate...\n");
00084         X509_free(cert);
00085         cert = NULL;
00086     }
00087 
00088     // double check RSA key
00089     if (rsa->isok())
00090         debug("RSA Key is fine.\n");
00091     else
00092         return;
00093 
00094     if ((cert = X509_new()) == NULL)
00095         return;
00096 
00097     // Completely broken in my mind - this sets the version
00098     // string to '3'  (I guess version starts at 0)
00099     set_version();
00100 
00101     // RFC2459 says that this number must be unique for each certificate
00102     // issued by a CA.  It may be that some web browsers get confused if
00103     // more than one cert with the same name has the same serial number, so
00104     // let's be careful.
00105     srand(time(NULL));
00106     int serial = rand();
00107     set_serial(serial);
00108     
00109     // 10 years...
00110     set_lifetime(60*60*24*3650);
00111     
00112     set_pubkey(*rsa);
00113                 
00114     set_issuer(dname);
00115     set_subject(dname);
00116     set_ski();
00117 
00118     if (is_ca)
00119     {
00120         debug("Setting Extensions with CA Parameters.\n");
00121         debug("Setting Key Usage.\n");
00122         set_key_usage("critical, keyCertSign, cRLSign");
00123         debug("Setting Basic Constraints.\n");
00124         set_extension(NID_basic_constraints, "critical, CA:TRUE");
00125         debug("Setting Netscape Certificate Type.\n");
00126         set_extension(NID_netscape_cert_type, "SSL CA, S/MIME CA, Object Signing CA");
00127 //      debug("Setting Constraints.\n");
00128 //      set_constraints("requireExplicitPolicy");
00129     }
00130     else
00131     {
00132         debug("Setting Key Usage with normal server parameters\n");
00133         set_nsserver(dname);
00134         set_key_usage("critical, digitalSignature, keyEncipherment, keyAgreement");
00135         set_extension(NID_basic_constraints, "CA:FALSE");
00136         set_ext_key_usage("TLS Web Server Authentication,"
00137                           "TLS Web Client Authentication");
00138     }
00139     
00140     // we do not actually sign the certificate here: that must be done by the 
00141     // user (WvX509Mgr most likely)
00142     
00143     debug("Certificate for %s created\n", dname);
00144 }
00145 
00146 
00147 WvX509Mgr::~WvX509Mgr()
00148 {
00149     debug("Deleting.\n");
00150     WVDELETE(rsa);
00151     wvssl_free();
00152 }
00153 
00154 
00155 bool WvX509Mgr::isok() const
00156 {
00157     return WvX509::isok() && rsa && rsa->isok() && test();
00158 }
00159 
00160 
00161 WvString WvX509Mgr::errstr() const
00162 {
00163     if (!WvX509::isok())
00164         return WvX509::errstr();
00165     
00166     if (!rsa)
00167         return "No RSA key set.";
00168     else if (!rsa->isok())
00169         return "RSA key not valid.";
00170     else if (!test())
00171         return "RSA key and certificate do not match.";
00172 
00173     return WvString::empty;
00174 }
00175 
00176 
00177 bool WvX509Mgr::bind_ssl(SSL_CTX *ctx)
00178 {
00179     if (SSL_CTX_use_certificate(ctx, get_cert()) <= 0)
00180     {
00181         return false;
00182     }
00183     debug("Certificate activated.\n");
00184     
00185     if (SSL_CTX_use_RSAPrivateKey(ctx, rsa->rsa) <= 0)
00186     {
00187         return false;
00188     }
00189     debug("RSA private key activated.\n");
00190     return true;
00191 }
00192 
00193 
00194 bool WvX509Mgr::test() const
00195 {
00196     if (!cert)
00197     {
00198         debug("No X509 certificate: test fails.\n");
00199         return false;
00200     }
00201    
00202     if (rsa)
00203     {
00204         EVP_PKEY *pk = EVP_PKEY_new();
00205         assert(pk);
00206 
00207         if (!EVP_PKEY_set1_RSA(pk, rsa->rsa))
00208         {
00209             debug("Error setting RSA keys: test fails.\n");
00210             EVP_PKEY_free(pk);
00211             return false;
00212         }
00213 
00214         bool bad = false;
00215         int verify_return = X509_verify(cert, pk);
00216         
00217         if (verify_return != 1) // only '1' means okay
00218         {
00219             // However let's double check:
00220             WvString rsapub = rsa->encode(WvRSAKey::RsaPubPEM);
00221             WvRSAKey *temprsa = get_rsa_pub();
00222             WvString certpub = temprsa->encode(WvRSAKey::RsaPubPEM);
00223             delete temprsa;
00224                 // debug("rsapub:\n%s\n", rsapub);
00225             // debug("certpub:\n%s\n", certpub);
00226                 if (certpub == rsapub)
00227                     ; // do nothing, since OpenSSL is lying
00228                 else
00229                 {
00230                     // I guess that it really did fail.
00231                     debug("Certificate test failed: %s\n", wvssl_errstr());
00232                     bad = true;
00233                 }
00234         }
00235 
00236         EVP_PKEY_free(pk);
00237         return !bad;
00238     }
00239     
00240     return false;    
00241 }
00242 
00243 
00244 WvString WvX509Mgr::signreq(WvStringParm pkcs10req) const
00245 {
00246     debug("Signing a certificate request with: %s\n", get_subject());
00247     if (!isok())
00248     {
00249         debug(WvLog::Warning, "Asked to sign certificate request, but not ok! "
00250               "Aborting.\n");
00251         return false;
00252     }
00253 
00254     // Break this next part out into a de-pemify section, since that is what
00255     // this part up until the FIXME: is about.
00256     WvString pkcs10(pkcs10req);
00257     
00258     char *begin = strstr(pkcs10.edit(), "\nMII");
00259     if (!begin)
00260     {
00261         debug("This doesn't look like PEM Encoded information...\n");
00262         return WvString::null;
00263     }
00264     char *end = strstr(begin + 1, "\n---");
00265     if (!end)
00266     {
00267         debug("Is this a complete certificate request?\n");
00268         return WvString::null;
00269     }
00270     *++end = '\0';
00271     WvString body(begin); // just the PKCS#10 request, 
00272                           // without the ---BEGIN and ---END
00273     
00274     WvDynBuf reqbuf;
00275     WvBase64Decoder dec;
00276     dec.flushstrbuf(body, reqbuf, true);
00277     
00278     // FIXME: Duplicates code from cert_selfsign
00279     size_t reqlen = reqbuf.used();
00280     const unsigned char *req = reqbuf.get(reqlen);
00281     X509_REQ *certreq = wv_d2i_X509_REQ(NULL, &req, reqlen);
00282     if (certreq)
00283     {
00284         WvX509 newcert(X509_new());
00285 
00286         newcert.set_subject(X509_REQ_get_subject_name(certreq));
00287         newcert.set_version();
00288         
00289         // Set the Serial Number for the certificate
00290         srand(time(NULL));
00291         int serial = rand();
00292         newcert.set_serial(serial);
00293         
00294         newcert.set_lifetime(60*60*24*3650);
00295         
00296         // The public key of the new cert should be the same as that from 
00297         // the request.
00298         EVP_PKEY *pk = X509_REQ_get_pubkey(certreq);
00299         X509_set_pubkey(newcert.get_cert(), pk);
00300         EVP_PKEY_free(pk);
00301 
00302         // every good cert needs an ski+aki
00303         newcert.set_ski();
00304         newcert.set_aki(*this);
00305 
00306         // The Issuer name is the subject name of the current cert
00307         newcert.set_issuer(*this); 
00308         
00309         X509_EXTENSION *ex = NULL;
00310         // Set the RFC2459-mandated keyUsage field to critical, and restrict
00311         // the usage of this cert to digital signature and key encipherment.
00312         newcert.set_key_usage("critical, digitalSignature, keyEncipherment");
00313     
00314         // This could cause Netscape to barf because if we set basicConstraints 
00315         // to critical, we break RFC2459 compliance. Why they chose to enforce 
00316         // that bit, and not the rest is beyond me... but oh well...
00317         ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints,
00318                                  "CA:FALSE");
00319         
00320         X509_add_ext(newcert.get_cert(), ex, -1);
00321         X509_EXTENSION_free(ex);
00322 
00323         newcert.set_ext_key_usage("critical, TLS Web Client Authentication");
00324 
00325         signcert(newcert);
00326         
00327         X509_REQ_free(certreq);
00328         return WvString(newcert.encode(WvX509::CertPEM));
00329     }
00330     else
00331     {
00332         debug("Can't decode Certificate Request\n");
00333         return WvString::null;
00334     }
00335 }
00336 
00337 
00338 bool WvX509Mgr::signcert(WvX509 &unsignedcert) const
00339 {
00340     if (!isok())
00341     {
00342         debug(WvLog::Warning, "Asked to sign certificate, but not ok! "
00343               "Aborting.\n");
00344         return false;
00345     }
00346 
00347     if (cert == unsignedcert.cert)
00348     {
00349         debug("Self Signing!\n");
00350     }
00351     else if (!X509_check_ca(cert))
00352     {
00353         debug("This certificate is not a CA, and is thus not allowed to sign "
00354               "certificates!\n");
00355         return false;
00356     }
00357     else if (!((cert->ex_flags & EXFLAG_KUSAGE) && 
00358                (cert->ex_kusage & KU_KEY_CERT_SIGN)))
00359     {
00360         debug("This Certificate is not allowed to sign certificates!\n");
00361         return false;
00362     }
00363     
00364     debug("Ok, now sign the new cert with the current RSA key.\n");
00365     EVP_PKEY *certkey = EVP_PKEY_new();
00366     bool cakeyok = EVP_PKEY_set1_RSA(certkey, rsa->rsa);
00367     if (cakeyok)
00368     {   
00369         X509_sign(unsignedcert.get_cert(), certkey, EVP_sha1());
00370     }
00371     else
00372     {
00373         debug("No keys??\n");
00374         EVP_PKEY_free(certkey);
00375         return false;
00376     }
00377     
00378     EVP_PKEY_free(certkey);
00379     return true;
00380 }
00381 
00382 
00383 bool WvX509Mgr::signcrl(WvCRL &crl) const
00384 {
00385     if (!isok() || !crl.isok())
00386     {
00387         debug(WvLog::Warning, "Asked to sign CRL, but certificate or CRL (or "
00388               "both) not ok! Aborting.\n");
00389         return false;
00390     }
00391     else if (!X509_check_ca(cert))
00392     {
00393         debug("This certificate is not a CA, and is thus not allowed to sign "
00394               "CRLs!\n");
00395         return false;
00396     }
00397     else if (!((cert->ex_flags & EXFLAG_KUSAGE) && 
00398           (cert->ex_kusage & KU_CRL_SIGN)))
00399     {
00400         debug("Certificate not allowed to sign CRLs! (%s %s)\n", 
00401               (cert->ex_flags & EXFLAG_KUSAGE), (cert->ex_kusage & KU_CRL_SIGN));
00402         return false;
00403     }
00404     
00405     EVP_PKEY *certkey = EVP_PKEY_new();
00406     bool cakeyok = EVP_PKEY_set1_RSA(certkey, rsa->rsa);
00407     if (cakeyok)
00408     {
00409         // Use Version 2 CRLs - Of COURSE that means
00410         // to set it to 1 here... grumble..
00411         X509_CRL_set_version(crl.getcrl(), 1);
00412 
00413         X509_CRL_set_issuer_name(crl.getcrl(), X509_get_subject_name(cert));
00414 
00415         ASN1_TIME *tmptm = ASN1_TIME_new();
00416         // Set the LastUpdate time to now.
00417         X509_gmtime_adj(tmptm, 0);
00418         X509_CRL_set_lastUpdate(crl.getcrl(), tmptm);
00419         // CRL's are valid for 30 days
00420         X509_gmtime_adj(tmptm, (long)60*60*24*30);
00421         X509_CRL_set_nextUpdate(crl.getcrl(), tmptm);
00422         ASN1_TIME_free(tmptm);
00423         
00424         // OK - now sign it...
00425         X509_CRL_sign(crl.getcrl(), certkey, EVP_sha1());
00426     }
00427     else
00428     {
00429         debug(WvLog::Warning, "Asked to sign CRL, but no RSA key associated "
00430               "with certificate. Aborting.\n");
00431         EVP_PKEY_free(certkey);
00432         return false;
00433     }
00434     EVP_PKEY_free(certkey);
00435 
00436     return true;
00437 }
00438 
00439 
00440 WvString WvX509Mgr::sign(WvStringParm data) const
00441 {
00442     WvDynBuf buf;
00443     buf.putstr(data);
00444     return sign(buf);
00445 }
00446 
00447 
00448 WvString WvX509Mgr::sign(WvBuf &data) const
00449 {
00450     assert(rsa);
00451 
00452     EVP_MD_CTX sig_ctx;
00453     unsigned char sig_buf[4096];
00454     
00455     EVP_PKEY *pk = EVP_PKEY_new();
00456     assert(pk); // OOM 
00457     
00458     if (!EVP_PKEY_set1_RSA(pk, rsa->rsa))
00459     {
00460         debug("Error setting RSA keys.\n");
00461         EVP_PKEY_free(pk);
00462         return WvString::null;
00463     }
00464     
00465     EVP_SignInit(&sig_ctx, EVP_sha1());
00466     EVP_SignUpdate(&sig_ctx, data.peek(0, data.used()), data.used());
00467     unsigned int sig_len = sizeof(sig_buf);
00468     int sig_err = EVP_SignFinal(&sig_ctx, sig_buf, 
00469                                 &sig_len, pk);
00470     if (sig_err != 1)
00471     {
00472         debug("Error while signing.\n");
00473         EVP_PKEY_free(pk);
00474         return WvString::null;
00475     }
00476 
00477     EVP_PKEY_free(pk);
00478     EVP_MD_CTX_cleanup(&sig_ctx); // this isn't my fault ://
00479     WvDynBuf buf;
00480     buf.put(sig_buf, sig_len);
00481     debug("Signature size: %s\n", buf.used());
00482     return WvBase64Encoder().strflushbuf(buf, true);
00483 }
00484 
00485 
00486 bool WvX509Mgr::write_p12(WvStringParm _fname, WvStringParm _pkcs12pass) const
00487 {
00488     debug("Dumping RSA Key and X509 Cert to PKCS12 structure.\n");
00489 
00490     AutoClose fp = fopen(_fname, "wb");
00491 
00492     if (!fp)
00493     {
00494         debug(WvLog::Warning, "Unable to open file. Error: %s\n", strerror(errno));
00495         return false;
00496     }
00497 
00498     if (!!_pkcs12pass)
00499     {
00500         if (rsa && cert)
00501         {
00502             EVP_PKEY *pk = EVP_PKEY_new();
00503             assert(pk); // OOM
00504 
00505             if (!EVP_PKEY_set1_RSA(pk, rsa->rsa))
00506             {
00507                 debug("Error setting RSA keys.\n");
00508                 EVP_PKEY_free(pk);
00509                 return false;
00510             }
00511             else
00512             {
00513                 WvString pkcs12pass(_pkcs12pass);
00514                 PKCS12 *pkg = PKCS12_create(pkcs12pass.edit(), "foo", pk, 
00515                                             cert, NULL, 0, 0, 0, 
00516                                             0, 0);
00517                 if (pkg)
00518                 {
00519                     debug("Writing the PKCS12 object out...\n");
00520                     i2d_PKCS12_fp(fp, pkg);
00521                     PKCS12_free(pkg);
00522                     EVP_PKEY_free(pk);
00523                 }
00524                 else
00525                 {
00526                     debug(WvLog::Warning, "Unable to create PKCS12 object.");
00527                     EVP_PKEY_free(pk);
00528                     return false;
00529                 }
00530             }
00531         }
00532         else
00533         {
00534             debug(WvLog::Warning, "The RSA key or the certificate is not present.");
00535             return false;
00536         }
00537     }
00538     else
00539     {
00540         debug(WvLog::Warning, "No password specified for PKCS12 dump.");
00541         return false; 
00542     }
00543 
00544     return true;
00545 }
00546 
00547 
00548 void WvX509Mgr::read_p12(WvStringParm _fname, WvStringParm _pkcs12pass)
00549 {
00550     debug("Reading Certificate and Private Key from PKCS12 file: %s\n", _fname);    
00551 
00552     if (rsa)
00553         WVDELETE(rsa);
00554 
00555     AutoClose fp = fopen(_fname, "r");
00556 
00557     if (!fp)
00558     {
00559         debug("Unable to open file '%s'!\n", _fname);
00560         return;
00561     }
00562 
00563     if (!!_pkcs12pass)
00564     {
00565         PKCS12 *pkg = d2i_PKCS12_fp(fp, NULL);
00566         if (pkg)
00567         {
00568             EVP_PKEY *pk = NULL;
00569             
00570             // Parse out the bits out the PKCS12 package.
00571             X509 *x;
00572             PKCS12_parse(pkg, _pkcs12pass, &pk, &x, NULL);
00573             PKCS12_free(pkg);
00574             if (!pk || !x)
00575             {
00576                 debug("Could not decode pkcs12 file.\n");
00577                 EVP_PKEY_free(pk);
00578                 return;
00579             }
00580 
00581             cert = x;
00582 
00583             // Now, cert should be OK, let's try and set up the RSA stuff
00584             // since we've essentially got a PKEY, and not a WvRSAKey
00585             // We need to create a new WvRSAKey from the PKEY...
00586             rsa = new WvRSAKey(EVP_PKEY_get1_RSA(pk), true);
00587             EVP_PKEY_free(pk);
00588 
00589             // Now that we have both, check to make sure that they match
00590             if (!test())
00591             {
00592                 debug("Could not fill in RSA and certificate with matching "
00593                       "values! Expect problems.\n");
00594                 return;
00595             }
00596         }
00597         else
00598         {
00599             debug("Read in of PKCS12 file '%s' failed", _fname);
00600             return;
00601         }
00602     }
00603     else
00604     {
00605         debug("No password specified for PKCS12 file\n");
00606         return;
00607     }
00608 }
00609 
00610 
00611 WvString WvX509Mgr::encode(const WvRSAKey::DumpMode mode) const
00612 {
00613     if (rsa)
00614         return rsa->encode(mode);
00615     return "";
00616 }
00617 
00618 
00619 WvString WvX509Mgr::encode(const WvX509::DumpMode mode) const
00620 {
00621     return WvX509::encode(mode);
00622 }
00623 
00624 
00625 void WvX509Mgr::encode(const WvRSAKey::DumpMode mode, WvBuf &buf) const
00626 {
00627     if (rsa)
00628         rsa->encode(mode, buf);
00629 }
00630 
00631 
00632 void WvX509Mgr::encode(const WvX509::DumpMode mode, WvBuf &buf) const
00633 {
00634     WvX509::encode(mode, buf);
00635 }
00636 
00637 
00638 void WvX509Mgr::decode(const WvRSAKey::DumpMode mode, WvStringParm encoded)
00639 {
00640     if (rsa)
00641         rsa->decode(mode, encoded);
00642     else
00643     {
00644         rsa = new WvRSAKey();
00645         rsa->decode(mode, encoded);
00646     }
00647 }
00648 
00649 
00650 void WvX509Mgr::decode(const WvX509::DumpMode mode, WvStringParm encoded)
00651 {
00652     WvX509::decode(mode, encoded);
00653 }
00654 
00655 
00656 void WvX509Mgr::decode(const WvRSAKey::DumpMode mode, WvBuf &encoded)
00657 {
00658     if (rsa)
00659         rsa->decode(mode, encoded);
00660     else
00661     {
00662         rsa = new WvRSAKey();
00663         rsa->decode(mode, encoded);
00664     }
00665 }
00666 
00667 
00668 void WvX509Mgr::decode(const WvX509::DumpMode mode, WvBuf &encoded)
00669 {
00670     WvX509::decode(mode, encoded);
00671 }

Generated on Thu Jan 24 16:50:57 2008 for WvStreams by  doxygen 1.5.4