WvStreams
|
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 "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 // enable this to add some extra debugging trace messages (this can be VERY 00023 // verbose) 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 // helper method to let us return and warn gracefully when getting/setting an 00035 // element in a null certificate 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 // HACK: old versions of OpenSSL can't handle ERR_free_strings() being called 00061 // more than once in the same process; the next wvssl_init won't work. So 00062 // let's make sure to make a global variable that holds the refcount at 1 00063 // even when all the objects go away, then clean it up at exit. 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 // The people who designed this garbage should be shot! 00163 // Support old versions of openssl... 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 // returns some approximation of the server's fqdn, or an empty string. 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 // dn is of the form: c=ca,o=foo organization,dc=foo,dc=com 00184 // (ie. name=value pairs separated by commas) 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 // Sometimes we just want to parse dn into fqdn. 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 // double check RSA key 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); /* version 1 */ 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 // Horribly involuted hack to get around the fact that the 00341 // OpenSSL people are too braindead to have a PEM_write function 00342 // that returns a char * 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 // Check and make sure that the certificate is still valid 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; // file modes are no ops with encode 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 // we use the buffer decode functions for everything else 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 // Assign RSA Key from WvRSAKey into stupid package that OpenSSL needs 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 // FQDN cannot have a = in it, therefore it 00681 // must be a distinguished name :) 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 // Add in the netscape-specific server extension 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 // Set the NotBefore time to now. 00749 X509_gmtime_adj(X509_get_notBefore(cert), 0); 00750 00751 // Now + 10 years... should be shorter, but since we don't currently 00752 // have a set of routines to refresh the certificates, make it 00753 // REALLY long. 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 * These functions are optional to the API. If OpenSSL doesn't support them, 00856 * we simply won't include them here, and apps that need them won't compile. 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); // don't substitute human-readable names 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 // this code would let you set URL information to a policy 01125 // qualifier 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 // we NEED to use a temporary pointer for ext_value_data, 01171 // as openssl's ASN1_item_d2i will muck around with it, 01172 // even though it's const (at least as of version 0.9.8e). 01173 // gah. 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 // first we check to see if the extension already exists, if so we need to 01267 // kill it 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 // now set the extension 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 /* Verify the signature */ 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); // Again, not my fault... 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 // For time values >= 2050, OpenSSL uses 01352 // ASN1_GENERALIZEDTIME - which we'll worry about 01353 // later. 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 /* Default to SHA-1 because OpenSSL does too */ 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 // can't set a meaningful AKI for subordinate certification without the 01470 // parent having an SKI 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