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