00001
00002
00003
00004
00005
00006
00007 #include "wvx509.h"
00008 #include "wvcrl.h"
00009 #include "wvsslhacks.h"
00010 #include "wvcrypto.h"
00011 #include "wvstringlist.h"
00012 #include "wvbase64.h"
00013 #include "wvstrutils.h"
00014
00015 #include <openssl/pem.h>
00016 #include <openssl/x509v3.h>
00017 #include <openssl/err.h>
00018 #include <openssl/sha.h>
00019 #include <openssl/ssl.h>
00020
00021
00022
00023 #if 0
00024 # define TRACE(x, y...) debug(x, ## y);
00025 #else
00026 #ifndef _MSC_VER
00027 # define TRACE(x, y...)
00028 #else
00029 # define TRACE
00030 #endif
00031 #endif
00032
00033
00034
00035 static const char * warning_str_set = "Tried to set %s, but certificate not ok.\n";
00036 static const char * warning_str_get = "Tried to set %s, but certificate not ok.\n";
00037 #define CHECK_CERT_EXISTS_SET(x) \
00038 if (!cert) { \
00039 debug(WvLog::Warning, warning_str_set, x); \
00040 return; \
00041 }
00042 #define CHECK_CERT_EXISTS_GET(x, y) \
00043 if (!cert) { \
00044 debug(WvLog::Warning, warning_str_get, x); \
00045 return y; \
00046 }
00047
00048
00049 UUID_MAP_BEGIN(WvX509)
00050 UUID_MAP_ENTRY(IObject)
00051 UUID_MAP_END
00052
00053 static int ssl_init_count = 0;
00054
00055
00056 void wvssl_init()
00057 {
00058 if (!ssl_init_count)
00059 {
00060 SSL_library_init();
00061 SSL_load_error_strings();
00062 ERR_load_BIO_strings();
00063 ERR_load_crypto_strings();
00064 OpenSSL_add_all_algorithms();
00065 OpenSSL_add_all_ciphers();
00066 OpenSSL_add_all_digests();
00067 }
00068
00069 ssl_init_count++;
00070 }
00071
00072
00073 void wvssl_free()
00074 {
00075 if (ssl_init_count >= 1)
00076 ssl_init_count--;
00077
00078 if (!ssl_init_count)
00079 {
00080 ERR_free_strings();
00081 EVP_cleanup();
00082 }
00083 }
00084
00085
00086 WvString wvssl_errstr()
00087 {
00088 char buf[256];
00089 ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
00090 buf[sizeof(buf)-1] = 0;
00091 return buf;
00092 }
00093
00094
00095 WvX509::WvX509(X509 *_cert)
00096 : debug("X509", WvLog::Debug5)
00097 {
00098 wvssl_init();
00099 cert = _cert;
00100 }
00101
00102
00103 WvX509::WvX509()
00104 : debug("X509", WvLog::Debug5)
00105 {
00106 wvssl_init();
00107 cert = NULL;
00108 }
00109
00110
00111 WvX509::~WvX509()
00112 {
00113 TRACE("Deleting.\n");
00114
00115 if (cert)
00116 X509_free(cert);
00117
00118 wvssl_free();
00119 }
00120
00121
00122
00123
00124
00125 #ifndef NID_domainComponent
00126 #define NID_domainComponent 391
00127 #endif
00128
00129 #ifndef NID_Domain
00130 #define NID_Domain 392
00131 #endif
00132
00133
00134
00135 static WvString set_name_entry(X509_NAME *name, WvStringParm dn)
00136 {
00137 WvString fqdn(""), force_fqdn("");
00138 X509_NAME_ENTRY *ne = NULL;
00139 int count = 0, nid;
00140
00141 WvStringList l;
00142 l.split(dn, ",");
00143
00144
00145
00146 WvStringList::Iter i(l);
00147 for (i.rewind(); i.next(); )
00148 {
00149 WvString s(*i), sid;
00150 char *cptr, *value;
00151
00152 cptr = s.edit();
00153 value = strchr(cptr, '=');
00154 if (value)
00155 *value++ = 0;
00156 else
00157 value = "NULL";
00158
00159 sid = strlwr(trim_string(cptr));
00160
00161 if (sid == "c")
00162 nid = NID_countryName;
00163 else if (sid == "st")
00164 nid = NID_stateOrProvinceName;
00165 else if (sid == "l")
00166 nid = NID_localityName;
00167 else if (sid == "o")
00168 nid = NID_organizationName;
00169 else if (sid == "ou")
00170 nid = NID_organizationalUnitName;
00171 else if (sid == "cn")
00172 {
00173 nid = NID_commonName;
00174 force_fqdn = value;
00175 }
00176 else if (sid == "dc")
00177 {
00178 nid = NID_domainComponent;
00179 if (!!fqdn)
00180 fqdn.append(".");
00181 fqdn.append(value);
00182 }
00183 else if (sid == "domain")
00184 {
00185 nid = NID_Domain;
00186 force_fqdn = value;
00187 }
00188 else if (sid == "email")
00189 nid = NID_pkcs9_emailAddress;
00190 else
00191 nid = NID_domainComponent;
00192
00193
00194 if (name == NULL)
00195 continue;
00196
00197 if (!ne)
00198 ne = X509_NAME_ENTRY_create_by_NID(NULL, nid,
00199 V_ASN1_APP_CHOOSE, (unsigned char *)value, -1);
00200 else
00201 X509_NAME_ENTRY_create_by_NID(&ne, nid,
00202 V_ASN1_APP_CHOOSE, (unsigned char *)value, -1);
00203 if (!ne)
00204 continue;
00205
00206 X509_NAME_add_entry(name, ne, count++, 0);
00207 }
00208
00209 X509_NAME_ENTRY_free(ne);
00210
00211 if (!!force_fqdn)
00212 return force_fqdn;
00213
00214 return fqdn;
00215 }
00216
00217
00218 WvRSAKey *WvX509::get_rsa_pub() const
00219 {
00220 EVP_PKEY *pkcert = X509_get_pubkey(cert);
00221 RSA *certrsa = EVP_PKEY_get1_RSA(pkcert);
00222 EVP_PKEY_free(pkcert);
00223 return new WvRSAKey(certrsa, false);
00224 }
00225
00226
00227 WvString WvX509::certreq(WvStringParm subject, const WvRSAKey &rsa)
00228 {
00229 WvLog debug("X509::certreq", WvLog::Debug5);
00230
00231 EVP_PKEY *pk = NULL;
00232 X509_NAME *name = NULL;
00233 X509_REQ *certreq = NULL;
00234
00235
00236 if (rsa.isok())
00237 debug("RSA Key is fine.\n");
00238 else
00239 {
00240 debug(WvLog::Warning, "RSA Key is bad");
00241 return WvString::null;
00242 }
00243
00244 if ((pk=EVP_PKEY_new()) == NULL)
00245 {
00246 debug(WvLog::Warning, "Error creating key handler for new certificate");
00247 return WvString::null;
00248 }
00249
00250 if ((certreq=X509_REQ_new()) == NULL)
00251 {
00252 debug(WvLog::Warning, "Error creating new PKCS#10 object");
00253 EVP_PKEY_free(pk);
00254 return WvString::null;
00255 }
00256
00257 if (!EVP_PKEY_set1_RSA(pk, rsa.rsa))
00258 {
00259 debug(WvLog::Warning, "Error adding RSA keys to certificate");
00260 X509_REQ_free(certreq);
00261 EVP_PKEY_free(pk);
00262 return WvString::null;
00263 }
00264
00265 X509_REQ_set_version(certreq, 0);
00266
00267 X509_REQ_set_pubkey(certreq, pk);
00268
00269 name = X509_REQ_get_subject_name(certreq);
00270
00271 debug("Creating Certificate request for %s\n", subject);
00272 set_name_entry(name, subject);
00273 X509_REQ_set_subject_name(certreq, name);
00274 char *sub_name = X509_NAME_oneline(X509_REQ_get_subject_name(certreq),
00275 0, 0);
00276 debug("SubjectDN: %s\n", sub_name);
00277 OPENSSL_free(sub_name);
00278
00279 if (!X509_REQ_sign(certreq, pk, EVP_sha1()))
00280 {
00281 debug(WvLog::Warning, "Could not self sign the request");
00282 X509_REQ_free(certreq);
00283 EVP_PKEY_free(pk);
00284 return WvString::null;
00285 }
00286
00287 int verify_result = X509_REQ_verify(certreq, pk);
00288 if (verify_result == 0 || verify_result == -1)
00289 {
00290 debug(WvLog::Warning, "Self signed request failed");
00291 X509_REQ_free(certreq);
00292 EVP_PKEY_free(pk);
00293 return WvString::null;
00294 }
00295 else
00296 {
00297 debug("Self Signed Certificate Request verifies OK!\n");
00298 }
00299
00300
00301
00302
00303 WvDynBuf retval;
00304 BIO *bufbio = BIO_new(BIO_s_mem());
00305 BUF_MEM *bm;
00306
00307 PEM_write_bio_X509_REQ(bufbio, certreq);
00308 BIO_get_mem_ptr(bufbio, &bm);
00309 retval.put(bm->data, bm->length);
00310
00311 X509_REQ_free(certreq);
00312 EVP_PKEY_free(pk);
00313 BIO_free(bufbio);
00314
00315 return retval.getstr();
00316 }
00317
00318
00319 bool WvX509::validate(WvX509 *cacert) const
00320 {
00321 if (cert == NULL)
00322 {
00323 debug(WvLog::Warning, "Tried to validate certificate against CA, but "
00324 "certificate is blank!\n");
00325 return false;
00326 }
00327
00328 bool retval = true;
00329
00330
00331 if (X509_cmp_current_time(X509_get_notAfter(cert)) < 0)
00332 {
00333 debug("Certificate has expired.\n");
00334 retval = false;
00335 }
00336
00337 if (X509_cmp_current_time(X509_get_notBefore(cert)) > 0)
00338 {
00339 debug("Certificate is not yet valid.\n");
00340 retval = false;
00341 }
00342
00343 if (cacert)
00344 {
00345 retval &= signedbyca(*cacert);
00346 retval &= issuedbyca(*cacert);
00347 }
00348
00349 return retval;
00350 }
00351
00352
00353 bool WvX509::signedbyca(WvX509 &cacert) const
00354 {
00355 if (!cert || !cacert.cert)
00356 {
00357 debug(WvLog::Warning, "Tried to determine if certificate was signed "
00358 "by CA, but either client or CA certificate (or both) are "
00359 "blank.\n");
00360 return false;
00361 }
00362
00363 EVP_PKEY *pkey = X509_get_pubkey(cacert.cert);
00364 int result = X509_verify(cert, pkey);
00365 EVP_PKEY_free(pkey);
00366
00367 if (result < 0)
00368 {
00369 debug("There was an error determining whether or not we were signed by "
00370 "CA '%s'.\n", cacert.get_subject());
00371 return false;
00372 }
00373 bool issigned = (result > 0);
00374
00375 debug("Certificate was%s signed by CA %s.\n", issigned ? "" : " NOT",
00376 cacert.get_subject());
00377
00378 return issigned;
00379 }
00380
00381
00382 bool WvX509::issuedbyca(WvX509 &cacert) const
00383 {
00384 if (!cert || !cacert.cert)
00385 {
00386 debug(WvLog::Warning, "Tried to determine if certificate was issued "
00387 "by CA, but either client or CA certificate (or both) are "
00388 "blank.\n");
00389 return false;
00390 }
00391
00392 int ret = X509_check_issued(cacert.cert, cert);
00393 debug("issuedbyca: %s==X509_V_OK(%s)\n", ret, X509_V_OK);
00394 if (ret != X509_V_OK)
00395 return false;
00396
00397 return true;
00398 }
00399
00400
00401 WvString WvX509::encode(const DumpMode mode) const
00402 {
00403 WvDynBuf retval;
00404 encode(mode, retval);
00405 return retval.getstr();
00406 }
00407
00408
00409 void WvX509::encode(const DumpMode mode, WvBuf &buf) const
00410 {
00411 if (mode == CertFileDER || mode == CertFilePEM)
00412 return;
00413
00414 if (!cert)
00415 {
00416 debug(WvLog::Warning, "Tried to encode certificate, but certificate "
00417 "is blank!\n");
00418 return;
00419 }
00420
00421 debug("Encoding X509 certificate.\n");
00422
00423 if (mode == CertHex)
00424 {
00425 size_t size;
00426 unsigned char *keybuf, *iend;
00427 WvString enccert;
00428
00429 size = i2d_X509(cert, NULL);
00430 iend = keybuf = new unsigned char[size];
00431 i2d_X509(cert, &iend);
00432
00433 enccert.setsize(size * 2 +1);
00434 ::hexify(enccert.edit(), keybuf, size);
00435
00436 deletev keybuf;
00437 buf.putstr(enccert);
00438 }
00439 else
00440 {
00441 BIO *bufbio = BIO_new(BIO_s_mem());
00442 BUF_MEM *bm;
00443
00444 if (mode == CertPEM)
00445 PEM_write_bio_X509(bufbio, cert);
00446 else if (mode == CertDER)
00447 i2d_X509_bio(bufbio, cert);
00448 else
00449 debug(WvLog::Warning, "Tried to encode certificate with unknown "
00450 "mode!\n");
00451
00452 BIO_get_mem_ptr(bufbio, &bm);
00453 buf.put(bm->data, bm->length);
00454 BIO_free(bufbio);
00455 }
00456 }
00457
00458
00459 void WvX509::decode(const DumpMode mode, WvStringParm str)
00460 {
00461 if (cert)
00462 {
00463 debug("Replacing an already existant X509 certificate.\n");
00464 X509_free(cert);
00465 cert = NULL;
00466 }
00467
00468 if (mode == CertFileDER)
00469 {
00470 BIO *bio = BIO_new(BIO_s_file());
00471
00472 if (BIO_read_filename(bio, str.cstr()) <= 0)
00473 {
00474 debug(WvLog::Warning, "Open '%s': %s\n", str, wvssl_errstr());
00475 BIO_free(bio);
00476 return;
00477 }
00478
00479 if (!(cert = d2i_X509_bio(bio, NULL)))
00480 debug(WvLog::Warning, "Import DER from '%s': %s\n",
00481 str, wvssl_errstr());
00482
00483 BIO_free(bio);
00484 return;
00485 }
00486 else if (mode == CertFilePEM)
00487 {
00488 FILE *fp = fopen(str, "rb");
00489 if (!fp)
00490 {
00491 int errnum = errno;
00492 debug("Open '%s': %s\n", str, strerror(errnum));
00493 return;
00494 }
00495
00496 if (!(cert = PEM_read_X509(fp, NULL, NULL, NULL)))
00497 debug(WvLog::Warning, "Import PEM from '%s': %s\n",
00498 str, wvssl_errstr());
00499
00500 fclose(fp);
00501 return;
00502 }
00503 else if (mode == CertHex)
00504 {
00505 int hexbytes = str.len();
00506 int bufsize = hexbytes/2;
00507 unsigned char *certbuf = new unsigned char[bufsize];
00508 unsigned char *cp = certbuf;
00509 X509 *tmpcert;
00510
00511 ::unhexify(certbuf, str);
00512 tmpcert = cert = X509_new();
00513 cert = wv_d2i_X509(&tmpcert, &cp, bufsize);
00514 delete[] certbuf;
00515 return;
00516 }
00517
00518
00519 WvDynBuf buf;
00520 buf.putstr(str);
00521 decode(mode, buf);
00522 }
00523
00524
00525 void WvX509::decode(const DumpMode mode, WvBuf &encoded)
00526 {
00527 if (cert)
00528 {
00529 debug("Replacing an already existant X509 certificate.\n");
00530 X509_free(cert);
00531 cert = NULL;
00532 }
00533
00534 if (mode == CertHex || mode == CertFileDER || mode == CertFilePEM)
00535 decode(mode, encoded.getstr());
00536 else
00537 {
00538 BIO *membuf = BIO_new(BIO_s_mem());
00539 BIO_write(membuf, encoded.get(encoded.used()), encoded.used());
00540
00541 if (mode == CertPEM)
00542 cert = PEM_read_bio_X509(membuf, NULL, NULL, NULL);
00543 else if (mode == CertDER)
00544 cert = d2i_X509_bio(membuf, NULL);
00545 else
00546 debug(WvLog::Warning, "Tried to encode certificate with unknown "
00547 "mode!\n");
00548
00549 BIO_free_all(membuf);
00550 }
00551 }
00552
00553
00554 WvString WvX509::get_issuer() const
00555 {
00556 CHECK_CERT_EXISTS_GET("issuer", WvString::null);
00557
00558 char *name = X509_NAME_oneline(X509_get_issuer_name(cert),0,0);
00559 WvString retval(name);
00560 OPENSSL_free(name);
00561 return retval;
00562 }
00563
00564
00565 void WvX509::set_issuer(WvStringParm issuer)
00566 {
00567 CHECK_CERT_EXISTS_SET("issuer");
00568
00569 X509_NAME *name = X509_get_issuer_name(cert);
00570 set_name_entry(name, issuer);
00571 X509_set_issuer_name(cert, name);
00572 }
00573
00574
00575 void WvX509::set_issuer(const WvX509 &cacert)
00576 {
00577 CHECK_CERT_EXISTS_SET("issuer");
00578
00579 X509_NAME *casubj = X509_get_subject_name(cacert.cert);
00580 X509_set_issuer_name(cert, casubj);
00581 }
00582
00583
00584 WvString WvX509::get_subject() const
00585 {
00586 CHECK_CERT_EXISTS_GET("subject", WvString::null);
00587
00588 char *name = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
00589 WvString retval(name);
00590 OPENSSL_free(name);
00591 return retval;
00592 }
00593
00594
00595 void WvX509::set_subject(WvStringParm subject)
00596 {
00597 CHECK_CERT_EXISTS_SET("subject");
00598
00599 X509_NAME *name = X509_get_subject_name(cert);
00600 set_name_entry(name, subject);
00601 X509_set_subject_name(cert, name);
00602 }
00603
00604
00605 void WvX509::set_subject(X509_NAME *name)
00606 {
00607 CHECK_CERT_EXISTS_SET("subject");
00608
00609 X509_set_subject_name(cert, name);
00610 }
00611
00612
00613 void WvX509::set_pubkey(WvRSAKey &_rsa)
00614 {
00615 CHECK_CERT_EXISTS_SET("pubkey");
00616
00617 EVP_PKEY *pk = EVP_PKEY_new();
00618 assert(pk);
00619
00620
00621 if (!EVP_PKEY_set1_RSA(pk, _rsa.rsa))
00622 {
00623 debug("Error adding RSA keys to certificate.\n");
00624 return;
00625 }
00626
00627 X509_set_pubkey(cert, pk);
00628
00629 EVP_PKEY_free(pk);
00630 }
00631
00632
00633
00634 void WvX509::set_nsserver(WvStringParm servername)
00635 {
00636 CHECK_CERT_EXISTS_SET("nsserver");
00637
00638 WvString fqdn;
00639
00640
00641
00642 if (strchr(servername, '='))
00643 fqdn = set_name_entry(NULL, servername);
00644 else
00645 fqdn = servername;
00646
00647 if (!fqdn)
00648 fqdn = "null.noname.null";
00649
00650 debug("Setting Netscape SSL server name extension to '%s'.\n", fqdn);
00651
00652
00653 set_extension(NID_netscape_cert_type, "server");
00654 set_extension(NID_netscape_ssl_server_name, fqdn);
00655 }
00656
00657
00658 WvString WvX509::get_nsserver() const
00659 {
00660 return get_extension(NID_netscape_ssl_server_name);
00661 }
00662
00663
00664 WvString WvX509::get_serial() const
00665 {
00666 CHECK_CERT_EXISTS_GET("serial", WvString::null);
00667
00668 BIGNUM *bn = BN_new();
00669 bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), bn);
00670 char * c = BN_bn2dec(bn);
00671 WvString ret("%s", c);
00672 OPENSSL_free(c);
00673 BN_free(bn);
00674 return ret;
00675 }
00676
00677
00678 void WvX509::set_version()
00679 {
00680 CHECK_CERT_EXISTS_SET("version");
00681
00682 X509_set_version(cert, 0x2);
00683 }
00684
00685
00686 void WvX509::set_serial(long serial)
00687 {
00688 CHECK_CERT_EXISTS_SET("serial");
00689
00690 ASN1_INTEGER_set(X509_get_serialNumber(cert), serial);
00691 }
00692
00693
00694 WvString WvX509::get_crl_dp() const
00695 {
00696 return get_extension(NID_crl_distribution_points);
00697 }
00698
00699
00700 void WvX509::set_lifetime(long seconds)
00701 {
00702 CHECK_CERT_EXISTS_SET("lifetime");
00703
00704
00705 X509_gmtime_adj(X509_get_notBefore(cert), 0);
00706
00707
00708
00709
00710 X509_gmtime_adj(X509_get_notAfter(cert), seconds);
00711 }
00712
00713
00714 void WvX509::set_key_usage(WvStringParm values)
00715 {
00716 set_extension(NID_key_usage, values);
00717 }
00718
00719
00720 WvString WvX509::get_key_usage() const
00721 {
00722 return get_extension(NID_key_usage);
00723 }
00724
00725
00726 void WvX509::set_ext_key_usage(WvStringParm values)
00727 {
00728 set_extension(NID_ext_key_usage, values);
00729 }
00730
00731
00732 WvString WvX509::get_ext_key_usage() const
00733 {
00734 return get_extension(NID_ext_key_usage);
00735 }
00736
00737
00738 WvString WvX509::get_altsubject() const
00739 {
00740 return get_extension(NID_subject_alt_name);
00741 }
00742
00743
00744 bool WvX509::get_basic_constraints(bool &ca, int &pathlen) const
00745 {
00746 CHECK_CERT_EXISTS_GET("basic constraints", false);
00747
00748 BASIC_CONSTRAINTS *constraints = NULL;
00749 int i;
00750
00751 constraints = static_cast<BASIC_CONSTRAINTS *>(X509_get_ext_d2i(
00752 cert, NID_basic_constraints,
00753 &i, NULL));
00754 if (constraints)
00755 {
00756 ca = constraints->ca;
00757 if (constraints->pathlen)
00758 {
00759 if ((constraints->pathlen->type == V_ASN1_NEG_INTEGER) || !ca)
00760 {
00761 debug("Path length type not valid when getting basic "
00762 "constraints.\n");
00763 BASIC_CONSTRAINTS_free(constraints);
00764 pathlen = 0;
00765 return false;
00766 }
00767
00768 pathlen = ASN1_INTEGER_get(constraints->pathlen);
00769 }
00770 else
00771 pathlen = (-1);
00772
00773 BASIC_CONSTRAINTS_free(constraints);
00774 return true;
00775 }
00776
00777 debug("Basic constraints extension not present.\n");
00778 return false;
00779 }
00780
00781
00782 void WvX509::set_basic_constraints(bool ca, int pathlen)
00783 {
00784 CHECK_CERT_EXISTS_SET("basic constraints");
00785
00786 BASIC_CONSTRAINTS *constraints = BASIC_CONSTRAINTS_new();
00787
00788 constraints->ca = static_cast<int>(ca);
00789 if (pathlen != (-1))
00790 {
00791 ASN1_INTEGER *i = ASN1_INTEGER_new();
00792 ASN1_INTEGER_set(i, pathlen);
00793 constraints->pathlen = i;
00794 }
00795
00796 X509_EXTENSION *ex = X509V3_EXT_i2d(NID_basic_constraints, 0,
00797 constraints);
00798 while (int idx = X509_get_ext_by_NID(cert, NID_basic_constraints, 0) >= 0)
00799 {
00800 debug("Found extension at idx %s\n", idx);
00801 X509_EXTENSION *tmpex = X509_delete_ext(cert, idx);
00802 X509_EXTENSION_free(tmpex);
00803 }
00804
00805 X509_add_ext(cert, ex, NID_basic_constraints);
00806 X509_EXTENSION_free(ex);
00807 BASIC_CONSTRAINTS_free(constraints);
00808 }
00809
00810
00811 bool WvX509::get_policy_constraints(int &require_explicit_policy,
00812 int &inhibit_policy_mapping) const
00813 {
00814 CHECK_CERT_EXISTS_GET("policy constraints", false);
00815
00816 POLICY_CONSTRAINTS *constraints = NULL;
00817 int i;
00818
00819 constraints = static_cast<POLICY_CONSTRAINTS *>(X509_get_ext_d2i(
00820 cert, NID_policy_constraints,
00821 &i, NULL));
00822 if (constraints)
00823 {
00824 if (constraints->requireExplicitPolicy)
00825 require_explicit_policy = ASN1_INTEGER_get(
00826 constraints->requireExplicitPolicy);
00827 else
00828 require_explicit_policy = (-1);
00829
00830 if (constraints->inhibitPolicyMapping)
00831 inhibit_policy_mapping = ASN1_INTEGER_get(
00832 constraints->inhibitPolicyMapping);
00833 else
00834 inhibit_policy_mapping = (-1);
00835 POLICY_CONSTRAINTS_free(constraints);
00836 return true;
00837 }
00838
00839 return false;
00840 }
00841
00842
00843 void WvX509::set_policy_constraints(int require_explicit_policy,
00844 int inhibit_policy_mapping)
00845 {
00846 CHECK_CERT_EXISTS_SET("policy constraints");
00847
00848 POLICY_CONSTRAINTS *constraints = POLICY_CONSTRAINTS_new();
00849
00850 ASN1_INTEGER *i = ASN1_INTEGER_new();
00851 ASN1_INTEGER_set(i, require_explicit_policy);
00852 constraints->requireExplicitPolicy = i;
00853 i = ASN1_INTEGER_new();
00854 ASN1_INTEGER_set(i, inhibit_policy_mapping);
00855 constraints->inhibitPolicyMapping = i;
00856
00857 X509_EXTENSION *ex = X509V3_EXT_i2d(NID_policy_constraints, 0,
00858 constraints);
00859 X509_add_ext(cert, ex, -1);
00860 X509_EXTENSION_free(ex);
00861 POLICY_CONSTRAINTS_free(constraints);
00862 }
00863
00864
00865 bool WvX509::get_policy_mapping(PolicyMapList &list) const
00866 {
00867 CHECK_CERT_EXISTS_GET("policy mapping", false);
00868
00869 POLICY_MAPPINGS *mappings = NULL;
00870 POLICY_MAPPING *map = NULL;
00871 int i;
00872
00873 mappings = static_cast<POLICY_MAPPINGS *>(X509_get_ext_d2i(
00874 cert, NID_policy_mappings,
00875 &i, NULL));
00876 if (!mappings)
00877 return false;
00878
00879 const int POLICYID_MAXLEN = 80;
00880 char tmp1[80];
00881 char tmp2[80];
00882 for(int j = 0; j < sk_POLICY_MAPPING_num(mappings); j++)
00883 {
00884 map = sk_POLICY_MAPPING_value(mappings, j);
00885 OBJ_obj2txt(tmp1, POLICYID_MAXLEN, map->issuerDomainPolicy, true);
00886 OBJ_obj2txt(tmp2, POLICYID_MAXLEN, map->subjectDomainPolicy, true);
00887 list.append(new PolicyMap(tmp1, tmp2), true);
00888 }
00889
00890 sk_POLICY_MAPPING_pop_free(mappings, POLICY_MAPPING_free);
00891
00892 return true;
00893 }
00894
00895
00896 void WvX509::set_policy_mapping(PolicyMapList &list)
00897 {
00898 CHECK_CERT_EXISTS_SET("policy mapping");
00899
00900 POLICY_MAPPINGS *maps = sk_POLICY_MAPPING_new_null();
00901
00902 PolicyMapList::Iter i(list);
00903 for (i.rewind(); i.next();)
00904 {
00905 POLICY_MAPPING *map = POLICY_MAPPING_new();
00906 map->issuerDomainPolicy = OBJ_txt2obj(i().issuer_domain.cstr(), 0);
00907 map->subjectDomainPolicy = OBJ_txt2obj(i().subject_domain.cstr(), 0);
00908 sk_POLICY_MAPPING_push(maps, map);
00909 printf("Push!\n");
00910 }
00911
00912 X509_EXTENSION *ex = X509V3_EXT_i2d(NID_policy_mappings, 0, maps);
00913 X509_add_ext(cert, ex, -1);
00914 X509_EXTENSION_free(ex);
00915 sk_POLICY_MAPPING_pop_free(maps, POLICY_MAPPING_free);
00916 }
00917
00918
00919 static void add_aia(WvStringParm type, WvString identifier, AUTHORITY_INFO_ACCESS *ainfo)
00920 {
00921 ACCESS_DESCRIPTION *acc = ACCESS_DESCRIPTION_new();
00922 sk_ACCESS_DESCRIPTION_push(ainfo, acc);
00923 acc->method = OBJ_txt2obj(type.cstr(), 0);
00924 acc->location->type = GEN_URI;
00925 acc->location->d.ia5 = M_ASN1_IA5STRING_new();
00926 unsigned char *cident = reinterpret_cast<unsigned char *>(identifier.edit());
00927 ASN1_STRING_set(acc->location->d.ia5, cident, identifier.len());
00928 }
00929
00930
00931 void WvX509::set_aia(WvStringList &ca_urls,
00932 WvStringList &responders)
00933 {
00934 CHECK_CERT_EXISTS_SET("aia");
00935
00936 AUTHORITY_INFO_ACCESS *ainfo = sk_ACCESS_DESCRIPTION_new_null();
00937
00938 WvStringList::Iter i(ca_urls);
00939 for (i.rewind(); i.next();)
00940 add_aia("caIssuers", i(), ainfo);
00941
00942 WvStringList::Iter j(responders);
00943 for (j.rewind(); j.next();)
00944 add_aia("OCSP", j(), ainfo);
00945
00946 X509_EXTENSION *ex = X509V3_EXT_i2d(NID_info_access, 0, ainfo);
00947 X509_add_ext(cert, ex, -1);
00948 X509_EXTENSION_free(ex);
00949 sk_ACCESS_DESCRIPTION_pop_free(ainfo, ACCESS_DESCRIPTION_free);
00950 }
00951
00952
00953 WvString WvX509::get_aia() const
00954 {
00955 return get_extension(NID_info_access);
00956 }
00957
00958
00959 static void parse_stack(WvStringParm ext, WvStringList &list, WvStringParm prefix)
00960 {
00961 WvStringList stack;
00962 stack.split(ext, ";\n");
00963 WvStringList::Iter i(stack);
00964 for (i.rewind();i.next();)
00965 {
00966 WvString stack_entry(*i);
00967 if (strstr(stack_entry, prefix))
00968 {
00969 WvString uri(stack_entry.edit() + prefix.len());
00970 list.append(uri);
00971 }
00972 }
00973 }
00974
00975
00976 void WvX509::get_ocsp(WvStringList &responders) const
00977 {
00978 parse_stack(get_aia(), responders, "OCSP - URI:");
00979 }
00980
00981
00982 void WvX509::get_ca_urls(WvStringList &urls) const
00983 {
00984 parse_stack(get_aia(), urls, "CA Issuers - URI:");
00985 }
00986
00987
00988 void WvX509::get_crl_urls(WvStringList &urls) const
00989 {
00990 parse_stack(get_crl_dp(), urls, "URI:");
00991 }
00992
00993
00994 void WvX509::set_crl_urls(WvStringList &urls)
00995 {
00996 CHECK_CERT_EXISTS_SET("CRL urls");
00997
00998 STACK_OF(DIST_POINT) *crldp = sk_DIST_POINT_new_null();
00999 WvStringList::Iter i(urls);
01000 for (i.rewind(); i.next();)
01001 {
01002 DIST_POINT *point = DIST_POINT_new();
01003 sk_DIST_POINT_push(crldp, point);
01004
01005 GENERAL_NAMES *uris = GENERAL_NAMES_new();
01006 GENERAL_NAME *uri = GENERAL_NAME_new();
01007 uri->type = GEN_URI;
01008 uri->d.ia5 = M_ASN1_IA5STRING_new();
01009 unsigned char *cident = reinterpret_cast<unsigned char *>(i().edit());
01010 ASN1_STRING_set(uri->d.ia5, cident, i().len());
01011 sk_GENERAL_NAME_push(uris, uri);
01012
01013 point->distpoint = DIST_POINT_NAME_new();
01014 point->distpoint->name.fullname = uris;
01015 point->distpoint->type = 0;
01016 }
01017
01018 X509_EXTENSION *ex = X509V3_EXT_i2d(NID_crl_distribution_points, 0, crldp);
01019 X509_add_ext(cert, ex, -1);
01020 X509_EXTENSION_free(ex);
01021 sk_DIST_POINT_pop_free(crldp, DIST_POINT_free);
01022 }
01023
01024
01025 bool WvX509::get_policies(WvStringList &policy_oids) const
01026 {
01027 CHECK_CERT_EXISTS_GET("policies", false);
01028
01029 int critical;
01030 CERTIFICATEPOLICIES * policies = static_cast<CERTIFICATEPOLICIES *>(
01031 X509_get_ext_d2i(cert, NID_certificate_policies, &critical, NULL));
01032 if (policies)
01033 {
01034 for (int i = 0; i < sk_POLICYINFO_num(policies); i++)
01035 {
01036 POLICYINFO * policy = sk_POLICYINFO_value(policies, i);
01037 const int POLICYID_MAXLEN = 80;
01038
01039 char policyid[POLICYID_MAXLEN];
01040 OBJ_obj2txt(policyid, POLICYID_MAXLEN, policy->policyid,
01041 true);
01042 policy_oids.append(policyid);
01043 }
01044
01045 sk_POLICYINFO_pop_free(policies, POLICYINFO_free);
01046 return true;
01047 }
01048
01049 return false;
01050 }
01051
01052
01053 void WvX509::set_policies(WvStringList &policy_oids)
01054 {
01055 CHECK_CERT_EXISTS_SET("policies");
01056
01057 STACK_OF(POLICYINFO) *sk_pinfo = sk_POLICYINFO_new_null();
01058
01059 WvStringList::Iter i(policy_oids);
01060 for (i.rewind(); i.next();)
01061 {
01062 ASN1_OBJECT *pobj = OBJ_txt2obj(i(), 0);
01063 POLICYINFO *pol = POLICYINFO_new();
01064 pol->policyid = pobj;
01065 sk_POLICYINFO_push(sk_pinfo, pol);
01066 }
01067
01068 #if 0
01069
01070
01071 POLICYQUALINFO *qual = NULL;
01072 WvString url(_url);
01073 if (!!url)
01074 {
01075 pol->qualifiers = sk_POLICYQUALINFO_new_null();
01076 qual = POLICYQUALINFO_new();
01077 qual->pqualid = OBJ_nid2obj(NID_id_qt_cps);
01078 qual->d.cpsouri = M_ASN1_IA5STRING_new();
01079 ASN1_STRING_set(qual->d.cpsuri, url.edit(), url.len());
01080 sk_POLICYQUALINFO_push(pol->qualifiers, qual);
01081 }
01082 #endif
01083
01084 X509_EXTENSION *ex = X509V3_EXT_i2d(NID_certificate_policies, 0,
01085 sk_pinfo);
01086 X509_add_ext(cert, ex, -1);
01087 X509_EXTENSION_free(ex);
01088 sk_POLICYINFO_pop_free(sk_pinfo, POLICYINFO_free);
01089 }
01090
01091
01092 WvString WvX509::get_extension(int nid) const
01093 {
01094 CHECK_CERT_EXISTS_GET("extension", WvString::null);
01095
01096 WvString retval = WvString::null;
01097
01098 int index = X509_get_ext_by_NID(cert, nid, -1);
01099 if (index >= 0)
01100 {
01101 X509_EXTENSION *ext = X509_get_ext(cert, index);
01102
01103 if (ext)
01104 {
01105 X509V3_EXT_METHOD *method = X509V3_EXT_get(ext);
01106 if (!method)
01107 {
01108 WvDynBuf buf;
01109 buf.put(ext->value->data, ext->value->length);
01110 retval = buf.getstr();
01111 }
01112 else
01113 {
01114 void *ext_data = NULL;
01115
01116
01117
01118
01119 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
01120 const unsigned char * ext_value_data = ext->value->data;
01121 #else
01122 unsigned char *ext_value_data = ext->value->data;
01123 #endif
01124 if (method->it)
01125 {
01126 ext_data = ASN1_item_d2i(NULL, &ext_value_data,
01127 ext->value->length,
01128 ASN1_ITEM_ptr(method->it));
01129 TRACE("Applied generic conversion!\n");
01130 }
01131 else
01132 {
01133 ext_data = method->d2i(NULL, &ext_value_data,
01134 ext->value->length);
01135 TRACE("Applied method specific conversion!\n");
01136 }
01137
01138 if (method->i2s)
01139 {
01140 TRACE("String Extension!\n");
01141 char *s = method->i2s(method, ext_data);
01142 retval = s;
01143 OPENSSL_free(s);
01144 }
01145 else if (method->i2v)
01146 {
01147 TRACE("Stack Extension!\n");
01148 CONF_VALUE *val = NULL;
01149 STACK_OF(CONF_VALUE) *svals = NULL;
01150 svals = method->i2v(method, ext_data, NULL);
01151 if (!sk_CONF_VALUE_num(svals))
01152 retval = "EMPTY";
01153 else
01154 {
01155 WvStringList list;
01156 for(int i = 0; i < sk_CONF_VALUE_num(svals); i++)
01157 {
01158 val = sk_CONF_VALUE_value(svals, i);
01159 if (!val->name)
01160 list.append(WvString(val->value));
01161 else if (!val->value)
01162 list.append(WvString(val->name));
01163 else
01164 {
01165 WvString pair("%s:%s", val->name, val->value);
01166 list.append(pair);
01167 }
01168 }
01169 retval = list.join(";\n");
01170 }
01171 sk_CONF_VALUE_pop_free(svals, X509V3_conf_free);
01172 }
01173 else if (method->i2r)
01174 {
01175 TRACE("Raw Extension!\n");
01176 WvDynBuf retvalbuf;
01177 BIO *bufbio = BIO_new(BIO_s_mem());
01178 BUF_MEM *bm;
01179 method->i2r(method, ext_data, bufbio, 0);
01180 BIO_get_mem_ptr(bufbio, &bm);
01181 retvalbuf.put(bm->data, bm->length);
01182 BIO_free(bufbio);
01183 retval = retvalbuf.getstr();
01184 }
01185
01186 if (method->it)
01187 ASN1_item_free((ASN1_VALUE *)ext_data,
01188 ASN1_ITEM_ptr(method->it));
01189 else
01190 method->ext_free(ext_data);
01191
01192 }
01193 }
01194 }
01195 else
01196 {
01197 TRACE("Extension not present!\n");
01198 }
01199
01200 if (!!retval)
01201 TRACE("Returning: %s\n", retval);
01202
01203 return retval;
01204 }
01205
01206
01207 void WvX509::set_extension(int nid, WvStringParm _values)
01208 {
01209 CHECK_CERT_EXISTS_SET("extension");
01210
01211 WvString values(_values);
01212 X509_EXTENSION *ex = NULL;
01213 ex = X509V3_EXT_conf_nid(NULL, NULL, nid, values.edit());
01214 X509_add_ext(cert, ex, -1);
01215 X509_EXTENSION_free(ex);
01216 }
01217
01218
01219 bool WvX509::isok() const
01220 {
01221 return cert;
01222 }
01223
01224
01225 WvString WvX509::errstr() const
01226 {
01227 if (!cert)
01228 return "No certificate.";
01229
01230 return WvString::empty;
01231 }
01232
01233
01234 bool WvX509::verify(WvStringParm original, WvStringParm signature) const
01235 {
01236 WvDynBuf buf;
01237 buf.putstr(original);
01238 return verify(buf, signature);
01239 }
01240
01241
01242 bool WvX509::verify(WvBuf &original, WvStringParm signature) const
01243 {
01244 unsigned char sig_buf[4096];
01245 size_t sig_size = sizeof(sig_buf);
01246 WvBase64Decoder().flushstrmem(signature, sig_buf, &sig_size, true);
01247
01248 EVP_PKEY *pk = X509_get_pubkey(cert);
01249 if (!pk)
01250 return false;
01251
01252
01253 EVP_MD_CTX sig_ctx;
01254 EVP_VerifyInit(&sig_ctx, EVP_sha1());
01255 EVP_VerifyUpdate(&sig_ctx, original.peek(0, original.used()), original.used());
01256 int sig_err = EVP_VerifyFinal(&sig_ctx, sig_buf, sig_size, pk);
01257 EVP_PKEY_free(pk);
01258 EVP_MD_CTX_cleanup(&sig_ctx);
01259 if (sig_err != 1)
01260 {
01261 debug("Verify failed!\n");
01262 return false;
01263 }
01264 else
01265 return true;
01266 }
01267
01268
01269 time_t ASN1_TIME_to_time_t(ASN1_TIME *t)
01270 {
01271 struct tm newtime;
01272 char *p = NULL;
01273 char d[18];
01274 memset(&d,'\0',sizeof(d));
01275 memset(&newtime,'\0',sizeof newtime);
01276
01277 if (t->type == V_ASN1_GENERALIZEDTIME)
01278 {
01279
01280
01281
01282 return 0;
01283 }
01284
01285 p = (char *)t->data;
01286 sscanf(p,"%2s%2s%2s%2s%2s%2sZ", d, &d[3], &d[6], &d[9], &d[12], &d[15]);
01287
01288 int year = strtol(d, (char **)NULL, 10);
01289 if (year < 49)
01290 year += 100;
01291 else
01292 year += 50;
01293
01294 newtime.tm_year = year;
01295 newtime.tm_mon = strtol(&d[3], (char **)NULL, 10) - 1;
01296 newtime.tm_mday = strtol(&d[6], (char **)NULL, 10);
01297 newtime.tm_hour = strtol(&d[9], (char **)NULL, 10);
01298 newtime.tm_min = strtol(&d[12], (char **)NULL, 10);
01299 newtime.tm_sec = strtol(&d[15], (char **)NULL, 10);
01300
01301 return mktime(&newtime);
01302 }
01303
01304
01305 time_t WvX509::get_notvalid_before() const
01306 {
01307 CHECK_CERT_EXISTS_GET("not valid before", 0);
01308
01309 return ASN1_TIME_to_time_t(X509_get_notBefore(cert));
01310 }
01311
01312
01313 time_t WvX509::get_notvalid_after() const
01314 {
01315 CHECK_CERT_EXISTS_GET("not valid after", 0);
01316
01317 return ASN1_TIME_to_time_t(X509_get_notAfter(cert));
01318 }
01319
01320
01321 WvString WvX509::get_ski() const
01322 {
01323 CHECK_CERT_EXISTS_GET("ski", WvString::null);
01324
01325 return get_extension(NID_subject_key_identifier);
01326 }
01327
01328
01329 WvString WvX509::get_aki() const
01330 {
01331 CHECK_CERT_EXISTS_GET("aki", WvString::null);
01332
01333 WvStringList aki_list;
01334 parse_stack(get_extension(NID_authority_key_identifier), aki_list, "keyid:");
01335 if (aki_list.count())
01336 return aki_list.popstr();
01337
01338 return WvString::null;
01339 }
01340
01341
01342 void WvX509::set_ski()
01343 {
01344 CHECK_CERT_EXISTS_SET("ski");
01345
01346 ASN1_OCTET_STRING *oct = M_ASN1_OCTET_STRING_new();
01347 ASN1_BIT_STRING *pk = cert->cert_info->key->public_key;
01348 unsigned char pkey_dig[EVP_MAX_MD_SIZE];
01349 unsigned int diglen;
01350
01351 EVP_Digest(pk->data, pk->length, pkey_dig, &diglen, EVP_sha1(), NULL);
01352
01353 M_ASN1_OCTET_STRING_set(oct, pkey_dig, diglen);
01354 X509_EXTENSION *ext = X509V3_EXT_i2d(NID_subject_key_identifier, 0,
01355 oct);
01356 X509_add_ext(cert, ext, -1);
01357 X509_EXTENSION_free(ext);
01358 M_ASN1_OCTET_STRING_free(oct);
01359 }
01360
01361
01362 void WvX509::set_aki(const WvX509 &cacert)
01363 {
01364 CHECK_CERT_EXISTS_SET("aki");
01365
01366
01367
01368 ASN1_OCTET_STRING *ikeyid = NULL;
01369 X509_EXTENSION *ext;
01370 int i = X509_get_ext_by_NID(cacert.cert, NID_subject_key_identifier, -1);
01371 if ((i >= 0) && (ext = X509_get_ext(cacert.cert, i)))
01372 ikeyid = static_cast<ASN1_OCTET_STRING *>(X509V3_EXT_d2i(ext));
01373
01374 if (!ikeyid)
01375 return;
01376
01377 AUTHORITY_KEYID *akeyid = AUTHORITY_KEYID_new();
01378 akeyid->issuer = NULL;
01379 akeyid->serial = NULL;
01380 akeyid->keyid = ikeyid;
01381 ext = X509V3_EXT_i2d(NID_authority_key_identifier, 0, akeyid);
01382 X509_add_ext(cert, ext, -1);
01383 X509_EXTENSION_free(ext);
01384 AUTHORITY_KEYID_free(akeyid);
01385 }
01386