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