wvx509.cc

00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2005 Net Integration Technologies, Inc.
00004  * 
00005  * X.509 certificate management classes.
00006  */ 
00007 #include "wvx509.h"
00008 #include "wvrsa.h"
00009 #include "wvcrl.h"
00010 #include "wvsslhacks.h"
00011 #include "wvdiriter.h"
00012 #include "wvcrypto.h"
00013 #include "wvstringlist.h"
00014 #include "wvbase64.h"
00015 #include "wvstrutils.h"
00016 #include "wvfileutils.h"
00017 
00018 #include <openssl/pem.h>
00019 #include <openssl/x509v3.h>
00020 #include <openssl/err.h>
00021 #include <openssl/ssl.h>
00022 #include <openssl/sha.h>
00023 #include <openssl/pkcs12.h>
00024 
00025 UUID_MAP_BEGIN(WvX509Mgr)
00026   UUID_MAP_ENTRY(IObject)
00027   UUID_MAP_END
00028 
00029 static int ssl_init_count = 0;
00030 
00031 namespace {
00032 class AutoClose {
00033 public:
00034     AutoClose(FILE *fp): fp(fp) { }
00035     ~AutoClose()
00036     {
00037         if (fp)
00038             fclose(fp);
00039     }
00040     
00041     operator FILE *() const
00042     {
00043         return fp;
00044     }
00045     
00046 private:
00047     FILE *fp;
00048 };
00049 } // anomymous namespace...
00050 
00051 
00052 
00053 void wvssl_init()
00054 {
00055     if (!ssl_init_count)
00056     {
00057         SSL_library_init();
00058         SSL_load_error_strings();
00059         ERR_load_BIO_strings();
00060         ERR_load_crypto_strings();
00061         OpenSSL_add_all_algorithms();
00062         OpenSSL_add_all_ciphers();
00063         OpenSSL_add_all_digests();
00064     }
00065     
00066     ssl_init_count++;
00067 }
00068 
00069 
00070 void wvssl_free()
00071 {
00072     if (ssl_init_count >= 1)
00073         ssl_init_count--;
00074 
00075     if (!ssl_init_count)
00076     {
00077         ERR_free_strings();
00078         EVP_cleanup();
00079     }
00080 }
00081 
00082 
00083 WvString wvssl_errstr()
00084 {
00085     char buf[256];
00086     ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
00087     buf[sizeof(buf)-1] = 0;
00088     return buf;
00089 }
00090 
00091 
00092 WvX509Mgr::WvX509Mgr(X509 *_cert)
00093     : debug("X509", WvLog::Debug5), pkcs12pass(WvString::null)
00094 {
00095     wvssl_init();
00096     cert = _cert;
00097     rsa = NULL;
00098     if (cert)
00099     {
00100         filldname();
00101         rsa = fillRSAPubKey();
00102         if (!rsa->isok())
00103             seterr("RSA Public Key Error: %s", rsa->errstr());
00104     }
00105     else
00106         ;
00107         // This isn't an error, or a mistake...
00108         // so this is one case where 
00109         // cert == NULL && rsa == NULL && errstr == NULL
00110         // That the programmer should be doing something about.
00111 }
00112 
00113 
00114 WvX509Mgr::WvX509Mgr()
00115     : debug("X509", WvLog::Debug5), pkcs12pass(WvString::null)
00116 {
00117     wvssl_init();
00118     cert = NULL;
00119     rsa = NULL;
00120 }
00121 
00122 
00123 WvX509Mgr::WvX509Mgr(WvStringParm hexified_cert,
00124                      WvStringParm hexified_rsa)
00125     : debug("X509", WvLog::Debug5), pkcs12pass(WvString::null)
00126 {
00127     wvssl_init();
00128     
00129     cert = NULL;
00130     rsa = new WvRSAKey(hexified_rsa, true);
00131     if (!rsa->isok())
00132     {
00133         seterr("RSA Error: %s\n", rsa->errstr());
00134         return;
00135     }
00136 
00137     if (!!hexified_cert)
00138         unhexify(hexified_cert);
00139     else
00140     {
00141         seterr("No Hexified Cert.. aborting!\n");
00142         return;
00143     }
00144 
00145     if (cert)
00146         filldname();
00147 }
00148 
00149 
00150 WvX509Mgr::WvX509Mgr(WvStringParm _dname, WvRSAKey *_rsa)
00151     : dname(_dname), debug("X509", WvLog::Debug5), pkcs12pass(WvString::null)
00152 {
00153     assert(_rsa);
00154     
00155     wvssl_init();
00156     debug("Creating new certificate for %s\n", dname);
00157     cert = NULL;
00158     rsa = _rsa;
00159     create_selfsigned();
00160 }
00161 
00162 
00163 WvX509Mgr::WvX509Mgr(WvStringParm _dname, int bits)
00164     : dname(_dname), debug("X509", WvLog::Debug5)
00165 {
00166     wvssl_init();
00167     debug("Creating new certificate for %s\n", dname);
00168     cert = NULL;
00169     rsa = NULL;
00170     
00171     if (!!dname)
00172     {
00173         rsa = new WvRSAKey(bits);
00174         create_selfsigned();
00175     }
00176     else
00177         seterr("Sorry, can't create an anonymous Certificate\n");
00178 }
00179 
00180 
00181 WvX509Mgr::~WvX509Mgr()
00182 {
00183     debug("Deleting.\n");
00184     
00185     if (rsa)
00186         delete rsa;
00187 
00188     if (cert)
00189         X509_free(cert);
00190 
00191     wvssl_free();
00192 }
00193 
00194 
00195 bool WvX509Mgr::bind_ssl(SSL_CTX *ctx)
00196 {
00197     if (SSL_CTX_use_certificate(ctx, cert) <= 0)
00198     {
00199         return false;
00200     }
00201     debug("Certificate activated.\n");
00202     
00203     if (SSL_CTX_use_RSAPrivateKey(ctx, rsa->rsa) <= 0)
00204     {
00205         return false;
00206     }
00207     debug("RSA private key activated.\n");
00208     return true;
00209 }
00210 
00211 
00212 const WvRSAKey &WvX509Mgr::get_rsa()
00213 {
00214     assert(rsa);
00215 
00216     return *rsa;
00217 }
00218 
00219 
00220 // The people who designed this garbage should be shot!
00221 // Support old versions of openssl...
00222 #ifndef NID_domainComponent
00223 #define NID_domainComponent 391
00224 #endif
00225 
00226 #ifndef NID_Domain
00227 #define NID_Domain 392
00228 #endif
00229 
00230 
00231 // returns some approximation of the server's fqdn, or an empty string.
00232 static WvString set_name_entry(X509_NAME *name, WvStringParm dn)
00233 {
00234     WvString fqdn(""), force_fqdn("");
00235     X509_NAME_ENTRY *ne = NULL;
00236     int count = 0, nid;
00237     
00238     WvStringList l;
00239     l.split(dn, ",");
00240     
00241     // dn is of the form: c=ca,o=foo organization,dc=foo,dc=com
00242     // (ie. name=value pairs separated by commas)
00243     WvStringList::Iter i(l);
00244     for (i.rewind(); i.next(); )
00245     {
00246         WvString s(*i), sid;
00247         char *cptr, *value;
00248         
00249         cptr = s.edit();
00250         value = strchr(cptr, '=');
00251         if (value)
00252             *value++ = 0;
00253         else
00254             value = "NULL";
00255         
00256         sid = strlwr(trim_string(cptr));
00257         
00258         if (sid == "c")
00259             nid = NID_countryName;
00260         else if (sid == "st")
00261             nid = NID_stateOrProvinceName;
00262         else if (sid == "l")
00263             nid = NID_localityName;
00264         else if (sid == "o")
00265             nid = NID_organizationName;
00266         else if (sid == "ou")
00267             nid = NID_organizationalUnitName;
00268         else if (sid == "cn")
00269         {
00270             nid = NID_commonName;
00271             force_fqdn = value;
00272         }
00273         else if (sid == "dc")
00274         {
00275             nid = NID_domainComponent;
00276             if (!!fqdn)
00277                 fqdn.append(".");
00278             fqdn.append(value);
00279         }
00280         else if (sid == "domain")
00281         {
00282             nid = NID_Domain;
00283             force_fqdn = value;
00284         }
00285         else if (sid == "email")
00286             nid = NID_pkcs9_emailAddress;
00287         else
00288             nid = NID_domainComponent;
00289         
00290         // Sometimes we just want to parse dn into fqdn.
00291         if (name == NULL)
00292             continue;
00293         
00294         if (!ne)
00295             ne = X509_NAME_ENTRY_create_by_NID(NULL, nid,
00296                                V_ASN1_APP_CHOOSE, (unsigned char *)value, -1);
00297         else
00298             X509_NAME_ENTRY_create_by_NID(&ne, nid,
00299                                V_ASN1_APP_CHOOSE, (unsigned char *)value, -1);
00300         if (!ne)
00301             continue;
00302         
00303         X509_NAME_add_entry(name, ne, count++, 0);
00304     }
00305     
00306     X509_NAME_ENTRY_free(ne);
00307     
00308     if (!!force_fqdn)
00309         return force_fqdn;
00310 
00311     return fqdn;
00312 }
00313 
00314 
00315 void WvX509Mgr::create_selfsigned(bool is_ca)
00316 {
00317     assert(rsa);
00318 
00319     if (cert)
00320     {
00321         debug("Replacing already existant certificate...\n");
00322         X509_free(cert);
00323         cert = NULL;
00324     }
00325     
00326     // double check RSA key
00327     if (rsa->isok())
00328         debug("RSA Key is fine.\n");
00329     else
00330     {
00331         seterr("RSA Key is bad!\n");
00332         return;
00333     }
00334 
00335     if ((cert = X509_new()) == NULL)
00336     {
00337         seterr("Error creating new X509 object");
00338         return;
00339     }
00340 
00341     // Completely broken in my mind - this sets the version
00342     // string to '3'  (I guess version starts at 0)
00343     set_version();
00344 
00345     // RFC2459 says that this number must be unique for each certificate
00346     // issued by a CA.  It may be that some web browsers get confused if
00347     // more than one cert with the same name has the same serial number, so
00348     // let's be careful.
00349     srand(time(NULL));
00350     int serial = rand();
00351     set_serial(serial);
00352     
00353     // 10 years...
00354     set_lifetime(60*60*24*3650);
00355     
00356     set_pubkey(rsa);
00357                                        
00358     set_issuer(dname);
00359     set_subject(dname);
00360     
00361     if (is_ca)
00362     {
00363         debug("Setting Extensions with CA Parameters.\n");
00364         debug("Setting Key Usage.\n");
00365         set_key_usage("critical, keyCertSign, cRLSign");
00366         debug("Setting Basic Constraints.\n");
00367         set_extension(NID_basic_constraints, "critical, CA:TRUE");
00368         debug("Setting Netscape Certificate Type.\n");
00369         set_extension(NID_netscape_cert_type, "SSL CA, S/MIME CA, Object Signing CA");
00370 //      debug("Setting Constraints.\n");
00371 //      set_constraints("requireExplicitPolicy");
00372     }
00373     else
00374     {
00375         debug("Setting Key Usage with normal server parameters\n");
00376         set_nsserver(dname);
00377         set_key_usage("critical, digitalSignature, keyEncipherment, keyAgreement");
00378         set_extension(NID_basic_constraints, "CA:FALSE");
00379         set_ext_key_usage("TLS Web Server Authentication,"
00380                           "TLS Web Client Authentication");
00381     }
00382     
00383     debug("Ok - Parameters set... now signing certificate.\n");
00384     signcert(cert);
00385     
00386     debug("Certificate for %s created\n", dname);
00387 }
00388 
00389 
00390 void WvX509Mgr::filldname()
00391 {
00392     assert(cert);
00393     
00394     char *name = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
00395     dname = name;
00396     OPENSSL_free(name);
00397 }
00398 
00399 
00400 // FIXME: This is EVIL!!!
00401 WvRSAKey *WvX509Mgr::fillRSAPubKey()
00402 {
00403     EVP_PKEY *pkcert = X509_get_pubkey(cert);
00404     RSA *certrsa = EVP_PKEY_get1_RSA(pkcert);
00405     EVP_PKEY_free(pkcert);
00406     return new WvRSAKey(certrsa, false); 
00407 }
00408 
00409 
00410 WvString WvX509Mgr::certreq()
00411 {
00412     EVP_PKEY *pk = NULL;
00413     X509_NAME *name = NULL;
00414     X509_REQ *certreq = NULL;
00415 
00416     assert(rsa);
00417     assert(dname);
00418 
00419     // double check RSA key
00420     if (rsa->isok())
00421         debug("RSA Key is fine.\n");
00422     else
00423     {
00424         seterr("RSA Key is bad!\n");
00425         return WvString::null;
00426     }
00427 
00428     if ((pk=EVP_PKEY_new()) == NULL)
00429     {
00430         seterr("Error creating key handler for new certificate");
00431         return WvString::null;
00432     }
00433     
00434     if ((certreq=X509_REQ_new()) == NULL)
00435     {
00436         seterr("Error creating new PKCS#10 object");
00437         EVP_PKEY_free(pk);
00438         return WvString::null;
00439     }
00440 
00441     if (!EVP_PKEY_set1_RSA(pk, rsa->rsa))
00442     {
00443         seterr("Error adding RSA keys to certificate");
00444         X509_REQ_free(certreq);
00445         EVP_PKEY_free(pk);
00446         return WvString::null;
00447     }
00448     
00449     X509_REQ_set_version(certreq, 0); /* version 1 */
00450 
00451     X509_REQ_set_pubkey(certreq, pk);
00452 
00453     name = X509_REQ_get_subject_name(certreq);
00454 
00455     debug("Creating Certificate request for %s\n", dname);
00456     set_name_entry(name, dname);
00457     X509_REQ_set_subject_name(certreq, name);
00458     char *sub_name = X509_NAME_oneline(X509_REQ_get_subject_name(certreq), 
00459                                        0, 0);
00460     debug("SubjectDN: %s\n", sub_name);
00461     OPENSSL_free(sub_name);
00462     
00463     if (!X509_REQ_sign(certreq, pk, EVP_sha1()))
00464     {
00465         seterr("Could not self sign the request");
00466         X509_REQ_free(certreq);
00467         EVP_PKEY_free(pk);
00468         return WvString::null;
00469     }
00470 
00471     int verify_result = X509_REQ_verify(certreq, pk);
00472     if (verify_result == 0)
00473     {
00474         seterr("Self Signed Request failed!");
00475         X509_REQ_free(certreq);
00476         EVP_PKEY_free(pk);
00477         return WvString::null;
00478     }
00479     else
00480     {
00481         debug("Self Signed Certificate Request verifies OK!\n");
00482     }
00483 
00484     // Horribly involuted hack to get around the fact that the
00485     // OpenSSL people are too braindead to have a PEM_write function
00486     // that returns a char *
00487     WvDynBuf retval;
00488     BIO *bufbio = BIO_new(BIO_s_mem());
00489     BUF_MEM *bm;
00490     
00491     PEM_write_bio_X509_REQ(bufbio, certreq);
00492     BIO_get_mem_ptr(bufbio, &bm);
00493     retval.put(bm->data, bm->length);
00494     
00495     X509_REQ_free(certreq);
00496     EVP_PKEY_free(pk);
00497     BIO_free(bufbio);
00498 
00499     return retval.getstr();
00500 }
00501 
00502 
00503 WvString WvX509Mgr::signreq(WvStringParm pkcs10req)
00504 {
00505     assert(rsa);
00506     assert(cert);
00507     debug("Signing a certificate request with : %s\n", get_subject());
00508     
00509     // Break this next part out into a de-pemify section, since that is what
00510     // this part up until the FIXME: is about.
00511     WvString pkcs10(pkcs10req);
00512     
00513     char *begin = strstr(pkcs10.edit(), "\nMII");
00514     if (!begin)
00515     {
00516         debug("This doesn't look like PEM Encoded information...\n");
00517         return WvString::null;
00518     }
00519     char *end = strstr(begin + 1, "\n---");
00520     if (!end)
00521     {
00522         debug("Is this a complete certificate request?\n");
00523         return WvString::null;
00524     }
00525     *++end = '\0';
00526     WvString body(begin); // just the PKCS#10 request, 
00527                           // without the ---BEGIN and ---END
00528     
00529     WvDynBuf reqbuf;
00530     WvBase64Decoder dec;
00531     dec.flushstrbuf(body, reqbuf, true);
00532     
00533     // FIXME: Duplicates code from cert_selfsign
00534     size_t reqlen = reqbuf.used();
00535     const unsigned char *req = reqbuf.get(reqlen);
00536     X509_REQ *certreq = wv_d2i_X509_REQ(NULL, &req, reqlen);
00537     if (certreq)
00538     {
00539         WvX509Mgr newcert;
00540 
00541         newcert.set_subject(X509_REQ_get_subject_name(certreq));
00542         newcert.set_version();
00543         
00544         // Set the Serial Number for the certificate
00545         srand(time(NULL));
00546         int serial = rand();
00547         newcert.set_serial(serial);
00548         
00549         newcert.set_lifetime(60*60*24*3650);
00550         
00551         // The public key of the new cert should be the same as that from 
00552         // the request.
00553         EVP_PKEY *pk = X509_REQ_get_pubkey(certreq);
00554         X509_set_pubkey(newcert.get_cert(), pk);
00555         EVP_PKEY_free(pk);
00556         
00557         // The Issuer name is the subject name of the current cert
00558         newcert.set_issuer(get_subject());
00559         
00560         X509_EXTENSION *ex = NULL;
00561         // Set the RFC2459-mandated keyUsage field to critical, and restrict
00562         // the usage of this cert to digital signature and key encipherment.
00563         newcert.set_key_usage("critical, digitalSignature, keyEncipherment");
00564     
00565         // This could cause Netscape to barf because if we set basicConstraints 
00566         // to critical, we break RFC2459 compliance. Why they chose to enforce 
00567         // that bit, and not the rest is beyond me... but oh well...
00568         ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints,
00569                                  "CA:FALSE");
00570         
00571         X509_add_ext(newcert.get_cert(), ex, -1);
00572         X509_EXTENSION_free(ex);
00573 
00574         newcert.set_ext_key_usage("critical, TLS Web Client Authentication");
00575 
00576         signcert(newcert.get_cert());
00577         
00578         X509_REQ_free(certreq);
00579         return WvString(newcert.encode(CertPEM));
00580     }
00581     else
00582     {
00583         debug("Can't decode Certificate Request\n");
00584         return WvString::null;
00585     }
00586 }
00587 
00588 
00589 bool WvX509Mgr::test()
00590 {
00591     bool bad = false;
00592     
00593     EVP_PKEY *pk = EVP_PKEY_new();
00594     
00595     if (!cert)
00596     {
00597         seterr("no Certificate in X509 Manager!");
00598         bad = true;
00599     }
00600     
00601     if (rsa && pk)
00602     {
00603         if (!EVP_PKEY_set1_RSA(pk, rsa->rsa))
00604         {
00605             seterr("Error setting RSA keys");
00606             bad = true;
00607         }
00608         else if (!bad)
00609         {
00610             int verify_return = X509_verify(cert, pk);
00611             if (verify_return != 1) // only '1' means okay
00612             {
00613                 // However let's double check:
00614                 WvString rsapub = encode(RsaPubPEM);
00615                 WvRSAKey *temprsa = fillRSAPubKey();
00616                 WvString certpub = temprsa->getpem(false);
00617                 delete temprsa;
00618                 // debug("rsapub:\n%s\n", rsapub);
00619                 // debug("certpub:\n%s\n", certpub);
00620                 if (certpub == rsapub)
00621                     ; // do nothing, since OpenSSL is lying
00622                 else
00623                 {
00624                     // I guess that it really did fail.
00625                     seterr("Certificate test failed: %s\n", wvssl_errstr());
00626                     bad = true;
00627                 }
00628             }
00629         }
00630     }
00631     else
00632     {
00633         seterr("no RSA keypair in X509 manager");
00634         bad = true;
00635     }
00636     
00637     if (pk)
00638         EVP_PKEY_free(pk);
00639     
00640     return !bad;
00641 }
00642 
00643 
00644 void WvX509Mgr::unhexify(WvStringParm encodedcert)
00645 {
00646     if (!encodedcert)
00647     {
00648         seterr("X.509 certificate can't be decoded from nothing!\n");
00649         return;
00650     }
00651     
00652     int hexbytes = strlen(encodedcert.cstr());
00653     int bufsize = hexbytes/2;
00654     unsigned char *certbuf = new unsigned char[bufsize];
00655     unsigned char *cp = certbuf;
00656     X509 *tmpcert;
00657     
00658     if (cert)
00659         X509_free(cert);
00660 
00661     ::unhexify(certbuf, encodedcert);
00662     tmpcert = cert = X509_new();
00663     cert = wv_d2i_X509(&tmpcert, &cp, hexbytes/2);
00664 
00665     // make sure that the cert is valid
00666     if (cert && !test())
00667     {
00668         X509_free(cert);
00669         cert = NULL;
00670     }
00671     
00672     if (!cert)
00673         seterr("X.509 certificate decode failed!");
00674     
00675     deletev certbuf;
00676 }
00677 
00678 
00679 WvString WvX509Mgr::hexify()
00680 {
00681     size_t size;
00682     unsigned char *keybuf, *iend;
00683     WvString enccert;
00684 
00685     size = i2d_X509(cert, NULL);
00686     iend = keybuf = new unsigned char[size];
00687     i2d_X509(cert, &iend);
00688 
00689     enccert.setsize(size * 2 +1);
00690     ::hexify(enccert.edit(), keybuf, size);
00691 
00692     deletev keybuf;
00693     return enccert;
00694 }
00695 
00696 
00697 bool WvX509Mgr::validate(WvX509Mgr *cacert, X509_CRL *crl)
00698 {
00699     bool retval = true;
00700     
00701     if (cert != NULL)
00702     {
00703         // Check and make sure that the certificate is still valid
00704         if (X509_cmp_current_time(X509_get_notAfter(cert)) == -1)
00705         {
00706             seterr("Certificate has expired!");
00707             retval = false;
00708         }
00709         
00710         if (cacert)
00711             retval &= signedbyCA(cacert);
00712 
00713         // Kind of a placeholder thing right now...
00714         // Later on, do CRL, and certificate validity checks here..
00715         // Actually, break these out in signedbyvalidCA(), and isinCRL()
00716         // Maybe have them here and activated by bool values as parameters 
00717         // to validate.
00718     }
00719     else
00720         debug("Peer doesn't have a certificate.\n");
00721     
00722     return retval;
00723 }
00724 
00725 
00726 bool WvX509Mgr::signedbyCAinfile(WvStringParm certfile)
00727 {
00728     X509_STORE *cert_ctx = NULL;
00729     X509_STORE_CTX csc;
00730     X509_LOOKUP *lookup = NULL;
00731     int result = 0;
00732 
00733     cert_ctx = X509_STORE_new();
00734     if (cert_ctx == NULL)
00735     {
00736         seterr("Unable to create Certificate Store Context");
00737         return false;
00738     }
00739 
00740     lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file());
00741     if (lookup == NULL)
00742     {
00743         seterr("Can't add lookup method...\n");
00744         return false;
00745     }  
00746 
00747     if (!X509_LOOKUP_load_file(lookup, certfile, X509_FILETYPE_PEM))
00748         X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT);
00749 
00750     X509_STORE_CTX_init(&csc, cert_ctx, cert, NULL);
00751     result = X509_verify_cert(&csc);
00752     X509_STORE_CTX_cleanup(&csc);
00753     
00754     X509_STORE_free(cert_ctx);
00755 
00756     if (result == 1)
00757         return true;
00758     else
00759         return false;
00760 }
00761 
00762 
00763 #ifndef _WIN32
00764 bool WvX509Mgr::signedbyCAindir(WvStringParm certdir)
00765 {
00766     WvDirIter i(certdir,false);
00767     for (i.rewind(); i.next(); )
00768     {
00769         if (!signedbyCAinfile(i->fullname))
00770             return false;
00771     }    
00772     return true;
00773 }
00774 #endif
00775 
00776 
00777 bool WvX509Mgr::signedbyCA(WvX509Mgr *cacert)
00778 {
00779     int ret = X509_check_issued(cacert->cert, cert);
00780     if (ret == X509_V_OK)
00781         return true;
00782     else
00783         return false;
00784 }
00785 
00786 
00787 WvString WvX509Mgr::encode(const DumpMode mode)
00788 {
00789     WvString nil;
00790     WvDynBuf retval;
00791     BIO *bufbio = BIO_new(BIO_s_mem());
00792     BUF_MEM *bm;
00793     
00794     switch(mode)
00795     {
00796     case CertPEM:
00797         debug("Dumping X509 certificate.\n");
00798         PEM_write_bio_X509(bufbio, cert);
00799         break;
00800         
00801     case CertDER:
00802         debug("Dumping X509 certificate in DER format\n");
00803         i2d_X509_bio(bufbio, cert);
00804         break;
00805         
00806     case RsaPEM:
00807         debug("Dumping RSA keypair.\n");
00808         BIO_free(bufbio);
00809         return rsa->getpem(true);
00810         break;
00811         
00812     case RsaPubPEM:
00813         debug("Dumping RSA Public Key!\n");
00814         BIO_free(bufbio);
00815         return rsa->getpem(false);
00816         break;
00817 
00818     case RsaRaw:
00819         debug("Dumping raw RSA keypair.\n");
00820         RSA_print(bufbio, rsa->rsa, 0);
00821         break;
00822         
00823     default:
00824         seterr("Unknown Mode\n");
00825         return nil;
00826     }
00827 
00828     BIO_get_mem_ptr(bufbio, &bm);
00829     retval.put(bm->data, bm->length);
00830     BIO_free(bufbio);
00831     if (mode == CertDER)
00832     {
00833         WvBase64Encoder enc;
00834         WvString output;
00835         enc.flushbufstr(retval, output, true);
00836         return output;
00837     }
00838     else
00839         return retval.getstr();
00840 }
00841 
00842 void WvX509Mgr::decode(const DumpMode mode, WvStringParm pemEncoded)
00843 {
00844     if (!pemEncoded)
00845     {
00846         debug(WvLog::Error, "Not decoding an empty string. - Sorry!\n");
00847         return;
00848     }
00849 
00850     BIO *membuf = BIO_new(BIO_s_mem());
00851     BIO_puts(membuf, pemEncoded);
00852     
00853     switch(mode)
00854     {
00855     case CertPEM:
00856         debug("Importing X509 certificate.\n");
00857         if(cert)
00858         {
00859             debug("Replacing an already existant X509 Certificate!\n");
00860             X509_free(cert);
00861             cert = NULL;
00862         }
00863         
00864         cert = PEM_read_bio_X509(membuf, NULL, NULL, NULL);
00865         if (cert)
00866         {
00867             filldname();
00868             if (!rsa)
00869                 rsa = fillRSAPubKey();
00870         }
00871         else
00872             seterr("Certificate failed to import!");
00873         break;
00874     case RsaPEM:
00875         debug("Importing RSA keypair.\n");
00876         debug("Make sure that you load or generate a new Certificate!\n");
00877         if (rsa) delete rsa;
00878 
00879         
00880         rsa = new WvRSAKey(PEM_read_bio_RSAPrivateKey(membuf, NULL, NULL, NULL), 
00881                            true);
00882         if (!rsa->isok())
00883             seterr("RSA Key failed to import\n");
00884         break;
00885     case RsaPubPEM:
00886         debug("Importing RSA Public Key.\n");
00887         debug("Are you REALLY sure that you want to do this?\n");
00888         if (rsa) delete rsa;
00889         rsa = new WvRSAKey(PEM_read_bio_RSAPublicKey(membuf, NULL, NULL, NULL), 
00890                            true);
00891         if (!rsa->isok())
00892             seterr("RSA Public Key failed to import\n");
00893         break;
00894     case RsaRaw:
00895         debug("Importing raw RSA keypair not supported.\n");
00896         break;
00897         
00898     default:
00899         seterr("Unknown Mode\n");
00900     }
00901     BIO_free_all(membuf);
00902 }
00903 
00904 
00905 void WvX509Mgr::write_p12(WvStringParm filename)
00906 {
00907     debug("Dumping RSA Key and X509 Cert to PKCS12 structure.\n");
00908 
00909     AutoClose fp = fopen(filename, "wb");
00910 
00911     if (!fp)
00912     {
00913         seterr("Unable to create: %s\n", filename);
00914         return;
00915     }
00916 
00917     if (!!pkcs12pass)
00918     {
00919         if (rsa && cert)
00920         {
00921             EVP_PKEY *pk = EVP_PKEY_new();
00922             if (!pk)
00923             {
00924                 seterr("Unable to create PKEY object.\n");
00925                 return;
00926             }
00927 
00928             if (!EVP_PKEY_set1_RSA(pk, rsa->rsa))
00929             {
00930                 seterr("Error setting RSA keys.\n");
00931                 EVP_PKEY_free(pk);
00932                 return;
00933             }
00934             else
00935             {
00936                 PKCS12 *pkg = PKCS12_create(pkcs12pass.edit(), "foo", pk, 
00937                                             cert, NULL, 0, 0, 0, 0, 0);
00938                 if (pkg)
00939                 {
00940                     debug("Write the PKCS12 object out...\n");
00941                     i2d_PKCS12_fp(fp, pkg);
00942                     PKCS12_free(pkg);
00943                     EVP_PKEY_free(pk);
00944                 }
00945                 else
00946                 {
00947                     seterr("Unable to create PKCS12 object.\n");
00948                     EVP_PKEY_free(pk);
00949                     return;
00950                 }
00951             }
00952         }
00953         else
00954         {
00955             seterr("Either the RSA key or the Certificate is not present\n");
00956             return;
00957         }
00958     }
00959     else
00960     {
00961         seterr("No Password specified for PKCS12 dump\n");
00962         return; 
00963     }
00964 }
00965 
00966 void WvX509Mgr::read_p12(WvStringParm filename)
00967 {
00968     debug("Reading Certificate and Private Key from PKCS12 file: %s\n", filename);
00969 
00970     AutoClose fp = fopen(filename, "r");
00971 
00972     if (!fp)
00973     {
00974         seterr("Unable to read from: %s\n", filename);
00975         return;
00976     }
00977 
00978     if (!!pkcs12pass)
00979     {
00980         PKCS12 *pkg = d2i_PKCS12_fp(fp, NULL);
00981         if (pkg)
00982         {
00983             EVP_PKEY *pk = EVP_PKEY_new();
00984             if (!pk)
00985             {
00986                 seterr("Unable to create PKEY object.\n");
00987                 return;
00988             }
00989             
00990             // Parse out the bits out the PKCS12 package.
00991             PKCS12_parse(pkg, pkcs12pass, &pk, &cert, NULL);
00992             PKCS12_free(pkg);
00993             
00994             // Now, cert should be OK, let's try and set up the RSA stuff
00995             // since we've essentially got a PKEY, and not a WvRSAKey
00996             // We need to create a new WvRSAKey from the PKEY...
00997             rsa = new WvRSAKey(EVP_PKEY_get1_RSA(pk), true);
00998             
00999             // Now that we have both, check to make sure that they match
01000             if (!rsa || !cert || test())
01001             {
01002                 seterr("Could not fill in RSA and Cert with matching values.\n");
01003                 return;
01004             }
01005             EVP_PKEY_free(pk);
01006         }
01007         else
01008         {
01009             seterr("Read in of PKCS12 file '%s' failed - aborting!\n", filename);
01010             return;
01011         }
01012     }
01013     else
01014     {
01015         seterr("No Password specified for PKCS12 file - aborting!\n");
01016         return;
01017     }
01018 }
01019 
01020 
01021 WvString WvX509Mgr::get_issuer()
01022 { 
01023     if (cert)
01024     {
01025         char *name = X509_NAME_oneline(X509_get_issuer_name(cert),0,0);
01026         WvString retval(name);
01027         OPENSSL_free(name);
01028         return retval;
01029     }
01030     else
01031         return WvString::null;
01032 }
01033 
01034 
01035 void WvX509Mgr::set_issuer(WvStringParm issuer)
01036 {
01037     assert(cert);
01038     X509_NAME *name = X509_get_issuer_name(cert);
01039     set_name_entry(name, issuer);
01040     X509_set_issuer_name(cert, name);
01041 }
01042 
01043 
01044 WvString WvX509Mgr::get_subject()
01045 {
01046     if (cert)
01047     {
01048         char *name = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
01049         WvString retval(name);
01050         OPENSSL_free(name);
01051         return retval;
01052     }
01053     else
01054         return WvString::null;
01055 }
01056 
01057 
01058 void WvX509Mgr::set_subject(WvStringParm subject)
01059 {
01060     assert(cert);
01061     X509_NAME *name = X509_get_subject_name(cert);
01062     set_name_entry(name, subject);
01063     X509_set_subject_name(cert, name);
01064 }
01065 
01066 
01067 void WvX509Mgr::set_subject(X509_NAME *name)
01068 {
01069     X509_set_subject_name(cert, name);
01070 }
01071 
01072 
01073 void WvX509Mgr::set_pubkey(WvRSAKey *_rsa)
01074 {
01075     EVP_PKEY *pk = NULL;
01076 
01077     if ((pk = EVP_PKEY_new()) == NULL)
01078     {
01079         seterr("Error creating key handler for new certificate");
01080         return;
01081     }
01082 
01083     // Assign RSA Key from WvRSAKey into stupid package that OpenSSL needs
01084     if (!EVP_PKEY_set1_RSA(pk, rsa->rsa))
01085     {
01086         seterr("Error adding RSA keys to certificate");
01087         return;
01088     }
01089     
01090     X509_set_pubkey(cert, pk);
01091 
01092     if (pk)
01093         EVP_PKEY_free(pk);
01094 }
01095 
01096 
01097 
01098 void WvX509Mgr::set_nsserver(WvStringParm servername)
01099 {
01100     assert(cert);
01101     
01102     WvString fqdn;
01103     
01104     // FQDN cannot have a = in it, therefore it
01105     // must be a distinguished name :)
01106     if (strchr(servername, '='))
01107         fqdn = set_name_entry(NULL, servername);
01108     else
01109         fqdn = servername;
01110     
01111     if (!fqdn)
01112         fqdn = "null.noname.null";
01113     
01114     debug("Setting Netscape SSL server name extension to '%s'.\n", fqdn);
01115 
01116     // Add in the netscape-specific server extension
01117     set_extension(NID_netscape_cert_type, "server");
01118     set_extension(NID_netscape_ssl_server_name, fqdn);
01119 }
01120 
01121 
01122 WvString WvX509Mgr::get_nsserver()
01123 {
01124     return get_extension(NID_netscape_ssl_server_name);
01125 }
01126 
01127 
01128 WvString WvX509Mgr::get_serial()
01129 {
01130     if (cert)
01131     {
01132         return WvString(ASN1_INTEGER_get(X509_get_serialNumber(cert)));
01133     }
01134     else
01135         return WvString::null;
01136 }
01137 
01138 
01139 void WvX509Mgr::set_version()
01140 {
01141         X509_set_version(cert, 0x2);
01142 }
01143 
01144 
01145 void WvX509Mgr::set_serial(long serial)
01146 {
01147     assert(cert);
01148     ASN1_INTEGER_set(X509_get_serialNumber(cert), serial);
01149 }
01150 
01151 
01152 WvString WvX509Mgr::get_crl_dp()
01153 {
01154     assert(cert);
01155     return get_extension(NID_crl_distribution_points);
01156 }
01157 
01158 
01159 WvString WvX509Mgr::get_cp_oid()
01160 {
01161     assert(cert);
01162     return get_extension(NID_certificate_policies);
01163 }
01164 
01165 void WvX509Mgr::set_cp_oid(WvStringParm oid, WvStringParm _url)
01166 {
01167     assert(cert);
01168     WvString url(_url);
01169     ASN1_OBJECT *pobj = OBJ_txt2obj(oid, 0);
01170     POLICYINFO *pol = POLICYINFO_new();
01171     POLICYQUALINFO *qual = NULL;
01172     STACK_OF(POLICYINFO) *sk_pinfo = sk_POLICYINFO_new_null();
01173     pol->policyid = pobj;
01174     if (!!url)
01175     {
01176         pol->qualifiers = sk_POLICYQUALINFO_new_null();
01177         qual = POLICYQUALINFO_new();
01178         qual->pqualid = OBJ_nid2obj(NID_id_qt_cps);
01179         qual->d.cpsuri = M_ASN1_IA5STRING_new();
01180         ASN1_STRING_set(qual->d.cpsuri, url.edit(), url.len());
01181         sk_POLICYQUALINFO_push(pol->qualifiers, qual);
01182     }
01183     sk_POLICYINFO_push(sk_pinfo, pol);
01184     X509_EXTENSION *ex = X509V3_EXT_i2d(NID_certificate_policies, 0, 
01185                                         sk_pinfo);
01186     X509_add_ext(cert, ex, -1);
01187     X509_EXTENSION_free(ex);
01188     sk_POLICYINFO_free(sk_pinfo);
01189 }
01190 
01191 
01192 void WvX509Mgr::set_lifetime(long seconds)
01193 {
01194     // Set the NotBefore time to now.
01195     X509_gmtime_adj(X509_get_notBefore(cert), 0);
01196     
01197     // Now + 10 years... should be shorter, but since we don't currently
01198     // have a set of routines to refresh the certificates, make it
01199     // REALLY long.
01200     X509_gmtime_adj(X509_get_notAfter(cert), seconds);
01201 }
01202 
01203 
01204 void WvX509Mgr::set_key_usage(WvStringParm values)
01205 {
01206     set_extension(NID_key_usage, values);
01207 }
01208 
01209 
01210 WvString WvX509Mgr::get_key_usage()
01211 {
01212     return get_extension(NID_key_usage);
01213 }
01214 
01215 
01216 void WvX509Mgr::set_ext_key_usage(WvStringParm values)
01217 {
01218     set_extension(NID_ext_key_usage, values);
01219 }
01220 
01221 
01222 WvString WvX509Mgr::get_ext_key_usage()
01223 {
01224     assert(cert);
01225     return get_extension(NID_ext_key_usage);
01226 }
01227 
01228 
01229 WvString WvX509Mgr::get_altsubject()
01230 {
01231     assert(cert);
01232     return get_extension(NID_subject_alt_name);
01233 }
01234 
01235 
01236 WvString WvX509Mgr::get_constraints()
01237 {
01238     assert(cert);
01239     return get_extension(NID_policy_constraints);
01240 }
01241 
01242 
01243 void WvX509Mgr::set_constraints(WvStringParm constraint)
01244 {
01245     assert(cert);
01246     set_extension(NID_policy_constraints, constraint);
01247 }
01248 
01249 
01250 void WvX509Mgr::set_aia(WvStringParm _identifier)
01251 {
01252     WvString identifier(_identifier);
01253     unsigned char *list;
01254     list = reinterpret_cast<unsigned char *>(identifier.edit());
01255     AUTHORITY_INFO_ACCESS *ainfo = sk_ACCESS_DESCRIPTION_new_null();
01256     ACCESS_DESCRIPTION *acc = ACCESS_DESCRIPTION_new();
01257     sk_ACCESS_DESCRIPTION_push(ainfo, acc);
01258     GENERAL_NAME_free(acc->location);
01259     i2d_GENERAL_NAME(acc->location, &list);
01260 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
01261     const unsigned char** plist = const_cast<const unsigned char**>(&list);
01262 #else
01263     unsigned char** plist = &list;
01264 #endif
01265     d2i_GENERAL_NAME(&acc->location, plist, identifier.len());
01266     X509_EXTENSION *ex = X509V3_EXT_i2d(NID_info_access, 0, ainfo);
01267     X509_add_ext(cert, ex, -1);
01268     X509_EXTENSION_free(ex);
01269     sk_ACCESS_DESCRIPTION_free(ainfo);
01270 }
01271 
01272 
01273 WvString WvX509Mgr::get_aia()
01274 {
01275     return get_extension(NID_info_access);
01276 }
01277 
01278 
01279 WvStringList *parse_stack(WvStringParm ext, 
01280                          WvStringList *list, WvStringParm prefix)
01281 {
01282     WvStringList whole_aia;
01283     whole_aia.split(ext, "\n");
01284     WvStringList::Iter i(whole_aia);
01285     for (i.rewind();i.next();)
01286     {
01287       WvString stack_entry(*i);
01288       if (strstr(stack_entry, prefix))
01289       {
01290           WvString uri(stack_entry.edit() + prefix.len());
01291           list->append(uri);  
01292       }
01293     }
01294     return list;
01295 }
01296 
01297 WvStringList *WvX509Mgr::get_ocsp(WvStringList *responders)
01298 {
01299     return parse_stack(get_aia(), responders, "OCSP - URI:");
01300 }
01301 
01302 
01303 WvStringList *WvX509Mgr::get_ca_urls(WvStringList *urls)
01304 {
01305     return parse_stack(get_aia(), urls, "CA Issuers - URI:");
01306 }
01307 
01308 
01309 WvString WvX509Mgr::get_extension(int nid)
01310 {
01311     WvString retval = WvString::null;
01312     
01313     if (cert)
01314     {
01315         X509 *copy = X509_dup(cert);
01316         int index = X509_get_ext_by_NID(copy, nid, -1);
01317         if (index >= 0)
01318         {
01319             X509_EXTENSION *ext = X509_get_ext(copy, index);
01320             if (ext)
01321             {
01322                 X509V3_EXT_METHOD *method = X509V3_EXT_get(ext);
01323                 if (!method)
01324                 {
01325                     WvDynBuf buf;
01326                     buf.put(ext->value->data, ext->value->length);
01327                     retval = buf.getstr();
01328                 }
01329                 else
01330                 {
01331                     void *ext_data = NULL;
01332 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
01333                     const unsigned char **ext_value_data;
01334                     ext_value_data = (const_cast<const unsigned char **>
01335                                       (&ext->value->data));
01336 #else
01337                     unsigned char **ext_value_data = &ext->value->data;
01338 #endif
01339                     if (method->it)
01340                     {
01341                         ext_data = ASN1_item_d2i(NULL, ext_value_data,
01342                                                 ext->value->length, 
01343                                                 ASN1_ITEM_ptr(method->it));
01344                         debug("Applied generic conversion!\n");
01345                     }
01346                     else
01347                     {
01348                         ext_data = method->d2i(NULL, ext_value_data,
01349                                               ext->value->length);
01350                         debug("Applied method specific conversion!\n");
01351                     }
01352                     
01353                     if (method->i2s)
01354                     {
01355                         debug("String Extension!\n");
01356                         retval = method->i2s(method, ext_data);
01357                     }
01358                     else if (method->i2v)
01359                     {
01360                         debug("Stack Extension!\n");
01361                         CONF_VALUE *val = NULL;
01362                         STACK_OF(CONF_VALUE) *svals = NULL;
01363                         svals = method->i2v(method, ext_data, NULL);
01364                         if (!sk_CONF_VALUE_num(svals))
01365                             retval = "EMPTY";
01366                         else
01367                         {
01368                             WvStringList list;
01369                             for(int i = 0; i < sk_CONF_VALUE_num(svals); i++)
01370                             {
01371                                 val = sk_CONF_VALUE_value(svals, i);
01372                                 if (!val->name)
01373                                     list.append(WvString(val->value));
01374                                 else if (!val->value)
01375                                     list.append(WvString(val->name));
01376                                 else 
01377                                 {
01378                                     WvString pair("%s:%s", val->name, val->value);
01379                                     list.append(pair);
01380                                 }
01381                             }
01382                             retval = list.join(";\n");
01383                         }
01384                         sk_CONF_VALUE_pop_free(svals, X509V3_conf_free);
01385                     }
01386                     else if (method->i2r)
01387                     {
01388                         debug("Raw Extension!\n");
01389                         WvDynBuf retvalbuf;
01390                         BIO *bufbio = BIO_new(BIO_s_mem());
01391                         BUF_MEM *bm;
01392                         method->i2r(method, ext_data, bufbio, 0);
01393                         BIO_get_mem_ptr(bufbio, &bm);
01394                         retvalbuf.put(bm->data, bm->length);
01395                         BIO_free(bufbio);
01396                         retval = retvalbuf.getstr();
01397                     }
01398                     
01399                     if (method->it)
01400                         ASN1_item_free((ASN1_VALUE *)ext_data, 
01401                                        ASN1_ITEM_ptr(method->it));
01402                     else
01403                         method->ext_free(ext_data);
01404 
01405                 }
01406             }
01407         }
01408         else
01409         {
01410             debug("Extension not present!\n");
01411         }
01412         if (copy)
01413           X509_free(copy);
01414     }
01415 
01416     if (!!retval)
01417     {
01418         debug("Returning: %s\n", retval);
01419         return retval;
01420     }
01421     else
01422         return WvString::null;
01423 }
01424 
01425 void WvX509Mgr::set_extension(int nid, WvStringParm _values)
01426 {
01427     WvString values(_values);
01428     X509_EXTENSION *ex = NULL;
01429     ex = X509V3_EXT_conf_nid(NULL, NULL, nid, values.edit());
01430     X509_add_ext(cert, ex, -1);
01431     X509_EXTENSION_free(ex);
01432 }
01433 
01434 
01435 bool WvX509Mgr::isok() const
01436 {
01437     return cert && rsa && WvError::isok();
01438 }
01439 
01440 
01441 WvString WvX509Mgr::errstr() const
01442 {
01443     if (WvError::geterr() == 0)
01444     {
01445         // only use a custom string if there's not an error set
01446         if (!cert && !rsa)
01447             return "No certificate or RSA key assigned";
01448         else if (!cert)
01449             return "No certificate assigned";
01450         else if (!rsa)
01451             return "No RSA key assigned";
01452     }
01453     return WvError::errstr();
01454 }
01455 
01456 
01457 int WvX509Mgr::geterr() const
01458 {
01459     int ret = WvError::geterr();
01460     if (ret == 0 && (!cert || !rsa))
01461     {
01462         // unless there's a regular error set, we'll be returning a custom
01463         // string: see errstr()
01464         ret = -1;
01465     }
01466     return ret;
01467 }
01468 
01469 
01470 bool WvX509Mgr::signcert(X509 *unsignedcert)
01471 {
01472     if (unsignedcert == NULL)
01473     {
01474         debug("No certificate to sign??\n");
01475         return false;
01476     }
01477 
01478     if (cert == unsignedcert)
01479     {
01480         debug("Self Signing!\n");
01481         printf("Looks like:\n%s\n", encode(WvX509Mgr::CertPEM).cstr());
01482     }
01483     else if (!((cert->ex_flags & EXFLAG_KUSAGE) && 
01484           (cert->ex_kusage & KU_KEY_CERT_SIGN)))
01485     {
01486         debug("This Certificate is not allowed to sign Certificates!\n");
01487         return false;
01488     }
01489     
01490     debug("Ok, now sign the new cert with the current RSA key.\n");
01491     EVP_PKEY *certkey = EVP_PKEY_new();
01492     bool cakeyok = EVP_PKEY_set1_RSA(certkey, rsa->rsa);
01493     if (cakeyok)
01494     {
01495         
01496         X509_sign(unsignedcert, certkey, EVP_sha1());
01497     }
01498     else
01499     {
01500         debug("No keys??\n");
01501         EVP_PKEY_free(certkey);
01502         return false;
01503     }
01504     
01505     EVP_PKEY_free(certkey);
01506     return true;
01507 }
01508 
01509 WvString WvX509Mgr::sign(WvStringParm data)
01510 {
01511     WvDynBuf buf;
01512     buf.putstr(data);
01513     return sign(buf);
01514 }
01515 
01516 WvString WvX509Mgr::sign(WvBuf &data)
01517 {
01518     assert(rsa);
01519 
01520     EVP_MD_CTX sig_ctx;
01521     unsigned char sig_buf[4096];
01522     
01523     EVP_PKEY *pk = EVP_PKEY_new();
01524     if (!pk)
01525     {
01526         seterr("Unable to create PKEY object.\n");
01527         return WvString::null;
01528     }
01529     
01530     if (!EVP_PKEY_set1_RSA(pk, rsa->rsa))
01531     {
01532         seterr("Error setting RSA keys.\n");
01533         EVP_PKEY_free(pk);
01534         return WvString::null;
01535     }
01536     
01537     EVP_SignInit(&sig_ctx, EVP_sha1());
01538     EVP_SignUpdate(&sig_ctx, data.peek(0, data.used()), data.used());
01539     unsigned int sig_len = sizeof(sig_buf);
01540     int sig_err = EVP_SignFinal(&sig_ctx, sig_buf, 
01541                                 &sig_len, pk);
01542     if (sig_err != 1)
01543     {
01544         seterr("Error while signing!\n");
01545         EVP_PKEY_free(pk);
01546         return WvString::null;
01547     }
01548 
01549     EVP_PKEY_free(pk);
01550     EVP_MD_CTX_cleanup(&sig_ctx); // this isn't my fault ://
01551     WvDynBuf buf;
01552     buf.put(sig_buf, sig_len);
01553     debug("Signature size: %s\n", buf.used());
01554     return WvBase64Encoder().strflushbuf(buf, true);
01555 }
01556 
01557 bool WvX509Mgr::verify(WvStringParm original, WvStringParm signature)
01558 {
01559     WvDynBuf buf;
01560     buf.putstr(original);
01561     return verify(buf, signature);
01562 }
01563 
01564 bool WvX509Mgr::verify(WvBuf &original, WvStringParm signature)
01565 {
01566     
01567     unsigned char sig_buf[4096];
01568     size_t sig_size = sizeof(sig_buf);
01569     WvBase64Decoder().flushstrmem(signature, sig_buf, &sig_size, true);
01570     
01571     EVP_PKEY *pk = X509_get_pubkey(cert);
01572     if (!pk) 
01573     {
01574         seterr("Couldn't allocate PKEY for verify()\n");
01575         return false;
01576     }
01577     
01578     /* Verify the signature */
01579     EVP_MD_CTX sig_ctx;
01580     EVP_VerifyInit(&sig_ctx, EVP_sha1());
01581     EVP_VerifyUpdate(&sig_ctx, original.peek(0, original.used()), original.used());
01582     int sig_err = EVP_VerifyFinal(&sig_ctx, sig_buf, sig_size, pk);
01583     EVP_PKEY_free(pk);
01584     EVP_MD_CTX_cleanup(&sig_ctx); // Again, not my fault... 
01585     if (sig_err != 1) 
01586     {
01587         debug("Verify failed!\n");
01588         return false;
01589     }
01590     else
01591         return true;
01592 }
01593 
01594 
01595 time_t ASN1_TIME_to_time_t(ASN1_TIME *t)
01596 {
01597     struct tm newtime;
01598     char *p = NULL;
01599     char d[18];
01600     memset(&d,'\0',sizeof(d));    
01601     memset(&newtime,'\0',sizeof newtime);
01602     
01603     if (t->type == V_ASN1_GENERALIZEDTIME) 
01604     {
01605          // For time values >= 2050, OpenSSL uses
01606          // ASN1_GENERALIZEDTIME - which we'll worry about
01607          // later.
01608         return 0;
01609     }
01610 
01611     p = (char *)t->data;
01612     sscanf(p,"%2s%2s%2s%2s%2s%2sZ", d, &d[3], &d[6], &d[9], &d[12], &d[15]);
01613     
01614     int year = strtol(d, (char **)NULL, 10);
01615     if (year < 49)
01616         year += 100;
01617     else
01618         year += 50;
01619     
01620     newtime.tm_year = year;
01621     newtime.tm_mon = strtol(&d[3], (char **)NULL, 10) - 1;
01622     newtime.tm_mday = strtol(&d[6], (char **)NULL, 10);
01623     newtime.tm_hour = strtol(&d[9], (char **)NULL, 10);
01624     newtime.tm_min = strtol(&d[12], (char **)NULL, 10);
01625     newtime.tm_sec = strtol(&d[15], (char **)NULL, 10);
01626 
01627     return mktime(&newtime);
01628 }
01629 
01630 time_t WvX509Mgr::get_notvalid_before()
01631 {
01632     assert(cert);
01633     return ASN1_TIME_to_time_t(X509_get_notBefore(cert));
01634 }
01635 
01636 
01637 time_t WvX509Mgr::get_notvalid_after()
01638 {
01639     assert(cert);
01640     return ASN1_TIME_to_time_t(X509_get_notAfter(cert));
01641 }
01642 
01643 
01644 bool WvX509Mgr::signcrl(WvCRLMgr *crl)
01645 {
01646     assert(crl);
01647     assert(rsa);
01648     
01649     if (!((cert->ex_flags & EXFLAG_KUSAGE) && 
01650           (cert->ex_kusage & KU_CRL_SIGN)))
01651     {
01652         debug("Certificate not allowed to sign CRLs!\n");
01653         return false;
01654     }
01655     
01656     EVP_PKEY *certkey = EVP_PKEY_new();
01657     bool cakeyok = EVP_PKEY_set1_RSA(certkey, rsa->rsa);
01658     if (crl->getcrl() && cakeyok)
01659     {
01660         // Use Version 2 CRLs - Of COURSE that means
01661         // to set it to 1 here... grumble..
01662         X509_CRL_set_version(crl->getcrl(), 1);
01663 
01664         X509_CRL_set_issuer_name(crl->getcrl(), X509_get_subject_name(cert));
01665 
01666         ASN1_TIME *tmptm = ASN1_TIME_new();
01667         // Set the LastUpdate time to now.
01668         X509_gmtime_adj(tmptm, 0);
01669         X509_CRL_set_lastUpdate(crl->getcrl(), tmptm);
01670         // CRL's are valid for 30 days
01671         X509_gmtime_adj(tmptm, (long)60*60*24*30);
01672         X509_CRL_set_nextUpdate(crl->getcrl(), tmptm);
01673         ASN1_TIME_free(tmptm);
01674         
01675         // OK - now sign it...
01676         X509_CRL_sign(crl->getcrl(), certkey, EVP_sha1());
01677     }
01678     else
01679     {
01680         debug("No keys??\n");
01681         EVP_PKEY_free(certkey);
01682         return false;
01683     }
01684     EVP_PKEY_free(certkey);
01685 
01686     crl->setca(this);
01687     
01688     return true;
01689 }
01690 
01691 
01692 WvString WvX509Mgr::get_ski()
01693 {
01694     assert(cert);
01695     return get_extension(NID_subject_key_identifier);
01696 }
01697 
01698 WvString WvX509Mgr::get_aki()
01699 {
01700     assert(cert);
01701     return get_extension(NID_authority_key_identifier);
01702 }

Generated on Fri Oct 5 18:20:29 2007 for WvStreams by  doxygen 1.5.3