11#include "wvstringlist.h"
13#include "wvstrutils.h"
14#include "wvautoconf.h"
16#include <openssl/pem.h>
17#include <openssl/x509v3.h>
18#include <openssl/err.h>
19#include <openssl/sha.h>
20#include <openssl/ssl.h>
25# define TRACE(x, y...) debug(x, ## y);
28# define TRACE(x, y...)
36static const char * warning_str_set
37 =
"Tried to set %s, but certificate not ok.\n";
38static const char * warning_str_get
39 =
"Tried to get %s, but certificate not ok.\n";
40#define CHECK_CERT_EXISTS_SET(x) \
42 debug(WvLog::Warning, warning_str_set, x); \
45#define CHECK_CERT_EXISTS_GET(x, y) \
47 debug(WvLog::Warning, warning_str_get, x); \
56static int ssl_init_count = 0;
58#if !HAVE_OPENSSL_POLICY_MAPPING
64class WvSSL_Stupid_Refcount
67 WvSSL_Stupid_Refcount()
72 ~WvSSL_Stupid_Refcount()
88 SSL_load_error_strings();
89 ERR_load_BIO_strings();
90 ERR_load_crypto_strings();
91 OpenSSL_add_all_algorithms();
92 OpenSSL_add_all_ciphers();
93 OpenSSL_add_all_digests();
102 assert(ssl_init_count >= 1);
103 if (ssl_init_count >= 1)
117 ERR_error_string_n(ERR_get_error(), buf,
sizeof(buf));
118 buf[
sizeof(buf)-1] = 0;
124 : debug(
"X509",
WvLog::Debug5)
132 : debug(
"X509",
WvLog::Debug5)
140 : debug(
"X509",
WvLog::Debug5)
144 cert = X509_dup(x509.cert);
152 TRACE(
"Deleting.\n");
164#ifndef NID_domainComponent
165#define NID_domainComponent 391
169#define NID_Domain 392
174static WvString set_name_entry(X509_NAME *name, WvStringParm dn)
177 X509_NAME_ENTRY *ne = NULL;
185 WvStringList::Iter i(l);
186 for (i.rewind(); i.next(); )
192 value = strchr(cptr,
'=');
196 value = (
char*)
"NULL";
201 nid = NID_countryName;
202 else if (sid ==
"st")
203 nid = NID_stateOrProvinceName;
205 nid = NID_localityName;
207 nid = NID_organizationName;
208 else if (sid ==
"ou")
209 nid = NID_organizationalUnitName;
210 else if (sid ==
"cn")
212 nid = NID_commonName;
215 else if (sid ==
"dc")
217 nid = NID_domainComponent;
222 else if (sid ==
"domain")
227 else if (sid ==
"email")
228 nid = NID_pkcs9_emailAddress;
230 nid = NID_domainComponent;
237 ne = X509_NAME_ENTRY_create_by_NID(NULL, nid,
238 V_ASN1_APP_CHOOSE, (
unsigned char *)value, -1);
240 X509_NAME_ENTRY_create_by_NID(&ne, nid,
241 V_ASN1_APP_CHOOSE, (
unsigned char *)value, -1);
245 X509_NAME_add_entry(name, ne, count++, 0);
248 X509_NAME_ENTRY_free(ne);
257WvRSAKey *WvX509::get_rsa_pub()
const
259 EVP_PKEY *pkcert = X509_get_pubkey(cert);
260 RSA *certrsa = EVP_PKEY_get1_RSA(pkcert);
261 EVP_PKEY_free(pkcert);
262 return new WvRSAKey(certrsa,
false);
268 WvLog debug(
"X509::certreq", WvLog::Debug5);
271 X509_NAME *name = NULL;
276 debug(
"RSA Key is fine.\n");
279 debug(WvLog::Warning,
"RSA Key is bad");
280 return WvString::null;
283 if ((pk=EVP_PKEY_new()) == NULL)
285 debug(WvLog::Warning,
286 "Error creating key handler for new certificate");
287 return WvString::null;
290 if ((
certreq=X509_REQ_new()) == NULL)
292 debug(WvLog::Warning,
"Error creating new PKCS#10 object");
294 return WvString::null;
297 if (!EVP_PKEY_set1_RSA(pk, rsa.rsa))
299 debug(WvLog::Warning,
"Error adding RSA keys to certificate");
302 return WvString::null;
305 X509_REQ_set_version(
certreq, 0);
307 X509_REQ_set_pubkey(
certreq, pk);
309 debug(
"Creating Certificate request for %s\n", subject);
310 if ((name = X509_NAME_new()) == NULL)
312 debug(WvLog::Warning,
"Error creating X509_NAME");
315 return WvString::null;
317 set_name_entry(name, subject);
318 X509_REQ_set_subject_name(
certreq, name);
319 X509_NAME_free(name);
320 char *sub_name = X509_NAME_oneline(X509_REQ_get_subject_name(
certreq),
322 debug(
"SubjectDN: %s\n", sub_name);
323 OPENSSL_free(sub_name);
325 if (!X509_REQ_sign(
certreq, pk, EVP_sha1()))
327 debug(WvLog::Warning,
"Could not self sign the request");
330 return WvString::null;
333 int verify_result = X509_REQ_verify(
certreq, pk);
334 if (verify_result == 0 || verify_result == -1)
336 debug(WvLog::Warning,
"Self signed request failed");
339 return WvString::null;
343 debug(
"Self Signed Certificate Request verifies OK!\n");
350 BIO *bufbio = BIO_new(BIO_s_mem());
353 PEM_write_bio_X509_REQ(bufbio,
certreq);
354 BIO_get_mem_ptr(bufbio, &bm);
355 retval.
put(bm->data, bm->length);
369 debug(WvLog::Warning,
"Tried to validate certificate against CA, but "
370 "certificate is blank!\n");
377 if (X509_cmp_current_time(X509_get_notAfter(cert)) < 0)
379 debug(
"Certificate has expired.\n");
383 if (X509_cmp_current_time(X509_get_notBefore(cert)) > 0)
385 debug(
"Certificate is not yet valid.\n");
401 if (!cert || !cacert.cert)
403 debug(WvLog::Warning,
"Tried to determine if certificate was signed "
404 "by CA, but either client or CA certificate (or both) are "
409 EVP_PKEY *pkey = X509_get_pubkey(cacert.cert);
410 int result = X509_verify(cert, pkey);
415 debug(
"Can't determine if we were signed by CA %s: %s\n",
419 bool issigned = (result > 0);
421 debug(
"Certificate was%s signed by CA %s.\n", issigned ?
"" :
" NOT",
430 if (!cert || !cacert.cert)
432 debug(WvLog::Warning,
"Tried to determine if certificate was issued "
433 "by CA, but either client or CA certificate (or both) are "
438 int ret = X509_check_issued(cacert.cert, cert);
439 debug(
"issuedbyca: %s==X509_V_OK(%s)\n", ret, X509_V_OK);
440 if (ret != X509_V_OK)
457 if (mode == CertFileDER || mode == CertFilePEM)
462 debug(WvLog::Warning,
"Tried to encode certificate, but certificate "
467 debug(
"Encoding X509 certificate.\n");
472 unsigned char *keybuf, *iend;
475 size = i2d_X509(cert, NULL);
476 iend = keybuf =
new unsigned char[size];
477 i2d_X509(cert, &iend);
479 enccert.setsize(size * 2 +1);
487 BIO *bufbio = BIO_new(BIO_s_mem());
491 PEM_write_bio_X509(bufbio, cert);
492 else if (mode == CertDER)
493 i2d_X509_bio(bufbio, cert);
495 debug(WvLog::Warning,
"Tried to encode certificate with unknown "
498 BIO_get_mem_ptr(bufbio, &bm);
499 buf.put(bm->data, bm->length);
509 debug(
"Replacing an already existant X509 certificate.\n");
514 if (mode == CertFileDER)
516 BIO *bio = BIO_new(BIO_s_file());
518 if (BIO_read_filename(bio, str.
cstr()) <= 0)
520 debug(WvLog::Warning,
"Open '%s': %s\n", str, wvssl_errstr());
525 if (!(cert = d2i_X509_bio(bio, NULL)))
526 debug(WvLog::Warning,
"Import DER from '%s': %s\n",
527 str, wvssl_errstr());
532 else if (mode == CertFilePEM)
534 FILE *fp = fopen(str,
"rb");
538 debug(
"Open '%s': %s\n", str, strerror(errnum));
542 if (!(cert = PEM_read_X509(fp, NULL, NULL, NULL)))
543 debug(WvLog::Warning,
"Import PEM from '%s': %s\n",
544 str, wvssl_errstr());
549 else if (mode == CertHex)
551 int hexbytes = str.len();
552 int bufsize = hexbytes/2;
553 unsigned char *certbuf =
new unsigned char[bufsize];
554 unsigned char *cp = certbuf;
558 tmpcert = cert = X509_new();
559 cert = wv_d2i_X509(&tmpcert, &cp, bufsize);
575 debug(
"Replacing an already existant X509 certificate.\n");
580 if (mode == CertHex || mode == CertFileDER || mode == CertFilePEM)
584 BIO *membuf = BIO_new(BIO_s_mem());
585 BIO_write(membuf, encoded.
get(encoded.
used()), encoded.
used());
588 cert = PEM_read_bio_X509(membuf, NULL, NULL, NULL);
589 else if (mode == CertDER)
590 cert = d2i_X509_bio(membuf, NULL);
592 debug(WvLog::Warning,
"Tried to decode certificate with unknown "
595 BIO_free_all(membuf);
602 CHECK_CERT_EXISTS_GET(
"issuer", WvString::null);
604 char *name = X509_NAME_oneline(X509_get_issuer_name(cert),0,0);
611void WvX509::set_issuer(WvStringParm issuer)
613 CHECK_CERT_EXISTS_SET(
"issuer");
616 if ((name = X509_NAME_new()) == NULL)
618 set_name_entry(name, issuer);
619 X509_set_issuer_name(cert, name);
620 X509_NAME_free(name);
624void WvX509::set_issuer(
const WvX509 &cacert)
626 CHECK_CERT_EXISTS_SET(
"issuer");
628 const X509_NAME *casubj = X509_get_subject_name(cacert.cert);
629 X509_set_issuer_name(cert, casubj);
635 CHECK_CERT_EXISTS_GET(
"subject", WvString::null);
637 char *name = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
644void WvX509::set_subject(WvStringParm subject)
646 CHECK_CERT_EXISTS_SET(
"subject");
649 if ((name = X509_NAME_new()) == NULL)
651 set_name_entry(name, subject);
652 X509_set_subject_name(cert, name);
653 X509_NAME_free(name);
657void WvX509::set_subject(
const X509_NAME *name)
659 CHECK_CERT_EXISTS_SET(
"subject");
661 X509_set_subject_name(cert, name);
667 CHECK_CERT_EXISTS_SET(
"pubkey");
669 EVP_PKEY *pk = EVP_PKEY_new();
673 if (!EVP_PKEY_set1_RSA(pk, _rsa.rsa))
675 debug(
"Error adding RSA keys to certificate.\n");
679 X509_set_pubkey(cert, pk);
686void WvX509::set_nsserver(WvStringParm servername)
688 CHECK_CERT_EXISTS_SET(
"nsserver");
694 if (strchr(servername,
'='))
695 fqdn = set_name_entry(NULL, servername);
700 fqdn =
"null.noname.null";
702 debug(
"Setting Netscape SSL server name extension to '%s'.\n", fqdn);
705 set_extension(NID_netscape_cert_type,
"server");
706 set_extension(NID_netscape_ssl_server_name, fqdn);
712 return get_extension(NID_netscape_ssl_server_name);
718 CHECK_CERT_EXISTS_GET(
"serial", WvString::null);
720 BIGNUM *bn = BN_new();
721 bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), bn);
736 CHECK_CERT_EXISTS_SET(
"version");
738 X509_set_version(cert, 0x2);
742void WvX509::set_serial(
long serial)
744 CHECK_CERT_EXISTS_SET(
"serial");
746 ASN1_INTEGER_set(X509_get_serialNumber(cert), serial);
752 return get_extension(NID_crl_distribution_points);
758 CHECK_CERT_EXISTS_SET(
"lifetime");
761 X509_gmtime_adj(X509_get_notBefore(cert), 0);
766 X509_gmtime_adj(X509_get_notAfter(cert), seconds);
770void WvX509::set_key_usage(WvStringParm values)
772 set_extension(NID_key_usage, values);
778 return get_extension(NID_key_usage);
782void WvX509::set_ext_key_usage(WvStringParm values)
784 set_extension(NID_ext_key_usage, values);
790 return get_extension(NID_ext_key_usage);
796 return get_extension(NID_subject_alt_name);
802 CHECK_CERT_EXISTS_GET(
"basic constraints",
false);
804 BASIC_CONSTRAINTS *constraints = NULL;
807 constraints =
static_cast<BASIC_CONSTRAINTS *
>
808 (X509_get_ext_d2i(cert, NID_basic_constraints, &i, NULL));
811 ca = constraints->ca;
812 if (constraints->pathlen)
814 if ((ASN1_STRING_type(constraints->pathlen) == V_ASN1_NEG_INTEGER) || !ca)
816 debug(
"Path length type not valid when getting basic "
818 BASIC_CONSTRAINTS_free(constraints);
823 pathlen = ASN1_INTEGER_get(constraints->pathlen);
828 BASIC_CONSTRAINTS_free(constraints);
832 debug(
"Basic constraints extension not present.\n");
839 CHECK_CERT_EXISTS_SET(
"basic constraints");
841 BASIC_CONSTRAINTS *constraints = BASIC_CONSTRAINTS_new();
843 constraints->ca =
static_cast<int>(ca);
846 ASN1_INTEGER *i = ASN1_INTEGER_new();
847 ASN1_INTEGER_set(i, pathlen);
848 constraints->pathlen = i;
851 X509_EXTENSION *ex = X509V3_EXT_i2d(NID_basic_constraints, 0,
853 while (
int idx = X509_get_ext_by_NID(cert, NID_basic_constraints, 0) >= 0)
855 debug(
"Found extension at idx %s\n", idx);
856 X509_EXTENSION *tmpex = X509_delete_ext(cert, idx);
857 X509_EXTENSION_free(tmpex);
860 X509_add_ext(cert, ex, NID_basic_constraints);
861 X509_EXTENSION_free(ex);
862 BASIC_CONSTRAINTS_free(constraints);
870#ifdef HAVE_OPENSSL_POLICY_MAPPING
873 int &inhibit_policy_mapping)
const
875 CHECK_CERT_EXISTS_GET(
"policy constraints",
false);
877 POLICY_CONSTRAINTS *constraints = NULL;
880 constraints =
static_cast<POLICY_CONSTRAINTS *
>(X509_get_ext_d2i(
881 cert, NID_policy_constraints,
885 if (constraints->requireExplicitPolicy)
886 require_explicit_policy = ASN1_INTEGER_get(
887 constraints->requireExplicitPolicy);
889 require_explicit_policy = (-1);
891 if (constraints->inhibitPolicyMapping)
892 inhibit_policy_mapping = ASN1_INTEGER_get(
893 constraints->inhibitPolicyMapping);
895 inhibit_policy_mapping = (-1);
896 POLICY_CONSTRAINTS_free(constraints);
905 int inhibit_policy_mapping)
907 CHECK_CERT_EXISTS_SET(
"policy constraints");
909 POLICY_CONSTRAINTS *constraints = POLICY_CONSTRAINTS_new();
911 ASN1_INTEGER *i = ASN1_INTEGER_new();
912 ASN1_INTEGER_set(i, require_explicit_policy);
913 constraints->requireExplicitPolicy = i;
914 i = ASN1_INTEGER_new();
915 ASN1_INTEGER_set(i, inhibit_policy_mapping);
916 constraints->inhibitPolicyMapping = i;
918 X509_EXTENSION *ex = X509V3_EXT_i2d(NID_policy_constraints, 0,
920 X509_add_ext(cert, ex, -1);
921 X509_EXTENSION_free(ex);
922 POLICY_CONSTRAINTS_free(constraints);
928 CHECK_CERT_EXISTS_GET(
"policy mapping",
false);
930 POLICY_MAPPINGS *mappings = NULL;
931 POLICY_MAPPING *map = NULL;
934 mappings =
static_cast<POLICY_MAPPINGS *
>(X509_get_ext_d2i(
935 cert, NID_policy_mappings,
940 const int POLICYID_MAXLEN = 80;
943 for(
int j = 0; j < sk_POLICY_MAPPING_num(mappings); j++)
945 map = sk_POLICY_MAPPING_value(mappings, j);
946 OBJ_obj2txt(tmp1, POLICYID_MAXLEN, map->issuerDomainPolicy,
true);
947 OBJ_obj2txt(tmp2, POLICYID_MAXLEN, map->subjectDomainPolicy,
true);
948 list.append(
new PolicyMap(tmp1, tmp2),
true);
951 sk_POLICY_MAPPING_pop_free(mappings, POLICY_MAPPING_free);
959 CHECK_CERT_EXISTS_SET(
"policy mapping");
961 POLICY_MAPPINGS *maps = sk_POLICY_MAPPING_new_null();
963 PolicyMapList::Iter i(list);
964 for (i.rewind(); i.next();)
966 POLICY_MAPPING *map = POLICY_MAPPING_new();
967 map->issuerDomainPolicy = OBJ_txt2obj(i().issuer_domain.cstr(), 0);
968 map->subjectDomainPolicy = OBJ_txt2obj(i().subject_domain.cstr(), 0);
969 sk_POLICY_MAPPING_push(maps, map);
973 X509_EXTENSION *ex = X509V3_EXT_i2d(NID_policy_mappings, 0, maps);
974 X509_add_ext(cert, ex, -1);
975 X509_EXTENSION_free(ex);
976 sk_POLICY_MAPPING_pop_free(maps, POLICY_MAPPING_free);
982static void add_aia(WvStringParm type,
WvString identifier,
983 AUTHORITY_INFO_ACCESS *ainfo)
985 ACCESS_DESCRIPTION *acc = ACCESS_DESCRIPTION_new();
986 sk_ACCESS_DESCRIPTION_push(ainfo, acc);
987 acc->method = OBJ_txt2obj(type.
cstr(), 0);
988 acc->location->type = GEN_URI;
989 acc->location->d.ia5 = ASN1_IA5STRING_new();
990 unsigned char *cident
991 =
reinterpret_cast<unsigned char *
>(identifier.
edit());
992 ASN1_STRING_set(acc->location->d.ia5, cident, identifier.len());
999 CHECK_CERT_EXISTS_SET(
"aia");
1001 AUTHORITY_INFO_ACCESS *ainfo = sk_ACCESS_DESCRIPTION_new_null();
1003 WvStringList::Iter i(ca_urls);
1004 for (i.rewind(); i.next();)
1005 add_aia(
"caIssuers", i(), ainfo);
1007 WvStringList::Iter j(responders);
1008 for (j.rewind(); j.next();)
1009 add_aia(
"OCSP", j(), ainfo);
1011 X509_EXTENSION *ex = X509V3_EXT_i2d(NID_info_access, 0, ainfo);
1012 X509_add_ext(cert, ex, -1);
1013 X509_EXTENSION_free(ex);
1014 sk_ACCESS_DESCRIPTION_pop_free(ainfo, ACCESS_DESCRIPTION_free);
1020 return get_extension(NID_info_access);
1024static void parse_stack(WvStringParm ext,
WvStringList &list,
1025 WvStringParm prefix)
1028 stack.
split(ext,
";\n");
1029 WvStringList::Iter i(stack);
1030 for (i.rewind();i.next();)
1033 if (strstr(stack_entry, prefix))
1044 parse_stack(
get_aia(), responders,
"OCSP - URI:");
1050 parse_stack(
get_aia(), urls,
"CA Issuers - URI:");
1062 CHECK_CERT_EXISTS_SET(
"CRL urls");
1064 STACK_OF(DIST_POINT) *crldp = sk_DIST_POINT_new_null();
1065 WvStringList::Iter i(urls);
1066 for (i.rewind(); i.next();)
1068 DIST_POINT *point = DIST_POINT_new();
1069 sk_DIST_POINT_push(crldp, point);
1071 GENERAL_NAMES *uris = GENERAL_NAMES_new();
1072 GENERAL_NAME *uri = GENERAL_NAME_new();
1073 uri->type = GEN_URI;
1074 uri->d.ia5 = ASN1_IA5STRING_new();
1075 unsigned char *cident
1076 =
reinterpret_cast<unsigned char *
>(i().edit());
1077 ASN1_STRING_set(uri->d.ia5, cident, i().len());
1078 sk_GENERAL_NAME_push(uris, uri);
1080 point->distpoint = DIST_POINT_NAME_new();
1081 point->distpoint->name.fullname = uris;
1082 point->distpoint->type = 0;
1085 X509_EXTENSION *ex = X509V3_EXT_i2d(NID_crl_distribution_points, 0, crldp);
1086 X509_add_ext(cert, ex, -1);
1087 X509_EXTENSION_free(ex);
1088 sk_DIST_POINT_pop_free(crldp, DIST_POINT_free);
1094 CHECK_CERT_EXISTS_GET(
"policies",
false);
1097 CERTIFICATEPOLICIES * policies =
static_cast<CERTIFICATEPOLICIES *
>(
1098 X509_get_ext_d2i(cert, NID_certificate_policies, &critical, NULL));
1101 for (
int i = 0; i < sk_POLICYINFO_num(policies); i++)
1103 POLICYINFO * policy = sk_POLICYINFO_value(policies, i);
1104 const int POLICYID_MAXLEN = 80;
1106 char policyid[POLICYID_MAXLEN];
1107 OBJ_obj2txt(policyid, POLICYID_MAXLEN, policy->policyid,
1109 policy_oids.append(policyid);
1112 sk_POLICYINFO_pop_free(policies, POLICYINFO_free);
1122 CHECK_CERT_EXISTS_SET(
"policies");
1124 STACK_OF(POLICYINFO) *sk_pinfo = sk_POLICYINFO_new_null();
1126 WvStringList::Iter i(policy_oids);
1127 for (i.rewind(); i.next();)
1129 ASN1_OBJECT *pobj = OBJ_txt2obj(i(), 0);
1130 POLICYINFO *pol = POLICYINFO_new();
1131 pol->policyid = pobj;
1132 sk_POLICYINFO_push(sk_pinfo, pol);
1138 POLICYQUALINFO *qual = NULL;
1142 pol->qualifiers = sk_POLICYQUALINFO_new_null();
1143 qual = POLICYQUALINFO_new();
1144 qual->pqualid = OBJ_nid2obj(NID_id_qt_cps);
1145 qual->d.cpsouri = M_ASN1_IA5STRING_new();
1146 ASN1_STRING_set(qual->d.cpsuri, url.
edit(), url.len());
1147 sk_POLICYQUALINFO_push(pol->qualifiers, qual);
1151 X509_EXTENSION *ex = X509V3_EXT_i2d(NID_certificate_policies, 0,
1153 X509_add_ext(cert, ex, -1);
1154 X509_EXTENSION_free(ex);
1155 sk_POLICYINFO_pop_free(sk_pinfo, POLICYINFO_free);
1159WvString WvX509::get_extension(
int nid)
const
1161 CHECK_CERT_EXISTS_GET(
"extension", WvString::null);
1165 int index = X509_get_ext_by_NID(cert, nid, -1);
1168 const X509_EXTENSION *ext = X509_get_ext(cert, index);
1172 X509V3_EXT_METHOD *method = (X509V3_EXT_METHOD *)X509V3_EXT_get(
const_cast<X509_EXTENSION *
>(ext));
1173 const ASN1_OCTET_STRING *ext_data_str = X509_EXTENSION_get_data(
const_cast<X509_EXTENSION *
>(ext));
1177 buf.
put(ASN1_STRING_get0_data(ext_data_str), ASN1_STRING_length(ext_data_str));
1182 void *ext_data = NULL;
1187#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
1188 const unsigned char * ext_value_data = ASN1_STRING_get0_data(ext_data_str);
1190 unsigned char *ext_value_data = ASN1_STRING_get0_data(ext_data_str);
1194 ext_data = ASN1_item_d2i(NULL, &ext_value_data,
1195 ASN1_STRING_length(ext_data_str),
1196 ASN1_ITEM_ptr(method->it));
1197 TRACE(
"Applied generic conversion!\n");
1201 ext_data = method->d2i(NULL, &ext_value_data,
1202 ASN1_STRING_length(ext_data_str));
1203 TRACE(
"Applied method specific conversion!\n");
1208 TRACE(
"String Extension!\n");
1209 char *s = method->i2s(method, ext_data);
1213 else if (method->i2v)
1215 TRACE(
"Stack Extension!\n");
1216 CONF_VALUE *val = NULL;
1217 STACK_OF(CONF_VALUE) *svals = NULL;
1218 svals = method->i2v(method, ext_data, NULL);
1219 if (!sk_CONF_VALUE_num(svals))
1224 for(
int i = 0; i < sk_CONF_VALUE_num(svals); i++)
1226 val = sk_CONF_VALUE_value(svals, i);
1228 list.append(WvString(val->value));
1229 else if (!val->value)
1230 list.append(WvString(val->name));
1233 WvString pair(
"%s:%s", val->name, val->value);
1237 retval = list.
join(
";\n");
1239 sk_CONF_VALUE_pop_free(svals, X509V3_conf_free);
1241 else if (method->i2r)
1243 TRACE(
"Raw Extension!\n");
1245 BIO *bufbio = BIO_new(BIO_s_mem());
1247 method->i2r(method, ext_data, bufbio, 0);
1248 BIO_get_mem_ptr(bufbio, &bm);
1249 retvalbuf.
put(bm->data, bm->length);
1251 retval = retvalbuf.
getstr();
1255 ASN1_item_free((ASN1_VALUE *)ext_data,
1256 ASN1_ITEM_ptr(method->it));
1258 method->ext_free(ext_data);
1265 TRACE(
"Extension not present!\n");
1269 TRACE(
"Returning: %s\n", retval);
1275void WvX509::set_extension(
int nid, WvStringParm _values)
1277 CHECK_CERT_EXISTS_SET(
"extension");
1281 int index = X509_get_ext_by_NID(cert, nid, -1);
1284 X509_EXTENSION *ex = X509_delete_ext(cert, index);
1285 X509_EXTENSION_free(ex);
1289 WvString values(_values);
1290 X509_EXTENSION *ex = NULL;
1291 ex = X509V3_EXT_conf_nid(NULL, NULL, nid, values.edit());
1292 X509_add_ext(cert, ex, -1);
1293 X509_EXTENSION_free(ex);
1312 return "No certificate.";
1314 return WvString::empty;
1318bool WvX509::verify(WvStringParm original, WvStringParm signature)
const
1322 return verify(buf, signature);
1328 unsigned char sig_buf[4096];
1329 size_t sig_size =
sizeof(sig_buf);
1332 EVP_PKEY *pk = X509_get_pubkey(cert);
1337 EVP_MD_CTX *sig_ctx = EVP_MD_CTX_new();
1338 EVP_VerifyInit(sig_ctx, EVP_sha1());
1339 EVP_VerifyUpdate(sig_ctx, original.
peek(0, original.
used()),
1341 int sig_err = EVP_VerifyFinal(sig_ctx, sig_buf, sig_size, pk);
1343 EVP_MD_CTX_free(sig_ctx);
1346 debug(
"Verify failed!\n");
1354static time_t ASN1_TIME_to_time_t(
const ASN1_TIME *t)
1359 memset(&d,
'\0',
sizeof(d));
1360 memset(&newtime,
'\0',
sizeof newtime);
1362 if (ASN1_STRING_type(t) == V_ASN1_GENERALIZEDTIME)
1370 p = (
char *)ASN1_STRING_get0_data(t);
1371 sscanf(p,
"%2s%2s%2s%2s%2s%2sZ", d, &d[3], &d[6], &d[9], &d[12], &d[15]);
1373 int year = strtol(d, (
char **)NULL, 10);
1379 newtime.tm_year = year;
1380 newtime.tm_mon = strtol(&d[3], (
char **)NULL, 10) - 1;
1381 newtime.tm_mday = strtol(&d[6], (
char **)NULL, 10);
1382 newtime.tm_hour = strtol(&d[9], (
char **)NULL, 10);
1383 newtime.tm_min = strtol(&d[12], (
char **)NULL, 10);
1384 newtime.tm_sec = strtol(&d[15], (
char **)NULL, 10);
1386 return mktime(&newtime);
1392 CHECK_CERT_EXISTS_GET(
"not valid before", 0);
1394 return ASN1_TIME_to_time_t(X509_get_notBefore(cert));
1398time_t WvX509::get_notvalid_after()
const
1400 CHECK_CERT_EXISTS_GET(
"not valid after", 0);
1402 return ASN1_TIME_to_time_t(X509_get_notAfter(cert));
1408 CHECK_CERT_EXISTS_GET(
"ski", WvString::null);
1410 return get_extension(NID_subject_key_identifier);
1416 CHECK_CERT_EXISTS_GET(
"aki", WvString::null);
1419 parse_stack(get_extension(NID_authority_key_identifier), aki_list,
1421 if (aki_list.count())
1422 return aki_list.
popstr();
1424 return WvString::null;
1430 CHECK_CERT_EXISTS_GET(
"fingerprint", WvString::null);
1433 const EVP_MD *digest = EVP_sha1();
1434 if (mode == FingerMD5)
1437 unsigned char md[EVP_MAX_MD_SIZE];
1439 if (!X509_digest(cert, digest, md, &n))
1442 debug(
"get_fingerprint: Out of memory\n");
1443 return WvString::null;
1450 sprintf(buf,
"%02X", md[i]);
1452 }
while (++i < n && (store.
putch(
':'), 1));
1458void WvX509::set_ski()
1460 CHECK_CERT_EXISTS_SET(
"ski");
1462 ASN1_OCTET_STRING *oct = ASN1_OCTET_STRING_new();
1463 const ASN1_BIT_STRING *pk = X509_get0_pubkey_bitstr(cert);
1464 unsigned char pkey_dig[EVP_MAX_MD_SIZE];
1465 unsigned int diglen;
1467 EVP_Digest(ASN1_STRING_get0_data(pk), ASN1_STRING_length(pk), pkey_dig, &diglen, EVP_sha1(), NULL);
1469 ASN1_OCTET_STRING_set(oct, pkey_dig, diglen);
1470 X509_EXTENSION *ext = X509V3_EXT_i2d(NID_subject_key_identifier, 0,
1472 X509_add_ext(cert, ext, -1);
1473 X509_EXTENSION_free(ext);
1474 ASN1_OCTET_STRING_free(oct);
1478void WvX509::set_aki(
const WvX509 &cacert)
1480 CHECK_CERT_EXISTS_SET(
"aki");
1484 ASN1_OCTET_STRING *ikeyid = NULL;
1485 const X509_EXTENSION *src_ext;
1486 X509_EXTENSION *ext;
1487 int i = X509_get_ext_by_NID(cacert.cert, NID_subject_key_identifier, -1);
1488 if ((i >= 0) && (src_ext = X509_get_ext(cacert.cert, i)))
1489 ikeyid =
static_cast<ASN1_OCTET_STRING *
>(X509V3_EXT_d2i(
const_cast<X509_EXTENSION *
>(src_ext)));
1494 AUTHORITY_KEYID *akeyid = AUTHORITY_KEYID_new();
1495 akeyid->issuer = NULL;
1496 akeyid->serial = NULL;
1497 akeyid->keyid = ikeyid;
1498 ext = X509V3_EXT_i2d(NID_authority_key_identifier, 0, akeyid);
1499 X509_add_ext(cert, ext, -1);
1500 X509_EXTENSION_free(ext);
1501 AUTHORITY_KEYID_free(akeyid);
The basic interface which is included by all other XPLC interfaces and objects.
const T * get(size_t count)
Reads exactly the specified number of elements and returns a pointer to a storage location owned by t...
void put(const T *data, size_t count)
Writes the specified number of elements from the specified storage location into the buffer at its ta...
const T * peek(int offset, size_t count)
Returns a const pointer into the buffer at the specified offset to the specified number of elements w...
size_t used() const
Returns the number of elements in the buffer currently available for reading.
WvString getstr()
Returns the entire buffer as a null-terminated WvString.
void putch(int ch)
Puts a single character into the buffer as an int.
void putstr(WvStringParm str)
Copies a WvString into the buffer, excluding the null-terminator.
bool flushstrmem(WvStringParm instr, void *outmem, size_t *outlen, bool finish=false)
Flushes data through the encoder from a string to memory.
const char * cstr() const
return a (const char *) for this string.
A WvLog stream accepts log messages from applications and forwards them to all registered WvLogRcv's.
An RSA public key or public/private key pair that can be used for encryption.
This is a WvList of WvStrings, and is a really handy way to parse strings.
WvString join(const char *joinchars=" ") const
concatenates all elements of the list seperating on joinchars
void split(WvStringParm s, const char *splitchars=" \t\r\n", int limit=0)
split s and form a list ignoring splitchars (except at beginning and end) ie.
WvString popstr()
get the first string in the list, or an empty string if the list is empty.
WvString is an implementation of a simple and efficient printable-string class.
char * edit()
make the string editable, and return a non-const (char*)
X509 Class to handle certificates and their related functions.
virtual WvString errstr() const
Returns an error string if isok() is not true.
WvString get_ski() const
Get the Subject Key Info.
void set_policy_mapping(PolicyMapList &list)
Set the policy mappings for this certificate.
void set_policies(WvStringList &policy_oids)
Set the Certificate Policy OIDs in the certificate to that of the input array.
time_t get_notvalid_before() const
Return the not before and not after in a format we're more able to easily use.
bool signedbyca(WvX509 &cacert) const
Check the certificate in cert against the CA certificate in cacert.
void set_basic_constraints(bool ca, int pathlen)
Set the values in the basic constraints extension.
WvString get_serial(bool hex=false) const
get and set the serialNumber field of the certificate
WvString get_aki() const
Get the Authority key Info.
void get_ocsp(WvStringList &responders) const
Get a list of OCSP Responders for this certificate.
void get_ca_urls(WvStringList &urls) const
Get a list of urls that have the Certificate of the CA that issued this certificate.
WvX509()
Initialize a completely empty X509 Object with an X509 certificate that doesn't have anything it it....
virtual ~WvX509()
Destructor.
bool get_policy_mapping(PolicyMapList &list) const
Get the policy mappings for this certificate.
void set_crl_urls(WvStringList &urls)
Set the list of URLs that are valid CRL distribution points for this certificate.
void set_version()
Set the Certificate to use X509v3, since that's all modern PKI uses anyways :).
WvString get_ext_key_usage() const
Get and set the extendedKeyUsage field.
bool get_policies(WvStringList &policy_oids) const
Get any certificate Policy OIDs.
WvString get_subject() const
get and set the Subject field of the certificate
bool validate(WvX509 *cacert=NULL) const
Function to verify the validity of a certificate that has been placed in cert.
bool get_policy_constraints(int &require_explicit_policy, int &inhibit_policy_mapping) const
Get the values in the policy constraints extension.
bool get_basic_constraints(bool &ca, int &pathlen) const
Get the values in the basic constraints extension.
WvString get_fingerprint(const FprintMode mode=FingerSHA1) const
Get the certHash (fingerprint) of the certificate.
DumpMode
Type for the encode() and decode() methods.
bool issuedbyca(WvX509 &cacert) const
Check to see if the certificate in cert was issued by the CA certificate in cacert.
WvString get_crl_dp() const
get the CRL Distribution points if they exist, WvString::null if they don't.
void set_lifetime(long seconds)
Set the lifetime to be used for this certificate... the lifetime starts from the minute that the cert...
void set_pubkey(WvRSAKey &rsa_pubkey)
Set the public key of the certificate to the public key rsa_pubkey.
virtual void decode(const DumpMode mode, WvStringParm str)
Load the information from the format requested by mode into the class - this overwrites the certifica...
static WvString certreq(WvStringParm subject, const WvRSAKey &rsa)
Create a certificate request (PKCS#10) using this function.
bool operator!() const
The not operator returns true if !isok().
void set_policy_constraints(int require_explicit_policy, int inhibit_policy_mapping)
Set the values in the policy constraints extension.
WvString get_issuer() const
Get and set the Certificate Issuer (usually the CA who signed the certificate).
WvString get_aia() const
Get the authority info access information.
WvString get_altsubject() const
Return the Subject alt name if it exists, and WvString::null if it doesn't.
bool verify(WvBuf &original, WvStringParm signature) const
Verify that the contents of data were signed by the certificate currently in cert.
WvString get_key_usage() const
Get and set the keyUsage field.
WvString encode(const DumpMode mode) const
Return the information requested by mode.
void get_crl_urls(WvStringList &urls) const
Get a list of URLs that are valid CRL distribution points for this certificate.
void set_aia(WvStringList &ca_urls, WvStringList &responders)
Set a list of urls that have the Certificate of the CA that issued this certificate,...
WvString get_nsserver() const
get and set the Netscape SSL Server extension
virtual bool isok() const
Is the certificate object valid?
void hexify(char *obuf, const void *ibuf, size_t len)
Write the contents of the binary string of length 'len' pointed to by 'ibuf' into the output buffer '...
void unhexify(void *obuf, const char *ibuf)
Reverse the operation performed by hexify().
char * trim_string(char *string)
Trims whitespace from the beginning and end of the character string, including carriage return / line...
char * strlwr(char *string)
In-place modify a character string so that all contained letters are in lower case.
#define deletev
Remplacement for delete[].
#define UUID_MAP_END
Marks the end of an interface map.
#define UUID_MAP_BEGIN(component)
Start the interface map for "component".
#define UUID_MAP_ENTRY(iface)
Add an entry to an interface map.