WvStreams
wvx509.cc
1 /*
2  * Worldvisions Weaver Software:
3  * Copyright (C) 1997-2005 Net Integration Technologies, Inc.
4  *
5  * X.509 certificate management classes.
6  */
7 #include "wvx509.h"
8 #include "wvcrl.h"
9 #include "wvsslhacks.h"
10 #include "wvcrypto.h"
11 #include "wvstringlist.h"
12 #include "wvbase64.h"
13 #include "wvstrutils.h"
14 #include "wvautoconf.h"
15 
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>
21 
22 // enable this to add some extra debugging trace messages (this can be VERY
23 // verbose)
24 #if 0
25 # define TRACE(x, y...) debug(x, ## y);
26 #else
27 #ifndef _MSC_VER
28 # define TRACE(x, y...)
29 #else
30 # define TRACE
31 #endif
32 #endif
33 
34 // helper method to let us return and warn gracefully when getting/setting an
35 // element in a null certificate
36 static const char * warning_str_set
37  = "Tried to set %s, but certificate not ok.\n";
38 static const char * warning_str_get
39  = "Tried to get %s, but certificate not ok.\n";
40 #define CHECK_CERT_EXISTS_SET(x) \
41  if (!cert) { \
42  debug(WvLog::Warning, warning_str_set, x); \
43  return; \
44  }
45 #define CHECK_CERT_EXISTS_GET(x, y) \
46  if (!cert) { \
47  debug(WvLog::Warning, warning_str_get, x); \
48  return y; \
49  }
50 
51 
55 
56 static int ssl_init_count = 0;
57 
58 #if !HAVE_OPENSSL_POLICY_MAPPING
59 
60 // HACK: old versions of OpenSSL can't handle ERR_free_strings() being called
61 // more than once in the same process; the next wvssl_init won't work. So
62 // let's make sure to make a global variable that holds the refcount at 1
63 // even when all the objects go away, then clean it up at exit.
65 {
66 public:
68  {
69  wvssl_init();
70  }
71 
73  {
74  wvssl_free();
75  }
76 };
77 
78 WvSSL_Stupid_Refcount wvssl_stupid_refcount;
79 
80 #endif // !HAVE_OPENSSL_POLICY_MAPPING
81 
82 
83 void wvssl_init()
84 {
85  if (!ssl_init_count)
86  {
87  SSL_library_init();
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();
94  }
95 
96  ssl_init_count++;
97 }
98 
99 
100 void wvssl_free()
101 {
102  assert(ssl_init_count >= 1);
103  if (ssl_init_count >= 1)
104  ssl_init_count--;
105 
106  if (!ssl_init_count)
107  {
108  ERR_free_strings();
109  EVP_cleanup();
110  }
111 }
112 
113 
114 WvString wvssl_errstr()
115 {
116  char buf[256];
117  ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
118  buf[sizeof(buf)-1] = 0;
119  return buf;
120 }
121 
122 
123 WvX509::WvX509(X509 *_cert)
124  : debug("X509", WvLog::Debug5)
125 {
126  wvssl_init();
127  cert = _cert;
128 }
129 
130 
132  : debug("X509", WvLog::Debug5)
133 {
134  wvssl_init();
135  cert = NULL;
136 }
137 
138 
139 WvX509::WvX509(const WvX509 &x509)
140  : debug("X509", WvLog::Debug5)
141 {
142  wvssl_init();
143  if (x509.cert)
144  cert = X509_dup(x509.cert);
145  else
146  cert = NULL;
147 }
148 
149 
151 {
152  TRACE("Deleting.\n");
153 
154  if (cert)
155  X509_free(cert);
156 
157  wvssl_free();
158 }
159 
160 
161 
162 // The people who designed this garbage should be shot!
163 // Support old versions of openssl...
164 #ifndef NID_domainComponent
165 #define NID_domainComponent 391
166 #endif
167 
168 #ifndef NID_Domain
169 #define NID_Domain 392
170 #endif
171 
172 
173 // returns some approximation of the server's fqdn, or an empty string.
174 static WvString set_name_entry(X509_NAME *name, WvStringParm dn)
175 {
176  WvString fqdn(""), force_fqdn("");
177  X509_NAME_ENTRY *ne = NULL;
178  int count = 0, nid;
179 
180  WvStringList l;
181  l.split(dn, ",");
182 
183  // dn is of the form: c=ca,o=foo organization,dc=foo,dc=com
184  // (ie. name=value pairs separated by commas)
185  WvStringList::Iter i(l);
186  for (i.rewind(); i.next(); )
187  {
188  WvString s(*i), sid;
189  char *cptr, *value;
190 
191  cptr = s.edit();
192  value = strchr(cptr, '=');
193  if (value)
194  *value++ = 0;
195  else
196  value = (char*)"NULL";
197 
198  sid = strlwr(trim_string(cptr));
199 
200  if (sid == "c")
201  nid = NID_countryName;
202  else if (sid == "st")
203  nid = NID_stateOrProvinceName;
204  else if (sid == "l")
205  nid = NID_localityName;
206  else if (sid == "o")
207  nid = NID_organizationName;
208  else if (sid == "ou")
209  nid = NID_organizationalUnitName;
210  else if (sid == "cn")
211  {
212  nid = NID_commonName;
213  force_fqdn = value;
214  }
215  else if (sid == "dc")
216  {
217  nid = NID_domainComponent;
218  if (!!fqdn)
219  fqdn.append(".");
220  fqdn.append(value);
221  }
222  else if (sid == "domain")
223  {
224  nid = NID_Domain;
225  force_fqdn = value;
226  }
227  else if (sid == "email")
228  nid = NID_pkcs9_emailAddress;
229  else
230  nid = NID_domainComponent;
231 
232  // Sometimes we just want to parse dn into fqdn.
233  if (name == NULL)
234  continue;
235 
236  if (!ne)
237  ne = X509_NAME_ENTRY_create_by_NID(NULL, nid,
238  V_ASN1_APP_CHOOSE, (unsigned char *)value, -1);
239  else
240  X509_NAME_ENTRY_create_by_NID(&ne, nid,
241  V_ASN1_APP_CHOOSE, (unsigned char *)value, -1);
242  if (!ne)
243  continue;
244 
245  X509_NAME_add_entry(name, ne, count++, 0);
246  }
247 
248  X509_NAME_ENTRY_free(ne);
249 
250  if (!!force_fqdn)
251  return force_fqdn;
252 
253  return fqdn;
254 }
255 
256 
257 WvRSAKey *WvX509::get_rsa_pub() const
258 {
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);
263 }
264 
265 
266 WvString WvX509::certreq(WvStringParm subject, const WvRSAKey &rsa)
267 {
268  WvLog debug("X509::certreq", WvLog::Debug5);
269 
270  EVP_PKEY *pk = NULL;
271  X509_NAME *name = NULL;
272  X509_REQ *certreq = NULL;
273 
274  // double check RSA key
275  if (rsa.isok())
276  debug("RSA Key is fine.\n");
277  else
278  {
279  debug(WvLog::Warning, "RSA Key is bad");
280  return WvString::null;
281  }
282 
283  if ((pk=EVP_PKEY_new()) == NULL)
284  {
285  debug(WvLog::Warning,
286  "Error creating key handler for new certificate");
287  return WvString::null;
288  }
289 
290  if ((certreq=X509_REQ_new()) == NULL)
291  {
292  debug(WvLog::Warning, "Error creating new PKCS#10 object");
293  EVP_PKEY_free(pk);
294  return WvString::null;
295  }
296 
297  if (!EVP_PKEY_set1_RSA(pk, rsa.rsa))
298  {
299  debug(WvLog::Warning, "Error adding RSA keys to certificate");
300  X509_REQ_free(certreq);
301  EVP_PKEY_free(pk);
302  return WvString::null;
303  }
304 
305  X509_REQ_set_version(certreq, 0); /* version 1 */
306 
307  X509_REQ_set_pubkey(certreq, pk);
308 
309  name = X509_REQ_get_subject_name(certreq);
310 
311  debug("Creating Certificate request for %s\n", subject);
312  set_name_entry(name, subject);
313  X509_REQ_set_subject_name(certreq, name);
314  char *sub_name = X509_NAME_oneline(X509_REQ_get_subject_name(certreq),
315  0, 0);
316  debug("SubjectDN: %s\n", sub_name);
317  OPENSSL_free(sub_name);
318 
319  if (!X509_REQ_sign(certreq, pk, EVP_sha1()))
320  {
321  debug(WvLog::Warning, "Could not self sign the request");
322  X509_REQ_free(certreq);
323  EVP_PKEY_free(pk);
324  return WvString::null;
325  }
326 
327  int verify_result = X509_REQ_verify(certreq, pk);
328  if (verify_result == 0)
329  {
330  debug(WvLog::Warning, "Self signed request failed");
331  X509_REQ_free(certreq);
332  EVP_PKEY_free(pk);
333  return WvString::null;
334  }
335  else
336  {
337  debug("Self Signed Certificate Request verifies OK!\n");
338  }
339 
340  // Horribly involuted hack to get around the fact that the
341  // OpenSSL people are too braindead to have a PEM_write function
342  // that returns a char *
343  WvDynBuf retval;
344  BIO *bufbio = BIO_new(BIO_s_mem());
345  BUF_MEM *bm;
346 
347  PEM_write_bio_X509_REQ(bufbio, certreq);
348  BIO_get_mem_ptr(bufbio, &bm);
349  retval.put(bm->data, bm->length);
350 
351  X509_REQ_free(certreq);
352  EVP_PKEY_free(pk);
353  BIO_free(bufbio);
354 
355  return retval.getstr();
356 }
357 
358 
359 bool WvX509::validate(WvX509 *cacert) const
360 {
361  if (cert == NULL)
362  {
363  debug(WvLog::Warning, "Tried to validate certificate against CA, but "
364  "certificate is blank!\n");
365  return false;
366  }
367 
368  bool retval = true;
369 
370  // Check and make sure that the certificate is still valid
371  if (X509_cmp_current_time(X509_get_notAfter(cert)) < 0)
372  {
373  debug("Certificate has expired.\n");
374  retval = false;
375  }
376 
377  if (X509_cmp_current_time(X509_get_notBefore(cert)) > 0)
378  {
379  debug("Certificate is not yet valid.\n");
380  retval = false;
381  }
382 
383  if (cacert)
384  {
385  retval &= signedbyca(*cacert);
386  retval &= issuedbyca(*cacert);
387  }
388 
389  return retval;
390 }
391 
392 
393 bool WvX509::signedbyca(WvX509 &cacert) const
394 {
395  if (!cert || !cacert.cert)
396  {
397  debug(WvLog::Warning, "Tried to determine if certificate was signed "
398  "by CA, but either client or CA certificate (or both) are "
399  "blank.\n");
400  return false;
401  }
402 
403  EVP_PKEY *pkey = X509_get_pubkey(cacert.cert);
404  int result = X509_verify(cert, pkey);
405  EVP_PKEY_free(pkey);
406 
407  if (result < 0)
408  {
409  debug("Can't determine if we were signed by CA %s: %s\n",
410  cacert.get_subject(), wvssl_errstr());
411  return false;
412  }
413  bool issigned = (result > 0);
414 
415  debug("Certificate was%s signed by CA %s.\n", issigned ? "" : " NOT",
416  cacert.get_subject());
417 
418  return issigned;
419 }
420 
421 
422 bool WvX509::issuedbyca(WvX509 &cacert) const
423 {
424  if (!cert || !cacert.cert)
425  {
426  debug(WvLog::Warning, "Tried to determine if certificate was issued "
427  "by CA, but either client or CA certificate (or both) are "
428  "blank.\n");
429  return false;
430  }
431 
432  int ret = X509_check_issued(cacert.cert, cert);
433  debug("issuedbyca: %s==X509_V_OK(%s)\n", ret, X509_V_OK);
434  if (ret != X509_V_OK)
435  return false;
436 
437  return true;
438 }
439 
440 
442 {
443  WvDynBuf retval;
444  encode(mode, retval);
445  return retval.getstr();
446 }
447 
448 
449 void WvX509::encode(const DumpMode mode, WvBuf &buf) const
450 {
451  if (mode == CertFileDER || mode == CertFilePEM)
452  return; // file modes are no ops with encode
453 
454  if (!cert)
455  {
456  debug(WvLog::Warning, "Tried to encode certificate, but certificate "
457  "is blank!\n");
458  return;
459  }
460 
461  debug("Encoding X509 certificate.\n");
462 
463  if (mode == CertHex)
464  {
465  size_t size;
466  unsigned char *keybuf, *iend;
467  WvString enccert;
468 
469  size = i2d_X509(cert, NULL);
470  iend = keybuf = new unsigned char[size];
471  i2d_X509(cert, &iend);
472 
473  enccert.setsize(size * 2 +1);
474  ::hexify(enccert.edit(), keybuf, size);
475 
476  deletev keybuf;
477  buf.putstr(enccert);
478  }
479  else
480  {
481  BIO *bufbio = BIO_new(BIO_s_mem());
482  BUF_MEM *bm;
483 
484  if (mode == CertPEM)
485  PEM_write_bio_X509(bufbio, cert);
486  else if (mode == CertDER)
487  i2d_X509_bio(bufbio, cert);
488  else
489  debug(WvLog::Warning, "Tried to encode certificate with unknown "
490  "mode!\n");
491 
492  BIO_get_mem_ptr(bufbio, &bm);
493  buf.put(bm->data, bm->length);
494  BIO_free(bufbio);
495  }
496 }
497 
498 
499 void WvX509::decode(const DumpMode mode, WvStringParm str)
500 {
501  if (cert)
502  {
503  debug("Replacing an already existant X509 certificate.\n");
504  X509_free(cert);
505  cert = NULL;
506  }
507 
508  if (mode == CertFileDER)
509  {
510  BIO *bio = BIO_new(BIO_s_file());
511 
512  if (BIO_read_filename(bio, str.cstr()) <= 0)
513  {
514  debug(WvLog::Warning, "Open '%s': %s\n", str, wvssl_errstr());
515  BIO_free(bio);
516  return;
517  }
518 
519  if (!(cert = d2i_X509_bio(bio, NULL)))
520  debug(WvLog::Warning, "Import DER from '%s': %s\n",
521  str, wvssl_errstr());
522 
523  BIO_free(bio);
524  return;
525  }
526  else if (mode == CertFilePEM)
527  {
528  FILE *fp = fopen(str, "rb");
529  if (!fp)
530  {
531  int errnum = errno;
532  debug("Open '%s': %s\n", str, strerror(errnum));
533  return;
534  }
535 
536  if (!(cert = PEM_read_X509(fp, NULL, NULL, NULL)))
537  debug(WvLog::Warning, "Import PEM from '%s': %s\n",
538  str, wvssl_errstr());
539 
540  fclose(fp);
541  return;
542  }
543  else if (mode == CertHex)
544  {
545  int hexbytes = str.len();
546  int bufsize = hexbytes/2;
547  unsigned char *certbuf = new unsigned char[bufsize];
548  unsigned char *cp = certbuf;
549  X509 *tmpcert;
550 
551  ::unhexify(certbuf, str);
552  tmpcert = cert = X509_new();
553  cert = wv_d2i_X509(&tmpcert, &cp, bufsize);
554  delete[] certbuf;
555  return;
556  }
557 
558  // we use the buffer decode functions for everything else
559  WvDynBuf buf;
560  buf.putstr(str);
561  decode(mode, buf);
562 }
563 
564 
565 void WvX509::decode(const DumpMode mode, WvBuf &encoded)
566 {
567  if (cert)
568  {
569  debug("Replacing an already existant X509 certificate.\n");
570  X509_free(cert);
571  cert = NULL;
572  }
573 
574  if (mode == CertHex || mode == CertFileDER || mode == CertFilePEM)
575  decode(mode, encoded.getstr());
576  else
577  {
578  BIO *membuf = BIO_new(BIO_s_mem());
579  BIO_write(membuf, encoded.get(encoded.used()), encoded.used());
580 
581  if (mode == CertPEM)
582  cert = PEM_read_bio_X509(membuf, NULL, NULL, NULL);
583  else if (mode == CertDER)
584  cert = d2i_X509_bio(membuf, NULL);
585  else
586  debug(WvLog::Warning, "Tried to decode certificate with unknown "
587  "mode!\n");
588 
589  BIO_free_all(membuf);
590  }
591 }
592 
593 
595 {
596  CHECK_CERT_EXISTS_GET("issuer", WvString::null);
597 
598  char *name = X509_NAME_oneline(X509_get_issuer_name(cert),0,0);
599  WvString retval(name);
600  OPENSSL_free(name);
601  return retval;
602 }
603 
604 
605 void WvX509::set_issuer(WvStringParm issuer)
606 {
607  CHECK_CERT_EXISTS_SET("issuer");
608 
609  X509_NAME *name = X509_get_issuer_name(cert);
610  set_name_entry(name, issuer);
611  X509_set_issuer_name(cert, name);
612 }
613 
614 
615 void WvX509::set_issuer(const WvX509 &cacert)
616 {
617  CHECK_CERT_EXISTS_SET("issuer");
618 
619  X509_NAME *casubj = X509_get_subject_name(cacert.cert);
620  X509_set_issuer_name(cert, casubj);
621 }
622 
623 
625 {
626  CHECK_CERT_EXISTS_GET("subject", WvString::null);
627 
628  char *name = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
629  WvString retval(name);
630  OPENSSL_free(name);
631  return retval;
632 }
633 
634 
635 void WvX509::set_subject(WvStringParm subject)
636 {
637  CHECK_CERT_EXISTS_SET("subject");
638 
639  X509_NAME *name = X509_get_subject_name(cert);
640  set_name_entry(name, subject);
641  X509_set_subject_name(cert, name);
642 }
643 
644 
645 void WvX509::set_subject(X509_NAME *name)
646 {
647  CHECK_CERT_EXISTS_SET("subject");
648 
649  X509_set_subject_name(cert, name);
650 }
651 
652 
654 {
655  CHECK_CERT_EXISTS_SET("pubkey");
656 
657  EVP_PKEY *pk = EVP_PKEY_new();
658  assert(pk);
659 
660  // Assign RSA Key from WvRSAKey into stupid package that OpenSSL needs
661  if (!EVP_PKEY_set1_RSA(pk, _rsa.rsa))
662  {
663  debug("Error adding RSA keys to certificate.\n");
664  return;
665  }
666 
667  X509_set_pubkey(cert, pk);
668 
669  EVP_PKEY_free(pk);
670 }
671 
672 
673 
674 void WvX509::set_nsserver(WvStringParm servername)
675 {
676  CHECK_CERT_EXISTS_SET("nsserver");
677 
678  WvString fqdn;
679 
680  // FQDN cannot have a = in it, therefore it
681  // must be a distinguished name :)
682  if (strchr(servername, '='))
683  fqdn = set_name_entry(NULL, servername);
684  else
685  fqdn = servername;
686 
687  if (!fqdn)
688  fqdn = "null.noname.null";
689 
690  debug("Setting Netscape SSL server name extension to '%s'.\n", fqdn);
691 
692  // Add in the netscape-specific server extension
693  set_extension(NID_netscape_cert_type, "server");
694  set_extension(NID_netscape_ssl_server_name, fqdn);
695 }
696 
697 
699 {
700  return get_extension(NID_netscape_ssl_server_name);
701 }
702 
703 
705 {
706  CHECK_CERT_EXISTS_GET("serial", WvString::null);
707 
708  BIGNUM *bn = BN_new();
709  bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), bn);
710  char * c;
711  if (hex)
712  c = BN_bn2hex(bn);
713  else
714  c = BN_bn2dec(bn);
715  WvString ret("%s", c);
716  OPENSSL_free(c);
717  BN_free(bn);
718  return ret;
719 }
720 
721 
723 {
724  CHECK_CERT_EXISTS_SET("version");
725 
726  X509_set_version(cert, 0x2);
727 }
728 
729 
730 void WvX509::set_serial(long serial)
731 {
732  CHECK_CERT_EXISTS_SET("serial");
733 
734  ASN1_INTEGER_set(X509_get_serialNumber(cert), serial);
735 }
736 
737 
739 {
740  return get_extension(NID_crl_distribution_points);
741 }
742 
743 
744 void WvX509::set_lifetime(long seconds)
745 {
746  CHECK_CERT_EXISTS_SET("lifetime");
747 
748  // Set the NotBefore time to now.
749  X509_gmtime_adj(X509_get_notBefore(cert), 0);
750 
751  // Now + 10 years... should be shorter, but since we don't currently
752  // have a set of routines to refresh the certificates, make it
753  // REALLY long.
754  X509_gmtime_adj(X509_get_notAfter(cert), seconds);
755 }
756 
757 
758 void WvX509::set_key_usage(WvStringParm values)
759 {
760  set_extension(NID_key_usage, values);
761 }
762 
763 
765 {
766  return get_extension(NID_key_usage);
767 }
768 
769 
770 void WvX509::set_ext_key_usage(WvStringParm values)
771 {
772  set_extension(NID_ext_key_usage, values);
773 }
774 
775 
777 {
778  return get_extension(NID_ext_key_usage);
779 }
780 
781 
783 {
784  return get_extension(NID_subject_alt_name);
785 }
786 
787 
788 bool WvX509::get_basic_constraints(bool &ca, int &pathlen) const
789 {
790  CHECK_CERT_EXISTS_GET("basic constraints", false);
791 
792  BASIC_CONSTRAINTS *constraints = NULL;
793  int i;
794 
795  constraints = static_cast<BASIC_CONSTRAINTS *>
796  (X509_get_ext_d2i(cert, NID_basic_constraints, &i, NULL));
797  if (constraints)
798  {
799  ca = constraints->ca;
800  if (constraints->pathlen)
801  {
802  if ((constraints->pathlen->type == V_ASN1_NEG_INTEGER) || !ca)
803  {
804  debug("Path length type not valid when getting basic "
805  "constraints.\n");
806  BASIC_CONSTRAINTS_free(constraints);
807  pathlen = 0;
808  return false;
809  }
810 
811  pathlen = ASN1_INTEGER_get(constraints->pathlen);
812  }
813  else
814  pathlen = (-1);
815 
816  BASIC_CONSTRAINTS_free(constraints);
817  return true;
818  }
819 
820  debug("Basic constraints extension not present.\n");
821  return false;
822 }
823 
824 
825 void WvX509::set_basic_constraints(bool ca, int pathlen)
826 {
827  CHECK_CERT_EXISTS_SET("basic constraints");
828 
829  BASIC_CONSTRAINTS *constraints = BASIC_CONSTRAINTS_new();
830 
831  constraints->ca = static_cast<int>(ca);
832  if (pathlen != (-1))
833  {
834  ASN1_INTEGER *i = ASN1_INTEGER_new();
835  ASN1_INTEGER_set(i, pathlen);
836  constraints->pathlen = i;
837  }
838 
839  X509_EXTENSION *ex = X509V3_EXT_i2d(NID_basic_constraints, 0,
840  constraints);
841  while (int idx = X509_get_ext_by_NID(cert, NID_basic_constraints, 0) >= 0)
842  {
843  debug("Found extension at idx %s\n", idx);
844  X509_EXTENSION *tmpex = X509_delete_ext(cert, idx);
845  X509_EXTENSION_free(tmpex);
846  }
847 
848  X509_add_ext(cert, ex, NID_basic_constraints);
849  X509_EXTENSION_free(ex);
850  BASIC_CONSTRAINTS_free(constraints);
851 }
852 
853 
854 /*
855  * These functions are optional to the API. If OpenSSL doesn't support them,
856  * we simply won't include them here, and apps that need them won't compile.
857  */
858 #ifdef HAVE_OPENSSL_POLICY_MAPPING
859 
860 bool WvX509::get_policy_constraints(int &require_explicit_policy,
861  int &inhibit_policy_mapping) const
862 {
863  CHECK_CERT_EXISTS_GET("policy constraints", false);
864 
865  POLICY_CONSTRAINTS *constraints = NULL;
866  int i;
867 
868  constraints = static_cast<POLICY_CONSTRAINTS *>(X509_get_ext_d2i(
869  cert, NID_policy_constraints,
870  &i, NULL));
871  if (constraints)
872  {
873  if (constraints->requireExplicitPolicy)
874  require_explicit_policy = ASN1_INTEGER_get(
875  constraints->requireExplicitPolicy);
876  else
877  require_explicit_policy = (-1);
878 
879  if (constraints->inhibitPolicyMapping)
880  inhibit_policy_mapping = ASN1_INTEGER_get(
881  constraints->inhibitPolicyMapping);
882  else
883  inhibit_policy_mapping = (-1);
884  POLICY_CONSTRAINTS_free(constraints);
885  return true;
886  }
887 
888  return false;
889 }
890 
891 
892 void WvX509::set_policy_constraints(int require_explicit_policy,
893  int inhibit_policy_mapping)
894 {
895  CHECK_CERT_EXISTS_SET("policy constraints");
896 
897  POLICY_CONSTRAINTS *constraints = POLICY_CONSTRAINTS_new();
898 
899  ASN1_INTEGER *i = ASN1_INTEGER_new();
900  ASN1_INTEGER_set(i, require_explicit_policy);
901  constraints->requireExplicitPolicy = i;
902  i = ASN1_INTEGER_new();
903  ASN1_INTEGER_set(i, inhibit_policy_mapping);
904  constraints->inhibitPolicyMapping = i;
905 
906  X509_EXTENSION *ex = X509V3_EXT_i2d(NID_policy_constraints, 0,
907  constraints);
908  X509_add_ext(cert, ex, -1);
909  X509_EXTENSION_free(ex);
910  POLICY_CONSTRAINTS_free(constraints);
911 }
912 
913 
914 bool WvX509::get_policy_mapping(PolicyMapList &list) const
915 {
916  CHECK_CERT_EXISTS_GET("policy mapping", false);
917 
918  POLICY_MAPPINGS *mappings = NULL;
919  POLICY_MAPPING *map = NULL;
920  int i;
921 
922  mappings = static_cast<POLICY_MAPPINGS *>(X509_get_ext_d2i(
923  cert, NID_policy_mappings,
924  &i, NULL));
925  if (!mappings)
926  return false;
927 
928  const int POLICYID_MAXLEN = 80;
929  char tmp1[80];
930  char tmp2[80];
931  for(int j = 0; j < sk_POLICY_MAPPING_num(mappings); j++)
932  {
933  map = sk_POLICY_MAPPING_value(mappings, j);
934  OBJ_obj2txt(tmp1, POLICYID_MAXLEN, map->issuerDomainPolicy, true);
935  OBJ_obj2txt(tmp2, POLICYID_MAXLEN, map->subjectDomainPolicy, true);
936  list.append(new PolicyMap(tmp1, tmp2), true);
937  }
938 
939  sk_POLICY_MAPPING_pop_free(mappings, POLICY_MAPPING_free);
940 
941  return true;
942 }
943 
944 
945 void WvX509::set_policy_mapping(PolicyMapList &list)
946 {
947  CHECK_CERT_EXISTS_SET("policy mapping");
948 
949  POLICY_MAPPINGS *maps = sk_POLICY_MAPPING_new_null();
950 
951  PolicyMapList::Iter i(list);
952  for (i.rewind(); i.next();)
953  {
954  POLICY_MAPPING *map = POLICY_MAPPING_new();
955  map->issuerDomainPolicy = OBJ_txt2obj(i().issuer_domain.cstr(), 0);
956  map->subjectDomainPolicy = OBJ_txt2obj(i().subject_domain.cstr(), 0);
957  sk_POLICY_MAPPING_push(maps, map);
958  printf("Push!\n");
959  }
960 
961  X509_EXTENSION *ex = X509V3_EXT_i2d(NID_policy_mappings, 0, maps);
962  X509_add_ext(cert, ex, -1);
963  X509_EXTENSION_free(ex);
964  sk_POLICY_MAPPING_pop_free(maps, POLICY_MAPPING_free);
965 }
966 
967 #endif // HAVE_OPENSSL_POLICY_MAPPING
968 
969 
970 static void add_aia(WvStringParm type, WvString identifier,
971  AUTHORITY_INFO_ACCESS *ainfo)
972 {
973  ACCESS_DESCRIPTION *acc = ACCESS_DESCRIPTION_new();
974  sk_ACCESS_DESCRIPTION_push(ainfo, acc);
975  acc->method = OBJ_txt2obj(type.cstr(), 0);
976  acc->location->type = GEN_URI;
977  acc->location->d.ia5 = ASN1_IA5STRING_new();
978  unsigned char *cident
979  = reinterpret_cast<unsigned char *>(identifier.edit());
980  ASN1_STRING_set(acc->location->d.ia5, cident, identifier.len());
981 }
982 
983 
985  WvStringList &responders)
986 {
987  CHECK_CERT_EXISTS_SET("aia");
988 
989  AUTHORITY_INFO_ACCESS *ainfo = sk_ACCESS_DESCRIPTION_new_null();
990 
991  WvStringList::Iter i(ca_urls);
992  for (i.rewind(); i.next();)
993  add_aia("caIssuers", i(), ainfo);
994 
995  WvStringList::Iter j(responders);
996  for (j.rewind(); j.next();)
997  add_aia("OCSP", j(), ainfo);
998 
999  X509_EXTENSION *ex = X509V3_EXT_i2d(NID_info_access, 0, ainfo);
1000  X509_add_ext(cert, ex, -1);
1001  X509_EXTENSION_free(ex);
1002  sk_ACCESS_DESCRIPTION_pop_free(ainfo, ACCESS_DESCRIPTION_free);
1003 }
1004 
1005 
1007 {
1008  return get_extension(NID_info_access);
1009 }
1010 
1011 
1012 static void parse_stack(WvStringParm ext, WvStringList &list,
1013  WvStringParm prefix)
1014 {
1015  WvStringList stack;
1016  stack.split(ext, ";\n");
1017  WvStringList::Iter i(stack);
1018  for (i.rewind();i.next();)
1019  {
1020  WvString stack_entry(*i);
1021  if (strstr(stack_entry, prefix))
1022  {
1023  WvString uri(stack_entry.edit() + prefix.len());
1024  list.append(uri);
1025  }
1026  }
1027 }
1028 
1029 
1030 void WvX509::get_ocsp(WvStringList &responders) const
1031 {
1032  parse_stack(get_aia(), responders, "OCSP - URI:");
1033 }
1034 
1035 
1037 {
1038  parse_stack(get_aia(), urls, "CA Issuers - URI:");
1039 }
1040 
1041 
1043 {
1044  parse_stack(get_crl_dp(), urls, "URI:");
1045 }
1046 
1047 
1049 {
1050  CHECK_CERT_EXISTS_SET("CRL urls");
1051 
1052  STACK_OF(DIST_POINT) *crldp = sk_DIST_POINT_new_null();
1053  WvStringList::Iter i(urls);
1054  for (i.rewind(); i.next();)
1055  {
1056  DIST_POINT *point = DIST_POINT_new();
1057  sk_DIST_POINT_push(crldp, point);
1058 
1059  GENERAL_NAMES *uris = GENERAL_NAMES_new();
1060  GENERAL_NAME *uri = GENERAL_NAME_new();
1061  uri->type = GEN_URI;
1062  uri->d.ia5 = ASN1_IA5STRING_new();
1063  unsigned char *cident
1064  = reinterpret_cast<unsigned char *>(i().edit());
1065  ASN1_STRING_set(uri->d.ia5, cident, i().len());
1066  sk_GENERAL_NAME_push(uris, uri);
1067 
1068  point->distpoint = DIST_POINT_NAME_new();
1069  point->distpoint->name.fullname = uris;
1070  point->distpoint->type = 0;
1071  }
1072 
1073  X509_EXTENSION *ex = X509V3_EXT_i2d(NID_crl_distribution_points, 0, crldp);
1074  X509_add_ext(cert, ex, -1);
1075  X509_EXTENSION_free(ex);
1076  sk_DIST_POINT_pop_free(crldp, DIST_POINT_free);
1077 }
1078 
1079 
1080 bool WvX509::get_policies(WvStringList &policy_oids) const
1081 {
1082  CHECK_CERT_EXISTS_GET("policies", false);
1083 
1084  int critical;
1085  CERTIFICATEPOLICIES * policies = static_cast<CERTIFICATEPOLICIES *>(
1086  X509_get_ext_d2i(cert, NID_certificate_policies, &critical, NULL));
1087  if (policies)
1088  {
1089  for (int i = 0; i < sk_POLICYINFO_num(policies); i++)
1090  {
1091  POLICYINFO * policy = sk_POLICYINFO_value(policies, i);
1092  const int POLICYID_MAXLEN = 80;
1093 
1094  char policyid[POLICYID_MAXLEN];
1095  OBJ_obj2txt(policyid, POLICYID_MAXLEN, policy->policyid,
1096  true); // don't substitute human-readable names
1097  policy_oids.append(policyid);
1098  }
1099 
1100  sk_POLICYINFO_pop_free(policies, POLICYINFO_free);
1101  return true;
1102  }
1103 
1104  return false;
1105 }
1106 
1107 
1109 {
1110  CHECK_CERT_EXISTS_SET("policies");
1111 
1112  STACK_OF(POLICYINFO) *sk_pinfo = sk_POLICYINFO_new_null();
1113 
1114  WvStringList::Iter i(policy_oids);
1115  for (i.rewind(); i.next();)
1116  {
1117  ASN1_OBJECT *pobj = OBJ_txt2obj(i(), 0);
1118  POLICYINFO *pol = POLICYINFO_new();
1119  pol->policyid = pobj;
1120  sk_POLICYINFO_push(sk_pinfo, pol);
1121  }
1122 
1123 #if 0
1124  // this code would let you set URL information to a policy
1125  // qualifier
1126  POLICYQUALINFO *qual = NULL;
1127  WvString url(_url);
1128  if (!!url)
1129  {
1130  pol->qualifiers = sk_POLICYQUALINFO_new_null();
1131  qual = POLICYQUALINFO_new();
1132  qual->pqualid = OBJ_nid2obj(NID_id_qt_cps);
1133  qual->d.cpsouri = M_ASN1_IA5STRING_new();
1134  ASN1_STRING_set(qual->d.cpsuri, url.edit(), url.len());
1135  sk_POLICYQUALINFO_push(pol->qualifiers, qual);
1136  }
1137 #endif
1138 
1139  X509_EXTENSION *ex = X509V3_EXT_i2d(NID_certificate_policies, 0,
1140  sk_pinfo);
1141  X509_add_ext(cert, ex, -1);
1142  X509_EXTENSION_free(ex);
1143  sk_POLICYINFO_pop_free(sk_pinfo, POLICYINFO_free);
1144 }
1145 
1146 
1147 WvString WvX509::get_extension(int nid) const
1148 {
1149  CHECK_CERT_EXISTS_GET("extension", WvString::null);
1150 
1151  WvString retval = WvString::null;
1152 
1153  int index = X509_get_ext_by_NID(cert, nid, -1);
1154  if (index >= 0)
1155  {
1156  X509_EXTENSION *ext = X509_get_ext(cert, index);
1157 
1158  if (ext)
1159  {
1160  X509V3_EXT_METHOD *method = (X509V3_EXT_METHOD *) X509V3_EXT_get(ext);
1161  ASN1_OCTET_STRING *ext_data_str = X509_EXTENSION_get_data(ext);
1162  if (!method)
1163  {
1164  WvDynBuf buf;
1165  buf.put(ext_data_str->data, ext_data_str->length);
1166  retval = buf.getstr();
1167  }
1168  else
1169  {
1170  void *ext_data = NULL;
1171  // we NEED to use a temporary pointer for ext_value_data,
1172  // as openssl's ASN1_item_d2i will muck around with it,
1173  // even though it's const (at least as of version 0.9.8e).
1174  // gah.
1175 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
1176  const unsigned char * ext_value_data = ext_data_str->data;
1177 #else
1178  unsigned char *ext_value_data = ext->value->data;
1179 #endif
1180  if (method->it)
1181  {
1182  ext_data = ASN1_item_d2i(NULL, &ext_value_data,
1183  ext_data_str->length,
1184  ASN1_ITEM_ptr(method->it));
1185  TRACE("Applied generic conversion!\n");
1186  }
1187  else
1188  {
1189  ext_data = method->d2i(NULL, &ext_value_data,
1190  ext_data_str->length);
1191  TRACE("Applied method specific conversion!\n");
1192  }
1193 
1194  if (method->i2s)
1195  {
1196  TRACE("String Extension!\n");
1197  char *s = method->i2s(method, ext_data);
1198  retval = s;
1199  OPENSSL_free(s);
1200  }
1201  else if (method->i2v)
1202  {
1203  TRACE("Stack Extension!\n");
1204  CONF_VALUE *val = NULL;
1205  STACK_OF(CONF_VALUE) *svals = NULL;
1206  svals = method->i2v(method, ext_data, NULL);
1207  if (!sk_CONF_VALUE_num(svals))
1208  retval = "EMPTY";
1209  else
1210  {
1211  WvStringList list;
1212  for(int i = 0; i < sk_CONF_VALUE_num(svals); i++)
1213  {
1214  val = sk_CONF_VALUE_value(svals, i);
1215  if (!val->name)
1216  list.append(WvString(val->value));
1217  else if (!val->value)
1218  list.append(WvString(val->name));
1219  else
1220  {
1221  WvString pair("%s:%s", val->name, val->value);
1222  list.append(pair);
1223  }
1224  }
1225  retval = list.join(";\n");
1226  }
1227  sk_CONF_VALUE_pop_free(svals, X509V3_conf_free);
1228  }
1229  else if (method->i2r)
1230  {
1231  TRACE("Raw Extension!\n");
1232  WvDynBuf retvalbuf;
1233  BIO *bufbio = BIO_new(BIO_s_mem());
1234  BUF_MEM *bm;
1235  method->i2r(method, ext_data, bufbio, 0);
1236  BIO_get_mem_ptr(bufbio, &bm);
1237  retvalbuf.put(bm->data, bm->length);
1238  BIO_free(bufbio);
1239  retval = retvalbuf.getstr();
1240  }
1241 
1242  if (method->it)
1243  ASN1_item_free((ASN1_VALUE *)ext_data,
1244  ASN1_ITEM_ptr(method->it));
1245  else
1246  method->ext_free(ext_data);
1247 
1248  }
1249  }
1250  }
1251  else
1252  {
1253  TRACE("Extension not present!\n");
1254  }
1255 
1256  if (!!retval)
1257  TRACE("Returning: %s\n", retval);
1258 
1259  return retval;
1260 }
1261 
1262 
1263 void WvX509::set_extension(int nid, WvStringParm _values)
1264 {
1265  CHECK_CERT_EXISTS_SET("extension");
1266 
1267  // first we check to see if the extension already exists, if so we need to
1268  // kill it
1269  int index = X509_get_ext_by_NID(cert, nid, -1);
1270  if (index >= 0)
1271  {
1272  X509_EXTENSION *ex = X509_delete_ext(cert, index);
1273  X509_EXTENSION_free(ex);
1274  }
1275 
1276  // now set the extension
1277  WvString values(_values);
1278  X509_EXTENSION *ex = NULL;
1279  ex = X509V3_EXT_conf_nid(NULL, NULL, nid, values.edit());
1280  X509_add_ext(cert, ex, -1);
1281  X509_EXTENSION_free(ex);
1282 }
1283 
1284 
1285 bool WvX509::isok() const
1286 {
1287  return cert;
1288 }
1289 
1290 
1292 {
1293  return !isok();
1294 }
1295 
1296 
1298 {
1299  if (!cert)
1300  return "No certificate.";
1301 
1302  return WvString::empty;
1303 }
1304 
1305 
1306 bool WvX509::verify(WvStringParm original, WvStringParm signature) const
1307 {
1308  WvDynBuf buf;
1309  buf.putstr(original);
1310  return verify(buf, signature);
1311 }
1312 
1313 
1314 bool WvX509::verify(WvBuf &original, WvStringParm signature) const
1315 {
1316  unsigned char sig_buf[4096];
1317  size_t sig_size = sizeof(sig_buf);
1318  WvBase64Decoder().flushstrmem(signature, sig_buf, &sig_size, true);
1319 
1320  EVP_PKEY *pk = X509_get_pubkey(cert);
1321  if (!pk)
1322  return false;
1323 
1324  /* Verify the signature */
1325  EVP_MD_CTX *sig_ctx = EVP_MD_CTX_new();
1326  EVP_VerifyInit(sig_ctx, EVP_sha1());
1327  EVP_VerifyUpdate(sig_ctx, original.peek(0, original.used()),
1328  original.used());
1329  int sig_err = EVP_VerifyFinal(sig_ctx, sig_buf, sig_size, pk);
1330  EVP_PKEY_free(pk);
1331  EVP_MD_CTX_free(sig_ctx); // Again, not my fault...
1332  if (sig_err != 1)
1333  {
1334  debug("Verify failed!\n");
1335  return false;
1336  }
1337  else
1338  return true;
1339 }
1340 
1341 
1342 static time_t ASN1_TIME_to_time_t(ASN1_TIME *t)
1343 {
1344  struct tm newtime;
1345  char *p = NULL;
1346  char d[18];
1347  memset(&d,'\0',sizeof(d));
1348  memset(&newtime,'\0',sizeof newtime);
1349 
1350  if (t->type == V_ASN1_GENERALIZEDTIME)
1351  {
1352  // For time values >= 2050, OpenSSL uses
1353  // ASN1_GENERALIZEDTIME - which we'll worry about
1354  // later.
1355  return 0;
1356  }
1357 
1358  p = (char *)t->data;
1359  sscanf(p,"%2s%2s%2s%2s%2s%2sZ", d, &d[3], &d[6], &d[9], &d[12], &d[15]);
1360 
1361  int year = strtol(d, (char **)NULL, 10);
1362  if (year < 49)
1363  year += 100;
1364  else
1365  year += 50;
1366 
1367  newtime.tm_year = year;
1368  newtime.tm_mon = strtol(&d[3], (char **)NULL, 10) - 1;
1369  newtime.tm_mday = strtol(&d[6], (char **)NULL, 10);
1370  newtime.tm_hour = strtol(&d[9], (char **)NULL, 10);
1371  newtime.tm_min = strtol(&d[12], (char **)NULL, 10);
1372  newtime.tm_sec = strtol(&d[15], (char **)NULL, 10);
1373 
1374  return mktime(&newtime);
1375 }
1376 
1377 
1379 {
1380  CHECK_CERT_EXISTS_GET("not valid before", 0);
1381 
1382  return ASN1_TIME_to_time_t(X509_get_notBefore(cert));
1383 }
1384 
1385 
1386 time_t WvX509::get_notvalid_after() const
1387 {
1388  CHECK_CERT_EXISTS_GET("not valid after", 0);
1389 
1390  return ASN1_TIME_to_time_t(X509_get_notAfter(cert));
1391 }
1392 
1393 
1395 {
1396  CHECK_CERT_EXISTS_GET("ski", WvString::null);
1397 
1398  return get_extension(NID_subject_key_identifier);
1399 }
1400 
1401 
1403 {
1404  CHECK_CERT_EXISTS_GET("aki", WvString::null);
1405 
1406  WvStringList aki_list;
1407  parse_stack(get_extension(NID_authority_key_identifier), aki_list,
1408  "keyid:");
1409  if (aki_list.count())
1410  return aki_list.popstr();
1411 
1412  return WvString::null;
1413 }
1414 
1415 
1416 WvString WvX509::get_fingerprint(const FprintMode mode) const
1417 {
1418  CHECK_CERT_EXISTS_GET("fingerprint", WvString::null);
1419 
1420  /* Default to SHA-1 because OpenSSL does too */
1421  const EVP_MD *digest = EVP_sha1();
1422  if (mode == FingerMD5)
1423  digest = EVP_md5();
1424 
1425  unsigned char md[EVP_MAX_MD_SIZE];
1426  unsigned int n;
1427  if (!X509_digest(cert, digest, md, &n))
1428  {
1429  errno = -ENOMEM;
1430  debug("get_fingerprint: Out of memory\n");
1431  return WvString::null;
1432  }
1433 
1434  WvDynBuf store;
1435  char buf[3];
1436  unsigned int i = 0;
1437  do {
1438  sprintf(buf, "%02X", md[i]);
1439  store.putstr(buf);
1440  } while (++i < n && (store.putch(':'), 1));
1441 
1442  return store.getstr();
1443 }
1444 
1445 
1446 void WvX509::set_ski()
1447 {
1448  CHECK_CERT_EXISTS_SET("ski");
1449 
1450  ASN1_OCTET_STRING *oct = ASN1_OCTET_STRING_new();
1451  ASN1_BIT_STRING *pk = X509_get0_pubkey_bitstr(cert);
1452  unsigned char pkey_dig[EVP_MAX_MD_SIZE];
1453  unsigned int diglen;
1454 
1455  EVP_Digest(pk->data, pk->length, pkey_dig, &diglen, EVP_sha1(), NULL);
1456 
1457  ASN1_OCTET_STRING_set(oct, pkey_dig, diglen);
1458  X509_EXTENSION *ext = X509V3_EXT_i2d(NID_subject_key_identifier, 0,
1459  oct);
1460  X509_add_ext(cert, ext, -1);
1461  X509_EXTENSION_free(ext);
1462  ASN1_OCTET_STRING_free(oct);
1463 }
1464 
1465 
1466 void WvX509::set_aki(const WvX509 &cacert)
1467 {
1468  CHECK_CERT_EXISTS_SET("aki");
1469 
1470  // can't set a meaningful AKI for subordinate certification without the
1471  // parent having an SKI
1472  ASN1_OCTET_STRING *ikeyid = NULL;
1473  X509_EXTENSION *ext;
1474  int i = X509_get_ext_by_NID(cacert.cert, NID_subject_key_identifier, -1);
1475  if ((i >= 0) && (ext = X509_get_ext(cacert.cert, i)))
1476  ikeyid = static_cast<ASN1_OCTET_STRING *>(X509V3_EXT_d2i(ext));
1477 
1478  if (!ikeyid)
1479  return;
1480 
1481  AUTHORITY_KEYID *akeyid = AUTHORITY_KEYID_new();
1482  akeyid->issuer = NULL;
1483  akeyid->serial = NULL;
1484  akeyid->keyid = ikeyid;
1485  ext = X509V3_EXT_i2d(NID_authority_key_identifier, 0, akeyid);
1486  X509_add_ext(cert, ext, -1);
1487  X509_EXTENSION_free(ext);
1488  AUTHORITY_KEYID_free(akeyid);
1489 }
1490 
WvString::edit
char * edit()
make the string editable, and return a non-const (char*)
Definition: wvstring.h:397
WvX509::get_notvalid_before
time_t get_notvalid_before() const
Return the not before and not after in a format we're more able to easily use.
Definition: wvx509.cc:1378
WvX509::set_lifetime
void set_lifetime(long seconds)
Set the lifetime to be used for this certificate...
Definition: wvx509.cc:744
WvBufBaseCommonImpl::get
const T * get(size_t count)
Reads exactly the specified number of elements and returns a pointer to a storage location owned by t...
Definition: wvbufbase.h:114
WvX509::get_ski
WvString get_ski() const
Get the Subject Key Info.
Definition: wvx509.cc:1394
WvBase64Decoder
A base 64 decoder.
Definition: wvbase64.h:49
WvX509::verify
bool verify(WvBuf &original, WvStringParm signature) const
Verify that the contents of data were signed by the certificate currently in cert.
Definition: wvx509.cc:1314
WvX509::get_fingerprint
WvString get_fingerprint(const FprintMode mode=FingerSHA1) const
Get the certHash (fingerprint) of the certificate.
Definition: wvx509.cc:1416
WvX509::get_policy_mapping
bool get_policy_mapping(PolicyMapList &list) const
Get the policy mappings for this certificate.
WvX509::get_basic_constraints
bool get_basic_constraints(bool &ca, int &pathlen) const
Get the values in the basic constraints extension.
Definition: wvx509.cc:788
WvStringList::popstr
WvString popstr()
get the first string in the list, or an empty string if the list is empty.
Definition: wvstringlist.cc:55
WvX509::set_basic_constraints
void set_basic_constraints(bool ca, int pathlen)
Set the values in the basic constraints extension.
Definition: wvx509.cc:825
WvX509
X509 Class to handle certificates and their related functions.
Definition: wvx509.h:41
WvX509::decode
virtual void decode(const DumpMode mode, WvStringParm str)
Load the information from the format requested by mode into the class - this overwrites the certifica...
Definition: wvx509.cc:499
WvX509::set_policies
void set_policies(WvStringList &policy_oids)
Set the Certificate Policy OIDs in the certificate to that of the input array.
Definition: wvx509.cc:1108
WvX509::DumpMode
DumpMode
Type for the encode() and decode() methods.
Definition: wvx509.h:56
WvX509::certreq
static WvString certreq(WvStringParm subject, const WvRSAKey &rsa)
Create a certificate request (PKCS#10) using this function.
Definition: wvx509.cc:266
WvX509::get_policy_constraints
bool get_policy_constraints(int &require_explicit_policy, int &inhibit_policy_mapping) const
Get the values in the policy constraints extension.
WvX509::get_altsubject
WvString get_altsubject() const
Return the Subject alt name if it exists, and WvString::null if it doesn't.
Definition: wvx509.cc:782
UUID_MAP_ENTRY
#define UUID_MAP_ENTRY(iface)
Add an entry to an interface map.
Definition: utils.h:68
WvBufBase< unsigned char >::getstr
WvString getstr()
Returns the entire buffer as a null-terminated WvString.
Definition: wvbuffer.cc:17
WvX509::signedbyca
bool signedbyca(WvX509 &cacert) const
Check the certificate in cert against the CA certificate in cacert.
Definition: wvx509.cc:393
WvBufBase< unsigned char >::putstr
void putstr(WvStringParm str)
Copies a WvString into the buffer, excluding the null-terminator.
Definition: wvbuffer.cc:11
UUID_MAP_BEGIN
#define UUID_MAP_BEGIN(component)
Start the interface map for "component".
Definition: utils.h:63
WvX509::set_policy_mapping
void set_policy_mapping(PolicyMapList &list)
Set the policy mappings for this certificate.
WvX509::get_ocsp
void get_ocsp(WvStringList &responders) const
Get a list of OCSP Responders for this certificate.
Definition: wvx509.cc:1030
WvX509::get_nsserver
WvString get_nsserver() const
get and set the Netscape SSL Server extension
Definition: wvx509.cc:698
WvBufBase< unsigned char >::putch
void putch(int ch)
Puts a single character into the buffer as an int.
Definition: wvbuf.h:76
WvX509::get_ext_key_usage
WvString get_ext_key_usage() const
Get and set the extendedKeyUsage field.
Definition: wvx509.cc:776
WvX509::validate
bool validate(WvX509 *cacert=NULL) const
Function to verify the validity of a certificate that has been placed in cert.
Definition: wvx509.cc:359
trim_string
char * trim_string(char *string)
Trims whitespace from the beginning and end of the character string, including carriage return / line...
Definition: strutils.cc:59
WvX509::isok
virtual bool isok() const
Is the certificate object valid?
Definition: wvx509.cc:1285
WvX509::errstr
virtual WvString errstr() const
Returns an error string if isok() is not true.
Definition: wvx509.cc:1297
WvX509::get_aia
WvString get_aia() const
Get the authority info access information.
Definition: wvx509.cc:1006
WvRSAKey
An RSA public key or public/private key pair that can be used for encryption.
Definition: wvrsa.h:26
WvString
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:329
WvLog
A WvLog stream accepts log messages from applications and forwards them to all registered WvLogRcv's.
Definition: wvlog.h:56
WvX509::set_pubkey
void set_pubkey(WvRSAKey &rsa_pubkey)
Set the public key of the certificate to the public key rsa_pubkey.
Definition: wvx509.cc:653
WvX509::set_version
void set_version()
Set the Certificate to use X509v3, since that's all modern PKI uses anyways :)
Definition: wvx509.cc:722
unhexify
void unhexify(void *obuf, const char *ibuf)
Reverse the operation performed by hexify().
Definition: wvhex.cc:104
wvstrutils.h
WvStringList::join
WvString join(const char *joinchars=" ") const
concatenates all elements of the list seperating on joinchars
Definition: wvstringlist.cc:14
WvX509::~WvX509
virtual ~WvX509()
Destructor.
Definition: wvx509.cc:150
WvX509::WvX509
WvX509()
Initialize a completely empty X509 Object with an X509 certificate that doesn't have anything it it....
Definition: wvx509.cc:131
WvBufBase< unsigned char >
Specialization of WvBufBase for unsigned char type buffers intended for use with raw memory buffers.
Definition: wvbuf.h:22
WvX509::get_serial
WvString get_serial(bool hex=false) const
get and set the serialNumber field of the certificate
Definition: wvx509.cc:704
UUID_MAP_END
#define UUID_MAP_END
Marks the end of an interface map.
Definition: utils.h:80
hexify
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 '...
Definition: wvhex.cc:95
IObject
Definition: IObject.h:65
WvX509::get_crl_urls
void get_crl_urls(WvStringList &urls) const
Get a list of URLs that are valid CRL distribution points for this certificate.
Definition: wvx509.cc:1042
WvX509::get_issuer
WvString get_issuer() const
Get and set the Certificate Issuer (usually the CA who signed the certificate).
Definition: wvx509.cc:594
deletev
#define deletev
Remplacement for delete[].
Definition: delete.h:129
strlwr
char * strlwr(char *string)
In-place modify a character string so that all contained letters are in lower case.
Definition: strutils.cc:201
WvX509::issuedbyca
bool issuedbyca(WvX509 &cacert) const
Check to see if the certificate in cert was issued by the CA certificate in cacert.
Definition: wvx509.cc:422
WvSSL_Stupid_Refcount
Definition: wvx509.cc:64
WvDynBufBase< unsigned char >
WvX509::get_policies
bool get_policies(WvStringList &policy_oids) const
Get any certificate Policy OIDs.
Definition: wvx509.cc:1080
WvX509::get_aki
WvString get_aki() const
Get the Authority key Info.
Definition: wvx509.cc:1402
WvX509::get_crl_dp
WvString get_crl_dp() const
get the CRL Distribution points if they exist, WvString::null if they don't.
Definition: wvx509.cc:738
WvBufBaseCommonImpl::used
size_t used() const
Returns the number of elements in the buffer currently available for reading.
Definition: wvbufbase.h:92
WvEncoder::flushstrmem
bool flushstrmem(WvStringParm instr, void *outmem, size_t *outlen, bool finish=false)
Flushes data through the encoder from a string to memory.
Definition: wvencoder.cc:150
WvBufBaseCommonImpl::peek
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...
Definition: wvbufbase.h:225
WvX509::operator!
bool operator!() const
The not operator returns true if !isok()
Definition: wvx509.cc:1291
WvStringList
This is a WvList of WvStrings, and is a really handy way to parse strings.
Definition: wvstringlist.h:27
WvX509::get_subject
WvString get_subject() const
get and set the Subject field of the certificate
Definition: wvx509.cc:624
WvStringList::split
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.
Definition: wvstringlist.cc:19
WvX509::get_key_usage
WvString get_key_usage() const
Get and set the keyUsage field.
Definition: wvx509.cc:764
WvX509::set_policy_constraints
void set_policy_constraints(int require_explicit_policy, int inhibit_policy_mapping)
Set the values in the policy constraints extension.
WvX509::get_ca_urls
void get_ca_urls(WvStringList &urls) const
Get a list of urls that have the Certificate of the CA that issued this certificate.
Definition: wvx509.cc:1036
WvX509::set_crl_urls
void set_crl_urls(WvStringList &urls)
Set the list of URLs that are valid CRL distribution points for this certificate.
Definition: wvx509.cc:1048
WvX509::set_aia
void set_aia(WvStringList &ca_urls, WvStringList &responders)
Set a list of urls that have the Certificate of the CA that issued this certificate,...
Definition: wvx509.cc:984
WvX509::encode
WvString encode(const DumpMode mode) const
Return the information requested by mode.
Definition: wvx509.cc:441